123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- /*
- Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
- */
- if(!dojo._hasResource["dojox.data.AtomReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
- dojo._hasResource["dojox.data.AtomReadStore"] = true;
- dojo.provide("dojox.data.AtomReadStore");
- dojo.require("dojo.data.util.filter");
- dojo.require("dojo.data.util.simpleFetch");
- dojo.require("dojo.date.stamp");
- dojo.experimental("dojox.data.AtomReadStore");
- dojo.declare("dojox.data.AtomReadStore", null, {
- // summary:
- // A read only data store for Atom XML based services or documents
- // description:
- // A data store for Atom XML based services or documents. This store is still under development
- // and doesn't support wildcard filtering yet. Attribute filtering is limited to category or id.
- constructor: function(/* object */ args){
- // summary:
- // Constructor for the AtomRead store.
- // args:
- // An anonymous object to initialize properties. It expects the following values:
- // url: The url to a service or an XML document that represents the store
- // unescapeHTML: A boolean to specify whether or not to unescape HTML text
- // sendQuery: A boolean indicate to add a query string to the service URL
- if(args){
- this.url = args.url;
- this.rewriteUrl = args.rewriteUrl;
- this.label = args.label || this.label;
- this.sendQuery = (args.sendQuery || args.sendquery || this.sendQuery);
- this.unescapeHTML = args.unescapeHTML;
- if("urlPreventCache" in args){
- this.urlPreventCache = args.urlPreventCache?true:false;
- }
- }
- if(!this.url){
- throw new Error("AtomReadStore: a URL must be specified when creating the data store");
- }
- },
- //Values that may be set by the parser.
- //Ergo, have to be instantiated to something
- //So the parser knows how to set them.
- url: "",
- label: "title",
- sendQuery: false,
- unescapeHTML: false,
- //Configurable preventCache option for the URL.
- urlPreventCache: false,
- /* dojo.data.api.Read */
- getValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue){
- // summary:
- // Return an attribute value
- // description:
- // 'item' must be an instance of an object created by the AtomReadStore instance.
- // Accepted attributes are id, subtitle, title, summary, content, author, updated,
- // published, category, link and alternate
- // item:
- // An item returned by a call to the 'fetch' method.
- // attribute:
- // A attribute of the Atom Entry
- // defaultValue:
- // A default value
- // returns:
- // An attribute value found, otherwise 'defaultValue'
- this._assertIsItem(item);
- this._assertIsAttribute(attribute);
- this._initItem(item);
- attribute = attribute.toLowerCase();
- //If the attribute has previously been retrieved, then return it
- if(!item._attribs[attribute] && !item._parsed){
- this._parseItem(item);
- item._parsed = true;
- }
- var retVal = item._attribs[attribute];
- if(!retVal && attribute == "summary"){
- var content = this.getValue(item, "content");
- var regexp = new RegExp("/(<([^>]+)>)/g", "i");
- var text = content.text.replace(regexp,"");
- retVal = {
- text: text.substring(0, Math.min(400, text.length)),
- type: "text"
- };
- item._attribs[attribute] = retVal;
- }
- if(retVal && this.unescapeHTML){
- if((attribute == "content" || attribute == "summary" || attribute == "subtitle") && !item["_"+attribute+"Escaped"]){
- retVal.text = this._unescapeHTML(retVal.text);
- item["_"+attribute+"Escaped"] = true;
- }
- }
- return retVal ? dojo.isArray(retVal) ? retVal[0]: retVal : defaultValue;
- },
- getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
- // summary:
- // Return an attribute value
- // description:
- // 'item' must be an instance of an object created by the AtomReadStore instance.
- // Accepted attributes are id, subtitle, title, summary, content, author, updated,
- // published, category, link and alternate
- // item:
- // An item returned by a call to the 'fetch' method.
- // attribute:
- // A attribute of the Atom Entry
- // returns:
- // An array of values for the attribute value found, otherwise 'defaultValue'
- this._assertIsItem(item);
- this._assertIsAttribute(attribute);
- this._initItem(item);
- attribute = attribute.toLowerCase();
- //If the attribute has previously been retrieved, then return it
- if(!item._attribs[attribute]){
- this._parseItem(item);
- }
- var retVal = item._attribs[attribute];
- return retVal ? ((retVal.length !== undefined && typeof(retVal) !== "string") ? retVal : [retVal]) : undefined;
- },
- getAttributes: function(/* item */ item){
- // summary:
- // Return an array of attribute names
- // description:
- // 'item' must be have been created by the AtomReadStore instance.
- // tag names of child elements and XML attribute names of attributes
- // specified to the element are returned along with special attribute
- // names applicable to the element including "tagName", "childNodes"
- // if the element has child elements, "text()" if the element has
- // child text nodes, and attribute names in '_attributeMap' that match
- // the tag name of the element.
- // item:
- // An XML element
- // returns:
- // An array of attributes found
- this._assertIsItem(item);
- if(!item._attribs){
- this._initItem(item);
- this._parseItem(item);
- }
- var attrNames = [];
- for(var x in item._attribs){
- attrNames.push(x);
- }
- return attrNames; //array
- },
- hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
- // summary:
- // Check whether an element has the attribute
- // item:
- // 'item' must be created by the AtomReadStore instance.
- // attribute:
- // An attribute of an Atom Entry item.
- // returns:
- // True if the element has the attribute, otherwise false
- return (this.getValue(item, attribute) !== undefined); //boolean
- },
- containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value){
- // summary:
- // Check whether the attribute values contain the value
- // item:
- // 'item' must be an instance of a dojox.data.XmlItem from the store instance.
- // attribute:
- // A tag name of a child element, An XML attribute name or one of
- // special names
- // returns:
- // True if the attribute values contain the value, otherwise false
- var values = this.getValues(item, attribute);
- for(var i = 0; i < values.length; i++){
- if((typeof value === "string")){
- if(values[i].toString && values[i].toString() === value){
- return true;
- }
- }else if(values[i] === value){
- return true; //boolean
- }
- }
- return false;//boolean
- },
- isItem: function(/* anything */ something){
- // summary:
- // Check whether the object is an item (XML element)
- // item:
- // An object to check
- // returns:
- // True if the object is an XML element, otherwise false
- if(something && something.element && something.store && something.store === this){
- return true; //boolean
- }
- return false; //boolran
- },
- isItemLoaded: function(/* anything */ something){
- // summary:
- // Check whether the object is an item (XML element) and loaded
- // item:
- // An object to check
- // returns:
- // True if the object is an XML element, otherwise false
- return this.isItem(something); //boolean
- },
- loadItem: function(/* object */ keywordArgs){
- // summary:
- // Load an item (XML element)
- // keywordArgs:
- // object containing the args for loadItem. See dojo.data.api.Read.loadItem()
- },
- getFeatures: function(){
- // summary:
- // Return supported data APIs
- // returns:
- // "dojo.data.api.Read" and "dojo.data.api.Write"
- var features = {
- "dojo.data.api.Read": true
- };
- return features; //array
- },
- getLabel: function(/* item */ item){
- // summary:
- // See dojo.data.api.Read.getLabel()
- if((this.label !== "") && this.isItem(item)){
- var label = this.getValue(item,this.label);
- if(label && label.text){
- return label.text;
- }else if(label){
- return label.toString();
- }else{
- return undefined;
- }
- }
- return undefined; //undefined
- },
- getLabelAttributes: function(/* item */ item){
- // summary:
- // See dojo.data.api.Read.getLabelAttributes()
- if(this.label !== ""){
- return [this.label]; //array
- }
- return null; //null
- },
- getFeedValue: function(attribute, defaultValue){
- // summary:
- // Non-API method for retrieving values regarding the Atom feed,
- // rather than the Atom entries.
- var values = this.getFeedValues(attribute, defaultValue);
- if(dojo.isArray(values)){
- return values[0];
- }
- return values;
- },
- getFeedValues: function(attribute, defaultValue){
- // summary:
- // Non-API method for retrieving values regarding the Atom feed,
- // rather than the Atom entries.
- if(!this.doc){
- return defaultValue;
- }
- if(!this._feedMetaData){
- this._feedMetaData = {
- element: this.doc.getElementsByTagName("feed")[0],
- store: this,
- _attribs: {}
- };
- this._parseItem(this._feedMetaData);
- }
- return this._feedMetaData._attribs[attribute] || defaultValue;
- },
- _initItem: function(item){
- // summary:
- // Initializes an item before it can be parsed.
- if(!item._attribs){
- item._attribs = {};
- }
- },
- _fetchItems: function(request, fetchHandler, errorHandler){
- // summary:
- // Retrieves the items from the Atom XML document.
- var url = this._getFetchUrl(request);
- if(!url){
- errorHandler(new Error("No URL specified."));
- return;
- }
- var localRequest = (!this.sendQuery ? request : null); // use request for _getItems()
- var _this = this;
- var docHandler = function(data){
- _this.doc = data;
- var items = _this._getItems(data, localRequest);
- var query = request.query;
- if(query){
- if(query.id){
- items = dojo.filter(items, function(item){
- return (_this.getValue(item, "id") == query.id);
- });
- }else if(query.category){
- items = dojo.filter(items, function(entry){
- var cats = _this.getValues(entry, "category");
- if(!cats){
- return false;
- }
- return dojo.some(cats, "return item.term=='"+query.category+"'");
- });
- }
- }
- if(items && items.length > 0){
- fetchHandler(items, request);
- }else{
- fetchHandler([], request);
- }
- };
- if(this.doc){
- docHandler(this.doc);
- }else{
- var getArgs = {
- url: url,
- handleAs: "xml",
- preventCache: this.urlPreventCache
- };
- var getHandler = dojo.xhrGet(getArgs);
- getHandler.addCallback(docHandler);
- getHandler.addErrback(function(data){
- errorHandler(data, request);
- });
- }
- },
- _getFetchUrl: function(request){
- if(!this.sendQuery){
- return this.url;
- }
- var query = request.query;
- if(!query){
- return this.url;
- }
- if(dojo.isString(query)){
- return this.url + query;
- }
- var queryString = "";
- for(var name in query){
- var value = query[name];
- if(value){
- if(queryString){
- queryString += "&";
- }
- queryString += (name + "=" + value);
- }
- }
- if(!queryString){
- return this.url;
- }
- //Check to see if the URL already has query params or not.
- var fullUrl = this.url;
- if(fullUrl.indexOf("?") < 0){
- fullUrl += "?";
- }else{
- fullUrl += "&";
- }
- return fullUrl + queryString;
- },
- _getItems: function(document, request){
- // summary:
- // Parses the document in a first pass
- if(this._items){
- return this._items;
- }
- var items = [];
- var nodes = [];
- if(document.childNodes.length < 1){
- this._items = items;
- console.log("dojox.data.AtomReadStore: Received an invalid Atom document. Check the content type header");
- return items;
- }
- var feedNodes = dojo.filter(document.childNodes, "return item.tagName && item.tagName.toLowerCase() == 'feed'");
- var query = request.query;
- if(!feedNodes || feedNodes.length != 1){
- console.log("dojox.data.AtomReadStore: Received an invalid Atom document, number of feed tags = " + (feedNodes? feedNodes.length : 0));
- return items;
- }
- nodes = dojo.filter(feedNodes[0].childNodes, "return item.tagName && item.tagName.toLowerCase() == 'entry'");
- if(request.onBegin){
- request.onBegin(nodes.length, this.sendQuery ? request : {});
- }
- for(var i = 0; i < nodes.length; i++){
- var node = nodes[i];
- if(node.nodeType != 1 /*ELEMENT_NODE*/){
- continue;
- }
- items.push(this._getItem(node));
- }
- this._items = items;
- return items;
- },
- close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
- // summary:
- // See dojo.data.api.Read.close()
- },
- /* internal API */
- _getItem: function(element){
- return {
- element: element,
- store: this
- };
- },
- _parseItem: function(item){
- var attribs = item._attribs;
- var _this = this;
- var text, type;
- function getNodeText(node){
- var txt = node.textContent || node.innerHTML || node.innerXML;
- if(!txt && node.childNodes[0]){
- var child = node.childNodes[0];
- if(child && (child.nodeType == 3 || child.nodeType == 4)){
- txt = node.childNodes[0].nodeValue;
- }
- }
- return txt;
- }
- function parseTextAndType(node){
- return {text: getNodeText(node),type: node.getAttribute("type")};
- }
- dojo.forEach(item.element.childNodes, function(node){
- var tagName = node.tagName ? node.tagName.toLowerCase() : "";
- switch(tagName){
- case "title":
- attribs[tagName] = {
- text: getNodeText(node),
- type: node.getAttribute("type")
- }; break;
- case "subtitle":
- case "summary":
- case "content":
- attribs[tagName] = parseTextAndType(node);
- break;
- case "author":
- var nameNode ,uriNode;
- dojo.forEach(node.childNodes, function(child){
- if(!child.tagName){
- return;
- }
- switch(child.tagName.toLowerCase()){
- case "name":
- nameNode = child;
- break;
- case "uri":
- uriNode = child;
- break;
- }
- });
- var author = {};
- if(nameNode && nameNode.length == 1){
- author.name = getNodeText(nameNode[0]);
- }
- if(uriNode && uriNode.length == 1){
- author.uri = getNodeText(uriNode[0]);
- }
- attribs[tagName] = author;
- break;
- case "id":
- attribs[tagName] = getNodeText(node);
- break;
- case "updated":
- attribs[tagName] = dojo.date.stamp.fromISOString(getNodeText(node) );
- break;
- case "published":
- attribs[tagName] = dojo.date.stamp.fromISOString(getNodeText(node));
- break;
- case "category":
- if(!attribs[tagName]){
- attribs[tagName] = [];
- }
- attribs[tagName].push({scheme:node.getAttribute("scheme"), term: node.getAttribute("term")});
- break;
- case "link":
- if(!attribs[tagName]){
- attribs[tagName] = [];
- }
- var link = {
- rel: node.getAttribute("rel"),
- href: node.getAttribute("href"),
- type: node.getAttribute("type")};
- attribs[tagName].push(link);
- if(link.rel == "alternate"){
- attribs["alternate"] = link;
- }
- break;
- default:
- break;
- }
- });
- },
- _unescapeHTML : function(text){
- //Replace HTML character codes with their unencoded equivalents, e.g. ’ with '
- text = text.replace(/’/m , "'").replace(/″/m , "\"").replace(/</m,">").replace(/>/m,"<").replace(/&/m,"&");
- return text;
- },
- _assertIsItem: function(/* item */ item){
- // summary:
- // This function tests whether the item passed in is indeed an item in the store.
- // item:
- // The item to test for being contained by the store.
- if(!this.isItem(item)){
- throw new Error("dojox.data.AtomReadStore: Invalid item argument.");
- }
- },
- _assertIsAttribute: function(/* attribute-name-string */ attribute){
- // summary:
- // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
- // attribute:
- // The attribute to test for being contained by the store.
- if(typeof attribute !== "string"){
- throw new Error("dojox.data.AtomReadStore: Invalid attribute argument.");
- }
- }
- });
- dojo.extend(dojox.data.AtomReadStore,dojo.data.util.simpleFetch);
- }
|