Diffstat (limited to 'frontend/beta/js/YUI-extensions/data/XMLDataModel.js') (more/less context) (ignore whitespace changes)
-rw-r--r-- | frontend/beta/js/YUI-extensions/data/XMLDataModel.js | 274 |
1 files changed, 274 insertions, 0 deletions
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 | }); | ||