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

View File

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

View File

@ -1,45 +1,62 @@
<vn>
<vn-group>
<vn-lot id="card-lot"/>
<vn-param id="realm" on-changed="onRealmChange"/>
<vn-param id="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"/>
<vn-param lot="hash" name="realm" on-changed="onRealmChange"/>
<vn-param lot="hash" name="type" on-changed="onTypeChange"/>
<sql-filter type="AND" id="filter">
<sql-filter-item type="EQUAL" primary="false" id="op-realm">
<sql-field name="reino_id" target="t"/>
<sql-value id="realm-value"/>
</sql-filter-item>
<sql-filter-item type="EQUAL" id="op-type">
<sql-field name="tipo_id" target="a"/>
<sql-value id="type-value"/>
</sql-filter-item>
<sql-filter-item type="LIKE" id="op-name">
<sql-field name="Article"/>
<sql-search-tags param="search"/>
</sql-filter-item>
<sql-filter-item type="EQUAL" id="op-color">
<sql-field name="Color"/>
<sql-value param="color"/>
</sql-filter-item>
<sql-filter-item type="EQUAL" id="op-origin">
<sql-field name="id_origen"/>
<sql-value param="origin"/>
</sql-filter-item>
<sql-filter-item type="EQUAL" id="op-category">
<sql-field name="Categoria"/>
<sql-value param="category"/>
</sql-filter-item>
<sql-filter-item type="EQUAL" id="op-producer">
<sql-field name="producer_id"/>
<sql-value param="producer"/>
</sql-filter-item>
<sql-filter-item type="EQUAL"
field="reino_id" target="t"
param="realm"/>
<sql-filter-item type="EQUAL"
field="tipo_id" target="a"
param="type"/>
<sql-filter type="OR">
<sql-filter-item type="LIKE"
field="Article" target="a"
param="search"/>
<sql-filter-item type="EQUAL"
field="Id_Article" target="a"
param="search"/>
</sql-filter>
<sql-filter-item type="EQUAL"
field="Color" target="a"
param="color"/>
<sql-filter-item type="EQUAL"
field="id_origen" target="a"
param="origin"/>
<sql-filter-item type="EQUAL"
field="Categoria" target="a"
param="category"/>
<sql-filter-item type="EQUAL"
field="producer_id" target="a"
param="producer"/>
</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-model property="model">
SELECT o.id, o.date_send, ag.description agency, v.code method
@ -53,35 +70,7 @@
FROM basket_item
GROUP BY warehouse_id
</db-query>
<db-model
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" model="items"/>
<db-form id="card-extend">
<db-model
property="model"
@ -96,8 +85,8 @@
<db-model
id="item-lots"
result-index="1"
on-status-changed-after="onStatusChange"
batch="card-batch">
lot="card-lot"
on-status-changed-after="onStatusChange">
CALL bionic_from_item (#item);
SELECT p.warehouse_id, w.name warehouse, p.grouping, p.price, p.rate, l.available
FROM tmp.bionic_lot l
@ -122,15 +111,15 @@
tip="_Switch view"
on-click="onSwitchViewClick"/>
<htk-search-entry
param="search"/>
lot="hash"
name="search"/>
</div>
<div id="main" class="catalog">
<div id="main" class="main">
<htk-repeater
id="grid-view"
empty-message="_Choose filter from right menu"
form-id="item"
model="items-model">
model="items">
<custom>
<div class="card item-box">
<htk-image
@ -174,7 +163,6 @@
</div>
</custom>
</htk-repeater>
</div>
</div>
<div id="right-panel" class="right-panel" on-click="onRightPanelClick">
<div class="basket-info">
@ -193,12 +181,10 @@
<div class="categories">
<div class="realms">
<htk-repeater
model="realms-model"
form-id="realm-form"
renderer="realmRenderer"
class="realms-box">
<db-model
id="realms-model"
id="realms"
property="model"
on-status-changed="refreshTitleColor">
SELECT r.id, l.str name, r.color
@ -222,12 +208,14 @@
<div id="filters" class="filters">
<h2><t>Filter by</t></h2>
<vn-filter
placeholder="_Family"
param="type">
lot="hash"
name="type"
placeholder="_Family">
<db-model
id="types-model"
id="types"
property="model"
conn="conn"
lot="hash"
result-index="1"
on-status-changed="refreshTitle">
CALL item_available ();
@ -236,19 +224,16 @@
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
JOIN tmp.item_available i ON i.item_id = a.Id_Article
WHERE #filter
WHERE t.reino_id = #realm
ORDER BY name
</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
id="test"
lot="hash"
name="color"
placeholder="_Color"
param="color">
filter="filter">
<db-model property="model" auto-load="false" result-index="1">
CALL item_available ();
SELECT DISTINCT c.Id_Tinta, l.str name
@ -260,18 +245,12 @@
WHERE #filter
ORDER BY name
</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
lot="hash"
name="producer"
placeholder="_Producer"
param="producer">
filter="filter">
<db-model property="model" auto-load="false" result-index="1">
CALL item_available ();
SELECT DISTINCT p.producer_id, p.name
@ -282,18 +261,12 @@
WHERE #filter
ORDER BY name
</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
lot="hash"
name="origin"
placeholder="_Origin"
param="origin">
filter="filter">
<db-model property="model" auto-load="false" result-index="1">
CALL item_available ();
SELECT DISTINCT o.id, l.str name, o.Abreviatura
@ -305,18 +278,12 @@
WHERE #filter
ORDER BY name
</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
lot="hash"
name="category"
placeholder="_Category"
param="category">
filter="filter">
<db-model property="model" auto-load="false" result-index="1">
CALL item_available ();
SELECT DISTINCT a.Categoria, a.Categoria category
@ -326,14 +293,6 @@
WHERE #filter
ORDER BY a.Categoria
</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>
</div>
<div id="order" class="order">
@ -444,4 +403,22 @@
</div>
</div>
</htk-popup>
<!--
<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
,initialize: function (props)
{
this.today = new Date ();
this.today.setHours (0, 0, 0, 0);
this.parent (props);
}
,activate: function ()
{
this.autoStepLocked = true;
this.today = new Date ();
this.today.setHours (0,0,0,0);
}
,onValuesReady: function ()

View File

@ -184,7 +184,7 @@
</p>
<p>
<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="dc"/>
<htk-text lot="iter" name="number"/>

View File

@ -75,6 +75,13 @@ Connection.implement
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)
{
return new Sql.String ({query: query}).render (params);

View File

@ -106,13 +106,13 @@ module.exports = new Class
this.lastRow = this._row;
this._ready = ready;
this.signalEmit ('status-changed');
this.emit ('status-changed');
if (this._row == -1)
this.row = this.lastRow;
if (ready)
this.signalEmit ('ready');
this.emit ('ready');
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
* columns have the same name, an alias should be used to make it updatable.
*/
var Model = new Class ();
module.exports = Model;
var Klass = new Class ();
module.exports = Klass;
var Status =
{
@ -40,7 +40,7 @@ var SortWay =
,DESC : 2
};
Model.extend
Klass.extend
({
Status: Status
,Mode: Mode
@ -48,7 +48,7 @@ Model.extend
,SortWay: SortWay
});
Model.implement
Klass.implement
({
Extends: Vn.Object
,Tag: 'db-model'
@ -85,22 +85,6 @@ Model.implement
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.
*/
@ -241,10 +225,10 @@ Model.implement
,_conn: null
,_resultIndex: 0
,_batch: null
,_lot: null
,_stmt: null
,_status: Status.CLEAN
,result: null
,data: null
,tables: null
,columns: null
@ -289,6 +273,10 @@ Model.implement
return null;
var lotParams = this._lot ? this._lot.params : {};
if (lotParams == null)
lotParams = {};
var params = {};
for (var i = 0; i < ids.length; i++)
@ -371,6 +359,7 @@ Model.implement
throw e;
}
this.result = dataResult;
this.data = dataResult.data;
this.tables = dataResult.tables;
this.columns = dataResult.columns;
@ -412,6 +401,7 @@ Model.implement
,_cleanData: function ()
{
this.result = null;
this.data = null;
this.tables = null;
this.columns = null;
@ -427,7 +417,7 @@ Model.implement
this._updatable = this._mainTable !== null && this._requestedUpdatable;
if (oldValue != this._updatable)
this.signalEmit ('updatable-changed');
this.emit ('updatable-changed');
}
,_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} column The column index
@ -605,6 +595,20 @@ Model.implement
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.
*
@ -654,9 +658,9 @@ Model.implement
&& op.oldValues[col] === undefined)
op.oldValues[col] = row[col];
this.signalEmit ('row-updated-before', rowIndex);
this.emit ('row-updated-before', rowIndex);
row[col] = value;
this.signalEmit ('row-updated', rowIndex, [col]);
this.emit ('row-updated', rowIndex, [col]);
if (this.mode == Mode.ON_CHANGE
&& !(op.type & Operation.INSERT))
@ -679,14 +683,14 @@ Model.implement
if (!this._requestedMainTable)
{
this.signalEmit ('row-deleted-before', rowIndex);
this.emit ('row-deleted-before', rowIndex);
this.data.splice (rowIndex, 1);
this.signalEmit ('row-deleted', rowIndex);
this.emit ('row-deleted', rowIndex);
this._refreshRowIndexes (rowIndex);
}
else
{
this.signalEmit ('row-updated-before', rowIndex);
this.emit ('row-updated-before', rowIndex);
if (!op.oldValues)
op.oldValues = [];
@ -703,7 +707,7 @@ Model.implement
updatedCols.push (i);
}
this.signalEmit ('row-updated', rowIndex, updatedCols);
this.emit ('row-updated', rowIndex, updatedCols);
}
if (this.mode === Mode.ON_CHANGE)
@ -735,7 +739,7 @@ Model.implement
var op = this._createOperation (rowIndex);
op.type |= Operation.INSERT;
this.signalEmit ('row-inserted', rowIndex);
this.emit ('row-inserted', rowIndex);
return rowIndex;
}
@ -749,7 +753,7 @@ Model.implement
if (ops.length === 0)
{
this.signalEmit ('operations-done');
this.emit ('operations-done');
return;
}
@ -912,7 +916,7 @@ Model.implement
}
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 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 ();
// if (isOperation)
this.signalEmit ('operations-done');
this.emit ('operations-done');
}
/**
@ -970,11 +974,11 @@ Model.implement
&& !(op.type & Operation.INSERT))
{
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)
{
this.signalEmit ('row-updated-before', row.index);
this.emit ('row-updated-before', row.index);
var updatedCols = [];
var cols = this.columns;
@ -986,7 +990,7 @@ Model.implement
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)
{
this._status = status;
this.signalEmit ('status-changed', status);
this.signalEmit ('status-changed-after', status);
this.emit ('status-changed', status);
this.emit ('status-changed-after', status);
}
,_createTarget: function (tableIndex)

View File

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

View File

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

View File

@ -1,20 +1,34 @@
var Gui = require ('./gui');
module.exports = new Class
({
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
,uiLoaded: false
,initialize: function (gui, formInfo)
{
this.gui = gui;
this.conn = gui.conn;
this.hash = gui.hash;
this.formInfo = formInfo;
this.parent ();
}
,loadUi: function ()
{
if (!this.isOpen)

View File

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

View File

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

View File

@ -106,7 +106,7 @@ module.exports = new Class
,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)
{
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)
{
this.hide ();
this.signalEmit ('response', response);
this.emit ('response', response);
}
,_onClosed: function ()
{
this.signalEmit ('response', null);
this.emit ('response', null);
}
});

View File

@ -1,44 +1,89 @@
var Widget = require ('./widget');
/**
* Base class for graphical fields.
*/
module.exports = new Class
({
Extends: Widget
,Implements: Vn.ParamIface
,Tag: 'htk-field'
,Properties:
{
value:
{
type: String
type: null
,set: function (x)
{
if (Vn.Value.compare (x, this._value))
return;
if (x instanceof Date)
x = x.clone ();
this.valueChanged (x);
this.putValue (x);
this._setValue (x);
}
,get: function ()
{
return this._value;
}
},
param:
type:
{
type: Vn.Param
type: Type
,set: function (x)
{
this.link ({_param: x}, {'changed': this.onParamChange});
this.onParamChange ();
this._setType (x);
}
,get: function ()
{
return this._type;
}
},
param:
{
type: Vn.ParamIface
,set: function (x)
{
this._setParam (x);
}
,get: function ()
{
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:
{
type: Boolean
@ -55,24 +100,6 @@ module.exports = new Class
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:
{
type: Function
@ -80,30 +107,26 @@ module.exports = new Class
}
}
,_value: undefined
,_param: null
,_editable: true
,_blockParamChange: false
,_blockValueChange: false
,onParamChange: function ()
,_setValue: function (newValue)
{
if (!this._blockValueChange)
{
this._blockParamChange = true;
this.value = this._param.value;
this._blockParamChange = false;
}
Vn.ParamIface.prototype._setValue.call (this, newValue);
this.putValue (newValue);
if (this.conditionalFunc)
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.param = new Vn.Param
({
lot: this._lot
,name: this._paramName
});
this._setValue (value);
}
/**
@ -121,28 +144,5 @@ module.exports = new Class
* @param {*} value The new value for the entry
*/
,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)
{
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.show (this.node, true, e);
this.signalEmit ('menu-show');
this.emit ('menu-show');
}
,_onGridClicked: function (grid, e)
@ -216,7 +216,7 @@ module.exports = new Class
,_onPopupClose: function ()
{
this._popup = null;
this.signalEmit ('menu-hide');
this.emit ('menu-hide');
}
,_refreshShowText: function ()
@ -238,7 +238,7 @@ module.exports = new Class
,_onModelChange: function ()
{
var model = this._model;
this.signalEmit ('status-changed');
this.emit ('status-changed');
if (this._popup)
this._popup.reset ();
@ -246,7 +246,7 @@ module.exports = new Class
if (model && model.ready)
{
this._selectOption ();
this.signalEmit ('ready');
this.emit ('ready');
}
else
this._setRow (-1);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,11 +12,17 @@ module.exports = new Class
,Tag: 'sql-field'
,Properties:
{
/**
* The column name.
*/
name:
{
type: String
,value: null
},
/**
* The source table name or its alias if it has been specified.
*/
target:
{
type: String
@ -24,7 +30,7 @@ module.exports = new Class
}
}
,render: function (batch)
,render: function ()
{
var sql = (this.target) ? '`' + this.target + '`.' : '';
return sql + '`' + this.name + '`';

View File

@ -1,8 +1,12 @@
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
({
@ -10,11 +14,66 @@ module.exports = new Class
,Tag: 'sql-filter-item'
,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 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
({
Extends: Operation
,Tag: 'sql-filter'
,Properties:
{
alwaysReady:
{
type: Boolean
}
}
,isReady: function ()
/**
* Checks if any of filters childs are ready.
*/
,isReady: function (params)
{
if (this.alwaysReady)
return true;
var e = this.exprs.getArray ();
for (var i = 0; i < e.length; i++)
if (e[i].isReady () && e[i].primary)
var exprs = this.exprs.objects;
for (var i = exprs.length; i--;)
if (exprs[i].isReady (params))
return true;
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 newOp = new Operation ({type: this.type});
var op = new Operation ({type: this.type});
var exprs = this.exprs.objects;
var e = this.exprs.getArray ();
for (var i = 0; i < e.length; i++)
if (e[i].isReady ())
{
newOp.exprs.add (e[i]);
isReady = true;
}
for (var i = 0; i < exprs.length; i++)
if (exprs[i].isReady (params))
op.exprs.add (exprs[i]);
if (!isReady)
return 'TRUE';
if (op.exprs.objects.length == 0)
op = new Value ({value: true});
return newOp.render (batch);
return op.render (params);
}
});

View File

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

View File

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

View File

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

View File

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

View File

@ -19,18 +19,18 @@ module.exports = new Class
,regexp: /#\w+/g
,replaceFunc: function (batch, token)
,replaceFunc: function (params, token)
{
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)
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 ()

View File

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

View File

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

View File

@ -5,7 +5,9 @@ var LotIface = require ('./lot-iface');
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
({
@ -61,11 +63,6 @@ module.exports = new Class
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)
{
var newObject = {};

View File

@ -79,7 +79,7 @@ module.exports = new Class
var storage = remember ? localStorage : sessionStorage;
storage.setItem ('vnToken', this.token);
this.signalEmit ('openned');
this.emit ('openned');
}
else
this._closeClient ();
@ -105,7 +105,7 @@ module.exports = new Class
*/
,_onClose: function (callback, json, error)
{
this.signalEmit ('closed');
this.emit ('closed');
if (callback)
callback (this, json === true, error);
@ -217,7 +217,7 @@ module.exports = new Class
this._requestsCount++;
if (this._requestsCount === 1)
this.signalEmit ('loading-changed', true);
this.emit ('loading-changed', true);
}
,_onStateChange: function (request, callback)
@ -228,7 +228,7 @@ module.exports = new Class
this._requestsCount--;
if (this._requestsCount === 0)
this.signalEmit ('loading-changed', false);
this.emit ('loading-changed', false);
var data = null;
var error = null;
@ -310,7 +310,7 @@ module.exports = new Class
if (error.exception == 'SessionExpired')
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
({
Properties:
@ -40,7 +44,7 @@ module.exports = new Class
*/
,changed: function ()
{
this.signalEmit ('change');
this.emit ('change');
}
/**
@ -56,6 +60,11 @@ module.exports = new Class
this.changed ();
}
/**
* Copies all values from another lot.
*
* @param {LotIface} lot The source lot
*/
,assignLot: function (lot)
{
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');
module.exports = new Class
({
Extends: Object
Extends: VnObject
,Implements: LotIface
,Tag: 'vn-lot'
,Properties:
@ -24,6 +24,8 @@ module.exports = new Class
}
}
,_attachments: null
,initialize: function (props)
{
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
,_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)
{
this.setProperties (props);
@ -48,17 +54,22 @@ module.exports = new Class
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.
*
* @param {Vn.Builder} builder The builder instance
* @param {Node} node The custom tag child nodes
*/
,loadXml: function () {}
,_signalInit: function ()
{
if (!this._signalData)
this._signalData = {
signals: {},
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.
@ -81,8 +92,7 @@ module.exports = new Class
if (!callbacks)
callbacks = this._signalData.signals[id] = [];
callbacks.push
({
callbacks.push ({
blocked: false
,callback: callback
,instance: instance
@ -117,7 +127,7 @@ module.exports = new Class
*
* @param {String} id The signal identifier
*/
,signalEmit: function (id)
,emit: function (id)
{
if (!this._signalData)
return;
@ -152,13 +162,11 @@ module.exports = new Class
var callbacks = this._signalData.signals[id];
if (!callbacks)
return;
for (var i = 0; i < callbacks.length; i++)
if (callbacks)
for (var i = callbacks.length; i--;)
if (callbacks[i].callback === callback
&& callbacks[i].instance === instance)
callbacks.splice (i--, 1);
callbacks.splice (i, 1);
}
/**
@ -177,9 +185,10 @@ module.exports = new Class
{
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)
callbacks.splice (i--, 1);
callbacks.splice (i, 1);
}
}
@ -200,12 +209,6 @@ module.exports = new Class
this._signalData = null;
}
,_unlink: function (object)
{
object.disconnectByInstance (this);
object.unref ();
}
/**
* Links the object with another object.
*
@ -238,5 +241,20 @@ module.exports = new Class
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 Lot = require ('./lot');
var Type = require ('./type');
var ParamIface = require ('./param-iface');
var LotIface = require ('./lot-iface');
/**
* A simple implementation of @ParamIface.
*/
module.exports = new Class
({
Extends: VnObject
,Implements: ParamIface
,Tag: 'vn-param'
,Child: 'param'
,Properties:
{
param:
value:
{
type: Object
type: null
,set: function (x)
{
this.link ({_param: x}, {'changed': this._onParamChange});
this._refreshParam ();
this._setValue (x);
}
,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 ()
{
return this._param;
}
},
lot:
{
type: LotIface
,set: function (x)
{
this._setLot (x);
}
,get: function ()
{
return this._lot;
}
},
name:
{
type: String
@ -36,48 +75,6 @@ module.exports = new Class
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:
{
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;
}
/**
* 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 =
{
regexpNumber: /%\.([0-9]+)d/g
,regexpString: /%s/g
,equals: equals
,diff: diff
,sprintf: sprintf
,compare: function (a, b)
{
@ -80,18 +133,3 @@ module.exports =
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')
,LotIface : require ('./lot-iface')
,Lot : require ('./lot')
,LotQuery : require ('./lot-query')
,Hash : require ('./hash')
,ParamIface : require ('./param-iface')
,Param : require ('./param')
,ModelIface : require ('./model-iface')
,ModelProxy : require ('./model-proxy')
,JsonModel : require ('./json-model')
,Node : require ('./node')
,Builder : require ('./builder')
,JsonException : require ('./json-exception')

View File

@ -3,6 +3,7 @@ LOAD DATA LOCAL INFILE #file
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)
SET
glnAddressCode = @col2,
supplier_id = @col4,
company_name = @col3,
entry_date = STR_TO_DATE(@col9, '%Y%m%d'),