diff --git a/forms/account/address-list/locale/ca.yml b/forms/account/address-list/locale/ca.yml index cf957550..26601428 100644 --- a/forms/account/address-list/locale/ca.yml +++ b/forms/account/address-list/locale/ca.yml @@ -1,4 +1,4 @@ -Addresses: Direccions +Addresses: Adreces Return: Tornar AddAddress: Afegir adreça SetAsDefault: Establir com per defecte diff --git a/forms/ecomerce/catalog/catalog.js b/forms/ecomerce/catalog/catalog.js index 5b5f91a1..a5341e76 100644 --- a/forms/ecomerce/catalog/catalog.js +++ b/forms/ecomerce/catalog/catalog.js @@ -31,7 +31,7 @@ Hedera.Catalog = new Class({ else this.setView(Hedera.Catalog.View.GRID); - this.onRealmChange(); + this.onFilterChange(); } ,deactivate: function() { @@ -40,58 +40,81 @@ Hedera.Catalog = new Class({ Vn.Node.remove(this.$.rightPanel); } - ,onFilterChange: function() { - const $ = this.$; - const hash = this.hash; + ,getFilter(params, tags, currentTag) { + if (params.search == null && params.type == null) + return null; - if (hash.search != null || hash.type != null) { - const filter = new Sql.Operation({ - type: Sql.Operation.Type.AND - }); - - let idSearch = false; - if (hash.search != null) { - idSearch = /^\d+$/.test(hash.search); - filter.push(idSearch ? $.idOp : $.nameOp); - } + const $ = this.$; + + params = Object.assign({}, params); + const filter = new Sql.Operation({ + type: Sql.Operation.Type.AND + }); + + let idSearch = false; + if (params.search != null) { + idSearch = /^\d+$/.test(params.search); if (!idSearch) { - if (hash.realm != null) - filter.push($.realmOp); - if (hash.type != null) - filter.push($.typeOp); + filter.push($.searchOp); + params.search = `%${params.search}%`; + } else + filter.push($.idOp); + } - const tags = [ - 'color', - 'origin', - 'category', - 'producer' - ]; - for (const tag of tags) - if (hash[tag] != null) - filter.push($[`${tag}Op`]); - } + if (!idSearch) { + if (params.realm != null) + filter.push($.realmOp); + if (params.type != null) + filter.push($.typeOp); - const lot = new Vn.Lot(); - lot.set('filter', filter); - $.items.lot = lot; - } else - $.items.lot = null; + for (const tag of tags) + if (tag != currentTag && params[tag] != null) + filter.push($[`${tag}Op`]); + } + + params.filter = filter; + const lot = new Vn.Lot(); + lot.setAll(params); + + return lot; } - - ,onRealmChange: function() { - const hasRealm = this.$.realm.value != null; - this.$.filters.style.display = hasRealm ? 'block' : 'none'; - this.$.realmMsg.style.display = hasRealm ? 'none' : 'block'; + + ,onFilterChange: function() { + const $ = this.$; + const params = $.params.$; + 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() { + const hash = this.hash.$; const types = this.$.types; const realms = this.$.realms; - const type = this.$.type.value; - const realm = this.$.realm.value; + const type = hash.type; + const realm = hash.realm; let typeName; let realmName; @@ -232,7 +255,7 @@ Hedera.Catalog = new Class({ this.onEraseClick(); this.$.card.row = form.row; - this.$.cardItem.value = form.$.id; + this.$.cardLot.value = form.$.id; this.$.cardPopup.show(event.currentTarget); } @@ -270,7 +293,7 @@ Hedera.Catalog = new Class({ const params = { warehouse: warehouse, - item: this.$.cardItem.value, + item: this.$.cardLot.value, amount: amount } sql += query.render(params); @@ -295,7 +318,7 @@ Hedera.Catalog = new Class({ ,onPopupClose: function() { this.onEraseClick(); this.$.card.row = -1; - this.$.cardItem.value = undefined; + this.$.cardLot.value = undefined; } ,onCardLoad: function() { @@ -309,163 +332,3 @@ Hedera.Catalog.extend({ 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; - } -}); - diff --git a/forms/ecomerce/catalog/style.css b/forms/ecomerce/catalog/style.css index 0714e225..56b00e37 100644 --- a/forms/ecomerce/catalog/style.css +++ b/forms/ecomerce/catalog/style.css @@ -88,41 +88,7 @@ padding: 0; 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 { - display: block; - margin: 0 auto; margin-top: 1em; } diff --git a/forms/ecomerce/catalog/ui.xml b/forms/ecomerce/catalog/ui.xml index 8826ba01..07dd0b3e 100644 --- a/forms/ecomerce/catalog/ui.xml +++ b/forms/ecomerce/catalog/ui.xml @@ -4,8 +4,7 @@
- + + - - - - + type="EQUAL" + target="i" + field="id" + param="search"/> - - + id="search-op" + type="OR"> + + - - - - - + - - - - + - - - - - - - - + - - - - + + - - - + type="EQUAL" + target="i" + field="producerFk" + param="producer"/> @@ -89,6 +97,7 @@ CREATE TEMPORARY TABLE tmp.item @@ -230,14 +239,16 @@

Filter by

- CALL myBasket_getAvailable; @@ -246,21 +257,21 @@ JOIN vn.itemType t ON t.id = i.typeFk JOIN tmp.itemAvailable a ON a.id = i.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 - - - - - - - - + - + form="params" + column="color" + on-click="$.colors.refresh()"> + CALL myBasket_getAvailable; SELECT DISTINCT l.id, l.name FROM vn.item i @@ -270,12 +281,17 @@ WHERE #filter ORDER BY name - - + - + form="params" + column="producer" + on-click="$.producers.refresh()"> + CALL myBasket_getAvailable; SELECT DISTINCT p.id, p.name FROM vn.item i @@ -285,12 +301,17 @@ WHERE #filter ORDER BY name - - + - + form="params" + column="origin" + on-click="$.origins.refresh()"> + CALL myBasket_getAvailable; SELECT DISTINCT o.id, l.name, o.code FROM vn.item i @@ -301,12 +322,17 @@ WHERE #filter ORDER BY name - - + - + form="params" + column="category" + on-click="$.categorys.refresh()"> + CALL myBasket_getAvailable; SELECT DISTINCT i.category, i.category FROM vn.item i @@ -315,7 +341,7 @@ WHERE #filter ORDER BY category - +

Order by

diff --git a/js/db/model.js b/js/db/model.js index e163fcac..63e8a25f 100644 --- a/js/db/model.js +++ b/js/db/model.js @@ -78,7 +78,7 @@ Model.implement({ lot: { type: Vn.LotIface ,set: function(x) { - this.link({_lot: x}, {'change': this._autoLoad}); + this.link({_lot: x}, {'change': this._onLotChange}); this._onLotChange(); } ,get: function() { @@ -231,47 +231,73 @@ Model.implement({ if (query) this.query = query; } - - ,_getLotParams: function() { - if (!this._stmt) - return null; - var holders = this._stmt.findHolders(); - if (!holders) - return null; - var lotParams = this._lot ? this._lot.params : {}; - - if (lotParams == null) - lotParams = {}; - var params = {}; - for (var i = 0; i < holders.length; i++) - params[holders[i]] = lotParams[holders[i]]; + + ,_getHolders(stmt) { + if (!stmt) return null; + let holders = this._stmt.findHolders(); + if (!holders) return null; + + if (this._lot) { + 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]; + return params; } ,_onLotChange: function() { - var lotParams = this._getLotParams(); - if (!Vn.Value.equals(lotParams, this._lastLotParams)) + const params = this._getHolderValues(); + const isEqual = Vn.Value.equals(params, this._lastParams); + this._lastParams = params; + + if (!isEqual) this._autoLoad(); } - + ,_autoLoad: function() { if (this.autoLoad) this.refresh(); else this.clean(); } - + ,_isReady: function(params) { if (!this._stmt || !this._conn) return false; - var holders = this._stmt.findHolders(); - if (!holders) - return true; - - for (var i = 0; i < holders.length; i++) - if (params[holders[i]] === undefined) - return false; + for (const param in params) + if (params[param] === undefined) + return false; return true; } @@ -279,26 +305,17 @@ Model.implement({ /** * Refresh the model data reexecuting the query on the database. */ - ,refresh: function(params) { - var lotParams = this._getLotParams(); - var myParams = {}; + ,refresh: function() { + const params = this._getHolderParams(); - Object.assign(myParams, lotParams); - Object.assign(myParams, params); - - if (this._filter && (!params || params.filter === undefined)) - myParams.filter = this._filter; - - this._lastLotParams = lotParams; - - if (this._isReady(myParams)) { + if (this._isReady(params)) { this._setStatus(Status.LOADING); this._conn.execStmt(this._stmt, - this._selectDone.bind(this), myParams); + this._selectDone.bind(this), params); } else this.clean(); } - + ,clean: function() { this._cleanData(); this._setStatus(Status.CLEAN); diff --git a/js/hedera/locale/ca.yml b/js/hedera/locale/ca.yml index c2ca263f..4de7b265 100644 --- a/js/hedera/locale/ca.yml +++ b/js/hedera/locale/ca.yml @@ -61,4 +61,4 @@ Training: Formació Agencies: Agències Configuration: Configuració Account: Compte -Addresses: Direccions +Addresses: Adreces diff --git a/js/htk/assistant-bar.js b/js/htk/assistant-bar/index.js similarity index 96% rename from js/htk/assistant-bar.js rename to js/htk/assistant-bar/index.js index 0f944549..7035e56b 100644 --- a/js/htk/assistant-bar.js +++ b/js/htk/assistant-bar/index.js @@ -1,6 +1,6 @@ - -var Widget = require('./widget'); -var Assistant = require('./assistant'); +require('./style.scss'); +var Widget = require('../widget'); +var Assistant = require('../assistant'); module.exports = new Class({ Extends: Widget, diff --git a/js/htk/assistant-bar/style.scss b/js/htk/assistant-bar/style.scss new file mode 100644 index 00000000..4b6877d3 --- /dev/null +++ b/js/htk/assistant-bar/style.scss @@ -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; + } + } + } +} diff --git a/js/htk/assistant.js b/js/htk/assistant/index.js similarity index 96% rename from js/htk/assistant.js rename to js/htk/assistant/index.js index 53865d9a..c03eb8d8 100644 --- a/js/htk/assistant.js +++ b/js/htk/assistant/index.js @@ -1,7 +1,7 @@ - -var Widget = require('./widget'); -var Step = require('./step'); -var Toast = require('./toast'); +require('./style.scss'); +var Widget = require('../widget'); +var Step = require('../step'); +var Toast = require('../toast'); /** * A simple assistant with steps. diff --git a/js/htk/assistant/style.scss b/js/htk/assistant/style.scss new file mode 100644 index 00000000..b5261194 --- /dev/null +++ b/js/htk/assistant/style.scss @@ -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; + } +} \ No newline at end of file diff --git a/js/htk/column/check.js b/js/htk/column/check.js deleted file mode 100644 index 950187d0..00000000 --- a/js/htk/column/check.js +++ /dev/null @@ -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); - } -}); diff --git a/js/htk/column.js b/js/htk/column/index.js similarity index 96% rename from js/htk/column.js rename to js/htk/column/index.js index b8e64bd3..c1588bfb 100644 --- a/js/htk/column.js +++ b/js/htk/column/index.js @@ -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 diff --git a/js/htk/column/radio.js b/js/htk/column/radio.js deleted file mode 100644 index a10235d2..00000000 --- a/js/htk/column/radio.js +++ /dev/null @@ -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 (); - } -}); diff --git a/js/htk/column/button.js b/js/htk/columns/button/index.js similarity index 100% rename from js/htk/column/button.js rename to js/htk/columns/button/index.js diff --git a/js/htk/columns/check/index.js b/js/htk/columns/check/index.js new file mode 100644 index 00000000..60868aa1 --- /dev/null +++ b/js/htk/columns/check/index.js @@ -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); + } +}); diff --git a/js/htk/column/date.js b/js/htk/columns/date/index.js similarity index 100% rename from js/htk/column/date.js rename to js/htk/columns/date/index.js diff --git a/js/htk/column/image.js b/js/htk/columns/image/index.js similarity index 88% rename from js/htk/column/image.js rename to js/htk/columns/image/index.js index acf246cd..757aa913 100644 --- a/js/htk/column/image.js +++ b/js/htk/columns/image/index.js @@ -1,39 +1,33 @@ -module.exports = new Class -({ +module.exports = new Class({ Extends: Htk.Column ,Tag: 'htk-column-image' - ,Properties: - { + ,Properties: { /** * The directory where the images are allocated. */ - directory: - { + directory:{ type: String ,value: null }, /** * The subdirectory where the images are allocated. */ - subdir: - { + subdir:{ type: String ,value: null }, /** * Subdirectory where full images are allocated. */ - fullDir: - { + fullDir:{ type: String ,value: null }, /** * The REST connection used to upload the image. */ - conn: - { + conn:{ type: Vn.JsonConnection } } diff --git a/js/htk/column/link.js b/js/htk/columns/link/index.js similarity index 86% rename from js/htk/column/link.js rename to js/htk/columns/link/index.js index 62b45f85..97efdc49 100644 --- a/js/htk/column/link.js +++ b/js/htk/columns/link/index.js @@ -1,23 +1,19 @@ -module.exports = new Class -({ +module.exports = new Class({ Extends: Htk.Column ,Tag: 'htk-column-link' - ,Properties: - { + ,Properties: { /** * The link url. */ - href: - { + href:{ type: String ,value: null }, /** * the target where the link is opened. */ - target: - { + target:{ type: String ,value: null } diff --git a/js/htk/columns/radio/index.js b/js/htk/columns/radio/index.js new file mode 100644 index 00000000..4ae7690e --- /dev/null +++ b/js/htk/columns/radio/index.js @@ -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(); + } +}); diff --git a/js/htk/column/spin.js b/js/htk/columns/spin/index.js similarity index 95% rename from js/htk/column/spin.js rename to js/htk/columns/spin/index.js index a115d739..f5885668 100644 --- a/js/htk/column/spin.js +++ b/js/htk/columns/spin/index.js @@ -1,15 +1,12 @@ -module.exports = new Class -({ +module.exports = new Class({ Extends: Htk.Column ,Tag: 'htk-column-spin' - ,Properties: - { + ,Properties: { /** * The text to append to the number. */ - unit: - { + unit:{ type: String ,value: null }, diff --git a/js/htk/column/text.js b/js/htk/columns/text/index.js similarity index 93% rename from js/htk/column/text.js rename to js/htk/columns/text/index.js index fabfd4bf..7d6bf395 100644 --- a/js/htk/column/text.js +++ b/js/htk/columns/text/index.js @@ -1,15 +1,12 @@ -module.exports = new Class -({ +module.exports = new Class({ Extends: Htk.Column ,Tag: 'htk-column-text' - ,Properties: - { + ,Properties: { /** * Format that applies to the value. */ - format: - { + format:{ type: String ,set: function(x) { this._format = _(x); diff --git a/js/htk/component.js b/js/htk/component/index.js similarity index 94% rename from js/htk/component.js rename to js/htk/component/index.js index c536e3ae..b3ae0755 100644 --- a/js/htk/component.js +++ b/js/htk/component/index.js @@ -1,5 +1,5 @@ -const Widget = require('./widget'); +const Widget = require('../widget'); module.exports = new Class({ Extends: Widget diff --git a/js/htk/dialog.js b/js/htk/dialog/index.js similarity index 97% rename from js/htk/dialog.js rename to js/htk/dialog/index.js index e2a392d4..0c1709a0 100644 --- a/js/htk/dialog.js +++ b/js/htk/dialog/index.js @@ -1,5 +1,5 @@ - -var Popup = require('./popup'); +require('./style.scss'); +var Popup = require('../popup'); /** * Class to show message dialogs with buttons. diff --git a/js/htk/dialog/style.scss b/js/htk/dialog/style.scss new file mode 100644 index 00000000..e2073089 --- /dev/null +++ b/js/htk/dialog/style.scss @@ -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; + } +} \ No newline at end of file diff --git a/js/htk/field.js b/js/htk/field/index.js similarity index 93% rename from js/htk/field.js rename to js/htk/field/index.js index 4c651c7c..ac4f2842 100644 --- a/js/htk/field.js +++ b/js/htk/field/index.js @@ -1,5 +1,5 @@ -var Widget = require('./widget'); +var Widget = require('../widget'); module.exports = new Class({ Extends: Widget @@ -109,6 +109,10 @@ module.exports = new Class({ if (this.conditionalFunc) this.conditionalFunc(this, newValue); + const node = this.node; + if (node && node.nodeType === Node.ELEMENT_NODE) + node.classList.toggle('filled', newValue !== undefined); + this._notifyChanges(); } diff --git a/js/htk/field/spin.js b/js/htk/field/spin.js deleted file mode 100644 index 102aff33..00000000 --- a/js/htk/field/spin.js +++ /dev/null @@ -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; - } -}); diff --git a/js/htk/field/bar-button.js b/js/htk/fields/bar-button/index.js similarity index 73% rename from js/htk/field/bar-button.js rename to js/htk/fields/bar-button/index.js index b923f17a..aad3e764 100644 --- a/js/htk/field/bar-button.js +++ b/js/htk/fields/bar-button/index.js @@ -1,5 +1,5 @@ -var Button = require('./button'); +var Button = require('../button'); module.exports = new Class({ Extends: Button diff --git a/js/htk/field/button.js b/js/htk/fields/button/index.js similarity index 97% rename from js/htk/field/button.js rename to js/htk/fields/button/index.js index 7d105b1c..f3d1ddb0 100644 --- a/js/htk/field/button.js +++ b/js/htk/fields/button/index.js @@ -1,3 +1,4 @@ +require('./style.scss'); module.exports = new Class({ Extends: Htk.Field diff --git a/js/htk/fields/button/style.scss b/js/htk/fields/button/style.scss new file mode 100644 index 00000000..4ac5ef43 --- /dev/null +++ b/js/htk/fields/button/style.scss @@ -0,0 +1,10 @@ + +.htk-button { + display: flex; + align-items: center; + gap: 8px; + + & > .htk-icon { + display: block; + } +} \ No newline at end of file diff --git a/js/htk/field/calendar.js b/js/htk/fields/calendar/index.js similarity index 99% rename from js/htk/field/calendar.js rename to js/htk/fields/calendar/index.js index f1e54421..0a1b7017 100644 --- a/js/htk/field/calendar.js +++ b/js/htk/fields/calendar/index.js @@ -1,3 +1,4 @@ +require('./style.scss'); module.exports = new Class({ Extends: Htk.Field diff --git a/js/htk/fields/calendar/style.scss b/js/htk/fields/calendar/style.scss new file mode 100644 index 00000000..cb1c5e37 --- /dev/null +++ b/js/htk/fields/calendar/style.scss @@ -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); + } + } + } +} diff --git a/js/htk/field/check.js b/js/htk/fields/check/index.js similarity index 100% rename from js/htk/field/check.js rename to js/htk/fields/check/index.js diff --git a/js/htk/field/date-chooser.js b/js/htk/fields/date-chooser/index.js similarity index 94% rename from js/htk/field/date-chooser.js rename to js/htk/fields/date-chooser/index.js index 579c4a44..a32b14cc 100644 --- a/js/htk/field/date-chooser.js +++ b/js/htk/fields/date-chooser/index.js @@ -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 ,Tag: 'htk-date-chooser' diff --git a/js/htk/fields/date-chooser/style.scss b/js/htk/fields/date-chooser/style.scss new file mode 100644 index 00000000..5a464056 --- /dev/null +++ b/js/htk/fields/date-chooser/style.scss @@ -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; + } +} \ No newline at end of file diff --git a/js/htk/field/entry.js b/js/htk/fields/entry/index.js similarity index 100% rename from js/htk/field/entry.js rename to js/htk/fields/entry/index.js diff --git a/js/htk/field/html.js b/js/htk/fields/html/index.js similarity index 100% rename from js/htk/field/html.js rename to js/htk/fields/html/index.js diff --git a/js/htk/field/image.js b/js/htk/fields/image/index.js similarity index 100% rename from js/htk/field/image.js rename to js/htk/fields/image/index.js diff --git a/js/htk/fields/image/style.scss b/js/htk/fields/image/style.scss new file mode 100644 index 00000000..fdfceb41 --- /dev/null +++ b/js/htk/fields/image/style.scss @@ -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; + } +} diff --git a/js/htk/field/label.js b/js/htk/fields/label/index.js similarity index 100% rename from js/htk/field/label.js rename to js/htk/fields/label/index.js diff --git a/js/htk/field/radio.js b/js/htk/fields/radio/index.js similarity index 100% rename from js/htk/field/radio.js rename to js/htk/fields/radio/index.js diff --git a/js/htk/field/radio-group.js b/js/htk/fields/radio/radio-group.js similarity index 66% rename from js/htk/field/radio-group.js rename to js/htk/fields/radio/radio-group.js index 9ed79344..74c38ba8 100644 --- a/js/htk/field/radio-group.js +++ b/js/htk/fields/radio/radio-group.js @@ -1,35 +1,30 @@ var htkRadioGroupUid = 0; -module.exports = new Class -({ +module.exports = new Class({ Extends: Htk.Field ,Tag: 'htk-radio-group' ,radioLock: false - ,initialize: function (props) - { - this.clear (); - this.parent (props); + ,initialize: function(props) { + this.clear(); + this.parent(props); } - ,clear: function () - { + ,clear: function() { this.name = htkRadioGroupUid++; this.buttons = []; } - ,createButton: function (value) - { - var button = Vn.Browser.createRadio (this.name, this.doc); + ,createButton: function(value) { + var button = Vn.Browser.createRadio(this.name, this.doc); button.value = value; button.radioGroup = this; return button; } - ,removeButton: function (button) - { + ,removeButton: function(button) { for (var i = 0; i < this.buttons.length; i++) if (this.buttons === button) { 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 */ - ,isSelected: function () { + ,isSelected: function() { for (var i = 0; i < this.buttons.length; i++) if (this.buttons[i].value == this.value) return true; diff --git a/js/htk/field/search-entry.js b/js/htk/fields/search-entry/index.js similarity index 97% rename from js/htk/field/search-entry.js rename to js/htk/fields/search-entry/index.js index e87fed09..c2b91fa0 100644 --- a/js/htk/field/search-entry.js +++ b/js/htk/fields/search-entry/index.js @@ -1,3 +1,4 @@ +require('./style.scss'); module.exports = new Class({ Extends: Htk.Field diff --git a/js/htk/fields/search-entry/style.scss b/js/htk/fields/search-entry/style.scss new file mode 100644 index 00000000..071f7d32 --- /dev/null +++ b/js/htk/fields/search-entry/style.scss @@ -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; + } +} \ No newline at end of file diff --git a/js/htk/field/select.js b/js/htk/fields/select/index.js similarity index 86% rename from js/htk/field/select.js rename to js/htk/fields/select/index.js index 04d6b78c..a247cca8 100644 --- a/js/htk/field/select.js +++ b/js/htk/fields/select/index.js @@ -1,5 +1,5 @@ - -var ColumnText = require('../column/text'); +require('./style.scss'); +var ColumnText = require('../../columns/text'); module.exports = new Class({ Extends: Htk.Field @@ -111,11 +111,21 @@ module.exports = new Class({ const button = this.createRoot('button'); button.type = 'button'; button.className = 'htk-select input'; - button.addEventListener('mousedown', this._onButtonMouseDown.bind(this)); + button.addEventListener('mousedown', + e => this._onButtonMouseDown(e)); this.label = this.createElement('span'); 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({ name: 'expand_more' }); @@ -127,12 +137,22 @@ module.exports = new Class({ this._refreshShowText(); this.iterChanged(); } + + ,_onEraseMouseDown(event) { + if (event.defaultPrevented) return; + event.preventDefault(); + this._setRow(-1); + this.valueChanged(undefined); + } - ,_onButtonMouseDown: function(e) { + ,_onButtonMouseDown: function(event) { if (this._popup) { this._popup.hide(); return; } + + if (event.defaultPrevented) return; + event.preventDefault(); var model = this._model; @@ -151,11 +171,9 @@ module.exports = new Class({ var popup = this._popup = new Htk.Popup({childNode: menu}); popup.on('closed', this._onPopupClose.bind(this)); - popup.show(this.node); + popup.show(this.node, event); this.emit('menu-show'); - - e.stopPropagation(); } ,_onGridClicked: function(grid, e) { diff --git a/js/htk/fields/select/style.scss b/js/htk/fields/select/style.scss new file mode 100644 index 00000000..9a678ebc --- /dev/null +++ b/js/htk/fields/select/style.scss @@ -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; + } +} \ No newline at end of file diff --git a/js/htk/fields/spin/index.js b/js/htk/fields/spin/index.js new file mode 100644 index 00000000..6de72ed9 --- /dev/null +++ b/js/htk/fields/spin/index.js @@ -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; + } +}); diff --git a/js/htk/field/table.js b/js/htk/fields/table/index.js similarity index 91% rename from js/htk/field/table.js rename to js/htk/fields/table/index.js index 59c95301..2f43ff03 100644 --- a/js/htk/field/table.js +++ b/js/htk/fields/table/index.js @@ -1,6 +1,6 @@ -var Entry = require('./entry'); -var ColumnRadio = require('../column/radio'); +var Entry = require('../entry'); +var ColumnRadio = require('../../columns/radio'); module.exports = new Class({ Extends: Entry diff --git a/js/htk/field/text-area.js b/js/htk/fields/text-area/index.js similarity index 100% rename from js/htk/field/text-area.js rename to js/htk/fields/text-area/index.js diff --git a/js/htk/field/text.js b/js/htk/fields/text/index.js similarity index 100% rename from js/htk/field/text.js rename to js/htk/fields/text/index.js diff --git a/js/htk/full-image.js b/js/htk/full-image/index.js similarity index 94% rename from js/htk/full-image.js rename to js/htk/full-image/index.js index b4e0d00e..cea3810e 100644 --- a/js/htk/full-image.js +++ b/js/htk/full-image/index.js @@ -1,6 +1,6 @@ - -var Popup = require('./popup'); -var Spinner = require('./spinner'); +require('./style.scss'); +var Popup = require('../popup'); +var Spinner = require('../spinner'); module.exports = new Class ({ diff --git a/js/htk/full-image/style.scss b/js/htk/full-image/style.scss new file mode 100644 index 00000000..8795818b --- /dev/null +++ b/js/htk/full-image/style.scss @@ -0,0 +1,12 @@ + +.htk-full-image { + img { + display: block; + cursor: pointer; + } + .htk-spinner { + background-color: #FFF; + margin: .6em; + display: block; + } +} diff --git a/js/htk/grid.js b/js/htk/grid/index.js similarity index 99% rename from js/htk/grid.js rename to js/htk/grid/index.js index 2e025501..4a9e6c72 100644 --- a/js/htk/grid.js +++ b/js/htk/grid/index.js @@ -1,5 +1,5 @@ - -var Widget = require('./widget'); +require('./style.scss'); +var Widget = require('../widget'); module.exports = new Class({ Extends: Widget diff --git a/js/htk/grid/style.scss b/js/htk/grid/style.scss new file mode 100644 index 00000000..a2a608db --- /dev/null +++ b/js/htk/grid/style.scss @@ -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; + } +} diff --git a/js/htk/htk.js b/js/htk/htk.js index 1fbd0362..b7f196f6 100644 --- a/js/htk/htk.js +++ b/js/htk/htk.js @@ -18,36 +18,37 @@ Htk = module.exports = { ,AssistantBar : require('./assistant-bar') ,Step : require('./step') ,Loader : require('./loader') + ,List : require('./list') ,Field : require('./field') ,Column : require('./column') }; var Fields = { - Text : require('./field/text') - ,Html : require('./field/html') - ,Entry : require('./field/entry') - ,RadioGroup : require('./field/radio-group') - ,Radio : require('./field/radio') - ,Label : require('./field/label') - ,TextArea : require('./field/text-area') - ,Spin : require('./field/spin') - ,Check : require('./field/check') - ,Select : require('./field/select') - ,Calendar : require('./field/calendar') - ,DateChooser : require('./field/date-chooser') - ,Image : require('./field/image') - ,Button : require('./field/button') - ,BarButton : require('./field/bar-button') - ,Table : require('./field/table') - ,SearchEntry : require('./field/search-entry') - ,ColumnButton : require('./column/button') - ,ColumnLink : require('./column/link') - ,ColumnDate : require('./column/date') - ,ColumnImage : require('./column/image') - ,ColumnRadio : require('./column/radio') - ,ColumnSpin : require('./column/spin') - ,ColumnText : require('./column/text') - ,ColumnCheck : require('./column/check') + Text : require('./fields/text') + ,Html : require('./fields/html') + ,Entry : require('./fields/entry') + ,RadioGroup : require('./fields/radio/radio-group') + ,Radio : require('./fields/radio') + ,Label : require('./fields/label') + ,TextArea : require('./fields/text-area') + ,Spin : require('./fields/spin') + ,Check : require('./fields/check') + ,Select : require('./fields/select') + ,Calendar : require('./fields/calendar') + ,DateChooser : require('./fields/date-chooser') + ,Image : require('./fields/image') + ,Button : require('./fields/button') + ,BarButton : require('./fields/bar-button') + ,Table : require('./fields/table') + ,SearchEntry : require('./fields/search-entry') + ,ColumnButton : require('./columns/button') + ,ColumnLink : require('./columns/link') + ,ColumnDate : require('./columns/date') + ,ColumnImage : require('./columns/image') + ,ColumnRadio : require('./columns/radio') + ,ColumnSpin : require('./columns/spin') + ,ColumnText : require('./columns/text') + ,ColumnCheck : require('./columns/check') }; for (var field in Fields) diff --git a/js/htk/icon.js b/js/htk/icon/index.js similarity index 95% rename from js/htk/icon.js rename to js/htk/icon/index.js index 75ed807f..e127a07a 100644 --- a/js/htk/icon.js +++ b/js/htk/icon/index.js @@ -1,5 +1,5 @@ -var Widget = require('./widget'); +var Widget = require('../widget'); module.exports = new Class({ Extends: Widget diff --git a/js/htk/image-editor.js b/js/htk/image-editor/index.js similarity index 89% rename from js/htk/image-editor.js rename to js/htk/image-editor/index.js index cb348f07..24ee2466 100644 --- a/js/htk/image-editor.js +++ b/js/htk/image-editor/index.js @@ -1,7 +1,7 @@ - -var Component = require('./component'); -var Toast = require('./toast'); -var Tpl = require('./image-editor.xml').default; +require('./style.scss'); +var Component = require('../component'); +var Toast = require('../toast'); +var Tpl = require('./ui.xml').default; /** * A form to handle the image database, it allows to add new images or diff --git a/js/htk/image-editor/style.scss b/js/htk/image-editor/style.scss new file mode 100644 index 00000000..22921146 --- /dev/null +++ b/js/htk/image-editor/style.scss @@ -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; + } + } +} diff --git a/js/htk/image-editor.xml b/js/htk/image-editor/ui.xml similarity index 100% rename from js/htk/image-editor.xml rename to js/htk/image-editor/ui.xml diff --git a/js/htk/list/index.js b/js/htk/list/index.js new file mode 100644 index 00000000..1fe6bd72 --- /dev/null +++ b/js/htk/list/index.js @@ -0,0 +1 @@ +require('./style.scss'); diff --git a/js/htk/list/style.scss b/js/htk/list/style.scss new file mode 100644 index 00000000..5bc03763 --- /dev/null +++ b/js/htk/list/style.scss @@ -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; + } +} diff --git a/js/htk/loader.js b/js/htk/loader.js deleted file mode 100644 index 8ca67313..00000000 --- a/js/htk/loader.js +++ /dev/null @@ -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 (); - } -}); - diff --git a/js/htk/loader/index.js b/js/htk/loader/index.js new file mode 100644 index 00000000..9b56cc62 --- /dev/null +++ b/js/htk/loader/index.js @@ -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(); + } +}); + diff --git a/js/htk/loader/style.scss b/js/htk/loader/style.scss new file mode 100644 index 00000000..5c42e10b --- /dev/null +++ b/js/htk/loader/style.scss @@ -0,0 +1,4 @@ + +.htk-loader > .spinner { + text-align: center; +} diff --git a/js/htk/locale/ca.yml b/js/htk/locale/ca.yml index ea06ed41..3bb55c1d 100644 --- a/js/htk/locale/ca.yml +++ b/js/htk/locale/ca.yml @@ -27,3 +27,4 @@ Next: Següent Confirm: Confirmar Search: Cercar Search...: Cercar... +Erase: Esborrar diff --git a/js/htk/locale/en.yml b/js/htk/locale/en.yml index e1f455d6..58547015 100644 --- a/js/htk/locale/en.yml +++ b/js/htk/locale/en.yml @@ -27,3 +27,4 @@ Next: Next Confirm: Confirm Search: Search Search...: Search... +Erase: Erase diff --git a/js/htk/locale/es.yml b/js/htk/locale/es.yml index 76a005ee..4210301e 100644 --- a/js/htk/locale/es.yml +++ b/js/htk/locale/es.yml @@ -27,3 +27,4 @@ Next: Siguiente Confirm: Confirmar Search: Buscar Search...: Buscar... +Erase: Borrar diff --git a/js/htk/locale/fr.yml b/js/htk/locale/fr.yml index 1d10627b..4bd0b2ca 100644 --- a/js/htk/locale/fr.yml +++ b/js/htk/locale/fr.yml @@ -27,3 +27,4 @@ Next: Suivant Confirm: Confirmer Search: Recherche Search...: Recherche... +Erase: Effacer diff --git a/js/htk/locale/pt.yml b/js/htk/locale/pt.yml index 67775386..17167706 100644 --- a/js/htk/locale/pt.yml +++ b/js/htk/locale/pt.yml @@ -27,3 +27,4 @@ Next: Seguinte Confirm: Confirmar Search: Procurar Search...: Procurar... +Erase: Apagar diff --git a/js/htk/popup.js b/js/htk/popup/index.js similarity index 94% rename from js/htk/popup.js rename to js/htk/popup/index.js index 044f5436..d62f2f01 100644 --- a/js/htk/popup.js +++ b/js/htk/popup/index.js @@ -1,20 +1,17 @@ - -var Widget = require('./widget'); +require('./style.scss'); +var Widget = require('../widget'); /** * Class to handle popups. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Widget ,Tag: 'htk-popup' - ,Properties: - { + ,Properties: { /** * The popup child. */ - child: - { + child: { type: Widget ,set: function(x) { this._child = x; @@ -27,8 +24,7 @@ module.exports = new Class /** * The popup child Node. */ - ,childNode: - { + ,childNode: { type: Object ,set: function(x) { this._child = null; @@ -41,8 +37,7 @@ module.exports = new Class /** * Indicates how the dialog must be displayed. */ - ,modal: - { + ,modal: { type: Boolean ,set: function(x) { this._modal = x; @@ -73,8 +68,9 @@ module.exports = new Class this.node.appendChild(childNode); } - ,show: function(parent) { + ,show: function(parent, event) { this._parent = parent; + this._lastEvent = event; this.open(); } diff --git a/js/htk/popup/style.scss b/js/htk/popup/style.scss new file mode 100644 index 00000000..c89d5967 --- /dev/null +++ b/js/htk/popup/style.scss @@ -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; +} diff --git a/js/htk/repeater.js b/js/htk/repeater/index.js similarity index 98% rename from js/htk/repeater.js rename to js/htk/repeater/index.js index 231f747a..b7947d53 100644 --- a/js/htk/repeater.js +++ b/js/htk/repeater/index.js @@ -1,5 +1,5 @@ - -var Widget = require('./widget'); +require('./style.scss'); +var Widget = require('../widget'); module.exports = new Class({ Extends: Widget diff --git a/js/htk/repeater/style.scss b/js/htk/repeater/style.scss new file mode 100644 index 00000000..fc353a74 --- /dev/null +++ b/js/htk/repeater/style.scss @@ -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; + } + } +} diff --git a/js/htk/spinner.js b/js/htk/spinner.js deleted file mode 100644 index f7edcd39..00000000 --- a/js/htk/spinner.js +++ /dev/null @@ -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; - } -}); - diff --git a/js/htk/spinner/index.js b/js/htk/spinner/index.js new file mode 100644 index 00000000..d2139b45 --- /dev/null +++ b/js/htk/spinner/index.js @@ -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; + } +}); + diff --git a/js/htk/spinner/style.scss b/js/htk/spinner/style.scss new file mode 100644 index 00000000..df630787 --- /dev/null +++ b/js/htk/spinner/style.scss @@ -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);} +} diff --git a/js/htk/step.js b/js/htk/step/index.js similarity index 95% rename from js/htk/step.js rename to js/htk/step/index.js index 724266a4..b3d4a72e 100644 --- a/js/htk/step.js +++ b/js/htk/step/index.js @@ -1,5 +1,5 @@ -var Widget = require('./widget'); +var Widget = require('../widget'); module.exports = new Class({ Extends: Widget, diff --git a/js/htk/style/components.scss b/js/htk/style/components.scss index 35822fbd..ca8f89fa 100644 --- a/js/htk/style/components.scss +++ b/js/htk/style/components.scss @@ -1,106 +1,6 @@ @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 { text-align: right; } @@ -108,601 +8,52 @@ td.cell-spin { width: 2.5em; text-align: right; } + th.cell-check, th.cell-radio { text-align: center; } + td.cell-button { max-width: 20px; 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 { - display: block; - } -} -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 { + & > button, + & > a { @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; - } -} - -/* 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; + display: block; + height: 44px; + width: 44px; margin: 0 auto; - color: #555; - } - div { - &.disabled { - color: #bbb; + border-radius: 50%; + padding: 10px; + border: none; + background-color: transparent; + 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 { - 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 { - float: left; - height: 3em; - 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 { + height: 1.5em; + width: 1.5em; 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; + margin: auto; + padding: 0; } } -/* Spinner */ - -.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 { +td.cell-image { text-align: center; -} + + .htk-image { + max-width: 2.5em; + max-height: 2.5em; + display: block; + margin: auto; + } +} \ No newline at end of file diff --git a/js/htk/toast.js b/js/htk/toast/index.js similarity index 99% rename from js/htk/toast.js rename to js/htk/toast/index.js index e08f142d..6a19ccd0 100644 --- a/js/htk/toast.js +++ b/js/htk/toast/index.js @@ -1,3 +1,5 @@ +require('./style.scss'); + /** * Class to show toast messages. */ diff --git a/js/htk/toast/style.scss b/js/htk/toast/style.scss new file mode 100644 index 00000000..4334fa08 --- /dev/null +++ b/js/htk/toast/style.scss @@ -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; + } +} \ No newline at end of file diff --git a/js/htk/widget.js b/js/htk/widget/index.js similarity index 91% rename from js/htk/widget.js rename to js/htk/widget/index.js index 5f911e36..103d9daa 100644 --- a/js/htk/widget.js +++ b/js/htk/widget/index.js @@ -1,7 +1,7 @@ -const NodeBuilder = require('../vn/node-builder'); +const NodeBuilder = require('../../vn/node-builder'); -const Widget = new Class({ +const WidgetClass = { Extends: NodeBuilder ,Properties: { /** @@ -115,7 +115,7 @@ const Widget = new Class({ } else this.parent(id, callback, instance); } -}); +}; htmlEventMap = {}; htmlEvents = [ @@ -141,9 +141,9 @@ htmlMethods = [ 'addEventListener' ]; htmlMethods.forEach(method => { - Widget[method] = function() { - this.node.apply(this.node, arguments); + WidgetClass[method] = function() { + this.node[method].apply(this.node, arguments); }; }); -module.exports = Widget; +module.exports = new Class(WidgetClass); diff --git a/js/sql/field.js b/js/sql/field.js index ccd7f1bf..79839d48 100644 --- a/js/sql/field.js +++ b/js/sql/field.js @@ -1,38 +1,33 @@ -var Expr = require ('./expr'); +var Expr = require('./expr'); /** * The equivalent of a SQL field. * * @param {string} taget The name of the owner table */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Expr ,Tag: 'sql-field' - ,Properties: - { + ,Properties: { /** * The column name. */ - name: - { + name: { type: String ,value: null }, /** * The source table name or its alias if it has been specified. */ - target: - { + target: { type: String ,value: null } } - ,render: function () - { - return this.renderPreIdent (this.target) - + this.renderIdent (this.name); + ,render: function() { + return this.renderPreIdent(this.target) + + this.renderIdent(this.name); } }); diff --git a/js/sql/filter-item.js b/js/sql/filter-item.js index 1f0286be..343eebb3 100644 --- a/js/sql/filter-item.js +++ b/js/sql/filter-item.js @@ -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) { return this.param != null && params != null && params[this.param] != null; @@ -51,18 +51,12 @@ module.exports = new Class({ })); 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})); return newOp.render(params); } - ,_escapeChar: function(char) { - return '\\'+ char; + ,findHolders: function() { + return this.param ? [this.param] : null; } }); diff --git a/js/sql/filter.js b/js/sql/filter.js index 53e9f8ec..111a6914 100644 --- a/js/sql/filter.js +++ b/js/sql/filter.js @@ -1,24 +1,22 @@ -var Operation = require ('./operation'); -var Value = require ('./value'); +var Operation = require('./operation'); +var Value = require('./value'); /** * The equivalent of a SQL filter expression. It allows to automatically build * SQL filters based on lot parameters. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Operation ,Tag: 'sql-filter' /** * Checks if any of filters childs are ready. */ - ,isReady: function (params) - { + ,isReady: function(params) { var exprs = this.exprs; for (var i = exprs.length; i--;) - if (exprs[i].isReady (params)) + if (exprs[i].isReady(params)) return true; return false; @@ -29,24 +27,23 @@ module.exports = new Class * ready is ommitted from the expression. If all of its childs aren't ready * renders the TRUE expression. */ - ,render: function (params) - { + ,render: function(params) { var newOp; var newExprs = []; - this.exprs.forEach (function (expr) { - if (expr.isReady (params)) - newExprs.push (expr); + this.exprs.forEach(function(expr) { + if (expr.isReady(params)) + newExprs.push(expr); }) if (newExprs.length > 0) - newOp = new Operation ({ + newOp = new Operation({ type: this.type, exprs: newExprs }); else - newOp = new Value ({value: true}); + newOp = new Value({value: true}); - return newOp.render (params); + return newOp.render(params); } }); diff --git a/js/sql/function.js b/js/sql/function.js index 113d0de9..50fc7c0a 100644 --- a/js/sql/function.js +++ b/js/sql/function.js @@ -1,56 +1,48 @@ -var Expr = require ('./expr'); -var ListHolder = require ('./list-holder'); +var Expr = require('./expr'); +var ListHolder = require('./list-holder'); /** * The equivalent of a SQL function. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Expr ,Tag: 'sql-function' ,Implements: ListHolder - ,Properties: - { + ,Properties: { /** * The function name. */ - name: - { + name: { type: String ,value: null }, /** * The function schema. */ - schema: - { + schema: { type: String ,value: null }, /** * The function parameters. */ - params: - { + params: { type: Array - ,set: function (x) - { + ,set: function(x) { this.list = x; } - ,get: function () - { + ,get: function() { return this.list; } } } - ,render: function (params) - { - return this.renderPreIdent (this.schema) - + this.renderIdent (this.name) + ,render: function(params) { + return this.renderPreIdent(this.schema) + + this.renderIdent(this.name) + '(' - + this.renderListWs (this.list, params, ', ') + + this.renderListWs(this.list, params, ', ') + ')'; } }); diff --git a/js/sql/holder.js b/js/sql/holder.js index 63288eab..67083cfa 100644 --- a/js/sql/holder.js +++ b/js/sql/holder.js @@ -1,38 +1,30 @@ -var SqlObject = require ('./object'); -var Value = require ('./value'); +var SqlObject = require('./object'); +var Value = require('./value'); /** * A holder for another object. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: SqlObject - ,Properties: - { - id: - { + ,Properties: { + id: { type: String ,value: null } } - ,render: function (params) - { - if (params) - { + ,render: function(params) { + if (params) { var object = params[this.id]; - if (object !== undefined) - { - if (!(object instanceof SqlObject)) - { - var sqlValue = new Value (); + if (object !== undefined) { + if (!(object instanceof SqlObject)) { + var sqlValue = new Value(); sqlValue.value = object; - return sqlValue.render (); - } - else - return object.render (params); + return sqlValue.render(); + } else + return object.render(params); } } diff --git a/js/sql/insert.js b/js/sql/insert.js index 0f6b46a9..6e6dd4c7 100644 --- a/js/sql/insert.js +++ b/js/sql/insert.js @@ -1,21 +1,19 @@ -var Dml = require ('./dml'); +var Dml = require('./dml'); /** * The equivalent of a SQL insert. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Dml - ,render: function (params) - { + ,render: function(params) { return 'INSERT INTO' - + this.renderTarget (params) + + this.renderTarget(params) + ' (' - + this.renderListWs (this.field, params, ', ') + + this.renderListWs(this.field, params, ', ') + ') VALUES (' - + this.renderListWs (this.expr, params, ', ') + + this.renderListWs(this.expr, params, ', ') + ')'; } }) diff --git a/js/sql/join-item.js b/js/sql/join-item.js index 8a765790..3e63cc9a 100644 --- a/js/sql/join-item.js +++ b/js/sql/join-item.js @@ -1,8 +1,8 @@ -var Target = require ('./target'); -var Expr = require ('./expr'); -var SqlObject = require ('./object'); -var Type = require ('./join').Type; +var Target = require('./target'); +var Expr = require('./expr'); +var SqlObject = require('./object'); +var Type = require('./join').Type; var TypeSql = [ 'INNER', @@ -13,42 +13,36 @@ var TypeSql = [ /** * The equivalent of a SQL join. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: SqlObject ,Tag: 'sql-join-table' - ,Properties: - { + ,Properties: { /** * The join type. */ - type: - { + type: { enumType: Type ,value: 0 }, /** * The right target. */ - target: - { + target: { type: Target ,value: null }, /** * The join on condition. */ - condition: - { + condition: { type: Expr ,value: null } } - ,render: function (params) - { + ,render: function(params) { return TypeSql[this.type] +' JOIN ' - + this.target.render (params) - + this.renderIfSet (this.condition, 'ON', params); + + this.target.render(params) + + this.renderIfSet(this.condition, 'ON', params); } }); diff --git a/js/sql/join.js b/js/sql/join.js index 40664d30..37fcb8c8 100644 --- a/js/sql/join.js +++ b/js/sql/join.js @@ -1,11 +1,11 @@ -var Target = require ('./target'); -var ListHolder = require ('./list-holder'); +var Target = require('./target'); +var ListHolder = require('./list-holder'); /** * The equivalent of a SQL join. */ -var Klass = new Class (); +var Klass = new Class(); module.exports = Klass; var Type = { @@ -14,41 +14,34 @@ var Type = { RIGHT : 2 }; -Klass.extend -({ +Klass.extend({ Type: Type }); -Klass.implement -({ +Klass.implement({ Extends: Target ,Implements: ListHolder ,Tag: 'sql-join' - ,Properties: - { + ,Properties: { /** * The right targets. */ - targets: - { + targets: { type: Array - ,set: function (x) - { + ,set: function(x) { this.list = x; } - ,get: function () - { + ,get: function() { return this.list; } } } - ,render: function (params) - { + ,render: function(params) { return '(' - + this.target.render (params) + + this.target.render(params) + ' ' - + this.renderList (this.list, params) + + this.renderList(this.list, params) + ')'; } }); diff --git a/js/sql/list-holder.js b/js/sql/list-holder.js index 4e42825f..470ee8bb 100644 --- a/js/sql/list-holder.js +++ b/js/sql/list-holder.js @@ -1,20 +1,14 @@ /** * Interface for array holders. */ -module.exports = new Class -({ - Properties: - { -/* - list: - { +module.exports = new Class({ + Properties: { +/* list: { type: Array - ,set: function (x) - { + ,set: function (x) { this._list = x; } - ,get: function () - { + ,get: function () { return this._list; } } @@ -23,9 +17,8 @@ module.exports = new Class ,list: [] - ,appendChild: function (child) - { - this.list.push (child); + ,appendChild: function(child) { + this.list.push(child); } /** @@ -33,9 +26,8 @@ module.exports = new Class * * @param {SqlObject} element The element to add */ - ,push: function (element) - { - this.list.push (element); + ,push: function(element) { + this.list.push(element); } /** @@ -43,9 +35,8 @@ module.exports = new Class * * @param {Number} i The element index */ - ,splice: function (i) - { - this.list.splice (i); + ,splice: function(i) { + this.list.splice(i); } /** @@ -53,8 +44,18 @@ module.exports = new Class * * @param {Number} i The element index */ - ,get: function (i) - { + ,get: function(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; + } }); diff --git a/js/sql/list.js b/js/sql/list.js index 00af5453..1f539f4a 100644 --- a/js/sql/list.js +++ b/js/sql/list.js @@ -1,69 +1,71 @@ -var Object = require ('./object'); +var Object = require('./object'); /** * List of Sql.Object */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Object ,objects: [] - ,add: function (object) - { - this.objects.push (object.ref ()); - object.on ('changed', this._onObjectChange, this); - this._onObjectChange (); + ,add: function(object) { + this.objects.push(object.ref()); + object.on('changed', this._onObjectChange, this); + this._onObjectChange(); } - ,get: function (i) - { + ,get: function(i) { return objects[i]; } - ,getArray: function () - { + ,getArray: function() { return this.objects; } - ,remove: function (i) - { - this._unrefObject (this.objects.splice (i, 1)); - this._onObjectChange (); + ,remove: function(i) { + this._unrefObject(this.objects.splice(i, 1)); + this._onObjectChange(); } - ,_onObjectChange: function () - { - this.emit ('changed'); + ,_onObjectChange: function() { + this.emit('changed'); } - ,isReady: function () - { + ,isReady: function() { var o = this.objects; if (o.length == 0) return false; for (var i = 0; i < o.length; i++) - if (!o[i].isReady ()) + if (!o[i].isReady()) return false; return true; } - - ,_unrefObject: function (object) - { - object.disconnect ('changed', this._onObjectChange, this); - object.unref (); + + ,findHolders() { + let ids = []; + + 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); + object.unref(); + } + + ,_destroy: function() { for (var i = 0; i < this.objects.length; i++) - this._unrefObject (this.objects[i]); + this._unrefObject(this.objects[i]); - this.parent (); + this.parent(); } }); diff --git a/js/sql/multi-stmt.js b/js/sql/multi-stmt.js index 67fcfe40..60504a28 100644 --- a/js/sql/multi-stmt.js +++ b/js/sql/multi-stmt.js @@ -1,36 +1,30 @@ -var Stmt = require ('./stmt'); -var ListHolder = require ('./list-holder'); +var Stmt = require('./stmt'); +var ListHolder = require('./list-holder'); /** * The equivalent of a SQL multi statement. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Stmt ,Implements: ListHolder ,Tag: 'sql-multi-stmt' - ,Properties: - { + ,Properties: { /** * The statements list. */ - stmts: - { + stmts: { type: Array - ,set: function (x) - { + ,set: function(x) { this.list = x; } - ,get: function () - { + ,get: function() { return this.list; } } } - ,render: function (params) - { - return this.renderListWs (this.list, params, ";\n"); + ,render: function(params) { + return this.renderListWs(this.list, params, ";\n"); } }); diff --git a/js/sql/operation.js b/js/sql/operation.js index 639ad3c6..9f491f4a 100644 --- a/js/sql/operation.js +++ b/js/sql/operation.js @@ -1,6 +1,6 @@ -var Expr = require ('./expr'); -var ListHolder = require ('./list-holder'); +var Expr = require('./expr'); +var ListHolder = require('./list-holder'); /** * 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 {Type} type The type of the operation */ -var Klass = new Class (); +var Klass = new Class(); module.exports = Klass; -var Type = -{ +var Type = { EQUAL : 0 ,LIKE : 1 ,AND : 2 @@ -30,8 +29,7 @@ var Type = ,MOD : 14 }; -var Operators = -[ +var Operators = [ '=' ,'LIKE' ,'AND' @@ -49,48 +47,39 @@ var Operators = ,'MOD' ]; -Klass.extend -({ +Klass.extend({ Type: Type ,Operators: Operators }); -Klass.implement -({ +Klass.implement({ Extends: Expr ,Implements: ListHolder ,Tag: 'sql-operation' - ,Properties: - { - type: - { + ,Properties: { + type: { enumType: Type ,value: -1 }, - target: - { + target: { type: String ,value: null }, - exprs: - { + exprs: { type: Array - ,set: function (x) - { + ,set: function(x) { this.list = x; } - ,get: function () - { + ,get: function() { return this.list; } } } - ,render: function (params) - { + ,render: function(params) { var operator = ' '+ Operators[this.type] +' '; return '(' - + this.renderListWs (this.list, params, operator) + + this.renderListWs(this.list, params, operator) + ')'; } }); diff --git a/js/sql/select.js b/js/sql/select.js index 958ae69a..12840246 100644 --- a/js/sql/select.js +++ b/js/sql/select.js @@ -1,28 +1,25 @@ -var Stmt = require ('./stmt'); -var Field = require ('./field'); +var Stmt = require('./stmt'); +var Field = require('./field'); /** * The equivalent of a SQL select. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Stmt ,expr: [] - ,addField: function (fieldName) - { - this.expr.push (new Field ({name: fieldName})); + ,addField: function(fieldName) { + this.expr.push(new Field({name: fieldName})); } - ,render: function (params) - { + ,render: function(params) { return 'SELECT ' - + this.renderListWs (this.expr, params, ', ') + + this.renderListWs(this.expr, params, ', ') + ' FROM' - + this.renderTarget (params) - + this.renderIfSet (this.where, 'WHERE', params) - + this.renderLimit (params); + + this.renderTarget(params) + + this.renderIfSet(this.where, 'WHERE', params) + + this.renderLimit(params); } }); diff --git a/js/sql/string.js b/js/sql/string.js index f95f3fbf..ed8989b4 100644 --- a/js/sql/string.js +++ b/js/sql/string.js @@ -1,18 +1,15 @@ -var Stmt = require ('./stmt'); -var Holder = require ('./holder'); +var Stmt = require('./stmt'); +var Holder = require('./holder'); /** * Literal SQL string. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Stmt ,Tag: 'sql-string' - ,Properties: - { - query: - { + ,Properties: { + query: { type: String ,value: null } @@ -20,33 +17,29 @@ module.exports = new Class ,regexp: /#\w+/g - ,appendChild: function (child) - { + ,appendChild: function(child) { if (child.nodeType === Node.TEXT_NODE) this.query = child.textContent; } - ,render: function (params) - { + ,render: function(params) { if (!this.query) return null; - function replaceFunc (token) - { - var holder = new Holder ({id: token.substr (1)}); - return holder.render (params); + function replaceFunc(token) { + var holder = new Holder({id: token.substr(1)}); + return holder.render(params); } - return this.query.replace (this.regexp, replaceFunc); + return this.query.replace(this.regexp, replaceFunc); } - ,findHolders: function () - { - var ids = this.query.match (this.regexp); + ,findHolders: function() { + var ids = this.query.match(this.regexp); if (ids) for (var i = 0; i < ids.length; i++) - ids[i] = ids[i].substr (1); + ids[i] = ids[i].substr(1); return ids; } diff --git a/js/sql/table.js b/js/sql/table.js index 578e5ea5..e97c8eec 100644 --- a/js/sql/table.js +++ b/js/sql/table.js @@ -1,38 +1,32 @@ -var Target = require ('./target'); +var Target = require('./target'); /** * Represents a database table. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Target - ,Properties: - { - name: - { + ,Properties: { + name: { type: String ,value: null }, - alias: - { + alias: { type: String ,value: null }, - schema: - { + schema: { type: String ,value: null } } - ,render: function () - { - var sql = this.renderPreIdent (this.schema) - + this.renderIdent (this.name); + ,render: function() { + var sql = this.renderPreIdent(this.schema) + + this.renderIdent(this.name); if (this.alias) - sql += ' AS '+ this.renderIdent (this.alias); + sql += ' AS '+ this.renderIdent(this.alias); return sql; } diff --git a/js/sql/target.js b/js/sql/target.js index 219e346d..bb19092c 100644 --- a/js/sql/target.js +++ b/js/sql/target.js @@ -1,10 +1,9 @@ -var Object = require ('./object'); +var Object = require('./object'); /** * The equivalent of a SQL target. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Object }); diff --git a/js/sql/update.js b/js/sql/update.js index 26594e71..8c91eab8 100644 --- a/js/sql/update.js +++ b/js/sql/update.js @@ -1,29 +1,27 @@ -var Dml = require ('./dml'); +var Dml = require('./dml'); /** * The equivalent of a SQL update. */ -module.exports = new Class -({ +module.exports = new Class({ Extends: Dml - ,render: function (params) - { + ,render: function(params) { var sql = 'UPDATE' - + this.renderTarget (params) + + this.renderTarget(params) + ' SET '; - this.field.forEach (function (field, i) { + this.field.forEach(function(field, i) { if (i > 0) sql += ', '; - sql += field.render (params) + sql += field.render(params) + ' = ' + this.expr[i].render(params); }, this); - sql += this.renderIfSet (this.where, 'WHERE', params) + sql += this.renderIfSet(this.where, 'WHERE', params) + this.renderLimit(params); return sql; }