hedera-web/js/vn/model.js

392 lines
6.9 KiB
JavaScript

var VnObject = require ('./object');
var simpleEquals = require ('./value').simpleEquals;
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)
{
var status = this._status;
this._setStatus (Status.LOADING);
this._realSort (columnName, way);
this._setStatus (status);
}
,_realSort: function (columnName, way)
{
if (!this._data)
return;
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);
}
,getHashValue: function (value)
{
if (value instanceof Date)
return value.getTime();
else
return value;
}
,_buildIndex: function (columnName)
{
if (this.columnMap[columnName] === undefined)
return;
var data = this._data;
var values = {};
var nulls = [];
for (var i = 0; i < data.length; i++)
{
var value = data[i][columnName];
if (value == null)
{
nulls.push (data[i]);
continue;
}
index[this.getHashValue (value)] = data[i];
}
this._indexes[columnName] = {
values: values,
index: index
};
}
/**
* 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 data = this._data;
if (data == null)
return -1;
// Searchs the value using an internal index.
var index = this._indexes[columnName];
if (index)
{
if (value == null)
{
if (index.nulls[0] !== undefined)
return index.nulls[0].index;
}
else
{
var row = index.values[this.getHashValue (value)];
if (rowIndex !== undefined)
return row.index;
}
return -1;
}
// Searchs the value using a loop.
for (var i = 0; i < data.length; i++)
if (simpleEquals (data[i][columnName], value))
return i;
return -1;
}
//+++++++++++++++++++++++++++++ Virtual
,refresh: function ()
{
this._setStatus (Status.READY);
}
});