0
1
Fork 0

Vn.Model v1

This commit is contained in:
Juan Ferrer Toribio 2017-10-25 09:47:32 +02:00
parent 4d8bd4ad95
commit fe68eb5ce0
17 changed files with 875 additions and 643 deletions

View File

@ -15,8 +15,8 @@ Hedera.Contact = new Class
,refreshCaptcha: function ()
{
params = {
'srv': 'rest:core/captcha',
'stamp': new Date ().getTime ()
srv: 'rest:core/captcha',
stamp: new Date ().getTime ()
};
this.$.captchaImg.src = '?'+ Vn.Url.makeUri (params);
}

View File

@ -123,8 +123,12 @@ Connection.implement
{
var data = json[i].data;
var columns = json[i].columns;
var nCols = columns.length;
for (var j = 0; j < columns.length; j++)
var result = [];
var castFuncs = new Array (nCols);
for (var j = 0; j < nCols; j++)
{
var castFunc = null;
@ -136,17 +140,32 @@ Connection.implement
castFunc = this.valueToDate;
break;
}
if (castFunc !== null)
{
castFuncs[j] = castFunc;
if (columns[j].def != null)
columns[j].def = castFunc (columns[j].def);
for (var k = 0; k < data.length; k++)
if (data[k][j] != null)
data[k][j] = castFunc (data[k][j]);
}
}
for (var j = 0; j < data.length; j++)
{
var row = data[j];
var object = {};
result.push (object);
for (var k = 0; k < nCols; k++)
{
var castFunc = castFuncs[k];
object[columns[k].name] =
castFunc ? castFunc (row[k]) : row[k];
}
}
json[i].data = result;
}
}
catch (e)

File diff suppressed because it is too large Load Diff

View File

@ -101,7 +101,7 @@ module.exports = new Class
{
var row = this.fetchRow ();
if (row instanceof Array && row.length > 0)
if (row instanceof Object && row.length > 0)
return row[0];
return null;

View File

@ -29,13 +29,12 @@ module.exports = new Class
/**
* Gets a value from de result.
*
* @param {string} columnName The column name
* @param {String} columnName The column name
* @return {Object} The cell value
*/
,get: function (columnName)
{
var columnIndex = this.columnMap[columnName];
return this.data[this.row][columnIndex];
return this.data[this.row][columnName];
}
/**
@ -48,7 +47,7 @@ module.exports = new Class
if (!this.next ())
return null;
return this.getObject (this.row);
return this.data[this.row];
}
/**
@ -59,14 +58,7 @@ module.exports = new Class
*/
,getObject: function (rowIndex)
{
var row = this.data[rowIndex];
var cols = this.columns;
var object = {};
for (var i = 0; i < cols.length; i++)
object[cols[i].name] = row[i];
return object;
return this.data[rowIndex];
}
/**

View File

@ -231,6 +231,7 @@ textarea,
.input
{
padding: 0 .2em;
padding-bottom: 1px;
}
input[type=text],
input[type=password],
@ -253,7 +254,9 @@ input[type=number]:focus,
textarea:focus,
.input:focus
{
border-color: #333;
border-color: #666;
border-bottom-width: 2px;
padding-bottom: 0;
}
input[type=checkbox],
input[type=radio]

View File

@ -96,10 +96,10 @@ module.exports = new Class
return td;
}
,updateColumnIndex: function (model)
,updateColumnName: function (model)
{
if (this.column)
this.columnIndex = model.getColumnIndex (this.column);
if (this.columnIndex != -1)
this.column = model.getColumnName (this.columnIndex);
}
,changed: function (tr, newValue)

View File

@ -1,4 +1,6 @@
var slide = require ('vn/transitions').slide;
module.exports = new Class
({
Extends: Htk.Field
@ -31,47 +33,44 @@ module.exports = new Class
var node = this.createRoot ('div');
node.className = 'htk-calendar';
var table = this.createElement ('table');
this.node.appendChild (table);
var div = this.createElement ('div');
div.className = 'month';
node.appendChild (div);
var colgroup = this.createElement ('colgroup');
table.appendChild (colgroup);
for (var i = 0; i < len; i++)
colgroup.appendChild (this.createElement ('col'));
var thead = this.createElement ('thead');
table.appendChild (thead);
var tr = this.createElement ('tr');
thead.appendChild (tr);
var th = this.createElement ('th');
th.appendChild (this.createTextNode ('<'));
th.className = 'button';
th.addEventListener ('click', this.prevMonthClicked.bind (this));
tr.appendChild (th);
var th = this.createElement ('th');
th.colSpan = 5;
tr.appendChild (th);
var button = this.createElement ('div');
button.appendChild (this.createTextNode ('<'));
button.className = 'button previous';
button.addEventListener ('click', this.prevMonthClicked.bind (this));
div.appendChild (button);
var monthNode = this.createElement ('span');
th.appendChild (monthNode);
div.appendChild (monthNode);
var space = this.createTextNode (' ');
th.appendChild (space);
div.appendChild (space);
var yearNode = this.createElement ('span');
th.appendChild (yearNode);
div.appendChild (yearNode);
var th = this.createElement ('th');
th.appendChild (this.createTextNode ('>'));
th.className = 'button';
th.addEventListener ('click', this.nextMonthClicked.bind (this));
tr.appendChild (th);
var button = this.createElement ('div');
button.appendChild (this.createTextNode ('>'));
button.className = 'button next';
button.addEventListener ('click', this.nextMonthClicked.bind (this));
div.appendChild (button);
var wrapper = this.createElement ('div');
wrapper.className = 'wrapper';
node.appendChild (wrapper);
var table = this.createElement ('table');
wrapper.appendChild (table);
this.table = table;
var thead = this.createElement ('thead');
table.appendChild (thead);
var tr = this.createElement ('tr');
tr.className = 'wdays';
thead.appendChild (tr);
for (var i = 1; i <= len; i++)
@ -255,8 +254,8 @@ module.exports = new Class
this.month = 11;
this.year--;
}
this.refresh ();
this.refreshSlide ('right');
}
,nextMonthClicked: function ()
@ -269,6 +268,12 @@ module.exports = new Class
this.year++;
}
this.refresh ();
this.refreshSlide ('left');
}
,refreshSlide: function (way)
{
var cb = this.refresh.bind (this);
slide (this.table, way, cb);
}
});

View File

@ -106,15 +106,15 @@ module.exports = new Class
this.showNoRecordsFound ();
}
,onRowInsert: function (model, row)
,onRowInsert: function ()
{
this.buildRow (1);
}
,renderCell: function (row, column, tr)
{
if (column.columnIndex != -1)
column.value = this._model.data[row][column.columnIndex];
if (column.column != null)
column.value = this._model.data[row][column.column];
if (column.renderer)
{
@ -131,7 +131,7 @@ module.exports = new Class
var tr = this.tbody.childNodes[row];
for (var i = 0; i < x.length; i++)
if (x[i].renderer || columns.indexOf (x[i].columnIndex) != -1)
if (x[i].renderer || columns.indexOf (x[i].column) != -1)
{
var cell = this.renderCell (row, x[i], tr);
tr.replaceChild (cell, tr.childNodes[i]);
@ -203,7 +203,7 @@ module.exports = new Class
case Db.Model.Status.READY:
{
for (var i = 0; i < this.columns.length; i++)
this.columns[i].updateColumnIndex (this._model);
this.columns[i].updateColumnName (this._model);
this.buildRow (this._model.numRows);
this.showNoRecordsFound ();
@ -223,7 +223,7 @@ module.exports = new Class
this._node.appendChild (this.tbody);
}
,showNoRecordsFound: function (count)
,showNoRecordsFound: function ()
{
if (this._model.numRows == 0)
this.showMessage (_('EmptyList'), 'clean');
@ -277,28 +277,30 @@ module.exports = new Class
,sortModel: function (column)
{
var columnIndex = column.columnIndex;
var columnName = column.column;
if (this._model && columnIndex != -1)
if (this._model && columnName != -1)
{
if (this.sortColumn === columnIndex
&& this.sortWay === Db.Model.SortWay.ASC)
this.sortWay = Db.Model.SortWay.DESC;
else
this.sortWay = Db.Model.SortWay.ASC;
var SortWay = Db.Model.SortWay;
this.sortColumn = columnIndex;
if (this.sortColumn === columnName
&& this.sortWay === SortWay.ASC)
this.sortWay = SortWay.DESC;
else
this.sortWay = SortWay.ASC;
this.sortColumn = columnName;
this._model.sort (columnIndex, this.sortWay);
this._model.sort (columnName, this.sortWay);
}
}
,columnChanged: function (column, row, newValue)
{
var columnIndex = column.columnIndex;
var columnName = column.column;
if (columnIndex != -1)
this._model.setByIndex (row, columnIndex, newValue);
if (columnName != -1)
this._model.set (row, columnName, newValue);
}
,addColumn: function (pos, column)

View File

@ -203,43 +203,63 @@ td.cell-image .htk-image
width: 20em;
background-color: white;
border: none;
overflow: hidden;
}
.htk-calendar .month
{
background-color: #009688;
color: white;
height: 2.2em;
padding: .5em;
text-align: center;
line-height: 2.2em;
font-size: 1.4em;
}
.htk-calendar .month > .button
{
cursor: pointer;
height: 2.2em;
width: 2.2em;
text-align: center;
border-radius: 50%;
}
.htk-calendar .month > .button:hover
{
background-color: rgba(1, 1, 1, 0.2);
}
.htk-calendar .month > .button.previous
{
float:left;
}
.htk-calendar .month > .button.next
{
float:right;
}
.htk-calendar .wrapper
{
padding: .8em;
}
.htk-calendar table
{
border-collapse: collapse;
}
.htk-calendar thead tr,
.htk-calendar tfoot tr
.htk-calendar thead th
{
background-color: #009688;
color: white;
color: #666;
font-weight: normal;
vertical-align: middle;
text-align: center;
height: 3em;
}
.htk-calendar thead span
{
color: white;
}
.htk-calendar thead tr
{
vertical-align: middle;
text-align: center;
height: 3em;
border-bottom: none;
}
.htk-calendar tfoot tr
.htk-calendar .wdays > th
{
border-top: none;
font-weight: normal;
}
.htk-calendar th.button:hover
{
cursor: pointer;
background-color: rgba(1, 1, 1, 0.2);
}
.htk-calendar col
{
width: 14.2%;
}
.htk-calendar tr
.htk-calendar tbody tr
{
height: 2em;
}
@ -249,30 +269,29 @@ td.cell-image .htk-image
}
.htk-calendar tbody td > div
{
height: 2em;
width: 2em;
line-height: 2em;
height: 1.8em;
width: 1.8em;
line-height: 1.8em;
text-align: center;
border-radius: 2em;
padding: 0.3em;
margin: 0 auto;
color: #555;
}
.htk-calendar div.disabled
.htk-calendar tbody .disabled
{
color: #999;
}
.htk-calendar div.today
.htk-calendar tbody .today
{
font-weight: bold;
color: black;
}
.htk-calendar div.selected
.htk-calendar tbody .selected
{
color: white;
background-color: #009688;
}
.htk-calendar div.enabled:hover
.htk-calendar tbody .enabled:hover
{
cursor: pointer;
background-color: #008678;
@ -632,6 +651,25 @@ td.cell-image .htk-image
border-left-color: white;
}
/* Transitions */
.slide
{
transition: transform 100ms;
}
.slide-right
{
transform: translate3d(20em, 0, 0);
}
.slide-left
{
transform: translate3d(-20em, 0, 0);
}
.slide-return
{
transform: translate3d(0, 0, 0);
}
} /*+++++++++ Screen end */
@keyframes spinner

View File

@ -12,7 +12,7 @@ var objectAttrs = {
};
/**
* Compiles a @HTML.Node from element tag.
* Compiles a @HTMLElement from element tag.
*/
module.exports = new Class
({

View File

@ -1,7 +1,7 @@
var VnObject = require ('./object');
var regex = /{{[\w_]+(\.[\w_]+)?}}/g;
var regex = /{{\s*[\w_]+\s*(\.\s*[\w_]+\s*)?}}/g;
/**
* Replaces all ocurrences of {{value}} by it's corresponding value in the
@ -51,13 +51,13 @@ module.exports = new Class
if (match.length > 1)
{
lotId = match[0];
name = match[1];
lotId = match[0].trim ();
name = match[1].trim ();
}
else
{
lotId = null;
name = match[0];
name = match[0].trim ();
}
params.push ({

View File

@ -2,7 +2,7 @@
var Compiler = require ('./compiler');
/**
* Compiles a @HTML.TextNode from text node.
* Compiles a @Text from text node.
*/
module.exports = new Class
({

View File

@ -21,7 +21,7 @@
,"April": "April"
,"May": "May"
,"June": "June"
,"July": "June"
,"July": "July"
,"August": "August"
,"September": "September"
,"October": "October"

View File

@ -1,36 +1,10 @@
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
module.exports = new Class
({
Status: Status
,SortWay: SortWay
});
Klass.implement
({
Extends: VnObject
,Properties:
Properties:
{
/**
* The number of rows in the model.

412
js/vn/model.js Normal file
View File

@ -0,0 +1,412 @@
var VnObject = require ('./object');
// TODO: Remove this dependency
var Type = require ('db/connection').Type;
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
,Tag: 'vn-model'
,Properties:
{
/**
* The model internal data.
*/
data:
{
type: Array
,get: function ()
{
return this._data;
}
,set: function (x)
{
this._setData (x);
}
},
/**
* The number of rows in the model.
*/
numRows:
{
type: Number
,get: function ()
{
if (this._data)
return this._data.length;
return 0;
}
},
/**
* The current status of the model.
*/
status:
{
type: Number
,get: function ()
{
return this._status;
}
},
/**
* Checks if the model data is ready.
*/
ready:
{
type: Boolean
,get: function ()
{
return this._status === Status.READY;
}
}
}
,_data: null
,_status: Status.CLEAN
,_requestedSortName: null
,_sortColumn: null
,_sortWay: null
,_requestedIndexes: {}
,_indexes: []
//+++++++++++++++++++++++++++++ Data hadling
,_setData: function (data)
{
this._data = data;
this._refreshRowIndexes (0);
if (this._requestedSortName != null)
this._realSort (this._requestedSortName, this._sortWay);
for (column in this._requestedIndexes)
this._buildIndex (column);
this._setStatus (Status.READY);
}
/**
* Checks if the row exists.
*
* @param {Integer} rowIndex The row index
* @return {Boolean} %true if row exists, %false otherwise
*/
,checkRowExists: function (rowIndex)
{
return this._data != null
&& rowIndex >= 0
&& rowIndex < this._data.length;
}
/**
* Gets a value from the model.
*
* @param {Number} rowIndex The row index
* @param {Number} columnName The column name
* @return {*} The value
*/
,get: function (rowIndex, columnName)
{
if (!this.checkRowExists (rowIndex))
return undefined;
return this._data[rowIndex][columnName];
}
/**
* Updates a value on the model.
*
* @param {Number} rowIndex The row index
* @param {Number} columnName The column name
* @param {*} value The new value
*/
,set: function (rowIndex, columnName, value)
{
if (!this.checkRowExists (rowIndex))
return;
this.emit ('row-updated-before', rowIndex);
this._data[rowIndex][columnName] = value;
this.emit ('row-updated', rowIndex, [columnName]);
}
/**
* 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)
{
return this.checkRowExists (rowIndex) ?
this._data[rowIndex] : null;
}
,_setStatus: function (status)
{
this._status = status;
this.emit ('status-changed', status);
this.emit ('status-changed-after', status);
}
/**
* Inserts a new row on the model.
*
* @return The index of the inserted row
*/
,insertRow: function (newRow)
{
var rowIndex = this._data.push (newRow) - 1;
newRow.index = rowIndex;
this.emit ('row-inserted', rowIndex);
return rowIndex;
}
/**
* Deletes a row from the model.
*
* @param {Number} rowIndex The row index
*/
,deleteRow: function (rowIndex)
{
if (!this.checkRowExists (rowIndex))
return;
this.emit ('row-deleted-before', rowIndex);
this._data.splice (rowIndex, 1);
this.emit ('row-deleted', rowIndex);
this._refreshRowIndexes (rowIndex);
}
//+++++++++++++++++++++++++++++ Sorting
/**
* Orders the model by the specified column name.
*
* @param {String} columnName The column name
* @param {SortWay} way The sort way
*/
,sort: function (columnName, way)
{
this._requestedSortName = columnName;
this._sort (columnName, way);
}
,_sort: function (columnName, way)
{
this._setStatus (Status.LOADING);
this._realSort (columnName, way);
this._setStatus (Status.READY);
}
,_realSort: function (columnName, way)
{
if (columnName !== this._sortColumn)
{
if (way === SortWay.DESC)
var sortFunction = this.sortFunctionDesc;
else
var sortFunction = this.sortFunctionAsc;
this._data.sort (sortFunction.bind (this, columnName));
}
else if (way !== this._sortWay)
this._data.reverse ();
this._sortColumn = columnName;
this._sortWay = way;
this._refreshRowIndexes (0);
}
,_refreshRowIndexes: function (start)
{
var data = this._data;
for (var i = start; i < data.length; i++)
data[i].index = i;
}
/*
* Function used to sort the model ascending.
*/
,sortFunctionAsc: function (column, a, b)
{
if (a[column] < b[column])
return -1;
else if (a[column] > b[column])
return 1;
return 0;
}
/*
* Function used to sort the model descending.
*/
,sortFunctionDesc: function (column, a, b)
{
if (a[column] > b[column])
return -1;
else if (a[column] < b[column])
return 1;
return 0;
}
//+++++++++++++++++++++++++++++ Searching
/**
* 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 (column)
{
this._requestedIndexes[column] = true;
if (this._status === Status.READY)
this._buildIndex (column);
}
,getHashFunc: function (type)
{
switch (type)
{
case Type.TIMESTAMP:
case Type.DATE_TIME:
case Type.DATE:
return function (value) { return value.toString (); };
default:
return function (value) { return value; };
}
}
,_buildIndex: function (columnName)
{
if (this.columnMap[columnName] === undefined)
return;
var index = {};
var data = this._data;
var hashFunc = getHashFunc (this.columns[columnName].type);
for (var i = 0; i < data.length; i++)
index[hashFunc (data[i][columnName])] = i;
this._indexes[columnName] = index;
}
/**
* 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} columnIndex The column index
* @param {Object} value The value to search
* @return {Number} The column index
*/
,searchByIndex: function (columnIndex, value)
{
var columnName = this.columns[columnIndex].name;
return this.search (columnName, value);
}
/**
* Searchs a value on the model and returns the row index of the first
* ocurrence.
*
* @param {Number} columnName The column name
* @param {Object} value The value to search
* @return {Number} The column index
*/
,search: function (columnName, value)
{
var columnIndex = this.columnMap[columnName];
if (columnIndex === undefined)
return -1;
if (value)
switch (this.columns[columnIndex].type)
{
case Type.BOOLEAN:
value = !!value;
break;
case Type.INTEGER:
value = parseInt (value);
break;
case Type.DOUBLE:
value = parseFloat (value);
break;
default:
value = value.toString ();
}
// Searchs the value using an internal index.
var index = this._indexes[columnName];
if (index)
{
if (index[value] !== undefined)
return index[value];
return -1;
}
// Searchs the value using a loop.
var data = this._data;
switch (this.columns[columnIndex].type)
{
case Type.TIMESTAMP:
case Type.DATE_TIME:
case Type.DATE:
{
for (var i = 0; i < data.length; i++)
if (value === data[i][columnName].toString ())
return i;
break;
}
default:
for (var i = 0; i < data.length; i++)
if (value === data[i][columnName])
return i;
}
return -1;
}
});

76
js/vn/transitions.js Normal file
View File

@ -0,0 +1,76 @@
var VnNode = require ('./node');
var transition = checkTransitions ();
module.exports = {
transition: transition,
slide: slide
};
/**
* Checks for transition support.
*
* @return {String} The transition end event name, or %null if no support
*/
function checkTransitions ()
{
var el = document.createElement ('div');
var transitionEndNames = {
transition : 'transitionend'
,OTransition : 'oTransitionEnd'
,MozTransition : 'transitionend'
,WebkitTransition : 'webkitTransitionEnd'
};
for (var name in transitionEndNames)
if (el.style[name] !== undefined)
return transitionEndNames[name];
return null;
}
checkTransitions ();
/**
* Slides an element.
*
* @param {Node} node The element to slide
* @param {String} way The slide way: 'left' or 'right'
* @param {Function} cb The callback to call when transition ends
*/
function slide (node, way, cb)
{
if (transition === null)
{
if (cb) cb();
return;
}
var inverseWay = way == 'left' ? 'right' : 'left';
VnNode.addClass (node, 'slide slide-'+ way);
node.addEventListener (transition, slideStart);
function slideStart ()
{
node.removeEventListener (transition, slideStart);
VnNode.removeClass (node, 'slide');
VnNode.removeClass (node, 'slide-'+ way);
VnNode.addClass (node, 'slide-'+ inverseWay);
cb ();
setTimeout (slideReturn, 20);
}
function slideReturn ()
{
VnNode.addClass (node, 'slide');
VnNode.removeClass (node, 'slide-'+ inverseWay);
node.addEventListener (transition, slideEnd);
}
function slideEnd ()
{
node.removeEventListener (transition, slideEnd);
VnNode.removeClass (node, 'slide');
}
}