Diffstat (limited to 'frontend/beta/js/YUI-extensions/data') (more/less context) (ignore whitespace changes)
-rw-r--r-- | frontend/beta/js/YUI-extensions/data/AbstractDataModel.js | 226 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/data/DefaultDataModel.js | 339 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/data/JSONDataModel.js | 81 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/data/LoadableDataModel.js | 330 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/data/Tree.js | 412 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/data/XMLDataModel.js | 274 |
6 files changed, 1662 insertions, 0 deletions
diff --git a/frontend/beta/js/YUI-extensions/data/AbstractDataModel.js b/frontend/beta/js/YUI-extensions/data/AbstractDataModel.js new file mode 100644 index 0000000..092ea75 --- a/dev/null +++ b/frontend/beta/js/YUI-extensions/data/AbstractDataModel.js | |||
@@ -0,0 +1,226 @@ | |||
1 | /** | ||
2 | * @class YAHOO.ext.grid.AbstractDataModel | ||
3 | * @extends YAHOO.ext.util.Observable | ||
4 | * This abstract class provides default implementations of the events required by the Grid. | ||
5 | It takes care of the creating the CustomEvents and provides some convenient methods for firing the events. <br><br> | ||
6 | * @constructor | ||
7 | */ | ||
8 | YAHOO.ext.grid.AbstractDataModel = function(){ | ||
9 | /** Fires when a cell is updated - fireDirect sig: (this, rowIndex, columnIndex) | ||
10 | * @private | ||
11 | * @type YAHOO.util.CustomEvent | ||
12 | * @deprecated Use addListener instead of accessing directly | ||
13 | */ | ||
14 | this.onCellUpdated = new YAHOO.util.CustomEvent('onCellUpdated'); | ||
15 | /** Fires when all data needs to be revalidated - fireDirect sig: (thisd) | ||
16 | * @private | ||
17 | * @type YAHOO.util.CustomEvent | ||
18 | * @deprecated Use addListener instead of accessing directly | ||
19 | */ | ||
20 | this.onTableDataChanged = new YAHOO.util.CustomEvent('onTableDataChanged'); | ||
21 | /** Fires when rows are deleted - fireDirect sig: (this, firstRowIndex, lastRowIndex) | ||
22 | * @private | ||
23 | * @type YAHOO.util.CustomEvent | ||
24 | * @deprecated Use addListener instead of accessing directly | ||
25 | */ | ||
26 | this.onRowsDeleted = new YAHOO.util.CustomEvent('onRowsDeleted'); | ||
27 | /** Fires when a rows are inserted - fireDirect sig: (this, firstRowIndex, lastRowIndex) | ||
28 | * @private | ||
29 | * @type YAHOO.util.CustomEvent | ||
30 | * @deprecated Use addListener instead of accessing directly | ||
31 | */ | ||
32 | this.onRowsInserted = new YAHOO.util.CustomEvent('onRowsInserted'); | ||
33 | /** Fires when a rows are updated - fireDirect sig: (this, firstRowIndex, lastRowIndex) | ||
34 | * @private | ||
35 | * @type YAHOO.util.CustomEvent | ||
36 | * @deprecated Use addListener instead of accessing directly | ||
37 | */ | ||
38 | this.onRowsUpdated = new YAHOO.util.CustomEvent('onRowsUpdated'); | ||
39 | /** Fires when a sort has reordered the rows - fireDirect sig: (this, sortColumnIndex, | ||
40 | * @private | ||
41 | * sortDirection = 'ASC' or 'DESC') | ||
42 | * @type YAHOO.util.CustomEvent | ||
43 | * @deprecated Use addListener instead of accessing directly | ||
44 | */ | ||
45 | this.onRowsSorted = new YAHOO.util.CustomEvent('onRowsSorted'); | ||
46 | |||
47 | this.events = { | ||
48 | /** | ||
49 | * @event cellupdated | ||
50 | * Fires when a cell is updated | ||
51 | * @param {DataModel} this | ||
52 | * @param {Number} rowIndex | ||
53 | * @param {Number} columnIndex | ||
54 | */ | ||
55 | 'cellupdated' : this.onCellUpdated, | ||
56 | /** | ||
57 | * @event datachanged | ||
58 | * Fires when the entire data structure has changed | ||
59 | * @param {DataModel} this | ||
60 | */ | ||
61 | 'datachanged' : this.onTableDataChanged, | ||
62 | /** | ||
63 | * @event rowsdeleted | ||
64 | * Fires when a range of rows have been deleted | ||
65 | * @param {DataModel} this | ||
66 | * @param {Number} firstRowIndex | ||
67 | * @param {Number} lastRowIndex | ||
68 | */ | ||
69 | 'rowsdeleted' : this.onRowsDeleted, | ||
70 | /** | ||
71 | * @event rowsinserted | ||
72 | * Fires when a range of rows have been inserted | ||
73 | * @param {DataModel} this | ||
74 | * @param {Number} firstRowIndex | ||
75 | * @param {Number} lastRowIndex | ||
76 | */ | ||
77 | 'rowsinserted' : this.onRowsInserted, | ||
78 | /** | ||
79 | * @event rowsupdated | ||
80 | * Fires when a range of rows have been updated | ||
81 | * @param {DataModel} this | ||
82 | * @param {Number} firstRowIndex | ||
83 | * @param {Number} lastRowIndex | ||
84 | */ | ||
85 | 'rowsupdated' : this.onRowsUpdated, | ||
86 | /** | ||
87 | * @event rowssorted | ||
88 | * Fires when the data has been sorted | ||
89 | * @param {DataModel} this | ||
90 | */ | ||
91 | 'rowssorted' : this.onRowsSorted | ||
92 | }; | ||
93 | }; | ||
94 | |||
95 | YAHOO.ext.grid.AbstractDataModel.prototype = { | ||
96 | |||
97 | fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent, | ||
98 | on : YAHOO.ext.util.Observable.prototype.on, | ||
99 | addListener : YAHOO.ext.util.Observable.prototype.addListener, | ||
100 | delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener, | ||
101 | removeListener : YAHOO.ext.util.Observable.prototype.removeListener, | ||
102 | purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners, | ||
103 | bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener, | ||
104 | |||
105 | /** | ||
106 | * Notifies listeners that the value of the cell at [row, col] has been updated | ||
107 | * @deprecated | ||
108 | * @private | ||
109 | */ | ||
110 | fireCellUpdated : function(row, col){ | ||
111 | this.onCellUpdated.fireDirect(this, row, col); | ||
112 | }, | ||
113 | |||
114 | /** | ||
115 | * Notifies listeners that all data for the grid may have changed - use as a last resort. This | ||
116 | * also wipes out all selections a user might have made. | ||
117 | * @deprecated | ||
118 | * @private | ||
119 | */ | ||
120 | fireTableDataChanged : function(){ | ||
121 | this.onTableDataChanged.fireDirect(this); | ||
122 | }, | ||
123 | |||
124 | /** | ||
125 | * Notifies listeners that rows in the range [firstRow, lastRow], inclusive, have been deleted | ||
126 | * @deprecated | ||
127 | * @private | ||
128 | */ | ||
129 | fireRowsDeleted : function(firstRow, lastRow){ | ||
130 | this.onRowsDeleted.fireDirect(this, firstRow, lastRow); | ||
131 | }, | ||
132 | |||
133 | /** | ||
134 | * Notifies listeners that rows in the range [firstRow, lastRow], inclusive, have been inserted | ||
135 | * @deprecated | ||
136 | * @private | ||
137 | */ | ||
138 | fireRowsInserted : function(firstRow, lastRow){ | ||
139 | this.onRowsInserted.fireDirect(this, firstRow, lastRow); | ||
140 | }, | ||
141 | |||
142 | /** | ||
143 | * Notifies listeners that rows in the range [firstRow, lastRow], inclusive, have been updated | ||
144 | * @deprecated | ||
145 | * @private | ||
146 | */ | ||
147 | fireRowsUpdated : function(firstRow, lastRow){ | ||
148 | this.onRowsUpdated.fireDirect(this, firstRow, lastRow); | ||
149 | }, | ||
150 | |||
151 | /** | ||
152 | * Notifies listeners that rows have been sorted and any indexes may be invalid | ||
153 | * @deprecated | ||
154 | * @private | ||
155 | */ | ||
156 | fireRowsSorted : function(sortColumnIndex, sortDir, noRefresh){ | ||
157 | this.onRowsSorted.fireDirect(this, sortColumnIndex, sortDir, noRefresh); | ||
158 | }, | ||
159 | |||
160 | /** | ||
161 | * Empty interface method - Classes which extend AbstractDataModel should implement this method. | ||
162 | * See {@link YAHOO.ext.DefaultDataModel#sort} for an example implementation. | ||
163 | * @private | ||
164 | */ | ||
165 | sort : function(sortInfo, columnIndex, direction, suppressEvent){ | ||
166 | |||
167 | }, | ||
168 | |||
169 | /** | ||
170 | * Interface method to supply info regarding the Grid's current sort state - if overridden, | ||
171 | * this should return an object like this {column: this.sortColumn, direction: this.sortDir}. | ||
172 | * @return {Object} | ||
173 | */ | ||
174 | getSortState : function(){ | ||
175 | return {column: this.sortColumn, direction: this.sortDir}; | ||
176 | }, | ||
177 | |||
178 | /** | ||
179 | * Empty interface method - Classes which extend AbstractDataModel should implement this method. | ||
180 | * See {@link YAHOO.ext.DefaultDataModel} for an example implementation. | ||
181 | * @private | ||
182 | */ | ||
183 | getRowCount : function(){ | ||
184 | |||
185 | }, | ||
186 | |||
187 | /** | ||
188 | * Empty interface method - Classes which extend AbstractDataModel should implement this method to support virtual row counts. | ||
189 | * @private | ||
190 | */ | ||
191 | getTotalRowCount : function(){ | ||
192 | return this.getRowCount(); | ||
193 | }, | ||
194 | |||
195 | |||
196 | /** | ||
197 | * Empty interface method - Classes which extend AbstractDataModel should implement this method. | ||
198 | * See {@link YAHOO.ext.DefaultDataModel} for an example implementation. | ||
199 | * @private | ||
200 | */ | ||
201 | getRowId : function(rowIndex){ | ||
202 | |||
203 | }, | ||
204 | |||
205 | /** | ||
206 | * Empty interface method - Classes which extend AbstractDataModel should implement this method. | ||
207 | * See {@link YAHOO.ext.DefaultDataModel} for an example implementation. | ||
208 | * @private | ||
209 | */ | ||
210 | getValueAt : function(rowIndex, colIndex){ | ||
211 | |||
212 | }, | ||
213 | |||
214 | /** | ||
215 | * Empty interface method - Classes which extend AbstractDataModel should implement this method. | ||
216 | * See {@link YAHOO.ext.DefaultDataModel} for an example implementation. | ||
217 | * @private | ||
218 | */ | ||
219 | setValueAt : function(value, rowIndex, colIndex){ | ||
220 | |||
221 | }, | ||
222 | |||
223 | isPaged : function(){ | ||
224 | return false; | ||
225 | } | ||
226 | }; | ||
diff --git a/frontend/beta/js/YUI-extensions/data/DefaultDataModel.js b/frontend/beta/js/YUI-extensions/data/DefaultDataModel.js new file mode 100644 index 0000000..57a022a --- a/dev/null +++ b/frontend/beta/js/YUI-extensions/data/DefaultDataModel.js | |||
@@ -0,0 +1,339 @@ | |||
1 | |||
2 | /** | ||
3 | * @class YAHOO.ext.grid.DefaultDataModel | ||
4 | * This is the default implementation of a DataModel used by the Grid. It works | ||
5 | * with multi-dimensional array based data. Using the event system in the base class | ||
6 | * {@link YAHOO.ext.grid.AbstractDataModel}, all updates to this DataModel are automatically | ||
7 | * reflected in the user interface. | ||
8 | * <br>Usage:<br> | ||
9 | * <pre><code> | ||
10 | * var myData = [ | ||
11 | ["MSFT","Microsoft Corporation", "314,571.156", "32,187.000", "55000"], | ||
12 | ["ORCL", "Oracle Corporation", "62,615.266", "9,519.000", "40650"] | ||
13 | * ]; | ||
14 | * var dataModel = new YAHOO.ext.grid.DefaultDataModel(myData); | ||
15 | * </code></pre> | ||
16 | * @extends YAHOO.ext.grid.AbstractDataModel | ||
17 | * @constructor | ||
18 | * @param {Array} data | ||
19 | */ | ||
20 | YAHOO.ext.grid.DefaultDataModel = function(data){ | ||
21 | YAHOO.ext.grid.DefaultDataModel.superclass.constructor.call(this); | ||
22 | /**@private*/ | ||
23 | this.data = data; | ||
24 | }; | ||
25 | YAHOO.extendX(YAHOO.ext.grid.DefaultDataModel, YAHOO.ext.grid.AbstractDataModel, { | ||
26 | /** | ||
27 | * Returns the number of rows in the dataset | ||
28 | * @return {Number} | ||
29 | */ | ||
30 | getRowCount : function(){ | ||
31 | return this.data.length; | ||
32 | }, | ||
33 | |||
34 | /** | ||
35 | * Returns the ID of the specified row. By default it return the value of the first column. | ||
36 | * Override to provide more advanced ID handling. | ||
37 | * @return {Number} | ||
38 | */ | ||
39 | getRowId : function(rowIndex){ | ||
40 | return this.data[rowIndex][0]; | ||
41 | }, | ||
42 | |||
43 | /** | ||
44 | * Returns the column data for the specified row. | ||
45 | * @return {Array} | ||
46 | */ | ||
47 | getRow : function(rowIndex){ | ||
48 | return this.data[rowIndex]; | ||
49 | }, | ||
50 | |||
51 | /** | ||
52 | * Returns the column data for the specified rows as a | ||
53 | * multi-dimensional array: rows[3][0] would give you the value of row 4, column 0. | ||
54 | * @param {Array} indexes The row indexes to fetch | ||
55 | * @return {Array} | ||
56 | */ | ||
57 | getRows : function(indexes){ | ||
58 | var data = this.data; | ||
59 | var r = []; | ||
60 | for(var i = 0; i < indexes.length; i++){ | ||
61 | r.push(data[indexes[i]]); | ||
62 | } | ||
63 | return r; | ||
64 | }, | ||
65 | |||
66 | /** | ||
67 | * Returns the value at the specified data position | ||
68 | * @param {Number} rowIndex | ||
69 | * @param {Number} colIndex | ||
70 | * @return {Object} | ||
71 | */ | ||
72 | getValueAt : function(rowIndex, colIndex){ | ||
73 | return this.data[rowIndex][colIndex]; | ||
74 | }, | ||
75 | |||
76 | /** | ||
77 | * Sets the specified value at the specified data position | ||
78 | * @param {Object} value The new value | ||
79 | * @param {Number} rowIndex | ||
80 | * @param {Number} colIndex | ||
81 | */ | ||
82 | setValueAt: function(value, rowIndex, colIndex){ | ||
83 | this.data[rowIndex][colIndex] = value; | ||
84 | this.fireCellUpdated(rowIndex, colIndex); | ||
85 | }, | ||
86 | |||
87 | /** | ||
88 | * @private | ||
89 | * Removes the specified range of rows. | ||
90 | * @param {Number} startIndex | ||
91 | * @param {<i>Number</i>} endIndex (optional) Defaults to startIndex | ||
92 | */ | ||
93 | removeRows: function(startIndex, endIndex){ | ||
94 | endIndex = endIndex || startIndex; | ||
95 | this.data.splice(startIndex, endIndex-startIndex+1); | ||
96 | this.fireRowsDeleted(startIndex, endIndex); | ||
97 | }, | ||
98 | |||
99 | /** | ||
100 | * Remove a row. | ||
101 | * @param {Number} index | ||
102 | */ | ||
103 | removeRow: function(index){ | ||
104 | this.data.splice(index, 1); | ||
105 | this.fireRowsDeleted(index, index); | ||
106 | }, | ||
107 | |||
108 | /** | ||
109 | * @private | ||
110 | * Removes all rows. | ||
111 | */ | ||
112 | removeAll: function(){ | ||
113 | var count = this.getRowCount(); | ||
114 | if(count > 0){ | ||
115 | this.removeRows(0, count-1); | ||
116 | } | ||
117 | }, | ||
118 | |||
119 | /** | ||
120 | * Query the DataModel rows by the filters defined in spec, for example... | ||
121 | * <pre><code> | ||
122 | * // column 1 starts with Jack, column 2 filtered by myFcn, column 3 equals 'Fred' | ||
123 | * dataModel.filter({1: /^Jack.+/i}, 2: myFcn, 3: 'Fred'}); | ||
124 | * </code></pre> | ||
125 | * @param {Object} spec The spec is generally an object literal consisting of | ||
126 | * column index and filter type. The filter type can be a string/number (exact match), | ||
127 | * a regular expression to test using String.search() or a function to call. If it's a function, | ||
128 | * it will be called with the value for the specified column and an array of the all column | ||
129 | * values for that row: yourFcn(value, columnData). If it returns anything other than true, | ||
130 | * the row is not a match. If you have modified Object.prototype this method may fail. | ||
131 | * @param {Boolean} returnUnmatched True to return rows which <b>don't</b> match the query instead | ||
132 | * of rows that do match | ||
133 | * @return {Array} An array of row indexes that match | ||
134 | */ | ||
135 | query: function(spec, returnUnmatched){ | ||
136 | var d = this.data; | ||
137 | var r = []; | ||
138 | for(var i = 0; i < d.length; i++){ | ||
139 | var row = d[i]; | ||
140 | var isMatch = true; | ||
141 | for(var col in spec){ | ||
142 | //if(typeof spec[col] != 'function'){ | ||
143 | if(!isMatch) continue; | ||
144 | var filter = spec[col]; | ||
145 | switch(typeof filter){ | ||
146 | case 'string': | ||
147 | case 'number': | ||
148 | case 'boolean': | ||
149 | if(row[col] != filter){ | ||
150 | isMatch = false; | ||
151 | } | ||
152 | break; | ||
153 | case 'function': | ||
154 | if(!filter(row[col], row)){ | ||
155 | isMatch = false; | ||
156 | } | ||
157 | break; | ||
158 | case 'object': | ||
159 | if(filter instanceof RegExp){ | ||
160 | if(String(row[col]).search(filter) === -1){ | ||
161 | isMatch = false; | ||
162 | } | ||
163 | } | ||
164 | break; | ||
165 | } | ||
166 | //} | ||
167 | } | ||
168 | if(isMatch && !returnUnmatched){ | ||
169 | r.push(i); | ||
170 | }else if(!isMatch && returnUnmatched){ | ||
171 | r.push(i); | ||
172 | } | ||
173 | } | ||
174 | return r; | ||
175 | }, | ||
176 | |||
177 | /** | ||
178 | * Filter the DataModel rows by the query defined in spec, see {@link #query} for more details | ||
179 | * on the query spec. | ||
180 | * @param {Object} query The query spec {@link #query} | ||
181 | * @return {Number} The number of rows removed | ||
182 | */ | ||
183 | filter: function(query){ | ||
184 | var matches = this.query(query, true); | ||
185 | var data = this.data; | ||
186 | // go thru the data setting matches to deleted | ||
187 | // while not disturbing row indexes | ||
188 | for(var i = 0; i < matches.length; i++){ | ||
189 | data[matches[i]]._deleted = true; | ||
190 | } | ||
191 | for(var i = 0; i < data.length; i++){ | ||
192 | while(data[i] && data[i]._deleted === true){ | ||
193 | this.removeRow(i); | ||
194 | } | ||
195 | } | ||
196 | return matches.length; | ||
197 | }, | ||
198 | |||
199 | /** | ||
200 | * Adds a row to the dataset. | ||
201 | * @param {Array} cellValues The array of values for the new row | ||
202 | * @return {Number} The index of the added row | ||
203 | */ | ||
204 | addRow: function(cellValues){ | ||
205 | this.data.push(cellValues); | ||
206 | var newIndex = this.data.length-1; | ||
207 | this.fireRowsInserted(newIndex, newIndex); | ||
208 | this.applySort(); | ||
209 | return newIndex; | ||
210 | }, | ||
211 | |||
212 | /** | ||
213 | * @private | ||
214 | * Adds a set of rows. | ||
215 | * @param {Array} rowData This should be an array of arrays like the constructor takes | ||
216 | */ | ||
217 | addRows: function(rowData){ | ||
218 | this.data = this.data.concat(rowData); | ||
219 | var firstIndex = this.data.length-rowData.length; | ||
220 | this.fireRowsInserted(firstIndex, firstIndex+rowData.length-1); | ||
221 | this.applySort(); | ||
222 | }, | ||
223 | |||
224 | /** | ||
225 | * Inserts a row a the specified location in the dataset. | ||
226 | * @param {Number} index The index where the row should be inserted | ||
227 | * @param {Array} cellValues The array of values for the new row | ||
228 | * @return {Number} The index the row was inserted in | ||
229 | */ | ||
230 | insertRow: function(index, cellValues){ | ||
231 | this.data.splice(index, 0, cellValues); | ||
232 | this.fireRowsInserted(index, index); | ||
233 | this.applySort(); | ||
234 | return index; | ||
235 | }, | ||
236 | |||
237 | /** | ||
238 | * @private | ||
239 | * Inserts a set of rows. | ||
240 | * @param {Number} index The index where the rows should be inserted | ||
241 | * @param {Array} rowData This should be an array of arrays like the constructor takes | ||
242 | */ | ||
243 | insertRows: function(index, rowData){ | ||
244 | /* | ||
245 | if(index == this.data.length){ // try these two first since they are faster | ||
246 | this.data = this.data.concat(rowData); | ||
247 | }else if(index == 0){ | ||
248 | this.data = rowData.concat(this.data); | ||
249 | }else{ | ||
250 | var newData = this.data.slice(0, index); | ||
251 | newData.concat(rowData); | ||
252 | newData.concat(this.data.slice(index)); | ||
253 | this.data = newData; | ||
254 | }*/ | ||
255 | var args = rowData.concat(); | ||
256 | args.splice(0, 0, index, 0); | ||
257 | this.data.splice.apply(this.data, args); | ||
258 | this.fireRowsInserted(index, index+rowData.length-1); | ||
259 | this.applySort(); | ||
260 | }, | ||
261 | |||
262 | /** | ||
263 | * Applies the last used sort to the current data. | ||
264 | */ | ||
265 | applySort: function(suppressEvent){ | ||
266 | if(typeof this.sortColumn != 'undefined'){ | ||
267 | this.sort(this.sortInfo, this.sortColumn, this.sortDir, suppressEvent); | ||
268 | } | ||
269 | }, | ||
270 | |||
271 | /** | ||
272 | * Sets the default sort info. Note: this function does not actually apply the sort. | ||
273 | * @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 | ||
274 | * a grid column model. | ||
275 | * @param {Number} columnIndex The column index to sort by | ||
276 | * @param {String} direction The direction of the sort ('DESC' or 'ASC') | ||
277 | */ | ||
278 | setDefaultSort: function(sortInfo, columnIndex, direction){ | ||
279 | this.sortInfo = sortInfo; | ||
280 | this.sortColumn = columnIndex; | ||
281 | this.sortDir = direction; | ||
282 | }, | ||
283 | /** | ||
284 | * Sorts the data by the specified column - Uses the sortType specified for the column in the passed columnModel. | ||
285 | * @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 | ||
286 | * a grid column model. | ||
287 | * @param {Number} columnIndex The column index to sort by | ||
288 | * @param {String} direction The direction of the sort ('DESC' or 'ASC') | ||
289 | */ | ||
290 | sort: function(sortInfo, columnIndex, direction, suppressEvent){ | ||
291 | // store these so we can maintain sorting when we load new data | ||
292 | this.sortInfo = sortInfo; | ||
293 | this.sortColumn = columnIndex; | ||
294 | this.sortDir = direction; | ||
295 | |||
296 | var dsc = (direction && direction.toUpperCase() == 'DESC'); | ||
297 | var sortType = null; | ||
298 | if(sortInfo != null){ | ||
299 | if(typeof sortInfo == 'function'){ | ||
300 | sortType = sortInfo; | ||
301 | }else if(typeof sortInfo == 'object'){ | ||
302 | sortType = sortInfo.getSortType(columnIndex);; | ||
303 | } | ||
304 | } | ||
305 | var fn = function(cells, cells2){ | ||
306 | var v1 = sortType ? sortType(cells[columnIndex], cells) : cells[columnIndex]; | ||
307 | var v2 = sortType ? sortType(cells2[columnIndex], cells2) : cells2[columnIndex]; | ||
308 | if(v1 < v2) | ||
309 | return dsc ? +1 : -1; | ||
310 | if(v1 > v2) | ||
311 | return dsc ? -1 : +1; | ||
312 | return 0; | ||
313 | }; | ||
314 | this.data.sort(fn); | ||
315 | if(!suppressEvent){ | ||
316 | this.fireRowsSorted(columnIndex, direction); | ||
317 | } | ||
318 | }, | ||
319 | |||
320 | /** | ||
321 | * Calls passed function with each rows data - if the function returns false it stops. | ||
322 | * @param {Function} fn | ||
323 | * @param {Object} scope (optional) | ||
324 | */ | ||
325 | each: function(fn, scope){ | ||
326 | var d = this.data; | ||
327 | for(var i = 0, len = d.length; i < len; i++){ | ||
328 | if(fn.call(scope || window, d[i], i) === false) break; | ||
329 | } | ||
330 | } | ||
331 | }); | ||
332 | |||
333 | /** | ||
334 | * Alias to YAHOO.ext.grid.DefaultColumnModel.sortTypes | ||
335 | * @static | ||
336 | */ | ||
337 | if(YAHOO.ext.grid.DefaultColumnModel){ | ||
338 | YAHOO.ext.grid.DefaultDataModel.sortTypes = YAHOO.ext.grid.DefaultColumnModel.sortTypes; | ||
339 | } | ||
diff --git a/frontend/beta/js/YUI-extensions/data/JSONDataModel.js b/frontend/beta/js/YUI-extensions/data/JSONDataModel.js new file mode 100644 index 0000000..ca48dce --- a/dev/null +++ b/frontend/beta/js/YUI-extensions/data/JSONDataModel.js | |||
@@ -0,0 +1,81 @@ | |||
1 | |||
2 | /** | ||
3 | * @class YAHOO.ext.grid.JSONDataModel | ||
4 | * This is an implementation of a DataModel used by the Grid. It works | ||
5 | * with JSON data. | ||
6 | * <br>Example schema: | ||
7 | * <pre><code> | ||
8 | * var schema = { | ||
9 | * root: 'Results.Result', | ||
10 | * id: 'ASIN', | ||
11 | * fields: ['Author', 'Title', 'Manufacturer', 'ProductGroup'] | ||
12 | * }; | ||
13 | * </code></pre> | ||
14 | * @extends YAHOO.ext.grid.LoadableDataModel | ||
15 | * @constructor | ||
16 | */ | ||
17 | YAHOO.ext.grid.JSONDataModel = function(schema){ | ||
18 | YAHOO.ext.grid.JSONDataModel.superclass.constructor.call(this, YAHOO.ext.grid.LoadableDataModel.JSON); | ||
19 | /**@private*/ | ||
20 | this.schema = schema; | ||
21 | }; | ||
22 | YAHOO.extendX(YAHOO.ext.grid.JSONDataModel, YAHOO.ext.grid.LoadableDataModel, { | ||
23 | /** | ||
24 | * Overrides loadData in LoadableDataModel to process JSON data | ||
25 | * @param {Object} data The JSON object to load | ||
26 | * @param {Function} callback | ||
27 | */ | ||
28 | loadData : function(data, callback, keepExisting){ | ||
29 | var idField = this.schema.id; | ||
30 | var fields = this.schema.fields; | ||
31 | try{ | ||
32 | if(this.schema.totalProperty){ | ||
33 | var v = parseInt(eval('data.' + this.schema.totalProperty), 10); | ||
34 | if(!isNaN(v)){ | ||
35 | this.totalCount = v; | ||
36 | } | ||
37 | } | ||
38 | var rowData = []; | ||
39 | var root = eval('data.' + this.schema.root); | ||
40 | for(var i = 0; i < root.length; i++){ | ||
41 | var node = root[i]; | ||
42 | var colData = []; | ||
43 | colData.node = node; | ||
44 | colData.id = (typeof node[idField] != 'undefined' && node[idField] !== '' ? node[idField] : String(i)); | ||
45 | for(var j = 0; j < fields.length; j++) { | ||
46 | var val = node[fields[j]]; | ||
47 | if(typeof val == 'undefined'){ | ||
48 | val = ''; | ||
49 | } | ||
50 | if(this.preprocessors[j]){ | ||
51 | val = this.preprocessors[j](val); | ||
52 | } | ||
53 | colData.push(val); | ||
54 | } | ||
55 | rowData.push(colData); | ||
56 | } | ||
57 | if(keepExisting !== true){ | ||
58 | this.removeAll(); | ||
59 | } | ||
60 | this.addRows(rowData); | ||
61 | if(typeof callback == 'function'){ | ||
62 | callback(this, true); | ||
63 | } | ||
64 | this.fireLoadEvent(); | ||
65 | }catch(e){ | ||
66 | this.fireLoadException(e, null); | ||
67 | if(typeof callback == 'function'){ | ||
68 | callback(this, false); | ||
69 | } | ||
70 | } | ||
71 | }, | ||
72 | |||
73 | /** | ||
74 | * Overrides getRowId in DefaultDataModel to return the ID value of the specified node. | ||
75 | * @param {Number} rowIndex | ||
76 | * @return {Number} | ||
77 | */ | ||
78 | getRowId : function(rowIndex){ | ||
79 | return this.data[rowIndex].id; | ||
80 | } | ||
81 | }); | ||
diff --git a/frontend/beta/js/YUI-extensions/data/LoadableDataModel.js b/frontend/beta/js/YUI-extensions/data/LoadableDataModel.js new file mode 100644 index 0000000..07def44 --- a/dev/null +++ b/frontend/beta/js/YUI-extensions/data/LoadableDataModel.js | |||
@@ -0,0 +1,330 @@ | |||
1 | /** | ||
2 | * @class YAHOO.ext.grid.LoadableDataModel | ||
3 | * 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> | ||
4 | * @extends YAHOO.ext.grid.DefaultDataModel | ||
5 | * @constructor | ||
6 | * @param {String} dataType YAHOO.ext.grid.LoadableDataModel.XML, YAHOO.ext.grid.LoadableDataModel.TEXT or YAHOO.ext.grid.JSON | ||
7 | */ | ||
8 | YAHOO.ext.grid.LoadableDataModel = function(dataType){ | ||
9 | YAHOO.ext.grid.LoadableDataModel.superclass.constructor.call(this, []); | ||
10 | |||
11 | /** Fires when a successful load is completed - fireDirect sig: (this) | ||
12 | * @type YAHOO.util.CustomEvent | ||
13 | * @deprecated Use addListener instead of accessing directly | ||
14 | * @private | ||
15 | */ | ||
16 | this.onLoad = new YAHOO.util.CustomEvent('load'); | ||
17 | /** Fires when a load fails - fireDirect sig: (this, errorMsg, responseObj) | ||
18 | * @type YAHOO.util.CustomEvent | ||
19 | * @deprecated Use addListener instead of accessing directly | ||
20 | * @private | ||
21 | */ | ||
22 | this.onLoadException = new YAHOO.util.CustomEvent('loadException'); | ||
23 | /** | ||
24 | * @event load | ||
25 | * Fires when new data has successfully been loaded | ||
26 | * @param {DataModel} this | ||
27 | */ | ||
28 | this.events['load'] = this.onLoad; | ||
29 | /** | ||
30 | * @event beforeload | ||
31 | * Fires before a load takes place | ||
32 | * @param {DataModel} this | ||
33 | */ | ||
34 | this.events['beforeload'] = new YAHOO.util.CustomEvent('beforeload'); | ||
35 | /** | ||
36 | * @event loadexception | ||
37 | * Fires when there's an error loading data | ||
38 | * @param {DataModel} this | ||
39 | * @param {Exception} e The exception object or null | ||
40 | * @param {Object} response The Connect response object | ||
41 | */ | ||
42 | this.events['loadexception'] = this.onLoadException; | ||
43 | |||
44 | /**@private*/ | ||
45 | this.dataType = dataType; | ||
46 | /**@private*/ | ||
47 | this.preprocessors = []; | ||
48 | /**@private*/ | ||
49 | this.postprocessors = []; | ||
50 | |||
51 | // paging info | ||
52 | /** The active page @type Number*/ | ||
53 | this.loadedPage = 1; | ||
54 | /** True to use remote sorting, initPaging automatically sets this to true @type Boolean */ | ||
55 | this.remoteSort = false; | ||
56 | /** The number of records per page @type Number*/ | ||
57 | this.pageSize = 0; | ||
58 | /** The script/page to call to provide paged/sorted data @type String*/ | ||
59 | this.pageUrl = null; | ||
60 | /** An object of key/value pairs to be passed as parameters | ||
61 | * when loading pages/sorting @type Object*/ | ||
62 | this.baseParams = {}; | ||
63 | /** Maps named params to url parameters - Override to specify your own param names */ | ||
64 | this.paramMap = {'page':'page', 'pageSize':'pageSize', 'sortColumn':'sortColumn', 'sortDir':'sortDir'}; | ||
65 | |||
66 | }; | ||
67 | YAHOO.extendX(YAHOO.ext.grid.LoadableDataModel, YAHOO.ext.grid.DefaultDataModel, { | ||
68 | |||
69 | /** @ignore */ | ||
70 | setLoadedPage: function(pageNum, userCallback){ | ||
71 | this.loadedPage = pageNum; | ||
72 | if(typeof userCallback == 'function'){ | ||
73 | userCallback(); | ||
74 | } | ||
75 | }, | ||
76 | |||
77 | /** Returns true if this model uses paging @return Boolean */ | ||
78 | isPaged: function(){ | ||
79 | return this.pageSize > 0; | ||
80 | }, | ||
81 | |||
82 | /** Returns the total number of records available, override if needed @return {Number} */ | ||
83 | getTotalRowCount: function(){ | ||
84 | return this.totalCount || this.getRowCount(); | ||
85 | }, | ||
86 | |||
87 | /** Returns the number of records per page @return Number */ | ||
88 | getPageSize: function(){ | ||
89 | return this.pageSize; | ||
90 | }, | ||
91 | |||
92 | /** Returns the total number of pages available @return Number */ | ||
93 | getTotalPages: function(){ | ||
94 | if(this.getPageSize() == 0 || this.getTotalRowCount() == 0){ | ||
95 | return 1; | ||
96 | } | ||
97 | return Math.ceil(this.getTotalRowCount()/this.getPageSize()); | ||
98 | }, | ||
99 | |||
100 | /** Initializes paging for this model. | ||
101 | * @param {String} url | ||
102 | * @param {Number} pageSize | ||
103 | * @param {Object} baseParams (optional) Object containing key/value pairs to add to all requests | ||
104 | */ | ||
105 | initPaging: function(url, pageSize, baseParams){ | ||
106 | this.pageUrl = url; | ||
107 | this.pageSize = pageSize; | ||
108 | this.remoteSort = true; | ||
109 | if(baseParams) this.baseParams = baseParams; | ||
110 | }, | ||
111 | |||
112 | /** @ignore */ | ||
113 | createParams: function(pageNum, sortColumn, sortDir){ | ||
114 | var params = {}, map = this.paramMap; | ||
115 | for(var key in this.baseParams){ | ||
116 | if(typeof this.baseParams[key] != 'function'){ | ||
117 | params[key] = this.baseParams[key]; | ||
118 | } | ||
119 | } | ||
120 | params[map['page']] = pageNum; | ||
121 | params[map['pageSize']] = this.getPageSize(); | ||
122 | params[map['sortColumn']] = (typeof sortColumn == 'undefined' ? '' : sortColumn); | ||
123 | params[map['sortDir']] = sortDir || ''; | ||
124 | return params; | ||
125 | }, | ||
126 | |||
127 | /** | ||
128 | * Loads a page of data. | ||
129 | * @param {Number} pageNum Which page to load. The first page is 1. | ||
130 | * @param {Function} callback (optional) Optional callback when loading is complete | ||
131 | * @param {Boolean} keepExisting (optional) true to keep existing data and append the new data | ||
132 | */ | ||
133 | loadPage: function(pageNum, callback, keepExisting){ | ||
134 | var sort = this.getSortState(); | ||
135 | var params = this.createParams(pageNum, sort.column, sort.direction); | ||
136 | this.load(this.pageUrl, params, this.setLoadedPage.createDelegate(this, [pageNum, callback]), | ||
137 | keepExisting ? (pageNum-1) * this.pageSize : null); | ||
138 | }, | ||
139 | |||
140 | /** @ignore */ | ||
141 | applySort: function(suppressEvent){ | ||
142 | if(!this.remoteSort){ | ||
143 | YAHOO.ext.grid.LoadableDataModel.superclass.applySort.apply(this, arguments); | ||
144 | }else if(!suppressEvent){ | ||
145 | var sort = this.getSortState(); | ||
146 | if(sort.column){ | ||
147 | this.fireRowsSorted(sort.column, sort.direction, true); | ||
148 | } | ||
149 | } | ||
150 | }, | ||
151 | |||
152 | /** @ignore */ | ||
153 | resetPaging: function(){ | ||
154 | this.loadedPage = 1; | ||
155 | }, | ||
156 | |||
157 | /* Overridden sort method to use remote sorting if turned on */ | ||
158 | sort: function(sortInfo, columnIndex, direction, suppressEvent){ | ||
159 | if(!this.remoteSort){ | ||
160 | YAHOO.ext.grid.LoadableDataModel.superclass.sort.apply(this, arguments); | ||
161 | }else{ | ||
162 | this.sortInfo = sortInfo; | ||
163 | this.sortColumn = columnIndex; | ||
164 | this.sortDir = direction; | ||
165 | var params = this.createParams(this.loadedPage, columnIndex, direction); | ||
166 | this.load(this.pageUrl, params, this.fireRowsSorted.createDelegate(this, [columnIndex, direction, true])); | ||
167 | } | ||
168 | }, | ||
169 | |||
170 | /** | ||
171 | * Initiates the loading of the data from the specified URL - Failed load attempts will | ||
172 | * fire the {@link #loadexception} event. | ||
173 | * @param {Object/String} url The url from which the data can be loaded | ||
174 | * @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} | ||
175 | * @param {<i>Function</i>} callback (optional) Callback when load is complete - called with signature (this, true for success, false for failure) | ||
176 | * @param {<i>Number</i>} insertIndex (optional) if present, loaded data is inserted at the specified index instead of overwriting existing data | ||
177 | */ | ||
178 | load: function(url, params, callback, insertIndex){ | ||
179 | this.fireEvent('beforeload', this); | ||
180 | if(params && typeof params != 'string'){ // must be object | ||
181 | var buf = []; | ||
182 | for(var key in params){ | ||
183 | if(typeof params[key] != 'function'){ | ||
184 | buf.push(encodeURIComponent(key), '=', encodeURIComponent(params[key]), '&'); | ||
185 | } | ||
186 | } | ||
187 | delete buf[buf.length-1]; | ||
188 | params = buf.join(''); | ||
189 | } | ||
190 | var cb = { | ||
191 | success: this.processResponse, | ||
192 | failure: this.processException, | ||
193 | scope: this, | ||
194 | argument: {callback: callback, insertIndex: insertIndex} | ||
195 | }; | ||
196 | var method = params ? 'POST' : 'GET'; | ||
197 | this.transId = YAHOO.util.Connect.asyncRequest(method, url, cb, params); | ||
198 | }, | ||
199 | |||
200 | /**@private*/ | ||
201 | processResponse: function(response){ | ||
202 | var cb = response.argument.callback; | ||
203 | var keepExisting = (typeof response.argument.insertIndex == 'number'); | ||
204 | var insertIndex = response.argument.insertIndex; | ||
205 | switch(this.dataType){ | ||
206 | case YAHOO.ext.grid.LoadableDataModel.XML: | ||
207 | this.loadData(response.responseXML, cb, keepExisting, insertIndex); | ||
208 | break; | ||
209 | case YAHOO.ext.grid.LoadableDataModel.JSON: | ||
210 | var rtext = response.responseText; | ||
211 | try { // this code is a modified version of Yahoo! UI DataSource JSON parsing | ||
212 | // Trim leading spaces | ||
213 | while(rtext.substring(0,1) == " ") { | ||
214 | rtext = rtext.substring(1, rtext.length); | ||
215 | } | ||
216 | // Invalid JSON response | ||
217 | if(rtext.indexOf("{") < 0) { | ||
218 | throw "Invalid JSON response"; | ||
219 | } | ||
220 | |||
221 | // Empty (but not invalid) JSON response | ||
222 | if(rtext.indexOf("{}") === 0) { | ||
223 | this.loadData({}, response.argument.callback); | ||
224 | return; | ||
225 | } | ||
226 | |||
227 | // Turn the string into an object literal... | ||
228 | // ...eval is necessary here | ||
229 | var jsonObjRaw = eval("(" + rtext + ")"); | ||
230 | if(!jsonObjRaw) { | ||
231 | throw "Error evaling JSON response"; | ||
232 | } | ||
233 | this.loadData(jsonObjRaw, cb, keepExisting, insertIndex); | ||
234 | } catch(e) { | ||
235 | this.fireLoadException(e, response); | ||
236 | if(typeof cb == 'function'){ | ||
237 | cb(this, false); | ||
238 | } | ||
239 | } | ||
240 | break; | ||
241 | case YAHOO.ext.grid.LoadableDataModel.TEXT: | ||
242 | this.loadData(response.responseText, cb, keepExisting, insertIndex); | ||
243 | break; | ||
244 | }; | ||
245 | }, | ||
246 | |||
247 | /**@private*/ | ||
248 | processException: function(response){ | ||
249 | this.fireLoadException(null, response); | ||
250 | if(typeof response.argument.callback == 'function'){ | ||
251 | response.argument.callback(this, false); | ||
252 | } | ||
253 | }, | ||
254 | |||
255 | fireLoadException: function(e, responseObj){ | ||
256 | this.onLoadException.fireDirect(this, e, responseObj); | ||
257 | }, | ||
258 | |||
259 | fireLoadEvent: function(){ | ||
260 | this.fireEvent('load', this.loadedPage, this.getTotalPages()); | ||
261 | }, | ||
262 | |||
263 | /** | ||
264 | * Adds a preprocessor function to parse data before it is added to the Model - ie. Date.parse to parse dates. | ||
265 | * @param {Number} columnIndex | ||
266 | * @param {Function} fn | ||
267 | */ | ||
268 | addPreprocessor: function(columnIndex, fn){ | ||
269 | this.preprocessors[columnIndex] = fn; | ||
270 | }, | ||
271 | |||
272 | /** | ||
273 | * Gets the preprocessor function for the specified column. | ||
274 | * @param {Number} columnIndex | ||
275 | * @return {Function} | ||
276 | */ | ||
277 | getPreprocessor: function(columnIndex){ | ||
278 | return this.preprocessors[columnIndex]; | ||
279 | }, | ||
280 | |||
281 | /** | ||
282 | * Removes a preprocessor function. | ||
283 | * @param {Number} columnIndex | ||
284 | */ | ||
285 | removePreprocessor: function(columnIndex){ | ||
286 | this.preprocessors[columnIndex] = null; | ||
287 | }, | ||
288 | |||
289 | /** | ||
290 | * Adds a postprocessor function to format data before updating the underlying data source (ie. convert date to string before updating XML document). | ||
291 | * @param {Number} columnIndex | ||
292 | * @param {Function} fn | ||
293 | */ | ||
294 | addPostprocessor: function(columnIndex, fn){ | ||
295 | this.postprocessors[columnIndex] = fn; | ||
296 | }, | ||
297 | |||
298 | /** | ||
299 | * Gets the postprocessor function for the specified column. | ||
300 | * @param {Number} columnIndex | ||
301 | * @return {Function} | ||
302 | */ | ||
303 | getPostprocessor: function(columnIndex){ | ||
304 | return this.postprocessors[columnIndex]; | ||
305 | }, | ||
306 | |||
307 | /** | ||
308 | * Removes a postprocessor function. | ||
309 | * @param {Number} columnIndex | ||
310 | */ | ||
311 | removePostprocessor: function(columnIndex){ | ||
312 | this.postprocessors[columnIndex] = null; | ||
313 | }, | ||
314 | /** | ||
315 | * Empty interface method - Called to process the data returned by the XHR - Classes which extend LoadableDataModel should implement this method. | ||
316 | * See {@link YAHOO.ext.XMLDataModel} for an example implementation. | ||
317 | */ | ||
318 | loadData: function(data, callback, keepExisting, insertIndex){ | ||
319 | |||
320 | } | ||
321 | }); | ||
322 | |||
323 | YAHOO.ext.grid.LoadableDataModel.XML = 'xml'; | ||
324 | YAHOO.ext.grid.LoadableDataModel.JSON = 'json'; | ||
325 | YAHOO.ext.grid.LoadableDataModel.TEXT = 'text'; | ||
326 | |||
327 | |||
328 | |||
329 | |||
330 | |||
diff --git a/frontend/beta/js/YUI-extensions/data/Tree.js b/frontend/beta/js/YUI-extensions/data/Tree.js new file mode 100644 index 0000000..afa5b20 --- a/dev/null +++ b/frontend/beta/js/YUI-extensions/data/Tree.js | |||
@@ -0,0 +1,412 @@ | |||
1 | YAHOO.namespace('ext.data'); | ||
2 | |||
3 | /** | ||
4 | * @class YAHOO.ext.data.Tree | ||
5 | * @extends YAHOO.ext.util.Observable | ||
6 | * The class represents a tree data structure and bubbles all the events for it's nodes. The nodes | ||
7 | * in the tree have most standard DOM functionality. | ||
8 | * @constructor | ||
9 | * @param {Node} root (optional) The root node | ||
10 | */ | ||
11 | YAHOO.ext.data.Tree = function(root){ | ||
12 | this.nodeHash = {}; | ||
13 | this.root = null; | ||
14 | if(root){ | ||
15 | this.setRootNode(root); | ||
16 | } | ||
17 | this.events = { | ||
18 | 'append' : true, | ||
19 | 'remove' : true, | ||
20 | 'move' : true, | ||
21 | 'insert' : true, | ||
22 | 'beforeappend' : true, | ||
23 | 'beforeremove' : true, | ||
24 | 'beforemove' : true, | ||
25 | 'beforeinsert' : true | ||
26 | }; | ||
27 | }; | ||
28 | |||
29 | YAHOO.extendX(YAHOO.ext.data.Tree, YAHOO.ext.util.Observable, { | ||
30 | pathSeparator: '/', | ||
31 | |||
32 | getRootNode : function(){ | ||
33 | return this.root; | ||
34 | }, | ||
35 | |||
36 | setRootNode : function(node){ | ||
37 | this.root = node; | ||
38 | node.ownerTree = this; | ||
39 | node.isRoot = true; | ||
40 | return node; | ||
41 | }, | ||
42 | |||
43 | getNodeById : function(id){ | ||
44 | return this.nodeHash[id]; | ||
45 | }, | ||
46 | |||
47 | registerNode : function(node){ | ||
48 | this.nodeHash[node.id] = node; | ||
49 | }, | ||
50 | |||
51 | unregisterNode : function(node){ | ||
52 | delete this.nodeHash[node.id]; | ||
53 | }, | ||
54 | |||
55 | toString : function(){ | ||
56 | return '[Tree'+(this.id?' '+this.id:'')+']'; | ||
57 | } | ||
58 | }); | ||
59 | |||
60 | /** | ||
61 | * @class YAHOO.ext.tree.Node | ||
62 | * @extends YAHOO.ext.util.Observable | ||
63 | * @cfg {String} text The text for this node | ||
64 | * @cfg {String} id The id for this node | ||
65 | * @constructor | ||
66 | * @param {Object} attributes The attributes/config for the node | ||
67 | */ | ||
68 | YAHOO.ext.data.Node = function(attributes){ | ||
69 | this.attributes = attributes || {}; | ||
70 | this.leaf = this.attributes.leaf; | ||
71 | this.id = this.attributes.id; | ||
72 | if(!this.id){ | ||
73 | this.id = YAHOO.util.Dom.generateId(null, 'ynode-'); | ||
74 | this.attributes.id = this.id; | ||
75 | } | ||
76 | |||
77 | this.childNodes = []; | ||
78 | if(!this.childNodes.indexOf){ // indexOf is a must | ||
79 | this.childNodes.indexOf = function(o){ | ||
80 | for(var i = 0, len = this.length; i < len; i++){ | ||
81 | if(this[i] == o) return i; | ||
82 | } | ||
83 | return -1; | ||
84 | }; | ||
85 | } | ||
86 | this.parentNode = null; | ||
87 | this.firstChild = null; | ||
88 | this.lastChild = null; | ||
89 | this.previousSibling = null; | ||
90 | this.nextSibling = null; | ||
91 | |||
92 | this.events = { | ||
93 | 'append' : true, | ||
94 | 'remove' : true, | ||
95 | 'move' : true, | ||
96 | 'insert' : true, | ||
97 | 'beforeappend' : true, | ||
98 | 'beforeremove' : true, | ||
99 | 'beforemove' : true, | ||
100 | 'beforeinsert' : true | ||
101 | }; | ||
102 | }; | ||
103 | |||
104 | YAHOO.extendX(YAHOO.ext.data.Node, YAHOO.ext.util.Observable, { | ||
105 | fireEvent : function(evtName){ | ||
106 | // first do standard event for this node | ||
107 | if(YAHOO.ext.data.Node.superclass.fireEvent.apply(this, arguments) === false){ | ||
108 | return false; | ||
109 | } | ||
110 | // then bubble it up to the tree if the event wasn't cancelled | ||
111 | if(this.ownerTree){ | ||
112 | if(this.ownerTree.fireEvent.apply(this.ownerTree, arguments) === false){ | ||
113 | return false; | ||
114 | } | ||
115 | } | ||
116 | return true; | ||
117 | }, | ||
118 | |||
119 | isLeaf : function(){ | ||
120 | return this.leaf === true; | ||
121 | }, | ||
122 | |||
123 | setFirstChild : function(node){ | ||
124 | this.firstChild = node; | ||
125 | }, | ||
126 | |||
127 | setLastChild : function(node){ | ||
128 | this.lastChild = node; | ||
129 | }, | ||
130 | |||
131 | isLast : function(){ | ||
132 | return (!this.parentNode ? true : this.parentNode.lastChild == this); | ||
133 | }, | ||
134 | |||
135 | isFirst : function(){ | ||
136 | return (!this.parentNode ? true : this.parentNode.firstChild == this); | ||
137 | }, | ||
138 | |||
139 | hasChildNodes : function(){ | ||
140 | return !this.isLeaf() && this.childNodes.length > 0; | ||
141 | }, | ||
142 | |||
143 | appendChild : function(node){ | ||
144 | var multi = false; | ||
145 | if(node instanceof Array){ | ||
146 | multi = node; | ||
147 | }else if(arguments.length > 1){ | ||
148 | multi = arguments; | ||
149 | } | ||
150 | // if passed an array or multiple args do them one by one | ||
151 | if(multi){ | ||
152 | for(var i = 0, len = multi.length; i < len; i++) { | ||
153 | this.appendChild(multi[i]); | ||
154 | } | ||
155 | }else{ | ||
156 | if(this.fireEvent('beforeappend', this.ownerTree, this, node) === false){ | ||
157 | return false; | ||
158 | } | ||
159 | var index = this.childNodes.length; | ||
160 | var oldParent = node.parentNode; | ||
161 | // it's a move, make sure we move it cleanly | ||
162 | if(oldParent){ | ||
163 | if(node.fireEvent('beforemove', node.getOwnerTree(), node, oldParent, this, index) === false){ | ||
164 | return false; | ||
165 | } | ||
166 | oldParent.removeChild(node); | ||
167 | } | ||
168 | var index = this.childNodes.length; | ||
169 | if(index == 0){ | ||
170 | this.setFirstChild(node); | ||
171 | } | ||
172 | this.childNodes.push(node); | ||
173 | node.parentNode = this; | ||
174 | var ps = this.childNodes[index-1]; | ||
175 | if(ps){ | ||
176 | node.previousSibling = ps; | ||
177 | ps.nextSibling = node; | ||
178 | } | ||
179 | this.setLastChild(node); | ||
180 | node.setOwnerTree(this.getOwnerTree()); | ||
181 | this.fireEvent('append', this.ownerTree, this, node, index); | ||
182 | if(oldParent){ | ||
183 | node.fireEvent('move', this.ownerTree, node, oldParent, this, index); | ||
184 | } | ||
185 | return node; | ||
186 | } | ||
187 | }, | ||
188 | |||
189 | removeChild : function(node){ | ||
190 | var index = this.childNodes.indexOf(node); | ||
191 | if(index == -1){ | ||
192 | return false; | ||
193 | } | ||
194 | if(this.fireEvent('beforeremove', this.ownerTree, this, node) === false){ | ||
195 | return false; | ||
196 | } | ||
197 | |||
198 | // remove it from childNodes collection | ||
199 | this.childNodes.splice(index, 1); | ||
200 | |||
201 | // update siblings | ||
202 | if(node.previousSibling){ | ||
203 | node.previousSibling.nextSibling = node.nextSibling; | ||
204 | } | ||
205 | if(node.nextSibling){ | ||
206 | node.nextSibling.previousSibling = node.previousSibling; | ||
207 | } | ||
208 | |||
209 | // update child refs | ||
210 | if(this.firstChild == node){ | ||
211 | this.setFirstChild(node.nextSibling); | ||
212 | } | ||
213 | if(this.lastChild == node){ | ||
214 | this.setLastChild(node.previousSibling); | ||
215 | } | ||
216 | |||
217 | node.setOwnerTree(null); | ||
218 | // clear any references from the node | ||
219 | node.parentNode = null; | ||
220 | node.previousSibling = null; | ||
221 | node.nextSibling = null; | ||
222 | this.fireEvent('remove', this.ownerTree, this, node); | ||
223 | return node; | ||
224 | }, | ||
225 | |||
226 | insertBefore : function(node, refNode){ | ||
227 | if(!refNode){ // like standard Dom, refNode can be null for append | ||
228 | return this.appendChild(node); | ||
229 | } | ||
230 | // nothing to do | ||
231 | if(node == refNode){ | ||
232 | return false; | ||
233 | } | ||
234 | |||
235 | if(this.fireEvent('beforeinsert', this.ownerTree, this, node, refNode) === false){ | ||
236 | return false; | ||
237 | } | ||
238 | var index = this.childNodes.indexOf(refNode); | ||
239 | var oldParent = node.parentNode; | ||
240 | var refIndex = index; | ||
241 | |||
242 | // when moving internally, indexes will change after remove | ||
243 | if(oldParent == this && this.childNodes.indexOf(node) < index){ | ||
244 | refIndex--; | ||
245 | } | ||
246 | |||
247 | // it's a move, make sure we move it cleanly | ||
248 | if(oldParent){ | ||
249 | if(node.fireEvent('beforemove', node.getOwnerTree(), node, oldParent, this, index, refNode) === false){ | ||
250 | return false; | ||
251 | } | ||
252 | oldParent.removeChild(node); | ||
253 | } | ||
254 | if(refIndex == 0){ | ||
255 | this.setFirstChild(node); | ||
256 | } | ||
257 | this.childNodes.splice(refIndex, 0, node); | ||
258 | node.parentNode = this; | ||
259 | var ps = this.childNodes[refIndex-1]; | ||
260 | if(ps){ | ||
261 | node.previousSibling = ps; | ||
262 | ps.nextSibling = node; | ||
263 | } | ||
264 | node.nextSibling = refNode; | ||
265 | node.setOwnerTree(this.getOwnerTree()); | ||
266 | this.fireEvent('insert', this.ownerTree, this, node, refNode); | ||
267 | if(oldParent){ | ||
268 | node.fireEvent('move', this.ownerTree, node, oldParent, this, refIndex, refNode); | ||
269 | } | ||
270 | return node; | ||
271 | }, | ||
272 | |||
273 | item : function(index){ | ||
274 | return this.childNodes[index]; | ||
275 | }, | ||
276 | |||
277 | replaceChild : function(newChild, oldChild){ | ||
278 | this.insertBefore(newChild, oldChild); | ||
279 | this.removeChild(oldChild); | ||
280 | return oldChild; | ||
281 | }, | ||
282 | |||
283 | indexOf : function(child){ | ||
284 | return this.childNodes.indexOf(child); | ||
285 | }, | ||
286 | |||
287 | getOwnerTree : function(){ | ||
288 | // if it doesn't have one, look for one | ||
289 | if(!this.ownerTree){ | ||
290 | var p = this; | ||
291 | while(p){ | ||
292 | if(p.ownerTree){ | ||
293 | this.ownerTree = p.ownerTree; | ||
294 | break; | ||
295 | } | ||
296 | p = p.parentNode; | ||
297 | } | ||
298 | } | ||
299 | return this.ownerTree; | ||
300 | }, | ||
301 | |||
302 | setOwnerTree : function(tree){ | ||
303 | // if it's move, we need to update everyone | ||
304 | if(tree != this.ownerTree){ | ||
305 | if(this.ownerTree){ | ||
306 | this.ownerTree.unregisterNode(this); | ||
307 | } | ||
308 | this.ownerTree = tree; | ||
309 | var cs = this.childNodes; | ||
310 | for(var i = 0, len = cs.length; i < len; i++) { | ||
311 | cs[i].setOwnerTree(tree); | ||
312 | } | ||
313 | if(tree){ | ||
314 | tree.registerNode(this); | ||
315 | } | ||
316 | } | ||
317 | }, | ||
318 | |||
319 | getPath : function(attr){ | ||
320 | attr = attr || 'id'; | ||
321 | var p = this.parentNode; | ||
322 | var b = [this.attributes[attr]]; | ||
323 | while(p){ | ||
324 | b.unshift(p.attributes[attr]); | ||
325 | p = p.parentNode; | ||
326 | } | ||
327 | var sep = this.getOwnerTree().pathSeparator; | ||
328 | return sep + b.join(sep); | ||
329 | }, | ||
330 | |||
331 | bubble : function(fn, scope, args){ | ||
332 | var p = this; | ||
333 | while(p){ | ||
334 | if(fn.call(scope || p, args || p) === false){ | ||
335 | break; | ||
336 | } | ||
337 | p = p.parentNode; | ||
338 | } | ||
339 | }, | ||
340 | |||
341 | cascade : function(fn, scope, args){ | ||
342 | if(fn.call(scope || this, args || this) !== false){ | ||
343 | var cs = this.childNodes; | ||
344 | for(var i = 0, len = cs.length; i < len; i++) { | ||
345 | cs[i].cascade(fn, scope, args); | ||
346 | } | ||
347 | } | ||
348 | }, | ||
349 | |||
350 | eachChild : function(fn, scope, args){ | ||
351 | var cs = this.childNodes; | ||
352 | for(var i = 0, len = cs.length; i < len; i++) { | ||
353 | if(fn.call(scope || this, args || cs[i]) === false){ | ||
354 | break; | ||
355 | } | ||
356 | } | ||
357 | }, | ||
358 | |||
359 | findChild : function(attribute, value){ | ||
360 | var cs = this.childNodes; | ||
361 | for(var i = 0, len = cs.length; i < len; i++) { | ||
362 | if(cs[i].attributes[attribute] == value){ | ||
363 | return cs[i]; | ||
364 | } | ||
365 | } | ||
366 | return null; | ||
367 | }, | ||
368 | |||
369 | /** | ||
370 | * Sorts this nodes children using the supplied sort function | ||
371 | * @param {Function} fn | ||
372 | * @param {Object} scope | ||
373 | */ | ||
374 | sort : function(fn, scope){ | ||
375 | var cs = this.childNodes; | ||
376 | var len = cs.length; | ||
377 | if(len > 0){ | ||
378 | var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn; | ||
379 | cs.sort(sortFn); | ||
380 | for(var i = 0; i < len; i++){ | ||
381 | var n = cs[i]; | ||
382 | n.previousSibling = cs[i-1]; | ||
383 | n.nextSibling = cs[i+1]; | ||
384 | if(i == 0){ | ||
385 | this.setFirstChild(n); | ||
386 | } | ||
387 | if(i == len-1){ | ||
388 | this.setLastChild(n); | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | }, | ||
393 | |||
394 | contains : function(node){ | ||
395 | return node.isAncestor(this); | ||
396 | }, | ||
397 | |||
398 | isAncestor : function(node){ | ||
399 | var p = this.parentNode; | ||
400 | while(p){ | ||
401 | if(p == node){ | ||
402 | return true; | ||
403 | } | ||
404 | p = p.parentNode; | ||
405 | } | ||
406 | return false; | ||
407 | }, | ||
408 | |||
409 | toString : function(){ | ||
410 | return '[Node'+(this.id?' '+this.id:'')+']'; | ||
411 | } | ||
412 | }); | ||
diff --git a/frontend/beta/js/YUI-extensions/data/XMLDataModel.js b/frontend/beta/js/YUI-extensions/data/XMLDataModel.js new file mode 100644 index 0000000..e312a9e --- a/dev/null +++ b/frontend/beta/js/YUI-extensions/data/XMLDataModel.js | |||
@@ -0,0 +1,274 @@ | |||
1 | /** | ||
2 | * @class YAHOO.ext.grid.XMLDataModel | ||
3 | * This is an implementation of a DataModel used by the Grid. It works | ||
4 | * with XML data. | ||
5 | * <br>Example schema from Amazon search: | ||
6 | * <pre><code> | ||
7 | * var schema = { | ||
8 | * tagName: 'Item', | ||
9 | * id: 'ASIN', | ||
10 | * fields: ['Author', 'Title', 'Manufacturer', 'ProductGroup'] | ||
11 | * }; | ||
12 | * </code></pre> | ||
13 | * @extends YAHOO.ext.grid.LoadableDataModel | ||
14 | * @constructor | ||
15 | * @param {Object} schema The schema to use | ||
16 | * @param {XMLDocument} xml An XML document to load immediately | ||
17 | */ | ||
18 | YAHOO.ext.grid.XMLDataModel = function(schema, xml){ | ||
19 | YAHOO.ext.grid.XMLDataModel.superclass.constructor.call(this, YAHOO.ext.grid.LoadableDataModel.XML); | ||
20 | /**@private*/ | ||
21 | this.schema = schema; | ||
22 | this.xml = xml; | ||
23 | if(xml){ | ||
24 | this.loadData(xml); | ||
25 | } | ||
26 | this.idSeed = 0; | ||
27 | }; | ||
28 | YAHOO.extendX(YAHOO.ext.grid.XMLDataModel, YAHOO.ext.grid.LoadableDataModel, { | ||
29 | |||
30 | getDocument: function(){ | ||
31 | return this.xml; | ||
32 | }, | ||
33 | |||
34 | /** | ||
35 | * Overrides loadData in LoadableDataModel to process XML | ||
36 | * @param {XMLDocument} doc The document to load | ||
37 | * @param {<i>Function</i>} callback (optional) callback to call when loading is complete | ||
38 | * @param {<i>Boolean</i>} keepExisting (optional) true to keep existing data | ||
39 | * @param {<i>Number</i>} insertIndex (optional) if present, loaded data is inserted at the specified index instead of overwriting existing data | ||
40 | */ | ||
41 | loadData: function(doc, callback, keepExisting, insertIndex){ | ||
42 | this.xml = doc; | ||
43 | var idField = this.schema.id; | ||
44 | var fields = this.schema.fields; | ||
45 | if(this.schema.totalTag){ | ||
46 | this.totalCount = null; | ||
47 | var totalNode = doc.getElementsByTagName(this.schema.totalTag); | ||
48 | if(totalNode && totalNode.item(0) && totalNode.item(0).firstChild) { | ||
49 | var v = parseInt(totalNode.item(0).firstChild.nodeValue, 10); | ||
50 | if(!isNaN(v)){ | ||
51 | this.totalCount = v; | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | var rowData = []; | ||
56 | var nodes = doc.getElementsByTagName(this.schema.tagName); | ||
57 | if(nodes && nodes.length > 0) { | ||
58 | for(var i = 0; i < nodes.length; i++) { | ||
59 | var node = nodes.item(i); | ||
60 | var colData = []; | ||
61 | colData.node = node; | ||
62 | colData.id = this.getNamedValue(node, idField, String(++this.idSeed)); | ||
63 | for(var j = 0; j < fields.length; j++) { | ||
64 | var val = this.getNamedValue(node, fields[j], ""); | ||
65 | if(this.preprocessors[j]){ | ||
66 | val = this.preprocessors[j](val); | ||
67 | } | ||
68 | colData.push(val); | ||
69 | } | ||
70 | rowData.push(colData); | ||
71 | } | ||
72 | } | ||
73 | if(keepExisting !== true){ | ||
74 | YAHOO.ext.grid.XMLDataModel.superclass.removeAll.call(this); | ||
75 | } | ||
76 | if(typeof insertIndex != 'number'){ | ||
77 | insertIndex = this.getRowCount(); | ||
78 | } | ||
79 | YAHOO.ext.grid.XMLDataModel.superclass.insertRows.call(this, insertIndex, rowData); | ||
80 | if(typeof callback == 'function'){ | ||
81 | callback(this, true); | ||
82 | } | ||
83 | this.fireLoadEvent(); | ||
84 | }, | ||
85 | |||
86 | /** | ||
87 | * Adds a row to this DataModel and syncs the XML document | ||
88 | * @param {String} id The id of the row, if null the next row index is used | ||
89 | * @param {Array} cellValues The cell values for this row | ||
90 | * @return {Number} The index of the new row (if the model is sorted this index may not be accurate) | ||
91 | */ | ||
92 | addRow: function(id, cellValues){ | ||
93 | var node = this.createNode(this.xml, id, cellValues); | ||
94 | cellValues.id = id || ++this.idSeed; | ||
95 | cellValues.node = node; | ||
96 | return YAHOO.ext.grid.XMLDataModel.superclass.addRow.call(this, cellValues); | ||
97 | }, | ||
98 | |||
99 | /** | ||
100 | * Inserts a row into this DataModel and syncs the XML document | ||
101 | * @param {Number} index The index to insert the row | ||
102 | * @param {String} id The id of the row, if null the next row index is used | ||
103 | * @param {Array} cellValues The cell values for this row | ||
104 | * @return {Number} The index of the new row (if the model is sorted this index may not be accurate) | ||
105 | */ | ||
106 | insertRow: function(index, id, cellValues){ | ||
107 | var node = this.createNode(this.xml, id, cellValues); | ||
108 | cellValues.id = id || ++this.idSeed; | ||
109 | cellValues.node = node; | ||
110 | return YAHOO.ext.grid.XMLDataModel.superclass.insertRow.call(this, index, cellValues); | ||
111 | }, | ||
112 | |||
113 | /** | ||
114 | * Removes the row from DataModel and syncs the XML document | ||
115 | * @param {Number} index The index of the row to remove | ||
116 | */ | ||
117 | removeRow: function(index){ | ||
118 | var node = this.data[index].node; | ||
119 | node.parentNode.removeChild(node); | ||
120 | YAHOO.ext.grid.XMLDataModel.superclass.removeRow.call(this, index, index); | ||
121 | }, | ||
122 | |||
123 | getNode: function(rowIndex){ | ||
124 | return this.data[rowIndex].node; | ||
125 | }, | ||
126 | |||
127 | /** | ||
128 | * Override this method to define your own node creation routine for when new rows are added. | ||
129 | * By default this method clones the first node and sets the column values in the newly cloned node. | ||
130 | * In many instances this will not work and you will have to create the node manually. | ||
131 | * @param {XMLDocument} xmlDoc The xml document being used by this model | ||
132 | * @param {String/Number} id The row id | ||
133 | * @param {Array} colData The column data for the new node | ||
134 | * @return {XMLNode} The created node | ||
135 | */ | ||
136 | createNode: function(xmlDoc, id, colData){ | ||
137 | var template = this.data[0].node; | ||
138 | var newNode = template.cloneNode(true); | ||
139 | var fields = this.schema.fields; | ||
140 | for(var i = 0, len = fields.length; i < len; i++){ | ||
141 | var nodeValue = colData[i]; | ||
142 | if(this.postprocessors[i]){ | ||
143 | nodeValue = this.postprocessors[i](nodeValue); | ||
144 | } | ||
145 | this.setNamedValue(newNode, fields[i], nodeValue); | ||
146 | } | ||
147 | if(id){ | ||
148 | this.setNamedValue(newNode, this.schema.idField, id); | ||
149 | } | ||
150 | template.parentNode.appendChild(newNode); | ||
151 | return newNode; | ||
152 | }, | ||
153 | |||
154 | /** | ||
155 | * @private | ||
156 | * Convenience function looks for value in attributes, then in children tags - also | ||
157 | * normalizes namespace matches (ie matches ns:tag, FireFox matches tag and not ns:tag). | ||
158 | */ | ||
159 | getNamedValue: function(node, name, defaultValue){ | ||
160 | if(!node || !name){ | ||
161 | return defaultValue; | ||
162 | } | ||
163 | var nodeValue = defaultValue; | ||
164 | var attrNode = node.attributes.getNamedItem(name); | ||
165 | if(attrNode) { | ||
166 | nodeValue = attrNode.value; | ||
167 | } else { | ||
168 | var childNode = node.getElementsByTagName(name); | ||
169 | if(childNode && childNode.item(0) && childNode.item(0).firstChild) { | ||
170 | nodeValue = childNode.item(0).firstChild.nodeValue; | ||
171 | }else{ | ||
172 | // try to strip namespace for FireFox | ||
173 | var index = name.indexOf(':'); | ||
174 | if(index > 0){ | ||
175 | return this.getNamedValue(node, name.substr(index+1), defaultValue); | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | return nodeValue; | ||
180 | }, | ||
181 | |||
182 | /** | ||
183 | * @private | ||
184 | * Convenience function set a value in the underlying xml node. | ||
185 | */ | ||
186 | setNamedValue: function(node, name, value){ | ||
187 | if(!node || !name){ | ||
188 | return; | ||
189 | } | ||
190 | var attrNode = node.attributes.getNamedItem(name); | ||
191 | if(attrNode) { | ||
192 | attrNode.value = value; | ||
193 | return; | ||
194 | } | ||
195 | var childNode = node.getElementsByTagName(name); | ||
196 | if(childNode && childNode.item(0) && childNode.item(0).firstChild) { | ||
197 | childNode.item(0).firstChild.nodeValue = value; | ||
198 | }else{ | ||
199 | // try to strip namespace for FireFox | ||
200 | var index = name.indexOf(':'); | ||
201 | if(index > 0){ | ||
202 | this.setNamedValue(node, name.substr(index+1), value); | ||
203 | } | ||
204 | } | ||
205 | }, | ||
206 | |||
207 | /** | ||
208 | * Overrides DefaultDataModel.setValueAt to update the underlying XML Document | ||
209 | * @param {Object} value The new value | ||
210 | * @param {Number} rowIndex | ||
211 | * @param {Number} colIndex | ||
212 | */ | ||
213 | setValueAt: function(value, rowIndex, colIndex){ | ||
214 | var node = this.data[rowIndex].node; | ||
215 | if(node){ | ||
216 | var nodeValue = value; | ||
217 | if(this.postprocessors[colIndex]){ | ||
218 | nodeValue = this.postprocessors[colIndex](value); | ||
219 | } | ||
220 | this.setNamedValue(node, this.schema.fields[colIndex], nodeValue); | ||
221 | } | ||
222 | YAHOO.ext.grid.XMLDataModel.superclass.setValueAt.call(this, value, rowIndex, colIndex); | ||
223 | }, | ||
224 | |||
225 | /** | ||
226 | * Overrides getRowId in DefaultDataModel to return the ID value of the specified node. | ||
227 | * @param {Number} rowIndex | ||
228 | * @return {Number} | ||
229 | */ | ||
230 | getRowId: function(rowIndex){ | ||
231 | return this.data[rowIndex].id; | ||
232 | }, | ||
233 | |||
234 | addRows : function(rowData){ | ||
235 | for(var j = 0, len = rowData.length; j < len; j++){ | ||
236 | var cellValues = rowData[j]; | ||
237 | var id = ++this.idSeed; | ||
238 | var node = this.createNode(this.xml, id, cellValues); | ||
239 | cellValues.node=node; | ||
240 | cellValues.id = cellValues.id || id; | ||
241 | YAHOO.ext.grid.XMLDataModel.superclass.addRow.call(this,cellValues); | ||
242 | } | ||
243 | }, | ||
244 | |||
245 | insertRows : function(index, rowData){ | ||
246 | // copy original array so it is not reversed | ||
247 | rowData = rowData.slice(0).reverse(); | ||
248 | for(var j = 0, len = rowData.length; j < len; j++){ | ||
249 | var cellValues = rowData[j]; | ||
250 | var id = ++this.idSeed; | ||
251 | var node = this.createNode(this.xml, id, cellValues); | ||
252 | cellValues.id = cellValues.id || id; | ||
253 | cellValues.node = node; | ||
254 | YAHOO.ext.grid.XMLDataModel.superclass.insertRow.call(this, index, cellValues); | ||
255 | } | ||
256 | } | ||
257 | }); | ||
258 | |||
259 | YAHOO.ext.grid.XMLQueryDataModel = function(){ | ||
260 | YAHOO.ext.grid.XMLQueryDataModel.superclass.constructor.apply(this, arguments); | ||
261 | }; | ||
262 | YAHOO.extendX(YAHOO.ext.grid.XMLQueryDataModel, YAHOO.ext.grid.XMLDataModel, { | ||
263 | getNamedValue: function(node, name, defaultValue){ | ||
264 | if(!node || !name){ | ||
265 | return defaultValue; | ||
266 | } | ||
267 | var nodeValue = defaultValue; | ||
268 | var childNode = cssQuery(name, node); | ||
269 | if(childNode && childNode[0]) { | ||
270 | nodeValue = childNode[0].firstChild.nodeValue; | ||
271 | } | ||
272 | return nodeValue; | ||
273 | } | ||
274 | }); | ||