0
1
Fork 0
This commit is contained in:
Juan Ferrer Toribio 2017-04-19 08:16:37 +02:00
parent 73b2fed910
commit 234566b6af
51 changed files with 1435 additions and 669 deletions

View File

@ -1,3 +1,4 @@
(function () {
Hedera.Home = new Class Hedera.Home = new Class
({ ({
@ -9,3 +10,4 @@ Hedera.Home = new Class
} }
}); });
})();

View File

@ -1,3 +1,9 @@
(function () {
var View = {
LIST: 0,
GRID: 1
};
Hedera.Catalog = new Class Hedera.Catalog = new Class
({ ({
@ -32,12 +38,14 @@ Hedera.Catalog = new Class
{ {
document.body.appendChild (this.$('right-panel')); document.body.appendChild (this.$('right-panel'));
this.$('items-model').setInfo ('a', 'Articles', 'vn2008', ['item_id']); this.$('items').setInfo ('a', 'Articles', 'vn2008', ['item_id']);
if (localStorage.getItem ('hederaView')) if (localStorage.getItem ('hederaView'))
this.setView (parseInt (localStorage.getItem ('hederaView'))); this.setView (parseInt (localStorage.getItem ('hederaView')));
else else
this.setView (Hedera.Catalog.View.GRID); this.setView (View.GRID);
this.hash.on ('change', this.onHashChange, this);
} }
,deactivate: function () ,deactivate: function ()
@ -45,17 +53,18 @@ Hedera.Catalog = new Class
this.hideMenu (); this.hideMenu ();
this.gui.$('top-bar').style.backgroundColor = ''; this.gui.$('top-bar').style.backgroundColor = '';
Vn.Node.remove (this.$('right-panel')); Vn.Node.remove (this.$('right-panel'));
this.hash.disconnect ('change', this.onHashChange, this);
} }
,setView: function (view) ,setView: function (view)
{ {
if (view === Hedera.Catalog.View.GRID) if (view === View.GRID)
{ {
this.$('view-button').setProperties ({ this.$('view-button').setProperties ({
icon: 'view-list', icon: 'view-list',
tip: _('List view') tip: _('List view')
}); });
this.view = Hedera.Catalog.View.GRID; this.view = View.GRID;
var className = 'grid-view'; var className = 'grid-view';
} }
else else
@ -64,7 +73,7 @@ Hedera.Catalog = new Class
icon: 'view-grid', icon: 'view-grid',
tip: _('Grid view') tip: _('Grid view')
}); });
this.view = Hedera.Catalog.View.LIST; this.view = View.LIST;
var className = 'list-view'; var className = 'list-view';
} }
@ -75,8 +84,8 @@ Hedera.Catalog = new Class
,onSwitchViewClick: function () ,onSwitchViewClick: function ()
{ {
this.setView (this.view === Hedera.Catalog.View.LIST ? this.setView (this.view === View.LIST ?
Hedera.Catalog.View.GRID : Hedera.Catalog.View.LIST); View.GRID : View.LIST);
} }
,onBasketReady: function (form) ,onBasketReady: function (form)
@ -103,23 +112,44 @@ Hedera.Catalog = new Class
Db.Model.SortWay.ASC : Db.Model.SortWay.DESC; Db.Model.SortWay.ASC : Db.Model.SortWay.DESC;
if (sortField) if (sortField)
this.$('items-model').sortByName (sortField, sortWay); this.$('items').sortByName (sortField, sortWay);
this.hideMenu (); this.hideMenu ();
} }
,onFilterChange: function (param, newValue) ,shouldRefresh: function ()
{ {
if (newValue) var params = this.hash.params;
this.hideMenu ();
if (params.search)
return true;
var refresh = params.realm && (
params.type ||
params.color ||
params.origin ||
params.category ||
params.producer
);
return refresh;
}
,onHashChange: function ()
{
if (!this.shouldRefresh ())
return;
this.$('items').refresh ();
this.hideMenu ();
} }
,realmRenderer: function (builder, form) ,realmRenderer: function (builder, form)
{ {
var link = builder.$('link'); var link = builder.$('link');
link.href = this.hash.make ({ link.href = this.hash.make ({
'form': this.hash.get ('form'), form: this.hash.get ('form'),
'realm': form.get ('id') realm: form.get ('id')
}); });
var img = builder.$('image'); var img = builder.$('image');
@ -147,36 +177,25 @@ Hedera.Catalog = new Class
,onTypeChange: function (param, newValue) ,onTypeChange: function (param, newValue)
{ {
this.onFilterChange (param, newValue);
this.refreshTitle (); this.refreshTitle ();
this.refreshFilter (undefined, newValue); this.refreshFilter (undefined, newValue);
} }
,refreshFilter: function (realm, type) ,refreshFilter: function (realm, type)
{ {
var batch = this.$('filter-batch'); this.hash.params = {
batch.block (); form: this.hash.get ('form'),
this.$('realm-value').value = realm; realm: realm,
this.$('type-value').value = type; type: type
this.$('search').value = undefined; };
this.$('color').value = undefined;
this.$('origin').value = undefined;
this.$('category').value = undefined;
this.$('producer').value = undefined;
batch.unblock ();
batch.changed ();
} }
,refreshTitleColor: function () ,refreshTitleColor: function ()
{ {
var realms = this.$('realms-model'); var realms = this.$('realms');
var realm = this.hash.get ('realm');
if (!realms.ready)
return;
var color = null; var color = null;
var realm = this.$('realm').value;
if (realm) if (realm)
{ {
var row = realms.search ('id', realm); var row = realms.search ('id', realm);
@ -190,14 +209,10 @@ Hedera.Catalog = new Class
,refreshTitle: function () ,refreshTitle: function ()
{ {
var types = this.$('types-model'); var types = this.$('types');
var type = this.hash.get ('type');
if (!types.ready)
return;
var title = _('Catalog'); var title = _('Catalog');
var type = this.$('type').value;
if (type) if (type)
{ {
var row = types.search ('tipo_id', type); var row = types.search ('tipo_id', type);
@ -251,7 +266,7 @@ Hedera.Catalog = new Class
if (this.isGuest ()) if (this.isGuest ())
return; return;
this.hash.setAll ({'form': 'ecomerce/basket'}); this.hash.params = {form: 'ecomerce/basket'};
} }
,onConfigureClick: function () ,onConfigureClick: function ()
@ -259,7 +274,7 @@ Hedera.Catalog = new Class
if (this.isGuest ()) if (this.isGuest ())
return; return;
this.hash.setAll ({'form': 'ecomerce/checkout'}); this.hash.params = {form: 'ecomerce/checkout'};
} }
,onAddItemClick: function (button, form) ,onAddItemClick: function (button, form)
@ -273,26 +288,22 @@ Hedera.Catalog = new Class
this.$('card-popup').show (button.node); this.$('card-popup').show (button.node);
} }
,onAddLotClick: function (column, value, row) ,onAddLotClick: function (column, value, rowIndex)
{ {
var model = this.$('item-lots'); var row = this.$('item-lots').getObject (rowIndex);
var grouping = model.get (row, 'grouping'); var lotAmount = this.items[row.warehouse];
var warehouse = model.get (row, 'warehouse_id');
var available = model.get (row, 'available');
var lotAmount = this.items[warehouse];
if (lotAmount === undefined) if (lotAmount === undefined)
lotAmount = 0; lotAmount = 0;
if (lotAmount < available) if (lotAmount < row.available)
{ {
var newAmount = lotAmount + grouping; var newAmount = lotAmount + row.grouping;
if (newAmount > available) if (newAmount > row.available)
newAmount = available; newAmount = row.available;
this.items[warehouse] = newAmount; this.items[row.warehouse] = newAmount;
this.$('amount').value += newAmount - lotAmount; this.$('amount').value += newAmount - lotAmount;
} }
else else
@ -302,21 +313,22 @@ Hedera.Catalog = new Class
,onConfirmClick: function () ,onConfirmClick: function ()
{ {
var sql = ''; var sql = '';
var batch = new Sql.Batch (); var query = 'CALL basket_item_add (#warehouse, #item, #amount);';
var query = new Sql.String ({query: 'CALL basket_item_add (#warehouse, #item, #amount);'});
var amountSum = 0; var amountSum = 0;
for (var warehouse in this.items) for (var warehouse in this.items)
{ {
var amount = this.items[warehouse]; var amount = this.items[warehouse];
amountSum += amount; amountSum += amount;
batch.addValue ('warehouse', warehouse); var params = {
batch.addValue ('item', this.$('card-item').value); item: this.$('card-item').value,
batch.addValue ('amount', amount); warehouse: warehouse,
sql += query.render (batch); amount: amount
};
sql += this.conn.render (query, params);
} }
if (amountSum > 0) if (amountSum > 0)
{ {
this.conn.execQuery (sql); this.conn.execQuery (sql);
@ -348,19 +360,10 @@ Hedera.Catalog = new Class
} }
}); });
Hedera.Catalog.extend
({
View: {
LIST: 0,
GRID: 1
}
});
Vn.Filter = new Class Vn.Filter = new Class
({ ({
Extends: Htk.Field Extends: Htk.Field
,Tag: 'vn-filter' ,Tag: 'vn-filter'
,Child: 'model'
,Properties: ,Properties:
{ {
model: model:
@ -368,9 +371,9 @@ Vn.Filter = new Class
type: Db.Model type: Db.Model
,set: function (x) ,set: function (x)
{ {
x.batch = this._batch;
this._model = x; this._model = x;
this._select.model = x; this._select.model = x;
this._refreshLot ();
} }
,get: function () ,get: function ()
{ {
@ -396,13 +399,40 @@ Vn.Filter = new Class
,set: function (x) ,set: function (x)
{ {
this._filter = x; this._filter = x;
this._batch.addObject ('filter', x); this._modelLot.assign ({filter: x});
this._refreshLot ();
} }
,get: function () ,get: function ()
{ {
return this._filter; return this._filter;
} }
}, },
lot:
{
type: Vn.LotIface
,set: function (x)
{
this._modelLot.source = x;
this._setLot (x);
}
,get: function ()
{
return this._lot;
}
},
name:
{
type: String
,set: function (x)
{
this._modelLot.fields = [x];
this._onLotChange ();
}
,get: function ()
{
return this._name;
}
}
} }
,_valueColumnIndex: 0 ,_valueColumnIndex: 0
@ -422,9 +452,22 @@ 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._modelLot = new Vn.LotQuery ({
type: Vn.LotQuery.Type.EXCLUDE
});
this.parent (props); this.parent (props);
} }
,_refreshLot: function ()
{
if (!this._model)
return;
if (this._filter)
this._model.lot = this._modelLot;
else
this._model.lot = null;
}
,_onMouseDown: function () ,_onMouseDown: function ()
{ {
@ -465,9 +508,7 @@ Vn.Filter = new Class
,_changeValue: function (newValue) ,_changeValue: function (newValue)
{ {
this._batch.block ();
this.value = newValue; this.value = newValue;
this._batch.unblock ();
} }
,_onTimeout: function () ,_onTimeout: function ()
@ -535,3 +576,4 @@ Vn.Filter = new Class
} }
}); });
})();

View File

@ -60,9 +60,6 @@
.right-panel .realm-msg .right-panel .realm-msg
{ {
margin-top: 1em; margin-top: 1em;
/* box-shadow: 0 0 .3em rgba(1, 1, 1, .5);
border-radius: 50%;
overflow: hidden;*/
} }
.right-panel .realm-msg > h1 .right-panel .realm-msg > h1
{ {
@ -70,8 +67,6 @@
text-align: center; text-align: center;
padding: 2.5em 0; padding: 2.5em 0;
color: #777; color: #777;
/* background-color: #009688;
color: white;*/
} }
.right-panel h2 .right-panel h2
{ {

View File

@ -1,45 +1,62 @@
<vn> <vn>
<vn-group> <vn-group>
<vn-lot id="card-lot"/> <vn-lot id="card-lot"/>
<vn-param id="realm" on-changed="onRealmChange"/> <vn-param lot="hash" name="realm" on-changed="onRealmChange"/>
<vn-param id="type" on-changed="onTypeChange"/> <vn-param lot="hash" name="type" on-changed="onTypeChange"/>
<vn-param id="search" on-changed="onFilterChange"/>
<vn-param id="color" on-changed="onFilterChange"/>
<vn-param id="origin" on-changed="onFilterChange"/>
<vn-param id="category" on-changed="onFilterChange"/>
<vn-param id="producer" on-changed="onFilterChange"/>
<vn-hash-param key="realm" param="realm"/>
<vn-hash-param key="type" param="type"/>
<sql-filter type="AND" id="filter"> <sql-filter type="AND" id="filter">
<sql-filter-item type="EQUAL" primary="false" id="op-realm"> <sql-filter-item type="EQUAL"
<sql-field name="reino_id" target="t"/> field="reino_id" target="t"
<sql-value id="realm-value"/> param="realm"/>
</sql-filter-item> <sql-filter-item type="EQUAL"
<sql-filter-item type="EQUAL" id="op-type"> field="tipo_id" target="a"
<sql-field name="tipo_id" target="a"/> param="type"/>
<sql-value id="type-value"/> <sql-filter type="OR">
</sql-filter-item> <sql-filter-item type="LIKE"
<sql-filter-item type="LIKE" id="op-name"> field="Article" target="a"
<sql-field name="Article"/> param="search"/>
<sql-search-tags param="search"/> <sql-filter-item type="EQUAL"
</sql-filter-item> field="Id_Article" target="a"
<sql-filter-item type="EQUAL" id="op-color"> param="search"/>
<sql-field name="Color"/> </sql-filter>
<sql-value param="color"/> <sql-filter-item type="EQUAL"
</sql-filter-item> field="Color" target="a"
<sql-filter-item type="EQUAL" id="op-origin"> param="color"/>
<sql-field name="id_origen"/> <sql-filter-item type="EQUAL"
<sql-value param="origin"/> field="id_origen" target="a"
</sql-filter-item> param="origin"/>
<sql-filter-item type="EQUAL" id="op-category"> <sql-filter-item type="EQUAL"
<sql-field name="Categoria"/> field="Categoria" target="a"
<sql-value param="category"/> param="category"/>
</sql-filter-item> <sql-filter-item type="EQUAL"
<sql-filter-item type="EQUAL" id="op-producer"> field="producer_id" target="a"
<sql-field name="producer_id"/> param="producer"/>
<sql-value param="producer"/>
</sql-filter-item>
</sql-filter> </sql-filter>
<db-model
id="items"
result-index="2"
lot="hash"
auto-load="false"
on-status-changed="onItemsChange">
CREATE TEMPORARY TABLE tmp.bionic_calc
(INDEX (item_id))
ENGINE = MEMORY
SELECT a.Id_Article item_id
FROM vn2008.Articles a
JOIN vn2008.Tipos t ON t.tipo_id = a.tipo_id
WHERE #filter;
CALL bionic_calc ();
SELECT a.Id_Article item_id, a.description, b.available, b.price,
b.producer, a.Foto, a.Article, a.Categoria, a.Medida,
IF(a.Tallos > 1, a.Tallos, NULL) Tallos, c.str color
FROM tmp.bionic_item b
JOIN vn2008.Articles a ON a.Id_Article = b.item_id
LEFT JOIN vn2008.producer p ON p.producer_id = a.producer_id
LEFT JOIN vn_locale.color_view c ON c.color_id = a.Color
LEFT JOIN vn_locale.origin_view o ON o.origin_id = a.id_origen
WHERE b.available > 0
ORDER BY a.Article, a.Medida
LIMIT 40;
</db-model>
<db-form id="basket" on-ready="onBasketReady"> <db-form id="basket" on-ready="onBasketReady">
<db-model property="model"> <db-model property="model">
SELECT o.id, o.date_send, ag.description agency, v.code method SELECT o.id, o.date_send, ag.description agency, v.code method
@ -53,35 +70,7 @@
FROM basket_item FROM basket_item
GROUP BY warehouse_id GROUP BY warehouse_id
</db-query> </db-query>
<db-model <db-form id="card" model="items"/>
id="items-model"
result-index="2"
on-status-changed="onItemsChange">
CREATE TEMPORARY TABLE tmp.bionic_calc
(INDEX (item_id))
ENGINE=MEMORY
SELECT a.Id_Article item_id FROM vn2008.Articles a
JOIN vn2008.Tipos t ON t.tipo_id = a.tipo_id
WHERE #filter;
CALL bionic_calc ();
SELECT a.Id_Article item_id, a.description, b.available, b.price,
b.producer, a.Foto, a.Article, a.Categoria, a.Medida,
IF(a.Tallos > 1, a.Tallos, NULL) Tallos, c.str color
FROM tmp.bionic_item b
JOIN vn2008.Articles a ON a.Id_Article = b.item_id
LEFT JOIN vn2008.producer p ON p.producer_id = a.producer_id
LEFT JOIN vn_locale.color_view c ON c.color_id = a.Color
LEFT JOIN vn_locale.origin_view o ON o.origin_id = a.id_origen
WHERE b.available > 0
ORDER BY a.Article, a.Medida
LIMIT 400;
<sql-batch property="batch" id="filter-batch">
<custom>
<item name="filter" object="filter"/>
</custom>
</sql-batch>
</db-model>
<db-form id="card" model="items-model"/>
<db-form id="card-extend"> <db-form id="card-extend">
<db-model <db-model
property="model" property="model"
@ -96,8 +85,8 @@
<db-model <db-model
id="item-lots" id="item-lots"
result-index="1" result-index="1"
on-status-changed-after="onStatusChange" lot="card-lot"
batch="card-batch"> on-status-changed-after="onStatusChange">
CALL bionic_from_item (#item); CALL bionic_from_item (#item);
SELECT p.warehouse_id, w.name warehouse, p.grouping, p.price, p.rate, l.available SELECT p.warehouse_id, w.name warehouse, p.grouping, p.price, p.rate, l.available
FROM tmp.bionic_lot l FROM tmp.bionic_lot l
@ -122,15 +111,15 @@
tip="_Switch view" tip="_Switch view"
on-click="onSwitchViewClick"/> on-click="onSwitchViewClick"/>
<htk-search-entry <htk-search-entry
param="search"/> lot="hash"
name="search"/>
</div> </div>
<div id="main" class="catalog"> <div id="main" class="catalog">
<div id="main" class="main">
<htk-repeater <htk-repeater
id="grid-view" id="grid-view"
empty-message="_Choose filter from right menu" empty-message="_Choose filter from right menu"
form-id="item" form-id="item"
model="items-model"> model="items">
<custom> <custom>
<div class="card item-box"> <div class="card item-box">
<htk-image <htk-image
@ -174,7 +163,6 @@
</div> </div>
</custom> </custom>
</htk-repeater> </htk-repeater>
</div>
</div> </div>
<div id="right-panel" class="right-panel" on-click="onRightPanelClick"> <div id="right-panel" class="right-panel" on-click="onRightPanelClick">
<div class="basket-info"> <div class="basket-info">
@ -193,12 +181,10 @@
<div class="categories"> <div class="categories">
<div class="realms"> <div class="realms">
<htk-repeater <htk-repeater
model="realms-model"
form-id="realm-form"
renderer="realmRenderer" renderer="realmRenderer"
class="realms-box"> class="realms-box">
<db-model <db-model
id="realms-model" id="realms"
property="model" property="model"
on-status-changed="refreshTitleColor"> on-status-changed="refreshTitleColor">
SELECT r.id, l.str name, r.color SELECT r.id, l.str name, r.color
@ -222,12 +208,14 @@
<div id="filters" class="filters"> <div id="filters" class="filters">
<h2><t>Filter by</t></h2> <h2><t>Filter by</t></h2>
<vn-filter <vn-filter
placeholder="_Family" lot="hash"
param="type"> name="type"
placeholder="_Family">
<db-model <db-model
id="types-model" id="types"
property="model" property="model"
conn="conn" conn="conn"
lot="hash"
result-index="1" result-index="1"
on-status-changed="refreshTitle"> on-status-changed="refreshTitle">
CALL item_available (); CALL item_available ();
@ -236,19 +224,16 @@
JOIN vn2008.Articles a ON a.tipo_id = t.tipo_id JOIN vn2008.Articles a ON a.tipo_id = t.tipo_id
LEFT JOIN vn_locale.family_view l ON l.family_id = t.tipo_id LEFT JOIN vn_locale.family_view l ON l.family_id = t.tipo_id
JOIN tmp.item_available i ON i.item_id = a.Id_Article JOIN tmp.item_available i ON i.item_id = a.Id_Article
WHERE #filter WHERE t.reino_id = #realm
ORDER BY name ORDER BY name
</db-model> </db-model>
<sql-filter property="filter" type="AND">
<sql-filter-item type="EQUAL">
<sql-field name="reino_id" target="t"/>
<sql-value param="realm"/>
</sql-filter-item>
</sql-filter>
</vn-filter> </vn-filter>
<vn-filter <vn-filter
id="test"
lot="hash"
name="color"
placeholder="_Color" placeholder="_Color"
param="color"> filter="filter">
<db-model property="model" auto-load="false" result-index="1"> <db-model property="model" auto-load="false" result-index="1">
CALL item_available (); CALL item_available ();
SELECT DISTINCT c.Id_Tinta, l.str name SELECT DISTINCT c.Id_Tinta, l.str name
@ -260,18 +245,12 @@
WHERE #filter WHERE #filter
ORDER BY name ORDER BY name
</db-model> </db-model>
<sql-filter property="filter" always-ready="true" type="AND">
<pointer object="op-realm"/>
<pointer object="op-type"/>
<pointer object="op-name="/>
<pointer object="op-origin"/>
<pointer object="op-category"/>
<pointer object="op-producer"/>
</sql-filter>
</vn-filter> </vn-filter>
<vn-filter <vn-filter
lot="hash"
name="producer"
placeholder="_Producer" placeholder="_Producer"
param="producer"> filter="filter">
<db-model property="model" auto-load="false" result-index="1"> <db-model property="model" auto-load="false" result-index="1">
CALL item_available (); CALL item_available ();
SELECT DISTINCT p.producer_id, p.name SELECT DISTINCT p.producer_id, p.name
@ -282,18 +261,12 @@
WHERE #filter WHERE #filter
ORDER BY name ORDER BY name
</db-model> </db-model>
<sql-filter property="filter" always-ready="true" type="AND">
<pointer object="op-realm"/>
<pointer object="op-type"/>
<pointer object="op-name="/>
<pointer object="op-origin"/>
<pointer object="op-color"/>
<pointer object="op-category"/>
</sql-filter>
</vn-filter> </vn-filter>
<vn-filter <vn-filter
lot="hash"
name="origin"
placeholder="_Origin" placeholder="_Origin"
param="origin"> filter="filter">
<db-model property="model" auto-load="false" result-index="1"> <db-model property="model" auto-load="false" result-index="1">
CALL item_available (); CALL item_available ();
SELECT DISTINCT o.id, l.str name, o.Abreviatura SELECT DISTINCT o.id, l.str name, o.Abreviatura
@ -305,18 +278,12 @@
WHERE #filter WHERE #filter
ORDER BY name ORDER BY name
</db-model> </db-model>
<sql-filter property="filter" always-ready="true" type="AND">
<pointer object="op-realm"/>
<pointer object="op-type"/>
<pointer object="op-name="/>
<pointer object="op-color"/>
<pointer object="op-category"/>
<pointer object="op-producer"/>
</sql-filter>
</vn-filter> </vn-filter>
<vn-filter <vn-filter
lot="hash"
name="category"
placeholder="_Category" placeholder="_Category"
param="category"> filter="filter">
<db-model property="model" auto-load="false" result-index="1"> <db-model property="model" auto-load="false" result-index="1">
CALL item_available (); CALL item_available ();
SELECT DISTINCT a.Categoria, a.Categoria category SELECT DISTINCT a.Categoria, a.Categoria category
@ -326,14 +293,6 @@
WHERE #filter WHERE #filter
ORDER BY a.Categoria ORDER BY a.Categoria
</db-model> </db-model>
<sql-filter property="filter" always-ready="true" type="AND">
<pointer object="op-realm"/>
<pointer object="op-type"/>
<pointer object="op-name="/>
<pointer object="op-color"/>
<pointer object="op-origin"/>
<pointer object="op-producer"/>
</sql-filter>
</vn-filter> </vn-filter>
</div> </div>
<div id="order" class="order"> <div id="order" class="order">
@ -444,4 +403,22 @@
</div> </div>
</div> </div>
</htk-popup> </htk-popup>
</vn> <!--
<htk-combo on-change="onOrderChange">
<vn-json-model property="model">
<array>
<object way="A" field="Article" desc="_Name"/>
<object way="A" field="price" desc="_Lower price"/>
<object way="D" field="price" desc="_Higher price"/>
<object way="A" field="available" desc="_Available"/>
<object way="A" field="Medida" desc="_Lower size"/>
<object way="D" field="Medida" desc="_Higher size"/>
<object way="A" field="color" desc="_Color"/>
<object way="A" field="producer" desc="_Producer"/>
<object way="A" field="Abreviatura" desc="_Origin"/>
<object way="A" field="Categoria" desc="_Category"/>
</array>
</vn-json-model>
</htk-combo>
-->
</vn>

View File

@ -3,12 +3,16 @@ Hedera.Checkout = new Class
({ ({
Extends: Hedera.Form Extends: Hedera.Form
,initialize: function (props)
{
this.today = new Date ();
this.today.setHours (0, 0, 0, 0);
this.parent (props);
}
,activate: function () ,activate: function ()
{ {
this.autoStepLocked = true; this.autoStepLocked = true;
this.today = new Date ();
this.today.setHours (0,0,0,0);
} }
,onValuesReady: function () ,onValuesReady: function ()

View File

@ -184,7 +184,7 @@
</p> </p>
<p> <p>
<htk-text lot="iter" name="iban"/> <htk-text lot="iter" name="iban"/>
<htk-text lot="iter" name="entity_id"/> <htk-text lot="iter" name="entity_id" format="%.4d"/>
<htk-text lot="iter" name="office"/> <htk-text lot="iter" name="office"/>
<htk-text lot="iter" name="dc"/> <htk-text lot="iter" name="dc"/>
<htk-text lot="iter" name="number"/> <htk-text lot="iter" name="number"/>

View File

@ -75,6 +75,13 @@ Connection.implement
this.execSql (this.renderQuery (query, params), callback); this.execSql (this.renderQuery (query, params), callback);
} }
/**
* Renders a query.
*
* @param {String} query The SQL statement
* @param {Object} params The statement parameters
* @return {String} The rendered statement
*/
,renderQuery: function (query, params) ,renderQuery: function (query, params)
{ {
return new Sql.String ({query: query}).render (params); return new Sql.String ({query: query}).render (params);

View File

@ -106,13 +106,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.changed (); this.changed ();
} }

View File

@ -10,8 +10,8 @@ var Connection = require ('./connection');
* otherwise updates are not allowed on that table/column. If two tables or * otherwise updates are not allowed on that table/column. If two tables or
* columns have the same name, an alias should be used to make it updatable. * columns have the same name, an alias should be used to make it updatable.
*/ */
var Model = new Class (); var Klass = new Class ();
module.exports = Model; module.exports = Klass;
var Status = var Status =
{ {
@ -40,7 +40,7 @@ var SortWay =
,DESC : 2 ,DESC : 2
}; };
Model.extend Klass.extend
({ ({
Status: Status Status: Status
,Mode: Mode ,Mode: Mode
@ -48,7 +48,7 @@ Model.extend
,SortWay: SortWay ,SortWay: SortWay
}); });
Model.implement Klass.implement
({ ({
Extends: Vn.Object Extends: Vn.Object
,Tag: 'db-model' ,Tag: 'db-model'
@ -85,22 +85,6 @@ Model.implement
return this._resultIndex; return this._resultIndex;
} }
}, },
/**
* The batch used to execute the statement.
*/
batch:
{
type: Sql.Batch
,set: function (x)
{
this.link ({_batch: x}, {'changed': this._autoLoad});
this._autoLoad ();
}
,get: function ()
{
return this._batch;
}
},
/** /**
* The lot used to execute the statement. * The lot used to execute the statement.
*/ */
@ -241,10 +225,10 @@ Model.implement
,_conn: null ,_conn: null
,_resultIndex: 0 ,_resultIndex: 0
,_batch: null
,_lot: null ,_lot: null
,_stmt: null ,_stmt: null
,_status: Status.CLEAN ,_status: Status.CLEAN
,result: null
,data: null ,data: null
,tables: null ,tables: null
,columns: null ,columns: null
@ -289,6 +273,10 @@ Model.implement
return null; return null;
var lotParams = this._lot ? this._lot.params : {}; var lotParams = this._lot ? this._lot.params : {};
if (lotParams == null)
lotParams = {};
var params = {}; var params = {};
for (var i = 0; i < ids.length; i++) for (var i = 0; i < ids.length; i++)
@ -371,6 +359,7 @@ Model.implement
throw e; throw e;
} }
this.result = dataResult;
this.data = dataResult.data; this.data = dataResult.data;
this.tables = dataResult.tables; this.tables = dataResult.tables;
this.columns = dataResult.columns; this.columns = dataResult.columns;
@ -412,6 +401,7 @@ Model.implement
,_cleanData: function () ,_cleanData: function ()
{ {
this.result = null;
this.data = null; this.data = null;
this.tables = null; this.tables = null;
this.columns = null; this.columns = null;
@ -427,7 +417,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 ()
@ -591,7 +581,7 @@ Model.implement
} }
/** /**
* Gets a value from the model using the column index. * Gets a value using the column index.
* *
* @param {number} rowIndex The row index * @param {number} rowIndex The row index
* @param {number} column The column index * @param {number} column The column index
@ -605,6 +595,20 @@ Model.implement
return undefined; return undefined;
} }
/**
* Gets a row as an object using the column index.
*
* @param {number} rowIndex The row index
* @return {Object} The row as an object
*/
,getObject: function (rowIndex)
{
if (!this.checkRowExists (rowIndex))
return null;
return this.result.getObject (rowIndex);
}
/** /**
* Updates a value on the model using the column index. * Updates a value on the model using the column index.
* *
@ -654,9 +658,9 @@ Model.implement
&& op.oldValues[col] === undefined) && op.oldValues[col] === undefined)
op.oldValues[col] = row[col]; op.oldValues[col] = row[col];
this.signalEmit ('row-updated-before', rowIndex); this.emit ('row-updated-before', rowIndex);
row[col] = value; row[col] = value;
this.signalEmit ('row-updated', rowIndex, [col]); this.emit ('row-updated', rowIndex, [col]);
if (this.mode == Mode.ON_CHANGE if (this.mode == Mode.ON_CHANGE
&& !(op.type & Operation.INSERT)) && !(op.type & Operation.INSERT))
@ -679,14 +683,14 @@ Model.implement
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 = [];
@ -703,7 +707,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)
@ -735,7 +739,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;
} }
@ -749,7 +753,7 @@ Model.implement
if (ops.length === 0) if (ops.length === 0)
{ {
this.signalEmit ('operations-done'); this.emit ('operations-done');
return; return;
} }
@ -912,7 +916,7 @@ Model.implement
} }
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;
@ -946,14 +950,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');
} }
/** /**
@ -970,11 +974,11 @@ Model.implement
&& !(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;
@ -986,7 +990,7 @@ Model.implement
updatedCols.push (i); updatedCols.push (i);
} }
this.signalEmit ('row-updated', row.index, updatedCols); this.emit ('row-updated', row.index, updatedCols);
} }
} }
@ -1215,8 +1219,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)

View File

@ -95,7 +95,7 @@ module.exports = new Class
,onQueryDone: function (resultSet) ,onQueryDone: function (resultSet)
{ {
this.signalEmit ('ready', resultSet); this.emit ('ready', resultSet);
} }
,onChange: function () ,onChange: function ()

View File

@ -2,11 +2,17 @@
var Login = require ('./login'); var Login = require ('./login');
var Gui = require ('./gui'); var Gui = require ('./gui');
/**
* The main application object.
*/
module.exports = new Class module.exports = new Class
({ ({
Extends: Vn.Object, Extends: Vn.Object,
Properties: Properties:
{ {
/**
* The main connection object.
*/
conn: conn:
{ {
type: Db.Connection type: Db.Connection
@ -15,6 +21,28 @@ module.exports = new Class
return this._conn; return this._conn;
} }
} }
/**
* The main screen component.
*/
,gui:
{
type: Gui
,get: function ()
{
return this._gui;
}
}
/**
* The login component.
*/
,login:
{
type: Login
,get: function ()
{
return this._login;
}
}
} }
,initialize: function () ,initialize: function ()
@ -66,7 +94,7 @@ module.exports = new Class
this.unref (); this.unref ();
} }
,_onWindowError: function (message, file, line, col, err) ,_onWindowError: function (message, file, line)
{ {
var error = new Error (message); var error = new Error (message);
error.fileName = file; error.fileName = file;

View File

@ -1,19 +1,33 @@
var Gui = require ('./gui');
module.exports = new Class module.exports = new Class
({ ({
Extends: Htk.Component Extends: Htk.Component
,Properties: {
gui:
{
type: Gui
,set: function (x)
{
this._gui = x;
this.conn = x.conn;
this.hash = x.hash;
}
,get: function ()
{
return this._gui;
}
},
formInfo:
{
type: Object,
value: null
}
}
,isOpen: false ,isOpen: false
,uiLoaded: false ,uiLoaded: false
,initialize: function (gui, formInfo)
{
this.gui = gui;
this.conn = gui.conn;
this.hash = gui.hash;
this.formInfo = formInfo;
this.parent ();
}
,loadUi: function () ,loadUi: function ()
{ {

View File

@ -1,13 +1,22 @@
var Module = require ('./module');
var Css = require ('./gui.css');
var Tpl = require ('./gui.xml'); var Tpl = require ('./gui.xml');
var Module = require ('./module');
var Form = require ('./form');
require ('./gui.css');
/**
* The main screen component. It has a left menu, a navbar with configurable
* action buttons and the body where @Db.Form childs can be displayed.
*/
module.exports = new Class module.exports = new Class
({ ({
Extends: Htk.Component, Extends: Htk.Component,
Properties: Properties:
{ {
/**
* The main connection object.
*/
conn: conn:
{ {
type: Db.Connection type: Db.Connection
@ -19,15 +28,26 @@ module.exports = new Class
{ {
return this._conn; return this._conn;
} }
},
/**
* The current open form.
*/
activeForm:
{
type: Form
,get: function ()
{
return this._activeForm;
}
} }
} }
,forms: {} ,_forms: {}
,activeForm: null ,_activeForm: null
,requestedForm: null ,_requestedForm: null
,menuShown: false ,_menuShown: false
,menuOptions: {} ,_menuOptions: {}
,choosedOption: null ,_choosedOption: null
,_shown: false ,_shown: false
,_scrollTimeout: null ,_scrollTimeout: null
,_navbarVisible: true ,_navbarVisible: true
@ -119,7 +139,7 @@ module.exports = new Class
,_onConnClose: function () ,_onConnClose: function ()
{ {
this.signalEmit ('logout'); this.emit ('logout');
} }
,_onConnLoadChange: function (conn, isLoading) ,_onConnLoadChange: function (conn, isLoading)
@ -220,7 +240,7 @@ module.exports = new Class
if (row.path) if (row.path)
{ {
a.href = this.hash.make ({'form': row.path}); a.href = this.hash.make ({'form': row.path});
this.menuOptions[row.path] = a; this._menuOptions[row.path] = a;
} }
a.appendChild (text); a.appendChild (text);
@ -246,7 +266,7 @@ module.exports = new Class
,_onLiMouseHover: function (submenu, parent) ,_onLiMouseHover: function (submenu, parent)
{ {
if (this.menuShown) if (this._menuShown)
return; return;
this.hideSubmenu (); this.hideSubmenu ();
@ -282,7 +302,7 @@ module.exports = new Class
{ {
this.showBackground (); this.showBackground ();
Vn.Node.addClass (this.$('left-panel'), 'show'); Vn.Node.addClass (this.$('left-panel'), 'show');
this.menuShown = true; this._menuShown = true;
this.hideMenuCallback = this.hideMenu.bind (this); this.hideMenuCallback = this.hideMenu.bind (this);
this.doc.addEventListener ('click', this.hideMenuCallback); this.doc.addEventListener ('click', this.hideMenuCallback);
@ -290,12 +310,12 @@ module.exports = new Class
,hideMenu: function () ,hideMenu: function ()
{ {
if (!this.menuShown) if (!this._menuShown)
return; return;
this.hideBackground (); this.hideBackground ();
Vn.Node.removeClass (this.$('left-panel'), 'show'); Vn.Node.removeClass (this.$('left-panel'), 'show');
this.menuShown = false; this._menuShown = false;
this.doc.removeEventListener ('click', this.hideMenuCallback); this.doc.removeEventListener ('click', this.hideMenuCallback);
this.hideMenuCallback = null; this.hideMenuCallback = null;
@ -387,22 +407,22 @@ module.exports = new Class
this.loaderPush (); this.loaderPush ();
this.closeForm (); this.closeForm ();
this.requestedForm = formPath; this._requestedForm = formPath;
var newChoosedOption = this.menuOptions[formPath]; var newChoosedOption = this._menuOptions[formPath];
if (newChoosedOption) if (newChoosedOption)
{ {
Vn.Node.addClass (newChoosedOption, 'selected'); Vn.Node.addClass (newChoosedOption, 'selected');
this.choosedOption = newChoosedOption; this._choosedOption = newChoosedOption;
} }
var formInfo = this.forms[formPath]; var formInfo = this._forms[formPath];
if (!formInfo) if (!formInfo)
{ {
formInfo = new Module ('forms', formPath); formInfo = new Module ('forms', formPath);
this.forms[formPath] = formInfo; this._forms[formPath] = formInfo;
} }
formInfo.load (callback); formInfo.load (callback);
@ -418,8 +438,11 @@ module.exports = new Class
return; return;
} }
this.activeForm = new formInfo.klass (this, formInfo); this._activeForm = new formInfo.klass ({
this.activeForm.open (); gui: this,
formInfo: formInfo
});
this._activeForm.open ();
} }
,setForm: function (form) ,setForm: function (form)
@ -453,18 +476,18 @@ module.exports = new Class
,closeForm: function () ,closeForm: function ()
{ {
if (this.activeForm) if (this._activeForm)
{ {
this.activeForm.formInfo.unload (); this._activeForm.formInfo.unload ();
this.activeForm.close (); this._activeForm.close ();
this.activeForm.unref (); this._activeForm.unref ();
this.activeForm = null; this._activeForm = null;
} }
if (this.choosedOption) if (this._choosedOption)
{ {
Vn.Node.removeClass (this.choosedOption, 'selected'); Vn.Node.removeClass (this._choosedOption, 'selected');
this.choosedOption = null; this._choosedOption = null;
} }
} }

View File

@ -1,12 +1,19 @@
var Css = require ('./login.css');
var Tpl = require ('./login.xml'); var Tpl = require ('./login.xml');
require ('./login.css');
/**
* The login component.
*/
module.exports = new Class module.exports = new Class
({ ({
Extends: Htk.Component, Extends: Htk.Component,
Properties: Properties:
{ {
/**
* The main connection object.
*/
conn: conn:
{ {
type: Db.Connection type: Db.Connection
@ -35,14 +42,6 @@ module.exports = new Class
return false; return false;
}; };
} }
,_onConnLoadChange: function (conn, isLoading)
{
if (isLoading)
this.$('spinner').start ();
else
this.$('spinner').stop ();
}
,show: function () ,show: function ()
{ {
@ -56,6 +55,19 @@ module.exports = new Class
this._focusUserInput (); this._focusUserInput ();
} }
,hide: function ()
{
Vn.Node.remove (this.node);
}
,_onConnLoadChange: function (conn, isLoading)
{
if (isLoading)
this.$('spinner').start ();
else
this.$('spinner').stop ();
}
,_onSubmit: function () ,_onSubmit: function ()
{ {
this._conn.open ( this._conn.open (
@ -79,7 +91,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
{ {
@ -88,11 +100,6 @@ module.exports = new Class
} }
} }
,hide: function ()
{
Vn.Node.remove (this.node);
}
,_focusUserInput: function () ,_focusUserInput: function ()
{ {
var userEntry = this.$('user'); var userEntry = this.$('user');
@ -114,7 +121,7 @@ module.exports = new Class
if (!user) if (!user)
Htk.Toast.showError (_('Please write your user name')); Htk.Toast.showError (_('Please write your user name'));
else else
this._conn.send ('core/recover-password', {'recoverUser': user}, this._conn.send ('core/recover-password', {recoverUser: user},
this._onPasswordRecovered.bind (this)); this._onPasswordRecovered.bind (this));
} }

View File

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="user-scalable=no"/>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"/>
<meta name="mobile-web-app-capable" content="yes">
<link rel="shortcut icon" type="image/x-icon" href="image/favicon.ico"/>
<link rel="stylesheet" type="text/css" href="report.css"/>
<title>Report</title>
</head>
<body>
<div id="topbar">
<button id="print">Print</button>
</div>
</body>
</html>

View File

@ -93,7 +93,7 @@ module.exports = new Class
,_setStepIndex: function (stepIndex) ,_setStepIndex: function (stepIndex)
{ {
this._stepIndex = stepIndex; this._stepIndex = stepIndex;
this.signalEmit ('step-change', stepIndex); this.emit ('step-change', stepIndex);
} }
,movePrevious: function () ,movePrevious: function ()

View File

@ -106,7 +106,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

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

View File

@ -173,12 +173,12 @@ Dialog.implement
,_onButtonClick: function (response) ,_onButtonClick: function (response)
{ {
this.hide (); this.hide ();
this.signalEmit ('response', response); this.emit ('response', response);
} }
,_onClosed: function () ,_onClosed: function ()
{ {
this.signalEmit ('response', null); this.emit ('response', null);
} }
}); });

View File

@ -1,44 +1,89 @@
var Widget = require ('./widget'); var Widget = require ('./widget');
/**
* Base class for graphical fields.
*/
module.exports = new Class module.exports = new Class
({ ({
Extends: Widget Extends: Widget
,Implements: Vn.ParamIface
,Tag: 'htk-field' ,Tag: 'htk-field'
,Properties: ,Properties:
{ {
value: value:
{ {
type: String type: null
,set: function (x) ,set: function (x)
{ {
if (Vn.Value.compare (x, this._value)) this._setValue (x);
return;
if (x instanceof Date)
x = x.clone ();
this.valueChanged (x);
this.putValue (x);
} }
,get: function () ,get: function ()
{ {
return this._value; return this._value;
} }
}, },
param: type:
{ {
type: Vn.Param type: Type
,set: function (x) ,set: function (x)
{ {
this.link ({_param: x}, {'changed': this.onParamChange}); this._setType (x);
this.onParamChange (); }
,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:
{
type: Vn.LotIface
,set: function (x)
{
this._setLot (x);
}
,get: function ()
{
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;
}
},
editable: editable:
{ {
type: Boolean type: Boolean
@ -55,24 +100,6 @@ module.exports = new Class
return this._editable; return this._editable;
} }
}, },
lot:
{
type: Db.Iterator
,set: function (x)
{
this._lot = x;
this.bindToLot ();
}
},
name:
{
type: String
,set: function (x)
{
this._paramName = x;
this.bindToLot ();
}
},
conditionalFunc: conditionalFunc:
{ {
type: Function type: Function
@ -80,30 +107,26 @@ module.exports = new Class
} }
} }
,_value: undefined
,_param: null
,_editable: true ,_editable: true
,_blockParamChange: false
,_blockValueChange: false
,onParamChange: function () ,_setValue: function (newValue)
{ {
if (!this._blockValueChange) Vn.ParamIface.prototype._setValue.call (this, newValue);
{ this.putValue (newValue);
this._blockParamChange = true;
this.value = this._param.value; if (this.conditionalFunc)
this._blockParamChange = false; this.conditionalFunc (this, newValue);
}
} }
,bindToLot: function () /**
* Protected method that should be called from class childs when the value
* on the associated entry changes.
*
* @param {*} value The new entry value
*/
,valueChanged: function (value)
{ {
if (this._lot && this._paramName) this._setValue (value);
this.param = new Vn.Param
({
lot: this._lot
,name: this._paramName
});
} }
/** /**
@ -121,28 +144,5 @@ module.exports = new Class
* @param {*} value The new value for the entry * @param {*} value The new value for the entry
*/ */
,putValue: function () {} ,putValue: function () {}
/**
* Protected method that should be called from class childs when the value
* on the associated entry changes.
*
* @param {*} value The new entry value
*/
,valueChanged: function (value)
{
this._value = value;
if (this.conditionalFunc)
this.conditionalFunc (this, value);
if (this._param && !this._blockParamChange)
{
this._blockValueChange = true;
this._param.value = value;
this._blockValueChange = false;
}
this.signalEmit ('changed');
}
}); });

View File

@ -82,6 +82,6 @@ module.exports = new Class
,_onClick: function (event) ,_onClick: function (event)
{ {
event.preventDefault (); event.preventDefault ();
this.signalEmit ('click', this._form, event); this.emit ('click', this._form, event);
} }
}); });

View File

@ -184,7 +184,7 @@ module.exports = new Class
popup.on ('closed', this._onPopupClose.bind (this)); popup.on ('closed', this._onPopupClose.bind (this));
popup.show (this.node, true, e); popup.show (this.node, true, e);
this.signalEmit ('menu-show'); this.emit ('menu-show');
} }
,_onGridClicked: function (grid, e) ,_onGridClicked: function (grid, e)
@ -216,7 +216,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 ()
@ -238,7 +238,7 @@ 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 ();
@ -246,7 +246,7 @@ module.exports = new Class
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

@ -21,7 +21,7 @@ module.exports = new Class
type: RadioGroup type: RadioGroup
,set: function (x) ,set: function (x)
{ {
this.link ({_radioGroup: x}, {'changed': this._onRadioGroupChange}); this.link ({_radioGroup: x}, {changed: this._onRadioGroupChange});
this.node.name = x.radioName this.node.name = x.radioName
this._onRadioGroupChange (); this._onRadioGroupChange ();
} }

View File

@ -32,7 +32,7 @@ module.exports = new Class
,changed: function (rbGroup) ,changed: function (rbGroup)
{ {
this.realValue = this.rbGroup.getValue (); this.realValue = this.rbGroup.getValue ();
this.signalEmit ('changed'); this.emit ('changed');
} }
,selectValue: function () ,selectValue: function ()

View File

@ -39,7 +39,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 ()
@ -60,7 +60,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

@ -261,7 +261,7 @@ module.exports = new Class
Vn.Node.remove (node); Vn.Node.remove (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 (count) ,_showNoRecordsFound: function (count)

View File

@ -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,7 +30,7 @@ module.exports = new Class
} }
} }
,render: function (batch) ,render: function ()
{ {
var sql = (this.target) ? '`' + this.target + '`.' : ''; var sql = (this.target) ? '`' + this.target + '`.' : '';
return sql + '`' + this.name + '`'; return sql + '`' + this.name + '`';

View File

@ -1,8 +1,12 @@
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
({ ({
@ -10,11 +14,66 @@ module.exports = new Class
,Tag: 'sql-filter-item' ,Tag: 'sql-filter-item'
,Properties: ,Properties:
{ {
primary: /**
* The column name.
*/
field:
{ {
type: Boolean 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 op = new Operation ({type: this.type});
var field = new Field ({
name: this.field,
target: this.target
});
op.appendChild (field);
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, '%');
}
var sqlValue = new Value ({value: value});
op.appendChild (sqlValue);
return op.render (params);
}
,_escapeChar: function (char)
{
return '\\'+ char;
}
}); });

View File

@ -1,50 +1,46 @@
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 () /**
* Checks if any of filters childs are ready.
*/
,isReady: function (params)
{ {
if (this.alwaysReady) var exprs = this.exprs.objects;
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) /**
* Renders the filter as an SQL expression. If any of its childs isn't
* ready is ommitted from the expression. If all of its childs aren't ready
* renders the TRUE expression.
*/
,render: function (params)
{ {
var isReady = false; var op = new Operation ({type: this.type});
var newOp = new Operation ({type: this.type}); var exprs = this.exprs.objects;
for (var i = 0; i < exprs.length; i++)
if (exprs[i].isReady (params))
op.exprs.add (exprs[i]);
var e = this.exprs.getArray (); if (op.exprs.objects.length == 0)
for (var i = 0; i < e.length; i++) op = new Value ({value: true});
if (e[i].isReady ())
{
newOp.exprs.add (e[i]);
isReady = true;
}
if (!isReady) return op.render (params);
return 'TRUE';
return newOp.render (batch);
} }
}); });

View File

@ -35,7 +35,7 @@ module.exports = new Class
,_onObjectChange: function () ,_onObjectChange: function ()
{ {
this.signalEmit ('changed'); this.emit ('changed');
} }
,isReady: function () ,isReady: function ()

View File

@ -16,6 +16,7 @@ module.exports = new Class
/** /**
* 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 ()

View File

@ -7,8 +7,8 @@ var Expr = require ('./expr');
* @param {Array#Sql.Expr} expr Array with the exprs * @param {Array#Sql.Expr} expr Array with the exprs
* @param {Sql..Operation.Type} type The type of the operation * @param {Sql..Operation.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 =
{ {
@ -28,13 +28,13 @@ var Operators =
,'REGEXP' ,'REGEXP'
]; ];
Operation.extend Klass.extend
({ ({
Type: Type Type: Type
,Operators: Operators ,Operators: Operators
}); });
Operation.implement Klass.implement
({ ({
Extends: Expr Extends: Expr
,Tag: 'sql-operation' ,Tag: 'sql-operation'
@ -60,7 +60,7 @@ Operation.implement
,onListChange: function () ,onListChange: function ()
{ {
this.signalEmit ('changed'); this.emit ('changed');
} }
,isReady: function () ,isReady: function ()

View File

@ -9,7 +9,7 @@ module.exports = new Class
Extends: Value Extends: Value
,Tag: 'sql-search-tags' ,Tag: 'sql-search-tags'
,render: function (batch) ,render: function ()
{ {
if (typeof this._value == 'string') if (typeof this._value == 'string')
{ {

View File

@ -19,18 +19,18 @@ module.exports = new Class
,regexp: /#\w+/g ,regexp: /#\w+/g
,replaceFunc: function (batch, token) ,replaceFunc: function (params, token)
{ {
var holder = new Holder ({id: token.substr (1)}); var holder = new Holder ({id: token.substr (1)});
return holder.render (batch); return holder.render (params);
} }
,render: function (batch) ,render: function (params)
{ {
if (!this.query) if (!this.query)
return null; return null;
return this.query.replace (this.regexp, this.replaceFunc.bind (this, batch)); return this.query.replace (this.regexp, this.replaceFunc.bind (this, params));
} }
,findHolders: function () ,findHolders: function ()

View File

@ -7,72 +7,86 @@ var Expr = require ('./expr');
module.exports = new Class module.exports = new Class
({ ({
Extends: Expr Extends: Expr
,Implements: Vn.ParamIface
,Tag: 'sql-value' ,Tag: 'sql-value'
,Properties: ,Properties:
{ {
/** value:
* The master param.
*/
param:
{ {
type: Vn.Param type: null
,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: ,set: function (x)
{
this._setLot (x);
}
,get: function ()
{
return this._lot;
}
},
name:
{ {
type: String type: String
,set: function (x) ,set: function (x)
{ {
if (Vn.Value.compare (x, this._value)) this._name = x;
return; this._onLotChange ();
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._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 ()
{ {

View File

@ -390,6 +390,9 @@ module.exports = new Class
switch (propInfo.type) switch (propInfo.type)
{ {
case null:
newValue = value;
break;
case Boolean: case Boolean:
newValue = (/^(true|1)$/i).test (value); newValue = (/^(true|1)$/i).test (value);
break; break;
@ -614,7 +617,7 @@ var BuilderResult = new Class
{ {
var objects = this.objects; var objects = this.objects;
for (var i = 0; i < objects.length; i++) for (var i = objects.length; i--;)
if (objects[i] instanceof VnObject) if (objects[i] instanceof VnObject)
objects[i].unref (); objects[i].unref ();

View File

@ -5,7 +5,9 @@ var LotIface = require ('./lot-iface');
var Value = require ('./value'); var Value = require ('./value');
/** /**
* 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 = new Class module.exports = new Class
({ ({
@ -60,12 +62,7 @@ module.exports = new Class
object[key] = value; object[key] = value;
this.assign (object); this.assign (object);
} }
/**
* Sets the hash part of the URL, respecting the current hash variables.
*
* @param {Object} object A key-value object
*/
,assign: function (object) ,assign: function (object)
{ {
var newObject = {}; var newObject = {};

View File

@ -79,7 +79,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 ();
@ -105,7 +105,7 @@ module.exports = new Class
*/ */
,_onClose: function (callback, json, error) ,_onClose: function (callback, json, error)
{ {
this.signalEmit ('closed'); this.emit ('closed');
if (callback) if (callback)
callback (this, json === true, error); callback (this, json === true, error);
@ -217,7 +217,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)
@ -228,7 +228,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;
@ -310,7 +310,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);
} }
} }
}); });

90
js/vn/json-model.js Normal file
View File

@ -0,0 +1,90 @@
var VnObject = require ('./object');
var ModelIface = require ('./model-iface');
var ModelProxy = require ('./model-proxy');
var Mode = ModelProxy.Mode;
/**
* Model that holds an array of Javascript objects with
* the same structure.
*/
module.exports = new Class
({
Extends: VnObject
,Implements: ModelIface
,Tag: 'vn-json-model'
,Properties:
{
numRows:
{
type: Number
},
status:
{
type: Number
},
mode:
{
enumType: Mode
,value: Mode.ON_CHANGE
},
data:
{
type: Array
,set: function (x)
{
this.data = x;
}
,get: function ()
{
return this.data;
}
}
}
,checkColExists: function () {}
,checkRowExists: function () {}
,getColumnIndex: function () {}
,get: function (rowIndex, columnName)
{
return this.data[rowIndex][columnName];
}
,getByIndex: function (rowIndex, column)
{
var columnName = this.columns[column];
return this.data[rowIndex][columnName];
}
,getObject: function (rowIndex)
{
return this.data[rowIndex];
}
,sortByName: function () {}
,sort: function () {}
,search: function () {}
,searchByIndex: function () {}
,set: function () {}
,setByIndex: function () {}
,deleteRow: function () {}
,insertRow: function () {}
,clean: function () {}
,performOperations: function () {}
,indexColumn: function () {}
});

View File

@ -1,4 +1,8 @@
/**
* Holds a plain key-value javascript object and monitorizes
* changes over it.
*/
module.exports = new Class module.exports = new Class
({ ({
Properties: Properties:
@ -40,7 +44,7 @@ module.exports = new Class
*/ */
,changed: function () ,changed: function ()
{ {
this.signalEmit ('change'); this.emit ('change');
} }
/** /**
@ -56,6 +60,11 @@ module.exports = new Class
this.changed (); this.changed ();
} }
/**
* Copies all values from another lot.
*
* @param {LotIface} lot The source lot
*/
,assignLot: function (lot) ,assignLot: function (lot)
{ {
this.assign (lot.params); this.assign (lot.params);

125
js/vn/lot-query.js Normal file
View File

@ -0,0 +1,125 @@
var Lot = require ('./lot');
var LotIface = require ('./lot-iface');
var Klass = new Class ();
module.exports = Klass;
var Type =
{
INCLUDE: 1,
EXCLUDE: 2
};
Klass.extend
({
Type: Type
});
Klass.implement
({
Extends: Lot
,Tag: 'vn-lot-query'
,Properties:
{
fields:
{
type: Array
,set: function (x)
{
this._fields = x;
this._onSourceChange ();
}
,get: function ()
{
return this._fields;
}
},
source:
{
type: LotIface
,set: function (x)
{
this.link ({_source: x}, {change: this._onSourceChange});
this._onSourceChange ();
}
,get: function ()
{
return this._source;
}
},
type:
{
enumType: Type
,set: function (x)
{
this._type = x;
this._onSourceChange ();
}
,get: function ()
{
return this._type;
}
}
}
,_fields: null
,_source: null
,_type: Type.INCLUDE
,_onSourceChange: function ()
{
var changed = false;
var params = this._source ? this._source.params : {};
if (this._fields)
switch (this._type)
{
case Type.EXCLUDE:
changed = this.typeExclude (params);
break;
default:
changed = this.typeInclude (params);
}
else
changed = true;
if (changed)
this.changed ();
}
,typeInclude: function (params)
{
var changed = false;
var fields = this._fields;
for (var i = fields.length; i--;)
{
var field = fields[i];
if (this._params[field] !== params[field])
{
this._params[field] = params[field];
changed = true;
}
}
return changed;
}
,typeExclude: function (params)
{
var changed = false;
for (var field in params)
if (this._fields.indexOf (field) === -1
&& this._params[field] !== params[field])
{
this._params[field] = params[field];
changed = true;
}
return changed;
}
});

View File

@ -1,10 +1,10 @@
var Object = require ('./object'); var VnObject = require ('./object');
var LotIface = require ('./lot-iface'); var LotIface = require ('./lot-iface');
module.exports = new Class module.exports = new Class
({ ({
Extends: Object Extends: VnObject
,Implements: LotIface ,Implements: LotIface
,Tag: 'vn-lot' ,Tag: 'vn-lot'
,Properties: ,Properties:
@ -24,6 +24,8 @@ module.exports = new Class
} }
} }
,_attachments: null
,initialize: function (props) ,initialize: function (props)
{ {
this._params = {}; this._params = {};

157
js/vn/model-iface.js Normal file
View File

@ -0,0 +1,157 @@
var VnObject = require ('./object');
/**
* Readable data model.
*/
var Klass = new Class ();
module.exports = Klass;
var Status =
{
CLEAN : 1
,LOADING : 2
,READY : 3
,ERROR : 4
};
var SortWay =
{
ASC : 1
,DESC : 2
};
Klass.extend
({
Status: Status
,SortWay: SortWay
});
Klass.implement
({
Extends: VnObject
,Properties:
{
/**
* The number of rows in the model.
*/
numRows:
{
type: Number
},
/**
* The current status of the model.
*/
status:
{
type: Number
},
/**
* Checks if the model data is ready.
*/
ready:
{
type: Boolean
}
}
/**
* Checks if the column exists.
*
* @param {integer} column The column index
* @return {Boolean} %true if column exists, %false otherwise
*/
,checkColExists: function () {}
/**
* Checks if the row exists.
*
* @param {integer} rowIndex The row index
* @return {Boolean} %true if row exists, %false otherwise
*/
,checkRowExists: function () {}
/**
* Get the index of the column from its name.
*
* @param {string} columnName The column name
* @return {number} The column index or -1 if column not exists
*/
,getColumnIndex: function () {}
/**
* Gets a value from the model.
*
* @param {number} rowIndex The row index
* @param {String} columnName The column name
* @return {*} The value, or %undefined
*/
,get: function () {}
/**
* Gets a value using the column index.
*
* @param {number} rowIndex The row index
* @param {number} column The column index
* @return {*} The value
*/
,getByIndex: function () {}
/**
* Gets a row as an object using the column index.
*
* @param {number} rowIndex The row index
* @return {Object} The row as an object
*/
,getObject: function () {}
/**
* Orders the model by the specified column name.
*
* @param {Number} column The column name
* @param {SortWay} way The sort way
*/
,sortByName: function () {}
/**
* Orders the model by the specified column.
*
* @param {Number} column The column index
* @param {SortWay} way The sort way
*/
,sort: function () {}
/**
* Searchs a value on the model and returns the row index of the first
* ocurrence.
* If an index have been built on that column, it will be used, for more
* information see the indexColumn() method.
*
* @param {String} column The column name
* @param {Object} value The value to search
* @return {Number} The column index
*/
,search: function () {}
/**
* Searchs a value on the model and returns the row index of the first
* ocurrence.
*
* @param {Number} col The column index
* @param {Object} value The value to search
* @return {Number} The column index
*/
,searchByIndex: function () {}
/**
* Builds an internal hash index for the specified column, this speeds
* significantly searches on that column, specially when model has a lot of
* rows.
*
* FIXME: Not fully implemented.
*
* @param {String} column The column name
*/
,indexColumn: function () {}
});

86
js/vn/model-proxy.js Normal file
View File

@ -0,0 +1,86 @@
var ModelIface = require ('./object');
/**
* Monitorizes all changes made to a model.
*/
var Klass = new Class ();
module.exports = Klass;
var Mode =
{
ON_CHANGE : 1
,ON_DEMAND : 2
};
var Operation =
{
INSERT : 1 << 1
,UPDATE : 1 << 2
,DELETE : 1 << 3
};
Klass.extend
({
Mode: Mode
,Operation: Operation
});
Klass.implement
({
Implements: ModelIface
,Properties:
{
/**
* Update mode.
*/
mode:
{
enumType: Mode
,value: Mode.ON_CHANGE
}
}
/**
* Updates a value on the model.
*
* @param {number} rowIndex The row index
* @param {String} columnName The column name
* @param {*} value The new value
*/
,set: function () {}
/**
* Updates a value on the model using the column index.
*
* @param {Number} rowIndex The row index
* @param {Number} col The column index
* @param {*} value The new value
*/
,setByIndex: function () {}
/**
* Deletes a row from the model.
*
* @param {number} rowIndex The row index
*/
,deleteRow: function () {}
/**
* Inserts a new row on the model.
*
* @return The index of the inserted row
*/
,insertRow: function () {}
/**
* Cleans the model data.
*/
,clean: function () {}
/**
* Performs all model changes on the database.
*/
,performOperations: function () {}
});

View File

@ -12,6 +12,12 @@ module.exports = new Class
,_refCount: 1 ,_refCount: 1
,_signalData: null ,_signalData: null
/**
* Initializes the object and sets all properties passed to the class
* constructor.
*
* @param {Object} props The properties passed to the contructor
*/
,initialize: function (props) ,initialize: function (props)
{ {
this.setProperties (props); this.setProperties (props);
@ -47,18 +53,23 @@ module.exports = new Class
if (this._refCount === 0) if (this._refCount === 0)
this._destroy (); this._destroy ();
} }
,loadXml: function (builder, node) {} /**
,appendChild: function (child) {} * Called from @Vn.Builder when it finds a custom tag as a child of the
* element.
,_signalInit: function () *
{ * @param {Vn.Builder} builder The builder instance
if (!this._signalData) * @param {Node} node The custom tag child nodes
this._signalData = { */
signals: {}, ,loadXml: function () {}
links: {}
}; /**
} * Called from @Vn.Builder when it finds a a child tag that isn't
* associated to any object property.
*
* @param {Object} child The child object instance
*/
,appendChild: function () {}
/** /**
* Conects a signal with a function. * Conects a signal with a function.
@ -81,8 +92,7 @@ module.exports = new Class
if (!callbacks) if (!callbacks)
callbacks = this._signalData.signals[id] = []; callbacks = this._signalData.signals[id] = [];
callbacks.push callbacks.push ({
({
blocked: false blocked: false
,callback: callback ,callback: callback
,instance: instance ,instance: instance
@ -117,7 +127,7 @@ module.exports = new Class
* *
* @param {String} id The signal identifier * @param {String} id The signal identifier
*/ */
,signalEmit: function (id) ,emit: function (id)
{ {
if (!this._signalData) if (!this._signalData)
return; return;
@ -152,13 +162,11 @@ module.exports = new Class
var callbacks = this._signalData.signals[id]; var callbacks = this._signalData.signals[id];
if (!callbacks) if (callbacks)
return; for (var i = callbacks.length; i--;)
for (var i = 0; i < callbacks.length; i++)
if (callbacks[i].callback === callback if (callbacks[i].callback === callback
&& callbacks[i].instance === instance) && callbacks[i].instance === instance)
callbacks.splice (i--, 1); callbacks.splice (i, 1);
} }
/** /**
@ -177,9 +185,10 @@ module.exports = new Class
{ {
var callbacks = signals[signalId]; var callbacks = signals[signalId];
for (var i = 0; i < callbacks.length; i++) if (callbacks)
for (var i = callbacks.length; i--;)
if (callbacks[i].instance === instance) if (callbacks[i].instance === instance)
callbacks.splice (i--, 1); callbacks.splice (i, 1);
} }
} }
@ -199,12 +208,6 @@ module.exports = new Class
this._signalData = null; this._signalData = null;
} }
,_unlink: function (object)
{
object.disconnectByInstance (this);
object.unref ();
}
/** /**
* Links the object with another object. * Links the object with another object.
@ -238,5 +241,20 @@ module.exports = new Class
delete links[key]; delete links[key];
} }
} }
,_unlink: function (object)
{
object.disconnectByInstance (this);
object.unref ();
}
,_signalInit: function ()
{
if (!this._signalData)
this._signalData = {
signals: {},
links: {}
};
}
}); });

140
js/vn/param-iface.js Normal file
View File

@ -0,0 +1,140 @@
var LotIface = require ('./lot-iface');
var Type = require ('./type');
/**
* A value holder, it emits the changed signal when value is changed.
* Also it can be linked with a lot value or another parameter.
*/
module.exports = new Class
({
Properties:
{
/**
* The parameter value.
*/
value:
{
type: null
},
/**
* The parameter type.
*/
type:
{
type: Type
},
/**
* Another parameter to bind with.
*/
param:
{
type: Object
},
/**
* A lot to bind with.
*/
lot:
{
type: LotIface
},
/**
* The field name in the lot.
*/
name:
{
type: String
},
/**
* Determines whether the link to the lot is unidirectional, ie, a
* change in the lot updates the parameter but not viceversa.
*/
oneWay:
{
type: Boolean
}
}
,_value: undefined
,_type: null
,_param: null
,_paramLock: false
,_lot: null
,_name: null
,_lotLock: false
,_oneWay: false
,_setValue: function (newValue)
{
if (newValue == this._value)
return;
if (newValue instanceof Date)
newValue = newValue.clone ();
this._value = newValue;
this._refreshLot ();
this._refreshParam ();
this.emit ('changed', newValue);
}
,_setType: function (type)
{
this._type = type;
this._onLotChange ();
}
,_setParam: function (param)
{
this.link ({_param: param}, {changed: this._onParamChange});
this._refreshParam ();
}
,_onParamChange: function ()
{
if (this._paramLock || !this._param)
return;
this._paramLock = true;
this._setValue (this._param.value);
this._paramLock = false;
}
,_refreshParam: function ()
{
if (this._paramLock || !this._param)
return;
this._paramLock = true;
this._param.value = this._value;
this._paramLock = false;
}
,_setLot: function (lot)
{
this.link ({_lot: lot}, {change: this._onLotChange});
this._onLotChange ();
}
,_onLotChange: function ()
{
if (this._lotLock || !this._name || !this._lot)
return;
var newValue = this._lot.get (this._name, this._type);
this._lotLock = true;
this._setValue (newValue);
this._lotLock = false;
}
,_refreshLot: function ()
{
if (this._lotLock || !this._name || !this._lot || this._oneWay)
return;
this._lotLock = true;
this._lot.set (this._name, this._value);
this._lotLock = false;
}
});

View File

@ -1,28 +1,67 @@
var VnObject = require ('./object'); var VnObject = require ('./object');
var Lot = require ('./lot');
var Type = require ('./type'); var Type = require ('./type');
var ParamIface = require ('./param-iface');
var LotIface = require ('./lot-iface');
/**
* A simple implementation of @ParamIface.
*/
module.exports = new Class module.exports = new Class
({ ({
Extends: VnObject Extends: VnObject
,Implements: ParamIface
,Tag: 'vn-param' ,Tag: 'vn-param'
,Child: 'param'
,Properties: ,Properties:
{ {
param: value:
{ {
type: Object type: null
,set: function (x) ,set: function (x)
{ {
this.link ({_param: x}, {'changed': this._onParamChange}); this._setValue (x);
this._refreshParam (); }
,get: function ()
{
return this._value;
}
},
type:
{
type: Type
,set: function (x)
{
this._setType (x);
}
,get: function ()
{
return this._type;
}
},
param:
{
type: ParamIface
,set: function (x)
{
this._setParam (x);
} }
,get: function () ,get: function ()
{ {
return this._param; return this._param;
} }
}, },
lot:
{
type: LotIface
,set: function (x)
{
this._setLot (x);
}
,get: function ()
{
return this._lot;
}
},
name: name:
{ {
type: String type: String
@ -36,48 +75,6 @@ module.exports = new Class
return this._name; return this._name;
} }
}, },
value:
{
type: Object
,set: function (x)
{
this._setValue (x, true);
}
,get: function ()
{
return this._value;
}
},
type:
{
type: Type
,set: function (x)
{
this._type = x;
this._onLotChange ();
}
,get: function ()
{
return this._type;
}
},
lot:
{
type: Lot
,set: function (x)
{
this.link ({_lot: x}, {'change': this._onLotChange});
this._onLotChange ();
}
,get: function ()
{
return this._lot;
}
},
/**
* Determines whether the link to the form is unidirectional, ie, a
* change in the lot updates the parameter but not vice versa.
*/
oneWay: oneWay:
{ {
type: Boolean type: Boolean
@ -91,67 +88,4 @@ module.exports = new Class
} }
} }
} }
,_lotLock: false
,_paramLock: false
,_value: undefined
,_lot: null
,_name: null
,_type: null
,_oneWay: false
,_onLotChange: function ()
{
if (this._lotLock || !this._name || !this._lot)
return;
var newValue = this._lot.get (this._name, this._type);
this._lotLock = true;
this._setValue (newValue, true);
this._lotLock = false;
}
,_setValue: function (newValue, signal)
{
if (newValue == this._value)
return;
if (newValue instanceof Date)
newValue = newValue.clone ();
this._value = newValue;
if (this._lot && this._name && !this._lotLock && !this._oneWay)
{
this._lotLock = true;
this._lot.set (this._name, newValue);
this._lotLock = 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

@ -31,12 +31,65 @@ function equals (a, b)
return false; return false;
} }
/**
* Calculates differences of to key-value objects.
*
* @param {Object} orgObject Value to compare to
* @param {Object} newObject Value to compare with
* @return {Object} The differences or %null if there are no differences
*/
function diff (orgObject, newObject)
{
var key;
var diff = {};
var keys = Object.keys (orgObject);
for (var i = keys.length; --i; key = keys[i])
if (orgObject[key] !== newObject[key])
diff[key] = newObject[key];
var keys = Object.keys (newObject);
for (var i = keys.length; --i; key = keys[i])
if (orgObject[key] === undefined)
diff[key] = newObject[key];
if (Object.keys (diff).length > 0)
return diff;
return null;
}
/**
* Returns a formated string.
*
* @param {Object} formatString The base string template
* @param {...} arguments Format parameters
* @return {String} The formated string
*/
function sprintf (formatString)
{
var args = arguments;
if (args.length <= 1)
return formatString;
var i = 1;
return formatString.replace (/%[s|d]/g, function ()
{
return args[i++];
});
}
module.exports = module.exports =
{ {
regexpNumber: /%\.([0-9]+)d/g regexpNumber: /%\.([0-9]+)d/g
,regexpString: /%s/g ,regexpString: /%s/g
,equals: equals ,equals: equals
,diff: diff
,sprintf: sprintf
,compare: function (a, b) ,compare: function (a, b)
{ {
@ -80,18 +133,3 @@ module.exports =
return value; return value;
} }
}; };
window.sprintf = function (formatString)
{
var args = arguments;
if (args.length <= 1)
return formatString;
var i = 1;
return formatString.replace (/%[s|d]/g, function ()
{
return args[i++];
});
}

View File

@ -14,8 +14,13 @@ Vn = module.exports = {
,Url : require ('./url') ,Url : require ('./url')
,LotIface : require ('./lot-iface') ,LotIface : require ('./lot-iface')
,Lot : require ('./lot') ,Lot : require ('./lot')
,LotQuery : require ('./lot-query')
,Hash : require ('./hash') ,Hash : require ('./hash')
,ParamIface : require ('./param-iface')
,Param : require ('./param') ,Param : require ('./param')
,ModelIface : require ('./model-iface')
,ModelProxy : require ('./model-proxy')
,JsonModel : require ('./json-model')
,Node : require ('./node') ,Node : require ('./node')
,Builder : require ('./builder') ,Builder : require ('./builder')
,JsonException : require ('./json-exception') ,JsonException : require ('./json-exception')

View File

@ -3,6 +3,7 @@ LOAD DATA LOCAL INFILE #file
FIELDS TERMINATED BY ';' FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12, @col13, @col14, @col15, @col16, @col17, @col18, @col19, @col20) LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12, @col13, @col14, @col15, @col16, @col17, @col18, @col19, @col20)
SET SET
glnAddressCode = @col2,
supplier_id = @col4, supplier_id = @col4,
company_name = @col3, company_name = @col3,
entry_date = STR_TO_DATE(@col9, '%Y%m%d'), entry_date = STR_TO_DATE(@col9, '%Y%m%d'),