0
1
Fork 0

Checkpoint

This commit is contained in:
Juan Ferrer 2022-06-06 10:53:59 +02:00
parent de19063ed9
commit 87a583794a
97 changed files with 1436 additions and 1673 deletions

View File

@ -1,4 +1,4 @@
Addresses: Direccions Addresses: Adreces
Return: Tornar Return: Tornar
AddAddress: Afegir adreça AddAddress: Afegir adreça
SetAsDefault: Establir com per defecte SetAsDefault: Establir com per defecte

View File

@ -31,7 +31,7 @@ Hedera.Catalog = new Class({
else else
this.setView(Hedera.Catalog.View.GRID); this.setView(Hedera.Catalog.View.GRID);
this.onRealmChange(); this.onFilterChange();
} }
,deactivate: function() { ,deactivate: function() {
@ -40,58 +40,81 @@ Hedera.Catalog = new Class({
Vn.Node.remove(this.$.rightPanel); Vn.Node.remove(this.$.rightPanel);
} }
,onFilterChange: function() { ,getFilter(params, tags, currentTag) {
if (params.search == null && params.type == null)
return null;
const $ = this.$; const $ = this.$;
const hash = this.hash;
if (hash.search != null || hash.type != null) { params = Object.assign({}, params);
const filter = new Sql.Operation({ const filter = new Sql.Operation({
type: Sql.Operation.Type.AND type: Sql.Operation.Type.AND
}); });
let idSearch = false; let idSearch = false;
if (hash.search != null) { if (params.search != null) {
idSearch = /^\d+$/.test(hash.search); idSearch = /^\d+$/.test(params.search);
filter.push(idSearch ? $.idOp : $.nameOp);
}
if (!idSearch) { if (!idSearch) {
if (hash.realm != null) filter.push($.searchOp);
filter.push($.realmOp); params.search = `%${params.search}%`;
if (hash.type != null) } else
filter.push($.typeOp); filter.push($.idOp);
}
const tags = [ if (!idSearch) {
'color', if (params.realm != null)
'origin', filter.push($.realmOp);
'category', if (params.type != null)
'producer' filter.push($.typeOp);
];
for (const tag of tags)
if (hash[tag] != null)
filter.push($[`${tag}Op`]);
}
const lot = new Vn.Lot(); for (const tag of tags)
lot.set('filter', filter); if (tag != currentTag && params[tag] != null)
$.items.lot = lot; filter.push($[`${tag}Op`]);
} else }
$.items.lot = null;
params.filter = filter;
const lot = new Vn.Lot();
lot.setAll(params);
return lot;
} }
,onRealmChange: function() { ,onFilterChange: function() {
const hasRealm = this.$.realm.value != null; const $ = this.$;
this.$.filters.style.display = hasRealm ? 'block' : 'none'; const params = $.params.$;
this.$.realmMsg.style.display = hasRealm ? 'none' : 'block';
this.refreshTitle(); this.refreshTitle();
const hasRealm = params.realm != null;
$.filters.style.display = hasRealm ? 'block' : 'none';
$.realmMsg.style.display = hasRealm ? 'none' : 'block';
const tags = [
'color',
'origin',
'category',
'producer'
];
const lot = this.getFilter(params, tags);
if (lot) {
$.items.lot = lot;
$.items.refresh();
} else
$.items.clean();
for (const tag of tags)
if (params[tag] != null)
$[`${tag}`].lot = this.getFilter(params, tags);
} }
,refreshTitle: function() { ,refreshTitle: function() {
const hash = this.hash.$;
const types = this.$.types; const types = this.$.types;
const realms = this.$.realms; const realms = this.$.realms;
const type = this.$.type.value; const type = hash.type;
const realm = this.$.realm.value; const realm = hash.realm;
let typeName; let typeName;
let realmName; let realmName;
@ -232,7 +255,7 @@ Hedera.Catalog = new Class({
this.onEraseClick(); this.onEraseClick();
this.$.card.row = form.row; this.$.card.row = form.row;
this.$.cardItem.value = form.$.id; this.$.cardLot.value = form.$.id;
this.$.cardPopup.show(event.currentTarget); this.$.cardPopup.show(event.currentTarget);
} }
@ -270,7 +293,7 @@ Hedera.Catalog = new Class({
const params = { const params = {
warehouse: warehouse, warehouse: warehouse,
item: this.$.cardItem.value, item: this.$.cardLot.value,
amount: amount amount: amount
} }
sql += query.render(params); sql += query.render(params);
@ -295,7 +318,7 @@ Hedera.Catalog = new Class({
,onPopupClose: function() { ,onPopupClose: function() {
this.onEraseClick(); this.onEraseClick();
this.$.card.row = -1; this.$.card.row = -1;
this.$.cardItem.value = undefined; this.$.cardLot.value = undefined;
} }
,onCardLoad: function() { ,onCardLoad: function() {
@ -309,163 +332,3 @@ Hedera.Catalog.extend({
GRID: 1 GRID: 1
} }
}); });
Vn.Filter = new Class({
Extends: Htk.Field
,Tag: 'vn-filter'
,Child: 'model'
,Properties: {
model: {
type: Db.Model
,set: function(x) {
x.lot = this._lot;
this._model = x;
this._select.model = x;
}
,get: function() {
return this._model;
}
},
placeholder: {
type: String
,set: function(x) {
this._select.placeholder = x;
this._placeholder = x;
}
,get: function() {
return this._placeholder;
}
},
filter: {
type: Sql.Filter
,set: function(x) {
this._filter = x;
this._lot.set('filter', x);
}
,get: function() {
return this._filter;
}
}
}
,_valueColumnIndex: 0
,_showColumnIndex: 1
,initialize: function(props) {
var node = this.createRoot('div');
node.className = 'vn-filter';
this._select = new Htk.Select();
this._select.on('mousedown', this._onMouseDown, this);
this._select.on('changed', this._onChange, this);
this._select.on('ready', this._onReady, this);
this.node.appendChild(this._select.node);
this._ul = this.createElement('ul');
this.node.appendChild(this._ul);
this._lot = new Vn.Lot();
this.parent(props);
}
,_onMouseDown: function() {
if (this._model && this._model.status === Db.Model.Status.CLEAN)
this._model.refresh();
}
,_onCloseClick: function() {
this._removeSelectionNode();
this._changeValue(undefined);
}
,_removeSelectionNode: function() {
if (this._lastLi) {
Vn.Node.remove(this._lastLi);
this._lastLi = null;
this._label = null;
}
}
,_onChange: function() {
if (this._select.value === null
|| this._select.value === undefined)
return;
this._realSetValue(this._select.value);
}
,_onReady: function() {
if (this._emptyLabel)
this._refreshLabel();
}
,_changeValue: function(newValue) {
this._lot.block();
this.value = newValue;
this._lot.unblock();
}
,_onTimeout: function() {
this._select.value = null;
}
,putValue: function(value) {
this._onMouseDown();
this._realSetValue(value);
}
,_realSetValue: function(value) {
this._removeSelectionNode();
if (value === null || value === undefined)
return;
var li = this._lastLi = this.createElement('li');
this._ul.appendChild(li);
var button = this.createElement('button');
button.addEventListener('click',
this._onCloseClick.bind(this, li));
li.appendChild(button);
var icon = new Htk.Icon({
name: 'close',
alt: _('Close')
});
button.appendChild(icon.node);
var text = this._label = this.createTextNode('');
li.appendChild(text);
setTimeout(this._onTimeout.bind(this));
this._changeValue(value);
this._refreshLabel();
}
,_refreshLabel: function() {
if (!this._label)
return;
let row = -1;
const model = this._model;
let showValue = '';
this._emptyLabel = true;
if (model) {
if (model.ready) {
row = model.searchByIndex(this._valueColumnIndex, this._value);
if (row != -1) {
var label = model.getByIndex(row, this._showColumnIndex);
showValue = label;
this._emptyLabel = false;
}
} else
showValue = _('Loading...');
}
this._label.nodeValue = showValue;
}
});

View File

@ -88,41 +88,7 @@
padding: 0; padding: 0;
width: 100%; width: 100%;
} }
.right-panel .vn-filter,
.right-panel select {
margin: 0 auto;
margin-bottom: .7em;
display: block;
}
.vn-filter > ul {
margin: 0;
list-style-type: none;
text-align: left;
color: #666;
padding-left: .8em;
}
.vn-filter li {
margin: 0;
margin-top: .3em;
line-height: 2em;
max-width: 90%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.vn-filter li > button {
vertical-align: middle;
text-align: center;
padding: .2em;
margin: 0;
margin-right: .2em;
}
.vn-filter li > button > span {
display: block;
}
.right-panel .filters > button { .right-panel .filters > button {
display: block;
margin: 0 auto;
margin-top: 1em; margin-top: 1em;
} }

View File

@ -4,8 +4,7 @@
<div id="subtitle"></div> <div id="subtitle"></div>
</div> </div>
<div id="actions" class="catalog-actions"> <div id="actions" class="catalog-actions">
<htk-search-entry <htk-search-entry form="params" column="search"/>
param="search"/>
<htk-bar-button <htk-bar-button
id="view-button" id="view-button"
tip="_Switch view" tip="_Switch view"
@ -27,56 +26,65 @@
<vn-spec name="realm" type="Number"/> <vn-spec name="realm" type="Number"/>
<vn-spec name="type" type="Number"/> <vn-spec name="type" type="Number"/>
</vn-lot-query> </vn-lot-query>
<vn-lot id="filter-lot"/>
</vn-group> </vn-group>
<vn-group> <vn-group>
<sql-operation <sql-filter-item
id="id-op" id="id-op"
type="EQUAL"> type="EQUAL"
<sql-field target="i" name="id"/> target="i"
<sql-value param="search"/> field="id"
</sql-operation> param="search"/>
<sql-operation <sql-operation
id="name-op" id="search-op"
type="LIKE"> type="OR">
<sql-field target="i" name="longName"/> <sql-filter-item
<sql-search-tags param="search"/> type="LIKE"
target="i"
field="longName"
param="search"/>
<sql-filter-item
type="LIKE"
target="i"
field="subname"
param="search"/>
</sql-operation> </sql-operation>
<sql-operation <sql-filter-item
id="realm-op" id="realm-op"
type="EQUAL"> type="EQUAL"
<sql-field target="t" name="categoryFk"/> target="t"
<sql-value param="realm"/> field="categoryFk"
</sql-operation> param="realm"/>
<sql-operation <sql-filter-item
id="type-op" id="type-op"
type="EQUAL"> type="EQUAL"
<sql-field target="i" name="typeFk"/> target="i"
<sql-value param="type"/> field="typeFk"
</sql-operation> param="type"/>
<sql-operation <sql-filter-item
id="color-op" id="color-op"
type="EQUAL">
<sql-field target="i" name="inkFk"/>
<sql-value param="color"/>
</sql-operation>
<sql-operation
type="EQUAL" type="EQUAL"
id="origin-op"> target="i"
<sql-field target="i" name="originFk"/> field="inkFk"
<sql-value param="origin"/> param="color"/>
</sql-operation> <sql-filter-item
<sql-operation
type="EQUAL" type="EQUAL"
id="category-op"> id="origin-op"
<sql-field target="i" name="category"/> target="i"
<sql-value param="category"/> field="originFk"
</sql-operation> param="origin"/>
<sql-operation <sql-filter-item
type="EQUAL"
id="category-op"
target="i"
field="category"
param="category"/>
<sql-filter-item
id="producer-op" id="producer-op"
type="EQUAL"> type="EQUAL"
<sql-field target="i" name="producerFk"/> target="i"
<sql-value param="producer"/> field="producerFk"
</sql-operation> param="producer"/>
</vn-group> </vn-group>
<vn-group> <vn-group>
<db-form id="basket" on-ready="onBasketReady"> <db-form id="basket" on-ready="onBasketReady">
@ -89,6 +97,7 @@
</db-form> </db-form>
<db-model <db-model
id="items" id="items"
auto-load="false"
result-index="2" result-index="2"
on-status-changed="onItemsChange"> on-status-changed="onItemsChange">
CREATE TEMPORARY TABLE tmp.item CREATE TEMPORARY TABLE tmp.item
@ -230,14 +239,16 @@
</div> </div>
<div id="filters" class="filters"> <div id="filters" class="filters">
<h2><t>Filter by</t></h2> <h2><t>Filter by</t></h2>
<vn-filter <htk-combo
placeholder="_Family" placeholder="_Family"
param="type" form="params"
column="type"
id="type-filter"> id="type-filter">
<db-model <db-model
id="types" id="types"
property="model" property="model"
conn="conn" conn="conn"
lot="params"
result-index="1" result-index="1"
on-status-changed="refreshTitle"> on-status-changed="refreshTitle">
CALL myBasket_getAvailable; CALL myBasket_getAvailable;
@ -246,21 +257,21 @@
JOIN vn.itemType t ON t.id = i.typeFk JOIN vn.itemType t ON t.id = i.typeFk
JOIN tmp.itemAvailable a ON a.id = i.id JOIN tmp.itemAvailable a ON a.id = i.id
JOIN vn.itemTypeL10n l ON l.id = t.id JOIN vn.itemTypeL10n l ON l.id = t.id
WHERE t.`order` >= 0 AND #filter WHERE t.`order` >= 0
AND t.categoryFk = #realm
ORDER BY t.`order`, l.name ORDER BY t.`order`, l.name
</db-model> </db-model>
<sql-filter property="filter" type="AND"> </htk-combo>
<sql-filter-item type="EQUAL"> <htk-combo
<sql-field name="categoryFk" target="t"/>
<sql-value param="realm"/>
</sql-filter-item>
</sql-filter>
</vn-filter>
<vn-filter
placeholder="_Color" placeholder="_Color"
param="color" form="params"
id="color-filter"> column="color"
<db-model property="model" auto-load="false" result-index="1"> on-click="$.colors.refresh()">
<db-model
id="colors"
property="model"
auto-load="false"
result-index="1">
CALL myBasket_getAvailable; CALL myBasket_getAvailable;
SELECT DISTINCT l.id, l.name SELECT DISTINCT l.id, l.name
FROM vn.item i FROM vn.item i
@ -270,12 +281,17 @@
WHERE #filter WHERE #filter
ORDER BY name ORDER BY name
</db-model> </db-model>
</vn-filter> </htk-combo>
<vn-filter <htk-combo
placeholder="_Producer" placeholder="_Producer"
param="producer" form="params"
id="producer-filter"> column="producer"
<db-model property="model" auto-load="false" result-index="1"> on-click="$.producers.refresh()">
<db-model
id="producers"
property="model"
auto-load="false"
result-index="1">
CALL myBasket_getAvailable; CALL myBasket_getAvailable;
SELECT DISTINCT p.id, p.name SELECT DISTINCT p.id, p.name
FROM vn.item i FROM vn.item i
@ -285,12 +301,17 @@
WHERE #filter WHERE #filter
ORDER BY name ORDER BY name
</db-model> </db-model>
</vn-filter> </htk-combo>
<vn-filter <htk-combo
placeholder="_Origin" placeholder="_Origin"
param="origin" form="params"
id="origin-filter"> column="origin"
<db-model property="model" auto-load="false" result-index="1"> on-click="$.origins.refresh()">
<db-model
id="origins"
property="model"
auto-load="false"
result-index="1">
CALL myBasket_getAvailable; CALL myBasket_getAvailable;
SELECT DISTINCT o.id, l.name, o.code SELECT DISTINCT o.id, l.name, o.code
FROM vn.item i FROM vn.item i
@ -301,12 +322,17 @@
WHERE #filter WHERE #filter
ORDER BY name ORDER BY name
</db-model> </db-model>
</vn-filter> </htk-combo>
<vn-filter <htk-combo
placeholder="_Category" placeholder="_Category"
param="category" form="params"
id="category-filter"> column="category"
<db-model property="model" auto-load="false" result-index="1"> on-click="$.categorys.refresh()">
<db-model
id="categorys"
property="model"
auto-load="false"
result-index="1">
CALL myBasket_getAvailable; CALL myBasket_getAvailable;
SELECT DISTINCT i.category, i.category SELECT DISTINCT i.category, i.category
FROM vn.item i FROM vn.item i
@ -315,7 +341,7 @@
WHERE #filter WHERE #filter
ORDER BY category ORDER BY category
</db-model> </db-model>
</vn-filter> </htk-combo>
</div> </div>
<div id="order" class="order"> <div id="order" class="order">
<h2><t>Order by</t></h2> <h2><t>Order by</t></h2>

View File

@ -78,7 +78,7 @@ Model.implement({
lot: { lot: {
type: Vn.LotIface type: Vn.LotIface
,set: function(x) { ,set: function(x) {
this.link({_lot: x}, {'change': this._autoLoad}); this.link({_lot: x}, {'change': this._onLotChange});
this._onLotChange(); this._onLotChange();
} }
,get: function() { ,get: function() {
@ -232,25 +232,55 @@ Model.implement({
this.query = query; this.query = query;
} }
,_getLotParams: function() { ,_getHolders(stmt) {
if (!this._stmt) if (!stmt) return null;
return null; let holders = this._stmt.findHolders();
var holders = this._stmt.findHolders(); if (!holders) return null;
if (!holders)
return null; if (this._lot) {
var lotParams = this._lot ? this._lot.params : {}; const params = this._lot.params;
for (const holder of holders)
if (params[holder] instanceof Sql.Object) {
const paramHolders = params[holder].findHolders();
if (paramHolders)
holders = holders.concat(paramHolders);
}
}
return holders;
}
,_getHolderValues: function() {
let holders = this._getHolders(this._stmt);
if (!holders) return null;
const lotParams = this._lot ? this._lot.params : {};
const params = {};
for (const holder of holders)
if (!(lotParams[holder] instanceof Sql.Object))
params[holder] = lotParams[holder];
return params;
}
,_getHolderParams: function() {
let holders = this._getHolders(this._stmt);
if (!holders) return null;
const lotParams = this._lot ? this._lot.params : {};
const params = {};
for (const holder of holders)
params[holder] = lotParams[holder];
if (lotParams == null)
lotParams = {};
var params = {};
for (var i = 0; i < holders.length; i++)
params[holders[i]] = lotParams[holders[i]];
return params; return params;
} }
,_onLotChange: function() { ,_onLotChange: function() {
var lotParams = this._getLotParams(); const params = this._getHolderValues();
if (!Vn.Value.equals(lotParams, this._lastLotParams)) const isEqual = Vn.Value.equals(params, this._lastParams);
this._lastParams = params;
if (!isEqual)
this._autoLoad(); this._autoLoad();
} }
@ -265,13 +295,9 @@ Model.implement({
if (!this._stmt || !this._conn) if (!this._stmt || !this._conn)
return false; return false;
var holders = this._stmt.findHolders(); for (const param in params)
if (!holders) if (params[param] === undefined)
return true; return false;
for (var i = 0; i < holders.length; i++)
if (params[holders[i]] === undefined)
return false;
return true; return true;
} }
@ -279,22 +305,13 @@ Model.implement({
/** /**
* Refresh the model data reexecuting the query on the database. * Refresh the model data reexecuting the query on the database.
*/ */
,refresh: function(params) { ,refresh: function() {
var lotParams = this._getLotParams(); const params = this._getHolderParams();
var myParams = {};
Object.assign(myParams, lotParams); if (this._isReady(params)) {
Object.assign(myParams, params);
if (this._filter && (!params || params.filter === undefined))
myParams.filter = this._filter;
this._lastLotParams = lotParams;
if (this._isReady(myParams)) {
this._setStatus(Status.LOADING); this._setStatus(Status.LOADING);
this._conn.execStmt(this._stmt, this._conn.execStmt(this._stmt,
this._selectDone.bind(this), myParams); this._selectDone.bind(this), params);
} else } else
this.clean(); this.clean();
} }

View File

@ -61,4 +61,4 @@ Training: Formació
Agencies: Agències Agencies: Agències
Configuration: Configuració Configuration: Configuració
Account: Compte Account: Compte
Addresses: Direccions Addresses: Adreces

View File

@ -1,6 +1,6 @@
require('./style.scss');
var Widget = require('./widget'); var Widget = require('../widget');
var Assistant = require('./assistant'); var Assistant = require('../assistant');
module.exports = new Class({ module.exports = new Class({
Extends: Widget, Extends: Widget,

View File

@ -0,0 +1,66 @@
.htk-assistant-bar {
position: relative;
padding: .8em;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
width: 100%;
& > button {
border-radius: 50%;
padding: .5em;
margin: 0;
text-align: center;
& > img {
display: block;
width: 1.8em;
padding: .5em;
}
}
& > .end {
display: none;
color: #8cc63f;
& > .icon {
font-size: 1.6rem;
}
}
& > .steps {
display: flex;
align-items: center;
& > div {
background-color: #AAA;
width: .5em;
height: .5em;
cursor: pointer;
border-radius: 50%;
margin: .5em;
transition-property: width, height;
transition-duration: 100ms;
transition-timing-function: ease-in-out;
&.selected {
background-color: #666;
width: 1em;
height: 1em;
}
&:hover {
opacity: .7;
}
}
& > img {
width: 1.3em;
margin: 0 .2em;
cursor: pointer;
&:hover {
opacity: .7;
}
}
}
}

View File

@ -1,7 +1,7 @@
require('./style.scss');
var Widget = require('./widget'); var Widget = require('../widget');
var Step = require('./step'); var Step = require('../step');
var Toast = require('./toast'); var Toast = require('../toast');
/** /**
* A simple assistant with steps. * A simple assistant with steps.

View File

@ -0,0 +1,14 @@
.htk-assistant > div {
display: none;
& > h2 {
text-align: center;
font-weight: normal;
font-size: 1.5rem;
margin: 0;
padding: 0;
margin-bottom: 1em;
font-weight: bold;
}
}

View File

@ -1,34 +0,0 @@
module.exports = new Class
({
Extends: Htk.Column
,Tag: 'htk-column-check'
,initialize: function (props)
{
this._cssClass = 'cell-check';
this.parent (props);
}
,render: function (tr)
{
var checkButton = this.createElement ('input');
checkButton.type = 'checkbox';
checkButton.checked = this.value;
if (this.editable)
checkButton.addEventListener ('changed',
this.inputChanged.bind (this, tr, node));
else
checkButton.disabled = true;
var td = this.parent (tr);
td.appendChild (checkButton);
return td;
}
,inputChanged: function (tr, node)
{
this.changed (tr, node.value);
}
});

View File

@ -1,5 +1,5 @@
var NodeBuilder = require('../vn/node-builder'); var NodeBuilder = require('../../vn/node-builder');
/** /**
* Represents a grid column. This is an abstract class and should not be * Represents a grid column. This is an abstract class and should not be

View File

@ -1,39 +0,0 @@
module.exports = new Class
({
Extends: Htk.Column
,Tag: 'htk-column-radio'
,Properties:
{
param:
{
type: Vn.Param
,set: function (x)
{
this.radioGroup.master = x;
}
}
}
,initialize: function (props)
{
this._cssClass = 'cell-radio';
this.radioGroup = new Htk.RadioGroup (this.doc);
this.parent (props);
}
,render: function (tr)
{
var td = this.parent (tr);
var radio = this.radioGroup.createButton (this.value);
td.appendChild (radio);
return td;
}
,clear: function ()
{
this.radioGroup.clear ();
}
});

View File

@ -0,0 +1,30 @@
module.exports = new Class({
Extends: Htk.Column
,Tag: 'htk-column-check'
,initialize: function(props) {
this._cssClass = 'cell-check';
this.parent(props);
}
,render: function(tr) {
var checkButton = this.createElement('input');
checkButton.type = 'checkbox';
checkButton.checked = this.value;
if (this.editable)
checkButton.addEventListener('changed',
this.inputChanged.bind(this, tr, node));
else
checkButton.disabled = true;
var td = this.parent(tr);
td.appendChild(checkButton);
return td;
}
,inputChanged: function(tr, node) {
this.changed(tr, node.value);
}
});

View File

@ -1,39 +1,33 @@
module.exports = new Class module.exports = new Class({
({
Extends: Htk.Column Extends: Htk.Column
,Tag: 'htk-column-image' ,Tag: 'htk-column-image'
,Properties: ,Properties: {
{
/** /**
* The directory where the images are allocated. * The directory where the images are allocated.
*/ */
directory: directory:{
{
type: String type: String
,value: null ,value: null
}, },
/** /**
* The subdirectory where the images are allocated. * The subdirectory where the images are allocated.
*/ */
subdir: subdir:{
{
type: String type: String
,value: null ,value: null
}, },
/** /**
* Subdirectory where full images are allocated. * Subdirectory where full images are allocated.
*/ */
fullDir: fullDir:{
{
type: String type: String
,value: null ,value: null
}, },
/** /**
* The REST connection used to upload the image. * The REST connection used to upload the image.
*/ */
conn: conn:{
{
type: Vn.JsonConnection type: Vn.JsonConnection
} }
} }

View File

@ -1,23 +1,19 @@
module.exports = new Class module.exports = new Class({
({
Extends: Htk.Column Extends: Htk.Column
,Tag: 'htk-column-link' ,Tag: 'htk-column-link'
,Properties: ,Properties: {
{
/** /**
* The link url. * The link url.
*/ */
href: href:{
{
type: String type: String
,value: null ,value: null
}, },
/** /**
* the target where the link is opened. * the target where the link is opened.
*/ */
target: target:{
{
type: String type: String
,value: null ,value: null
} }

View File

@ -0,0 +1,32 @@
module.exports = new Class({
Extends: Htk.Column
,Tag: 'htk-column-radio'
,Properties: {
param:{
type: Vn.Param
,set: function(x) {
this.radioGroup.master = x;
}
}
}
,initialize: function(props) {
this._cssClass = 'cell-radio';
this.radioGroup = new Htk.RadioGroup(this.doc);
this.parent(props);
}
,render: function(tr) {
var td = this.parent(tr);
var radio = this.radioGroup.createButton(this.value);
td.appendChild(radio);
return td;
}
,clear: function() {
this.radioGroup.clear();
}
});

View File

@ -1,15 +1,12 @@
module.exports = new Class module.exports = new Class({
({
Extends: Htk.Column Extends: Htk.Column
,Tag: 'htk-column-spin' ,Tag: 'htk-column-spin'
,Properties: ,Properties: {
{
/** /**
* The text to append to the number. * The text to append to the number.
*/ */
unit: unit:{
{
type: String type: String
,value: null ,value: null
}, },

View File

@ -1,15 +1,12 @@
module.exports = new Class module.exports = new Class({
({
Extends: Htk.Column Extends: Htk.Column
,Tag: 'htk-column-text' ,Tag: 'htk-column-text'
,Properties: ,Properties: {
{
/** /**
* Format that applies to the value. * Format that applies to the value.
*/ */
format: format:{
{
type: String type: String
,set: function(x) { ,set: function(x) {
this._format = _(x); this._format = _(x);

View File

@ -1,5 +1,5 @@
const Widget = require('./widget'); const Widget = require('../widget');
module.exports = new Class({ module.exports = new Class({
Extends: Widget Extends: Widget

View File

@ -1,5 +1,5 @@
require('./style.scss');
var Popup = require('./popup'); var Popup = require('../popup');
/** /**
* Class to show message dialogs with buttons. * Class to show message dialogs with buttons.

25
js/htk/dialog/style.scss Normal file
View File

@ -0,0 +1,25 @@
.htk-dialog {
padding: 1.5em;
max-width: 20em;
font-weight: normal;
color: #555;
p {
margin: 0;
}
img {
float: left;
height: 3em;
margin-top: 0;
margin-right: 1em;
}
p {
padding: 0;
}
.button-bar > button {
float: right;
margin-left: 1em;
margin-top: .5em;
}
}

View File

@ -1,5 +1,5 @@
var Widget = require('./widget'); var Widget = require('../widget');
module.exports = new Class({ module.exports = new Class({
Extends: Widget Extends: Widget
@ -109,6 +109,10 @@ module.exports = new Class({
if (this.conditionalFunc) if (this.conditionalFunc)
this.conditionalFunc(this, newValue); this.conditionalFunc(this, newValue);
const node = this.node;
if (node && node.nodeType === Node.ELEMENT_NODE)
node.classList.toggle('filled', newValue !== undefined);
this._notifyChanges(); this._notifyChanges();
} }

View File

@ -1,46 +0,0 @@
module.exports = new Class
({
Extends: Htk.Field
,Tag: 'htk-spin'
,render: function ()
{
var input = this.createRoot ('input');
//setInputTypeNumber (input);
this.node.type = 'number';
input.addEventListener ('change', this._onChange.bind (this));
this.unit = null;
this.digits = 0;
}
,_onChange: function ()
{
var newValue = (this.node.value == '') ? null : parseFloat (this.node.value);
this.node.value = newValue;
this.valueChanged (newValue);
}
,putValue: function (value)
{
var text;
if (value != null)
{
text = (new Number (value)).toFixed (this.digits);
if (this.unit != null)
text += ' ' + this.unit;
}
else
text = '';
this.node.value = text;
}
,setEditable: function (editable)
{
this.node.readOnly = !editable;
}
});

View File

@ -1,5 +1,5 @@
var Button = require('./button'); var Button = require('../button');
module.exports = new Class({ module.exports = new Class({
Extends: Button Extends: Button

View File

@ -1,3 +1,4 @@
require('./style.scss');
module.exports = new Class({ module.exports = new Class({
Extends: Htk.Field Extends: Htk.Field

View File

@ -0,0 +1,10 @@
.htk-button {
display: flex;
align-items: center;
gap: 8px;
& > .htk-icon {
display: block;
}
}

View File

@ -1,3 +1,4 @@
require('./style.scss');
module.exports = new Class({ module.exports = new Class({
Extends: Htk.Field Extends: Htk.Field

View File

@ -0,0 +1,94 @@
@import "../../style/variables";
@import "../../style/classes";
.htk-calendar {
@extend %box;
width: 20em;
table {
border-collapse: collapse;
}
thead tr,
tfoot tr {
font-weight: normal;
vertical-align: middle;
text-align: center;
height: 3em;
}
thead > tr {
&.weekdays > th {
font-weight: normal;
color: #999;
text-transform: lowercase;
}
& > th {
&.previous, &.next {
font-size: .8rem;
button {
border-radius: 50%;
padding: 10px;
display: block;
margin: 0 auto;
& > .htk-icon {
font-size: 1rem;
}
}
}
&.month-year {
font-size: 1.2rem;
text-transform: lowercase;
}
}
}
tfoot tr {
border-top: none;
}
th.button {
display: table-cell;
}
th.button:hover {
cursor: pointer;
background-color: rgba(1, 1, 1, 0.2);
}
col {
width: 14.2%;
}
tr {
height: 2em;
}
tbody td {
text-align: right;
}
tbody td > div {
height: 2em;
width: 2em;
line-height: 2em;
text-align: center;
border-radius: 2em;
padding: 0.3em;
margin: 0 auto;
color: #555;
}
div {
&.disabled {
color: #bbb;
}
&.today {
font-weight: bold;
color: black;
}
&.selected {
color: white;
background-color: $color-primary;
}
&.enabled {
@extend %clickable;
&:hover {
background-color: rgba(140, 198, 63, 0.8);
}
}
}
}

View File

@ -1,8 +1,7 @@
require('./style.scss');
var Calendar = require('../calendar');
var Calendar = require('./calendar'); module.exports = new Class({
module.exports = new Class
({
Extends: Htk.Field Extends: Htk.Field
,Tag: 'htk-date-chooser' ,Tag: 'htk-date-chooser'

View File

@ -0,0 +1,17 @@
.htk-date-chooser {
display: flex;
align-items: center;
font-weight: normal;
& > span {
flex: 1;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
& > .htk-icon {
flex: none;
color: #666;
}
}

View File

@ -0,0 +1,35 @@
.htk-image {
position: relative;
overflow: hidden;
transition: opacity 250ms ease-out;
&.clickable:hover {
cursor: pointer;
opacity: 0.85;
}
& > img {
display: block;
height: 100%;
width: 100%;
}
& > button {
position: absolute;
top: 0;
left: 0;
padding: 8px;
margin: 4px;
display: none;
background-color: rgba(255, 255, 255, .6);
&:hover {
background-color: rgba(255, 255, 255, .8);
}
}
&:hover > button {
display: block;
}
& > button > .htk-icon {
display: block;
}
}

View File

@ -1,35 +1,30 @@
var htkRadioGroupUid = 0; var htkRadioGroupUid = 0;
module.exports = new Class module.exports = new Class({
({
Extends: Htk.Field Extends: Htk.Field
,Tag: 'htk-radio-group' ,Tag: 'htk-radio-group'
,radioLock: false ,radioLock: false
,initialize: function (props) ,initialize: function(props) {
{ this.clear();
this.clear (); this.parent(props);
this.parent (props);
} }
,clear: function () ,clear: function() {
{
this.name = htkRadioGroupUid++; this.name = htkRadioGroupUid++;
this.buttons = []; this.buttons = [];
} }
,createButton: function (value) ,createButton: function(value) {
{ var button = Vn.Browser.createRadio(this.name, this.doc);
var button = Vn.Browser.createRadio (this.name, this.doc);
button.value = value; button.value = value;
button.radioGroup = this; button.radioGroup = this;
return button; return button;
} }
,removeButton: function (button) ,removeButton: function(button) {
{
for (var i = 0; i < this.buttons.length; i++) for (var i = 0; i < this.buttons.length; i++)
if (this.buttons === button) { if (this.buttons === button) {
this.buttons.splice(i, 1); this.buttons.splice(i, 1);
@ -40,7 +35,7 @@ module.exports = new Class
/** /**
* @return %true if there is an option selected, otherwise it returns %false * @return %true if there is an option selected, otherwise it returns %false
*/ */
,isSelected: function () { ,isSelected: function() {
for (var i = 0; i < this.buttons.length; i++) for (var i = 0; i < this.buttons.length; i++)
if (this.buttons[i].value == this.value) if (this.buttons[i].value == this.value)
return true; return true;

View File

@ -1,3 +1,4 @@
require('./style.scss');
module.exports = new Class({ module.exports = new Class({
Extends: Htk.Field Extends: Htk.Field

View File

@ -0,0 +1,33 @@
.htk-search-entry {
display: flex;
align-items: center;
gap: 6px;
background-color: white;
height: 40px;
border-radius: 20px;
padding: 0 12px;
overflow: hidden;
& > * {
display: inline-block;
vertical-align: middle;
}
& > .htk-icon {
display: block;
margin: 0;
color: gray;
}
& > .entry {
margin: 0;
border: none;
width: 80px;
box-shadow: none;
padding-right: 0;
padding-left: 0;
height: inherit;
}
& > .entry:focus {
background-color: initial;
}
}

View File

@ -1,5 +1,5 @@
require('./style.scss');
var ColumnText = require('../column/text'); var ColumnText = require('../../columns/text');
module.exports = new Class({ module.exports = new Class({
Extends: Htk.Field Extends: Htk.Field
@ -111,11 +111,21 @@ module.exports = new Class({
const button = this.createRoot('button'); const button = this.createRoot('button');
button.type = 'button'; button.type = 'button';
button.className = 'htk-select input'; button.className = 'htk-select input';
button.addEventListener('mousedown', this._onButtonMouseDown.bind(this)); button.addEventListener('mousedown',
e => this._onButtonMouseDown(e));
this.label = this.createElement('span'); this.label = this.createElement('span');
button.appendChild(this.label); button.appendChild(this.label);
const erase = new Htk.Icon({
name: 'close',
title: _('Erase')
});
erase.classList.add('erase');
erase.addEventListener('mousedown',
e => this._onEraseMouseDown(e));
button.appendChild(erase.node);
const dropDown = new Htk.Icon({ const dropDown = new Htk.Icon({
name: 'expand_more' name: 'expand_more'
}); });
@ -128,12 +138,22 @@ module.exports = new Class({
this.iterChanged(); this.iterChanged();
} }
,_onButtonMouseDown: function(e) { ,_onEraseMouseDown(event) {
if (event.defaultPrevented) return;
event.preventDefault();
this._setRow(-1);
this.valueChanged(undefined);
}
,_onButtonMouseDown: function(event) {
if (this._popup) { if (this._popup) {
this._popup.hide(); this._popup.hide();
return; return;
} }
if (event.defaultPrevented) return;
event.preventDefault();
var model = this._model; var model = this._model;
var menu = this.createElement('div'); var menu = this.createElement('div');
@ -151,11 +171,9 @@ module.exports = new Class({
var popup = this._popup = new Htk.Popup({childNode: menu}); var popup = this._popup = new Htk.Popup({childNode: menu});
popup.on('closed', this._onPopupClose.bind(this)); popup.on('closed', this._onPopupClose.bind(this));
popup.show(this.node); popup.show(this.node, event);
this.emit('menu-show'); this.emit('menu-show');
e.stopPropagation();
} }
,_onGridClicked: function(grid, e) { ,_onGridClicked: function(grid, e) {

View File

@ -0,0 +1,53 @@
@import "../../style/variables";
.htk-select {
display: flex;
align-items: center;
font-weight: normal;
width: 100%;
& > span {
flex: 1;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
& > .htk-icon {
flex: none;
color: #666;
&.erase {
display: none
}
}
&:not(.filled) > span {
color: #666;
}
&.filled:hover > .htk-icon.erase {
display: block;
}
}
.htk-select-menu {
height: 100%;
max-height: 80em;
overflow: auto;
min-width: 14em;
tbody > tr {
border-top: none;
height: 2.5em;
}
td.message {
padding: 1em;
}
tr:hover {
background-color: rgba(1, 1, 1, 0.1);
cursor: pointer;
}
td {
max-width: 11em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}

View File

@ -0,0 +1,39 @@
module.exports = new Class({
Extends: Htk.Field
,Tag: 'htk-spin'
,render: function() {
var input = this.createRoot('input');
//setInputTypeNumber (input);
this.node.type = 'number';
input.addEventListener('change', this._onChange.bind(this));
this.unit = null;
this.digits = 0;
}
,_onChange: function() {
var newValue = (this.node.value == '') ? null : parseFloat(this.node.value);
this.node.value = newValue;
this.valueChanged(newValue);
}
,putValue: function(value) {
var text;
if (value != null) {
text = (new Number(value)).toFixed(this.digits);
if (this.unit != null)
text += ' ' + this.unit;
} else
text = '';
this.node.value = text;
}
,setEditable: function(editable) {
this.node.readOnly = !editable;
}
});

View File

@ -1,6 +1,6 @@
var Entry = require('./entry'); var Entry = require('../entry');
var ColumnRadio = require('../column/radio'); var ColumnRadio = require('../../columns/radio');
module.exports = new Class({ module.exports = new Class({
Extends: Entry Extends: Entry

View File

@ -1,6 +1,6 @@
require('./style.scss');
var Popup = require('./popup'); var Popup = require('../popup');
var Spinner = require('./spinner'); var Spinner = require('../spinner');
module.exports = new Class module.exports = new Class
({ ({

View File

@ -0,0 +1,12 @@
.htk-full-image {
img {
display: block;
cursor: pointer;
}
.htk-spinner {
background-color: #FFF;
margin: .6em;
display: block;
}
}

View File

@ -1,5 +1,5 @@
require('./style.scss');
var Widget = require('./widget'); var Widget = require('../widget');
module.exports = new Class({ module.exports = new Class({
Extends: Widget Extends: Widget

63
js/htk/grid/style.scss Normal file
View File

@ -0,0 +1,63 @@
@import "../style/variables";
.htk-grid {
margin: auto;
border-collapse: collapse;
& > thead > tr,
& > tfoot > tr {
background-color: $color-primary;
vertical-align: middle;
height: 3em;
}
th {
color: white;
cursor: pointer;
font-weight: normal;
padding: 0 0.4em;
}
th:hover {
background-color: rgba(1, 1, 1, 0.2);
}
tr {
height: 3.5em;
}
& > tfoot a,
& > thead a {
color: black;
}
tr.pair-row {
background-color: transparent;
}
& > tbody tr {
border-top: 1px solid #DDD;
}
& > tbody tr:first-child {
border-top: none;
}
& > tbody td {
margin: 0;
padding: 0 0.5em;
}
th,
td {
text-align: left;
}
td:first-child,
th:first-child {
padding-left: 1em;
}
td:last-child,
th:last-child {
padding-right: 1em;
}
.message {
padding: 1.5em;
text-align: center;
}
.message > * {
display: inline-block;
vertical-align: middle;
padding-right: .8em;
}
}

View File

@ -18,36 +18,37 @@ Htk = module.exports = {
,AssistantBar : require('./assistant-bar') ,AssistantBar : require('./assistant-bar')
,Step : require('./step') ,Step : require('./step')
,Loader : require('./loader') ,Loader : require('./loader')
,List : require('./list')
,Field : require('./field') ,Field : require('./field')
,Column : require('./column') ,Column : require('./column')
}; };
var Fields = { var Fields = {
Text : require('./field/text') Text : require('./fields/text')
,Html : require('./field/html') ,Html : require('./fields/html')
,Entry : require('./field/entry') ,Entry : require('./fields/entry')
,RadioGroup : require('./field/radio-group') ,RadioGroup : require('./fields/radio/radio-group')
,Radio : require('./field/radio') ,Radio : require('./fields/radio')
,Label : require('./field/label') ,Label : require('./fields/label')
,TextArea : require('./field/text-area') ,TextArea : require('./fields/text-area')
,Spin : require('./field/spin') ,Spin : require('./fields/spin')
,Check : require('./field/check') ,Check : require('./fields/check')
,Select : require('./field/select') ,Select : require('./fields/select')
,Calendar : require('./field/calendar') ,Calendar : require('./fields/calendar')
,DateChooser : require('./field/date-chooser') ,DateChooser : require('./fields/date-chooser')
,Image : require('./field/image') ,Image : require('./fields/image')
,Button : require('./field/button') ,Button : require('./fields/button')
,BarButton : require('./field/bar-button') ,BarButton : require('./fields/bar-button')
,Table : require('./field/table') ,Table : require('./fields/table')
,SearchEntry : require('./field/search-entry') ,SearchEntry : require('./fields/search-entry')
,ColumnButton : require('./column/button') ,ColumnButton : require('./columns/button')
,ColumnLink : require('./column/link') ,ColumnLink : require('./columns/link')
,ColumnDate : require('./column/date') ,ColumnDate : require('./columns/date')
,ColumnImage : require('./column/image') ,ColumnImage : require('./columns/image')
,ColumnRadio : require('./column/radio') ,ColumnRadio : require('./columns/radio')
,ColumnSpin : require('./column/spin') ,ColumnSpin : require('./columns/spin')
,ColumnText : require('./column/text') ,ColumnText : require('./columns/text')
,ColumnCheck : require('./column/check') ,ColumnCheck : require('./columns/check')
}; };
for (var field in Fields) for (var field in Fields)

View File

@ -1,5 +1,5 @@
var Widget = require('./widget'); var Widget = require('../widget');
module.exports = new Class({ module.exports = new Class({
Extends: Widget Extends: Widget

View File

@ -1,7 +1,7 @@
require('./style.scss');
var Component = require('./component'); var Component = require('../component');
var Toast = require('./toast'); var Toast = require('../toast');
var Tpl = require('./image-editor.xml').default; var Tpl = require('./ui.xml').default;
/** /**
* A form to handle the image database, it allows to add new images or * A form to handle the image database, it allows to add new images or

View File

@ -0,0 +1,33 @@
.htk-image-editor {
width: 18em;
margin: 0 auto;
padding: 1.5em;
h2 {
color: white;
background-color: #009688;
text-align: left;
font-size: 1.3em;
line-height: 1.7em;
font-weight: normal;
padding: 0.6em 0.8em;
margin: 0;
}
iframe {
display: none;
}
.footer {
margin-top: 2em;
& > .htk-spinner {
padding-right: 1.2em;
height: 1.3em;
width: 1.3em;
}
& > .htk-spinner,
& > input {
float: right;
}
}
}

1
js/htk/list/index.js Normal file
View File

@ -0,0 +1 @@
require('./style.scss');

56
js/htk/list/style.scss Normal file
View File

@ -0,0 +1,56 @@
@import "../style/classes";
.htk-list {
a.item,
.item.clickable {
@extend %clickable;
}
.item {
padding: 20px;
border-bottom: 1px solid #DDD;
display: flex;
align-items: center;
& > .side {
flex: none;
}
& > .content {
flex: 1;
overflow: hidden;
& > .important {
font-weight: bold;
font-size: 1rem;
margin-bottom: .5em;
}
& > p {
margin: .1em 0;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
& > .actions {
flex: none;
display: none;
align-items: center;
& > .htk-button {
margin: 0;
}
& > * {
display: inline-block;
vertical-align: middle;
}
& > input {
margin: .6em;
}
}
}
.item:hover > .actions {
display: flex;
}
.item:last-child {
border-bottom: none;
}
}

View File

@ -1,79 +0,0 @@
var Widget = require ('./widget');
module.exports = new Class
({
Tag: 'htk-loader'
,Extends: Widget
,Properties: {
form:
{
type: Db.Form
,set: function (x)
{
this.link ({_form: x}, {'status-changed': this.onFormChange});
this.onFormChange ();
}
,get: function ()
{
return this._form;
}
}
}
,initialize: function ()
{
var node = this.createRoot ('div');
node.className = 'htk-loader';
var div = this.createElement ('div');
div.className = 'spinner';
var spinner = new Htk.Spinner ();
div.appendChild (spinner.node);
var childs = this.createElement ('div');
this.spinner = spinner;
this.div = div;
this.childs = childs;
this.isLoading = true;
this.stop ();
}
,appendChild: function (child)
{
this.childs.appendChild (child);
}
,stop: function ()
{
if (!this.isLoading)
return;
this.isLoading = false;
this.spinner.stop ();
Vn.Node.removeChilds (this.node);
this.node.appendChild (this.childs);
}
,start: function ()
{
if (this.isLoading)
return;
this.isLoading = true;
this.spinner.start ();
Vn.Node.removeChilds (this.node);
this.node.appendChild (this.div);
}
,onFormChange: function ()
{
if (this._form.ready)
this.stop ();
else
this.start ();
}
});

70
js/htk/loader/index.js Normal file
View File

@ -0,0 +1,70 @@
require('./style.scss');
var Widget = require('../widget');
module.exports = new Class({
Tag: 'htk-loader'
,Extends: Widget
,Properties: {
form: {
type: Db.Form
,set: function(x) {
this.link({_form: x}, {'status-changed': this.onFormChange});
this.onFormChange();
}
,get: function() {
return this._form;
}
}
}
,initialize: function() {
var node = this.createRoot('div');
node.className = 'htk-loader';
var div = this.createElement('div');
div.className = 'spinner';
var spinner = new Htk.Spinner();
div.appendChild(spinner.node);
var childs = this.createElement('div');
this.spinner = spinner;
this.div = div;
this.childs = childs;
this.isLoading = true;
this.stop();
}
,appendChild: function(child) {
this.childs.appendChild(child);
}
,stop: function() {
if (!this.isLoading)
return;
this.isLoading = false;
this.spinner.stop();
Vn.Node.removeChilds(this.node);
this.node.appendChild(this.childs);
}
,start: function() {
if (this.isLoading)
return;
this.isLoading = true;
this.spinner.start();
Vn.Node.removeChilds(this.node);
this.node.appendChild(this.div);
}
,onFormChange: function() {
if (this._form.ready)
this.stop();
else
this.start();
}
});

4
js/htk/loader/style.scss Normal file
View File

@ -0,0 +1,4 @@
.htk-loader > .spinner {
text-align: center;
}

View File

@ -27,3 +27,4 @@ Next: Següent
Confirm: Confirmar Confirm: Confirmar
Search: Cercar Search: Cercar
Search...: Cercar... Search...: Cercar...
Erase: Esborrar

View File

@ -27,3 +27,4 @@ Next: Next
Confirm: Confirm Confirm: Confirm
Search: Search Search: Search
Search...: Search... Search...: Search...
Erase: Erase

View File

@ -27,3 +27,4 @@ Next: Siguiente
Confirm: Confirmar Confirm: Confirmar
Search: Buscar Search: Buscar
Search...: Buscar... Search...: Buscar...
Erase: Borrar

View File

@ -27,3 +27,4 @@ Next: Suivant
Confirm: Confirmer Confirm: Confirmer
Search: Recherche Search: Recherche
Search...: Recherche... Search...: Recherche...
Erase: Effacer

View File

@ -27,3 +27,4 @@ Next: Seguinte
Confirm: Confirmar Confirm: Confirmar
Search: Procurar Search: Procurar
Search...: Procurar... Search...: Procurar...
Erase: Apagar

View File

@ -1,20 +1,17 @@
require('./style.scss');
var Widget = require('./widget'); var Widget = require('../widget');
/** /**
* Class to handle popups. * Class to handle popups.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Widget Extends: Widget
,Tag: 'htk-popup' ,Tag: 'htk-popup'
,Properties: ,Properties: {
{
/** /**
* The popup child. * The popup child.
*/ */
child: child: {
{
type: Widget type: Widget
,set: function(x) { ,set: function(x) {
this._child = x; this._child = x;
@ -27,8 +24,7 @@ module.exports = new Class
/** /**
* The popup child Node. * The popup child Node.
*/ */
,childNode: ,childNode: {
{
type: Object type: Object
,set: function(x) { ,set: function(x) {
this._child = null; this._child = null;
@ -41,8 +37,7 @@ module.exports = new Class
/** /**
* Indicates how the dialog must be displayed. * Indicates how the dialog must be displayed.
*/ */
,modal: ,modal: {
{
type: Boolean type: Boolean
,set: function(x) { ,set: function(x) {
this._modal = x; this._modal = x;
@ -73,8 +68,9 @@ module.exports = new Class
this.node.appendChild(childNode); this.node.appendChild(childNode);
} }
,show: function(parent) { ,show: function(parent, event) {
this._parent = parent; this._parent = parent;
this._lastEvent = event;
this.open(); this.open();
} }

32
js/htk/popup/style.scss Normal file
View File

@ -0,0 +1,32 @@
.htk-popup {
z-index: 200;
display: block;
position: fixed;
overflow: hidden;
background-color: white;
border-radius: 10px;
box-shadow: 0 0 0.4em rgba(1, 1, 1, 0.6);
box-sizing: content-box;
&.modal {
position: absolute;
font-size: 1.2em;
top: 50%;
left: 50%;
}
& > * {
border-radius: 0.1em;
}
}
.htk-background {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 190;
background-color: rgba(1, 1, 1, 0.7);
opacity: 0;
transition: opacity 200ms ease-in-out;
}

View File

@ -1,5 +1,5 @@
require('./style.scss');
var Widget = require('./widget'); var Widget = require('../widget');
module.exports = new Class({ module.exports = new Class({
Extends: Widget Extends: Widget

View File

@ -0,0 +1,16 @@
.htk-repeater {
& > .message {
padding: 1.5em;
text-align: center;
& > * {
vertical-align: middle;
}
& > span,
& > .htk-spinner {
display: inline-block;
padding-right: 10px;
}
}
}

View File

@ -1,38 +0,0 @@
var Widget = require ('./widget');
module.exports = new Class
({
Extends: Widget
,Tag: 'htk-spinner'
,_started: false
,render: function ()
{
var loader = this.createRoot ('div');
loader.className = 'htk-spinner';
var spin = this.spin = this.createElement ('div');
loader.appendChild (spin);
}
,start: function ()
{
if (this._started)
return;
Vn.Node.addClass (this.spin, 'spinner');
this._started = true;
}
,stop: function ()
{
if (!this._started)
return;
Vn.Node.removeClass (this.spin, 'spinner');
this._started = false;
}
});

34
js/htk/spinner/index.js Normal file
View File

@ -0,0 +1,34 @@
require('./style.scss');
var Widget = require('../widget');
module.exports = new Class({
Extends: Widget
,Tag: 'htk-spinner'
,_started: false
,render: function() {
var loader = this.createRoot('div');
loader.className = 'htk-spinner';
var spin = this.spin = this.createElement('div');
loader.appendChild(spin);
}
,start: function() {
if (this._started)
return;
Vn.Node.addClass(this.spin, 'spinner');
this._started = true;
}
,stop: function() {
if (!this._started)
return;
Vn.Node.removeClass(this.spin, 'spinner');
this._started = false;
}
});

31
js/htk/spinner/style.scss Normal file
View File

@ -0,0 +1,31 @@
.htk-spinner {
width: 1.8em;
height: 1.8em;
position: relative;
display: inline-block;
& > .spinner {
left: 0;
position: absolute;
width: inherit;
height: inherit;
box-sizing: border-box;
border-radius: 50%;
border: 2px solid transparent;
border-top-color: #666;
border-left-color: #666;
animation: spinner 1s linear infinite;
-webkit-animation: spinner 1s linear infinite;
}
&.dark > .spinner {
border-top-color: white;
border-left-color: white;
}
}
@keyframes spinner {
to {transform: rotate(360deg);}
}
@-webkit-keyframes spinner {
to {-webkit-transform: rotate(360deg);}
}

View File

@ -1,5 +1,5 @@
var Widget = require('./widget'); var Widget = require('../widget');
module.exports = new Class({ module.exports = new Class({
Extends: Widget, Extends: Widget,

View File

@ -1,106 +1,6 @@
@import "./variables"; @import "./variables";
/* Icon */
.htk-icon {}
/* Button */
.htk-button {
display: flex;
align-items: center;
gap: 8px;
& > .htk-icon {
display: block;
}
}
/* Grid */
.htk-grid {
margin: auto;
border-collapse: collapse;
& > thead > tr,
& > tfoot > tr {
background-color: $color-primary;
vertical-align: middle;
height: 3em;
}
th {
color: white;
cursor: pointer;
font-weight: normal;
padding: 0 0.4em;
}
th:hover {
background-color: rgba(1, 1, 1, 0.2);
}
tr {
height: 3.5em;
}
& > tfoot a,
& > thead a {
color: black;
}
tr.pair-row {
background-color: transparent;
}
& > tbody tr {
border-top: 1px solid #DDD;
}
& > tbody tr:first-child {
border-top: none;
}
& > tbody td {
margin: 0;
padding: 0 0.5em;
}
th,
td {
text-align: left;
}
td:first-child,
th:first-child {
padding-left: 1em;
}
td:last-child,
th:last-child {
padding-right: 1em;
}
.message {
padding: 1.5em;
text-align: center;
}
.message > * {
display: inline-block;
vertical-align: middle;
padding-right: .8em;
}
}
/* Repater */
.htk-repeater {
& > .message {
padding: 1.5em;
text-align: center;
& > * {
vertical-align: middle;
}
& > span,
& > .htk-spinner {
display: inline-block;
padding-right: 10px;
}
}
}
/* Grid cells */
th.cell-spin { th.cell-spin {
text-align: right; text-align: right;
} }
@ -108,601 +8,52 @@ td.cell-spin {
width: 2.5em; width: 2.5em;
text-align: right; text-align: right;
} }
th.cell-check, th.cell-check,
th.cell-radio { th.cell-radio {
text-align: center; text-align: center;
} }
td.cell-button { td.cell-button {
max-width: 20px; max-width: 20px;
text-align: center; text-align: center;
}
td.cell-button > button,
td.cell-button > a {
@extend %clickable;
display: block;
height: 44px;
width: 44px;
margin: 0 auto;
border-radius: 50%;
padding: 10px;
border: none;
background-color: transparent;
box-sizing: border-box;
& > .htk-icon { & > button,
display: block; & > a {
}
}
td.cell-button > button:hover,
td.cell-button > a:hover {
background-color: rgba(1, 1, 1, 0.1);
}
td.cell-button img {
height: 1.5em;
width: 1.5em;
display: block;
margin: auto;
padding: 0;
}
td.cell-image {
text-align: center;
}
td.cell-image .htk-image {
max-width: 2.5em;
max-height: 2.5em;
display: block;
margin: auto;
}
/* Select */
.htk-select,
.htk-date-chooser {
display: flex;
align-items: center;
font-weight: normal;
& > span {
flex: 1;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
& > .htk-icon {
flex: none;
color: #666;
}
}
.htk-select {
width: 100%;
}
.htk-select-menu {
height: 100%;
max-height: 80em;
overflow: auto;
min-width: 14em;
tbody > tr {
border-top: none;
height: 2.5em;
}
td.message {
padding: 1em;
}
tr:hover {
background-color: rgba(1, 1, 1, 0.1);
cursor: pointer;
}
td {
max-width: 11em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
/* List */
.htk-list {
a.item,
.item.clickable {
@extend %clickable; @extend %clickable;
} display: block;
.item { height: 44px;
padding: 20px; width: 44px;
border-bottom: 1px solid #DDD;
display: flex;
align-items: center;
& > .side {
flex: none;
}
& > .content {
flex: 1;
overflow: hidden;
& > .important {
font-weight: bold;
font-size: 1rem;
margin-bottom: .5em;
}
& > p {
margin: .1em 0;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
& > .actions {
flex: none;
display: none;
align-items: center;
& > .htk-button {
margin: 0;
}
& > * {
display: inline-block;
vertical-align: middle;
}
& > input {
margin: .6em;
}
}
}
.item:hover > .actions {
display: flex;
}
.item:last-child {
border-bottom: none;
}
}
/* Calendar */
.htk-calendar {
@extend %box;
width: 20em;
table {
border-collapse: collapse;
}
thead tr,
tfoot tr {
font-weight: normal;
vertical-align: middle;
text-align: center;
height: 3em;
}
thead > tr {
&.weekdays > th {
font-weight: normal;
color: #999;
text-transform: lowercase;
}
& > th {
&.previous, &.next {
font-size: .8rem;
button {
border-radius: 50%;
padding: 10px;
display: block;
margin: 0 auto;
& > .htk-icon {
font-size: 1rem;
}
}
}
&.month-year {
font-size: 1.2rem;
text-transform: lowercase;
}
}
}
tfoot tr {
border-top: none;
}
th.button {
display: table-cell;
}
th.button:hover {
cursor: pointer;
background-color: rgba(1, 1, 1, 0.2);
}
col {
width: 14.2%;
}
tr {
height: 2em;
}
tbody td {
text-align: right;
}
tbody td > div {
height: 2em;
width: 2em;
line-height: 2em;
text-align: center;
border-radius: 2em;
padding: 0.3em;
margin: 0 auto; margin: 0 auto;
color: #555; border-radius: 50%;
} padding: 10px;
div { border: none;
&.disabled { background-color: transparent;
color: #bbb; box-sizing: border-box;
& > .htk-icon {
display: block;
} }
&.today {
font-weight: bold;
color: black;
}
&.selected {
color: white;
background-color: $color-primary;
}
&.enabled {
@extend %clickable;
&:hover {
background-color: rgba(140, 198, 63, 0.8);
}
}
}
}
/* Image */
.htk-image {
position: relative;
overflow: hidden;
transition: opacity 250ms ease-out;
&.clickable:hover {
cursor: pointer;
opacity: 0.85;
}
& > img {
display: block;
height: 100%;
width: 100%;
}
& > button {
position: absolute;
top: 0;
left: 0;
padding: 8px;
margin: 4px;
display: none;
background-color: rgba(255, 255, 255, .6);
&:hover { &:hover {
background-color: rgba(255, 255, 255, .8); background-color: rgba(1, 1, 1, 0.1);
} }
} }
&:hover > button {
display: block;
}
& > button > .htk-icon {
display: block;
}
}
/* Full image */
.htk-full-image {
img {
display: block;
cursor: pointer;
}
.htk-spinner {
background-color: #FFF;
margin: .6em;
display: block;
}
}
/* Image editor */
.htk-image-editor {
width: 18em;
margin: 0 auto;
padding: 1.5em;
h2 {
color: white;
background-color: #009688;
text-align: left;
font-size: 1.3em;
line-height: 1.7em;
font-weight: normal;
padding: 0.6em 0.8em;
margin: 0;
}
iframe {
display: none;
}
.footer {
margin-top: 2em;
& > .htk-spinner {
padding-right: 1.2em;
height: 1.3em;
width: 1.3em;
}
& > .htk-spinner,
& > input {
float: right;
}
}
}
/* Toast */
.htk-toast {
z-index: 210;
display: block;
position: fixed;
left: 50%;
top: 4em;
width: 21em;
margin-left: -10.5em;
text-align: center;
overflow: auto;
max-height: 40em;
overflow: visible;
& > div {
margin: .5em 0;
padding: .5em 2%;
border-radius: 0.1em;
box-shadow: 0 0 0.4em rgba(1, 1, 1, 0.6);
width: 96%;
opacity: 0;
transform: translateZ(0) translateY(-1em);
-webkit-transform: translateZ(0) translateY(-1em);
transition-property: opacity, transform;
transition-duration: 200ms;
transition-timing-function: ease-out;
&.show {
opacity: 1;
transform: translateZ(0) translateY(0em);
-webkit-transform: translateZ(0) translateY(0em);
}
}
& > .message {
background-color: #BBFFBB;
color: #363;
}
& > .warning {
background-color: #FFE0B2;
color: #C30;
}
& > .error {
background-color: #FFCDD2;
color: #A00;
}
}
/* Popup */
.htk-background {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 190;
background-color: rgba(1, 1, 1, 0.7);
opacity: 0;
transition: opacity 200ms ease-in-out;
}
.htk-popup {
z-index: 200;
display: block;
position: fixed;
overflow: hidden;
background-color: white;
border-radius: 10px;
box-shadow: 0 0 0.4em rgba(1, 1, 1, 0.6);
box-sizing: content-box;
&.modal {
position: absolute;
font-size: 1.2em;
top: 50%;
left: 50%;
}
& > * {
border-radius: 0.1em;
}
}
/* Dialog */
.htk-dialog {
padding: 1.5em;
max-width: 20em;
font-weight: normal;
color: #555;
p {
margin: 0;
}
img { img {
float: left; height: 1.5em;
height: 3em; width: 1.5em;
margin-top: 0;
margin-right: 1em;
}
p {
padding: 0;
}
.button-bar > button {
float: right;
margin-left: 1em;
margin-top: .5em;
}
}
/* Assistant */
.htk-assistant > div {
display: none;
& > h2 {
text-align: center;
font-weight: normal;
font-size: 1.5rem;
margin: 0;
padding: 0;
margin-bottom: 1em;
font-weight: bold;
}
}
/* Assistant bar */
.htk-assistant-bar {
position: relative;
padding: .8em;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
width: 100%;
& > button {
border-radius: 50%;
padding: .5em;
margin: 0;
text-align: center;
& > img {
display: block;
width: 1.8em;
padding: .5em;
}
}
& > .end {
display: none;
color: #8cc63f;
& > .icon {
font-size: 1.6rem;
}
}
& > .steps {
display: flex;
align-items: center;
& > div {
background-color: #AAA;
width: .5em;
height: .5em;
cursor: pointer;
border-radius: 50%;
margin: .5em;
transition-property: width, height;
transition-duration: 100ms;
transition-timing-function: ease-in-out;
&.selected {
background-color: #666;
width: 1em;
height: 1em;
}
&:hover {
opacity: .7;
}
}
& > img {
width: 1.3em;
margin: 0 .2em;
cursor: pointer;
&:hover {
opacity: .7;
}
}
}
}
/* Search entry */
.htk-search-entry {
display: flex;
align-items: center;
gap: 6px;
background-color: white;
height: 40px;
border-radius: 20px;
padding: 0 12px;
overflow: hidden;
& > * {
display: inline-block;
vertical-align: middle;
}
& > .htk-icon {
display: block; display: block;
margin: 0; margin: auto;
color: gray; padding: 0;
}
& > .entry {
margin: 0;
border: none;
width: 80px;
box-shadow: none;
padding-right: 0;
padding-left: 0;
height: inherit;
}
& > .entry:focus {
background-color: initial;
} }
} }
/* Spinner */ td.cell-image {
.htk-spinner {
width: 1.8em;
height: 1.8em;
position: relative;
display: inline-block;
& > .spinner {
left: 0;
position: absolute;
width: inherit;
height: inherit;
box-sizing: border-box;
border-radius: 50%;
border: 2px solid transparent;
border-top-color: #666;
border-left-color: #666;
animation: spinner 1s linear infinite;
-webkit-animation: spinner 1s linear infinite;
}
&.dark > .spinner {
border-top-color: white;
border-left-color: white;
}
}
@keyframes spinner {
to {transform: rotate(360deg);}
}
@-webkit-keyframes spinner {
to {-webkit-transform: rotate(360deg);}
}
/* Loader */
.htk-loader > .spinner {
text-align: center; text-align: center;
.htk-image {
max-width: 2.5em;
max-height: 2.5em;
display: block;
margin: auto;
}
} }

View File

@ -1,3 +1,5 @@
require('./style.scss');
/** /**
* Class to show toast messages. * Class to show toast messages.
*/ */

47
js/htk/toast/style.scss Normal file
View File

@ -0,0 +1,47 @@
.htk-toast {
z-index: 210;
display: block;
position: fixed;
left: 50%;
top: 4em;
width: 21em;
margin-left: -10.5em;
text-align: center;
overflow: auto;
max-height: 40em;
overflow: visible;
& > div {
margin: .5em 0;
padding: .5em 2%;
border-radius: 0.1em;
box-shadow: 0 0 0.4em rgba(1, 1, 1, 0.6);
width: 96%;
opacity: 0;
transform: translateZ(0) translateY(-1em);
-webkit-transform: translateZ(0) translateY(-1em);
transition-property: opacity, transform;
transition-duration: 200ms;
transition-timing-function: ease-out;
&.show {
opacity: 1;
transform: translateZ(0) translateY(0em);
-webkit-transform: translateZ(0) translateY(0em);
}
}
& > .message {
background-color: #BBFFBB;
color: #363;
}
& > .warning {
background-color: #FFE0B2;
color: #C30;
}
& > .error {
background-color: #FFCDD2;
color: #A00;
}
}

View File

@ -1,7 +1,7 @@
const NodeBuilder = require('../vn/node-builder'); const NodeBuilder = require('../../vn/node-builder');
const Widget = new Class({ const WidgetClass = {
Extends: NodeBuilder Extends: NodeBuilder
,Properties: { ,Properties: {
/** /**
@ -115,7 +115,7 @@ const Widget = new Class({
} else } else
this.parent(id, callback, instance); this.parent(id, callback, instance);
} }
}); };
htmlEventMap = {}; htmlEventMap = {};
htmlEvents = [ htmlEvents = [
@ -141,9 +141,9 @@ htmlMethods = [
'addEventListener' 'addEventListener'
]; ];
htmlMethods.forEach(method => { htmlMethods.forEach(method => {
Widget[method] = function() { WidgetClass[method] = function() {
this.node.apply(this.node, arguments); this.node[method].apply(this.node, arguments);
}; };
}); });
module.exports = Widget; module.exports = new Class(WidgetClass);

View File

@ -1,38 +1,33 @@
var Expr = require ('./expr'); var Expr = require('./expr');
/** /**
* The equivalent of a SQL field. * The equivalent of a SQL field.
* *
* @param {string} taget The name of the owner table * @param {string} taget The name of the owner table
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Expr Extends: Expr
,Tag: 'sql-field' ,Tag: 'sql-field'
,Properties: ,Properties: {
{
/** /**
* The column name. * The column name.
*/ */
name: name: {
{
type: String type: String
,value: null ,value: null
}, },
/** /**
* The source table name or its alias if it has been specified. * The source table name or its alias if it has been specified.
*/ */
target: target: {
{
type: String type: String
,value: null ,value: null
} }
} }
,render: function () ,render: function() {
{ return this.renderPreIdent(this.target)
return this.renderPreIdent (this.target) + this.renderIdent(this.name);
+ this.renderIdent (this.name);
} }
}); });

View File

@ -36,7 +36,7 @@ module.exports = new Class({
} }
/** /**
* Checks if parameter name haa been defined and if it has a value. * Checks if parameter name has been defined and if it has a value.
*/ */
,isReady: function(params) { ,isReady: function(params) {
return this.param != null && params != null && params[this.param] != null; return this.param != null && params != null && params[this.param] != null;
@ -51,18 +51,12 @@ module.exports = new Class({
})); }));
var value = params[this.param]; var value = params[this.param];
if (this.type === Operation.Type.LIKE && typeof value === 'string') {
value = value.replace(/[\%\?]/g, this._escapeChar);
value = value.replace(/^|\s+|$/g, '%');
}
newOp.push(new Value({value: value})); newOp.push(new Value({value: value}));
return newOp.render(params); return newOp.render(params);
} }
,_escapeChar: function(char) { ,findHolders: function() {
return '\\'+ char; return this.param ? [this.param] : null;
} }
}); });

View File

@ -1,24 +1,22 @@
var Operation = require ('./operation'); var Operation = require('./operation');
var Value = require ('./value'); var Value = require('./value');
/** /**
* The equivalent of a SQL filter expression. It allows to automatically build * The equivalent of a SQL filter expression. It allows to automatically build
* SQL filters based on lot parameters. * SQL filters based on lot parameters.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Operation Extends: Operation
,Tag: 'sql-filter' ,Tag: 'sql-filter'
/** /**
* Checks if any of filters childs are ready. * Checks if any of filters childs are ready.
*/ */
,isReady: function (params) ,isReady: function(params) {
{
var exprs = this.exprs; var exprs = this.exprs;
for (var i = exprs.length; i--;) for (var i = exprs.length; i--;)
if (exprs[i].isReady (params)) if (exprs[i].isReady(params))
return true; return true;
return false; return false;
@ -29,24 +27,23 @@ module.exports = new Class
* ready is ommitted from the expression. If all of its childs aren't ready * ready is ommitted from the expression. If all of its childs aren't ready
* renders the TRUE expression. * renders the TRUE expression.
*/ */
,render: function (params) ,render: function(params) {
{
var newOp; var newOp;
var newExprs = []; var newExprs = [];
this.exprs.forEach (function (expr) { this.exprs.forEach(function(expr) {
if (expr.isReady (params)) if (expr.isReady(params))
newExprs.push (expr); newExprs.push(expr);
}) })
if (newExprs.length > 0) if (newExprs.length > 0)
newOp = new Operation ({ newOp = new Operation({
type: this.type, type: this.type,
exprs: newExprs exprs: newExprs
}); });
else else
newOp = new Value ({value: true}); newOp = new Value({value: true});
return newOp.render (params); return newOp.render(params);
} }
}); });

View File

@ -1,56 +1,48 @@
var Expr = require ('./expr'); var Expr = require('./expr');
var ListHolder = require ('./list-holder'); var ListHolder = require('./list-holder');
/** /**
* The equivalent of a SQL function. * The equivalent of a SQL function.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Expr Extends: Expr
,Tag: 'sql-function' ,Tag: 'sql-function'
,Implements: ListHolder ,Implements: ListHolder
,Properties: ,Properties: {
{
/** /**
* The function name. * The function name.
*/ */
name: name: {
{
type: String type: String
,value: null ,value: null
}, },
/** /**
* The function schema. * The function schema.
*/ */
schema: schema: {
{
type: String type: String
,value: null ,value: null
}, },
/** /**
* The function parameters. * The function parameters.
*/ */
params: params: {
{
type: Array type: Array
,set: function (x) ,set: function(x) {
{
this.list = x; this.list = x;
} }
,get: function () ,get: function() {
{
return this.list; return this.list;
} }
} }
} }
,render: function (params) ,render: function(params) {
{ return this.renderPreIdent(this.schema)
return this.renderPreIdent (this.schema) + this.renderIdent(this.name)
+ this.renderIdent (this.name)
+ '(' + '('
+ this.renderListWs (this.list, params, ', ') + this.renderListWs(this.list, params, ', ')
+ ')'; + ')';
} }
}); });

View File

@ -1,38 +1,30 @@
var SqlObject = require ('./object'); var SqlObject = require('./object');
var Value = require ('./value'); var Value = require('./value');
/** /**
* A holder for another object. * A holder for another object.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: SqlObject Extends: SqlObject
,Properties: ,Properties: {
{ id: {
id:
{
type: String type: String
,value: null ,value: null
} }
} }
,render: function (params) ,render: function(params) {
{ if (params) {
if (params)
{
var object = params[this.id]; var object = params[this.id];
if (object !== undefined) if (object !== undefined) {
{ if (!(object instanceof SqlObject)) {
if (!(object instanceof SqlObject)) var sqlValue = new Value();
{
var sqlValue = new Value ();
sqlValue.value = object; sqlValue.value = object;
return sqlValue.render (); return sqlValue.render();
} } else
else return object.render(params);
return object.render (params);
} }
} }

View File

@ -1,21 +1,19 @@
var Dml = require ('./dml'); var Dml = require('./dml');
/** /**
* The equivalent of a SQL insert. * The equivalent of a SQL insert.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Dml Extends: Dml
,render: function (params) ,render: function(params) {
{
return 'INSERT INTO' return 'INSERT INTO'
+ this.renderTarget (params) + this.renderTarget(params)
+ ' (' + ' ('
+ this.renderListWs (this.field, params, ', ') + this.renderListWs(this.field, params, ', ')
+ ') VALUES (' + ') VALUES ('
+ this.renderListWs (this.expr, params, ', ') + this.renderListWs(this.expr, params, ', ')
+ ')'; + ')';
} }
}) })

View File

@ -1,8 +1,8 @@
var Target = require ('./target'); var Target = require('./target');
var Expr = require ('./expr'); var Expr = require('./expr');
var SqlObject = require ('./object'); var SqlObject = require('./object');
var Type = require ('./join').Type; var Type = require('./join').Type;
var TypeSql = [ var TypeSql = [
'INNER', 'INNER',
@ -13,42 +13,36 @@ var TypeSql = [
/** /**
* The equivalent of a SQL join. * The equivalent of a SQL join.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: SqlObject Extends: SqlObject
,Tag: 'sql-join-table' ,Tag: 'sql-join-table'
,Properties: ,Properties: {
{
/** /**
* The join type. * The join type.
*/ */
type: type: {
{
enumType: Type enumType: Type
,value: 0 ,value: 0
}, },
/** /**
* The right target. * The right target.
*/ */
target: target: {
{
type: Target type: Target
,value: null ,value: null
}, },
/** /**
* The join on condition. * The join on condition.
*/ */
condition: condition: {
{
type: Expr type: Expr
,value: null ,value: null
} }
} }
,render: function (params) ,render: function(params) {
{
return TypeSql[this.type] +' JOIN ' return TypeSql[this.type] +' JOIN '
+ this.target.render (params) + this.target.render(params)
+ this.renderIfSet (this.condition, 'ON', params); + this.renderIfSet(this.condition, 'ON', params);
} }
}); });

View File

@ -1,11 +1,11 @@
var Target = require ('./target'); var Target = require('./target');
var ListHolder = require ('./list-holder'); var ListHolder = require('./list-holder');
/** /**
* The equivalent of a SQL join. * The equivalent of a SQL join.
*/ */
var Klass = new Class (); var Klass = new Class();
module.exports = Klass; module.exports = Klass;
var Type = { var Type = {
@ -14,41 +14,34 @@ var Type = {
RIGHT : 2 RIGHT : 2
}; };
Klass.extend Klass.extend({
({
Type: Type Type: Type
}); });
Klass.implement Klass.implement({
({
Extends: Target Extends: Target
,Implements: ListHolder ,Implements: ListHolder
,Tag: 'sql-join' ,Tag: 'sql-join'
,Properties: ,Properties: {
{
/** /**
* The right targets. * The right targets.
*/ */
targets: targets: {
{
type: Array type: Array
,set: function (x) ,set: function(x) {
{
this.list = x; this.list = x;
} }
,get: function () ,get: function() {
{
return this.list; return this.list;
} }
} }
} }
,render: function (params) ,render: function(params) {
{
return '(' return '('
+ this.target.render (params) + this.target.render(params)
+ ' ' + ' '
+ this.renderList (this.list, params) + this.renderList(this.list, params)
+ ')'; + ')';
} }
}); });

View File

@ -1,20 +1,14 @@
/** /**
* Interface for array holders. * Interface for array holders.
*/ */
module.exports = new Class module.exports = new Class({
({ Properties: {
Properties: /* list: {
{
/*
list:
{
type: Array type: Array
,set: function (x) ,set: function (x) {
{
this._list = x; this._list = x;
} }
,get: function () ,get: function () {
{
return this._list; return this._list;
} }
} }
@ -23,9 +17,8 @@ module.exports = new Class
,list: [] ,list: []
,appendChild: function (child) ,appendChild: function(child) {
{ this.list.push(child);
this.list.push (child);
} }
/** /**
@ -33,9 +26,8 @@ module.exports = new Class
* *
* @param {SqlObject} element The element to add * @param {SqlObject} element The element to add
*/ */
,push: function (element) ,push: function(element) {
{ this.list.push(element);
this.list.push (element);
} }
/** /**
@ -43,9 +35,8 @@ module.exports = new Class
* *
* @param {Number} i The element index * @param {Number} i The element index
*/ */
,splice: function (i) ,splice: function(i) {
{ this.list.splice(i);
this.list.splice (i);
} }
/** /**
@ -53,8 +44,18 @@ module.exports = new Class
* *
* @param {Number} i The element index * @param {Number} i The element index
*/ */
,get: function (i) ,get: function(i) {
{
return this.list[i]; return this.list[i];
} }
,findHolders() {
let ids = [];
for (const object of this.list){
holders = object.findHolders();
if (holders) ids = ids.concat(holders);
}
return ids;
}
}); });

View File

@ -1,69 +1,71 @@
var Object = require ('./object'); var Object = require('./object');
/** /**
* List of Sql.Object * List of Sql.Object
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Object Extends: Object
,objects: [] ,objects: []
,add: function (object) ,add: function(object) {
{ this.objects.push(object.ref());
this.objects.push (object.ref ()); object.on('changed', this._onObjectChange, this);
object.on ('changed', this._onObjectChange, this); this._onObjectChange();
this._onObjectChange ();
} }
,get: function (i) ,get: function(i) {
{
return objects[i]; return objects[i];
} }
,getArray: function () ,getArray: function() {
{
return this.objects; return this.objects;
} }
,remove: function (i) ,remove: function(i) {
{ this._unrefObject(this.objects.splice(i, 1));
this._unrefObject (this.objects.splice (i, 1)); this._onObjectChange();
this._onObjectChange ();
} }
,_onObjectChange: function () ,_onObjectChange: function() {
{ this.emit('changed');
this.emit ('changed');
} }
,isReady: function () ,isReady: function() {
{
var o = this.objects; var o = this.objects;
if (o.length == 0) if (o.length == 0)
return false; return false;
for (var i = 0; i < o.length; i++) for (var i = 0; i < o.length; i++)
if (!o[i].isReady ()) if (!o[i].isReady())
return false; return false;
return true; return true;
} }
,_unrefObject: function (object) ,findHolders() {
{ let ids = [];
object.disconnect ('changed', this._onObjectChange, this);
object.unref (); for (const object of this.objects){
holders = object.findHolders();
if (holders) ids = ids.concat(holders);
}
return ids;
} }
,_destroy: function () ,_unrefObject: function(object) {
{ object.disconnect('changed', this._onObjectChange, this);
for (var i = 0; i < this.objects.length; i++) object.unref();
this._unrefObject (this.objects[i]); }
this.parent (); ,_destroy: function() {
for (var i = 0; i < this.objects.length; i++)
this._unrefObject(this.objects[i]);
this.parent();
} }
}); });

View File

@ -1,36 +1,30 @@
var Stmt = require ('./stmt'); var Stmt = require('./stmt');
var ListHolder = require ('./list-holder'); var ListHolder = require('./list-holder');
/** /**
* The equivalent of a SQL multi statement. * The equivalent of a SQL multi statement.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Stmt Extends: Stmt
,Implements: ListHolder ,Implements: ListHolder
,Tag: 'sql-multi-stmt' ,Tag: 'sql-multi-stmt'
,Properties: ,Properties: {
{
/** /**
* The statements list. * The statements list.
*/ */
stmts: stmts: {
{
type: Array type: Array
,set: function (x) ,set: function(x) {
{
this.list = x; this.list = x;
} }
,get: function () ,get: function() {
{
return this.list; return this.list;
} }
} }
} }
,render: function (params) ,render: function(params) {
{ return this.renderListWs(this.list, params, ";\n");
return this.renderListWs (this.list, params, ";\n");
} }
}); });

View File

@ -1,6 +1,6 @@
var Expr = require ('./expr'); var Expr = require('./expr');
var ListHolder = require ('./list-holder'); var ListHolder = require('./list-holder');
/** /**
* The equivalent of a SQL operation between exprs. * The equivalent of a SQL operation between exprs.
@ -8,11 +8,10 @@ var ListHolder = require ('./list-holder');
* @param {Array#Expr} exprs Array with the exprs * @param {Array#Expr} exprs Array with the exprs
* @param {Type} type The type of the operation * @param {Type} type The type of the operation
*/ */
var Klass = new Class (); var Klass = new Class();
module.exports = Klass; module.exports = Klass;
var Type = var Type = {
{
EQUAL : 0 EQUAL : 0
,LIKE : 1 ,LIKE : 1
,AND : 2 ,AND : 2
@ -30,8 +29,7 @@ var Type =
,MOD : 14 ,MOD : 14
}; };
var Operators = var Operators = [
[
'=' '='
,'LIKE' ,'LIKE'
,'AND' ,'AND'
@ -49,48 +47,39 @@ var Operators =
,'MOD' ,'MOD'
]; ];
Klass.extend Klass.extend({
({
Type: Type Type: Type
,Operators: Operators ,Operators: Operators
}); });
Klass.implement Klass.implement({
({
Extends: Expr Extends: Expr
,Implements: ListHolder ,Implements: ListHolder
,Tag: 'sql-operation' ,Tag: 'sql-operation'
,Properties: ,Properties: {
{ type: {
type:
{
enumType: Type enumType: Type
,value: -1 ,value: -1
}, },
target: target: {
{
type: String type: String
,value: null ,value: null
}, },
exprs: exprs: {
{
type: Array type: Array
,set: function (x) ,set: function(x) {
{
this.list = x; this.list = x;
} }
,get: function () ,get: function() {
{
return this.list; return this.list;
} }
} }
} }
,render: function (params) ,render: function(params) {
{
var operator = ' '+ Operators[this.type] +' '; var operator = ' '+ Operators[this.type] +' ';
return '(' return '('
+ this.renderListWs (this.list, params, operator) + this.renderListWs(this.list, params, operator)
+ ')'; + ')';
} }
}); });

View File

@ -1,28 +1,25 @@
var Stmt = require ('./stmt'); var Stmt = require('./stmt');
var Field = require ('./field'); var Field = require('./field');
/** /**
* The equivalent of a SQL select. * The equivalent of a SQL select.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Stmt Extends: Stmt
,expr: [] ,expr: []
,addField: function (fieldName) ,addField: function(fieldName) {
{ this.expr.push(new Field({name: fieldName}));
this.expr.push (new Field ({name: fieldName}));
} }
,render: function (params) ,render: function(params) {
{
return 'SELECT ' return 'SELECT '
+ this.renderListWs (this.expr, params, ', ') + this.renderListWs(this.expr, params, ', ')
+ ' FROM' + ' FROM'
+ this.renderTarget (params) + this.renderTarget(params)
+ this.renderIfSet (this.where, 'WHERE', params) + this.renderIfSet(this.where, 'WHERE', params)
+ this.renderLimit (params); + this.renderLimit(params);
} }
}); });

View File

@ -1,18 +1,15 @@
var Stmt = require ('./stmt'); var Stmt = require('./stmt');
var Holder = require ('./holder'); var Holder = require('./holder');
/** /**
* Literal SQL string. * Literal SQL string.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Stmt Extends: Stmt
,Tag: 'sql-string' ,Tag: 'sql-string'
,Properties: ,Properties: {
{ query: {
query:
{
type: String type: String
,value: null ,value: null
} }
@ -20,33 +17,29 @@ module.exports = new Class
,regexp: /#\w+/g ,regexp: /#\w+/g
,appendChild: function (child) ,appendChild: function(child) {
{
if (child.nodeType === Node.TEXT_NODE) if (child.nodeType === Node.TEXT_NODE)
this.query = child.textContent; this.query = child.textContent;
} }
,render: function (params) ,render: function(params) {
{
if (!this.query) if (!this.query)
return null; return null;
function replaceFunc (token) function replaceFunc(token) {
{ var holder = new Holder({id: token.substr(1)});
var holder = new Holder ({id: token.substr (1)}); return holder.render(params);
return holder.render (params);
} }
return this.query.replace (this.regexp, replaceFunc); return this.query.replace(this.regexp, replaceFunc);
} }
,findHolders: function () ,findHolders: function() {
{ var ids = this.query.match(this.regexp);
var ids = this.query.match (this.regexp);
if (ids) if (ids)
for (var i = 0; i < ids.length; i++) for (var i = 0; i < ids.length; i++)
ids[i] = ids[i].substr (1); ids[i] = ids[i].substr(1);
return ids; return ids;
} }

View File

@ -1,38 +1,32 @@
var Target = require ('./target'); var Target = require('./target');
/** /**
* Represents a database table. * Represents a database table.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Target Extends: Target
,Properties: ,Properties: {
{ name: {
name:
{
type: String type: String
,value: null ,value: null
}, },
alias: alias: {
{
type: String type: String
,value: null ,value: null
}, },
schema: schema: {
{
type: String type: String
,value: null ,value: null
} }
} }
,render: function () ,render: function() {
{ var sql = this.renderPreIdent(this.schema)
var sql = this.renderPreIdent (this.schema) + this.renderIdent(this.name);
+ this.renderIdent (this.name);
if (this.alias) if (this.alias)
sql += ' AS '+ this.renderIdent (this.alias); sql += ' AS '+ this.renderIdent(this.alias);
return sql; return sql;
} }

View File

@ -1,10 +1,9 @@
var Object = require ('./object'); var Object = require('./object');
/** /**
* The equivalent of a SQL target. * The equivalent of a SQL target.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Object Extends: Object
}); });

View File

@ -1,29 +1,27 @@
var Dml = require ('./dml'); var Dml = require('./dml');
/** /**
* The equivalent of a SQL update. * The equivalent of a SQL update.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Dml Extends: Dml
,render: function (params) ,render: function(params) {
{
var sql = 'UPDATE' var sql = 'UPDATE'
+ this.renderTarget (params) + this.renderTarget(params)
+ ' SET '; + ' SET ';
this.field.forEach (function (field, i) { this.field.forEach(function(field, i) {
if (i > 0) if (i > 0)
sql += ', '; sql += ', ';
sql += field.render (params) sql += field.render(params)
+ ' = ' + ' = '
+ this.expr[i].render(params); + this.expr[i].render(params);
}, this); }, this);
sql += this.renderIfSet (this.where, 'WHERE', params) sql += this.renderIfSet(this.where, 'WHERE', params)
+ this.renderLimit(params); + this.renderLimit(params);
return sql; return sql;
} }