]> git.pond.sub.org Git - eow/blob - static/dojo-release-1.1.1/dojox/data/AtomReadStore.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dojox / data / AtomReadStore.js
1 if(!dojo._hasResource["dojox.data.AtomReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojox.data.AtomReadStore"] = true;
3 dojo.provide("dojox.data.AtomReadStore");
4
5 dojo.require("dojo.data.util.simpleFetch");
6 dojo.require("dojo.data.util.filter");
7 dojo.require("dojo.date.stamp");
8
9 dojo.experimental("dojox.data.AtomReadStore");
10
11 dojo.declare("dojox.data.AtomReadStore", null, {
12         //      summary:
13         //              A read only data store for Atom XML based services or documents
14         //      description:
15         //              A data store for Atom XML based services or documents.  This store is still under development
16         //              and doesn't support wildcard filtering yet.  Attribute filtering is limited to category or id.
17
18         constructor: function(/* object */ args) {
19                 //      summary:
20                 //              Constructor for the AtomRead store.
21                 //      args:
22                 //              An anonymous object to initialize properties.  It expects the following values:
23                 //              url:                    The url to a service or an XML document that represents the store
24                 //              unescapeHTML:   A boolean to specify whether or not to unescape HTML text
25                 //              sendQuery:              A boolean indicate to add a query string to the service URL
26
27                 if(args){
28                         this.url = args.url;
29                         this.rewriteUrl = args.rewriteUrl;
30                         this.label = args.label || this.label;
31                         this.sendQuery = (args.sendQuery || args.sendquery || this.sendQuery);
32                         this.unescapeHTML = args.unescapeHTML;
33                 }
34                 if(!this.url){
35                         throw new Error("AtomReadStore: a URL must be specified when creating the data store");
36                 }
37         },
38
39         //Values that may be set by the parser.
40         //Ergo, have to be instantiated to something
41         //So the parser knows how to set them.
42         url: "",
43
44         label: "title",
45
46         sendQuery: false,
47
48         unescapeHTML: false,
49
50         /* dojo.data.api.Read */
51
52         getValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue){
53                 //      summary:
54                 //              Return an attribute value
55                 //      description:
56                 //              'item' must be an instance of an object created by the AtomReadStore instance.
57                 //              Accepted attributes are id, subtitle, title, summary, content, author, updated,
58                 //              published, category, link and alternate
59                 //      item:
60                 //              An item returned by a call to the 'fetch' method.
61                 //      attribute:
62                 //              A attribute of the Atom Entry
63                 //      defaultValue:
64                 //              A default value
65                 //      returns:
66                 //              An attribute value found, otherwise 'defaultValue'
67                 this._assertIsItem(item);
68                 this._assertIsAttribute(attribute);
69                 this._initItem(item);
70                 attribute = attribute.toLowerCase();
71                 //If the attribute has previously been retrieved, then return it
72                 if(!item._attribs[attribute] && !item._parsed){
73                         this._parseItem(item);
74                         item._parsed = true;
75                 }
76                 var retVal = item._attribs[attribute];
77
78                 if(!retVal && attribute=="summary") {
79                         var content = this.getValue(item, "content");
80                         var regexp = new RegExp("/(<([^>]+)>)/g", "i");
81                         var text = content.text.replace(regexp,"");
82                         retVal = {
83                                 text: text.substring(0, Math.min(400, text.length)),
84                                 type: "text"
85                         };
86                         item._attribs[attribute] = retVal;
87                 }
88
89                 if(retVal && this.unescapeHTML){
90                         if ((attribute == "content" || attribute == "summary" || attribute == "subtitle") && !item["_"+attribute+"Escaped"]) {
91                                 retVal.text = this._unescapeHTML(retVal.text);
92                                 item["_"+attribute+"Escaped"] = true;
93                         }
94                 }
95                 return retVal ? dojo.isArray(retVal) ? retVal[0]: retVal : undefined;
96         },
97
98         getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
99                 //      summary:
100                 //              Return an attribute value
101                 //      description:
102                 //              'item' must be an instance of an object created by the AtomReadStore instance.
103                 //              Accepted attributes are id, subtitle, title, summary, content, author, updated,
104                 //              published, category, link and alternate
105                 //      item:
106                 //              An item returned by a call to the 'fetch' method.
107                 //      attribute:
108                 //              A attribute of the Atom Entry
109                 //      defaultValue:
110                 //              A default value
111                 //      returns:
112                 //              An array of values for the attribute value found, otherwise 'defaultValue'
113                 this._assertIsItem(item);
114                 this._assertIsAttribute(attribute);
115                 this._initItem(item);
116                 attribute = attribute.toLowerCase();
117                 //If the attribute has previously been retrieved, then return it
118                 if(!item._attribs[attribute]){
119                         this._parseItem(item);
120                 }
121                 var retVal = item._attribs[attribute];
122                 return retVal ? ((retVal.length !== undefined && typeof(retVal) !== "string") ? retVal : [retVal]) : undefined;
123         },
124
125         getAttributes: function(/* item */ item) {
126                 //      summary:
127                 //              Return an array of attribute names
128                 //      description:
129                 //              'item' must be have been created by the AtomReadStore instance.
130                 //              tag names of child elements and XML attribute names of attributes
131                 //              specified to the element are returned along with special attribute
132                 //              names applicable to the element including "tagName", "childNodes"
133                 //              if the element has child elements, "text()" if the element has
134                 //              child text nodes, and attribute names in '_attributeMap' that match
135                 //              the tag name of the element.
136                 //      item:
137                 //              An XML element
138                 //      returns:
139                 //              An array of attributes found
140                 this._assertIsItem(item);
141                 if(!item._attribs){
142                         this._initItem(item);
143                         this._parseItem(item);
144                 }
145                 var attrNames = [];
146                 for(var x in item._attribs){
147                         attrNames.push(x);
148                 }
149                 return attrNames; //array
150         },
151
152         hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
153                 //      summary:
154                 //              Check whether an element has the attribute
155                 //      item:
156                 //              'item' must be created by the AtomReadStore instance.
157                 //      attribute:
158                 //              An attribute of an Atom Entry item.
159                 //      returns:
160                 //              True if the element has the attribute, otherwise false
161                 return (this.getValue(item, attribute) !== undefined); //boolean
162         },
163
164         containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value){
165                 //      summary:
166                 //              Check whether the attribute values contain the value
167                 //      item:
168                 //              'item' must be an instance of a dojox.data.XmlItem from the store instance.
169                 //      attribute:
170                 //              A tag name of a child element, An XML attribute name or one of
171                 //              special names
172                 //      returns:
173                 //              True if the attribute values contain the value, otherwise false
174                 var values = this.getValues(item, attribute);
175                 for(var i = 0; i < values.length; i++){
176                         if((typeof value === "string")){
177                                 if(values[i].toString && values[i].toString() === value){
178                                         return true;
179                                 }
180                         }else if (values[i] === value){
181                                 return true; //boolean
182                         }
183                 }
184                 return false;//boolean
185         },
186
187         isItem: function(/* anything */ something){
188                 //      summary:
189                 //              Check whether the object is an item (XML element)
190                 //      item:
191                 //              An object to check
192                 //      returns:
193                 //              True if the object is an XML element, otherwise false
194                 if(something && something.element && something.store && something.store === this){
195                         return true; //boolean
196                 }
197                 return false; //boolran
198         },
199
200         isItemLoaded: function(/* anything */ something){
201                 //      summary:
202                 //              Check whether the object is an item (XML element) and loaded
203                 //      item:
204                 //              An object to check
205                 //      returns:
206                 //              True if the object is an XML element, otherwise false
207                 return this.isItem(something); //boolean
208         },
209
210         loadItem: function(/* object */ keywordArgs){
211                 //      summary:
212                 //              Load an item (XML element)
213                 //      keywordArgs:
214                 //              object containing the args for loadItem.  See dojo.data.api.Read.loadItem()
215         },
216
217         getFeatures: function() {
218                 //      summary:
219                 //              Return supported data APIs
220                 //      returns:
221                 //              "dojo.data.api.Read" and "dojo.data.api.Write"
222                 var features = {
223                         "dojo.data.api.Read": true
224                 };
225                 return features; //array
226         },
227
228         getLabel: function(/* item */ item){
229                 //      summary:
230                 //              See dojo.data.api.Read.getLabel()
231                 if((this.label !== "") && this.isItem(item)){
232                         var label = this.getValue(item,this.label);
233                         if(label && label.text){
234                                 return label.text;
235                         }else if (label){
236                                 return label.toString();
237                         }else{
238                                 return undefined;
239                         }
240                 }
241                 return undefined; //undefined
242         },
243
244         getLabelAttributes: function(/* item */ item){
245                 //      summary:
246                 //              See dojo.data.api.Read.getLabelAttributes()
247                 if(this.label !== ""){
248                         return [this.label]; //array
249                 }
250                 return null; //null
251         },
252
253         getFeedValue: function(attribute, defaultValue){
254                 // summary:
255                 //              Non-API method for retrieving values regarding the Atom feed,
256                 //              rather than the Atom entries.
257                 var values = this.getFeedValues(attribute, defaultValue);
258                 if(dojo.isArray(values)){
259                         return values[0];
260                 }
261                 return values;
262         },
263
264         getFeedValues: function(attribute, defaultValue){
265                 // summary:
266                 //              Non-API method for retrieving values regarding the Atom feed,
267                 //              rather than the Atom entries.
268                 if(!this.doc){
269                         return defaultValue;
270                 }
271                 if(!this._feedMetaData){
272                         this._feedMetaData = {
273                                 element: this.doc.getElementsByTagName("feed")[0],
274                                 store: this,
275                                 _attribs: {}
276                         };
277                         this._parseItem(this._feedMetaData);
278                 }
279                 return this._feedMetaData._attribs[attribute] || defaultValue;
280         },
281
282         _initItem: function(item){
283                 // summary:
284                 //              Initializes an item before it can be parsed.
285                 if(!item._attribs){
286                         item._attribs = {};
287                 }
288         },
289
290         _fetchItems: function(request, fetchHandler, errorHandler) {
291                 // summary:
292                 //              Retrieves the items from the Atom XML document.
293                 var url = this._getFetchUrl(request);
294                 if(!url){
295                         errorHandler(new Error("No URL specified."));
296                         return;
297                 }
298                 var localRequest = (!this.sendQuery ? request : null); // use request for _getItems()
299
300                 var _this = this;
301                 var docHandler = function(data){
302                         _this.doc = data;
303                         var items = _this._getItems(data, localRequest);
304                         var query = request.query;
305                         if(query) {
306                                 if(query.id) {
307                                         items = dojo.filter(items, function(item){
308                                                 return (_this.getValue(item, "id") == query.id);
309                                         });
310                                 } else if(query.category){
311                                         items = dojo.filter(items, function(entry) {
312                                                 var cats = _this.getValues(entry, "category");
313                                                 if(!cats){
314                                                         return false;
315                                                 }
316                                                 return dojo.some(cats, "return item.term=='"+query.category+"'");
317                                         });
318                                 }
319                         }
320
321                         if (items && items.length > 0) {
322                                 fetchHandler(items, request);
323                         }
324                         else {
325                                 fetchHandler([], request);
326                         }
327                 };
328
329                 if (this.doc) {
330                         docHandler(this.doc);
331                 }else{
332                         var getArgs = {
333                                 url: url,
334                                 handleAs: "xml"//,
335                         //      preventCache: true
336                         };
337                         var getHandler = dojo.xhrGet(getArgs);
338                         getHandler.addCallback(docHandler);
339
340                         getHandler.addErrback(function(data){
341                                 errorHandler(data, request);
342                         });
343                 }
344         },
345
346         _getFetchUrl: function(request){
347                 if(!this.sendQuery){
348                         return this.url;
349                 }
350                 var query = request.query;
351                 if(!query){
352                         return this.url;
353                 }
354                 if(dojo.isString(query)){
355                         return this.url + query;
356                 }
357                 var queryString = "";
358                 for(var name in query){
359                         var value = query[name];
360                         if(value){
361                                 if(queryString){
362                                         queryString += "&";
363                                 }
364                                 queryString += (name + "=" + value);
365                         }
366                 }
367                 if(!queryString){
368                         return this.url;
369                 }
370                 //Check to see if the URL already has query params or not.
371                 var fullUrl = this.url;
372                 if(fullUrl.indexOf("?") < 0){
373                         fullUrl += "?";
374                 }else{
375                         fullUrl += "&";
376                 }
377                 return fullUrl + queryString;
378         },
379
380         _getItems: function(document, request) {
381                 // summary:
382                 //              Parses the document in a first pass
383                 if(this._items){
384                         return this._items;
385                 }
386                 var items = [];
387                 var nodes = [];
388                 
389                 if(document.childNodes.length < 1){
390                         this._items = items;
391                         console.log("dojox.data.AtomReadStore: Received an invalid Atom document. Check the content type header");
392                         return items;
393                 }
394                 
395                 var feedNodes = dojo.filter(document.childNodes, "return item.tagName && item.tagName.toLowerCase() == 'feed'");
396
397                 var query = request.query;
398
399                 if(!feedNodes || feedNodes.length != 1){
400                         console.log("dojox.data.AtomReadStore: Received an invalid Atom document, number of feed tags = " + (feedNodes? feedNodes.length : 0));
401                         return items;
402                 }
403
404                 nodes = dojo.filter(feedNodes[0].childNodes, "return item.tagName && item.tagName.toLowerCase() == 'entry'");
405
406                 if(request.onBegin){
407                         request.onBegin(nodes.length);
408                 }
409
410                 for(var i = 0; i < nodes.length; i++){
411                         var node = nodes[i];
412                         if(node.nodeType != 1 /*ELEMENT_NODE*/){
413                                 continue;
414                         }
415                         items.push(this._getItem(node));
416                 }
417                 this._items = items;
418                 return items;
419         },
420
421         close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
422                  //     summary:
423                  //             See dojo.data.api.Read.close()
424         },
425
426 /* internal API */
427
428         _getItem: function(element){
429                 return {
430                         element: element,
431                         store: this
432                 };
433         },
434
435         _parseItem: function(item) {
436                 var attribs = item._attribs;
437                 var _this = this;
438                 var text, type;
439
440                 function getNodeText(node){
441                         var txt = node.textContent || node.innerHTML || node.innerXML;                  
442                         if(!txt && node.childNodes[0]){
443                                 var child = node.childNodes[0];
444                                 if (child && (child.nodeType == 3 || child.nodeType == 4)) {
445                                         txt = node.childNodes[0].nodeValue;
446                                 }
447                         }
448                         return txt;
449                 }
450                 function parseTextAndType(node) {
451                         return {text: getNodeText(node),type: node.getAttribute("type")};
452                 }
453                 dojo.forEach(item.element.childNodes, function(node){
454                         var tagName = node.tagName ? node.tagName.toLowerCase() : "";
455                         switch(tagName){
456                                 case "title":
457                                         attribs[tagName] = {
458                                                 text: getNodeText(node),
459                                                 type: node.getAttribute("type")
460                                         }; break;
461                                 case "subtitle":
462                                 case "summary":
463                                 case "content":
464                                         attribs[tagName] = parseTextAndType(node);
465                                         break;
466                                 case "author":
467                                         var nameNode ,uriNode;
468                                         dojo.forEach(node.childNodes, function(child){
469                                                 if(!child.tagName){
470                                                         return;
471                                                 }
472                                                 switch(child.tagName.toLowerCase()){
473                                                         case "name":nameNode = child;break;
474                                                         case "uri": uriNode = child; break;
475                                                 }
476                                         });
477                                         var author = {};
478                                         if(nameNode && nameNode.length == 1){
479                                                 author.name = getNodeText(nameNode[0]);
480                                         }
481                                         if(uriNode && uriNode.length == 1){
482                                                 author.uri = getNodeText(uriNode[0]);
483                                         }
484                                         attribs[tagName] = author;
485                                         break;
486                                 case "id": attribs[tagName] = getNodeText(node); break;
487                                 case "updated": attribs[tagName] = dojo.date.stamp.fromISOString(getNodeText(node) );break;
488                                 case "published": attribs[tagName] = dojo.date.stamp.fromISOString(getNodeText(node));break;
489                                 case "category":
490                                         if(!attribs[tagName]){
491                                                 attribs[tagName] = [];
492                                         }
493                                         attribs[tagName].push({scheme:node.getAttribute("scheme"), term: node.getAttribute("term")});
494                                         break;
495                                 case "link":
496                                         if(!attribs[tagName]){
497                                                 attribs[tagName] = [];
498                                         }
499                                         var link = {
500                                                 rel: node.getAttribute("rel"),
501                                                 href: node.getAttribute("href"),
502                                                 type: node.getAttribute("type")};
503                                         attribs[tagName].push(link);
504
505                                         if(link.rel == "alternate") {
506                                                 attribs["alternate"] = link;
507                                         }
508                                         break;
509                                 default:
510                                         break;
511                         }
512                 });
513         },
514
515         _unescapeHTML : function(text) {
516                 //Replace HTML character codes with their unencoded equivalents, e.g. &#8217; with '
517                 text = text.replace(/&#8217;/m , "'").replace(/&#8243;/m , "\"").replace(/&#60;/m,">").replace(/&#62;/m,"<").replace(/&#38;/m,"&");
518                 return text;
519         },
520
521         _assertIsItem: function(/* item */ item){
522                 //      summary:
523                 //              This function tests whether the item passed in is indeed an item in the store.
524                 //      item: 
525                 //              The item to test for being contained by the store.
526                 if(!this.isItem(item)){ 
527                         throw new Error("dojox.data.AtomReadStore: Invalid item argument.");
528                 }
529         },
530
531         _assertIsAttribute: function(/* attribute-name-string */ attribute){
532                 //      summary:
533                 //              This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
534                 //      attribute: 
535                 //              The attribute to test for being contained by the store.
536                 if(typeof attribute !== "string"){ 
537                         throw new Error("dojox.data.AtomReadStore: Invalid attribute argument.");
538                 }
539         }
540 });
541 dojo.extend(dojox.data.AtomReadStore,dojo.data.util.simpleFetch);
542
543 }