From 546e67d6f69bf808cdc21804aa82bde42f3f77ee Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Tue, 24 May 2022 12:18:44 +0200 Subject: [PATCH] Checkpoint --- forms/account/address-list/address-list.js | 36 +- forms/account/address-list/locale/ca.yml | 1 + forms/account/address-list/locale/en.yml | 1 + forms/account/address-list/locale/es.yml | 1 + forms/account/address-list/locale/fr.yml | 1 + forms/account/address-list/locale/pt.yml | 1 + forms/account/address-list/style.css | 43 +- forms/account/address-list/ui.xml | 29 +- forms/cms/home/style.css | 6 +- forms/cms/home/ui.xml | 8 +- forms/ecomerce/basket/basket.js | 53 +- forms/ecomerce/basket/style.css | 73 +- forms/ecomerce/basket/ui.xml | 12 +- forms/ecomerce/catalog/catalog.js | 5 - forms/ecomerce/catalog/ui.xml | 32 +- forms/ecomerce/checkout/locale/ca.yml | 2 +- forms/ecomerce/checkout/locale/en.yml | 2 +- forms/ecomerce/checkout/locale/es.yml | 2 +- forms/ecomerce/checkout/locale/fr.yml | 2 +- forms/ecomerce/checkout/locale/pt.yml | 2 +- forms/ecomerce/checkout/style.css | 8 +- forms/ecomerce/checkout/ui.xml | 4 +- forms/ecomerce/orders/style.css | 48 +- forms/ecomerce/orders/ui.xml | 31 +- forms/ecomerce/ticket/locale/ca.yml | 2 + forms/ecomerce/ticket/locale/en.yml | 2 + forms/ecomerce/ticket/locale/es.yml | 2 + forms/ecomerce/ticket/locale/fr.yml | 2 + forms/ecomerce/ticket/locale/pt.yml | 2 + forms/ecomerce/ticket/style.css | 80 +-- forms/ecomerce/ticket/ui.xml | 5 +- forms/news/news/ui.xml | 11 +- js/db/iterator.js | 103 ++- js/db/model.js | 796 +++++++++------------ js/db/result-set.js | 19 +- js/db/simple-iterator.js | 50 +- js/hedera/form.js | 90 ++- js/hedera/gui.scss | 52 +- js/hedera/opensans.ttf | Bin 0 -> 129796 bytes js/hedera/style.scss | 17 +- js/htk/field/bar-button.js | 3 +- js/htk/field/button.js | 11 +- js/htk/field/calendar.js | 22 +- js/htk/field/html.js | 8 +- js/htk/htk.js | 3 +- js/htk/icon.js | 2 +- js/htk/repeater.js | 4 +- js/htk/style/classes.scss | 20 + js/htk/{style.scss => style/main.scss} | 223 ++++-- js/htk/style/variables.scss | 2 + js/vn/builder.js | 513 ++++++------- js/vn/date.js | 2 +- js/vn/locale/ca.yml | 1 + js/vn/locale/en.yml | 1 + js/vn/locale/es.yml | 3 +- js/vn/locale/fr.yml | 1 + js/vn/locale/mn.yml | 1 + js/vn/locale/pt.yml | 1 + 58 files changed, 1176 insertions(+), 1281 deletions(-) create mode 100644 js/hedera/opensans.ttf create mode 100644 js/htk/style/classes.scss rename js/htk/{style.scss => style/main.scss} (78%) create mode 100644 js/htk/style/variables.scss diff --git a/forms/account/address-list/address-list.js b/forms/account/address-list/address-list.js index 527cc6da..1be4719e 100644 --- a/forms/account/address-list/address-list.js +++ b/forms/account/address-list/address-list.js @@ -3,39 +3,37 @@ Hedera.AddressList = new Class ({ Extends: Hedera.Form - ,activate: function () - { - this.$('user-model').setInfo ('c', 'myClient', 'hedera'); - this.$('addresses').setInfo ('a', 'myAddress', 'hedera'); + ,activate: function() { + this.$('user-model').setInfo('c', 'myClient', 'hedera'); + this.$('addresses').setInfo('a', 'myAddress', 'hedera'); } - ,onAddAddressClick: function () - { - this.hash.set ({ + ,onAddAddressClick: function() { + this.hash.set({ form: 'account/address', address: 0 }); } - ,onReturnClick: function () - { + ,onReturnClick: function() { window.history.back(); } + + ,onSetDefaultClick: function() { + Htk.Toast.showMessage(_('DefaultAddressModified')); + } - ,onRemoveAddressClick: function (button, form) - { - if (confirm (_('AreYouSureDeleteAddress'))) - { - form.set ('isActive', false); - form.refresh (); + ,onRemoveAddressClick: function(button, form) { + if (confirm(_('AreYouSureDeleteAddress'))) { + form.set('isActive', false); + form.refresh(); } } - ,onEditAddressClick: function (button, form) - { - this.hash.set ({ + ,onEditAddressClick: function(button, form) { + this.hash.set({ form: 'account/address', - address: form.get ('id') + address: form.get('id') }); } }); diff --git a/forms/account/address-list/locale/ca.yml b/forms/account/address-list/locale/ca.yml index cf541723..cf957550 100644 --- a/forms/account/address-list/locale/ca.yml +++ b/forms/account/address-list/locale/ca.yml @@ -5,3 +5,4 @@ SetAsDefault: Establir com per defecte RemoveAddress: Esborrar direcció EditAddress: Modificar direcció AreYouSureDeleteAddress: Estàs segur de que vols eliminar la direcció? +DefaultAddressModified: Adreça per defecte modificada diff --git a/forms/account/address-list/locale/en.yml b/forms/account/address-list/locale/en.yml index df5b564f..75bdb2ac 100644 --- a/forms/account/address-list/locale/en.yml +++ b/forms/account/address-list/locale/en.yml @@ -5,3 +5,4 @@ SetAsDefault: Set as default RemoveAddress: Remove address EditAddress: Edit address AreYouSureDeleteAddress: Are you sure you want to delete the address? +DefaultAddressModified: Default address modified diff --git a/forms/account/address-list/locale/es.yml b/forms/account/address-list/locale/es.yml index 66c4576d..50a29c77 100644 --- a/forms/account/address-list/locale/es.yml +++ b/forms/account/address-list/locale/es.yml @@ -5,3 +5,4 @@ SetAsDefault: Establecer como predeterminada RemoveAddress: Borrar dirección EditAddress: Modificar dirección AreYouSureDeleteAddress: ¿Estás seguro de que quieres borrar la dirección? +DefaultAddressModified: Dirección por defecto modificada diff --git a/forms/account/address-list/locale/fr.yml b/forms/account/address-list/locale/fr.yml index 9126d4fb..8530ec22 100644 --- a/forms/account/address-list/locale/fr.yml +++ b/forms/account/address-list/locale/fr.yml @@ -5,3 +5,4 @@ SetAsDefault: Définir par défaut RemoveAddress: Supprimer l'adresse EditAddress: Changement d'adresse AreYouSureDeleteAddress: Souhaitez-vous vraiment supprier l'adresse? +DefaultAddressModified: Adresse par défaut modifiée diff --git a/forms/account/address-list/locale/pt.yml b/forms/account/address-list/locale/pt.yml index 4f5fd79a..7657ab26 100644 --- a/forms/account/address-list/locale/pt.yml +++ b/forms/account/address-list/locale/pt.yml @@ -5,3 +5,4 @@ SetAsDefault: Selecionar como pre-determinado RemoveAddress: Eliminar Morada EditAddress: Modificar Morada AreYouSureDeleteAddress: Tens certeza que queres eliminar esta morada? +DefaultAddressModified: Endereço padrão modificado diff --git a/forms/account/address-list/style.css b/forms/account/address-list/style.css index 8bd9a259..661afa20 100644 --- a/forms/account/address-list/style.css +++ b/forms/account/address-list/style.css @@ -1,48 +1,15 @@ -.address-list -{ +.address-list { padding: 1em; } -.address-list .box -{ +.address-list .box { max-width: 30em; } -.address-list .form -{ +.address-list .form { margin: 0 auto; max-width: 25em; padding: 2em; } -.address -{ - padding: 1em; - border-bottom: 1px solid #DDD; -} -.address p -{ - margin: 0.2em 0; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} -.address p.important -{ - font-size: 1.2em; -} -.address .actions -{ - float: right; -} -.address .actions > .htk-button -{ - margin: 0; -} -.address .actions > * -{ - display: inline-block; - vertical-align: middle; -} -.address .actions > input -{ - margin: .6em; +.address-list .htk-list .side { + padding-right: 16px; } diff --git a/forms/account/address-list/ui.xml b/forms/account/address-list/ui.xml index f43d945a..e113593b 100644 --- a/forms/account/address-list/ui.xml +++ b/forms/account/address-list/ui.xml @@ -33,15 +33,28 @@ id="default-address" column="defaultAddressFk" form="user-form"/> - + -
-
+
+
+
+
+

+ {{iter.nickname}} +

+

+ {{iter.street}} +

+

+ {{iter.postalCode}}, {{iter.city}} +

+
+
-

- -

-

- -

-

- , - -

diff --git a/forms/cms/home/style.css b/forms/cms/home/style.css index 5f35e4f3..cabc2689 100644 --- a/forms/cms/home/style.css +++ b/forms/cms/home/style.css @@ -43,9 +43,13 @@ } .new-text { margin: 1.5em 0; + font-family: 'Open Sans'; + line-height: 1.3em; } .new-text a { - color: blue; + color: #6a1; +} +.new-text a:hover { text-decoration: underline; } .new-text li { diff --git a/forms/cms/home/ui.xml b/forms/cms/home/ui.xml index d4bc7d88..2ec3e7c2 100644 --- a/forms/cms/home/ui.xml +++ b/forms/cms/home/ui.xml @@ -11,7 +11,7 @@
- + SELECT title, text, image, id FROM news @@ -25,14 +25,14 @@
-

+

{{iter.title}}

- +
diff --git a/forms/ecomerce/basket/basket.js b/forms/ecomerce/basket/basket.js index 2f1239ac..a4366e6a 100644 --- a/forms/ecomerce/basket/basket.js +++ b/forms/ecomerce/basket/basket.js @@ -3,56 +3,43 @@ Hedera.Basket = new Class ({ Extends: Hedera.Form - ,open: function () - { - this.close (); + ,open: function() { + this.close(); this.isOpen = true; - Hedera.BasketChecker.check (this.conn, - this.onBasketCheck.bind (this)); + Hedera.BasketChecker.check(this.conn, + this.onBasketCheck.bind(this)); } - ,onBasketCheck: function (isOk) - { + ,onBasketCheck: function(isOk) { if (isOk) - this.loadUi (); + this.loadUi(); } - ,activate: function () - { - this.$('items').setInfo ('bi', 'myBasketItem', 'hedera'); + ,activate: function() { + this.$('items').setInfo('bi', 'myBasketItem', 'hedera'); } - ,onConfigureClick: function () - { - Htk.Toast.showWarning (_('RememberReconfiguringImpact')); - this.hash.set ({form: 'ecomerce/checkout'}); + ,onConfigureClick: function() { + Htk.Toast.showWarning(_('RememberReconfiguringImpact')); + this.hash.set({form: 'ecomerce/checkout'}); } - ,onCatalogClick: function () - { - this.hash.set ({form: 'ecomerce/catalog'}); + ,onCatalogClick: function() { + this.hash.set({form: 'ecomerce/catalog'}); } - ,onCheckoutClick: function () - { - this.hash.set ({form: 'ecomerce/confirm'}); + ,onCheckoutClick: function() { + this.hash.set({form: 'ecomerce/confirm'}); } - ,repeaterFunc: function (res, form) - { - res.$('subtotal').value = this.subtotal (form); + ,onDeleteClick: function(button, form) { + if (confirm(_('ReallyDelete'))) + form.deleteRow(); } - ,onDeleteClick: function (button, form) - { - if (confirm (_('ReallyDelete'))) - form.deleteRow (); - } - - ,subtotal: function (form) - { - return form.get ('amount') * form.get ('price'); + ,subtotal: function(form) { + return form.get('amount') * form.get('price'); } }); diff --git a/forms/ecomerce/basket/style.css b/forms/ecomerce/basket/style.css index 2b0d1889..09abc932 100644 --- a/forms/ecomerce/basket/style.css +++ b/forms/ecomerce/basket/style.css @@ -1,28 +1,24 @@ -.basket -{ +.basket { padding: 1em; } -.basket .box -{ +.basket .box { max-width: 30em; margin: 0 auto; - padding: 0 2em; + padding: 30px; } -.basket .form > p -{ +.basket .form > p { margin: 0; font-size: 1.4em; color: white; text-align: right; } -.basket .head -{ - padding: 1.8em 0; +.basket .head { + padding-bottom: 30px; margin: 0; border-bottom: 1px solid #DDD; } -.basket .head p -{ +.basket .head p { + font-weight: bold; margin: 0; padding: 0; font-size: 1.4em; @@ -31,61 +27,48 @@ /* Lines */ -.basket .lines -{ - padding: .8em 0; +.basket .line { + display: flex; + gap: 20px; + margin: 24px 0; + height: 65px; } -.basket .line -{ - padding: 1em 0; +.basket .line:last-child { + margin-bottom: 0; } -.basket .line > .delete -{ - margin: -0.5em; - margin-top: 1em; - margin-right: .5em; - float: left; +.basket .line > .delete { + align-self: center; } -.basket .line > .photo -{ - margin-right: 1em; - float: left; +.basket .line > .photo { + flex: none; border-radius: 50%; - height: 4.25em; - width: 4.25em; + width: 65px; } -.basket .line > .info -{ - margin-left: 7.5em; +.basket .line > .info { + flex: 1; } -.basket .line > .info > h2 -{ +.basket .line > .info > h2 { font-size: 1em; font-weight: normal; padding: 0; padding-bottom: .1em; } -.basket .line > .info > p -{ +.basket .line > .info > p { margin: 0; } -.basket .line > .info > .tags -{ +.basket .line > .info > .tags { color: #777; } -.basket .line .subtotal -{ +.basket .line .subtotal { float: right; } /* Fields */ -.basket td.available-exceeded input -{ +.basket td.available-exceeded input { background-color: #FCC; } -.basket .icon > img -{ +.basket .icon > img { border-radius: 50%; } diff --git a/forms/ecomerce/basket/ui.xml b/forms/ecomerce/basket/ui.xml index 62b7b39b..a9de28ac 100644 --- a/forms/ecomerce/basket/ui.xml +++ b/forms/ecomerce/basket/ui.xml @@ -27,7 +27,7 @@

- + SELECT bi.id, bi.amount, bi.price, i.longName item, i.tag5, i.value5, i.tag6, i.value6, i.tag7, i.value7, @@ -60,19 +60,15 @@

- - - + {{iter.value5}} {{iter.value6}} {{iter.value7}}

- x - + {{iter.amount}} x {{Vn.Value.format(iter.price, '%.2d€')}} - + {{Vn.Value.format(iter.price * iter.amount, '%.2d€')}}

-
diff --git a/forms/ecomerce/catalog/catalog.js b/forms/ecomerce/catalog/catalog.js index d34903e9..048706c5 100644 --- a/forms/ecomerce/catalog/catalog.js +++ b/forms/ecomerce/catalog/catalog.js @@ -103,11 +103,6 @@ Hedera.Catalog = new Class({ 'form': this.hash.get('form'), 'realm': form.get('id') }); - - var img = builder.$('image'); - img.src = 'image/family/black/'+ form.get('code') +'.svg'; - img.title = form.get('name'); - img.alt = img.title; } ,onRealmChange: function(param, newValue) { diff --git a/forms/ecomerce/catalog/ui.xml b/forms/ecomerce/catalog/ui.xml index 35a38fe8..dfb992f3 100644 --- a/forms/ecomerce/catalog/ui.xml +++ b/forms/ecomerce/catalog/ui.xml @@ -121,7 +121,7 @@
+ title="{{_('AddToBasket')}}">

- + {{item.item}}

- + {{item.subName}}

- - + + - - + + - - + +
{{item.tag5}}{{item.value5}}
{{item.tag6}}{{item.value6}}
{{item.tag7}}{{item.value7}}
- + {{Vn.Value.format(item.grouping, 'x%.0d')}} - + {{item.available}} - + {{Vn.Value.format(item.price, 'x%.0d')}}
@@ -185,7 +185,7 @@
- + {{form.name}} diff --git a/forms/ecomerce/checkout/locale/ca.yml b/forms/ecomerce/checkout/locale/ca.yml index 5846dff5..41a84a8f 100644 --- a/forms/ecomerce/checkout/locale/ca.yml +++ b/forms/ecomerce/checkout/locale/ca.yml @@ -11,7 +11,7 @@ AddressQuestion: On vols rebre la comanda? AddressQuestionPickup: A què direcció vols associar la comanda? (Opcional) AgencyQuestion: Com vols rebre la comanda? PickupWarehouseQuestion: En quin magatzem vols recollir la comanda? -ConfirmToAccessCatalog: Confirma les dades per accedir al catàleg +ConfirmData: Confirma les dades Arrival: Arribada Pickup: Recollida Agency: Agència diff --git a/forms/ecomerce/checkout/locale/en.yml b/forms/ecomerce/checkout/locale/en.yml index 45a54a7b..c9c94c90 100644 --- a/forms/ecomerce/checkout/locale/en.yml +++ b/forms/ecomerce/checkout/locale/en.yml @@ -11,7 +11,7 @@ AddressQuestion: Where do you want to receive the order? AddressQuestionPickup: To which address do you want to associate the order? (Optional) AgencyQuestion: How you want to receive the order? PickupWarehouseQuestion: What store you want to pickup your order? -ConfirmToAccessCatalog: Confirm the data to access the catalog +ConfirmData: Confirm the data Arrival: Arrival Pickup: Pickup Agency: Agency diff --git a/forms/ecomerce/checkout/locale/es.yml b/forms/ecomerce/checkout/locale/es.yml index a699f3e0..b2276376 100644 --- a/forms/ecomerce/checkout/locale/es.yml +++ b/forms/ecomerce/checkout/locale/es.yml @@ -11,7 +11,7 @@ AddressQuestion: ¿Dónde quieres recibir el pedido? AddressQuestionPickup: ¿A qué dirección quieres asociar el pedido? (Opcional) AgencyQuestion: ¿Cómo quieres recibir el pedido? PickupWarehouseQuestion: ¿En qué almacén quieres recoger el pedido? -ConfirmToAccessCatalog: Confirma los datos para acceder al catálogo +ConfirmData: Confirma los datos Arrival: Llegada Pickup: Recogida Agency: Agencia diff --git a/forms/ecomerce/checkout/locale/fr.yml b/forms/ecomerce/checkout/locale/fr.yml index 5a04e06a..53166061 100644 --- a/forms/ecomerce/checkout/locale/fr.yml +++ b/forms/ecomerce/checkout/locale/fr.yml @@ -11,7 +11,7 @@ AddressQuestion: Adresse livraison? AddressQuestionPickup: À quelle adresse voulez-vous associer la commande? (Optionnel) AgencyQuestion: Agence de livraison PickupWarehouseQuestion: Dans quel magasin vuoulez-vous retirer votre commande? -ConfirmToAccessCatalog: Confirmez les coordonnées pour accéder au catalogue +ConfirmData: Confirmez les coordonnées Arrival: Arrivée Pickup: Retrait Agency: Agence diff --git a/forms/ecomerce/checkout/locale/pt.yml b/forms/ecomerce/checkout/locale/pt.yml index aa4b59e2..c6f76484 100644 --- a/forms/ecomerce/checkout/locale/pt.yml +++ b/forms/ecomerce/checkout/locale/pt.yml @@ -11,7 +11,7 @@ AddressQuestion: Onde queres receber a encomenda? AddressQuestionPickup: Para qual endereço deseja associar o pedido? (Opcional) AgencyQuestion: Como queres receber a encomenda? PickupWarehouseQuestion: Em qual armazém queres levantar a encomenda? -ConfirmToAccessCatalog: Confirme os dados para entrar no catálogo +ConfirmData: Confirme os dados Arrival: Chegada Pickup: Recolhida Agency: Agência diff --git a/forms/ecomerce/checkout/style.css b/forms/ecomerce/checkout/style.css index 7f928f4d..01e75703 100644 --- a/forms/ecomerce/checkout/style.css +++ b/forms/ecomerce/checkout/style.css @@ -16,7 +16,7 @@ .answers button, .answers p, .radio > div { - font-size: 1.4em; + font-size: 1.2em; } .answers .htk-select { max-width: 10em; @@ -54,13 +54,9 @@ padding: 0.5em; } .thin-calendar { - width: inherit; max-width: 24em; margin: 0 auto; - box-shadow: .05em .05em .2em rgba(0, 0, 0, .2); -} -.thin-calendar tr > th { - color: white; + box-shadow: none; } .htk-assistant .thin { float: right; diff --git a/forms/ecomerce/checkout/ui.xml b/forms/ecomerce/checkout/ui.xml index 47100763..69eecd9a 100644 --- a/forms/ecomerce/checkout/ui.xml +++ b/forms/ecomerce/checkout/ui.xml @@ -174,7 +174,7 @@ -

ConfirmToAccessCatalog

+

ConfirmData

Arrival @@ -192,7 +192,7 @@ -

ConfirmToAccessCatalog

+

ConfirmData

Pickup diff --git a/forms/ecomerce/orders/style.css b/forms/ecomerce/orders/style.css index 01d9ef4f..3dd75dbb 100644 --- a/forms/ecomerce/orders/style.css +++ b/forms/ecomerce/orders/style.css @@ -1,72 +1,44 @@ -.orders -{ +.orders { padding: 1em; } -.orders .box -{ +.orders .box { max-width: 25em; } /* Balance */ -.balance -{ +.balance { margin-right: .5em; } -.balance > * -{ +.balance > * { vertical-align: middle; } -.balance > .amount -{ +.balance > .amount { color: white; padding: 0.3em; } -.balance > .info -{ +.balance > .info { display: inline; cursor: pointer; height: 1.2em; cursor: pointer; } -.balance > .negative -{ +.balance > .negative { background-color: #EF5350; border-radius: 0.1em; box-shadow: 0 0 0.4em #666; } -.balance-popup -{ +.balance-popup { width: 25em; } -.balance-grid -{ +.balance-grid { width: 100%; margin: auto; } /* List */ -.orders .item -{ - display: block; - padding: 1em; - border-bottom: 1px solid #DDD; -} -.orders .item:hover -{ - background-color: rgba(1, 1, 1, 0.05); -} -.orders .item > p -{ - margin: .1em 0; -} -.orders .item > p.important -{ - font-size: 1.2em; -} -.orders .item > p.total -{ +.orders .htk-list .total { float: right; } diff --git a/forms/ecomerce/orders/ui.xml b/forms/ecomerce/orders/ui.xml index 8cf4a6bc..9f52ef70 100644 --- a/forms/ecomerce/orders/ui.xml +++ b/forms/ecomerce/orders/ui.xml @@ -39,30 +39,25 @@

- + CALL myTicket_list (NULL, NULL); - -

- -

-

- -

-

- # -

-

- -

-

- -

-
+ +
+

+ {{Vn.Value.format(iter.total, '%.2d€')}} +

+

+ {{Vn.Value.format(iter.landed, '%D')}} +

+

#{{iter.id}}

+

{{iter.nickname}}

+

{{iter.agency}}

+
diff --git a/forms/ecomerce/ticket/locale/ca.yml b/forms/ecomerce/ticket/locale/ca.yml index c0141846..680bc6d6 100644 --- a/forms/ecomerce/ticket/locale/ca.yml +++ b/forms/ecomerce/ticket/locale/ca.yml @@ -1,4 +1,6 @@ OrderDetail: Detall de l'encarrec +ShippingInformation: Dades d'enviament +DeliveryAddress: Adreça de lliurament Print delivery note: Imprimir albarà Agency: Agència Warehouse: Magatzem diff --git a/forms/ecomerce/ticket/locale/en.yml b/forms/ecomerce/ticket/locale/en.yml index 01412c9e..ae229f20 100644 --- a/forms/ecomerce/ticket/locale/en.yml +++ b/forms/ecomerce/ticket/locale/en.yml @@ -1,4 +1,6 @@ OrderDetail: Order detail +ShippingInformation: Shipping information +DeliveryAddress: Delivery address Print delivery note: Print delivery note Agency: Agency Warehouse: Store diff --git a/forms/ecomerce/ticket/locale/es.yml b/forms/ecomerce/ticket/locale/es.yml index 627786d3..f798dc7e 100644 --- a/forms/ecomerce/ticket/locale/es.yml +++ b/forms/ecomerce/ticket/locale/es.yml @@ -1,4 +1,6 @@ OrderDetail: Detalle del pedido +ShippingInformation: Datos de envío +DeliveryAddress: Dirección de entrega Print delivery note: Imprimir albarán Agency: Agencia Warehouse: Almacén diff --git a/forms/ecomerce/ticket/locale/fr.yml b/forms/ecomerce/ticket/locale/fr.yml index 6345329e..74cc068a 100644 --- a/forms/ecomerce/ticket/locale/fr.yml +++ b/forms/ecomerce/ticket/locale/fr.yml @@ -1,4 +1,6 @@ OrderDetail: Détails de la commande +ShippingInformation: Informations sur la livraison +DeliveryAddress: Addresse de livraison Print delivery note: Imprimer bulletin de livraison Agency: Agence Warehouse: Entrepôt diff --git a/forms/ecomerce/ticket/locale/pt.yml b/forms/ecomerce/ticket/locale/pt.yml index 2399b4fb..64bca977 100644 --- a/forms/ecomerce/ticket/locale/pt.yml +++ b/forms/ecomerce/ticket/locale/pt.yml @@ -1,4 +1,6 @@ OrderDetail: Detalhes da encomenda +ShippingInformation: Dados de envio +DeliveryAddress: Endereço de entrega Print delivery note: Imprimir nota de entrega Agency: Agência Warehouse: Armazém diff --git a/forms/ecomerce/ticket/style.css b/forms/ecomerce/ticket/style.css index 9fecbb6f..695c24e5 100644 --- a/forms/ecomerce/ticket/style.css +++ b/forms/ecomerce/ticket/style.css @@ -1,9 +1,7 @@ -.ticket -{ +.ticket { padding: 1em; } -.ticket .box -{ +.ticket .box { max-width: 30em; margin: 0 auto; padding: 2em; @@ -12,36 +10,29 @@ /* Header */ -.ticket .head -{ +.ticket .head { padding: 0; padding-bottom: .2em; border-bottom: 1px solid #DDD; margin-bottom: 1em; } -.ticket .address, -.ticket .total -{ - margin-top: .8em; +.ticket .head > div > div { + margin: 15px 0; } -.ticket .head > div -{ - padding-bottom: .8em; +.ticket .head > div > div:first-child { + margin: 0; } -.ticket .head p -{ - margin: .2em; +.ticket .head p { + margin: .2em 0; } -.ticket .head p.important -{ - font-size: 1.4em; +.ticket .head p.important { + font-size: 1.2rem; + font-weight: bold; } -.ticket .total -{ +.ticket .total { text-align: right; } -.ticket .packages -{ +.ticket .packages { margin-top: 1em; padding-top: 1em; border-top: 1px solid #DDD; @@ -50,47 +41,42 @@ /* Lines */ -.ticket .line -{ - padding: .5em 0; +.ticket .line { + display: flex; + gap: 20px; + margin: 24px 0; + height: 65px; } -.ticket .line > .photo -{ - margin-right: 1em; - float: left; +.ticket .line:last-child { + margin-bottom: 0; +} +.ticket .line > .photo { + flex: none; border-radius: 50%; - height: 4.25em; - width: 4.25em; + width: 65px; } -.ticket .line > .info -{ - margin-left: 5.25em; +.ticket .line > .info { + flex: 1; } -.ticket .line > .info > h2 -{ +.ticket .line > .info > h2 { font-size: 1em; font-weight: normal; padding: 0; padding-bottom: .1em; } -.ticket .line > .info > p -{ +.ticket .line > .info > p { margin: 0; } -.ticket .line > .info > .tags -{ +.ticket .line > .info > .tags { color: #777; } -.ticket .line > .info .discount -{ +.ticket .line > .info .discount { color: green; } -.ticket .line > .info > .amount -{ +.ticket .line > .info > .amount { float: left; } -.ticket .line > .info > .subtotal -{ +.ticket .line > .info > .subtotal { float: right; } diff --git a/forms/ecomerce/ticket/ui.xml b/forms/ecomerce/ticket/ui.xml index c14ff6fa..9f986f6c 100644 --- a/forms/ecomerce/ticket/ui.xml +++ b/forms/ecomerce/ticket/ui.xml @@ -29,6 +29,9 @@

#

+
+
+

ShippingInformation

Preparation

@@ -40,6 +43,7 @@

+

DeliveryAddress

@@ -101,7 +105,6 @@

-
diff --git a/forms/news/news/ui.xml b/forms/news/news/ui.xml index 0cde1a0a..9e8f7109 100644 --- a/forms/news/news/ui.xml +++ b/forms/news/news/ui.xml @@ -43,15 +43,10 @@ editable="true" conn="conn"/>

- -

-

- -

-

- Priority - + {{iter.title}}

+

{{iter.nickname}}

+

{{iter.priority}}

diff --git a/js/db/iterator.js b/js/db/iterator.js index 346f4d7e..c69d6b48 100644 --- a/js/db/iterator.js +++ b/js/db/iterator.js @@ -1,36 +1,30 @@ -var Model = require ('./model'); +var Model = require('./model'); -module.exports = new Class -({ - Properties: - { +module.exports = new Class({ + Properties: { /** * The model associated to this form. - **/ - model: - { + */ + model: { type: Model }, /** * The row where the form positioned, has -1 if the row is unselected. - **/ - row: - { + */ + row: { type: Number }, /** * The number of rows in the form. - **/ - numRows: - { + */ + numRows: { type: Number }, /** * Checks if the form data is ready. - **/ - ready: - { + */ + ready: { type: Boolean } } @@ -38,18 +32,16 @@ module.exports = new Class ,_model: null ,_row: -1 - ,refresh: function () - { + ,refresh: function() { if (this._model) - this._model.refresh (); + this._model.refresh(); } /** * Emits the 'iter-changed' signal on the form. - **/ - ,iterChanged: function () - { - this.signalEmit ('iter-changed'); + */ + ,iterChanged: function() { + this.signalEmit('iter-changed'); } /** @@ -57,45 +49,49 @@ module.exports = new Class * * @param {String} columnName The column name * @return {integer} The column index or -1 if column not exists - **/ - ,getColumnIndex: function (columnName) - { + */ + ,getColumnIndex: function(columnName) { if (this._model) - return this._model.getColumnIndex (columnName); + return this._model.getColumnIndex(columnName); return -1; } - ,insertRow: function () - { + ,insertRow: function() { if (this._model) - this.row = this._model.insertRow (); + this.row = this._model.insertRow(); } - ,performOperations: function () - { + ,performOperations: function() { if (this._model) - this._model.performOperations (); + this._model.performOperations(); } /** * Removes the current row. - **/ - ,deleteRow: function () - { + */ + ,deleteRow: function() { if (this._row >= 0) - this._model.deleteRow (this._row); + this._model.deleteRow(this._row); } - + + /** + * Gets the row as object. + * + * @return {Object} The row + */ + ,getObject: function() { + return this._model.getObject(this._row); + } + /** * Gets a value from the form. * * @param {String} columnName The column name * @return {Object} The value - **/ - ,get: function (columnName) - { - return this._model.get (this._row, columnName); + */ + ,get: function(columnName) { + return this._model.get(this._row, columnName); } /** @@ -103,10 +99,9 @@ module.exports = new Class * * @param {String} columnName The column name * @param {Object} value The new value - **/ - ,set: function (columnName, value) - { - return this._model.set (this._row, columnName, value); + */ + ,set: function(columnName, value) { + return this._model.set(this._row, columnName, value); } /** @@ -114,10 +109,9 @@ module.exports = new Class * * @param {String} columnName The column index * @return {Object} The value - **/ - ,getByIndex: function (column) - { - return this._model.getByIndex (this._row, column); + */ + ,getByIndex: function(column) { + return this._model.getByIndex(this._row, column); } /** @@ -125,10 +119,9 @@ module.exports = new Class * * @param {String} columnName The column index * @param {Object} value The new value - **/ - ,setByIndex: function (column, value) - { - return this._model.setByIndex (this._row, column, value); + */ + ,setByIndex: function(column, value) { + return this._model.setByIndex(this._row, column, value); } }); diff --git a/js/db/model.js b/js/db/model.js index 469140d7..e8b67ef3 100644 --- a/js/db/model.js +++ b/js/db/model.js @@ -1,5 +1,5 @@ -var Connection = require ('./connection'); +var Connection = require('./connection'); /** * Class to handle the Database select results. Also allows @@ -9,174 +9,152 @@ var Connection = require ('./connection'); * Note that table and column names must be unique in the selection query, * otherwise updates are not allowed on that table/column. If two tables or * columns have the same name, an alias should be used to make it updatable. - **/ -var Model = new Class (); + */ +var Model = new Class(); module.exports = Model; -var Status = -{ +var Status = { CLEAN : 1 ,LOADING : 2 ,READY : 3 ,ERROR : 4 }; -var Mode = -{ +var Mode = { ON_CHANGE : 1 ,ON_DEMAND : 2 }; -var Operation = -{ +var Operation = { INSERT : 1 << 1 ,UPDATE : 1 << 2 ,DELETE : 1 << 3 }; -var SortWay = -{ +var SortWay = { ASC : 1 ,DESC : 2 }; -Model.extend -({ +Model.extend({ Status: Status ,Mode: Mode ,Operation: Operation ,SortWay: SortWay }); -Model.implement -({ +Model.implement({ Extends: Vn.Object ,Tag: 'db-model' - ,Properties: - { + ,Properties: { /** * The connection used to execute the statement. - **/ + */ conn: { type: Connection - ,set: function (x) - { + ,set: function(x) { this._conn = x; - this._autoLoad (); + this._autoLoad(); } - ,get: function () - { + ,get: function() { return this._conn; } }, /** * The result index. - **/ + */ resultIndex: { type: Number - ,set: function (x) - { + ,set: function(x) { this._resultIndex = x; } - ,get: function () - { + ,get: function() { return this._resultIndex; } }, /** * The batch used to execute the statement. - **/ + */ batch: { type: Sql.Batch - ,set: function (x) - { - this.link ({_batch: x}, {'changed': this._autoLoad}); - this._autoLoad (); + ,set: function(x) { + this.link({_batch: x}, {'changed': this._autoLoad}); + this._autoLoad(); } - ,get: function () - { + ,get: function() { return this._batch; } }, /** * The model select statement. - **/ + */ stmt: { type: Sql.Stmt - ,set: function (x) - { + ,set: function(x) { this._stmt = x; - this._autoLoad (); + this._autoLoad(); } - ,get: function () - { + ,get: function() { return this._stmt; } }, /** * The model query. - **/ + */ query: { type: String - ,set: function (x) - { - this.stmt = new Sql.String ({query: x}); + ,set: function(x) { + this.stmt = new Sql.String({query: x}); } - ,get: function () - { + ,get: function() { if (this._stmt) - return this._stmt.render (null); + return this._stmt.render(null); else return null; } }, /** * The main table. - **/ + */ mainTable: { type: String - ,set: function (x) - { + ,set: function(x) { this._mainTable = null; this._requestedMainTable = x; - this._refreshMainTable (); + this._refreshMainTable(); } - ,get: function () - { + ,get: function() { return this._mainTable; } }, /** * Determines if the model is updatable. - **/ + */ updatable: { type: Boolean - ,set: function (x) - { + ,set: function(x) { this._updatable = false; this._requestedUpdatable = x; - this._refreshUpdatable (); + this._refreshUpdatable(); } - ,get: function () - { + ,get: function() { return this._updatable; } }, /** * The number of rows in the model. - **/ + */ numRows: { type: Number - ,get: function () - { + ,get: function() { if (this.data) return this.data.length; @@ -185,29 +163,27 @@ Model.implement }, /** * The current status of the model. - **/ + */ status: { type: Number - ,get: function () - { + ,get: function() { return this._status; } }, /** * Checks if the model data is ready. - **/ + */ ready: { type: Boolean - ,get: function () - { + ,get: function() { return this._status == Status.READY; } }, /** * Update mode. - **/ + */ mode: { enumType: Mode @@ -215,7 +191,7 @@ Model.implement }, /** * Wether to execute the model query automatically. - **/ + */ autoLoad: { type: Boolean @@ -248,22 +224,19 @@ Model.implement ,_defaults: [] ,_requestedMainTable: null - ,initialize: function (props) - { - this.parent (props); - this._cleanData (); - this._setStatus (Status.CLEAN); + ,initialize: function(props) { + this.parent(props); + this._cleanData(); + this._setStatus(Status.CLEAN); } - ,appendChild: function (child) - { + ,appendChild: function(child) { if (child.nodeType === Node.TEXT_NODE) this.query = child.textContent; } - ,loadXml: function (builder, node) - { - this.parent (builder, node); + ,loadXml: function(builder, node) { + this.parent(builder, node); var query = node.firstChild.nodeValue; @@ -271,76 +244,63 @@ Model.implement this.query = query; } - ,_autoLoad: function () - { + ,_autoLoad: function() { if (this.autoLoad) - this.refresh (); + this.refresh(); else - this.clean (); + this.clean(); } /** * Refresh the model data reexecuting the query on the database. - **/ - ,refresh: function () - { + */ + ,refresh: function() { var ready = false; - if (this._stmt && this._conn) - { - var ids = this._stmt.findHolders (); + if (this._stmt && this._conn) { + var ids = this._stmt.findHolders(); - if (ids) - { - if (this._batch && this._batch.isReady ()) - { + if (ids) { + if (this._batch && this._batch.isReady()) { ready = true; for (var i = 0; i < ids.length; i++) - if (!this._batch.get (ids[i])) - { + if (!this._batch.get(ids[i])) { ready = false; break; } } - } - else + } else ready = true; } - if (ready) - { - this._setStatus (Status.LOADING); - this._conn.execStmt (this._stmt, this._selectDone.bind (this), this._batch); - } - else - this.clean (); + if (ready) { + this._setStatus(Status.LOADING); + this._conn.execStmt(this._stmt, this._selectDone.bind(this), this._batch); + } else + this.clean(); } - ,clean: function () - { - this._cleanData (); - this._setStatus (Status.CLEAN); + ,clean: function() { + this._cleanData(); + this._setStatus(Status.CLEAN); } - ,_selectDone: function (resultSet) - { + ,_selectDone: function(resultSet) { var result; var dataResult; - this._cleanData (); + this._cleanData(); try { - for (var i = 0; result = resultSet.fetchResult (); i++) + for (var i = 0; result = resultSet.fetchResult(); i++) if (i == this._resultIndex) dataResult = result; if (!dataResult || typeof dataResult !== 'object') - throw new Error ('The provided statement doesn\'t return a result set'); - } - catch (e) - { - this._setStatus (Status.ERROR); + throw new Error('The provided statement doesn\'t return a result set'); + } catch (e) { + this._setStatus(Status.ERROR); throw e; } @@ -348,34 +308,32 @@ Model.implement this.tables = dataResult.tables; this.columns = dataResult.columns; this.columnMap = dataResult.columnMap; - this._repairColumns (); - this._refreshRowIndexes (0); - this._refreshMainTable (); + this._repairColumns(); + this._refreshRowIndexes(0); + this._refreshMainTable(); for (column in this._requestedIndexes) - this._buildIndex (column); + this._buildIndex(column); var sortColumn = -1; if (this._requestedSortName) - sortColumn = this.getColumnIndex (this._requestedSortName); + sortColumn = this.getColumnIndex(this._requestedSortName); else if (this._requestedSortIndex !== -1 - && this.checkColExists (this._requestedSortIndex)) + && this.checkColExists(this._requestedSortIndex)) sortColumn = this._requestedSortIndex; if (sortColumn !== -1) - this._realSort (sortColumn, this._sortWay); + this._realSort(sortColumn, this._sortWay); - this._setStatus (Status.READY); + this._setStatus(Status.READY); } - ,_refreshRowIndexes: function (start) - { + ,_refreshRowIndexes: function(start) { for (var i = start; i < this.data.length; i++) this.data[i].index = i; - if (this._operationsMap) - { + if (this._operationsMap) { this._operationsMap = {}; for (var i = 0; i < this._operations.length; i++) @@ -383,28 +341,25 @@ Model.implement } } - ,_cleanData: function () - { + ,_cleanData: function() { this.data = null; this.tables = null; this.columns = null; this.columnMap = null; this._sortColumn = -1; this._indexes = []; - this._resetOperations (); + this._resetOperations(); } - ,_refreshUpdatable: function () - { + ,_refreshUpdatable: function() { var oldValue = this._updatable; this._updatable = this._mainTable !== null && this._requestedUpdatable; if (oldValue != this._updatable) - this.signalEmit ('updatable-changed'); + this.signalEmit('updatable-changed'); } - ,_refreshMainTable: function () - { + ,_refreshMainTable: function() { var newMainTable = null; var tables = this.tables; @@ -412,14 +367,13 @@ Model.implement for (var i = 0; i < tables.length; i++) if (tables[i].pks.length > 0) if (!this._requestedMainTable - || tables[i].name === this._requestedMainTable) - { + || tables[i].name === this._requestedMainTable) { newMainTable = i; break; } this._mainTable = newMainTable; - this._refreshUpdatable (); + this._refreshUpdatable(); } /** @@ -428,11 +382,9 @@ Model.implement * @param {String} field The destination field name * @param {String} table The destination table name * @param {Sql.Expr} srcColumn The default value expression - **/ - ,setDefault: function (field, table, expr) - { - this._defaults.push - ({ + */ + ,setDefault: function(field, table, expr) { + this._defaults.push({ field: field ,table: table ,expr: expr @@ -445,11 +397,9 @@ Model.implement * @param {String} field The destination field name * @param {String} table The destination table name * @param {Object} value The default value - **/ - ,setDefaultFromValue: function (field, table, value) - { - this._defaults.push - ({ + */ + ,setDefaultFromValue: function(field, table, value) { + this._defaults.push({ field: field ,table: table ,value: value @@ -463,11 +413,9 @@ Model.implement * @param {String} field The destination field name * @param {String} table The destination table name * @param {String} srcColumn The source column - **/ - ,setDefaultFromColumn: function (field, table, srcColumn) - { - this._defaults.push - ({ + */ + ,setDefaultFromColumn: function(field, table, srcColumn) { + this._defaults.push({ field: field ,table: table ,srcColumn: srcColumn @@ -479,9 +427,8 @@ Model.implement * * @param {integer} column The column index * @return {Boolean} %true if column exists, %false otherwise - **/ - ,checkColExists: function (column) - { + */ + ,checkColExists: function(column) { return this.columns && column >= 0 && column < this.columns.length; @@ -492,21 +439,19 @@ Model.implement * * @param {integer} rowIndex The row index * @return {Boolean} %true if row exists, %false otherwise - **/ - ,checkRowExists: function (rowIndex) - { + */ + ,checkRowExists: function(rowIndex) { return this.data && rowIndex >= 0 && rowIndex < this.data.length; } - ,_checkTableUpdatable: function (tableIndex) - { + ,_checkTableUpdatable: function(tableIndex) { var tableUpdatable = tableIndex !== null && this.tables[tableIndex].pks.length > 0; if (!tableUpdatable) - console.warn ("Db.Model: Table %s is not updatable", + console.warn("Db.Model: Table %s is not updatable", this.tables[tableIndex].name); return tableUpdatable; @@ -517,9 +462,8 @@ Model.implement * * @param {string} columnName The column name * @return {number} The column index or -1 if column not exists - **/ - ,getColumnIndex: function (columnName) - { + */ + ,getColumnIndex: function(columnName) { var index; if (this.columnMap @@ -528,6 +472,23 @@ Model.implement return -1; } + + /** + * Gets the row as object. + * + * @param {number} rowIndex The row index + * @return {Object} The row + */ + ,getObject: function(rowIndex) { + if (!this.checkRowExists(rowIndex)) + return undefined; + + const row = this.data[rowIndex]; + const object = {}; + for(let i = 0; i < row.length; i++) + object[this.columns[i].name] = row[i]; + return object; + } /** * Gets a value from the model. @@ -535,13 +496,12 @@ Model.implement * @param {number} rowIndex The row index * @param {string} columnName The column name * @return {mixed} The value - **/ - ,get: function (rowIndex, columnName) - { - var index = this.getColumnIndex (columnName); + */ + ,get: function(rowIndex, columnName) { + var index = this.getColumnIndex(columnName); if (index != -1) - return this.getByIndex (rowIndex, index); + return this.getByIndex(rowIndex, index); return undefined; } @@ -552,15 +512,14 @@ Model.implement * @param {number} rowIndex The row index * @param {string} columnName The column name * @param {mixed} value The new value - **/ - ,set: function (rowIndex, columnName, value) - { - var index = this.getColumnIndex (columnName); + */ + ,set: function(rowIndex, columnName, value) { + var index = this.getColumnIndex(columnName); if (index != -1) - this.setByIndex (rowIndex, index, value); + this.setByIndex(rowIndex, index, value); else - console.warn ('Db.Model: Column %s doesn\'t exist', columnName); + console.warn('Db.Model: Column %s doesn\'t exist', columnName); } /** @@ -569,10 +528,9 @@ Model.implement * @param {number} rowIndex The row index * @param {number} column The column index * @return {mixed} The value - **/ - ,getByIndex: function (rowIndex, column) - { - if (this.checkRowExists (rowIndex) && this.checkColExists (column)) + */ + ,getByIndex: function(rowIndex, column) { + if (this.checkRowExists(rowIndex) && this.checkColExists(column)) return this.data[rowIndex][column]; return undefined; @@ -584,21 +542,20 @@ Model.implement * @param {number} rowIndex The row index * @param {number} col The column index * @param {mixed} value The new value - **/ - ,setByIndex: function (rowIndex, col, value) - { - if (!this.checkRowExists (rowIndex) - && !this.checkColExists (col)) + */ + ,setByIndex: function(rowIndex, col, value) { + if (!this.checkRowExists(rowIndex) + && !this.checkColExists(col)) return; var tableIndex = this.columns[col].table; - if (!this._checkTableUpdatable (tableIndex)) + if (!this._checkTableUpdatable(tableIndex)) return; var row = this.data[rowIndex]; - var op = this._createOperation (rowIndex); + var op = this._createOperation(rowIndex); op.type |= Operation.UPDATE; if (!op.oldValues) @@ -608,14 +565,12 @@ Model.implement var tableOp = op.tables[tableIndex]; - if (!tableOp) - { + if (!tableOp) { tableOp = Operation.UPDATE; var pks = this.tables[tableIndex].pks; for (var i = 0; i < pks.length; i++) - if (!row[pks[i]] && !op.oldValues[pks[i]]) - { + if (!row[pks[i]] && !op.oldValues[pks[i]]) { tableOp = Operation.INSERT; break; } @@ -627,39 +582,35 @@ Model.implement && op.oldValues[col] === undefined) op.oldValues[col] = row[col]; - this.signalEmit ('row-updated-before', rowIndex); + this.signalEmit('row-updated-before', rowIndex); row[col] = value; - this.signalEmit ('row-updated', rowIndex, [col]); + this.signalEmit('row-updated', rowIndex, [col]); if (this.mode == Mode.ON_CHANGE && !(op.type & Operation.INSERT)) - this.performOperations (); + this.performOperations(); } /** * Deletes a row from the model. * * @param {number} rowIndex The row index - **/ - ,deleteRow: function (rowIndex) - { - if (!this.checkRowExists (rowIndex) - || !this._checkTableUpdatable (this._mainTable)) + */ + ,deleteRow: function(rowIndex) { + if (!this.checkRowExists(rowIndex) + || !this._checkTableUpdatable(this._mainTable)) return; - var op = this._createOperation (rowIndex); + var op = this._createOperation(rowIndex); op.type |= Operation.DELETE; - if (!this._requestedMainTable) - { - this.signalEmit ('row-deleted-before', rowIndex); - this.data.splice (rowIndex, 1); - this.signalEmit ('row-deleted', rowIndex); - this._refreshRowIndexes (rowIndex); - } - else - { - this.signalEmit ('row-updated-before', rowIndex); + if (!this._requestedMainTable) { + this.signalEmit('row-deleted-before', rowIndex); + this.data.splice(rowIndex, 1); + this.signalEmit('row-deleted', rowIndex); + this._refreshRowIndexes(rowIndex); + } else { + this.signalEmit('row-updated-before', rowIndex); if (!op.oldValues) op.oldValues = []; @@ -667,34 +618,32 @@ Model.implement var updatedCols = []; for (var i = 0; i < this.columns.length; i++) - if (this.columns[i].table == this._mainTable) - { + if (this.columns[i].table == this._mainTable) { if (op.oldValues[i] === undefined) op.oldValues[i] = op.row[i]; op.row[i] = null; - updatedCols.push (i); + updatedCols.push(i); } - this.signalEmit ('row-updated', rowIndex, updatedCols); + this.signalEmit('row-updated', rowIndex, updatedCols); } if (this.mode === Mode.ON_CHANGE) - this.performOperations (); + this.performOperations(); } /** * Inserts a new row on the model. * * @return The index of the inserted row - **/ - ,insertRow: function () - { - if (!this._checkTableUpdatable (this._mainTable)) + */ + ,insertRow: function() { + if (!this._checkTableUpdatable(this._mainTable)) return -1; var cols = this.columns; - var newRow = new Array (cols.length); + var newRow = new Array(cols.length); for (var i = 0; i < cols.length; i++) if (cols[i].table === this._mainTable) @@ -702,164 +651,142 @@ Model.implement else newRow[i] = null; - var rowIndex = this.data.push (newRow) - 1; + var rowIndex = this.data.push(newRow) - 1; newRow.index = rowIndex; - var op = this._createOperation (rowIndex); + var op = this._createOperation(rowIndex); op.type |= Operation.INSERT; - this.signalEmit ('row-inserted', rowIndex); + this.signalEmit('row-inserted', rowIndex); return rowIndex; } /** * Performs all model changes on the database. - **/ - ,performOperations: function () - { + */ + ,performOperations: function() { var ops = this._operations; - if (ops.length === 0) - { - this.signalEmit ('operations-done'); + if (ops.length === 0) { + this.signalEmit('operations-done'); return; } - var stmts = new Sql.MultiStmt (); + var stmts = new Sql.MultiStmt(); - var query = new Sql.String ({query: 'START TRANSACTION'}); - stmts.addStmt (query); + var query = new Sql.String({query: 'START TRANSACTION'}); + stmts.addStmt(query); - for (var i = 0; i < ops.length; i++) - { + for (var i = 0; i < ops.length; i++) { query = null; var op = ops[i]; - if (op.type & Operation.DELETE) - { + if (op.type & Operation.DELETE) { if (op.type & Operation.INSERT) continue; - var where = this._createWhere (this._mainTable, op, true); + var where = this._createWhere(this._mainTable, op, true); - if (where) - { - query = new Sql.Delete ({where: where}); - query.addTarget (this._createTarget (this._mainTable)); + if (where) { + query = new Sql.Delete({where: where}); + query.addTarget(this._createTarget(this._mainTable)); } - } - else if (op.type & (Operation.INSERT | Operation.UPDATE)) - { - query = new Sql.MultiStmt (); + } else if (op.type & (Operation.INSERT | Operation.UPDATE)) { + query = new Sql.MultiStmt(); - for (var tableIndex in op.tables) - { - var stmt = this._createDmlQuery (op, parseInt (tableIndex)); - query.addStmt (stmt); + for (var tableIndex in op.tables) { + var stmt = this._createDmlQuery(op, parseInt(tableIndex)); + query.addStmt(stmt); } } - if (query) - { - stmts.addStmt (query); - } - else - { - console.warn ('Db.Model: %s', _('ErrorSavingChanges')); + if (query) { + stmts.addStmt(query); + } else { + console.warn('Db.Model: %s', _('ErrorSavingChanges')); return; } } - var query = new Sql.String ({query: 'COMMIT'}); - stmts.addStmt (query); + var query = new Sql.String({query: 'COMMIT'}); + stmts.addStmt(query); - this._conn.execStmt (stmts, - this._onOperationsDone.bind (this, ops)); + this._conn.execStmt(stmts, + this._onOperationsDone.bind(this, ops)); - this._resetOperations (); + this._resetOperations(); } - ,_createDmlQuery: function (op, tableIndex) - { - var where = this._createWhere (tableIndex, op, false); + ,_createDmlQuery: function(op, tableIndex) { + var where = this._createWhere(tableIndex, op, false); if (!where) return null; - var multiStmt = new Sql.MultiStmt (); - var target = this._createTarget (tableIndex); + var multiStmt = new Sql.MultiStmt(); + var target = this._createTarget(tableIndex); - var select = new Sql.Select ({where: where}); - select.addTarget (target); + var select = new Sql.Select({where: where}); + select.addTarget(target); var row = op.row; var cols = this.columns; - if (op.tables[tableIndex] & Operation.INSERT) - { - var dmlQuery = new Sql.Insert (); + if (op.tables[tableIndex] & Operation.INSERT) { + var dmlQuery = new Sql.Insert(); var table = this.tables[tableIndex]; - for (var i = 0; i < this._defaults.length; i++) - { + for (var i = 0; i < this._defaults.length; i++) { var def = this._defaults[i]; - if (def.table === table.name) - { + if (def.table === table.name) { if (def.value) - dmlQuery.addSet (def.field, def.value); + dmlQuery.addSet(def.field, def.value); else if (def.expr) - dmlQuery.addExpr (def.field, def.expr); - else if (def.srcColumn) - { - var columnIndex = this.getColumnIndex (def.srcColumn); - dmlQuery.addSet (def.field, row[columnIndex]); + dmlQuery.addExpr(def.field, def.expr); + else if (def.srcColumn) { + var columnIndex = this.getColumnIndex(def.srcColumn); + dmlQuery.addSet(def.field, row[columnIndex]); } } } for (var i = 0; i < cols.length; i++) - if (cols[i].table === tableIndex) - { + if (cols[i].table === tableIndex) { if (row[i] !== null) - dmlQuery.addSet (cols[i].orgname, row[i]); + dmlQuery.addSet(cols[i].orgname, row[i]); - select.addField (cols[i].orgname); + select.addField(cols[i].orgname); } - } - else - { - var updateWhere = this._createWhere (tableIndex, op, true); + } else { + var updateWhere = this._createWhere(tableIndex, op, true); if (!updateWhere) return null; - var dmlQuery = new Sql.Update ({where: updateWhere}); + var dmlQuery = new Sql.Update({where: updateWhere}); for (var i = 0; i < cols.length; i++) - if (cols[i].table === tableIndex && op.oldValues[i] !== undefined) - { + if (cols[i].table === tableIndex && op.oldValues[i] !== undefined) { var fieldName = cols[i].orgname; - dmlQuery.addSet (fieldName, row[i]); - select.addField (fieldName); + dmlQuery.addSet(fieldName, row[i]); + select.addField(fieldName); } } - dmlQuery.addTarget (target); + dmlQuery.addTarget(target); - multiStmt.addStmt (dmlQuery); - multiStmt.addStmt (select); + multiStmt.addStmt(dmlQuery); + multiStmt.addStmt(select); return multiStmt; } - ,_onOperationsDone: function (ops, resultSet) - { - var error = resultSet.getError (); + ,_onOperationsDone: function(ops, resultSet) { + var error = resultSet.getError(); - if (error) - { - this._operations = this._operations.concat (ops); + if (error) { + this._operations = this._operations.concat(ops); for (var i = 0; i < ops.length; i++) this._operationsMap[ops[i].row.index] = ops[i]; @@ -867,11 +794,10 @@ Model.implement throw error; } - resultSet.fetchResult (); + resultSet.fetchResult(); var isOperation = false; - for (var i = 0; i < ops.length; i++) - { + for (var i = 0; i < ops.length; i++) { var op = ops[i]; var row = op.row; @@ -879,96 +805,80 @@ Model.implement && op.type & Operation.INSERT)) isOperation = true; - if (op.type & Operation.DELETE) - { - resultSet.fetchResult (); - } - else if (op.type & (Operation.INSERT | Operation.UPDATE)) - { - this.signalEmit ('row-updated-before', row.index); + if (op.type & Operation.DELETE) { + resultSet.fetchResult(); + } else if (op.type & (Operation.INSERT | Operation.UPDATE)) { + this.signalEmit('row-updated-before', row.index); var updatedCols = []; var cols = this.columns; - for (var tableIndex in op.tables) - { + for (var tableIndex in op.tables) { var j = 0; - tableIndex = parseInt (tableIndex); + tableIndex = parseInt(tableIndex); - resultSet.fetchResult (); - var newValues = resultSet.fetchRow (); + resultSet.fetchResult(); + var newValues = resultSet.fetchRow(); - if (op.tables[tableIndex] & Operation.INSERT) - { + if (op.tables[tableIndex] & Operation.INSERT) { for (var i = 0; i < cols.length; i++) - if (cols[i].table === tableIndex) - { + if (cols[i].table === tableIndex) { row[i] = newValues[j++]; - updatedCols.push (i); + updatedCols.push(i); } - } - else - { + } else { for (var i = 0; i < cols.length; i++) if (cols[i].table === tableIndex - && op.oldValues[i] !== undefined) - { + && op.oldValues[i] !== undefined) { row[i] = newValues[j++]; - updatedCols.push (i); + updatedCols.push(i); } } } - this.signalEmit ('row-updated', row.index, updatedCols); + this.signalEmit('row-updated', row.index, updatedCols); } } - resultSet.fetchResult (); + resultSet.fetchResult(); // if (isOperation) - this.signalEmit ('operations-done'); + this.signalEmit('operations-done'); } /** * Undoes all unsaved changes made to the model. - **/ - ,reverseOperations: function () - { - for (var i = 0; i < this._operations.length; i++) - { + */ + ,reverseOperations: function() { + for (var i = 0; i < this._operations.length; i++) { var op = this._operations[i]; var row = op.row; if (op.type & Operation.DELETE - && !(op.type & Operation.INSERT)) - { - this.data.splice (row.index, 0, row); - this.signalEmit ('row-inserted', row.index); - } - else if (op.type & Operation.UPDATE) - { - this.signalEmit ('row-updated-before', row.index); + && !(op.type & Operation.INSERT)) { + this.data.splice(row.index, 0, row); + this.signalEmit('row-inserted', row.index); + } else if (op.type & Operation.UPDATE) { + this.signalEmit('row-updated-before', row.index); var updatedCols = []; var cols = this.columns; for (var i = 0; i < cols.length; i++) - if (op.oldValues[i] !== undefined) - { + if (op.oldValues[i] !== undefined) { row[i] = op.oldValues[i]; - updatedCols.push (i); + updatedCols.push(i); } - this.signalEmit ('row-updated', row.index, updatedCols); + this.signalEmit('row-updated', row.index, updatedCols); } } - this._resetOperations (); - this._refreshRowIndexes (0); + this._resetOperations(); + this._refreshRowIndexes(0); } - ,_resetOperations: function () - { + ,_resetOperations: function() { this._operations = []; this._operationsMap = {}; } @@ -976,8 +886,7 @@ Model.implement /* * Function used to sort the model ascending. */ - ,sortFunctionAsc: function (column, a, b) - { + ,sortFunctionAsc: function(column, a, b) { if (a[column] < b[column]) return -1; else if (a[column] > b[column]) @@ -989,8 +898,7 @@ Model.implement /* * Function used to sort the model descending. */ - ,sortFunctionDesc: function (column, a, b) - { + ,sortFunctionDesc: function(column, a, b) { if (a[column] > b[column]) return -1; else if (a[column] < b[column]) @@ -1004,16 +912,15 @@ Model.implement * * @param {integer} column The column name * @param {SortWay} way The sort way - **/ - ,sortByName: function (columnName, way) - { + */ + ,sortByName: function(columnName, way) { this._requestedSortIndex = -1; this._requestedSortName = columnName; - var index = this.getColumnIndex (columnName); + var index = this.getColumnIndex(columnName); if (index != -1) - this._sort (index, way); + this._sort(index, way); } /** @@ -1021,43 +928,38 @@ Model.implement * * @param {integer} column The column index * @param {SortWay} way The sort way - **/ - ,sort: function (column, way) - { + */ + ,sort: function(column, way) { this._requestedSortIndex = column; this._requestedSortName = null; - if (!this.checkColExists (column)) + if (!this.checkColExists(column)) return; - this._sort (column, way); + this._sort(column, way); } - ,_sort: function (column, way) - { - this._setStatus (Status.LOADING); - this._realSort (column, way); - this._setStatus (Status.READY); + ,_sort: function(column, way) { + this._setStatus(Status.LOADING); + this._realSort(column, way); + this._setStatus(Status.READY); } - ,_realSort: function (column, way) - { - if (column !== this._sortColumn) - { + ,_realSort: function(column, way) { + if (column !== this._sortColumn) { if (way === SortWay.DESC) var sortFunction = this.sortFunctionDesc; else var sortFunction = this.sortFunctionAsc; - this.data.sort (sortFunction.bind (this, column)); - } - else if (way !== this._sortWay) - this.data.reverse (); + this.data.sort(sortFunction.bind(this, column)); + } else if (way !== this._sortWay) + this.data.reverse(); this._sortColumn = column; this._sortWay = way; - this._refreshRowIndexes (0); + this._refreshRowIndexes(0); } /** @@ -1068,31 +970,27 @@ Model.implement * FIXME: Not fully implemented. * * @param {String} column The column name - **/ - ,indexColumn: function (column) - { + */ + ,indexColumn: function(column) { this._requestedIndexes[column] = true; if (this._status === Status.READY) - this._buildIndex (column); + this._buildIndex(column); } - ,_buildIndex: function (column) - { - var columnIndex = this.getColumnIndex (column); + ,_buildIndex: function(column) { + var columnIndex = this.getColumnIndex(column); - if (columnIndex !== -1) - { + if (columnIndex !== -1) { var index = {}; var data = this.data; - switch (this.columns[columnIndex].type) - { + switch (this.columns[columnIndex].type) { case Connection.Type.TIMESTAMP: case Connection.Type.DATE_TIME: case Connection.Type.DATE: for (var i = 0; i < data.length; i++) - index[data[i][columnIndex].toString ()] = i; + index[data[i][columnIndex].toString()] = i; break; default: for (var i = 0; i < data.length; i++) @@ -1112,11 +1010,10 @@ Model.implement * @param {String} column The column name * @param {Object} value The value to search * @return {integer} The column index - **/ - ,search: function (column, value) - { - var index = this.getColumnIndex (column); - return this.searchByIndex (index, value); + */ + ,search: function(column, value) { + var index = this.getColumnIndex(column); + return this.searchByIndex(index, value); } /** @@ -1126,34 +1023,31 @@ Model.implement * @param {integer} col The column index * @param {Object} value The value to search * @return {integer} The column index - **/ - ,searchByIndex: function (col, value) - { - if (!this.checkColExists (col)) + */ + ,searchByIndex: function(col, value) { + if (!this.checkColExists(col)) return -1; if (value) - switch (this.columns[col].type) - { + switch (this.columns[col].type) { case Connection.Type.BOOLEAN: value = !!value; break; case Connection.Type.INTEGER: - value = parseInt (value); + value = parseInt(value); break; case Connection.Type.DOUBLE: - value = parseFloat (value); + value = parseFloat(value); break; default: - value = value.toString (); + value = value.toString(); } // Searchs the value using an internal index. var index = this._indexes[col]; - if (index) - { + if (index) { if (index[value] !== undefined) return index[value]; @@ -1164,14 +1058,13 @@ Model.implement var data = this.data; - switch (this.columns[col].type) - { + switch (this.columns[col].type) { case Connection.Type.TIMESTAMP: case Connection.Type.DATE_TIME: case Connection.Type.DATE: { for (var i = 0; i < data.length; i++) - if (value === data[i][col].toString ()) + if (value === data[i][col].toString()) return i; break; @@ -1185,40 +1078,35 @@ Model.implement return -1; } - ,_setStatus: function (status) - { + ,_setStatus: function(status) { this._status = status; - this.signalEmit ('status-changed', status); - this.signalEmit ('status-changed-after', status); + this.signalEmit('status-changed', status); + this.signalEmit('status-changed-after', status); } - ,_createTarget: function (tableIndex) - { + ,_createTarget: function(tableIndex) { var table = this.tables[tableIndex]; - return new Sql.Table - ({ + return new Sql.Table({ name: table.orgname ,schema: table.schema }); } - ,_createWhere: function (tableIndex, op, useOldValues) - { - var where = new Sql.Operation ({type: Sql.Operation.Type.AND}); + ,_createWhere: function(tableIndex, op, useOldValues) { + var where = new Sql.Operation({type: Sql.Operation.Type.AND}); var pks = this.tables[tableIndex].pks; if (pks.length === 0) return null; - for (var i = 0; i < pks.length; i++) - { + for (var i = 0; i < pks.length; i++) { var col = pks[i]; var column = this.columns[col]; - var equalOp = new Sql.Operation ({type: Sql.Operation.Type.EQUAL}); - equalOp.exprs.add (new Sql.Field ({name: column.orgname})); - where.exprs.add (equalOp); + var equalOp = new Sql.Operation({type: Sql.Operation.Type.EQUAL}); + equalOp.exprs.add(new Sql.Field({name: column.orgname})); + where.exprs.add(equalOp); var pkValue = null; @@ -1229,9 +1117,9 @@ Model.implement pkValue = op.row[col]; if (pkValue) - equalOp.exprs.add (new Sql.Value ({value: pkValue})); + equalOp.exprs.add(new Sql.Value({value: pkValue})); else if (column.flags & Connection.Flag.AI && !useOldValues) - equalOp.exprs.add (new Sql.Function ({name: 'LAST_INSERT_ID'})); + equalOp.exprs.add(new Sql.Function({name: 'LAST_INSERT_ID'})); else return null; } @@ -1239,17 +1127,15 @@ Model.implement return where; } - ,_createOperation: function (rowIndex) - { + ,_createOperation: function(rowIndex) { var op = this._operationsMap[rowIndex]; - if (!op) - { + if (!op) { op = { type: 0, row: this.data[rowIndex] }; - this._operations.push (op); + this._operations.push(op); this._operationsMap[rowIndex] = op; } @@ -1270,9 +1156,8 @@ Model.implement * @param {String} schema The original table schema * @param {Array} pks Array with the names of primary keys * @param {String} ai The autoincrement column name - **/ - ,setInfo: function (table, orgname, schema, pks, ai) - { + */ + ,setInfo: function(table, orgname, schema, pks, ai) { if (!this.tableInfo) this.tableInfo = {}; @@ -1284,16 +1169,14 @@ Model.implement ai: ai }; - this._repairColumns (); + this._repairColumns(); } - ,_repairColumns: function () - { + ,_repairColumns: function() { // Repairs wrong table info if (this.tableInfo && this.tables) - for (var i = 0; i < this.tables.length; i++) - { + for (var i = 0; i < this.tables.length; i++) { var table = this.tables[i]; var tableInfo = this.tableInfo[table.name]; @@ -1303,32 +1186,29 @@ Model.implement table.orgname = tableInfo.orgname; table.schema = tableInfo.schema; - if (tableInfo.pks) - { + if (tableInfo.pks) { table.pks = []; - for (var j = 0; j < tableInfo.pks.length; j++) - { - var colIndex = this.getColumnIndex (tableInfo.pks[j]); + for (var j = 0; j < tableInfo.pks.length; j++) { + var colIndex = this.getColumnIndex(tableInfo.pks[j]); if (colIndex !== -1) - table.pks.push (colIndex); + table.pks.push(colIndex); else - console.warn ('Db.Model: Can\'t repair primary key: `%s`.`%s`' + console.warn('Db.Model: Can\'t repair primary key: `%s`.`%s`' ,tableInfo.orgname ,tableInfo.pks[j] ); } } - if (tableInfo.ai) - { - var colIndex = this.getColumnIndex (tableInfo.ai); + if (tableInfo.ai) { + var colIndex = this.getColumnIndex(tableInfo.ai); if (colIndex !== -1) this.columns[colIndex].flags |= Connection.Flag.AI; else - console.warn ('Db.Model: Can\'t repair autoincrement column: `%s`.`%s`' + console.warn('Db.Model: Can\'t repair autoincrement column: `%s`.`%s`' ,tableInfo.orgname ,tableInfo.ai ); diff --git a/js/db/result-set.js b/js/db/result-set.js index 241a219b..daaed703 100644 --- a/js/db/result-set.js +++ b/js/db/result-set.js @@ -3,14 +3,14 @@ var Result = require('./result'); /** * This class stores the database results. - **/ + */ module.exports = new Class({ results: null ,error: null /** * Initilizes the resultset object. - **/ + */ ,initialize: function(results, error) { this.results = results; this.error = error; @@ -20,7 +20,7 @@ module.exports = new Class({ * Gets the query error. * * @return {Db.Err} the error or null if no errors hapened - **/ + */ ,getError: function() { return this.error; } @@ -40,7 +40,7 @@ module.exports = new Class({ * Fetchs the next result from the resultset. * * @return {Db.Result} the result or %null if error or there are no more results - **/ + */ ,fetchResult: function() { var result = this.fetch(); @@ -53,12 +53,12 @@ module.exports = new Class({ return null; } - + /** * Fetchs the first row from the next resultset. * * @return {Array} the row if success, %null otherwise - **/ + */ ,fetchRow: function() { var result = this.fetch(); @@ -70,6 +70,11 @@ module.exports = new Class({ return null; } + /** + * Fetchs the first row object from the next resultset. + * + * @return {Array} the row if success, %null otherwise + */ ,fetchObject: function() { var result = this.fetch(); @@ -90,7 +95,7 @@ module.exports = new Class({ * Fetchs the first row and column value from the next resultset. * * @return {Object} the value if success, %null otherwise - **/ + */ ,fetchValue: function() { var row = this.fetchRow(); diff --git a/js/db/simple-iterator.js b/js/db/simple-iterator.js index 7aca8a49..b2f8537e 100644 --- a/js/db/simple-iterator.js +++ b/js/db/simple-iterator.js @@ -1,54 +1,44 @@ -var Iterator = require ('./iterator'); -var Model = require ('./model'); +var Iterator = require('./iterator'); +var Model = require('./model'); /** * A light iterator for models. - **/ -module.exports = new Class -({ + */ +module.exports = new Class({ Extends: Vn.Object ,Implements: Iterator - ,Properties: - { + ,Properties: { /** * The model associated to this form. - **/ - model: - { + */ + model: { type: Model - ,set: function (x) - { + ,set: function(x) { this._model = x; } - ,get: function () - { + ,get: function() { return this._model; } }, /** * The row where the form positioned, has -1 if the row is unselected. - **/ - row: - { + */ + row: { type: Number - ,set: function (x) - { + ,set: function(x) { this._row = x; } - ,get: function () - { + ,get: function() { return this._row; } }, /** * The number of rows in the form. - **/ - numRows: - { + */ + numRows: { type: Number - ,get: function () - { + ,get: function() { if (this._model) return this._model.numRows; @@ -57,12 +47,10 @@ module.exports = new Class }, /** * Checks if the form data is ready. - **/ - ready: - { + */ + ready: { type: Boolean - ,get: function () - { + ,get: function() { if (this._model) return this._model.ready; diff --git a/js/hedera/form.js b/js/hedera/form.js index 7040315c..b28fa327 100644 --- a/js/hedera/form.js +++ b/js/hedera/form.js @@ -6,8 +6,7 @@ module.exports = new Class ,isOpen: false ,uiLoaded: false - ,initialize: function (gui, formInfo) - { + ,initialize: function(gui, formInfo) { this.gui = gui; this.conn = gui.conn; this.hash = gui.hash; @@ -19,107 +18,98 @@ module.exports = new Class * * @param {string} objectId The object identifier * @return {Object} The object, or %null if not found - **/ - ,$: function (objectId) - { + */ + ,$: function(objectId) { if (this.builder) - return this.builder.getById (objectId); + return this.builder.getById(objectId); return null; } - ,loadUi: function () - { + ,loadUi: function() { if (!this.isOpen) return; - var builder = new Vn.Builder (); + var builder = new Vn.Builder(); builder.signalData = this; - builder.add ('conn', this.conn); - builder.loadXml ('forms/'+ this.formInfo.path +'/ui.xml'); + builder.add('conn', this.conn); + builder.loadXml('forms/'+ this.formInfo.path +'/ui.xml'); - var res = this.builder = builder.load (); + var res = this.builder = builder.load(); this.node = res.$('form'); - res.link (); + res.link(this); - var models = res.getByTagName ('db-model'); + var models = res.getByTagName('db-model'); for (var i = 0; i < models.length; i++) models[i].conn = this.conn; - var queries = res.getByTagName ('db-query'); + var queries = res.getByTagName('db-query'); for (var i = 0; i < queries.length; i++) queries[i].conn = this.conn; - if (this.node) - { - this.gui.setForm (this.node); - this.gui.setTitle (res.$('title')); - this.gui.setActions (res.$('actions')); - this.activate (); + if (this.node) { + this.gui.setForm(this.node); + this.gui.setTitle(res.$('title')); + this.gui.setActions(res.$('actions')); + this.activate(); } this.uiLoaded = true; } - ,unloadUi: function () - { + ,unloadUi: function() { if (!this.uiLoaded) return; - if (this.node) - { - this.deactivate (); - this.gui.setTitle (null); - this.gui.setActions (null); - Vn.Node.remove (this.node); - this.deactivate (); + if (this.node) { + this.deactivate(); + this.gui.setTitle(null); + this.gui.setActions(null); + Vn.Node.remove(this.node); + this.deactivate(); this.node = null; } - if (this.builder) - { - this.builder.unref (); + if (this.builder) { + this.builder.unref(); this.builder = null; } } /** * Called when the form is opened. - **/ - ,open: function () - { - this.close (); + */ + ,open: function() { + this.close(); this.isOpen = true; - this.loadUi (); + this.loadUi(); } /** * Called when the form is closed. - **/ - ,close: function () - { + */ + ,close: function() { if (!this.isOpen) return; this.isOpen = false; - this.unloadUi (); + this.unloadUi(); } /** * Called when the form is activated. - **/ - ,activate: function () {} + */ + ,activate: function() {} /** * Called when the form is deactivated. - **/ - ,deactivate: function () {} + */ + ,deactivate: function() {} - ,_destroy: function () - { - this.close (); - this.parent (); + ,_destroy: function() { + this.close(); + this.parent(); } }); diff --git a/js/hedera/gui.scss b/js/hedera/gui.scss index 1240081a..7542f73d 100644 --- a/js/hedera/gui.scss +++ b/js/hedera/gui.scss @@ -64,25 +64,28 @@ padding: 0; margin: 0; height: 100%; - } - .action-bar > div { - padding: 0; - margin: 0; - height: 100%; - display: flex; - align-items: center; - padding: 0 1em; - gap: .5em; - } - .action-bar > div > * { - float: right; - } - .action-bar button { - margin: 0; - padding: .6em; - } - .action-bar button:hover { - background-color: rgba(2550, 255, 255, .2); + + & > div { + padding: 0; + margin: 0; + height: 100%; + display: flex; + align-items: center; + padding: 0 1em; + gap: .5em; + + & > * { + float: right; + } + } + button { + margin: 0; + padding: 10px 15px; + + &:hover { + background-color: rgba(2550, 255, 255, .2); + } + } } /* Background */ @@ -277,9 +280,14 @@ /* Mobile */ @media (max-width: 960px) { - .action-bar span.label, - .htk-button > .text { - display: none; + .action-bar { + span.label, + .htk-button > .text { + display: none; + } + .htk-button { + padding: 10px; + } } & > .navbar { padding-left: 2.8em; diff --git a/js/hedera/opensans.ttf b/js/hedera/opensans.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e21ff5f1ec01719e9e699df260db5be8b220aa2a GIT binary patch literal 129796 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
  • 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 CDHovt literal 0 HcmV?d00001 diff --git a/js/hedera/style.scss b/js/hedera/style.scss index e91c6804..779de98c 100644 --- a/js/hedera/style.scss +++ b/js/hedera/style.scss @@ -1,8 +1,14 @@ +@import "../htk/style/classes"; + @font-face { font-family: 'Poppins'; src: url('poppins.ttf') format('truetype'); } +@font-face { + font-family: 'Open Sans'; + src: url('opensans.ttf') format('truetype'); +} /* Global */ @@ -243,12 +249,6 @@ img.editable { cursor: pointer; } -/* Button */ - -.htk-button img { - height: 1.5em; -} - /* Float */ .clear { @@ -258,11 +258,8 @@ img.editable { /* Box */ .box { - background-color: white; + @extend %box; margin: 0 auto; - border-radius: .6em; - box-shadow: .05em .05em .2em rgba(0, 0, 0, .1); - overflow: hidden; } .box .header { padding: 0.6em 0.8em; diff --git a/js/htk/field/bar-button.js b/js/htk/field/bar-button.js index cdb0c1a4..b923f17a 100644 --- a/js/htk/field/bar-button.js +++ b/js/htk/field/bar-button.js @@ -1,8 +1,7 @@ var Button = require('./button'); -module.exports = new Class -({ +module.exports = new Class({ Extends: Button ,Tag: 'htk-bar-button' diff --git a/js/htk/field/button.js b/js/htk/field/button.js index a812f43a..cd01a41d 100644 --- a/js/htk/field/button.js +++ b/js/htk/field/button.js @@ -7,13 +7,13 @@ module.exports = new Class({ image: { type: String ,set: function(x) { - this.span.innerText = x; + this.iconNode.name = x; } }, icon: { type: String ,set: function(x) { - this.span.innerText = x; + this.iconNode.name = x; } }, tip: { @@ -21,7 +21,7 @@ module.exports = new Class({ ,set: function(x) { if (x) { this.node.title = _(x); - this.span.title = _(x); + this.iconNode.title = _(x); } this.renderContent(); @@ -49,9 +49,8 @@ module.exports = new Class({ node.className = 'htk-button'; node.addEventListener('click', this.onClick.bind(this)); - this.span = this.createElement('span'); - this.span.className = 'material-symbols-rounded icon'; - node.appendChild(this.span); + this.iconNode = new Htk.Icon(); + node.appendChild(this.iconNode.node); } ,renderContent: function() { diff --git a/js/htk/field/calendar.js b/js/htk/field/calendar.js index 0a1eb085..f1e54421 100644 --- a/js/htk/field/calendar.js +++ b/js/htk/field/calendar.js @@ -43,12 +43,17 @@ module.exports = new Class({ thead.appendChild(tr); var th = this.createElement('th'); - th.appendChild(this.createTextNode('<')); - th.className = 'button'; - th.addEventListener('click', this.prevMonthClicked.bind(this)); + th.className = 'previous'; tr.appendChild(th); + var previousButton = new Htk.Button({ + icon: 'arrow_back_ios' + }).node; + previousButton.addEventListener('click', this.prevMonthClicked.bind(this)); + th.appendChild(previousButton); + var th = this.createElement('th'); + th.className = 'month-year'; th.colSpan = 5; tr.appendChild(th); @@ -62,12 +67,17 @@ module.exports = new Class({ th.appendChild(yearNode); var th = this.createElement('th'); - th.appendChild(this.createTextNode('>')); - th.className = 'button'; - th.addEventListener('click', this.nextMonthClicked.bind(this)); + th.className = 'next'; tr.appendChild(th); + + var nextButton = new Htk.Button({ + icon: 'arrow_forward_ios' + }).node; + nextButton.addEventListener('click', this.nextMonthClicked.bind(this)); + th.appendChild(nextButton); var tr = this.createElement('tr'); + tr.className = 'weekdays'; thead.appendChild(tr); for (var i = 1; i <= len; i++) { diff --git a/js/htk/field/html.js b/js/htk/field/html.js index 166cab44..641d9a46 100644 --- a/js/htk/field/html.js +++ b/js/htk/field/html.js @@ -4,13 +4,11 @@ module.exports = new Class Extends: Htk.Field ,Tag: 'htk-html' - ,render: function () - { - this.createRoot ('div'); + ,render: function() { + this.createRoot('div'); } - ,putValue: function (value) - { + ,putValue: function(value) { this.node.innerHTML = value; } }); diff --git a/js/htk/htk.js b/js/htk/htk.js index 5fe8cc2f..a193ab6f 100644 --- a/js/htk/htk.js +++ b/js/htk/htk.js @@ -1,6 +1,7 @@ require('db/db'); -require('./style.scss'); +require('./style/classes.scss'); +require('./style/main.scss'); Htk = module.exports = { NodeBuilder : require('./node-builder') diff --git a/js/htk/icon.js b/js/htk/icon.js index 0988fda3..75ed807f 100644 --- a/js/htk/icon.js +++ b/js/htk/icon.js @@ -42,7 +42,7 @@ module.exports = new Class({ ,render: function() { const node = this.createRoot('span'); - node.className = 'material-symbols-rounded icon'; + node.className = 'htk-icon material-symbols-rounded'; } ,_setIcon: function() { diff --git a/js/htk/repeater.js b/js/htk/repeater.js index ef15b692..183e01c2 100644 --- a/js/htk/repeater.js +++ b/js/htk/repeater.js @@ -96,7 +96,7 @@ module.exports = new Class({ var builder = this._builder = new Vn.Builder(); builder.setParent(builderResult); - builder.loadXmlFromNode(node.firstElementChild); + builder.loadXmlFromNode(node.firstElementChild, null, [this._formId]); this._onModelChange(); } @@ -121,7 +121,7 @@ module.exports = new Class({ this._builder.add(this._formId, set); var res = this._builder.load(); - res.link(); + res.link(null, [set.getObject()]); this._childsData.push({ builder: res, diff --git a/js/htk/style/classes.scss b/js/htk/style/classes.scss new file mode 100644 index 00000000..c3f913f3 --- /dev/null +++ b/js/htk/style/classes.scss @@ -0,0 +1,20 @@ + +@import "variables"; + +%box { + border-radius: .6em; + box-shadow: .05em .05em .2em rgba(0, 0, 0, .1); + overflow: hidden; + border: none; + background-color: white; +} +%clickable { + cursor: pointer; + transition: background-color 250ms ease-out; + + &:hover, + &:focus { + background-color: $color-hover-cd; + outline: none; + } +} diff --git a/js/htk/style.scss b/js/htk/style/main.scss similarity index 78% rename from js/htk/style.scss rename to js/htk/style/main.scss index 1bb9d983..cd31d7c0 100644 --- a/js/htk/style.scss +++ b/js/htk/style/main.scss @@ -1,4 +1,7 @@ +@import "variables"; +@import "classes"; + /* Grid */ .htk-grid { @@ -156,8 +159,64 @@ td.cell-image .htk-image { .htk-select-menu td { max-width: 11em; overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* Icon */ + +.htk-icon {} + +/* List */ + +.htk-list { + .item { + @extend %clickable; + padding: 20px; + border-bottom: 1px solid #DDD; + display: flex; + align-items: center; + + &:hover { + background-color: rgba(1, 1, 1, 0.05); + } + & > .side { + flex: none; + } + & > .content { + flex: 1; + + & > .important { + font-weight: bold; + font-size: 1rem; + margin-bottom: .5em; + } + & > p { + margin: .1em 0; + } + } + & > .actions { + flex: none; + display: none; + + & > .htk-button { + margin: 0; + } + & > * { + display: inline-block; + vertical-align: middle; + } + & > input { + margin: .6em; + } + } + } + .item:hover > .actions { + display: block; + } + .item:last-child { + border-bottom: none; + } } /* Button */ @@ -165,12 +224,12 @@ td.cell-image .htk-image { .htk-button { display: flex; align-items: center; - border-radius: 2em; + border-radius: 22px; font-weight: bold; - gap: .5em; - padding: 0 .5em; + gap: 8px; + padding: 0 10px; - & > span.icon { + & > .htk-icon { display: block; } } @@ -178,73 +237,91 @@ td.cell-image .htk-image { /* Calendar */ .htk-calendar { + @extend %box; width: 20em; - background-color: white; - border: none; - border-radius: .5em; -} -.htk-calendar table { - border-collapse: collapse; -} -.htk-calendar thead tr, -.htk-calendar tfoot tr { - background-color: #888; - color: white; - font-weight: normal; - vertical-align: middle; - text-align: center; - height: 3em; -} -.htk-calendar thead span { - color: white; -} -.htk-calendar thead tr { - border-bottom: none; -} -.htk-calendar tfoot tr { - border-top: none; -} -.htk-calendar th.button { - display: table-cell; -} -.htk-calendar th.button:hover { - cursor: pointer; - background-color: rgba(1, 1, 1, 0.2); -} -.htk-calendar col { - width: 14.2%; -} -.htk-calendar tr { - height: 2em; -} -.htk-calendar tbody td { - text-align: right; -} -.htk-calendar tbody td > div { - height: 2em; - width: 2em; - line-height: 2em; - text-align: center; - border-radius: 2em; - padding: 0.3em; - margin: 0 auto; - color: #555; -} -.htk-calendar div.disabled { - color: #999; -} -.htk-calendar div.today { - font-weight: bold; - color: black; -} -.htk-calendar div.selected { - color: white; - background-color: #8cc63f; -} -.htk-calendar div.enabled:hover { - cursor: pointer; - background-color: rgba(140, 198, 63, 0.8); - color: white; + + 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; + } + div.today { + font-weight: bold; + color: black; + } + div.selected { + color: white; + background-color: #8cc63f; + } + div.enabled:hover { + cursor: pointer; + background-color: rgba(140, 198, 63, 0.8); + color: white; + } } /* Image */ @@ -439,7 +516,7 @@ td.cell-image .htk-image { & > h2 { text-align: center; font-weight: normal; - font-size: 1.5em; + font-size: 1.5rem; margin: 0; padding: 0; margin-bottom: 1em; diff --git a/js/htk/style/variables.scss b/js/htk/style/variables.scss new file mode 100644 index 00000000..aa5a68f3 --- /dev/null +++ b/js/htk/style/variables.scss @@ -0,0 +1,2 @@ + +$color-hover-cd: rgba(255, 255, 255, .1); \ No newline at end of file diff --git a/js/vn/builder.js b/js/vn/builder.js index fd741cce..ff38cce1 100644 --- a/js/vn/builder.js +++ b/js/vn/builder.js @@ -1,35 +1,30 @@ -var Object = require ('./object'); +var Object = require('./object'); /** * Creates a object from a XML specification. - **/ -module.exports = new Class -({ + */ +module.exports = new Class({ Extends: Object ,_addedMap: {} ,_contexts: null - ,add: function (id, object) - { + ,add: function(id, object) { this._addedMap[id] = object; } - ,setParent: function (parentResult) - { + ,setParent: function(parentResult) { this._parentResult = parentResult; if (parentResult && !this.signalData) this.signalData = parentResult.builder.signalData; } - ,getMain: function (result) - { + ,getMain: function(result) { return result.objects[this._mainContext]; } - ,getById: function (result, objectId) - { + ,getById: function(result, objectId) { var index = this._contextMap[objectId]; if (index !== undefined) @@ -41,18 +36,16 @@ module.exports = new Class return object; if (this._parentResult) - return this._parentResult.getById (objectId); + return this._parentResult.getById(objectId); return null; } - ,getByTagName: function (result, tagName) - { + ,getByTagName: function(result, tagName) { var tags = this._tags[tagName]; - if (tags) - { - var arr = new Array (tags.length); + if (tags) { + var arr = new Array(tags.length); for (var i = 0; i < tags.length; i++) arr[i] = result.objects[tags[i]]; @@ -69,32 +62,28 @@ module.exports = new Class * @path String The XML path * @dstDocument Document The document used to create the nodes * @return %true on success, %false othersise - **/ - ,loadXml: function (path, dstDocument) - { + */ + ,loadXml: function(path, dstDocument) { this._path = path; - return this.loadFromXmlDoc (Vn.getXml (path), dstDocument); + return this.loadFromXmlDoc(Vn.getXml(path), dstDocument); } - ,loadFromString: function (xmlString, dstDocument) - { - var parser = new DOMParser (); - var xmlDoc = parser.parseFromString (xmlString, 'text/xml'); - return this.loadFromXmlDoc (xmlDoc, dstDocument); + ,loadFromString: function(xmlString, dstDocument) { + var parser = new DOMParser(); + var xmlDoc = parser.parseFromString(xmlString, 'text/xml'); + return this.loadFromXmlDoc(xmlDoc, dstDocument); } - ,loadFromXmlDoc: function (xmlDoc, dstDocument) - { + ,loadFromXmlDoc: function(xmlDoc, dstDocument, scope) { if (!xmlDoc) return false; - this._compileInit (dstDocument); + this._compileInit(dstDocument, scope); var docElement = xmlDoc.documentElement; - if (docElement.tagName !== 'vn') - { - this._showError ('Malformed XML'); + if (docElement.tagName !== 'vn') { + this._showError('Malformed XML'); this._contexts = null; return false; } @@ -103,9 +92,9 @@ module.exports = new Class if (childs) for (var i = 0; i < childs.length; i++) - this._compileNode (childs[i]); + this._compileNode(childs[i]); - this._compileEnd (); + this._compileEnd(); return true; } @@ -115,75 +104,130 @@ module.exports = new Class * @path Node The DOM node * @dstDocument Document The document used to create the nodes * @return %true on success, %false othersise - **/ - ,loadXmlFromNode: function (node, dstDocument) - { - this._compileInit (dstDocument); - this._mainContext = this._compileNode (node).id; - this._compileEnd (); + */ + ,loadXmlFromNode: function(node, dstDocument, scope) { + this._compileInit(dstDocument, scope); + this._mainContext = this._compileNode(node).id; + this._compileEnd(); return true; } - ,load: function () - { + ,load: function() { if (this._contexts === null) return null; var contexts = this._contexts; var len = contexts.length; - var objects = new Array (len); + var objects = new Array(len); - for (var i = 0; i < len; i++) - { + for (var i = 0; i < len; i++) { var context = contexts[i]; if (context.tagName) - objects[i] = this.elementInstantiate (context); + objects[i] = this.elementInstantiate(context); else if (context.klass) - objects[i] = this.objectInstantiate (context); + objects[i] = this.objectInstantiate(context); else - objects[i] = this.textInstantiate (context); + objects[i] = this.textInstantiate(context); } - return new BuilderResult (this, objects); + return new BuilderResult(this, objects); } - ,link: function (result) - { + ,link: function(result, self, scope) { var objects = result.objects; - for (var i = this._links.length - 1; i >= 0; i--) - { + for (var i = this._links.length - 1; i >= 0; i--) { var l = this._links[i]; var addedObject = this._addedMap[l.objectId]; - if (addedObject) - { + if (addedObject) { if (l.prop) objects[l.context.id][l.prop] = addedObject; else - objects[l.context.id].appendChild (addedObject); - } - else - this._showError ('Referenced unexistent object with id \'%s\'', + objects[l.context.id].appendChild(addedObject); + } else + this._showError('Referenced unexistent object with id \'%s\'', l.objectId); } + this.linkExpr(result, self, scope); + var contexts = this._contexts; - for (var i = 0; i < contexts.length; i++) - { + for (var i = 0; i < contexts.length; i++) { var context = contexts[i]; var object = objects[i]; if (context.tagName) - this.elementLink (context, object, objects, result); + this.elementLink(context, object, objects, result); else if (context.klass) - this.objectLink (context, object, objects, result); + this.objectLink(context, object, objects, result); } } + + ,fnExpr(expr) { + return new Function(this._scopeArgs, + '"use strict"; return ' + expr + ';' + ); + } - ,_compileInit: function (dstDocument) - { + ,matchExpr(value) { + const match = /^{{(.*)}}$/.exec(value); + if (!match) return null; + return this.fnExpr(match[1]); + } + + ,linkExpr(result, self, scope) { + const contexts = this._contexts; + const objects = result.objects; + let args = [_] + + if (scope) args = args.concat(scope); + + for (let i = 0; i < contexts.length; i++) { + const context = contexts[i]; + const object = objects[i]; + + if (context.exprs) { + const values = []; + for (expr of context.exprs) { + let value = undefined; + try { + value = expr.apply(self, args); + } catch (e) { + console.warn('Expression error:', e.message); + continue; + } + values.push(value); + } + + let k = 0; + const text = context.text.replace(/{{\d+}}/g, function() { + return values[k++]; + }); + object.textContent = text; + } else { + const dynProps = context.dynProps; + + for (const prop in dynProps) { + let value = undefined; + try { + value = dynProps[prop].apply(self, args); + } catch (e) { + console.warn('Expression error:', e.message); + continue; + } + + if (context.tagName) + object.setAttribute(prop, value); + else + object[prop] = value; + } + } + } + } + + ,_compileInit: function(dstDocument, scope) { this._path = null; this._tags = {}; this._contexts = []; @@ -191,61 +235,58 @@ module.exports = new Class this._links = []; this._mainContext = null; this._doc = dstDocument ? dstDocument : document; + + this._scope = ['_']; + if (scope) + this._scope = this._scope.concat(scope); + this._scopeArgs = this._scope.join(','); } - ,_compileEnd: function () - { - for (var i = this._links.length - 1; i >= 0; i--) - { + ,_compileEnd: function() { + for (var i = this._links.length - 1; i >= 0; i--) { var l = this._links[i]; var contextId = this._contextMap[l.objectId]; - if (contextId != undefined) - { + if (contextId != undefined) { if (l.prop) l.context.objectProps[l.prop] = contextId; else - l.context.childs.push (contextId); + l.context.childs.push(contextId); - this._links.splice (i, 1); - } - else - { + this._links.splice(i, 1); + } else { var object = this._addedMap[l.objectId]; if (!object && this._parentResult) - object = this._parentResult.getById (l.objectId); + object = this._parentResult.getById(l.objectId); - if (object) - { + if (object) { l.context.props[l.prop] = object; - this._links.splice (i, 1); + this._links.splice(i, 1); } } } } - ,_compileNode: function (node) - { + ,_compileNode: function(node) { var context = null; var tagName = null; if (node.nodeType === Node.ELEMENT_NODE) - tagName = node.tagName.toLowerCase (); + tagName = node.tagName.toLowerCase(); else if (node.nodeType !== Node.TEXT_NODE - || /^[\n\r\t]*$/.test (node.textContent)) + || /^[\n\r\t]*$/.test(node.textContent)) return null; var context = - this.textCompile (node, tagName) - || this.objectCompile (node, tagName) - || this.elementCompile (node, tagName); + this.textCompile(node, tagName) + || this.objectCompile(node, tagName) + || this.elementCompile(node, tagName); context.id = this._contexts.length; - if (tagName) - { - var nodeId = node.getAttribute ('id'); + if (tagName) { + var nodeId = node.getAttribute('id'); if (nodeId) this._contextMap[nodeId] = context.id; @@ -255,44 +296,53 @@ module.exports = new Class if (!tags) this._tags[tagName] = tags = []; - tags.push (context.id); + tags.push(context.id); } - this._contexts.push (context); + this._contexts.push(context); return context; } /** * Creates a text node context. - **/ - ,textCompile: function (node, tagName) - { - if (!tagName) - var text = node.textContent; - else if (tagName === 't') - var text = _(node.firstChild.textContent); + */ + ,textCompile: function(node, tagName) { + if (!tagName) { + let text = node.textContent; + + if (/{{.*}}/.test(text)) { + let i = 0; + const self = this; + const exprs = []; + text = text.replace(/{{((?:(?!}}).)*)}}/g, function(match, capture) { + exprs.push(self.fnExpr(capture)); + return `{{${i++}}}`; + }); + + return {text, exprs}; + } else + return {text}; + } else if (tagName === 't') + return {text: _(node.firstChild.textContent)}; else return null; - - return {text: text}; } - ,textInstantiate: function (context) - { - return this._doc.createTextNode (context.text); + ,textInstantiate: function(context) { + return this._doc.createTextNode(context.exprs ? '' : context.text); } /** * Creates a object context. - **/ - ,objectCompile: function (node, tagName) - { + */ + ,objectCompile: function(node, tagName) { var klass = vnCustomTags[tagName]; if (!klass) return null; var props = {}; + var dynProps = {}; var objectProps = {}; var childs = []; var events = {}; @@ -300,6 +350,7 @@ module.exports = new Class var context = { klass: klass, props: props, + dynProps: dynProps, objectProps: objectProps, childs: childs, events: events, @@ -308,21 +359,17 @@ module.exports = new Class var a = node.attributes; - for (var i = 0; i < a.length; i++) - { + for (var i = 0; i < a.length; i++) { var attribute = a[i].nodeName; var value = a[i].nodeValue; - if (this._isEvent (attribute)) - { - var handler = this._getMethod (value) + if (this._isEvent(attribute)) { + var handler = this._getMethod(value) if (handler) - events[attribute.substr (3)] = handler; - } - else if (!/^(id|property)$/.test (attribute)) - { - this.propCompile (context, klass, props, + events[attribute.substr(3)] = handler; + } else if (!/^(id|property)$/.test(attribute)) { + this.propCompile(context, klass, props, dynProps, node, attribute, value); } } @@ -330,97 +377,89 @@ module.exports = new Class var childNodes = node.childNodes; if (childNodes) - for (var i = 0; i < childNodes.length; i++) - { + for (var i = 0; i < childNodes.length; i++) { var child = childNodes[i]; var isElement = child.nodeType === Node.ELEMENT_NODE; - var childTagName = isElement ? child.tagName.toLowerCase () : null; + var childTagName = isElement ? child.tagName.toLowerCase() : null; var childContext; - if (childTagName === 'pointer') - { - this._addLink (context, null, child.getAttribute ('object')); - } - else if (childTagName === 'custom') - { + if (childTagName === 'pointer') { + this._addLink(context, null, child.getAttribute('object')); + } else if (childTagName === 'custom') { context.custom = child; - } - else if (childContext = this._compileNode (child)) - { - var prop = isElement ? child.getAttribute ('property') : null; + } else if (childContext = this._compileNode(child)) { + var prop = isElement ? child.getAttribute('property') : null; - if (prop) - { - prop = prop.replace (/-./g, this._replaceFunc); + if (prop) { + prop = prop.replace(/-./g, this._replaceFunc); objectProps[prop] = childContext.id; - } - else - childs.push (childContext.id); + } else + childs.push(childContext.id); } } return context; } - ,propCompile: function (context, klass, props, node, attribute, value) - { + ,propCompile: function(context, klass, props, dynProps, node, attribute, value) { var isLink = false; var newValue = null; - var propName = attribute.replace (/-./g, this._replaceFunc); + var propName = attribute.replace(/-./g, this._replaceFunc); var propInfo = klass.Properties[propName]; - if (!propInfo) - { - this._showError ('Attribute \'%s\' not valid for tag \'%s\'', + if (!propInfo) { + this._showError('Attribute \'%s\' not valid for tag \'%s\'', attribute, node.tagName); return; } - if (!value) - { - this._showError ('Attribute \'%s\' empty on tag \'%s\'', + if (!value) { + this._showError('Attribute \'%s\' empty on tag \'%s\'', attribute, node.tagName); return; } - switch (propInfo.type) - { + const expr = this.matchExpr(value); + + if (expr) { + dynProps[propName] = expr; + } else { + switch (propInfo.type) { case Boolean: - newValue = (/^(true|1)$/i).test (value); + newValue = (/^(true|1)$/i).test(value); break; case Number: - newValue = 0 + new Number (value); + newValue = 0 + new Number(value); break; case String: - newValue = this._translateValue (value); + newValue = this._translateValue(value); break; case Function: - var method = this._getMethod (value); - newValue = method ? method.bind (this.signalData) : null; + var method = this._getMethod(value); + newValue = method ? method.bind(this.signalData) : null; break; default: if (propInfo.enumType) newValue = propInfo.enumType[value]; else if (propInfo.type instanceof Function) isLink = true; + } + + if (isLink) + this._addLink(context, propName, value); + else if (newValue !== null && newValue !== undefined) + props[propName] = newValue; + else + this._showError('Attribute \'%s\' invalid for tag \'%s\'', + attribute, node.tagName); } - - if (isLink) - this._addLink (context, propName, value); - else if (newValue !== null && newValue !== undefined) - props[propName] = newValue; - else - this._showError ('Attribute \'%s\' invalid for tag \'%s\'', - attribute, node.tagName); } - ,objectInstantiate: function (context) - { - return new context.klass (); + ,objectInstantiate: function(context) { + return new context.klass(); } - ,objectLink: function (context, object, objects, res) - { - object.setProperties (context.props); + ,objectLink: function(context, object, objects, res) { + object.setProperties(context.props); var objectProps = context.objectProps; for (var prop in objectProps) @@ -428,42 +467,42 @@ module.exports = new Class var childs = context.childs; for (var i = 0; i < childs.length; i++) - object.appendChild (objects[childs[i]]); + object.appendChild(objects[childs[i]]); var events = context.events; for (var event in events) - object.on (event, events[event], this.signalData); + object.on(event, events[event], this.signalData); if (context.custom) - object.loadXml (res, context.custom); + object.loadXml(res, context.custom); } /** * Creates a HTML node context. - **/ - ,elementCompile: function (node, tagName) - { + */ + ,elementCompile: function(node, tagName) { var attributes = {}; + var dynProps = {}; var childs = []; var events = {}; var handler; var a = node.attributes; - for (var i = 0; i < a.length; i++) - { + for (var i = 0; i < a.length; i++) { var attribute = a[i].nodeName; var value = a[i].nodeValue; - - if (this._isEvent (attribute)) - { - var handler = this._getMethod (value); + const expr = this.matchExpr(value); + + if (expr) { + dynProps[attribute] = expr; + } else if (this._isEvent(attribute)) { + var handler = this._getMethod(value); if (handler) - events[attribute.substr (3)] = handler; - } - else if (attribute !== 'id') - attributes[attribute] = this._translateValue (value); + events[attribute.substr(3)] = handler; + } else if (attribute !== 'id') + attributes[attribute] = this._translateValue(value); } var childContext; @@ -471,145 +510,129 @@ module.exports = new Class if (childNodes) for (var i = 0; i < childNodes.length; i++) - if (childContext = this._compileNode (childNodes[i])) - childs.push (childContext.id); + if (childContext = this._compileNode(childNodes[i])) + childs.push(childContext.id); return { - tagName: tagName, - attributes: attributes, - childs: childs, - events: events + tagName, + attributes, + dynProps, + childs, + events }; } - ,elementInstantiate: function (context) - { - return this._doc.createElement (context.tagName); + ,elementInstantiate: function(context) { + return this._doc.createElement(context.tagName); } - ,elementLink: function (context, object, objects) - { + ,elementLink: function(context, object, objects) { var attributes = context.attributes; for (var attribute in attributes) - object.setAttribute (attribute, attributes[attribute]); + object.setAttribute(attribute, attributes[attribute]); var childs = context.childs; - for (var i = 0; i < childs.length; i++) - { + for (var i = 0; i < childs.length; i++) { var child = objects[childs[i]]; if (child instanceof Htk.Widget) child = child.node; if (child instanceof Node) - object.appendChild (child); + object.appendChild(child); } var events = context.events; for (var event in events) - object.addEventListener (event, - events[event].bind (this.signalData)); + object.addEventListener(event, + events[event].bind(this.signalData)); } - ,_showError: function (error) - { + ,_showError: function(error) { var path = this._path ? this._path : 'Node'; var logArgs = ['Vn.Builder: %s: '+ error, path]; for (var i = 1; i < arguments.length; i++) - logArgs.push (arguments[i]); + logArgs.push(arguments[i]); - console.warn.apply (null, logArgs); + console.warn.apply(null, logArgs); } - ,_addLink: function (context, prop, objectId) - { - this._links.push ({ + ,_addLink: function(context, prop, objectId) { + this._links.push({ context: context ,prop: prop ,objectId: objectId }); } - ,_translateValue: function (value) - { - var chr = value.charAt (0); + ,_translateValue: function(value) { + var chr = value.charAt(0); if (chr === '_') - return _(value.substr (1)); - else if (chr === '\\' && value.charAt (1) === '_') - return value.substr (1); + return _(value.substr(1)); + else if (chr === '\\' && value.charAt(1) === '_') + return value.substr(1); return value; } - ,_getMethod: function (value) - { + ,_getMethod: function(value) { if (this.signalData) var method = this.signalData[value]; else var method = window[value]; if (method === undefined) - this._showError ('Function \'%s\' not found', value); + this._showError('Function \'%s\' not found', value); return method; } - ,_isEvent: function (attribute) - { - return /^on-\w+/.test (attribute); + ,_isEvent: function(attribute) { + return /^on-\w+/.test(attribute); } - ,_replaceFunc: function (token) - { - return token.charAt(1).toUpperCase (); + ,_replaceFunc: function(token) { + return token.charAt(1).toUpperCase(); } }); -var BuilderResult = new Class -({ +var BuilderResult = new Class({ Extends: Object - ,initialize: function (builder, objects) - { + ,initialize: function(builder, objects) { this.builder = builder; this.objects = objects; } - ,getMain: function () - { - return this.builder.getMain (this); + ,getMain: function() { + return this.builder.getMain(this); } - ,$: function (objectId) - { - return this.builder.getById (this, objectId); + ,$: function(objectId) { + return this.builder.getById(this, objectId); } - ,getById: function (objectId) - { - return this.builder.getById (this, objectId); + ,getById: function(objectId) { + return this.builder.getById(this, objectId); } - ,getByTagName: function (tagName) - { - return this.builder.getByTagName (this, tagName); + ,getByTagName: function(tagName) { + return this.builder.getByTagName(this, tagName); } - ,link: function () - { - this.builder.link (this); + ,link: function(self, scope) { + this.builder.link(this, self, scope); } - ,_destroy: function () - { + ,_destroy: function() { var objects = this.objects; for (var i = 0; i < objects.length; i++) if (objects[i] instanceof Object) - objects[i].unref (); + objects[i].unref(); - this.parent (); + this.parent(); } }); diff --git a/js/vn/date.js b/js/vn/date.js index 96b5a8e0..256c2edb 100644 --- a/js/vn/date.js +++ b/js/vn/date.js @@ -49,7 +49,7 @@ module.exports = ,'Feb' ,'Mar' ,'Apr' - ,'May' + ,'AbrMay' ,'Jun' ,'Jul' ,'Ago' diff --git a/js/vn/locale/ca.yml b/js/vn/locale/ca.yml index cba6b455..8af6588c 100644 --- a/js/vn/locale/ca.yml +++ b/js/vn/locale/ca.yml @@ -27,6 +27,7 @@ December: Decembre Jan: Gen Feb: Febr Mar: Març +AbrMay: Mai Apr: Abr Jun: Juny Jul: Jul diff --git a/js/vn/locale/en.yml b/js/vn/locale/en.yml index ea9ffe58..4ca5bcfa 100644 --- a/js/vn/locale/en.yml +++ b/js/vn/locale/en.yml @@ -28,6 +28,7 @@ Jan: Jan Feb: Feb Mar: Mar Apr: Apr +AbrMay: May Jun: Jun Jul: Jul Ago: Ago diff --git a/js/vn/locale/es.yml b/js/vn/locale/es.yml index 254dffc9..d9663c12 100644 --- a/js/vn/locale/es.yml +++ b/js/vn/locale/es.yml @@ -16,7 +16,7 @@ January: Enero February: Febrero March: Marzo April: Abril -May: May +May: Mayo June: Junio July: Julio August: Agosto @@ -28,6 +28,7 @@ Jan: Ene Feb: Feb Mar: Mar Apr: Abr +AbrMay: May Jun: Jun Jul: Jul Ago: Ago diff --git a/js/vn/locale/fr.yml b/js/vn/locale/fr.yml index bf6b5ba6..a2789597 100644 --- a/js/vn/locale/fr.yml +++ b/js/vn/locale/fr.yml @@ -28,6 +28,7 @@ Jan: Jan Feb: Fév Mar: Mars Apr: Avr +AbrMay: Mai Jun: Juin Jul: Juil Ago: Août diff --git a/js/vn/locale/mn.yml b/js/vn/locale/mn.yml index 9719aec5..97eb4d32 100644 --- a/js/vn/locale/mn.yml +++ b/js/vn/locale/mn.yml @@ -28,6 +28,7 @@ Jan: оны Feb: хоё Mar: Гур Apr: Дөр +AbrMay: May Jun: Jun Jul: Jul Ago: Най diff --git a/js/vn/locale/pt.yml b/js/vn/locale/pt.yml index 05ca2b73..db6c2892 100644 --- a/js/vn/locale/pt.yml +++ b/js/vn/locale/pt.yml @@ -28,6 +28,7 @@ Jan: Jan Feb: Fev Mar: Mar Apr: Abr +AbrMay: Mai Jun: Jun Jul: Jul Ago: Ago