Checkpoint
gitea/hedera-web/pipeline/head This commit looks good Details

This commit is contained in:
Juan Ferrer 2022-05-30 03:30:33 +02:00
parent 894ff77877
commit de19063ed9
118 changed files with 3166 additions and 1895 deletions

View File

@ -9,7 +9,7 @@ Hedera.AddressList = new Class
} }
,onAddAddressClick: function() { ,onAddAddressClick: function() {
this.hash.set({ this.hash.setAll({
form: 'account/address', form: 'account/address',
address: 0 address: 0
}); });
@ -33,7 +33,7 @@ Hedera.AddressList = new Class
} }
,onEditAddressClick: function(id) { ,onEditAddressClick: function(id) {
this.hash.set({ this.hash.setAll({
form: 'account/address', form: 'account/address',
address: id address: id
}); });

View File

@ -9,20 +9,12 @@ Hedera.Address = new Class({
}, },
onStatusChange: function() { onStatusChange: function() {
if (this.$.iter.ready && this.$.address.value == 0) if (this.$.iter.ready && this.hash.$.address == 0)
this.$.iter.insertRow(); this.$.iter.insertRow();
}, },
onOperationsDone: function() { onOperationsDone: function() {
Htk.Toast.showMessage(_('AddressChangedSuccessfully')); Htk.Toast.showMessage(_('AddressChangedSuccessfully'));
this.onReturnClick(); window.history.back()
},
onAcceptClick: function() {
this.$.iter.performOperations();
},
onReturnClick: function() {
window.history.back();
} }
}); });

View File

@ -1,24 +1,21 @@
<vn> <vn>
<vn-group> <vn-group>
<vn-param id="address"/> <vn-lot-query id="params">
<vn-hash-param key="address" param="address"/> <vn-spec name="address" type="Number"/>
</vn-lot-query>
<db-form id="iter" on-status-changed="this.onStatusChange()"> <db-form id="iter" on-status-changed="this.onStatusChange()">
<db-model <db-model
id="model" id="model"
property="model" property="model"
updatable="true" updatable="true"
mode="ON_DEMAND" mode="ON_DEMAND"
lot="params"
on-operations-done="this.onOperationsDone()"> on-operations-done="this.onOperationsDone()">
SELECT a.id, a.street, a.nickname, a.city, SELECT a.id, a.street, a.nickname, a.city,
a.postalCode, a.provinceFk, p.countryFk a.postalCode, a.provinceFk, p.countryFk
FROM myAddress a FROM myAddress a
LEFT JOIN vn.province p ON p.id = a.provinceFk LEFT JOIN vn.province p ON p.id = a.provinceFk
WHERE a.id = #address WHERE a.id = #address
<sql-batch property="batch">
<custom>
<item name="address" param="address"/>
</custom>
</sql-batch>
</db-model> </db-model>
</db-form> </db-form>
</vn-group> </vn-group>
@ -29,11 +26,11 @@
<htk-bar-button <htk-bar-button
icon="close" icon="close"
tip="_Return" tip="_Return"
on-click="this.onReturnClick()"/> on-click="window.history.back()"/>
<htk-bar-button <htk-bar-button
icon="check" icon="check"
tip="_Accept" tip="_Accept"
on-click="this.onAcceptClick()"/> on-click="$.iter.performOperations()"/>
</div> </div>
<div id="form" class="address"> <div id="form" class="address">
<div class="form box vn-w-sm vn-pa-lg"> <div class="form box vn-w-sm vn-pa-lg">
@ -63,11 +60,11 @@
<div class="form-group"> <div class="form-group">
<htk-combo <htk-combo
placeholder="_Country"> placeholder="_Country">
<db-param <vn-param
id="country" id="country"
property="param" property="param"
form="iter" lot="iter"
column="countryFk" name="countryFk"
one-way="true"/> one-way="true"/>
<db-model property="model"> <db-model property="model">
SELECT id, country FROM vn.country SELECT id, country FROM vn.country
@ -80,15 +77,10 @@
placeholder="_Province" placeholder="_Province"
column="provinceFk" column="provinceFk"
form="iter"> form="iter">
<db-model property="model"> <db-model property="model" lot="iter">
SELECT id, name FROM vn.province SELECT id, name FROM vn.province
WHERE countryFk = #country WHERE countryFk = #countryFk
ORDER BY name ORDER BY name
<sql-batch property="batch">
<custom>
<item name="country" param="country"/>
</custom>
</sql-batch>
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>

View File

@ -9,7 +9,7 @@ Hedera.Conf = new Class({
if (this.hash.$.verificationToken) if (this.hash.$.verificationToken)
this.onPassChangeClick(); this.onPassChangeClick();
} }
,onPassChangeClick: function() { ,onPassChangeClick: function() {
this.$.oldPassword.value = ''; this.$.oldPassword.value = '';
this.$.newPassword.value = ''; this.$.newPassword.value = '';
@ -75,9 +75,5 @@ Hedera.Conf = new Class({
,onPassInfoClick: function() { ,onPassInfoClick: function() {
this.$.passwordInfo.show(); this.$.passwordInfo.show();
} }
,onAddressesClick: function() {
this.hash.set({form: 'account/address-list'});
}
}); });

View File

@ -27,7 +27,7 @@
<htk-bar-button <htk-bar-button
icon="place" icon="place"
tip="_Addresses" tip="_Addresses"
on-click="this.onAddressesClick()"/> on-click="$.hash.setAll({form: 'account/address-list'})"/>
<htk-bar-button <htk-bar-button
icon="lock_reset" icon="lock_reset"
tip="_Change password" tip="_Change password"

View File

@ -1,21 +1,12 @@
<vn> <vn>
<vn-group> <vn-group>
<vn-param id="user"/> <db-form id="user">
<vn-hash-param key="user" param="user"/> <db-model property="model" lot="hash">
<db-form id="userForm"> SELECT u.id, u.name user, u.nickname, u.email, c.phone, r.name role
<db-model property="model"> FROM account.user u
<custom> JOIN account.role r ON r.id = u.role
SELECT u.id, u.name user, u.nickname, u.email, c.phone, r.name role LEFT JOIN vn.client c ON c.id = u.id
FROM account.user u WHERE u.id = #user
JOIN account.role r ON r.id = u.role
LEFT JOIN vn.client c ON c.id = u.id
WHERE u.id = #user
</custom>
<sql-batch property="batch">
<custom>
<item name="user" param="user"/>
</custom>
</sql-batch>
</db-model> </db-model>
</db-form> </db-form>
</vn-group> </vn-group>
@ -25,29 +16,22 @@
<div id="form" class="access-log"> <div id="form" class="access-log">
<div class="box vn-w-xs vn-pa-lg"> <div class="box vn-w-xs vn-pa-lg">
<div class="form"> <div class="form">
<h4><htk-text form="user-form" column="nickname"/></h4> <h4><htk-text form="user" column="nickname"/></h4>
<p>#<htk-text form="user-form" column="id"/> - <htk-text form="user-form" column="user"/></p> <p>#<htk-text form="user" column="id"/> - <htk-text form="user" column="user"/></p>
<p><htk-text form="user-form" column="role"/></p> <p><htk-text form="user" column="role"/></p>
<p><htk-text form="user-form" column="email"/></p> <p><htk-text form="user" column="email"/></p>
<p><htk-text form="user-form" column="phone"/></p> <p><htk-text form="user" column="phone"/></p>
</div> </div>
</div> </div>
<htk-repeater form-id="iter" class="box vn-w-xs htk-list vn-mt-md"> <htk-repeater form-id="iter" class="box vn-w-xs htk-list vn-mt-md">
<db-model property="model"> <db-model property="model" lot="hash">
<custom> SELECT u.stamp, a.platform, a.browser, a.version, a.javascript, a.cookies
SELECT u.stamp, a.platform, a.browser, a.version, a.javascript, a.cookies FROM visitUser u
FROM visitUser u JOIN visitAccess c ON c.id = u.accessFk
JOIN visitAccess c ON c.id = u.accessFk JOIN visitAgent a ON a.id = c.agentFk
JOIN visitAgent a ON a.id = c.agentFk WHERE u.userFk = #user
WHERE u.userFk = #user ORDER BY u.stamp DESC
ORDER BY u.stamp DESC LIMIT 8
LIMIT 8
</custom>
<sql-batch property="batch">
<custom>
<item name="user" param="user"/>
</custom>
</sql-batch>
</db-model> </db-model>
<custom> <custom>
<div class="item"> <div class="item">

View File

@ -25,7 +25,7 @@ Hedera.Connections = new Class({
} }
,_onUserSupplant: function() { ,_onUserSupplant: function() {
this.hash.set({form: 'ecomerce/orders'}); this.hash.setAll({form: 'ecomerce/orders'});
} }
,sessionsFunc: function() { ,sessionsFunc: function() {

View File

@ -23,17 +23,15 @@
property="model" property="model"
id="sessions" id="sessions"
on-status-changed="this.onModelStatusChange()"> on-status-changed="this.onModelStatusChange()">
<custom> SELECT vu.userFk userId, vu.stamp, u.nickname, s.lastUpdate,
SELECT vu.userFk userId, vu.stamp, u.nickname, s.lastUpdate, a.platform, a.browser, a.version, u.name user
a.platform, a.browser, a.version, u.name user FROM userSession s
FROM userSession s JOIN visitUser vu ON vu.id = s.userVisitFk
JOIN visitUser vu ON vu.id = s.userVisitFk JOIN visitAccess ac ON ac.id = vu.accessFk
JOIN visitAccess ac ON ac.id = vu.accessFk JOIN visitAgent a ON a.id = ac.agentFk
JOIN visitAgent a ON a.id = ac.agentFk JOIN visit v ON v.id = a.visitFk
JOIN visit v ON v.id = a.visitFk JOIN account.user u ON u.id = vu.userFk
JOIN account.user u ON u.id = vu.userFk ORDER BY lastUpdate DESC
ORDER BY lastUpdate DESC
</custom>
</db-model> </db-model>
<custom> <custom>
<a class="item" <a class="item"

View File

@ -1,20 +1,16 @@
<vn> <vn>
<vn-group>
<vn-param id="filter"/>
<vn-hash-param key="filter" param="filter"/>
</vn-group>
<div id="title"> <div id="title">
<h1><t>Items</t></h1> <h1><t>Items</t></h1>
</div> </div>
<div id="actions"> <div id="actions">
<htk-search-entry param="filter"/> <htk-search-entry form="hash" column="search"/>
</div> </div>
<div id="form" class="items"> <div id="form" class="items">
<htk-repeater <htk-repeater
class="htk-list rows box vn-w-xs" class="htk-list rows box vn-w-xs"
form-id="iter" form-id="iter"
empty-message="_Enter a search term"> empty-message="_Enter a search term">
<db-model property="model" id="items"> <db-model property="model" id="items" lot="hash">
SELECT i.id, i.longName, i.size, i.category, SELECT i.id, i.longName, i.size, i.category,
i.value5, i.value6, i.value7, i.value5, i.value6, i.value7,
i.image, im.updated i.image, im.updated
@ -22,14 +18,9 @@
LEFT JOIN image im LEFT JOIN image im
ON im.collectionFk = 'catalog' ON im.collectionFk = 'catalog'
AND im.name = i.image AND im.name = i.image
WHERE i.longName LIKE CONCAT('%', #filter, '%') WHERE i.longName LIKE CONCAT('%', #search, '%')
OR i.id = #filter OR i.id = #search
ORDER BY i.longName LIMIT 50 ORDER BY i.longName LIMIT 50
<sql-batch property="batch">
<custom>
<item name="filter" param="filter"/>
</custom>
</sql-batch>
</db-model> </db-model>
<custom> <custom>
<div class="item"> <div class="item">

View File

@ -1,34 +1,22 @@
<vn> <vn>
<vn-group>
<vn-param id="user-name"/>
<vn-hash-param key="user" param="user-name"/>
</vn-group>
<div id="title"> <div id="title">
<h1><t>User management</t></h1> <h1><t>User management</t></h1>
</div> </div>
<div id="actions"> <div id="actions">
<htk-search-entry <htk-search-entry form="hash" column="user"/>
param="user-name"/>
</div> </div>
<div id="form" class="users"> <div id="form" class="users">
<htk-repeater <htk-repeater
form-id="iter" form-id="iter"
renderer="rendererFunc" renderer="rendererFunc"
class="htk-list box vn-w-xs"> class="htk-list box vn-w-xs">
<db-model property="model"> <db-model property="model" lot="hash">
<custom> SELECT u.id, u.name, u.nickname, u.active
SELECT u.id, u.name, u.nickname, u.active FROM account.user u
FROM account.user u WHERE u.name LIKE CONCAT('%', #user, '%')
WHERE u.name LIKE CONCAT('%', #user, '%') OR u.nickname LIKE CONCAT('%', #user, '%')
OR u.nickname LIKE CONCAT('%', #user, '%') OR u.id = #user
OR u.id = #user ORDER BY u.name LIMIT 200
ORDER BY u.name LIMIT 200
</custom>
<sql-batch property="batch">
<custom>
<item name="user" param="user-name"/>
</custom>
</sql-batch>
</db-model> </db-model>
<custom> <custom>
<a class="users-box item" <a class="users-box item"

View File

@ -16,7 +16,7 @@ Hedera.Users = new Class({
} }
,onUserSupplant: function() { ,onUserSupplant: function() {
this.hash.set({form: 'ecomerce/orders'}); this.hash.setAll({form: 'ecomerce/orders'});
} }
}); });

View File

@ -1,4 +1,8 @@
<vn> <vn>
<vn-lot-query id="params">
<vn-spec name="from" type="Date"/>
<vn-spec name="to" type="Date"/>
</vn-lot-query>
<div id="title"> <div id="title">
<h1><t>Visits</t></h1> <h1><t>Visits</t></h1>
</div> </div>
@ -6,26 +10,26 @@
<htk-bar-button <htk-bar-button
icon="refresh" icon="refresh"
tip="_Refresh" tip="_Refresh"
on-click="this.onRefreshClick()"/> on-click="$.visits.refresh()"/>
<htk-bar-button <htk-bar-button
icon="visibility" icon="visibility"
tip="_Connections" tip="_Connections"
on-click="this.onSessionsClick()"/> on-click="this.hash.setAll({form: 'admin/connections'})"/>
</div> </div>
<div id="form" class="visits"> <div id="form" class="visits">
<div class="vn-w-xs"> <div class="vn-w-xs">
<div class="form vn-pa-lg box"> <div class="form vn-pa-lg box">
<div class="form-group"> <div class="form-group">
<label><t>From</t></label> <label><t>From</t></label>
<htk-date-chooser> <htk-date-chooser
<vn-param property="param" id="from"/> form="params"
</htk-date-chooser> column="from"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>To</t></label> <label><t>To</t></label>
<htk-date-chooser> <htk-date-chooser
<vn-param property="param" id="to"/> form="params"
</htk-date-chooser> column="to"/>
</div> </div>
</div> </div>
<div class="summary vn-pa-lg box"> <div class="summary vn-pa-lg box">
@ -50,27 +54,19 @@
class="box htk-list" class="box htk-list"
form-id="iter" form-id="iter"
empty-message="_Select date interval"> empty-message="_Select date interval">
<db-model property="model" id="visits"> <db-model property="model" id="visits" lot="params">
<custom> SELECT browser,
SELECT browser, MIN(CAST(version AS DECIMAL(4,1))) minVersion,
MIN(CAST(version AS DECIMAL(4,1))) minVersion, MAX(CAST(version AS DECIMAL(4,1))) maxVersion,
MAX(CAST(version AS DECIMAL(4,1))) maxVersion, MAX(c.stamp) lastVisit,
MAX(c.stamp) lastVisit, COUNT(DISTINCT c.id) visits,
COUNT(DISTINCT c.id) visits, SUM(a.firstAccessFk = c.id AND v.firstAgentFk = a.id) newVisits
SUM(a.firstAccessFk = c.id AND v.firstAgentFk = a.id) newVisits FROM visitUser e
FROM visitUser e JOIN visitAccess c ON c.id = e.accessFk
JOIN visitAccess c ON c.id = e.accessFk JOIN visitAgent a ON a.id = c.agentFk
JOIN visitAgent a ON a.id = c.agentFk JOIN visit v ON v.id = a.visitFk
JOIN visit v ON v.id = a.visitFk WHERE c.stamp BETWEEN TIMESTAMP(#from,'00:00:00') AND TIMESTAMP(#to,'23:59:59')
WHERE c.stamp BETWEEN TIMESTAMP(#from,'00:00:00') AND TIMESTAMP(#to,'23:59:59') GROUP BY browser ORDER BY visits DESC
GROUP BY browser ORDER BY visits DESC
</custom>
<sql-batch property="batch">
<custom>
<item name="from" param="from"/>
<item name="to" param="to"/>
</custom>
</sql-batch>
</db-model> </db-model>
<custom> <custom>
<div class="item"> <div class="item">

View File

@ -3,16 +3,11 @@ Hedera.Visits = new Class({
Extends: Hedera.Form Extends: Hedera.Form
,activate: function() { ,activate: function() {
this.$.from.value = new Date(); if (!this.hash.$.to)
this.$.to.value = new Date(); this.hash.assign({
} from: new Date(),
to: new Date()
,onRefreshClick: function() { });
this.$.visits.refresh();
}
,onSessionsClick: function() {
this.hash.set({form: 'admin/connections'});
} }
}); });

View File

@ -3,7 +3,7 @@ Hedera.Packages = new Class({
Extends: Hedera.Form Extends: Hedera.Form
,onShowClick: function(column, agencyId) { ,onShowClick: function(column, agencyId) {
this.hash.set({ this.hash.setAll({
form: 'agencies/provinces', form: 'agencies/provinces',
agency: agencyId agency: agencyId
}); });

View File

@ -1,6 +1,5 @@
Hedera.Provinces = new Class Hedera.Provinces = new Class({
({
Extends: Hedera.Form Extends: Hedera.Form
}); });

View File

@ -1,23 +1,12 @@
<vn> <vn>
<vn-group>
<vn-param id="agency"/>
<vn-hash-param key="agency" param="agency"/>
</vn-group>
<div id="title"> <div id="title">
<h1><t>ByProvince</t></h1> <h1><t>ByProvince</t></h1>
</div> </div>
<div id="form" class="provinces vn-w-sm"> <div id="form" class="provinces vn-w-sm">
<div class="box"> <div class="box">
<htk-grid> <htk-grid>
<db-model property="model"> <db-model property="model" lot="hash">
<custom> CALL vn2008.desglose_volume(#agency)
CALL vn2008.desglose_volume(#agency)
</custom>
<sql-batch property="batch">
<custom>
<item name="agency" param="agency"/>
</custom>
</sql-batch>
</db-model> </db-model>
<htk-column-text title="_Province" column="Provincia"/> <htk-column-text title="_Province" column="Provincia"/>
<htk-column-spin title="_Expeditions" column="expediciones"/> <htk-column-spin title="_Expeditions" column="expediciones"/>

View File

@ -7,7 +7,7 @@
class="start-order" class="start-order"
icon="add_shopping_cart" icon="add_shopping_cart"
tip="_Start order" tip="_Start order"
on-click="this.hash.set({form: 'ecomerce/catalog'})"/> on-click="$.hash.setAll({form: 'ecomerce/catalog'})"/>
</div> </div>
<div id="form" class="home"> <div id="form" class="home">
<div class="column mansonry" id="news-column"> <div class="column mansonry" id="news-column">

View File

@ -6,7 +6,7 @@ Hedera.Basket = new Class({
this.close(); this.close();
this.isOpen = true; this.isOpen = true;
Hedera.BasketChecker.check(this.conn, Hedera.BasketChecker.check(this.conn, this.hash,
this.onBasketCheck.bind(this)); this.onBasketCheck.bind(this));
} }
@ -21,7 +21,7 @@ Hedera.Basket = new Class({
,onConfigureClick: function() { ,onConfigureClick: function() {
Htk.Toast.showWarning(_('RememberReconfiguringImpact')); Htk.Toast.showWarning(_('RememberReconfiguringImpact'));
this.hash.set({form: 'ecomerce/checkout'}); this.hash.setAll({form: 'ecomerce/checkout'});
} }
,onDeleteClick: function(form) { ,onDeleteClick: function(form) {

View File

@ -10,11 +10,11 @@
<htk-bar-button <htk-bar-button
icon="local_florist" icon="local_florist"
tip="_Catalog" tip="_Catalog"
on-click="this.hash.set({form: 'ecomerce/catalog'})"/> on-click="this.hash.setAll({form: 'ecomerce/catalog'})"/>
<htk-bar-button <htk-bar-button
icon="shopping_cart_checkout" icon="shopping_cart_checkout"
tip="_Checkout" tip="_Checkout"
on-click="this.hash.set({form: 'ecomerce/confirm'})"/> on-click="this.hash.setAll({form: 'ecomerce/confirm'})"/>
</div> </div>
<div id="form" class="basket"> <div id="form" class="basket">
<div class="box vn-w-sm vn-pa-lg"> <div class="box vn-w-sm vn-pa-lg">

View File

@ -8,8 +8,8 @@ Hedera.Catalog = new Class({
this.close(); this.close();
this.isOpen = true; this.isOpen = true;
if (!localStorage.getItem('hederaGuest')) { if (!localStorage.getItem('hederaGuest')) {
Hedera.BasketChecker.check(this.conn, Hedera.BasketChecker.check(this.conn, this.hash,
this.onBasketCheck.bind(this)); this.onBasketCheck.bind(this));
} else { } else {
var query = 'CALL mybasket_configureForGuest'; var query = 'CALL mybasket_configureForGuest';
@ -42,36 +42,24 @@ Hedera.Catalog = new Class({
,onFilterChange: function() { ,onFilterChange: function() {
const $ = this.$; const $ = this.$;
const params = [ const hash = this.hash;
'search',
'realm',
'type',
'color',
'origin',
'category',
'producer'
];
const lot = {};
for (const param of params)
lot[param] = this.$[param].value;
if (lot.search != null || lot.type != null) { if (hash.search != null || hash.type != null) {
const filter = new Sql.Operation({ const filter = new Sql.Operation({
type: Sql.Operation.Type.AND type: Sql.Operation.Type.AND
}); });
const exprs = filter.exprs;
let idSearch = false; let idSearch = false;
if (lot.search != null) { if (hash.search != null) {
idSearch = /^\d+$/.test(lot.search); idSearch = /^\d+$/.test(hash.search);
exprs.add(idSearch ? $.idOp : $.nameOp); filter.push(idSearch ? $.idOp : $.nameOp);
} }
if (!idSearch) { if (!idSearch) {
if (lot.realm != null) if (hash.realm != null)
exprs.add($.realmOp); filter.push($.realmOp);
if (lot.type != null) if (hash.type != null)
exprs.add($.typeOp); filter.push($.typeOp);
const tags = [ const tags = [
'color', 'color',
@ -80,28 +68,21 @@ Hedera.Catalog = new Class({
'producer' 'producer'
]; ];
for (const tag of tags) for (const tag of tags)
if (lot[tag] != null) if (hash[tag] != null)
exprs.add($[`${tag}Op`]); filter.push($[`${tag}Op`]);
} }
const batch = new Sql.Batch(); const lot = new Vn.Lot();
batch.addObject('filter', filter); lot.set('filter', filter);
batch.block(); $.items.lot = lot;
$.items.batch = batch;
} else } else
$.items.batch = null; $.items.lot = null;
} }
,onRealmChange: function() { ,onRealmChange: function() {
const hasRealm = this.$.realm.value != null; const hasRealm = this.$.realm.value != null;
this.$.filters.style.display = hasRealm ? 'block' : 'none'; this.$.filters.style.display = hasRealm ? 'block' : 'none';
this.$.realmMsg.style.display = hasRealm ? 'none' : 'block'; this.$.realmMsg.style.display = hasRealm ? 'none' : 'block';
this.onFilterChange();
this.refreshTitle();
}
,onTypeChange: function() {
this.onFilterChange();
this.refreshTitle(); this.refreshTitle();
} }
@ -234,14 +215,14 @@ Hedera.Catalog = new Class({
if (this.isGuest()) if (this.isGuest())
return; return;
this.hash.set({form: 'ecomerce/basket'}); this.hash.setAll({form: 'ecomerce/basket'});
} }
,onConfigureClick: function() { ,onConfigureClick: function() {
if (this.isGuest()) if (this.isGuest())
return; return;
this.hash.set({form: 'ecomerce/checkout'}); this.hash.setAll({form: 'ecomerce/checkout'});
} }
,onAddItemClick: function(event, form) { ,onAddItemClick: function(event, form) {
@ -280,7 +261,6 @@ Hedera.Catalog = new Class({
,onConfirmClick: function() { ,onConfirmClick: function() {
var sql = ''; var sql = '';
var batch = new Sql.Batch();
var query = new Sql.String({query: 'CALL myBasket_addItem(#warehouse, #item, #amount);'}); var query = new Sql.String({query: 'CALL myBasket_addItem(#warehouse, #item, #amount);'});
var amountSum = 0; var amountSum = 0;
@ -288,10 +268,12 @@ Hedera.Catalog = new Class({
var amount = this.items[warehouse]; var amount = this.items[warehouse];
amountSum += amount; amountSum += amount;
batch.addValue('warehouse', warehouse); const params = {
batch.addValue('item', this.$.cardItem.value); warehouse: warehouse,
batch.addValue('amount', amount); item: this.$.cardItem.value,
sql += query.render(batch); amount: amount
}
sql += query.render(params);
} }
if (amountSum > 0) { if (amountSum > 0) {
@ -336,7 +318,7 @@ Vn.Filter = new Class({
model: { model: {
type: Db.Model type: Db.Model
,set: function(x) { ,set: function(x) {
x.batch = this._batch; x.lot = this._lot;
this._model = x; this._model = x;
this._select.model = x; this._select.model = x;
} }
@ -358,7 +340,7 @@ Vn.Filter = new Class({
type: Sql.Filter type: Sql.Filter
,set: function(x) { ,set: function(x) {
this._filter = x; this._filter = x;
this._batch.addObject('filter', x); this._lot.set('filter', x);
} }
,get: function() { ,get: function() {
return this._filter; return this._filter;
@ -382,7 +364,7 @@ Vn.Filter = new Class({
this._ul = this.createElement('ul'); this._ul = this.createElement('ul');
this.node.appendChild(this._ul); this.node.appendChild(this._ul);
this._batch = new Sql.Batch(); this._lot = new Vn.Lot();
this.parent(props); this.parent(props);
} }
@ -418,9 +400,9 @@ Vn.Filter = new Class({
} }
,_changeValue: function(newValue) { ,_changeValue: function(newValue) {
this._batch.block(); this._lot.block();
this.value = newValue; this.value = newValue;
this._batch.unblock(); this._lot.unblock();
} }
,_onTimeout: function() { ,_onTimeout: function() {

View File

@ -157,7 +157,7 @@
font-size: 1em; font-size: 1em;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
max-height: 2.8em; max-height: 3em;
} }
.item-info > p { .item-info > p {
margin: 0; margin: 0;
@ -247,7 +247,7 @@
flex-direction: column; flex-direction: column;
width: 240px; width: 240px;
height: 405px; height: 410px;
overflow: hidden; overflow: hidden;
} }
.grid-view .item-box:hover { .grid-view .item-box:hover {

View File

@ -22,18 +22,11 @@
</button> </button>
</div> </div>
<vn-group> <vn-group>
<vn-hash-param key="realm" param="realm"/> <vn-lot-query id="params" on-change="this.onFilterChange()">
<vn-hash-param key="type" param="type"/> <vn-spec name="search" type="String"/>
</vn-group> <vn-spec name="realm" type="Number"/>
<vn-group> <vn-spec name="type" type="Number"/>
<vn-param id="card-item"/> </vn-lot-query>
<vn-param id="search" on-changed="this.onFilterChange()"/>
<vn-param id="realm" on-changed="this.onRealmChange()"/>
<vn-param id="type" on-changed="this.onTypeChange()"/>
<vn-param id="color" on-changed="this.onFilterChange()"/>
<vn-param id="origin" on-changed="this.onFilterChange()"/>
<vn-param id="category" on-changed="this.onFilterChange()"/>
<vn-param id="producer" on-changed="this.onFilterChange()"/>
</vn-group> </vn-group>
<vn-group> <vn-group>
<sql-operation <sql-operation
@ -125,11 +118,7 @@
LIMIT 5000; LIMIT 5000;
</db-model> </db-model>
<db-form id="card" model="items"/> <db-form id="card" model="items"/>
<sql-batch id="card-batch"> <vn-lot id="card-lot"/>
<custom>
<item name="item" param="card-item"/>
</custom>
</sql-batch>
</vn-group> </vn-group>
<div id="form" class="catalog"> <div id="form" class="catalog">
<div id="main" class="main"> <div id="main" class="main">
@ -383,7 +372,7 @@
<db-form id="card-extend"> <db-form id="card-extend">
<db-model <db-model
property="model" property="model"
batch="card-batch" lot="card-lot"
on-status-changed-after="onCardLoad"> on-status-changed-after="onCardLoad">
SELECT i.description, o.name origin SELECT i.description, o.name origin
FROM vn.item i FROM vn.item i
@ -421,7 +410,7 @@
<htk-repeater show-status="false" form-id="tag" class="tags"> <htk-repeater show-status="false" form-id="tag" class="tags">
<db-model <db-model
property="model" property="model"
batch="card-batch" lot="card-lot"
on-status-changed-after="onCardLoad"> on-status-changed-after="onCardLoad">
SELECT l.name, it.value SELECT l.name, it.value
FROM vn.itemTag it FROM vn.itemTag it
@ -445,7 +434,7 @@
property="model" property="model"
result-index="1" result-index="1"
on-status-changed-after="onCardLoad" on-status-changed-after="onCardLoad"
batch="card-batch"> lot="card-lot">
CALL myBasket_calcCatalogFromItem(#item); CALL myBasket_calcCatalogFromItem(#item);
SELECT l.warehouseFk, w.name warehouse, p.`grouping`, SELECT l.warehouseFk, w.name warehouse, p.`grouping`,
p.price, p.priceKg, p.rate, l.available p.price, p.priceKg, p.rate, l.available

View File

@ -40,12 +40,13 @@ Hedera.Checkout = new Class({
date.setDate(date.getDate() + addDays); date.setDate(date.getDate() + addDays);
} }
this.$.date.value = date;
this.$.method.value = row.deliveryMethod;
this.$.agency.value = row.agencyModeFk;
this.$.address.value = row.addressFk;
this.$.lot.assign({
date: date,
method: row.deliveryMethod,
agency: row.agencyModeFk,
address: row.addressFk
});
this.autoStepLocked = false; this.autoStepLocked = false;
}, },
@ -57,15 +58,8 @@ Hedera.Checkout = new Class({
this.disableButtons(true); this.disableButtons(true);
var query = 'CALL myBasket_configure(#date, #method, #agency, #address)'; var query = 'CALL myBasket_configure(#date, #method, #agency, #address)';
var batch = new Sql.Batch();
batch.addParam('method', this.$.method);
batch.addParam('date', this.$.date);
batch.addParam('agency', this.$.agency);
batch.addParam('address', this.$.address);
this.conn.execQuery(query, this.conn.execQuery(query,
this.onBasketConfigured.bind(this), batch); this.onBasketConfigured.bind(this), this.$.lot.$);
}, },
onBasketConfigured: function(resultSet) { onBasketConfigured: function(resultSet) {
@ -79,14 +73,14 @@ Hedera.Checkout = new Class({
else else
Htk.Toast.showMessage(_('OrderStarted')); Htk.Toast.showMessage(_('OrderStarted'));
this.hash.set({form: 'ecomerce/catalog'}); this.hash.setAll({form: 'ecomerce/catalog'});
}, },
onCancelClick: function() { onCancelClick: function() {
if (this.$.orderForm.numRows > 0) if (this.$.orderForm.numRows > 0)
window.history.back(); window.history.back();
else else
this.hash.set({form: 'ecomerce/orders'}); this.hash.setAll({form: 'ecomerce/orders'});
}, },
agencySteps: ['method', 'date', 'address', 'agency', 'confirm-delivery'], agencySteps: ['method', 'date', 'address', 'agency', 'confirm-delivery'],
@ -163,7 +157,7 @@ Hedera.Checkout = new Class({
}, },
onAddressClick: function(addressId) { onAddressClick: function(addressId) {
this.$.address.value = addressId; this.$.lot.set('address', addressId);
this.goNextStep(); this.goNextStep();
}, },
@ -171,7 +165,7 @@ Hedera.Checkout = new Class({
if (this.selectedNode) if (this.selectedNode)
Vn.Node.removeClass(this.selectedNode, 'selected'); Vn.Node.removeClass(this.selectedNode, 'selected');
var row = this.$.addresses.search('id', this.$.address.value); var row = this.$.addresses.search('id', this.$.lot.$.address);
if (row != -1) { if (row != -1) {
var builder = this.$.repeater.getBuilder(row); var builder = this.$.repeater.getBuilder(row);

View File

@ -1,9 +1,6 @@
<vn> <vn>
<vn-group> <vn-group>
<vn-param id="method"/> <vn-lot id="lot" on-change="this.onAddressChange()"/>
<vn-param id="date"/>
<vn-param id="agency"/>
<vn-param id="address" on-changed="onAddressChange"/>
<db-form id="defaults" on-ready="onValuesReady"> <db-form id="defaults" on-ready="onValuesReady">
<db-model property="model"> <db-model property="model">
SELECT deliveryMethod, agencyModeFk, addressFk, defaultAgencyFk SELECT deliveryMethod, agencyModeFk, addressFk, defaultAgencyFk
@ -19,6 +16,7 @@
</db-form> </db-form>
<db-model id="agencies" <db-model id="agencies"
auto-load="false" auto-load="false"
lot="lot"
result-index="1" result-index="1"
on-status-changed="onAgenciesReady"> on-status-changed="onAgenciesReady">
CALL vn.zone_getAgency(#address, #date); CALL vn.zone_getAgency(#address, #date);
@ -30,15 +28,10 @@
AND a.isVisible AND a.isVisible
ORDER BY a.description; ORDER BY a.description;
DROP TEMPORARY TABLE tmp.zoneGetAgency; DROP TEMPORARY TABLE tmp.zoneGetAgency;
<sql-batch property="batch">
<custom>
<item name="address" param="address"/>
<item name="date" param="date"/>
</custom>
</sql-batch>
</db-model> </db-model>
<db-model id="warehouses" <db-model id="warehouses"
auto-load="false" auto-load="false"
lot="lot"
result-index="1" result-index="1"
on-status-changed="onWarehousesReady"> on-status-changed="onWarehousesReady">
CALL vn.zone_getAgency(#address, #date); CALL vn.zone_getAgency(#address, #date);
@ -50,12 +43,6 @@
AND a.isVisible AND a.isVisible
ORDER BY a.description; ORDER BY a.description;
DROP TEMPORARY TABLE tmp.zoneGetAgency; DROP TEMPORARY TABLE tmp.zoneGetAgency;
<sql-batch property="batch">
<custom>
<item name="address" param="address"/>
<item name="date" param="date"/>
</custom>
</sql-batch>
</db-model> </db-model>
</vn-group> </vn-group>
<div id="title"> <div id="title">

View File

@ -6,7 +6,7 @@ Hedera.Confirm = new Class({
this.close(); this.close();
this.isOpen = true; this.isOpen = true;
Hedera.BasketChecker.check(this.conn, Hedera.BasketChecker.check(this.conn, this.hash,
this.onBasketCheck.bind(this)); this.onBasketCheck.bind(this));
}, },
@ -139,10 +139,13 @@ Hedera.Confirm = new Class({
else else
var payAmount = this.$.totalAmount.value; var payAmount = this.$.totalAmount.value;
var tpv = new Hedera.Tpv({conn: this.conn}); var tpv = new Hedera.Tpv({
conn: this.conn,
hash: this.hash
});
tpv.pay(payAmount, this.$.orderForm.$.companyFk); tpv.pay(payAmount, this.$.orderForm.$.companyFk);
} else } else
this.hash.set({'form': 'ecomerce/orders'}); this.hash.setAll({'form': 'ecomerce/orders'});
} }
}); });

View File

@ -3,7 +3,10 @@ Hedera.Orders = new Class({
Extends: Hedera.Form, Extends: Hedera.Form,
activate: function() { activate: function() {
this.tpv = new Hedera.Tpv({conn: this.conn}); this.tpv = new Hedera.Tpv({
conn: this.conn,
hash: this.hash
});
this.tpv.check(this._onTpvCheck.bind(this)); this.tpv.check(this._onTpvCheck.bind(this));
}, },
@ -13,7 +16,7 @@ Hedera.Orders = new Class({
}, },
onBasketClick: function() { onBasketClick: function() {
this.hash.set({form: 'ecomerce/basket'}); this.hash.setAll({form: 'ecomerce/basket'});
}, },
repeaterFunc: function(res, form) { repeaterFunc: function(res, form) {

View File

@ -6,9 +6,8 @@ Hedera.Ticket = new Class({
if (!ticket.value) if (!ticket.value)
return; return;
var batch = new Sql.Batch(); var params = {ticket: ticket.value};
batch.addValue('ticket', ticket.value); this.conn.execQuery('CALL myTicket_logAccess(#ticket)', null, params);
this.conn.execQuery('CALL myTicket_logAccess(#ticket)', null, batch);
}, },
onTicketReady: function(form) { onTicketReady: function(form) {

View File

@ -1,18 +1,10 @@
<vn> <vn>
<vn-group> <vn-lot-query id="params">
<vn-param id="ticket-id" on-changed="onTicketChange"/> <vn-spec name="ticket" type="Number"/>
<vn-hash-param key="ticket" param="ticket-id"/> </vn-lot-query>
<sql-batch id="batch"> <db-lot id="ticket" lot="params" on-ready="onTicketReady">
<custom> CALL myTicket_get(#ticket)
<item name="ticket" param="ticket-id"/> </db-lot>
</custom>
</sql-batch>
<db-form id="ticket" on-ready="onTicketReady">
<db-model id="ticket-data" property="model" batch="batch">
CALL myTicket_get(#ticket)
</db-model>
</db-form>
</vn-group>
<div id="title"> <div id="title">
<h1><t>OrderDetail</t></h1> <h1><t>OrderDetail</t></h1>
</div> </div>
@ -20,7 +12,7 @@
<htk-bar-button <htk-bar-button
icon="print" icon="print"
tip="_Print delivery note" tip="_Print delivery note"
on-click="onPrintClick"/> on-click="this.onPrintClick()"/>
</div> </div>
<div id="form" class="ticket"> <div id="form" class="ticket">
<div class="box vn-w-sm vn-pa-lg"> <div class="box vn-w-sm vn-pa-lg">
@ -67,7 +59,7 @@
<db-model <db-model
property="model" property="model"
id="movements" id="movements"
batch="batch"> lot="params">
CALL myTicket_getRows(#ticket) CALL myTicket_getRows(#ticket)
</db-model> </db-model>
<custom> <custom>
@ -108,7 +100,7 @@
<db-model <db-model
property="model" property="model"
on-status-changed="onServicesChanged" on-status-changed="onServicesChanged"
batch="batch"> lot="params">
CALL myTicket_getServices(#ticket) CALL myTicket_getServices(#ticket)
</db-model> </db-model>
<custom> <custom>
@ -133,7 +125,7 @@
<db-model <db-model
property="model" property="model"
on-status-changed="onPackagesChanged" on-status-changed="onPackagesChanged"
batch="batch"> lot="params">
CALL myTicket_getPackages(#ticket) CALL myTicket_getPackages(#ticket)
</db-model> </db-model>
<custom> <custom>

View File

@ -55,7 +55,7 @@ Hedera.New = new Class({
}, },
onStatusChange: function() { onStatusChange: function() {
if (this.$.newId.value == 0) if (this.hash.$.new == 0)
this.$.iter.insertRow(); this.$.iter.insertRow();
}, },
@ -71,10 +71,6 @@ Hedera.New = new Class({
onAcceptClick: function() { onAcceptClick: function() {
this.$.iter.set('text', this.editor.getContent()); this.$.iter.set('text', this.editor.getContent());
this.$.iter.performOperations(); this.$.iter.performOperations();
},
onReturnClick: function() {
this.hash.set({form: 'news/news'});
} }
}); });
}); });

View File

@ -1,22 +1,14 @@
<vn> <vn>
<vn-group> <vn-group>
<vn-param id="new-id"/>
<vn-hash-param key="new" param="new-id"/>
<db-form id="iter" on-status-changed="this.onStatusChange()"> <db-form id="iter" on-status-changed="this.onStatusChange()">
<db-model <db-model
id="model" id="model"
property="model" property="model"
updatable="true" updatable="true"
lot="hash"
on-operations-done="this.onOperationsDone()"> on-operations-done="this.onOperationsDone()">
<custom> SELECT id, title, text, tag, priority, image
SELECT id, title, text, tag, priority, image FROM news WHERE id = #new
FROM news WHERE id = #new
</custom>
<sql-batch property="batch">
<custom>
<item name="new" param="new-id"/>
</custom>
</sql-batch>
</db-model> </db-model>
</db-form> </db-form>
<db-param form="iter" column="text" on-changed="this.onBodyChange()"/> <db-param form="iter" column="text" on-changed="this.onBodyChange()"/>
@ -28,7 +20,7 @@
<htk-bar-button <htk-bar-button
icon="close" icon="close"
tip="_Return" tip="_Return"
on-click="this.onReturnClick()"/> on-click="this.hash.setAll({form: 'news/news'});"/>
<htk-bar-button <htk-bar-button
icon="check" icon="check"
tip="_Accept" tip="_Accept"
@ -55,10 +47,8 @@
<label><t>Tag</t></label> <label><t>Tag</t></label>
<htk-combo form="iter" column="tag"> <htk-combo form="iter" column="tag">
<db-model property="model"> <db-model property="model">
<custom> SELECT name, description FROM newsTag
SELECT name, description FROM newsTag ORDER BY description
ORDER BY description
</custom>
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>

View File

@ -3,7 +3,7 @@ Hedera.News = new Class({
Extends: Hedera.Form Extends: Hedera.Form
,editNew: function(newId) { ,editNew: function(newId) {
this.hash.set({ this.hash.setAll({
form: 'news/new', form: 'news/new',
new: newId new: newId
}); });

View File

@ -3,18 +3,15 @@ Hedera.ItemsForm = new Class({
Extends: Hedera.Form Extends: Hedera.Form
,activate: function() { ,activate: function() {
this.$.warehouse.value = 7; this.$.lot.assign({
this.$.realm.value = null; warehouse: 7,
realm: null
});
} }
,onPreviewClick: function() { ,onPreviewClick: function() {
var batch = new Sql.Batch(); this.$.lot.set('rate', this.$.rate.value);
batch.addValues({ this.gui.openReport('items-report', this.$.lot);
warehouse: this.$.warehouse.value
,realm: this.$.realm.value
,rate: this.$.rate.value
});
this.gui.openReport('items-report', batch);
} }
}); });

View File

@ -1,4 +1,5 @@
<vn> <vn>
<vn-lot id="lot"/>
<div id="title"> <div id="title">
<h1><t>Item list</t></h1> <h1><t>Item list</t></h1>
</div> </div>
@ -12,25 +13,19 @@
<div class="form box vn-w-sm vn-pa-lg"> <div class="form box vn-w-sm vn-pa-lg">
<div class="form-group"> <div class="form-group">
<label><t>Store</t></label> <label><t>Store</t></label>
<htk-combo> <htk-combo form="lot" column="warehouse">
<vn-param property="param" id="warehouse"/>
<db-model property="model"> <db-model property="model">
<custom> SELECT id, name FROM vn2008.warehouse
SELECT id, name FROM vn2008.warehouse WHERE reserve ORDER BY name
WHERE reserve ORDER BY name
</custom>
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Realm</t></label> <label><t>Realm</t></label>
<htk-combo not-null="false"> <htk-combo form="lot" column="realm" not-null="false">
<vn-param property="param" id="realm"/>
<db-model property="model"> <db-model property="model">
<custom> SELECT id, reino FROM vn2008.reinos
SELECT id, reino FROM vn2008.reinos WHERE display != FALSE ORDER BY reino
WHERE display != FALSE ORDER BY reino
</custom>
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>

View File

@ -3,49 +3,18 @@ Hedera.Shelves = new Class({
Extends: Hedera.Form Extends: Hedera.Form
,activate: function() { ,activate: function() {
this.$.date.value = new Date(); this.$.lot.assign({
this.$.useIds.value = false; date: new Date(),
useIds: false
});
} }
,onConfigChange: function() { ,onConfigChange: function() {
const fields = [ this.$.lot.assignLot(this.$.config);
'realm'
,'family'
,'warehouse'
,'shelf'
,'namePrefix'
,'maxAmount'
,'reportTitle'
,'showPacking'
,'stack'
];
const config = this.$.config.$;
if (config)
for (const field of fields)
this.$[field].value = config[field];
} }
,onPreviewClick: function() { ,onPreviewClick: function() {
var fields = [ this.gui.openReport('shelves-report', this.$.lot);
'family'
,'warehouse'
,'shelf'
,'namePrefix'
,'maxAmount'
,'reportTitle'
,'showPacking'
,'stack'
,'useIds'
,'date'
];
var batch = new Sql.Batch();
for (const field of fields)
batch.addValue(field, this.$[field].value);
this.gui.openReport('shelves-report', batch);
} }
}); });

View File

@ -1,14 +1,8 @@
<vn> <vn>
<vn-group> <vn-lot-query id="params">
<db-model property="model" id="configs-model"> <vn-spec name="config" type="Number"/>
<custom> </vn-lot-query>
SELECT c.id, c.name reportTitle, c.namePrefix, c.warehouse, c.family, <vn-lot id="lot"/>
c.shelf, c.maxAmount, c.showPacking, c.stack, t.reino_id realm
FROM shelfConfig c
JOIN vn2008.Tipos t ON t.tipo_id = c.family
</custom>
</db-model>
</vn-group>
<div id="title"> <div id="title">
<h1><t>Shelves</t></h1> <h1><t>Shelves</t></h1>
</div> </div>
@ -25,89 +19,84 @@
<htk-combo <htk-combo
id="config" id="config"
placeholder="_Select config" placeholder="_Select config"
model="configs-model" form="params"
column="config"
on-changed="this.onConfigChange()" on-changed="this.onConfigChange()"
on-ready="this.onConfigChange()"/> on-ready="this.onConfigChange()">
<db-model property="model">
SELECT c.id, c.name reportTitle, c.namePrefix, c.warehouse, c.family,
c.shelf, c.maxAmount, c.showPacking, c.stack, t.reino_id realm
FROM shelfConfig c
JOIN vn2008.Tipos t ON t.tipo_id = c.family
</db-model>
</htk-combo>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Date</t></label> <label><t>Date</t></label>
<htk-date-chooser id="date"/> <htk-date-chooser form="lot" name="date"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Reign</t></label> <label><t>Reign</t></label>
<htk-combo id="realm"> <htk-combo form="lot" name="realm">
<db-model property="model" id="realms"> <db-model property="model">
<custom> SELECT id, reino FROM vn2008.reinos
SELECT id, reino FROM vn2008.reinos WHERE display != FALSE ORDER BY reino
WHERE display != FALSE ORDER BY reino
</custom>
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Family</t></label> <label><t>Family</t></label>
<htk-combo id="family"> <htk-combo form="lot" name="family">
<db-model property="model"> <db-model property="model" lot="lot">
<custom> SELECT tipo_id, Tipo FROM vn2008.Tipos
SELECT tipo_id, Tipo FROM vn2008.Tipos WHERE reino_id = #realm ORDER BY Tipo
WHERE reino_id = #realm ORDER BY Tipo
</custom>
<sql-batch property="batch">
<custom>
<item name="realm" param="realm"/>
</custom>
</sql-batch>
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Store</t></label> <label><t>Store</t></label>
<htk-combo id="warehouse"> <htk-combo form="lot">
<db-model property="model" id="warehouses"> <db-model property="model">
<custom> SELECT id, name FROM vn2008.warehouse
SELECT id, name FROM vn2008.warehouse WHERE reserve ORDER BY name
WHERE reserve ORDER BY name
</custom>
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Shelf</t></label> <label><t>Shelf</t></label>
<htk-combo id="shelf"> <htk-combo form="lot" name="shelf">
<db-model property="model" id="shelves"> <db-model property="model">
<custom> SELECT id, name FROM shelf
SELECT id, name FROM shelf
</custom>
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Name prefix</t></label> <label><t>Name prefix</t></label>
<htk-entry id="namePrefix"/> <htk-entry form="lot" name="namePrefix"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Limit amount per item</t></label> <label><t>Limit amount per item</t></label>
<htk-entry id="maxAmount"/> <htk-entry form="lot" name="maxAmount"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Title</t></label> <label><t>Title</t></label>
<htk-entry id="reportTitle"/> <htk-entry form="lot" name="reportTitle"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label> <label>
<htk-check id="showPacking"/> <htk-check form="lot" name="showPacking"/>
<t>Show packing</t> <t>Show packing</t>
</label> </label>
</div> </div>
<div class="form-group"> <div class="form-group">
<label> <label>
<htk-check id="stack"/> <htk-check form="lot" name="stack"/>
<t>Stack different items</t> <t>Stack different items</t>
</label> </label>
</div> </div>
<div class="form-group"> <div class="form-group">
<label> <label>
<htk-check id="useIds"/> <htk-check form="lot" name="useIds"/>
<t>Use ids instead of names</t> <t>Use ids instead of names</t>
</label> </label>
</div> </div>

View File

@ -12,15 +12,13 @@
var Connection = new Class(); var Connection = new Class();
module.exports = Connection; module.exports = Connection;
var Flag = var Flag = {
{
NOT_NULL : 1 NOT_NULL : 1
,PRI_KEY : 2 ,PRI_KEY : 2
,AI : 512 | 2 | 1 ,AI : 512 | 2 | 1
}; };
var Type = var Type = {
{
BOOLEAN : 1 BOOLEAN : 1
,INTEGER : 3 ,INTEGER : 3
,DOUBLE : 4 ,DOUBLE : 4
@ -53,10 +51,10 @@ Connection.implement({
* *
* @param {Sql.Stmt} stmt The statement * @param {Sql.Stmt} stmt The statement
* @param {Function} callback The function to call when operation is done * @param {Function} callback The function to call when operation is done
* @param {Sql.Batch} batch The batch used to set the parameters * @param {Object} params The query params
*/ */
,execStmt: function(stmt, callback, batch) { ,execStmt: function(stmt, callback, params) {
this.execSql(stmt.render(batch), callback); this.execSql(stmt.render(params), callback);
} }
/** /**
@ -64,10 +62,10 @@ Connection.implement({
* *
* @param {String} query The SQL statement * @param {String} query The SQL statement
* @param {Function} callback The function to call when operation is done * @param {Function} callback The function to call when operation is done
* @param {Sql.Batch} batch The batch used to set the parameters * @param {Object} params The query params
*/ */
,execQuery: function(query, callback, batch) { ,execQuery: function(query, callback, params) {
this.execStmt(new Sql.String({query: query}), callback, batch); this.execStmt(new Sql.String({query: query}), callback, params);
} }
/* /*

109
js/db/db-lot.js Normal file
View File

@ -0,0 +1,109 @@
var Connection = require('./connection');
var Model = require('./model');
module.exports = new Class({
Extends: Vn.Form
,Tag: 'db-lot'
,Properties: {
/**
* The connection used to execute the statement.
*/
conn: {
type: Connection
,set: function(x) {
this.model.conn = x;
}
,get: function() {
return this.model.conn;
}
},
/**
* The model query.
*/
query: {
type: String
,set: function(x) {
this.model.query = x;
}
,get: function() {
return this.model.query;
}
},
/**
* The model select statement.
*/
stmt: {
type: Sql.Stmt
,set: function(x) {
this.model.stmt = x;
}
,get: function() {
return this.model.stmt;
}
},
/**
* The lot used to execute the statement.
*/
lot: {
type: Vn.Lot
,set: function(x) {
this.model.lot = x;
}
,get: function() {
return this.model.lot;
}
}
}
,initialize: function(props) {
this.model = new Model();
this.parent(props);
}
,appendChild: function(child) {
if (child.nodeType === Node.TEXT_NODE)
this.query = child.textContent;
}
,refresh: function() {
if (this._model)
this._model.refresh();
}
,performOperations: function() {
if (this._model)
this._model.performOperations();
}
/**
* Get the index of the column from its name.
*
* @param {string} columnName The column name
* @return {integer} The column index or -1 if column not exists
*/
,getColumnIndex: function(columnName) {
return this._model ?
this._model.getColumnIndex(columnName) : -1;
}
/**
* Gets a value from the form using the column index.
*
* @param {string} columnName The column index
* @return {Object} The value
*/
,getByIndex: function(column) {
return this._model.getByIndex(this._row, column);
}
/**
* Sets a value on the form using the column index.
*
* @param {string} columnName The column index
* @param {Object} value The new value
*/
,setByIndex: function(column, value) {
return this._model.setByIndex(this._row, column, value);
}
});

View File

@ -1,17 +1,17 @@
require ('sql/sql'); require('sql/sql');
Db = module.exports = { Db = module.exports = {
Connection : require ('./connection') Connection : require('./connection')
,Result : require ('./result') ,Result : require('./result')
,ResultSet : require ('./result-set') ,ResultSet : require('./result-set')
,Model : require ('./model') ,Model : require('./model')
,Iterator : require ('./iterator') ,Iterator : require('./iterator')
,SimpleIterator : require ('./simple-iterator') ,SimpleIterator : require('./simple-iterator')
,Form : require ('./form') ,Form : require('./form')
,Param : require ('./param') ,Query : require('./query')
,Query : require ('./query') ,Calc : require('./calc')
,Calc : require ('./calc') ,CalcSum : require('./calc-sum')
,CalcSum : require ('./calc-sum') ,Lot : require('./db-lot')
}; };

View File

@ -67,7 +67,7 @@ module.exports = new Class({
$: { $: {
type: Object type: Object
,get: function() { ,get: function() {
return this._model.getObject(this._row); return this._model && this._model.getObject(this._row);
} }
} }
} }
@ -85,13 +85,13 @@ module.exports = new Class({
this.lastRow = this._row; this.lastRow = this._row;
this._ready = ready; this._ready = ready;
this.signalEmit('status-changed'); this.emit('status-changed');
if (this._row == -1) if (this._row == -1)
this.row = this.lastRow; this.row = this.lastRow;
if (ready) if (ready)
this.signalEmit('ready'); this.emit('ready');
this.iterChanged(); this.iterChanged();
} }

View File

@ -44,10 +44,10 @@ module.exports = new Class({
} }
/** /**
* Emits the 'iter-changed' signal on the form. * Emits the 'change' signal on the form.
*/ */
,iterChanged: function() { ,iterChanged: function() {
this.signalEmit('iter-changed'); this.emit('change');
} }
/** /**
@ -90,6 +90,16 @@ module.exports = new Class({
return this._model.getObject(this._row); return this._model.getObject(this._row);
} }
/**
* Sets a value on the form.
*
* @param {String} columnName The column name
*/
,get: function(columnName) {
if (!this._model) return undefined;
return this._model.get(this._row, columnName);
}
/** /**
* Sets a value on the form. * Sets a value on the form.
* *

View File

@ -73,16 +73,16 @@ Model.implement({
} }
}, },
/** /**
* The batch used to execute the statement. * The lot used to execute the statement.
*/ */
batch: { lot: {
type: Sql.Batch type: Vn.LotIface
,set: function(x) { ,set: function(x) {
this.link({_batch: x}, {'changed': this._autoLoad}); this.link({_lot: x}, {'change': this._autoLoad});
this._autoLoad(); this._onLotChange();
} }
,get: function() { ,get: function() {
return this._batch; return this._lot;
} }
}, },
/** /**
@ -189,7 +189,7 @@ Model.implement({
,_conn: null ,_conn: null
,_resultIndex: 0 ,_resultIndex: 0
,_batch: null ,_lot: null
,_stmt: null ,_stmt: null
,_status: Status.CLEAN ,_status: Status.CLEAN
,data: null ,data: null
@ -232,39 +232,69 @@ Model.implement({
this.query = query; this.query = query;
} }
,_getLotParams: function() {
if (!this._stmt)
return null;
var holders = this._stmt.findHolders();
if (!holders)
return null;
var lotParams = this._lot ? this._lot.params : {};
if (lotParams == null)
lotParams = {};
var params = {};
for (var i = 0; i < holders.length; i++)
params[holders[i]] = lotParams[holders[i]];
return params;
}
,_onLotChange: function() {
var lotParams = this._getLotParams();
if (!Vn.Value.equals(lotParams, this._lastLotParams))
this._autoLoad();
}
,_autoLoad: function() { ,_autoLoad: function() {
if (this.autoLoad) if (this.autoLoad)
this.refresh(); this.refresh();
else else
this.clean(); this.clean();
} }
,_isReady: function(params) {
if (!this._stmt || !this._conn)
return false;
var holders = this._stmt.findHolders();
if (!holders)
return true;
for (var i = 0; i < holders.length; i++)
if (params[holders[i]] === undefined)
return false;
return true;
}
/** /**
* Refresh the model data reexecuting the query on the database. * Refresh the model data reexecuting the query on the database.
*/ */
,refresh: function() { ,refresh: function(params) {
var ready = false; var lotParams = this._getLotParams();
var myParams = {};
if (this._stmt && this._conn) {
var ids = this._stmt.findHolders();
if (ids) {
if (this._batch && this._batch.isReady()) {
ready = true;
for (var i = 0; i < ids.length; i++) Object.assign(myParams, lotParams);
if (!this._batch.get(ids[i])) { Object.assign(myParams, params);
ready = false;
break;
}
}
} else
ready = true;
}
if (ready) { if (this._filter && (!params || params.filter === undefined))
myParams.filter = this._filter;
this._lastLotParams = lotParams;
if (this._isReady(myParams)) {
this._setStatus(Status.LOADING); this._setStatus(Status.LOADING);
this._conn.execStmt(this._stmt, this._selectDone.bind(this), this._batch); this._conn.execStmt(this._stmt,
this._selectDone.bind(this), myParams);
} else } else
this.clean(); this.clean();
} }
@ -344,7 +374,7 @@ Model.implement({
this._updatable = this._mainTable !== null && this._requestedUpdatable; this._updatable = this._mainTable !== null && this._requestedUpdatable;
if (oldValue != this._updatable) if (oldValue != this._updatable)
this.signalEmit('updatable-changed'); this.emit('updatable-changed');
} }
,_refreshMainTable: function() { ,_refreshMainTable: function() {
@ -492,7 +522,7 @@ Model.implement({
*/ */
,get: function(rowIndex, columnName) { ,get: function(rowIndex, columnName) {
if (this.checkRowExists(rowIndex)) if (this.checkRowExists(rowIndex))
return this.data[rowIndex][columnName]; return this.data[rowIndex][columnName];
} }
/** /**
@ -541,9 +571,9 @@ Model.implement({
&& op.oldValues[columnName] === undefined) && op.oldValues[columnName] === undefined)
op.oldValues[columnName] = row[columnName]; op.oldValues[columnName] = row[columnName];
this.signalEmit('row-updated-before', rowIndex); this.emit('row-updated-before', rowIndex);
row[columnName] = value; row[columnName] = value;
this.signalEmit('row-updated', rowIndex, [columnName]); this.emit('row-updated', rowIndex, [columnName]);
if (this.mode == Mode.ON_CHANGE if (this.mode == Mode.ON_CHANGE
&& !(op.type & Operation.INSERT)) && !(op.type & Operation.INSERT))
@ -596,12 +626,12 @@ Model.implement({
op.type |= Operation.DELETE; op.type |= Operation.DELETE;
if (!this._requestedMainTable) { if (!this._requestedMainTable) {
this.signalEmit('row-deleted-before', rowIndex); this.emit('row-deleted-before', rowIndex);
this.data.splice(rowIndex, 1); this.data.splice(rowIndex, 1);
this.signalEmit('row-deleted', rowIndex); this.emit('row-deleted', rowIndex);
this._refreshRowIndexes(rowIndex); this._refreshRowIndexes(rowIndex);
} else { } else {
this.signalEmit('row-updated-before', rowIndex); this.emit('row-updated-before', rowIndex);
if (!op.oldValues) if (!op.oldValues)
op.oldValues = []; op.oldValues = [];
@ -619,7 +649,7 @@ Model.implement({
updatedCols.push(i); updatedCols.push(i);
} }
this.signalEmit('row-updated', rowIndex, updatedCols); this.emit('row-updated', rowIndex, updatedCols);
} }
if (this.mode === Mode.ON_CHANGE) if (this.mode === Mode.ON_CHANGE)
@ -650,7 +680,7 @@ Model.implement({
var op = this._createOperation(rowIndex); var op = this._createOperation(rowIndex);
op.type |= Operation.INSERT; op.type |= Operation.INSERT;
this.signalEmit('row-inserted', rowIndex); this.emit('row-inserted', rowIndex);
return rowIndex; return rowIndex;
} }
@ -662,14 +692,14 @@ Model.implement({
var ops = this._operations; var ops = this._operations;
if (ops.length === 0) { if (ops.length === 0) {
this.signalEmit('operations-done'); this.emit('operations-done');
return; return;
} }
var stmts = new Sql.MultiStmt(); var stmts = new Sql.MultiStmt();
var query = new Sql.String({query: 'START TRANSACTION'}); var query = new Sql.String({query: 'START TRANSACTION'});
stmts.addStmt(query); stmts.push(query);
for (var i = 0; i < ops.length; i++) { for (var i = 0; i < ops.length; i++) {
query = null; query = null;
@ -690,12 +720,12 @@ Model.implement({
for (var tableIndex in op.tables) { for (var tableIndex in op.tables) {
var stmt = this._createDmlQuery(op, parseInt(tableIndex)); var stmt = this._createDmlQuery(op, parseInt(tableIndex));
query.addStmt(stmt); query.push(stmt);
} }
} }
if (query) { if (query) {
stmts.addStmt(query); stmts.push(query);
} else { } else {
console.warn('Db.Model: %s', _('ErrorSavingChanges')); console.warn('Db.Model: %s', _('ErrorSavingChanges'));
return; return;
@ -703,7 +733,7 @@ Model.implement({
} }
var query = new Sql.String({query: 'COMMIT'}); var query = new Sql.String({query: 'COMMIT'});
stmts.addStmt(query); stmts.push(query);
this._conn.execStmt(stmts, this._conn.execStmt(stmts,
this._onOperationsDone.bind(this, ops)); this._onOperationsDone.bind(this, ops));
@ -764,8 +794,8 @@ Model.implement({
dmlQuery.addTarget(target); dmlQuery.addTarget(target);
multiStmt.addStmt(dmlQuery); multiStmt.push(dmlQuery);
multiStmt.addStmt(select); multiStmt.push(select);
return multiStmt; return multiStmt;
} }
@ -795,7 +825,7 @@ Model.implement({
if (op.type & Operation.DELETE) { if (op.type & Operation.DELETE) {
resultSet.fetchResult(); resultSet.fetchResult();
} else if (op.type & (Operation.INSERT | Operation.UPDATE)) { } else if (op.type & (Operation.INSERT | Operation.UPDATE)) {
this.signalEmit('row-updated-before', row.index); this.emit('row-updated-before', row.index);
var updatedCols = []; var updatedCols = [];
var cols = this.columns; var cols = this.columns;
@ -823,14 +853,14 @@ Model.implement({
} }
} }
this.signalEmit('row-updated', row.index, updatedCols); this.emit('row-updated', row.index, updatedCols);
} }
} }
resultSet.fetchResult(); resultSet.fetchResult();
// if (isOperation) // if (isOperation)
this.signalEmit('operations-done'); this.emit('operations-done');
} }
/** /**
@ -844,9 +874,9 @@ Model.implement({
if (op.type & Operation.DELETE if (op.type & Operation.DELETE
&& !(op.type & Operation.INSERT)) { && !(op.type & Operation.INSERT)) {
this.data.splice(row.index, 0, row); this.data.splice(row.index, 0, row);
this.signalEmit('row-inserted', row.index); this.emit('row-inserted', row.index);
} else if (op.type & Operation.UPDATE) { } else if (op.type & Operation.UPDATE) {
this.signalEmit('row-updated-before', row.index); this.emit('row-updated-before', row.index);
var updatedCols = []; var updatedCols = [];
var cols = this.columns; var cols = this.columns;
@ -858,7 +888,7 @@ Model.implement({
updatedCols.push(i); updatedCols.push(i);
} }
this.signalEmit('row-updated', row.index, updatedCols); this.emit('row-updated', row.index, updatedCols);
} }
} }
@ -1064,8 +1094,8 @@ Model.implement({
,_setStatus: function(status) { ,_setStatus: function(status) {
this._status = status; this._status = status;
this.signalEmit('status-changed', status); this.emit('status-changed', status);
this.signalEmit('status-changed-after', status); this.emit('status-changed-after', status);
} }
,_createTarget: function(tableIndex) { ,_createTarget: function(tableIndex) {
@ -1088,8 +1118,8 @@ Model.implement({
const column = this.columnMap[pk]; const column = this.columnMap[pk];
const equalOp = new Sql.Operation({type: Sql.Operation.Type.EQUAL}); const equalOp = new Sql.Operation({type: Sql.Operation.Type.EQUAL});
equalOp.exprs.add(new Sql.Field({name: column.orgname})); equalOp.push(new Sql.Field({name: column.orgname}));
where.exprs.add(equalOp); where.push(equalOp);
let pkValue = null; let pkValue = null;
@ -1100,9 +1130,9 @@ Model.implement({
pkValue = op.row[pk]; pkValue = op.row[pk];
if (pkValue) if (pkValue)
equalOp.exprs.add(new Sql.Value({value: pkValue})); equalOp.push(new Sql.Value({value: pkValue}));
else if (column.flags & Connection.Flag.AI && !useOldValues) else if (column.flags & Connection.Flag.AI && !useOldValues)
equalOp.exprs.add(new Sql.Function({name: 'LAST_INSERT_ID'})); equalOp.push(new Sql.Function({name: 'LAST_INSERT_ID'}));
else else
return null; return null;
} }

View File

@ -1,105 +0,0 @@
var Form = require('./form');
module.exports = new Class({
Extends: Vn.Param
,Tag: 'db-param'
,Parent: 'form'
,Properties:
{
/**
* The form field referenced by this param.
*/
column:
{
type: String
,set: function(x) {
this._columnName = x;
this.refresh();
}
,get: function() {
this._columnName;
}
},
/**
* The form referenced by this param.
*/
form:
{
type: Form
,set: function(x) {
this.link({_form: x},
{
'status-changed': this.onFormChange
,'iter-changed': this.onIterChange
});
this.refresh();
}
,get: function() {
return this._form;
}
},
/**
* Determines whether the link to the form is unidirectional, ie, a
* change in the form updates the parameter but not vice versa.
*/
oneWay:
{
type: Boolean
,set: function(x) {
this._oneWay = x;
}
,get: function() {
return this._oneWay;
}
}
}
,_columnName: null
,_form: null
,_formLock: false
,_columnIndex: -1
,_oneWay: false
,_formValue: null
,initialize: function(props) {
this.parent(props);
this.on('changed', this.onChange, this);
}
,refresh: function() {
if (this._form) {
this.onFormChange();
this.onIterChange();
}
}
,onFormChange: function() {
if (this._columnName != null)
this._columnIndex = this._form.getColumnIndex(this._columnName);
}
,onIterChange: function() {
if (this._oneWay && this.value != null)
return;
this._formLock = true;
var formValue;
if (this._columnIndex !== -1)
formValue = this._form.getByIndex(this._columnIndex);
else
formValue = undefined;
this.value = formValue;
this._formLock = false;
}
,onChange: function() {
if (!this._formLock && this._columnIndex != -1 && !this.oneWay)
this._form.setByIndex(this._columnIndex, this._value);
}
});

View File

@ -1,100 +1,78 @@
var Connection = require ('./connection'); var Connection = require('./connection');
module.exports = new Class module.exports = new Class({
({
Extends: Vn.Object Extends: Vn.Object
,Tag: 'db-query' ,Tag: 'db-query'
,Properties: ,Properties: {
{
/** /**
* The connection used to execute the statement. * The connection used to execute the statement.
*/ */
conn: conn: {
{
type: Connection type: Connection
,set: function (x) ,set: function(x) {
{
this._conn = x; this._conn = x;
this.onChange (); this.onChange();
} }
,get: function () ,get: function() {
{
return this._conn; return this._conn;
} }
}, },
/** /**
* The model query. * The model query.
*/ */
query: query: {
{
type: String type: String
,set: function (x) ,set: function(x) {
{ this._stmt = new Sql.String({query: x});
this._stmt = new Sql.String ({query: x}); this.onChange();
this.onChange ();
} }
,get: function () ,get: function() {
{ return this._stmt.render(null);
return this._stmt.render (null);
} }
}, },
/** /**
* The model select statement. * The model select statement.
*/ */
stmt: stmt: {
{
type: Sql.Stmt type: Sql.Stmt
,set: function (x) ,set: function(x) {
{
this._stmt = x; this._stmt = x;
this.onChange (); this.onChange();
} }
,get: function () ,get: function() {
{
return this._stmt; return this._stmt;
} }
}, },
/** /**
* The batch used to execute the statement. * The lot used to execute the statement.
*/ */
batch: lot: {
{ type: Vn.LotIface
type: Sql.Batch ,set: function(x) {
,set: function (x) this.link({_lot: x}, {'change': this.onChange});
{ this.onChange();
this.link ({_batch: x}, {'changed': this.onChange});
this.onChange ();
} }
,get: function () ,get: function() {
{ return this._lot;
return this._batch;
} }
}, },
/** /**
* Wether to execute automatically de query que it's ready. * Wether to execute automatically de query que it's ready.
*/ */
autoLoad: autoLoad: {
{
type: Boolean, type: Boolean,
value: false value: false
} }
} }
,initialize: function (props) ,appendChild: function(child) {
{
this.parent (props);
}
,appendChild: function (child)
{
if (child.nodeType === Node.TEXT_NODE) if (child.nodeType === Node.TEXT_NODE)
this.query = child.textContent; this.query = child.textContent;
} }
,loadXml: function (builder, node) ,loadXml: function(builder, node) {
{ this.parent(builder, node);
this.parent (builder, node);
var query = node.firstChild.nodeValue; var query = node.firstChild.nodeValue;
@ -102,21 +80,18 @@ module.exports = new Class
this.query = query; this.query = query;
} }
,execute: function () ,execute: function() {
{ this._conn.execStmt(this._stmt,
this._conn.execStmt (this._stmt, this.onQueryDone.bind(this), this._lot);
this.onQueryDone.bind (this), this._batch);
} }
,onQueryDone: function (resultSet) ,onQueryDone: function(resultSet) {
{ this.emit('ready', resultSet);
this.signalEmit ('ready', resultSet);
} }
,onChange: function () ,onChange: function() {
{ if (this.autoLoad && this._conn && this._stmt && this._lot)
if (this.autoLoad && this._conn && this._stmt && this._batch) this.execute();
this.execute ();
} }
}); });

View File

@ -16,7 +16,7 @@ module.exports = new Class({
,initialize: function() { ,initialize: function() {
window.onerror = this._onWindowError.bind(this); window.onerror = this._onWindowError.bind(this);
window.onunload = this._onWindowUnload.bind(this); window.onunload = this._onWindowUnload.bind(this);
Vn.Hash.initialize(); this._hash = new Vn.Hash({window: window});
var conn = new Db.Connection(); var conn = new Db.Connection();
this.link({_conn: conn}, {'error': this._onConnError}); this.link({_conn: conn}, {'error': this._onConnError});
@ -28,7 +28,10 @@ module.exports = new Class({
if (this.tryAutoLogin()) if (this.tryAutoLogin())
return; return;
var login = this._login = new Login({conn: this._conn}); var login = this._login = new Login({
conn: this._conn,
hash: this._hash
});
login.on('login', this._onLogin, this); login.on('login', this._onLogin, this);
login.show(); login.show();
} }
@ -39,7 +42,10 @@ module.exports = new Class({
if (this._gui) if (this._gui)
return; return;
var gui = this._gui = new Gui({conn: this._conn}); var gui = this._gui = new Gui({
conn: this._conn,
hash: this._hash
});
gui.on('logout', this._onLogout, this); gui.on('logout', this._onLogout, this);
gui.show(); gui.show();
} }
@ -164,6 +170,7 @@ module.exports = new Class({
this._freeGui(); this._freeGui();
this.deinitAutoLogin(); this.deinitAutoLogin();
this._conn.unref(); this._conn.unref();
this._hash.unref();
} }
// Auto login functionality // Auto login functionality
@ -171,15 +178,17 @@ module.exports = new Class({
,_firstLogin: true ,_firstLogin: true
,initAutoLogin: function() { ,initAutoLogin: function() {
var isGuest = new Vn.HashParam({ var isGuest = new Vn.Param({
lot: this._hash,
type: Boolean, type: Boolean,
key: 'guest' name: 'guest'
}); });
this.link({_isGuest: isGuest}, {'changed': this._onGuestChange}); this.link({_isGuest: isGuest}, {'changed': this._onGuestChange});
var token = new Vn.HashParam({ var token = new Vn.Param({
lot: this._hash,
type: String, type: String,
key: 'token' name: 'token'
}); });
this.link({_token: token}, {'changed': this._onTokenChange}); this.link({_token: token}, {'changed': this._onTokenChange});
} }

View File

@ -1,6 +1,7 @@
module.exports = { module.exports = {
check: function(conn, callback) { check: function(conn, hash, callback) {
this.hash = hash;
conn.execQuery('CALL myBasket_check', conn.execQuery('CALL myBasket_check',
this._onBasketCheck.bind(this, callback)); this._onBasketCheck.bind(this, callback));
}, },
@ -18,7 +19,7 @@ module.exports = {
if (callback) if (callback)
callback(isOk); callback(isOk);
if (!isOk) if (!isOk)
Vn.Hash.set({form: 'ecomerce/checkout'}); this.hash.setAll({form: 'ecomerce/checkout'});
} }
}; };

View File

@ -15,25 +15,33 @@ module.exports = new Class({
,loadUi: function() { ,loadUi: function() {
if (!this.isOpen) if (!this.isOpen)
return; return;
const conn = this.conn;
const hash = this.hash;
var builder = new Vn.Builder(); const builder = new Vn.Builder();
builder.compileFile('forms/'+ this.formInfo.path +'/ui.xml'); builder.compileFile('forms/'+ this.formInfo.path +'/ui.xml');
var scope = this.builder = builder.load(null, this); const scope = this.builder = builder.load(null, this);
this.$ = scope.$; this.$ = scope.$;
scope.link(null, {conn: this.conn}); scope.link(null, {conn, hash});
this.node = scope.$.form; this.node = scope.$.form;
var models = scope.getByTagName('db-model'); const paramsLot = this.$.params;
if (paramsLot) {
paramsLot.source = hash;
this.params = paramsLot;
}
for (var i = 0; i < models.length; i++) function setConnection(tagName) {
models[i].conn = this.conn; const objects = scope.getByTagName(tagName);
for (let i = 0; i < objects.length; i++)
objects[i].conn = conn;
}
var queries = scope.getByTagName('db-query'); const tags = ['db-model', 'db-query', 'db-lot'];
for (let i = 0; i < tags.length; i++)
for (var i = 0; i < queries.length; i++) setConnection(tags[i]);
queries[i].conn = this.conn;
if (this.node) { if (this.node) {
this.gui.setForm(this.node); this.gui.setForm(this.node);

View File

@ -64,8 +64,10 @@ module.exports = new Class({
window.addEventListener('scroll', this._onScrollHandler ); window.addEventListener('scroll', this._onScrollHandler );
} }
this.hash = Vn.Hash; this.formParam = new Vn.Param({
this.formParam = new Vn.HashParam({key: 'form'}); lot: this.hash,
name: 'form',
});
this.formParam.on('changed', this._onFormChange, this); this.formParam.on('changed', this._onFormChange, this);
if (!localStorage.getItem('hederaCookies')) { if (!localStorage.getItem('hederaCookies')) {
@ -101,7 +103,7 @@ module.exports = new Class({
} }
,_onConnClose: function() { ,_onConnClose: function() {
this.signalEmit('logout'); this.emit('logout');
} }
,_onConnLoadChange: function(conn, isLoading) { ,_onConnLoadChange: function(conn, isLoading) {
@ -206,7 +208,7 @@ module.exports = new Class({
var a = this.createElement('a'); var a = this.createElement('a');
if (row.path) { if (row.path) {
a.href = Vn.Hash.make({form: row.path}); a.href = this.hash.make({form: row.path});
this.menuOptions[row.path] = a; this.menuOptions[row.path] = a;
} }
@ -445,14 +447,14 @@ module.exports = new Class({
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Reports //++++++++++++++++++++++++++++++++++++++++++++++++++++++ Reports
,openReport: function(reportName, batch) { ,openReport: function(reportName, lot) {
this.loaderPush(); this.loaderPush();
var module = new Module('reports', reportName); var module = new Module('reports', reportName);
module.addCallback(this._onReportLoad.bind(this, batch)); module.addCallback(this._onReportLoad.bind(this, lot));
} }
,_onReportLoad: function(batch, module) { ,_onReportLoad: function(lot, module) {
this.loaderPop(); this.loaderPop();
if (module.error) { if (module.error) {
@ -461,7 +463,7 @@ module.exports = new Class({
} }
var report = new module.klass(module, this); var report = new module.klass(module, this);
report.open(batch); report.open(lot);
} }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Supplant //++++++++++++++++++++++++++++++++++++++++++++++++++++++ Supplant

View File

@ -69,7 +69,7 @@ module.exports = new Class({
if (user) if (user)
localStorage.setItem('hederaLastUser', user); localStorage.setItem('hederaLastUser', user);
this.signalEmit('login'); this.emit('login');
} else { } else {
this._focusUserInput(); this._focusUserInput();
throw error; throw error;

View File

@ -9,8 +9,8 @@ module.exports = new Class({
this.parent(null); this.parent(null);
} }
,open: function(batch) { ,open: function(lot) {
this.batch = batch; this.lot = lot;
this.createWindow(); this.createWindow();
} }
@ -70,7 +70,7 @@ module.exports = new Class({
var scope = this.scope = builder.load(this.doc, this); var scope = this.scope = builder.load(this.doc, this);
scope.link(null, { scope.link(null, {
batch: this.batch, lot: this.lot,
conn: this.conn conn: this.conn
}); });
this.$ = scope.$; this.$ = scope.$;

View File

@ -1,33 +1,25 @@
module.exports = new Class module.exports = new Class({
({
Extends: Htk.Widget Extends: Htk.Widget
,Tag: 'htk-social-bar' ,Tag: 'htk-social-bar'
,Properties: ,Properties: {
{ conn: {
conn:
{
type: Db.Connection type: Db.Connection
,set: function (x) ,set: function(x) {
{
this._conn = x; this._conn = x;
this._refresh (); this._refresh();
} }
,get: function () ,get: function() {
{
return this._conn; return this._conn;
} }
}, },
priority: priority: {
{
type: Number type: Number
,set: function (x) ,set: function(x) {
{
this._priority = x; this._priority = x;
this._refresh (); this._refresh();
} }
,get: function () ,get: function() {
{
return this._priority; return this._priority;
} }
} }
@ -35,42 +27,37 @@ module.exports = new Class
,_priority: 0 ,_priority: 0
,initialize: function () ,initialize: function() {
{ var node = this.createRoot('div');
var node = this.createRoot ('div');
node.className = 'htk-social-bar'; node.className = 'htk-social-bar';
} }
,_refresh: function () ,_refresh: function() {
{
if (!this._conn || this._priority === null) if (!this._conn || this._priority === null)
return; return;
var batch = new Sql.Batch (); const params = {priority: this._priority};
batch.addValue ('priority', this._priority);
var query = 'SELECT title, link, icon FROM social ' var query = 'SELECT title, link, icon FROM social '
+'WHERE priority >= #priority ORDER BY priority'; +'WHERE priority >= #priority ORDER BY priority';
this._conn.execQuery (query, this._onQueryDone.bind (this), batch); this._conn.execQuery(query, this._onQueryDone.bind(this), params);
} }
,_onQueryDone: function (resultSet) ,_onQueryDone: function(resultSet) {
{ Vn.Node.removeChilds(this._node);
Vn.Node.removeChilds (this._node); var res = resultSet.fetchResult();
var res = resultSet.fetchResult ();
while (res.next ()) while (res.next()) {
{ var a = this.createElement('a');
var a = this.createElement ('a'); a.href = res.get('link');
a.href = res.get ('link');
a.target = '_blank'; a.target = '_blank';
this._node.appendChild (a); this._node.appendChild(a);
var img = this.createElement ('img'); var img = this.createElement('img');
img.src = 'image/social/'+ res.get ('icon'); img.src = 'image/social/'+ res.get('icon');
img.alt = res.get ('title'); img.alt = res.get('title');
img.title = res.get ('title'); img.title = res.get('title');
a.appendChild (img); a.appendChild(img);
} }
} }
}); });

View File

@ -6,16 +6,16 @@ module.exports = new Class({
,tpvStatus: null ,tpvStatus: null
,check: function(callback) { ,check: function(callback) {
this.tpvOrder = Vn.Hash.$.tpvOrder; this.tpvOrder = this.hash.$.tpvOrder;
this.tpvStatus = Vn.Hash.$.tpvStatus; this.tpvStatus = this.hash.$.tpvStatus;
if (this.tpvStatus) { if (this.tpvStatus) {
var batch = new Sql.Batch(); const params = {
batch.addValue('transaction', this.tpvOrder); transaction: this.tpvOrder,
batch.addValue('status', this.tpvStatus); status: this.tpvStatus
};
var query = 'CALL myTpvTransaction_end(#transaction, #status)'; var query = 'CALL myTpvTransaction_end(#transaction, #status)';
this.conn.execQuery(query, null, batch); this.conn.execQuery(query, null, params);
} }
if (callback) if (callback)
@ -66,15 +66,14 @@ module.exports = new Class({
} }
,retryPay: function() { ,retryPay: function() {
var batch = new Sql.Batch(); const params = {transaction: parseInt(this.tpvOrder)};
batch.addValue('transaction', parseInt(this.tpvOrder));
var query = 'SELECT t.amount, m.companyFk ' var query = 'SELECT t.amount, m.companyFk '
+'FROM myTpvTransaction t ' +'FROM myTpvTransaction t '
+'JOIN tpvMerchant m ON m.id = t.merchantFk ' +'JOIN tpvMerchant m ON m.id = t.merchantFk '
+'WHERE t.id = #transaction'; +'WHERE t.id = #transaction';
this.conn.execQuery(query, this.conn.execQuery(query,
this._onRetryPayDone.bind(this), batch); this._onRetryPayDone.bind(this), params);
} }
,_onRetryPayDone: function(resultSet) { ,_onRetryPayDone: function(resultSet) {

View File

@ -42,7 +42,7 @@ module.exports = new Class({
set: function(x) { set: function(x) {
this._stepsIndex = x; this._stepsIndex = x;
this.setStep(this._stepIndex); this.setStep(this._stepIndex);
this.signalEmit('steps-change'); this.emit('steps-change');
}, },
get: function() { get: function() {
return this._stepsIndex; return this._stepsIndex;
@ -132,7 +132,7 @@ module.exports = new Class({
this._stepName = stepName; this._stepName = stepName;
this.currentStep = step; this.currentStep = step;
step.show(); step.show();
this.signalEmit('step-change', stepIndex); this.emit('step-change', stepIndex);
if (this.stepFunc) if (this.stepFunc)
this.stepFunc(step); this.stepFunc(step);

View File

@ -90,7 +90,7 @@ module.exports = new Class({
} }
,changed: function(tr, newValue) { ,changed: function(tr, newValue) {
this.signalEmit('changed', tr.rowIndex - 1, newValue); this.emit('changed', tr.rowIndex - 1, newValue);
} }
}); });

View File

@ -69,6 +69,6 @@ module.exports = new Class({
}, },
buttonClicked: function(value, tr, button) { buttonClicked: function(value, tr, button) {
this.signalEmit('clicked', value, tr.rowIndex - 1, button); this.emit('clicked', value, tr.rowIndex - 1, button);
} }
}); });

View File

@ -147,7 +147,7 @@ Dialog.implement({
,hide(response) { ,hide(response) {
if (!this._isOpen) return; if (!this._isOpen) return;
this.parent(); this.parent();
this.signalEmit('response', response); this.emit('response', response);
} }
,createButton: function(label, response) { ,createButton: function(label, response) {

View File

@ -3,10 +3,10 @@ var Widget = require('./widget');
module.exports = new Class({ module.exports = new Class({
Extends: Widget Extends: Widget
,Implements: Vn.ParamIface
,Tag: 'htk-field' ,Tag: 'htk-field'
,Child: 'param' ,Child: 'param'
,Properties: ,Properties: {
{
value: { value: {
type: String type: String
,set: function(x) { ,set: function(x) {
@ -18,21 +18,48 @@ module.exports = new Class({
this.valueChanged(x); this.valueChanged(x);
this.putValue(x); this.putValue(x);
this._notifyChanges();
} }
,get: function(x) { ,get: function() {
return this._value; return this._value;
} }
}, },
param: { param: {
type: Vn.Param type: Vn.ParamIface
,set: function(x) { ,set: function(x) {
this.link({_param: x}, {'changed': this.onParamChange}); this._setParam(x);
this.onParamChange();
} }
,get: function() { ,get: function() {
return this._param; return this._param;
} }
}, },
lot: {
type: Vn.LotIface
,set: function(x) {
this._setLot(x);
}
,get: function() {
return this._lot;
}
},
name: {
type: String
,set: function(x) {
this._setName(x);
}
,get: function() {
return this._name;
}
},
oneWay: {
type: Boolean
,set: function(x) {
this._oneWay = x;
}
,get: function() {
return this._oneWay;
}
},
editable: { editable: {
type: Boolean type: Boolean
,set: function(x) { ,set: function(x) {
@ -48,21 +75,19 @@ module.exports = new Class({
form: { form: {
type: Db.Iterator type: Db.Iterator
,set: function(x) { ,set: function(x) {
this._form = x; this.lot = x;
this.bindToForm();
} }
,get: function() { ,get: function() {
return this._form; return this._lot;
} }
}, },
column: { column: {
type: String type: String
,set: function(x) { ,set: function(x) {
this._paramName = x; this.name = x;
this.bindToForm();
} }
,get: function() { ,get: function() {
return this._paramName; return this._name;
} }
}, },
conditionalFunc: { conditionalFunc: {
@ -71,27 +96,20 @@ module.exports = new Class({
} }
} }
,_value: undefined
,_param: null
,_editable: true ,_editable: true
,_blockParamChange: false ,_lockField: false
,_blockValueChange: false
,onParamChange: function() { ,_setValue: function(newValue) {
if (!this._blockValueChange) { if (!this._putValue(newValue))
this._blockParamChange = true; return;
this.value = this._param.value;
this._blockParamChange = false; if (!this._lockField)
} this.putValue(newValue);
}
if (this.conditionalFunc)
,bindToForm: function() { this.conditionalFunc(this, newValue);
if (this._form && this._paramName)
this.param = new Db.Param this._notifyChanges();
({
form: this._form
,column: this._paramName
});
} }
/** /**
@ -100,7 +118,7 @@ module.exports = new Class({
* *
* @param {Boolean} editable Whether the user is allowed to edit the entry * @param {Boolean} editable Whether the user is allowed to edit the entry
*/ */
,setEditable: function(editable) {} ,setEditable: function() {}
/** /**
* Virtual method that must be implemented by class childs to put the value * Virtual method that must be implemented by class childs to put the value
@ -108,7 +126,7 @@ module.exports = new Class({
* *
* @param {Object} value The new value for the entry * @param {Object} value The new value for the entry
*/ */
,putValue: function(value) {} ,putValue: function() {}
/** /**
* Protected method that should be called from class childs when the value * Protected method that should be called from class childs when the value
@ -117,18 +135,9 @@ module.exports = new Class({
* @param {Object} value The new entry value * @param {Object} value The new entry value
*/ */
,valueChanged: function(value) { ,valueChanged: function(value) {
this._value = value; this._lockField = true;
this._setValue(value);
if (this.conditionalFunc) this._lockField = false;
this.conditionalFunc(this, value);
if (this._param && !this._blockParamChange) {
this._blockValueChange = true;
this._param.value = value;
this._blockValueChange = false;
}
this.signalEmit('changed');
} }
}); });

View File

@ -1,10 +1,8 @@
module.exports = new Class module.exports = new Class({
({
Extends: Htk.Field Extends: Htk.Field
,Tag: 'htk-entry' ,Tag: 'htk-entry'
,Properties: ,Properties: {
{
/** /**
* Displayed text when there is no content. * Displayed text when there is no content.
*/ */
@ -52,7 +50,7 @@ module.exports = new Class
node.addEventListener('change', this._onChange.bind(this)); node.addEventListener('change', this._onChange.bind(this));
} }
,_onChange: function(event) { ,_onChange: function() {
var newValue; var newValue;
if (this.node.value == '') if (this.node.value == '')

View File

@ -153,7 +153,7 @@ module.exports = new Class({
popup.on('closed', this._onPopupClose.bind(this)); popup.on('closed', this._onPopupClose.bind(this));
popup.show(this.node); popup.show(this.node);
this.signalEmit('menu-show'); this.emit('menu-show');
e.stopPropagation(); e.stopPropagation();
} }
@ -184,7 +184,7 @@ module.exports = new Class({
,_onPopupClose: function() { ,_onPopupClose: function() {
this._popup = null; this._popup = null;
this.signalEmit('menu-hide'); this.emit('menu-hide');
} }
,_refreshShowText: function() { ,_refreshShowText: function() {
@ -204,14 +204,14 @@ module.exports = new Class({
,_onModelChange: function() { ,_onModelChange: function() {
var model = this._model; var model = this._model;
this.signalEmit('status-changed'); this.emit('status-changed');
if (this._popup) if (this._popup)
this._popup.reset(); this._popup.reset();
if (model && model.ready) { if (model && model.ready) {
this._selectOption(); this._selectOption();
this.signalEmit('ready'); this.emit('ready');
} else } else
this._setRow(-1); this._setRow(-1);
} }

View File

@ -1,58 +1,50 @@
var Entry = require ('./entry'); var Entry = require('./entry');
var ColumnRadio = require ('../column/radio'); var ColumnRadio = require('../column/radio');
module.exports = new Class module.exports = new Class({
({
Extends: Entry Extends: Entry
,Tag: 'htk-table' ,Tag: 'htk-table'
,render: function () ,render: function() {
{ var tv = new Htk.TreeView();
var tv = new Htk.TreeView (); this.node.appendChild(tv.node);
this.node.appendChild (tv.node);
var renderer = new ColumnRadio (); var renderer = new ColumnRadio();
tv.appendColumn (0, renderer, ''); tv.appendColumn(0, renderer, '');
var rbGroup = renderer.rbGroup; var rbGroup = renderer.rbGroup;
rbGroup.addSignal ('changed', this.changed, this); rbGroup.addSignal('changed', this.changed, this);
this.treeview = tv; this.treeview = tv;
this.rbGroup = rbGroup; this.rbGroup = rbGroup;
} }
,setModel: function (model) ,setModel: function(model) {
{ this.treeview.setModel(model);
this.treeview.setModel (model); model.addSignal('status-changed', this.modelRefresh, this);
model.addSignal ('status-changed', this.modelRefresh, this); this.selectValue();
this.selectValue ();
} }
,changed: function (rbGroup) ,changed: function() {
{ this.realValue = this.rbGroup.getValue();
this.realValue = this.rbGroup.getValue (); this.emit('changed');
this.signalEmit ('changed');
} }
,selectValue: function () ,selectValue: function() {
{ this.rbGroup.setValue(this.realValue);
this.rbGroup.setValue (this.realValue);
} }
,setRealValue: function () ,setRealValue: function() {
{ this.selectValue();
this.selectValue ();
} }
,modelRefresh: function (model, status) ,modelRefresh: function(model, status) {
{
if (status == Db.Model.Status.READY) if (status == Db.Model.Status.READY)
this.selectValue (); this.selectValue();
} }
,setEditable: function (editable) ,setEditable: function(editable) {
{ this.rbGroup.setEditable(editable);
this.rbGroup.setEditable (editable);
} }
}); });

View File

@ -35,7 +35,7 @@ module.exports = new Class({
if (!newValue) if (!newValue)
newValue = null newValue = null
this.signalEmit('name-changed', newValue); this.emit('name-changed', newValue);
}, },
_onSubmit: function() { _onSubmit: function() {
@ -55,7 +55,7 @@ module.exports = new Class({
throw error; throw error;
Toast.showMessage(_('ImageAdded')); Toast.showMessage(_('ImageAdded'));
this.signalEmit('file-uploaded', this.$.name.value); this.emit('file-uploaded', this.$.name.value);
}, },
setData: function(image, directory) { setData: function(image, directory) {

View File

@ -185,7 +185,7 @@ module.exports = new Class
Vn.Node.remove(this._node); Vn.Node.remove(this._node);
this._parent = null; this._parent = null;
this._isOpen = false; this._isOpen = false;
this.signalEmit('closed'); this.emit('closed');
} }
,_bgMouseDown: function(e) { ,_bgMouseDown: function(e) {

View File

@ -169,7 +169,7 @@ module.exports = new Class({
} }
this.node.appendChild(this._container); this.node.appendChild(this._container);
this.signalEmit('change'); this.emit('change');
} }
,_showNoRecordsFound: function() { ,_showNoRecordsFound: function() {

View File

@ -68,7 +68,8 @@ const Widget = new Class({
type: String type: String
,set: function(x) { ,set: function(x) {
this._htmlId = x; this._htmlId = x;
this._node.id = x; if (this._node)
this._node.id = x;
} }
,get: function() { ,get: function() {
return this._htmlId; return this._htmlId;
@ -85,7 +86,9 @@ const Widget = new Class({
} }
,createRoot: function(tagName) { ,createRoot: function(tagName) {
return this._node = this.createElement(tagName); const node = this._node = this.createElement(tagName);
if (this._htmlId) node.id = this._htmlId;
return node;
} }
,renderBase: function() { ,renderBase: function() {

View File

@ -1,142 +0,0 @@
var Object = require('./object');
var Value = require('./value');
/**
* A map container for many Sql.Object
*/
module.exports = new Class({
Extends: Object
,Tag: 'sql-batch'
,Properties: {
blocked: {
type: Boolean
,set: function(x) {
this._blocked = x;
}
,get: function() {
return this._blocked;
}
}
}
,objects: {}
,_blocked: false
,loadXml: function(scope, node) {
this.parent(scope, node);
var childs = node.childNodes;
for (var i = 0; i < childs.length; i++)
if (childs[i].tagName && childs[i].tagName.toLowerCase() == 'item') {
var object;
var id = childs[i].getAttribute('name');
if (id) {
if (object = scope.getById(childs[i].getAttribute('param')))
this.addParam(id, object);
else if (object = scope.getById(childs[i].getAttribute('object')))
this.addObject(id, object);
}
}
}
,get: function(id) {
if (this.objects[id])
return this.objects[id];
return null;
}
,add: function(id) {
if (!this.objects[id])
this.objects[id] = null;
}
,_addObject: function(id, object) {
this.remove(id);
this.objects[id] = object;
object.on('changed', this.emitChanged, this);
this.emitChanged();
}
,addObject: function(id, object) {
this._addObject(id, object.ref());
}
,addValue: function(id, value) {
this._addObject(id,
new Value({value: value}));
}
,addValues: function(values) {
for (var id in values)
this.addValue(id, values[id]);
}
,addParam: function(id, param) {
this._addObject(id,
new Value({param: param}));
}
,getValue: function(id) {
var object = this.objects[id];
if (object instanceof Value)
return object.value;
return null;
}
,addParams: function(params) {
for (var id in params)
this.addParam(id, params[id]);
}
,remove: function(id) {
if (this.objects[id]) {
this._unrefObject(this.objects[id]);
delete this.objects[id];
}
}
,block: function() {
this._blocked = true;
}
,unblock: function() {
this._blocked = false;
}
,emitChanged: function() {
if (!this._blocked)
this.signalEmit('changed');
}
,changed: function() {
this.signalEmit('changed');
}
,isReady: function() {
for (var id in this.objects)
if (!(this.objects[id] && this.objects[id].isReady()))
return false;
return true;
}
,_unrefObject: function(object) {
if (object) {
object.disconnect('changed', this.emitChanged, this);
object.unref();
}
}
,_destroy: function() {
for (var id in this.objects)
this._unrefObject(this.objects[id]);
this.parent();
}
});

View File

@ -4,19 +4,14 @@ var Stmt = require('./stmt');
/** /**
* The equivalent of a SQL delete. * The equivalent of a SQL delete.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Stmt Extends: Stmt
,Tag: 'sql-delete'
,render: function(batch) { ,render: function(params) {
var sql = 'DELETE FROM ' + this.renderTarget(batch); return 'DELETE FROM'
+ this.renderTarget(params)
if (this.where) + this.renderIfSet(this.where, 'WHERE', params)
sql += ' WHERE ' + this.where.render(batch); + this.renderLimit(params);
sql += ' LIMIT 1'; // Only for security.
return sql;
} }
}); });

View File

@ -13,13 +13,13 @@ module.exports = new Class({
,expr: [] ,expr: []
,addSet: function(fieldName, value) { ,addSet: function(fieldName, value) {
this.expr.push(new Value({value: value}));
this.field.push(new Field({name: fieldName})); this.field.push(new Field({name: fieldName}));
this.expr.push(new Value({value: value}));
} }
,addExpr: function(fieldName, expr) { ,addExpr: function(fieldName, expr) {
this.expr.push(expr);
this.field.push(new Field({name: fieldName})); this.field.push(new Field({name: fieldName}));
this.expr.push(expr);
} }
,delSet: function() { ,delSet: function() {

View File

@ -1,5 +1,5 @@
var Expr = require('./expr'); var Expr = require ('./expr');
/** /**
* The equivalent of a SQL field. * The equivalent of a SQL field.
@ -12,11 +12,17 @@ module.exports = new Class
,Tag: 'sql-field' ,Tag: 'sql-field'
,Properties: ,Properties:
{ {
/**
* The column name.
*/
name: name:
{ {
type: String type: String
,value: null ,value: null
}, },
/**
* The source table name or its alias if it has been specified.
*/
target: target:
{ {
type: String type: String
@ -24,8 +30,9 @@ module.exports = new Class
} }
} }
,render: function(batch) { ,render: function ()
var sql = (this.target) ? '`' + this.target + '`.' : ''; {
return sql + '`' + this.name + '`'; return this.renderPreIdent (this.target)
+ this.renderIdent (this.name);
} }
}); });

View File

@ -1,17 +1,68 @@
var Operation = require('./operation'); var Operation = require('./operation');
var Value = require('./value');
var Field = require('./field');
/** /**
* The equivalent of a SQL operation. * Objects to be used as an operands of @Sql.Filter. It represents a two
* expressions basic operation composed by a table column, the operator and the
* value extracted from the rendering paramerers.
*/ */
module.exports = new Class({ module.exports = new Class({
Extends: Operation Extends: Operation
,Tag: 'sql-filter-item' ,Tag: 'sql-filter-item'
,Properties: { ,Properties: {
primary: { /**
type: Boolean * The column name.
*/
field: {
type: String,
value: null
},
/**
* The source table name or its alias if it has been specified.
*/
target: {
type: String,
value: null
},
/**
* The parameter name.
*/
param: {
type: String,
value: null
} }
} }
,primary: true /**
* Checks if parameter name haa been defined and if it has a value.
*/
,isReady: function(params) {
return this.param != null && params != null && params[this.param] != null;
}
,render: function(params) {
var newOp = new Operation({type: this.type});
newOp.push(new Field({
name: this.field,
target: this.target
}));
var value = params[this.param];
if (this.type === Operation.Type.LIKE && typeof value === 'string') {
value = value.replace(/[\%\?]/g, this._escapeChar);
value = value.replace(/^|\s+|$/g, '%');
}
newOp.push(new Value({value: value}));
return newOp.render(params);
}
,_escapeChar: function(char) {
return '\\'+ char;
}
}); });

View File

@ -1,44 +1,52 @@
var Operation = require('./operation'); var Operation = require ('./operation');
var Value = require ('./value');
/** /**
* The equivalent of a SQL operation. * The equivalent of a SQL filter expression. It allows to automatically build
* SQL filters based on lot parameters.
*/ */
module.exports = new Class({ module.exports = new Class
({
Extends: Operation Extends: Operation
,Tag: 'sql-filter' ,Tag: 'sql-filter'
,Properties: {
alwaysReady: {
type: Boolean
}
}
,isReady: function() { /**
if (this.alwaysReady) * Checks if any of filters childs are ready.
*/
,isReady: function (params)
{
var exprs = this.exprs;
for (var i = exprs.length; i--;)
if (exprs[i].isReady (params))
return true; return true;
var e = this.exprs.getArray();
for (var i = 0; i < e.length; i++)
if (e[i].isReady() && e[i].primary)
return true;
return false; return false;
} }
,render: function(batch) { /**
var isReady = false; * Renders the filter as an SQL expression. If any of its childs isn't
var newOp = new Operation({type: this.type}); * ready is ommitted from the expression. If all of its childs aren't ready
* renders the TRUE expression.
*/
,render: function (params)
{
var newOp;
var newExprs = [];
this.exprs.forEach (function (expr) {
if (expr.isReady (params))
newExprs.push (expr);
})
var e = this.exprs.getArray(); if (newExprs.length > 0)
for (var i = 0; i < e.length; i++) newOp = new Operation ({
if (e[i].isReady()) { type: this.type,
newOp.exprs.add(e[i]); exprs: newExprs
isReady = true; });
} else
newOp = new Value ({value: true});
if (!isReady) return newOp.render (params);
return 'TRUE';
return newOp.render(batch);
} }
}); });

View File

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

View File

@ -1,12 +1,13 @@
var Object = require('./object'); var SqlObject = require ('./object');
var Value = require ('./value');
/** /**
* A holder for another object. * A holder for another object.
*/ */
module.exports = new Class module.exports = new Class
({ ({
Extends: Object Extends: SqlObject
,Properties: ,Properties:
{ {
id: id:
@ -16,11 +17,24 @@ module.exports = new Class
} }
} }
,render: function(batch) { ,render: function (params)
var object; {
if (params)
{
var object = params[this.id];
if (batch && (object = batch.get(this.id))) if (object !== undefined)
return object.render(batch); {
if (!(object instanceof SqlObject))
{
var sqlValue = new Value ();
sqlValue.value = object;
return sqlValue.render ();
}
else
return object.render (params);
}
}
return '#'+ this.id; return '#'+ this.id;
} }

View File

@ -8,31 +8,14 @@ module.exports = new Class
({ ({
Extends: Dml Extends: Dml
,render: function (batch) ,render: function (params)
{ {
var sql; return 'INSERT INTO'
var n; + this.renderTarget (params)
+ ' ('
sql = 'INSERT INTO ' + this.renderTarget (batch) + ' ('; + this.renderListWs (this.field, params, ', ')
+ ') VALUES ('
for (n = 0; n < this.field.length; n++) + this.renderListWs (this.expr, params, ', ')
{ + ')';
if (n > 0)
sql += ', ';
sql += this.field[n].render (batch);
}
sql += ') VALUES (';
for (n = 0; n < this.field.length; n++)
{
if (n > 0)
sql += ', ';
sql += this.expr[n].render(batch);
}
sql += ')';
return sql;
} }
}) })

54
js/sql/join-item.js Normal file
View File

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

54
js/sql/join.js Normal file
View File

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

60
js/sql/list-holder.js Normal file
View File

@ -0,0 +1,60 @@
/**
* Interface for array holders.
*/
module.exports = new Class
({
Properties:
{
/*
list:
{
type: Array
,set: function (x)
{
this._list = x;
}
,get: function ()
{
return this._list;
}
}
*/
}
,list: []
,appendChild: function (child)
{
this.list.push (child);
}
/**
* Adds an element to the list.
*
* @param {SqlObject} element The element to add
*/
,push: function (element)
{
this.list.push (element);
}
/**
* Removes an element from the list.
*
* @param {Number} i The element index
*/
,splice: function (i)
{
this.list.splice (i);
}
/**
* Adds an element to the list.
*
* @param {Number} i The element index
*/
,get: function (i)
{
return this.list[i];
}
});

View File

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

View File

@ -1,5 +1,6 @@
var Stmt = require ('./stmt'); var Stmt = require ('./stmt');
var ListHolder = require ('./list-holder');
/** /**
* The equivalent of a SQL multi statement. * The equivalent of a SQL multi statement.
@ -7,43 +8,29 @@ var Stmt = require ('./stmt');
module.exports = new Class module.exports = new Class
({ ({
Extends: Stmt Extends: Stmt
,Implements: ListHolder
,stmts: [] ,Tag: 'sql-multi-stmt'
,Properties:
,addStmt: function (stmt)
{ {
return this.stmts.push (stmt); /**
} * The statements list.
*/
,getStmt: function (stmtIndex) stmts:
{
return this.stmts[index];
}
,isReady: function ()
{
if (this.stmts.length == 0)
return false;
for (var i = 0; i < this.stmts.length; i++)
if (!this.stmts[i].isReady ())
return false;
return true;
}
,render: function (batch)
{
var sql = '';
for (var i = 0; i < this.stmts.length; i++)
{ {
if (i > 0) type: Array
sql += ";\n"; ,set: function (x)
{
sql += this.stmts[i].render (batch); this.list = x;
}
,get: function ()
{
return this.list;
}
} }
}
return sql; ,render: function (params)
{
return this.renderListWs (this.list, params, ";\n");
} }
}); });

View File

@ -3,18 +3,11 @@
*/ */
module.exports = new Class({ module.exports = new Class({
Extends: Vn.Object Extends: Vn.Object
/**
* Renders the object as an SQL string.
*
* @param {Sql.Batch} batch The batch used to render the object
* @return {String} The SQL string
*/
,render: function(batch) {}
/** /**
* Gets if the object is ready to be rendered. * Gets if the object is ready to be rendered.
* *
* @param {Object} params The query parameters
* @return {boolean} %true if the object is ready, %false otherwise * @return {boolean} %true if the object is ready, %false otherwise
*/ */
,isReady: function() { ,isReady: function() {
@ -22,9 +15,90 @@ module.exports = new Class({
} }
/** /**
* Through the query looking for containers and adds it to the batch. * Through the query looking for containers.
* *
* @return {Sql.Batch} batch The batch * @return {Array} An array with the names of the found parameters
*/ */
,findHolders: function(batch) {} ,findHolders: function() {}
/**
* Renders the object as an SQL string.
*
* @param {Object} params The params used to render the object
* @return {string} The SQL string
*/
,render: function() {}
/**
* Renders an objects array.
*
* @param {Array} list The objects array
* @param {Object} params The parameters
* @return {string} The rendered SQL string
*/
,renderList: function(list, params) {
var sql = '';
list.forEach(function(item) {
sql += item.render(params);
})
return sql;
}
/**
* Renders an objects array using a separator.
*
* @param {Array} list The objects array
* @param {Object} params The parameters
* @param {String} separator The separator between items
* @return {string} The rendered SQL string
*/
,renderListWs: function(list, params, separator) {
var sql = '';
list.forEach(function(item, i) {
if (i > 0)
sql += separator;
sql += item.render(params);
})
return sql;
}
/**
* Renders a quoted SQL identifier.
*
* @param {String} identifier The identifier
* @return {string} The quoted identifier
*/
,renderIdent: function(identifier) {
return '`'+ identifier +'`';
}
/**
* Renders a quoted SQL identifier.
*
* @param {String} identifier The identifier
* @return {string} The quoted identifier
*/
,renderPreIdent: function(identifier) {
if (identifier)
return this.renderIdent(identifier) +'.';
else
return '';
}
/**
* Renders the object if it's defined.
*
* @param {String} prefix The rendered string prefix
* @return {string} The rendered object with its prefix
*/
,renderIfSet: function(object, prefix, params) {
if (object)
return ' '+ prefix +' '+ object.render(params);
else
return '';
}
}); });

View File

@ -1,78 +1,96 @@
var Expr = require('./expr'); var Expr = require ('./expr');
var ListHolder = require ('./list-holder');
/** /**
* The equivalent of a SQL operation between exprs. * The equivalent of a SQL operation between exprs.
* *
* @param {Array#Sql.Expr} expr Array with the exprs * @param {Array#Expr} exprs Array with the exprs
* @param {Sql..Operation.Type} type The type of the operation * @param {Type} type The type of the operation
*/ */
var Operation = new Class(); var Klass = new Class ();
module.exports = Operation; module.exports = Klass;
var Type = { var Type =
{
EQUAL : 0 EQUAL : 0
,LIKE : 1 ,LIKE : 1
,AND : 2 ,AND : 2
,OR : 3 ,OR : 3
,REGEXP : 4 ,REGEXP : 4
,LOWER : 5
,UPPER : 6
,LE : 7
,UE : 8
,PLUS : 9
,MINUS : 10
,MULT : 11
,DIV : 12
,NE : 13
,MOD : 14
}; };
var Operators = [ var Operators =
[
'=' '='
,'LIKE' ,'LIKE'
,'AND' ,'AND'
,'OR' ,'OR'
,'REGEXP' ,'REGEXP'
,'<'
,'>'
,'<='
,'>='
,'+'
,'-'
,'*'
,'/'
,'<>'
,'MOD'
]; ];
Operation.extend({ Klass.extend
({
Type: Type Type: Type
,Operators: Operators ,Operators: Operators
}); });
Operation.implement({ Klass.implement
({
Extends: Expr Extends: Expr
,Implements: ListHolder
,Tag: 'sql-operation' ,Tag: 'sql-operation'
,Properties: { ,Properties:
type: { {
type:
{
enumType: Type enumType: Type
,value: -1 ,value: -1
},
target:
{
type: String
,value: null
},
exprs:
{
type: Array
,set: function (x)
{
this.list = x;
}
,get: function ()
{
return this.list;
}
} }
} }
,initialize: function(props) { ,render: function (params)
this.parent(props); {
this.link({exprs: new Sql.List()}, {'changed': this.onListChange});
}
,appendChild: function(child) {
this.exprs.add(child);
}
,onListChange: function() {
this.signalEmit('changed');
}
,isReady: function() {
return this.exprs.isReady();
}
,render: function(batch) {
var sql = '(';
var operator = ' '+ Operators[this.type] +' '; var operator = ' '+ Operators[this.type] +' ';
var e = this.exprs.getArray(); return '('
+ this.renderListWs (this.list, params, operator)
for (var i = 0; i < e.length; i++) { + ')';
if (i > 0)
sql += operator;
sql += e[i].render(batch);
}
sql += ')';
return sql;
} }
}); });

View File

@ -1,19 +0,0 @@
var Value = require('./value');
/**
* The equivalent of a SQL value.
*/
module.exports = new Class
({
Extends: Value
,Tag: 'sql-search-tags'
,render: function(batch) {
if (typeof this._value == 'string') {
var value = this._value.replace(/^|\s+|$/g, '%');
return "'" + value.replace(this.regexp, this.replaceFunc) + "'";
} else
return this.parent();
}
});

View File

@ -16,22 +16,13 @@ module.exports = new Class
this.expr.push (new Field ({name: fieldName})); this.expr.push (new Field ({name: fieldName}));
} }
,render: function (batch) ,render: function (params)
{ {
var sql = 'SELECT ' return 'SELECT '
+ this.renderListWs (this.expr, params, ', ')
for (var i = 0; i < this.expr.length; i++) + ' FROM'
{ + this.renderTarget (params)
if (i > 0) + this.renderIfSet (this.where, 'WHERE', params)
sql += ', '; + this.renderLimit (params);
sql += this.expr[i].render(batch);
}
sql += ' FROM ' + this.renderTarget (batch);
if (this.where)
sql += ' WHERE ' + this.where.render (batch);
return sql;
} }
}); });

View File

@ -1,28 +1,29 @@
require ('vn/vn'); require('vn/vn');
Sql = module.exports = { Sql = module.exports = {
Object : require ('./object') Object : require('./object')
,Holder : require ('./holder') ,Holder : require('./holder')
,Batch : require ('./batch') ,List : require('./list')
,List : require ('./list') ,ListHolder : require('./list-holder')
,Expr : require ('./expr') ,Expr : require('./expr')
,Value : require ('./value') ,Value : require('./value')
,Field : require ('./field') ,Field : require('./field')
,Function : require ('./function') ,Function : require('./function')
,Operation : require ('./operation') ,Operation : require('./operation')
,Target : require ('./target') ,Target : require('./target')
,Table : require ('./table') ,Table : require('./table')
,Stmt : require ('./stmt') ,Join : require('./join')
,Dml : require ('./dml') ,JoinItem : require('./join-item')
,String : require ('./string') ,Stmt : require('./stmt')
,Delete : require ('./delete') ,Dml : require('./dml')
,Insert : require ('./insert') ,String : require('./string')
,Select : require ('./select') ,Delete : require('./delete')
,Update : require ('./update') ,Insert : require('./insert')
,MultiStmt : require ('./multi-stmt') ,Select : require('./select')
,Filter : require ('./filter') ,Update : require('./update')
,FilterItem : require ('./filter-item') ,MultiStmt : require('./multi-stmt')
,SearchTags : require ('./search-tags') ,Filter : require('./filter')
,FilterItem : require('./filter-item')
}; };

View File

@ -1,47 +1,40 @@
var Object = require ('./object'); var Object = require('./object');
var Expr = require ('./expr'); var Expr = require('./expr');
/** /**
* The equivalent of a SQL statement. * The equivalent of a SQL statement.
*/ */
module.exports = new Class module.exports = new Class({
({
Extends: Object Extends: Object
,Properties: ,Properties: {
{ where: {
where:
{
type: Expr type: Expr
,value: null ,value: null
},
limit: {
type: Number
,value: null
} }
} }
,target: [] ,target: []
,addTarget: function (target) ,addTarget: function(target) {
{ this.target.push(target);
this.target.push (target);
} }
,renderTarget: function (batch) ,renderTarget: function(params) {
{ if (this.target.length > 0)
var sql; return ' '+ this.renderListWs(this.target, params, ', ');
var len = this.target.length;
if (len > 0)
{
sql = ' ';
for (var n = 0; n < len; n++)
{
if (n > 0) sql += ', ';
sql += this.target[n].render (batch);
}
}
else else
sql += 'DUAL'; return ' DUAL';
}
return sql;
} ,renderLimit: function() {
if (this.limit != null)
return ' LIMIT '+ parseInt(this.limit);
else
return '';
}
}); });

View File

@ -8,6 +8,7 @@ var Holder = require ('./holder');
module.exports = new Class module.exports = new Class
({ ({
Extends: Stmt Extends: Stmt
,Tag: 'sql-string'
,Properties: ,Properties:
{ {
query: query:
@ -18,19 +19,25 @@ module.exports = new Class
} }
,regexp: /#\w+/g ,regexp: /#\w+/g
,replaceFunc: function (batch, token) ,appendChild: function (child)
{ {
var holder = new Holder ({id: token.substr (1)}); if (child.nodeType === Node.TEXT_NODE)
return holder.render (batch); this.query = child.textContent;
} }
,render: function (batch) ,render: function (params)
{ {
if (!this.query) if (!this.query)
return null; return null;
function replaceFunc (token)
{
var holder = new Holder ({id: token.substr (1)});
return holder.render (params);
}
return this.query.replace (this.regexp, this.replaceFunc.bind (this, batch)); return this.query.replace (this.regexp, replaceFunc);
} }
,findHolders: function () ,findHolders: function ()

View File

@ -1,5 +1,5 @@
var Target = require('./target'); var Target = require ('./target');
/** /**
* Represents a database table. * Represents a database table.
@ -14,6 +14,11 @@ module.exports = new Class
type: String type: String
,value: null ,value: null
}, },
alias:
{
type: String
,value: null
},
schema: schema:
{ {
type: String type: String
@ -21,9 +26,14 @@ module.exports = new Class
} }
} }
,render: function(batch) { ,render: function ()
var sql = this.schema ? '`' + this.schema + '`.' : ''; {
sql += '`' + this.name + '`'; var sql = this.renderPreIdent (this.schema)
+ this.renderIdent (this.name);
if (this.alias)
sql += ' AS '+ this.renderIdent (this.alias);
return sql; return sql;
} }
}); });

View File

@ -1,5 +1,5 @@
var Object = require('./object'); var Object = require ('./object');
/** /**
* The equivalent of a SQL target. * The equivalent of a SQL target.

View File

@ -8,25 +8,23 @@ module.exports = new Class
({ ({
Extends: Dml Extends: Dml
,render: function (batch) ,render: function (params)
{ {
var sql; var sql = 'UPDATE'
var n; + this.renderTarget (params)
+ ' SET ';
sql = 'UPDATE ' + this.renderTarget (batch) + ' SET '; this.field.forEach (function (field, i) {
if (i > 0)
for (n = 0; n < this.field.length; n++)
{
if (n > 0)
sql += ', '; sql += ', ';
sql += this.field[n].render () + ' = ' + this.expr[n].render(batch);
} sql += field.render (params)
+ ' = '
+ this.expr[i].render(params);
}, this);
if (this.where) sql += this.renderIfSet (this.where, 'WHERE', params)
sql += ' WHERE ' + this.where.render (batch); + this.renderLimit(params);
sql += ' LIMIT 1'; // Only for security.
return sql; return sql;
} }
}); });

View File

@ -5,64 +5,69 @@ var Expr = require('./expr');
* The equivalent of a SQL value. * The equivalent of a SQL value.
*/ */
module.exports = new Class({ module.exports = new Class({
Extends: Expr
,Tag: 'sql-value'
Extends: Expr
,Implements: Vn.ParamIface
,Tag: 'sql-value'
,Properties: { ,Properties: {
/** value: {
* The master param. type: null
*/
param: {
type: Vn.Param
,set: function(x) { ,set: function(x) {
this.link({_param: x}, {'changed': this.onParamChange}); this._setValue(x);
this.onParamChange(); }
,get: function() {
return this._value;
}
},
type: {
type: Type
,set: function(x) {
this._setType(x);
}
,get: function() {
return this._type;
}
},
param: {
type: Vn.ParamIface
,set: function(x) {
this._setParam(x);
} }
,get: function() { ,get: function() {
return this._param; return this._param;
} }
}, },
/** lot: {
* The value. type: Vn.LotIface
*/
value: {
type: String
,set: function(x) { ,set: function(x) {
if (Vn.Value.compare(x, this._value)) this._setLot(x);
return;
if (x instanceof Date)
x = x.clone();
this._value = x;
if (this._param && !this.paramLock) {
this.paramLock = true;
this._param.value = x;
this.paramLock = false;
}
this.signalEmit('changed');
} }
,get: function() { ,get: function() {
return this._value; return this._lot;
}
},
name: {
type: String
,set: function(x) {
this._name = x;
this._onLotChange();
}
,get: function() {
return this._name;
}
},
oneWay: {
type: Boolean
,set: function(x) {
this._oneWay = x;
}
,get: function() {
return this._oneWay;
} }
} }
} }
,_value: undefined
,_param: null
,regexp: new RegExp('(\\\\)|\'', 'g') ,regexp: new RegExp('(\\\\)|\'', 'g')
,paramLock: false
,onParamChange: function() {
if (this.paramLock || !this._param)
return;
this.paramLock = true;
this.value = this._param.value;
this.paramLock = false;
}
,isReady: function() { ,isReady: function() {
return this._value !== undefined; return this._value !== undefined;

View File

@ -1,36 +1,29 @@
module.exports = module.exports = {
{ getPageYOffset: function() {
getPageYOffset: function ()
{
return window.pageYOffset; return window.pageYOffset;
}, },
getPageXOffset: function () getPageXOffset: function() {
{
return window.pageXOffset; return window.pageXOffset;
}, },
getInnerHeight: function () getInnerHeight: function() {
{
return window.innerHeight; return window.innerHeight;
}, },
getInnerWidth: function () getInnerWidth: function() {
{
return window.innerWidth; return window.innerWidth;
}, },
createRadio: function (uid, doc) createRadio: function(uid, doc) {
{ var radio = doc.createElement('input');
var radio = doc.createElement ('input');
radio.type = 'radio'; radio.type = 'radio';
radio.name = uid; radio.name = uid;
return radio; return radio;
}, },
setInputTypeNumber: function (input) setInputTypeNumber: function(input) {
{
input.type = 'number'; input.type = 'number';
} }
}; };

View File

@ -2,6 +2,7 @@ const VnObject = require('./object');
const Widget = require('../htk/widget'); const Widget = require('../htk/widget');
const VnNode = require('./node'); const VnNode = require('./node');
const Scope = require('./scope'); const Scope = require('./scope');
const Type = require('./type');
const kebabToCamel = require('./string-util').kebabToCamel; const kebabToCamel = require('./string-util').kebabToCamel;
/** /**
@ -488,6 +489,9 @@ module.exports = new Class({
case Function: case Function:
context.funcProps[propName] = this._getMethod(value); context.funcProps[propName] = this._getMethod(value);
break; break;
case Type:
newValue = window[value];
break;
default: default:
if (propInfo.enumType) if (propInfo.enumType)
newValue = propInfo.enumType[value]; newValue = propInfo.enumType[value];

View File

@ -8,8 +8,7 @@ Date.prototype.clone = function() {
module.exports = module.exports =
{ {
WDays: WDays: [
[
'Sunday' 'Sunday'
,'Monday' ,'Monday'
,'Tuesday' ,'Tuesday'
@ -18,8 +17,7 @@ module.exports =
,'Friday' ,'Friday'
,'Saturday' ,'Saturday'
] ]
,AbrWDays: ,AbrWDays: [
[
'Su' 'Su'
,'Mo' ,'Mo'
,'Tu' ,'Tu'
@ -28,8 +26,7 @@ module.exports =
,'Fr' ,'Fr'
,'Sa' ,'Sa'
] ]
,Months: ,Months: [
[
'January' 'January'
,'February' ,'February'
,'March' ,'March'
@ -43,8 +40,7 @@ module.exports =
,'November' ,'November'
,'December' ,'December'
] ]
,AbrMonths: ,AbrMonths: [
[
'Jan' 'Jan'
,'Feb' ,'Feb'
,'Mar' ,'Mar'

4
js/vn/enum.js Normal file
View File

@ -0,0 +1,4 @@
/**
* Base type for ennumerations.
*/
module.exports = function() {};

72
js/vn/form.js Normal file
View File

@ -0,0 +1,72 @@
var Iterator = require('./iterator');
var ModelIface = require('./model-iface');
module.exports = new Class({
Extends: Iterator
,Tag: 'db-form'
,Properties: {
model: {
type: ModelIface
,set: function(x) {
this.link({_model: x},
{
'status-changed': this.onModelChange
,'row-updated': this.onModelRowUpdate
});
}
,get: function() {
return this._model;
}
},
/**
* The row where the form positioned, has -1 if the row is unselected.
*/
row: {
type: Number
,set: function(x) {
if (!this._model || this._model.numRows <= x || x < -1)
x = -1;
if (x == this._row)
return;
this._row = x;
this.rowChanged();
}
,get: function() {
return this._row;
}
}
}
,initialize: function(props) {
Object.assign(this, {
_lastRow: 0
,_lastReady: false
});
this.parent(props);
}
,onModelChange: function() {
var ready = this._model && this._model.ready;
if (ready != this._lastReady) {
if (this._row != -1)
this._lastRow = this._row;
this._lastReady = ready;
this.emit('status-changed');
if (this._row == -1)
this.row = this._lastRow;
if (ready)
this.emit('ready');
}
}
,onModelRowUpdate: function(model, row) {
if (row == this._row)
this.rowChanged();
}
});

View File

@ -1,14 +0,0 @@
var Object = require('./object');
/**
* Class to handle the URL.
*/
module.exports = new Class
({
Extends: Object
,changed: function() {
this.signalEmit('changed');
}
});

View File

@ -1,127 +0,0 @@
var Object = require('./object');
var Param = require('./param');
var Hash = require('./hash');
module.exports = new Class({
Extends: Object
,Tag: 'vn-hash-param'
,Child: 'param'
,Properties: {
param: {
type: Param
,set: function(x) {
this.link({_param: x}, {'changed': this._onParamChange});
this._refreshParam();
}
,get: function() {
return this._param;
}
},
key: {
type: String
,set: function(x) {
this._key = x;
this._onHashChange();
}
,get: function() {
return this._key;
}
},
value: {
type: Object
,set: function(x) {
this._setValue(x, true);
}
,get: function() {
return this._value;
}
},
type: {
type: Object
,set: function(x) {
this._type = x;
this._onHashChange();
}
,get: function() {
return this._type;
}
}
}
,_hashLock: false
,_paramLock: false
,_value: undefined
,_key: null
,_type: null
,initialize: function(props) {
this.parent(props);
var listener = Hash.getListener();
this.link({_listener: listener}, {'changed': this._onHashChange});
this._onHashChange();
}
,_onHashChange: function() {
if (this._hashLock || !this._key || !this._listener)
return;
var newValue = Hash.get(this._key);
if (newValue === '')
newValue = null;
if (this._type && newValue !== undefined && newValue !== null)
switch (this._type) {
case Boolean:
newValue = (/^(true|1)$/i).test(newValue);
break;
case Number:
newValue = 0 + new Number(newValue);
break;
}
this._hashLock = true;
this._setValue(newValue, true);
this._hashLock = false;
}
,_setValue: function(newValue, signal) {
if (newValue == this._value)
return;
this._value = newValue;
if (this._key && !this._hashLock) {
this._hashLock = true;
var map = {};
map[this._key] = newValue;
Hash.add(map);
this._hashLock = false;
}
this._refreshParam();
if (signal)
this.signalEmit('changed', newValue);
}
,_refreshParam: function() {
if (this._param && !this._paramLock) {
this._paramLock = true;
this._param.value = this._value;
this._paramLock = false;
}
}
,_onParamChange: function() {
if (this._paramLock)
return;
this._paramLock = true;
this._setValue(this._param.value);
this._paramLock = false;
}
});

View File

@ -1,137 +1,164 @@
var HashListener = require('./hash-listener'); var VnDate = require('./date');
var Lot = require('./lot');
/** /**
* Class to handle the URL. * Class to handle the hash part of the URL as a key-value javascript object.
* It also handles dates and objects as a value.
*/ */
module.exports = { module.exports = new Class({
path: null Extends: Lot
,_hash: null ,Properties: {
,_hashMap: {} /**
,_listener: null * The main window object.
*/
,initialize: function() { window:
this.$ = this._hasMap; {
this._listener = new HashListener(); type: Window
,set: function(x) {
this._hashChangedHandler = this._hashChanged.bind(this); this._window = x;
window.addEventListener('hashchange', this._hashChangedHandler); x.addEventListener('hashchange', this._hashChangedHandler);
this._hashChanged(); this._hashChanged();
} }
,get: function() {
,destroy: function() { return this._window;
window.removeEventListener('hashchange', this._hashChangedHandler); }
}
,getListener: function() {
return this._listener;
}
/**
* Gets the hash part of the URL.
*
* @param {string} key The variable name
*/
,get: function(key) {
return this._hashMap[key];
}
/**
* Unsets a hash key.
*
* @param {string} key The variable name
*/
,unset: function(key) {
this.add({[key]: undefined});
}
/**
* Sets the hash part of the URL, respecting the current hash variables.
*
* @param {Object} map A key-value map
*/
,add: function(map) {
var newMap = this._hashMap;
for (var key in map)
newMap[key] = map[key];
this.set(newMap);
}
/**
* Sets the hash part of the URL.
*
* @param {Object} map A key-value map
*/
,set: function(map) {
if (map)
for (var key in map)
if (map[key] === null || map[key] === undefined)
delete map[key];
var newHash = this.make(map);
if (!map)
map = {};
if (newHash !== this._hash) {
this._hashMap = map;
this.$ = map;
this._hash = newHash;
this._blockChanged = true;
location.hash = newHash;
this._blockChanged = false;
this._listener.changed();
} }
} }
,initialize: function(props) {
Object.assign(this, {
_hash: null
,_hashLock: false
,_window: null
,_hashChangedHandler: this._hashChanged.bind(this)
});
this.parent(props);
}
,_paramsChanged: function() {
this.updateHash();
}
/** /**
* Creates a URL with the given hash data. * Creates a URL with the given hash data.
* *
* @param {Object} map A key-value map * @param {Object} params A key-value object
* @param {boolean} add %true to combine with the current map, %false otherwise * @param {boolean} add %true to combine with the current params, %false otherwise
* @return {String} The URL * @return {string} The URL
*/ */
,make: function(map, add) { ,make: function(params, add) {
var hash = '#!'; if (add) {
params = Object.assign({}, params);
if (add && map)
for (var key in this._hashMap)
if (!map[key])
map[key] = this._hashMap[key];
for (var key in map) { for (var key in this._params)
if (!params[key])
params[key] = this._params[key];
}
return this.renderHash(params);
}
/**
* Updates the window hash with current params.
*/
,updateHash: function() {
if (this._hashLock)
return;
this._hash = this.renderHash(this._params);
this._hashLock = true;
location.hash = this._hash;
this._hashLock = false;
}
/*
* Called when window hash changes.
*/
,_hashChanged: function() {
var newHash = location.hash;
if (this._hashLock || this._hash === newHash)
return;
this._hash = newHash;
this._hashLock = true;
this.params = this.parseHash(newHash);
this._hashLock = false;
}
/**
* Creates a URL with the given hash data.
*
* @param {Object} params The key-value object
* @return {string} The URL
*/
,renderHash: function(params) {
var hash = '#!';
for (var key in params)
if (params[key] !== undefined) {
if (hash.length > 2) if (hash.length > 2)
hash += '&'; hash += '&';
hash += encodeURIComponent(key) +'='+ encodeURIComponent(map[key]); hash += encodeURIComponent(key) +'='+ this.renderValue(params[key]);
} }
return hash; return hash;
} }
,_hashChanged: function() { /**
var newHash = location.hash; * Parses a hash string to a key-value object.
*
if (this._blockChanged || newHash === this._hash) * @param {string} hashString The hash string
return; * @return {Object} The key-value object
*/
,parseHash: function(hashString) {
var newMap = hashMap = {}; var newMap = hashMap = {};
var kvPairs = newHash.substring(2).split('&'); var kvPairs = hashString.substr(2).split('&');
for (var i = 0; i < kvPairs.length; i++) { for (var i = 0; i < kvPairs.length; i++) {
var kvPair = kvPairs[i].split('=', 2); var kvPair = kvPairs[i].split('=', 2);
if (kvPair[0]) if (kvPair[0])
newMap[decodeURIComponent(kvPair[0])] = decodeURIComponent(kvPair[1]); newMap[decodeURIComponent(kvPair[0])] = this.parseValue(kvPair[1]);
} }
this._hashMap = newMap; return newMap;
this.$ = newMap;
this._hash = newHash;
this._listener.changed();
} }
};
,renderValue: function(v) {
if (v == null)
return '';
switch (typeof v) {
case 'object':
if (v instanceof Date)
return VnDate.strftime(v, '%Y-%m-%d');
else
return JSON.stringify(v)
}
return v;
}
,parseValue: function(v) {
if (v == null)
return v;
v = decodeURIComponent(v);
if (v === '')
return null;
return v;
}
,_destroy: function() {
this._window.removeEventListener('hashchange', this._hashChangedHandler);
this._window = null;
this.parent();
}
});

View File

@ -1,48 +1,40 @@
module.exports = module.exports = {
{ getPageYOffset: function() {
getPageYOffset: function ()
{
if (document.documentElement.scrollTop) if (document.documentElement.scrollTop)
return document.documentElement.scrollTop; return document.documentElement.scrollTop;
else else
return document.body.scrollTop; return document.body.scrollTop;
}, },
getPageXOffset: function () getPageXOffset: function() {
{
if (document.documentElement.scrollLeft) if (document.documentElement.scrollLeft)
return document.documentElement.scrollLeft; return document.documentElement.scrollLeft;
else else
return document.body.scrollLeft; return document.body.scrollLeft;
}, },
getInnerHeight: function () getInnerHeight: function() {
{
if (document.documentElement.clientHeight) if (document.documentElement.clientHeight)
return document.documentElement.clientHeight; return document.documentElement.clientHeight;
else else
return document.body.clientHeight; return document.body.clientHeight;
}, },
getInnerWidth: function () getInnerWidth: function() {
{
if (document.documentElement.clientWidth) if (document.documentElement.clientWidth)
return document.documentElement.clientWidth; return document.documentElement.clientWidth;
else else
return document.body.clientWidth; return document.body.clientWidth;
}, },
createRadio: function (radioName) createRadio: function(radioName) {
{
var radio; var radio;
try { try {
radio = document.createElement ('<input type="radio" name="' + radioName + '">'); radio = document.createElement('<input type="radio" name="' + radioName + '">');
} } catch (e) {
catch (e) radio = document.createElement('input');
{
radio = document.createElement ('input');
radio.type = 'radio'; radio.type = 'radio';
radio.name = radioName; radio.name = radioName;
} }
@ -50,30 +42,26 @@ module.exports =
return radio; return radio;
}, },
setInputTypeNumber: function (input) setInputTypeNumber: function(input) {
{
input.type = 'text'; input.type = 'text';
} }
}; };
if (!Function.bind) if (!Function.bind) {
{ Function.prototype.bind = function() {
Function.prototype.bind = function ()
{
var bindFunc = this; var bindFunc = this;
var bindThis = arguments[0]; var bindThis = arguments[0];
var bindArgs = arguments; var bindArgs = arguments;
var IE_bind = function () var IE_bind = function() {
{ var args = new Array();
var args = new Array ();
for (var i = 1; i < bindArgs.length; i++) for (var i = 1; i < bindArgs.length; i++)
args.push (bindArgs[i]); args.push(bindArgs[i]);
for (var i = 0; i < arguments.length; i++) for (var i = 0; i < arguments.length; i++)
args.push (arguments[i]); args.push(arguments[i]);
bindFunc.apply (bindThis, args); bindFunc.apply(bindThis, args);
} }
return IE_bind; return IE_bind;
@ -82,33 +70,28 @@ if (!Function.bind)
// attachEvent -> addEventListener // attachEvent -> addEventListener
if (window.attachEvent && !window.addEventListener) if (window.attachEvent && !window.addEventListener) {
{ function IE_addEventListener(signal, func, capture) {
function IE_addEventListener (signal, func, capture)
{
var obj = this; var obj = this;
func.IE_eventHandler = function (event) func.IE_eventHandler = function(event) {
{
event.target = event.srcElement; event.target = event.srcElement;
event.layerY = event.clientY; event.layerY = event.clientY;
event.layerX = event.clientX; event.layerX = event.clientX;
event.pageX = event.offsetX; event.pageX = event.offsetX;
event.pageY = event.offsetY; event.pageY = event.offsetY;
event.stopPropagation = function () event.stopPropagation = function() {
{
this.cancelBubble = true; this.cancelBubble = true;
} }
func.call (obj, event); func.call(obj, event);
} }
this.attachEvent ('on' + signal, func.IE_eventHandler); this.attachEvent('on' + signal, func.IE_eventHandler);
} }
function IE_removeEventListener (signal, func, capture) function IE_removeEventListener(signal, func, capture) {
{ this.detachEvent('on' + signal, func.IE_eventHandler);
this.detachEvent ('on' + signal, func.IE_eventHandler);
} }
window.addEventListener = IE_addEventListener; window.addEventListener = IE_addEventListener;
@ -118,9 +101,8 @@ if (window.attachEvent && !window.addEventListener)
var IE_createElement = document.createElement; var IE_createElement = document.createElement;
document.createElement = function (tagName) document.createElement = function(tagName) {
{ var node = IE_createElement(tagName);
var node = IE_createElement (tagName);
node.addEventListener = IE_addEventListener; node.addEventListener = IE_addEventListener;
node.removeEventListener = IE_removeEventListener; node.removeEventListener = IE_removeEventListener;
return node; return node;
@ -129,11 +111,9 @@ if (window.attachEvent && !window.addEventListener)
// ActiveXObject ('Microsoft.XMLHTTP') -> XMLHttpRequest // ActiveXObject ('Microsoft.XMLHTTP') -> XMLHttpRequest
if (!window.XMLHttpRequest && window.ActiveXObject) if (!window.XMLHttpRequest && window.ActiveXObject) {
{ function XMLHttpRequest() {
function XMLHttpRequest () return new ActiveXObject('Microsoft.XMLHTTP');
{
return new ActiveXObject ('Microsoft.XMLHTTP');
} }
} }

67
js/vn/iterator-iface.js Normal file
View File

@ -0,0 +1,67 @@
var LotIface = require('./lot-iface');
var ModelIface = require('./model-iface');
module.exports = new Class({
Implements: LotIface
,Properties: {
/**
* The model associated to this form.
*/
model: {
type: ModelIface
},
/**
* The row where the form positioned, has -1 if the row is unselected.
*/
row: {
type: Number
},
/**
* The number of rows in the form.
*/
numRows: {
type: Number
},
/**
* Checks if the form data is ready.
*/
ready: {
type: Boolean
}
}
,insertRow: function() {
if (this._model)
this.row = this._model.insertRow();
}
/**
* Removes the current row.
*/
,deleteRow: function() {
if (this._row >= 0)
this._model.deleteRow(this._row);
}
/**
* Gets a value from the form.
*
* @param {string} columnName The column name
* @return {Object} The value
*/
,get: function(columnName) {
return this._model ?
this._model.get(this._row, columnName) : undefined;
}
/**
* Sets a value on the form.
*
* @param {string} columnName The column name
* @param {Object} value The new value
*/
,set: function(columnName, value) {
this._model.set(this._row, columnName, value);
}
});

75
js/vn/iterator.js Normal file
View File

@ -0,0 +1,75 @@
var Lot = require('./lot');
var IteratorIface = require('./iterator-iface');
var ModelIface = require('./model-iface');
/**
* A light iterator for models. It assumes that its row and model properties
* are always valid.
*/
module.exports = new Class({
Extends: Lot
,Implements: IteratorIface
,Properties: {
model: {
type: ModelIface
,set: function(x) {
this._model = x;
}
,get: function() {
return this._model;
}
},
row: {
type: Number
,set: function(x) {
this._row = x;
this.rowChanged();
}
,get: function() {
return this._row;
}
},
numRows: {
type: Number
,get: function() {
return this._model ?
this._model.numRows : 0;
}
},
ready: {
type: Boolean
,get: function() {
return this._model ?
this._model.ready : false;
}
}
}
,_model: null
,initialize: function(props) {
Object.assign(this, {
_row: -1
,_rowLock: false
});
this.parent(props);
}
,_paramsChanged: function(diff) {
if (!this._rowLock)
for (var key in diff)
this._model.set(this._row, key, diff[key]);
}
,rowChanged: function() {
var row;
if (this._model)
row = this._model.getObject(this._row);
this._rowLock = true;
this.params = row != null ? row : {};
this._rowLock = false;
}
});

View File

@ -70,7 +70,7 @@ module.exports = new Class({
var storage = remember ? localStorage : sessionStorage; var storage = remember ? localStorage : sessionStorage;
storage.setItem('vnToken', this.token); storage.setItem('vnToken', this.token);
this.signalEmit('openned'); this.emit('openned');
} else } else
this._closeClient(); this._closeClient();
@ -93,7 +93,7 @@ module.exports = new Class({
* Called when close operation is done. * Called when close operation is done.
*/ */
,_onClose: function(callback, json, error) { ,_onClose: function(callback, json, error) {
this.signalEmit('closed'); this.emit('closed');
if (callback) if (callback)
callback(this, null, error); callback(this, null, error);
@ -221,7 +221,7 @@ module.exports = new Class({
this._requestsCount++; this._requestsCount++;
if (this._requestsCount === 1) if (this._requestsCount === 1)
this.signalEmit('loading-changed', true); this.emit('loading-changed', true);
} }
,_onStateChange: function(request, callback) { ,_onStateChange: function(request, callback) {
@ -231,7 +231,7 @@ module.exports = new Class({
this._requestsCount--; this._requestsCount--;
if (this._requestsCount === 0) if (this._requestsCount === 0)
this.signalEmit('loading-changed', false); this.emit('loading-changed', false);
var data = null; var data = null;
var error = null; var error = null;
@ -314,7 +314,7 @@ module.exports = new Class({
if (error.exception == 'SessionExpired') if (error.exception == 'SessionExpired')
this.clearToken(); this.clearToken();
this.signalEmit('error', error); this.emit('error', error);
} }
} }
}); });

Some files were not shown because too many files have changed in this diff Show More