source: Dev/branches/rest-dojo-ui/client/dojox/data/HtmlTableStore.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 13.9 KB
Line 
1define(["dojo/_base/kernel", "dojo/_base/declare", "dojo/_base/lang", "dojo/dom", "dojo/_base/array",
2                "dojo/_base/xhr", "dojo/_base/sniff", "dojo/_base/window", "dojo/data/util/simpleFetch",
3                "dojo/data/util/filter", "dojox/xml/parser"],
4  function(kernel, declare, lang, dom, array, xhr, has, winUtil, simpleFetch, filter, xmlParser) {
5
6var HtmlTableStore = declare("dojox.data.HtmlTableStore", null, {
7        constructor: function(/*Object*/args){
8                kernel.deprecated("dojox.data.HtmlTableStore", "Please use dojox.data.HtmlStore");
9                //      summary:
10                //              Initializer for the HTML table store.
11                //      description:
12                //              The HtmlTableStore can be created in one of two ways: a) by parsing an existing
13                //              table DOM node on the current page or b) by referencing an external url and giving
14                //              the id of the table in that page.  The remote url will be parsed as an html page.
15                //
16                //              The HTML table should be of the following form:
17                //              <table id="myTable">
18                //                      <thead>
19                //                              <tr>
20                //                                      <th>Attribute1</th>
21                //                                      <th>Attribute2</th>
22                //                              </tr>
23                //                      </thead>
24                //                      <tbody>
25                //                              <tr>
26                //                                      <td>Value1.1</td>
27                //                                      <td>Value1.2</td>
28                //                              </tr>
29                //                              <tr>
30                //                                      <td>Value2.1</td>
31                //                                      <td>Value2.2</td>
32                //                              </tr>
33                //                      </tbody>
34                //              </table>
35                //
36                //      args:
37                //              An anonymous object to initialize properties.  It expects the following values:
38                //              tableId:        The id of the HTML table to use.
39                //              OR
40                //              url:            The url of the remote page to load
41                //              tableId:        The id of the table element in the remote page
42               
43                if(args.url){
44                        if(!args.tableId)
45                                throw new Error("dojo.data.HtmlTableStore: Cannot instantiate using url without an id!");
46                        this.url = args.url;
47                        this.tableId = args.tableId;
48                }else{
49                        if(args.tableId){
50                                this._rootNode = dom.byId(args.tableId);
51                                this.tableId = this._rootNode.id;
52                        }else{
53                                this._rootNode = dom.byId(this.tableId);
54                        }
55                        this._getHeadings();
56                        for(var i=0; i<this._rootNode.rows.length; i++){
57                                this._rootNode.rows[i].store = this;
58                        }
59                }
60        },
61
62        // url: [public] string
63        //              The URL from which to load an HTML document for data loading
64        url: "",
65       
66        // tableId: [public] string
67        //              The id of the table to load as store contents.
68        tableId: "",
69
70        _getHeadings: function(){
71                //      summary:
72                //              Function to load the attribute names from the table header so that the
73                //              attributes (cells in a row), can have a reasonable name.
74                this._headings = [];
75                array.forEach(this._rootNode.tHead.rows[0].cells, lang.hitch(this, function(th){
76                        this._headings.push(xmlParser.textContent(th));
77                }));
78        },
79       
80        _getAllItems: function(){
81                //      summary:
82                //              Function to return all rows in the table as an array of items.
83                var items = [];
84                for(var i=1; i<this._rootNode.rows.length; i++){
85                        items.push(this._rootNode.rows[i]);
86                }
87                return items; //array
88        },
89       
90        _assertIsItem: function(/* item */ item){
91                //      summary:
92                //      This function tests whether the item passed in is indeed an item in the store.
93                //      item:
94                //              The item to test for being contained by the store.
95                if(!this.isItem(item)){
96                        throw new Error("dojo.data.HtmlTableStore: a function was passed an item argument that was not an item");
97                }
98        },
99
100        _assertIsAttribute: function(/* String */ attribute){
101                //      summary:
102                //      This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
103                //      attribute:
104                //              The attribute to test for being contained by the store.
105                //
106                //      returns:
107                //              Returns the index (column) that the attribute resides in the row.
108                if(typeof attribute !== "string"){
109                        throw new Error("dojo.data.HtmlTableStore: a function was passed an attribute argument that was not an attribute name string");
110                        return -1;
111                }
112                return array.indexOf(this._headings, attribute); //int
113        },
114
115/***************************************
116     dojo.data.api.Read API
117***************************************/
118       
119        getValue: function(     /* item */ item,
120                                                /* attribute-name-string */ attribute,
121                                                /* value? */ defaultValue){
122                //      summary:
123                //      See dojo.data.api.Read.getValue()
124                var values = this.getValues(item, attribute);
125                return (values.length > 0)?values[0]:defaultValue; //Object || int || Boolean
126        },
127
128        getValues: function(/* item */ item,
129                                                /* attribute-name-string */ attribute){
130                //      summary:
131                //              See dojo.data.api.Read.getValues()
132
133                this._assertIsItem(item);
134                var index = this._assertIsAttribute(attribute);
135
136                if(index>-1){
137                        return [xmlParser.textContent(item.cells[index])] ;
138                }
139                return []; //Array
140        },
141
142        getAttributes: function(/* item */ item){
143                //      summary:
144                //              See dojo.data.api.Read.getAttributes()
145                this._assertIsItem(item);
146                var attributes = [];
147                for(var i=0; i<this._headings.length; i++){
148                        if(this.hasAttribute(item, this._headings[i]))
149                                attributes.push(this._headings[i]);
150                }
151                return attributes; //Array
152        },
153
154        hasAttribute: function( /* item */ item,
155                                                        /* attribute-name-string */ attribute){
156                //      summary:
157                //              See dojo.data.api.Read.hasAttribute()
158                return this.getValues(item, attribute).length > 0;
159        },
160
161        containsValue: function(/* item */ item,
162                                                        /* attribute-name-string */ attribute,
163                                                        /* anything */ value){
164                //      summary:
165                //              See dojo.data.api.Read.containsValue()
166                var regexp = undefined;
167                if(typeof value === "string"){
168                        regexp = filter.patternToRegExp(value, false);
169                }
170                return this._containsValue(item, attribute, value, regexp); //boolean.
171        },
172
173        _containsValue: function(       /* item */ item,
174                                                                /* attribute-name-string */ attribute,
175                                                                /* anything */ value,
176                                                                /* RegExp?*/ regexp){
177                //      summary:
178                //              Internal function for looking at the values contained by the item.
179                //      description:
180                //              Internal function for looking at the values contained by the item.  This
181                //              function allows for denoting if the comparison should be case sensitive for
182                //              strings or not (for handling filtering cases where string case should not matter)
183                //
184                //      item:
185                //              The data item to examine for attribute values.
186                //      attribute:
187                //              The attribute to inspect.
188                //      value:
189                //              The value to match.
190                //      regexp:
191                //              Optional regular expression generated off value if value was of string type to handle wildcarding.
192                //              If present and attribute values are string, then it can be used for comparison instead of 'value'
193                var values = this.getValues(item, attribute);
194                for(var i = 0; i < values.length; ++i){
195                        var possibleValue = values[i];
196                        if(typeof possibleValue === "string" && regexp){
197                                return (possibleValue.match(regexp) !== null);
198                        }else{
199                                //Non-string matching.
200                                if(value === possibleValue){
201                                        return true; // Boolean
202                                }
203                        }
204                }
205                return false; // Boolean
206        },
207
208        isItem: function(/* anything */ something){
209                //      summary:
210                //              See dojo.data.api.Read.isItem()
211                if(something && something.store && something.store === this){
212                        return true; //boolean
213                }
214                return false; //boolean
215        },
216
217        isItemLoaded: function(/* anything */ something){
218                //      summary:
219                //              See dojo.data.api.Read.isItemLoaded()
220                return this.isItem(something);
221        },
222
223        loadItem: function(/* Object */ keywordArgs){
224                //      summary:
225                //              See dojo.data.api.Read.loadItem()
226                this._assertIsItem(keywordArgs.item);
227        },
228       
229        _fetchItems: function(request, fetchHandler, errorHandler){
230                //      summary:
231                //              Fetch items (XML elements) that match to a query
232                //      description:
233                //              If '_fetchUrl' is specified, it is used to load an XML document
234                //              with a query string.
235                //              Otherwise and if 'url' is specified, the XML document is
236                //              loaded and list XML elements that match to a query (set of element
237                //              names and their text attribute values that the items to contain).
238                //              A wildcard, "*" can be used to query values to match all
239                //              occurrences.
240                //              If '_rootItem' is specified, it is used to fetch items.
241                //      request:
242                //              A request object
243                //      fetchHandler:
244                //              A function to call for fetched items
245                //      errorHandler:
246                //              A function to call on error
247               
248                if(this._rootNode){
249                        this._finishFetchItems(request, fetchHandler, errorHandler);
250                }else{
251                        if(!this.url){
252                                this._rootNode = dom.byId(this.tableId);
253                                this._getHeadings();
254                                for(var i=0; i<this._rootNode.rows.length; i++){
255                                        this._rootNode.rows[i].store = this;
256                                }
257                        }else{
258                                var getArgs = {
259                                                url: this.url,
260                                                handleAs: "text"
261                                        };
262                                var self = this;
263                                var getHandler = xhr.get(getArgs);
264                                getHandler.addCallback(function(data){
265                                        var findNode = function(node, id){
266                                                if(node.id == id){
267                                                        return node; //object
268                                                }
269                                                if(node.childNodes){
270                                                        for(var i=0; i<node.childNodes.length; i++){
271                                                                var returnNode = findNode(node.childNodes[i], id);
272                                                                if(returnNode){
273                                                                        return returnNode; //object
274                                                                }
275                                                        }
276                                                }
277                                                return null; //null
278                                        }
279
280                                        var d = document.createElement("div");
281                                        d.innerHTML = data;
282                                        self._rootNode = findNode(d, self.tableId);
283                                        self._getHeadings.call(self);
284                                        for(var i=0; i<self._rootNode.rows.length; i++){
285                                                self._rootNode.rows[i].store = self;
286                                        }
287                                        self._finishFetchItems(request, fetchHandler, errorHandler);
288                                });
289                                getHandler.addErrback(function(error){
290                                        errorHandler(error, request);
291                                });
292                        }
293                }
294        },
295       
296        _finishFetchItems: function(request, fetchHandler, errorHandler){
297                //      summary:
298                //              Internal function for processing the passed in request and locating the requested items.
299                var items = null;
300                var arrayOfAllItems = this._getAllItems();
301                if(request.query){
302                        var ignoreCase = request.queryOptions ? request.queryOptions.ignoreCase : false;
303                        items = [];
304
305                        //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
306                        //same value for each item examined.  Much more efficient.
307                        var regexpList = {};
308                        var value;
309                        var key;
310                        for(key in request.query){
311                                value = request.query[key]+'';
312                                if(typeof value === "string"){
313                                        regexpList[key] = filter.patternToRegExp(value, ignoreCase);
314                                }
315                        }
316
317                        for(var i = 0; i < arrayOfAllItems.length; ++i){
318                                var match = true;
319                                var candidateItem = arrayOfAllItems[i];
320                                for(key in request.query){
321                                        value = request.query[key]+'';
322                                        if(!this._containsValue(candidateItem, key, value, regexpList[key])){
323                                                match = false;
324                                        }
325                                }
326                                if(match){
327                                        items.push(candidateItem);
328                                }
329                        }
330                        fetchHandler(items, request);
331                }else{
332                        // We want a copy to pass back in case the parent wishes to sort the array.  We shouldn't allow resort
333                        // of the internal list so that multiple callers can get listsand sort without affecting each other.
334                        if(arrayOfAllItems.length> 0){
335                                items = arrayOfAllItems.slice(0,arrayOfAllItems.length);
336                        }
337                        fetchHandler(items, request);
338                }
339        },
340
341        getFeatures: function(){
342                //      summary:
343                //              See dojo.data.api.Read.getFeatures()
344                return {
345                        'dojo.data.api.Read': true,
346                        'dojo.data.api.Identity': true
347                };
348        },
349       
350        close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
351                //      summary:
352                //              See dojo.data.api.Read.close()
353                // nothing to do here!
354        },
355
356        getLabel: function(/* item */ item){
357                //      summary:
358                //              See dojo.data.api.Read.getLabel()
359                if(this.isItem(item))
360                        return "Table Row #" + this.getIdentity(item);
361                return undefined;
362        },
363
364        getLabelAttributes: function(/* item */ item){
365                //      summary:
366                //              See dojo.data.api.Read.getLabelAttributes()
367                return null;
368        },
369
370/***************************************
371     dojo.data.api.Identity API
372***************************************/
373
374        getIdentity: function(/* item */ item){
375                //      summary:
376                //              See dojo.data.api.Identity.getIdentity()
377                this._assertIsItem(item);
378                //Opera doesn't support the sectionRowIndex,
379                //So, have to call the indexOf to locate it.
380                //Blah.
381                if(!has("opera")){
382                        return item.sectionRowIndex; // int
383                }else{
384                        return (array.indexOf(this._rootNode.rows, item) - 1) // int
385                }
386        },
387
388        getIdentityAttributes: function(/* item */ item){
389                 //     summary:
390                 //             See dojo.data.api.Identity.getIdentityAttributes()
391                 //Identity isn't taken from a public attribute.
392                 return null;
393        },
394
395        fetchItemByIdentity: function(keywordArgs){
396                //      summary:
397                //              See dojo.data.api.Identity.fetchItemByIdentity()
398                var identity = keywordArgs.identity;
399                var self = this;
400                var item = null;
401                var scope = null;
402
403                if(!this._rootNode){
404                        if(!this.url){
405                                this._rootNode = dom.byId(this.tableId);
406                                this._getHeadings();
407                                for(var i=0; i<this._rootNode.rows.length; i++){
408                                        this._rootNode.rows[i].store = this;
409                                }
410                                item = this._rootNode.rows[identity+1];
411                                if(keywordArgs.onItem){
412                                        scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
413                                        keywordArgs.onItem.call(scope, item);
414                                }
415
416                        }else{
417                                var getArgs = {
418                                                url: this.url,
419                                                handleAs: "text"
420                                        };
421                                var getHandler = xhr.get(getArgs);
422                                getHandler.addCallback(function(data){
423                                        var findNode = function(node, id){
424                                                if(node.id == id){
425                                                        return node; //object
426                                                }
427                                                if(node.childNodes){
428                                                        for(var i=0; i<node.childNodes.length; i++){
429                                                                var returnNode = findNode(node.childNodes[i], id);
430                                                                if(returnNode){
431                                                                        return returnNode; //object
432                                                                }
433                                                        }
434                                                }
435                                                return null; //null
436                                        }
437                                        var d = document.createElement("div");
438                                        d.innerHTML = data;
439                                        self._rootNode = findNode(d, self.tableId);
440                                        self._getHeadings.call(self);
441                                        for(var i=0; i<self._rootNode.rows.length; i++){
442                                                self._rootNode.rows[i].store = self;
443                                        }
444                                        item = self._rootNode.rows[identity+1];
445                                        if(keywordArgs.onItem){
446                                                scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
447                                                keywordArgs.onItem.call(scope, item);
448                                        }
449                                });
450                                getHandler.addErrback(function(error){
451                                        if(keywordArgs.onError){
452                                                scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
453                                                keywordArgs.onError.call(scope, error);
454
455                                        }
456                                });
457                        }
458                }else{
459                        if(this._rootNode.rows[identity+1]){
460                                item = this._rootNode.rows[identity+1];
461                                if(keywordArgs.onItem){
462                                        scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
463                                        keywordArgs.onItem.call(scope, item);
464                                }
465                        }
466                }
467        }
468});
469lang.extend(HtmlTableStore,simpleFetch);
470
471return HtmlTableStore;
472});
Note: See TracBrowser for help on using the repository browser.