mirror of
http://git.whoc.org.uk/git/password-manager.git
synced 2025-10-25 01:37:34 +02:00
First version of the newly restructured repository
This commit is contained in:
226
frontend/beta/js/YUI-extensions/data/AbstractDataModel.js
Normal file
226
frontend/beta/js/YUI-extensions/data/AbstractDataModel.js
Normal file
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* @class YAHOO.ext.grid.AbstractDataModel
|
||||
* @extends YAHOO.ext.util.Observable
|
||||
* This abstract class provides default implementations of the events required by the Grid.
|
||||
It takes care of the creating the CustomEvents and provides some convenient methods for firing the events. <br><br>
|
||||
* @constructor
|
||||
*/
|
||||
YAHOO.ext.grid.AbstractDataModel = function(){
|
||||
/** Fires when a cell is updated - fireDirect sig: (this, rowIndex, columnIndex)
|
||||
* @private
|
||||
* @type YAHOO.util.CustomEvent
|
||||
* @deprecated Use addListener instead of accessing directly
|
||||
*/
|
||||
this.onCellUpdated = new YAHOO.util.CustomEvent('onCellUpdated');
|
||||
/** Fires when all data needs to be revalidated - fireDirect sig: (thisd)
|
||||
* @private
|
||||
* @type YAHOO.util.CustomEvent
|
||||
* @deprecated Use addListener instead of accessing directly
|
||||
*/
|
||||
this.onTableDataChanged = new YAHOO.util.CustomEvent('onTableDataChanged');
|
||||
/** Fires when rows are deleted - fireDirect sig: (this, firstRowIndex, lastRowIndex)
|
||||
* @private
|
||||
* @type YAHOO.util.CustomEvent
|
||||
* @deprecated Use addListener instead of accessing directly
|
||||
*/
|
||||
this.onRowsDeleted = new YAHOO.util.CustomEvent('onRowsDeleted');
|
||||
/** Fires when a rows are inserted - fireDirect sig: (this, firstRowIndex, lastRowIndex)
|
||||
* @private
|
||||
* @type YAHOO.util.CustomEvent
|
||||
* @deprecated Use addListener instead of accessing directly
|
||||
*/
|
||||
this.onRowsInserted = new YAHOO.util.CustomEvent('onRowsInserted');
|
||||
/** Fires when a rows are updated - fireDirect sig: (this, firstRowIndex, lastRowIndex)
|
||||
* @private
|
||||
* @type YAHOO.util.CustomEvent
|
||||
* @deprecated Use addListener instead of accessing directly
|
||||
*/
|
||||
this.onRowsUpdated = new YAHOO.util.CustomEvent('onRowsUpdated');
|
||||
/** Fires when a sort has reordered the rows - fireDirect sig: (this, sortColumnIndex,
|
||||
* @private
|
||||
* sortDirection = 'ASC' or 'DESC')
|
||||
* @type YAHOO.util.CustomEvent
|
||||
* @deprecated Use addListener instead of accessing directly
|
||||
*/
|
||||
this.onRowsSorted = new YAHOO.util.CustomEvent('onRowsSorted');
|
||||
|
||||
this.events = {
|
||||
/**
|
||||
* @event cellupdated
|
||||
* Fires when a cell is updated
|
||||
* @param {DataModel} this
|
||||
* @param {Number} rowIndex
|
||||
* @param {Number} columnIndex
|
||||
*/
|
||||
'cellupdated' : this.onCellUpdated,
|
||||
/**
|
||||
* @event datachanged
|
||||
* Fires when the entire data structure has changed
|
||||
* @param {DataModel} this
|
||||
*/
|
||||
'datachanged' : this.onTableDataChanged,
|
||||
/**
|
||||
* @event rowsdeleted
|
||||
* Fires when a range of rows have been deleted
|
||||
* @param {DataModel} this
|
||||
* @param {Number} firstRowIndex
|
||||
* @param {Number} lastRowIndex
|
||||
*/
|
||||
'rowsdeleted' : this.onRowsDeleted,
|
||||
/**
|
||||
* @event rowsinserted
|
||||
* Fires when a range of rows have been inserted
|
||||
* @param {DataModel} this
|
||||
* @param {Number} firstRowIndex
|
||||
* @param {Number} lastRowIndex
|
||||
*/
|
||||
'rowsinserted' : this.onRowsInserted,
|
||||
/**
|
||||
* @event rowsupdated
|
||||
* Fires when a range of rows have been updated
|
||||
* @param {DataModel} this
|
||||
* @param {Number} firstRowIndex
|
||||
* @param {Number} lastRowIndex
|
||||
*/
|
||||
'rowsupdated' : this.onRowsUpdated,
|
||||
/**
|
||||
* @event rowssorted
|
||||
* Fires when the data has been sorted
|
||||
* @param {DataModel} this
|
||||
*/
|
||||
'rowssorted' : this.onRowsSorted
|
||||
};
|
||||
};
|
||||
|
||||
YAHOO.ext.grid.AbstractDataModel.prototype = {
|
||||
|
||||
fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
|
||||
on : YAHOO.ext.util.Observable.prototype.on,
|
||||
addListener : YAHOO.ext.util.Observable.prototype.addListener,
|
||||
delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
|
||||
removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
|
||||
purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
|
||||
bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener,
|
||||
|
||||
/**
|
||||
* Notifies listeners that the value of the cell at [row, col] has been updated
|
||||
* @deprecated
|
||||
* @private
|
||||
*/
|
||||
fireCellUpdated : function(row, col){
|
||||
this.onCellUpdated.fireDirect(this, row, col);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies listeners that all data for the grid may have changed - use as a last resort. This
|
||||
* also wipes out all selections a user might have made.
|
||||
* @deprecated
|
||||
* @private
|
||||
*/
|
||||
fireTableDataChanged : function(){
|
||||
this.onTableDataChanged.fireDirect(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies listeners that rows in the range [firstRow, lastRow], inclusive, have been deleted
|
||||
* @deprecated
|
||||
* @private
|
||||
*/
|
||||
fireRowsDeleted : function(firstRow, lastRow){
|
||||
this.onRowsDeleted.fireDirect(this, firstRow, lastRow);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies listeners that rows in the range [firstRow, lastRow], inclusive, have been inserted
|
||||
* @deprecated
|
||||
* @private
|
||||
*/
|
||||
fireRowsInserted : function(firstRow, lastRow){
|
||||
this.onRowsInserted.fireDirect(this, firstRow, lastRow);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies listeners that rows in the range [firstRow, lastRow], inclusive, have been updated
|
||||
* @deprecated
|
||||
* @private
|
||||
*/
|
||||
fireRowsUpdated : function(firstRow, lastRow){
|
||||
this.onRowsUpdated.fireDirect(this, firstRow, lastRow);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies listeners that rows have been sorted and any indexes may be invalid
|
||||
* @deprecated
|
||||
* @private
|
||||
*/
|
||||
fireRowsSorted : function(sortColumnIndex, sortDir, noRefresh){
|
||||
this.onRowsSorted.fireDirect(this, sortColumnIndex, sortDir, noRefresh);
|
||||
},
|
||||
|
||||
/**
|
||||
* Empty interface method - Classes which extend AbstractDataModel should implement this method.
|
||||
* See {@link YAHOO.ext.DefaultDataModel#sort} for an example implementation.
|
||||
* @private
|
||||
*/
|
||||
sort : function(sortInfo, columnIndex, direction, suppressEvent){
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Interface method to supply info regarding the Grid's current sort state - if overridden,
|
||||
* this should return an object like this {column: this.sortColumn, direction: this.sortDir}.
|
||||
* @return {Object}
|
||||
*/
|
||||
getSortState : function(){
|
||||
return {column: this.sortColumn, direction: this.sortDir};
|
||||
},
|
||||
|
||||
/**
|
||||
* Empty interface method - Classes which extend AbstractDataModel should implement this method.
|
||||
* See {@link YAHOO.ext.DefaultDataModel} for an example implementation.
|
||||
* @private
|
||||
*/
|
||||
getRowCount : function(){
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Empty interface method - Classes which extend AbstractDataModel should implement this method to support virtual row counts.
|
||||
* @private
|
||||
*/
|
||||
getTotalRowCount : function(){
|
||||
return this.getRowCount();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Empty interface method - Classes which extend AbstractDataModel should implement this method.
|
||||
* See {@link YAHOO.ext.DefaultDataModel} for an example implementation.
|
||||
* @private
|
||||
*/
|
||||
getRowId : function(rowIndex){
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Empty interface method - Classes which extend AbstractDataModel should implement this method.
|
||||
* See {@link YAHOO.ext.DefaultDataModel} for an example implementation.
|
||||
* @private
|
||||
*/
|
||||
getValueAt : function(rowIndex, colIndex){
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Empty interface method - Classes which extend AbstractDataModel should implement this method.
|
||||
* See {@link YAHOO.ext.DefaultDataModel} for an example implementation.
|
||||
* @private
|
||||
*/
|
||||
setValueAt : function(value, rowIndex, colIndex){
|
||||
|
||||
},
|
||||
|
||||
isPaged : function(){
|
||||
return false;
|
||||
}
|
||||
};
|
||||
339
frontend/beta/js/YUI-extensions/data/DefaultDataModel.js
Normal file
339
frontend/beta/js/YUI-extensions/data/DefaultDataModel.js
Normal file
@@ -0,0 +1,339 @@
|
||||
|
||||
/**
|
||||
* @class YAHOO.ext.grid.DefaultDataModel
|
||||
* This is the default implementation of a DataModel used by the Grid. It works
|
||||
* with multi-dimensional array based data. Using the event system in the base class
|
||||
* {@link YAHOO.ext.grid.AbstractDataModel}, all updates to this DataModel are automatically
|
||||
* reflected in the user interface.
|
||||
* <br>Usage:<br>
|
||||
* <pre><code>
|
||||
* var myData = [
|
||||
["MSFT","Microsoft Corporation", "314,571.156", "32,187.000", "55000"],
|
||||
["ORCL", "Oracle Corporation", "62,615.266", "9,519.000", "40650"]
|
||||
* ];
|
||||
* var dataModel = new YAHOO.ext.grid.DefaultDataModel(myData);
|
||||
* </code></pre>
|
||||
* @extends YAHOO.ext.grid.AbstractDataModel
|
||||
* @constructor
|
||||
* @param {Array} data
|
||||
*/
|
||||
YAHOO.ext.grid.DefaultDataModel = function(data){
|
||||
YAHOO.ext.grid.DefaultDataModel.superclass.constructor.call(this);
|
||||
/**@private*/
|
||||
this.data = data;
|
||||
};
|
||||
YAHOO.extendX(YAHOO.ext.grid.DefaultDataModel, YAHOO.ext.grid.AbstractDataModel, {
|
||||
/**
|
||||
* Returns the number of rows in the dataset
|
||||
* @return {Number}
|
||||
*/
|
||||
getRowCount : function(){
|
||||
return this.data.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the ID of the specified row. By default it return the value of the first column.
|
||||
* Override to provide more advanced ID handling.
|
||||
* @return {Number}
|
||||
*/
|
||||
getRowId : function(rowIndex){
|
||||
return this.data[rowIndex][0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the column data for the specified row.
|
||||
* @return {Array}
|
||||
*/
|
||||
getRow : function(rowIndex){
|
||||
return this.data[rowIndex];
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the column data for the specified rows as a
|
||||
* multi-dimensional array: rows[3][0] would give you the value of row 4, column 0.
|
||||
* @param {Array} indexes The row indexes to fetch
|
||||
* @return {Array}
|
||||
*/
|
||||
getRows : function(indexes){
|
||||
var data = this.data;
|
||||
var r = [];
|
||||
for(var i = 0; i < indexes.length; i++){
|
||||
r.push(data[indexes[i]]);
|
||||
}
|
||||
return r;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the value at the specified data position
|
||||
* @param {Number} rowIndex
|
||||
* @param {Number} colIndex
|
||||
* @return {Object}
|
||||
*/
|
||||
getValueAt : function(rowIndex, colIndex){
|
||||
return this.data[rowIndex][colIndex];
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the specified value at the specified data position
|
||||
* @param {Object} value The new value
|
||||
* @param {Number} rowIndex
|
||||
* @param {Number} colIndex
|
||||
*/
|
||||
setValueAt: function(value, rowIndex, colIndex){
|
||||
this.data[rowIndex][colIndex] = value;
|
||||
this.fireCellUpdated(rowIndex, colIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Removes the specified range of rows.
|
||||
* @param {Number} startIndex
|
||||
* @param {<i>Number</i>} endIndex (optional) Defaults to startIndex
|
||||
*/
|
||||
removeRows: function(startIndex, endIndex){
|
||||
endIndex = endIndex || startIndex;
|
||||
this.data.splice(startIndex, endIndex-startIndex+1);
|
||||
this.fireRowsDeleted(startIndex, endIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a row.
|
||||
* @param {Number} index
|
||||
*/
|
||||
removeRow: function(index){
|
||||
this.data.splice(index, 1);
|
||||
this.fireRowsDeleted(index, index);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Removes all rows.
|
||||
*/
|
||||
removeAll: function(){
|
||||
var count = this.getRowCount();
|
||||
if(count > 0){
|
||||
this.removeRows(0, count-1);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Query the DataModel rows by the filters defined in spec, for example...
|
||||
* <pre><code>
|
||||
* // column 1 starts with Jack, column 2 filtered by myFcn, column 3 equals 'Fred'
|
||||
* dataModel.filter({1: /^Jack.+/i}, 2: myFcn, 3: 'Fred'});
|
||||
* </code></pre>
|
||||
* @param {Object} spec The spec is generally an object literal consisting of
|
||||
* column index and filter type. The filter type can be a string/number (exact match),
|
||||
* a regular expression to test using String.search() or a function to call. If it's a function,
|
||||
* it will be called with the value for the specified column and an array of the all column
|
||||
* values for that row: yourFcn(value, columnData). If it returns anything other than true,
|
||||
* the row is not a match. If you have modified Object.prototype this method may fail.
|
||||
* @param {Boolean} returnUnmatched True to return rows which <b>don't</b> match the query instead
|
||||
* of rows that do match
|
||||
* @return {Array} An array of row indexes that match
|
||||
*/
|
||||
query: function(spec, returnUnmatched){
|
||||
var d = this.data;
|
||||
var r = [];
|
||||
for(var i = 0; i < d.length; i++){
|
||||
var row = d[i];
|
||||
var isMatch = true;
|
||||
for(var col in spec){
|
||||
//if(typeof spec[col] != 'function'){
|
||||
if(!isMatch) continue;
|
||||
var filter = spec[col];
|
||||
switch(typeof filter){
|
||||
case 'string':
|
||||
case 'number':
|
||||
case 'boolean':
|
||||
if(row[col] != filter){
|
||||
isMatch = false;
|
||||
}
|
||||
break;
|
||||
case 'function':
|
||||
if(!filter(row[col], row)){
|
||||
isMatch = false;
|
||||
}
|
||||
break;
|
||||
case 'object':
|
||||
if(filter instanceof RegExp){
|
||||
if(String(row[col]).search(filter) === -1){
|
||||
isMatch = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
//}
|
||||
}
|
||||
if(isMatch && !returnUnmatched){
|
||||
r.push(i);
|
||||
}else if(!isMatch && returnUnmatched){
|
||||
r.push(i);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter the DataModel rows by the query defined in spec, see {@link #query} for more details
|
||||
* on the query spec.
|
||||
* @param {Object} query The query spec {@link #query}
|
||||
* @return {Number} The number of rows removed
|
||||
*/
|
||||
filter: function(query){
|
||||
var matches = this.query(query, true);
|
||||
var data = this.data;
|
||||
// go thru the data setting matches to deleted
|
||||
// while not disturbing row indexes
|
||||
for(var i = 0; i < matches.length; i++){
|
||||
data[matches[i]]._deleted = true;
|
||||
}
|
||||
for(var i = 0; i < data.length; i++){
|
||||
while(data[i] && data[i]._deleted === true){
|
||||
this.removeRow(i);
|
||||
}
|
||||
}
|
||||
return matches.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a row to the dataset.
|
||||
* @param {Array} cellValues The array of values for the new row
|
||||
* @return {Number} The index of the added row
|
||||
*/
|
||||
addRow: function(cellValues){
|
||||
this.data.push(cellValues);
|
||||
var newIndex = this.data.length-1;
|
||||
this.fireRowsInserted(newIndex, newIndex);
|
||||
this.applySort();
|
||||
return newIndex;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Adds a set of rows.
|
||||
* @param {Array} rowData This should be an array of arrays like the constructor takes
|
||||
*/
|
||||
addRows: function(rowData){
|
||||
this.data = this.data.concat(rowData);
|
||||
var firstIndex = this.data.length-rowData.length;
|
||||
this.fireRowsInserted(firstIndex, firstIndex+rowData.length-1);
|
||||
this.applySort();
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a row a the specified location in the dataset.
|
||||
* @param {Number} index The index where the row should be inserted
|
||||
* @param {Array} cellValues The array of values for the new row
|
||||
* @return {Number} The index the row was inserted in
|
||||
*/
|
||||
insertRow: function(index, cellValues){
|
||||
this.data.splice(index, 0, cellValues);
|
||||
this.fireRowsInserted(index, index);
|
||||
this.applySort();
|
||||
return index;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Inserts a set of rows.
|
||||
* @param {Number} index The index where the rows should be inserted
|
||||
* @param {Array} rowData This should be an array of arrays like the constructor takes
|
||||
*/
|
||||
insertRows: function(index, rowData){
|
||||
/*
|
||||
if(index == this.data.length){ // try these two first since they are faster
|
||||
this.data = this.data.concat(rowData);
|
||||
}else if(index == 0){
|
||||
this.data = rowData.concat(this.data);
|
||||
}else{
|
||||
var newData = this.data.slice(0, index);
|
||||
newData.concat(rowData);
|
||||
newData.concat(this.data.slice(index));
|
||||
this.data = newData;
|
||||
}*/
|
||||
var args = rowData.concat();
|
||||
args.splice(0, 0, index, 0);
|
||||
this.data.splice.apply(this.data, args);
|
||||
this.fireRowsInserted(index, index+rowData.length-1);
|
||||
this.applySort();
|
||||
},
|
||||
|
||||
/**
|
||||
* Applies the last used sort to the current data.
|
||||
*/
|
||||
applySort: function(suppressEvent){
|
||||
if(typeof this.sortColumn != 'undefined'){
|
||||
this.sort(this.sortInfo, this.sortColumn, this.sortDir, suppressEvent);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the default sort info. Note: this function does not actually apply the sort.
|
||||
* @param {Function/Object} sortInfo A sort comparison function or null to use the default or A object that has a method getSortType(index) that returns a function like
|
||||
* a grid column model.
|
||||
* @param {Number} columnIndex The column index to sort by
|
||||
* @param {String} direction The direction of the sort ('DESC' or 'ASC')
|
||||
*/
|
||||
setDefaultSort: function(sortInfo, columnIndex, direction){
|
||||
this.sortInfo = sortInfo;
|
||||
this.sortColumn = columnIndex;
|
||||
this.sortDir = direction;
|
||||
},
|
||||
/**
|
||||
* Sorts the data by the specified column - Uses the sortType specified for the column in the passed columnModel.
|
||||
* @param {Function/Object} sortInfo A sort comparison function or null to use the default or A object that has a method getSortType(index) that returns a function like
|
||||
* a grid column model.
|
||||
* @param {Number} columnIndex The column index to sort by
|
||||
* @param {String} direction The direction of the sort ('DESC' or 'ASC')
|
||||
*/
|
||||
sort: function(sortInfo, columnIndex, direction, suppressEvent){
|
||||
// store these so we can maintain sorting when we load new data
|
||||
this.sortInfo = sortInfo;
|
||||
this.sortColumn = columnIndex;
|
||||
this.sortDir = direction;
|
||||
|
||||
var dsc = (direction && direction.toUpperCase() == 'DESC');
|
||||
var sortType = null;
|
||||
if(sortInfo != null){
|
||||
if(typeof sortInfo == 'function'){
|
||||
sortType = sortInfo;
|
||||
}else if(typeof sortInfo == 'object'){
|
||||
sortType = sortInfo.getSortType(columnIndex);;
|
||||
}
|
||||
}
|
||||
var fn = function(cells, cells2){
|
||||
var v1 = sortType ? sortType(cells[columnIndex], cells) : cells[columnIndex];
|
||||
var v2 = sortType ? sortType(cells2[columnIndex], cells2) : cells2[columnIndex];
|
||||
if(v1 < v2)
|
||||
return dsc ? +1 : -1;
|
||||
if(v1 > v2)
|
||||
return dsc ? -1 : +1;
|
||||
return 0;
|
||||
};
|
||||
this.data.sort(fn);
|
||||
if(!suppressEvent){
|
||||
this.fireRowsSorted(columnIndex, direction);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls passed function with each rows data - if the function returns false it stops.
|
||||
* @param {Function} fn
|
||||
* @param {Object} scope (optional)
|
||||
*/
|
||||
each: function(fn, scope){
|
||||
var d = this.data;
|
||||
for(var i = 0, len = d.length; i < len; i++){
|
||||
if(fn.call(scope || window, d[i], i) === false) break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Alias to YAHOO.ext.grid.DefaultColumnModel.sortTypes
|
||||
* @static
|
||||
*/
|
||||
if(YAHOO.ext.grid.DefaultColumnModel){
|
||||
YAHOO.ext.grid.DefaultDataModel.sortTypes = YAHOO.ext.grid.DefaultColumnModel.sortTypes;
|
||||
}
|
||||
81
frontend/beta/js/YUI-extensions/data/JSONDataModel.js
Normal file
81
frontend/beta/js/YUI-extensions/data/JSONDataModel.js
Normal file
@@ -0,0 +1,81 @@
|
||||
|
||||
/**
|
||||
* @class YAHOO.ext.grid.JSONDataModel
|
||||
* This is an implementation of a DataModel used by the Grid. It works
|
||||
* with JSON data.
|
||||
* <br>Example schema:
|
||||
* <pre><code>
|
||||
* var schema = {
|
||||
* root: 'Results.Result',
|
||||
* id: 'ASIN',
|
||||
* fields: ['Author', 'Title', 'Manufacturer', 'ProductGroup']
|
||||
* };
|
||||
* </code></pre>
|
||||
* @extends YAHOO.ext.grid.LoadableDataModel
|
||||
* @constructor
|
||||
*/
|
||||
YAHOO.ext.grid.JSONDataModel = function(schema){
|
||||
YAHOO.ext.grid.JSONDataModel.superclass.constructor.call(this, YAHOO.ext.grid.LoadableDataModel.JSON);
|
||||
/**@private*/
|
||||
this.schema = schema;
|
||||
};
|
||||
YAHOO.extendX(YAHOO.ext.grid.JSONDataModel, YAHOO.ext.grid.LoadableDataModel, {
|
||||
/**
|
||||
* Overrides loadData in LoadableDataModel to process JSON data
|
||||
* @param {Object} data The JSON object to load
|
||||
* @param {Function} callback
|
||||
*/
|
||||
loadData : function(data, callback, keepExisting){
|
||||
var idField = this.schema.id;
|
||||
var fields = this.schema.fields;
|
||||
try{
|
||||
if(this.schema.totalProperty){
|
||||
var v = parseInt(eval('data.' + this.schema.totalProperty), 10);
|
||||
if(!isNaN(v)){
|
||||
this.totalCount = v;
|
||||
}
|
||||
}
|
||||
var rowData = [];
|
||||
var root = eval('data.' + this.schema.root);
|
||||
for(var i = 0; i < root.length; i++){
|
||||
var node = root[i];
|
||||
var colData = [];
|
||||
colData.node = node;
|
||||
colData.id = (typeof node[idField] != 'undefined' && node[idField] !== '' ? node[idField] : String(i));
|
||||
for(var j = 0; j < fields.length; j++) {
|
||||
var val = node[fields[j]];
|
||||
if(typeof val == 'undefined'){
|
||||
val = '';
|
||||
}
|
||||
if(this.preprocessors[j]){
|
||||
val = this.preprocessors[j](val);
|
||||
}
|
||||
colData.push(val);
|
||||
}
|
||||
rowData.push(colData);
|
||||
}
|
||||
if(keepExisting !== true){
|
||||
this.removeAll();
|
||||
}
|
||||
this.addRows(rowData);
|
||||
if(typeof callback == 'function'){
|
||||
callback(this, true);
|
||||
}
|
||||
this.fireLoadEvent();
|
||||
}catch(e){
|
||||
this.fireLoadException(e, null);
|
||||
if(typeof callback == 'function'){
|
||||
callback(this, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides getRowId in DefaultDataModel to return the ID value of the specified node.
|
||||
* @param {Number} rowIndex
|
||||
* @return {Number}
|
||||
*/
|
||||
getRowId : function(rowIndex){
|
||||
return this.data[rowIndex].id;
|
||||
}
|
||||
});
|
||||
330
frontend/beta/js/YUI-extensions/data/LoadableDataModel.js
Normal file
330
frontend/beta/js/YUI-extensions/data/LoadableDataModel.js
Normal file
@@ -0,0 +1,330 @@
|
||||
/**
|
||||
* @class YAHOO.ext.grid.LoadableDataModel
|
||||
* This class extends DefaultDataModel and adds the core functionality to load data remotely. Generally you will want to use one of it's subclasses.<br><br>
|
||||
* @extends YAHOO.ext.grid.DefaultDataModel
|
||||
* @constructor
|
||||
* @param {String} dataType YAHOO.ext.grid.LoadableDataModel.XML, YAHOO.ext.grid.LoadableDataModel.TEXT or YAHOO.ext.grid.JSON
|
||||
*/
|
||||
YAHOO.ext.grid.LoadableDataModel = function(dataType){
|
||||
YAHOO.ext.grid.LoadableDataModel.superclass.constructor.call(this, []);
|
||||
|
||||
/** Fires when a successful load is completed - fireDirect sig: (this)
|
||||
* @type YAHOO.util.CustomEvent
|
||||
* @deprecated Use addListener instead of accessing directly
|
||||
* @private
|
||||
*/
|
||||
this.onLoad = new YAHOO.util.CustomEvent('load');
|
||||
/** Fires when a load fails - fireDirect sig: (this, errorMsg, responseObj)
|
||||
* @type YAHOO.util.CustomEvent
|
||||
* @deprecated Use addListener instead of accessing directly
|
||||
* @private
|
||||
*/
|
||||
this.onLoadException = new YAHOO.util.CustomEvent('loadException');
|
||||
/**
|
||||
* @event load
|
||||
* Fires when new data has successfully been loaded
|
||||
* @param {DataModel} this
|
||||
*/
|
||||
this.events['load'] = this.onLoad;
|
||||
/**
|
||||
* @event beforeload
|
||||
* Fires before a load takes place
|
||||
* @param {DataModel} this
|
||||
*/
|
||||
this.events['beforeload'] = new YAHOO.util.CustomEvent('beforeload');
|
||||
/**
|
||||
* @event loadexception
|
||||
* Fires when there's an error loading data
|
||||
* @param {DataModel} this
|
||||
* @param {Exception} e The exception object or null
|
||||
* @param {Object} response The Connect response object
|
||||
*/
|
||||
this.events['loadexception'] = this.onLoadException;
|
||||
|
||||
/**@private*/
|
||||
this.dataType = dataType;
|
||||
/**@private*/
|
||||
this.preprocessors = [];
|
||||
/**@private*/
|
||||
this.postprocessors = [];
|
||||
|
||||
// paging info
|
||||
/** The active page @type Number*/
|
||||
this.loadedPage = 1;
|
||||
/** True to use remote sorting, initPaging automatically sets this to true @type Boolean */
|
||||
this.remoteSort = false;
|
||||
/** The number of records per page @type Number*/
|
||||
this.pageSize = 0;
|
||||
/** The script/page to call to provide paged/sorted data @type String*/
|
||||
this.pageUrl = null;
|
||||
/** An object of key/value pairs to be passed as parameters
|
||||
* when loading pages/sorting @type Object*/
|
||||
this.baseParams = {};
|
||||
/** Maps named params to url parameters - Override to specify your own param names */
|
||||
this.paramMap = {'page':'page', 'pageSize':'pageSize', 'sortColumn':'sortColumn', 'sortDir':'sortDir'};
|
||||
|
||||
};
|
||||
YAHOO.extendX(YAHOO.ext.grid.LoadableDataModel, YAHOO.ext.grid.DefaultDataModel, {
|
||||
|
||||
/** @ignore */
|
||||
setLoadedPage: function(pageNum, userCallback){
|
||||
this.loadedPage = pageNum;
|
||||
if(typeof userCallback == 'function'){
|
||||
userCallback();
|
||||
}
|
||||
},
|
||||
|
||||
/** Returns true if this model uses paging @return Boolean */
|
||||
isPaged: function(){
|
||||
return this.pageSize > 0;
|
||||
},
|
||||
|
||||
/** Returns the total number of records available, override if needed @return {Number} */
|
||||
getTotalRowCount: function(){
|
||||
return this.totalCount || this.getRowCount();
|
||||
},
|
||||
|
||||
/** Returns the number of records per page @return Number */
|
||||
getPageSize: function(){
|
||||
return this.pageSize;
|
||||
},
|
||||
|
||||
/** Returns the total number of pages available @return Number */
|
||||
getTotalPages: function(){
|
||||
if(this.getPageSize() == 0 || this.getTotalRowCount() == 0){
|
||||
return 1;
|
||||
}
|
||||
return Math.ceil(this.getTotalRowCount()/this.getPageSize());
|
||||
},
|
||||
|
||||
/** Initializes paging for this model.
|
||||
* @param {String} url
|
||||
* @param {Number} pageSize
|
||||
* @param {Object} baseParams (optional) Object containing key/value pairs to add to all requests
|
||||
*/
|
||||
initPaging: function(url, pageSize, baseParams){
|
||||
this.pageUrl = url;
|
||||
this.pageSize = pageSize;
|
||||
this.remoteSort = true;
|
||||
if(baseParams) this.baseParams = baseParams;
|
||||
},
|
||||
|
||||
/** @ignore */
|
||||
createParams: function(pageNum, sortColumn, sortDir){
|
||||
var params = {}, map = this.paramMap;
|
||||
for(var key in this.baseParams){
|
||||
if(typeof this.baseParams[key] != 'function'){
|
||||
params[key] = this.baseParams[key];
|
||||
}
|
||||
}
|
||||
params[map['page']] = pageNum;
|
||||
params[map['pageSize']] = this.getPageSize();
|
||||
params[map['sortColumn']] = (typeof sortColumn == 'undefined' ? '' : sortColumn);
|
||||
params[map['sortDir']] = sortDir || '';
|
||||
return params;
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads a page of data.
|
||||
* @param {Number} pageNum Which page to load. The first page is 1.
|
||||
* @param {Function} callback (optional) Optional callback when loading is complete
|
||||
* @param {Boolean} keepExisting (optional) true to keep existing data and append the new data
|
||||
*/
|
||||
loadPage: function(pageNum, callback, keepExisting){
|
||||
var sort = this.getSortState();
|
||||
var params = this.createParams(pageNum, sort.column, sort.direction);
|
||||
this.load(this.pageUrl, params, this.setLoadedPage.createDelegate(this, [pageNum, callback]),
|
||||
keepExisting ? (pageNum-1) * this.pageSize : null);
|
||||
},
|
||||
|
||||
/** @ignore */
|
||||
applySort: function(suppressEvent){
|
||||
if(!this.remoteSort){
|
||||
YAHOO.ext.grid.LoadableDataModel.superclass.applySort.apply(this, arguments);
|
||||
}else if(!suppressEvent){
|
||||
var sort = this.getSortState();
|
||||
if(sort.column){
|
||||
this.fireRowsSorted(sort.column, sort.direction, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** @ignore */
|
||||
resetPaging: function(){
|
||||
this.loadedPage = 1;
|
||||
},
|
||||
|
||||
/* Overridden sort method to use remote sorting if turned on */
|
||||
sort: function(sortInfo, columnIndex, direction, suppressEvent){
|
||||
if(!this.remoteSort){
|
||||
YAHOO.ext.grid.LoadableDataModel.superclass.sort.apply(this, arguments);
|
||||
}else{
|
||||
this.sortInfo = sortInfo;
|
||||
this.sortColumn = columnIndex;
|
||||
this.sortDir = direction;
|
||||
var params = this.createParams(this.loadedPage, columnIndex, direction);
|
||||
this.load(this.pageUrl, params, this.fireRowsSorted.createDelegate(this, [columnIndex, direction, true]));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initiates the loading of the data from the specified URL - Failed load attempts will
|
||||
* fire the {@link #loadexception} event.
|
||||
* @param {Object/String} url The url from which the data can be loaded
|
||||
* @param {<i>String/Object</i>} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or as an object {param1: 1, param2: 2}
|
||||
* @param {<i>Function</i>} callback (optional) Callback when load is complete - called with signature (this, true for success, false for failure)
|
||||
* @param {<i>Number</i>} insertIndex (optional) if present, loaded data is inserted at the specified index instead of overwriting existing data
|
||||
*/
|
||||
load: function(url, params, callback, insertIndex){
|
||||
this.fireEvent('beforeload', this);
|
||||
if(params && typeof params != 'string'){ // must be object
|
||||
var buf = [];
|
||||
for(var key in params){
|
||||
if(typeof params[key] != 'function'){
|
||||
buf.push(encodeURIComponent(key), '=', encodeURIComponent(params[key]), '&');
|
||||
}
|
||||
}
|
||||
delete buf[buf.length-1];
|
||||
params = buf.join('');
|
||||
}
|
||||
var cb = {
|
||||
success: this.processResponse,
|
||||
failure: this.processException,
|
||||
scope: this,
|
||||
argument: {callback: callback, insertIndex: insertIndex}
|
||||
};
|
||||
var method = params ? 'POST' : 'GET';
|
||||
this.transId = YAHOO.util.Connect.asyncRequest(method, url, cb, params);
|
||||
},
|
||||
|
||||
/**@private*/
|
||||
processResponse: function(response){
|
||||
var cb = response.argument.callback;
|
||||
var keepExisting = (typeof response.argument.insertIndex == 'number');
|
||||
var insertIndex = response.argument.insertIndex;
|
||||
switch(this.dataType){
|
||||
case YAHOO.ext.grid.LoadableDataModel.XML:
|
||||
this.loadData(response.responseXML, cb, keepExisting, insertIndex);
|
||||
break;
|
||||
case YAHOO.ext.grid.LoadableDataModel.JSON:
|
||||
var rtext = response.responseText;
|
||||
try { // this code is a modified version of Yahoo! UI DataSource JSON parsing
|
||||
// Trim leading spaces
|
||||
while(rtext.substring(0,1) == " ") {
|
||||
rtext = rtext.substring(1, rtext.length);
|
||||
}
|
||||
// Invalid JSON response
|
||||
if(rtext.indexOf("{") < 0) {
|
||||
throw "Invalid JSON response";
|
||||
}
|
||||
|
||||
// Empty (but not invalid) JSON response
|
||||
if(rtext.indexOf("{}") === 0) {
|
||||
this.loadData({}, response.argument.callback);
|
||||
return;
|
||||
}
|
||||
|
||||
// Turn the string into an object literal...
|
||||
// ...eval is necessary here
|
||||
var jsonObjRaw = eval("(" + rtext + ")");
|
||||
if(!jsonObjRaw) {
|
||||
throw "Error evaling JSON response";
|
||||
}
|
||||
this.loadData(jsonObjRaw, cb, keepExisting, insertIndex);
|
||||
} catch(e) {
|
||||
this.fireLoadException(e, response);
|
||||
if(typeof cb == 'function'){
|
||||
cb(this, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YAHOO.ext.grid.LoadableDataModel.TEXT:
|
||||
this.loadData(response.responseText, cb, keepExisting, insertIndex);
|
||||
break;
|
||||
};
|
||||
},
|
||||
|
||||
/**@private*/
|
||||
processException: function(response){
|
||||
this.fireLoadException(null, response);
|
||||
if(typeof response.argument.callback == 'function'){
|
||||
response.argument.callback(this, false);
|
||||
}
|
||||
},
|
||||
|
||||
fireLoadException: function(e, responseObj){
|
||||
this.onLoadException.fireDirect(this, e, responseObj);
|
||||
},
|
||||
|
||||
fireLoadEvent: function(){
|
||||
this.fireEvent('load', this.loadedPage, this.getTotalPages());
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a preprocessor function to parse data before it is added to the Model - ie. Date.parse to parse dates.
|
||||
* @param {Number} columnIndex
|
||||
* @param {Function} fn
|
||||
*/
|
||||
addPreprocessor: function(columnIndex, fn){
|
||||
this.preprocessors[columnIndex] = fn;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the preprocessor function for the specified column.
|
||||
* @param {Number} columnIndex
|
||||
* @return {Function}
|
||||
*/
|
||||
getPreprocessor: function(columnIndex){
|
||||
return this.preprocessors[columnIndex];
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a preprocessor function.
|
||||
* @param {Number} columnIndex
|
||||
*/
|
||||
removePreprocessor: function(columnIndex){
|
||||
this.preprocessors[columnIndex] = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a postprocessor function to format data before updating the underlying data source (ie. convert date to string before updating XML document).
|
||||
* @param {Number} columnIndex
|
||||
* @param {Function} fn
|
||||
*/
|
||||
addPostprocessor: function(columnIndex, fn){
|
||||
this.postprocessors[columnIndex] = fn;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the postprocessor function for the specified column.
|
||||
* @param {Number} columnIndex
|
||||
* @return {Function}
|
||||
*/
|
||||
getPostprocessor: function(columnIndex){
|
||||
return this.postprocessors[columnIndex];
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a postprocessor function.
|
||||
* @param {Number} columnIndex
|
||||
*/
|
||||
removePostprocessor: function(columnIndex){
|
||||
this.postprocessors[columnIndex] = null;
|
||||
},
|
||||
/**
|
||||
* Empty interface method - Called to process the data returned by the XHR - Classes which extend LoadableDataModel should implement this method.
|
||||
* See {@link YAHOO.ext.XMLDataModel} for an example implementation.
|
||||
*/
|
||||
loadData: function(data, callback, keepExisting, insertIndex){
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
YAHOO.ext.grid.LoadableDataModel.XML = 'xml';
|
||||
YAHOO.ext.grid.LoadableDataModel.JSON = 'json';
|
||||
YAHOO.ext.grid.LoadableDataModel.TEXT = 'text';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
412
frontend/beta/js/YUI-extensions/data/Tree.js
Normal file
412
frontend/beta/js/YUI-extensions/data/Tree.js
Normal file
@@ -0,0 +1,412 @@
|
||||
YAHOO.namespace('ext.data');
|
||||
|
||||
/**
|
||||
* @class YAHOO.ext.data.Tree
|
||||
* @extends YAHOO.ext.util.Observable
|
||||
* The class represents a tree data structure and bubbles all the events for it's nodes. The nodes
|
||||
* in the tree have most standard DOM functionality.
|
||||
* @constructor
|
||||
* @param {Node} root (optional) The root node
|
||||
*/
|
||||
YAHOO.ext.data.Tree = function(root){
|
||||
this.nodeHash = {};
|
||||
this.root = null;
|
||||
if(root){
|
||||
this.setRootNode(root);
|
||||
}
|
||||
this.events = {
|
||||
'append' : true,
|
||||
'remove' : true,
|
||||
'move' : true,
|
||||
'insert' : true,
|
||||
'beforeappend' : true,
|
||||
'beforeremove' : true,
|
||||
'beforemove' : true,
|
||||
'beforeinsert' : true
|
||||
};
|
||||
};
|
||||
|
||||
YAHOO.extendX(YAHOO.ext.data.Tree, YAHOO.ext.util.Observable, {
|
||||
pathSeparator: '/',
|
||||
|
||||
getRootNode : function(){
|
||||
return this.root;
|
||||
},
|
||||
|
||||
setRootNode : function(node){
|
||||
this.root = node;
|
||||
node.ownerTree = this;
|
||||
node.isRoot = true;
|
||||
return node;
|
||||
},
|
||||
|
||||
getNodeById : function(id){
|
||||
return this.nodeHash[id];
|
||||
},
|
||||
|
||||
registerNode : function(node){
|
||||
this.nodeHash[node.id] = node;
|
||||
},
|
||||
|
||||
unregisterNode : function(node){
|
||||
delete this.nodeHash[node.id];
|
||||
},
|
||||
|
||||
toString : function(){
|
||||
return '[Tree'+(this.id?' '+this.id:'')+']';
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @class YAHOO.ext.tree.Node
|
||||
* @extends YAHOO.ext.util.Observable
|
||||
* @cfg {String} text The text for this node
|
||||
* @cfg {String} id The id for this node
|
||||
* @constructor
|
||||
* @param {Object} attributes The attributes/config for the node
|
||||
*/
|
||||
YAHOO.ext.data.Node = function(attributes){
|
||||
this.attributes = attributes || {};
|
||||
this.leaf = this.attributes.leaf;
|
||||
this.id = this.attributes.id;
|
||||
if(!this.id){
|
||||
this.id = YAHOO.util.Dom.generateId(null, 'ynode-');
|
||||
this.attributes.id = this.id;
|
||||
}
|
||||
|
||||
this.childNodes = [];
|
||||
if(!this.childNodes.indexOf){ // indexOf is a must
|
||||
this.childNodes.indexOf = function(o){
|
||||
for(var i = 0, len = this.length; i < len; i++){
|
||||
if(this[i] == o) return i;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
this.parentNode = null;
|
||||
this.firstChild = null;
|
||||
this.lastChild = null;
|
||||
this.previousSibling = null;
|
||||
this.nextSibling = null;
|
||||
|
||||
this.events = {
|
||||
'append' : true,
|
||||
'remove' : true,
|
||||
'move' : true,
|
||||
'insert' : true,
|
||||
'beforeappend' : true,
|
||||
'beforeremove' : true,
|
||||
'beforemove' : true,
|
||||
'beforeinsert' : true
|
||||
};
|
||||
};
|
||||
|
||||
YAHOO.extendX(YAHOO.ext.data.Node, YAHOO.ext.util.Observable, {
|
||||
fireEvent : function(evtName){
|
||||
// first do standard event for this node
|
||||
if(YAHOO.ext.data.Node.superclass.fireEvent.apply(this, arguments) === false){
|
||||
return false;
|
||||
}
|
||||
// then bubble it up to the tree if the event wasn't cancelled
|
||||
if(this.ownerTree){
|
||||
if(this.ownerTree.fireEvent.apply(this.ownerTree, arguments) === false){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
isLeaf : function(){
|
||||
return this.leaf === true;
|
||||
},
|
||||
|
||||
setFirstChild : function(node){
|
||||
this.firstChild = node;
|
||||
},
|
||||
|
||||
setLastChild : function(node){
|
||||
this.lastChild = node;
|
||||
},
|
||||
|
||||
isLast : function(){
|
||||
return (!this.parentNode ? true : this.parentNode.lastChild == this);
|
||||
},
|
||||
|
||||
isFirst : function(){
|
||||
return (!this.parentNode ? true : this.parentNode.firstChild == this);
|
||||
},
|
||||
|
||||
hasChildNodes : function(){
|
||||
return !this.isLeaf() && this.childNodes.length > 0;
|
||||
},
|
||||
|
||||
appendChild : function(node){
|
||||
var multi = false;
|
||||
if(node instanceof Array){
|
||||
multi = node;
|
||||
}else if(arguments.length > 1){
|
||||
multi = arguments;
|
||||
}
|
||||
// if passed an array or multiple args do them one by one
|
||||
if(multi){
|
||||
for(var i = 0, len = multi.length; i < len; i++) {
|
||||
this.appendChild(multi[i]);
|
||||
}
|
||||
}else{
|
||||
if(this.fireEvent('beforeappend', this.ownerTree, this, node) === false){
|
||||
return false;
|
||||
}
|
||||
var index = this.childNodes.length;
|
||||
var oldParent = node.parentNode;
|
||||
// it's a move, make sure we move it cleanly
|
||||
if(oldParent){
|
||||
if(node.fireEvent('beforemove', node.getOwnerTree(), node, oldParent, this, index) === false){
|
||||
return false;
|
||||
}
|
||||
oldParent.removeChild(node);
|
||||
}
|
||||
var index = this.childNodes.length;
|
||||
if(index == 0){
|
||||
this.setFirstChild(node);
|
||||
}
|
||||
this.childNodes.push(node);
|
||||
node.parentNode = this;
|
||||
var ps = this.childNodes[index-1];
|
||||
if(ps){
|
||||
node.previousSibling = ps;
|
||||
ps.nextSibling = node;
|
||||
}
|
||||
this.setLastChild(node);
|
||||
node.setOwnerTree(this.getOwnerTree());
|
||||
this.fireEvent('append', this.ownerTree, this, node, index);
|
||||
if(oldParent){
|
||||
node.fireEvent('move', this.ownerTree, node, oldParent, this, index);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
},
|
||||
|
||||
removeChild : function(node){
|
||||
var index = this.childNodes.indexOf(node);
|
||||
if(index == -1){
|
||||
return false;
|
||||
}
|
||||
if(this.fireEvent('beforeremove', this.ownerTree, this, node) === false){
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove it from childNodes collection
|
||||
this.childNodes.splice(index, 1);
|
||||
|
||||
// update siblings
|
||||
if(node.previousSibling){
|
||||
node.previousSibling.nextSibling = node.nextSibling;
|
||||
}
|
||||
if(node.nextSibling){
|
||||
node.nextSibling.previousSibling = node.previousSibling;
|
||||
}
|
||||
|
||||
// update child refs
|
||||
if(this.firstChild == node){
|
||||
this.setFirstChild(node.nextSibling);
|
||||
}
|
||||
if(this.lastChild == node){
|
||||
this.setLastChild(node.previousSibling);
|
||||
}
|
||||
|
||||
node.setOwnerTree(null);
|
||||
// clear any references from the node
|
||||
node.parentNode = null;
|
||||
node.previousSibling = null;
|
||||
node.nextSibling = null;
|
||||
this.fireEvent('remove', this.ownerTree, this, node);
|
||||
return node;
|
||||
},
|
||||
|
||||
insertBefore : function(node, refNode){
|
||||
if(!refNode){ // like standard Dom, refNode can be null for append
|
||||
return this.appendChild(node);
|
||||
}
|
||||
// nothing to do
|
||||
if(node == refNode){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this.fireEvent('beforeinsert', this.ownerTree, this, node, refNode) === false){
|
||||
return false;
|
||||
}
|
||||
var index = this.childNodes.indexOf(refNode);
|
||||
var oldParent = node.parentNode;
|
||||
var refIndex = index;
|
||||
|
||||
// when moving internally, indexes will change after remove
|
||||
if(oldParent == this && this.childNodes.indexOf(node) < index){
|
||||
refIndex--;
|
||||
}
|
||||
|
||||
// it's a move, make sure we move it cleanly
|
||||
if(oldParent){
|
||||
if(node.fireEvent('beforemove', node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
|
||||
return false;
|
||||
}
|
||||
oldParent.removeChild(node);
|
||||
}
|
||||
if(refIndex == 0){
|
||||
this.setFirstChild(node);
|
||||
}
|
||||
this.childNodes.splice(refIndex, 0, node);
|
||||
node.parentNode = this;
|
||||
var ps = this.childNodes[refIndex-1];
|
||||
if(ps){
|
||||
node.previousSibling = ps;
|
||||
ps.nextSibling = node;
|
||||
}
|
||||
node.nextSibling = refNode;
|
||||
node.setOwnerTree(this.getOwnerTree());
|
||||
this.fireEvent('insert', this.ownerTree, this, node, refNode);
|
||||
if(oldParent){
|
||||
node.fireEvent('move', this.ownerTree, node, oldParent, this, refIndex, refNode);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
|
||||
item : function(index){
|
||||
return this.childNodes[index];
|
||||
},
|
||||
|
||||
replaceChild : function(newChild, oldChild){
|
||||
this.insertBefore(newChild, oldChild);
|
||||
this.removeChild(oldChild);
|
||||
return oldChild;
|
||||
},
|
||||
|
||||
indexOf : function(child){
|
||||
return this.childNodes.indexOf(child);
|
||||
},
|
||||
|
||||
getOwnerTree : function(){
|
||||
// if it doesn't have one, look for one
|
||||
if(!this.ownerTree){
|
||||
var p = this;
|
||||
while(p){
|
||||
if(p.ownerTree){
|
||||
this.ownerTree = p.ownerTree;
|
||||
break;
|
||||
}
|
||||
p = p.parentNode;
|
||||
}
|
||||
}
|
||||
return this.ownerTree;
|
||||
},
|
||||
|
||||
setOwnerTree : function(tree){
|
||||
// if it's move, we need to update everyone
|
||||
if(tree != this.ownerTree){
|
||||
if(this.ownerTree){
|
||||
this.ownerTree.unregisterNode(this);
|
||||
}
|
||||
this.ownerTree = tree;
|
||||
var cs = this.childNodes;
|
||||
for(var i = 0, len = cs.length; i < len; i++) {
|
||||
cs[i].setOwnerTree(tree);
|
||||
}
|
||||
if(tree){
|
||||
tree.registerNode(this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getPath : function(attr){
|
||||
attr = attr || 'id';
|
||||
var p = this.parentNode;
|
||||
var b = [this.attributes[attr]];
|
||||
while(p){
|
||||
b.unshift(p.attributes[attr]);
|
||||
p = p.parentNode;
|
||||
}
|
||||
var sep = this.getOwnerTree().pathSeparator;
|
||||
return sep + b.join(sep);
|
||||
},
|
||||
|
||||
bubble : function(fn, scope, args){
|
||||
var p = this;
|
||||
while(p){
|
||||
if(fn.call(scope || p, args || p) === false){
|
||||
break;
|
||||
}
|
||||
p = p.parentNode;
|
||||
}
|
||||
},
|
||||
|
||||
cascade : function(fn, scope, args){
|
||||
if(fn.call(scope || this, args || this) !== false){
|
||||
var cs = this.childNodes;
|
||||
for(var i = 0, len = cs.length; i < len; i++) {
|
||||
cs[i].cascade(fn, scope, args);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
eachChild : function(fn, scope, args){
|
||||
var cs = this.childNodes;
|
||||
for(var i = 0, len = cs.length; i < len; i++) {
|
||||
if(fn.call(scope || this, args || cs[i]) === false){
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
findChild : function(attribute, value){
|
||||
var cs = this.childNodes;
|
||||
for(var i = 0, len = cs.length; i < len; i++) {
|
||||
if(cs[i].attributes[attribute] == value){
|
||||
return cs[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sorts this nodes children using the supplied sort function
|
||||
* @param {Function} fn
|
||||
* @param {Object} scope
|
||||
*/
|
||||
sort : function(fn, scope){
|
||||
var cs = this.childNodes;
|
||||
var len = cs.length;
|
||||
if(len > 0){
|
||||
var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
|
||||
cs.sort(sortFn);
|
||||
for(var i = 0; i < len; i++){
|
||||
var n = cs[i];
|
||||
n.previousSibling = cs[i-1];
|
||||
n.nextSibling = cs[i+1];
|
||||
if(i == 0){
|
||||
this.setFirstChild(n);
|
||||
}
|
||||
if(i == len-1){
|
||||
this.setLastChild(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
contains : function(node){
|
||||
return node.isAncestor(this);
|
||||
},
|
||||
|
||||
isAncestor : function(node){
|
||||
var p = this.parentNode;
|
||||
while(p){
|
||||
if(p == node){
|
||||
return true;
|
||||
}
|
||||
p = p.parentNode;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
toString : function(){
|
||||
return '[Node'+(this.id?' '+this.id:'')+']';
|
||||
}
|
||||
});
|
||||
274
frontend/beta/js/YUI-extensions/data/XMLDataModel.js
Normal file
274
frontend/beta/js/YUI-extensions/data/XMLDataModel.js
Normal file
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* @class YAHOO.ext.grid.XMLDataModel
|
||||
* This is an implementation of a DataModel used by the Grid. It works
|
||||
* with XML data.
|
||||
* <br>Example schema from Amazon search:
|
||||
* <pre><code>
|
||||
* var schema = {
|
||||
* tagName: 'Item',
|
||||
* id: 'ASIN',
|
||||
* fields: ['Author', 'Title', 'Manufacturer', 'ProductGroup']
|
||||
* };
|
||||
* </code></pre>
|
||||
* @extends YAHOO.ext.grid.LoadableDataModel
|
||||
* @constructor
|
||||
* @param {Object} schema The schema to use
|
||||
* @param {XMLDocument} xml An XML document to load immediately
|
||||
*/
|
||||
YAHOO.ext.grid.XMLDataModel = function(schema, xml){
|
||||
YAHOO.ext.grid.XMLDataModel.superclass.constructor.call(this, YAHOO.ext.grid.LoadableDataModel.XML);
|
||||
/**@private*/
|
||||
this.schema = schema;
|
||||
this.xml = xml;
|
||||
if(xml){
|
||||
this.loadData(xml);
|
||||
}
|
||||
this.idSeed = 0;
|
||||
};
|
||||
YAHOO.extendX(YAHOO.ext.grid.XMLDataModel, YAHOO.ext.grid.LoadableDataModel, {
|
||||
|
||||
getDocument: function(){
|
||||
return this.xml;
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides loadData in LoadableDataModel to process XML
|
||||
* @param {XMLDocument} doc The document to load
|
||||
* @param {<i>Function</i>} callback (optional) callback to call when loading is complete
|
||||
* @param {<i>Boolean</i>} keepExisting (optional) true to keep existing data
|
||||
* @param {<i>Number</i>} insertIndex (optional) if present, loaded data is inserted at the specified index instead of overwriting existing data
|
||||
*/
|
||||
loadData: function(doc, callback, keepExisting, insertIndex){
|
||||
this.xml = doc;
|
||||
var idField = this.schema.id;
|
||||
var fields = this.schema.fields;
|
||||
if(this.schema.totalTag){
|
||||
this.totalCount = null;
|
||||
var totalNode = doc.getElementsByTagName(this.schema.totalTag);
|
||||
if(totalNode && totalNode.item(0) && totalNode.item(0).firstChild) {
|
||||
var v = parseInt(totalNode.item(0).firstChild.nodeValue, 10);
|
||||
if(!isNaN(v)){
|
||||
this.totalCount = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
var rowData = [];
|
||||
var nodes = doc.getElementsByTagName(this.schema.tagName);
|
||||
if(nodes && nodes.length > 0) {
|
||||
for(var i = 0; i < nodes.length; i++) {
|
||||
var node = nodes.item(i);
|
||||
var colData = [];
|
||||
colData.node = node;
|
||||
colData.id = this.getNamedValue(node, idField, String(++this.idSeed));
|
||||
for(var j = 0; j < fields.length; j++) {
|
||||
var val = this.getNamedValue(node, fields[j], "");
|
||||
if(this.preprocessors[j]){
|
||||
val = this.preprocessors[j](val);
|
||||
}
|
||||
colData.push(val);
|
||||
}
|
||||
rowData.push(colData);
|
||||
}
|
||||
}
|
||||
if(keepExisting !== true){
|
||||
YAHOO.ext.grid.XMLDataModel.superclass.removeAll.call(this);
|
||||
}
|
||||
if(typeof insertIndex != 'number'){
|
||||
insertIndex = this.getRowCount();
|
||||
}
|
||||
YAHOO.ext.grid.XMLDataModel.superclass.insertRows.call(this, insertIndex, rowData);
|
||||
if(typeof callback == 'function'){
|
||||
callback(this, true);
|
||||
}
|
||||
this.fireLoadEvent();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a row to this DataModel and syncs the XML document
|
||||
* @param {String} id The id of the row, if null the next row index is used
|
||||
* @param {Array} cellValues The cell values for this row
|
||||
* @return {Number} The index of the new row (if the model is sorted this index may not be accurate)
|
||||
*/
|
||||
addRow: function(id, cellValues){
|
||||
var node = this.createNode(this.xml, id, cellValues);
|
||||
cellValues.id = id || ++this.idSeed;
|
||||
cellValues.node = node;
|
||||
return YAHOO.ext.grid.XMLDataModel.superclass.addRow.call(this, cellValues);
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a row into this DataModel and syncs the XML document
|
||||
* @param {Number} index The index to insert the row
|
||||
* @param {String} id The id of the row, if null the next row index is used
|
||||
* @param {Array} cellValues The cell values for this row
|
||||
* @return {Number} The index of the new row (if the model is sorted this index may not be accurate)
|
||||
*/
|
||||
insertRow: function(index, id, cellValues){
|
||||
var node = this.createNode(this.xml, id, cellValues);
|
||||
cellValues.id = id || ++this.idSeed;
|
||||
cellValues.node = node;
|
||||
return YAHOO.ext.grid.XMLDataModel.superclass.insertRow.call(this, index, cellValues);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the row from DataModel and syncs the XML document
|
||||
* @param {Number} index The index of the row to remove
|
||||
*/
|
||||
removeRow: function(index){
|
||||
var node = this.data[index].node;
|
||||
node.parentNode.removeChild(node);
|
||||
YAHOO.ext.grid.XMLDataModel.superclass.removeRow.call(this, index, index);
|
||||
},
|
||||
|
||||
getNode: function(rowIndex){
|
||||
return this.data[rowIndex].node;
|
||||
},
|
||||
|
||||
/**
|
||||
* Override this method to define your own node creation routine for when new rows are added.
|
||||
* By default this method clones the first node and sets the column values in the newly cloned node.
|
||||
* In many instances this will not work and you will have to create the node manually.
|
||||
* @param {XMLDocument} xmlDoc The xml document being used by this model
|
||||
* @param {String/Number} id The row id
|
||||
* @param {Array} colData The column data for the new node
|
||||
* @return {XMLNode} The created node
|
||||
*/
|
||||
createNode: function(xmlDoc, id, colData){
|
||||
var template = this.data[0].node;
|
||||
var newNode = template.cloneNode(true);
|
||||
var fields = this.schema.fields;
|
||||
for(var i = 0, len = fields.length; i < len; i++){
|
||||
var nodeValue = colData[i];
|
||||
if(this.postprocessors[i]){
|
||||
nodeValue = this.postprocessors[i](nodeValue);
|
||||
}
|
||||
this.setNamedValue(newNode, fields[i], nodeValue);
|
||||
}
|
||||
if(id){
|
||||
this.setNamedValue(newNode, this.schema.idField, id);
|
||||
}
|
||||
template.parentNode.appendChild(newNode);
|
||||
return newNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Convenience function looks for value in attributes, then in children tags - also
|
||||
* normalizes namespace matches (ie matches ns:tag, FireFox matches tag and not ns:tag).
|
||||
*/
|
||||
getNamedValue: function(node, name, defaultValue){
|
||||
if(!node || !name){
|
||||
return defaultValue;
|
||||
}
|
||||
var nodeValue = defaultValue;
|
||||
var attrNode = node.attributes.getNamedItem(name);
|
||||
if(attrNode) {
|
||||
nodeValue = attrNode.value;
|
||||
} else {
|
||||
var childNode = node.getElementsByTagName(name);
|
||||
if(childNode && childNode.item(0) && childNode.item(0).firstChild) {
|
||||
nodeValue = childNode.item(0).firstChild.nodeValue;
|
||||
}else{
|
||||
// try to strip namespace for FireFox
|
||||
var index = name.indexOf(':');
|
||||
if(index > 0){
|
||||
return this.getNamedValue(node, name.substr(index+1), defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nodeValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Convenience function set a value in the underlying xml node.
|
||||
*/
|
||||
setNamedValue: function(node, name, value){
|
||||
if(!node || !name){
|
||||
return;
|
||||
}
|
||||
var attrNode = node.attributes.getNamedItem(name);
|
||||
if(attrNode) {
|
||||
attrNode.value = value;
|
||||
return;
|
||||
}
|
||||
var childNode = node.getElementsByTagName(name);
|
||||
if(childNode && childNode.item(0) && childNode.item(0).firstChild) {
|
||||
childNode.item(0).firstChild.nodeValue = value;
|
||||
}else{
|
||||
// try to strip namespace for FireFox
|
||||
var index = name.indexOf(':');
|
||||
if(index > 0){
|
||||
this.setNamedValue(node, name.substr(index+1), value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides DefaultDataModel.setValueAt to update the underlying XML Document
|
||||
* @param {Object} value The new value
|
||||
* @param {Number} rowIndex
|
||||
* @param {Number} colIndex
|
||||
*/
|
||||
setValueAt: function(value, rowIndex, colIndex){
|
||||
var node = this.data[rowIndex].node;
|
||||
if(node){
|
||||
var nodeValue = value;
|
||||
if(this.postprocessors[colIndex]){
|
||||
nodeValue = this.postprocessors[colIndex](value);
|
||||
}
|
||||
this.setNamedValue(node, this.schema.fields[colIndex], nodeValue);
|
||||
}
|
||||
YAHOO.ext.grid.XMLDataModel.superclass.setValueAt.call(this, value, rowIndex, colIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides getRowId in DefaultDataModel to return the ID value of the specified node.
|
||||
* @param {Number} rowIndex
|
||||
* @return {Number}
|
||||
*/
|
||||
getRowId: function(rowIndex){
|
||||
return this.data[rowIndex].id;
|
||||
},
|
||||
|
||||
addRows : function(rowData){
|
||||
for(var j = 0, len = rowData.length; j < len; j++){
|
||||
var cellValues = rowData[j];
|
||||
var id = ++this.idSeed;
|
||||
var node = this.createNode(this.xml, id, cellValues);
|
||||
cellValues.node=node;
|
||||
cellValues.id = cellValues.id || id;
|
||||
YAHOO.ext.grid.XMLDataModel.superclass.addRow.call(this,cellValues);
|
||||
}
|
||||
},
|
||||
|
||||
insertRows : function(index, rowData){
|
||||
// copy original array so it is not reversed
|
||||
rowData = rowData.slice(0).reverse();
|
||||
for(var j = 0, len = rowData.length; j < len; j++){
|
||||
var cellValues = rowData[j];
|
||||
var id = ++this.idSeed;
|
||||
var node = this.createNode(this.xml, id, cellValues);
|
||||
cellValues.id = cellValues.id || id;
|
||||
cellValues.node = node;
|
||||
YAHOO.ext.grid.XMLDataModel.superclass.insertRow.call(this, index, cellValues);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
YAHOO.ext.grid.XMLQueryDataModel = function(){
|
||||
YAHOO.ext.grid.XMLQueryDataModel.superclass.constructor.apply(this, arguments);
|
||||
};
|
||||
YAHOO.extendX(YAHOO.ext.grid.XMLQueryDataModel, YAHOO.ext.grid.XMLDataModel, {
|
||||
getNamedValue: function(node, name, defaultValue){
|
||||
if(!node || !name){
|
||||
return defaultValue;
|
||||
}
|
||||
var nodeValue = defaultValue;
|
||||
var childNode = cssQuery(name, node);
|
||||
if(childNode && childNode[0]) {
|
||||
nodeValue = childNode[0].firstChild.nodeValue;
|
||||
}
|
||||
return nodeValue;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user