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");
5 dojo.require("dojo.data.util.simpleFetch");
6 dojo.require("dojo.data.util.filter");
7 dojo.require("dojo.date.stamp");
9 dojo.experimental("dojox.data.AtomReadStore");
11 dojo.declare("dojox.data.AtomReadStore", null, {
13 // A read only data store for Atom XML based services or documents
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.
18 constructor: function(/* object */ args) {
20 // Constructor for the AtomRead store.
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
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;
35 throw new Error("AtomReadStore: a URL must be specified when creating the data store");
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.
50 /* dojo.data.api.Read */
52 getValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue){
54 // Return an attribute value
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
60 // An item returned by a call to the 'fetch' method.
62 // A attribute of the Atom Entry
66 // An attribute value found, otherwise 'defaultValue'
67 this._assertIsItem(item);
68 this._assertIsAttribute(attribute);
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);
76 var retVal = item._attribs[attribute];
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,"");
83 text: text.substring(0, Math.min(400, text.length)),
86 item._attribs[attribute] = retVal;
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;
95 return retVal ? dojo.isArray(retVal) ? retVal[0]: retVal : undefined;
98 getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
100 // Return an attribute value
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
106 // An item returned by a call to the 'fetch' method.
108 // A attribute of the Atom Entry
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);
121 var retVal = item._attribs[attribute];
122 return retVal ? ((retVal.length !== undefined && typeof(retVal) !== "string") ? retVal : [retVal]) : undefined;
125 getAttributes: function(/* item */ item) {
127 // Return an array of attribute names
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.
139 // An array of attributes found
140 this._assertIsItem(item);
142 this._initItem(item);
143 this._parseItem(item);
146 for(var x in item._attribs){
149 return attrNames; //array
152 hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
154 // Check whether an element has the attribute
156 // 'item' must be created by the AtomReadStore instance.
158 // An attribute of an Atom Entry item.
160 // True if the element has the attribute, otherwise false
161 return (this.getValue(item, attribute) !== undefined); //boolean
164 containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value){
166 // Check whether the attribute values contain the value
168 // 'item' must be an instance of a dojox.data.XmlItem from the store instance.
170 // A tag name of a child element, An XML attribute name or one of
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){
180 }else if (values[i] === value){
181 return true; //boolean
184 return false;//boolean
187 isItem: function(/* anything */ something){
189 // Check whether the object is an item (XML element)
191 // An object to check
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
197 return false; //boolran
200 isItemLoaded: function(/* anything */ something){
202 // Check whether the object is an item (XML element) and loaded
204 // An object to check
206 // True if the object is an XML element, otherwise false
207 return this.isItem(something); //boolean
210 loadItem: function(/* object */ keywordArgs){
212 // Load an item (XML element)
214 // object containing the args for loadItem. See dojo.data.api.Read.loadItem()
217 getFeatures: function() {
219 // Return supported data APIs
221 // "dojo.data.api.Read" and "dojo.data.api.Write"
223 "dojo.data.api.Read": true
225 return features; //array
228 getLabel: function(/* item */ item){
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){
236 return label.toString();
241 return undefined; //undefined
244 getLabelAttributes: function(/* item */ item){
246 // See dojo.data.api.Read.getLabelAttributes()
247 if(this.label !== ""){
248 return [this.label]; //array
253 getFeedValue: function(attribute, defaultValue){
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)){
264 getFeedValues: function(attribute, defaultValue){
266 // Non-API method for retrieving values regarding the Atom feed,
267 // rather than the Atom entries.
271 if(!this._feedMetaData){
272 this._feedMetaData = {
273 element: this.doc.getElementsByTagName("feed")[0],
277 this._parseItem(this._feedMetaData);
279 return this._feedMetaData._attribs[attribute] || defaultValue;
282 _initItem: function(item){
284 // Initializes an item before it can be parsed.
290 _fetchItems: function(request, fetchHandler, errorHandler) {
292 // Retrieves the items from the Atom XML document.
293 var url = this._getFetchUrl(request);
295 errorHandler(new Error("No URL specified."));
298 var localRequest = (!this.sendQuery ? request : null); // use request for _getItems()
301 var docHandler = function(data){
303 var items = _this._getItems(data, localRequest);
304 var query = request.query;
307 items = dojo.filter(items, function(item){
308 return (_this.getValue(item, "id") == query.id);
310 } else if(query.category){
311 items = dojo.filter(items, function(entry) {
312 var cats = _this.getValues(entry, "category");
316 return dojo.some(cats, "return item.term=='"+query.category+"'");
321 if (items && items.length > 0) {
322 fetchHandler(items, request);
325 fetchHandler([], request);
330 docHandler(this.doc);
335 // preventCache: true
337 var getHandler = dojo.xhrGet(getArgs);
338 getHandler.addCallback(docHandler);
340 getHandler.addErrback(function(data){
341 errorHandler(data, request);
346 _getFetchUrl: function(request){
350 var query = request.query;
354 if(dojo.isString(query)){
355 return this.url + query;
357 var queryString = "";
358 for(var name in query){
359 var value = query[name];
364 queryString += (name + "=" + value);
370 //Check to see if the URL already has query params or not.
371 var fullUrl = this.url;
372 if(fullUrl.indexOf("?") < 0){
377 return fullUrl + queryString;
380 _getItems: function(document, request) {
382 // Parses the document in a first pass
389 if(document.childNodes.length < 1){
391 console.log("dojox.data.AtomReadStore: Received an invalid Atom document. Check the content type header");
395 var feedNodes = dojo.filter(document.childNodes, "return item.tagName && item.tagName.toLowerCase() == 'feed'");
397 var query = request.query;
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));
404 nodes = dojo.filter(feedNodes[0].childNodes, "return item.tagName && item.tagName.toLowerCase() == 'entry'");
407 request.onBegin(nodes.length);
410 for(var i = 0; i < nodes.length; i++){
412 if(node.nodeType != 1 /*ELEMENT_NODE*/){
415 items.push(this._getItem(node));
421 close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
423 // See dojo.data.api.Read.close()
428 _getItem: function(element){
435 _parseItem: function(item) {
436 var attribs = item._attribs;
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;
450 function parseTextAndType(node) {
451 return {text: getNodeText(node),type: node.getAttribute("type")};
453 dojo.forEach(item.element.childNodes, function(node){
454 var tagName = node.tagName ? node.tagName.toLowerCase() : "";
458 text: getNodeText(node),
459 type: node.getAttribute("type")
464 attribs[tagName] = parseTextAndType(node);
467 var nameNode ,uriNode;
468 dojo.forEach(node.childNodes, function(child){
472 switch(child.tagName.toLowerCase()){
473 case "name":nameNode = child;break;
474 case "uri": uriNode = child; break;
478 if(nameNode && nameNode.length == 1){
479 author.name = getNodeText(nameNode[0]);
481 if(uriNode && uriNode.length == 1){
482 author.uri = getNodeText(uriNode[0]);
484 attribs[tagName] = author;
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;
490 if(!attribs[tagName]){
491 attribs[tagName] = [];
493 attribs[tagName].push({scheme:node.getAttribute("scheme"), term: node.getAttribute("term")});
496 if(!attribs[tagName]){
497 attribs[tagName] = [];
500 rel: node.getAttribute("rel"),
501 href: node.getAttribute("href"),
502 type: node.getAttribute("type")};
503 attribs[tagName].push(link);
505 if(link.rel == "alternate") {
506 attribs["alternate"] = link;
515 _unescapeHTML : function(text) {
516 //Replace HTML character codes with their unencoded equivalents, e.g. ’ with '
517 text = text.replace(/’/m , "'").replace(/″/m , "\"").replace(/</m,">").replace(/>/m,"<").replace(/&/m,"&");
521 _assertIsItem: function(/* item */ item){
523 // This function tests whether the item passed in is indeed an item in the store.
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.");
531 _assertIsAttribute: function(/* attribute-name-string */ attribute){
533 // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
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.");
541 dojo.extend(dojox.data.AtomReadStore,dojo.data.util.simpleFetch);