source: Dev/trunk/src/client/dojox/data/HtmlTableStore.js @ 529

Last change on this file since 529 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 13.8 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/data/util/simpleFetch",
3                "dojo/data/util/filter", "dojox/xml/parser"],
4  function(kernel, declare, lang, dom, array, xhr, has, 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                // args:
36                //              An anonymous object to initialize properties.  It expects the following values:
37                //
38                //              - tableId:      The id of the HTML table to use.
39                //
40                //              OR
41                //
42                //              - url:          The url of the remote page to load
43                //              - tableId:      The id of the table element in the remote page
44               
45                if(args.url){
46                        if(!args.tableId)
47                                throw new Error("dojo.data.HtmlTableStore: Cannot instantiate using url without an id!");
48                        this.url = args.url;
49                        this.tableId = args.tableId;
50                }else{
51                        if(args.tableId){
52                                this._rootNode = dom.byId(args.tableId);
53                                this.tableId = this._rootNode.id;
54                        }else{
55                                this._rootNode = dom.byId(this.tableId);
56                        }
57                        this._getHeadings();
58                        for(var i=0; i<this._rootNode.rows.length; i++){
59                                this._rootNode.rows[i].store = this;
60                        }
61                }
62        },
63
64        // url: [public] string
65        //              The URL from which to load an HTML document for data loading
66        url: "",
67       
68        // tableId: [public] string
69        //              The id of the table to load as store contents.
70        tableId: "",
71
72        _getHeadings: function(){
73                // summary:
74                //              Function to load the attribute names from the table header so that the
75                //              attributes (cells in a row), can have a reasonable name.
76                this._headings = [];
77                array.forEach(this._rootNode.tHead.rows[0].cells, lang.hitch(this, function(th){
78                        this._headings.push(xmlParser.textContent(th));
79                }));
80        },
81       
82        _getAllItems: function(){
83                // summary:
84                //              Function to return all rows in the table as an array of items.
85                var items = [];
86                for(var i=1; i<this._rootNode.rows.length; i++){
87                        items.push(this._rootNode.rows[i]);
88                }
89                return items; //array
90        },
91       
92        _assertIsItem: function(/* item */ item){
93                // summary:
94                //              This function tests whether the item passed in is indeed an item in the store.
95                // item:
96                //              The item to test for being contained by the store.
97                if(!this.isItem(item)){
98                        throw new Error("dojo.data.HtmlTableStore: a function was passed an item argument that was not an item");
99                }
100        },
101
102        _assertIsAttribute: function(/* String */ attribute){
103                // summary:
104                //              This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
105                // attribute:
106                //              The attribute to test for being contained by the store.
107                // returns:
108                //              Returns the index (column) that the attribute resides in the row.
109                if(typeof attribute !== "string"){
110                        throw new Error("dojo.data.HtmlTableStore: a function was passed an attribute argument that was not an attribute name string");
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|Number|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                // item:
184                //              The data item to examine for attribute values.
185                // attribute:
186                //              The attribute to inspect.
187                // value:
188                //              The value to match.
189                // regexp:
190                //              Optional regular expression generated off value if value was of string type to handle wildcarding.
191                //              If present and attribute values are string, then it can be used for comparison instead of 'value'
192                var values = this.getValues(item, attribute);
193                for(var i = 0; i < values.length; ++i){
194                        var possibleValue = values[i];
195                        if(typeof possibleValue === "string" && regexp){
196                                return (possibleValue.match(regexp) !== null);
197                        }else{
198                                //Non-string matching.
199                                if(value === possibleValue){
200                                        return true; // Boolean
201                                }
202                        }
203                }
204                return false; // Boolean
205        },
206
207        isItem: function(/* anything */ something){
208                // summary:
209                //              See dojo/data/api/Read.isItem()
210                if(something && something.store && something.store === this){
211                        return true; //boolean
212                }
213                return false; //boolean
214        },
215
216        isItemLoaded: function(/* anything */ something){
217                // summary:
218                //              See dojo/data/api/Read.isItemLoaded()
219                return this.isItem(something);
220        },
221
222        loadItem: function(/* Object */ keywordArgs){
223                // summary:
224                //              See dojo/data/api/Read.loadItem()
225                this._assertIsItem(keywordArgs.item);
226        },
227       
228        _fetchItems: function(request, fetchHandler, errorHandler){
229                // summary:
230                //              Fetch items (XML elements) that match to a query
231                // description:
232                //              If '_fetchUrl' is specified, it is used to load an XML document
233                //              with a query string.
234                //              Otherwise and if 'url' is specified, the XML document is
235                //              loaded and list XML elements that match to a query (set of element
236                //              names and their text attribute values that the items to contain).
237                //              A wildcard, "*" can be used to query values to match all
238                //              occurrences.
239                //              If '_rootItem' is specified, it is used to fetch items.
240                // request:
241                //              A request object
242                // fetchHandler:
243                //              A function to call for fetched items
244                // errorHandler:
245                //              A function to call on error
246               
247                if(this._rootNode){
248                        this._finishFetchItems(request, fetchHandler, errorHandler);
249                }else{
250                        if(!this.url){
251                                this._rootNode = dom.byId(this.tableId);
252                                this._getHeadings();
253                                for(var i=0; i<this._rootNode.rows.length; i++){
254                                        this._rootNode.rows[i].store = this;
255                                }
256                        }else{
257                                var getArgs = {
258                                                url: this.url,
259                                                handleAs: "text"
260                                        };
261                                var self = this;
262                                var getHandler = xhr.get(getArgs);
263                                getHandler.addCallback(function(data){
264                                        var findNode = function(node, id){
265                                                if(node.id == id){
266                                                        return node; //object
267                                                }
268                                                if(node.childNodes){
269                                                        for(var i=0; i<node.childNodes.length; i++){
270                                                                var returnNode = findNode(node.childNodes[i], id);
271                                                                if(returnNode){
272                                                                        return returnNode; //object
273                                                                }
274                                                        }
275                                                }
276                                                return null; //null
277                                        }
278
279                                        var d = document.createElement("div");
280                                        d.innerHTML = data;
281                                        self._rootNode = findNode(d, self.tableId);
282                                        self._getHeadings.call(self);
283                                        for(var i=0; i<self._rootNode.rows.length; i++){
284                                                self._rootNode.rows[i].store = self;
285                                        }
286                                        self._finishFetchItems(request, fetchHandler, errorHandler);
287                                });
288                                getHandler.addErrback(function(error){
289                                        errorHandler(error, request);
290                                });
291                        }
292                }
293        },
294       
295        _finishFetchItems: function(request, fetchHandler, errorHandler){
296                // summary:
297                //              Internal function for processing the passed in request and locating the requested items.
298                var items = null;
299                var arrayOfAllItems = this._getAllItems();
300                if(request.query){
301                        var ignoreCase = request.queryOptions ? request.queryOptions.ignoreCase : false;
302                        items = [];
303
304                        //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
305                        //same value for each item examined.  Much more efficient.
306                        var regexpList = {};
307                        var value;
308                        var key;
309                        for(key in request.query){
310                                value = request.query[key]+'';
311                                if(typeof value === "string"){
312                                        regexpList[key] = filter.patternToRegExp(value, ignoreCase);
313                                }
314                        }
315
316                        for(var i = 0; i < arrayOfAllItems.length; ++i){
317                                var match = true;
318                                var candidateItem = arrayOfAllItems[i];
319                                for(key in request.query){
320                                        value = request.query[key]+'';
321                                        if(!this._containsValue(candidateItem, key, value, regexpList[key])){
322                                                match = false;
323                                        }
324                                }
325                                if(match){
326                                        items.push(candidateItem);
327                                }
328                        }
329                        fetchHandler(items, request);
330                }else{
331                        // We want a copy to pass back in case the parent wishes to sort the array.  We shouldn't allow resort
332                        // of the internal list so that multiple callers can get listsand sort without affecting each other.
333                        if(arrayOfAllItems.length> 0){
334                                items = arrayOfAllItems.slice(0,arrayOfAllItems.length);
335                        }
336                        fetchHandler(items, request);
337                }
338        },
339
340        getFeatures: function(){
341                // summary:
342                //              See dojo/data/api/Read.getFeatures()
343                return {
344                        'dojo.data.api.Read': true,
345                        'dojo.data.api.Identity': true
346                };
347        },
348       
349        close: function(/*dojo/data/api/Request|Object?*/ request){
350                // summary:
351                //              See dojo/data/api/Read.close()
352
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
392                //Identity isn't taken from a public attribute.
393                return null;
394        },
395
396        fetchItemByIdentity: function(keywordArgs){
397                // summary:
398                //              See dojo/data/api/Identity.fetchItemByIdentity()
399                var identity = keywordArgs.identity;
400                var self = this;
401                var item = null;
402                var scope = null;
403
404                if(!this._rootNode){
405                        if(!this.url){
406                                this._rootNode = dom.byId(this.tableId);
407                                this._getHeadings();
408                                for(var i=0; i<this._rootNode.rows.length; i++){
409                                        this._rootNode.rows[i].store = this;
410                                }
411                                item = this._rootNode.rows[identity+1];
412                                if(keywordArgs.onItem){
413                                        scope = keywordArgs.scope?keywordArgs.scope:kernel.global;
414                                        keywordArgs.onItem.call(scope, item);
415                                }
416
417                        }else{
418                                var getArgs = {
419                                                url: this.url,
420                                                handleAs: "text"
421                                        };
422                                var getHandler = xhr.get(getArgs);
423                                getHandler.addCallback(function(data){
424                                        var findNode = function(node, id){
425                                                if(node.id == id){
426                                                        return node; //object
427                                                }
428                                                if(node.childNodes){
429                                                        for(var i=0; i<node.childNodes.length; i++){
430                                                                var returnNode = findNode(node.childNodes[i], id);
431                                                                if(returnNode){
432                                                                        return returnNode; //object
433                                                                }
434                                                        }
435                                                }
436                                                return null; //null
437                                        }
438                                        var d = document.createElement("div");
439                                        d.innerHTML = data;
440                                        self._rootNode = findNode(d, self.tableId);
441                                        self._getHeadings.call(self);
442                                        for(var i=0; i<self._rootNode.rows.length; i++){
443                                                self._rootNode.rows[i].store = self;
444                                        }
445                                        item = self._rootNode.rows[identity+1];
446                                        if(keywordArgs.onItem){
447                                                scope = keywordArgs.scope?keywordArgs.scope:kernel.global;
448                                                keywordArgs.onItem.call(scope, item);
449                                        }
450                                });
451                                getHandler.addErrback(function(error){
452                                        if(keywordArgs.onError){
453                                                scope = keywordArgs.scope?keywordArgs.scope:kernel.global;
454                                                keywordArgs.onError.call(scope, error);
455
456                                        }
457                                });
458                        }
459                }else{
460                        if(this._rootNode.rows[identity+1]){
461                                item = this._rootNode.rows[identity+1];
462                                if(keywordArgs.onItem){
463                                        scope = keywordArgs.scope?keywordArgs.scope:kernel.global;
464                                        keywordArgs.onItem.call(scope, item);
465                                }
466                        }
467                }
468        }
469});
470lang.extend(HtmlTableStore,simpleFetch);
471
472return HtmlTableStore;
473});
Note: See TracBrowser for help on using the repository browser.