hedera-web/js/vn/model.js

413 lines
7.7 KiB
JavaScript
Raw Normal View History

2017-10-25 07:47:32 +00:00
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;
}
});