summaryrefslogtreecommitdiffstatshomepage
path: root/includes/js/dojox/data
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dojox/data')
-rw-r--r--includes/js/dojox/data/AtomReadStore.js543
-rw-r--r--includes/js/dojox/data/CsvStore.js561
-rw-r--r--includes/js/dojox/data/FlickrRestStore.js471
-rw-r--r--includes/js/dojox/data/FlickrStore.js257
-rw-r--r--includes/js/dojox/data/HtmlStore.js531
-rw-r--r--includes/js/dojox/data/HtmlTableStore.js469
-rw-r--r--includes/js/dojox/data/KeyValueStore.js381
-rw-r--r--includes/js/dojox/data/OpmlStore.js515
-rw-r--r--includes/js/dojox/data/PicasaStore.js254
-rw-r--r--includes/js/dojox/data/QueryReadStore.js513
-rw-r--r--includes/js/dojox/data/README89
-rw-r--r--includes/js/dojox/data/SnapLogicStore.js332
-rw-r--r--includes/js/dojox/data/XmlStore.js1141
-rw-r--r--includes/js/dojox/data/demos/demo_DataDemoTable.html130
-rw-r--r--includes/js/dojox/data/demos/demo_FlickrRestStore.html275
-rw-r--r--includes/js/dojox/data/demos/demo_FlickrStore.html199
-rw-r--r--includes/js/dojox/data/demos/demo_LazyLoad.html66
-rw-r--r--includes/js/dojox/data/demos/demo_MultiStores.html72
-rw-r--r--includes/js/dojox/data/demos/demo_PicasaStore.html188
-rw-r--r--includes/js/dojox/data/demos/demo_QueryReadStore_ComboBox.html56
-rw-r--r--includes/js/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html56
-rw-r--r--includes/js/dojox/data/demos/demo_QueryReadStore_grid.html129
-rw-r--r--includes/js/dojox/data/demos/flickrDemo.css29
-rw-r--r--includes/js/dojox/data/demos/flickrDemo.css.commented.css35
-rw-r--r--includes/js/dojox/data/demos/geography.json45
-rw-r--r--includes/js/dojox/data/demos/geography.xml51
-rw-r--r--includes/js/dojox/data/demos/geography/Argentina/data.json5
-rw-r--r--includes/js/dojox/data/demos/geography/Brazil/data.json5
-rw-r--r--includes/js/dojox/data/demos/geography/Canada/Ottawa/data.json6
-rw-r--r--includes/js/dojox/data/demos/geography/Canada/Toronto/data.json6
-rw-r--r--includes/js/dojox/data/demos/geography/Canada/data.json10
-rw-r--r--includes/js/dojox/data/demos/geography/China/data.json4
-rw-r--r--includes/js/dojox/data/demos/geography/Commonwealth of Australia/data.json5
-rw-r--r--includes/js/dojox/data/demos/geography/Egypt/data.json5
-rw-r--r--includes/js/dojox/data/demos/geography/France/data.json4
-rw-r--r--includes/js/dojox/data/demos/geography/Germany/data.json4
-rw-r--r--includes/js/dojox/data/demos/geography/India/data.json4
-rw-r--r--includes/js/dojox/data/demos/geography/Italy/data.json4
-rw-r--r--includes/js/dojox/data/demos/geography/Kenya/Mombasa/data.json5
-rw-r--r--includes/js/dojox/data/demos/geography/Kenya/Nairobi/data.json5
-rw-r--r--includes/js/dojox/data/demos/geography/Kenya/data.json9
-rw-r--r--includes/js/dojox/data/demos/geography/Mexico/Guadalajara/data.json7
-rw-r--r--includes/js/dojox/data/demos/geography/Mexico/Mexico City/data.json6
-rw-r--r--includes/js/dojox/data/demos/geography/Mexico/data.json10
-rw-r--r--includes/js/dojox/data/demos/geography/Mongolia/data.json4
-rw-r--r--includes/js/dojox/data/demos/geography/Russia/data.json4
-rw-r--r--includes/js/dojox/data/demos/geography/Spain/data.json4
-rw-r--r--includes/js/dojox/data/demos/geography/Sudan/Khartoum/data.json5
-rw-r--r--includes/js/dojox/data/demos/geography/Sudan/data.json6
-rw-r--r--includes/js/dojox/data/demos/geography/United States of America/data.json4
-rw-r--r--includes/js/dojox/data/demos/geography/root.json39
-rw-r--r--includes/js/dojox/data/demos/picasaDemo.css37
-rw-r--r--includes/js/dojox/data/demos/picasaDemo.css.commented.css44
-rw-r--r--includes/js/dojox/data/demos/stores/LazyLoadJSIStore.js142
-rw-r--r--includes/js/dojox/data/demos/widgets/FlickrView.js36
-rw-r--r--includes/js/dojox/data/demos/widgets/FlickrViewList.js37
-rw-r--r--includes/js/dojox/data/demos/widgets/PicasaView.js37
-rw-r--r--includes/js/dojox/data/demos/widgets/PicasaViewList.js37
-rw-r--r--includes/js/dojox/data/demos/widgets/templates/FlickrView.html34
-rw-r--r--includes/js/dojox/data/demos/widgets/templates/FlickrViewList.html2
-rw-r--r--includes/js/dojox/data/demos/widgets/templates/PicasaView.html35
-rw-r--r--includes/js/dojox/data/demos/widgets/templates/PicasaViewList.html2
-rw-r--r--includes/js/dojox/data/dom.js187
-rw-r--r--includes/js/dojox/data/jsonPathStore.js1191
-rw-r--r--includes/js/dojox/data/tests/QueryReadStore.html220
-rw-r--r--includes/js/dojox/data/tests/dom.js133
-rw-r--r--includes/js/dojox/data/tests/ml/divList.html14
-rw-r--r--includes/js/dojox/data/tests/ml/orderedList.html16
-rw-r--r--includes/js/dojox/data/tests/ml/table.html46
-rw-r--r--includes/js/dojox/data/tests/ml/test_HtmlStore_declaratively.html172
-rw-r--r--includes/js/dojox/data/tests/ml/test_HtmlStore_remote.html115
-rw-r--r--includes/js/dojox/data/tests/ml/test_HtmlTableStore_declaratively.html120
-rw-r--r--includes/js/dojox/data/tests/ml/unorderedList.html17
-rw-r--r--includes/js/dojox/data/tests/module.js30
-rw-r--r--includes/js/dojox/data/tests/runTests.html9
-rw-r--r--includes/js/dojox/data/tests/stores/AtomReadStore.js641
-rw-r--r--includes/js/dojox/data/tests/stores/CsvStore.js1127
-rw-r--r--includes/js/dojox/data/tests/stores/FlickrRestStore.js476
-rw-r--r--includes/js/dojox/data/tests/stores/FlickrStore.js410
-rw-r--r--includes/js/dojox/data/tests/stores/HtmlStore.js804
-rw-r--r--includes/js/dojox/data/tests/stores/HtmlTableStore.js702
-rw-r--r--includes/js/dojox/data/tests/stores/KeyValueStore.js1002
-rw-r--r--includes/js/dojox/data/tests/stores/OpmlStore.js1075
-rw-r--r--includes/js/dojox/data/tests/stores/QueryReadStore.js442
-rw-r--r--includes/js/dojox/data/tests/stores/QueryReadStore.php114
-rw-r--r--includes/js/dojox/data/tests/stores/SnapLogicStore.js438
-rw-r--r--includes/js/dojox/data/tests/stores/XmlStore.js881
-rw-r--r--includes/js/dojox/data/tests/stores/atom1.xml848
-rw-r--r--includes/js/dojox/data/tests/stores/books.html118
-rw-r--r--includes/js/dojox/data/tests/stores/books.xml103
-rw-r--r--includes/js/dojox/data/tests/stores/books2.html43
-rw-r--r--includes/js/dojox/data/tests/stores/books2.xml28
-rw-r--r--includes/js/dojox/data/tests/stores/books3.html14
-rw-r--r--includes/js/dojox/data/tests/stores/books3.xml31
-rw-r--r--includes/js/dojox/data/tests/stores/books_isbnAttr.xml23
-rw-r--r--includes/js/dojox/data/tests/stores/books_isbnAttr2.xml23
-rw-r--r--includes/js/dojox/data/tests/stores/geography.xml51
-rw-r--r--includes/js/dojox/data/tests/stores/geography_withspeciallabel.xml51
-rw-r--r--includes/js/dojox/data/tests/stores/jsonPathStore.js604
-rw-r--r--includes/js/dojox/data/tests/stores/movies.csv9
-rw-r--r--includes/js/dojox/data/tests/stores/movies2.csv9
-rw-r--r--includes/js/dojox/data/tests/stores/patterns.csv11
-rw-r--r--includes/js/dojox/data/tests/stores/properties.js10
-rw-r--r--includes/js/dojox/data/tests/stores/snap_pipeline.php72
-rw-r--r--includes/js/dojox/data/tests/test_Tree_vs_jsonPathStore.html105
-rw-r--r--includes/js/dojox/data/tests/treeTest.json10
106 files changed, 20546 insertions, 0 deletions
diff --git a/includes/js/dojox/data/AtomReadStore.js b/includes/js/dojox/data/AtomReadStore.js
new file mode 100644
index 0000000..2bc6920
--- /dev/null
+++ b/includes/js/dojox/data/AtomReadStore.js
@@ -0,0 +1,543 @@
+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.simpleFetch");
+dojo.require("dojo.data.util.filter");
+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(!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,
+
+ /* 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 : undefined;
+ },
+
+ 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
+ // defaultValue:
+ // A default value
+ // 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: true
+ };
+ 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);
+ }
+
+ 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. &#8217; with '
+ text = text.replace(/&#8217;/m , "'").replace(/&#8243;/m , "\"").replace(/&#60;/m,">").replace(/&#62;/m,"<").replace(/&#38;/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);
+
+}
diff --git a/includes/js/dojox/data/CsvStore.js b/includes/js/dojox/data/CsvStore.js
new file mode 100644
index 0000000..87f7466
--- /dev/null
+++ b/includes/js/dojox/data/CsvStore.js
@@ -0,0 +1,561 @@
+if(!dojo._hasResource["dojox.data.CsvStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.CsvStore"] = true;
+dojo.provide("dojox.data.CsvStore");
+
+dojo.require("dojo.data.util.filter");
+dojo.require("dojo.data.util.simpleFetch");
+
+dojo.declare("dojox.data.CsvStore", null, {
+ // summary:
+ // The CsvStore implements the dojo.data.api.Read API and reads
+ // data from files in CSV (Comma Separated Values) format.
+ // All values are simple string values. References to other items
+ // are not supported as attribute values in this datastore.
+ //
+ // Example data file:
+ // name, color, age, tagline
+ // Kermit, green, 12, "Hi, I'm Kermit the Frog."
+ // Fozzie Bear, orange, 10, "Wakka Wakka Wakka!"
+ // Miss Piggy, pink, 11, "Kermie!"
+ //
+ // Note that values containing a comma must be enclosed with quotes ("")
+ // Also note that values containing quotes must be escaped with two consecutive quotes (""quoted"")
+
+ /* examples:
+ * var csvStore = new dojox.data.CsvStore({url:"movies.csv");
+ * var csvStore = new dojox.data.CsvStore({url:"http://example.com/movies.csv");
+ */
+
+ constructor: function(/* Object */ keywordParameters){
+ // summary: initializer
+ // keywordParameters: {url: String}
+ // keywordParameters: {data: String}
+ // keywordParameters: {label: String} The column label for the column to use for the label returned by getLabel.
+
+ this._attributes = []; // e.g. ["Title", "Year", "Producer"]
+ this._attributeIndexes = {}; // e.g. {Title: 0, Year: 1, Producer: 2}
+ this._dataArray = []; // e.g. [[<Item0>],[<Item1>],[<Item2>]]
+ this._arrayOfAllItems = []; // e.g. [{_csvId:0,_csvStore:store},...]
+ this._loadFinished = false;
+ if(keywordParameters.url){
+ this.url = keywordParameters.url;
+ }
+ this._csvData = keywordParameters.data;
+ if(keywordParameters.label){
+ this.label = keywordParameters.label;
+ }else if(this.label === ""){
+ this.label = undefined;
+ }
+ this._storeProp = "_csvStore"; // Property name for the store reference on every item.
+ this._idProp = "_csvId"; // Property name for the Item Id on every item.
+ this._features = {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Identity': true
+ };
+ this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset.
+ this._queuedFetches = [];
+ },
+
+ url: "", //Declarative hook for setting Csv source url.
+
+ label: "", //Declarative hook for setting the label attribute.
+
+ _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.CsvStore: a function was passed an item argument that was not an item");
+ }
+ },
+
+ _assertIsAttribute: function(/* item || 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(!dojo.isString(attribute)){
+ throw new Error("dojox.data.CsvStore: a function was passed an attribute argument that was not an attribute object nor an attribute name string");
+ }
+ },
+
+/***************************************
+ dojo.data.api.Read API
+***************************************/
+ getValue: function( /* item */ item,
+ /* attribute || attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ // Note that for the CsvStore, an empty string value is the same as no value,
+ // so the defaultValue would be returned instead of an empty string.
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ var itemValue = defaultValue;
+ if(this.hasAttribute(item, attribute)){
+ var itemData = this._dataArray[this.getIdentity(item)];
+ itemValue = itemData[this._attributeIndexes[attribute]];
+ }
+ return itemValue; //String
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute || attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+ // CSV syntax does not support multi-valued attributes, so this is just a
+ // wrapper function for getValue().
+ var value = this.getValue(item, attribute);
+ return (value ? [value] : []); //Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ var itemData = this._dataArray[this.getIdentity(item)];
+ for(var i=0; i<itemData.length; i++){
+ // Check for empty string values. CsvStore treats empty strings as no value.
+ if(itemData[i] != ""){
+ attributes.push(this._attributes[i]);
+ }
+ }
+ return attributes; //Array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute || attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ // The hasAttribute test is true if attribute has an index number within the item's array length
+ // AND if the item has a value for that attribute. Note that for the CsvStore, an
+ // empty string value is the same as no value.
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ var attributeIndex = this._attributeIndexes[attribute];
+ var itemData = this._dataArray[this.getIdentity(item)];
+ return (typeof attributeIndex != "undefined" && attributeIndex < itemData.length && itemData[attributeIndex] != ""); //Boolean
+ },
+
+ containsValue: function(/* item */ item,
+ /* attribute || attribute-name-string */ attribute,
+ /* anything */ value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ var regexp = undefined;
+ if(typeof value === "string"){
+ regexp = dojo.data.util.filter.patternToRegExp(value, false);
+ }
+ return this._containsValue(item, attribute, value, regexp); //boolean.
+ },
+
+ _containsValue: function( /* item */ item,
+ /* attribute || attribute-name-string */ attribute,
+ /* anything */ value,
+ /* RegExp?*/ regexp){
+ // summary:
+ // Internal function for looking at the values contained by the item.
+ // description:
+ // Internal function for looking at the values contained by the item. This
+ // function allows for denoting if the comparison should be case sensitive for
+ // strings or not (for handling filtering cases where string case should not matter)
+ //
+ // item:
+ // The data item to examine for attribute values.
+ // attribute:
+ // The attribute to inspect.
+ // value:
+ // The value to match.
+ // regexp:
+ // Optional regular expression generated off value if value was of string type to handle wildcarding.
+ // If present and attribute values are string, then it can be used for comparison instead of 'value'
+ var values = this.getValues(item, attribute);
+ for(var i = 0; i < values.length; ++i){
+ var possibleValue = values[i];
+ if(typeof possibleValue === "string" && regexp){
+ return (possibleValue.match(regexp) !== null);
+ }else{
+ //Non-string matching.
+ if(value === possibleValue){
+ return true; // Boolean
+ }
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(something && something[this._storeProp] === this){
+ var identity = something[this._idProp];
+ if(identity >= 0 && identity < this._dataArray.length){
+ return true; //Boolean
+ }
+ }
+ return false; //Boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ // The CsvStore always loads all items, so if it's an item, then it's loaded.
+ return this.isItem(something); //Boolean
+ },
+
+ loadItem: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ // description:
+ // The CsvStore always loads all items, so if it's an item, then it's loaded.
+ // From the dojo.data.api.Read.loadItem docs:
+ // If a call to isItemLoaded() returns true before loadItem() is even called,
+ // then loadItem() need not do any work at all and will not even invoke
+ // the callback handlers.
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return this._features; //Object
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if(this.label && this.isItem(item)){
+ return this.getValue(item,this.label); //String
+ }
+ return undefined; //undefined
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ if(this.label){
+ return [this.label]; //array
+ }
+ return null; //null
+ },
+
+
+ // The dojo.data.api.Read.fetch() function is implemented as
+ // a mixin from dojo.data.util.simpleFetch.
+ // That mixin requires us to define _fetchItems().
+ _fetchItems: function( /* Object */ keywordArgs,
+ /* Function */ findCallback,
+ /* Function */ errorCallback){
+ // summary:
+ // See dojo.data.util.simpleFetch.fetch()
+
+ var self = this;
+
+ var filter = function(requestArgs, arrayOfAllItems){
+ var items = null;
+ if(requestArgs.query){
+ items = [];
+ var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false;
+
+ //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+ //same value for each item examined. Much more efficient.
+ var regexpList = {};
+ for(var key in requestArgs.query){
+ var value = requestArgs.query[key];
+ if(typeof value === "string"){
+ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+ }
+ }
+
+ for(var i = 0; i < arrayOfAllItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfAllItems[i];
+ for(var key in requestArgs.query){
+ var value = requestArgs.query[key];
+ if(!self._containsValue(candidateItem, key, value, regexpList[key])){
+ match = false;
+ }
+ }
+ if(match){
+ items.push(candidateItem);
+ }
+ }
+ }else{
+ // We want a copy to pass back in case the parent wishes to sort the array. We shouldn't allow resort
+ // of the internal list so that multiple callers can get lists and sort without affecting each other.
+ if(arrayOfAllItems.length> 0){
+ items = arrayOfAllItems.slice(0,arrayOfAllItems.length);
+ }
+ }
+ findCallback(items, requestArgs);
+ };
+
+ if(this._loadFinished){
+ filter(keywordArgs, this._arrayOfAllItems);
+ }else{
+ if(this.url !== ""){
+ //If fetches come in before the loading has finished, but while
+ //a load is in progress, we have to defer the fetching to be
+ //invoked in the callback.
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs, filter: filter});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self.url,
+ handleAs: "text"
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ self._processData(data);
+ filter(keywordArgs, self._arrayOfAllItems);
+ self._handleQueuedFetches();
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ if(errorCallback){
+ errorCallback(error, keywordArgs);
+ }else{
+ throw error;
+ }
+ });
+ }
+ }else if(this._csvData){
+ this._processData(this._csvData);
+ this._csvData = null;
+ filter(keywordArgs, this._arrayOfAllItems);
+ }else{
+ var error = new Error("dojox.data.CsvStore: No CSV source data was provided as either URL or String data input.");
+ if(errorCallback){
+ errorCallback(error, keywordArgs);
+ }else{
+ throw error;
+ }
+ }
+ }
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ },
+
+
+ // -------------------------------------------------------------------
+ // Private methods
+ _getArrayOfArraysFromCsvFileContents: function(/* string */ csvFileContents){
+ /* summary:
+ * Parses a string of CSV records into a nested array structure.
+ * description:
+ * Given a string containing CSV records, this method parses
+ * the string and returns a data structure containing the parsed
+ * content. The data structure we return is an array of length
+ * R, where R is the number of rows (lines) in the CSV data. The
+ * return array contains one sub-array for each CSV line, and each
+ * sub-array contains C string values, where C is the number of
+ * columns in the CSV data.
+ */
+
+ /* example:
+ * For example, given this CSV string as input:
+ * "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott"
+ * this._dataArray will be set to:
+ * [["Alien", "1979", "Ridley Scott"],
+ * ["Blade Runner", "1982", "Ridley Scott"]]
+ * And this._attributes will be set to:
+ * ["Title", "Year", "Producer"]
+ * And this._attributeIndexes will be set to:
+ * { "Title":0, "Year":1, "Producer":2 }
+ */
+ if(dojo.isString(csvFileContents)){
+ var lineEndingCharacters = new RegExp("\r\n|\n|\r");
+ var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g');
+ var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g');
+ var doubleQuotes = new RegExp('""','g');
+ var arrayOfOutputRecords = [];
+
+ var arrayOfInputLines = csvFileContents.split(lineEndingCharacters);
+ for(var i = 0; i < arrayOfInputLines.length; ++i){
+ var singleLine = arrayOfInputLines[i];
+ if(singleLine.length > 0){
+ var listOfFields = singleLine.split(',');
+ var j = 0;
+ while(j < listOfFields.length){
+ var space_field_space = listOfFields[j];
+ var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace
+ var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace
+ var firstChar = field.charAt(0);
+ var lastChar = field.charAt(field.length - 1);
+ var secondToLastChar = field.charAt(field.length - 2);
+ var thirdToLastChar = field.charAt(field.length - 3);
+ if(field.length === 2 && field == "\"\""){
+ listOfFields[j] = ""; //Special case empty string field.
+ }else if((firstChar == '"') &&
+ ((lastChar != '"') ||
+ ((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')))){
+ if(j+1 === listOfFields.length){
+ // alert("The last field in record " + i + " is corrupted:\n" + field);
+ return null; //null
+ }
+ var nextField = listOfFields[j+1];
+ listOfFields[j] = field_space + ',' + nextField;
+ listOfFields.splice(j+1, 1); // delete element [j+1] from the list
+ }else{
+ if((firstChar == '"') && (lastChar == '"')){
+ field = field.slice(1, (field.length - 1)); // trim the " characters off the ends
+ field = field.replace(doubleQuotes, '"'); // replace "" with "
+ }
+ listOfFields[j] = field;
+ j += 1;
+ }
+ }
+ arrayOfOutputRecords.push(listOfFields);
+ }
+ }
+
+ // The first item of the array must be the header row with attribute names.
+ this._attributes = arrayOfOutputRecords.shift();
+ for(var i=0; i<this._attributes.length; i++){
+ // Store the index of each attribute
+ this._attributeIndexes[this._attributes[i]] = i;
+ }
+ this._dataArray = arrayOfOutputRecords; //Array
+ }
+ },
+
+ _processData: function(/* String */ data){
+ this._getArrayOfArraysFromCsvFileContents(data);
+ this._arrayOfAllItems = [];
+ for(var i=0; i<this._dataArray.length; i++){
+ this._arrayOfAllItems.push(this._createItemFromIdentity(i));
+ }
+ this._loadFinished = true;
+ this._loadInProgress = false;
+ },
+
+ _createItemFromIdentity: function(/* String */ identity){
+ var item = {};
+ item[this._storeProp] = this;
+ item[this._idProp] = identity;
+ return item; //Object
+ },
+
+
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ if(this.isItem(item)){
+ return item[this._idProp]; //String
+ }
+ return null; //null
+ },
+
+ fetchItemByIdentity: function(/* Object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+
+ //Hasn't loaded yet, we have to trigger the load.
+
+
+ if(!this._loadFinished){
+ var self = this;
+ if(this.url !== ""){
+ //If fetches come in before the loading has finished, but while
+ //a load is in progress, we have to defer the fetching to be
+ //invoked in the callback.
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self.url,
+ handleAs: "text"
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ try{
+ self._processData(data);
+ var item = self._createItemFromIdentity(keywordArgs.identity);
+ if(!self.isItem(item)){
+ item = null;
+ }
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ self._handleQueuedFetches();
+ }catch(error){
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ }
+ });
+ getHandler.addErrback(function(error){
+ this._loadInProgress = false;
+ if(keywordArgs.onError){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+ }
+ }else if(this._csvData){
+ self._processData(self._csvData);
+ self._csvData = null;
+ var item = self._createItemFromIdentity(keywordArgs.identity);
+ if(!self.isItem(item)){
+ item = null;
+ }
+ if(keywordArgs.onItem){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }else{
+ //Already loaded. We can just look it up and call back.
+ var item = this._createItemFromIdentity(keywordArgs.identity);
+ if(!this.isItem(item)){
+ item = null;
+ }
+ if(keywordArgs.onItem){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentifierAttributes()
+
+ //Identity isn't a public attribute in the item, it's the row position index.
+ //So, return null.
+ return null;
+ },
+
+ _handleQueuedFetches: function(){
+ // summary:
+ // Internal function to execute delayed request in the store.
+ //Execute any deferred fetches now.
+ if (this._queuedFetches.length > 0) {
+ for(var i = 0; i < this._queuedFetches.length; i++){
+ var fData = this._queuedFetches[i];
+ var delayedFilter = fData.filter;
+ var delayedQuery = fData.args;
+ if(delayedFilter){
+ delayedFilter(delayedQuery, this._arrayOfAllItems);
+ }else{
+ this.fetchItemByIdentity(fData.args);
+ }
+ }
+ this._queuedFetches = [];
+ }
+ }
+});
+//Mix in the simple fetch implementation to this class.
+dojo.extend(dojox.data.CsvStore,dojo.data.util.simpleFetch);
+
+}
diff --git a/includes/js/dojox/data/FlickrRestStore.js b/includes/js/dojox/data/FlickrRestStore.js
new file mode 100644
index 0000000..466d6df
--- /dev/null
+++ b/includes/js/dojox/data/FlickrRestStore.js
@@ -0,0 +1,471 @@
+if(!dojo._hasResource["dojox.data.FlickrRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.FlickrRestStore"] = true;
+dojo.provide("dojox.data.FlickrRestStore");
+
+dojo.require("dojox.data.FlickrStore");
+
+dojo.declare("dojox.data.FlickrRestStore",
+ dojox.data.FlickrStore, {
+ constructor: function(/*Object*/args){
+ // summary:
+ // Initializer for the FlickrRestStore store.
+ // description:
+ // The FlickrRestStore is a Datastore interface to one of the basic services
+ // of the Flickr service, the public photo feed. This does not provide
+ // access to all the services of Flickr.
+ // This store cannot do * and ? filtering as the flickr service
+ // provides no interface for wildcards.
+ if(args && args.label){
+ if(args.label) {
+ this.label = args.label;
+ }
+ if(args.apikey) {
+ this._apikey = args.apikey;
+ }
+ }
+ this._cache = [];
+ this._prevRequests = {};
+ this._handlers = {};
+ this._prevRequestRanges = [];
+ this._maxPhotosPerUser = {};
+ this._id = dojox.data.FlickrRestStore.prototype._id++;
+ },
+
+ // _id: Integer
+ // A unique identifier for this store.
+ _id: 0,
+
+ // _requestCount: Integer
+ // A counter for the number of requests made. This is used to define
+ // the callback function that Flickr will use.
+ _requestCount: 0,
+
+ // _flickrRestUrl: String
+ // The URL to the Flickr REST services.
+ _flickrRestUrl: "http://www.flickr.com/services/rest/",
+
+ // _apikey: String
+ // The users API key to be used when accessing Flickr REST services.
+ _apikey: null,
+
+ // _storeRef: String
+ // A key used to mark an data store item as belonging to this store.
+ _storeRef: "_S",
+
+ // _cache: Array
+ // An Array of all previously downloaded picture info.
+ _cache: null,
+
+ // _prevRequests: Object
+ // A HashMap used to record the signature of a request to prevent duplicate
+ // request being made.
+ _prevRequests: null,
+
+ // _handlers: Object
+ // A HashMap used to record the handlers registered for a single remote request. Multiple
+ // requests may be made for the same information before the first request has finished.
+ // Each element of this Object is an array of handlers to call back when the request finishes.
+ // This prevents multiple requests being made for the same information.
+ _handlers: null,
+
+ // _sortAttributes: Object
+ // A quick lookup of valid attribute names in a sort query.
+ _sortAttributes: {
+ "date-posted": true,
+ "date-taken": true,
+ "interestingness": true
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler){
+ // summary: Fetch flickr items that match to a query
+ // request:
+ // A request object
+ // fetchHandler:
+ // A function to call for fetched items
+ // errorHandler:
+ // A function to call on error
+ var query = {};
+ if(!request.query){
+ request.query = query = {};
+ } else {
+ dojo.mixin(query, request.query);
+ }
+
+ var primaryKey = [];
+ var secondaryKey = [];
+
+ //Generate a unique function to be called back
+ var callbackFn = "FlickrRestStoreCallback_" + this._id + "_" + (++this._requestCount);
+ //Build up the content to send the request for.
+ var content = {
+ format: "json",
+ method: "flickr.photos.search",
+ api_key: this._apikey,
+ extras: "owner_name,date_upload,date_taken",
+ jsoncallback: callbackFn
+ };
+ var isRest = false;
+ if(query.userid){
+ isRest = true;
+ content.user_id = request.query.userid;
+ primaryKey.push("userid"+request.query.userid);
+ }
+ if(query.apikey){
+ isRest = true;
+ content.api_key = request.query.apikey;
+ secondaryKey.push("api"+request.query.apikey);
+ } else{
+ throw Error("dojox.data.FlickrRestStore: An API key must be specified.");
+ }
+ request._curCount = request.count;
+ if(query.page){
+ content.page = request.query.page;
+ secondaryKey.push("page" + content.page);
+ }else if(typeof(request.start) != "undefined" && request.start != null) {
+ if(!request.count){
+ request.count = 20;
+ }
+ var diff = request.start % request.count;
+ var start = request.start, count = request.count;
+ //If the count does not divide cleanly into the start number,
+ //more work has to be done to figure out the best page to request
+ if(diff != 0) {
+ if(start < count / 2) {
+ //If the first record requested is less than half the amount requested,
+ //then request from 0 to the count record
+ count = start + count;
+ start = 0;
+ } else {
+ var divLimit = 20, div = 2;
+ for(var i = divLimit; i > 0; i--) {
+ if(start % i == 0 && (start/i) >= count){
+ div = i;
+ break;
+ }
+ }
+ count = start/div;
+ }
+ request._realStart = request.start;
+ request._realCount = request.count;
+ request._curStart = start;
+ request._curCount = count;
+ } else {
+ request._realStart = request._realCount = null;
+ request._curStart = request.start;
+ request._curCount = request.count;
+ }
+
+ content.page = (start / count) + 1;
+ secondaryKey.push("page" + content.page);
+ }
+ if(request._curCount){
+ content.per_page = request._curCount;
+ secondaryKey.push("count" + request._curCount);
+ }
+
+ if(query.lang){
+ content.lang = request.query.lang;
+ primaryKey.push("lang" + request.lang);
+ }
+ var url = this._flickrRestUrl;
+
+ if(query.setid){
+ content.method = "flickr.photosets.getPhotos";
+ content.photoset_id = request.query.set;
+ primaryKey.push("set" + request.query.set);
+ }
+
+ if(query.tags){
+ if(query.tags instanceof Array){
+ content.tags = query.tags.join(",");
+ } else {
+ content.tags=query.tags;
+ }
+ primaryKey.push("tags" + content.tags);
+
+ if(query["tag_mode"] && (query.tag_mode.toLowerCase() == "any"
+ || query.tag_mode.toLowerCase() == "all")){
+ content.tag_mode = query.tag_mode;
+ }
+ }
+ if(query.text){
+ content.text=query.text;
+ primaryKey.push("text:"+query.text);
+ }
+
+ //The store only supports a single sort attribute, even though the
+ //Read API technically allows multiple sort attributes
+ if(query.sort && query.sort.length > 0){
+ //The default sort attribute is 'date-posted'
+ if(!query.sort[0].attribute){
+ query.sort[0].attribute = "date-posted";
+ }
+
+ //If the sort attribute is valid, check if it is ascending or
+ //descending.
+ if(this._sortAttributes[query.sort[0].attribute]) {
+ if(query.sort[0].descending){
+ content.sort = query.sort[0].attribute + "-desc";
+ } else {
+ content.sort = query.sort[0].attribute + "-asc";
+ }
+ }
+ } else {
+ //The default sort in the Dojo Data API is ascending.
+ content.sort = "date-posted-asc";
+ }
+ primaryKey.push("sort:"+content.sort);
+
+ //Generate a unique key for this request, so the store can
+ //detect duplicate requests.
+ primaryKey = primaryKey.join(".");
+ secondaryKey = secondaryKey.length > 0 ? "." + secondaryKey.join(".") : "";
+ var requestKey = primaryKey + secondaryKey;
+
+ //Make a copy of the request, in case the source object is modified
+ //before the request completes
+ request = {
+ query: query,
+ count: request._curCount,
+ start: request._curStart,
+ _realCount: request._realCount,
+ _realStart: request._realStart,
+ onBegin: request.onBegin,
+ onComplete: request.onComplete,
+ onItem: request.onItem
+ };
+
+ var thisHandler = {
+ request: request,
+ fetchHandler: fetchHandler,
+ errorHandler: errorHandler
+ };
+
+ //If the request has already been made, but not yet completed,
+ //then add the callback handler to the list of handlers
+ //for this request, and finish.
+ if(this._handlers[requestKey]){
+ this._handlers[requestKey].push(thisHandler);
+ return;
+ }
+
+ this._handlers[requestKey] = [thisHandler];
+
+ //Linking this up to Flickr is a PAIN!
+ var self = this;
+ var handle = null;
+ var getArgs = {
+ url: this._flickrRestUrl,
+ preventCache: true,
+ content: content
+ };
+
+ var doHandle = function(processedData, data, handler){
+ var onBegin = handler.request.onBegin;
+ handler.request.onBegin = null;
+ var maxPhotos;
+ var req = handler.request;
+
+ if(typeof(req._realStart) != undefined && req._realStart != null) {
+ req.start = req._realStart;
+ req.count = req._realCount;
+ req._realStart = req._realCount = null;
+ }
+
+ //If the request contains an onBegin method, the total number
+ //of photos must be calculated.
+ if(onBegin){
+ if(data && typeof(data.photos.perpage) != "undefined" && typeof(data.photos.pages) != "undefined"){
+ if(data.photos.perpage * data.photos.pages <= handler.request.start + handler.request.count){
+ //If the final page of results has been received, it is possible to
+ //know exactly how many photos there are
+ maxPhotos = handler.request.start + data.photos.photo.length;
+ }else{
+ //If the final page of results has not yet been received,
+ //it is not possible to tell exactly how many photos exist, so
+ //return the number of pages multiplied by the number of photos per page.
+ maxPhotos = data.photos.perpage * data.photos.pages;
+ }
+ self._maxPhotosPerUser[primaryKey] = maxPhotos;
+ onBegin(maxPhotos, handler.request);
+ } else if(self._maxPhotosPerUser[primaryKey]) {
+ onBegin(self._maxPhotosPerUser[primaryKey], handler.request);
+ }
+ }
+ //Call whatever functions the caller has defined on the request object, except for onBegin
+ handler.fetchHandler(processedData, handler.request);
+ if(onBegin){
+ //Replace the onBegin function, if it existed.
+ handler.request.onBegin = onBegin;
+ }
+ };
+
+ //Define a callback for the script that iterates through a list of
+ //handlers for this piece of data. Multiple requests can come into
+ //the store for the same data.
+ var myHandler = function(data){
+ //The handler should not be called more than once, so disconnect it.
+ //if(handle !== null){ dojo.disconnect(handle); }
+ if(data.stat != "ok"){
+ errorHandler(null, request);
+ }else{ //Process the items...
+ var handlers = self._handlers[requestKey];
+ if(!handlers){
+ console.log("FlickrRestStore: no handlers for data", data);
+ return;
+ }
+
+ self._handlers[requestKey] = null;
+ self._prevRequests[requestKey] = data;
+
+ //Process the data once.
+ var processedData = self._processFlickrData(data, request, primaryKey);
+ if(!self._prevRequestRanges[primaryKey]) {
+ self._prevRequestRanges[primaryKey] = [];
+ }
+ self._prevRequestRanges[primaryKey].push({
+ start: request.start,
+ end: request.start + data.photos.photo.length
+ });
+
+ //Iterate through the array of handlers, calling each one.
+ for(var i = 0; i < handlers.length; i++ ){
+ doHandle(processedData, data, handlers[i]);
+ }
+ }
+ };
+
+ var data = this._prevRequests[requestKey];
+
+ //If the data was previously retrieved, there is no need to fetch it again.
+ if(data){
+ this._handlers[requestKey] = null;
+ doHandle(this._cache[primaryKey], data, thisHandler);
+ return;
+ } else if(this._checkPrevRanges(primaryKey, request.start, request.count)) {
+ //If this range of data has already been retrieved, reuse it.
+ this._handlers[requestKey] = null;
+ doHandle(this._cache[primaryKey], null, thisHandler);
+ return;
+ }
+
+ dojo.global[callbackFn] = function(data){
+ myHandler(data);
+ //Clean up the function, it should never be called again
+ dojo.global[callbackFn] = null;
+ };
+
+ var deferred = dojo.io.script.get(getArgs);
+
+ //We only set up the errback, because the callback isn't ever really used because we have
+ //to link to the jsonFlickrFeed function....
+ deferred.addErrback(function(error){
+ dojo.disconnect(handle);
+ errorHandler(error, request);
+ });
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ return ["title", "author", "imageUrl", "imageUrlSmall",
+ "imageUrlMedium", "imageUrlThumb", "link",
+ "dateTaken", "datePublished"];
+ },
+
+ getValues: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ if(attribute === "title"){
+ return [this._unescapeHtml(item.title)]; // String
+ }else if(attribute === "author"){
+ return [item.ownername]; // String
+ }else if(attribute === "imageUrlSmall"){
+ return [item.media.s]; // String
+ }else if(attribute === "imageUrl"){
+ return [item.media.l]; // String
+ }else if(attribute === "imageUrlMedium"){
+ return [item.media.m]; // String
+ }else if(attribute === "imageUrlThumb"){
+ return [item.media.t]; // String
+ }else if(attribute === "link"){
+ return ["http://www.flickr.com/photos/" + item.owner + "/" + item.id]; // String
+ }else if(attribute === "dateTaken"){
+ return item.datetaken;
+ }else if(attribute === "datePublished"){
+ return item.datepublished;
+ }
+
+ return undefined;
+ },
+
+ _processFlickrData: function(/* Object */data, /* Object */request, /* String */ cacheKey){
+ // summary: Processes the raw data from Flickr and updates the internal cache.
+ // data:
+ // Data returned from Flickr
+ // request:
+ // The original dojo.data.Request object passed in by the user.
+
+ //If the data contains an 'item' object, it has not come from the REST services,
+ //so process it using the FlickrStore.
+ if(data.items){
+ return dojox.data.FlickrStore.prototype._processFlickrData.apply(this,arguments);
+ }
+
+ var template = ["http://farm", null, ".static.flickr.com/", null, "/", null, "_", null];
+
+ var items = [];
+ if(data.stat == "ok" && data.photos && data.photos.photo){
+ items = data.photos.photo;
+
+ //Add on the store ref so that isItem can work.
+ for(var i = 0; i < items.length; i++){
+ var item = items[i];
+ item[this._storeRef] = this;
+
+ template[1] = item.farm;
+ template[3] = item.server;
+ template[5] = item.id;
+ template[7] = item.secret;
+
+ var base = template.join("");
+ item.media = {
+ s: base + "_s.jpg",
+ m: base + "_m.jpg",
+ l: base + ".jpg",
+ t: base + "_t.jpg"
+ };
+ }
+ }
+ var start = request.start ? request.start : 0;
+ var arr = this._cache[cacheKey];
+ if(!arr) {
+ this._cache[cacheKey] = arr = [];
+ }
+ for(var count = 0; count < items.length; count++){
+ arr[count + start] = items[count];
+ }
+
+ return arr; // Array
+ },
+
+ _checkPrevRanges: function(primaryKey, start, count) {
+ var end = start + count;
+ var arr = this._prevRequestRanges[primaryKey];
+ if(!arr) {
+ return false;
+ }
+ for(var i = 0; i< arr.length; i++) {
+ if(start >= arr[i].start &&
+ end <= arr[i].end) {
+ return true;
+ }
+ }
+ return false;
+ }
+});
+
+
+}
diff --git a/includes/js/dojox/data/FlickrStore.js b/includes/js/dojox/data/FlickrStore.js
new file mode 100644
index 0000000..4f282df
--- /dev/null
+++ b/includes/js/dojox/data/FlickrStore.js
@@ -0,0 +1,257 @@
+if(!dojo._hasResource["dojox.data.FlickrStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.FlickrStore"] = true;
+dojo.provide("dojox.data.FlickrStore");
+
+dojo.require("dojo.data.util.simpleFetch");
+dojo.require("dojo.io.script");
+dojo.require("dojo.date.stamp");
+
+dojo.declare("dojox.data.FlickrStore", null, {
+ constructor: function(/*Object*/args){
+ // summary:
+ // Initializer for the FlickrStore store.
+ // description:
+ // The FlickrStore is a Datastore interface to one of the basic services
+ // of the Flickr service, the public photo feed. This does not provide
+ // access to all the services of Flickr.
+ // This store cannot do * and ? filtering as the flickr service
+ // provides no interface for wildcards.
+ if(args && args.label){
+ this.label = args.label;
+ }
+ },
+
+ _flickrUrl: "http://api.flickr.com/services/feeds/photos_public.gne",
+
+ _storeRef: "_S",
+
+ label: "title",
+
+ _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.FlickrStore: a function was passed an item argument that was not an item");
+ }
+ },
+
+ _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.FlickrStore: a function was passed an attribute argument that was not an attribute name string");
+ }
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true
+ };
+ },
+
+ getValue: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ if(values){
+ return values[0];
+ }
+ return undefined;
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ return ["title", "description", "author", "datePublished", "dateTaken", "imageUrl", "imageUrlSmall", "imageUrlMedium", "tags", "link"];
+ },
+
+ hasAttribute: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttributes()
+ if(this.getValue(item,attribute)){
+ return true;
+ }
+ return false;
+ },
+
+ isItemLoaded: function(item){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(item);
+ },
+
+ loadItem: function(keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ },
+
+ getLabel: function(item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ return this.getValue(item,this.label);
+ },
+
+ getLabelAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return [this.label];
+ },
+
+ containsValue: function(item, attribute, value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ var values = this.getValues(item,attribute);
+ for(var i = 0; i < values.length; i++){
+ if(values[i] === value){
+ return true;
+ }
+ }
+ return false;
+ },
+
+ getValues: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ if(attribute === "title"){
+ return [this._unescapeHtml(item.title)];
+ }else if(attribute === "author"){
+ return [this._unescapeHtml(item.author)];
+ }else if(attribute === "datePublished"){
+ return [dojo.date.stamp.fromISOString(item.published)];
+ }else if(attribute === "dateTaken"){
+ return [dojo.date.stamp.fromISOString(item.date_taken)];
+ }else if(attribute === "imageUrlSmall"){
+ return [item.media.m.replace(/_m\./, "_s.")];
+ }else if(attribute === "imageUrl"){
+ return [item.media.m.replace(/_m\./, ".")];
+ }else if(attribute === "imageUrlMedium"){
+ return [item.media.m];
+ }else if(attribute === "link"){
+ return [item.link];
+ }else if(attribute === "tags"){
+ return item.tags.split(" ");
+ }else if(attribute === "description"){
+ return [this._unescapeHtml(item.description)];
+ }
+ return undefined;
+ },
+
+ isItem: function(item){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(item && item[this._storeRef] === this){
+ return true;
+ }
+ return false;
+ },
+
+ close: function(request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Fetch flickr items that match to a query
+ // request:
+ // A request object
+ // fetchHandler:
+ // A function to call for fetched items
+ // errorHandler:
+ // A function to call on error
+
+ if(!request.query){
+ request.query={};
+ }
+
+ //Build up the content to send the request for.
+ var content = {format: "json", tagmode:"any"};
+ if (request.query.tags) {
+ content.tags = request.query.tags;
+ }
+ if (request.query.tagmode) {
+ content.tagmode = request.query.tagmode;
+ }
+ if (request.query.userid) {
+ content.id = request.query.userid;
+ }
+ if (request.query.userids) {
+ content.ids = request.query.userids;
+ }
+ if (request.query.lang) {
+ content.lang = request.query.lang;
+ }
+
+ //Linking this up to Flickr is a PAIN!
+ var self = this;
+ var handle = null;
+ var getArgs = {
+ url: this._flickrUrl,
+ preventCache: true,
+ content: content
+ };
+ var myHandler = function(data){
+ if(handle !== null){
+ dojo.disconnect(handle);
+ }
+
+ //Process the items...
+ fetchHandler(self._processFlickrData(data), request);
+ };
+ handle = dojo.connect("jsonFlickrFeed", myHandler);
+ var deferred = dojo.io.script.get(getArgs);
+
+ //We only set up the errback, because the callback isn't ever really used because we have
+ //to link to the jsonFlickrFeed function....
+ deferred.addErrback(function(error){
+ dojo.disconnect(handle);
+ errorHandler(error, request);
+ });
+ },
+
+ _processFlickrData: function(data){
+ var items = [];
+ if(data.items){
+ items = data.items;
+ //Add on the store ref so that isItem can work.
+ for(var i = 0; i < data.items.length; i++){
+ var item = data.items[i];
+ item[this._storeRef] = this;
+ }
+ }
+ return items;
+ },
+
+ _unescapeHtml: function(str){
+ // summary: Utility function to un-escape XML special characters in an HTML string.
+ // description: Utility function to un-escape XML special characters in an HTML string.
+ //
+ // str: String.
+ // The string to un-escape
+ // returns: HTML String converted back to the normal text (unescaped) characters (<,>,&, ", etc,).
+ //
+ //TODO: Check to see if theres already compatible escape() in dojo.string or dojo.html
+ str = str.replace(/&amp;/gm, "&").replace(/&lt;/gm, "<").replace(/&gt;/gm, ">").replace(/&quot;/gm, "\"");
+ str = str.replace(/&#39;/gm, "'");
+ return str;
+ }
+});
+dojo.extend(dojox.data.FlickrStore,dojo.data.util.simpleFetch);
+
+//We have to define this because of how the Flickr API works.
+//This somewhat stinks, but what can you do?
+if (!jsonFlickrFeed) {
+ var jsonFlickrFeed = function(data){};
+}
+
+
+}
diff --git a/includes/js/dojox/data/HtmlStore.js b/includes/js/dojox/data/HtmlStore.js
new file mode 100644
index 0000000..188aac6
--- /dev/null
+++ b/includes/js/dojox/data/HtmlStore.js
@@ -0,0 +1,531 @@
+if(!dojo._hasResource["dojox.data.HtmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.HtmlStore"] = true;
+dojo.provide("dojox.data.HtmlStore");
+
+dojo.require("dojox.data.dom");
+dojo.require("dojo.data.util.simpleFetch");
+dojo.require("dojo.data.util.filter");
+
+dojo.declare("dojox.data.HtmlStore", null, {
+ constructor: function(/*Object*/args){
+ // summary:
+ // Initializer for the HTML table store.
+ // description:
+ // The HtmlStore can be created in one of two ways: a) by parsing an existing
+ // table or list DOM node on the current page or b) by referencing an external url and giving
+ // the id of the table or listin that page. The remote url will be parsed as an html page.
+ //
+ // The HTML table or list should be of the following form:
+ //
+ // | <table id="myTable">
+ // | <thead>
+ // | <tr>
+ // | <th>Attribute1</th>
+ // | <th>Attribute2</th>
+ // | </tr>
+ // | </thead>
+ // | <tbody>
+ // | <tr>
+ // | <td>Value1.1</td>
+ // | <td>Value1.2</td>
+ // | </tr>
+ // | <tr>
+ // | <td>Value2.1</td>
+ // | <td>Value2.2</td>
+ // | </tr>
+ // | </tbody>
+ // | </table>
+ //
+ // -or-
+ //
+ // | <ul id="myUnorderedList">
+ // | <li>Value.1</li>
+ // | <li>Value.2</li>
+ // | </ul>
+ //
+ // -or-
+ //
+ // | <ol id="myOrderedList">
+ // | <li>Value.1</li>
+ // | <li>Value.2</li>
+ // | </ol>
+ //
+ // args:
+ // An anonymous object to initialize properties. It expects the following values:
+ // dataId: The id of the HTML table to use.
+ // OR
+ // url: The url of the remote page to load
+ // dataId: The id of the table element in the remote page
+
+ if(args.url){
+ if(!args.dataId)
+ throw new Error("dojo.data.HtmlStore: Cannot instantiate using url without an id!");
+ this.url = args.url;
+ this.dataId = args.dataId;
+ }else{
+ if(args.dataId){
+ this._rootNode = dojo.byId(args.dataId);
+ this.dataId = this._rootNode.id;
+ }else{
+ this._rootNode = dojo.byId(this.dataId);
+ }
+ this._indexItems();
+ }
+ },
+
+ url: "", // So the parser can instantiate the store via markup.
+ dataId: "", // So the parser can instantiate the store via markup.
+
+ _indexItems: function(){
+ this._getHeadings();
+ if (this._rootNode.rows){//tables
+ if(this._rootNode.tBodies && this._rootNode.tBodies.length > 0) {
+ this._rootNode = this._rootNode.tBodies[0];
+ }
+ var i;
+ for(i=0; i<this._rootNode.rows.length; i++){
+ this._rootNode.rows[i].store = this;
+ this._rootNode.rows[i]._ident = i+1;
+ }
+ }else{//lists
+ var c=1;
+ for(i=0; i<this._rootNode.childNodes.length; i++){
+ if(this._rootNode.childNodes[i].nodeType===1){
+ this._rootNode.childNodes[i].store = this;
+ this._rootNode.childNodes[i]._ident = c;
+ c++;
+ }
+ }
+ }
+ },
+
+ _getHeadings: function(){
+ // summary:
+ // Function to load the attribute names from the table header so that the
+ // attributes (cells in a row), can have a reasonable name.
+ // For list items, returns single implicit heading, ["name"]
+ this._headings = [];
+ if(this._rootNode.tHead){
+ dojo.forEach(this._rootNode.tHead.rows[0].cells, dojo.hitch(this, function(th){
+ this._headings.push(dojox.data.dom.textContent(th));
+ }));
+ }else{
+ this._headings = ["name"];
+ }
+ },
+
+ _getAllItems: function(){
+ // summary:
+ // Function to return all rows in the table as an array of items.
+ var items = [];
+ var i;
+ if(this._rootNode.rows){//table
+ for(i=0; i<this._rootNode.rows.length; i++){
+ items.push(this._rootNode.rows[i]);
+ }
+ }else{ //list
+ for(i=0; i<this._rootNode.childNodes.length; i++){
+ if (this._rootNode.childNodes[i].nodeType===1){
+ items.push(this._rootNode.childNodes[i]);
+ }
+ }
+ }
+ return items; //array
+ },
+
+ _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("dojo.data.HtmlStore: a function was passed an item argument that was not an item");
+ }
+ },
+
+ _assertIsAttribute: function(/* 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.
+ //
+ // returns:
+ // Returns the index (column) that the attribute resides in the row.
+ if(typeof attribute !== "string"){
+ throw new Error("dojo.data.HtmlStore: a function was passed an attribute argument that was not an attribute name string");
+ return -1;
+ }
+ return dojo.indexOf(this._headings, attribute); //int
+ },
+
+/***************************************
+ dojo.data.api.Read API
+***************************************/
+
+ getValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ return (values.length > 0)?values[0]:defaultValue; //Object || int || Boolean
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+
+ this._assertIsItem(item);
+ var index = this._assertIsAttribute(attribute);
+
+ if(index>-1){
+ if (item.cells){
+ return [dojox.data.dom.textContent(item.cells[index])];
+ }else{//return Value for lists
+ return [dojox.data.dom.textContent(item)];
+ }
+ }
+ return []; //Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ for(var i=0; i<this._headings.length; i++){
+ if(this.hasAttribute(item, this._headings[i]))
+ attributes.push(this._headings[i]);
+ }
+ return attributes; //Array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ return this.getValues(item, attribute).length > 0;
+ },
+
+ containsValue: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ var regexp = undefined;
+ if(typeof value === "string"){
+ regexp = dojo.data.util.filter.patternToRegExp(value, false);
+ }
+ return this._containsValue(item, attribute, value, regexp); //boolean.
+ },
+
+ _containsValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value,
+ /* RegExp?*/ regexp){
+ // summary:
+ // Internal function for looking at the values contained by the item.
+ // description:
+ // Internal function for looking at the values contained by the item. This
+ // function allows for denoting if the comparison should be case sensitive for
+ // strings or not (for handling filtering cases where string case should not matter)
+ //
+ // item:
+ // The data item to examine for attribute values.
+ // attribute:
+ // The attribute to inspect.
+ // value:
+ // The value to match.
+ // regexp:
+ // Optional regular expression generated off value if value was of string type to handle wildcarding.
+ // If present and attribute values are string, then it can be used for comparison instead of 'value'
+ var values = this.getValues(item, attribute);
+ for(var i = 0; i < values.length; ++i){
+ var possibleValue = values[i];
+ if(typeof possibleValue === "string" && regexp){
+ return (possibleValue.match(regexp) !== null);
+ }else{
+ //Non-string matching.
+ if(value === possibleValue){
+ return true; // Boolean
+ }
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(something && something.store && something.store === this){
+ return true; //boolean
+ }
+ return false; //boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(something);
+ },
+
+ loadItem: function(/* Object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ this._assertIsItem(keywordArgs.item);
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Fetch items (XML elements) that match to a query
+ // description:
+ // If '_fetchUrl' is specified, it is used to load an XML document
+ // with a query string.
+ // Otherwise and if 'url' is specified, the XML document is
+ // loaded and list XML elements that match to a query (set of element
+ // names and their text attribute values that the items to contain).
+ // A wildcard, "*" can be used to query values to match all
+ // occurrences.
+ // If '_rootItem' is specified, it is used to fetch items.
+ // request:
+ // A request object
+ // fetchHandler:
+ // A function to call for fetched items
+ // errorHandler:
+ // A function to call on error
+
+ if(this._rootNode){
+ this._finishFetchItems(request, fetchHandler, errorHandler);
+ }else{
+ if(!this.url){
+ this._rootNode = dojo.byId(this.dataId);
+ }else{
+ var getArgs = {
+ url: this.url,
+ handleAs: "text"
+ };
+ var self = this;
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var findNode = function(node, id){
+ if(node.id == id){
+ return node; //object
+ }
+ if(node.childNodes){
+ for(var i=0; i<node.childNodes.length; i++){
+ var returnNode = findNode(node.childNodes[i], id);
+ if(returnNode){
+ return returnNode; //object
+ }
+ }
+ }
+ return null; //null
+ }
+
+ var d = document.createElement("div");
+ d.innerHTML = data;
+ self._rootNode = findNode(d, self.dataId);
+ self._indexItems();
+ self._finishFetchItems(request, fetchHandler, errorHandler);
+ });
+ getHandler.addErrback(function(error){
+ errorHandler(error, request);
+ });
+ }
+ }
+ },
+
+ _finishFetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Internal function for processing the passed in request and locating the requested items.
+ var items = null;
+ var arrayOfAllItems = this._getAllItems();
+ if(request.query){
+ var ignoreCase = request.queryOptions ? request.queryOptions.ignoreCase : false;
+ items = [];
+
+ //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+ //same value for each item examined. Much more efficient.
+ var regexpList = {};
+ var key;
+ var value;
+ for(key in request.query){
+ value = request.query[key]+'';
+ if(typeof value === "string"){
+ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+ }
+ }
+
+ for(var i = 0; i < arrayOfAllItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfAllItems[i];
+ for(key in request.query){
+ value = request.query[key]+'';
+ if (!this._containsValue(candidateItem, key, value, regexpList[key])){
+ match = false;
+ }
+ }
+ if(match){
+ items.push(candidateItem);
+ }
+ }
+ fetchHandler(items, request);
+ }else{
+ // We want a copy to pass back in case the parent wishes to sort the array. We shouldn't allow resort
+ // of the internal list so that multiple callers can get listsand sort without affecting each other.
+ if(arrayOfAllItems.length> 0){
+ items = arrayOfAllItems.slice(0,arrayOfAllItems.length);
+ }
+ fetchHandler(items, request);
+ }
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Identity': true
+ };
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ // nothing to do here!
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if(this.isItem(item)){
+ if(item.cells){
+ return "Item #" + this.getIdentity(item);
+ }else{
+ return this.getValue(item,"name");
+ }
+ }
+ return undefined;
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ if(item.cells){
+ return null;
+ }else{
+ return ["name"];
+ }
+ },
+
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ this._assertIsItem(item);
+ if(this.hasAttribute(item, "name")){
+ return this.getValue(item,"name");
+ }else{
+ return item._ident;
+ }
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentityAttributes()
+ //Identity isn't taken from a public attribute.
+ return null;
+ },
+
+ fetchItemByIdentity: function(keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+ var identity = keywordArgs.identity;
+ var self = this;
+ var item = null;
+ var scope = null;
+
+ if(!this._rootNode){
+ if(!this.url){
+ this._rootNode = dojo.byId(this.dataId);
+ this._indexItems();
+ if(self._rootNode.rows){ //Table
+ item = this._rootNode.rows[identity + 1];
+ }else{ //Lists
+ for(var i = 0; i < self._rootNode.childNodes.length; i++){
+ if(self._rootNode.childNodes[i].nodeType === 1 && identity === dojox.data.dom.textContent(self._rootNode.childNodes[i])) {
+ item = self._rootNode.childNodes[i];
+ }
+ }
+ }
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+
+ }else{
+ var getArgs = {
+ url: this.url,
+ handleAs: "text"
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var findNode = function(node, id){
+ if(node.id == id){
+ return node; //object
+ }
+ if(node.childNodes){
+ for(var i=0; i<node.childNodes.length; i++){
+ var returnNode = findNode(node.childNodes[i], id);
+ if(returnNode){
+ return returnNode; //object
+ }
+ }
+ }
+ return null; //null
+ }
+ var d = document.createElement("div");
+ d.innerHTML = data;
+ self._rootNode = findNode(d, self.dataId);
+ self._indexItems();
+ if(self._rootNode.rows && identity <= self._rootNode.rows.length){ //Table
+ item = self._rootNode.rows[identity-1];
+ }else{ //List
+ for(var i = 0; i < self._rootNode.childNodes.length; i++){
+ if(self._rootNode.childNodes[i].nodeType === 1 && identity === dojox.data.dom.textContent(self._rootNode.childNodes[i])) {
+ item = self._rootNode.childNodes[i];
+ break;
+ }
+ }
+ }
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ });
+ getHandler.addErrback(function(error){
+ if(keywordArgs.onError){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onError.call(scope, error);
+
+ }
+ });
+ }
+ }else{
+ if(this._rootNode.rows[identity+1]){
+ item = this._rootNode.rows[identity+1];
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }
+ }
+});
+dojo.extend(dojox.data.HtmlStore,dojo.data.util.simpleFetch);
+
+}
diff --git a/includes/js/dojox/data/HtmlTableStore.js b/includes/js/dojox/data/HtmlTableStore.js
new file mode 100644
index 0000000..98f1073
--- /dev/null
+++ b/includes/js/dojox/data/HtmlTableStore.js
@@ -0,0 +1,469 @@
+if(!dojo._hasResource["dojox.data.HtmlTableStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.HtmlTableStore"] = true;
+dojo.provide("dojox.data.HtmlTableStore");
+
+dojo.require("dojox.data.dom");
+dojo.require("dojo.data.util.simpleFetch");
+dojo.require("dojo.data.util.filter");
+
+dojo.declare("dojox.data.HtmlTableStore", null, {
+ constructor: function(/*Object*/args){
+ dojo.deprecated("dojox.data.HtmlTableStore", "Please use dojox.data.HtmlStore");
+ // summary:
+ // Initializer for the HTML table store.
+ // description:
+ // The HtmlTableStore can be created in one of two ways: a) by parsing an existing
+ // table DOM node on the current page or b) by referencing an external url and giving
+ // the id of the table in that page. The remote url will be parsed as an html page.
+ //
+ // The HTML table should be of the following form:
+ // <table id="myTable">
+ // <thead>
+ // <tr>
+ // <th>Attribute1</th>
+ // <th>Attribute2</th>
+ // </tr>
+ // </thead>
+ // <tbody>
+ // <tr>
+ // <td>Value1.1</td>
+ // <td>Value1.2</td>
+ // </tr>
+ // <tr>
+ // <td>Value2.1</td>
+ // <td>Value2.2</td>
+ // </tr>
+ // </tbody>
+ // </table>
+ //
+ // args:
+ // An anonymous object to initialize properties. It expects the following values:
+ // tableId: The id of the HTML table to use.
+ // OR
+ // url: The url of the remote page to load
+ // tableId: The id of the table element in the remote page
+
+ if(args.url){
+ if(!args.tableId)
+ throw new Error("dojo.data.HtmlTableStore: Cannot instantiate using url without an id!");
+ this.url = args.url;
+ this.tableId = args.tableId;
+ }else{
+ if(args.tableId){
+ this._rootNode = dojo.byId(args.tableId);
+ this.tableId = this._rootNode.id;
+ }else{
+ this._rootNode = dojo.byId(this.tableId);
+ }
+ this._getHeadings();
+ for(var i=0; i<this._rootNode.rows.length; i++){
+ this._rootNode.rows[i].store = this;
+ }
+ }
+ },
+
+ url: "", // So the parser can instantiate the store via markup.
+ tableId: "", // So the parser can instantiate the store via markup.
+
+ _getHeadings: function(){
+ // summary:
+ // Function to load the attribute names from the table header so that the
+ // attributes (cells in a row), can have a reasonable name.
+ this._headings = [];
+ dojo.forEach(this._rootNode.tHead.rows[0].cells, dojo.hitch(this, function(th){
+ this._headings.push(dojox.data.dom.textContent(th));
+ }));
+ },
+
+ _getAllItems: function(){
+ // summary:
+ // Function to return all rows in the table as an array of items.
+ var items = [];
+ for(var i=1; i<this._rootNode.rows.length; i++){
+ items.push(this._rootNode.rows[i]);
+ }
+ return items; //array
+ },
+
+ _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("dojo.data.HtmlTableStore: a function was passed an item argument that was not an item");
+ }
+ },
+
+ _assertIsAttribute: function(/* 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.
+ //
+ // returns:
+ // Returns the index (column) that the attribute resides in the row.
+ if(typeof attribute !== "string"){
+ throw new Error("dojo.data.HtmlTableStore: a function was passed an attribute argument that was not an attribute name string");
+ return -1;
+ }
+ return dojo.indexOf(this._headings, attribute); //int
+ },
+
+/***************************************
+ dojo.data.api.Read API
+***************************************/
+
+ getValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ return (values.length > 0)?values[0]:defaultValue; //Object || int || Boolean
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+
+ this._assertIsItem(item);
+ var index = this._assertIsAttribute(attribute);
+
+ if(index>-1){
+ return [dojox.data.dom.textContent(item.cells[index])] ;
+ }
+ return []; //Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ for(var i=0; i<this._headings.length; i++){
+ if(this.hasAttribute(item, this._headings[i]))
+ attributes.push(this._headings[i]);
+ }
+ return attributes; //Array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ return this.getValues(item, attribute).length > 0;
+ },
+
+ containsValue: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ var regexp = undefined;
+ if(typeof value === "string"){
+ regexp = dojo.data.util.filter.patternToRegExp(value, false);
+ }
+ return this._containsValue(item, attribute, value, regexp); //boolean.
+ },
+
+ _containsValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value,
+ /* RegExp?*/ regexp){
+ // summary:
+ // Internal function for looking at the values contained by the item.
+ // description:
+ // Internal function for looking at the values contained by the item. This
+ // function allows for denoting if the comparison should be case sensitive for
+ // strings or not (for handling filtering cases where string case should not matter)
+ //
+ // item:
+ // The data item to examine for attribute values.
+ // attribute:
+ // The attribute to inspect.
+ // value:
+ // The value to match.
+ // regexp:
+ // Optional regular expression generated off value if value was of string type to handle wildcarding.
+ // If present and attribute values are string, then it can be used for comparison instead of 'value'
+ var values = this.getValues(item, attribute);
+ for(var i = 0; i < values.length; ++i){
+ var possibleValue = values[i];
+ if(typeof possibleValue === "string" && regexp){
+ return (possibleValue.match(regexp) !== null);
+ }else{
+ //Non-string matching.
+ if(value === possibleValue){
+ return true; // Boolean
+ }
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(something && something.store && something.store === this){
+ return true; //boolean
+ }
+ return false; //boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(something);
+ },
+
+ loadItem: function(/* Object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ this._assertIsItem(keywordArgs.item);
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler) {
+ // summary:
+ // Fetch items (XML elements) that match to a query
+ // description:
+ // If '_fetchUrl' is specified, it is used to load an XML document
+ // with a query string.
+ // Otherwise and if 'url' is specified, the XML document is
+ // loaded and list XML elements that match to a query (set of element
+ // names and their text attribute values that the items to contain).
+ // A wildcard, "*" can be used to query values to match all
+ // occurrences.
+ // If '_rootItem' is specified, it is used to fetch items.
+ // request:
+ // A request object
+ // fetchHandler:
+ // A function to call for fetched items
+ // errorHandler:
+ // A function to call on error
+
+ if(this._rootNode){
+ this._finishFetchItems(request, fetchHandler, errorHandler);
+ }else{
+ if(!this.url){
+ this._rootNode = dojo.byId(this.tableId);
+ this._getHeadings();
+ for(var i=0; i<this._rootNode.rows.length; i++){
+ this._rootNode.rows[i].store = this;
+ }
+ }else{
+ var getArgs = {
+ url: this.url,
+ handleAs: "text"
+ };
+ var self = this;
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var findNode = function(node, id){
+ if(node.id == id){
+ return node; //object
+ }
+ if(node.childNodes){
+ for(var i=0; i<node.childNodes.length; i++){
+ var returnNode = findNode(node.childNodes[i], id);
+ if(returnNode){
+ return returnNode; //object
+ }
+ }
+ }
+ return null; //null
+ }
+
+ var d = document.createElement("div");
+ d.innerHTML = data;
+ self._rootNode = findNode(d, self.tableId);
+ self._getHeadings.call(self);
+ for(var i=0; i<self._rootNode.rows.length; i++) {
+ self._rootNode.rows[i].store = self;
+ }
+ self._finishFetchItems(request, fetchHandler, errorHandler);
+ });
+ getHandler.addErrback(function(error){
+ errorHandler(error, request);
+ });
+ }
+ }
+ },
+
+ _finishFetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Internal function for processing the passed in request and locating the requested items.
+ var items = null;
+ var arrayOfAllItems = this._getAllItems();
+ if(request.query){
+ var ignoreCase = request.queryOptions ? request.queryOptions.ignoreCase : false;
+ items = [];
+
+ //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+ //same value for each item examined. Much more efficient.
+ var regexpList = {};
+ var value;
+ var key;
+ for(key in request.query){
+ value = request.query[key]+'';
+ if(typeof value === "string"){
+ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+ }
+ }
+
+ for(var i = 0; i < arrayOfAllItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfAllItems[i];
+ for(key in request.query){
+ value = request.query[key]+'';
+ if (!this._containsValue(candidateItem, key, value, regexpList[key])){
+ match = false;
+ }
+ }
+ if(match){
+ items.push(candidateItem);
+ }
+ }
+ fetchHandler(items, request);
+ }else{
+ // We want a copy to pass back in case the parent wishes to sort the array. We shouldn't allow resort
+ // of the internal list so that multiple callers can get listsand sort without affecting each other.
+ if(arrayOfAllItems.length> 0){
+ items = arrayOfAllItems.slice(0,arrayOfAllItems.length);
+ }
+ fetchHandler(items, request);
+ }
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Identity': true
+ };
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ // nothing to do here!
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if(this.isItem(item))
+ return "Table Row #" + this.getIdentity(item);
+ return undefined;
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return null;
+ },
+
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ this._assertIsItem(item);
+ //Opera doesn't support the sectionRowIndex,
+ //So, have to call the indexOf to locate it.
+ //Blah.
+ if(!dojo.isOpera){
+ return item.sectionRowIndex; // int
+ }else{
+ return (dojo.indexOf(this._rootNode.rows, item) - 1) // int
+ }
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentityAttributes()
+ //Identity isn't taken from a public attribute.
+ return null;
+ },
+
+ fetchItemByIdentity: function(keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+ var identity = keywordArgs.identity;
+ var self = this;
+ var item = null;
+ var scope = null;
+
+ if(!this._rootNode){
+ if(!this.url){
+ this._rootNode = dojo.byId(this.tableId);
+ this._getHeadings();
+ for(var i=0; i<this._rootNode.rows.length; i++){
+ this._rootNode.rows[i].store = this;
+ }
+ item = this._rootNode.rows[identity+1];
+ if (keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+
+ }else{
+ var getArgs = {
+ url: this.url,
+ handleAs: "text"
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var findNode = function(node, id){
+ if(node.id == id){
+ return node; //object
+ }
+ if(node.childNodes) {
+ for(var i=0; i<node.childNodes.length; i++){
+ var returnNode = findNode(node.childNodes[i], id);
+ if(returnNode){
+ return returnNode; //object
+ }
+ }
+ }
+ return null; //null
+ }
+ var d = document.createElement("div");
+ d.innerHTML = data;
+ self._rootNode = findNode(d, self.tableId);
+ self._getHeadings.call(self);
+ for(var i=0; i<self._rootNode.rows.length; i++){
+ self._rootNode.rows[i].store = self;
+ }
+ item = self._rootNode.rows[identity+1];
+ if (keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ });
+ getHandler.addErrback(function(error){
+ if(keywordArgs.onError){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onError.call(scope, error);
+
+ }
+ });
+ }
+ }else{
+ if(this._rootNode.rows[identity+1]){
+ item = this._rootNode.rows[identity+1];
+ if (keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }
+ }
+});
+dojo.extend(dojox.data.HtmlTableStore,dojo.data.util.simpleFetch);
+
+}
diff --git a/includes/js/dojox/data/KeyValueStore.js b/includes/js/dojox/data/KeyValueStore.js
new file mode 100644
index 0000000..e86b686
--- /dev/null
+++ b/includes/js/dojox/data/KeyValueStore.js
@@ -0,0 +1,381 @@
+if(!dojo._hasResource["dojox.data.KeyValueStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.KeyValueStore"] = true;
+dojo.provide("dojox.data.KeyValueStore");
+
+dojo.require("dojo.data.util.filter");
+dojo.require("dojo.data.util.simpleFetch");
+
+dojo.declare("dojox.data.KeyValueStore", null, {
+ // summary:
+ // This is a dojo.data store implementation. It can take in either a Javascript
+ // array, JSON string, or URL as the data source. Data is expected to be in the
+ // following format:
+ // [
+ // { "key1": "value1" },
+ // { "key2": "value2" }
+ // ]
+ // This is to mimic the Java Properties file format. Each 'item' from this store
+ // is a JS object representing a key-value pair. If an item in the above array has
+ // more than one key/value pair, only the first will be used/accessed.
+ constructor: function(/* Object */ keywordParameters){
+ // summary: constructor
+ // keywordParameters: {url: String}
+ // keywordParameters: {data: string}
+ // keywordParameters: {dataVar: jsonObject}
+ if(keywordParameters.url){
+ this.url = keywordParameters.url;
+ }
+ this._keyValueString = keywordParameters.data;
+ this._keyValueVar = keywordParameters.dataVar;
+ this._keyAttribute = "key";
+ this._valueAttribute = "value";
+ this._storeProp = "_keyValueStore";
+ this._features = {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Identity': true
+ };
+ this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset.
+ this._queuedFetches = [];
+ },
+
+ url: "",
+ data: "",
+
+ _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.KeyValueStore: a function was passed an item argument that was not an item");
+ }
+ },
+
+ _assertIsAttribute: function(/* item */ item, /* 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(!dojo.isString(attribute)){
+ throw new Error("dojox.data.KeyValueStore: a function was passed an attribute argument that was not an attribute object nor an attribute name string");
+ }
+ },
+
+/***************************************
+ dojo.data.api.Read API
+***************************************/
+ getValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ this._assertIsItem(item);
+ this._assertIsAttribute(item, attribute);
+ if(attribute == this._keyAttribute){ // Looking for key
+ return item[this._keyAttribute];
+ }
+ return item[this._valueAttribute]; // Otherwise, attribute == ('value' || the actual key )
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+ // Key/Value syntax does not support multi-valued attributes, so this is just a
+ // wrapper function for getValue().
+ var value = this.getValue(item, attribute);
+ return (value ? [value] : []); //Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ return [this._keyAttribute, this._valueAttribute, item[this._keyAttribute]];
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ this._assertIsItem(item);
+ this._assertIsAttribute(item, attribute);
+ return (attribute == this._keyAttribute || attribute == this._valueAttribute || attribute == item[this._keyAttribute]);
+ },
+
+ containsValue: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ var regexp = undefined;
+ if(typeof value === "string"){
+ regexp = dojo.data.util.filter.patternToRegExp(value, false);
+ }
+ return this._containsValue(item, attribute, value, regexp); //boolean.
+ },
+
+ _containsValue: function( /* item */ item,
+ /* attribute || attribute-name-string */ attribute,
+ /* anything */ value,
+ /* RegExp?*/ regexp){
+ // summary:
+ // Internal function for looking at the values contained by the item.
+ // description:
+ // Internal function for looking at the values contained by the item. This
+ // function allows for denoting if the comparison should be case sensitive for
+ // strings or not (for handling filtering cases where string case should not matter)
+ //
+ // item:
+ // The data item to examine for attribute values.
+ // attribute:
+ // The attribute to inspect.
+ // value:
+ // The value to match.
+ // regexp:
+ // Optional regular expression generated off value if value was of string type to handle wildcarding.
+ // If present and attribute values are string, then it can be used for comparison instead of 'value'
+ var values = this.getValues(item, attribute);
+ for(var i = 0; i < values.length; ++i){
+ var possibleValue = values[i];
+ if(typeof possibleValue === "string" && regexp){
+ return (possibleValue.match(regexp) !== null);
+ }else{
+ //Non-string matching.
+ if(value === possibleValue){
+ return true; // Boolean
+ }
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if (something && something[this._storeProp] === this) {
+ return true; //Boolean
+ }
+ return false; //Boolean
+ },
+
+ isItemLoaded: function(/* anything */ something) {
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ // The KeyValueStore always loads all items, so if it's an item, then it's loaded.
+ return this.isItem(something); //Boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ // description:
+ // The KeyValueStore always loads all items, so if it's an item, then it's loaded.
+ // From the dojo.data.api.Read.loadItem docs:
+ // If a call to isItemLoaded() returns true before loadItem() is even called,
+ // then loadItem() need not do any work at all and will not even invoke
+ // the callback handlers.
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return this._features; //Object
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ return item[this._keyAttribute];
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return [this._keyAttribute];
+ },
+
+ // The dojo.data.api.Read.fetch() function is implemented as
+ // a mixin from dojo.data.util.simpleFetch.
+ // That mixin requires us to define _fetchItems().
+ _fetchItems: function( /* Object */ keywordArgs,
+ /* Function */ findCallback,
+ /* Function */ errorCallback){
+ // summary:
+ // See dojo.data.util.simpleFetch.fetch()
+
+ var self = this;
+
+ var filter = function(requestArgs, arrayOfAllItems){
+ var items = null;
+ if(requestArgs.query){
+ items = [];
+ var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false;
+
+ //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+ //same value for each item examined. Much more efficient.
+ var regexpList = {};
+ for(var key in requestArgs.query){
+ var value = requestArgs.query[key];
+ if(typeof value === "string"){
+ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+ }
+ }
+
+ for(var i = 0; i < arrayOfAllItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfAllItems[i];
+ for(var key in requestArgs.query){
+ var value = requestArgs.query[key];
+ if(!self._containsValue(candidateItem, key, value, regexpList[key])){
+ match = false;
+ }
+ }
+ if(match){
+ items.push(candidateItem);
+ }
+ }
+ }else if(requestArgs.identity){
+ items = [];
+ var item;
+ for(var key in arrayOfAllItems){
+ item = arrayOfAllItems[key];
+ if(item[self._keyAttribute] == requestArgs.identity){
+ items.push(item);
+ break;
+ }
+ }
+ }else{
+ // We want a copy to pass back in case the parent wishes to sort the array. We shouldn't allow resort
+ // of the internal list so that multiple callers can get lists and sort without affecting each other.
+ if(arrayOfAllItems.length> 0){
+ items = arrayOfAllItems.slice(0,arrayOfAllItems.length);
+ }
+ }
+ findCallback(items, requestArgs);
+ };
+
+ if(this._loadFinished){
+ filter(keywordArgs, this._arrayOfAllItems);
+ }else{
+ if(this.url !== ""){
+ //If fetches come in before the loading has finished, but while
+ //a load is in progress, we have to defer the fetching to be
+ //invoked in the callback.
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs, filter: filter});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self.url,
+ handleAs: "json-comment-filtered"
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ self._processData(data);
+ filter(keywordArgs, self._arrayOfAllItems);
+ self._handleQueuedFetches();
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ throw error;
+ });
+ }
+ }else if(this._keyValueString){
+ this._processData(eval(this._keyValueString));
+ this._keyValueString = null;
+ filter(keywordArgs, this._arrayOfAllItems);
+ }else if(this._keyValueVar){
+ this._processData(this._keyValueVar);
+ this._keyValueVar = null;
+ filter(keywordArgs, this._arrayOfAllItems);
+ }else{
+ throw new Error("dojox.data.KeyValueStore: No source data was provided as either URL, String, or Javascript variable data input.");
+ }
+ }
+
+ },
+
+ _handleQueuedFetches: function(){
+ // summary:
+ // Internal function to execute delayed request in the store.
+ //Execute any deferred fetches now.
+ if(this._queuedFetches.length > 0){
+ for(var i = 0; i < this._queuedFetches.length; i++){
+ var fData = this._queuedFetches[i];
+ var delayedFilter = fData.filter;
+ var delayedQuery = fData.args;
+ if(delayedFilter){
+ delayedFilter(delayedQuery, this._arrayOfAllItems);
+ }else{
+ this.fetchItemByIdentity(fData.args);
+ }
+ }
+ this._queuedFetches = [];
+ }
+ },
+
+ _processData: function(/* Array */ data){
+ this._arrayOfAllItems = [];
+ for(var i=0; i<data.length; i++){
+ this._arrayOfAllItems.push(this._createItem(data[i]));
+ }
+ this._loadFinished = true;
+ this._loadInProgress = false;
+ },
+
+ _createItem: function(/* Object */ something){
+ var item = {};
+ item[this._storeProp] = this;
+ for(var i in something){
+ item[this._keyAttribute] = i;
+ item[this._valueAttribute] = something[i];
+ break;
+ }
+ return item; //Object
+ },
+
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ if(this.isItem(item)){
+ return item[this._keyAttribute]; //String
+ }
+ return null; //null
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentifierAttributes()
+ return [this._keyAttribute];
+ },
+
+ fetchItemByIdentity: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+ keywordArgs.oldOnItem = keywordArgs.onItem;
+ keywordArgs.onItem = null;
+ keywordArgs.onComplete = this._finishFetchItemByIdentity ;
+ this.fetch(keywordArgs);
+ },
+
+ _finishFetchItemByIdentity: function(/* Array */ items, /* object */ request) {
+ var scope = request.scope || dojo.global;
+ if(items.length){
+ request.oldOnItem.call(scope, items[0]);
+ }else{
+ request.oldOnItem.call(scope, null);
+ }
+ }
+});
+//Mix in the simple fetch implementation to this class.
+dojo.extend(dojox.data.KeyValueStore,dojo.data.util.simpleFetch);
+
+}
diff --git a/includes/js/dojox/data/OpmlStore.js b/includes/js/dojox/data/OpmlStore.js
new file mode 100644
index 0000000..94b3150
--- /dev/null
+++ b/includes/js/dojox/data/OpmlStore.js
@@ -0,0 +1,515 @@
+if(!dojo._hasResource["dojox.data.OpmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.OpmlStore"] = true;
+dojo.provide("dojox.data.OpmlStore");
+
+dojo.require("dojo.data.util.filter");
+dojo.require("dojo.data.util.simpleFetch");
+
+dojo.declare("dojox.data.OpmlStore", null, {
+ /* summary:
+ * The OpmlStore implements the dojo.data.api.Read API.
+ */
+
+ /* examples:
+ * var opmlStore = new dojo.data.OpmlStore({url:"geography.xml"});
+ * var opmlStore = new dojo.data.OpmlStore({url:"http://example.com/geography.xml"});
+ */
+ constructor: function(/* Object */ keywordParameters){
+ // summary: constructor
+ // keywordParameters: {url: String, label: String} Where label is optional and configures what should be used as the return from getLabel()
+ this._xmlData = null;
+ this._arrayOfTopLevelItems = [];
+ this._arrayOfAllItems = [];
+ this._metadataNodes = null;
+ this._loadFinished = false;
+ this.url = keywordParameters.url;
+ this._opmlData = keywordParameters.data; // XML DOM Document
+ if(keywordParameters.label){
+ this.label = keywordParameters.label;
+ }
+ this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset.
+ this._queuedFetches = [];
+ this._identityMap = {};
+ this._identCount = 0;
+ this._idProp = "_I";
+ },
+
+ label: "text",
+
+ url: "",
+
+ _assertIsItem: function(/* item */ item){
+ if(!this.isItem(item)){
+ throw new Error("dojo.data.OpmlStore: a function was passed an item argument that was not an item");
+ }
+ },
+
+ _assertIsAttribute: function(/* item || 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(!dojo.isString(attribute)){
+ throw new Error("dojox.data.OpmlStore: a function was passed an attribute argument that was not an attribute object nor an attribute name string");
+ }
+ },
+
+ _removeChildNodesThatAreNotElementNodes: function(/* node */ node, /* boolean */ recursive){
+ var childNodes = node.childNodes;
+ if(childNodes.length === 0){
+ return;
+ }
+ var nodesToRemove = [];
+ var i, childNode;
+ for(i = 0; i < childNodes.length; ++i){
+ childNode = childNodes[i];
+ if(childNode.nodeType != 1){
+ nodesToRemove.push(childNode);
+ }
+ }
+ for(i = 0; i < nodesToRemove.length; ++i){
+ childNode = nodesToRemove[i];
+ node.removeChild(childNode);
+ }
+ if(recursive){
+ for(i = 0; i < childNodes.length; ++i){
+ childNode = childNodes[i];
+ this._removeChildNodesThatAreNotElementNodes(childNode, recursive);
+ }
+ }
+ },
+
+ _processRawXmlTree: function(/* xmlDoc */ rawXmlTree){
+ this._loadFinished = true;
+ this._xmlData = rawXmlTree;
+ var headNodes = rawXmlTree.getElementsByTagName('head');
+ var headNode = headNodes[0];
+ if(headNode){
+ this._removeChildNodesThatAreNotElementNodes(headNode);
+ this._metadataNodes = headNode.childNodes;
+ }
+ var bodyNodes = rawXmlTree.getElementsByTagName('body');
+ var bodyNode = bodyNodes[0];
+ if(bodyNode){
+ this._removeChildNodesThatAreNotElementNodes(bodyNode, true);
+
+ var bodyChildNodes = bodyNodes[0].childNodes;
+ for(var i = 0; i < bodyChildNodes.length; ++i){
+ var node = bodyChildNodes[i];
+ if(node.tagName == 'outline'){
+ this._identityMap[this._identCount] = node;
+ this._identCount++;
+ this._arrayOfTopLevelItems.push(node);
+ this._arrayOfAllItems.push(node);
+ this._checkChildNodes(node);
+ }
+ }
+ }
+ },
+
+ _checkChildNodes: function(node /*Node*/){
+ // summary:
+ // Internal function to recurse over all child nodes from the store and add them
+ // As non-toplevel items
+ // description:
+ // Internal function to recurse over all child nodes from the store and add them
+ // As non-toplevel items
+ //
+ // node:
+ // The child node to walk.
+ if(node.firstChild){
+ for(var i = 0; i < node.childNodes.length; i++){
+ var child = node.childNodes[i];
+ if(child.tagName == 'outline'){
+ this._identityMap[this._identCount] = child;
+ this._identCount++;
+ this._arrayOfAllItems.push(child);
+ this._checkChildNodes(child);
+ }
+ }
+ }
+ },
+
+ _getItemsArray: function(/*object?*/queryOptions){
+ // summary:
+ // Internal function to determine which list of items to search over.
+ // queryOptions: The query options parameter, if any.
+ if(queryOptions && queryOptions.deep) {
+ return this._arrayOfAllItems;
+ }
+ return this._arrayOfTopLevelItems;
+ },
+
+/***************************************
+ dojo.data.api.Read API
+***************************************/
+ getValue: function( /* item */ item,
+ /* attribute || attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ if(attribute == 'children'){
+ return (item.firstChild || defaultValue); //Object
+ } else {
+ var value = item.getAttribute(attribute);
+ return (value !== undefined) ? value : defaultValue; //Object
+ }
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute || attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ var array = [];
+ if(attribute == 'children'){
+ for(var i = 0; i < item.childNodes.length; ++i){
+ array.push(item.childNodes[i]);
+ }
+ } else if(item.getAttribute(attribute) !== null){
+ array.push(item.getAttribute(attribute));
+ }
+ return array; // Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ var xmlNode = item;
+ var xmlAttributes = xmlNode.attributes;
+ for(var i = 0; i < xmlAttributes.length; ++i){
+ var xmlAttribute = xmlAttributes.item(i);
+ attributes.push(xmlAttribute.nodeName);
+ }
+ if(xmlNode.childNodes.length > 0){
+ attributes.push('children');
+ }
+ return attributes; //Array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute || attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ return (this.getValues(item, attribute).length > 0); //Boolean
+ },
+
+ containsValue: function(/* item */ item,
+ /* attribute || attribute-name-string */ attribute,
+ /* anything */ value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ var regexp = undefined;
+ if(typeof value === "string"){
+ regexp = dojo.data.util.filter.patternToRegExp(value, false);
+ }
+ return this._containsValue(item, attribute, value, regexp); //boolean.
+ },
+
+ _containsValue: function( /* item */ item,
+ /* attribute || attribute-name-string */ attribute,
+ /* anything */ value,
+ /* RegExp?*/ regexp){
+ // summary:
+ // Internal function for looking at the values contained by the item.
+ // description:
+ // Internal function for looking at the values contained by the item. This
+ // function allows for denoting if the comparison should be case sensitive for
+ // strings or not (for handling filtering cases where string case should not matter)
+ //
+ // item:
+ // The data item to examine for attribute values.
+ // attribute:
+ // The attribute to inspect.
+ // value:
+ // The value to match.
+ // regexp:
+ // Optional regular expression generated off value if value was of string type to handle wildcarding.
+ // If present and attribute values are string, then it can be used for comparison instead of 'value'
+ var values = this.getValues(item, attribute);
+ for(var i = 0; i < values.length; ++i){
+ var possibleValue = values[i];
+ if(typeof possibleValue === "string" && regexp){
+ return (possibleValue.match(regexp) !== null);
+ }else{
+ //Non-string matching.
+ if(value === possibleValue){
+ return true; // Boolean
+ }
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ // description:
+ // Four things are verified to ensure that "something" is an item:
+ // something can not be null, the nodeType must be an XML Element,
+ // the tagName must be "outline", and the node must be a member of
+ // XML document for this datastore.
+ return (something &&
+ something.nodeType == 1 &&
+ something.tagName == 'outline' &&
+ something.ownerDocument === this._xmlData); //Boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ // OpmlStore loads every item, so if it's an item, then it's loaded.
+ return this.isItem(something); //Boolean
+ },
+
+ loadItem: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ // description:
+ // The OpmlStore always loads all items, so if it's an item, then it's loaded.
+ // From the dojo.data.api.Read.loadItem docs:
+ // If a call to isItemLoaded() returns true before loadItem() is even called,
+ // then loadItem() need not do any work at all and will not even invoke the callback handlers.
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if(this.isItem(item)){
+ return this.getValue(item,this.label); //String
+ }
+ return undefined; //undefined
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return [this.label]; //array
+ },
+
+ // The dojo.data.api.Read.fetch() function is implemented as
+ // a mixin from dojo.data.util.simpleFetch.
+ // That mixin requires us to define _fetchItems().
+ _fetchItems: function( /* Object */ keywordArgs,
+ /* Function */ findCallback,
+ /* Function */ errorCallback){
+ // summary:
+ // See dojo.data.util.simpleFetch.fetch()
+
+ var self = this;
+ var filter = function(requestArgs, arrayOfItems){
+ var items = null;
+ if(requestArgs.query){
+ items = [];
+ var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false;
+
+ //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+ //same value for each item examined. Much more efficient.
+ var regexpList = {};
+ for(var key in requestArgs.query){
+ var value = requestArgs.query[key];
+ if(typeof value === "string"){
+ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+ }
+ }
+
+ for(var i = 0; i < arrayOfItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfItems[i];
+ for(var key in requestArgs.query){
+ var value = requestArgs.query[key];
+ if(!self._containsValue(candidateItem, key, value, regexpList[key])){
+ match = false;
+ }
+ }
+ if(match){
+ items.push(candidateItem);
+ }
+ }
+ }else{
+ // We want a copy to pass back in case the parent wishes to sort the array. We shouldn't allow resort
+ // of the internal list so that multiple callers can get lists and sort without affecting each other.
+ if(arrayOfItems.length> 0){
+ items = arrayOfItems.slice(0,arrayOfItems.length);
+ }
+ }
+ findCallback(items, requestArgs);
+ };
+
+ if(this._loadFinished){
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }else{
+
+ //If fetches come in before the loading has finished, but while
+ //a load is in progress, we have to defer the fetching to be
+ //invoked in the callback.
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs, filter: filter});
+ }else{
+ if(this.url !== ""){
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self.url,
+ handleAs: "xml"
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ self._processRawXmlTree(data);
+ filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
+ self._handleQueuedFetches();
+ });
+ getHandler.addErrback(function(error){
+ throw error;
+ });
+ }else if(this._opmlData){
+ this._processRawXmlTree(this._opmlData);
+ this._opmlData = null;
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }else{
+ throw new Error("dojox.data.OpmlStore: No OPML source data was provided as either URL or XML data input.");
+ }
+ }
+ }
+ },
+
+ getFeatures: function(){
+ // summary: See dojo.data.api.Read.getFeatures()
+ var features = {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Identity': true
+ };
+ return features; //Object
+ },
+
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ if(this.isItem(item)){
+ //No ther way to do this other than O(n) without
+ //complete rework of how the tree stores nodes.
+ for(var i in this._identityMap){
+ if(this._identityMap[i] === item){
+ return i;
+ }
+ }
+ }
+ return null; //null
+ },
+
+ fetchItemByIdentity: function(/* Object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+
+ //Hasn't loaded yet, we have to trigger the load.
+ if(!this._loadFinished){
+ var self = this;
+ if(this.url !== ""){
+ //If fetches come in before the loading has finished, but while
+ //a load is in progress, we have to defer the fetching to be
+ //invoked in the callback.
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self.url,
+ handleAs: "xml"
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ try{
+ self._processRawXmlTree(data);
+ var item = self._identityMap[keywordArgs.identity];
+ if(!self.isItem(item)){
+ item = null;
+ }
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ self._handleQueuedFetches();
+ }catch(error){
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ }
+ });
+ getHandler.addErrback(function(error){
+ this._loadInProgress = false;
+ if(keywordArgs.onError){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+ }
+ }else if(this._opmlData){
+ this._processRawXmlTree(this._opmlData);
+ this._opmlData = null;
+ var item = this._identityMap[keywordArgs.identity];
+ if(!self.isItem(item)){
+ item = null;
+ }
+ if(keywordArgs.onItem){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }else{
+ //Already loaded. We can just look it up and call back.
+ var item = this._identityMap[keywordArgs.identity];
+ if(!this.isItem(item)){
+ item = null;
+ }
+ if(keywordArgs.onItem){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentifierAttributes()
+
+ //Identity isn't a public attribute in the item, it's the node count.
+ //So, return null.
+ return null;
+ },
+
+ _handleQueuedFetches: function(){
+ // summary:
+ // Internal function to execute delayed request in the store.
+ //Execute any deferred fetches now.
+ if (this._queuedFetches.length > 0) {
+ for(var i = 0; i < this._queuedFetches.length; i++){
+ var fData = this._queuedFetches[i];
+ var delayedQuery = fData.args;
+ var delayedFilter = fData.filter;
+ if(delayedFilter){
+ delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions));
+ }else{
+ this.fetchItemByIdentity(delayedQuery);
+ }
+ }
+ this._queuedFetches = [];
+ }
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ }
+});
+//Mix in the simple fetch implementation to this class.
+dojo.extend(dojox.data.OpmlStore,dojo.data.util.simpleFetch);
+
+
+}
diff --git a/includes/js/dojox/data/PicasaStore.js b/includes/js/dojox/data/PicasaStore.js
new file mode 100644
index 0000000..e1b96b0
--- /dev/null
+++ b/includes/js/dojox/data/PicasaStore.js
@@ -0,0 +1,254 @@
+if(!dojo._hasResource["dojox.data.PicasaStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.PicasaStore"] = true;
+dojo.provide("dojox.data.PicasaStore");
+
+dojo.require("dojo.data.util.simpleFetch");
+dojo.require("dojo.io.script");
+dojo.require("dojo.date.stamp");
+
+dojo.declare("dojox.data.PicasaStore", null, {
+ constructor: function(/*Object*/args){
+ // summary:
+ // Initializer for the PicasaStore store.
+ // description:
+ // The PicasaStore is a Datastore interface to one of the basic services
+ // of the Picasa service, the public photo feed. This does not provide
+ // access to all the services of Picasa.
+ // This store cannot do * and ? filtering as the picasa service
+ // provides no interface for wildcards.
+ if(args && args.label){
+ this.label = args.label;
+ }
+ },
+
+ _picasaUrl: "http://picasaweb.google.com/data/feed/api/all",
+
+ _storeRef: "_S",
+
+ label: "title",
+
+ _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.PicasaStore: a function was passed an item argument that was not an item");
+ }
+ },
+
+ _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.PicasaStore: a function was passed an attribute argument that was not an attribute name string");
+ }
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true
+ };
+ },
+
+ getValue: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ if(values){
+ return values[0];
+ }
+ return undefined;
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ return ["id", "published", "updated", "category", "title$type", "title", "summary$type", "summary", "rights$type", "rights", "link", "author", "gphoto$id", "gphoto$name", "location"];
+ },
+
+ hasAttribute: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttributes()
+ if(this.getValue(item,attribute)){
+ return true;
+ }
+ return false;
+ },
+
+ isItemLoaded: function(item){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(item);
+ },
+
+ loadItem: function(keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ },
+
+ getLabel: function(item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ return this.getValue(item,this.label);
+ },
+
+ getLabelAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return [this.label];
+ },
+
+ containsValue: function(item, attribute, value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ var values = this.getValues(item,attribute);
+ for(var i = 0; i < values.length; i++){
+ if(values[i] === value){
+ return true;
+ }
+ }
+ return false;
+ },
+
+ getValues: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ if(attribute === "title"){
+ return [this._unescapeHtml(item.title)];
+ }else if(attribute === "author"){
+ return [this._unescapeHtml(item.author[0].name)];
+ }else if(attribute === "datePublished"){
+ return [dojo.date.stamp.fromISOString(item.published)];
+ }else if(attribute === "dateTaken"){
+ return [dojo.date.stamp.fromISOString(item.date_taken)];
+ }else if(attribute === "imageUrlSmall"){
+ return [item.media.thumbnail[1].url];
+ }else if(attribute === "imageUrl"){
+ return [item.content$src];
+ }else if(attribute === "imageUrlMedium"){
+ return [item.media.thumbnail[2].url];
+ }else if(attribute === "link"){
+ return [item.link[1]];
+ }else if(attribute === "tags"){
+ return item.tags.split(" ");
+ }else if(attribute === "description"){
+ return [this._unescapeHtml(item.summary)];
+ }
+ return undefined;
+ },
+
+ isItem: function(item){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(item && item[this._storeRef] === this){
+ return true;
+ }
+ return false;
+ },
+
+ close: function(request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Fetch picasa items that match to a query
+ // request:
+ // A request object
+ // fetchHandler:
+ // A function to call for fetched items
+ // errorHandler:
+ // A function to call on error
+
+ if(!request.query){
+ request.query={};
+ }
+
+ //Build up the content to send the request for.
+ var content = {alt: "jsonm", pp: "1", psc: "G"};
+ content['start-index'] = "1";
+ if(request.query.start){
+ content['start-index'] = request.query.start;
+ }
+ if(request.query.tags){
+ content.q = request.query.tags;
+ }
+ if(request.query.userid){
+ content.uname = request.query.userid;
+ }
+ if(request.query.userids){
+ content.ids = request.query.userids;
+ }
+ if(request.query.lang){
+ content.hl = request.query.lang;
+ }
+ if(request.count){
+ content['max-results'] = request.count;
+ }else{
+ content['max-results'] = "20";
+ }
+
+ //Linking this up to Picasa is a JOY!
+ var self = this;
+ var handle = null;
+ var myHandler = function(data){
+ if(handle !== null){
+ dojo.disconnect(handle);
+ }
+
+ //Process the items...
+ fetchHandler(self._processPicasaData(data), request);
+ };
+ var getArgs = {
+ url: this._picasaUrl,
+ // preventCache: true,
+ content: content,
+ callbackParamName: 'callback',
+ handle: myHandler
+ };
+ var deferred = dojo.io.script.get(getArgs);
+
+ deferred.addErrback(function(error){
+ dojo.disconnect(handle);
+ errorHandler(error, request);
+ });
+ },
+
+ _processPicasaData: function(data){
+ var items = [];
+ if(data.feed){
+ items = data.feed.entry;
+ //Add on the store ref so that isItem can work.
+ for(var i = 0; i < items.length; i++){
+ var item = items[i];
+ item[this._storeRef] = this;
+ }
+ }
+ return items;
+ },
+
+ _unescapeHtml: function(str){
+ // summary: Utility function to un-escape XML special characters in an HTML string.
+ // description: Utility function to un-escape XML special characters in an HTML string.
+ // str: String.
+ // The string to un-escape
+ // returns: HTML String converted back to the normal text (unescaped) characters (<,>,&, ", etc,).
+ //
+ //TODO: Check to see if theres already compatible escape() in dojo.string or dojo.html
+ str = str.replace(/&amp;/gm, "&").replace(/&lt;/gm, "<").replace(/&gt;/gm, ">").replace(/&quot;/gm, "\"");
+ str = str.replace(/&#39;/gm, "'");
+ return str;
+ }
+});
+dojo.extend(dojox.data.PicasaStore,dojo.data.util.simpleFetch);
+
+}
diff --git a/includes/js/dojox/data/QueryReadStore.js b/includes/js/dojox/data/QueryReadStore.js
new file mode 100644
index 0000000..95af166
--- /dev/null
+++ b/includes/js/dojox/data/QueryReadStore.js
@@ -0,0 +1,513 @@
+if(!dojo._hasResource["dojox.data.QueryReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.QueryReadStore"] = true;
+dojo.provide("dojox.data.QueryReadStore");
+
+dojo.require("dojo.string");
+
+dojo.declare("dojox.data.QueryReadStore",
+ null,
+ {
+ // summary:
+ // This class provides a store that is mainly intended to be used
+ // for loading data dynamically from the server, used i.e. for
+ // retreiving chunks of data from huge data stores on the server (by server-side filtering!).
+ // Upon calling the fetch() method of this store the data are requested from
+ // the server if they are not yet loaded for paging (or cached).
+ //
+ // For example used for a combobox which works on lots of data. It
+ // can be used to retreive the data partially upon entering the
+ // letters "ac" it returns only items like "action", "acting", etc.
+ //
+ // note:
+ // The field name "id" in a query is reserved for looking up data
+ // by id. This is necessary as before the first fetch, the store
+ // has no way of knowing which field the server will declare as
+ // identifier.
+ //
+ // examples:
+ // | // The parameter "query" contains the data that are sent to the server.
+ // | var store = new dojox.data.QueryReadStore({url:'/search.php'});
+ // | store.fetch({query:{name:'a'}, queryOptions:{ignoreCase:false}});
+ //
+ // | // Since "serverQuery" is given, it overrules and those data are
+ // | // sent to the server.
+ // | var store = new dojox.data.QueryReadStore({url:'/search.php'});
+ // | store.fetch({serverQuery:{name:'a'}, queryOptions:{ignoreCase:false}});
+ //
+ // | <div dojoType="dojox.data.QueryReadStore"
+ // | jsId="store2"
+ // | url="../tests/stores/QueryReadStore.php"
+ // | requestMethod="post"></div>
+ // | <div dojoType="dojox.grid.data.DojoData"
+ // | jsId="model2"
+ // | store="store2"
+ // | sortFields="[{attribute: 'name', descending: true}]"
+ // | rowsPerPage="30"></div>
+ // | <div dojoType="dojox.Grid" id="grid2"
+ // | model="model2"
+ // | structure="gridLayout"
+ // | style="height:300px; width:800px;"></div>
+
+ //
+ // todo:
+ // - there is a bug in the paging, when i set start:2, count:5 after an initial fetch() and doClientPaging:true
+ // it returns 6 elemetns, though count=5, try it in QueryReadStore.html
+ // - add optional caching
+ // - when the first query searched for "a" and the next for a subset of
+ // the first, i.e. "ab" then we actually dont need a server request, if
+ // we have client paging, we just need to filter the items we already have
+ // that might also be tooo much logic
+
+ url:"",
+ requestMethod:"get",
+ //useCache:false,
+
+ // We use the name in the errors, once the name is fixed hardcode it, may be.
+ _className:"dojox.data.QueryReadStore",
+
+ // This will contain the items we have loaded from the server.
+ // The contents of this array is optimized to satisfy all read-api requirements
+ // and for using lesser storage, so the keys and their content need some explaination:
+ // this._items[0].i - the item itself
+ // this._items[0].r - a reference to the store, so we can identify the item
+ // securly. We set this reference right after receiving the item from the
+ // server.
+ _items:[],
+
+ // Store the last query that triggered xhr request to the server.
+ // So we can compare if the request changed and if we shall reload
+ // (this also depends on other factors, such as is caching used, etc).
+ _lastServerQuery:null,
+
+
+ // Store a hash of the last server request. Actually I introduced this
+ // for testing, so I can check if no unnecessary requests were issued for
+ // client-side-paging.
+ lastRequestHash:null,
+
+ // summary:
+ // By default every request for paging is sent to the server.
+ doClientPaging:false,
+
+ // summary:
+ // By default all the sorting is done serverside before the data is returned
+ // which is the proper place to be doing it for really large datasets.
+ doClientSorting:false,
+
+ // Items by identify for Identify API
+ _itemsByIdentity:null,
+
+ // Identifier used
+ _identifier:null,
+
+ _features: {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true},
+
+ _labelAttr: "label",
+
+ constructor: function(/* Object */ params){
+ dojo.mixin(this,params);
+ },
+
+ getValue: function(/* item */ item, /* attribute-name-string */ attribute, /* value? */ defaultValue){
+ // According to the Read API comments in getValue() and exception is
+ // thrown when an item is not an item or the attribute not a string!
+ this._assertIsItem(item);
+ if (!dojo.isString(attribute)) {
+ throw new Error(this._className+".getValue(): Invalid attribute, string expected!");
+ }
+ if(!this.hasAttribute(item, attribute)){
+ // read api says: return defaultValue "only if *item* does not have a value for *attribute*."
+ // Is this the case here? The attribute doesn't exist, but a defaultValue, sounds reasonable.
+ if(defaultValue){
+ return defaultValue;
+ }
+ console.log(this._className+".getValue(): Item does not have the attribute '"+attribute+"'.");
+ }
+ return item.i[attribute];
+ },
+
+ getValues: function(/* item */ item, /* attribute-name-string */ attribute){
+ this._assertIsItem(item);
+ var ret = [];
+ if(this.hasAttribute(item, attribute)){
+ ret.push(item.i[attribute]);
+ }
+ return ret;
+ },
+
+ getAttributes: function(/* item */ item){
+ this._assertIsItem(item);
+ var ret = [];
+ for(var i in item.i){
+ ret.push(i);
+ }
+ return ret;
+ },
+
+ hasAttribute: function(/* item */ item, /* attribute-name-string */ attribute) {
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ return this.isItem(item) && typeof item.i[attribute]!="undefined";
+ },
+
+ containsValue: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ value){
+ var values = this.getValues(item, attribute);
+ var len = values.length;
+ for(var i=0; i<len; i++){
+ if(values[i]==value){
+ return true;
+ }
+ }
+ return false;
+ },
+
+ isItem: function(/* anything */ something){
+ // Some basic tests, that are quick and easy to do here.
+ // >>> var store = new dojox.data.QueryReadStore({});
+ // >>> store.isItem("");
+ // false
+ //
+ // >>> var store = new dojox.data.QueryReadStore({});
+ // >>> store.isItem({});
+ // false
+ //
+ // >>> var store = new dojox.data.QueryReadStore({});
+ // >>> store.isItem(0);
+ // false
+ //
+ // >>> var store = new dojox.data.QueryReadStore({});
+ // >>> store.isItem({name:"me", label:"me too"});
+ // false
+ //
+ if(something){
+ return typeof something.r!="undefined" && something.r==this;
+ }
+ return false;
+ },
+
+ isItemLoaded: function(/* anything */ something) {
+ // Currently we dont have any state that tells if an item is loaded or not
+ // if the item exists its also loaded.
+ // This might change when we start working with refs inside items ...
+ return this.isItem(something);
+ },
+
+ loadItem: function(/* object */ args){
+ if(this.isItemLoaded(args.item)){
+ return;
+ }
+ // Actually we have nothing to do here, or at least I dont know what to do here ...
+ },
+
+ fetch:function(/* Object? */ request){
+ // summary:
+ // See dojo.data.util.simpleFetch.fetch() this is just a copy and I adjusted
+ // only the paging, since it happens on the server if doClientPaging is
+ // false, thx to http://trac.dojotoolkit.org/ticket/4761 reporting this.
+ // Would be nice to be able to use simpleFetch() to reduce copied code,
+ // but i dont know how yet. Ideas please!
+ request = request || {};
+ if(!request.store){
+ request.store = this;
+ }
+ var self = this;
+
+ var _errorHandler = function(errorData, requestObject){
+ if(requestObject.onError){
+ var scope = requestObject.scope || dojo.global;
+ requestObject.onError.call(scope, errorData, requestObject);
+ }
+ };
+
+ var _fetchHandler = function(items, requestObject, numRows){
+ var oldAbortFunction = requestObject.abort || null;
+ var aborted = false;
+
+ var startIndex = requestObject.start?requestObject.start:0;
+ if (self.doClientPaging==false) {
+ // For client paging we dont need no slicing of the result.
+ startIndex = 0;
+ }
+ var endIndex = requestObject.count?(startIndex + requestObject.count):items.length;
+
+ requestObject.abort = function(){
+ aborted = true;
+ if(oldAbortFunction){
+ oldAbortFunction.call(requestObject);
+ }
+ };
+
+ var scope = requestObject.scope || dojo.global;
+ if(!requestObject.store){
+ requestObject.store = self;
+ }
+ if(requestObject.onBegin){
+ requestObject.onBegin.call(scope, numRows, requestObject);
+ }
+ if(requestObject.sort && this.doClientSorting){
+ items.sort(dojo.data.util.sorter.createSortFunction(requestObject.sort, self));
+ }
+ if(requestObject.onItem){
+ for(var i = startIndex; (i < items.length) && (i < endIndex); ++i){
+ var item = items[i];
+ if(!aborted){
+ requestObject.onItem.call(scope, item, requestObject);
+ }
+ }
+ }
+ if(requestObject.onComplete && !aborted){
+ var subset = null;
+ if (!requestObject.onItem) {
+ subset = items.slice(startIndex, endIndex);
+ }
+ requestObject.onComplete.call(scope, subset, requestObject);
+ }
+ };
+ this._fetchItems(request, _fetchHandler, _errorHandler);
+ return request; // Object
+ },
+
+ getFeatures: function(){
+ return this._features;
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // I have no idea if this is really needed ...
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if(this._labelAttr && this.isItem(item)){
+ return this.getValue(item, this._labelAttr); //String
+ }
+ return undefined; //undefined
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ if(this._labelAttr){
+ return [this._labelAttr]; //array
+ }
+ return null; //null
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // The request contains the data as defined in the Read-API.
+ // Additionally there is following keyword "serverQuery".
+ //
+ // The *serverQuery* parameter, optional.
+ // This parameter contains the data that will be sent to the server.
+ // If this parameter is not given the parameter "query"'s
+ // data are sent to the server. This is done for some reasons:
+ // - to specify explicitly which data are sent to the server, they
+ // might also be a mix of what is contained in "query", "queryOptions"
+ // and the paging parameters "start" and "count" or may be even
+ // completely different things.
+ // - don't modify the request.query data, so the interface using this
+ // store can rely on unmodified data, as the combobox dijit currently
+ // does it, it compares if the query has changed
+ // - request.query is required by the Read-API
+ //
+ // I.e. the following examples might be sent via GET:
+ // fetch({query:{name:"abc"}, queryOptions:{ignoreCase:true}})
+ // the URL will become: /url.php?name=abc
+ //
+ // fetch({serverQuery:{q:"abc", c:true}, query:{name:"abc"}, queryOptions:{ignoreCase:true}})
+ // the URL will become: /url.php?q=abc&c=true
+ // // The serverQuery-parameter has overruled the query-parameter
+ // // but the query parameter stays untouched, but is not sent to the server!
+ // // The serverQuery contains more data than the query, so they might differ!
+ //
+
+ var serverQuery = request.serverQuery || request.query || {};
+ //Need to add start and count
+ if(!this.doClientPaging){
+ serverQuery.start = request.start || 0;
+ // Count might not be sent if not given.
+ if (request.count) {
+ serverQuery.count = request.count;
+ }
+ }
+ if(!this.doClientSorting){
+ if(request.sort){
+ var sort = request.sort[0];
+ if(sort && sort.attribute){
+ var sortStr = sort.attribute;
+ if(sort.descending){
+ sortStr = "-" + sortStr;
+ }
+ serverQuery.sort = sortStr;
+ }
+ }
+ }
+ // Compare the last query and the current query by simply json-encoding them,
+ // so we dont have to do any deep object compare ... is there some dojo.areObjectsEqual()???
+ if(this.doClientPaging && this._lastServerQuery!==null &&
+ dojo.toJson(serverQuery)==dojo.toJson(this._lastServerQuery)
+ ){
+ fetchHandler(this._items, request);
+ }else{
+ var xhrFunc = this.requestMethod.toLowerCase()=="post" ? dojo.xhrPost : dojo.xhrGet;
+ var xhrHandler = xhrFunc({url:this.url, handleAs:"json-comment-optional", content:serverQuery});
+ xhrHandler.addCallback(dojo.hitch(this, function(data){
+ data = this._filterResponse(data);
+ if (data.label){
+ this._labelAttr = data.label;
+ }
+ var numRows = data.numRows || -1;
+
+ this._items = [];
+ // Store a ref to "this" in each item, so we can simply check if an item
+ // really origins form here (idea is from ItemFileReadStore, I just don't know
+ // how efficient the real storage use, garbage collection effort, etc. is).
+ dojo.forEach(data.items,function(e){
+ this._items.push({i:e, r:this});
+ },this);
+
+ var identifier = data.identifier;
+ this._itemsByIdentity = {};
+ if(identifier){
+ this._identifier = identifier;
+ for(i = 0; i < this._items.length; ++i){
+ var item = this._items[i].i;
+ var identity = item[identifier];
+ if(!this._itemsByIdentity[identity]){
+ this._itemsByIdentity[identity] = item;
+ }else{
+ throw new Error(this._className+": The json data as specified by: [" + this.url + "] is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
+ }
+ }
+ }else{
+ this._identifier = Number;
+ for(i = 0; i < this._items.length; ++i){
+ this._items[i].n = i;
+ }
+ }
+
+ // TODO actually we should do the same as dojo.data.ItemFileReadStore._getItemsFromLoadedData() to sanitize
+ // (does it really sanititze them) and store the data optimal. should we? for security reasons???
+ numRows = (numRows === -1) ? this._items.length : numRows;
+ fetchHandler(this._items, request, numRows);
+ }));
+ xhrHandler.addErrback(function(error){
+ errorHandler(error, request);
+ });
+ // Generate the hash using the time in milliseconds and a randon number.
+ // Since Math.randon() returns something like: 0.23453463, we just remove the "0."
+ // probably just for esthetic reasons :-).
+ this.lastRequestHash = new Date().getTime()+"-"+String(Math.random()).substring(2);
+ this._lastServerQuery = dojo.mixin({}, serverQuery);
+ }
+ },
+
+ _filterResponse: function(data){
+ // summary:
+ // If the data from servers needs to be processed before it can be processed by this
+ // store, then this function should be re-implemented in subclass. This default
+ // implementation just return the data unchanged.
+ // data:
+ // The data received from server
+ return data;
+ },
+
+ _assertIsItem: function(/* item */ item){
+ // summary:
+ // It throws an error if item is not valid, so you can call it in every method that needs to
+ // throw an error when item is invalid.
+ // item:
+ // The item to test for being contained by the store.
+ if(!this.isItem(item)){
+ throw new Error(this._className+": 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(this._className+": Invalid attribute argument ('"+attribute+"').");
+ }
+ },
+
+ fetchItemByIdentity: function(/* Object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+
+ // See if we have already loaded the item with that id
+ // In case there hasn't been a fetch yet, _itemsByIdentity is null
+ // and thus a fetch will be triggered below.
+ if(this._itemsByIdentity){
+ var item = this._itemsByIdentity[keywordArgs.identity];
+ if(!(item === undefined)){
+ if(keywordArgs.onItem){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, {i:item, r:this});
+ }
+ return;
+ }
+ }
+
+ // Otherwise we need to go remote
+ // Set up error handler
+ var _errorHandler = function(errorData, requestObject){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ };
+
+ // Set up fetch handler
+ var _fetchHandler = function(items, requestObject){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ try{
+ // There is supposed to be only one result
+ var item = null;
+ if(items && items.length == 1){
+ item = items[0];
+ }
+
+ // If no item was found, item is still null and we'll
+ // fire the onItem event with the null here
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ }catch(error){
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ }
+ };
+
+ // Construct query
+ var request = {serverQuery:{id:keywordArgs.identity}};
+
+ // Dispatch query
+ this._fetchItems(request, _fetchHandler, _errorHandler);
+ },
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ var identifier = null;
+ if(this._identifier === Number){
+ identifier = item.n; // Number
+ }else{
+ identifier = item.i[this._identifier];
+ }
+ return identifier;
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentityAttributes()
+ return [this._identifier];
+ }
+ }
+);
+
+}
diff --git a/includes/js/dojox/data/README b/includes/js/dojox/data/README
new file mode 100644
index 0000000..94565f9
--- /dev/null
+++ b/includes/js/dojox/data/README
@@ -0,0 +1,89 @@
+-------------------------------------------------------------------------------
+DojoX Data
+-------------------------------------------------------------------------------
+Version 1.1
+Release date: 03/18/2008
+-------------------------------------------------------------------------------
+Project state: stable
+-------------------------------------------------------------------------------
+Project authors
+ Jared Jurkiewicz (jared.jurkiewicz@gmail.com)
+ Shane O'Sullivan (shaneosullivan1@gmail.com) (FlickrRestStore, AtomReadStore)
+ Wolfram Kriesing (wolfram@kriesing.de) (QueryReadStore)
+ Dustin Machi (dmachi@dojotolkit.org) (jsonPathStore);
+ Russell Jones (KeyValueStore) (CLA)
+ Benjamin Schell (KeyValueStore) (Corporate CLA)
+ Kurt Stutsman (kurt@snaplogic.org) (SnapLogicStore)
+
+-------------------------------------------------------------------------------
+Project description
+
+The DojoX Data project is a container for extensions and extra example stores
+that implement the dojo.data APIs. It may also contain utility functions for
+working with specific types of data.
+
+-------------------------------------------------------------------------------
+Dependencies:
+
+DojoX Data has dependencies on core dojo (dojo.data) and the D.O.H. unit test
+framework.
+-------------------------------------------------------------------------------
+Documentation:
+
+See the Dojo API tool (http://dojotoolkit.org/api)
+-------------------------------------------------------------------------------
+Contributions:
+
+For contributions to be committed into the dojox repository, the datastore
+should have basic unit tests that exercise the API's that the store declares it
+implements. Documentation and demos are a plus, but unit tests are required
+to be committed into this sub-package. This is necessary to help keep the
+provided datastores as stable as possible.
+
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/data/*
+
+Install into the following directory structure:
+/dojox/data/
+
+...which should be at the same level as your Dojo checkout.
+
+/dojox/data/*
+
+Require in the dojox.data stores you wish to use.
+-------------------------------------------------------------------------------
+Additional Notes:
+ dojox.data.AtomReadStore - Reads Atom XML documents.
+
+ dojox.data.CvsStore - comma-separated (spreadsheet output)
+ datastore implementation
+
+ dojox.data.FlickrRestStore - advanced version of: dojox.data.FlickrStore
+ (Caching + user key support)
+
+ dojox.data.FlickrStore - data store driven by Flickr.com public API.
+
+ dojox.data.HtmlTableStore - Implementation of an HTML Table reading
+ datastore
+
+ dojox.data.HtmlStore - Implementation of an HTML reading datastore. Can
+ handle tables, ordered and un-ordered lists, and lists of divs.
+
+ dojox.data.OpmlStore - Store for reading OMPL formatted data
+
+ dojox.data.XmlStore - datastore for XML based services or
+ documents.
+
+ dojox.data.QueryReadStore - datastore to provide serverside URL query
+ matching. Similar to the 0.4.X ComboBox dataUrl parameter.
+
+ dojox.data.jsonPathStore - datastore that takes an arbitrary js object
+ and uses it as the store. Pre-Alpha at the moment.
+
+ dojox.data.KeyValueStore - datastore that mimics a key/value property
+ file format.
+
+ dojox.data.SnapLogicStore - Store to interface to SnapLogic data services.
diff --git a/includes/js/dojox/data/SnapLogicStore.js b/includes/js/dojox/data/SnapLogicStore.js
new file mode 100644
index 0000000..101ab91
--- /dev/null
+++ b/includes/js/dojox/data/SnapLogicStore.js
@@ -0,0 +1,332 @@
+if(!dojo._hasResource["dojox.data.SnapLogicStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.SnapLogicStore"] = true;
+dojo.provide("dojox.data.SnapLogicStore");
+
+dojo.require("dojo.io.script");
+dojo.require("dojo.data.util.sorter");
+
+dojo.declare("dojox.data.SnapLogicStore", null, {
+ Parts: {
+ DATA: "data",
+ COUNT: "count"
+ },
+
+ url: "",
+
+ constructor: function(/* Object */args){
+ // summary:
+ // Initialize a SnapLogicStore object.
+ // args:
+ // An object that contains properties for initializing the new data store object. The
+ // following properties are understood:
+ // url:
+ // A URL to the SnapLogic pipeline's output routed through PipeToHttp. Typically, this
+ // will look like "http://<server-host>:<port>/pipe/<pipeline-url>/<pipeline-output-view>".
+ // parameters:
+ // An object whose properties define parameters to the pipeline. The values of these
+ // properties will be sent to the pipeline as parameters when it run.
+ //
+ if(args.url){
+ this.url = args.url;
+ }
+ this._parameters = args.parameters;
+ },
+
+ _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.SnapLogicStore: a function was passed an item argument that was not an item");
+ }
+ },
+
+ _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.SnapLogicStore: a function was passed an attribute argument that was not an attribute name string");
+ }
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true
+ };
+ },
+
+ getValue: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ i = dojo.indexOf(item.attributes, attribute);
+ if(i !== -1){
+ return item.values[i];
+ }
+ return undefined;
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ return item.attributes;
+ },
+
+ hasAttribute: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttributes()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ for(var i = 0; i < item.attributes.length; ++i){
+ if(attribute == item.attributes[i]){
+ return true;
+ }
+ }
+ return false;
+ },
+
+ isItemLoaded: function(item){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(item); // Boolean
+ },
+
+ loadItem: function(keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ },
+
+ getLabel: function(item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ return undefined;
+ },
+
+ getLabelAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return null;
+ },
+
+ containsValue: function(item, attribute, value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ return this.getValue(item, attribute) === value; // Boolean
+ },
+
+ getValues: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ i = dojo.indexOf(item.attributes, attribute);
+ if(i !== -1){
+ return [item.values[i]]; // Array
+ }
+ return undefined;
+ },
+
+ isItem: function(item){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(item && item._store === this){
+ return true;
+ }
+ return false;
+ },
+
+ close: function(request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ },
+
+ _fetchHandler: function(/* Object */request){
+ // summary:
+ // Process data retrieved via fetch and send it back to requester.
+ // response:
+ // The data returend from the I/O transport. In the normal case, it will be an array of result rows
+ // from the pipeline. In the special case for record count optimization, response will be an array
+ // with a single element containing the total pipeline result row count. See fetch() for details
+ // on this optimization.
+
+ var scope = request.scope || dojo.global;
+
+ if(request.onBegin){
+ // Check for the record count optimization
+ request.onBegin.call(scope, request._countResponse[0], request);
+ }
+
+ if(request.onItem || request.onComplete){
+ response = request._dataResponse;
+
+ if (!response.length){
+ request.onError.call(scope,
+ new Error("dojox.data.SnapLogicStore: invalid response of length 0"),
+ request);
+ return;
+ }else if(request.query != 'record count'){
+ //If this was not a record count request, the first element returned will contain
+ //the field names.
+ field_names = response.shift();
+
+ var items = [];
+ for(var i = 0; i < response.length; ++i){
+ if(request._aborted){
+ break;
+ }
+
+ items.push({attributes: field_names, values: response[i], _store: this});
+ }
+
+ if(request.sort && !request._aborted){
+ items.sort(dojo.data.util.sorter.createSortFunction(request.sort, self));
+ }
+ }else{
+ //This is a record count request, so manually set the field names.
+ items = [({attributes: ['count'], values: response, _store: this})];
+ }
+
+ if(request.onItem){
+ for(var i = 0; i < items.length; ++i){
+ if (request._aborted) {
+ break;
+ }
+ request.onItem.call(scope, items[i], request);
+ }
+ items = null;
+ }
+
+ if(request.onComplete && !request._aborted){
+ request.onComplete.call(scope, items, request);
+ }
+ }
+ },
+
+ _partHandler: function(/* Object */request, /* String */part, /* Object */response){
+ // summary:
+ // Handle the individual replies for both data and length requests.
+ // request:
+ // The request/handle object used with the original fetch() call.
+ // part:
+ // A value indicating which request this handler call is for (this.Parts).
+ // response:
+ // Response received from the underlying IO transport.
+
+ if(response instanceof Error){
+ if(part == this.Parts.DATA){
+ request._dataHandle = null;
+ }else{
+ request._countHandle = null;
+ }
+ request._aborted = true;
+ if(request.onError){
+ request.onError.call(request.scope, response, request);
+ }
+ }else{
+ if(request._aborted){
+ return;
+ }
+ if(part == this.Parts.DATA){
+ request._dataResponse = response;
+ }else{
+ request._countResponse = response;
+ }
+ if((!request._dataHandle || request._dataResponse !== null) &&
+ (!request._countHandle || request._countResponse !== null)){
+ this._fetchHandler(request);
+ }
+ }
+ },
+
+ fetch: function(/* Object */request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ // request:
+ // See dojo.data.api.Read.close() for generic interface.
+ //
+ // In addition to the standard Read API fetch support, this store supports an optimization for
+ // for retrieving the total count of records in the Pipeline without retrieving the data. To
+ // use this optimization, simply provide an onBegin handler without an onItem or onComplete handler.
+
+ request._countResponse = null;
+ request._dataResponse = null;
+ request._aborted = false;
+ request.abort = function(){
+ if(!request._aborted){
+ request._aborted = true;
+ if(request._dataHandle && request._dataHandle.cancel){
+ request._dataHandle.cancel();
+ }
+ if(request._countHandle && request._countHandle.cancel){
+ request._countHandle.cancel();
+ }
+ }
+ };
+
+ // Only make the call for data if onItem or onComplete is used. Otherwise, onBegin will only
+ // require the total row count.
+ if(request.onItem || request.onComplete){
+ var content = this._parameters || {};
+ if(request.start){
+ if(request.start < 0){
+ throw new Error("dojox.data.SnapLogicStore: request start value must be 0 or greater");
+ }
+ content['sn.start'] = request.start + 1;
+ }
+ if(request.count){
+ if(request.count < 0){
+ throw new Error("dojox.data.SnapLogicStore: request count value 0 or greater");
+ }
+ content['sn.limit'] = request.count;
+ }
+
+ content['sn.content_type'] = 'application/javascript';
+
+ var store = this;
+ var handler = function(response, ioArgs){
+ if(response instanceof Error){
+ store._fetchHandler(response, request);
+ }
+ };
+
+ var getArgs = {
+ url: this.url,
+ content: content,
+ // preventCache: true,
+ timeout: 60000, //Starting a pipeline can take a long time.
+ callbackParamName: "sn.stream_header",
+ handle: dojo.hitch(this, "_partHandler", request, this.Parts.DATA)
+ };
+
+ request._dataHandle = dojo.io.script.get(getArgs);
+ }
+
+ if(request.onBegin){
+ var content = {};
+ content['sn.count'] = 'records';
+ content['sn.content_type'] = 'application/javascript';
+
+ var getArgs = {
+ url: this.url,
+ content: content,
+ timeout: 60000,
+ callbackParamName: "sn.stream_header",
+ handle: dojo.hitch(this, "_partHandler", request, this.Parts.COUNT)
+ };
+
+ request._countHandle = dojo.io.script.get(getArgs);
+ }
+
+ return request; // Object
+ }
+});
+
+
+}
diff --git a/includes/js/dojox/data/XmlStore.js b/includes/js/dojox/data/XmlStore.js
new file mode 100644
index 0000000..90b26a9
--- /dev/null
+++ b/includes/js/dojox/data/XmlStore.js
@@ -0,0 +1,1141 @@
+if(!dojo._hasResource["dojox.data.XmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.XmlStore"] = true;
+dojo.provide("dojox.data.XmlStore");
+dojo.provide("dojox.data.XmlItem");
+
+dojo.require("dojo.data.util.simpleFetch");
+dojo.require("dojo.data.util.filter");
+dojo.require("dojox.data.dom");
+
+dojo.declare("dojox.data.XmlStore", null, {
+ // summary:
+ // A data store for XML based services or documents
+ // description:
+ // A data store for XML based services or documents
+
+ constructor: function(/* object */ args) {
+ // summary:
+ // Constructor for the XML 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
+ // rootItem: A tag name for root items
+ // keyAttribute: An attribute name for a key or an indentify
+ // attributeMap: An anonymous object contains properties for attribute mapping,
+ // {"tag_name.item_attribute_name": "@xml_attribute_name", ...}
+ // sendQuery: A boolean indicate to add a query string to the service URL
+ console.log("XmlStore()");
+ if(args){
+ this.url = args.url;
+ this.rootItem = (args.rootItem || args.rootitem || this.rootItem);
+ this.keyAttribute = (args.keyAttribute || args.keyattribute || this.keyAttribute);
+ this._attributeMap = (args.attributeMap || args.attributemap);
+ this.label = args.label || this.label;
+ this.sendQuery = (args.sendQuery || args.sendquery || this.sendQuery);
+ }
+ this._newItems = [];
+ this._deletedItems = [];
+ this._modifiedItems = [];
+ },
+
+ //Values that may be set by the parser.
+ //Ergo, have to be instantiated to something
+ //So the parser knows how to set them.
+ url: "",
+
+ rootItem: "",
+
+ keyAttribute: "",
+
+ label: "",
+
+ sendQuery: 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 a dojox.data.XmlItem from the store instance.
+ // If 'attribute' specifies "tagName", the tag name of the element is
+ // returned.
+ // If 'attribute' specifies "childNodes", the first element child is
+ // returned.
+ // If 'attribute' specifies "text()", the value of the first text
+ // child is returned.
+ // For generic attributes, if '_attributeMap' is specified,
+ // an actual attribute name is looked up with the tag name of
+ // the element and 'attribute' (concatenated with '.').
+ // Then, if 'attribute' starts with "@", the value of the XML
+ // attribute is returned.
+ // Otherwise, the first child element of the tag name specified with
+ // 'attribute' is returned.
+ // item:
+ // An XML element that holds the attribute
+ // attribute:
+ // A tag name of a child element, An XML attribute name or one of
+ // special names
+ // defaultValue:
+ // A default value
+ // returns:
+ // An attribute value found, otherwise 'defaultValue'
+ var element = item.element;
+ if(attribute === "tagName"){
+ return element.nodeName;
+ }else if (attribute === "childNodes"){
+ for (var i = 0; i < element.childNodes.length; i++) {
+ var node = element.childNodes[i];
+ if (node.nodeType === 1 /*ELEMENT_NODE*/) {
+ return this._getItem(node); //object
+ }
+ }
+ return defaultValue;
+ }else if(attribute === "text()"){
+ for(var i = 0; i < element.childNodes.length; i++){
+ var node = element.childNodes[i];
+ if(node.nodeType === 3 /*TEXT_NODE*/ ||
+ node.nodeType === 4 /*CDATA_SECTION_NODE*/){
+ return node.nodeValue; //string
+ }
+ }
+ return defaultValue;
+ }else{
+ attribute = this._getAttribute(element.nodeName, attribute);
+ if(attribute.charAt(0) === '@'){
+ var name = attribute.substring(1);
+ var value = element.getAttribute(name);
+ return (value !== undefined) ? value : defaultValue; //object
+ }else{
+ for(var i = 0; i < element.childNodes.length; i++){
+ var node = element.childNodes[i];
+ if( node.nodeType === 1 /*ELEMENT_NODE*/ &&
+ node.nodeName === attribute){
+ return this._getItem(node); //object
+ }
+ }
+ return defaultValue; //object
+ }
+ }
+ },
+
+ getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
+ // summary:
+ // Return an array of attribute values
+ // description:
+ // 'item' must be an instance of a dojox.data.XmlItem from the store instance.
+ // If 'attribute' specifies "tagName", the tag name of the element is
+ // returned.
+ // If 'attribute' specifies "childNodes", child elements are returned.
+ // If 'attribute' specifies "text()", the values of child text nodes
+ // are returned.
+ // For generic attributes, if '_attributeMap' is specified,
+ // an actual attribute name is looked up with the tag name of
+ // the element and 'attribute' (concatenated with '.').
+ // Then, if 'attribute' starts with "@", the value of the XML
+ // attribute is returned.
+ // Otherwise, child elements of the tag name specified with
+ // 'attribute' are returned.
+ // item:
+ // An XML element that holds the attribute
+ // attribute:
+ // A tag name of child elements, An XML attribute name or one of
+ // special names
+ // returns:
+ // An array of attribute values found, otherwise an empty array
+ var element = item.element;
+ if(attribute === "tagName"){
+ return [element.nodeName];
+ }else if(attribute === "childNodes"){
+ var values = [];
+ for(var i = 0; i < element.childNodes.length; i++){
+ var node = element.childNodes[i];
+ if(node.nodeType === 1 /*ELEMENT_NODE*/){
+ values.push(this._getItem(node));
+ }
+ }
+ return values; //array
+ }else if(attribute === "text()"){
+ var values = [];
+ for(var i = 0; i < element.childNodes.length; i++){
+ var node = childNodes[i];
+ if(node.nodeType === 3){
+ values.push(node.nodeValue);
+ }
+ }
+ return values; //array
+ }else{
+ attribute = this._getAttribute(element.nodeName, attribute);
+ if(attribute.charAt(0) === '@'){
+ var name = attribute.substring(1);
+ var value = element.getAttribute(name);
+ return (value !== undefined) ? [value] : []; //array
+ }else{
+ var values = [];
+ for(var i = 0; i < element.childNodes.length; i++){
+ var node = element.childNodes[i];
+ if( node.nodeType === 1 /*ELEMENT_NODE*/ &&
+ node.nodeName === attribute){
+ values.push(this._getItem(node));
+ }
+ }
+ return values; //array
+ }
+ }
+ },
+
+ getAttributes: function(/* item */ item) {
+ // summary:
+ // Return an array of attribute names
+ // description:
+ // 'item' must be an instance of a dojox.data.XmlItem from the store 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
+ var element = item.element;
+ var attributes = [];
+ attributes.push("tagName");
+ if(element.childNodes.length > 0){
+ var names = {};
+ var childNodes = true;
+ var text = false;
+ for(var i = 0; i < element.childNodes.length; i++){
+ var node = element.childNodes[i];
+ if (node.nodeType === 1 /*ELEMENT_NODE*/) {
+ var name = node.nodeName;
+ if(!names[name]){
+ attributes.push(name);
+ names[name] = name;
+ }
+ childNodes = true;
+ }else if(node.nodeType === 3){
+ text = true;
+ }
+ }
+ if(childNodes){
+ attributes.push("childNodes");
+ }
+ if(text){
+ attributes.push("text()");
+ }
+ }
+ for(var i = 0; i < element.attributes.length; i++){
+ attributes.push("@" + element.attributes[i].nodeName);
+ }
+ if(this._attributeMap){
+ for (var key in this._attributeMap){
+ var i = key.indexOf('.');
+ if(i > 0){
+ var tagName = key.substring(0, i);
+ if (tagName === element.nodeName){
+ attributes.push(key.substring(i + 1));
+ }
+ }else{ // global attribute
+ attributes.push(key);
+ }
+ }
+ }
+ return attributes; //array
+ },
+
+ hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
+ // summary:
+ // Check whether an element has the attribute
+ // 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 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,
+ "dojo.data.api.Write": 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){
+ return label.toString();
+ }
+ }
+ return undefined; //undefined
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ if(this.label !== ""){
+ return [this.label]; //array
+ }
+ return null; //null
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler) {
+ // summary:
+ // Fetch items (XML elements) that match to a query
+ // description:
+ // If 'sendQuery' is true, an XML document is loaded from
+ // 'url' with a query string.
+ // Otherwise, an XML document is loaded and list XML elements that
+ // match to a query (set of element names and their text attribute
+ // values that the items to contain).
+ // A wildcard, "*" can be used to query values to match all
+ // occurrences.
+ // If 'rootItem' is specified, it is used to fetch items.
+ // request:
+ // A request object
+ // fetchHandler:
+ // A function to call for fetched items
+ // errorHandler:
+ // A function to call on error
+ var url = this._getFetchUrl(request);
+ console.log("XmlStore._fetchItems(): url=" + url);
+ if(!url){
+ errorHandler(new Error("No URL specified."));
+ return;
+ }
+ var localRequest = (!this.sendQuery ? request : null); // use request for _getItems()
+
+ var self = this;
+ var getArgs = {
+ url: url,
+ handleAs: "xml",
+ preventCache: true
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var items = self._getItems(data, localRequest);
+ console.log("XmlStore._fetchItems(): length=" + (items ? items.length : 0));
+ if (items && items.length > 0) {
+ fetchHandler(items, request);
+ }
+ else {
+ fetchHandler([], request);
+ }
+ });
+ getHandler.addErrback(function(data){
+ errorHandler(data, request);
+ });
+ },
+
+ _getFetchUrl: function(request){
+ // summary:
+ // Generate a URL for fetch
+ // description:
+ // This default implementation generates a query string in the form of
+ // "?name1=value1&name2=value2..." off properties of 'query' object
+ // specified in 'request' and appends it to 'url', if 'sendQuery'
+ // is set to false.
+ // Otherwise, 'url' is returned as is.
+ // Sub-classes may override this method for the custom URL generation.
+ // request:
+ // A request object
+ // returns:
+ // A fetch URL
+ 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:
+ // Fetch items (XML elements) in an XML document based on a request
+ // description:
+ // This default implementation walks through child elements of
+ // the document element to see if all properties of 'query' object
+ // match corresponding attributes of the element (item).
+ // If 'request' is not specified, all child elements are returned.
+ // Sub-classes may override this method for the custom search in
+ // an XML document.
+ // document:
+ // An XML document
+ // request:
+ // A request object
+ // returns:
+ // An array of items
+ var query = null;
+ if(request){
+ query = request.query;
+ }
+ var items = [];
+ var nodes = null;
+
+ console.log("Looking up root item: " + this.rootItem);
+ if(this.rootItem !== ""){
+
+ nodes = document.getElementsByTagName(this.rootItem);
+ }
+ else{
+ nodes = document.documentElement.childNodes;
+ }
+ for(var i = 0; i < nodes.length; i++){
+ var node = nodes[i];
+ if(node.nodeType != 1 /*ELEMENT_NODE*/){
+ continue;
+ }
+ var item = this._getItem(node);
+ if(query){
+ var found = true;
+ var ignoreCase = request.queryOptions ? request.queryOptions.ignoreCase : false;
+
+ //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+ //same value for each item examined. Much more efficient.
+ var regexpList = {};
+ for(var key in query){
+ var value = query[key];
+ if(typeof value === "string"){
+ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+ }
+ }
+
+ for(var attribute in query){
+ var value = this.getValue(item, attribute);
+ if(value){
+ var queryValue = query[attribute];
+ if ((typeof value) === "string" &&
+ (regexpList[attribute])){
+ if((value.match(regexpList[attribute])) !== null){
+ continue;
+ }
+ }else if((typeof value) === "object"){
+ if( value.toString &&
+ (regexpList[attribute])){
+ var stringValue = value.toString();
+ if((stringValue.match(regexpList[attribute])) !== null){
+ continue;
+ }
+ }else{
+ if(queryValue === "*" || queryValue === value){
+ continue;
+ }
+ }
+ }
+ }
+ found = false;
+ break;
+ }
+ if(!found){
+ continue;
+ }
+ }
+ items.push(item);
+ }
+ dojo.forEach(items,function(item){
+ item.element.parentNode.removeChild(item.element); // make it root
+ },this);
+ return items;
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ },
+
+/* dojo.data.api.Write */
+
+ newItem: function(/* object? */ keywordArgs){
+ // summary:
+ // Return a new dojox.data.XmlItem
+ // description:
+ // At least, 'keywordArgs' must contain "tagName" to be used for
+ // the new element.
+ // Other attributes in 'keywordArgs' are set to the new element,
+ // including "text()", but excluding "childNodes".
+ // keywordArgs:
+ // An object containing initial attributes
+ // returns:
+ // An XML element
+ console.log("XmlStore.newItem()");
+ keywordArgs = (keywordArgs || {});
+ var tagName = keywordArgs.tagName;
+ if(!tagName){
+ tagName = this.rootItem;
+ if(tagName === ""){
+ return null;
+ }
+ }
+
+ var document = this._getDocument();
+ var element = document.createElement(tagName);
+ for(var attribute in keywordArgs){
+ if(attribute === "tagName"){
+ continue;
+ }else if(attribute === "text()"){
+ var text = document.createTextNode(keywordArgs[attribute]);
+ element.appendChild(text);
+ }else{
+ attribute = this._getAttribute(tagName, attribute);
+ if(attribute.charAt(0) === '@'){
+ var name = attribute.substring(1);
+ element.setAttribute(name, keywordArgs[attribute]);
+ }else{
+ var child = document.createElement(attribute);
+ var text = document.createTextNode(keywordArgs[attribute]);
+ child.appendChild(text);
+ element.appendChild(child);
+ }
+ }
+ }
+
+ var item = this._getItem(element);
+ this._newItems.push(item);
+ return item; //object
+ },
+
+ deleteItem: function(/* item */ item){
+ // summary:
+ // Delete an dojox.data.XmlItem (wrapper to a XML element).
+ // item:
+ // An XML element to delete
+ // returns:
+ // True
+ console.log("XmlStore.deleteItem()");
+ var element = item.element;
+ if(element.parentNode){
+ this._backupItem(item);
+ element.parentNode.removeChild(element);
+ return true;
+ }
+ this._forgetItem(item);
+ this._deletedItems.push(item);
+ return true; //boolean
+ },
+
+ setValue: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value){
+ // summary:
+ // Set an attribute value
+ // description:
+ // 'item' must be an instance of a dojox.data.XmlItem from the store instance.
+ // If 'attribute' specifies "tagName", nothing is set and false is
+ // returned.
+ // If 'attribute' specifies "childNodes", the value (XML element) is
+ // added to the element.
+ // If 'attribute' specifies "text()", a text node is created with
+ // the value and set it to the element as a child.
+ // For generic attributes, if '_attributeMap' is specified,
+ // an actual attribute name is looked up with the tag name of
+ // the element and 'attribute' (concatenated with '.').
+ // Then, if 'attribute' starts with "@", the value is set to the XML
+ // attribute.
+ // Otherwise, a text node is created with the value and set it to
+ // the first child element of the tag name specified with 'attribute'.
+ // If the child element does not exist, it is created.
+ // item:
+ // An XML element that holds the attribute
+ // attribute:
+ // A tag name of a child element, An XML attribute name or one of
+ // special names
+ // value:
+ // A attribute value to set
+ // returns:
+ // False for "tagName", otherwise true
+ if(attribute === "tagName"){
+ return false; //boolean
+ }
+
+ this._backupItem(item);
+
+ var element = item.element;
+ if(attribute === "childNodes"){
+ var child = value.element;
+ element.appendChild(child);
+ }else if(attribute === "text()"){
+ while (element.firstChild){
+ element.removeChild(element.firstChild);
+ }
+ var text = this._getDocument(element).createTextNode(value);
+ element.appendChild(text);
+ }else{
+ attribute = this._getAttribute(element.nodeName, attribute);
+ if(attribute.charAt(0) === '@'){
+ var name = attribute.substring(1);
+ element.setAttribute(name, value);
+ }else{
+ var child = null;
+ for(var i = 0; i < element.childNodes.length; i++){
+ var node = element.childNodes[i];
+ if( node.nodeType === 1 /*ELEMENT_NODE*/&&
+ node.nodeName === attribute){
+ child = node;
+ break;
+ }
+ }
+ var document = this._getDocument(element);
+ if(child){
+ while(child.firstChild){
+ child.removeChild(child.firstChild);
+ }
+ }else{
+ child = document.createElement(attribute);
+ element.appendChild(child);
+ }
+ var text = document.createTextNode(value);
+ child.appendChild(text);
+ }
+ }
+ return true; //boolean
+ },
+
+ setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values){
+ // summary:
+ // Set attribute values
+ // description:
+ // 'item' must be an instance of a dojox.data.XmlItem from the store instance.
+ // If 'attribute' specifies "tagName", nothing is set and false is
+ // returned.
+ // If 'attribute' specifies "childNodes", the value (array of XML
+ // elements) is set to the element's childNodes.
+ // If 'attribute' specifies "text()", a text node is created with
+ // the values and set it to the element as a child.
+ // For generic attributes, if '_attributeMap' is specified,
+ // an actual attribute name is looked up with the tag name of
+ // the element and 'attribute' (concatenated with '.').
+ // Then, if 'attribute' starts with "@", the first value is set to
+ // the XML attribute.
+ // Otherwise, child elements of the tag name specified with
+ // 'attribute' are replaced with new child elements and their
+ // child text nodes of values.
+ // item:
+ // An XML element that holds the attribute
+ // attribute:
+ // A tag name of child elements, an XML attribute name or one of
+ // special names
+ // value:
+ // A attribute value to set
+ // returns:
+ // False for "tagName", otherwise true
+ if(attribute === "tagName"){
+ return false; //boolean
+ }
+
+ this._backupItem(item);
+
+ var element = item.element;
+ if(attribute === "childNodes"){
+ while(element.firstChild){
+ element.removeChild(element.firstChild);
+ }
+ for(var i = 0; i < values.length; i++){
+ var child = values[i].element;
+ element.appendChild(child);
+ }
+ }else if(attribute === "text()"){
+ while (element.firstChild){
+ element.removeChild(element.firstChild);
+ }
+ var value = "";
+ for(var i = 0; i < values.length; i++){
+ value += values[i];
+ }
+ var text = this._getDocument(element).createTextNode(value);
+ element.appendChild(text);
+ }else{
+ attribute = this._getAttribute(element.nodeName, attribute);
+ if(attribute.charAt(0) === '@'){
+ var name = attribute.substring(1);
+ element.setAttribute(name, values[0]);
+ }else{
+ for(var i = element.childNodes.length - 1; i >= 0; i--){
+ var node = element.childNodes[i];
+ if( node.nodeType === 1 /*ELEMENT_NODE*/ &&
+ node.nodeName === attribute){
+ element.removeChild(node);
+ }
+ }
+ var document = this._getDocument(element);
+ for(var i = 0; i < values.length; i++){
+ var child = document.createElement(attribute);
+ var text = document.createTextNode(values[i]);
+ child.appendChild(text);
+ element.appendChild(child);
+ }
+ }
+ }
+ return true; //boolean
+ },
+
+ unsetAttribute: function(/* item */ item, /* attribute || string */ attribute){
+ // summary:
+ // Remove an attribute
+ // description:
+ // 'item' must be an instance of a dojox.data.XmlItem from the store instance.
+ // 'attribute' can be an XML attribute name of the element or one of
+ // special names described below.
+ // If 'attribute' specifies "tagName", nothing is removed and false is
+ // returned.
+ // If 'attribute' specifies "childNodes" or "text()", all child nodes
+ // are removed.
+ // For generic attributes, if '_attributeMap' is specified,
+ // an actual attribute name is looked up with the tag name of
+ // the element and 'attribute' (concatenated with '.').
+ // Then, if 'attribute' starts with "@", the XML attribute is removed.
+ // Otherwise, child elements of the tag name specified with
+ // 'attribute' are removed.
+ // item:
+ // An XML element that holds the attribute
+ // attribute:
+ // A tag name of child elements, an XML attribute name or one of
+ // special names
+ // returns:
+ // False for "tagName", otherwise true
+ if(attribute === "tagName"){
+ return false; //boolean
+ }
+
+ this._backupItem(item);
+
+ var element = item.element;
+ if(attribute === "childNodes" || attribute === "text()"){
+ while(element.firstChild){
+ element.removeChild(element.firstChild);
+ }
+ }else{
+ attribute = this._getAttribute(element.nodeName, attribute);
+ if(attribute.charAt(0) === '@'){
+ var name = attribute.substring(1);
+ element.removeAttribute(name);
+ }else{
+ for(var i = element.childNodes.length - 1; i >= 0; i--){
+ var node = element.childNodes[i];
+ if( node.nodeType === 1 /*ELEMENT_NODE*/ &&
+ node.nodeName === attribute){
+ element.removeChild(node);
+ }
+ }
+ }
+ }
+ return true; //boolean
+ },
+
+ save: function(/* object */ keywordArgs){
+ // summary:
+ // Save new and/or modified items (XML elements)
+ // description:
+ // 'url' is used to save XML documents for new, modified and/or
+ // deleted XML elements.
+ // keywordArgs:
+ // An object for callbacks
+ if(!keywordArgs){
+ keywordArgs = {};
+ }
+ for(var i = 0; i < this._modifiedItems.length; i++){
+ this._saveItem(this._modifiedItems[i], keywordArgs, "PUT");
+ }
+ for(var i = 0; i < this._newItems.length; i++){
+ var item = this._newItems[i];
+ if(item.element.parentNode){ // reparented
+ this._newItems.splice(i, 1);
+ i--;
+ continue;
+ }
+ this._saveItem(this._newItems[i], keywordArgs, "POST");
+ }
+ for(var i = 0; i < this._deletedItems.length; i++){
+ this._saveItem(this._deletedItems[i], keywordArgs, "DELETE");
+ }
+ },
+
+ revert: function(){
+ // summary:
+ // Invalidate changes (new and/or modified elements)
+ // returns:
+ // True
+ console.log("XmlStore.revert() _newItems=" + this._newItems.length);
+ console.log("XmlStore.revert() _deletedItems=" + this._deletedItems.length);
+ console.log("XmlStore.revert() _modifiedItems=" + this._modifiedItems.length);
+ this._newItems = [];
+ this._restoreItems(this._deletedItems);
+ this._deletedItems = [];
+ this._restoreItems(this._modifiedItems);
+ this._modifiedItems = [];
+ return true; //boolean
+ },
+
+ isDirty: function(/* item? */ item){
+ // summary:
+ // Check whether an item is new, modified or deleted
+ // description:
+ // If 'item' is specified, true is returned if the item is new,
+ // modified or deleted.
+ // Otherwise, true is returned if there are any new, modified
+ // or deleted items.
+ // item:
+ // An item (XML element) to check
+ // returns:
+ // True if an item or items are new, modified or deleted, otherwise
+ // false
+ if (item) {
+ var element = this._getRootElement(item.element);
+ return (this._getItemIndex(this._newItems, element) >= 0 ||
+ this._getItemIndex(this._deletedItems, element) >= 0 ||
+ this._getItemIndex(this._modifiedItems, element) >= 0); //boolean
+ }
+ else {
+ return (this._newItems.length > 0 ||
+ this._deletedItems.length > 0 ||
+ this._modifiedItems.length > 0); //boolean
+ }
+ },
+
+ _saveItem: function(item, keywordArgs, method){
+ if(method === "PUT"){
+ url = this._getPutUrl(item);
+ }else if(method === "DELETE"){
+ url = this._getDeleteUrl(item);
+ }else{ // POST
+ url = this._getPostUrl(item);
+ }
+ if(!url){
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, new Error("No URL for saving content: " + postContent));
+ }
+ return;
+ }
+
+ var saveArgs = {
+ url: url,
+ method: (method || "POST"),
+ contentType: "text/xml",
+ handleAs: "xml"
+ };
+ var saveHander;
+ if(method === "PUT"){
+ saveArgs.putData = this._getPutContent(item);
+ saveHandler = dojo.rawXhrPut(saveArgs);
+ }else if(method === "DELETE"){
+ saveHandler = dojo.xhrDelete(saveArgs);
+ }else{ // POST
+ saveArgs.postData = this._getPostContent(item);
+ saveHandler = dojo.rawXhrPost(saveArgs);
+ }
+ var scope = (keywordArgs.scope || dojo.global);
+ var self = this;
+ saveHandler.addCallback(function(data){
+ self._forgetItem(item);
+ if(keywordArgs.onComplete){
+ keywordArgs.onComplete.call(scope);
+ }
+ });
+ saveHandler.addErrback(function(error){
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+ },
+
+ _getPostUrl: function(item){
+ // summary:
+ // Generate a URL for post
+ // description:
+ // This default implementation just returns 'url'.
+ // Sub-classes may override this method for the custom URL.
+ // item:
+ // An item to save
+ // returns:
+ // A post URL
+ return this.url; //string
+ },
+
+ _getPutUrl: function(item){
+ // summary:
+ // Generate a URL for put
+ // description:
+ // This default implementation just returns 'url'.
+ // Sub-classes may override this method for the custom URL.
+ // item:
+ // An item to save
+ // returns:
+ // A put URL
+ return this.url; //string
+ },
+
+ _getDeleteUrl: function(item){
+ // summary:
+ // Generate a URL for delete
+ // description:
+ // This default implementation returns 'url' with 'keyAttribute'
+ // as a query string.
+ // Sub-classes may override this method for the custom URL based on
+ // changes (new, deleted, or modified).
+ // item:
+ // An item to delete
+ // returns:
+ // A delete URL
+ var url = this.url;
+ if (item && this.keyAttribute !== "") {
+ var value = this.getValue(item, this.keyAttribute);
+ if (value) {
+ var key = this.keyAttribute.charAt(0) ==='@' ? this.keyAttribute.substring(1): this.keyAttribute;
+ url += url.indexOf('?') < 0 ? '?' : '&';
+ url += key + '=' + value;
+ }
+ }
+ return url; //string
+ },
+
+ _getPostContent: function(item){
+ // summary:
+ // Generate a content to post
+ // description:
+ // This default implementation generates an XML document for one
+ // (the first only) new or modified element.
+ // Sub-classes may override this method for the custom post content
+ // generation.
+ // item:
+ // An item to save
+ // returns:
+ // A post content
+ var element = item.element;
+ var declaration = "<?xml version=\"1.0\"?>"; // FIXME: encoding?
+ return declaration + dojox.data.dom.innerXML(element); //XML string
+ },
+
+ _getPutContent: function(item){
+ // summary:
+ // Generate a content to put
+ // description:
+ // This default implementation generates an XML document for one
+ // (the first only) new or modified element.
+ // Sub-classes may override this method for the custom put content
+ // generation.
+ // item:
+ // An item to save
+ // returns:
+ // A post content
+ var element = item.element;
+ var declaration = "<?xml version=\"1.0\"?>"; // FIXME: encoding?
+ return declaration + dojox.data.dom.innerXML(element); //XML string
+ },
+
+/* internal API */
+
+ _getAttribute: function(tagName, attribute){
+ if(this._attributeMap){
+ var key = tagName + "." + attribute;
+ var value = this._attributeMap[key];
+ if(value){
+ attribute = value;
+ }else{ // look for global attribute
+ value = this._attributeMap[attribute];
+ if(value){
+ attribute = value;
+ }
+ }
+ }
+ return attribute; //object
+ },
+
+ _getItem: function(element){
+ return new dojox.data.XmlItem(element, this); //object
+ },
+
+ _getItemIndex: function(items, element){
+ for(var i = 0; i < items.length; i++){
+ if(items[i].element === element){
+ return i; //int
+ }
+ }
+ return -1; //int
+ },
+
+ _backupItem: function(item){
+ var element = this._getRootElement(item.element);
+ if( this._getItemIndex(this._newItems, element) >= 0 ||
+ this._getItemIndex(this._modifiedItems, element) >= 0){
+ return; // new or already modified
+ }
+ if(element != item.element){
+ item = this._getItem(element);
+ }
+ item._backup = element.cloneNode(true);
+ this._modifiedItems.push(item);
+ },
+
+ _restoreItems: function(items){
+
+ dojo.forEach(items,function(item){
+ if(item._backup){
+ item.element = item._backup;
+ item._backup = null;
+ }
+ },this);
+ },
+
+ _forgetItem: function(item){
+ var element = item.element;
+ var index = this._getItemIndex(this._newItems, element);
+ if(index >= 0){
+ this._newItems.splice(index, 1);
+ }
+ index = this._getItemIndex(this._deletedItems, element);
+ if(index >= 0){
+ this._deletedItems.splice(index, 1);
+ }
+ index = this._getItemIndex(this._modifiedItems, element);
+ if(index >= 0){
+ this._modifiedItems.splice(index, 1);
+ }
+ },
+
+ _getDocument: function(element){
+ if(element){
+ return element.ownerDocument; //DOMDocument
+ }else if(!this._document){
+ return dojox.data.dom.createDocument(); // DOMDocument
+ }
+ },
+
+ _getRootElement: function(element){
+ while(element.parentNode){
+ element = element.parentNode;
+ }
+ return element; //DOMElement
+ }
+
+});
+
+//FIXME: Is a full class here really needed for containment of the item or would
+//an anon object work fine?
+dojo.declare("dojox.data.XmlItem", null, {
+ constructor: function(element, store) {
+ // summary:
+ // Initialize with an XML element
+ // element:
+ // An XML element
+ // store:
+ // The containing store, if any.
+ this.element = element;
+ this.store = store;
+ },
+ // summary:
+ // A data item of 'XmlStore'
+ // description:
+ // This class represents an item of 'XmlStore' holding an XML element.
+ // 'element'
+ // element:
+ // An XML element
+
+ toString: function() {
+ // summary:
+ // Return a value of the first text child of the element
+ // returns:
+ // a value of the first text child of the element
+ var str = "";
+ if (this.element) {
+ for (var i = 0; i < this.element.childNodes.length; i++) {
+ var node = this.element.childNodes[i];
+ if (node.nodeType === 3) {
+ str = node.nodeValue;
+ break;
+ }
+ }
+ }
+ return str; //String
+ }
+
+});
+dojo.extend(dojox.data.XmlStore,dojo.data.util.simpleFetch);
+
+}
diff --git a/includes/js/dojox/data/demos/demo_DataDemoTable.html b/includes/js/dojox/data/demos/demo_DataDemoTable.html
new file mode 100644
index 0000000..09761b9
--- /dev/null
+++ b/includes/js/dojox/data/demos/demo_DataDemoTable.html
@@ -0,0 +1,130 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojo Visual Loader Test</title>
+ <style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dijit/themes/dijit.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+
+ .oddRow { background-color: #f2f5f9; }
+ .population { text-align: right; }
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: false, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dijit.dijit");
+ dojo.require("dojo.parser");
+ dojo.require("dijit.Declaration");
+ dojo.require("dojo.data.ItemFileReadStore");
+ dojo.require("dojox.data.FlickrStore");
+ </script>
+</head>
+<body class="tundra">
+ <span dojoType="dojo.data.ItemFileReadStore"
+ jsId="continentStore"
+ url="../../../dijit/tests/_data/countries.json"></span>
+ <span dojoType="dojox.data.FlickrStore" jsId="flickrStore"></span>
+
+
+ <h1 class="testTitle">Dojox Data Demo Table</h1>
+
+ <table dojoType="dijit.Declaration"
+ widgetClass="demo.Table" class="dojoTabular"
+ defaults="{ store: null, query: { query: { name: '*' } }, columns: [ { name: 'Name', attribute: 'name' } ] }">
+ <thead dojoAttachPoint="head">
+ <tr dojoAttachPoint="headRow"></tr>
+ </thead>
+ <tbody dojoAttachPoint="body">
+ <tr dojoAttachPoint="row">
+ </tr>
+ </tbody>
+
+ <script type="dojo/method">
+ dojo.forEach(this.columns, function(item, idx){
+ var icn = item.className||"";
+ // add a header for each column
+ var tth = document.createElement("th");
+ tth.innerHTML = item.name;
+ tth.className = icn;
+ dojo.connect(tth, "onclick", dojo.hitch(this, "onSort", idx));
+ this.headRow.appendChild(tth);
+
+ // and fill in the column cell in the template row
+ this.row.appendChild(document.createElement("td"));
+ this.row.lastChild.className = icn;
+ }, this);
+ this.runQuery();
+ </script>
+ <script type="dojo/method" event="onSort" args="index">
+ var ca = this.columns[index].attribute;
+ var qs = this.query.sort;
+ // clobber an existing sort arrow
+ dojo.query("> th", this.headRow).style("background", "").style("paddingRight", "");
+ if(qs && qs[0].attribute == ca){
+ qs[0].descending = !qs[0].descending;
+ }else{
+ this.query.sort = [{
+ attribute: ca,
+ descending: false
+ }];
+ }
+ var th = dojo.query("> th", this.headRow)[index];
+ th.style.paddingRight = "16px"; // space for the sort arrow
+ th.style.background = "url(\""+dojo.moduleUrl("dijit", "themes/tundra/images/arrow"+(this.query.sort[0].descending ? "Up" : "Down")+((dojo.isIE == 6) ? ".gif" : ".png")) + "\") no-repeat 98% 4px";
+ this.runQuery();
+ </script>
+ <script type="dojo/method" event="runQuery">
+ this.query.onBegin = dojo.hitch(this, function(){ dojo.query("tr", this.body).orphan(); });
+ this.query.onItem = dojo.hitch(this, "onItem");
+ this.query.onComplete = dojo.hitch(this, function(){
+ dojo.query("tr:nth-child(odd)", this.body).addClass("oddRow");
+ dojo.query("tr:nth-child(even)", this.body).removeClass("oddRow");
+ });
+ this.store.fetch(this.query);
+ </script>
+ <script type="dojo/method" event="onItem" args="item">
+ var tr = this.row.cloneNode(true);
+ dojo.query("td", tr).forEach(function(n, i, a){
+ var tc = this.columns[i];
+ var tv = this.store.getValue(item, tc.attribute)||"";
+ if(tc.format){ tv = tc.format(tv, item, this.store); }
+ n.innerHTML = tv;
+ }, this);
+ this.body.appendChild(tr);
+ </script>
+ </table>
+
+ <span dojoType="demo.Table" store="continentStore"
+ query="{ query: { type: 'country' }, sort: [ { attribute: 'name', descending: true } ] }"
+ id="foo">
+ <script type="dojo/method" event="preamble">
+ this.columns = [
+ { name: "Name", attribute: "name" },
+ { name: "Population",
+ attribute: "population",
+ className: "population"
+ }
+ ];
+ </script>
+ </span>
+ <span dojoType="demo.Table" store="continentStore"
+ query="{ query: { name: 'A*' } }"></span>
+ <span dojoType="demo.Table" store="flickrStore"
+ query="{ query: { tags: '3dny' } }">
+ <script type="dojo/method" event="preamble">
+ this.columns = [
+ { name: "", attribute: "imageUrlSmall",
+ format: function(value, item, store){
+ return (value.length) ? "<img src='"+value+"'>" : "";
+ }
+ },
+ { name: "Title", attribute: "title" }
+ ];
+ </script>
+ </span>
+</body>
+</html>
diff --git a/includes/js/dojox/data/demos/demo_FlickrRestStore.html b/includes/js/dojox/data/demos/demo_FlickrRestStore.html
new file mode 100644
index 0000000..a094bc6
--- /dev/null
+++ b/includes/js/dojox/data/demos/demo_FlickrRestStore.html
@@ -0,0 +1,275 @@
+<!--
+ This file is a demo of the FlickrStore, a simple wrapper to the public feed service
+ of Flickr. This just does very basic queries against Flickr and loads the results
+ into a list viewing widget.
+-->
+<html>
+<head>
+ <title>Demo of FlickrRestStore</title>
+ <style type="text/css">
+
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "./flickrDemo.css";
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dijit.form.TextBox");
+ dojo.require("dijit.form.Button");
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dijit.form.NumberSpinner");
+ dojo.require("dijit.Tree");
+ dojo.require("dojox.data.FlickrStore");
+ dojo.require("dojox.data.FlickrRestStore");
+ dojo.require("dojox.data.demos.widgets.FlickrViewList");
+ dojo.require("dojox.data.demos.widgets.FlickrView");
+
+ function init(){
+ var fViewWidgets = [];
+
+ //Set up an onComplete handler for flickrData
+ function onComplete(items, request){
+ flickrViewsWidget.clearList();
+ if(items.length > 0){
+ for(var i = 0; i < items.length; i++){
+ var flickrData = {
+ title: flickrStore.getValue(items[i],"title"),
+ author: flickrStore.getValue(items[i],"author"),
+ iconUrl: flickrStore.getValue(items[i],"imageUrlSmall"),
+ imageUrl: flickrStore.getValue(items[i],"imageUrl")
+ }
+ flickrViewsWidget.addView(flickrData);
+ }
+ }
+ statusWidget.setValue("PROCESSING COMPLETE.");
+
+ }
+ //What to do if a search fails...
+ function onError(error, request){
+ flickrViewsWidget.clearList();
+ statusWidget.setValue("PROCESSING ERROR.");
+ }
+
+ //Function to invoke the search of the FlickrStore
+ function invokeSearch(){
+ var request = {
+ query: {
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ onComplete: onComplete,
+ onError: onError
+ };
+
+ if(idWidget){
+ var userid = idWidget.getValue();
+ if(userid && userid !== ""){
+ request.query.userid = userid;
+ }
+ }
+ if(tagsWidget){
+ var tags = tagsWidget.getValue();
+ if(tags && tags !== ""){
+ var tagsArray = tags.split(" ");
+ tags = "";
+ for(var i = 0; i < tagsArray.length; i++){
+ tags = tags + tagsArray[i];
+ if(i < (tagsArray.length - 1)){
+ tags += ","
+ }
+ }
+ request.query.tags = tags;
+ }
+ }
+ if(tagmodeWidget){
+ var tagmode = tagmodeWidget.getValue();
+ if(tagmode !== ""){
+ request.query.tagmode = tagmode;
+ }
+ }
+
+ if(setIdWidget){
+ var setId = setIdWidget.getValue();
+ if(setId != ""){
+ request.query.setId = setId;
+ }
+ }
+
+ if(fullTextWidget){
+ var fullText = fullTextWidget.getValue();
+ if(fullText != ""){
+ request.query.text = fullText;
+ }
+ }
+
+ if(sortTypeWidget && sortDirWidget){
+ var sortType = sortTypeWidget.getValue();
+ var sortDirection = sortDirWidget.getValue();
+
+ if(sortType != "" && sortDirection != ""){
+ request.query.sort = [
+ {
+ attribute: sortType,
+ descending: (sortDirection.toLowerCase() == "descending")
+ }
+ ];
+ }
+ }
+
+ if(countWidget){
+ request.count = countWidget.getValue();
+ }
+ if(pageWidget){
+ request.start = request.count * (pageWidget.getValue() -1);
+ }
+
+ if(statusWidget){
+ statusWidget.setValue("PROCESSING REQUEST");
+ }
+
+ flickrStore.fetch(request);
+ }
+
+ //Lastly, link up the search event.
+ var button = dijit.byId("searchButton");
+ dojo.connect(button, "onClick", invokeSearch);
+ }
+ dojo.addOnLoad(init);
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>
+ DEMO: FlickrRestStore Search
+ </h1>
+ <hr>
+ <h3>
+ Description:
+ </h3>
+ <p>
+ This simple demo shows how services, such as Flickr, can be wrapped by the datastore API.
+ In this demo, you can search public Flickr images through a FlickrRestStore by specifying
+ a series of tags (separated by spaces) to search on. The results will be displayed below the search box.
+ </p>
+ <p>
+ For fun, search on the 3dny tag!
+ </p>
+
+ <blockquote>
+
+ <!--
+ The store instance used by this demo.
+ -->
+ <table>
+ <tbody>
+ <tr>
+ <td>
+ <b>Status:</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="status" jsId="statusWidget" disabled="true"></div>
+ </td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>
+ <b>User ID:</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="userid" jsId="idWidget" value="44153025@N00"></div>
+ </td>
+ <td>
+ <b>Set ID</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="setid" jsId="setIdWidget"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>Tags:</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="tags" jsId="tagsWidget" value="rollingstones,kinsale"></div>
+ </td>
+ <td>
+ <b>Full Text</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="fulltext" jsId="fullTextWidget"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>Tagmode:</b>
+ </td>
+ <td>
+ <select id="tagmode"
+ jsId="tagmodeWidget"
+ dojoType="dijit.form.ComboBox"
+ autocomplete="false"
+ value="any"
+ >
+ <option>any</option>
+ <option>all</option>
+ </select>
+ </td>
+ <td>
+ <b>Sort</b>
+ </td>
+ <td>
+ <select dojoType="dijit.form.ComboBox" size="15" id="sorttype" jsId="sortTypeWidget">
+ <option>date-posted</option>
+ <option>date-taken</option>
+ <option>interestingness</option>
+ </select>
+ <select dojoType="dijit.form.ComboBox" size="15" id="sortdirection" jsId="sortDirWidget">
+ <option>ascending</option>
+ <option>descending</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>Number of Pictures:</b>
+ </td>
+ <td>
+ <div
+ id="count"
+ jsId="countWidget"
+ dojoType="dijit.form.NumberSpinner"
+ value="20"
+ constraints="{min:1,max:20,places:0}"
+ ></div>
+ </td>
+ <td>
+ <b>Page:</b>
+ </td>
+ <td>
+ <div
+ id="page"
+ jsId="pageWidget"
+ dojoType="dijit.form.NumberSpinner"
+ value="1"
+ constraints="{min:1,max:5,places:0}"
+ ></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ </td>
+ <td>
+ <div dojoType="dijit.form.Button" label="Search" id="searchButton" jsId="searchButtonWidget"></div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <hr/>
+ <div dojoType="dojox.data.FlickrRestStore" jsId="flickrStore" label="title"></div>
+ <div dojoType="dojox.data.demos.widgets.FlickrViewList" id="flickrViews" jsId="flickrViewsWidget"></div>
+
+</body>
+</html>
diff --git a/includes/js/dojox/data/demos/demo_FlickrStore.html b/includes/js/dojox/data/demos/demo_FlickrStore.html
new file mode 100644
index 0000000..5ca48cf
--- /dev/null
+++ b/includes/js/dojox/data/demos/demo_FlickrStore.html
@@ -0,0 +1,199 @@
+<!--
+ This file is a demo of the FlickrStore, a simple wrapper to the public feed service
+ of Flickr. This just does very basic queries against Flickr and loads the results
+ into a list viewing widget.
+-->
+<html>
+<head>
+ <title>Demo of FlickrStore</title>
+ <style type="text/css">
+
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "./flickrDemo.css";
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dijit.form.TextBox");
+ dojo.require("dijit.form.Button");
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dijit.form.NumberSpinner");
+ dojo.require("dijit.Tree");
+ dojo.require("dojox.data.FlickrStore");
+ dojo.require("dojox.data.demos.widgets.FlickrViewList");
+ dojo.require("dojox.data.demos.widgets.FlickrView");
+
+ function init(){
+ var fViewWidgets = [];
+
+ //Set up an onComplete handler for flickrData
+ function onComplete(items, request){
+ flickrViewsWidget.clearList();
+ if(items.length > 0){
+ for(var i = 0; i < items.length; i++){
+ var flickrData = {
+ title: flickrStore.getValue(items[i],"title"),
+ author: flickrStore.getValue(items[i],"author"),
+ iconUrl: flickrStore.getValue(items[i],"imageUrlSmall"),
+ imageUrl: flickrStore.getValue(items[i],"imageUrl")
+ }
+ flickrViewsWidget.addView(flickrData);
+ }
+ }
+ statusWidget.setValue("PROCESSING COMPLETE.");
+
+ }
+ //What to do if a search fails...
+ function onError(error, request){
+ flickrViewsWidget.clearList();
+ statusWidget.setValue("PROCESSING ERROR.");
+ }
+
+ //Function to invoke the search of the FlickrStore
+ function invokeSearch(){
+ var request = {
+ query: {},
+ onComplete: onComplete,
+ onError: onError
+ };
+
+ if(idWidget){
+ var userid = idWidget.getValue();
+ if(userid && userid !== ""){
+ request.query.userid = userid;
+ }
+ }
+ if(tagsWidget){
+ var tags = tagsWidget.getValue();
+ if(tags && tags !== ""){
+ var tagsArray = tags.split(" ");
+ tags = "";
+ for(var i = 0; i < tagsArray.length; i++){
+ tags = tags + tagsArray[i];
+ if(i < (tagsArray.length - 1)){
+ tags += ","
+ }
+ }
+ request.query.tags = tags;
+ }
+ }
+ if(tagmodeWidget){
+ var tagmode = tagmodeWidget.getValue();
+ if(tagmode !== ""){
+ request.query.tagmode = tagmode;
+ }
+ }
+
+ if(countWidget){
+ request.count = countWidget.getValue();
+ }
+
+ if(statusWidget){
+ statusWidget.setValue("PROCESSING REQUEST");
+ }
+
+ flickrStore.fetch(request);
+ }
+
+ //Lastly, link up the search event.
+ var button = dijit.byId("searchButton");
+ dojo.connect(button, "onClick", invokeSearch);
+ }
+ dojo.addOnLoad(init);
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>
+ DEMO: FlickrStore Search
+ </h1>
+ <hr>
+ <h3>
+ Description:
+ </h3>
+ <p>
+ This simple demo shows how services, such as Flickr, can be wrapped by the datastore API. In this demo, you can search public Flickr images through a simple FlickrStore by specifying a series of tags (separated by spaces) to search on. The results will be displayed below the search box.
+ </p>
+ <p>
+ For fun, search on the 3dny tag!
+ </p>
+
+ <blockquote>
+
+ <!--
+ The store instance used by this demo.
+ -->
+ <table>
+ <tbody>
+ <tr>
+ <td>
+ <b>Status:</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="status" jsId="statusWidget" disabled="true"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>ID:</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="userid" jsId="idWidget"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>Tags:</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="tags" jsId="tagsWidget" value="3dny"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>Tagmode:</b>
+ </td>
+ <td>
+ <select id="tagmode"
+ jsId="tagmodeWidget"
+ dojoType="dijit.form.ComboBox"
+ autocomplete="false"
+ value="any"
+ >
+ <option>any</option>
+ <option>all</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>Number of Pictures:</b>
+ </td>
+ <td>
+ <div
+ id="count"
+ jsId="countWidget"
+ dojoType="dijit.form.NumberSpinner"
+ value="20"
+ constraints="{min:1,max:20,places:0}"
+ ></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ </td>
+ <td>
+ <div dojoType="dijit.form.Button" label="Search" id="searchButton" jsId="searchButtonWidget"></div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <hr/>
+ <div dojoType="dojox.data.FlickrStore" jsId="flickrStore" label="title"></div>
+ <div dojoType="dojox.data.demos.widgets.FlickrViewList" id="flickrViews" jsId="flickrViewsWidget"></div>
+
+</body>
+</html>
diff --git a/includes/js/dojox/data/demos/demo_LazyLoad.html b/includes/js/dojox/data/demos/demo_LazyLoad.html
new file mode 100644
index 0000000..358ce84
--- /dev/null
+++ b/includes/js/dojox/data/demos/demo_LazyLoad.html
@@ -0,0 +1,66 @@
+<!--
+ This file is a simple loader for the Lazy Load demo of a Datastore. In this
+ Example, a simple extension of ItemFileReadStore that can do rudimentary lazy-loading
+ of items into the store is used to showcase how Datastores can hide how data
+ is loaded from the widget. As long as the widget implements to the Dojo.data API
+ spec, then it should be able to use most datastores as input sources for its
+ values.
+-->
+<html>
+<head>
+ <title>Demo of Lazy Loading Datastore</title>
+ <style type="text/css">
+
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true, usePlainJson: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojox.data.demos.stores.LazyLoadJSIStore");
+ dojo.require("dijit.Tree");
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>
+ DEMO: Lazy Loading Datastore used by dijit.Tree
+ </h1>
+ <hr>
+ <h3>
+ Description:
+ </h3>
+ <p>
+ This simple demo shows how the dijit.Tree widget can work with a Datastore that does lazy-loading of values into the tree.
+ In this demo, the Datastore is an extension of ItemFileReadStore that overrides the <i>isItemLoaded()</i> and <i>loadItem()</i> functions of
+ with ones that can detect 'stub' items and use the data in the stub item to load the real data for that item when it
+ is required. In this demo, the real data is required when one of the tree nodes is expanded.
+ </p>
+ <p>
+ The key thing to note is that all the lazy-loading logic (how to locate the data from the backend and so forth) is encapsulated
+ into the store functions. The dijit.Tree widget only knows about and uses the dojo.data.Read API interfaces to call to the store to
+ get items, test if child items are fully loaded or not, and to invoke the <i>loadItem()</i> function on items that are not yet fully
+ loaded but have been requested to be expanded into view. It has no knowledge of how the store actually goes and gets the data.
+ </p>
+
+ <blockquote>
+
+ <!--
+ The store instance used by this demo.
+ -->
+ <div dojoType="dojox.data.demos.stores.LazyLoadJSIStore" jsId="continentStore"
+ url="geography/root.json"></div>
+
+ <!--
+ Display the toplevel tree with items that have an attribute of 'type',
+ with value of 'contintent'
+ -->
+ <b>Continents</b>
+ <div dojoType="dijit.Tree" id=tree label="Continents" store="continentStore" query="{type:'continent'}"
+ labelAttr="name" typeAttr="type"></div>
+ </blockquote>
+
+</body>
+</html>
diff --git a/includes/js/dojox/data/demos/demo_MultiStores.html b/includes/js/dojox/data/demos/demo_MultiStores.html
new file mode 100644
index 0000000..9faa8be
--- /dev/null
+++ b/includes/js/dojox/data/demos/demo_MultiStores.html
@@ -0,0 +1,72 @@
+<!--
+ This file is a demo of multiple dojo.data aware widgets using different datastore implementations for displaying data.
+-->
+<html>
+<head>
+ <title>Demo of Multiple Widgets using different Datastores</title>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dijit.Tree");
+
+ dojo.require("dojox.data.OpmlStore");
+ dojo.require("dojo.data.ItemFileReadStore");
+
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>
+ DEMO: Multiple DataStore implementations with dojo.data aware Widgets
+ </h1>
+ <hr>
+ <h3>
+ Description:
+ </h3>
+ <p>
+ This simple demo shows how widgets which know only the dojo.data interfaces can work with data sources of varying formats. In this case an OpmlStore
+ and a ItemFileReadStore are used to house the same data in different formats.
+ </p>
+
+ <blockquote>
+
+ <!--
+ The store instances used by this demo.
+ -->
+ <div dojoType="dojo.data.ItemFileReadStore" url="geography.json" jsId="ifrGeoStore"></div>
+ <div dojoType="dojox.data.OpmlStore" url="geography.xml" label="text" jsId="opmlGeoStore"></div>
+
+ <h3>
+ Widgets using OpmlStore:
+ </h3>
+ <blockquote>
+ <b>ComboBox:</b><br>
+ <input dojoType="dijit.form.ComboBox" id="combo1" name="combo1" class="medium" store="opmlGeoStore" searchAttr="text" query="{}"></input>
+ <br>
+ <br>
+
+ <b>Tree:</b><br>
+ <div dojoType="dijit.Tree" id="tree1" label="Continents" store="opmlGeoStore"></div>
+ </blockquote>
+
+ <h3>
+ Widgets using ItemFileReadStore:
+ </h3>
+ <blockquote>
+ <b>ComboBox:</b><br>
+ <input dojoType="dijit.form.ComboBox" id="combo2" name="combo2" class="medium" store="ifrGeoStore" searchAttr="name" query="{}"></input>
+ <br>
+ <br>
+
+ <b>Tree:</b><br>
+ <div dojoType="dijit.Tree" id="tree2" label="Continents" store="ifrGeoStore"></div>
+ </blockquote>
+</body>
+</html>
diff --git a/includes/js/dojox/data/demos/demo_PicasaStore.html b/includes/js/dojox/data/demos/demo_PicasaStore.html
new file mode 100644
index 0000000..78bc961
--- /dev/null
+++ b/includes/js/dojox/data/demos/demo_PicasaStore.html
@@ -0,0 +1,188 @@
+<!--
+ This file is a demo of the PicasaStore, a simple wrapper to the public feed service
+ of Picasa. This just does very basic queries against Picasa and loads the results
+ into a list viewing widget.
+-->
+<html>
+<head>
+ <title>Demo of PicasaStore</title>
+ <style type="text/css">
+
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "./picasaDemo.css";
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dijit.form.TextBox");
+ dojo.require("dijit.form.Button");
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dijit.form.NumberSpinner");
+ dojo.require("dijit.Tree");
+ dojo.require("dojox.data.PicasaStore");
+ dojo.require("dojox.data.demos.widgets.PicasaViewList");
+ dojo.require("dojox.data.demos.widgets.PicasaView");
+
+ function init(){
+ var fViewWidgets = [];
+
+ //Set up an onComplete handler for flickrData
+ function onComplete(items, request){
+ flickrViewsWidget.clearList();
+ if(items.length > 0){
+ for(var i = 0; i < items.length; i++){
+ var flickrData = {
+ title: flickrStore.getValue(items[i],"title"),
+ author: flickrStore.getValue(items[i],"author"),
+ description: flickrStore.getValue(items[i],"description"),
+ iconUrl: flickrStore.getValue(items[i],"imageUrlSmall"),
+ imageUrl: flickrStore.getValue(items[i],"imageUrl")
+ }
+ flickrViewsWidget.addView(flickrData);
+ }
+ }
+ statusWidget.setValue("PROCESSING COMPLETE.");
+
+ }
+ //What to do if a search fails...
+ function onError(error, request){
+ flickrViewsWidget.clearList();
+ statusWidget.setValue("PROCESSING ERROR.");
+ }
+
+ //Function to invoke the search of the FlickrStore
+ function invokeSearch(){
+ var request = {
+ query: {},
+ onComplete: onComplete,
+ onError: onError
+ };
+
+ if(idWidget){
+ var userid = idWidget.getValue();
+ if(userid && userid !== ""){
+ request.query.userid = userid;
+ }
+ }
+ if(tagsWidget){
+ var tags = tagsWidget.getValue();
+ if(tags && tags !== ""){
+ var tagsArray = tags.split(" ");
+ tags = "";
+ for(var i = 0; i < tagsArray.length; i++){
+ tags = tags + tagsArray[i];
+ if(i < (tagsArray.length - 1)){
+ tags += ","
+ }
+ }
+ request.query.tags = tags;
+ }
+ }
+ if(countWidget){
+ request.count = countWidget.getValue();
+ }
+
+ if(startWidget){
+ request.query.start = startWidget.getValue();
+ }
+
+ if(statusWidget){
+ statusWidget.setValue("PROCESSING REQUEST");
+ }
+
+ flickrStore.fetch(request);
+ }
+
+ //Lastly, link up the search event.
+ var button = dijit.byId("searchButton");
+ dojo.connect(button, "onClick", invokeSearch);
+ }
+ dojo.addOnLoad(init);
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>
+ DEMO: PicasaStore Search
+ </h1>
+ <hr>
+ <h3>
+ Description:
+ </h3>
+ <p>
+ This simple demo shows how services, such as Flickr, can be wrapped by the datastore API. In this demo, you can search public Flickr images through a simple FlickrStore by specifying a series of tags (separated by spaces) to search on. The results will be displayed below the search box.
+ </p>
+ <p>
+ For fun, search on the 3dny tag!
+ </p>
+
+ <blockquote>
+
+ <!--
+ The store instance used by this demo.
+ -->
+ <table>
+ <tbody>
+ <tr>
+ <td>
+ <b>Status:</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="status" jsId="statusWidget" disabled="true"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>ID:</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="userid" jsId="idWidget"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>Query:</b>
+ </td>
+ <td>
+ <div dojoType="dijit.form.TextBox" size="50" id="tags" jsId="tagsWidget" value="flower"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>Number of Pictures:</b>
+ </td>
+ <td>
+ <div
+ id="start"
+ jsId="startWidget"
+ dojoType="dijit.form.NumberSpinner"
+ value="1"
+ constraints="{min:1,places:0}"
+ ></div>
+ <div
+ id="count"
+ jsId="countWidget"
+ dojoType="dijit.form.NumberSpinner"
+ value="20"
+ constraints="{min:1,max:100,places:0}"
+ ></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ </td>
+ <td>
+ <div dojoType="dijit.form.Button" label="Search" id="searchButton" jsId="searchButtonWidget"></div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <hr/>
+ <div dojoType="dojox.data.PicasaStore" jsId="flickrStore" label="title"></div>
+ <div dojoType="dojox.data.demos.widgets.PicasaViewList" id="flickrViews" jsId="flickrViewsWidget"></div>
+
+</body>
+</html>
diff --git a/includes/js/dojox/data/demos/demo_QueryReadStore_ComboBox.html b/includes/js/dojox/data/demos/demo_QueryReadStore_ComboBox.html
new file mode 100644
index 0000000..f6d187f
--- /dev/null
+++ b/includes/js/dojox/data/demos/demo_QueryReadStore_ComboBox.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojox QueryReadStore+ComboBox Demo</title>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug:true, parseOnLoad: true"></script>
+</head>
+<body class="tundra">
+
+ <h1 class="testTitle">Dojox QueryReadStore + ComboBox demo</h1>
+
+ <h2>Everything is created ONLY in markup</h2>
+ <div style="float:left;">
+ <div dojoType="dojox.data.QueryReadStore"
+ jsId="store1"
+ url="../tests/stores/QueryReadStore.php"
+ requestMethod="post"></div>
+ <div dojoType="dijit.form.ComboBox" id="cb1" store="store1" pageSize="10"></div>
+ <button dojoType="dijit.form.Button" onclick="dijit.byId('cb1').reset()">reset</button>
+ </div>
+ <div style="float:left; margin-left:5em;">
+ var w = dijit.byId("cb1");
+ <br /><input id="value1" type="text" /> = w.value
+ <br /><input id="itemId1" type="text" /> = w.item ? w.store.getValue(w.item, "id") : "-"
+ <br /><input id="displayedValue1" type="text" /> = w.getDisplayedValue()
+ <br /><input id="isValid1" type="text" /> = w.isValid()
+ <br /><button dojoType="dijit.form.Button" onclick="refresh1()">refresh</button>
+ </div>
+
+ <script type="text/javascript">
+ dojo.require("dojox.data.QueryReadStore");
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dijit.form.Button");
+
+ var w = null;
+ var refresh1 = function() {
+ dojo.byId("value1").value = w.value;
+ dojo.byId("itemId1").value = w.item ? w.store.getValue(w.item, "id") : "-";
+ dojo.byId("displayedValue1").value = w.getDisplayedValue();
+ dojo.byId("isValid1").value = w.isValid();
+ };
+ dojo.addOnLoad(function() {
+ w = dijit.byId("cb1");
+ dojo.connect(w.domNode, "onkeyup", refresh1);
+ dojo.connect(w, "onBlur", refresh1);
+ dojo.connect(w, "onChange", refresh1);
+ refresh1();
+ });
+ </script>
+</body>
+</html>
diff --git a/includes/js/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html b/includes/js/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html
new file mode 100644
index 0000000..addaeca
--- /dev/null
+++ b/includes/js/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojox QueryReadStore+FilteringSelect Demo</title>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug:true, parseOnLoad: true"></script>
+</head>
+<body class="tundra">
+
+ <h1 class="testTitle">Dojox QueryReadStore + FilteringSelect demo</h1>
+
+ <h2>Everything is created ONLY in markup</h2>
+ <div style="float:left;">
+ <div dojoType="dojox.data.QueryReadStore"
+ jsId="store1"
+ url="../tests/stores/QueryReadStore.php"
+ requestMethod="post"></div>
+ <div dojoType="dijit.form.FilteringSelect" id="fs1" store="store1" pageSize="10"></div>
+ <button dojoType="dijit.form.Button" onclick="dijit.byId('fs1').reset()">reset</button>
+ </div>
+ <div style="float:left; margin-left:5em;">
+ var w = dijit.byId("fs1");
+ <br /><input id="value1" type="text" /> = w.value
+ <br /><input id="itemId1" type="text" /> = w.item ? w.store.getValue(w.item, "id") : "-"
+ <br /><input id="displayedValue1" type="text" /> = w.getDisplayedValue()
+ <br /><input id="isValid1" type="text" /> = w.isValid()
+ <br /><button dojoType="dijit.form.Button" onclick="refresh1()">refresh</button>
+ </div>
+
+ <script type="text/javascript">
+ dojo.require("dojox.data.QueryReadStore");
+ dojo.require("dijit.form.FilteringSelect");
+ dojo.require("dijit.form.Button");
+
+ var w = null;
+ var refresh1 = function() {
+ dojo.byId("value1").value = w.value;
+ dojo.byId("itemId1").value = w.item ? w.store.getValue(w.item, "id") : "-";
+ dojo.byId("displayedValue1").value = w.getDisplayedValue();
+ dojo.byId("isValid1").value = w.isValid();
+ };
+ dojo.addOnLoad(function() {
+ w = dijit.byId("fs1");
+ dojo.connect(w.domNode, "onkeyup", refresh1);
+ dojo.connect(w, "onBlur", refresh1);
+ dojo.connect(w, "onChange", refresh1);
+ refresh1();
+ });
+ </script>
+</body>
+</html>
diff --git a/includes/js/dojox/data/demos/demo_QueryReadStore_grid.html b/includes/js/dojox/data/demos/demo_QueryReadStore_grid.html
new file mode 100644
index 0000000..3f7db7e
--- /dev/null
+++ b/includes/js/dojox/data/demos/demo_QueryReadStore_grid.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojox QueryReadStore+grid Demo</title>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ /* BE SURE TO NEVER FORGET IMPORTING THE GRID's CSS, or you will wonder why the hell the grid looks so strange (or even think that it doesnt work) */
+ @import "../../../dojox/grid/_grid/tundraGrid.css";
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug:true, parseOnLoad: true"></script>
+</head>
+<body class="tundra">
+
+ <h1 class="testTitle">Dojox QueryReadStore + Grid demo - paging, sortable and filterable all server-side</h1>
+
+ <h2>The grid is in HTML, store, model, etc. are JS, sorting is added by extending the model class</h2>
+ <b>Capabilities:</b> load data from server, show data, paging (30 rows at a time), sort, filter<br />
+ You can see that data are loaded upon demand by scrolling down in the grid below line #30,
+ open FireBug and you see a server request being issued, to retreive another 30 rows/items.<br />
+ <br /><br />
+ <input type="text" onkeyup="doSearch(this)" />
+ <div id="grid1" dojoType="dojox.Grid" style="height:300px; width:800px;"></div>
+
+ <h2>The store and grid are "generated" and connected in HTML, filtering is done via JS</h2>
+ This store is by default sorted descending by name (not as the one above, which is ascending).
+ <div dojoType="dojox.data.QueryReadStore"
+ jsId="store2"
+ url="../tests/stores/QueryReadStore.php"
+ requestMethod="post"></div>
+ <div dojoType="dojox.grid.data.DojoData"
+ jsId="model2"
+ store="store2"
+ sortFields="[{attribute: 'capital', descending: true}]"
+ rowsPerPage="30"></div>
+ <div dojoType="dojox.Grid" id="grid2"
+ model="model2"
+ structure="gridLayout"
+ style="height:300px; width:800px;"></div>
+
+ <script type="text/javascript">
+ dojo.require("dojo.parser"); // scan page for widgets and instantiate them
+ dojo.require("dojox.grid.Grid");
+ dojo.require("dojox.grid._data.model"); // dojox.grid.data.DojoData is in there
+ dojo.require("dojox.data.QueryReadStore");
+ var gridLayout = [
+ {
+ cells: [[
+ {
+ name: "row #",
+ width:5,
+ styles: "text-align:right;",
+ get:function(inRowIndex) { return inRowIndex+1;} // this auto generates a row num
+ }
+ ,{
+ name: "id",
+ field: "id",
+ styles: "text-align:right;",
+ width:5
+ }
+ ,{
+ name: "Name",
+ field: "name",
+ width:20
+ //formatter: rs.chunk.adminUser.grid.formatUser
+ }
+ ,{
+ name: "Capital",
+ field: "capital",
+ width:20
+ //formatter: rs.chunk.adminUser.grid.formatUser
+ }
+ ,{
+ name: "Label",
+ width:20,
+ //styles: "text-align:right;",
+ field: "label"
+ //formatter: phpr.grid.formatDate
+ }
+ ,{
+ name: "Abbrev.",
+ width:5,
+ //styles: "text-align:right;",
+ field: "abbreviation"
+ //formatter: phpr.grid.formatDate
+ }
+ ]]
+ }
+ ];
+ // Connect the model and store AFTER the page is loaded, since we can only access
+ // the widget then, since it will be created just before dojo.addOnLoad() is called.
+ var grid = null;
+ dojo.addOnLoad(function() {
+ // Instanciate the store, pass it to the model, connect them to the grid and add the layout ... just some hand work :-)
+ //var store = new dojox.data.QueryReadStore({url:"../tests/stores/QueryReadStore.php", requestMethod:"post", doClientPaging:false});
+ var store = new dojox.data.QueryReadStore({
+ url:"../tests/stores/QueryReadStore.php",
+ requestMethod:"post"
+ });
+ var model = new dojox.grid.data.DojoData(null, null, {
+ store:store,
+ rowsPerPage:30,
+ sortFields:[{attribute: 'name', descending: false}]
+ });
+ grid = dijit.byId("grid1");
+ grid.setModel(model);
+ grid.setStructure(gridLayout);
+ grid2 = dijit.byId("grid2");
+ });
+
+ var lastSearchValue = "";
+ function doSearch(el) {
+ if (el.value!=lastSearchValue) {
+ grid.model.query = {name:el.value};
+ lastSearchValue = el.value;
+ grid.model.requestRows();
+
+ // Filter the grid2 too.
+ grid2.model.query = {name:el.value};
+ grid2.model.requestRows();
+ }
+ }
+ </script>
+
+
+</body>
+</html>
diff --git a/includes/js/dojox/data/demos/flickrDemo.css b/includes/js/dojox/data/demos/flickrDemo.css
new file mode 100644
index 0000000..793d1c6
--- /dev/null
+++ b/includes/js/dojox/data/demos/flickrDemo.css
@@ -0,0 +1,29 @@
+.flickrView {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+ border-collapse: separate;
+ width: 100%;
+}
+.flickrView th {
+ text-align: left;
+}
+.flickrView tr {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+}
+.flickrView tr td {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+}
+.flickrView {
+ background-color: #EFEFEF;
+}
+.flickrTitle {
+ background-color: #CCCCCC;
+}
diff --git a/includes/js/dojox/data/demos/flickrDemo.css.commented.css b/includes/js/dojox/data/demos/flickrDemo.css.commented.css
new file mode 100644
index 0000000..7e75a5d
--- /dev/null
+++ b/includes/js/dojox/data/demos/flickrDemo.css.commented.css
@@ -0,0 +1,35 @@
+.flickrView {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+ border-collapse: separate;
+ width: 100%;
+}
+
+.flickrView th {
+ text-align: left;
+}
+
+.flickrView tr {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+}
+
+.flickrView tr td {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+}
+
+.flickrView {
+ background-color: #EFEFEF;
+}
+
+.flickrTitle {
+ background-color: #CCCCCC;
+}
+
diff --git a/includes/js/dojox/data/demos/geography.json b/includes/js/dojox/data/demos/geography.json
new file mode 100644
index 0000000..c2f01bb
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography.json
@@ -0,0 +1,45 @@
+{ identifier: 'name',
+ label: 'name',
+ items: [
+ { name:'Africa', type:'continent', children:[
+ { name:'Egypt', type:'country' },
+ { name:'Kenya', type:'country', children:[
+ { name:'Nairobi', type:'city' },
+ { name:'Mombasa', type:'city' } ]
+ },
+ { name:'Sudan', type:'country', children:
+ { name:'Khartoum', type:'city' }
+ } ]
+ },
+ { name:'Asia', type:'continent', children:[
+ { name:'China', type:'country' },
+ { name:'India', type:'country' },
+ { name:'Russia', type:'country' },
+ { name:'Mongolia', type:'country' } ]
+ },
+ { name:'Australia', type:'continent', population:'21 million', children:
+ { name:'Commonwealth of Australia', type:'country', population:'21 million'}
+ },
+ { name:'Europe', type:'continent', children:[
+ { name:'Germany', type:'country' },
+ { name:'France', type:'country' },
+ { name:'Spain', type:'country' },
+ { name:'Italy', type:'country' } ]
+ },
+ { name:'North America', type:'continent', children:[
+ { name:'Mexico', type:'country', population:'108 million', area:'1,972,550 sq km', children:[
+ { name:'Mexico City', type:'city', population:'19 million', timezone:'-6 UTC'},
+ { name:'Guadalajara', type:'city', population:'4 million', timezone:'-6 UTC' } ]
+ },
+ { name:'Canada', type:'country', population:'33 million', area:'9,984,670 sq km', children:[
+ { name:'Ottawa', type:'city', population:'0.9 million', timezone:'-5 UTC'},
+ { name:'Toronto', type:'city', population:'2.5 million', timezone:'-5 UTC' }]
+ },
+ { name:'United States of America', type:'country' } ]
+ },
+ { name:'South America', type:'continent', children:[
+ { name:'Brazil', type:'country', population:'186 million' },
+ { name:'Argentina', type:'country', population:'40 million' } ]
+ } ]
+}
+
diff --git a/includes/js/dojox/data/demos/geography.xml b/includes/js/dojox/data/demos/geography.xml
new file mode 100644
index 0000000..070a8c1
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<opml version="1.0">
+ <head>
+ <title>geography.opml</title>
+ <dateCreated>2006-11-10</dateCreated>
+ <dateModified>2006-11-13</dateModified>
+ <ownerName>Magellan, Ferdinand</ownerName>
+ </head>
+ <body>
+ <outline text="Africa" type="continent">
+ <outline text="Egypt" type="country"/>
+ <outline text="Kenya" type="country">
+ <outline text="Nairobi" type="city"/>
+ <outline text="Mombasa" type="city"/>
+ </outline>
+ <outline text="Sudan" type="country">
+ <outline text="Khartoum" type="city"/>
+ </outline>
+ </outline>
+ <outline text="Asia" type="continent">
+ <outline text="China" type="country"/>
+ <outline text="India" type="country"/>
+ <outline text="Russia" type="country"/>
+ <outline text="Mongolia" type="country"/>
+ </outline>
+ <outline text="Australia" type="continent" population="21 million">
+ <outline text="Australia" type="country" population="21 million"/>
+ </outline>
+ <outline text="Europe" type="continent">
+ <outline text="Germany" type="country"/>
+ <outline text="France" type="country"/>
+ <outline text="Spain" type="country"/>
+ <outline text="Italy" type="country"/>
+ </outline>
+ <outline text="North America" type="continent">
+ <outline text="Mexico" type="country" population="108 million" area="1,972,550 sq km">
+ <outline text="Mexico City" type="city" population="19 million" timezone="-6 UTC"/>
+ <outline text="Guadalajara" type="city" population="4 million" timezone="-6 UTC"/>
+ </outline>
+ <outline text="Canada" type="country" population="33 million" area="9,984,670 sq km">
+ <outline text="Ottawa" type="city" population="0.9 million" timezone="-5 UTC"/>
+ <outline text="Toronto" type="city" population="2.5 million" timezone="-5 UTC"/>
+ </outline>
+ <outline text="United States of America" type="country"/>
+ </outline>
+ <outline text="South America" type="continent">
+ <outline text="Brazil" type="country" population="186 million"/>
+ <outline text="Argentina" type="country" population="40 million"/>
+ </outline>
+ </body>
+</opml>
diff --git a/includes/js/dojox/data/demos/geography/Argentina/data.json b/includes/js/dojox/data/demos/geography/Argentina/data.json
new file mode 100644
index 0000000..17ba291
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Argentina/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Argentina',
+ type:'country',
+ population:'40 million'
+}
diff --git a/includes/js/dojox/data/demos/geography/Brazil/data.json b/includes/js/dojox/data/demos/geography/Brazil/data.json
new file mode 100644
index 0000000..a326c24
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Brazil/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Brazil',
+ type:'country',
+ population:'186 million'
+}
diff --git a/includes/js/dojox/data/demos/geography/Canada/Ottawa/data.json b/includes/js/dojox/data/demos/geography/Canada/Ottawa/data.json
new file mode 100644
index 0000000..df3bbc8
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Canada/Ottawa/data.json
@@ -0,0 +1,6 @@
+{
+ name:'Ottawa',
+ type:'city',
+ population:'0.9 million',
+ timezone:'-5 UTC'
+}
diff --git a/includes/js/dojox/data/demos/geography/Canada/Toronto/data.json b/includes/js/dojox/data/demos/geography/Canada/Toronto/data.json
new file mode 100644
index 0000000..534409b
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Canada/Toronto/data.json
@@ -0,0 +1,6 @@
+{
+ name:'Toronto',
+ type:'city',
+ population:'2.5 million',
+ timezone:'-5 UTC'
+}
diff --git a/includes/js/dojox/data/demos/geography/Canada/data.json b/includes/js/dojox/data/demos/geography/Canada/data.json
new file mode 100644
index 0000000..6ef34ed
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Canada/data.json
@@ -0,0 +1,10 @@
+{
+ name:'Canada',
+ type:'country',
+ population:'33 million', area:'9,984,670 sq km',
+ children:[
+ {stub:'Ottawa'},
+ {stub:'Toronto'}
+ ]
+}
+
diff --git a/includes/js/dojox/data/demos/geography/China/data.json b/includes/js/dojox/data/demos/geography/China/data.json
new file mode 100644
index 0000000..72c29cc
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/China/data.json
@@ -0,0 +1,4 @@
+{
+ name:'China',
+ type:'country'
+}
diff --git a/includes/js/dojox/data/demos/geography/Commonwealth of Australia/data.json b/includes/js/dojox/data/demos/geography/Commonwealth of Australia/data.json
new file mode 100644
index 0000000..e093295
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Commonwealth of Australia/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Commonwealth of Australia',
+ type:'country',
+ population:'21 million'
+}
diff --git a/includes/js/dojox/data/demos/geography/Egypt/data.json b/includes/js/dojox/data/demos/geography/Egypt/data.json
new file mode 100644
index 0000000..d355537
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Egypt/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Egypt',
+ type:'country'
+}
+
diff --git a/includes/js/dojox/data/demos/geography/France/data.json b/includes/js/dojox/data/demos/geography/France/data.json
new file mode 100644
index 0000000..5b5f3c3
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/France/data.json
@@ -0,0 +1,4 @@
+{
+ name:'France',
+ type:'country'
+}
diff --git a/includes/js/dojox/data/demos/geography/Germany/data.json b/includes/js/dojox/data/demos/geography/Germany/data.json
new file mode 100644
index 0000000..1656257
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Germany/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Germany',
+ type:'country'
+}
diff --git a/includes/js/dojox/data/demos/geography/India/data.json b/includes/js/dojox/data/demos/geography/India/data.json
new file mode 100644
index 0000000..3103f89
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/India/data.json
@@ -0,0 +1,4 @@
+{
+ name:'India',
+ type:'country'
+}
diff --git a/includes/js/dojox/data/demos/geography/Italy/data.json b/includes/js/dojox/data/demos/geography/Italy/data.json
new file mode 100644
index 0000000..6e6b076
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Italy/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Italy',
+ type:'country'
+}
diff --git a/includes/js/dojox/data/demos/geography/Kenya/Mombasa/data.json b/includes/js/dojox/data/demos/geography/Kenya/Mombasa/data.json
new file mode 100644
index 0000000..28aa849
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Kenya/Mombasa/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Mombasa',
+ type:'city',
+ population: "Unknown"
+}
diff --git a/includes/js/dojox/data/demos/geography/Kenya/Nairobi/data.json b/includes/js/dojox/data/demos/geography/Kenya/Nairobi/data.json
new file mode 100644
index 0000000..f5658ec
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Kenya/Nairobi/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Nairobi',
+ type:'city',
+ population: "Unknown"
+}
diff --git a/includes/js/dojox/data/demos/geography/Kenya/data.json b/includes/js/dojox/data/demos/geography/Kenya/data.json
new file mode 100644
index 0000000..9253c25
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Kenya/data.json
@@ -0,0 +1,9 @@
+{
+ name:'Kenya',
+ type:'country',
+ children:[
+ {stub:'Nairobi'},
+ {stub:'Mombasa'}
+ ]
+}
+
diff --git a/includes/js/dojox/data/demos/geography/Mexico/Guadalajara/data.json b/includes/js/dojox/data/demos/geography/Mexico/Guadalajara/data.json
new file mode 100644
index 0000000..059fc82
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Mexico/Guadalajara/data.json
@@ -0,0 +1,7 @@
+{
+ name:'Guadalajara',
+ type:'city',
+ population:'4 million',
+ timezone:'-6 UTC'
+}
+
diff --git a/includes/js/dojox/data/demos/geography/Mexico/Mexico City/data.json b/includes/js/dojox/data/demos/geography/Mexico/Mexico City/data.json
new file mode 100644
index 0000000..8c67622
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Mexico/Mexico City/data.json
@@ -0,0 +1,6 @@
+{
+ name:'Mexico City',
+ type:'city',
+ population:'19 million',
+ timezone:'-6 UTC'
+}
diff --git a/includes/js/dojox/data/demos/geography/Mexico/data.json b/includes/js/dojox/data/demos/geography/Mexico/data.json
new file mode 100644
index 0000000..aa381e4
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Mexico/data.json
@@ -0,0 +1,10 @@
+{
+ name:'Mexico',
+ type:'country',
+ population:'108 million',
+ area:'1,972,550 sq km',
+ children:[
+ {stub:'Mexico City'},
+ {stub:'Guadalajara'}
+ ]
+}
diff --git a/includes/js/dojox/data/demos/geography/Mongolia/data.json b/includes/js/dojox/data/demos/geography/Mongolia/data.json
new file mode 100644
index 0000000..4c60b22
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Mongolia/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Mongolia',
+ type:'country'
+}
diff --git a/includes/js/dojox/data/demos/geography/Russia/data.json b/includes/js/dojox/data/demos/geography/Russia/data.json
new file mode 100644
index 0000000..5d9a6ba
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Russia/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Russia',
+ type:'country'
+}
diff --git a/includes/js/dojox/data/demos/geography/Spain/data.json b/includes/js/dojox/data/demos/geography/Spain/data.json
new file mode 100644
index 0000000..d9a1210
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Spain/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Spain',
+ type:'country'
+}
diff --git a/includes/js/dojox/data/demos/geography/Sudan/Khartoum/data.json b/includes/js/dojox/data/demos/geography/Sudan/Khartoum/data.json
new file mode 100644
index 0000000..befa3c7
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Sudan/Khartoum/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Khartoum',
+ type:'city'
+}
+
diff --git a/includes/js/dojox/data/demos/geography/Sudan/data.json b/includes/js/dojox/data/demos/geography/Sudan/data.json
new file mode 100644
index 0000000..fe7585b
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/Sudan/data.json
@@ -0,0 +1,6 @@
+{
+ name:'Sudan',
+ type:'country',
+ children:{stub:'Khartoum'}
+}
+
diff --git a/includes/js/dojox/data/demos/geography/United States of America/data.json b/includes/js/dojox/data/demos/geography/United States of America/data.json
new file mode 100644
index 0000000..7dbdd61
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/United States of America/data.json
@@ -0,0 +1,4 @@
+{
+ name:'United States of America',
+ type:'country'
+}
diff --git a/includes/js/dojox/data/demos/geography/root.json b/includes/js/dojox/data/demos/geography/root.json
new file mode 100644
index 0000000..dda74f5
--- /dev/null
+++ b/includes/js/dojox/data/demos/geography/root.json
@@ -0,0 +1,39 @@
+{
+ identifier: 'name',
+ label: 'name',
+ items: [
+ { name:'Africa', type:'continent',
+ children:[{_reference:'Egypt'}, {_reference:'Kenya'}, {_reference:'Sudan'}] },
+ { name:'Egypt', type:'stub', parent: 'geography'},
+ { name:'Kenya', type:'stub', parent: 'geography'},
+ { name:'Sudan', type:'stub', parent: 'geography'},
+
+ { name:'Asia', type:'continent',
+ children:[{_reference:'China'}, {_reference:'India'}, {_reference:'Russia'}, {_reference:'Mongolia'}] },
+ { name:'China', type:'stub', parent: 'geography'},
+ { name:'India', type:'stub', parent: 'geography'},
+ { name:'Russia', type:'stub', parent: 'geography'},
+ { name:'Mongolia', type:'stub', parent: 'geography'},
+
+ { name:'Australia', type:'continent', population:'21 million',
+ children:{_reference:'Commonwealth of Australia'}},
+ { name:'Commonwealth of Australia', type:'stub', parent:'geography'},
+
+ { name:'Europe', type:'continent',
+ children:[{_reference:'Germany'}, {_reference:'France'}, {_reference:'Spain'}, {_reference:'Italy'}] },
+ { name:'Germany', type:'stub', parent: 'geography'},
+ { name:'France', type:'stub', parent: 'geography'},
+ { name:'Spain', type:'stub', parent: 'geography'},
+ { name:'Italy', type:'stub', parent: 'geography'},
+
+ { name:'North America', type:'continent',
+ children:[{_reference:'Mexico'}, {_reference:'Canada'}, {_reference:'United States of America'}] },
+ { name:'Mexico', type:'stub', parent: 'geography'},
+ { name:'Canada', type:'stub', parent: 'geography'},
+ { name:'United States of America', type:'stub', parent: 'geography'},
+
+ { name:'South America', type:'continent',
+ children:[{_reference:'Brazil'}, {_reference:'Argentina'}] },
+ { name:'Brazil', type:'stub', parent: 'geography'},
+ { name:'Argentina', type:'stub', parent: 'geography'}
+]}
diff --git a/includes/js/dojox/data/demos/picasaDemo.css b/includes/js/dojox/data/demos/picasaDemo.css
new file mode 100644
index 0000000..9163d40
--- /dev/null
+++ b/includes/js/dojox/data/demos/picasaDemo.css
@@ -0,0 +1,37 @@
+.picasaView {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+ border-collapse: separate;
+ width: 100%;
+}
+.picasaView th {
+ text-align: left;
+}
+.picasaView tr {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+}
+.picasaView tr td {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+}
+.picasaView {
+ background-color: #EFEFEF;
+ float: left;
+ width: 250px;
+ height: 250px;
+}
+.picasaSummary {
+ width: 250px;
+ height: 30px;
+ overflow: hidden;
+ }
+.picasaTitle {
+ background-color: #CCCCCC;
+}
diff --git a/includes/js/dojox/data/demos/picasaDemo.css.commented.css b/includes/js/dojox/data/demos/picasaDemo.css.commented.css
new file mode 100644
index 0000000..e274f87
--- /dev/null
+++ b/includes/js/dojox/data/demos/picasaDemo.css.commented.css
@@ -0,0 +1,44 @@
+.picasaView {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+ border-collapse: separate;
+ width: 100%;
+}
+
+.picasaView th {
+ text-align: left;
+}
+
+.picasaView tr {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+}
+
+.picasaView tr td {
+ padding: 3 3 3 3;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #000000;
+}
+
+.picasaView {
+ background-color: #EFEFEF;
+ float: left;
+ width: 250px;
+ height: 250px;
+}
+
+.picasaSummary {
+ width: 250px;
+ height: 30px;
+ overflow: hidden;
+ }
+
+.picasaTitle {
+ background-color: #CCCCCC;
+}
+
diff --git a/includes/js/dojox/data/demos/stores/LazyLoadJSIStore.js b/includes/js/dojox/data/demos/stores/LazyLoadJSIStore.js
new file mode 100644
index 0000000..e7acff7
--- /dev/null
+++ b/includes/js/dojox/data/demos/stores/LazyLoadJSIStore.js
@@ -0,0 +1,142 @@
+if(!dojo._hasResource["dojox.data.demos.stores.LazyLoadJSIStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.demos.stores.LazyLoadJSIStore"] = true;
+dojo.provide("dojox.data.demos.stores.LazyLoadJSIStore");
+dojo.require("dojo.data.ItemFileReadStore");
+
+dojo.declare("dojox.data.demos.stores.LazyLoadJSIStore", dojo.data.ItemFileReadStore, {
+ constructor: function(/* object */ keywordParameters){
+ // LazyLoadJSIStore extends ItemFileReadStore to implement an
+ // example of lazy-loading/faulting in items on-demand.
+ // Note this is certianly not a perfect implementation, it is
+ // an example.
+ },
+
+ isItemLoaded: function(/*object*/ item) {
+ // summary:
+ // Overload of the isItemLoaded function to look for items of type 'stub', which indicate
+ // the data hasn't been loaded in yet.
+ //
+ // item:
+ // The item to examine.
+
+ //For this store, if it has the value of stub for its type attribute,
+ //then the item basn't been fully loaded yet. It's just a placeholder.
+ if(this.getValue(item, "type") === "stub"){
+ return false;
+ }
+ return true;
+ },
+
+ loadItem: function(keywordArgs){
+ // summary:
+ // Overload of the loadItem function to fault in items. This assumes the data for an item is laid out
+ // in a RESTful sort of pattern name0/name1/data.json and so on and uses that to load the data.
+ // It will also detect stub items in the newly loaded item and insert the stubs into the ItemFileReadStore
+ // list so they can also be loaded in on-demand.
+ //
+ // item:
+ // The item to examine.
+
+ var item = keywordArgs.item;
+ this._assertIsItem(item);
+
+ //Build the path to the data.json for this item
+ //The path consists of where its parent was loaded from
+ //plus the item name.
+ var itemName = this.getValue(item, "name");
+ var parent = this.getValue(item, "parent");
+ var dataUrl = "";
+ if (parent){
+ dataUrl += (parent + "/");
+ }
+
+ //For this store, all child input data is loaded from a url that ends with data.json
+ dataUrl += itemName + "/data.json";
+
+ //Need a reference to the store to call back to its structures.
+ var self = this;
+
+ // Callback for handling a successful load.
+ var gotData = function(data){
+ //Now we need to modify the existing item a bit to take it out of stub state
+ //Since we extend the store and have knowledge of the internal
+ //structure, this can be done here. Now, is we extended
+ //a write store, we could call the write APIs to do this too
+ //But for a simple demo the diretc modification in the store function
+ //is sufficient.
+
+ //Clear off the stub indicators.
+ delete item.type;
+ delete item.parent;
+
+ //Set up the loaded values in the format ItemFileReadStore uses for attributes.
+ for (i in data) {
+ if (dojo.isArray(data[i])) {
+ item[i] = data[i];
+ }else{
+ item[i] = [data[i]];
+ }
+ }
+
+ //Reset the item in the reference.
+ self._arrayOfAllItems[item[self._itemNumPropName]] = item;
+
+ //Scan the new values in the item for extra stub items we need to
+ //add to the items array of the store so they can be lazy-loaded later...
+ var attributes = self.getAttributes(item);
+ for(i in attributes){
+ var values = self.getValues(item, attributes[i]);
+ for (var j = 0; j < values.length; j++) {
+ var value = values[j];
+
+ if(typeof value === "object"){
+ if(value["stub"] ){
+ //We have a stub reference here, we need to create the stub item
+ var stub = {
+ type: ["stub"],
+ name: [value["stub"]], //
+ parent: [itemName] //The child stub item is parented by this item name...
+ };
+ if (parent) {
+ //Add in any parents to your parent so URL construstruction is accurate.
+ stub.parent[0] = parent + "/" + stub.parent[0];
+ }
+ //Finalize the addition of the new stub item into the ItemFileReadStore list.
+ self._arrayOfAllItems.push(stub);
+ stub[self._storeRefPropName] = self;
+ stub[self._itemNumPropName] = (self._arrayOfAllItems.length - 1); //Last one pushed in should be the item
+ values[j] = stub; //Set the stub item back in its place and replace the stub notation.
+ }
+ }
+ }
+ }
+
+ //Done processing! Call the onItem, if any.
+ if(keywordArgs.onItem){
+ var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ };
+
+ //Callback for any errors that occur during load.
+ var gotError = function(error){
+ //Call the onComplete, if any
+ if(keywordArgs.onError){
+ var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global;
+ keywordArgs.onError.call(scope, error);
+ }
+ };
+
+ //Fire the get and pass the proper callbacks to the deferred.
+ var xhrArgs = {
+ url: dataUrl,
+ handleAs: "json-comment-optional"
+ };
+ var d = dojo.xhrGet(xhrArgs);
+ d.addCallback(gotData);
+ d.addErrback(gotError);
+ }
+});
+
+
+}
diff --git a/includes/js/dojox/data/demos/widgets/FlickrView.js b/includes/js/dojox/data/demos/widgets/FlickrView.js
new file mode 100644
index 0000000..cacb127
--- /dev/null
+++ b/includes/js/dojox/data/demos/widgets/FlickrView.js
@@ -0,0 +1,36 @@
+if(!dojo._hasResource["dojox.data.demos.widgets.FlickrView"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.demos.widgets.FlickrView"] = true;
+dojo.provide("dojox.data.demos.widgets.FlickrView");
+dojo.require("dijit._Templated");
+dojo.require("dijit._Widget");
+
+dojo.declare("dojox.data.demos.widgets.FlickrView", [dijit._Widget, dijit._Templated], {
+ //Simple demo widget for representing a view of a Flickr Item.
+
+ templateString:"<table class=\"flickrView\">\n\t<tbody>\n\t\t<tr class=\"flickrTitle\">\n\t\t\t<td>\n\t\t\t\t<b>\n\t\t\t\t\tTitle:\n\t\t\t\t</b>\n\t\t\t</td>\n\t\t\t<td dojoAttachPoint=\"titleNode\">\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<b>\n\t\t\t\t\tAuthor:\n\t\t\t\t</b>\n\t\t\t</td>\n\t\t\t<td dojoAttachPoint=\"authorNode\">\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td colspan=\"2\">\n\t\t\t\t<b>\n\t\t\t\t\tImage:\n\t\t\t\t</b>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td dojoAttachPoint=\"imageNode\" colspan=\"2\">\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n",
+
+ //Attach points for reference.
+ titleNode: null,
+ descriptionNode: null,
+ imageNode: null,
+ authorNode: null,
+
+ title: "",
+ author: "",
+ imageUrl: "",
+ iconUrl: "",
+
+ postCreate: function(){
+ this.titleNode.appendChild(document.createTextNode(this.title));
+ this.authorNode.appendChild(document.createTextNode(this.author));
+ var href = document.createElement("a");
+ href.setAttribute("href", this.imageUrl);
+ href.setAttribute("target", "_blank");
+ var imageTag = document.createElement("img");
+ imageTag.setAttribute("src", this.iconUrl);
+ href.appendChild(imageTag);
+ this.imageNode.appendChild(href);
+ }
+});
+
+}
diff --git a/includes/js/dojox/data/demos/widgets/FlickrViewList.js b/includes/js/dojox/data/demos/widgets/FlickrViewList.js
new file mode 100644
index 0000000..2c3c881
--- /dev/null
+++ b/includes/js/dojox/data/demos/widgets/FlickrViewList.js
@@ -0,0 +1,37 @@
+if(!dojo._hasResource["dojox.data.demos.widgets.FlickrViewList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.demos.widgets.FlickrViewList"] = true;
+dojo.provide("dojox.data.demos.widgets.FlickrViewList");
+dojo.require("dijit._Templated");
+dojo.require("dijit._Widget");
+dojo.require("dojox.data.demos.widgets.FlickrView");
+
+dojo.declare("dojox.data.demos.widgets.FlickrViewList", [dijit._Widget, dijit._Templated], {
+ //Simple demo widget that is just a list of FlickrView Widgets.
+
+ templateString:"<div dojoAttachPoint=\"list\"></div>\n\n",
+
+ //Attach points for reference.
+ listNode: null,
+
+ postCreate: function(){
+ this.fViewWidgets = [];
+ },
+
+ clearList: function(){
+ while(this.list.firstChild){
+ this.list.removeChild(this.list.firstChild);
+ }
+ for(var i = 0; i < this.fViewWidgets.length; i++){
+ this.fViewWidgets[i].destroy();
+ }
+ this.fViewWidgets = [];
+ },
+
+ addView: function(viewData){
+ var newView = new dojox.data.demos.widgets.FlickrView(viewData);
+ this.fViewWidgets.push(newView);
+ this.list.appendChild(newView.domNode);
+ }
+});
+
+}
diff --git a/includes/js/dojox/data/demos/widgets/PicasaView.js b/includes/js/dojox/data/demos/widgets/PicasaView.js
new file mode 100644
index 0000000..6b100ac
--- /dev/null
+++ b/includes/js/dojox/data/demos/widgets/PicasaView.js
@@ -0,0 +1,37 @@
+if(!dojo._hasResource["dojox.data.demos.widgets.PicasaView"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.demos.widgets.PicasaView"] = true;
+dojo.provide("dojox.data.demos.widgets.PicasaView");
+dojo.require("dijit._Templated");
+dojo.require("dijit._Widget");
+
+dojo.declare("dojox.data.demos.widgets.PicasaView", [dijit._Widget, dijit._Templated], {
+ //Simple demo widget for representing a view of a Picasa Item.
+
+ templateString:"<table class=\"picasaView\">\n\t<tbody>\n\t\t<tr class=\"picasaTitle\">\n\t\t\t<td>\n\t\t\t\t<b>\n\t\t\t\t\tTitle:\n\t\t\t\t</b>\n\t\t\t</td>\n\t\t\t<td dojoAttachPoint=\"titleNode\">\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<b>\n\t\t\t\t\tAuthor:\n\t\t\t\t</b>\n\t\t\t</td>\n\t\t\t<td dojoAttachPoint=\"authorNode\">\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td colspan=\"2\">\n\t\t\t\t<b>\n\t\t\t\t\tSummary:\n\t\t\t\t</b>\n\t\t\t\t<span class=\"picasaSummary\" dojoAttachPoint=\"descriptionNode\"></span>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td dojoAttachPoint=\"imageNode\" colspan=\"2\">\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n",
+
+ //Attach points for reference.
+ titleNode: null,
+ descriptionNode: null,
+ imageNode: null,
+ authorNode: null,
+
+ title: "",
+ author: "",
+ imageUrl: "",
+ iconUrl: "",
+
+ postCreate: function(){
+ this.titleNode.appendChild(document.createTextNode(this.title));
+ this.authorNode.appendChild(document.createTextNode(this.author));
+ this.descriptionNode.appendChild(document.createTextNode(this.description));
+ var href = document.createElement("a");
+ href.setAttribute("href", this.imageUrl);
+ href.setAttribute("target", "_blank");
+ var imageTag = document.createElement("img");
+ imageTag.setAttribute("src", this.iconUrl);
+ href.appendChild(imageTag);
+ this.imageNode.appendChild(href);
+ }
+});
+
+}
diff --git a/includes/js/dojox/data/demos/widgets/PicasaViewList.js b/includes/js/dojox/data/demos/widgets/PicasaViewList.js
new file mode 100644
index 0000000..45371cd
--- /dev/null
+++ b/includes/js/dojox/data/demos/widgets/PicasaViewList.js
@@ -0,0 +1,37 @@
+if(!dojo._hasResource["dojox.data.demos.widgets.PicasaViewList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.demos.widgets.PicasaViewList"] = true;
+dojo.provide("dojox.data.demos.widgets.PicasaViewList");
+dojo.require("dijit._Templated");
+dojo.require("dijit._Widget");
+dojo.require("dojox.data.demos.widgets.PicasaView");
+
+dojo.declare("dojox.data.demos.widgets.PicasaViewList", [dijit._Widget, dijit._Templated], {
+ //Simple demo widget that is just a list of PicasaView Widgets.
+
+ templateString:"<div dojoAttachPoint=\"list\"></div>\n\n",
+
+ //Attach points for reference.
+ listNode: null,
+
+ postCreate: function(){
+ this.fViewWidgets = [];
+ },
+
+ clearList: function(){
+ while(this.list.firstChild){
+ this.list.removeChild(this.list.firstChild);
+ }
+ for(var i = 0; i < this.fViewWidgets.length; i++){
+ this.fViewWidgets[i].destroy();
+ }
+ this.fViewWidgets = [];
+ },
+
+ addView: function(viewData){
+ var newView = new dojox.data.demos.widgets.PicasaView(viewData);
+ this.fViewWidgets.push(newView);
+ this.list.appendChild(newView.domNode);
+ }
+});
+
+}
diff --git a/includes/js/dojox/data/demos/widgets/templates/FlickrView.html b/includes/js/dojox/data/demos/widgets/templates/FlickrView.html
new file mode 100644
index 0000000..b9d3bf9
--- /dev/null
+++ b/includes/js/dojox/data/demos/widgets/templates/FlickrView.html
@@ -0,0 +1,34 @@
+<table class="flickrView">
+ <tbody>
+ <tr class="flickrTitle">
+ <td>
+ <b>
+ Title:
+ </b>
+ </td>
+ <td dojoAttachPoint="titleNode">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>
+ Author:
+ </b>
+ </td>
+ <td dojoAttachPoint="authorNode">
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <b>
+ Image:
+ </b>
+ </td>
+ </tr>
+ <tr>
+ <td dojoAttachPoint="imageNode" colspan="2">
+ </td>
+ </tr>
+ </tbody>
+</table>
+
diff --git a/includes/js/dojox/data/demos/widgets/templates/FlickrViewList.html b/includes/js/dojox/data/demos/widgets/templates/FlickrViewList.html
new file mode 100644
index 0000000..3a9f565
--- /dev/null
+++ b/includes/js/dojox/data/demos/widgets/templates/FlickrViewList.html
@@ -0,0 +1,2 @@
+<div dojoAttachPoint="list"></div>
+
diff --git a/includes/js/dojox/data/demos/widgets/templates/PicasaView.html b/includes/js/dojox/data/demos/widgets/templates/PicasaView.html
new file mode 100644
index 0000000..88dbb31
--- /dev/null
+++ b/includes/js/dojox/data/demos/widgets/templates/PicasaView.html
@@ -0,0 +1,35 @@
+<table class="picasaView">
+ <tbody>
+ <tr class="picasaTitle">
+ <td>
+ <b>
+ Title:
+ </b>
+ </td>
+ <td dojoAttachPoint="titleNode">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>
+ Author:
+ </b>
+ </td>
+ <td dojoAttachPoint="authorNode">
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <b>
+ Summary:
+ </b>
+ <span class="picasaSummary" dojoAttachPoint="descriptionNode"></span>
+ </td>
+ </tr>
+ <tr>
+ <td dojoAttachPoint="imageNode" colspan="2">
+ </td>
+ </tr>
+ </tbody>
+</table>
+
diff --git a/includes/js/dojox/data/demos/widgets/templates/PicasaViewList.html b/includes/js/dojox/data/demos/widgets/templates/PicasaViewList.html
new file mode 100644
index 0000000..3a9f565
--- /dev/null
+++ b/includes/js/dojox/data/demos/widgets/templates/PicasaViewList.html
@@ -0,0 +1,2 @@
+<div dojoAttachPoint="list"></div>
+
diff --git a/includes/js/dojox/data/dom.js b/includes/js/dojox/data/dom.js
new file mode 100644
index 0000000..8911bc3
--- /dev/null
+++ b/includes/js/dojox/data/dom.js
@@ -0,0 +1,187 @@
+if(!dojo._hasResource["dojox.data.dom"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.dom"] = true;
+dojo.provide("dojox.data.dom");
+
+//DOM type to int value for reference.
+//Ints make for more compact code than full constant names.
+//ELEMENT_NODE = 1;
+//ATTRIBUTE_NODE = 2;
+//TEXT_NODE = 3;
+//CDATA_SECTION_NODE = 4;
+//ENTITY_REFERENCE_NODE = 5;
+//ENTITY_NODE = 6;
+//PROCESSING_INSTRUCTION_NODE = 7;
+//COMMENT_NODE = 8;
+//DOCUMENT_NODE = 9;
+//DOCUMENT_TYPE_NODE = 10;
+//DOCUMENT_FRAGMENT_NODE = 11;
+//NOTATION_NODE = 12;
+
+//FIXME: Remove this file when possible.
+//This file contains internal/helper APIs as holders until the true DOM apis of Dojo 0.9 are finalized.
+//Therefore, these should not be generally used, they are present only for the use by XmlStore and the
+//wires project until proper dojo replacements are available. When such exist, XmlStore and the like
+//will be ported off these and this file will be deleted.
+dojo.experimental("dojox.data.dom");
+
+dojox.data.dom.createDocument = function(/*string?*/ str, /*string?*/ mimetype){
+ // summary:
+ // cross-browser implementation of creating an XML document object.
+ //
+ // str:
+ // Optional text to create the document from. If not provided, an empty XML document will be created.
+ // mimetype:
+ // Optional mimetype of the text. Typically, this is text/xml. Will be defaulted to text/xml if not provided.
+ var _document = dojo.doc;
+
+ if(!mimetype){ mimetype = "text/xml"; }
+ if(str && (typeof dojo.global["DOMParser"]) !== "undefined"){
+ var parser = new DOMParser();
+ return parser.parseFromString(str, mimetype); // DOMDocument
+ }else if((typeof dojo.global["ActiveXObject"]) !== "undefined"){
+ var prefixes = [ "MSXML2", "Microsoft", "MSXML", "MSXML3" ];
+ for(var i = 0; i<prefixes.length; i++){
+ try{
+ var doc = new ActiveXObject(prefixes[i]+".XMLDOM");
+ if(str){
+ if(doc){
+ doc.async = false;
+ doc.loadXML(str);
+ return doc; // DOMDocument
+ }else{
+ console.log("loadXML didn't work?");
+ }
+ }else{
+ if(doc){
+ return doc; //DOMDocument
+ }
+ }
+ }catch(e){ /* squelch */ };
+ }
+ }else if((_document.implementation)&&
+ (_document.implementation.createDocument)){
+ if(str){
+ if(_document.createElement){
+ // FIXME: this may change all tags to uppercase!
+ var tmp = _document.createElement("xml");
+ tmp.innerHTML = str;
+ var xmlDoc = _document.implementation.createDocument("foo", "", null);
+ for(var i = 0; i < tmp.childNodes.length; i++) {
+ xmlDoc.importNode(tmp.childNodes.item(i), true);
+ }
+ return xmlDoc; // DOMDocument
+ }
+ }else{
+ return _document.implementation.createDocument("", "", null); // DOMDocument
+ }
+ }
+ return null; // DOMDocument
+}
+
+dojox.data.dom.textContent = function(/*Node*/node, /*string?*/text){
+ // summary:
+ // Implementation of the DOM Level 3 attribute; scan node for text
+ // description:
+ // Implementation of the DOM Level 3 attribute; scan node for text
+ // This function can also update the text of a node by replacing all child
+ // content of the node.
+ // node:
+ // The node to get the text off of or set the text on.
+ // text:
+ // Optional argument of the text to apply to the node.
+ if(arguments.length>1){
+ var _document = node.ownerDocument || dojo.doc; //Preference is to get the node owning doc first or it may fail
+ dojox.data.dom.replaceChildren(node, _document.createTextNode(text));
+ return text; // string
+ } else {
+ if(node.textContent !== undefined){ //FF 1.5
+ return node.textContent; // string
+ }
+ var _result = "";
+ if(node == null){
+ return _result; //empty string.
+ }
+ for(var i = 0; i < node.childNodes.length; i++){
+ switch(node.childNodes[i].nodeType){
+ case 1: // ELEMENT_NODE
+ case 5: // ENTITY_REFERENCE_NODE
+ _result += dojox.data.dom.textContent(node.childNodes[i]);
+ break;
+ case 3: // TEXT_NODE
+ case 2: // ATTRIBUTE_NODE
+ case 4: // CDATA_SECTION_NODE
+ _result += node.childNodes[i].nodeValue;
+ break;
+ default:
+ break;
+ }
+ }
+ return _result; // string
+ }
+}
+
+dojox.data.dom.replaceChildren = function(/*Element*/node, /*Node || array*/ newChildren){
+ // summary:
+ // Removes all children of node and appends newChild. All the existing
+ // children will be destroyed.
+ // description:
+ // Removes all children of node and appends newChild. All the existing
+ // children will be destroyed.
+ // node:
+ // The node to modify the children on
+ // newChildren:
+ // The children to add to the node. It can either be a single Node or an
+ // array of Nodes.
+ var nodes = [];
+
+ if(dojo.isIE){
+ for(var i=0;i<node.childNodes.length;i++){
+ nodes.push(node.childNodes[i]);
+ }
+ }
+
+ dojox.data.dom.removeChildren(node);
+ for(var i=0;i<nodes.length;i++){
+ dojo._destroyElement(nodes[i]);
+ }
+
+ if(!dojo.isArray(newChildren)){
+ node.appendChild(newChildren);
+ }else{
+ for(var i=0;i<newChildren.length;i++){
+ node.appendChild(newChildren[i]);
+ }
+ }
+}
+
+dojox.data.dom.removeChildren = function(/*Element*/node){
+ // summary:
+ // removes all children from node and returns the count of children removed.
+ // The children nodes are not destroyed. Be sure to call dojo._destroyElement on them
+ // after they are not used anymore.
+ // node:
+ // The node to remove all the children from.
+ var count = node.childNodes.length;
+ while(node.hasChildNodes()){
+ node.removeChild(node.firstChild);
+ }
+ return count; // int
+}
+
+
+dojox.data.dom.innerXML = function(/*Node*/node){
+ // summary:
+ // Implementation of MS's innerXML function.
+ // node:
+ // The node from which to generate the XML text representation.
+ if(node.innerXML){
+ return node.innerXML; // string
+ }else if (node.xml){
+ return node.xml; // string
+ }else if(typeof XMLSerializer != "undefined"){
+ return (new XMLSerializer()).serializeToString(node); // string
+ }
+}
+
+
+}
diff --git a/includes/js/dojox/data/jsonPathStore.js b/includes/js/dojox/data/jsonPathStore.js
new file mode 100644
index 0000000..01e4e23
--- /dev/null
+++ b/includes/js/dojox/data/jsonPathStore.js
@@ -0,0 +1,1191 @@
+if(!dojo._hasResource["dojox.data.jsonPathStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.jsonPathStore"] = true;
+dojo.provide("dojox.data.jsonPathStore");
+dojo.require("dojox.jsonPath");
+dojo.require("dojo.date");
+dojo.require("dojo.date.locale");
+dojo.require("dojo.date.stamp");
+
+dojox.data.ASYNC_MODE = 0;
+dojox.data.SYNC_MODE = 1;
+
+dojo.declare("dojox.data.jsonPathStore",
+ null,
+ {
+ mode: dojox.data.ASYNC_MODE,
+ metaLabel: "_meta",
+ hideMetaAttributes: false,
+ autoIdPrefix: "_auto_",
+ autoIdentity: true,
+ idAttribute: "_id",
+ indexOnLoad: true,
+ labelAttribute: "",
+ url: "",
+ _replaceRegex: /\'\]/gi,
+
+ constructor: function(options){
+ //summary:
+ // jsonPathStore constructor, instantiate a new jsonPathStore
+ //
+ // Takes a single optional parameter in the form of a Javascript object
+ // containing one or more of the following properties.
+ //
+ // data: /*JSON String*/ || /* Javascript Object */,
+ // JSON String or Javascript object this store will control
+ // JSON is converted into an object, and an object passed to
+ // the store will be used directly. If no data and no url
+ // is provide, an empty object, {}, will be used as the initial
+ // store.
+ //
+ // url: /* string url */
+ // Load data from this url in JSON format and use the Object
+ // created from the data as the data source.
+ //
+ // indexOnLoad: /* boolean */
+ // Defaults to true, but this may change in the near future.
+ // Parse the data object and set individual objects up as
+ // appropriate. This will add meta data and assign
+ // id's to objects that dont' have them as defined by the
+ // idAttribute option. Disabling this option will keep this
+ // parsing from happening until a query is performed at which
+ // time only the top level of an item has meta info stored.
+ // This might work in some situations, but you will almost
+ // always want to indexOnLoad or use another option which
+ // will create an index. In the future we will support a
+ // generated index that maps by jsonPath allowing the
+ // server to take some of this load for larger data sets.
+ //
+ // idAttribute: /* string */
+ // Defaults to '_id'. The name of the attribute that holds an objects id.
+ // This can be a preexisting id provided by the server.
+ // If an ID isn't already provided when an object
+ // is fetched or added to the store, the autoIdentity system
+ // will generate an id for it and add it to the index. There
+ // are utility routines for exporting data from the store
+ // that can clean any generated IDs before exporting and leave
+ // preexisting id's in tact.
+ //
+ // metaLabel: /* string */
+ // Defaults to '_meta' overrides the attribute name that is used by the store
+ // for attaching meta information to an object while
+ // in the store's control. Defaults to '_meta'.
+ //
+ // hideMetaAttributes: /* boolean */
+ // Defaults to False. When enabled, calls to getAttributes() will not
+ // include the meta attribute.
+ //
+ // autoIdPrefix: /*string*/
+ // Defaults to "_auto_". This string is used as the prefix to any
+ // objects which have a generated id. A numeric index is appended
+ // to this string to complete the ID
+ //
+ // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE
+ // Defaults to ASYNC_MODE. This option sets the default mode for this store.
+ // Sync calls return their data immediately from the calling function
+ // instead of calling the callback functions. Functions such as
+ // fetchItemByIdentity() and fetch() both accept a string parameter in addtion
+ // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will
+ // automatically be used even when the default mode of the system is ASYNC_MODE.
+ // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also
+ // include a mode property to override this setting for that one request.
+
+ //setup a byId alias to the api call
+ this.byId=this.fetchItemByIdentity;
+
+ if (options){
+ dojo.mixin(this,options);
+ }
+
+ this._dirtyItems=[];
+ this._autoId=0;
+ this._referenceId=0;
+ this._references={};
+ this._fetchQueue=[];
+ this.index={};
+
+ //regex to identify when we're travelling down metaObject (which we don't want to do)
+ var expr="("+this.metaLabel+"\'\])";
+ this.metaRegex = new RegExp(expr);
+
+
+ //no data or url, start with an empty object for a store
+ if (!this.data && !this.url){
+ this.setData({});
+ }
+
+ //we have data, but no url, set the store as the data
+ if (this.data && !this.url){
+ this.setData(this.data);
+
+ //remove the original refernce, we're now using _data from here on out
+ delete this.data;
+ }
+
+ //given a url, load json data from as the store
+ if (this.url){
+ dojo.xhrGet({
+ url: options.url,
+ handleAs: "json",
+ load: dojo.hitch(this, "setData"),
+ sync: this.mode
+ });
+ }
+ },
+
+ _loadData: function(data){
+ // summary:
+ // load data into the store. Index it if appropriate.
+ if (this._data){
+ delete this._data;
+ }
+
+ if (dojo.isString(data)){
+ this._data = dojo.fromJson(data);
+ }else{
+ this._data = data;
+ }
+
+ if (this.indexOnLoad){
+ this.buildIndex();
+ }
+
+ this._updateMeta(this._data, {path: "$"});
+
+ this.onLoadData(this._data);
+ },
+
+ onLoadData: function(data){
+ // summary
+ // Called after data has been loaded in the store.
+ // If any requests happened while the startup is happening
+ // then process them now.
+
+ while (this._fetchQueue.length>0){
+ var req = this._fetchQueue.shift();
+ this.fetch(req);
+ }
+
+ },
+
+ setData: function(data){
+ // summary:
+ // set the stores' data to the supplied object and then
+ // load and/or setup that data with the required meta info
+ this._loadData(data);
+ },
+
+ buildIndex: function(path, item){
+ //summary:
+ // parse the object structure, and turn any objects into
+ // jsonPathStore items. Basically this just does a recursive
+ // series of fetches which itself already examines any items
+ // as they are retrieved and setups up the required meta information.
+ //
+ // path: /* string */
+ // jsonPath Query for the starting point of this index construction.
+
+ if (!this.idAttribute){
+ throw new Error("buildIndex requires idAttribute for the store");
+ }
+
+ item = item || this._data;
+ var origPath = path;
+ path = path||"$";
+ path += "[*]";
+ var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE});
+ for(var i=0; i<data.length;i++){
+ if(dojo.isObject(data[i])){
+ var newPath = data[i][this.metaLabel]["path"];
+ if (origPath){
+ //console.log("newPath: ", newPath);
+ //console.log("origPath: ", origPath);
+ //console.log("path: ", path);
+ //console.log("data[i]: ", data[i]);
+ var parts = origPath.split("\[\'");
+ var attribute = parts[parts.length-1].replace(this._replaceRegex,'');
+ //console.log("attribute: ", attribute);
+ //console.log("ParentItem: ", item, attribute);
+ if (!dojo.isArray(data[i])){
+ this._addReference(data[i], {parent: item, attribute:attribute});
+ this.buildIndex(newPath, data[i]);
+ }else{
+ this.buildIndex(newPath,item);
+ }
+ }else{
+ var parts = newPath.split("\[\'");
+ var attribute = parts[parts.length-1].replace(this._replaceRegex,'');
+ this._addReference(data[i], {parent: this._data, attribute:attribute});
+ this.buildIndex(newPath, data[i]);
+ }
+ }
+ }
+ },
+
+ _correctReference: function(item){
+ // summary:
+ // make sure we have an reference to the item in the store
+ // and not a clone. Takes an item, matches it to the corresponding
+ // item in the store and if it is the same, returns itself, otherwise
+ // it returns the item from the store.
+
+ if (this.index[item[this.idAttribute]][this.metaLabel]===item[this.metaLabel]){
+ return this.index[item[this.idAttribute]];
+ }
+ return item;
+ },
+
+ getValue: function(item, property){
+ // summary:
+ // Gets the value of an item's 'property'
+ //
+ // item: /* object */
+ // property: /* string */
+ // property to look up value for
+ item = this._correctReference(item);
+ return item[property];
+ },
+
+ getValues: function(item, property){
+ // summary:
+ // Gets the value of an item's 'property' and returns
+ // it. If this value is an array it is just returned,
+ // if not, the value is added to an array and that is returned.
+ //
+ // item: /* object */
+ // property: /* string */
+ // property to look up value for
+
+ item = this._correctReference(item);
+ return dojo.isArray(item[property]) ? item[property] : [item[property]];
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // Gets the available attributes of an item's 'property' and returns
+ // it as an array. If the store has 'hideMetaAttributes' set to true
+ // the attributed identified by 'metaLabel' will not be included.
+ //
+ // item: /* object */
+
+ item = this._correctReference(item);
+ var res = [];
+ for (var i in item){
+ if (this.hideMetaAttributes && (i==this.metaLabel)){continue;}
+ res.push(i);
+ }
+ return res;
+ },
+
+ hasAttribute: function(item,attribute){
+ // summary:
+ // Checks to see if item has attribute
+ //
+ // item: /* object */
+ // attribute: /* string */
+
+ item = this._correctReference(item);
+ if (attribute in item){return true;}
+ return false;
+ },
+
+ containsValue: function(item, attribute, value){
+ // summary:
+ // Checks to see if 'item' has 'value' at 'attribute'
+ //
+ // item: /* object */
+ // attribute: /* string */
+ // value: /* anything */
+ item = this._correctReference(item);
+
+ if (item[attribute] && item[attribute]==value){return true}
+ if (dojo.isObject(item[attribute]) || dojo.isObject(value)){
+ if (this._shallowCompare(item[attribute],value)){return true}
+ }
+ return false;
+ },
+
+ _shallowCompare: function(a, b){
+ //summary does a simple/shallow compare of properties on an object
+ //to the same named properties on the given item. Returns
+ //true if all props match. It will not descend into child objects
+ //but it will compare child date objects
+
+ if ((dojo.isObject(a) && !dojo.isObject(b))|| (dojo.isObject(b) && !dojo.isObject(a))) {
+ return false;
+ }
+
+ if ( a["getFullYear"] || b["getFullYear"] ){
+ //confirm that both are dates
+ if ( (a["getFullYear"] && !b["getFullYear"]) || (b["getFullYear"] && !a["getFullYear"]) ){
+ return false;
+ }else{
+ if (!dojo.date.compare(a,b)){
+ return true;
+ }
+ return false;
+ }
+ }
+
+ for (var i in b){
+ if (dojo.isObject(b[i])){
+ if (!a[i] || !dojo.isObject(a[i])){return false}
+
+ if (b[i]["getFullYear"]){
+ if(!a[i]["getFullYear"]){return false}
+ if (dojo.date.compare(a,b)){return false}
+ }else{
+ if (!this._shallowCompare(a[i],b[i])){return false}
+ }
+ }else{
+ if (!b[i] || (a[i]!=b[i])){return false}
+ }
+ }
+
+ //make sure there werent props on a that aren't on b, if there aren't, then
+ //the previous section will have already evaluated things.
+
+ for (var i in a){
+ if (!b[i]){return false}
+ }
+
+ return true;
+ },
+
+ isItem: function(item){
+ // summary:
+ // Checks to see if a passed 'item'
+ // is really a jsonPathStore item. Currently
+ // it only verifies structure. It does not verify
+ // that it belongs to this store at this time.
+ //
+ // item: /* object */
+ // attribute: /* string */
+
+ if (!dojo.isObject(item) || !item[this.metaLabel]){return false}
+ if (this.requireId && this._hasId && !item[this._id]){return false}
+ return true;
+ },
+
+ isItemLoaded: function(item){
+ // summary:
+ // returns isItem() :)
+ //
+ // item: /* object */
+
+ item = this._correctReference(item);
+ return this.isItem(item);
+ },
+
+ loadItem: function(item){
+ // summary:
+ // returns true. Future implementatins might alter this
+ return true;
+ },
+
+ _updateMeta: function(item, props){
+ // summary:
+ // verifies that 'item' has a meta object attached
+ // and if not it creates it by setting it to 'props'
+ // if the meta attribute already exists, mix 'props'
+ // into it.
+
+ if (item && item[this.metaLabel]){
+ dojo.mixin(item[this.metaLabel], props);
+ return;
+ }
+
+ item[this.metaLabel]=props;
+ },
+
+ cleanMeta: function(data, options){
+ // summary
+ // Recurses through 'data' and removes an
+ // meta information that has been attached. This
+ // function will also removes any id's that were autogenerated
+ // from objects. It will not touch id's that were not generated
+
+ data = data || this._data;
+
+ if (data[this.metaLabel]){
+ if(data[this.metaLabel]["autoId"]){
+ delete data[this.idAttribute];
+ }
+ delete data[this.metaLabel];
+ }
+
+ if (dojo.isArray(data)){
+ for(var i=0; i<data.length;i++){
+ if(dojo.isObject(data[i]) || dojo.isArray(data[i]) ){
+ this.cleanMeta(data[i]);
+ }
+ }
+ } else if (dojo.isObject(data)){
+ for (var i in data){
+ this.cleanMeta(data[i]);
+ }
+ }
+ },
+
+ fetch: function(args){
+ //console.log("fetch() ", args);
+ // summary
+ //
+ // fetch takes either a string argument or a keywordArgs
+ // object containing the parameters for the search.
+ // If passed a string, fetch will interpret this string
+ // as the query to be performed and will do so in
+ // SYNC_MODE returning the results immediately.
+ // If an object is supplied as 'args', its options will be
+ // parsed and then contained query executed.
+ //
+ // query: /* string or object */
+ // Defaults to "$..*". jsonPath query to be performed
+ // on data store. **note that since some widgets
+ // expect this to be an object, an object in the form
+ // of {query: '$[*'], queryOptions: "someOptions"} is
+ // acceptable
+ //
+ // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE
+ // Override the stores default mode.
+ //
+ // queryOptions: /* object */
+ // Options passed on to the underlying jsonPath query
+ // system.
+ //
+ // start: /* int */
+ // Starting item in result set
+ //
+ // count: /* int */
+ // Maximum number of items to return
+ //
+ // sort: /* function */
+ // Not Implemented yet
+ //
+ // The following only apply to ASYNC requests (the default)
+ //
+ // onBegin: /* function */
+ // called before any results are returned. Parameters
+ // will be the count and the original fetch request
+ //
+ // onItem: /*function*/
+ // called for each returned item. Parameters will be
+ // the item and the fetch request
+ //
+ // onComplete: /* function */
+ // called on completion of the request. Parameters will
+ // be the complete result set and the request
+ //
+ // onError: /* function */
+ // colled in the event of an error
+
+ // we're not started yet, add this request to a queue and wait till we do
+ if (!this._data){
+ this._fetchQueue.push(args);
+ return args;
+ }
+ if(dojo.isString(args)){
+ query = args;
+ args={query: query, mode: dojox.data.SYNC_MODE};
+
+ }
+
+ var query;
+ if (!args || !args.query){
+ if (!args){
+ var args={};
+ }
+
+ if (!args.query){
+ args.query="$..*";
+ query=args.query;
+ }
+
+ }
+
+ if (dojo.isObject(args.query)){
+ if (args.query.query){
+ query = args.query.query;
+ }else{
+ query = args.query = "$..*";
+ }
+ if (args.query.queryOptions){
+ args.queryOptions=args.query.queryOptions
+ }
+ }else{
+ query=args.query;
+ }
+
+ if (!args.mode) {args.mode = this.mode;}
+ if (!args.queryOptions) {args.queryOptions={};}
+
+ args.queryOptions.resultType='BOTH';
+ var results = dojox.jsonPath.query(this._data, query, args.queryOptions);
+ var tmp=[];
+ var count=0;
+ for (var i=0; i<results.length; i++){
+ if(args.start && i<args.start){continue;}
+ if (args.count && (count >= args.count)) { continue; }
+
+ var item = results[i]["value"];
+ var path = results[i]["path"];
+ if (!dojo.isObject(item)){continue;}
+ if(this.metaRegex.exec(path)){continue;}
+
+ //this automatically records the objects path
+ this._updateMeta(item,{path: results[i].path});
+
+ //if autoIdentity and no id, generate one and add it to the item
+ if(this.autoIdentity && !item[this.idAttribute]){
+ var newId = this.autoIdPrefix + this._autoId++;
+ item[this.idAttribute]=newId;
+ item[this.metaLabel]["autoId"]=true;
+ }
+
+ //add item to the item index if appropriate
+ if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item}
+ count++;
+ tmp.push(item);
+ }
+ results = tmp;
+ var scope = args.scope || dojo.global;
+
+ if ("sort" in args){
+ console.log("TODO::add support for sorting in the fetch");
+ }
+
+ if (args.mode==dojox.data.SYNC_MODE){
+ return results;
+ };
+
+ if (args.onBegin){
+ args["onBegin"].call(scope, results.length, args);
+ }
+
+ if (args.onItem){
+ for (var i=0; i<results.length;i++){
+ args["onItem"].call(scope, results[i], args);
+ }
+ }
+
+ if (args.onComplete){
+ args["onComplete"].call(scope, results, args);
+ }
+
+ return args;
+ },
+
+ dump: function(options){
+ // summary:
+ //
+ // exports the store data set. Takes an options
+ // object with a number of parameters
+ //
+ // data: /* object */
+ // Defaults to the root of the store.
+ // The data to be exported.
+ //
+ // clone: /* boolean */
+ // clone the data set before returning it
+ // or modifying it for export
+ //
+ // cleanMeta: /* boolean */
+ // clean the meta data off of the data. Note
+ // that this will happen to the actual
+ // store data if !clone. If you want
+ // to continue using the store after
+ // this operation, it is probably better to export
+ // it as a clone if you want it cleaned.
+ //
+ // suppressExportMeta: /* boolean */
+ // By default, when data is exported from the store
+ // some information, such as as a timestamp, is
+ // added to the root of exported data. This
+ // prevents that from happening. It is mainly used
+ // for making tests easier.
+ //
+ // type: "raw" || "json"
+ // Defaults to 'json'. 'json' will convert the data into
+ // json before returning it. 'raw' will just return a
+ // reference to the object
+
+ var options = options || {};
+ var d=options.data || this._data;
+
+ if (!options.suppressExportMeta && options.clone){
+ data = dojo.clone(d);
+ if (data[this.metaLabel]){
+ data[this.metaLabel]["clone"]=true;
+ }
+ }else{
+ var data=d;
+ }
+
+ if (!options.suppressExportMeta && data[this.metaLabel]){
+ data[this.metaLabel]["last_export"]=new Date().toString()
+ }
+
+ if(options.cleanMeta){
+ this.cleanMeta(data);
+ }
+
+ //console.log("Exporting: ", options, dojo.toJson(data));
+ switch(options.type){
+ case "raw":
+ return data;
+ case "json":
+ default:
+ return dojo.toJson(data);
+ }
+ },
+
+ getFeatures: function(){
+ // summary:
+ // return the store feature set
+
+ return {
+ "dojo.data.api.Read": true,
+ "dojo.data.api.Identity": true,
+ "dojo.data.api.Write": true,
+ "dojo.data.api.Notification": true
+ }
+ },
+
+ getLabel: function(item){
+ // summary
+ // returns the label for an item. The label
+ // is created by setting the store's labelAttribute
+ // property with either an attribute name or an array
+ // of attribute names. Developers can also
+ // provide the store with a createLabel function which
+ // will do the actaul work of creating the label. If not
+ // the default will just concatenate any of the identified
+ // attributes together.
+ item = this._correctReference(item);
+ var label="";
+
+ if (dojo.isFunction(this.createLabel)){
+ return this.createLabel(item);
+ }
+
+ if (this.labelAttribute){
+ if (dojo.isArray(this.labelAttribute)) {
+ for(var i=0; i<this.labelAttribute.length; i++){
+ if (i>0) { label+=" ";}
+ label += item[this.labelAttribute[i]];
+ }
+ return label;
+ }else{
+ return item[this.labelAttribute];
+ }
+ }
+ return item.toString();
+ },
+
+ getLabelAttributes: function(item){
+ // summary:
+ // returns an array of attributes that are used to create the label of an item
+ item = this._correctReference(item);
+ return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute];
+ },
+
+ sort: function(a,b){
+ console.log("TODO::implement default sort algo");
+ },
+
+ //Identity API Support
+
+ getIdentity: function(item){
+ // summary
+ // returns the identity of an item or throws
+ // a not found error.
+
+ if (this.isItem(item)){
+ return item[this.idAttribute];
+ }
+ throw new Error("Id not found for item");
+ },
+
+ getIdentityAttributes: function(item){
+ // summary:
+ // returns the attributes which are used to make up the
+ // identity of an item. Basically returns this.idAttribute
+
+ return [this.idAttribute];
+ },
+
+ fetchItemByIdentity: function(args){
+ // summary:
+ // fetch an item by its identity. This store also provides
+ // a much more finger friendly alias, 'byId' which does the
+ // same thing as this function. If provided a string
+ // this call will be treated as a SYNC request and will
+ // return the identified item immediatly. Alternatively it
+ // takes a object as a set of keywordArgs:
+ //
+ // identity: /* string */
+ // the id of the item you want to retrieve
+ //
+ // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE
+ // overrides the default store fetch mode
+ //
+ // onItem: /* function */
+ // Result call back. Passed the fetched item.
+ //
+ // onError: /* function */
+ // error callback.
+ var id;
+ if (dojo.isString(args)){
+ id = args;
+ args = {identity: id, mode: dojox.data.SYNC_MODE}
+ }else{
+ if (args){
+ id = args["identity"];
+ }
+ if (!args.mode){args.mode = this.mode}
+ }
+
+ if (this.index && (this.index[id] || this.index["identity"])){
+
+ if (args.mode==dojox.data.SYNC_MODE){
+ return this.index[id];
+ }
+
+ if (args.onItem){
+ args["onItem"].call(args.scope || dojo.global, this.index[id], args);
+ }
+
+ return args;
+ }else{
+ if (args.mode==dojox.data.SYNC_MODE){
+ return false;
+ }
+ }
+
+
+ if(args.onError){
+ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args);
+ }
+
+ return args;
+ },
+
+ //Write API Support
+ newItem: function(data, options){
+ // summary:
+ // adds a new item to the store at the specified point.
+ // Takes two parameters, data, and options.
+ //
+ // data: /* object */
+ // The data to be added in as an item. This could be a
+ // new javascript object, or it could be an item that
+ // already exists in the store. If it already exists in the
+ // store, then this will be added as a reference.
+ //
+ // options: /* object */
+ //
+ // item: /* item */
+ // reference to an existing store item
+ //
+ // attribute: /* string */
+ // attribute to add the item at. If this is
+ // not provided, the item's id will be used as the
+ // attribute name. If specified attribute is an
+ // array, the new item will be push()d on to the
+ // end of it.
+ // oldValue: /* old value of item[attribute]
+ // newValue: new value item[attribute]
+
+ var meta={};
+
+ //default parent to the store root;
+ var pInfo ={item:this._data};
+
+ if (options){
+ if (options.parent){
+ options.item = options.parent;
+ }
+
+ dojo.mixin(pInfo, options);
+ }
+
+ if (this.idAttribute && !data[this.idAttribute]){
+ if (this.requireId){throw new Error("requireId is enabled, new items must have an id defined to be added");}
+ if (this.autoIdentity){
+ var newId = this.autoIdPrefix + this._autoId++;
+ data[this.idAttribute]=newId;
+ meta["autoId"]=true;
+ }
+ }
+
+ if (!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){
+ throw new Error("Adding a new item requires, at a minumum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute");
+ }
+
+ //pInfo.parent = this._correctReference(pInfo.parent);
+ //if there is no parent info supplied, default to the store root
+ //and add to the pInfo.attribute or if that doestn' exist create an
+ //attribute with the same name as the new items ID
+ if(!pInfo.attribute){pInfo.attribute = data[this.idAttribute]}
+
+ pInfo.oldValue = this._trimItem(pInfo.item[pInfo.attribute]);
+ if (dojo.isArray(pInfo.item[pInfo.attribute])){
+ this._setDirty(pInfo.item);
+ pInfo.item[pInfo.attribute].push(data);
+ }else{
+ this._setDirty(pInfo.item);
+ pInfo.item[pInfo.attribute]=data;
+ }
+
+ pInfo.newValue = pInfo.item[pInfo.attribute];
+
+ //add this item to the index
+ if(data[this.idAttribute]){this.index[data[this.idAttribute]]=data}
+
+ this._updateMeta(data, meta)
+
+ //keep track of all references in the store so we can delete them as necessary
+ this._addReference(data, pInfo);
+
+ //mark this new item as dirty
+ this._setDirty(data);
+
+ //Notification API
+ this.onNew(data, pInfo);
+
+ //returns the original item, now decorated with some meta info
+ return data;
+ },
+
+ _addReference: function(item, pInfo){
+ // summary
+ // adds meta information to an item containing a reference id
+ // so that references can be deleted as necessary, when passed
+ // only a string, the string for parent info, it will only
+ // it will be treated as a string reference
+
+ //console.log("_addReference: ", item, pInfo);
+ var rid = '_ref_' + this._referenceId++;
+ if (!item[this.metaLabel]["referenceIds"]){
+ item[this.metaLabel]["referenceIds"]=[];
+ }
+
+ item[this.metaLabel]["referenceIds"].push(rid);
+ this._references[rid] = pInfo;
+ },
+
+ deleteItem: function(item){
+ // summary
+ // deletes item and any references to that item from the store.
+ // If the desire is to delete only one reference, unsetAttribute or
+ // setValue is the way to go.
+
+ item = this._correctReference(item);
+ console.log("Item: ", item);
+ if (this.isItem(item)){
+ while(item[this.metaLabel]["referenceIds"].length>0){
+ console.log("refs map: " , this._references);
+ console.log("item to delete: ", item);
+ var rid = item[this.metaLabel]["referenceIds"].pop();
+ var pInfo = this._references[rid];
+
+ console.log("deleteItem(): ", pInfo, pInfo.parent);
+ parentItem = pInfo.parent;
+ var attribute = pInfo.attribute;
+ if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){
+ this._setDirty(parentItem);
+ this.unsetAttribute(parentItem, attribute);
+ delete parentItem[attribute];
+ }
+
+ if (dojo.isArray(parentItem[attribute])){
+ console.log("Parent is array");
+ var oldValue = this._trimItem(parentItem[attribute]);
+ var found=false;
+ for (var i=0; i<parentItem[attribute].length && !found;i++){
+ if (parentItem[attribute][i][this.metaLabel]===item[this.metaLabel]){
+ found=true;
+ }
+ }
+
+ if (found){
+ this._setDirty(parentItem);
+ var del = parentItem[attribute].splice(i-1,1);
+ delete del;
+ }
+
+ var newValue = this._trimItem(parentItem[attribute]);
+ this.onSet(parentItem,attribute,oldValue,newValue);
+ }
+ delete this._references[rid];
+
+ }
+ this.onDelete(item);
+ delete item;
+ }
+ },
+
+ _setDirty: function(item){
+ // summary:
+ // adds an item to the list of dirty items. This item
+ // contains a reference to the item itself as well as a
+ // cloned and trimmed version of old item for use with
+ // revert.
+
+ //if an item is already in the list of dirty items, don't add it again
+ //or it will overwrite the premodification data set.
+ for (var i=0; i<this._dirtyItems.length; i++){
+ if (item[this.idAttribute]==this._dirtyItems[i][this.idAttribute]){
+ return;
+ }
+ }
+
+ this._dirtyItems.push({item: item, old: this._trimItem(item)});
+ this._updateMeta(item, {isDirty: true});
+ },
+
+ setValue: function(item, attribute, value){
+ // summary:
+ // sets 'attribute' on 'item' to 'value'
+ item = this._correctReference(item);
+
+ this._setDirty(item);
+ var old = item[attribute] | undefined;
+ item[attribute]=value;
+ this.onSet(item,attribute,old,value);
+
+ },
+
+ setValues: function(item, attribute, values){
+ // summary:
+ // sets 'attribute' on 'item' to 'value' value
+ // must be an array.
+
+
+ item = this._correctReference(item);
+ if (!dojo.isArray(values)){throw new Error("setValues expects to be passed an Array object as its value");}
+ this._setDirty(item);
+ var old = item[attribute] || null;
+ item[attribute]=values
+ this.onSet(item,attribute,old,values);
+ },
+
+ unsetAttribute: function(item, attribute){
+ // summary:
+ // unsets 'attribute' on 'item'
+
+ item = this._correctReference(item);
+ this._setDirty(item);
+ var old = item[attribute];
+ delete item[attribute];
+ this.onSet(item,attribute,old,null);
+ },
+
+ save: function(kwArgs){
+ // summary:
+ // Takes an optional set of keyword Args with
+ // some save options. Currently only format with options
+ // being "raw" or "json". This function goes through
+ // the dirty item lists, clones and trims the item down so that
+ // the items children are not part of the data (the children are replaced
+ // with reference objects). This data is compiled into a single array, the dirty objects
+ // are all marked as clean, and the new data is then passed on to the onSave handler.
+
+ var data = [];
+
+ if (!kwArgs){kwArgs={}}
+ while (this._dirtyItems.length > 0){
+ var item = this._dirtyItems.pop()["item"];
+ var t = this._trimItem(item);
+ var d;
+ switch(kwArgs.format){
+ case "json":
+ d = dojo.toJson(t);
+ break;
+ case "raw":
+ default:
+ d = t;
+ }
+ data.push(d);
+ this._markClean(item);
+ }
+
+ this.onSave(data);
+ },
+
+ _markClean: function(item){
+ // summary
+ // remove this meta information marking an item as "dirty"
+
+ if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){
+ delete item[this.metaLabel]["isDirty"];
+ }
+ },
+
+ revert: function(){
+ // summary
+ // returns any modified data to its original state prior to a save();
+
+ while (this._dirtyItems.length>0){
+ var d = this._dirtyItems.pop();
+ this._mixin(d.item, d.old);
+ }
+ this.onRevert();
+ },
+
+ _mixin: function(target, data){
+ // summary:
+ // specialized mixin that hooks up objects in the store where references are identified.
+
+ if (dojo.isObject(data)){
+ if (dojo.isArray(data)){
+ while(target.length>0){target.pop();}
+ for (var i=0; i<data.length;i++){
+ if (dojo.isObject(data[i])){
+ if (dojo.isArray(data[i])){
+ var mix=[];
+ }else{
+ var mix={};
+ if (data[i][this.metaLabel] && data[i][this.metaLabel]["type"] && data[i][this.metaLabel]["type"]=='reference'){
+ target[i]=this.index[data[i][this.idAttribute]];
+ continue;
+ }
+ }
+
+ this._mixin(mix, data[i]);
+ target.push(mix);
+ }else{
+ target.push(data[i]);
+ }
+ }
+ }else{
+ for (var i in target){
+ if (i in data){continue;}
+ delete target[i];
+ }
+
+ for (var i in data){
+ if (dojo.isObject(data[i])){
+ if (dojo.isArray(data[i])){
+ var mix=[];
+ }else{
+ if (data[i][this.metaLabel] && data[i][this.metaLabel]["type"] && data[i][this.metaLabel]["type"]=='reference'){
+ target[i]=this.index[data[i][this.idAttribute]];
+ continue;
+ }
+
+ var mix={};
+ }
+ this._mixin(mix, data[i]);
+ target[i]=mix;
+ }else{
+ target[i]=data[i];
+ }
+ }
+
+ }
+ }
+ },
+
+ isDirty: function(item){
+ // summary
+ // returns true if the item is marked as dirty.
+
+ item = this._correctReference(item);
+ return item && item[this.metaLabel] && item[this.metaLabel]["isDirty"];
+ },
+
+ _createReference: function(item){
+ // summary
+ // Create a small reference object that can be used to replace
+ // child objects during a trim
+
+ var obj={};
+ obj[this.metaLabel]={
+ type:'reference'
+ };
+
+ obj[this.idAttribute]=item[this.idAttribute];
+ return obj;
+ },
+
+ _trimItem: function(item){
+ //summary:
+ // copy an item recursively stoppying at other items that have id's
+ // and replace them with a refrence object;
+ var copy;
+ if (dojo.isArray(item)){
+ copy = [];
+ for (var i=0; i<item.length;i++){
+ if (dojo.isArray(item[i])){
+ copy.push(this._trimItem(item[i]))
+ }else if (dojo.isObject(item[i])){
+ if (item[i]["getFullYear"]){
+ copy.push(dojo.date.stamp.toISOString(item[i]));
+ }else if (item[i][this.idAttribute]){
+ copy.push(this._createReference(item[i]));
+ }else{
+ copy.push(this._trimItem(item[i]));
+ }
+ } else {
+ copy.push(item[i]);
+ }
+ }
+ return copy;
+ }
+
+ if (dojo.isObject(item)){
+ copy = {};
+
+ for (var attr in item){
+ if (!item[attr]){ copy[attr]=undefined;continue;}
+ if (dojo.isArray(item[attr])){
+ copy[attr] = this._trimItem(item[attr]);
+ }else if (dojo.isObject(item[attr])){
+ if (item[attr]["getFullYear"]){
+ copy[attr] = dojo.date.stamp.toISOString(item[attr]);
+ }else if(item[attr][this.idAttribute]){
+ copy[attr]=this._createReference(item[attr]);
+ } else {
+ copy[attr]=this._trimItem(item[attr]);
+ }
+ } else {
+ copy[attr]=item[attr];
+ }
+ }
+ return copy;
+ }
+ },
+
+ //Notifcation Support
+
+ onSet: function(){
+ },
+
+ onNew: function(){
+
+ },
+
+ onDelete: function(){
+
+ },
+
+ onSave: function(items){
+ // summary:
+ // notification of the save event..not part of the notification api,
+ // but probably should be.
+ //console.log("onSave() ", items);
+ },
+
+ onRevert: function(){
+ // summary:
+ // notification of the revert event..not part of the notification api,
+ // but probably should be.
+
+ }
+ }
+);
+
+//setup an alias to byId, is there a better way to do this?
+dojox.data.jsonPathStore.byId=dojox.data.jsonPathStore.fetchItemByIdentity;
+
+}
diff --git a/includes/js/dojox/data/tests/QueryReadStore.html b/includes/js/dojox/data/tests/QueryReadStore.html
new file mode 100644
index 0000000..c1634a5
--- /dev/null
+++ b/includes/js/dojox/data/tests/QueryReadStore.html
@@ -0,0 +1,220 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dijit/themes/tundra/tundra_rtl.css";
+ </style>
+
+ <title>Query read store</title>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../../dojo/data/util/simpleFetch.js"></script>
+ <script type="text/javascript" src="../../../dojox/data/QueryReadStore.js"></script>
+ <script type="text/javascript">
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dijit.form.FilteringSelect");
+ dojo.require("dojox.data.QueryReadStore");
+
+ dojo.provide("ComboBoxReadStore");
+ dojo.declare("ComboBoxReadStore", dojox.data.QueryReadStore, {
+ fetch:function(request) {
+ // Copy the GET/POST parameters (request.query) we need into
+ // request.serverQuery. We actually want to have
+ // the query added to the URL like so: /url.php?q=<searchString>
+ // The data in "queryOptions" are useless for our backend,
+ // we ignore them, they are not sent to the server.
+ // The combobox puts this into the request-parameter:
+ // {
+ // query: {name:<searchString>},
+ // queryOptions: {ignoreCase:true, deep:true},
+ // ...
+ // }
+ // We generate request.serverQuery to be this, since those values will
+ // be sent to the server.
+ // {
+ // q:<searchString>}
+ // }
+ // This results in a xhr request to the following URL (in case of GET):
+ // /url.php?q=<searchString>
+ //
+
+ request.serverQuery = {q:request.query.name};
+ // If we wanted to send the queryOptions too, we could simply do:
+ // request.serverQuery = {
+ // q:request.query.name,
+ // ignoreCase:request.queryOptions.ignoreCase,
+ // deep:request.queryOptions.deep
+ // };
+ // This would then result in this URL, for ignoreCase and deep
+ // assumed to be true:
+ // /url.php?q=<searchString>&ignoreCase=true&deep=true
+ return this.inherited("fetch", arguments);
+ }
+ });
+
+ dojo.provide("ServerPagingReadStore");
+ dojo.declare("ServerPagingReadStore", dojox.data.QueryReadStore, {
+ fetch:function(request) {
+ request.serverQuery = {q:request.query.name, start:request.start, count:request.count};
+ return this.inherited("fetch", arguments);
+ }
+ });
+
+ var testStore = new dojox.data.QueryReadStore({url:'stores/QueryReadStore.php'});;
+ function doSearch() {
+ var queryOptions = {};
+ if (dojo.byId("ignoreCaseEnabled").checked) {
+ queryOptions.ignoreCase = dojo.query("#fetchForm")[0].ignoreCase[0].checked;
+ }
+ if (dojo.byId("deepEnabled").checked) {
+ queryOptions.deep = dojo.query("#fetchForm")[0].deep[0].checked;
+ }
+
+ var query = {};
+ query.q = dojo.byId("searchText").value;
+ var request = {query:query, queryOptions:queryOptions};
+ request.start = parseInt(dojo.query("#fetchForm")[0].pagingStart.value);
+ request.count = parseInt(dojo.query("#fetchForm")[0].pagingCount.value);
+
+ var requestMethod = "get";
+ var radioButtons = dojo.query("#fetchForm")[0].requestMethod;
+ for (var i=0; i<radioButtons.length; i++){
+ if (radioButtons[i].checked) {
+ requestMethod = radioButtons[i].value;
+ }
+ }
+
+ testStore.requestMethod = requestMethod;
+ testStore.doClientPaging = dojo.query("#fetchForm")[0].doClientPaging.checked;
+
+ if (!testStore.doClientPaging) {
+ // We have to fill the serverQuery, since we also want to send the
+ // paging data "start" and "count" along with what is in query.
+ request.serverQuery = {q:request.query.q, start:request.start, count:request.count};
+ }
+
+ request.onComplete = function (items) {
+ var s = "number of items: "+items.length+"<br /><br />";
+ for (var i=0; i<items.length; i++) {
+ s += i+": name: '"+testStore.getValue(items[i], "name")+"'<br />";
+ }
+ //s += "<pre>"+dojo.toJson(items)+"</pre>";
+ dojo.byId("fetchOutput").innerHTML = s;
+ };
+
+ console.log(dojo.toJson(request));
+ testStore.fetch(request);
+ }
+ </script>
+</head>
+<body class="tundra" style="margin:20px;">
+ <div dojoType="ComboBoxReadStore" jsId="store" url="stores/QueryReadStore.php" requestMethod="get"></div>
+ This is a ComboBox: <input id="cb" dojoType="dijit.form.ComboBox" store="store" pageSize="5" />
+ <br /><br /><hr />
+
+ This is a FilteringSelect: <input id="fs" dojoType="dijit.form.FilteringSelect" store="store" pageSize="5" />
+ <br />
+ <form id="filteringSelectForm">
+ <input id="selectById" value="0" size="3" />
+ <input type="button" value="set by id" onclick="dijit.byId('fs').setValue(dojo.byId('selectById').value)" />
+ </form>
+
+ <br /><br /><hr />
+
+ This ComboBox uses a customized QueryReadStore, it prepares the query-string for the URL that
+ way that the paging parameters "start" and "count" are also send.<br />
+ <div dojoType="ServerPagingReadStore" jsId="serverPagingStore" url="stores/QueryReadStore.php" requestMethod="get"></div>
+ <input dojoType="dijit.form.ComboBox" store="serverPagingStore" pageSize="5" />
+ <br />
+ <a href="javascript://" onclick="var d = dojo.byId('pagingCode'); d.style.display= d.style.display=='none'?'block':'none';">Click here to see the code!</a>
+<div id="pagingCode" style="display:none;">
+ The HTML might look like this.
+ <pre>
+&lt;div dojoType="ServerPagingReadStore" jsId="serverPagingStore" url="stores/QueryReadStore.php" requestMethod="get"&gt;&lt;/div&gt;
+&lt;input dojoType="dijit.form.ComboBox" store="serverPagingStore" pageSize="10" /&gt;
+ </pre>
+ <pre>
+ dojo.require("dojox.data.QueryReadStore");
+ dojo.provide("ServerPagingReadStore");
+ dojo.declare("ServerPagingReadStore", dojox.data.QueryReadStore, {
+ fetch:function(request) {
+ request.serverQuery = {q:request.query.name, start:request.start, count:request.count};
+ return this.inherited("fetch", arguments);
+ }
+ });
+ </pre>
+</div>
+ <br /><br />
+
+ <hr />
+
+ <style>
+ fieldset {
+ border:1px solid black;
+ display:inline;
+ padding:10px;
+ }
+ div.disabled {
+ opacity:0.1;
+ }
+ </style>
+ <form id="fetchForm">
+ <fieldset title="requestMethod">
+ <legend>requestMethod</legend>
+ get <input type="radio" value="get" checked="checked" name="requestMethod" />
+ post <input type="radio" value="post" name="requestMethod" />
+ </fieldset>
+
+ <fieldset title="queryOptions">
+ <legend>queryOptions</legend>
+
+ <fieldset id="ignoreCaseFieldset">
+ <legend><input type="checkbox" id="ignoreCaseEnabled" /> ignoreCase</legend>
+ <div class="disabled">
+ true <input type="radio" value="0" checked="checked" name="ignoreCase" />
+ false <input type="radio" value="1" name="ignoreCase" />
+ </div>
+ </fieldset>
+ <fieldset id="deepFieldset">
+ <legend><input type="checkbox" id="deepEnabled" /> deep</legend>
+ <div class="disabled">
+ true <input type="radio" value="0" name="deep" />
+ false <input type="radio" value="1" name="deep" checked="checked" />
+ </div>
+ </fieldset>
+ </fieldset>
+ <fieldset title="paging">
+ <legend>paging</legend>
+ start: <input id="pagingStart" value="0" size="3" />
+ count: <input id="pagingCount" value="10" size="3" />
+ <br /><br />
+ do client paging: <input id="doClientPaging" type="checkbox" checked="checked" />
+ </fieldset>
+ <script>
+ var fieldsets = ["ignoreCaseFieldset", "deepFieldset"];
+ for (var i=0; i<fieldsets.length; i++) {
+ dojo.connect(dojo.byId(fieldsets[i]), "onchange", toggleFieldset);
+ }
+ function toggleFieldset(el) {
+ var divs = dojo.query("div", el.target.parentNode.parentNode);
+ if (divs.length) {
+ var div = divs[0];
+ if (el.target.checked) {
+ dojo.removeClass(div, "disabled");
+ } else {
+ dojo.addClass(div, "disabled");
+ }
+ }
+ }
+ </script>
+
+ <br /><br />
+ <input id="searchText" type="text" value="a">
+ <input id="searchButton" type="button" value="store.fetch()" onclick="doSearch()" />
+ </form>
+ <div id="fetchOutput" style="background-color:#FFDDDD; margin-top:1em; float:left;"></div>
+</body>
+</html>
diff --git a/includes/js/dojox/data/tests/dom.js b/includes/js/dojox/data/tests/dom.js
new file mode 100644
index 0000000..a6eb621
--- /dev/null
+++ b/includes/js/dojox/data/tests/dom.js
@@ -0,0 +1,133 @@
+if(!dojo._hasResource["dojox.data.tests.dom"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.dom"] = true;
+dojo.provide("dojox.data.tests.dom");
+dojo.require("dojox.data.dom");
+
+tests.register("dojox.data.tests.dom",
+ [
+ function testCreateDocument(t){
+ var document = dojox.data.dom.createDocument();
+ t.assertTrue(document !== null);
+ },
+ function testCreateDocumentFromText(t){
+ var simpleXml = "<parentNode><childNode><grandchildNode/></childNode><childNode/></parentNode>";
+ var document = dojox.data.dom.createDocument(simpleXml, "text/xml");
+
+ var parent = document.firstChild;
+ t.assertTrue(parent !== null);
+ t.assertTrue(parent.tagName === "parentNode");
+ t.assertTrue(parent.childNodes.length == 2);
+
+ var firstChild = parent.firstChild;
+ t.assertTrue(firstChild !== null);
+ t.assertTrue(firstChild.tagName === "childNode");
+ t.assertTrue(firstChild.childNodes.length == 1);
+
+ var secondChild = firstChild.nextSibling;
+ t.assertTrue(secondChild !== null);
+ t.assertTrue(secondChild.tagName === "childNode");
+
+ var grandChild = firstChild.firstChild;
+ t.assertTrue(grandChild !== null);
+ t.assertTrue(grandChild.tagName === "grandchildNode");
+
+ },
+ function testReadTextContent(t){
+ var text = "This is a bunch of child text on the node";
+ var simpleXml = "<parentNode>" + text + "</parentNode>";
+ var document = dojox.data.dom.createDocument(simpleXml, "text/xml");
+
+ var topNode = document.firstChild;
+ t.assertTrue(topNode !== null);
+ t.assertTrue(topNode.tagName === "parentNode");
+ t.assertTrue(text === dojox.data.dom.textContent(topNode));
+ dojo._destroyElement(topNode);
+ t.assertTrue(document.firstChild === null);
+ },
+ function testSetTextContent(t){
+ var text = "This is a bunch of child text on the node";
+ var text2 = "This is the new text";
+ var simpleXml = "<parentNode>" + text + "</parentNode>";
+ var document = dojox.data.dom.createDocument(simpleXml, "text/xml");
+
+ var topNode = document.firstChild;
+ t.assertTrue(topNode !== null);
+ t.assertTrue(topNode.tagName === "parentNode");
+ t.assertTrue(text === dojox.data.dom.textContent(topNode));
+ dojox.data.dom.textContent(topNode, text2);
+ t.assertTrue(text2 === dojox.data.dom.textContent(topNode));
+ dojo._destroyElement(topNode);
+ t.assertTrue(document.firstChild === null);
+
+ },
+ function testReplaceChildrenArray(t){
+ var simpleXml1 = "<parentNode><child1/><child2/><child3/></parentNode>";
+ var simpleXml2 = "<parentNode><child4/><child5/><child6/><child7/></parentNode>";
+ var doc1 = dojox.data.dom.createDocument(simpleXml1, "text/xml");
+ var doc2 = dojox.data.dom.createDocument(simpleXml2, "text/xml");
+
+ var topNode1 = doc1.firstChild;
+ var topNode2 = doc2.firstChild;
+ t.assertTrue(topNode1 !== null);
+ t.assertTrue(topNode1.tagName === "parentNode");
+ t.assertTrue(topNode2 !== null);
+ t.assertTrue(topNode2.tagName === "parentNode");
+ dojox.data.dom.removeChildren(topNode1);
+ var newChildren=[];
+ for(var i=0;i<topNode2.childNodes.length;i++){
+ newChildren.push(topNode2.childNodes[i]);
+ }
+ dojox.data.dom.removeChildren(topNode2);
+ dojox.data.dom.replaceChildren(topNode1,newChildren);
+ t.assertTrue(topNode1.childNodes.length === 4);
+ t.assertTrue(topNode1.firstChild.tagName === "child4");
+ t.assertTrue(topNode1.lastChild.tagName === "child7");
+
+ },
+ function testReplaceChildrenSingle(t){
+ var simpleXml1 = "<parentNode><child1/><child2/><child3/></parentNode>";
+ var simpleXml2 = "<parentNode><child4/></parentNode>";
+ var doc1 = dojox.data.dom.createDocument(simpleXml1, "text/xml");
+ var doc2 = dojox.data.dom.createDocument(simpleXml2, "text/xml");
+
+ var topNode1 = doc1.firstChild;
+ var topNode2 = doc2.firstChild;
+ t.assertTrue(topNode1 !== null);
+ t.assertTrue(topNode1.tagName === "parentNode");
+ t.assertTrue(topNode2 !== null);
+ t.assertTrue(topNode2.tagName === "parentNode");
+ dojox.data.dom.removeChildren(topNode1);
+
+ var newChildren = topNode2.firstChild;
+ dojox.data.dom.removeChildren(topNode2);
+ dojox.data.dom.replaceChildren(topNode1,newChildren);
+ t.assertTrue(topNode1.childNodes.length === 1);
+ t.assertTrue(topNode1.firstChild.tagName === "child4");
+ t.assertTrue(topNode1.lastChild.tagName === "child4");
+ },
+ function testRemoveChildren(t){
+ var simpleXml1 = "<parentNode><child1/><child2/><child3/></parentNode>";
+ var doc1 = dojox.data.dom.createDocument(simpleXml1, "text/xml");
+
+ var topNode1 = doc1.firstChild;
+ t.assertTrue(topNode1 !== null);
+ t.assertTrue(topNode1.tagName === "parentNode");
+ dojox.data.dom.removeChildren(topNode1);
+ t.assertTrue(topNode1.childNodes.length === 0);
+ t.assertTrue(topNode1.firstChild === null);
+ },
+ function testInnerXML(t){
+ var simpleXml1 = "<parentNode><child1/><child2/><child3/></parentNode>";
+ var doc1 = dojox.data.dom.createDocument(simpleXml1, "text/xml");
+
+ var topNode1 = doc1.firstChild;
+ t.assertTrue(topNode1 !== null);
+ t.assertTrue(topNode1.tagName === "parentNode");
+
+ var innerXml = dojox.data.dom.innerXML(topNode1);
+ t.assertTrue(simpleXml1 === innerXml);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/data/tests/ml/divList.html b/includes/js/dojox/data/tests/ml/divList.html
new file mode 100644
index 0000000..3f0da2f
--- /dev/null
+++ b/includes/js/dojox/data/tests/ml/divList.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>HTML Div List for HtmlStore</title>
+ </head>
+ <body>
+ <div id="divExample">
+ <div><b>bold</b></div>
+ <div><i>italic</i></div>
+ <div><i>normal</i></div>
+ </div>
+ </body>
+</html>
diff --git a/includes/js/dojox/data/tests/ml/orderedList.html b/includes/js/dojox/data/tests/ml/orderedList.html
new file mode 100644
index 0000000..e995377
--- /dev/null
+++ b/includes/js/dojox/data/tests/ml/orderedList.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>HTML Ordered List for HtmlStore</title>
+ </head>
+ <body>
+ <ol id="olExample">
+ <li>Every</li>
+ <li>Good</li>
+ <li>Boy</li>
+ <li>Does</li>
+ <li>Fine</li>
+ </ol>
+ </body>
+</html>
diff --git a/includes/js/dojox/data/tests/ml/table.html b/includes/js/dojox/data/tests/ml/table.html
new file mode 100644
index 0000000..0c556d0
--- /dev/null
+++ b/includes/js/dojox/data/tests/ml/table.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>HTML Ordered List for HtmlStore</title>
+ </head>
+ <body>
+ <!-- The table to link into with the HtmlStore-->
+ <table id="tableExample">
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>A</th>
+ <th>B</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr id="test">
+ <td>2</td>
+ <td>3</td>
+ <td></td>
+ <td>8</td>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>3</td>
+ <td>5</td>
+ <td>7</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>9</td>
+ <td>22</td>
+ <td>777</td>
+ </tr>
+ <tr>
+ <td>3231</td>
+ <td>3</td>
+ <td>535</td>
+ <td>747</td>
+ </tr>
+ </tbody>
+ </table>
+ </body>
+</html>
diff --git a/includes/js/dojox/data/tests/ml/test_HtmlStore_declaratively.html b/includes/js/dojox/data/tests/ml/test_HtmlStore_declaratively.html
new file mode 100644
index 0000000..ea36c8a
--- /dev/null
+++ b/includes/js/dojox/data/tests/ml/test_HtmlStore_declaratively.html
@@ -0,0 +1,172 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Dojox HtmlDataStore Widget</title>
+<style>
+ @import "../../../../dijit/themes/tundra/tundra.css";
+ @import "../../../../dojo/resources/dojo.css";
+ @import "../../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript">
+ djConfig = {
+ isDebug: true,
+ parseOnLoad: true
+ };
+</script>
+<script type="text/javascript" src="../../../../dojo/dojo.js"></script>
+<!--
+<script language="JavaScript" type="text/javascript">
+ dojo.require("doh.runner");
+ function registerTests() {
+ doh.register("t",
+ [
+ function testTableLoaded(t){
+ t.assertTrue(tableStore !== null);
+ t.assertTrue(tableStore !== undefined);
+ }
+ ]
+ );
+ doh.run();
+ };
+ dojo.addOnLoad(registerTests);
+</script>
+-->
+
+<script language="JavaScript" type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojox.data.HtmlStore");
+ dojo.require("dijit.Tree");
+ dojo.require("dijit.form.ComboBox");
+
+ function init() {
+ var table = tableStore;
+
+ function testComplete(items, request){
+ console.debug("Completed!");
+
+ var attributes = null;
+ for(var i = 0; i < items.length; i++){
+ attributes = table.getAttributes(items[i]);
+ for(var j=0; j < attributes.length; j++){
+ console.debug("attribute: [" + attributes[j] + "] have value: " + table.getValue(items[i], attributes[j]));
+ }
+ }
+
+ }
+ table.fetch({query:{X:1}, onComplete: testComplete});
+ table.fetch({query:{X:2}, onComplete: testComplete});
+ table.fetch({query:{X:3}, onComplete: testComplete});
+ table.fetch({query:{X:4}, onComplete: testComplete});
+ table.fetch({query:{X:5}, onComplete: testComplete}); // Should be empty
+ }
+ dojo.addOnLoad(init);
+</script>
+
+</head>
+<body class="tundra">
+ <h1>Dojox HtmlDataStore Widget</h1>
+ <hr/>
+ <br/>
+ <br/>
+
+ <!-- Instantiate the HtmlStore and bind it to global name tableStore -->
+ <div dojoType="dojox.data.HtmlStore" dataId="tableExample" jsId="tableStore"></div>
+ <div dojoType="dojox.data.HtmlStore" dataId="ulExample" jsId="ulStore"></div>
+ <div dojoType="dojox.data.HtmlStore" dataId="olExample" jsId="olStore"></div>
+ <div dojoType="dojox.data.HtmlStore" dataId="divExample" jsId="divStore"></div>
+
+ <!-- The table to link into with the HtmlStore-->
+ <table id="tableExample">
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>A</th>
+ <th>B</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr id="test">
+ <td>2</td>
+ <td>3</td>
+ <td></td>
+ <td>8</td>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>3</td>
+ <td>5</td>
+ <td>7</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>9</td>
+ <td>22</td>
+ <td>777</td>
+ </tr>
+ <tr>
+ <td>3231</td>
+ <td>3</td>
+ <td>535</td>
+ <td>747</td>
+ </tr>
+ </tbody>
+ </table>
+
+ <br/>
+ <br/>
+ <blockquote>
+ <b>Table Rows: <br/><i>(Just to show that the tree can determine that the tableStore works like a store).<br/>Should have three branches, where the row had attr Y value of 3.</i></b>
+ <div dojoType="dijit.Tree" id="tree" store="tableStore" query="{Y:3}"></div>
+ </blockquote>
+
+ <ul id="ulExample">
+ <li>Red</li>
+ <li>Orange</li>
+ <li>Yellow</li>
+ <li>Green</li>
+ <li>Blue</li>
+ <li>Violet</li>
+ </ul>
+
+ <label for="combo1">Unordered List in ComboBox: </label>
+ <input dojoType="dijit.form.ComboBox" value="Red" class="medium" store="ulStore" searchAttr="name" style="width: 300px;" name="ul.item1" id="combo1" >
+
+ <blockquote>
+ <b>Unordered List in Tree: <br/></b>
+ <div dojoType="dijit.Tree" id="tree2" labelAttr="name" store="ulStore" query="{name:'*'}"></div>
+ </blockquote>
+
+ <ol id="olExample">
+ <li>Every</li>
+ <li>Good</li>
+ <li>Boy</li>
+ <li>Does</li>
+ <li>Fine</li>
+ </ol>
+
+ <label for="combo2">Ordered List in ComboBox: </label>
+ <input dojoType="dijit.form.ComboBox" value="Every" class="medium" store="olStore" searchAttr="name" style="width: 300px;" name="ol.item1" id="combo2" >
+
+ <blockquote>
+ <b>Ordered List in Tree: <br/></b>
+ <div dojoType="dijit.Tree" id="tree3" labelAttr="name" store="olStore" query="{name:'*'}"></div>
+ </blockquote>
+
+
+ <div id="divExample">
+ <div><b>bold</b></div>
+ <div><i>italic</i></div>
+ <div><i>normal</i></div>
+ </div>
+
+ <label for="combo3">Div List in ComboBox: </label>
+ <input dojoType="dijit.form.ComboBox" value="bold" class="medium" store="divStore" searchAttr="name" style="width: 300px;" name="bold" id="combo3" >
+
+ <blockquote>
+ <b>Div list in tree: <br/></b>
+ <div dojoType="dijit.Tree" id="tree4" labelAttr="name" store="divStore" query="{name:'*'}"></div>
+ </blockquote>
+
+</body>
+</html>
diff --git a/includes/js/dojox/data/tests/ml/test_HtmlStore_remote.html b/includes/js/dojox/data/tests/ml/test_HtmlStore_remote.html
new file mode 100644
index 0000000..f9d9eff
--- /dev/null
+++ b/includes/js/dojox/data/tests/ml/test_HtmlStore_remote.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Dojox HtmlDataStore Widget</title>
+<style>
+ @import "../../../../dijit/themes/tundra/tundra.css";
+ @import "../../../../dojo/resources/dojo.css";
+ @import "../../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript">
+ djConfig = {
+ isDebug: true,
+ parseOnLoad: true
+ };
+</script>
+<script type="text/javascript" src="../../../../dojo/dojo.js"></script>
+<!--
+<script language="JavaScript" type="text/javascript">
+ dojo.require("doh.runner");
+ function registerTests() {
+ doh.register("t",
+ [
+ function testTableLoaded(t){
+ t.assertTrue(tableStore !== null);
+ t.assertTrue(tableStore !== undefined);
+ }
+ ]
+ );
+ doh.run();
+ };
+ dojo.addOnLoad(registerTests);
+</script>
+-->
+
+<script language="JavaScript" type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojox.data.HtmlStore");
+ dojo.require("dijit.Tree");
+ dojo.require("dijit.form.ComboBox");
+
+ function init() {
+ var table = tableStore;
+
+ function testComplete(items, request){
+ console.debug("Completed!");
+
+ var attributes = null;
+ for(var i = 0; i < items.length; i++){
+ attributes = table.getAttributes(items[i]);
+ for(var j=0; j < attributes.length; j++){
+ console.debug("attribute: [" + attributes[j] + "] have value: " + table.getValue(items[i], attributes[j]));
+ }
+ }
+
+ }
+ table.fetch({query:{X:1}, onComplete: testComplete});
+ table.fetch({query:{X:2}, onComplete: testComplete});
+ table.fetch({query:{X:3}, onComplete: testComplete});
+ table.fetch({query:{X:4}, onComplete: testComplete});
+ table.fetch({query:{X:5}, onComplete: testComplete}); // Should be empty
+ }
+ dojo.addOnLoad(init);
+</script>
+
+</head>
+<body class="tundra">
+ <h1>Dojox HtmlDataStore Widget</h1>
+ <hr/>
+ <br/>
+ <br/>
+
+ <!-- Instantiate the HtmlStore and bind it to global name tableStore -->
+ <div dojoType="dojox.data.HtmlStore" url="table.html" dataId="tableExample" jsId="tableStore"></div>
+ <div dojoType="dojox.data.HtmlStore" url="unorderedList.html" dataId="ulExample" jsId="ulStore"></div>
+ <div dojoType="dojox.data.HtmlStore" url="orderedList.html" dataId="olExample" jsId="olStore"></div>
+ <div dojoType="dojox.data.HtmlStore" url="divList.html" dataId="divExample" jsId="divStore"></div>
+
+ <blockquote>
+ <b>Table Rows: <br/><i>(Just to show that the tree can determine that the tableStore works like a store).<br/>Should have three branches, where the row had attr Y value of 3.</i></b>
+ <div dojoType="dijit.Tree" id="tree" store="tableStore" query="{Y:3}"></div>
+ </blockquote>
+
+ <label for="combo1">Unordered List in ComboBox: </label>
+ <input dojoType="dijit.form.ComboBox" value="Red" class="medium" store="ulStore" searchAttr="name" style="width: 300px;" name="ul.item1" id="combo1" >
+
+ <blockquote>
+ <b>Unordered List in Tree: <br/></b>
+ <div dojoType="dijit.Tree" id="tree2" labelAttr="name" store="ulStore" query="{name:'*'}"></div>
+ </blockquote>
+
+ <label for="combo2">Ordered List in ComboBox: </label>
+ <input dojoType="dijit.form.ComboBox" value="Every" class="medium" store="olStore" searchAttr="name" style="width: 300px;" name="ol.item1" id="combo2" >
+
+ <blockquote>
+ <b>Ordered List in Tree: <br/></b>
+ <div dojoType="dijit.Tree" id="tree3" labelAttr="name" store="olStore" query="{name:'*'}"></div>
+ </blockquote>
+
+
+ <div id="divExample">
+ <div><b>bold</b></div>
+ <div><i>italic</i></div>
+ <div><i>normal</i></div>
+ </div>
+
+ <label for="combo3">Div List in ComboBox: </label>
+ <input dojoType="dijit.form.ComboBox" value="bold" class="medium" store="divStore" searchAttr="name" style="width: 300px;" name="bold" id="combo3" >
+
+ <blockquote>
+ <b>Div list in tree: <br/></b>
+ <div dojoType="dijit.Tree" id="tree4" labelAttr="name" store="divStore" query="{name:'*'}"></div>
+ </blockquote>
+
+</body>
+</html>
diff --git a/includes/js/dojox/data/tests/ml/test_HtmlTableStore_declaratively.html b/includes/js/dojox/data/tests/ml/test_HtmlTableStore_declaratively.html
new file mode 100644
index 0000000..f69ba68
--- /dev/null
+++ b/includes/js/dojox/data/tests/ml/test_HtmlTableStore_declaratively.html
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Dojox HtmlDataStore Widget</title>
+<style>
+ @import "../../../../dijit/themes/tundra/tundra.css";
+ @import "../../../../dojo/resources/dojo.css";
+ @import "../../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript">
+ djConfig = {
+ isDebug: true,
+ parseOnLoad: true
+ };
+</script>
+<script type="text/javascript" src="../../../../dojo/dojo.js"></script>
+<!--
+<script language="JavaScript" type="text/javascript">
+ dojo.require("doh.runner");
+ function registerTests() {
+ doh.register("t",
+ [
+ function testTableLoaded(t){
+ t.assertTrue(tableStore !== null);
+ t.assertTrue(tableStore !== undefined);
+ }
+ ]
+ );
+ doh.run();
+ };
+ dojo.addOnLoad(registerTests);
+</script>
+-->
+
+<script language="JavaScript" type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojox.data.HtmlTableStore");
+ dojo.require("dijit.Tree");
+
+ function init() {
+ var table = tableStore;
+
+ function testComplete(items, request){
+ console.debug("Completed!");
+
+ var attributes = null;
+ for(var i = 0; i < items.length; i++){
+ attributes = table.getAttributes(items[i]);
+ for(var j=0; j < attributes.length; j++){
+ console.debug("attribute: [" + attributes[j] + "] have value: " + table.getValue(items[i], attributes[j]));
+ }
+ }
+
+ }
+ table.fetch({query:{X:1}, onComplete: testComplete});
+ table.fetch({query:{X:2}, onComplete: testComplete});
+ table.fetch({query:{X:3}, onComplete: testComplete});
+ table.fetch({query:{X:4}, onComplete: testComplete});
+ table.fetch({query:{X:5}, onComplete: testComplete}); // Should be empty
+ }
+ dojo.addOnLoad(init);
+</script>
+
+</head>
+<body class="tundra">
+ <h1>Dojox HtmlDataStore Widget</h1>
+ <hr/>
+ <br/>
+ <br/>
+
+ <!-- Instantiate the HtmlTableStore and bind it to global name tableStore -->
+ <div dojoType="dojox.data.HtmlTableStore" tableId="tableExample" jsId="tableStore"></div>
+
+ <!-- The table to link into with the HtmlTableStore-->
+ <table id="tableExample">
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>A</th>
+ <th>B</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr id="test">
+ <td>2</td>
+ <td>3</td>
+ <td></td>
+ <td>8</td>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>3</td>
+ <td>5</td>
+ <td>7</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>9</td>
+ <td>22</td>
+ <td>777</td>
+ </tr>
+ <tr>
+ <td>3231</td>
+ <td>3</td>
+ <td>535</td>
+ <td>747</td>
+ </tr>
+
+ </tbody>
+ </table>
+
+ <br/>
+ <br/>
+ <blockquote>
+ <b>Table Rows: <br/><i>(Just to show that the tree can determine that the tableStore works like a store).<br/>Should have three branches, where the row had attr Y value of 3.</i></b>
+ <div dojoType="dijit.Tree" id="tree" store="tableStore" query="{Y:3}" label="Test tree"></div>
+ </blockquote>
+</body>
+</html>
diff --git a/includes/js/dojox/data/tests/ml/unorderedList.html b/includes/js/dojox/data/tests/ml/unorderedList.html
new file mode 100644
index 0000000..a19149a
--- /dev/null
+++ b/includes/js/dojox/data/tests/ml/unorderedList.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>HTML Unorderd List for HtmlStore</title>
+ </head>
+ <body>
+ <ul id="ulExample">
+ <li>Red</li>
+ <li>Orange</li>
+ <li>Yellow</li>
+ <li>Green</li>
+ <li>Blue</li>
+ <li>Violet</li>
+ </ul>
+ </body>
+</html>
diff --git a/includes/js/dojox/data/tests/module.js b/includes/js/dojox/data/tests/module.js
new file mode 100644
index 0000000..8474eb4
--- /dev/null
+++ b/includes/js/dojox/data/tests/module.js
@@ -0,0 +1,30 @@
+if(!dojo._hasResource["dojox.data.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.module"] = true;
+dojo.provide("dojox.data.tests.module");
+
+try{
+ dojo.require("dojox.data.tests.stores.CsvStore");
+ dojo.require("dojox.data.tests.stores.KeyValueStore");
+ dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.HtmlTableStore");
+ dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.HtmlStore");
+ dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.OpmlStore");
+ dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.XmlStore");
+ dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.FlickrStore");
+ dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.FlickrRestStore");
+ dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.AtomReadStore");
+ dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.jsonPathStore");
+ //Load only if in a browser AND if the location is remote (not file. As it needs a PHP server to work).
+ if(dojo.isBrowser){
+ if(window.location.protocol !== "file:"){
+ dojo.require("dojox.data.tests.stores.QueryReadStore");
+ dojo.require("dojox.data.tests.stores.SnapLogicStore");
+ }
+ }
+ dojo.requireIf(dojo.isBrowser, "dojox.data.tests.dom");
+}catch(e){
+ doh.debug(e);
+}
+
+
+
+}
diff --git a/includes/js/dojox/data/tests/runTests.html b/includes/js/dojox/data/tests/runTests.html
new file mode 100644
index 0000000..49f065c
--- /dev/null
+++ b/includes/js/dojox/data/tests/runTests.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+ <head>
+ <title>Dojox Unit Test Runner</title>
+ <meta http-equiv="REFRESH" content="0;url=../../../util/doh/runner.html?testModule=dojox.data.tests.module"></HEAD>
+ <BODY>
+ Redirecting to D.O.H runner.
+ </BODY>
+</HTML>
diff --git a/includes/js/dojox/data/tests/stores/AtomReadStore.js b/includes/js/dojox/data/tests/stores/AtomReadStore.js
new file mode 100644
index 0000000..1df9493
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/AtomReadStore.js
@@ -0,0 +1,641 @@
+if(!dojo._hasResource["dojox.data.tests.stores.AtomReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.AtomReadStore"] = true;
+dojo.provide("dojox.data.tests.stores.AtomReadStore");
+dojo.require("dojox.data.AtomReadStore");
+dojo.require("dojo.data.api.Read");
+
+dojox.data.tests.stores.AtomReadStore.getBlog1Store = function(){
+ return new dojox.data.AtomReadStore({url: dojo.moduleUrl("dojox.data.tests", "stores/atom1.xml").toString()});
+ //return new dojox.data.AtomReadStore({url: "/sos/feeds/blog.php"});
+};
+/*
+dojox.data.tests.stores.AtomReadStore.getBlog2Store = function(){
+ return new dojox.data.AtomReadStore({url: dojo.moduleUrl("dojox.data.tests", "stores/atom2.xml").toString()});
+};
+*/
+dojox.data.tests.stores.AtomReadStore.error = function(t, d, errData){
+ // summary:
+ // The error callback function to be used for all of the tests.
+ //console.log("In here.");
+ //console.trace();
+ d.errback(errData);
+}
+
+doh.register("dojox.data.tests.stores.AtomReadStore",
+ [
+ {
+ name: "ReadAPI: Fetch_One",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of a basic fetch on AtomReadStore of a single item.
+ // description:
+ // Simple test of a basic fetch on AtomReadStore of a single item.
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.is(1, items.length);
+ d.callback(true);
+ }
+ atomStore.fetch({
+ query: {
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, doh, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: Fetch_5_Streaming",
+ timeout: 5000, //1 second.
+ runTest: function(t) {
+ // summary:
+ // Simple test of a basic fetch on AtomReadStore.
+ // description:
+ // Simple test of a basic fetch on AtomReadStore.
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ var count = 0;
+
+ function onItem(item, requestObj){
+ t.assertTrue(atomStore.isItem(item));
+ count++;
+ }
+ function onComplete(items, request){
+ t.is(5, count);
+
+ t.is(null, items);
+ d.callback(true);
+ }
+ //Get everything...
+ atomStore.fetch({
+ query: {
+ },
+ onBegin: null,
+ count: 5,
+ onItem: onItem,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: Fetch_Paging",
+ timeout: 5000, //1 second.
+ runTest: function(t) {
+ // summary:
+ // Test of multiple fetches on a single result. Paging, if you will.
+ // description:
+ // Test of multiple fetches on a single result. Paging, if you will.
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+ var d = new doh.Deferred();
+
+ function dumpFirstFetch(items, request){
+ t.is(5, items.length);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ atomStore.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ console.log("dumpSecondFetch: got "+items.length);
+ t.is(1, items.length);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ atomStore.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ console.log("dumpThirdFetch: got "+items.length);
+ t.is(5, items.length);
+ request.start = 2;
+ request.count = 18;
+ request.onComplete = dumpFourthFetch;
+ atomStore.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ console.log("dumpFourthFetch: got "+items.length);
+ t.is(18, items.length);
+ request.start = 5;
+ request.count = 11;
+ request.onComplete = dumpFifthFetch;
+ atomStore.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ console.log("dumpFifthFetch: got "+items.length);
+ t.is(11, items.length);
+ request.start = 4;
+ request.count = 16;
+ request.onComplete = dumpSixthFetch;
+ atomStore.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ console.log("dumpSixthFetch: got "+items.length);
+ t.is(16, items.length);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.is(7, items.length);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ atomStore.fetch(request);
+ }
+ atomStore.fetch({
+ query: {
+ },
+ count: 7,
+ onComplete: completed,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getLabel",
+ timeout: 5000, //1 second.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = atomStore.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ d.callback(true);
+ }
+ atomStore.fetch({
+ query: {
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d;
+ }
+ },
+ {
+ name: "ReadAPI: getLabelAttributes",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = atomStore.getLabelAttributes(items[0]);
+ t.assertTrue(dojo.isArray(labelList));
+ t.assertEqual("title", labelList[0]);
+ d.callback(true);
+ }
+ atomStore.fetch({
+ query: {
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d;
+
+ }
+ },
+ {
+ name: "ReadAPI: getValue",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(1, items.length);
+ t.assertTrue(atomStore.getValue(items[0], "summary") !== null);
+ t.assertTrue(atomStore.getValue(items[0], "content") !== null);
+ t.assertTrue(atomStore.getValue(items[0], "published") !== null);
+ t.assertTrue(atomStore.getValue(items[0], "updated") !== null);
+ console.log("typeof updated = "+typeof(atomStore.getValue(items[0], "updated")));
+ t.assertTrue(atomStore.getValue(items[0], "updated").getFullYear);
+ d.callback(true);
+ }
+
+ //Get one item and look at it.
+ atomStore.fetch({
+ query: {
+ },
+ count: 1,
+ onComplete: completedAll,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getValue_Failure",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+ var passed = false;
+ try{
+ var value = store.getValue("NotAnItem", foo);
+ }catch(e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ }
+ },
+ {
+ name: "ReadAPI: getValues",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(1, items.length);
+ var summary = atomStore.getValues(items[0], "summary");
+ t.assertTrue(dojo.isArray(summary));
+
+ var content = atomStore.getValues(items[0], "content");
+ t.assertTrue(dojo.isArray(content));
+
+ var published = atomStore.getValues(items[0], "published");
+ t.assertTrue(dojo.isArray(published));
+
+ var updated = atomStore.getValues(items[0], "updated");
+ t.assertTrue(dojo.isArray(updated));
+ d.callback(true);
+ }
+ //Get one item and look at it.
+ atomStore.fetch({
+ query: {
+ },
+ count: 1,
+ onComplete: completedAll,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error,
+ t,
+ d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getValues_Failure",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+ var passed = false;
+ try{
+ var value = store.getValues("NotAnItem", foo);
+ }catch(e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ }
+ },
+ {
+ name: "ReadAPI: isItem",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of the isItem function of the store
+ // description:
+ // Simple test of the isItem function of the store
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(5, items.length);
+ for(var i=0; i < items.length; i++){
+ t.assertTrue(atomStore.isItem(items[i]));
+ }
+ d.callback(true);
+ }
+
+ //Get everything...
+ atomStore.fetch({
+ query: {
+ },
+ count: 5,
+ onComplete: completedAll,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: hasAttribute",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of the hasAttribute function of the store
+ // description:
+ // Simple test of the hasAttribute function of the store
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ t.assertTrue(items[0] !== null);
+ var count = 0;
+ console.log("hasAttribute");
+ t.assertTrue(atomStore.hasAttribute(items[0], "author"));
+ t.assertTrue(atomStore.hasAttribute(items[0], "published"));
+ t.assertTrue(atomStore.hasAttribute(items[0], "updated"));
+ t.assertTrue(atomStore.hasAttribute(items[0], "category"));
+ t.assertTrue(atomStore.hasAttribute(items[0], "id"));
+ t.assertTrue(!atomStore.hasAttribute(items[0], "foo"));
+ t.assertTrue(!atomStore.hasAttribute(items[0], "bar"));
+
+
+ t.assertTrue(atomStore.hasAttribute(items[0], "summary"));
+ t.assertTrue(atomStore.hasAttribute(items[0], "content"));
+ t.assertTrue(atomStore.hasAttribute(items[0], "title"));
+
+
+ var summary = atomStore.getValue(items[0], "summary");
+ var content = atomStore.getValue(items[0], "content");
+ var title = atomStore.getValue(items[0], "title");
+
+ t.assertTrue(summary && summary.text && summary.type == "html");
+ t.assertTrue(content && content.text && content.type == "html");
+ t.assertTrue(title && title.text && title.type == "html");
+
+ //Test that null attributes throw an exception
+ try{
+ atomStore.hasAttribute(items[0], null);
+ t.assertTrue(false);
+ }catch (e){
+
+ }
+ d.callback(true);
+ }
+
+ //Get one item...
+ atomStore.fetch({
+ query: {
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: containsValue",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of the containsValue function of the store
+ // description:
+ // Simple test of the containsValue function of the store
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+
+ t.assertTrue(atomStore.containsValue(items[0], "id","http://shaneosullivan.wordpress.com/2008/01/22/using-aol-hosted-dojo-with-your-custom-code/"));
+
+ d.callback(true);
+ }
+
+ //Get one item...
+ atomStore.fetch({
+ query: {
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getAttributes",
+ timeout: 5000, //1 second
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ t.assertTrue(atomStore.isItem(items[0]));
+
+ var attributes = atomStore.getAttributes(items[0]);
+ console.log("getAttributes 4: "+attributes.length);
+ t.is(10, attributes.length);
+ d.callback(true);
+ }
+
+ //Get everything...
+ atomStore.fetch({
+ query: {
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: fetch_Category",
+ timeout: 5000, //1 second.
+ runTest: function(t) {
+ // summary:
+ // Retrieve items from the store by category
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(2, items.length);
+ t.assertTrue(atomStore.isItem(items[0]));
+ t.assertTrue(atomStore.isItem(items[1]));
+
+ var categories = atomStore.getValues(items[0], "category");
+ t.assertTrue(dojo.some(categories, function(category){
+ return category.term == "aol";
+ }));
+ categories = atomStore.getValues(items[1], "category");
+ t.assertTrue(dojo.some(categories, function(category){
+ return category.term == "aol";
+ }));
+
+ d.callback(true);
+ }
+
+ //Get everything...
+ atomStore.fetch({
+ query: {
+ category: "aol"
+ },
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: fetch_byID",
+ timeout: 5000, //1 second.
+ runTest: function(t) {
+ // summary:
+ // Retrieve items from the store by category
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ console.log("getById: items.length="+items.length)
+ t.is(1, items.length);
+ t.assertTrue(atomStore.isItem(items[0]));
+
+ var title = atomStore.getValue(items[0], "title");
+ console.log("getById: title.text="+title.text)
+ t.assertTrue(title.text == "Dojo Grid has landed");
+
+ d.callback(true);
+ }
+
+ //Get everything...
+ atomStore.fetch({
+ query: {
+ id: "http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/"
+ },
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: fetch_alternate",
+ timeout: 5000, //1 second.
+ runTest: function(t) {
+ // summary:
+ // Retrieve items from the store by category
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ t.assertTrue(atomStore.isItem(items[0]));
+
+ var alternate = atomStore.getValue(items[0], "alternate");
+ t.assertEqual(alternate.href, "http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/");
+
+ d.callback(true);
+ }
+
+ //Get everything...
+ atomStore.fetch({
+ query: {
+ id: "http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/"
+ },
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+
+ var features = atomStore.getFeatures();
+ var count = 0;
+ for(i in features){
+ t.assertTrue((i === "dojo.data.api.Read"));
+ count++;
+ }
+ t.assertTrue(count === 1);
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store();
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ if(i.toString().charAt(0) !== '_')
+ {
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ console.log("Looking at function: [" + i + "]");
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ console.log("Problem with function: [" + i + "]. Got value: " + testStoreMember);
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/data/tests/stores/CsvStore.js b/includes/js/dojox/data/tests/stores/CsvStore.js
new file mode 100644
index 0000000..c1bad11
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/CsvStore.js
@@ -0,0 +1,1127 @@
+if(!dojo._hasResource["dojox.data.tests.stores.CsvStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.CsvStore"] = true;
+dojo.provide("dojox.data.tests.stores.CsvStore");
+dojo.require("dojox.data.CsvStore");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Identity");
+
+dojox.data.tests.stores.CsvStore.getDatasource = function(filepath){
+ // summary:
+ // A simple helper function for getting the sample data used in each of the tests.
+ // description:
+ // A simple helper function for getting the sample data used in each of the tests.
+
+ var dataSource = {};
+ if(dojo.isBrowser){
+ dataSource.url = dojo.moduleUrl("dojox.data.tests", filepath).toString();
+ }else{
+ // When running tests in Rhino, xhrGet is not available,
+ // so we have the file data in the code below.
+ switch(filepath){
+ case "stores/movies.csv":
+ var csvData = "";
+ csvData += "Title, Year, Producer\n";
+ csvData += "City of God, 2002, Katia Lund\n";
+ csvData += "Rain,, Christine Jeffs\n";
+ csvData += "2001: A Space Odyssey, 1968, Stanley Kubrick\n";
+ csvData += '"This is a ""fake"" movie title", 1957, Sidney Lumet\n';
+ csvData += "Alien, 1979 , Ridley Scott\n";
+ csvData += '"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott\n';
+ csvData += '"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward"\n';
+ break;
+ case "stores/movies2.csv":
+ var csvData = "";
+ csvData += "Title, Year, Producer\n";
+ csvData += "City of God, 2002, Katia Lund\n";
+ csvData += "Rain,\"\", Christine Jeffs\n";
+ csvData += "2001: A Space Odyssey, 1968, Stanley Kubrick\n";
+ csvData += '"This is a ""fake"" movie title", 1957, Sidney Lumet\n';
+ csvData += "Alien, 1979 , Ridley Scott\n";
+ csvData += '"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott\n';
+ csvData += '"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward"\n';
+ break;
+ case "stores/books.csv":
+ var csvData = "";
+ csvData += "Title, Author\n";
+ csvData += "The Transparent Society, David Brin\n";
+ csvData += "The First Measured Century, Theodore Caplow\n";
+ csvData += "Maps in a Mirror, Orson Scott Card\n";
+ csvData += "Princess Smartypants, Babette Cole\n";
+ csvData += "Carfree Cities, Crawford J.H.\n";
+ csvData += "Down and Out in the Magic Kingdom, Cory Doctorow\n";
+ csvData += "Tax Shift, Alan Thein Durning\n";
+ csvData += "The Sneetches and other stories, Dr. Seuss\n";
+ csvData += "News from Tartary, Peter Fleming\n";
+ break;
+ case "stores/patterns.csv":
+ var csvData = "";
+ csvData += "uniqueId, value\n";
+ csvData += "9, jfq4@#!$!@Rf14r14i5u\n";
+ csvData += "6, BaBaMaSaRa***Foo\n";
+ csvData += "2, bar*foo\n";
+ csvData += "8, 123abc\n";
+ csvData += "4, bit$Bite\n";
+ csvData += "3, 123abc\n";
+ csvData += "10, 123abcdefg\n";
+ csvData += "1, foo*bar\n";
+ csvData += "7, \n";
+ csvData += "5, 123abc\n"
+ break;
+ }
+ dataSource.data = csvData;
+ }
+ return dataSource; //Object
+}
+
+dojox.data.tests.stores.CsvStore.verifyItems = function(csvStore, items, attribute, compareArray){
+ // summary:
+ // A helper function for validating that the items array is ordered
+ // the same as the compareArray
+ if(items.length != compareArray.length){ return false; }
+ for(var i = 0; i < items.length; i++){
+ if(!(csvStore.getValue(items[i], attribute) === compareArray[i])){
+ return false; //Boolean
+ }
+ }
+ return true; //Boolean
+}
+
+dojox.data.tests.stores.CsvStore.error = function(t, d, errData){
+ // summary:
+ // The error callback function to be used for all of the tests.
+ for (i in errData) {
+ console.log(errData[i]);
+ }
+ d.errback(errData);
+}
+
+doh.register("dojox.data.tests.stores.CsvStore",
+ [
+ function testReadAPI_fetch_all(t){
+ // summary:
+ // Simple test of a basic fetch on CsvStore.
+ // description:
+ // Simple test of a basic fetch on CsvStore.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.assertTrue((items.length === 7));
+ d.callback(true);
+ }
+
+ //Get everything...
+ csvStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_all_withEmptyStringField(t){
+ // summary:
+ // Simple test of a basic fetch on CsvStore.
+ // description:
+ // Simple test of a basic fetch on CsvStore.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies2.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.assertTrue((items.length === 7));
+ d.callback(true);
+ }
+
+ //Get everything...
+ csvStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_one(t){
+ // summary:
+ // Simple test of a basic fetch on CsvStore of a single item.
+ // description:
+ // Simple test of a basic fetch on CsvStore of a single item.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.is(1, items.length);
+ d.callback(true);
+ }
+ csvStore.fetch({ query: {Title: "*Sequel*"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)
+ });
+ return d; //Object
+ },
+ function testReadAPI_fetch_Multiple(t){
+ // summary:
+ // Simple test of a basic fetch on CsvStore of a single item.
+ // description:
+ // Simple test of a basic fetch on CsvStore of a single item.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+
+ var done = [false, false];
+
+ function onCompleteOne(items, request){
+ done[0] = true;
+ t.is(1, items.length);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ function onCompleteTwo(items, request){
+ done[1] = true;
+ t.is(1, items.length);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ try
+ {
+ csvStore.fetch({ query: {Title: "*Sequel*"},
+ onComplete: onCompleteOne,
+ onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)
+ });
+ csvStore.fetch({ query: {Title: "2001:*"},
+ onComplete: onCompleteTwo,
+ onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)
+ });
+ }
+ catch(e)
+ {
+ for (i in e) {
+ console.log(e[i]);
+ }
+ }
+
+ return d; //Object
+ },
+ function testReadAPI_fetch_MultipleMixed(t){
+ // summary:
+ // Simple test of a basic fetch on CsvStore of a single item.
+ // description:
+ // Simple test of a basic fetch on CsvStore of a single item.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+
+ var done = [false, false];
+ function onComplete(items, request){
+ done[0] = true;
+ t.is(1, items.length);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ function onItem(item){
+ done[1] = true;
+ t.assertTrue(item !== null);
+ t.is('Dymtryk "the King", Edward', csvStore.getValue(item,"Producer"));
+ t.is('Caine Mutiny, The', csvStore.getValue(item,"Title"));
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ csvStore.fetch({ query: {Title: "*Sequel*"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)
+ });
+
+ csvStore.fetchItemByIdentity({identity: "6", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_all_streaming(t){
+ // summary:
+ // Simple test of a basic fetch on CsvStore.
+ // description:
+ // Simple test of a basic fetch on CsvStore.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ count = 0;
+
+ function onBegin(size, requestObj){
+ t.assertTrue(size === 7);
+ }
+ function onItem(item, requestObj){
+ t.assertTrue(csvStore.isItem(item));
+ count++;
+ }
+ function onComplete(items, request){
+ t.is(7, count);
+ t.is(null, items);
+ d.callback(true);
+ }
+
+ //Get everything...
+ csvStore.fetch({ onBegin: onBegin,
+ onItem: onItem,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)
+ });
+ return d; //Object
+ },
+ function testReadAPI_fetch_paging(t){
+ // summary:
+ // Test of multiple fetches on a single result. Paging, if you will.
+ // description:
+ // Test of multiple fetches on a single result. Paging, if you will.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.is(5, items.length);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ csvStore.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.is(1, items.length);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ csvStore.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.is(5, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpFourthFetch;
+ csvStore.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.is(5, items.length);
+ request.start = 9;
+ request.count = 100;
+ request.onComplete = dumpFifthFetch;
+ csvStore.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.is(0, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpSixthFetch;
+ csvStore.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.is(5, items.length);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.is(7, items.length);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ csvStore.fetch(request);
+ }
+
+ csvStore.fetch({onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+
+ },
+
+ function testReadAPI_getLabel(t){
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ args.label = "Title";
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = csvStore.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ t.assertEqual("The Sequel to \"Dances With Wolves.\"", label);
+ d.callback(true);
+ }
+ csvStore.fetch({ query: {Title: "*Sequel*"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)
+ });
+ return d;
+ },
+ function testReadAPI_getLabelAttributes(t){
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ args.label = "Title";
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = csvStore.getLabelAttributes(items[0]);
+ t.assertTrue(dojo.isArray(labelList));
+ t.assertEqual("Title", labelList[0]);
+ d.callback(true);
+ }
+ csvStore.fetch({ query: {Title: "*Sequel*"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)
+ });
+ return d;
+ },
+ function testReadAPI_getValue(t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.is('Dymtryk "the King", Edward', csvStore.getValue(item,"Producer"));
+ t.is('Caine Mutiny, The', csvStore.getValue(item,"Title"));
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "6", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_getValue_2(t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.is("City of God", csvStore.getValue(item,"Title"));
+ t.is("2002", csvStore.getValue(item,"Year"));
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "0", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_getValue_3(t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.is("1979", csvStore.getValue(item,"Year"));
+ t.is("Alien", csvStore.getValue(item,"Title"));
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "4", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_getValue_4(t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.is("2001: A Space Odyssey", csvStore.getValue(item,"Title"));
+ t.is("Stanley Kubrick", csvStore.getValue(item,"Producer"));
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "2", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+
+ function testReadAPI_getValues(t){
+ // summary:
+ // Simple test of the getValues function of the store.
+ // description:
+ // Simple test of the getValues function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var names = csvStore.getValues(item,"Title");
+ t.assertTrue(dojo.isArray(names));
+ t.is(1, names.length);
+ t.is("Rain", names[0]);
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_fetchItemByIdentity(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+
+ function testIdentityAPI_fetchItemByIdentity_bad1(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "7", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_fetchItemByIdentity_bad2(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "-1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_fetchItemByIdentity_bad3(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "999999", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_getIdentity(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(7, items.length);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ if(!(csvStore.getIdentity(items[i]) === i)){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+
+ //Get everything...
+ csvStore.fetch({ onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testIdentityAPI_getIdentityAttributes(t){
+ // summary:
+ // Simple test of the getIdentityAttributes
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(csvStore.isItem(item));
+ t.assertEqual(null, csvStore.getIdentityAttributes(item));
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_isItem(t){
+ // summary:
+ // Simple test of the isItem function of the store
+ // description:
+ // Simple test of the isItem function of the store
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(csvStore.isItem(item));
+ t.assertTrue(!csvStore.isItem({}));
+ t.assertTrue(!csvStore.isItem({ item: "not an item" }));
+ t.assertTrue(!csvStore.isItem("not an item"));
+ t.assertTrue(!csvStore.isItem(["not an item"]));
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_hasAttribute(t){
+ // summary:
+ // Simple test of the hasAttribute function of the store
+ // description:
+ // Simple test of the hasAttribute function of the store
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(csvStore.hasAttribute(item, "Title"));
+ t.assertTrue(csvStore.hasAttribute(item, "Producer"));
+ t.assertTrue(!csvStore.hasAttribute(item, "Year"));
+ t.assertTrue(!csvStore.hasAttribute(item, "Nothing"));
+ t.assertTrue(!csvStore.hasAttribute(item, "title"));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ csvStore.hasAttribute(item, null);
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_containsValue(t){
+ // summary:
+ // Simple test of the containsValue function of the store
+ // description:
+ // Simple test of the containsValue function of the store
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(csvStore.containsValue(item, "Title", "Alien"));
+ t.assertTrue(csvStore.containsValue(item, "Year", "1979"));
+ t.assertTrue(csvStore.containsValue(item, "Producer", "Ridley Scott"));
+ t.assertTrue(!csvStore.containsValue(item, "Title", "Alien2"));
+ t.assertTrue(!csvStore.containsValue(item, "Year", "1979 "));
+ t.assertTrue(!csvStore.containsValue(item, "Title", null));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ csvStore.containsValue(item, null, "foo");
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "4", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_getAttributes(t){
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(csvStore.isItem(item));
+
+ var attributes = csvStore.getAttributes(item);
+ t.is(3, attributes.length);
+ for(var i = 0; i < attributes.length; i++){
+ t.assertTrue((attributes[i] === "Title" || attributes[i] === "Year" || attributes[i] === "Producer"));
+ }
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "4", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+
+ function testReadAPI_getAttributes_onlyTwo(t){
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ // Test an item that does not have all of the attributes
+ t.assertTrue(item !== null);
+ t.assertTrue(csvStore.isItem(item));
+
+ var attributes = csvStore.getAttributes(item);
+ t.assertTrue(attributes.length === 2);
+ t.assertTrue(attributes[0] === "Title");
+ t.assertTrue(attributes[1] === "Producer");
+ d.callback(true);
+ }
+ csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d;
+ },
+
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var features = csvStore.getFeatures();
+ var count = 0;
+ for(i in features){
+ t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Identity"));
+ count++;
+ }
+ t.assertTrue(count === 2);
+ },
+ function testReadAPI_fetch_patternMatch0(t){
+ // summary:
+ // Function to test pattern matching of everything starting with lowercase e
+ // description:
+ // Function to test pattern matching of everything starting with lowercase e
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(2, items.length);
+ var valueArray = [ "Alien", "The Sequel to \"Dances With Wolves.\""];
+ t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "Title", valueArray));
+ d.callback(true);
+ }
+
+ csvStore.fetch({query: {Producer: "* Scott"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch1(t){
+ // summary:
+ // Function to test pattern matching of everything with $ in it.
+ // description:
+ // Function to test pattern matching of everything with $ in it.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertTrue(items.length === 2);
+ var valueArray = [ "jfq4@#!$!@Rf14r14i5u", "bit$Bite"];
+ t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", valueArray));
+ d.callback(true);
+ }
+
+ csvStore.fetch({query: {value: "*$*"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch2(t){
+ // summary:
+ // Function to test exact pattern match
+ // description:
+ // Function to test exact pattern match
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(1, items.length);
+ t.assertTrue(csvStore.getValue(items[0], "value") === "bar*foo");
+ d.callback(true);
+ }
+
+ csvStore.fetch({query: {value: "bar\*foo"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch_caseInsensitive(t){
+ // summary:
+ // Function to test exact pattern match with case insensitivity set.
+ // description:
+ // Function to test exact pattern match with case insensitivity set.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(1, items.length);
+ t.assertTrue(csvStore.getValue(items[0], "value") === "bar*foo");
+ d.callback(true);
+ }
+
+ csvStore.fetch({query: {value: "BAR\\*foo"}, queryOptions: {ignoreCase: true}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch_caseSensitive(t){
+ // summary:
+ // Function to test exact pattern match with case insensitivity set.
+ // description:
+ // Function to test exact pattern match with case insensitivity set.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(0, items.length);
+ d.callback(true);
+ }
+
+ csvStore.fetch({query: {value: "BAR\\*foo"}, queryOptions: {ignoreCase: false}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortNumeric(t){
+ // summary:
+ // Function to test sorting numerically.
+ // description:
+ // Function to test sorting numerically.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertTrue(items.length === 10);
+ // TODO: CsvStore treats everything like a string, so these numbers will be sorted lexicographically.
+ var orderedArray = [ "1", "10", "2", "3", "4", "5", "6", "7", "8", "9" ];
+ t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "uniqueId"}];
+ csvStore.fetch({onComplete: completed,
+ onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d),
+ sort: sortAttributes});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortNumericDescending(t){
+ // summary:
+ // Function to test sorting numerically.
+ // description:
+ // Function to test sorting numerically.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(10, items.length);
+ // TODO: CsvStore treats everything like a string, so these numbers will be sorted lexicographically.
+ var orderedArray = [ "9", "8", "7", "6", "5", "4", "3", "2", "10", "1" ];
+ t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "uniqueId", descending: true}];
+ csvStore.fetch({ sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortNumericWithCount(t){
+ // summary:
+ // Function to test sorting numerically in descending order, returning only a specified number of them.
+ // description:
+ // Function to test sorting numerically in descending order, returning only a specified number of them.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(5, items.length);
+ // TODO: CsvStore treats everything like a string, so these numbers will be sorted lexicographically.
+ var orderedArray = [ "9", "8", "7", "6", "5" ];
+ t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "uniqueId", descending: true}];
+ csvStore.fetch({sort: sortAttributes,
+ count: 5,
+ onComplete: completed,
+ onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortAlphabetic(t){
+ // summary:
+ // Function to test sorting alphabetic ordering.
+ // description:
+ // Function to test sorting alphabetic ordering.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [ "123abc",
+ "123abc",
+ "123abc",
+ "123abcdefg",
+ "BaBaMaSaRa***Foo",
+ "bar*foo",
+ "bit$Bite",
+ "foo*bar",
+ "jfq4@#!$!@Rf14r14i5u",
+ undefined
+ ];
+ t.is(10, items.length);
+ t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "value"}];
+ csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortAlphabeticDescending(t){
+ // summary:
+ // Function to test sorting alphabetic ordering in descending mode.
+ // description:
+ // Function to test sorting alphabetic ordering in descending mode.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [ undefined,
+ "jfq4@#!$!@Rf14r14i5u",
+ "foo*bar",
+ "bit$Bite",
+ "bar*foo",
+ "BaBaMaSaRa***Foo",
+ "123abcdefg",
+ "123abc",
+ "123abc",
+ "123abc"
+ ];
+ t.is(10, items.length);
+ t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "value", descending: true}];
+ csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortMultiple(t){
+ // summary:
+ // Function to test sorting on multiple attributes.
+ // description:
+ // Function to test sorting on multiple attributes.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ var orderedArray0 = [ "8", "5", "3", "10", "6", "2", "4", "1", "9", "7" ];
+ var orderedArray1 = [ "123abc",
+ "123abc",
+ "123abc",
+ "123abcdefg",
+ "BaBaMaSaRa***Foo",
+ "bar*foo",
+ "bit$Bite",
+ "foo*bar",
+ "jfq4@#!$!@Rf14r14i5u",
+ undefined
+ ];
+ t.is(10, items.length);
+ t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray0));
+ t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", orderedArray1));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{ attribute: "value"}, { attribute: "uniqueId", descending: true}];
+ csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortMultipleSpecialComparator(t){
+ // summary:
+ // Function to test sorting on multiple attributes with a custom comparator.
+ // description:
+ // Function to test sorting on multiple attributes with a custom comparator.
+
+ var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+ var csvStore = new dojox.data.CsvStore(args);
+
+ csvStore.comparatorMap = {};
+ csvStore.comparatorMap["Producer"] = function(a,b){
+ var ret = 0;
+ // We want to sort authors alphabetical by their last name
+ function lastName(name){
+ if(typeof name === "undefined"){ return undefined; }
+
+ var matches = name.match(/\s*(\S+)$/); // Grab the last word in the string.
+ return matches ? matches[1] : name; // Strings with only whitespace will not match.
+ }
+ var lastNameA = lastName(a);
+ var lastNameB = lastName(b);
+ if(lastNameA > lastNameB || typeof lastNameA === "undefined"){
+ ret = 1;
+ }else if(lastNameA < lastNameB || typeof lastNameB === "undefined"){
+ ret = -1;
+ }
+ return ret;
+ };
+
+ var sortAttributes = [{attribute: "Producer", descending: true}, { attribute: "Title", descending: true}];
+
+ var d = new doh.Deferred();
+ function completed(items, findResult){
+ var orderedArray = [5,4,0,3,2,1,6];
+ t.assertTrue(items.length === 7);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ if(!(csvStore.getIdentity(items[i]) === orderedArray[i])){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+
+ csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = new dojox.data.CsvStore(dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"));
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ if(i.toString().charAt(0) !== '_')
+ {
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ console.log("Looking at function: [" + i + "]");
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ console.log("Problem with function: [" + i + "]. Got value: " + testStoreMember);
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ },
+ function testIdentityAPI_functionConformance(t){
+ // summary:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = new dojox.data.CsvStore(dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"));
+ var identityApi = new dojo.data.api.Identity();
+ var passed = true;
+
+ for(i in identityApi){
+ if(i.toString().charAt(0) !== '_')
+ {
+ var member = identityApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ console.log("Looking at function: [" + i + "]");
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+
+}
diff --git a/includes/js/dojox/data/tests/stores/FlickrRestStore.js b/includes/js/dojox/data/tests/stores/FlickrRestStore.js
new file mode 100644
index 0000000..23320ec
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/FlickrRestStore.js
@@ -0,0 +1,476 @@
+if(!dojo._hasResource["dojox.data.tests.stores.FlickrRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.FlickrRestStore"] = true;
+dojo.provide("dojox.data.tests.stores.FlickrRestStore");
+dojo.require("dojox.data.FlickrRestStore");
+dojo.require("dojo.data.api.Read");
+
+
+dojox.data.tests.stores.FlickrRestStore.error = function(t, d, errData){
+ // summary:
+ // The error callback function to be used for all of the tests.
+ d.errback(errData);
+}
+
+doh.register("dojox.data.tests.stores.FlickrRestStore",
+ [
+ {
+ name: "ReadAPI: Fetch_One",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of a basic fetch on FlickrRestStore of a single item.
+ // description:
+ // Simple test of a basic fetch on FlickrRestStore of a single item.
+
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.is(1, items.length);
+ d.callback(true);
+ }
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, doh, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: Fetch_20_Streaming",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of a basic fetch on FlickrRestStore.
+ // description:
+ // Simple test of a basic fetch on FlickrRestStore.
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ var count = 0;
+
+ function onItem(item, requestObj){
+ t.assertTrue(flickrStore.isItem(item));
+ count++;
+ }
+ function onComplete(items, request){
+ t.is(5, count);
+
+ t.is(null, items);
+ d.callback(true);
+ }
+ //Get everything...
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ onBegin: null,
+ count: 5,
+ onItem: onItem,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: Fetch_Paging",
+ timeout: 30000, //30 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Test of multiple fetches on a single result. Paging, if you will.
+ // description:
+ // Test of multiple fetches on a single result. Paging, if you will.
+
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.is(5, items.length);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.is(1, items.length);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.is(5, items.length);
+ request.start = 2;
+ request.count = 18;
+ request.onComplete = dumpFourthFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.is(18, items.length);
+ request.start = 9;
+ request.count = 11;
+ request.onComplete = dumpFifthFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.is(11, items.length);
+ request.start = 4;
+ request.count = 16;
+ request.onComplete = dumpSixthFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.is(16, items.length);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.is(7, items.length);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ flickrStore.fetch(request);
+ }
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 7,
+ onComplete: completed,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getLabel",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = flickrStore.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ d.callback(true);
+ }
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)
+ });
+ return d;
+ }
+ },
+ {
+ name: "ReadAPI: getLabelAttributes",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = flickrStore.getLabelAttributes(items[0]);
+ t.assertTrue(dojo.isArray(labelList));
+ t.assertEqual("title", labelList[0]);
+ d.callback(true);
+ }
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)
+ });
+ return d;
+ }
+ },
+ {
+ name: "ReadAPI: getValue",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(1, items.length);
+ t.assertTrue(flickrStore.getValue(items[0], "title") !== null);
+ t.assertTrue(flickrStore.getValue(items[0], "imageUrl") !== null);
+ t.assertTrue(flickrStore.getValue(items[0], "imageUrlSmall") !== null);
+ t.assertTrue(flickrStore.getValue(items[0], "imageUrlMedium") !== null);
+ d.callback(true);
+ }
+
+ //Get one item and look at it.
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 1,
+ onComplete: completedAll,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getValues",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(1, items.length);
+ var title = flickrStore.getValues(items[0], "title");
+ t.assertTrue(title instanceof Array);
+
+ var imgUrl = flickrStore.getValues(items[0], "imageUrl");
+ t.assertTrue(imgUrl instanceof Array);
+
+ var imgUrlSmall = flickrStore.getValues(items[0], "imageUrlSmall");
+ t.assertTrue(imgUrlSmall instanceof Array);
+
+ var imgUrlMedium = flickrStore.getValues(items[0], "imageUrlMedium");
+ t.assertTrue(imgUrlMedium instanceof Array);
+ d.callback(true);
+ }
+ //Get one item and look at it.
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 1,
+ onComplete: completedAll,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error,
+ t,
+ d)});
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: isItem",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the isItem function of the store
+ // description:
+ // Simple test of the isItem function of the store
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(5, items.length);
+ for(var i=0; i < items.length; i++){
+ t.assertTrue(flickrStore.isItem(items[i]));
+ }
+ d.callback(true);
+ }
+
+ //Get everything...
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 5,
+ onComplete: completedAll,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: hasAttribute",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the hasAttribute function of the store
+ // description:
+ // Simple test of the hasAttribute function of the store
+
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ t.assertTrue(items[0] !== null);
+ t.assertTrue(flickrStore.hasAttribute(items[0], "title"));
+ t.assertTrue(flickrStore.hasAttribute(items[0], "author"));
+ t.assertTrue(!flickrStore.hasAttribute(items[0], "Nothing"));
+ t.assertTrue(!flickrStore.hasAttribute(items[0], "Text"));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ flickrStore.hasAttribute(items[0], null);
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+
+ //Get one item...
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: containsValue",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the containsValue function of the store
+ // description:
+ // Simple test of the containsValue function of the store
+
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ d.callback(true);
+ }
+
+ //Get one item...
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getAttributes",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ t.assertTrue(flickrStore.isItem(items[0]));
+
+ var attributes = flickrStore.getAttributes(items[0]);
+ t.is(9, attributes.length);
+ d.callback(true);
+ }
+
+ //Get everything...
+ flickrStore.fetch({
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ },
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var flickrStore = new dojox.data.FlickrRestStore();
+
+ var features = flickrStore.getFeatures();
+ var count = 0;
+ for(i in features){
+ t.assertTrue((i === "dojo.data.api.Read"));
+ count++;
+ }
+ t.assertTrue(count === 1);
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = new dojox.data.FlickrRestStore();
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ if(i.toString().charAt(0) !== '_')
+ {
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ ]
+);
+
+
+}
diff --git a/includes/js/dojox/data/tests/stores/FlickrStore.js b/includes/js/dojox/data/tests/stores/FlickrStore.js
new file mode 100644
index 0000000..3ed8c6c
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/FlickrStore.js
@@ -0,0 +1,410 @@
+if(!dojo._hasResource["dojox.data.tests.stores.FlickrStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.FlickrStore"] = true;
+dojo.provide("dojox.data.tests.stores.FlickrStore");
+dojo.require("dojox.data.FlickrStore");
+dojo.require("dojo.data.api.Read");
+
+
+dojox.data.tests.stores.FlickrStore.error = function(t, d, errData){
+ // summary:
+ // The error callback function to be used for all of the tests.
+ d.errback(errData);
+}
+
+doh.register("dojox.data.tests.stores.FlickrStore",
+ [
+ {
+ name: "ReadAPI: Fetch_One",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of a basic fetch on FlickrStore of a single item.
+ // description:
+ // Simple test of a basic fetch on FlickrStore of a single item.
+
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.is(1, items.length);
+ d.callback(true);
+ }
+ flickrStore.fetch({ query: {tags: "animals"},
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, doh, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: Fetch_20_Streaming",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of a basic fetch on FlickrStore.
+ // description:
+ // Simple test of a basic fetch on FlickrStore.
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ count = 0;
+
+ function onBegin(size, requestObj){
+ t.is(20, size);
+ }
+ function onItem(item, requestObj){
+ t.assertTrue(flickrStore.isItem(item));
+ count++;
+ }
+ function onComplete(items, request){
+ t.is(20, count);
+ t.is(null, items);
+ d.callback(true);
+ }
+
+ //Get everything...
+ flickrStore.fetch({ onBegin: onBegin,
+ count: 20,
+ onItem: onItem,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: Fetch_Paging",
+ timeout: 30000, //30 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Test of multiple fetches on a single result. Paging, if you will.
+ // description:
+ // Test of multiple fetches on a single result. Paging, if you will.
+
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.is(5, items.length);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.is(1, items.length);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.is(5, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpFourthFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.is(18, items.length);
+ request.start = 9;
+ request.count = 100;
+ request.onComplete = dumpFifthFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.is(11, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpSixthFetch;
+ flickrStore.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.is(18, items.length);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.is(7, items.length);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ flickrStore.fetch(request);
+ }
+ flickrStore.fetch({count: 7, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getLabel",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = flickrStore.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ d.callback(true);
+ }
+ flickrStore.fetch({ query: {tags: "animals"},
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)
+ });
+ return d;
+ }
+ },
+ {
+ name: "ReadAPI: getLabelAttributes",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = flickrStore.getLabelAttributes(items[0]);
+ t.assertTrue(dojo.isArray(labelList));
+ t.assertEqual("title", labelList[0]);
+ d.callback(true);
+ }
+ flickrStore.fetch({ query: {tags: "animals"},
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)
+ });
+ return d;
+ }
+ },
+ {
+ name: "ReadAPI: getValue",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(1, items.length);
+ t.assertTrue(flickrStore.getValue(items[0], "title") !== null);
+ t.assertTrue(flickrStore.getValue(items[0], "imageUrl") !== null);
+ t.assertTrue(flickrStore.getValue(items[0], "imageUrlSmall") !== null);
+ t.assertTrue(flickrStore.getValue(items[0], "imageUrlMedium") !== null);
+ d.callback(true);
+ }
+
+ //Get one item and look at it.
+ flickrStore.fetch({ count: 1, onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getValues",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(1, items.length);
+ t.assertTrue(flickrStore.getValues(items[0], "title") instanceof Array);
+ t.assertTrue(flickrStore.getValues(items[0], "description") instanceof Array);
+ t.assertTrue(flickrStore.getValues(items[0], "imageUrl") instanceof Array);
+ t.assertTrue(flickrStore.getValues(items[0], "imageUrlSmall") instanceof Array);
+ t.assertTrue(flickrStore.getValues(items[0], "imageUrlMedium") instanceof Array);
+ d.callback(true);
+ }
+ //Get one item and look at it.
+ flickrStore.fetch({ count: 1, onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: isItem",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the isItem function of the store
+ // description:
+ // Simple test of the isItem function of the store
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(5, items.length);
+ for(var i=0; i < items.length; i++){
+ t.assertTrue(flickrStore.isItem(items[i]));
+ }
+ d.callback(true);
+ }
+
+ //Get everything...
+ flickrStore.fetch({ count: 5, onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: hasAttribute",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the hasAttribute function of the store
+ // description:
+ // Simple test of the hasAttribute function of the store
+
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ t.assertTrue(items[0] !== null);
+ t.assertTrue(flickrStore.hasAttribute(items[0], "title"));
+ t.assertTrue(flickrStore.hasAttribute(items[0], "description"));
+ t.assertTrue(flickrStore.hasAttribute(items[0], "author"));
+ t.assertTrue(!flickrStore.hasAttribute(items[0], "Nothing"));
+ t.assertTrue(!flickrStore.hasAttribute(items[0], "Text"));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ flickrStore.hasAttribute(items[0], null);
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+
+ //Get one item...
+ flickrStore.fetch({ query: {tags: "animals"},
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: containsValue",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the containsValue function of the store
+ // description:
+ // Simple test of the containsValue function of the store
+
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ d.callback(true);
+ }
+
+ //Get one item...
+ flickrStore.fetch({ query: {tags: "animals"},
+ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getAttributes",
+ timeout: 10000, //10 seconds. Flickr can sometimes be slow.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ t.assertTrue(flickrStore.isItem(items[0]));
+
+ var attributes = flickrStore.getAttributes(items[0]);
+ t.is(10, attributes.length);
+ d.callback(true);
+ }
+
+ //Get everything...
+ flickrStore.fetch({ count: 1, onComplete: onComplete, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var flickrStore = new dojox.data.FlickrStore();
+
+ var features = flickrStore.getFeatures();
+ var count = 0;
+ for(i in features){
+ t.assertTrue((i === "dojo.data.api.Read"));
+ count++;
+ }
+ t.assertTrue(count === 1);
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = new dojox.data.FlickrStore();
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ if(i.toString().charAt(0) !== '_')
+ {
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+
+}
diff --git a/includes/js/dojox/data/tests/stores/HtmlStore.js b/includes/js/dojox/data/tests/stores/HtmlStore.js
new file mode 100644
index 0000000..648dd06
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/HtmlStore.js
@@ -0,0 +1,804 @@
+if(!dojo._hasResource["dojox.data.tests.stores.HtmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.HtmlStore"] = true;
+dojo.provide("dojox.data.tests.stores.HtmlStore");
+dojo.require("dojox.data.HtmlStore");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Identity");
+
+
+dojox.data.tests.stores.HtmlStore.getBooks3Store = function(){
+ return new dojox.data.HtmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books3.html").toString(), dataId: "books3"});
+};
+
+dojox.data.tests.stores.HtmlStore.getBooks2Store = function(){
+ return new dojox.data.HtmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books2.html").toString(), dataId: "books2"});
+};
+
+dojox.data.tests.stores.HtmlStore.getBooksStore = function(){
+ return new dojox.data.HtmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books.html").toString(), dataId: "books"});
+};
+
+doh.register("dojox.data.tests.stores.HtmlStore",
+ [
+/***************************************
+ dojo.data.api.Read API
+***************************************/
+ function testReadAPI_fetch_all_table(t){
+ // summary:
+ // Simple test of fetching all xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching all xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.HtmlStore.getBooksStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_all_list(t){
+ // summary:
+ // Simple test of fetching all xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching all xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.HtmlStore.getBooks3Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{name:"*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_one_table(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_one_list(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.HtmlStore.getBooks3Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{name:"A9B57C - Title of 1 - Author of 1"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_paging(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.HtmlStore.getBooksStore();
+
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.assertEqual(5, items.length);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ store.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.assertEqual(1, items.length);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ store.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.assertEqual(5, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpFourthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.assertEqual(18, items.length);
+ request.start = 9;
+ request.count = 100;
+ request.onComplete = dumpFifthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.assertEqual(11, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpSixthFetch;
+ store.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.assertEqual(18, items.length);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.assertEqual(20, items.length);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ store.fetch(request);
+ }
+
+ function error(errData, request){
+ d.errback(errData);
+ }
+
+ store.fetch({onComplete: completed, onError: error});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern0(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern1(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(4, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B57?"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern2(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with * pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with * pattern match
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern_caseInsensitive(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode.
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode.
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?9b574"}, queryOptions: {ignoreCase: true}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern_caseSensitive(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode.
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode.
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?9B574"}, queryOptions: {ignoreCase: false}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_getLabel_table(t){
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = store.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ t.assertEqual("Item #4", label);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d;
+ },
+ function testReadAPI_getLabel_list(t){
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var store = dojox.data.tests.stores.HtmlStore.getBooks3Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = store.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ t.assertEqual("A9B57C - Title of 1 - Author of 1", label);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{name:"A9B57C - Title of 1 - Author of 1"}, onComplete: onComplete, onError: onError});
+ return d;
+ },
+ function testReadAPI_getLabelAttributes(t){
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = store.getLabelAttributes(items[0]);
+ t.assertTrue(labelList === null);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d;
+ },
+
+ function testReadAPI_getValue(t){
+ // summary:
+ // Simple test of the getValue API
+ // description:
+ // Simple test of the getValue API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.hasAttribute(item,"isbn"));
+ t.assertEqual(store.getValue(item,"isbn"), "A9B574");
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_getValues(t){
+ // summary:
+ // Simple test of the getValues API
+ // description:
+ // Simple test of the getValues API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.hasAttribute(item,"isbn"));
+ var values = store.getValues(item,"isbn");
+ t.assertEqual(1,values.length);
+ t.assertEqual("A9B574", values[0]);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_isItem(t){
+ // summary:
+ // Simple test of the isItem API
+ // description:
+ // Simple test of the isItem API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.isItem(item));
+ t.assertTrue(!store.isItem({}));
+ t.assertTrue(!store.isItem("Foo"));
+ t.assertTrue(!store.isItem(1));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_isItem_multistore(t){
+ // summary:
+ // Simple test of the isItem API across multiple store instances.
+ // description:
+ // Simple test of the isItem API across multiple store instances.
+ var store1 = dojox.data.tests.stores.HtmlStore.getBooksStore();
+ var store2 = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete1(items, request) {
+ t.assertEqual(1, items.length);
+ var item1 = items[0];
+ t.assertTrue(store1.isItem(item1));
+
+ function onComplete2(items, request) {
+ t.assertEqual(1, items.length);
+ var item2 = items[0];
+ t.assertTrue(store2.isItem(item2));
+ t.assertTrue(!store1.isItem(item2));
+ t.assertTrue(!store2.isItem(item1));
+ d.callback(true);
+ }
+ store2.fetch({query:{isbn:"A9B574"}, onComplete: onComplete2, onError: onError});
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store1.fetch({query:{isbn:"1"}, onComplete: onComplete1, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_hasAttribute(t){
+ // summary:
+ // Simple test of the hasAttribute API
+ // description:
+ // Simple test of the hasAttribute API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.hasAttribute(item,"isbn"));
+ t.assertTrue(!store.hasAttribute(item,"bob"));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_containsValue(t){
+ // summary:
+ // Simple test of the containsValue API
+ // description:
+ // Simple test of the containsValue API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+ t.assertTrue(!store.containsValue(item,"isbn", "bob"));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortDescending(t){
+ // summary:
+ // Simple test of the sorting API in descending order.
+ // description:
+ // Simple test of the sorting API in descending order.
+ var store = dojox.data.tests.stores.HtmlStore.getBooksStore();
+
+ //Comparison is done as a string type (toString comparison), so the order won't be numeric
+ //So have to compare in 'alphabetic' order.
+ var order = [9,8,7,6,5,4,3,20,2,19,18,17,16,15,14,13,12,11,10,1];
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(order[i], store.getValue(items[i],"isbn").toString());
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn", descending: true}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortAscending(t){
+ // summary:
+ // Simple test of the sorting API in ascending order.
+ // description:
+ // Simple test of the sorting API in ascending order.
+ var store = dojox.data.tests.stores.HtmlStore.getBooksStore();
+
+ //Comparison is done as a string type (toString comparison), so the order won't be numeric
+ //So have to compare in 'alphabetic' order.
+ var order = [1,10,11,12,13,14,15,16,17,18,19,2,20,3,4,5,6,7,8,9];
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ var itemId = 1;
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(order[i], store.getValue(items[i],"isbn").toString());
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn"}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortDescendingNumeric(t){
+ // summary:
+ // Simple test of the sorting API in descending order using a numeric comparator.
+ // description:
+ // Simple test of the sorting API in descending order using a numeric comparator.
+ var store = dojox.data.tests.stores.HtmlStore.getBooksStore();
+
+ //isbn should be treated as a numeric, not as a string comparison
+ store.comparatorMap = {};
+ store.comparatorMap["isbn"] = function(a, b){
+ var ret = 0;
+ if(parseInt(a.toString()) > parseInt(b.toString())){
+ ret = 1;
+ }else if(parseInt(a.toString()) < parseInt(b.toString())){
+ ret = -1;
+ }
+ return ret; //int, {-1,0,1}
+ };
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ var itemId = 20;
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(itemId, store.getValue(items[i],"isbn").toString());
+ itemId--;
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn", descending: true}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortAscendingNumeric(t){
+ // summary:
+ // Simple test of the sorting API in ascending order using a numeric comparator.
+ // description:
+ // Simple test of the sorting API in ascending order using a numeric comparator.
+ var store = dojox.data.tests.stores.HtmlStore.getBooksStore();
+
+ //isbn should be treated as a numeric, not as a string comparison
+ store.comparatorMap = {};
+ store.comparatorMap["isbn"] = function(a, b){
+ var ret = 0;
+ if(parseInt(a.toString()) > parseInt(b.toString())){
+ ret = 1;
+ }else if(parseInt(a.toString()) < parseInt(b.toString())){
+ ret = -1;
+ }
+ return ret; //int, {-1,0,1}
+ };
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ var itemId = 1;
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(itemId, store.getValue(items[i],"isbn").toString());
+ itemId++;
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn"}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_isItemLoaded(t){
+ // summary:
+ // Simple test of the isItemLoaded API
+ // description:
+ // Simple test of the isItemLoaded API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.isItemLoaded(item));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+ var features = store.getFeatures();
+ var count = 0;
+ for(i in features){
+ t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Identity"));
+ count++;
+ }
+ t.assertEqual(2, count);
+ },
+ function testReadAPI_getAttributes(t){
+ // summary:
+ // Simple test of the getAttributes API
+ // description:
+ // Simple test of the getAttributes API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ var attributes = store.getAttributes(item);
+ t.assertEqual(3,attributes.length);
+ for(var i=0; i<attributes.length; i++){
+ t.assertTrue((attributes[i] === "isbn" || attributes[i] === "title" || attributes[i] === "author"));
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = dojox.data.tests.stores.HtmlStore.getBooksStore();
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ console.log("Problem with function: [" + i + "]");
+ passed = false;
+ break;
+ }
+ }
+ }
+ t.assertTrue(passed);
+ },
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+ function testIdentityAPI_getIdentity_table(t){
+ // summary:
+ // Simple test of the getAttributes API
+ // description:
+ // Simple test of the getAttributes API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertEqual(4,store.getIdentity(item));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testIdentityAPI_getIdentity_list(t){
+ // summary:
+ // Simple test of the getAttributes API
+ // description:
+ // Simple test of the getAttributes API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks3Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertEqual("A9B57C - Title of 1 - Author of 1",store.getIdentity(item));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{name:"A9B57C - Title of 1 - Author of 1"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testIdentityAPI_getIdentityAttributes(t){
+ // summary:
+ // Simple test of the getAttributes API
+ // description:
+ // Simple test of the getAttributes API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ //Should have none, as it's not a public attribute.
+ var attributes = store.getIdentityAttributes(item);
+ t.assertEqual(null, attributes);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testIdentityAPI_fetchItemByIdentity_table(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity API
+ // description:
+ // Simple test of the fetchItemByIdentity API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onItem(item, request) {
+ t.assertTrue(item !== null);
+ t.assertTrue(store.isItem(item));
+ t.assertEqual("A9B574", store.getValue(item, "isbn"));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetchItemByIdentity({identity: 4, onItem: onItem, onError: onError});
+ return d; //Object
+ },
+ function testIdentityAPI_fetchItemByIdentity_list(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity API
+ // description:
+ // Simple test of the fetchItemByIdentity API
+ var store = dojox.data.tests.stores.HtmlStore.getBooks3Store();
+
+ var d = new doh.Deferred();
+ function onItem(item, request) {
+ t.assertTrue(item !== null);
+ t.assertTrue(store.isItem(item));
+ t.assertEqual("A9B57C - Title of 1 - Author of 1", store.getValue(item, "name"));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetchItemByIdentity({identity: "A9B57C - Title of 1 - Author of 1", onItem: onItem, onError: onError});
+ return d; //Object
+ },
+ function testIdentityAPI_functionConformance(t){
+ // summary:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = dojox.data.tests.stores.HtmlStore.getBooksStore();
+ var identityApi = new dojo.data.api.Identity();
+ var passed = true;
+
+ for(i in identityApi){
+ var member = identityApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ console.log("Problem with function: [" + i + "]");
+ passed = false;
+ break;
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+//Register the remote tests ... when they work.
+//doh.registerUrl("dojox.data.tests.stores.HtmlStore.remote", dojo.moduleUrl("dojox.data.tests", "ml/test_HtmlStore_declaratively.html"));
+
+}
diff --git a/includes/js/dojox/data/tests/stores/HtmlTableStore.js b/includes/js/dojox/data/tests/stores/HtmlTableStore.js
new file mode 100644
index 0000000..5c21e85
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/HtmlTableStore.js
@@ -0,0 +1,702 @@
+if(!dojo._hasResource["dojox.data.tests.stores.HtmlTableStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.HtmlTableStore"] = true;
+dojo.provide("dojox.data.tests.stores.HtmlTableStore");
+dojo.require("dojox.data.HtmlTableStore");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Identity");
+
+
+dojox.data.tests.stores.HtmlTableStore.getBooks2Store = function(){
+ return new dojox.data.HtmlTableStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books2.html").toString(), tableId: "books2"});
+};
+
+dojox.data.tests.stores.HtmlTableStore.getBooksStore = function(){
+ return new dojox.data.HtmlTableStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books.html").toString(), tableId: "books"});
+};
+
+doh.register("dojox.data.tests.stores.HtmlTableStore",
+ [
+/***************************************
+ dojo.data.api.Read API
+***************************************/
+ function testReadAPI_fetch_all(t){
+ // summary:
+ // Simple test of fetching all xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching all xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooksStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_one(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_paging(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooksStore();
+
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.assertEqual(5, items.length);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ store.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.assertEqual(1, items.length);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ store.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.assertEqual(5, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpFourthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.assertEqual(18, items.length);
+ request.start = 9;
+ request.count = 100;
+ request.onComplete = dumpFifthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.assertEqual(11, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpSixthFetch;
+ store.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.assertEqual(18, items.length);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.assertEqual(20, items.length);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ store.fetch(request);
+ }
+
+ function error(errData, request){
+ d.errback(errData);
+ }
+
+ store.fetch({onComplete: completed, onError: error});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern0(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern1(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(4, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B57?"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern2(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with * pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with * pattern match
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern_caseInsensitive(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode.
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode.
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?9b574"}, queryOptions: {ignoreCase: true}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern_caseSensitive(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode.
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode.
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?9B574"}, queryOptions: {ignoreCase: false}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_getLabel(t){
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = store.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ t.assertEqual("Table Row #3", label);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d;
+ },
+ function testReadAPI_getLabelAttributes(t){
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = store.getLabelAttributes(items[0]);
+ t.assertTrue(labelList === null);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d;
+ },
+
+ function testReadAPI_getValue(t){
+ // summary:
+ // Simple test of the getValue API
+ // description:
+ // Simple test of the getValue API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.hasAttribute(item,"isbn"));
+ t.assertEqual(store.getValue(item,"isbn"), "A9B574");
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_getValues(t){
+ // summary:
+ // Simple test of the getValues API
+ // description:
+ // Simple test of the getValues API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.hasAttribute(item,"isbn"));
+ var values = store.getValues(item,"isbn");
+ t.assertEqual(1,values.length);
+ t.assertEqual("A9B574", values[0]);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_isItem(t){
+ // summary:
+ // Simple test of the isItem API
+ // description:
+ // Simple test of the isItem API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.isItem(item));
+ t.assertTrue(!store.isItem({}));
+ t.assertTrue(!store.isItem("Foo"));
+ t.assertTrue(!store.isItem(1));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_isItem_multistore(t){
+ // summary:
+ // Simple test of the isItem API across multiple store instances.
+ // description:
+ // Simple test of the isItem API across multiple store instances.
+ var store1 = dojox.data.tests.stores.HtmlTableStore.getBooksStore();
+ var store2 = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete1(items, request) {
+ t.assertEqual(1, items.length);
+ var item1 = items[0];
+ t.assertTrue(store1.isItem(item1));
+
+ function onComplete2(items, request) {
+ t.assertEqual(1, items.length);
+ var item2 = items[0];
+ t.assertTrue(store2.isItem(item2));
+ t.assertTrue(!store1.isItem(item2));
+ t.assertTrue(!store2.isItem(item1));
+ d.callback(true);
+ }
+ store2.fetch({query:{isbn:"A9B574"}, onComplete: onComplete2, onError: onError});
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store1.fetch({query:{isbn:"1"}, onComplete: onComplete1, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_hasAttribute(t){
+ // summary:
+ // Simple test of the hasAttribute API
+ // description:
+ // Simple test of the hasAttribute API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.hasAttribute(item,"isbn"));
+ t.assertTrue(!store.hasAttribute(item,"bob"));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_containsValue(t){
+ // summary:
+ // Simple test of the containsValue API
+ // description:
+ // Simple test of the containsValue API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+ t.assertTrue(!store.containsValue(item,"isbn", "bob"));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortDescending(t){
+ // summary:
+ // Simple test of the sorting API in descending order.
+ // description:
+ // Simple test of the sorting API in descending order.
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooksStore();
+
+ //Comparison is done as a string type (toString comparison), so the order won't be numeric
+ //So have to compare in 'alphabetic' order.
+ var order = [9,8,7,6,5,4,3,20,2,19,18,17,16,15,14,13,12,11,10,1];
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(order[i], store.getValue(items[i],"isbn").toString());
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn", descending: true}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortAscending(t){
+ // summary:
+ // Simple test of the sorting API in ascending order.
+ // description:
+ // Simple test of the sorting API in ascending order.
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooksStore();
+
+ //Comparison is done as a string type (toString comparison), so the order won't be numeric
+ //So have to compare in 'alphabetic' order.
+ var order = [1,10,11,12,13,14,15,16,17,18,19,2,20,3,4,5,6,7,8,9];
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ var itemId = 1;
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(order[i], store.getValue(items[i],"isbn").toString());
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn"}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortDescendingNumeric(t){
+ // summary:
+ // Simple test of the sorting API in descending order using a numeric comparator.
+ // description:
+ // Simple test of the sorting API in descending order using a numeric comparator.
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooksStore();
+
+ //isbn should be treated as a numeric, not as a string comparison
+ store.comparatorMap = {};
+ store.comparatorMap["isbn"] = function(a, b){
+ var ret = 0;
+ if(parseInt(a.toString()) > parseInt(b.toString())){
+ ret = 1;
+ }else if(parseInt(a.toString()) < parseInt(b.toString())){
+ ret = -1;
+ }
+ return ret; //int, {-1,0,1}
+ };
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ var itemId = 20;
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(itemId, store.getValue(items[i],"isbn").toString());
+ itemId--;
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn", descending: true}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortAscendingNumeric(t){
+ // summary:
+ // Simple test of the sorting API in ascending order using a numeric comparator.
+ // description:
+ // Simple test of the sorting API in ascending order using a numeric comparator.
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooksStore();
+
+ //isbn should be treated as a numeric, not as a string comparison
+ store.comparatorMap = {};
+ store.comparatorMap["isbn"] = function(a, b){
+ var ret = 0;
+ if(parseInt(a.toString()) > parseInt(b.toString())){
+ ret = 1;
+ }else if(parseInt(a.toString()) < parseInt(b.toString())){
+ ret = -1;
+ }
+ return ret; //int, {-1,0,1}
+ };
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ var itemId = 1;
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(itemId, store.getValue(items[i],"isbn").toString());
+ itemId++;
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn"}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_isItemLoaded(t){
+ // summary:
+ // Simple test of the isItemLoaded API
+ // description:
+ // Simple test of the isItemLoaded API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.isItemLoaded(item));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+ var features = store.getFeatures();
+ var count = 0;
+ for(i in features){
+ t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Identity"));
+ count++;
+ }
+ t.assertEqual(2, count);
+ },
+ function testReadAPI_getAttributes(t){
+ // summary:
+ // Simple test of the getAttributes API
+ // description:
+ // Simple test of the getAttributes API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ var attributes = store.getAttributes(item);
+ t.assertEqual(3,attributes.length);
+ for(var i=0; i<attributes.length; i++){
+ t.assertTrue((attributes[i] === "isbn" || attributes[i] === "title" || attributes[i] === "author"));
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = dojox.data.tests.stores.HtmlTableStore.getBooksStore();
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ console.log("Problem with function: [" + i + "]");
+ passed = false;
+ break;
+ }
+ }
+ }
+ t.assertTrue(passed);
+ },
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+ function testIdentityAPI_getIdentity(t){
+ // summary:
+ // Simple test of the getAttributes API
+ // description:
+ // Simple test of the getAttributes API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertEqual(3,store.getIdentity(item));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testIdentityAPI_getIdentityAttributes(t){
+ // summary:
+ // Simple test of the getAttributes API
+ // description:
+ // Simple test of the getAttributes API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ //Should have none, as it's not a public attribute.
+ var attributes = store.getIdentityAttributes(item);
+ t.assertEqual(null, attributes);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testIdentityAPI_fetchItemByIdentity(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity API
+ // description:
+ // Simple test of the fetchItemByIdentity API
+ var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onItem(item, request) {
+ t.assertTrue(item !== null);
+ t.assertTrue(store.isItem(item));
+ t.assertEqual("A9B574", store.getValue(item, "isbn"));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetchItemByIdentity({identity: 3, onItem: onItem, onError: onError});
+ return d; //Object
+ },
+ function testIdentityAPI_functionConformance(t){
+ // summary:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = dojox.data.tests.stores.HtmlTableStore.getBooksStore();
+ var identityApi = new dojo.data.api.Identity();
+ var passed = true;
+
+ for(i in identityApi){
+ var member = identityApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ console.log("Problem with function: [" + i + "]");
+ passed = false;
+ break;
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+//Register the remote tests ... when they work.
+//doh.registerUrl("dojox.data.tests.stores.HtmlTableStore.remote", dojo.moduleUrl("dojox.data.tests", "ml/test_HtmlTableStore_declaratively.html"));
+
+}
diff --git a/includes/js/dojox/data/tests/stores/KeyValueStore.js b/includes/js/dojox/data/tests/stores/KeyValueStore.js
new file mode 100644
index 0000000..1be92a7
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/KeyValueStore.js
@@ -0,0 +1,1002 @@
+if(!dojo._hasResource["dojox.data.tests.stores.KeyValueStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.KeyValueStore"] = true;
+dojo.provide("dojox.data.tests.stores.KeyValueStore");
+dojo.require("dojox.data.KeyValueStore");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Identity");
+
+dojox.data.tests.stores.KeyValueStore.getDatasource = function(type){
+ // summary:
+ // A simple helper function for getting the sample data used in each of the tests.
+ // description:
+ // A simple helper function for getting the sample data used in each of the tests.
+
+ var dataSource = {};
+ var filepath = "stores/properties.js";
+ if(dojo.isBrowser){
+ dataSource.url = dojo.moduleUrl("dojox.data.tests", filepath).toString();
+ }else{
+ // When running tests in Rhino, xhrGet is not available,
+ // so we have the file data in the code below.
+ var keyData = "/*[";
+ // Properties of December 1, 2007
+ keyData += '{ "year": "2007" },';
+ keyData += '{ "nmonth": "12" },';
+ keyData += '{ "month": "December" },';
+ keyData += '{ "nday": "1" },';
+ keyData += '{ "day": "Saturday" },';
+ keyData += '{ "dayOfYear": "335" },';
+ keyData += '{ "weekOfYear": "48" }';
+ keyData += ']*/';
+ dataSource.data = keyData;
+ }
+ return dataSource; //Object
+}
+
+dojox.data.tests.stores.KeyValueStore.verifyItems = function(keyStore, items, attribute, compareArray){
+ // summary:
+ // A helper function for validating that the items array is ordered
+ // the same as the compareArray
+ if(items.length != compareArray.length){ return false; }
+ for(var i = 0; i < items.length; i++){
+ if(!(keyStore.getValue(items[i], attribute) === compareArray[i])){
+ return false; //Boolean
+ }
+ }
+ return true; //Boolean
+}
+
+dojox.data.tests.stores.KeyValueStore.error = function(t, d, errData){
+ // summary:
+ // The error callback function to be used for all of the tests.
+ for (i in errData) {
+ console.log(errData[i]);
+ }
+ d.errback(errData);
+}
+
+doh.register("dojox.data.tests.stores.KeyValueStore",
+ [
+ function testReadAPI_fetch_all(t){
+ // summary:
+ // Simple test of a basic fetch on KeyValueStore.
+ // description:
+ // Simple test of a basic fetch on KeyValueStore.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/properties.js");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.assertTrue((items.length === 7));
+ d.callback(true);
+ }
+
+ //Get everything...
+ keyStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_all_withEmptyStringField(t){
+ // summary:
+ // Simple test of a basic fetch on KeyValueStore.
+ // description:
+ // Simple test of a basic fetch on KeyValueStore.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource();
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.assertTrue((items.length === 7));
+ d.callback(true);
+ }
+
+ //Get everything...
+ keyStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_one(t){
+ // summary:
+ // Simple test of a basic fetch on KeyValueStore of a single item.
+ // description:
+ // Simple test of a basic fetch on KeyValueStore of a single item.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource();
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.is(1, items.length);
+ d.callback(true);
+ }
+ keyStore.fetch({ query: {key: "year"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)
+ });
+ return d; //Object
+ },
+ function testReadAPI_fetch_Multiple(t){
+ // summary:
+ // Simple test of a basic fetch on KeyValueStore of a single item.
+ // description:
+ // Simple test of a basic fetch on KeyValueStore of a single item.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource();
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+
+ var done = [false, false];
+
+ function onCompleteOne(items, request){
+ done[0] = true;
+ t.is(1, items.length);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ function onCompleteTwo(items, request){
+ done[1] = true;
+ t.is(1, items.length);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ try
+ {
+ keyStore.fetch({ query: {key: "year"},
+ onComplete: onCompleteOne,
+ onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)
+ });
+ keyStore.fetch({ query: {key: "month"},
+ onComplete: onCompleteTwo,
+ onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)
+ });
+ }
+ catch(e)
+ {
+ for (i in e) {
+ console.log(e[i]);
+ }
+ }
+
+ return d; //Object
+ },
+ function testReadAPI_fetch_MultipleMixed(t){
+ // summary:
+ // Simple test of a basic fetch on KeyValueStore of a single item.
+ // description:
+ // Simple test of a basic fetch on KeyValueStore of a single item.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource();
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+
+ var done = [false, false];
+ function onComplete(items, request){
+ done[0] = true;
+ t.is(1, items.length);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ function onItem(item){
+ done[1] = true;
+ t.assertTrue(item !== null);
+ t.is('year', keyStore.getValue(item,"key"));
+ t.is(2007, keyStore.getValue(item,"value"));
+ t.is(2007, keyStore.getValue(item,"year"));
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ keyStore.fetch({ query: {key: "day"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)
+ });
+
+ keyStore.fetchItemByIdentity({identity: "year", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_all_streaming(t){
+ // summary:
+ // Simple test of a basic fetch on KeyValueStore.
+ // description:
+ // Simple test of a basic fetch on KeyValueStore.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource();
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ count = 0;
+
+ function onBegin(size, requestObj){
+ t.assertTrue(size === 7);
+ }
+ function onItem(item, requestObj){
+ t.assertTrue(keyStore.isItem(item));
+ count++;
+ }
+ function onComplete(items, request){
+ t.is(7, count);
+ t.is(null, items);
+ d.callback(true);
+ }
+
+ //Get everything...
+ keyStore.fetch({ onBegin: onBegin,
+ onItem: onItem,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)
+ });
+ return d; //Object
+ },
+ function testReadAPI_fetch_paging(t){
+ // summary:
+ // Test of multiple fetches on a single result. Paging, if you will.
+ // description:
+ // Test of multiple fetches on a single result. Paging, if you will.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource();
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.is(5, items.length);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ keyStore.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.is(1, items.length);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ keyStore.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.is(5, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpFourthFetch;
+ keyStore.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.is(5, items.length);
+ request.start = 9;
+ request.count = 100;
+ request.onComplete = dumpFifthFetch;
+ keyStore.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.is(0, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpSixthFetch;
+ keyStore.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.is(5, items.length);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.is(7, items.length);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ keyStore.fetch(request);
+ }
+
+ keyStore.fetch({onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+
+ function testReadAPI_getLabel(t){
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource();
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = keyStore.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ t.assertEqual("year", label);
+ d.callback(true);
+ }
+ keyStore.fetch({ query: {key: "year"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)
+ });
+ return d;
+ },
+ function testReadAPI_getLabelAttributes(t){
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource();
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = keyStore.getLabelAttributes(items[0]);
+ t.assertTrue(dojo.isArray(labelList));
+ t.assertEqual("key", labelList[0]);
+ d.callback(true);
+ }
+ keyStore.fetch({ query: {key: "year"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)
+ });
+ return d;
+ },
+ function testReadAPI_getValue(t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.is("nday", keyStore.getValue(item,"key"));
+ t.is(1, keyStore.getValue(item,"value"));
+ t.is(1, keyStore.getValue(item,"nday"));
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "nday", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_getValue_2(t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.is("day", keyStore.getValue(item,"key"));
+ t.is("Saturday", keyStore.getValue(item,"value"));
+ t.is("Saturday", keyStore.getValue(item,"day"));
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "day", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_getValue_3(t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.is("dayOfYear", keyStore.getValue(item,"key"));
+ t.is(335, keyStore.getValue(item,"value"));
+ t.is(335, keyStore.getValue(item,"dayOfYear"));
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "dayOfYear", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_getValue_4(t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.is("weekOfYear", keyStore.getValue(item,"key"));
+ t.is(48, keyStore.getValue(item,"value"));
+ t.is(48, keyStore.getValue(item,"weekOfYear"));
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "weekOfYear", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_getValues(t){
+ // summary:
+ // Simple test of the getValues function of the store.
+ // description:
+ // Simple test of the getValues function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var names = keyStore.getValues(item,"year");
+ t.assertTrue(dojo.isArray(names));
+ t.is(1, names.length);
+ t.is(2007, names[0]);
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "year", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_fetchItemByIdentity(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "year", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+
+ function testIdentityAPI_fetchItemByIdentity_bad1(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "y3ar", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_fetchItemByIdentity_bad2(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "-1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_fetchItemByIdentity_bad3(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "999999", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_getIdentity(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(7, items.length);
+ t.is(keyStore.getIdentity(items[0]), 'year');
+ t.is(keyStore.getIdentity(items[1]), 'nmonth');
+ t.is(keyStore.getIdentity(items[2]), 'month');
+ t.is(keyStore.getIdentity(items[3]), 'nday');
+ t.is(keyStore.getIdentity(items[4]), 'day');
+ t.is(keyStore.getIdentity(items[5]), 'dayOfYear');
+ t.is(keyStore.getIdentity(items[6]), 'weekOfYear');
+ d.callback(true);
+ }
+
+ //Get everything...
+ keyStore.fetch({ onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testIdentityAPI_getIdentityAttributes(t){
+ // summary:
+ // Simple test of the getIdentityAttributes
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(keyStore.isItem(item));
+ t.assertEqual("key", keyStore.getIdentityAttributes(item));
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "year", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_isItem(t){
+ // summary:
+ // Simple test of the isItem function of the store
+ // description:
+ // Simple test of the isItem function of the store
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(keyStore.isItem(item));
+ t.assertTrue(!keyStore.isItem({}));
+ t.assertTrue(!keyStore.isItem({ item: "not an item" }));
+ t.assertTrue(!keyStore.isItem("not an item"));
+ t.assertTrue(!keyStore.isItem(["not an item"]));
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "year", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_hasAttribute(t){
+ // summary:
+ // Simple test of the hasAttribute function of the store
+ // description:
+ // Simple test of the hasAttribute function of the store
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(keyStore.hasAttribute(item, "key"));
+ t.assertTrue(keyStore.hasAttribute(item, "value"));
+ t.assertTrue(keyStore.hasAttribute(item, "year"));
+ t.assertTrue(!keyStore.hasAttribute(item, "Year"));
+ t.assertTrue(!keyStore.hasAttribute(item, "Nothing"));
+ t.assertTrue(!keyStore.hasAttribute(item, "Title"));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ keyStore.hasAttribute(item, null);
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "year", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_containsValue(t){
+ // summary:
+ // Simple test of the containsValue function of the store
+ // description:
+ // Simple test of the containsValue function of the store
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(keyStore.containsValue(item, "year", "2007"));
+ t.assertTrue(keyStore.containsValue(item, "value", "2007"));
+ t.assertTrue(keyStore.containsValue(item, "key", "year"));
+ t.assertTrue(!keyStore.containsValue(item, "Title", "Alien2"));
+ t.assertTrue(!keyStore.containsValue(item, "Year", "1979 "));
+ t.assertTrue(!keyStore.containsValue(item, "Title", null));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ keyStore.containsValue(item, null, "foo");
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "year", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+ function testReadAPI_getAttributes(t){
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(keyStore.isItem(item));
+
+ var attributes = keyStore.getAttributes(item);
+ t.is(3, attributes.length);
+ for(var i = 0; i < attributes.length; i++){
+ t.assertTrue((attributes[i] === "year" || attributes[i] === "value" || attributes[i] === "key"));
+ }
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "year", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+
+ function testReadAPI_getAttributes_onlyTwo(t){
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ // Test an item that does not have all of the attributes
+ t.assertTrue(item !== null);
+ t.assertTrue(keyStore.isItem(item));
+
+ var attributes = keyStore.getAttributes(item);
+ t.assertTrue(attributes.length === 3);
+ t.assertTrue(attributes[0] === "key");
+ t.assertTrue(attributes[1] === "value");
+ t.assertTrue(attributes[2] === "nmonth");
+ d.callback(true);
+ }
+ keyStore.fetchItemByIdentity({identity: "nmonth", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d;
+ },
+
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var features = keyStore.getFeatures();
+ var count = 0;
+ for(i in features){
+ t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Identity"));
+ count++;
+ }
+ t.assertTrue(count === 2);
+ },
+ function testReadAPI_fetch_patternMatch0(t){
+ // summary:
+ // Function to test pattern matching of everything starting with lowercase e
+ // description:
+ // Function to test pattern matching of everything starting with lowercase e
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(2, items.length);
+ var valueArray = [ "nmonth", "month"];
+ t.assertTrue(dojox.data.tests.stores.KeyValueStore.verifyItems(keyStore, items, "key", valueArray));
+ d.callback(true);
+ }
+
+ keyStore.fetch({query: {key: "*month"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch1(t){
+ // summary:
+ // Function to test pattern matching of everything with $ in it.
+ // description:
+ // Function to test pattern matching of everything with $ in it.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/patterns.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertTrue(items.length === 2);
+ var valueArray = [ "1", "Saturday"];
+ t.assertTrue(dojox.data.tests.stores.KeyValueStore.verifyItems(keyStore, items, "value", valueArray));
+ d.callback(true);
+ }
+
+ keyStore.fetch({query: {key: "*day"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch2(t){
+ // summary:
+ // Function to test exact pattern match
+ // description:
+ // Function to test exact pattern match
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/patterns.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(2, items.length);
+ t.assertTrue(keyStore.getValue(items[0], "value") === "12");
+ t.assertTrue(keyStore.getValue(items[0], "key") === "nmonth");
+ t.assertTrue(keyStore.getValue(items[1], "value") === "1");
+ t.assertTrue(keyStore.getValue(items[1], "key") === "nday");
+ d.callback(true);
+ }
+
+ keyStore.fetch({query: {value: "1*"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch_caseInsensitive(t){
+ // summary:
+ // Function to test exact pattern match with case insensitivity set.
+ // description:
+ // Function to test exact pattern match with case insensitivity set.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/patterns.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(1, items.length);
+ t.assertTrue(keyStore.getValue(items[0], "value") === "December");
+ d.callback(true);
+ }
+
+ keyStore.fetch({query: {key: "MONth"}, queryOptions: {ignoreCase: true}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch_caseSensitive(t){
+ // summary:
+ // Function to test exact pattern match with case insensitivity set.
+ // description:
+ // Function to test exact pattern match with case insensitivity set.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/patterns.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(0, items.length);
+ d.callback(true);
+ }
+
+ keyStore.fetch({query: {value: "DECEMberO"}, queryOptions: {ignoreCase: false}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortAlphabetic(t){
+ // summary:
+ // Function to test sorting alphabetic ordering.
+ // description:
+ // Function to test sorting alphabetic ordering.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/patterns.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [ "day", "dayOfYear", "month", "nday", "nmonth", "weekOfYear", "year" ];
+ t.is(7, items.length);
+ t.assertTrue(dojox.data.tests.stores.KeyValueStore.verifyItems(keyStore, items, "key", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "key"}];
+ keyStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortAlphabeticDescending(t){
+ // summary:
+ // Function to test sorting alphabetic ordering in descending mode.
+ // description:
+ // Function to test sorting alphabetic ordering in descending mode.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/patterns.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [ "year", "weekOfYear", "nmonth", "nday", "month", "dayOfYear", "day" ];
+ t.is(7, items.length);
+ t.assertTrue(dojox.data.tests.stores.KeyValueStore.verifyItems(keyStore, items, "key", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "key", descending: true}];
+ keyStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortMultiple(t){
+ // summary:
+ // Function to test sorting on multiple attributes.
+ // description:
+ // Function to test sorting on multiple attributes.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/patterns.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ var orderedArray1 = [ "123abc",
+ "123abc",
+ "123abc",
+ "123abcdefg",
+ "BaBaMaSaRa***Foo",
+ "bar*foo",
+ "bit$Bite",
+ "foo*bar",
+ "jfq4@#!$!@Rf14r14i5u",
+ undefined
+ ];
+ var orderedArray0 = [ "day", "dayOfYear", "month", "nday", "nmonth", "weekOfYear", "year" ];
+ var orderedArray1 = [ "Saturday", "335", "December", "1", "12", "48", "2007" ];
+ t.is(7, items.length);
+ t.assertTrue(dojox.data.tests.stores.KeyValueStore.verifyItems(keyStore, items, "key", orderedArray0));
+ t.assertTrue(dojox.data.tests.stores.KeyValueStore.verifyItems(keyStore, items, "value", orderedArray1));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{ attribute: "key"}, { attribute: "value", descending: true}];
+ keyStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortMultipleSpecialComparator(t){
+ // summary:
+ // Function to test sorting on multiple attributes with a custom comparator.
+ // description:
+ // Function to test sorting on multiple attributes with a custom comparator.
+
+ var args = dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv");
+ var keyStore = new dojox.data.KeyValueStore(args);
+
+ keyStore.comparatorMap = {};
+ keyStore.comparatorMap["key"] = function(a,b){
+ var ret = 0;
+ // We want to sort keys alphabetical by the last character in the string
+ function lastChar(name){
+ if(typeof name === "undefined"){ return undefined; }
+
+ return name.slice(name.length-1); // Grab the last character in the string.
+ }
+ var lastCharA = lastChar(a);
+ var lastCharB = lastChar(b);
+ if(lastCharA > lastCharB || typeof lastCharA === "undefined"){
+ ret = 1;
+ }else if(lastCharA < lastCharB || typeof lastCharB === "undefined"){
+ ret = -1;
+ }
+ return ret;
+ };
+
+ var sortAttributes = [{attribute: "key", descending: true}, { attribute: "value", descending: true}];
+
+ var d = new doh.Deferred();
+ function completed(items, findResult){
+ var orderedArray = [5,4,0,3,2,1,6];
+ var orderedArray = [ "day", "nday", "weekOfYear", "dayOfYear", "year", "month", "nmonth" ];
+ t.assertTrue(items.length === 7);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ if(!(keyStore.getIdentity(items[i]) === orderedArray[i])){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+
+ keyStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = new dojox.data.KeyValueStore(dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv"));
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ if(i.toString().charAt(0) !== '_')
+ {
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ console.log("Looking at function: [" + i + "]");
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ console.log("Problem with function: [" + i + "]. Got value: " + testStoreMember);
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ },
+ function testIdentityAPI_functionConformance(t){
+ // summary:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = new dojox.data.KeyValueStore(dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv"));
+ var identityApi = new dojo.data.api.Identity();
+ var passed = true;
+
+ for(i in identityApi){
+ if(i.toString().charAt(0) !== '_')
+ {
+ var member = identityApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ console.log("Looking at function: [" + i + "]");
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+
+}
diff --git a/includes/js/dojox/data/tests/stores/OpmlStore.js b/includes/js/dojox/data/tests/stores/OpmlStore.js
new file mode 100644
index 0000000..4fe7be4
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/OpmlStore.js
@@ -0,0 +1,1075 @@
+if(!dojo._hasResource["dojox.data.tests.stores.OpmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.OpmlStore"] = true;
+dojo.provide("dojox.data.tests.stores.OpmlStore");
+dojo.require("dojox.data.OpmlStore");
+dojo.require("dojo.data.api.Read");
+
+dojox.data.tests.stores.OpmlStore.getDatasource = function(filepath){
+ // summary:
+ // A simple helper function for getting the sample data used in each of the tests.
+ // description:
+ // A simple helper function for getting the sample data used in each of the tests.
+
+ var dataSource = {};
+ if(dojo.isBrowser){
+ dataSource.url = dojo.moduleUrl("dojox.data.tests", filepath).toString();
+ }else{
+ // When running tests in Rhino, xhrGet is not available,
+ // so we have the file data in the code below.
+ switch(filepath){
+ case "stores/geography.xml":
+ var opmlData = "";
+ opmlData += '<?xml version="1.0" encoding="ISO-8859-1"?>\n';
+ opmlData += ' <opml version="1.0">\n';
+ opmlData += ' <head>\n';
+ opmlData += ' <title>geography.opml</title>\n';
+ opmlData += ' <dateCreated>2006-11-10</dateCreated>\n';
+ opmlData += ' <dateModified>2006-11-13</dateModified>\n';
+ opmlData += ' <ownerName>Magellan, Ferdinand</ownerName>\n';
+ opmlData += ' </head>\n';
+ opmlData += ' <body>\n';
+ opmlData += ' <outline text="Africa" type="continent">\n';
+ opmlData += ' <outline text="Egypt" type="country"/>\n';
+ opmlData += ' <outline text="Kenya" type="country">\n';
+ opmlData += ' <outline text="Nairobi" type="city"/>\n';
+ opmlData += ' <outline text="Mombasa" type="city"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Sudan" type="country">\n';
+ opmlData += ' <outline text="Khartoum" type="city"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Asia" type="continent">\n';
+ opmlData += ' <outline text="China" type="country"/>\n';
+ opmlData += ' <outline text="India" type="country"/>\n';
+ opmlData += ' <outline text="Russia" type="country"/>\n';
+ opmlData += ' <outline text="Mongolia" type="country"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Australia" type="continent" population="21 million">\n';
+ opmlData += ' <outline text="Australia" type="country" population="21 million"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Europe" type="continent">\n';
+ opmlData += ' <outline text="Germany" type="country"/>\n';
+ opmlData += ' <outline text="France" type="country"/>\n';
+ opmlData += ' <outline text="Spain" type="country"/>\n';
+ opmlData += ' <outline text="Italy" type="country"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="North America" type="continent">\n';
+ opmlData += ' <outline text="Mexico" type="country" population="108 million" area="1,972,550 sq km">\n';
+ opmlData += ' <outline text="Mexico City" type="city" population="19 million" timezone="-6 UTC"/>\n';
+ opmlData += ' <outline text="Guadalajara" type="city" population="4 million" timezone="-6 UTC"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Canada" type="country" population="33 million" area="9,984,670 sq km">\n';
+ opmlData += ' <outline text="Ottawa" type="city" population="0.9 million" timezone="-5 UTC"/>\n';
+ opmlData += ' <outline text="Toronto" type="city" population="2.5 million" timezone="-5 UTC"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="United States of America" type="country"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="South America" type="continent">\n';
+ opmlData += ' <outline text="Brazil" type="country" population="186 million"/>\n';
+ opmlData += ' <outline text="Argentina" type="country" population="40 million"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' </body>\n';
+ opmlData += ' </opml>\n';
+ break;
+ case "stores/geography_withspeciallabel.xml":
+ var opmlData = "";
+ opmlData += '<?xml version="1.0" encoding="ISO-8859-1"?>\n';
+ opmlData += '<opml version="1.0">\n';
+ opmlData += ' <head>\n';
+ opmlData += ' <title>geography.opml</title>\n';
+ opmlData += ' <dateCreated>2006-11-10</dateCreated>\n';
+ opmlData += ' <dateModified>2006-11-13</dateModified>\n';
+ opmlData += ' <ownerName>Magellan, Ferdinand</ownerName>\n';
+ opmlData += ' </head>\n';
+ opmlData += ' <body>\n';
+ opmlData += ' <outline text="Africa" type="continent" label="Continent/Africa">\n';
+ opmlData += ' <outline text="Egypt" type="country" label="Country/Egypt"/>\n';
+ opmlData += ' <outline text="Kenya" type="country" label="Country/Kenya">\n';
+ opmlData += ' <outline text="Nairobi" type="city" label="City/Nairobi"/>\n';
+ opmlData += ' <outline text="Mombasa" type="city" label="City/Mombasa"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Sudan" type="country" label="Country/Sudan">\n';
+ opmlData += ' <outline text="Khartoum" type="city" label="City/Khartoum"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Asia" type="continent" label="Continent/Asia">\n';
+ opmlData += ' <outline text="China" type="country" label="Country/China"/>\n';
+ opmlData += ' <outline text="India" type="country" label="Country/India"/>\n';
+ opmlData += ' <outline text="Russia" type="country" label="Country/Russia"/>\n';
+ opmlData += ' <outline text="Mongolia" type="country" label="Country/Mongolia"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Australia" type="continent" population="21 million" label="Continent/Australia">\n';
+ opmlData += ' <outline text="Australia" type="country" population="21 million" label="Country/Australia"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Europe" type="continent" label="Contintent/Europe">\n';
+ opmlData += ' <outline text="Germany" type="country" label="Country/Germany"/>\n';
+ opmlData += ' <outline text="France" type="country" label="Country/France"/>\n';
+ opmlData += ' <outline text="Spain" type="country" label="Country/Spain"/>\n';
+ opmlData += ' <outline text="Italy" type="country" label="Country/Italy"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="North America" type="continent" label="Continent/North America">\n';
+ opmlData += ' <outline text="Mexico" type="country" population="108 million" area="1,972,550 sq km" label="Country/Mexico">\n';
+ opmlData += ' <outline text="Mexico City" type="city" population="19 million" timezone="-6 UTC" label="City/Mexico City"/>\n';
+ opmlData += ' <outline text="Guadalajara" type="city" population="4 million" timezone="-6 UTC" label="City/Guadalajara"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="Canada" type="country" population="33 million" area="9,984,670 sq km" label="Country/Canada">\n';
+ opmlData += ' <outline text="Ottawa" type="city" population="0.9 million" timezone="-5 UTC" label="City/Ottawa"/>\n';
+ opmlData += ' <outline text="Toronto" type="city" population="2.5 million" timezone="-5 UTC" label="City/Toronto"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="United States of America" type="country" label="Country/United States of America"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' <outline text="South America" type="continent" label="Continent/South America">\n';
+ opmlData += ' <outline text="Brazil" type="country" population="186 million" label="Country/Brazil"/>\n';
+ opmlData += ' <outline text="Argentina" type="country" population="40 million" label="Country/Argentina"/>\n';
+ opmlData += ' </outline>\n';
+ opmlData += ' </body>\n';
+ opmlData += '</opml>\n';
+ break;
+ }
+ dataSource.data = opmlData;
+ }
+ return dataSource; //Object
+}
+
+dojox.data.tests.stores.OpmlStore.verifyItems = function(opmlStore, items, attribute, compareArray){
+ // summary:
+ // A helper function for validating that the items array is ordered
+ // the same as the compareArray
+ if(items.length != compareArray.length){ return false; }
+ for(var i = 0; i < items.length; i++){
+ if(!(opmlStore.getValue(items[i], attribute) === compareArray[i])){
+ return false; //Boolean
+ }
+ }
+ return true; //Boolean
+}
+
+dojox.data.tests.stores.OpmlStore.error = function(t, d, errData){
+ // summary:
+ // The error callback function to be used for all of the tests.
+ d.errback(errData);
+}
+
+doh.register("dojox.data.tests.stores.OpmlStore",
+ [
+ function testReadAPI_fetch_all(t){
+ // summary:
+ // Simple test of a basic fetch on OpmlStore.
+ // description:
+ // Simple test of a basic fetch on OpmlStore.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(6, items.length);
+ d.callback(true);
+ }
+
+ //Get everything...
+ opmlStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_one(t){
+ // summary:
+ // Simple test of a basic fetch on OpmlStore of a single item.
+ // description:
+ // Simple test of a basic fetch on OpmlStore of a single item.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.is(1, items.length);
+ d.callback(true);
+ }
+ opmlStore.fetch({ query: {text: "Asia"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d; //Object
+ },
+
+ function testReadAPI_fetch_one_Multiple(t){
+ // summary:
+ // Simple test of a basic fetch on OpmlStore of a single item.
+ // description:
+ // Simple test of a basic fetch on OpmlStore of a single item.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ var done = [false,false];
+ function onCompleteOne(items, request){
+ done[0] = true;
+ t.is(1, items.length);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+ function onCompleteTwo(items, request){
+ done[1] = true;
+ t.is(1, items.length);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ opmlStore.fetch({ query: {text: "Asia"},
+ onComplete: onCompleteOne,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+
+ opmlStore.fetch({ query: {text: "North America"},
+ onComplete: onCompleteTwo,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+
+ return d; //Object
+ },
+
+ function testReadAPI_fetch_one_MultipleMixed(t){
+ // summary:
+ // Simple test of a basic fetch on OpmlStore of a single item mixing two fetch types.
+ // description:
+ // Simple test of a basic fetch on Cpmltore of a single item mixing two fetch types.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+
+ var done = [false, false];
+ function onComplete(items, request){
+ done[0] = true;
+ t.is(1, items.length);
+ console.log("Found item: " + opmlStore.getValue(items[0],"text") + " with identity: " + opmlStore.getIdentity(items[0]));
+ t.is(0, opmlStore.getIdentity(items[0]));
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ function onItem(item){
+ done[1] = true;
+ t.assertTrue(item !== null);
+ console.log("Found item: " + opmlStore.getValue(item,"text"));
+ t.is('Egypt', opmlStore.getValue(item,"text")); //Should be the second node parsed, ergo id 1, first node is id 0.
+ t.is(1, opmlStore.getIdentity(item));
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+
+ opmlStore.fetch({ query: {text: "Africa"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+
+ opmlStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+
+ return d; //Object
+ },
+
+ function testReadAPI_fetch_one_deep(t){
+ // summary:
+ // Simple test of a basic fetch on OpmlStore of a single item that's nested down as a child item.
+ // description:
+ // Simple test of a basic fetch on OpmlStore of a single item that's nested down as a child item.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.is(1, items.length);
+ d.callback(true);
+ }
+ opmlStore.fetch({ query: {text: "Mexico City"},
+ queryOptions: {deep:true},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d; //Object
+ },
+
+ function testReadAPI_fetch_one_deep_off(t){
+ // summary:
+ // Simple test of a basic fetch on OpmlStore of a single item that's nested down as a child item.
+ // description:
+ // Simple test of a basic fetch on OpmlStore of a single item that's nested down as a child item.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ //Nothing should be found.
+ t.is(0, items.length);
+ d.callback(true);
+ }
+ opmlStore.fetch({ query: {text: "Mexico City"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d; //Object
+ },
+
+ function testReadAPI_fetch_all_streaming(t){
+ // summary:
+ // Simple test of a basic fetch on OpmlStore.
+ // description:
+ // Simple test of a basic fetch on OpmlStore.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ count = 0;
+
+ function onBegin(size, requestObj){
+ t.is(6, size);
+ }
+ function onItem(item, requestObj){
+ t.assertTrue(opmlStore.isItem(item));
+ count++;
+ }
+ function onComplete(items, request){
+ t.is(6, count);
+ t.is(null, items);
+ d.callback(true);
+ }
+
+ //Get everything...
+ opmlStore.fetch({ onBegin: onBegin,
+ onItem: onItem,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d; //Object
+ },
+ function testReadAPI_fetch_paging(t){
+ // summary:
+ // Test of multiple fetches on a single result. Paging, if you will.
+ // description:
+ // Test of multiple fetches on a single result. Paging, if you will.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.is(5, items.length);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ opmlStore.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.is(1, items.length);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ opmlStore.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.is(5, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpFourthFetch;
+ opmlStore.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.is(4, items.length);
+ request.start = 9;
+ request.count = 100;
+ request.onComplete = dumpFifthFetch;
+ opmlStore.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.is(0, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpSixthFetch;
+ opmlStore.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.is(4, items.length);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.is(6, items.length);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ opmlStore.fetch(request);
+ }
+
+ opmlStore.fetch({onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+
+ },
+ function testReadAPI_getLabel(t){
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = opmlStore.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ t.assertEqual("Asia", label);
+ d.callback(true);
+ }
+ opmlStore.fetch({ query: {text: "Asia"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d;
+ },
+ function testReadAPI_getLabelAttributes(t){
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = opmlStore.getLabelAttributes(items[0]);
+ t.assertTrue(dojo.isArray(labelList));
+ t.assertEqual("text", labelList[0]);
+ d.callback(true);
+ }
+ opmlStore.fetch({ query: {text: "Asia"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d;
+ },
+
+ function testReadAPI_getLabel_nondefault(t){
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography_withspeciallabel.xml");
+ args.label="label";
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = opmlStore.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ t.assertEqual("Continent/Asia", label);
+ d.callback(true);
+ }
+ opmlStore.fetch({ query: {text: "Asia"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d;
+ },
+ function testReadAPI_getLabelAttributes_nondefault(t){
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography_withspeciallabel.xml");
+ args.label="label";
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = opmlStore.getLabelAttributes(items[0]);
+ t.assertTrue(dojo.isArray(labelList));
+ t.assertEqual("label", labelList[0]);
+ d.callback(true);
+ }
+ opmlStore.fetch({ query: {text: "Asia"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d;
+ },
+
+ function testReadAPI_getValue(t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(6, items.length);
+
+ t.is("Africa", opmlStore.getValue(items[0],"text"));
+ t.is("Asia", opmlStore.getValue(items[1],"text"));
+ t.is("Australia", opmlStore.getValue(items[2],"text"));
+ t.is("Europe", opmlStore.getValue(items[3],"text"));
+ t.is("North America", opmlStore.getValue(items[4],"text"));
+ t.is("South America", opmlStore.getValue(items[5],"text"));
+
+ t.is("continent", opmlStore.getValue(items[1],"type"));
+ t.is("21 million", opmlStore.getValue(items[2],"population"));
+
+ var firstChild = opmlStore.getValue(items[4],"children");
+ t.assertTrue(opmlStore.isItem(firstChild));
+ t.is("Mexico", opmlStore.getValue(firstChild,"text"));
+ t.is("country", opmlStore.getValue(firstChild,"type"));
+ t.is("108 million", opmlStore.getValue(firstChild,"population"));
+ t.is("1,972,550 sq km", opmlStore.getValue(firstChild,"area"));
+
+ firstChild = opmlStore.getValue(firstChild,"children");
+ t.assertTrue(opmlStore.isItem(firstChild));
+ t.is("Mexico City", opmlStore.getValue(firstChild,"text"));
+ t.is("city", opmlStore.getValue(firstChild,"type"));
+ t.is("19 million", opmlStore.getValue(firstChild,"population"));
+ t.is("-6 UTC", opmlStore.getValue(firstChild,"timezone"));
+
+ d.callback(true);
+ }
+
+ //Get everything...
+ opmlStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_getValues(t){
+ // summary:
+ // Simple test of the getValues function of the store.
+ // description:
+ // Simple test of the getValues function of the store.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items){
+ t.is(1, items.length);
+
+ var children = opmlStore.getValues(items[0],"children");
+ t.is(3, children.length);
+ for(var i=0; i<children.length; i++){
+ t.assertTrue(opmlStore.isItem(children[i]));
+ }
+
+ t.is("Mexico", opmlStore.getValues(children[0],"text")[0]);
+ t.is("country", opmlStore.getValues(children[0],"type")[0]);
+ t.is("108 million", opmlStore.getValues(children[0],"population")[0]);
+ t.is("1,972,550 sq km", opmlStore.getValues(children[0],"area")[0]);
+
+ t.is("Canada", opmlStore.getValues(children[1],"text")[0]);
+ t.is("country", opmlStore.getValues(children[1],"type")[0]);
+
+ children = opmlStore.getValues(children[1],"children");
+ t.is(2, children.length);
+ for(var i=0; i<children.length; i++){
+ t.assertTrue(opmlStore.isItem(children[i]));
+ }
+ t.is("Ottawa", opmlStore.getValues(children[0],"text")[0]);
+ t.is("Toronto", opmlStore.getValues(children[1],"text")[0]);
+
+ d.callback(true);
+ }
+
+ //Get one item...
+ opmlStore.fetch({ query: {text: "North America"},
+ onComplete: completed,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_isItem(t){
+ // summary:
+ // Simple test of the isItem function of the store
+ // description:
+ // Simple test of the isItem function of the store
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.is(6, items.length);
+ for(var i=0; i<6; i++){
+ t.assertTrue(opmlStore.isItem(items[i]));
+ }
+ t.assertTrue(!opmlStore.isItem({}));
+ t.assertTrue(!opmlStore.isItem({ item: "not an item" }));
+ t.assertTrue(!opmlStore.isItem("not an item"));
+ t.assertTrue(!opmlStore.isItem(["not an item"]));
+
+ d.callback(true);
+ }
+
+ //Get everything...
+ opmlStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_hasAttribute(t){
+ // summary:
+ // Simple test of the hasAttribute function of the store
+ // description:
+ // Simple test of the hasAttribute function of the store
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ t.assertTrue(items[0] !== null);
+ t.assertTrue(opmlStore.hasAttribute(items[0], "text"));
+ t.assertTrue(opmlStore.hasAttribute(items[0], "type"));
+ t.assertTrue(!opmlStore.hasAttribute(items[0], "population"));
+ t.assertTrue(!opmlStore.hasAttribute(items[0], "Nothing"));
+ t.assertTrue(!opmlStore.hasAttribute(items[0], "Text"));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ opmlStore.hasAttribute(items[0], null);
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+
+ d.callback(true);
+ }
+
+ //Get one item...
+ opmlStore.fetch({ query: {text: "Asia"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d; //Object
+ },
+ function testReadAPI_containsValue(t){
+ // summary:
+ // Simple test of the containsValue function of the store
+ // description:
+ // Simple test of the containsValue function of the store
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(1, items.length);
+ t.assertTrue(items[0] !== null);
+ t.assertTrue(opmlStore.containsValue(items[0], "text", "North America"));
+ t.assertTrue(opmlStore.containsValue(items[0], "type", "continent"));
+ t.assertTrue(!opmlStore.containsValue(items[0], "text", "America"));
+ t.assertTrue(!opmlStore.containsValue(items[0], "Type", "continent"));
+ t.assertTrue(!opmlStore.containsValue(items[0], "text", null));
+
+ var children = opmlStore.getValues(items[0], "children");
+ t.assertTrue(opmlStore.containsValue(items[0], "children", children[0]));
+ t.assertTrue(opmlStore.containsValue(items[0], "children", children[1]));
+ t.assertTrue(opmlStore.containsValue(items[0], "children", children[2]));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ opmlStore.containsValue(items[0], null, "foo");
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+
+ d.callback(true);
+ }
+
+ //Get one item...
+ opmlStore.fetch({ query: {text: "North America"},
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+ });
+ return d; //Object
+ },
+ function testReadAPI_getAttributes(t){
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.is(6, items.length);
+ t.assertTrue(opmlStore.isItem(items[0]));
+
+ var attributes = opmlStore.getAttributes(items[0]);
+ t.is(3, attributes.length);
+ for(var i = 0; i < attributes.length; i++){
+ t.assertTrue((attributes[i] === "text" || attributes[i] === "type" || attributes[i] === "children"));
+ }
+
+ d.callback(true);
+ }
+
+ //Get everything...
+ opmlStore.fetch({ onComplete: onComplete, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var features = opmlStore.getFeatures();
+ var count = 0;
+ for(i in features){
+ t.assertTrue((i === "dojo.data.api.Read") || (i === "dojo.data.api.Identity"));
+ count++;
+ }
+ t.assertTrue(count === 2);
+ },
+ function testReadAPI_fetch_patternMatch0(t){
+ // summary:
+ // Function to test pattern matching of everything starting with Capital A
+ // description:
+ // Function to test pattern matching of everything starting with Capital A
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(3, items.length);
+ var valueArray = [ "Africa", "Asia", "Australia"];
+ t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", valueArray));
+ d.callback(true);
+ }
+
+ opmlStore.fetch({query: {text: "A*"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch1(t){
+ // summary:
+ // Function to test pattern matching of everything with America in it.
+ // description:
+ // Function to test pattern matching of everything with America in it.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertTrue(items.length === 2);
+ var valueArray = [ "North America", "South America"];
+ t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", valueArray));
+ d.callback(true);
+ }
+
+ opmlStore.fetch({query: {text: "*America*"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch2(t){
+ // summary:
+ // Function to test exact pattern match
+ // description:
+ // Function to test exact pattern match
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(1, items.length);
+ t.assertTrue(opmlStore.getValue(items[0], "text") === "Europe");
+ d.callback(true);
+ }
+
+ opmlStore.fetch({query: {text: "Europe"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch_caseInsensitive(t){
+ // summary:
+ // Function to test exact pattern match with case insensitivity set.
+ // description:
+ // Function to test exact pattern match with case insensitivity set.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(1, items.length);
+ t.assertTrue(opmlStore.getValue(items[0], "text") === "Asia");
+ d.callback(true);
+ }
+
+ opmlStore.fetch({query: {text: "asia"}, queryOptions: {ignoreCase: true}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_patternMatch_caseSensitive(t){
+ // summary:
+ // Function to test exact pattern match with case sensitivity set.
+ // description:
+ // Function to test exact pattern match with case sensitivity set.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.is(0, items.length);
+ d.callback(true);
+ }
+
+ opmlStore.fetch({query: {text: "ASIA"}, queryOptions: {ignoreCase: false}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortAlphabetic(t){
+ // summary:
+ // Function to test sorting alphabetic ordering.
+ // description:
+ // Function to test sorting alphabetic ordering.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [ "Africa", "Asia", "Australia", "Europe", "North America", "South America"];
+ t.is(6, items.length);
+ t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "text"}];
+ opmlStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortAlphabeticDescending(t){
+ // summary:
+ // Function to test sorting alphabetic ordering in descending mode.
+ // description:
+ // Function to test sorting alphabetic ordering in descending mode.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [ "South America", "North America", "Europe", "Australia", "Asia", "Africa"
+ ];
+ t.is(6, items.length);
+ t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "text", descending: true}];
+ opmlStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_fetch_sortAlphabeticWithCount(t){
+ // summary:
+ // Function to test sorting numerically in descending order, returning only a specified number of them.
+ // description:
+ // Function to test sorting numerically in descending order, returning only a specified number of them.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [ "South America", "North America", "Europe", "Australia"
+ ];
+ t.is(4, items.length);
+ t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", orderedArray));
+ d.callback(true);
+ }
+
+ var sortAttributes = [{attribute: "text", descending: true}];
+ opmlStore.fetch({sort: sortAttributes,
+ count: 4,
+ onComplete: completed,
+ onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d; //Object
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = new dojox.data.OpmlStore(dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"));
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ if(i.toString().charAt(0) !== '_')
+ {
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ },
+ function testIdentityAPI_fetchItemByIdentity(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ d.callback(true);
+ }
+ opmlStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d;
+ },
+
+ function testIdentityAPI_fetchItemByIdentity_bad1(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ opmlStore.fetchItemByIdentity({identity: "200", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_fetchItemByIdentity_bad2(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ opmlStore.fetchItemByIdentity({identity: "-1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_fetchItemByIdentity_bad3(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ opmlStore.fetchItemByIdentity({identity: "999999", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+ return d;
+ },
+ function testIdentityAPI_getIdentity(t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+
+ var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+ var opmlStore = new dojox.data.OpmlStore(args);
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ console.log("Identity is: " + opmlStore.getIdentity(items[i]) + " count is : "+ i);
+ if(!(opmlStore.getIdentity(items[i]) == i)){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+
+ //Get everything...
+ opmlStore.fetch({ onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d), queryOptions: {deep: true}});
+ return d; //Object
+ },
+ function testIdentityAPI_functionConformance(t){
+ // summary:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = new dojox.data.OpmlStore(dojox.data.tests.stores.CsvStore.getDatasource("stores/geography.xml"));
+ var identityApi = new dojo.data.api.Identity();
+ var passed = true;
+
+ for(i in identityApi){
+ if(i.toString().charAt(0) !== '_')
+ {
+ var member = identityApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ console.log("Looking at function: [" + i + "]");
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+
+}
diff --git a/includes/js/dojox/data/tests/stores/QueryReadStore.js b/includes/js/dojox/data/tests/stores/QueryReadStore.js
new file mode 100644
index 0000000..f725f06
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/QueryReadStore.js
@@ -0,0 +1,442 @@
+if(!dojo._hasResource["dojox.data.tests.stores.QueryReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.QueryReadStore"] = true;
+dojo.provide("dojox.data.tests.stores.QueryReadStore");
+dojo.require("dojox.data.QueryReadStore");
+dojo.require("dojo.data.api.Read");
+
+//dojo.require("dojox.testing.DocTest");
+
+dojox.data.tests.stores.QueryReadStore.getStore = function(){
+ return new dojox.data.QueryReadStore({
+ url: dojo.moduleUrl("dojox.data.tests", "stores/QueryReadStore.php").toString()
+ });
+};
+
+
+tests.register("dojox.data.tests.stores.QueryReadStore",
+ [
+ /*
+ function testDocTests(t) {
+ // summary:
+ // Run all the doc comments.
+ var doctest = new dojox.testing.DocTest();
+ doctest.run("dojox.data.QueryReadStore");
+ t.assertTrue(doctest.errors.length==0);
+ },
+ */
+
+ function testReadApi_getValue(t){
+ // summary:
+ // description:
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ var item = items[0];
+ // The good cases.
+ t.assertEqual("Alabama", store.getValue(item, "name"));
+ t.assertEqual("<img src='images/Alabama.jpg'/>Alabama", store.getValue(item, "label"));
+ t.assertEqual("AL", store.getValue(item, "abbreviation"));
+ // Test the defaultValue cases (the third paramter).
+ t.assertEqual("default value", store.getValue(item, "NAME", "default value"));
+ // TODO Test for null somehow ...
+ // Read api says: Returns null if and only if null was explicitly set as the attribute value.
+
+ // According to Read-API getValue() an exception is thrown when
+ // the item is not an item or when the attribute is not a string.
+ t.assertError(Error, store, "getValue", ["not an item", "NOT THERE"]);
+ t.assertError(Error, store, "getValue", [item, {}]);
+
+ d.callback(true);
+ }
+ store.fetch({query:{q:"Alabama"}, onComplete: onComplete});
+ return d; //Object
+ },
+
+ function testReadApi_getValues(t){
+ // summary:
+ // description:
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ var item = items[0];
+ // The good cases.
+ t.assertEqual(["Alabama"], store.getValues(item, "name"));
+ t.assertEqual(["<img src='images/Alabama.jpg'/>Alabama"], store.getValues(item, "label"));
+ t.assertEqual(["AL"], store.getValues(item, "abbreviation"));
+ // TODO Test for null somehow ...
+ // Read api says: Returns null if and only if null was explicitly set as the attribute value.
+
+ // Test for not-existing attributes without defaultValues and invalid items.
+ // TODO
+ t.assertEqual([], store.getValues(item, "NOT THERE"));
+ var errThrown = false;
+ try{
+ //Should throw an exception.
+ var values = store.getValues("not an item", "NOT THERE");
+ }catch (e){
+ errThrown = true;
+ }
+ t.assertTrue(errThrown);
+ d.callback(true);
+ }
+ store.fetch({query:{q:"Alabama"}, onComplete: onComplete});
+ return d; //Object
+ },
+
+ function testReadApi_getAttributes(t){
+ // summary:
+ // description:
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ var item = items[0];
+ // The good case(s).
+ t.assertEqual(['id', 'name', 'label', 'abbreviation', 'capital'], store.getAttributes(item));
+ t.assertError(Error, store, "getAttributes", [{}]);
+
+ d.callback(true);
+ }
+ store.fetch({query:{q:"Alabama"}, onComplete: onComplete});
+ return d; //Object
+ },
+
+ function testReadApi_getLabel(t){
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ var item = items[0];
+ // The good cases.
+ t.assertEqual(["<img src='images/Alabama.jpg'/>Alabama"], store.getLabel(item));
+ d.callback(true);
+ }
+ store.fetch({query:{q:"Alabama"}, onComplete: onComplete});
+ return d; //Object
+ },
+
+ function testReadApi_hasAttribute(t){
+ // summary:
+ // description:
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ var item = items[0];
+ // The positive cases.
+ t.assertEqual(true, store.hasAttribute(item, "name"));
+ t.assertEqual(true, store.hasAttribute(item, "label"));
+ t.assertEqual(true, store.hasAttribute(item, "abbreviation"));
+ // Make sure attribute case doesnt matter.
+ t.assertEqual(false, store.hasAttribute(item, "NAME"));
+ t.assertEqual(false, store.hasAttribute(item, "Name"));
+ t.assertEqual(false, store.hasAttribute(item, "Label"));
+ // Pass in an invalid item.
+ t.assertEqual(false, store.hasAttribute({}, "abbreviation"));
+ // pass in something that looks like the item with the attribute.
+ t.assertEqual(false, store.hasAttribute({name:"yo"}, "name"));
+
+ d.callback(true);
+ }
+ store.fetch({query:{q:"Alaska"}, onComplete: onComplete});
+ return d; //Object
+ },
+
+ function testReadApi_containsValue(t){
+ // summary:
+ // description:
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ var item = items[0];
+ t.assertTrue(store.containsValue(item, "name", "Alaska"));
+ d.callback(true);
+ }
+ store.fetch({query:{q:"Alaska"}, onComplete: onComplete});
+ return d; //Object
+ },
+
+ function testReadApi_isItem(t){
+ // summary:
+ // description:
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ // The good case.
+ t.assertEqual(true, store.isItem(items[0]));
+ // Try a pure object.
+ t.assertEqual(false, store.isItem({}));
+ // Try to look like an item.
+ t.assertEqual(false, store.isItem({name:"Alaska", label:"Alaska", abbreviation:"AK"}));
+ d.callback(true);
+ }
+ store.fetch({query:{q:"Alaska"}, onComplete: onComplete});
+ return d; //Object
+ },
+
+ function testReadApi_isItemLoaded(t){
+ // summary:
+ // description:
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ var item = items[0];
+ // The good case(s).
+ t.assertTrue(store.isItemLoaded(item));
+
+ d.callback(true);
+ }
+ store.fetch({query:{q:"Alabama"}, onComplete: onComplete});
+ return d; //Object
+ },
+
+ //function testReadApi_loadItem(t){
+ // // summary:
+ // // description:
+ // t.assertTrue(false);
+ //},
+
+ function testReadApi_fetch_all(t){
+ // summary:
+ // Simple test of fetching all items.
+ // description:
+ // Simple test of fetching all items.
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(8, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{q:"m"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+
+ function testReadApi_fetch_onBegin(t){
+ // summary:
+ // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for.
+ // description:
+ // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for.
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ var passed = false;
+ function onBegin(size, request){
+ t.assertEqual(8, size);
+ passed = true;
+ }
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ if(passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Store did not return proper number of rows, regardless of page size"));
+ }
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{q:"m"}, start: 0, count: 5, onBegin: onBegin, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+
+ function testReadApi_fetch_onBegin_ServersidePaging(t){
+ // summary:
+ // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for.
+ // description:
+ // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for.
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ var passed = false;
+ function onBegin(size, request){
+ t.assertEqual(8, size);
+ passed = true;
+ }
+ function onComplete(items, request) {
+ t.assertEqual(3, items.length);
+ if(passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Store did not return proper number of rows, regardless of page size"));
+ }
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{q:"m"}, start: 5, count: 5, onBegin: onBegin, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+
+ function testReadApi_fetch_onBegin_ClientsidePaging(t){
+ // summary:
+ // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for.
+ // description:
+ // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for.
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+ store.doClientPaging = true;
+
+ var d = new doh.Deferred();
+ var passed = false;
+ function onBegin(size, request){
+ t.assertEqual(8, size);
+ passed = true;
+ }
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ if(passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Store did not return proper number of rows, regardless of page size"));
+ }
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{q:"m"}, start: 0, count: 5, onBegin: onBegin, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+
+ function testReadApi_fetch_one(t){
+ // summary:
+ // description:
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{q:"Alaska"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+
+ function testReadApi_fetch_client_paging(t){
+ // summary:
+ // Lets test that paging on the same request does not trigger
+ // server requests.
+ // description:
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+ store.doClientPaging = true;
+
+ var lastRequestHash = null;
+ var firstItems = [];
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ lastRequestHash = store.lastRequestHash;
+ firstItems = items;
+
+ // Do the next request AFTER the previous one, so we are sure its sequential.
+ // We need to be sure so we can compare to the data from the first request.
+ function onComplete1(items, request) {
+ t.assertEqual(5, items.length);
+ t.assertEqual(lastRequestHash, store.lastRequestHash);
+ t.assertEqual(firstItems[1], items[0]);
+ d.callback(true);
+ }
+ req.start = 1;
+ req.onComplete = onComplete1;
+ store.fetch(req);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ var req = {query:{q:"m"}, start:0, count:5,
+ onComplete: onComplete, onError: onError};
+ store.fetch(req);
+ return d; //Object
+ },
+
+ function testReadApi_fetch_server_paging(t) {
+ // Verify that the paging on the server side does work.
+ // This is the test for http://trac.dojotoolkit.org/ticket/4761
+ //
+ // How? We request 10 items from the server, start=0, count=10.
+ // The second request requests 5 items: start=5, count=5 and those
+ // 5 items should have the same values as the last 5 of the first
+ // request.
+ // This tests if the server side paging does work.
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+
+ var lastRequestHash = null;
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(10, items.length);
+ lastRequestHash = store.lastRequestHash;
+ firstItems = items;
+
+ // Do the next request AFTER the previous one, so we are sure its sequential.
+ // We need to be sure so we can compare to the data from the first request.
+ function onComplete1(items, request) {
+ t.assertEqual(5, items.length);
+ // Compare the hash of the last request, they must be different,
+ // since another server request was issued.
+ t.assertTrue(lastRequestHash!=store.lastRequestHash);
+ t.assertEqual(store.getValue(firstItems[5], "name"), store.getValue(items[0], "name"));
+ t.assertEqual(store.getValue(firstItems[6], "name"), store.getValue(items[1], "name"));
+ t.assertEqual(store.getValue(firstItems[7], "name"), store.getValue(items[2], "name"));
+ t.assertEqual(store.getValue(firstItems[8], "name"), store.getValue(items[3], "name"));
+ t.assertEqual(store.getValue(firstItems[9], "name"), store.getValue(items[4], "name"));
+ d.callback(true);
+ }
+ // Init a new store, or it will use the old data, since the query has not changed.
+ store.doClientPaging = false;
+ store.fetch({start:5, count:5, onComplete: onComplete1, onError: onError});
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{}, start:0, count:10, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+
+ function testReadApi_getFeatures(t) {
+ var store = dojox.data.tests.stores.QueryReadStore.getStore();
+ var features = store.getFeatures();
+ t.assertTrue(features["dojo.data.api.Read"]);
+ t.assertTrue(features["dojo.data.api.Identity"]);
+ var count = 0;
+ for (i in features){
+ count++;
+ }
+ t.assertEqual(2, count);
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = dojox.data.tests.stores.QueryReadStore.getStore();
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ console.log("Problem with function: [" + i + "]");
+ passed = false;
+ break;
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/data/tests/stores/QueryReadStore.php b/includes/js/dojox/data/tests/stores/QueryReadStore.php
new file mode 100644
index 0000000..26fbcde
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/QueryReadStore.php
@@ -0,0 +1,114 @@
+<?php
+
+header("Content-Type", "text/json");
+
+$allItems = array(
+ array('id'=>0, 'name'=>"Alabama", 'label'=>"<img src='images/Alabama.jpg'/>Alabama", 'abbreviation'=>"AL", 'capital'=>'Montgomery'),
+ array('id'=>1, 'name'=>"Alaska", 'label'=>"Alaska", 'abbreviation'=>"AK", 'capital'=>'Juneau'),
+ //array('id'=>2, 'name'=>"American Samoa", 'label'=>"American Samoa", 'abbreviation'=>"AS", 'capital'=>''),
+ array('id'=>3, 'name'=>"Arizona", 'label'=>"Arizona", 'abbreviation'=>"AZ", 'capital'=>'Phoenix'),
+ array('id'=>4, 'name'=>"Arkansas", 'label'=>"Arkansas", 'abbreviation'=>"AR", 'capital'=>'Little Rock'),
+ //array('id'=>5, 'name'=>"Armed Forces Europe", 'label'=>"Armed Forces Europe", 'abbreviation'=>"AE", 'capital'=>''),
+ //array('id'=>6, 'name'=>"Armed Forces Pacific", 'label'=>"Armed Forces Pacific", 'abbreviation'=>"AP", 'capital'=>''),
+ //array('id'=>7, 'name'=>"Armed Forces the Americas", 'label'=>"Armed Forces the Americas", 'abbreviation'=>"AA", 'capital'=>''),
+ array('id'=>8, 'name'=>"California", 'label'=>"California", 'abbreviation'=>"CA", 'capital'=>'Sacramento'),
+ array('id'=>9, 'name'=>"Colorado", 'label'=>"Colorado", 'abbreviation'=>"CO", 'capital'=>'Denver'),
+ array('id'=>10, 'name'=>"Connecticut", 'label'=>"Connecticut", 'abbreviation'=>"CT", 'capital'=>'Hartford'),
+ array('id'=>11, 'name'=>"Delaware", 'label'=>"Delaware", 'abbreviation'=>"DE", 'capital'=>'Dover'),
+ //array('id'=>12, 'name'=>"District of Columbia", 'label'=>"District of Columbia", 'abbreviation'=>"DC", 'capital'=>''),
+ //array('id'=>13, 'name'=>"Federated States of Micronesia", 'label'=>"Federated States of Micronesia", 'abbreviation'=>"FM", 'capital'=>''),
+ array('id'=>14, 'name'=>"Florida", 'label'=>"Florida", 'abbreviation'=>"FL", 'capital'=>'Tallahassee'),
+ array('id'=>15, 'name'=>"Georgia", 'label'=>"Georgia", 'abbreviation'=>"GA", 'capital'=>'Atlanta'),
+ //array('id'=>16, 'name'=>"Guam", 'label'=>"Guam", 'abbreviation'=>"GU", 'capital'=>''),
+ array('id'=>17, 'name'=>"Hawaii", 'label'=>"Hawaii", 'abbreviation'=>"HI", 'capital'=>'Honolulu'),
+ array('id'=>18, 'name'=>"Idaho", 'label'=>"Idaho", 'abbreviation'=>"ID", 'capital'=>'Boise'),
+ array('id'=>19, 'name'=>"Illinois", 'label'=>"Illinois", 'abbreviation'=>"IL", 'capital'=>'Springfield'),
+ array('id'=>20, 'name'=>"Indiana", 'label'=>"Indiana", 'abbreviation'=>"IN", 'capital'=>'Indianapolis'),
+ array('id'=>21, 'name'=>"Iowa", 'label'=>"Iowa", 'abbreviation'=>"IA", 'capital'=>'Des Moines'),
+ array('id'=>22, 'name'=>"Kansas", 'label'=>"Kansas", 'abbreviation'=>"KS", 'capital'=>'Topeka'),
+ array('id'=>23, 'name'=>"Kentucky", 'label'=>"Kentucky", 'abbreviation'=>"KY", 'capital'=>'Frankfort'),
+ array('id'=>24, 'name'=>"Louisiana", 'label'=>"Louisiana", 'abbreviation'=>"LA", 'capital'=>'Baton Rouge'),
+ array('id'=>25, 'name'=>"Maine", 'label'=>"Maine", 'abbreviation'=>"ME", 'capital'=>'Augusta'),
+ //array('id'=>26, 'name'=>"Marshall Islands", 'label'=>"Marshall Islands", 'abbreviation'=>"MH", 'capital'=>''),
+ array('id'=>27, 'name'=>"Maryland", 'label'=>"Maryland", 'abbreviation'=>"MD", 'capital'=>'Annapolis'),
+ array('id'=>28, 'name'=>"Massachusetts", 'label'=>"Massachusetts", 'abbreviation'=>"MA", 'capital'=>'Boston'),
+ array('id'=>29, 'name'=>"Michigan", 'label'=>"Michigan", 'abbreviation'=>"MI", 'capital'=>'Lansing'),
+ array('id'=>30, 'name'=>"Minnesota", 'label'=>"Minnesota", 'abbreviation'=>"MN", 'capital'=>'Saint Paul'),
+ array('id'=>31, 'name'=>"Mississippi", 'label'=>"Mississippi", 'abbreviation'=>"MS", 'capital'=>'Jackson'),
+ array('id'=>32, 'name'=>"Missouri", 'label'=>"Missouri", 'abbreviation'=>"MO", 'capital'=>'Jefferson City'),
+ array('id'=>33, 'name'=>"Montana", 'label'=>"Montana", 'abbreviation'=>"MT", 'capital'=>'Helena'),
+ array('id'=>34, 'name'=>"Nebraska", 'label'=>"Nebraska", 'abbreviation'=>"NE", 'capital'=>'Lincoln'),
+ array('id'=>35, 'name'=>"Nevada", 'label'=>"Nevada", 'abbreviation'=>"NV", 'capital'=>'Carson City'),
+ array('id'=>36, 'name'=>"New Hampshire", 'label'=>"New Hampshire", 'abbreviation'=>"NH", 'capital'=>'Concord'),
+ array('id'=>37, 'name'=>"New Jersey", 'label'=>"New Jersey", 'abbreviation'=>"NJ", 'capital'=>'Trenton'),
+ array('id'=>38, 'name'=>"New Mexico", 'label'=>"New Mexico", 'abbreviation'=>"NM", 'capital'=>'Santa Fe'),
+ array('id'=>39, 'name'=>"New York", 'label'=>"New York", 'abbreviation'=>"NY", 'capital'=>'Albany'),
+ array('id'=>40, 'name'=>"North Carolina", 'label'=>"North Carolina", 'abbreviation'=>"NC", 'capital'=>'Raleigh'),
+ array('id'=>41, 'name'=>"North Dakota", 'label'=>"North Dakota", 'abbreviation'=>"ND", 'capital'=>'Bismarck'),
+ //array('id'=>42, 'name'=>"Northern Mariana Islands", 'label'=>"Northern Mariana Islands", 'abbreviation'=>"MP", 'capital'=>''),
+ array('id'=>43, 'name'=>"Ohio", 'label'=>"Ohio", 'abbreviation'=>"OH", 'capital'=>'Columbus'),
+ array('id'=>44, 'name'=>"Oklahoma", 'label'=>"Oklahoma", 'abbreviation'=>"OK", 'capital'=>'Oklahoma City'),
+ array('id'=>45, 'name'=>"Oregon", 'label'=>"Oregon", 'abbreviation'=>"OR", 'capital'=>'Salem'),
+ array('id'=>46, 'name'=>"Pennsylvania", 'label'=>"Pennsylvania", 'abbreviation'=>"PA", 'capital'=>'Harrisburg'),
+ //array('id'=>47, 'name'=>"Puerto Rico", 'label'=>"Puerto Rico", 'abbreviation'=>"PR", 'capital'=>''),
+ array('id'=>48, 'name'=>"Rhode Island", 'label'=>"Rhode Island", 'abbreviation'=>"RI", 'capital'=>'Providence'),
+ array('id'=>49, 'name'=>"South Carolina", 'label'=>"South Carolina", 'abbreviation'=>"SC", 'capital'=>'Columbia'),
+ array('id'=>50, 'name'=>"South Dakota", 'label'=>"South Dakota", 'abbreviation'=>"SD", 'capital'=>'Pierre'),
+ array('id'=>51, 'name'=>"Tennessee", 'label'=>"Tennessee", 'abbreviation'=>"TN", 'capital'=>'Nashville'),
+ array('id'=>52, 'name'=>"Texas", 'label'=>"Texas", 'abbreviation'=>"TX", 'capital'=>'Austin'),
+ array('id'=>53, 'name'=>"Utah", 'label'=>"Utah", 'abbreviation'=>"UT", 'capital'=>'Salt Lake City'),
+ array('id'=>54, 'name'=>"Vermont", 'label'=>"Vermont", 'abbreviation'=>"VT", 'capital'=>'Montpelier'),
+ //array('id'=>55, 'name'=> "Virgin Islands, U.S.", 'label'=>"Virgin Islands, U.S.", 'abbreviation'=>"VI", 'capital'=>''),
+ array('id'=>56, 'name'=>"Virginia", 'label'=>"Virginia", 'abbreviation'=>"VA", 'capital'=>'Richmond'),
+ array('id'=>57, 'name'=>"Washington", 'label'=>"Washington", 'abbreviation'=>"WA", 'capital'=>'Olympia'),
+ array('id'=>58, 'name'=>"West Virginia", 'label'=>"West Virginia", 'abbreviation'=>"WV", 'capital'=>'Charleston'),
+ array('id'=>59, 'name'=>"Wisconsin", 'label'=>"Wisconsin", 'abbreviation'=>"WI", 'capital'=>'Madison'),
+ array('id'=>60, 'name'=>"Wyoming", 'label'=>"Wyoming", 'abbreviation'=>"WY", 'capital'=>'Cheyenne'),
+);
+
+$q = "";
+if (array_key_exists("q", $_REQUEST)) {
+ $q = $_REQUEST['q'];
+}else if (array_key_exists("name", $_REQUEST)) {
+ $q = $_REQUEST['name'];
+}
+
+if (strlen($q) && $q[strlen($q)-1]=="*") {
+ $q = substr($q, 0, strlen($q)-1);
+}
+$ret = array();
+foreach ($allItems as $item) {
+ if (!$q || strpos(strtolower($item['name']), strtolower($q))===0) {
+ $ret[] = $item;
+ }
+}
+
+// Handle sorting
+if (array_key_exists("sort", $_REQUEST)) {
+ $sort = $_REQUEST['sort'];
+ // Check if $sort starts with "-" then we have a DESC sort.
+ $desc = strpos($sort, '-')===0 ? true : false;
+ $sort = strpos($sort, '-')===0 ? substr($sort, 1) : $sort;
+ if (in_array($sort, array_keys($ret[0]))) {
+ $toSort = array();
+ foreach ($ret as $i) $toSort[$i[$sort]] = $i;
+ if ($desc) krsort($toSort); else ksort($toSort);
+ $newRet = array();
+ foreach ($toSort as $i) $newRet[] = $i;
+ $ret = $newRet;
+ }
+}
+
+
+// Handle total number of matches as a return, regardless of page size, but taking the filtering into account (if taken place).
+$numRows = count($ret);
+
+// Handle paging, if given.
+if (array_key_exists("start", $_REQUEST)) {
+ $ret = array_slice($ret, $_REQUEST['start']);
+}
+if (array_key_exists("count", $_REQUEST)) {
+ $ret = array_slice($ret, 0, $_REQUEST['count']);
+}
+
+print '/*'.json_encode(array('numRows'=>$numRows, 'items'=>$ret, 'identity'=>'id')).'*/';
diff --git a/includes/js/dojox/data/tests/stores/SnapLogicStore.js b/includes/js/dojox/data/tests/stores/SnapLogicStore.js
new file mode 100644
index 0000000..d544799
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/SnapLogicStore.js
@@ -0,0 +1,438 @@
+if(!dojo._hasResource["dojox.data.tests.stores.SnapLogicStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.SnapLogicStore"] = true;
+dojo.provide("dojox.data.tests.stores.SnapLogicStore");
+dojo.require("dojox.data.SnapLogicStore");
+dojo.require("dojo.data.api.Read");
+
+dojox.data.tests.stores.SnapLogicStore.pipelineUrl = dojo.moduleUrl("dojox.data.tests", "stores/snap_pipeline.php").toString();
+dojox.data.tests.stores.SnapLogicStore.pipelineSize = 14;
+dojox.data.tests.stores.SnapLogicStore.attributes = ["empno", "ename", "job", "hiredate", "sal", "comm", "deptno"];
+
+dojox.data.tests.stores.SnapLogicStore.error = function(t, d, errData){
+ // summary:
+ // The error callback function to be used for all of the tests.
+ d.errback(errData);
+}
+
+doh.register("dojox.data.tests.stores.SnapLogicStore",
+ [
+ {
+ name: "ReadAPI: Fetch One",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Simple test of a basic fetch from a SnapLogic pipeline
+ // description:
+ // Simple test of a basic fetch from a SnapLogic pipeline
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ store.fetch({ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, doh, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: Fetch_10_Streaming",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Simple test of a basic fetch on SnapLogic pipeline.
+ // description:
+ // Simple test of a basic fetch on SnapLogic pipeline.
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ count = 0;
+
+ function onBegin(size, requestObj){
+ t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize, size);
+ }
+ function onItem(item, requestObj){
+ t.assertTrue(store.isItem(item));
+ count++;
+ }
+ function onComplete(items, request){
+ t.assertEqual(10, count);
+ t.assertTrue(items === null);
+ d.callback(true);
+ }
+
+ //Get everything...
+ store.fetch({ onBegin: onBegin,
+ count: 10,
+ onItem: onItem,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: Fetch Zero",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Try fetching 0 records. A count of the items in the pipeline should be returned.
+ // description:
+ // Try fetching 0 records. A count of the items in the pipeline should be returned.
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function onBegin(count, request){
+ t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize, count);
+ d.callback(true);
+ }
+ store.fetch({ count: 0,
+ onBegin: onBegin,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, doh, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: Fetch_Paging",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Test of multiple fetches on a single result. Paging, if you will.
+ // description:
+ // Test of multiple fetches on a single result. Paging, if you will.
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.assertEqual(request.count, items.length);
+ request.start = dojox.data.tests.stores.SnapLogicStore.pipelineSize / 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ store.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.assertEqual(1, items.length);
+ request.start = 0;
+ request.count = dojox.data.tests.stores.SnapLogicStore.pipelineSize / 2;
+ request.onComplete = dumpThirdFetch;
+ store.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.assertEqual(request.count, items.length);
+ request.count = dojox.data.tests.stores.SnapLogicStore.pipelineSize * 2;
+ request.onComplete = dumpFourthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize, items.length);
+ request.start = Math.floor(3 * dojox.data.tests.stores.SnapLogicStore.pipelineSize / 4);
+ request.count = dojox.data.tests.stores.SnapLogicStore.pipelineSize;
+ request.onComplete = dumpFifthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize - request.start, items.length);
+ request.start = 2;
+ request.count = dojox.data.tests.stores.SnapLogicStore.pipelineSize * 10;
+ request.onComplete = dumpSixthFetch;
+ store.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize - request.start, items.length);
+ d.callback(true);
+ }
+
+ store.fetch({ count: 5,
+ onComplete: dumpFirstFetch,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getLabel",
+ timeout: 3000, //3 seconds
+ runTest: function(t) {
+ // summary:
+ // Test that the label function returns undefined since it's not supported.
+ // description:
+ // Test that the label function returns undefined since it's not supported.
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = store.getLabel(items[0]);
+ t.assertTrue(label === undefined);
+ d.callback(true);
+ }
+ store.fetch({ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)
+ });
+ return d;
+ }
+ },
+ {
+ name: "ReadAPI: getLabelAttributes",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getLabelAttributes returns null since it's not supported.
+ // description:
+ // Simple test of the getLabelAttributes returns null since it's not supported.
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = store.getLabelAttributes(items[0]);
+ t.assertTrue(labelList === null);
+ d.callback(true);
+ }
+ store.fetch({ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)
+ });
+ return d;
+ }
+ },
+ {
+ name: "ReadAPI: getValue",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.assertEqual(1, items.length);
+ console.debug(items[0]);
+ t.assertTrue(store.getValue(items[0], "empno") === 7369);
+ t.assertTrue(store.getValue(items[0], "ename") === "SMITH,CLERK");
+ console.debug(store.getValue(items[0], "sal"));
+ t.assertTrue(store.getValue(items[0], "sal") == 800.00);
+ console.debug(1);
+ t.assertTrue(store.getValue(items[0], "deptno") === 20);
+ d.callback(true);
+ }
+
+ store.fetch({ count: 1,
+ onComplete: completedAll,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)});
+ return d;
+ }
+ },
+ {
+ name: "ReadAPI: getValues",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.assertEqual(1, items.length);
+ for(var i = 0; i < dojox.data.tests.stores.SnapLogicStore.attributes.length; ++i){
+ var values = store.getValues(items[0], dojox.data.tests.stores.SnapLogicStore.attributes[i]);
+ t.assertTrue(dojo.isArray(values));
+ t.assertTrue(values[0] === store.getValue(items[0], dojox.data.tests.stores.SnapLogicStore.attributes[i]));
+ }
+ d.callback(true);
+ }
+
+ store.fetch({ count: 1,
+ onComplete: completedAll,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)});
+ return d;
+ }
+ },
+ {
+ name: "ReadAPI: isItem",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the isItem function of the store
+ // description:
+ // Simple test of the isItem function of the store
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function completedAll(items){
+ t.assertEqual(5, items.length);
+ for(var i=0; i < items.length; i++){
+ t.assertTrue(store.isItem(items[i]));
+ }
+ d.callback(true);
+ }
+
+ //Get everything...
+ store.fetch({ count: 5,
+ onComplete: completedAll,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: hasAttribute",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the hasAttribute function of the store
+ // description:
+ // Simple test of the hasAttribute function of the store
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.assertEqual(1, items.length);
+ t.assertTrue(items[0] !== null);
+ for(var i = 0; i < dojox.data.tests.stores.SnapLogicStore.attributes.length; ++i){
+ t.assertTrue(store.hasAttribute(items[0], dojox.data.tests.stores.SnapLogicStore.attributes[i]));
+ }
+ t.assertTrue(!store.hasAttribute(items[0], "Nothing"));
+ t.assertTrue(!store.hasAttribute(items[0], "Text"));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ store.hasAttribute(items[0], null);
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+
+ //Get one item...
+ store.fetch({ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: containsValue",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the containsValue function of the store
+ // description:
+ // Simple test of the containsValue function of the store
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.assertEqual(1, items.length);
+ var value = store.getValue(items[0], "LastName");
+ t.assertTrue(store.containsValue(items[0], "LastName", value));
+ d.callback(true);
+ }
+
+ //Get one item...
+ store.fetch({ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)
+ });
+ return d; //Object
+ }
+ },
+ {
+ name: "ReadAPI: getAttributes",
+ timeout: 3000, //3 seconds.
+ runTest: function(t) {
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var d = new doh.Deferred();
+ function onComplete(items){
+ t.assertEqual(1, items.length);
+
+ var itemAttributes = store.getAttributes(items[0]);
+ t.assertEqual(dojox.data.tests.stores.SnapLogicStore.attributes.length, itemAttributes.length);
+ for(var i = 0; i < dojox.data.tests.stores.SnapLogicStore.attributes.length; ++i){
+ t.assertTrue(dojo.indexOf(itemAttributes, dojox.data.tests.stores.SnapLogicStore.attributes[i]) !== -1);
+ }
+ d.callback(true);
+ }
+
+ //Get everything...
+ store.fetch({ count: 1,
+ onComplete: onComplete,
+ onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)});
+ return d; //Object
+ }
+ },
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+
+ var features = store.getFeatures();
+ var count = 0;
+ for(var i in features){
+ t.assertEqual(i, "dojo.data.api.Read");
+ count++;
+ }
+
+ t.assertEqual(count, 1);
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl});
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(var i in readApi){
+ if(i.toString().charAt(0) !== '_'){
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/data/tests/stores/XmlStore.js b/includes/js/dojox/data/tests/stores/XmlStore.js
new file mode 100644
index 0000000..0c99732
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/XmlStore.js
@@ -0,0 +1,881 @@
+if(!dojo._hasResource["dojox.data.tests.stores.XmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.XmlStore"] = true;
+dojo.provide("dojox.data.tests.stores.XmlStore");
+dojo.require("dojox.data.XmlStore");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Write");
+
+
+dojox.data.tests.stores.XmlStore.getBooks2Store = function(){
+ return new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books2.xml").toString(), label: "title"});
+};
+
+dojox.data.tests.stores.XmlStore.getBooksStore = function(){
+ return new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books.xml").toString(), label: "title"});
+};
+
+doh.register("dojox.data.tests.stores.XmlStore",
+ [
+ function testReadAPI_fetch_all(t){
+ // summary:
+ // Simple test of fetching all xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching all xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_one(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ {
+ name: "testReadAPI_fetch_paging",
+ timeout: 10000,
+ runTest: function(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn
+ var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.assertEqual(5, items.length);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ store.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.assertEqual(1, items.length);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ store.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.assertEqual(5, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpFourthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.assertEqual(18, items.length);
+ request.start = 9;
+ request.count = 100;
+ request.onComplete = dumpFifthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.assertEqual(11, items.length);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpSixthFetch;
+ store.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.assertEqual(18, items.length);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.assertEqual(20, items.length);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ store.fetch(request);
+ }
+
+ function error(errData, request){
+ d.errback(errData);
+ }
+
+ store.fetch({onComplete: completed, onError: error});
+ return d; //Object
+ }
+ },
+ function testReadAPI_fetch_pattern0(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern1(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(4, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B57?"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern2(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with * pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with * pattern match
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern_caseInsensitive(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode.
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode.
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?9b574"}, queryOptions: {ignoreCase: true}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_pattern_caseSensitive(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode.
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode.
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?9B574"}, queryOptions: {ignoreCase: false}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_all_rootItem(t){
+ // summary:
+ // Simple test of fetching all xml items through an XML element called isbn
+ // description:
+ // Simple test of fetching all xml items through an XML element called isbn
+ var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books3.xml").toString(),
+ rootItem:"book"});
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_withAttrMap_all(t){
+ var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr.xml").toString(),
+ attributeMap: {"book.isbn": "@isbn"}});
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ console.debug(error);
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_withAttrMap_one(t){
+ var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr.xml").toString(),
+ attributeMap: {"book.isbn": "@isbn"}});
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ console.debug(error);
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"2"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_withAttrMap_pattern0(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr2.xml").toString(),
+ attributeMap: {"book.isbn": "@isbn"}});
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(3, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"ABC?"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_withAttrMap_pattern1(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr2.xml").toString(),
+ attributeMap: {"book.isbn": "@isbn"}});
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(5, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_fetch_withAttrMap_pattern2(t){
+ // summary:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ // description:
+ // Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+ var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr2.xml").toString(),
+ attributeMap: {"book.isbn": "@isbn"}});
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(2, items.length);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"?C*"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+
+ function testReadAPI_getLabel(t){
+ // summary:
+ // Simple test of the getLabel function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabel function against a store set that has a label defined.
+
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var label = store.getLabel(items[0]);
+ t.assertTrue(label !== null);
+ t.assertEqual("Title of 4", label);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d;
+ },
+ function testReadAPI_getLabelAttributes(t){
+ // summary:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+ // description:
+ // Simple test of the getLabelAttributes function against a store set that has a label defined.
+
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var labelList = store.getLabelAttributes(items[0]);
+ t.assertTrue(dojo.isArray(labelList));
+ t.assertEqual("title", labelList[0]);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d;
+ },
+
+ function testReadAPI_getValue(t){
+ // summary:
+ // Simple test of the getValue API
+ // description:
+ // Simple test of the getValue API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.hasAttribute(item,"isbn"));
+ t.assertEqual(store.getValue(item,"isbn"), "A9B574");
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_getValues(t){
+ // summary:
+ // Simple test of the getValues API
+ // description:
+ // Simple test of the getValues API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.hasAttribute(item,"isbn"));
+ var values = store.getValues(item,"isbn");
+ t.assertEqual(1,values.length);
+ t.assertEqual("A9B574", values[0]);
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_isItem(t){
+ // summary:
+ // Simple test of the isItem API
+ // description:
+ // Simple test of the isItem API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.isItem(item));
+ t.assertTrue(!store.isItem({}));
+ t.assertTrue(!store.isItem("Foo"));
+ t.assertTrue(!store.isItem(1));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_isItem_multistore(t){
+ // summary:
+ // Simple test of the isItem API across multiple store instances.
+ // description:
+ // Simple test of the isItem API across multiple store instances.
+ var store1 = dojox.data.tests.stores.XmlStore.getBooks2Store();
+ var store2 = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete1(items, request) {
+ t.assertEqual(1, items.length);
+ var item1 = items[0];
+ t.assertTrue(store1.isItem(item1));
+
+ function onComplete2(items, request) {
+ t.assertEqual(1, items.length);
+ var item2 = items[0];
+ t.assertTrue(store2.isItem(item2));
+ t.assertTrue(!store1.isItem(item2));
+ t.assertTrue(!store2.isItem(item1));
+ d.callback(true);
+ }
+ store2.fetch({query:{isbn:"A9B574"}, onComplete: onComplete2, onError: onError});
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store1.fetch({query:{isbn:"A9B574"}, onComplete: onComplete1, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_hasAttribute(t){
+ // summary:
+ // Simple test of the hasAttribute API
+ // description:
+ // Simple test of the hasAttribute API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.hasAttribute(item,"isbn"));
+ t.assertTrue(!store.hasAttribute(item,"bob"));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_containsValue(t){
+ // summary:
+ // Simple test of the containsValue API
+ // description:
+ // Simple test of the containsValue API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+ t.assertTrue(!store.containsValue(item,"isbn", "bob"));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortDescending(t){
+ // summary:
+ // Simple test of the sorting API in descending order.
+ // description:
+ // Simple test of the sorting API in descending order.
+ var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+ //Comparison is done as a string type (toString comparison), so the order won't be numeric
+ //So have to compare in 'alphabetic' order.
+ var order = [9,8,7,6,5,4,3,20,2,19,18,17,16,15,14,13,12,11,10,1];
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ console.log("Number of items: " + items.length);
+ t.assertEqual(20, items.length);
+
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(order[i], store.getValue(items[i],"isbn").toString());
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn", descending: true}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortAscending(t){
+ // summary:
+ // Simple test of the sorting API in ascending order.
+ // description:
+ // Simple test of the sorting API in ascending order.
+ var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+ //Comparison is done as a string type (toString comparison), so the order won't be numeric
+ //So have to compare in 'alphabetic' order.
+ var order = [1,10,11,12,13,14,15,16,17,18,19,2,20,3,4,5,6,7,8,9];
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ var itemId = 1;
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(order[i], store.getValue(items[i],"isbn").toString());
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn"}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortDescendingNumeric(t){
+ // summary:
+ // Simple test of the sorting API in descending order using a numeric comparator.
+ // description:
+ // Simple test of the sorting API in descending order using a numeric comparator.
+ var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+ //isbn should be treated as a numeric, not as a string comparison
+ store.comparatorMap = {};
+ store.comparatorMap["isbn"] = function(a, b){
+ var ret = 0;
+ if(parseInt(a.toString()) > parseInt(b.toString())){
+ ret = 1;
+ }else if(parseInt(a.toString()) < parseInt(b.toString())){
+ ret = -1;
+ }
+ return ret; //int, {-1,0,1}
+ };
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ var itemId = 20;
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(itemId, store.getValue(items[i],"isbn").toString());
+ itemId--;
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn", descending: true}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_sortAscendingNumeric(t){
+ // summary:
+ // Simple test of the sorting API in ascending order using a numeric comparator.
+ // description:
+ // Simple test of the sorting API in ascending order using a numeric comparator.
+ var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+ //isbn should be treated as a numeric, not as a string comparison
+ store.comparatorMap = {};
+ store.comparatorMap["isbn"] = function(a, b){
+ var ret = 0;
+ if(parseInt(a.toString()) > parseInt(b.toString())){
+ ret = 1;
+ }else if(parseInt(a.toString()) < parseInt(b.toString())){
+ ret = -1;
+ }
+ return ret; //int, {-1,0,1}
+ };
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(20, items.length);
+ var itemId = 1;
+ for(var i = 0; i < items.length; i++){
+ t.assertEqual(itemId, store.getValue(items[i],"isbn").toString());
+ itemId++;
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "isbn"}];
+ store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_isItemLoaded(t){
+ // summary:
+ // Simple test of the isItemLoaded API
+ // description:
+ // Simple test of the isItemLoaded API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.isItemLoaded(item));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_getFeatures(t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+ var features = store.getFeatures();
+ var count = 0;
+ for(i in features){
+ t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Write"));
+ count++;
+ }
+ t.assertEqual(2, count);
+ },
+ function testReadAPI_getAttributes(t){
+ // summary:
+ // Simple test of the getAttributes API
+ // description:
+ // Simple test of the getAttributes API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ var attributes = store.getAttributes(item);
+
+ //Should be six, as all items should have tagName, childNodes, and text() special attributes
+ //in addition to any doc defined ones, which in this case are author, title, and isbn
+ //FIXME: Figure out why IE returns 5! Need to get firebug lite working in IE for that.
+ //Suspect it's childNodes, may not be defined if there are no child nodes.
+ for(var i = 0; i < attributes.length; i++){
+ console.log("attribute found: " + attributes[i]);
+ }
+ if(dojo.isIE){
+ t.assertEqual(5,attributes.length);
+ }else{
+ t.assertEqual(6,attributes.length);
+ }
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testWriteAPI_setValue(t){
+ // summary:
+ // Simple test of the setValue API
+ // description:
+ // Simple test of the setValue API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+ store.setValue(item, "isbn", "A9B574-new");
+ t.assertEqual(store.getValue(item,"isbn").toString(), "A9B574-new");
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testWriteAPI_setValues(t){
+ // summary:
+ // Simple test of the setValues API
+ // description:
+ // Simple test of the setValues API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+ store.setValues(item, "isbn", ["A9B574-new1", "A9B574-new2"]);
+ var values = store.getValues(item,"isbn");
+ t.assertEqual(values[0].toString(), "A9B574-new1");
+ t.assertEqual(values[1].toString(), "A9B574-new2");
+ store.setValues(values[0], "text()", ["A9B574", "-new3"]);
+ t.assertEqual(store.getValue(values[0],"text()").toString(), "A9B574-new3");
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testWriteAPI_unsetAttribute(t){
+ // summary:
+ // Simple test of the unsetAttribute API
+ // description:
+ // Simple test of the unsetAttribute API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+ store.unsetAttribute(item,"isbn");
+ t.assertTrue(!store.hasAttribute(item,"isbn"));
+ t.assertTrue(store.isDirty(item));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testWriteAPI_isDirty(t){
+ // summary:
+ // Simple test of the isDirty API
+ // description:
+ // Simple test of the isDirty API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+ store.setValue(item, "isbn", "A9B574-new");
+ t.assertEqual(store.getValue(item,"isbn").toString(), "A9B574-new");
+ t.assertTrue(store.isDirty(item));
+ d.callback(true);
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testWriteAPI_revert(t){
+ // summary:
+ // Simple test of the isDirty API
+ // description:
+ // Simple test of the isDirty API
+ var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+ var d = new doh.Deferred();
+ function onComplete(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+ t.assertTrue(!store.isDirty(item));
+ store.setValue(item, "isbn", "A9B574-new");
+ t.assertEqual(store.getValue(item,"isbn").toString(), "A9B574-new");
+ t.assertTrue(store.isDirty(item));
+ store.revert();
+
+ //Fetch again to see if it reset the state.
+ function onComplete1(items, request) {
+ t.assertEqual(1, items.length);
+ var item = items[0];
+ t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+ d.callback(true);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete1, onError: onError});
+ }
+ function onError(error, request) {
+ d.errback(error);
+ }
+ store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+ return d; //Object
+ },
+ function testReadAPI_functionConformance(t){
+ // summary:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = dojox.data.tests.stores.XmlStore.getBooksStore();
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(i in readApi){
+ var member = readApi[i];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ console.log("Problem with function: [" + i + "]");
+ passed = false;
+ break;
+ }
+ }
+ }
+ t.assertTrue(passed);
+ },
+ function testWriteAPI_functionConformance(t){
+ // summary:
+ // Simple test write API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test write API conformance. Checks to see all declared functions are actual functions on the instances.
+
+ var testStore = dojox.data.tests.stores.XmlStore.getBooksStore();
+ var writeApi = new dojo.data.api.Write();
+ var passed = true;
+
+ for(i in writeApi){
+ var member = writeApi[i];
+ //Check that all the 'Write' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ ]
+);
+
+
+
+
+
+}
diff --git a/includes/js/dojox/data/tests/stores/atom1.xml b/includes/js/dojox/data/tests/stores/atom1.xml
new file mode 100644
index 0000000..faff9aa
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/atom1.xml
@@ -0,0 +1,848 @@
+<?xml version="1.0" encoding="UTF-8"?><feed
+ xmlns="http://www.w3.org/2005/Atom"
+ xmlns:thr="http://purl.org/syndication/thread/1.0"
+ xml:lang="en"
+ xml:base="http://shaneosullivan.wordpress.com/wp-atom.php"
+ >
+ <title type="text">SOS</title>
+ <subtitle type="text">..where the wave finally broke, and rolled back.. Shane O'Sullivan's technical blog</subtitle>
+
+ <updated>2008-01-22T14:32:09Z</updated>
+ <generator uri="http://wordpress.org/" version="MU">WordPress</generator>
+
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com" />
+ <id>http://shaneosullivan.wordpress.com/feed/atom/</id>
+ <link rel="self" type="application/atom+xml" href="http://shaneosullivan.wordpress.com/feed/atom/" />
+
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Using AOL hosted Dojo with your custom code]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2008/01/22/using-aol-hosted-dojo-with-your-custom-code/" />
+ <id>http://shaneosullivan.wordpress.com/2008/01/22/using-aol-hosted-dojo-with-your-custom-code/</id>
+ <updated>2008-01-22T14:32:09Z</updated>
+ <published>2008-01-22T14:32:09Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="Dojo" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="Javascript" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="Technical" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="aol" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="cross domain" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="open source" />
+ <summary type="html"><![CDATA[The Dojo Ajax Toolkit is kindly hosted by AOL for the consumption of anyone at all. This has the advantage of
+
+Reducing the load on your own server
+Speeding up the delivery, as a Content Delivery Network (CDN) is used to ensure that the server is as close as possible to the client, and
+The more people [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2008/01/22/using-aol-hosted-dojo-with-your-custom-code/"><![CDATA[<div class='snap_preview'><br /><p>The <a href="http://www.dojotoolkit.org" target="_blank">Dojo Ajax Toolkit</a> is kindly <a href="http://dev.aol.com/dojo" target="_blank">hosted</a> by AOL for the consumption of anyone at all. This has the advantage of</p>
+
+<ul>
+<li>Reducing the load on your own server</li>
+<li>Speeding up the delivery, as a Content Delivery Network (CDN) is used to ensure that the server is as close as possible to the client, and</li>
+<li>The more people who use this the better, as the same Dojo files will be cached when users move from site to site, as they&#8217;ll all be downloading the AOL hosted files.</li>
+<li>Gzip compression as standard, so the files are as small as possible</li>
+</ul>
+<p>Additionally, since release 0.9 onwards, the main Dojo JavaScript file, <i>dojo.js</i>, is always exactly the same, whereas in previous released it changed for every developer who built it.</p>
+<p>However, the problem comes in where you want to use your own custom code with the hosted Dojo code. This is because the hosted code uses <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/functions-used-everywhere/dojo-require" target="_blank">Dojo&#8217;s loading system</a> to dynamically load the resources needed on the page, and this will read the files from AOL, not your server (as you would expect - it knows nothing about your server). If you want to <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/package-system-and-custom-builds" target="_blank">build custom layers</a> to improve performance, the remotely hosted Dojo will not be able to find them.</p>
+
+<p>So, the solution I generally tend to use is to put the AOL <i>dojo.js</i> on every page, and tell Dojo to load any other required files from my own server. To do this, set the <i>baseUrl </i>parameter on the djConfig attribute for the JavaScript file to the folder where Dojo is stored on your server. E.g.</p>
+<p><b>&lt;script type=&#8221;text/javascript&#8221; src=&#8221;http://o.aolcdn.com/dojo/1.0.2/dojo/dojo.js&#8221; djConfig=&#8221;{baseUrl:&#8217;/js/dojo/&#8217;}&#8221;&gt;&lt;/script&gt;</b></p>
+
+<p>Notice here that the file I load is <i>dojo.js</i>, the normal version, not <i>dojo.xd.js</i>, which is the cross domain version capable of loading files from AOL.</p>
+<p>After doing this, you can then include whatever custom built layers you like onto an particular page. For example, if you have a layer built for the <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-image/gallery" target="_blank">dojox.image.Gallery</a> widget called <i>/js/dojo/dojox/image/Gallery-layer.js</i>, you can load it either dynamically:</p>
+<p><b>&lt;script type=&#8221;text/javascript&#8221;&gt;dojo.require(&#8221;dojox.image.Gallery-layer.js&#8221;);&lt;/script&gt;</b></p>
+
+<p>or include it via a script tag:</p>
+<p><b>&lt;script type=&#8221;text/javascript&#8221; src=&#8221;js/dojo/dojox/image/Gallery-layer.js&#8221;&gt;&lt;/script&gt;</b></p>
+<p>and it should work just as if you were using Dojo from your own server. Only of course you are not - AOL is serving up that file, and in many cases users will already have cached that file, speeding up your site quite nicely.</p>
+<p>Another approach is to create a custom namespace, register it with Dojo, and put all your layers in there&#8230;. but that&#8217;s for another post <img src='http://shaneosullivan.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
+
+<b>Share this post:</b><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2008/1/22/using-aol-hosted-dojo-with-your-custom-code&amp;phase=2" target="_blank" title="Post 'Using AOL hosted Dojo with your custom code">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2008/1/22/using-aol-hosted-dojo-with-your-custom-code&amp;title=Using+AOL+hosted+Dojo+with+your+custom+code" target="_blank" title="Post 'Using AOL hosted Dojo with your custom code">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2008/1/22/using-aol-hosted-dojo-with-your-custom-code&amp;subject=Using+AOL+hosted+Dojo+with+your+custom+code" target="_blank" title="Post 'Using AOL hosted Dojo with your custom code">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2008/1/22/using-aol-hosted-dojo-with-your-custom-code&amp;title=Using+AOL+hosted+Dojo+with+your+custom+code" target="_blank" title="Post 'Using AOL hosted Dojo with your custom code">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2008/1/22/using-aol-hosted-dojo-with-your-custom-code&amp;title=Using+AOL+hosted+Dojo+with+your+custom+code" target="_blank" title="Post 'Using AOL hosted Dojo with your custom code">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2008/1/22/using-aol-hosted-dojo-with-your-custom-code&amp;title=Using+AOL+hosted+Dojo+with+your+custom+code&amp;top=1" target="_blank" title="Post 'Using AOL hosted Dojo with your custom code">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/88/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/88/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/88/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=88&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2008/01/22/using-aol-hosted-dojo-with-your-custom-code/#comments" thr:count="1"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2008/01/22/using-aol-hosted-dojo-with-your-custom-code/feed/atom/" thr:count="1"/>
+ <thr:total>1</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Dojo Demo Engine Update]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update/" />
+ <id>http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update/</id>
+ <updated>2008-01-12T13:22:38Z</updated>
+ <published>2008-01-07T01:02:43Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Demo Engine" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="demo" /><category scheme="http://shaneosullivan.wordpress.com" term="dijit" /><category scheme="http://shaneosullivan.wordpress.com" term="documentation" /><category scheme="http://shaneosullivan.wordpress.com" term="dojo.query" /><category scheme="http://shaneosullivan.wordpress.com" term="dojox" /><category scheme="http://shaneosullivan.wordpress.com" term="json" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[A short while ago I posted about the demo engine I&#8217;m writing for the Dojo Ajax Toolkit. Click here to read that post or go to http://www.skynet.ie/~sos/js/demo/dojo/dojoc/demos/featureexplorer.html to see it in action.
+Features
+Since that post, quite a lot of work has gone into both the features and the content of the demo engine, and the development [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update/"><![CDATA[<div class='snap_preview'><br /><p>A short while ago I posted about the demo engine I&#8217;m writing for the Dojo Ajax Toolkit. <a href="http://shaneosullivan.wordpress.com/2007/12/04/a-new-demo-engine-for-dojo/" target="_blank">Click here</a> to read that post or go to <a href="http://www.skynet.ie/~sos/js/demo/dojo/dojoc/demos/featureexplorer.html" target="_blank">http://www.skynet.ie/~sos/js/demo/dojo/dojoc/demos/featureexplorer.html</a> to see it in action.</p>
+
+<p><b>Features</b></p>
+<p><b></b>Since that post, quite a lot of work has gone into both the features and the content of the demo engine, and the development process has solidified nicely. Some of the features include:</p>
+<ul>
+<li><b>Tree navigation</b>. A <i>dijit.Tree</i> widget, reading from a remote JSON data store is used to navigate the various demos.</li>
+<li><b>Search feature</b>. A <i>dijit.form.ComboBox</i> widget, reading from the same JSON data store as the tree, can be used to dynamically search for demos by matching any part of their name.</li>
+
+<li><b>Theme switcher</b>. A <i>dijit.form.ComboBox</i> widget is used to switch between the CSS styles that Dojo provides.</li>
+<li><b>URL addressability</b>. Using a hash identifier (e.g. <i>#Dojo_Query_By%20Class</i>) in the URL of the demo engine causes it to open that demo when it has finished loading. For example, if you click <a href="http://www.skynet.ie/~sos/js/demo/dojo/dijit/demos/featureexplorer.html#Dojo_Query_By%20Class" target="_blank">this link</a>, it will open the <i>dojo.query</i> demo showing you how to select nodes by class name. Opening any demo changes the URL in the browser to the URL for that demo, for easy bookmarking.</li>
+
+<li><b>Integrated build process</b>. A simple build script is integrated with the Dojo build process. It builds a JSON data file listing all the existing demos and their respective files. It also builds files with URL links for each demo.</li>
+</ul>
+<p><b>Content</b></p>
+<p>To date, a lot of content has been added. Many, many widgets in <a href="http://www.skynet.ie/~sos/js/demo/dojo/dijit/demos/featureexplorer.html#Dijit" target="_blank">Dijit</a> and <a href="http://www.skynet.ie/~sos/js/demo/dojo/dijit/demos/featureexplorer.html#Dojox" target="_blank">DojoX<br />
+</a> have have been added, including the majority of the <a href="http://www.skynet.ie/~sos/js/demo/dojo/dijit/demos/featureexplorer.html#Dijit_Form%20Controls" target="_blank">Form Controls</a>.</p>
+
+<p>The latest, pretty cool additions have been the <a href="http://www.skynet.ie/~sos/js/demo/dojo/dijit/demos/featureexplorer.html#Dojo_IO" target="_blank">IO</a> and <a href="http://www.skynet.ie/~sos/js/demo/dojo/dijit/demos/featureexplorer.html#Dojo_Query" target="_blank">dojo.query</a> demos. These cover things such as:</p>
+<ul>
+<li>Performing a XMLHttpRequest request</li>
+<li>Using an iFrame transport</li>
+<li>Submitting a form asynchronously</li>
+<li>Loading remote JavaScript files from another domain</li>
+<li>Selecting nodes using <a href="http://www.w3.org/TR/REC-CSS2/selector.html" target="_blank">CSS selectors</a> with <a href="http://ajaxian.com/archives/dojoquery-a-css-query-engine" target="_blank">dojo.query</a></li>
+
+<li>Performing operations on the NodeList returned from dojo.query</li>
+<li>Attaching events to the <a href="http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-536297177" target="_blank">NodeList</a> returned from dojo.query</li>
+</ul>
+<p><b>File Naming Scheme</b><br />
+A simple file naming scheme is used to add content to the demo framework. Each folder beneath the root folder represents a demo. Each file in a folder must be named the same as the folder, with five possible extensions. For example, given a folder with the name &#8216;<b>Button</b>&#8216;, the possible files are:</p>
+<ul>
+
+<li><b>Button.html</b> - this contains the demo to be displayed. Any JavaScript code inside &lt;script&gt; tags is executed, and any &lt;link type=&#8221;text/css&#8221;&gt; and &lt;style&gt; tags have their CSS loaded. The executed code is shown in the <i>View</i> tab, and and the source code is shown in the <i>XML</i> tab. The <i>&lt;html&gt;</i>, <i>&lt;head&gt;</i> and <i>&lt;body&gt;</i> tags are not required.</li>
+
+<li><b>Button.js</b> - this contains pure JavaScript code that performs the same operations as Button.html, if applicable. It is not executed however. It is shown in the <i>JS</i> tab.</li>
+<li><b>Button.txt</b> - this contains the text description of the demo. It is loaded above the tabs.</li>
+<li><b>Button.links</b> - this contains a JSON array of URL links. The build script transforms these links into HTML, and the result is loaded into the <i>Links</i> tab. One neat feature of this is that all links from sub folders are integrated with the parent folder and displayed in a nested structure. Do, for example, clicking on <i>Dijit</i> will show all the links for all widgets in the Dijit project.</li>
+
+<li><b>Button.full.html</b> - this is standalone demo, that is designed to run outside the demo engine. The <i>View</i> tab provides a link to the external file.</li>
+<li><b>sort.txt</b> - this contains a comma separated list of the child folders contained in this folder. It specifies the order in which to display the child demos in the tree. If this file is not specified, then an alphabetical ordering is used.</li>
+</ul>
+<p>All of these files are optional. If a file in a folder does not match this naming scheme, it is assumed to be some kind of resource that the demo needs, such as an image or a JSON data file. In this case, the file can be named whatever you like.</p>
+<p>The tree structure in the demo engine mirrors the folder layout.</p>
+
+<p><b>Still To Do</b></p>
+<p>There remains quite a lot of work ahead. There are a few bugs remaining, some more cross browser testing is needed, and of course more content is required, particularly the base Dojo package.</p>
+<p>In the relatively near future this should be opened up to the public for development. The Dojo folks are setting up a source control server for community additions, and this demo engine should be part of that. Once that is done, people can start adding all sorts of cool stuff!<br />
+<b>Share this post:</b><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update&amp;phase=2" target="_blank" title="Post 'Dojo Demo Engine Update">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update&amp;title=Dojo+Demo+Engine+Update" target="_blank" title="Post 'Dojo Demo Engine Update">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update&amp;subject=Dojo+Demo+Engine+Update" target="_blank" title="Post 'Dojo Demo Engine Update">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update&amp;title=Dojo+Demo+Engine+Update" target="_blank" title="Post 'Dojo Demo Engine Update">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update&amp;title=Dojo+Demo+Engine+Update" target="_blank" title="Post 'Dojo Demo Engine Update">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update&amp;title=Dojo+Demo+Engine+Update&amp;top=1" target="_blank" title="Post 'Dojo Demo Engine Update">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/87/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/87/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/87/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=87&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update/#comments" thr:count="3"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update/feed/atom/" thr:count="3"/>
+ <thr:total>3</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Navigating in an IE Modal Dialog]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog/" />
+ <id>http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog/</id>
+ <updated>2007-12-31T16:36:21Z</updated>
+ <published>2007-12-31T16:36:21Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Internet Explorer" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="modal" /> <summary type="html"><![CDATA[Internet Explorer has a nice feature where a new window can be opened modally using the window.showModalDialog function, meaning that the page that opened it cannot be accessed until the new window is closed. This can be useful in many situations.
+However, the main limitation of IE Modal Dialogs (other than being non-standard), is that [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog/"><![CDATA[<div class='snap_preview'><br /><p>Internet Explorer has a nice feature where a new window can be opened modally using the <a href="http://msdn2.microsoft.com/en-us/library/ms536759.aspx"><i>window.showModalDialog</i></a> function, meaning that the page that opened it cannot be accessed until the new window is closed. This can be useful in many situations.</p>
+
+<p>However, the main limitation of IE Modal Dialogs (other than being non-standard), is that any hyperlink clicked in a modal dialog causes another, non modal, dialog to be opened, rather than opening the page linked to in the same window, as would happen in a normal pop up window.</p>
+<p>The key to solving this problem is to note that a modal dialog only opens another window when a <a href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_Methods" target="_blank">GET</a> request is made, not when a <a href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_Methods" target="_blank">POST</a> request is made. However, an anchor tag automatically causes a GET request, so the solution is to:</p>
+<ol>
+<li> Catch the click on each anchor tag, cancel it,</li>
+<li>Submit a dynamically created FORM element, with it&#8217;s <i>method</i> set to &#8216;<i>POST&#8217; </i>and it&#8217;s <i>action</i> set to the URL of the link clicked.</li>
+
+</ol>
+<p>While it is possible to put a listener on each anchor tag to achieve this, such an approach will not scale well. Instead, place a listener on the <b>body </b>tag. The example below is done using methods from the <a href="http://www.dojotoolkit.org" target="_blank">Dojo Ajax Toolkit</a>, since that the toolkit I use the most, but you can of course use whatever methods you like to achieve the same result:</p>
+<blockquote><p> <code>&lt;script type="text/javascript"&gt;<br />
+dojo.addOnLoad(function(){<br />
+dojo.connect(dojo.body(), &#8220;onclick&#8221;, function(evt) {<br />
+if(evt.target.tagName != &#8220;A&#8221;) {return true;}<br />
+dojo.stopEvent(evt);<br />
+var form = document.createElement(&#8221;form&#8221;);<br />
+form.setAttribute(&#8221;target&#8221;, window.name ? window.name : &#8220;SrPopUp&#8221;);<br />
+form.setAttribute(&#8221;action&#8221;, url);<br />
+form.setAttribute(&#8221;method&#8221;,&#8221;POST&#8221;);<br />
+document.appendChild(form);<br />
+form.submit();<br />
+return false;<br />
+});<br />
+});<br />
+
+&lt;/script&gt;</code></p></blockquote>
+<p>This method assumes that you have control over the content of the page being shown in the modal dialog. It would also make sense to add a similar listener to the body tag for key events, as a user can trigger an anchor tag by tabbing to it and hitting enter.</p>
+<p>Thanks to <a href="http://www.dannyg.com/support/modalFix.html" target="_blank">Danny Goodman</a> and <a href="http://www.dannyg.com/support/SOCmodalWindow.js" target="_blank">Steiner Overbeck Cook</a> for coming up with this solution.<br />
+<b>Share this post:</b><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog&amp;phase=2" target="_blank" title="Post 'Navigating in an IE Modal Dialog">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog&amp;title=Navigating+in+an+IE+Modal+Dialog" target="_blank" title="Post 'Navigating in an IE Modal Dialog">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog&amp;subject=Navigating+in+an+IE+Modal+Dialog" target="_blank" title="Post 'Navigating in an IE Modal Dialog">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog&amp;title=Navigating+in+an+IE+Modal+Dialog" target="_blank" title="Post 'Navigating in an IE Modal Dialog">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog&amp;title=Navigating+in+an+IE+Modal+Dialog" target="_blank" title="Post 'Navigating in an IE Modal Dialog">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog&amp;title=Navigating+in+an+IE+Modal+Dialog&amp;top=1" target="_blank" title="Post 'Navigating in an IE Modal Dialog">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/86/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/86/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/86/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/86/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/86/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/86/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/86/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/86/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/86/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/86/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/86/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/86/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=86&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog/#comments" thr:count="1"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog/feed/atom/" thr:count="1"/>
+ <thr:total>1</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[A new Demo engine for Dojo]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/12/04/a-new-demo-engine-for-dojo/" />
+ <id>http://shaneosullivan.wordpress.com/2007/12/04/a-new-demo-engine-for-dojo/</id>
+ <updated>2008-01-12T13:23:15Z</updated>
+ <published>2007-12-04T09:29:16Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="demo" /><category scheme="http://shaneosullivan.wordpress.com" term="dijit" /><category scheme="http://shaneosullivan.wordpress.com" term="documentation" /><category scheme="http://shaneosullivan.wordpress.com" term="dojox.image" /><category scheme="http://shaneosullivan.wordpress.com" term="json" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[A couple of weeks ago I saw a cool demo framework for an Ajax toolkit just released as open source. It&#8217;s a very slick implementation, with a tree listing all the various demos, and a tabbed area showing the implementation, and the widget in practice.
+So, I think to myself, this is exactly what the [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/12/04/a-new-demo-engine-for-dojo/"><![CDATA[<div class='snap_preview'><br /><p>A couple of weeks ago I saw a cool <a href="http://www.smartclient.com/#_Welcome" target="_blank">demo framework</a> for an Ajax toolkit just released as open source. It&#8217;s a very slick implementation, with a tree listing all the various demos, and a tabbed area showing the implementation, and the widget in practice.</p>
+
+<p>So, I think to myself, this is exactly what the <a href="http://www.dojotoolkit.org/" target="_blank">Dojo Ajax Toolkit</a> is missing! Cut to today, and I&#8217;ve put the first rough cut at the demo framework on the web for people&#8217;s perusal. Check it out at <a href="http://www.skynet.ie/~sos/js/demo/dojo/dojoc/demos/featureexplorer.html" target="_blank">http://www.skynet.ie/~sos/js/demo/dojo/dojoc/demos/featureexplorer.html</a> .</p>
+<p><b>Note: I have written a follow up post <a href="http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update/" target="_blank">here</a>.</b></p>
+<p>Some of the features include:</p>
+<ul>
+
+<li>Tree navigation for the demos. Demos can be nested as deep as required.</li>
+<li>View tab. This shows the widgets in action.</li>
+<li>HTML tab. This shows how to instantiate the widget using HTML markup.</li>
+<li>JS tab. This shows how to instantiate the widget using JavaScript code.</li>
+<li>Links tab. This shows various hyperlinks to alternate content for that demo, e.g. the <a href="http://dojotoolkit.org/book/dojo-book-0-9-0" target="_blank">Dojo Book</a>.</li>
+<li>Demo description. Gives a text description of the demo.</li>
+<li>Theme selector. This allows you to change from one CSS theme to another</li>
+<li>Ability to link to standalone demos that open in a new page. This is useful for large demos that show the integration of many widgets together, and may not fit well within the demo framework itself. See the Dijit/Mail demo for an example of this.</li>
+
+<li>A build system that takes a very simple naming scheme for the demos, and creates a JSON data store that the framework runs off of. So, whenever a user adds a new demo, they simply have to re-run the build step, and that&#8217;s it! No need for a server side script, so you can run this right off your hard drive.</li>
+</ul>
+<p>This is still very much beta code, and there are a couple of errors floating around, but those will of course be hunted down. There are also some Internet Explorer issues that I&#8217;ll get to soon, so try this in Firefox for now (<b>update Dec 05 2007 - most of these have been solved, with one or two small bugs remaining)</b>. I&#8217;m in discussions to get this into the Dojo toolkit, so that the community at large can start adding in demos. I&#8217;ve put in quite a few already, but it&#8217;s so easy to do that this could become a huge resource for the Dojo community.</p>
+<p>If you have any suggestions, please let me know.</p>
+<p><a href="http://shaneosullivan.wordpress.com/2007/12/04/a-new-demo-engine-for-dojo/demo-framework/" target="_blank" rel="attachment wp-att-85" title="Demo Framework"><img src="http://shaneosullivan.files.wordpress.com/2007/12/demo_framework.jpg" alt="Demo Framework" /></a><br />
+
+<b>Share this post:</b><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/12/4/a-new-demo-engine-for-dojo&amp;phase=2" target="_blank" title="Post 'A new Demo engine for Dojo">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/12/4/a-new-demo-engine-for-dojo&amp;title=A+new+Demo+engine+for+Dojo" target="_blank" title="Post 'A new Demo engine for Dojo">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/12/4/a-new-demo-engine-for-dojo&amp;subject=A+new+Demo+engine+for+Dojo" target="_blank" title="Post 'A new Demo engine for Dojo">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/12/4/a-new-demo-engine-for-dojo&amp;title=A+new+Demo+engine+for+Dojo" target="_blank" title="Post 'A new Demo engine for Dojo">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/12/4/a-new-demo-engine-for-dojo&amp;title=A+new+Demo+engine+for+Dojo" target="_blank" title="Post 'A new Demo engine for Dojo">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/12/4/a-new-demo-engine-for-dojo&amp;title=A+new+Demo+engine+for+Dojo&amp;top=1" target="_blank" title="Post 'A new Demo engine for Dojo">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/84/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/84/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/84/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/84/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/84/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/84/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/84/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/84/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/84/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/84/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/84/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/84/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=84&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/12/04/a-new-demo-engine-for-dojo/#comments" thr:count="3"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/12/04/a-new-demo-engine-for-dojo/feed/atom/" thr:count="3"/>
+ <thr:total>3</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Upgrading Ubuntu Feisty Fawn (7.04) to Gutsy Gibbon (7.10)]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-704-to-gutsy-gibbon-710/" />
+ <id>http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-704-to-gutsy-gibbon-710/</id>
+ <updated>2008-01-12T10:26:42Z</updated>
+ <published>2007-10-18T16:11:37Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Gutsy Gibbon" /><category scheme="http://shaneosullivan.wordpress.com" term="Ubuntu" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[Today I&#8217;ve begun the process of upgrading my Ubuntu installation of version 7.04 to version 7.10. To see my previous tutorial of getting Ubuntu installed on my IBM Thinkpad X41, see http://shaneosullivan.wordpress.com/2007/02/16/installing-ubuntu-edgy-on-a-thinkpad-x41-tablet/.
+This post lists whatever issues I found when upgrading, and my solutions to them. For the official instructions, see https://help.ubuntu.com/community/GutsyUpgrades.
+Third Party software [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-704-to-gutsy-gibbon-710/"><![CDATA[<div class='snap_preview'><br /><p>Today I&#8217;ve begun the process of upgrading my Ubuntu installation of version 7.04 to version 7.10. To see my previous tutorial of getting Ubuntu installed on my IBM Thinkpad X41, see <a href="http://shaneosullivan.wordpress.com/2007/02/16/installing-ubuntu-edgy-on-a-thinkpad-x41-tablet/" target="_blank">http://shaneosullivan.wordpress.com/2007/02/16/installing-ubuntu-edgy-on-a-thinkpad-x41-tablet/</a>.</p>
+
+<p>This post lists whatever issues I found when upgrading, and my solutions to them. For the official instructions, see <a href="https://help.ubuntu.com/community/GutsyUpgrades" target="_blank">https://help.ubuntu.com/community/GutsyUpgrades</a>.</p>
+<p><b>Third Party software sources cause problems</b></p>
+<p>My first problem was caused by having links to third party software distribution sites. When running the &#8220;<i>update-manager -d</i>&#8221; command, I received an error, saying the dbus couldn&#8217;t run.</p>
+<p>This was caused by having third party software sources enabled that no longer existed, for whatever reason.</p>
+
+<p>To fix this:</p>
+<ol>
+<li>click <i>&#8220;System/Administration/Software Sources&#8221;</i></li>
+<li>Click the &#8220;<i>Third-Party Software</i>&#8221; tab</li>
+<li>Deselect any non-Ubuntu software sources. You can always reselect them after the upgrade</li>
+
+</ol>
+<p><b>Modifying the software channels gets stuck</b></p>
+<p>When the second step in the &#8220;Distribution Upgrade&#8221; application is running, that is, the &#8220;Modifying the software channels&#8221; step, it got stuck downloading files. It would say</p>
+<p>Downloading file 36 of 97</p>
+<p>and stay at that number for a long time. This was not a bandwidth issue, it simply stopped. To fix this</p>
+<ol>
+<li>Click the &#8220;<i>Cancel</i>&#8221; button.</li>
+
+<li>Run the &#8220;<i>update-manager -d</i>&#8221; command again.</li>
+<li>Repeat this each time it gets stuck downloading files. I had to do this four times for it to work completely.</li>
+</ol>
+<p><b>Dual monitors didn&#8217;t work correctly</b></p>
+<p>When booted up with an external monitor plugged in, the desktop was fixed at 640 * 480 pixels resolution. I found someone else with a similar issue at <a href="http://ubuntuforums.org/showthread.php?t=566947" target="_blank">http://ubuntuforums.org/showthread.php?t=566947</a> , but their solution didn&#8217;t work for me. I solved this by:</p>
+
+<ol>
+<li>Unplugging the monitor.</li>
+<li>Restart the machine, and log in.</li>
+<li>Click &#8220;<i>System/Administration/Screens and Graphics</i>&#8220;</li>
+<li>Click the &#8220;<i>Graphics Card</i>&#8221; tab.</li>
+
+<li>Click the &#8220;<i>Driver</i>&#8221; button</li>
+<li>From the &#8220;<i>Driver</i>&#8221; dropdown list, choose &#8220;<i>i810 - Intel Integrated Graphics Chipsets</i>&#8220;</li>
+<li>Restart the machine.</li>
+
+</ol>
+<p><b>Compiz has problems with dual monitors</b></p>
+<p>Compiz (the 3D graphics stuff) causes problems and refuses to work at all if I am using dual monitors. Still working on this one.</p>
+<p><b>Some Eclipse plug-ins no longer work</b></p>
+<p>As a Java developer, I often use the <a href="http://www.eclipse.org" target="_blank">Eclipse</a> development platform. I include some non-standard plugins in the application, like plugins for Subversion support. However, when Ubuntu is upgraded to 7.10, the base Eclipse platform in upgraded, but not the non-standard plugins, which stops some of them from working.</p>
+<p><i>Update: actually, this didn&#8217;t fix my Eclipse problems, please ignore <img src='http://shaneosullivan.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </i></p>
+
+<p>The solution is to upgrade the plugins in the usual Eclipse manner:</p>
+<ol>
+<li>Open Eclipse</li>
+<li>Click <i>Help/Software Updates/Find and Install</i></li>
+<li>Click <i>Finish</i></li>
+<li>Wait a while&#8230;</li>
+</ol>
+
+<p><b>Running low on disk space after upgrade</b></p>
+<p>My laptop was running out of disk space after the install, as it downloaded quite a few packages. I found a very good blog post on how to clean up your Ubuntu install at <a href="http://www.ubuntugeek.com/cleaning-up-all-unnecessary-junk-files-in-ubuntu.html" target="_blank">http://www.ubuntugeek.com/cleaning-up-all-unnecessary-junk-files-in-ubuntu.html</a>.</p>
+<p>Make sure to read comment #7 also, that alone saved me 1GB.</p>
+<p><span style="font-weight:bold;">Some Thinkpad features no longer work</span></p>
+<p>I found that some things didn&#8217;t work that did work before, for example the stylus pen and the middle &#8217;scroller&#8217; button of the mouse. If this happens, just reapply the settings I describe <a href="http://shaneosullivan.wordpress.com/2007/02/16/ubuntu-on-thinkpad-x41-enabling-thinkpad-specific-components/" target="_blank">here</a>, as the upgrade removed them. This solved the problems for me.</p>
+
+<p><b>Share this post:</b><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-%28704%29-to-gutsy-gibbon-%287.10%29&amp;phase=2" target="_blank" title="Post 'Upgrading Ubuntu Feisty Fawn (704) to Gutsy Gibbon (7.10)">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-%28704%29-to-gutsy-gibbon-%287.10%29&amp;title=Upgrading+Ubuntu+Feisty+Fawn+%28704%29+to+Gutsy+Gibbon+%287.10%29" target="_blank" title="Post 'Upgrading Ubuntu Feisty Fawn (704) to Gutsy Gibbon (7.10)">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-%28704%29-to-gutsy-gibbon-%287.10%29&amp;subject=Upgrading+Ubuntu+Feisty+Fawn+%28704%29+to+Gutsy+Gibbon+%287.10%29" target="_blank" title="Post 'Upgrading Ubuntu Feisty Fawn (704) to Gutsy Gibbon (7.10)">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-%28704%29-to-gutsy-gibbon-%287.10%29&amp;title=Upgrading+Ubuntu+Feisty+Fawn+%28704%29+to+Gutsy+Gibbon+%287.10%29" target="_blank" title="Post 'Upgrading Ubuntu Feisty Fawn (704) to Gutsy Gibbon (7.10)">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-%28704%29-to-gutsy-gibbon-%287.10%29&amp;title=Upgrading+Ubuntu+Feisty+Fawn+%28704%29+to+Gutsy+Gibbon+%287.10%29" target="_blank" title="Post 'Upgrading Ubuntu Feisty Fawn (704) to Gutsy Gibbon (7.10)">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-%28704%29-to-gutsy-gibbon-%287.10%29&amp;title=Upgrading+Ubuntu+Feisty+Fawn+%28704%29+to+Gutsy+Gibbon+%287.10%29&amp;top=1" target="_blank" title="Post 'Upgrading Ubuntu Feisty Fawn (704) to Gutsy Gibbon (7.10)">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/82/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/82/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/82/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=82&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-704-to-gutsy-gibbon-710/#comments" thr:count="25"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-704-to-gutsy-gibbon-710/feed/atom/" thr:count="25"/>
+ <thr:total>25</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Introducing the new Dojo Image Widgets]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets/" />
+ <id>http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets/</id>
+ <updated>2008-01-08T11:23:13Z</updated>
+ <published>2007-10-13T11:09:13Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="Dojo" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="Flickr" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="Image Gallery" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="Javascript" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="Technical" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="aol" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="cross domain" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="dijit" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="dojo.data" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="dojox" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="dojox.data" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="dojox.image" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="json" />
+ <category scheme="http://shaneosullivan.wordpress.com" term="open source" />
+ <summary type="html"><![CDATA[In previous posts (here for the Dojo 0.4.3 version, here and here), I wrote how I wrote an image gallery for version 0.4.3 of the Dojo Ajax Toolkit, and how I was translating it for the latest version of the toolkit, version 1.0.
+Well, that work is now, finally, complete, and I have to say, I&#8217;m [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets/"><![CDATA[<div class='snap_preview'><br /><p>In previous posts (<a href="http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery/" target="_blank">here for the Dojo 0.4.3 version</a>, <a href="http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09/" target="_blank">here</a> and <a href="http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo/" target="_blank">here</a>), I wrote how I wrote an <a href="http://www.skynet.ie/~sos/ajax/imagegallery.php">image gallery for version 0.4.3</a> of the <a href="http://www.dojotoolkit.org" target="_blank">Dojo Ajax Toolkit</a>, and how I was translating it for the latest version of the toolkit, version 1.0.</p>
+
+<p>Well, that work is now, finally, complete, and I have to say, I&#8217;m pretty damn happy with the results. The code is now part of the <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-image" target="_blank">dojox.image</a> project (dojox is the Dojo extensions project, for cool new code that may in the future make it into the core code base if enough people like/want it).</p>
+<p>If you&#8217;d like to just see the gallery in action, have a look at the <a href="http://www.skynet.ie/~sos/photos.php" target="_blank">Photos page on my personal website</a>, or see the links at the bottom of the post, otherwise, read on!</p>
+<p><b>Update: changes have been made to the widgets since this post was written, resulting in some badly aligned images. This will be fixed in the next few days. (Oct 25th 2007)</b></p>
+<p><b>Update: issue above has been fixed (Oct 29th 2007)</b></p>
+
+<h2>All For One&#8230;.</h2>
+<p>The gallery is composed of three widgets:</p>
+<ul>
+<li>dojox.image.<a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-image/thumbnailpicker" target="_blank">ThumbnailPicker</a> - a widget to list many small images in either a horizontal or vertical orientation, scroll through them, and attach click events that other widgets can listen to</li>
+<li>dojox.image.<a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-image/slideshow" target="_blank">SlideShow</a> - a widget that displays one image at a time, and can run a slideshow, changing the images every &#8216;x&#8217; seconds.</li>
+<li>dojox.image.<a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-image/gallery" target="_blank">Gallery</a> - A wrapper around the ThumbnailPicker, and SlideShow widgets.</li>
+
+</ul>
+<p>Both the ThumbnailPicker and Slideshow widgets can also be used on their own, and have no dependencies on each other.<br />
+<img src="http://dojotoolkit.org/files/gallery_0.jpg" height="515" width="524" /></p>
+<h2>Dojo Data Is Too Cool for School</h2>
+<p>One of the coolest features of all of these widgets is that they all feed off image data provided by the<a href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/data-retrieval-dojo-data-0" target="_blank"> dojo.data</a> API. What this basically means is that each widget can display images from any source, with no modification whatsoever. You simply pass it a Dojo data store, and is shows the pictures. Some of the data stores currently in the Dojo toolkit include:</p>
+<ul>
+<li>dojo.data.<a href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/what-dojo-data/available-stores/dojo-data-item" target="_blank">ItemFileReadStore</a> - pull in simple JSON data in an array. You could use this if you simply have a directory of images on your own web server you would like to display</li>
+<li>dojox.data.<a href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/using-dojo-data/available-stores/flickr-rest-s" target="_blank">FlickrRestStore</a> (<a href="http://archive.dojotoolkit.org/nightly/checkout/dojox/data/demos/demo_FlickrRestStore.html" target="_blank">demo</a>) - query the Flickr photo sharing website for images. This is all done on the browser, with no need for any server-side redirects. This is <a href="http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo/" target="_blank">another of my additions</a> to the Dojo toolkit - I love Flickr, feel free to check out my photo stream <a href="http://www.flickr.com/photos/shaneosullivan/" target="_blank">here</a>. I previously wrote another blog post on this data store <a href="http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo/" target="_blank">here</a>.</li>
+
+<li>dojox.data.PicasaStore (<a href="http://archive.dojotoolkit.org/nightly/checkout/dojox/data/demos/demo_PicasaStore.html" target="_blank">demo</a>) - query Google&#8217;s Picasa image sharing website for images. As with the Flickr data store, this is done on the browser, with no need for server side support.</li>
+</ul>
+<p>and many more&#8230;.. You can also write your own data store if you so desire, but the ones included in the toolkit should cover almost everything you might need.</p>
+<h2>Gimme, Gimme, Gimme!</h2>
+<p>So, how can I get this, you ask! Well, you can:</p>
+<ul>
+<li>Have a look at the test pages for the widgets:
+
+<ul>
+<li><a href="http://archive.dojotoolkit.org/nightly/checkout/dojox/image/tests/test_Gallery.html" target="_blank">Test page for ThumbnailPicker</a></li>
+<li><a href="http://archive.dojotoolkit.org/nightly/checkout/dojox/image/tests/test_SlideShow.html">Test page for SlideShow</a></li>
+<li><a href="http://archive.dojotoolkit.org/nightly/checkout/dojox/image/tests/test_Gallery.html" target="_blank">Test page for Gallery</a></li>
+<li><a href="http://archive.dojotoolkit.org/nightly/checkout/dojox/data/demos/demo_FlickrRestStore.html" target="_blank">Demo page for dojox.data.FlickrRestStore</a></li>
+
+<li><a href="http://www.skynet.ie/~sos/photos.php" target="_blank">The Gallery on my personal website</a> - example of using the widget hosted on your own server</li>
+<li><a href="http://kadca.com/site/index.php?/photos" target="_blank">The Gallery on another website</a> - example of using the widget hosted on <a href="http://dev.aol.com/dojo" target="_blank">AOL&#8217;s cross domain</a> <a href="http://en.wikipedia.org/wiki/Content_Delivery_Network" target="_blank">CDN</a> network.</li>
+<li><a href="http://www.skynet.ie/~sos/js/demo/dojo/dijit/demos/featureexplorer.html#Dojox_Image" target="_blank">Demo page for all DojoX Image widgets</a></li>
+
+</ul>
+</li>
+<li>Read the documentation (I know!! Documentation&#8230; in Dojo!!)
+<ul>
+<li><a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-image/thumbnailpicker" target="_blank">Doc page for ThumbnailPicker</a></li>
+<li><a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-image/slideshow" target="_blank">Doc page for SlideShow</a></li>
+<li><a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-image/gallery" target="_blank">Doc page for Gallery</a></li>
+
+<li><a href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/using-dojo-data/available-stores/dojox-data-fl" target="_blank">Doc page for dojox.data.FlickrRestStore</a></li>
+</ul>
+</li>
+<li>Download the <a href="http://archive.dojotoolkit.org/nightly/" target="_blank">latest nightly archive</a> from Dojo.</li>
+<li><a href="http://dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/get-code-subversion" target="_blank">Check out the code</a> from the Subversion repository.</li>
+<li>Wait for Dojo 1.0 to come out (end of Oct 2007) and download the full release from the main<a href="http://www.dojotoolkit.org" target="_blank"> Dojo website</a>.</li>
+
+</ul>
+<p><b>Update: Dojo 1.0 is now released. Get it at <a href="http://www.dojotoolkit.org/downloads" target="_blank">http://www.dojotoolkit.org/downloads</a></b><br />
+As always, any and all feedback is welcome. Also, a big thanks to <a href="http://higginsforpresident.net/" target="_blank">Peter Higgins</a>, owner of the dojox.image project, and <a href="http://www.ibm.com/developerworks/blogs/page/webtwooh?tag=Jared_Jurkiewicz" target="_blank">Jared Jurkiewicz</a>, owner of the dojo.data project, for all their helpful ideas, and for reviewing/committing my code to the Dojo project.<br />
+<b>Share this post:</b><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets&amp;phase=2" target="_blank" title="Post 'Introducing the new Dojo Image Widgets">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets&amp;title=Introducing+the+new+Dojo+Image+Widgets" target="_blank" title="Post 'Introducing the new Dojo Image Widgets">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets&amp;subject=Introducing+the+new+Dojo+Image+Widgets" target="_blank" title="Post 'Introducing the new Dojo Image Widgets">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets&amp;title=Introducing+the+new+Dojo+Image+Widgets" target="_blank" title="Post 'Introducing the new Dojo Image Widgets">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets&amp;title=Introducing+the+new+Dojo+Image+Widgets" target="_blank" title="Post 'Introducing the new Dojo Image Widgets">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets&amp;title=Introducing+the+new+Dojo+Image+Widgets&amp;top=1" target="_blank" title="Post 'Introducing the new Dojo Image Widgets">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/81/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/81/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/81/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=81&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets/#comments" thr:count="46"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets/feed/atom/" thr:count="46"/>
+ <thr:total>46</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Dojo Grid has landed]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/" />
+ <id>http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/</id>
+ <updated>2007-10-14T21:46:03Z</updated>
+ <published>2007-10-05T13:23:17Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="grid" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[The previously announced Dojo Grid has landed in source control, and is in the nightly builds. It has all sorts of fancy functionality, like support for lazy loading huge data sets, individual styling of rows and columns, inline editing etc.
+Check it out at http://archive.dojotoolkit.org/nightly/checkout/dojox/grid/tests/
+Very cool stuff!
+Update: The Sitepen guys have recently blogged about [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/"><![CDATA[<div class='snap_preview'><br /><p>The <a href="http://ajaxian.com/archives/plugging-in-to-the-dojo-grid" target="_blank">previously </a> <a href="http://sitepen.com/pressReleases.php?item=20070917">announced</a> Dojo Grid has landed in source control, and is in the nightly builds. It has all sorts of fancy functionality, like support for lazy loading huge data sets, individual styling of rows and columns, inline editing etc.</p>
+
+<p>Check it out at <a href="http://archive.dojotoolkit.org/nightly/checkout/dojox/grid/tests/" target="_blank">http://archive.dojotoolkit.org/nightly/checkout/dojox/grid/tests/</a></p>
+<p>Very cool stuff!</p>
+<p><strong>Update: </strong>The Sitepen guys have recently blogged about the grid at <a href="http://www.sitepen.com/blog/2007/10/13/dojo-grid-update/" target="_blank">http://www.sitepen.com/blog/2007/10/13/dojo-grid-update/</a></p>
+<p><strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed&amp;phase=2" target="_blank" title="Post 'Dojo Grid has landed">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed&amp;title=Dojo+Grid+has+landed" target="_blank" title="Post 'Dojo Grid has landed">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed&amp;subject=Dojo+Grid+has+landed" target="_blank" title="Post 'Dojo Grid has landed">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed&amp;title=Dojo+Grid+has+landed" target="_blank" title="Post 'Dojo Grid has landed">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed&amp;title=Dojo+Grid+has+landed" target="_blank" title="Post 'Dojo Grid has landed">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed&amp;title=Dojo+Grid+has+landed&amp;top=1" target="_blank" title="Post 'Dojo Grid has landed">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/80/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/80/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/80/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/80/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/80/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/80/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/80/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/80/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/80/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/80/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/80/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/80/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=80&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/#comments" thr:count="0"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/feed/atom/" thr:count="0"/>
+ <thr:total>0</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[A TortoiseSVN replacement for Ubuntu]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu/" />
+ <id>http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu/</id>
+ <updated>2007-10-04T15:50:50Z</updated>
+ <published>2007-10-04T15:50:50Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Linux" /><category scheme="http://shaneosullivan.wordpress.com" term="Nautilus" /><category scheme="http://shaneosullivan.wordpress.com" term="Subversion" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="TortoiseSVN" /><category scheme="http://shaneosullivan.wordpress.com" term="Ubuntu" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[I work on a number of open source projects, and many of them use the Subversion version control system to manage their code. Before my switch from Windows XP to Ubuntu Linux (which I am still ecstatically happy with btw), I became a big fan of TortoiseSVN, an extremely useful Subversion client that integrates itself [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu/"><![CDATA[<div class='snap_preview'><br /><p>I work on a number of open source projects, and many of them use the <a href="http://subversion.tigris.org/" target="_blank">Subversion</a> version control system to manage their code. Before <a href="http://shaneosullivan.wordpress.com/2007/02/16/installing-ubuntu-edgy-on-a-thinkpad-x41-tablet/" target="_blank">my switch</a> from Windows XP to <a href="http://www.ubuntu.com" target="_blank">Ubuntu Linux </a>(which I am still ecstatically happy with btw), I became a big fan of <a href="http://tortoisesvn.tigris.org/" target="_blank">TortoiseSVN,</a> an extremely useful Subversion client that integrates itself directly into Windows Explorer.</p>
+
+<p>TortoiseSVN is simple to use, very intuitive, and does everything I need from it. You simply right click on a folder you want to store your checked out files in, give it the URL of the Subversion server, and it checks out the code, updates it, checks it back in (if you have permission), performs file diffs &#8230;.. basically everything you need to do is integrated right in with your file browser.</p>
+<p>So, I miss this in Ubuntu, as TortoiseSVN is Windows only. However, I recently found a replacement, which integrates nicely with Nautilus, the Ubuntu file browser. While it is not as slick as TortoiseSVN, it works in a very similar way. You right click on a folder, and have a selection of SVN operations you can perform.</p>
+<p>See <a href="http://marius.scurtescu.com/2005/08/24/nautilus_scripts_for_subversion" target="_blank">http://marius.scurtescu.com/2005/08/24/nautilus_scripts_for_subversion</a> for details.</p>
+<p><img src="http://shaneosullivan.files.wordpress.com/2007/10/nautilussubversionscripts.png?w=615&h=264" alt="Nautilus Subversion Menu" height="264" width="615" /></p>
+<p><img src="http://shaneosullivan.files.wordpress.com/2007/10/nautilussubversionscripts-add.png" alt="Nautilus Subversion Dialog" /></p>
+<p>One thing that is missing from this is the display of icons in the file browser (Nautilus) to inform you of the state of a file - checked out, modified, not added to source control etc. Another person has developed a solution to this, which unfortunately I have not, yet, been able to get working, but perhaps you will have more luck.</p>
+
+<p>See <a href="http://www.kryogenix.org/days/2006/09/12/extremely-noddy-tortoisesvn-for-the-gnome-desktop" target="_blank">http://www.kryogenix.org/days/2006/09/12/extremely-noddy-tortoisesvn-for-the-gnome-desktop</a> for details on this.<br />
+<strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu&amp;phase=2" target="_blank" title="Post 'A TortoiseSVN replacement for Ubuntu">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu&amp;title=A+TortoiseSVN+replacement+for+Ubuntu" target="_blank" title="Post 'A TortoiseSVN replacement for Ubuntu">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu&amp;subject=A+TortoiseSVN+replacement+for+Ubuntu" target="_blank" title="Post 'A TortoiseSVN replacement for Ubuntu">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu&amp;title=A+TortoiseSVN+replacement+for+Ubuntu" target="_blank" title="Post 'A TortoiseSVN replacement for Ubuntu">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu&amp;title=A+TortoiseSVN+replacement+for+Ubuntu" target="_blank" title="Post 'A TortoiseSVN replacement for Ubuntu">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu&amp;title=A+TortoiseSVN+replacement+for+Ubuntu&amp;top=1" target="_blank" title="Post 'A TortoiseSVN replacement for Ubuntu">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/77/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/77/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/77/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=77&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu/#comments" thr:count="3"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu/feed/atom/" thr:count="3"/>
+ <thr:total>3</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Querying Flickr with Dojo!]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo/" />
+ <id>http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo/</id>
+ <updated>2007-09-22T18:26:51Z</updated>
+ <published>2007-09-22T16:10:05Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Flickr" /><category scheme="http://shaneosullivan.wordpress.com" term="Image Gallery" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="dojo.data" /><category scheme="http://shaneosullivan.wordpress.com" term="dojox.data" /><category scheme="http://shaneosullivan.wordpress.com" term="dojox.image" /><category scheme="http://shaneosullivan.wordpress.com" term="json" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[I&#8217;ve recently submitted a new data store for the Dojo Ajax Toolkit that makes it very simple to query Flickr for your and other peoples images. For those not familiar with Flickr, it is a photo sharing website, one of the most popular on the net. However, what makes it quite special is [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo/"><![CDATA[<div class='snap_preview'><br /><p>I&#8217;ve recently submitted a new data store for the <a href="http://www.dojotoolkit.org" target="_blank">Dojo Ajax Toolkit</a> that makes it very simple to query <a href="http://www.flickr.com">Flickr</a> for your and other peoples images. For those not familiar with Flickr, it is a photo sharing website, one of the most popular on the net. However, what makes it quite special is the <a href="http://www.flickr.com/services/api/" target="_blank">comprehensive public API</a>s that it exposes.</p>
+
+<p>While these APIs are extremely useful, however, they are also very complex, with a steep learning curve before you can even get started. In steps Dojo and their new <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/using-dojo-data" target="_blank">Data API</a> specification, whose stated aim is to have a single unified interface to all data sources, so that users of a data store won&#8217;t have to care if they&#8217;re reading from a database, from a XML or JSON file, or from some remote service like Flickr.</p>
+<p>So, long story short, I&#8217;ve written an implementation of the Dojo Data APIs to query data from Flickr. It is part of the <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox-extensions-dojo-0" target="_blank">DojoX</a> project, and is called <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/using-dojo-data/available-stores/flickr-rest-s" target="_blank">dojox.data.FlickrRestStore</a>. It provides quite a few methods of querying for photos:</p>
+<ul>
+<li>By one or more tags, matchine any or all of them</li>
+<li>By user id</li>
+
+<li>By set id</li>
+<li>Full text search</li>
+<li>Sorting on date taken, date published or &#8216;interestingness&#8217;</li>
+</ul>
+<p>FlickrRestStore also performs caching of image data, so if you request the data twice it won&#8217;t make a second remote request.</p>
+<p>The store is also designed to be accessed by multiple clients simultaneously. If two clients request the same data, only one request is made, with both clients being notified of the identical results.</p>
+<p><strong>Examples</strong></p>
+
+<p>I&#8217;ve put a fairly comprehensive set of examples in the Dojo book at <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/using-dojo-data/available-stores/flickr-rest-s#examples" target="_blank">http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo<br />
+/using-dojo-data/available-stores/flickr-rest-s#examples </a>.</p>
+<p>You can see a <a href="http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/data/demos/demo_FlickrRestStore.html" target="_blank">Demo</a> of it running at <a href="http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/data/demos/demo_FlickrRestStore.html" target="_blank">http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/data/demos/demo_FlickrRestStore.html</a> .</p>
+<p>The unit tests cover quite a few cases also, and you can see them at <a href="http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/data/tests/stores/FlickrRestStore.js" target="_blank">http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/data/tests/stores/FlickrRestStore.js</a></p>
+<p>To get the code, you can:</p>
+
+<ul>
+<li>Check out the latest copy of the Dojo toolkit, see the instructions <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/get-code-subversion" target="_blank">here</a>.</li>
+<li>Grab the entire nightly build from <a href="http://archive.dojotoolkit.org/nightly/" target="_blank">http://archive.dojotoolkit.org/nightly/</a></li>
+<li>Wait for release 1.0!</li>
+</ul>
+<p><strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo&amp;phase=2" target="_blank" title="Post 'Querying Flickr with Dojo!">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo&amp;title=Querying+Flickr+with+Dojo%21" target="_blank" title="Post 'Querying Flickr with Dojo!">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo%21&amp;subject=Querying+Flickr+with+Dojo" target="_blank" title="Post 'Querying Flickr with Dojo!">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo%21&amp;title=Querying+Flickr+with+Dojo" target="_blank" title="Post 'Querying Flickr with Dojo!">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo%21&amp;title=Querying+Flickr+with+Dojo" target="_blank" title="Post 'Querying Flickr with Dojo!">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo&amp;title=Querying+Flickr+with+Dojo%21&amp;top=1" target="_blank" title="Post 'Querying Flickr with Dojo!">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/76/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/76/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/76/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/76/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/76/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/76/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/76/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/76/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/76/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/76/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/76/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/76/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=76&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo/#comments" thr:count="3"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo/feed/atom/" thr:count="3"/>
+ <thr:total>3</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Specifying the callback function with the Flickr JSON APIs]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis/" />
+ <id>http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis/</id>
+ <updated>2007-09-13T09:54:53Z</updated>
+ <published>2007-09-13T09:31:30Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Flickr" /><category scheme="http://shaneosullivan.wordpress.com" term="Image Gallery" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="dojox" /><category scheme="http://shaneosullivan.wordpress.com" term="dojox.data" /><category scheme="http://shaneosullivan.wordpress.com" term="dojox.image" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[Flickr is a photo sharing website that has a very flexible set of APIs that other applications and websites can use to access the photos it stores. This post shows you how to specify a callback function that Flickr can call to pass your web application information on photos it stores.
+Quite a while ago I [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis/"><![CDATA[<div class='snap_preview'><br /><p>Flickr is a photo sharing website that has a very flexible set of <a href="http://en.wikipedia.org/wiki/Api" target="_blank">API</a>s that other applications and websites can use to access the photos it stores. This post shows you how to specify a callback function that Flickr can call to pass your web application information on photos it stores.</p>
+
+<p>Quite a while ago I looked into the <a href="http://www.flickr.com" target="_blank">Flickr</a> APIs for a website I was writing. Looking at the service that returns photo data in <a href="http://en.wikipedia.org/wiki/Json" target="_blank">JSON</a> (Javascript Object Notation), I noticed that it did so by calling a predefined function, <em>jsonFlickrApi, </em>passing in the data to that function. This seemed to be an obvious weak spot, since if more than one widget on a page were accessing the Flickr REST services, they would clash with each other, possibly receiving each others data. Obviously not a good thing.</p>
+<p>Cut to today. I&#8217;ve been working on a JavaScript data store that operates against the Flickr <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" target="_blank">REST</a> services for the <a href="http://www.dojotoolkit.org" target="_blank">Dojo Ajax Toolkit</a>, and had another look at the Flickr APIs. Now, whether I missed it before (doubtful, as I looked specifically for it), or the fine Flickr folk have listened to complaints (very likely), but there is now a parameter that can be passed to the Flickr API that specifies the callback function to use when the data is retrieved from Flickr.</p>
+<p>All you have to do is pass a parameter <em>jsoncallback</em> to Flickr, with the name of the function you want to be called with the data, and thats it.</p>
+
+<p>E.g. if I had a function:</p>
+<p>function myCallbackFunction(data) {</p>
+<p>alert(&#8221;I received &#8221; + data.photos.photo.length +&#8221; photos&#8221;);</p>
+<p>}</p>
+<p>I could then specify a &lt;script&gt; element in my HTML page to retrieve the data in a cross site manner (since you can&#8217;t make cross site <a href="http://en.wikipedia.org/wiki/XmlHttpRequest" target="_blank">XmlHttpRequest </a>calls), like so:</p>
+
+<p>&lt;SCRIPT type=&#8221;text/javascript&#8221; src=&#8221;http://www.flickr.com/services/rest/?format=json&amp;<font color="#ff0000">jsoncallback=myCallbackFunction</font><br />
+&amp;method=flickr.people.getPublicPhotos<br />
+&amp;api_key=8c6803164dbc395fb7131c9d54843627<br />
+&amp;user_id=44153025%40N00&amp;per_page=1&#8243;&gt;</p>
+
+<p>&lt;/SCRIPT&gt;</p>
+<p>Note the jsoncallback parameter in the <em>src</em> attribute. This results in JavaScript similar to:</p>
+<p><em>myCallbackFunction<span class="sourceRowText">({&#8221;photos&#8221;:{&#8221;page&#8221;:1, &#8220;pages&#8221;:489, &#8220;perpage&#8221;:1, &#8220;total&#8221;:&#8221;489&#8243;, &#8220;photo&#8221;:[{&#8221;id&#8221;:&#8221;1352049918&#8243;, &#8220;owner&#8221;:&#8221;44153025@N00&#8243;, &#8220;secret&#8221;:&#8221;5636009306&#8243;, &#8220;server&#8221;:&#8221;1111&#8243;, &#8220;farm&#8221;:2, &#8220;title&#8221;:&#8221;The Liffey Panorama&#8221;, &#8220;ispublic&#8221;:1, &#8220;isfriend&#8221;:0, &#8220;isfamily&#8221;:0}]}, &#8220;stat&#8221;:&#8221;ok&#8221;});</span></em></p>
+
+<p>being called.</p>
+<p>Thanks Flickr! Nice to see them listening, and continually improving. This will make web applications built on Flickr much more robust, without the need of ridiculous hackery to get around unnecessarily difficult APIs. See <a href="http://www.flickr.com/services/api/response.json.html" target="_blank">http://www.flickr.com/services/api/response.json.html</a> for the offical info on JSON responses.</p>
+<p>Keep an eye out for my dojox.data.FlickrRestStore being release some day soon!!<br />
+<strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis&amp;phase=2" target="_blank" title="Post 'Specifying the callback function with the Flickr JSON APIs">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis&amp;title=Specifying+the+callback+function+with+the+Flickr+JSON+APIs" target="_blank" title="Post 'Specifying the callback function with the Flickr JSON APIs">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis&amp;subject=Specifying+the+callback+function+with+the+Flickr+JSON+APIs" target="_blank" title="Post 'Specifying the callback function with the Flickr JSON APIs">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis&amp;title=Specifying+the+callback+function+with+the+Flickr+JSON+APIs" target="_blank" title="Post 'Specifying the callback function with the Flickr JSON APIs">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis&amp;title=Specifying+the+callback+function+with+the+Flickr+JSON+APIs" target="_blank" title="Post 'Specifying the callback function with the Flickr JSON APIs">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis&amp;title=Specifying+the+callback+function+with+the+Flickr+JSON+APIs&amp;top=1" target="_blank" title="Post 'Specifying the callback function with the Flickr JSON APIs">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/75/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/75/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/75/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=75&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis/#comments" thr:count="0"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis/feed/atom/" thr:count="0"/>
+ <thr:total>0</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Image Gallery, Slideshow, and Flickr data source for Dojo 0.9]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09/" />
+ <id>http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09/</id>
+ <updated>2007-09-05T08:32:22Z</updated>
+ <published>2007-09-04T23:32:51Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Image Gallery" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="dijit" /><category scheme="http://shaneosullivan.wordpress.com" term="dojo.image" /><category scheme="http://shaneosullivan.wordpress.com" term="dojox" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[In a previous post (see here) I spoke about how I&#8217;d written an Image Gallery widget that worked with Dojo Ajax Toolkit version 0.4.2 and 0.4.3. I contacted the good folks at Dojo about updating it for the latest release, 0.9, and adding it to the toolkit.
+They were very receptive to the idea, [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09/"><![CDATA[<div class='snap_preview'><br /><p>In a previous post (see <a href="http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery/" target="_blank">here</a>) I spoke about how I&#8217;d written an Image Gallery widget that worked with <a href="http://www.dojotoolkit.org" target="_blank">Dojo Ajax Toolkit</a> version 0.4.2 and 0.4.3. I contacted the good folks at Dojo about updating it for the latest release, <a href="http://ajaxian.com/archives/dojo-09-final-version-released" target="_blank">0.9</a>, and adding it to the toolkit.</p>
+
+<p>They were very receptive to the idea, with a few suggestions. Firstly, rather than having its own method of storing information, it should run off the <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/data-retrieval-dojo-data-0" target="_blank">dojo.data </a>API, and secondly, it should go into the newly created dojox.image project.</p>
+<p>Both of these suggestions were perfectly reasonable, so, cut to a few weeks later and I&#8217;ve finished my first pass at converting over the code from 0.4.3 to 0.9. As the Dojo APIs have changed drastically recently, this was no simple matter, but thats the subject of another blog post.</p>
+<p>The code is not finished (or even checked in) yet, but you can see some examples of it running from test pages. There are two separate widgets:</p>
+<ul>
+<li>dojox.image.SlideShow - a simple widget that runs a slide show of images, with urls loaded from a dojo.data store.</li>
+<li>dojox.image.ImageGallery - this wraps the SlideShow widget, adding thumbnail views. This is also loaded from a dojo.data store.</li>
+</ul>
+<p>Finally, I&#8217;ve implemented a dojo.data store that reads from the <a href="http://www.flickr.com/photos/shaneosullivan" target="_blank">Flickr</a> REST APIs, to pull down lists of photos. This store is more complex than the existing Flickr store, as it does caching of results, as well as going against a much more flexible API, meaning that expanding its capabilities later is possible.</p>
+
+<p>Whether or not this goes into dojox or not is still undecided. However, you can see the widgets running using this data store.</p>
+<p>See the test files at <a href="http://www.skynet.ie/~sos/js2/dojox/image/tests/" target="_blank">http://www.skynet.ie/~sos/js2/dojox/image/tests</a> for examples of this working.</p>
+<p>Note that this is NOT the final code. It may still be buggy, may look different in the future (it&#8217;s pretty basic now), and the code will be cleaned up. However, if you have any suggestions, please feel free to leave comments on this post.</p>
+<p><strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09&amp;phase=2" target="_blank" title="Post 'Image Gallery, Slideshow, and Flickr data source for Dojo 09">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09&amp;title=Image+Gallery,+Slideshow,+and+Flickr+data+source+for+Dojo+09" target="_blank" title="Post 'Image Gallery, Slideshow, and Flickr data source for Dojo 09">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09&amp;subject=Image+Gallery,+Slideshow,+and+Flickr+data+source+for+Dojo+09" target="_blank" title="Post 'Image Gallery, Slideshow, and Flickr data source for Dojo 09">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09&amp;title=Image+Gallery,+Slideshow,+and+Flickr+data+source+for+Dojo+09" target="_blank" title="Post 'Image Gallery, Slideshow, and Flickr data source for Dojo 09">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09&amp;title=Image+Gallery,+Slideshow,+and+Flickr+data+source+for+Dojo+09" target="_blank" title="Post 'Image Gallery, Slideshow, and Flickr data source for Dojo 09">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09&amp;title=Image+Gallery,+Slideshow,+and+Flickr+data+source+for+Dojo+09&amp;top=1" target="_blank" title="Post 'Image Gallery, Slideshow, and Flickr data source for Dojo 09">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/74/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/74/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/74/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/74/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/74/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/74/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/74/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/74/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/74/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/74/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/74/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/74/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=74&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09/#comments" thr:count="1"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09/feed/atom/" thr:count="1"/>
+ <thr:total>1</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Dojo event performance tip]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip/" />
+ <id>http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip/</id>
+ <updated>2007-08-23T12:38:36Z</updated>
+ <published>2007-08-23T12:29:08Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="dojo.event" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /><category scheme="http://shaneosullivan.wordpress.com" term="performance" /> <summary type="html"><![CDATA[When working with the Dojo Ajax Toolkit and using it&#8217;s dojo.event package to listen to DOM and custom events, the two most common approaches are:
+
+Listen for an event (or function call) to be triggered on an object, and when it is to run a custom function, e.g.
+ var alertFn = function() [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip/"><![CDATA[<div class='snap_preview'><br /><p>When working with the <a href="http://www.dojotoolkit.org" target="_blank">Dojo Ajax Toolkit</a> and using it&#8217;s <em>dojo.event</em> package to listen to DOM and custom events, the two most common approaches are:</p>
+
+<ol>
+<li>Listen for an event (or function call) to be triggered on an object, and when it is to run a custom function, e.g.<br />
+<strong> var alertFn = function() {alert(&#8221;widget is showing&#8221;);};<br />
+dojo.event.connect(myWidget, &#8220;onShow&#8221;, <font color="#ff0000">alertFn</font>);</strong></li>
+<p>This basically says that when the &#8220;onShow&#8221; function is called on some widget, called myWidget, run a function that does a simple alert. Of course you can do whatever you like inside this function.</p>
+
+<li>Listen for an event (or function call) to be triggered on an object, and when it is to run a custom function defined in the scope of an object, e.g.<br />
+<strong> var myObj = {<br />
+alertFn: function() {alert(&#8221;widget is showing&#8221;);}<br />
+};<br />
+dojo.event.connect(myWidget, &#8220;onShow&#8221;,<font color="#ff0000">myObj, &#8220;alertFn&#8221;</font>);</strong></p>
+<p>This is saying that I have an object called &#8220;<font color="#ff0000">myObj</font>&#8220;, which has a function called &#8220;<font color="#ff0000">alertFn</font>&#8220;, and when the &#8220;<font color="#ff0000">onShow</font>&#8221; method on &#8220;<font color="#ff0000">myWidget</font>&#8221; is called, call the &#8220;<font color="#ff0000">alertFn</font>&#8221; function on &#8220;<font color="#ff0000">myObj</font>&#8220;.</li>
+
+</ol>
+<p>I&#8217;ve found that when working with Dojo version 0.4.2 and 0.4.3, <strong>using the second approach is far far quicker</strong>. It turns out that internally, if you simply pass an anonymous function to Dojo, it will add that function to an internal structure and do a brute force search on that internal structure to make sure that this function is unique. This can result in a very significant performance hit - I&#8217;ve seen it take up over 50% of the startup time of a page on one of our more JavaScript heavy applications.</p>
+<p>So, the conclusion is that if you are <em>dojo.event.connect</em>, which is one of the most useful functions in the toolkit, make sure to use four arguments to the function (approach #2 above), rather than just three (approach #1 above). If necessary, place a simple wrapper around the function as I have shown.<br />
+<strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip&amp;phase=2" target="_blank" title="Post 'Dojo event performance tip">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip&amp;title=Dojo+event+performance+tip" target="_blank" title="Post 'Dojo event performance tip">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip&amp;subject=Dojo+event+performance+tip" target="_blank" title="Post 'Dojo event performance tip">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip&amp;title=Dojo+event+performance+tip" target="_blank" title="Post 'Dojo event performance tip">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip&amp;title=Dojo+event+performance+tip" target="_blank" title="Post 'Dojo event performance tip">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip&amp;title=Dojo+event+performance+tip&amp;top=1" target="_blank" title="Post 'Dojo event performance tip">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/73/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/73/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/73/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=73&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip/#comments" thr:count="0"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip/feed/atom/" thr:count="0"/>
+ <thr:total>0</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Dojo 0.9 released]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released/" />
+ <id>http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released/</id>
+ <updated>2007-09-04T15:23:50Z</updated>
+ <published>2007-08-22T10:24:51Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="dijit" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[The latest version of the Dojo Ajax Toolkit has just been released into the wild. Version 0.9 is a very streamlined progression of the toolkit, with many of the less essential features pushed out to another project, DojoX, and the Dojo widgets given their own project, Dijit.
+Another big change is the the main [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released/"><![CDATA[<div class='snap_preview'><br /><p>The latest version of the <a href="http://www.dojotoolkit.org" target="_blank">Dojo Ajax Toolkit</a> has just been released into the wild. Version 0.9 is a very streamlined progression of the toolkit, with many of the less essential features pushed out to another project, DojoX, and the Dojo widgets given their own project, Dijit.</p>
+
+<p>Another big change is the the main JavaScript file in Dojo, dojo.js, is no longer customisable. It now contains the most common features required by most web developers, and nothing more. As a result, it is far smaller than previous incarnations, down to ~24k when gzipped.</p>
+<p>Some resources:</p>
+<p>James Burke has written up a very informative post about what exactly is baked into the default build of dojo.js, which you can find at <a href="http://dojotoolkit.org/2007/08/22/dissecting-0-9s-dojo-js" target="_blank">http://dojotoolkit.org/2007/08/22/dissecting-0-9s-dojo-js</a> . Well worth a read.</p>
+<p>Bill Keese wrote up a guided tour of 0.9 at <a href="http://dojotoolkit.org/2007/08/20/dijit-0-9-guided-tour" target="_blank">http://dojotoolkit.org/2007/08/20/dijit-0-9-guided-tour</a>.</p>
+<p>The Dojo book for version 0.9 can be found at <a href="http://dojotoolkit.org/book/dojo-book-0-9-0" target="_blank">http://dojotoolkit.org/book/dojo-book-0-9-0</a>. It&#8217;s almost finished (almost!) as of today, Aug 22 2007.</p>
+
+<p>The Ajaxian post on Dojo 0.9 can be read at <a href="http://ajaxian.com/archives/dojo-09-final-version-released" target="_blank">http://ajaxian.com/archives/dojo-09-final-version-released</a>.</p>
+<p>Download the toolkit from <a href="http://build.dojotoolkit.org/0.9.0/" target="_blank">http://build.dojotoolkit.org/0.9.0</a>. This page gives some information on how you can use Dojo from AOL&#8217;s hosting servers, so you never have to download it at all.<br />
+<strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released&amp;phase=2" target="_blank" title="Post 'Dojo 0.9 released">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released&amp;title=Dojo+0.9+released" target="_blank" title="Post 'Dojo 0.9 released">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released&amp;subject=Dojo+0.9+released" target="_blank" title="Post 'Dojo 0.9 released">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released&amp;title=Dojo+0.9+released" target="_blank" title="Post 'Dojo 0.9 released">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released&amp;title=Dojo+0.9+released" target="_blank" title="Post 'Dojo 0.9 released">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released&amp;title=Dojo+0.9+released&amp;top=1" target="_blank" title="Post 'Dojo 0.9 released">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/72/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/72/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/72/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=72&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released/#comments" thr:count="2"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released/feed/atom/" thr:count="2"/>
+ <thr:total>2</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Dojo theme browser shows off Dijit widgets]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets/" />
+ <id>http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets/</id>
+ <updated>2007-11-05T13:45:45Z</updated>
+ <published>2007-08-17T12:18:57Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Rich Text" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="dijit" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[The Dojo/Dijit (Dojo&#8217;s widget project) toolkit has created a page where you can view many of their widgets using the four CSS themes written so far for Dojo. This is cool for a couple of reasons.
+Firstly, it showcases the excellent work the Dijit developers have put into new themeing skins. There are four [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets/"><![CDATA[<div class='snap_preview'><br /><p>The <a href="http://www.dojotoolkit.org" target="_blank">Dojo</a>/<a href="http://dojotoolkit.org/developer/dijit" target="_blank">Dijit</a> (Dojo&#8217;s widget project) toolkit has <a href="http://dojotoolkit.org/~bill/0.9/dijit/themes/themeTester.html?theme=tundra" target="_blank">created a page</a> where you can view many of their widgets using the four <a href="http://en.wikipedia.org/wiki/Css" target="_blank">CSS</a> themes written so far for Dojo. This is cool for a couple of reasons.</p>
+
+<p>Firstly, it showcases the excellent work the Dijit developers have put into new themeing skins. There are four themes completed so far, and changing the look of Dojo is now as simple as including a different CSS file on your web page. All Dijit widgets now run off a single CSS file, rather than each having their own CSS file.</p>
+<p>Secondly, it shows the usage of many of Dijit&#8217;s widgets (say that five times in a row! <img src='http://shaneosullivan.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> ). Many of the demos from the 0.4.* days are gone now, and this is about as comprehensive a demo of Dojo&#8217;s widgets as you&#8217;re likely to see for a while. And yes, they are very nice indeed.</p>
+<p>Go to <a href="http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/themes/themeTester.html" target="_blank">http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/themes/themeTester.html</a> to see the default theme (<em>tundra</em>) in use. Click on the &#8220;Alternate Themes&#8221; tab at the bottom of the page to switch themes to one of the alternate themes.</p>
+
+<p>Enjoy!</p>
+<p><strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets&amp;phase=2" target="_blank" title="Post 'Dojo theme browser shows off Dijit widgets">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets&amp;title=Dojo+theme+browser+shows+off+Dijit+widgets" target="_blank" title="Post 'Dojo theme browser shows off Dijit widgets">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets&amp;subject=Dojo+theme+browser+shows+off+Dijit+widgets" target="_blank" title="Post 'Dojo theme browser shows off Dijit widgets">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets&amp;title=Dojo+theme+browser+shows+off+Dijit+widgets" target="_blank" title="Post 'Dojo theme browser shows off Dijit widgets">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets&amp;title=Dojo+theme+browser+shows+off+Dijit+widgets" target="_blank" title="Post 'Dojo theme browser shows off Dijit widgets">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets&amp;title=Dojo+theme+browser+shows+off+Dijit+widgets&amp;top=1" target="_blank" title="Post 'Dojo theme browser shows off Dijit widgets">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/71/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/71/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/71/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=71&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets/#comments" thr:count="2"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets/feed/atom/" thr:count="2"/>
+ <thr:total>2</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Why is my web page slow? YSlow for Firebug can tell you.]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you/" />
+ <id>http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you/</id>
+ <updated>2007-07-26T08:28:03Z</updated>
+ <published>2007-07-25T15:08:30Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Firebug" /><category scheme="http://shaneosullivan.wordpress.com" term="Firefox" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="tools" /> <summary type="html"><![CDATA[Yahoo have released a very useful extension for Firebug, which is itself an extension for Firefox, which can be used to analyze a web page&#8217;s performance. The extension, called YSlow, appears as a separate pane in Firebug, and gives you a whole load of statistics about your page.
+However, in addition to the bare numbers, [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you/"><![CDATA[<div class='snap_preview'><br /><p>Yahoo have released a <a href="http://developer.yahoo.com/yslow/" target="_blank">very useful extension</a> for <a href="http://www.getfirebug.com" target="_blank">Firebug</a>, which is itself an extension for <a href="http://www.getfirefox.com" target="_blank">Firefox</a>, which can be used to analyze a web page&#8217;s performance. The extension, called <a href="http://developer.yahoo.com/yslow/" target="_blank">YSlow</a>, appears as a separate pane in Firebug, and gives you a whole load of statistics about your page.</p>
+
+<p>However, in addition to the bare numbers, it also gives your page a ranking, from zero to a hundred, and offers tips in plain English on you can improve the performance of your page.</p>
+<p>All in all, a very handy little addition to a web developer&#8217;s toolkit.</p>
+<p>One caveat is that it is of course not perfect - I tried to use it on Gmail, and it gave the site a 98% mark (practically impossible to achieve in reality), as the initial page of the Gmail application simply loads a single JavaScript page and not much else. Therefore, YSlow seems to only analyze content sent down the wire to browser upon page load, and ignores generated content. However, this does not take away from the fact that it is perfectly suitable for the vast majority of websites out there.</p>
+<p>More information available <a href="http://developer.yahoo.com/yslow/" target="_blank">here</a>, or read Ajaxian&#8217;s post <a href="http://ajaxian.com/archives/yahoo-announces-yslow-firebug-based-performance-tool" target="_blank">here</a>.<br />
+<strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you&amp;phase=2" target="_blank" title="Post 'Why is my web page slow YSlow for Firebug can tell you.">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you&amp;title=Why+is+my+web+page+slow+YSlow+for+Firebug+can+tell+you." target="_blank" title="Post 'Why is my web page slow YSlow for Firebug can tell you.">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you&amp;subject=Why+is+my+web+page+slow+YSlow+for+Firebug+can+tell+you." target="_blank" title="Post 'Why is my web page slow YSlow for Firebug can tell you.">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you&amp;title=Why+is+my+web+page+slow+YSlow+for+Firebug+can+tell+you." target="_blank" title="Post 'Why is my web page slow YSlow for Firebug can tell you.">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you&amp;title=Why+is+my+web+page+slow+YSlow+for+Firebug+can+tell+you." target="_blank" title="Post 'Why is my web page slow YSlow for Firebug can tell you.">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you&amp;title=Why+is+my+web+page+slow+YSlow+for+Firebug+can+tell+you.&amp;top=1" target="_blank" title="Post 'Why is my web page slow YSlow for Firebug can tell you.">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/68/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/68/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/68/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/68/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/68/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/68/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/68/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/68/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/68/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/68/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/68/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/68/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=68&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you/#comments" thr:count="1"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you/feed/atom/" thr:count="1"/>
+ <thr:total>1</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Flickr and Dojo Image Gallery]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery/" />
+ <id>http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery/</id>
+ <updated>2007-07-19T10:44:19Z</updated>
+ <published>2007-07-03T15:53:33Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Flickr" /><category scheme="http://shaneosullivan.wordpress.com" term="Image Gallery" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="json" /> <summary type="html"><![CDATA[I have created an Image Gallery widget built on Dojo 0.4.3 that integrates nicely with Flickr. The widget it written entirely using JavaScript and CSS as a standalone Dojo widget, and is released under the same open source license as Dojo, the Academic Free License.
+For more information, including the code and examples, see http://www.skynet.ie/~sos/ajax/imagegallery.php.
+Some [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery/"><![CDATA[<div class='snap_preview'><br /><p>I have created an Image Gallery widget built on <a href="http://www.dojotoolkit.org" target="_blank">Dojo</a> 0.4.3 that integrates nicely with <a href="http://www.flickr.com" target="_blank">Flickr</a>. The widget it written entirely using JavaScript and CSS as a standalone Dojo widget, and is released under the same open source license as Dojo, the Academic Free License.</p>
+
+<p>For more information, including the code and examples, see <a href="http://www.skynet.ie/~sos/ajax/imagegallery.php" target="_blank">http://www.skynet.ie/~sos/ajax/imagegallery.php</a>.</p>
+<p>Some of the features of the widget include:</p>
+<ul>
+<li> Pages of thumbnails.</li>
+<li> Intelligent pre-loading of images so the images you are looking at are loaded first.</li>
+<li> Fade effects for transitioning of images</li>
+<li> Populated using JSON data - any JSON data, not just Flickr.</li>
+<li> Flickr integration - remotely load your Flickr images.</li>
+
+<li> Paging through a Flickr collection.</li>
+<li> Slideshow</li>
+</ul>
+<p>The widget can be instantiated from both HTML markup and programmatically in JavaScript.</p>
+<p>To view your own Flickr pictures on the widget, without installing it on your own site, go to <a href="http://www.skynet.ie/~sos/ajax/yourpics.php" target="_blank">http://www.skynet.ie/~sos/ajax/yourpics.php</a> .</p>
+<p>There is a discussion thread in the Flickr API group at <a href="http://www.flickr.com/groups/api/discuss/72157600624623643/" target="_blank">http://www.flickr.com/groups/api/discuss/72157600624623643</a>.</p>
+<p>So, why create this widget? Well, firstly I wanted a JavaScript image gallery that would list thumbnails and allow me to page through Flickr photos. Also, a slide show would have been nice. I was surprised to discover that I couldn&#8217;t find one that I liked in the twenty or so minutes I spent looking for one. I found a handy Flash based one, but I wanted a HTML and JavaScript only widget. So I grabbed Dojo 0.4.3 (my JavaScript library of choice right now) and wrote one.</p>
+
+<p>Here is a screen shot:</p>
+<p><a href="http://www.skynet.ie/~sos/ajax/imagegallery.php" target="_blank"><br />
+<img src="http://farm2.static.flickr.com/1359/704747548_d3062f896a.jpg?v=0" alt="Screenshot" border="0" height="458" width="500" /></a></p>
+<p>The widget has all the features that I personally require at the moment, but will probably evolve as I think of new things to add. If you have any suggestions/bug reports, please comment on this post.</p>
+<p><strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery&amp;phase=2" target="_blank" title="Post 'Flickr and Dojo Image Gallery">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery&amp;title=Flickr+and+Dojo+Image+Gallery" target="_blank" title="Post 'Flickr and Dojo Image Gallery">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery&amp;subject=Flickr+and+Dojo+Image+Gallery" target="_blank" title="Post 'Flickr and Dojo Image Gallery">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery&amp;title=Flickr+and+Dojo+Image+Gallery" target="_blank" title="Post 'Flickr and Dojo Image Gallery">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery&amp;title=Flickr+and+Dojo+Image+Gallery" target="_blank" title="Post 'Flickr and Dojo Image Gallery">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery&amp;title=Flickr+and+Dojo+Image+Gallery&amp;top=1" target="_blank" title="Post 'Flickr and Dojo Image Gallery">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/66/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/66/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/66/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/66/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/66/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/66/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/66/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=66&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery/#comments" thr:count="7"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery/feed/atom/" thr:count="7"/>
+ <thr:total>7</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Is Dojo being ignored by developers?]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/06/19/is-dojo-being-ignored-by-developers/" />
+ <id>http://shaneosullivan.wordpress.com/2007/06/19/is-dojo-being-ignored-by-developers/</id>
+ <updated>2007-06-26T10:18:09Z</updated>
+ <published>2007-06-19T10:36:49Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /> <summary type="html"><![CDATA[The two main areas of interest for me over the last year or two, blog-wise that is, have been the Dojo Ajax toolkit, one of the more popular open source JavaScript toolkits, and Ubuntu Linux, the very popular operating system that is seen by many as the best chance Linux has of succeeding on the [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/06/19/is-dojo-being-ignored-by-developers/"><![CDATA[<div class='snap_preview'><br /><p>The two main areas of interest for me over the last year or two, blog-wise that is, have been the <a href="http://www.dojotoolkit.org" target="_blank">Dojo</a> <a href="http://en.wikipedia.org/wiki/Ajax_%28programming%29" target="_blank">Ajax</a> toolkit, one of the more popular open source <a href="http://en.wikipedia.org/wiki/JavaScript" target="_blank">JavaScript</a> toolkits, and <a href="http://www.ubuntu.com/" target="_blank">Ubuntu Linux</a>, the very popular operating system that is seen by many as the best chance Linux has of succeeding on the desktop.</p>
+
+<p>Due to the fact that my blog is hosted on Wordpress.com, I am provided with very detailed statistics on which blog posts are more popular, what days they are accessed on etc. Looking at these, a very definite trend has become apparent</p>
+<blockquote><p><strong>While the number of hits received by the Ubuntu blogs remains more or less steady, hits on Dojo blog posts falls dramatically on the weekend.</strong></p></blockquote>
+<p>While this is not an exact measurement by any means, it points to a worrying possibility. People are obviously working with Ubuntu on their spare time, <a href="http://shaneosullivan.wordpress.com/2007/02/16/ubuntu-on-thinkpad-x41-basic-installation-instructions/" target="_blank">installing it</a>, <a href="http://shaneosullivan.wordpress.com/2007/04/30/ubuntu-on-thinkpad-x41-upgrading-to-feisty-fawn-704/" target="_blank">upgrading</a>, <a href="http://shaneosullivan.wordpress.com/2007/02/16/ubuntu-on-thinkpad-x41-installing-utility-programs/" target="_blank">adding applications</a> and <a href="http://shaneosullivan.wordpress.com/2007/02/16/ubuntu-on-thinkpad-x41-installing-the-beryl-window-manager/" target="_blank">window managers</a> etc, and need help doing this. They are personally interested in Ubuntu, not just professionally. This is one of the main reasons for Ubuntu&#8217;s success - people are excited and motivated by it. They want to work and play with it on their own time.</p>
+
+<p>This does not seem to be the case for Dojo.</p>
+<p>Dojo has the backing of many large and small companies, including two I have worked for, my previous employer <a href="http://www.ibm.com" target="_blank">IBM</a>, and my current employer <a href="http://www.curamsoftware.com" target="_blank">Curam</a>. Both of these are attracted to Dojo for a number of reasons, chief among them being it&#8217;s good design and wide range of features. The very large size of the toolkit is not a problem for them (and corporations in general) because it will be included in websites that employees will use to do their everyday work tasks (e.g. using a corporate installation of <a href="http://www-306.ibm.com/software/info1/websphere/index.jsp?tab=landings/portalbuzz&amp;S_TACT=103BEW01" target="_blank">IBM WebSphere Portal</a>), so the JavaScript is cached and the performance hit is avoided.</p>
+<p>However, for hobbyists, this is not the case. A person might only visit a single page on their website, and a ~200KB overhead for perhaps something simple like a collapsible menu and some fading effects is simply not feasible. I&#8217;ve experienced this recently when writing a <a href="http://www.skynet.ie/~sos" target="_blank">simple website for myself </a>- all I wanted was some fading/sliding effects, but the huge overhead just wasn&#8217;t worth it. And I am a very big supporter of Dojo (I&#8217;ve contributed code even - <a href="http://dojotoolkit.org/node/291" target="_blank">here</a> and <a href="http://codinginparadise.org/weblog/2007/03/shane-osullivan-creates-dojo-storage.html" target="_blank">here</a>), and use it every day at <u><em>work</em></u>.</p>
+
+<p>The Dojo team are working hard on the 0.9 release, which is addressing many of these issues, bringing the base size down to a more manageable size (at time of writing <a href="http://archive.dojotoolkit.org/nightly/dojotoolkit/dojo/dojo.js" target="_blank">dojo.js</a> is down to 68KB). I look forward to the day when my site statistics change, when Dojo can stand on the shoulders of many thousands of enthusiastic hackers rather than being held up by a few big corporations. I really do.</p>
+<p>However, this does not seem to be the case today. Version 0.9 has a lot of work to do.<br />
+<strong>Share this post: </strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/6/19/is-dojo-being-ignored-by-developers&amp;phase=2" target="_blank" title="Post 'Is Dojo being ignored by developers?">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/6/19/is-dojo-being-ignored-by-developers&amp;title=Is+Dojo+being+ignored+by+developers" target="_blank" title="Post 'Is Dojo being ignored by developers?">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/6/19/is-dojo-being-ignored-by-developers&amp;subject=Is+Dojo+being+ignored+by+developers?" target="_blank" title="Post 'Is Dojo being ignored by developers?">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/6/19/is-dojo-being-ignored-by-developers&amp;title=Is+Dojo+being+ignored+by+developers?" target="_blank" title="Post 'Is Dojo being ignored by developers?">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/6/19/is-dojo-being-ignored-by-developers&amp;title=Is+Dojo+being+ignored+by+developers" target="_blank" title="Post 'Is Dojo being ignored by developers?">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/6/19/is-dojo-being-ignored-by-developers&amp;title=Is+Dojo+being+ignored+by+developers&amp;top=1" target="_blank" title="Post 'Is Dojo being ignored by developers?">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/64/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/64/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/64/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=64&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/06/19/is-dojo-being-ignored-by-developers/#comments" thr:count="5"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/06/19/is-dojo-being-ignored-by-developers/feed/atom/" thr:count="5"/>
+ <thr:total>5</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Dojo Charting example to show website statistics]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/06/15/dojo-charting-example-to-show-website-statistics-2/" />
+ <id>http://shaneosullivan.wordpress.com/2007/06/15/dojo-charting-example-to-show-website-statistics-2/</id>
+ <updated>2007-06-15T12:38:24Z</updated>
+ <published>2007-06-15T12:35:35Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Dojo" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Technical" /><category scheme="http://shaneosullivan.wordpress.com" term="chart" /><category scheme="http://shaneosullivan.wordpress.com" term="charting" /><category scheme="http://shaneosullivan.wordpress.com" term="dojo.charting" /><category scheme="http://shaneosullivan.wordpress.com" term="json" /><category scheme="http://shaneosullivan.wordpress.com" term="open source" /><category scheme="http://shaneosullivan.wordpress.com" term="php" /> <summary type="html"><![CDATA[I&#8217;ve created an example usage of the Dojo Charting engine, which you can find at http://www.skynet.ie/~sos/pageStats.php. View the source to see how it works.
+It&#8217;s a modified version of the unit test available with the Dojo toolkit, but used in a specific scenario - in this case, to graph the page impressions for my personal [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/06/15/dojo-charting-example-to-show-website-statistics-2/"><![CDATA[<div class='snap_preview'><br /><p>I&#8217;ve created an example usage of the <a href="http://www.dojotoolkit.org" target="_blank">Dojo</a> <a href="http://ajaxian.com/archives/dojo-charting-engine-released" target="_blank">Charting</a> engine, which you can find at <a href="http://www.skynet.ie/~sos/pageStats.php" target="_blank">http://www.skynet.ie/~sos/pageStats.php</a>. View the source to see how it works.<br />
+It&#8217;s a modified version of the unit test available with the Dojo toolkit, but used in a specific scenario - in this case, to graph the page impressions for my <a href="http://www.skynet.ie/~sos">personal website</a> . The <a href="http://en.wikipedia.org/wiki/Json" target="_blank">JSON</a> data on the page is dynamically generated by PHP, however all other processing is done in JavaScript.</p>
+
+<p>You can filter the data to show info on any combination of pages, and also use a number of different chart types.</p>
+<p>The code is well documented, so should be easy to follow.<br />
+Some other good examples of using the Dojo Charting engine can be found <a href="http://www.ridgway.co.za/archive/2007/04/13/A-Simple-Dojo-Charting-Example.aspx" target="_blank">here</a> and <a href="http://labs.mackirdy.com/chart/chart4.html" target="_blank">here</a>.<br />
+<strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/6/15/dojo-charting-example-to-show-website-statistics-2&amp;phase=2" target="_blank" title="Post 'Dojo Charting example to show website statistics">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/6/15/dojo-charting-example-to-show-website-statistics-2&amp;title=Dojo+Charting+example+to+show+website+statistics" target="_blank" title="Post 'Dojo Charting example to show website statistics">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/6/15/dojo-charting-example-to-show-website-statistics-2&amp;subject=Dojo+Charting+example+to+show+website+statistics" target="_blank" title="Post 'Dojo Charting example to show website statistics">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/6/15/dojo-charting-example-to-show-website-statistics-2&amp;title=Dojo+Charting+example+to+show+website+statistics" target="_blank" title="Post 'Dojo Charting example to show website statistics">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/6/15/dojo-charting-example-to-show-website-statistics-2&amp;title=Dojo+Charting+example+to+show+website+statistics" target="_blank" title="Post 'Dojo Charting example to show website statistics">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/6/15/dojo-charting-example-to-show-website-statistics-2&amp;title=Dojo+Charting+example+to+show+website+statistics&amp;top=1" target="_blank" title="Post 'Dojo Charting example to show website statistics">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/63/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/63/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/63/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/63/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/63/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/63/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/63/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/63/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/63/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/63/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/63/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/63/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=63&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/06/15/dojo-charting-example-to-show-website-statistics-2/#comments" thr:count="4"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/06/15/dojo-charting-example-to-show-website-statistics-2/feed/atom/" thr:count="4"/>
+ <thr:total>4</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[GreaseMonkey script to add Digg-like links to posts]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/05/22/greasemonkey-script-to-add-digg-like-links-to-posts/" />
+ <id>http://shaneosullivan.wordpress.com/2007/05/22/greasemonkey-script-to-add-digg-like-links-to-posts/</id>
+ <updated>2007-05-23T14:56:07Z</updated>
+ <published>2007-05-22T16:57:02Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Firefox" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="greasemonkey" /> <summary type="html"><![CDATA[I decided today that I wanted to put links at the bottom of each of my blog posts that would allow people to perform actions on the post, e.g:
+
+Digg it
+Kick it
+Mail it
+Bookmark it on del.icio.us
+Bookmark it on reddit.com
+Bookmark it on live.com
+
+My blog is on Wordpress.com which doesn&#8217;t seem to have a plugin that will [...]]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/05/22/greasemonkey-script-to-add-digg-like-links-to-posts/"><![CDATA[<div class='snap_preview'><br /><p>I decided today that I wanted to put links at the bottom of each of my blog posts that would allow people to perform actions on the post, e.g:</p>
+
+<ul>
+<li><a href="http://digg.com" target="_blank">Digg </a>it</li>
+<li><a href="http://www.dotnetkicks.com" target="_blank">Kick</a> it</li>
+<li>Mail it</li>
+<li>Bookmark it on <a href="http://del.icio.us" target="_blank">del.icio.us</a></li>
+<li>Bookmark it on <a href="http://reddit.com" target="_blank">reddit.com</a></li>
+
+<li>Bookmark it on <a href="http://favorites.live.com" target="_blank">live.com</a></li>
+</ul>
+<p>My blog is on <a href="http://shaneosullivan.wordpress.com" target="_blank">Wordpress.com</a> which doesn&#8217;t seem to have a plugin that will allow me to do this. So, I got off my ass and wrote a <a href="http://greasemonkey.mozdev.org/" target="_blank">GreaseMonkey</a> Firefox script that&#8217;ll do it for me. You can download this script <a href="http://www.skynet.ie/~sos/misc/wordpresslinker.user.js" target="_blank"></a>by going to <a href="http://userscripts.org/scripts/show/9421" target="_blank">http://userscripts.org/scripts/show/9421</a> and clicking the &#8220;Install This Script&#8221; button.</p>
+
+<p>The links that are inserted are at the bottom of this post. The script is open source (GPL license), so take it, play with it, whatever. If you find any bugs, please let me know by commenting on this post.<br />
+<strong>Share this post:</strong><a href="http://www.digg.com/submit?url=http://shaneosullivan.wordpress.com/2007/5/22/greasemonkey-script-to-add-digg-like-links-to-posts&amp;phase=2" target="_blank" title="Post 'GreaseMonkey script to add Digg-like links to posts">digg it</a>|<a href="http://www.dotnetkicks.com/submit/?url=http://shaneosullivan.wordpress.com/2007/5/22/greasemonkey-script-to-add-digg-like-links-to-posts&amp;title=GreaseMonkey+script+to+add+Digg-like+links+to+posts" target="_blank" title="Post 'GreaseMonkey script to add Digg-like links to posts">kick it</a>|<a href="mailto:?body=Thought%20you%20might%20like%20this:%20http://shaneosullivan.wordpress.com/2007/5/22/greasemonkey-script-to-add-digg-like-links-to-posts&amp;subject=GreaseMonkey+script+to+add+Digg-like+links+to+posts" target="_blank" title="Post 'GreaseMonkey script to add Digg-like links to posts">Email it</a>|<a href="http://del.icio.us/post?url=http://shaneosullivan.wordpress.com/2007/5/22/greasemonkey-script-to-add-digg-like-links-to-posts&amp;title=GreaseMonkey+script+to+add+Digg-like+links+to+posts" target="_blank" title="Post 'GreaseMonkey script to add Digg-like links to posts">bookmark it</a>|<a href="http://reddit.com/submit?url=http://shaneosullivan.wordpress.com/2007/5/22/greasemonkey-script-to-add-digg-like-links-to-posts&amp;title=GreaseMonkey+script+to+add+Digg-like+links+to+posts" target="_blank" title="Post 'GreaseMonkey script to add Digg-like links to posts">reddit</a>|<a href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;mkt=en-us&amp;url=http://shaneosullivan.wordpress.com/2007/5/22/greasemonkey-script-to-add-digg-like-links-to-posts&amp;title=GreaseMonkey+script+to+add+Digg-like+links+to+posts&amp;top=1" target="_blank" title="Post 'GreaseMonkey script to add Digg-like links to posts">liveIt</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/61/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/61/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/61/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=61&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/05/22/greasemonkey-script-to-add-digg-like-links-to-posts/#comments" thr:count="8"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/05/22/greasemonkey-script-to-add-digg-like-links-to-posts/feed/atom/" thr:count="8"/>
+ <thr:total>8</thr:total>
+ </entry>
+ <entry>
+ <author>
+ <name>Shane O'Sullivan</name>
+ <uri>http://shaneosullivan.wordpress.com/</uri>
+ </author>
+ <title type="html"><![CDATA[Article on the square pegs and round holes of desktop and web applications]]></title>
+ <link rel="alternate" type="text/html" href="http://shaneosullivan.wordpress.com/2007/05/22/article-on-the-square-pegs-and-round-holes-of-desktop-and-web-applications/" />
+ <id>http://shaneosullivan.wordpress.com/2007/05/22/article-on-the-square-pegs-and-round-holes-of-desktop-and-web-applications/</id>
+ <updated>2007-05-22T08:57:59Z</updated>
+ <published>2007-05-22T08:49:00Z</published>
+ <category scheme="http://shaneosullivan.wordpress.com" term="Ajax" /><category scheme="http://shaneosullivan.wordpress.com" term="Javascript" /><category scheme="http://shaneosullivan.wordpress.com" term="Zimbra" /> <summary type="html"><![CDATA[Bill Higgins of IBM has written a very well thought out article of why web applications should look and act like web applications, and not the desktop variety. Well worth a read - http://billhiggins.us/weblog/2007/05/17/the-uncanny-valley-of-user-interface-design
+ ]]></summary>
+ <content type="html" xml:base="http://shaneosullivan.wordpress.com/2007/05/22/article-on-the-square-pegs-and-round-holes-of-desktop-and-web-applications/"><![CDATA[<div class='snap_preview'><br /><p><a href="http://billhiggins.us/weblog/about/" target="_blank">Bill Higgins</a> of IBM has written a very well thought out article of why web applications should look and act like web applications, and not the desktop variety. Well worth a read - <a href="http://billhiggins.us/weblog/2007/05/17/the-uncanny-valley-of-user-interface-design" target="_blank">http://billhiggins.us/weblog/2007/05/17/the-uncanny-valley-of-user-interface-design</a></p>
+
+<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/shaneosullivan.wordpress.com/56/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/shaneosullivan.wordpress.com/56/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shaneosullivan.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shaneosullivan.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shaneosullivan.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shaneosullivan.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shaneosullivan.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shaneosullivan.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shaneosullivan.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shaneosullivan.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shaneosullivan.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shaneosullivan.wordpress.com/56/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=shaneosullivan.wordpress.com&blog=258432&post=56&subd=shaneosullivan&ref=&feed=1" /></div>]]></content>
+ <link rel="replies" type="text/html" href="http://shaneosullivan.wordpress.com/2007/05/22/article-on-the-square-pegs-and-round-holes-of-desktop-and-web-applications/#comments" thr:count="0"/>
+ <link rel="replies" type="appication/atom+xml" href="http://shaneosullivan.wordpress.com/2007/05/22/article-on-the-square-pegs-and-round-holes-of-desktop-and-web-applications/feed/atom/" thr:count="0"/>
+ <thr:total>0</thr:total>
+ </entry>
+ </feed>
+
diff --git a/includes/js/dojox/data/tests/stores/books.html b/includes/js/dojox/data/tests/stores/books.html
new file mode 100644
index 0000000..8535cec
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/books.html
@@ -0,0 +1,118 @@
+<html>
+<head>
+ <title>Books.html</title>
+</head>
+<body>
+<table id="books">
+ <thead>
+ <tr>
+ <th>isbn</th>
+ <th>title</th>
+ <th>author</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>Title of 1</td>
+ <td>Author of 1</td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>Title of 2</td>
+ <td>Author of 2</td>
+ </tr>
+ <tr>
+ <td>3</td>
+ <td>Title of 3</td>
+ <td>Author of 3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>Title of 4</td>
+ <td>Author of 4</td>
+ </tr>
+ <tr>
+ <td>5</td>
+ <td>Title of 5</td>
+ <td>Author of 5</td>
+ </tr>
+ <tr>
+ <td>6</td>
+ <td>Title of 6</td>
+ <td>Author of 6</td>
+ </tr>
+ <tr>
+ <td>7</td>
+ <td>Title of 7</td>
+ <td>Author of 7</td>
+ </tr>
+ <tr>
+ <td>8</td>
+ <td>Title of 8</td>
+ <td>Author of 8</td>
+ </tr>
+ <tr>
+ <td>9</td>
+ <td>Title of 9</td>
+ <td>Author of 9</td>
+ </tr>
+ <tr>
+ <td>10</td>
+ <td>Title of 10</td>
+ <td>Author of 10</td>
+ </tr>
+ <tr>
+ <td>11</td>
+ <td>Title of 11</td>
+ <td>Author of 11</td>
+ </tr>
+ <tr>
+ <td>12</td>
+ <td>Title of 12</td>
+ <td>Author of 12</td>
+ </tr>
+ <tr>
+ <td>13</td>
+ <td>Title of 13</td>
+ <td>Author of 13</td>
+ </tr>
+ <tr>
+ <td>14</td>
+ <td>Title of 14</td>
+ <td>Author of 14</td>
+ </tr>
+ <tr>
+ <td>15</td>
+ <td>Title of 15</td>
+ <td>Author of 15</td>
+ </tr>
+ <tr>
+ <td>16</td>
+ <td>Title of 16</td>
+ <td>Author of 16</td>
+ </tr>
+ <tr>
+ <td>17</td>
+ <td>Title of 17</td>
+ <td>Author of 17</td>
+ </tr>
+ <tr>
+ <td>18</td>
+ <td>Title of 18</td>
+ <td>Author of 18</td>
+ </tr>
+ <tr>
+ <td>19</td>
+ <td>Title of 19</td>
+ <td>Author of 19</td>
+ </tr>
+ <tr>
+ <td>20</td>
+ <td>Title of 20</td>
+ <td>Author of 20</td>
+ </tr>
+ </tbody>
+</table>
+</body>
+</html>
diff --git a/includes/js/dojox/data/tests/stores/books.xml b/includes/js/dojox/data/tests/stores/books.xml
new file mode 100644
index 0000000..4c330e6
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/books.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+ <book>
+ <isbn>1</isbn>
+ <title>Title of 1</title>
+ <author>Author of 1</author>
+ </book>
+ <book>
+ <isbn>2</isbn>
+ <title>Title of 2</title>
+ <author>Author of 2</author>
+ </book>
+ <book>
+ <isbn>3</isbn>
+ <title>Title of 3</title>
+ <author>Author of 3</author>
+ </book>
+ <book>
+ <isbn>4</isbn>
+ <title>Title of 4</title>
+ <author>Author of 4</author>
+ </book>
+ <book>
+ <isbn>5</isbn>
+ <title>Title of 5</title>
+ <author>Author of 5</author>
+ </book>
+ <book>
+ <isbn>6</isbn>
+ <title>Title of 6</title>
+ <author>Author of 6</author>
+ </book>
+ <book>
+ <isbn>7</isbn>
+ <title>Title of 7</title>
+ <author>Author of 7</author>
+ </book>
+ <book>
+ <isbn>8</isbn>
+ <title>Title of 8</title>
+ <author>Author of 8</author>
+ </book>
+ <book>
+ <isbn>9</isbn>
+ <title>Title of 9</title>
+ <author>Author of 9</author>
+ </book>
+ <book>
+ <isbn>10</isbn>
+ <title>Title of 10</title>
+ <author>Author of 10</author>
+ </book>
+ <book>
+ <isbn>11</isbn>
+ <title>Title of 11</title>
+ <author>Author of 11</author>
+ </book>
+ <book>
+ <isbn>12</isbn>
+ <title>Title of 12</title>
+ <author>Author of 12</author>
+ </book>
+ <book>
+ <isbn>13</isbn>
+ <title>Title of 13</title>
+ <author>Author of 13</author>
+ </book>
+ <book>
+ <isbn>14</isbn>
+ <title>Title of 14</title>
+ <author>Author of 14</author>
+ </book>
+ <book>
+ <isbn>15</isbn>
+ <title>Title of 15</title>
+ <author>Author of 15</author>
+ </book>
+ <book>
+ <isbn>16</isbn>
+ <title>Title of 16</title>
+ <author>Author of 16</author>
+ </book>
+ <book>
+ <isbn>17</isbn>
+ <title>Title of 17</title>
+ <author>Author of 17</author>
+ </book>
+ <book>
+ <isbn>18</isbn>
+ <title>Title of 18</title>
+ <author>Author of 18</author>
+ </book>
+ <book>
+ <isbn>19</isbn>
+ <title>Title of 19</title>
+ <author>Author of 19</author>
+ </book>
+ <book>
+ <isbn>20</isbn>
+ <title>Title of 20</title>
+ <author>Author of 20</author>
+ </book>
+</books>
diff --git a/includes/js/dojox/data/tests/stores/books2.html b/includes/js/dojox/data/tests/stores/books2.html
new file mode 100644
index 0000000..c0b3550
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/books2.html
@@ -0,0 +1,43 @@
+<html>
+<head>
+ <title>Books2.html</title>
+</head>
+<body>
+<table id="books2">
+ <thead>
+ <tr>
+ <th>isbn</th>
+ <th>title</th>
+ <th>author</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>A9B57C</td>
+ <td>Title of 1</td>
+ <td>Author of 1</td>
+ </tr>
+ <tr>
+ <td>A9B57F</td>
+ <td>Title of 2</td>
+ <td>Author of 2</td>
+ </tr>
+ <tr>
+ <td>A9B577</td>
+ <td>Title of 3</td>
+ <td>Author of 3</td>
+ </tr>
+ <tr>
+ <td>A9B574</td>
+ <td>Title of 4</td>
+ <td>Author of 4</td>
+ </tr>
+ <tr>
+ <td>A9B5CC</td>
+ <td>Title of 5</td>
+ <td>Author of 5</td>
+ </tr>
+ </tbody>
+</table>
+</body>
+</html> \ No newline at end of file
diff --git a/includes/js/dojox/data/tests/stores/books2.xml b/includes/js/dojox/data/tests/stores/books2.xml
new file mode 100644
index 0000000..d1fa494
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/books2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+ <book>
+ <isbn>A9B57C</isbn>
+ <title>Title of 1</title>
+ <author>Author of 1</author>
+ </book>
+ <book>
+ <isbn>A9B57F</isbn>
+ <title>Title of 2</title>
+ <author>Author of 2</author>
+ </book>
+ <book>
+ <isbn>A9B577</isbn>
+ <title>Title of 3</title>
+ <author>Author of 3</author>
+ </book>
+ <book>
+ <isbn>A9B574</isbn>
+ <title>Title of 4</title>
+ <author>Author of 4</author>
+ </book>
+ <book>
+ <isbn>A9B5CC</isbn>
+ <title>Title of 5</title>
+ <author>Author of 5</author>
+ </book>
+</books>
diff --git a/includes/js/dojox/data/tests/stores/books3.html b/includes/js/dojox/data/tests/stores/books3.html
new file mode 100644
index 0000000..7d0f81d
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/books3.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+ <title>Books2.html</title>
+</head>
+<body>
+<ul id="books3">
+ <li>A9B57C - Title of 1 - Author of 1</li>
+ <li>A9B57F - Title of 2 - Author of 2</li>
+ <li>A9B577 - Title of 3 - Author of 3</li>
+ <li>A9B574 - Title of 4 - Author of 4</li>
+ <li>A9B5CC - Title of 5 - Author of 5</li>
+</ul>
+</body>
+</html> \ No newline at end of file
diff --git a/includes/js/dojox/data/tests/stores/books3.xml b/includes/js/dojox/data/tests/stores/books3.xml
new file mode 100644
index 0000000..c44b4c3
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/books3.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+ <category>
+ <name>Category 1</name>
+ <book>
+ <isbn>1</isbn>
+ <title>Title of 1</title>
+ <author>Author of 1</author>
+ </book>
+ <book>
+ <isbn>2</isbn>
+ <title>Title of 2</title>
+ <author>Author of 2</author>
+ </book>
+ <book>
+ <isbn>3</isbn>
+ <title>Title of 3</title>
+ <author>Author of 3</author>
+ </book>
+ <book>
+ <isbn>4</isbn>
+ <title>Title of 4</title>
+ <author>Author of 4</author>
+ </book>
+ <book>
+ <isbn>5</isbn>
+ <title>Title of 5</title>
+ <author>Author of 5</author>
+ </book>
+ </category>
+</books>
diff --git a/includes/js/dojox/data/tests/stores/books_isbnAttr.xml b/includes/js/dojox/data/tests/stores/books_isbnAttr.xml
new file mode 100644
index 0000000..b9f3d27
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/books_isbnAttr.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+ <book isbn="1">
+ <title>Title of 1</title>
+ <author>Author of 1</author>
+ </book>
+ <book isbn="2">
+ <title>Title of 2</title>
+ <author>Author of 2</author>
+ </book>
+ <book isbn="3">
+ <title>Title of 3</title>
+ <author>Author of 3</author>
+ </book>
+ <book isbn="4">
+ <title>Title of 4</title>
+ <author>Author of 4</author>
+ </book>
+ <book isbn="5">
+ <title>Title of 5</title>
+ <author>Author of 5</author>
+ </book>
+</books>
diff --git a/includes/js/dojox/data/tests/stores/books_isbnAttr2.xml b/includes/js/dojox/data/tests/stores/books_isbnAttr2.xml
new file mode 100644
index 0000000..a6ce005
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/books_isbnAttr2.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+ <book isbn="ABC1">
+ <title>Title of 1</title>
+ <author>Author of 1</author>
+ </book>
+ <book isbn="ABC2">
+ <title>Title of 2</title>
+ <author>Author of 2</author>
+ </book>
+ <book isbn="ABC3">
+ <title>Title of 3</title>
+ <author>Author of 3</author>
+ </book>
+ <book isbn="ACB4">
+ <title>Title of 4</title>
+ <author>Author of 4</author>
+ </book>
+ <book isbn="ACF5">
+ <title>Title of 5</title>
+ <author>Author of 5</author>
+ </book>
+</books>
diff --git a/includes/js/dojox/data/tests/stores/geography.xml b/includes/js/dojox/data/tests/stores/geography.xml
new file mode 100644
index 0000000..070a8c1
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/geography.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<opml version="1.0">
+ <head>
+ <title>geography.opml</title>
+ <dateCreated>2006-11-10</dateCreated>
+ <dateModified>2006-11-13</dateModified>
+ <ownerName>Magellan, Ferdinand</ownerName>
+ </head>
+ <body>
+ <outline text="Africa" type="continent">
+ <outline text="Egypt" type="country"/>
+ <outline text="Kenya" type="country">
+ <outline text="Nairobi" type="city"/>
+ <outline text="Mombasa" type="city"/>
+ </outline>
+ <outline text="Sudan" type="country">
+ <outline text="Khartoum" type="city"/>
+ </outline>
+ </outline>
+ <outline text="Asia" type="continent">
+ <outline text="China" type="country"/>
+ <outline text="India" type="country"/>
+ <outline text="Russia" type="country"/>
+ <outline text="Mongolia" type="country"/>
+ </outline>
+ <outline text="Australia" type="continent" population="21 million">
+ <outline text="Australia" type="country" population="21 million"/>
+ </outline>
+ <outline text="Europe" type="continent">
+ <outline text="Germany" type="country"/>
+ <outline text="France" type="country"/>
+ <outline text="Spain" type="country"/>
+ <outline text="Italy" type="country"/>
+ </outline>
+ <outline text="North America" type="continent">
+ <outline text="Mexico" type="country" population="108 million" area="1,972,550 sq km">
+ <outline text="Mexico City" type="city" population="19 million" timezone="-6 UTC"/>
+ <outline text="Guadalajara" type="city" population="4 million" timezone="-6 UTC"/>
+ </outline>
+ <outline text="Canada" type="country" population="33 million" area="9,984,670 sq km">
+ <outline text="Ottawa" type="city" population="0.9 million" timezone="-5 UTC"/>
+ <outline text="Toronto" type="city" population="2.5 million" timezone="-5 UTC"/>
+ </outline>
+ <outline text="United States of America" type="country"/>
+ </outline>
+ <outline text="South America" type="continent">
+ <outline text="Brazil" type="country" population="186 million"/>
+ <outline text="Argentina" type="country" population="40 million"/>
+ </outline>
+ </body>
+</opml>
diff --git a/includes/js/dojox/data/tests/stores/geography_withspeciallabel.xml b/includes/js/dojox/data/tests/stores/geography_withspeciallabel.xml
new file mode 100644
index 0000000..597c164
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/geography_withspeciallabel.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<opml version="1.0">
+ <head>
+ <title>geography.opml</title>
+ <dateCreated>2006-11-10</dateCreated>
+ <dateModified>2006-11-13</dateModified>
+ <ownerName>Magellan, Ferdinand</ownerName>
+ </head>
+ <body>
+ <outline text="Africa" type="continent" label="Continent/Africa">
+ <outline text="Egypt" type="country" label="Country/Egypt"/>
+ <outline text="Kenya" type="country" label="Country/Kenya">
+ <outline text="Nairobi" type="city" label="City/Nairobi"/>
+ <outline text="Mombasa" type="city" label="City/Mombasa"/>
+ </outline>
+ <outline text="Sudan" type="country" label="Country/Sudan">
+ <outline text="Khartoum" type="city" label="City/Khartoum"/>
+ </outline>
+ </outline>
+ <outline text="Asia" type="continent" label="Continent/Asia">
+ <outline text="China" type="country" label="Country/China"/>
+ <outline text="India" type="country" label="Country/India"/>
+ <outline text="Russia" type="country" label="Country/Russia"/>
+ <outline text="Mongolia" type="country" label="Country/Mongolia"/>
+ </outline>
+ <outline text="Australia" type="continent" population="21 million" label="Continent/Australia">
+ <outline text="Australia" type="country" population="21 million" label="Country/Australia"/>
+ </outline>
+ <outline text="Europe" type="continent" label="Contintent/Europe">
+ <outline text="Germany" type="country" label="Country/Germany"/>
+ <outline text="France" type="country" label="Country/France"/>
+ <outline text="Spain" type="country" label="Country/Spain"/>
+ <outline text="Italy" type="country" label="Country/Italy"/>
+ </outline>
+ <outline text="North America" type="continent" label="Continent/North America">
+ <outline text="Mexico" type="country" population="108 million" area="1,972,550 sq km" label="Country/Mexico">
+ <outline text="Mexico City" type="city" population="19 million" timezone="-6 UTC" label="City/Mexico City"/>
+ <outline text="Guadalajara" type="city" population="4 million" timezone="-6 UTC" label="City/Guadalajara"/>
+ </outline>
+ <outline text="Canada" type="country" population="33 million" area="9,984,670 sq km" label="Country/Canada">
+ <outline text="Ottawa" type="city" population="0.9 million" timezone="-5 UTC" label="City/Ottawa"/>
+ <outline text="Toronto" type="city" population="2.5 million" timezone="-5 UTC" label="City/Toronto"/>
+ </outline>
+ <outline text="United States of America" type="country" label="Country/United States of America"/>
+ </outline>
+ <outline text="South America" type="continent" label="Continent/South America">
+ <outline text="Brazil" type="country" population="186 million" label="Country/Brazil"/>
+ <outline text="Argentina" type="country" population="40 million" label="Country/Argentina"/>
+ </outline>
+ </body>
+</opml>
diff --git a/includes/js/dojox/data/tests/stores/jsonPathStore.js b/includes/js/dojox/data/tests/stores/jsonPathStore.js
new file mode 100644
index 0000000..9a42a18
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/jsonPathStore.js
@@ -0,0 +1,604 @@
+if(!dojo._hasResource["dojox.data.tests.stores.jsonPathStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.tests.stores.jsonPathStore"] = true;
+dojo.provide("dojox.data.tests.stores.jsonPathStore");
+dojo.require("dojox.data.jsonPathStore");
+
+dojox.data.tests.stores.jsonPathStore.error = function(t, d, errData){
+ // summary:
+ // The error callback function to be used for all of the tests.
+ d.errback(errData);
+}
+
+dojox.data.tests.testData=dojo.toJson({"store": {"book": [{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99}], "bicycle": {"color": "red", "price": 19.95}}});
+
+dojox.data.tests.test_ID_Data=dojo.toJson({"gadgetList": {"myId": "product", "1000": {"name": "Gadget", "type": "Junk", "myId": "1000", "price": "19.99"}, "1001": {"name": "Gadget2", "type": "Junk", "myId": "1010", "price": "17.99"}, "1003": {"name": "Gadget3", "type": "Junk", "myId": "1009", "price": "15.99"}, "1004": {"name": "Gadget4", "type": "Junk", "myId": "1008", "price": "13.99"}, "1005": {"name": "Gadget5", "type": "Junk", "myId": "1007", "price": "11.99"}, "1006": {"name": "Gadget6", "type": "Junk", "myId": "1006", "price": "9.99"}}, "testList": {"a": {"name": "test", "type": "Junk", "myId": "3000", "price": "19.99"}, "b": {"name": "test2", "type": "Junk", "myId": "3010", "price": "17.99"}, "c": {"name": "test3", "type": "Junk", "myId": "3009", "price": "15.99"}, "d": {"name": "test4", "type": "Junk", "myId": "3008", "price": "13.99"}, "e": {"name": "test5", "type": "Junk", "myId": "3007", "price": "11.99"}, "f": {"name": "test6", "type": "Junk", "myId": "3006", "price": "9.99"}}, "bricknbrack": [{"name": "BrickNBrack", "type": "Junk", "myId": "2000", "price": "19.99"}, {"name": "BrickNBrack2", "type": "Junk", "myId": "2010", "price": "17.99"}, {"name": "BrickNBrack3", "type": "Junk", "myId": "2009", "price": "15.99"}, {"name": "BrickNBrack4", "type": "Junk", "myId": "2008", "price": "13.99"}, {"name": "BrickNBrack5", "type": "Junk", "myId": "2007", "price": "11.99"}, {"name": "BrickNBrack6", "type": "Junk", "myId": "2006", "price": "9.99"}]});
+
+doh.register("dojox.data.tests.stores.jsonPathStore",
+ [
+ {
+ name: "Create, Index, Export: {clone: true, suppressExportMeta: true}",
+ options: {clone: true, suppressExportMeta: true},
+ runTest: function(t) {
+ var original= dojox.data.tests.test_ID_Data;
+ var store= new dojox.data.jsonPathStore({
+ data: original,
+ mode: dojox.data.SYNC_MODE,
+ idAttribute: "myId",
+ indexOnLoad: true
+ });
+
+ //snapshot of the store after creation;
+ var storeWithMeta = dojo.toJson(store._data);
+ var result = store.dump(this.options);
+ doh.assertEqual(storeWithMeta, result);
+ }
+ },
+ {
+ name: "Create, Index, Export: {cleanMeta: true, clone: true}",
+ options: {cleanMeta: true, clone: true, suppressExportMeta: true},
+ runTest: function(t) {
+ var original= dojox.data.tests.test_ID_Data;
+ var store= new dojox.data.jsonPathStore({
+ data: original,
+ mode: dojox.data.SYNC_MODE,
+ idAttribute: "myId",
+ indexOnLoad: true
+ });
+
+ var result = store.dump(this.options);
+ doh.assertEqual(original, result);
+ }
+ },
+ {
+ name: "Create, Index, Export: {suppressExportMeta: true}",
+ options: {suppressExportMeta: true},
+ runTest: function(t) {
+ var original= dojox.data.tests.test_ID_Data;
+ var store= new dojox.data.jsonPathStore({
+ data: original,
+ mode: dojox.data.SYNC_MODE,
+ idAttribute: "myId",
+ indexOnLoad: true
+ });
+
+ //snapshot of the store after creation;
+ var storeWithMeta = dojo.toJson(store._data);
+ var result = store.dump(this.options);
+ doh.assertEqual(storeWithMeta, result);
+ }
+ },
+ {
+ name: "Create, Index, Export: {clone: true, type: 'raw', suppressExportMeta: true}",
+ options: {clone: true, type: "raw", suppressExportMeta: true},
+ runTest: function(t) {
+ var original= dojox.data.tests.test_ID_Data;
+ var store= new dojox.data.jsonPathStore({
+ data: original,
+ mode: dojox.data.SYNC_MODE,
+ idAttribute: "myId",
+ indexOnLoad: true
+ });
+
+ //snapshot of the store after creation;
+ var storeWithMeta = dojo.toJson(store._data);
+ var result = dojo.toJson(store.dump(this.options));
+ doh.assertEqual(storeWithMeta, result);
+ }
+ },
+ {
+ name: "Create, Index, Export: {clone: true, suppressExportMeta: true}",
+ options: {cleanMeta: true},
+ runTest: function(t) {
+ var original= dojox.data.tests.test_ID_Data;
+ var store= new dojox.data.jsonPathStore({
+ data: original,
+ mode: dojox.data.SYNC_MODE,
+ idAttribute: "myId",
+ indexOnLoad: true
+ });
+
+ //snapshot of the store after creation;
+ var result = store.dump(this.options);
+ doh.assertEqual(original, result);
+ }
+ },
+ {
+ name: "Create, Index, Export: {type: raw}",
+ options: {type: "raw"},
+ runTest: function(t) {
+ var original= dojox.data.tests.test_ID_Data;
+ var store= new dojox.data.jsonPathStore({
+ data: original,
+ mode: dojox.data.SYNC_MODE,
+ idAttribute: "myId",
+ indexOnLoad: true
+ });
+
+ //snapshot of the store after creation;
+ var result = dojo.toJson(store.dump(this.options));
+ var storeWithMeta = dojo.toJson(store._data);
+ doh.assertEqual(storeWithMeta, result);
+ }
+ },
+ {
+ name: "ReadAPI: fetch() Empty Request Test [SYNC_MODE]",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var success = dojo.toJson([{"book": [{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}], "bicycle": {"color": "red", "price": 19.95, "_meta": {"path": "$['store']['bicycle']", "autoId": true, "referenceIds": ["_ref_5"]}, "_id": "_auto_2"}, "_meta": {"path": "$['store']", "autoId": true, "referenceIds": ["_ref_0"]}, "_id": "_auto_0"}, [{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}], {"color": "red", "price": 19.95, "_meta": {"path": "$['store']['bicycle']", "autoId": true, "referenceIds": ["_ref_5"]}, "_id": "_auto_2"}, {"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}]);
+ var result = dojo.toJson(store.fetch());
+ doh.assertEqual(success, result);
+ return true;
+ }
+ },
+
+ {
+ name: "ReadAPI: fetch('$.store.book[*]') test [SYNC_MODE]",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var success = dojo.toJson([{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}]);
+ var result = dojo.toJson(store.fetch({query:"$.store.book[*]"}));
+ doh.assertEqual(success, result);
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: fetch('$.store.book[*]') test [ASYNC_MODE forced SYNC_MODE by string parameter]",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.ASYNC_MODE});
+ var success = dojo.toJson([{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}]);
+ var result = dojo.toJson(store.fetch("$.store.book[*]"));
+ doh.assertEqual(success, result);
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: fetch({query: '$.store.book[*]', start: 2})",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var success = dojo.toJson([{"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}]);
+ var result = dojo.toJson(store.fetch({query: '$.store.book[*]', start: 2}));
+ doh.assertEqual(success, result);
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: fetch({query: '$.store.book[*]', start: 2, count: 1})",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var result = store.fetch({query: "$.store.book[*]", start: 2, count: 1});
+ doh.assertEqual(result[0].author, 'Herman Melville');
+ return true;
+ }
+ },
+
+ {
+ name: "ReadAPI: fetch(query: '$.store.book[0]'...callbacks...) [ASYNC_MODE]",
+ runTest: function(datastore, t){
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData});
+ var d = new doh.Deferred();
+ function onBegin(count, args){
+ doh.assertEqual(1, count);
+ }
+ function onItem(item){
+ doh.assertTrue(store.isItem(item));
+ }
+
+ function onComplete(results){
+ doh.assertEqual(1, results.length);
+ doh.assertEqual("Nigel Rees", results[0]["author"]);
+ d.callback(true);
+ }
+
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+
+ store.fetch({query: "$.store.book[0]", onBegin: onBegin, onItem: onItem, onError: onError, onComplete: onComplete});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "ReadAPI: isItem() test",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var result = store.fetch("$.store.book[*].author");
+ doh.assertFalse(store.isItem(result[0]));
+ result = store.fetch("$.store.book[*]");
+ doh.assertTrue(store.isItem(result[0]));
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: getValue() test",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var data = store.fetch("$.store.book[*]");
+ var result = store.getValue(data[0], "author");
+ doh.assertEqual("Nigel Rees", result);
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: getValues() test",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var result = store.fetch("$.store.book[*]");
+ doh.assertEqual(dojo.toJson(store.getValues(result[0], "author")),dojo.toJson(["Nigel Rees"]));
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: getAttributes() test",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var result = store.fetch("$.store.book[*]");
+ doh.assertEqual(dojo.toJson(store.getAttributes(result[0])),'["category","author","title","price","_meta","_id"]');
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: getAttributes() test [hideMetaAttributes]",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, hideMetaAttributes: true});
+ var result = store.fetch("$.store.book[*]");
+ doh.assertEqual('["category","author","title","price","_id"]',dojo.toJson(store.getAttributes(result[0])));
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: hasAttribute() test",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var result = store.fetch("$.store.book[*]");
+ doh.assertTrue(store.hasAttribute(result[0], "author"));
+ doh.assertFalse(store.hasAttribute(result[0],"_im_invalid_fooBar"));
+ return true;
+ }
+ },
+
+ {
+ name: "ReadAPI: containsValue() test",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ var result = store.fetch("$.store.book[*]");
+ doh.assertTrue(store.containsValue(result[0], "author", "Nigel Rees"));
+ doh.assertFalse(store.containsValue(result[0], "author", "_im_invalid_fooBar"));
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: getFeatures() test",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE});
+ //doh.debug("Store Features: ", dojo.toJson(store.getFeatures()));
+ var success='{"dojo.data.api.Read":true,"dojo.data.api.Identity":true,"dojo.data.api.Write":true,"dojo.data.api.Notification":true}';
+ doh.assertEqual(success,dojo.toJson(store.getFeatures()));
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: getLabel(item) test [multiple label attributes]",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, labelAttribute: ["title", "author"]});
+ var result = store.fetch("$.store.book[0]")[0];
+ doh.assertEqual("Sayings of the Century Nigel Rees",store.getLabel(result));
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: getLabelAttributes(item) test [multiple label attributes]",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, labelAttribute: ["title", "author"]});
+ var result = store.fetch("$.store.book[0]")[0];
+ doh.assertEqual('["title","author"]',dojo.toJson(store.getLabelAttributes(result)));
+ return true;
+ }
+ },
+ {
+ name: "ReadAPI: getLabelAttributes(item) test [single label attribute]",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, labelAttribute: ["title"]});
+ var result = store.fetch("$.store.book[0]")[0];
+ doh.assertEqual('["title"]',dojo.toJson(store.getLabelAttributes(result)));
+ return true;
+ }
+ },
+ {
+ name: "jsonPathStore Feature: override createLabel",
+ runTest: function(t) {
+ var createLabel = function(item){
+ return item[this.labelAttribute[0]] + " By " + item[this.labelAttribute[1]];
+ };
+
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, labelAttribute: ["title", "author"], createLabel: createLabel});
+ var result = store.fetch("$.store.book[0]")[0];
+ doh.assertEqual('Sayings of the Century By Nigel Rees',store.getLabel(result));
+ return true;
+ }
+ },
+ {
+ name: "jsonPathStore Feature: autoIdentity",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+ var result = dojo.toJson(store.fetch("$.store.book[0]")[0]);
+ var success=dojo.toJson( {"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"});
+ doh.assertEqual(success,result);
+ return true;
+ }
+ },
+
+ {
+ name: "jsonPathStore Feature: autoIdentity [clean export removing added id attributes in addition to meta]",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+ //do a search to popuplate some of the itesm with autoId data
+ var result = store.fetch("$.store.book[0]");
+ result = store.dump({cleanMeta: true});
+ doh.assertEqual(dojox.data.tests.testData,result);
+ return true;
+ }
+ },
+
+ {
+ name: "IdentityAPI: getIdentity(item)",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+ var data= store.fetch("$.store.book[0]")[0];
+ var result= store.getIdentity(data);
+ var success="_auto_3";
+ doh.assertEqual(success,result);
+ return true;
+ }
+ },
+
+ {
+
+ name: "IdentityAPI: fetchItemByIdentity(item) [SYNC_MODE]",
+ runTest: function(t){
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+
+ var data= store.fetch("$.store.book[0]")[0];
+ var id = store.getIdentity(data);
+ var result = dojo.toJson(store.fetchItemByIdentity({identity:id}));
+ var success = dojo.toJson(data);
+ doh.assertEqual(success,result);
+ return true;
+ }
+ },
+ {
+
+ name: "jsonPathStore Feature: byId(item) [fetchItemByIdentity alias] [SYNC_MODE]",
+ runTest: function(t){
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+
+ var data= store.fetch("$.store.book[0]")[0];
+ var id = store.getIdentity(data);
+ var result = dojo.toJson(store.byId({identity:id}));
+ var success = dojo.toJson(data);
+ doh.assertEqual(success,result);
+ return true;
+ }
+ },
+
+ {
+ name: "IdentityAPI: fetchItemByIdentity(id) single Item [ASYNC_MODE]",
+ timeout: 1000,
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, indexOnLoad: true});
+ var d = new doh.Deferred();
+ var query = {query: "$.store.book[0]", mode: dojox.data.SYNC_MODE};
+ var data = store.fetch(query)[0];
+ var id = store.getIdentity(data);
+
+ function onItem(item){
+ doh.assertTrue(store.isItem(item));
+ doh.assertEqual(data["author"], item["author"]);
+ d.callback(true);
+ }
+
+ function onError(errData){
+
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+
+ store.fetchItemByIdentity({identity: id, onItem: onItem, onError: onError});
+
+ return d; // Deferred
+ }
+ },
+ {
+ name: "IdentityAPI: getIdentityAttributes(item) ",
+ runTest: function(t) {
+ var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+ var data= store.fetch("$.store.book[0]")[0];
+ var result = dojo.toJson(store.getIdentityAttributes(data));
+ var success = '["_id"]';
+ doh.assertEqual(success,result);
+ return true;
+ }
+ },
+ {
+ name: "WriteAPI: newItem(item) add to store root.",
+ runTest: function(t) {
+ var original = dojox.data.tests.testData;
+ var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+
+ var testObject = {
+ propA: "foo",
+ propB: "bar"
+ }
+
+ var testObject2 = {
+ propA: "foo",
+ propB: "bar"
+ }
+
+ var newItem = store.newItem(testObject);
+ doh.assertTrue(store.isItem(newItem));
+
+ newItem = store.newItem(testObject2);
+ doh.assertTrue(store.isItem(newItem));
+
+ return true;
+ }
+ },
+ {
+ name: "WriteAPI: newItem(item) no idAttribute on data item, added only with pInfo",
+ runTest: function(t) {
+ var original = dojox.data.tests.testData;
+ var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE});
+
+ var parentItem = store.fetch("$.store.book[0]")[0];
+
+ var testObject = {
+ propA: "foo",
+ propB: "bar"
+ }
+
+ var newItem = store.newItem(testObject,{parent: parentItem, attribute: "TEST_PROPERTY"});
+ doh.assertTrue(store.isItem(newItem));
+ return true;
+ }
+ },
+ {
+ name: "WriteAPI: newItem(item) given id, no parent Attribute",
+ runTest: function(t) {
+ var original = dojox.data.tests.testData;
+ var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+
+ var parentItem = store.fetch("$.store.book[0]")[0];
+
+ var testObject = {
+ _id: "99999",
+ propA: "foo",
+ propB: "bar"
+ }
+
+ var newItem = store.newItem(testObject,{parent: parentItem});
+ doh.assertTrue(store.isItem(newItem));
+ return true;
+ }
+ },
+ {
+ name: "WriteAPI: newItem(item) given id and parent Attribute",
+ runTest: function(t) {
+ var original = dojox.data.tests.testData;
+ var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+
+ var parentItem = store.fetch("$.store.book[0]")[0];
+
+ var testObject = {
+ _id: "99999",
+ propA: "foo",
+ propB: "bar"
+ }
+
+ var newItem = store.newItem(testObject,{parent: parentItem, attribute: "TEST"});
+ doh.assertTrue(store.isItem(newItem));
+ return true;
+ }
+ },
+ {
+ name: "WriteAPI: newItem(item) adding to an array",
+ runTest: function(t) {
+ var original = dojox.data.tests.testData;
+ var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, idAttribute: "_id"});
+
+ var parentItem = store.fetch("$.store")[0];
+
+ var testObject = {
+ _id: "99999",
+ propA: "foo",
+ propB: "bar"
+ }
+
+ var newItem = store.newItem(testObject,{parent: parentItem, attribute: "book"});
+ doh.assertTrue(store.isItem(newItem));
+ return true;
+ }
+ },
+ {
+ name: "WriteAPI: setValue(item, value)",
+ runTest: function(t) {
+ var original = dojox.data.tests.testData;
+ var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, indexOnLoad: true, idAttribute: "_id"});
+ var item = store.fetch("$.store")[0];
+
+ var snapshot = store.dump({clone:true, cleanMeta: false, suppressExportMeta: true});
+
+ store.setValue(item, "Foo", "Bar");
+ doh.assertEqual(store._data.store.Foo, "Bar");
+ doh.assertTrue(store._data.store._meta.isDirty);
+ store.save();
+ doh.assertFalse(store._data.store._meta.isDirty);
+ return true;
+ }
+ },
+ {
+ name: "WriteAPI: setValues(item, value)",
+ runTest: function(t) {
+ var original = dojox.data.tests.testData;
+ var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, indexOnLoad: true, idAttribute: "_id"});
+ var item = store.fetch("$.store")[0];
+
+ var snapshot = store.dump({clone:true, cleanMeta: false, suppressExportMeta: true});
+
+ store.setValues(item, "Foo", ["Bar", "Diddly", "Ar"]);
+ doh.assertEqual(store._data.store.Foo[0], "Bar");
+ doh.assertEqual(store._data.store.Foo.length, 3);
+ doh.assertTrue(store._data.store._meta.isDirty);
+ store.save();
+ doh.assertFalse(store._data.store._meta.isDirty);
+ return true;
+ }
+ },
+ {
+ name: "WriteAPI: unsetAttribute(item, attribute)",
+ runTest: function(t) {
+ var original = dojox.data.tests.testData;
+ var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, indexOnLoad: true, idAttribute: "_id"});
+ var item = store.fetch("$.store")[0];
+
+ var snapshot = store.dump({clone:true, cleanMeta: false, suppressExportMeta: true});
+
+ store.setValues(item, "Foo", ["Bar", "Diddly", "Ar"]);
+ doh.assertEqual(store._data.store.Foo[0], "Bar");
+ doh.assertEqual(store._data.store.Foo.length, 3);
+ doh.assertTrue(store._data.store._meta.isDirty);
+ store.save();
+ doh.assertFalse(store._data.store._meta.isDirty);
+ store.unsetAttribute(item,"Foo");
+ doh.assertFalse(item.Foo);
+ doh.assertTrue(store._data.store._meta.isDirty);
+ store.save();
+ doh.assertFalse(store._data.store._meta.isDirty);
+ return true;
+ }
+ },
+ {
+ name: "WriteAPI: revert()",
+ runTest: function(t) {
+ var original = dojox.data.tests.testData;
+ var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, indexOnLoad: true, idAttribute: "_id"});
+ var item = store.fetch("$.store")[0];
+
+ var snapshot = store.dump({clone:true, cleanMeta: false, suppressExportMeta: true});
+
+ store.setValues(item, "Foo", ["Bar", "Diddly", "Ar"]);
+ doh.assertEqual(store._data.store.Foo[0], "Bar");
+ doh.assertEqual(store._data.store.Foo.length, 3);
+ doh.assertTrue(store._data.store._meta.isDirty);
+ store.revert();
+ doh.assertFalse(store._data.store._meta.isDirty);
+ doh.assertFalse(store._data.store.Foo);
+ return true;
+ }
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/data/tests/stores/movies.csv b/includes/js/dojox/data/tests/stores/movies.csv
new file mode 100644
index 0000000..baf71eb
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/movies.csv
@@ -0,0 +1,9 @@
+Title, Year, Producer
+City of God, 2002, Katia Lund
+Rain,, Christine Jeffs
+2001: A Space Odyssey, , Stanley Kubrick
+"This is a ""fake"" movie title", 1957, Sidney Lumet
+Alien, 1979 , Ridley Scott
+"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott
+"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward"
+
diff --git a/includes/js/dojox/data/tests/stores/movies2.csv b/includes/js/dojox/data/tests/stores/movies2.csv
new file mode 100644
index 0000000..401bcfc
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/movies2.csv
@@ -0,0 +1,9 @@
+Title, Year, Producer
+City of God, 2002, Katia Lund
+Rain,"", Christine Jeffs
+2001: A Space Odyssey, , Stanley Kubrick
+"This is a ""fake"" movie title", 1957, Sidney Lumet
+Alien, 1979 , Ridley Scott
+"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott
+"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward"
+
diff --git a/includes/js/dojox/data/tests/stores/patterns.csv b/includes/js/dojox/data/tests/stores/patterns.csv
new file mode 100644
index 0000000..a9bee64
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/patterns.csv
@@ -0,0 +1,11 @@
+uniqueId, value
+9, jfq4@#!$!@Rf14r14i5u
+6, BaBaMaSaRa***Foo
+2, bar*foo
+8, 123abc
+4, bit$Bite
+3, 123abc
+10, 123abcdefg
+1, foo*bar
+7,
+5, 123abc
diff --git a/includes/js/dojox/data/tests/stores/properties.js b/includes/js/dojox/data/tests/stores/properties.js
new file mode 100644
index 0000000..bbdd38d
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/properties.js
@@ -0,0 +1,10 @@
+/*[
+ // Properties of December 1, 2007
+ { "year": "2007" },
+ { "nmonth": "12" },
+ { "month": "December" },
+ { "nday": "1" },
+ { "day": "Saturday" },
+ { "dayOfYear": "335" },
+ { "weekOfYear": "48" }
+]*/
diff --git a/includes/js/dojox/data/tests/stores/snap_pipeline.php b/includes/js/dojox/data/tests/stores/snap_pipeline.php
new file mode 100644
index 0000000..a7e6033
--- /dev/null
+++ b/includes/js/dojox/data/tests/stores/snap_pipeline.php
@@ -0,0 +1,72 @@
+<?php
+
+$field_names = array('"empno"', '"ename"', '"job"', '"hiredate"', '"sal"', '"comm"', '"deptno"');
+
+$rows = array(array("7369", '"SMITH,CLERK"', "7902", '"1993-06-13"', "800.00", "0.00", "20"),
+ array("7499", '"ALLEN,SALESMAN"', "7698", '"1998-08-15"', "1600.00", "300.00", "30"),
+ array("7521", '"WARD,SALESMAN"', "7698", '"1996-03-26"', "1250.00", "500.00", "30"),
+ array("7566", '"JONES,MANAGER"', "7839", '"1995-10-31"', "2975.00", '""', "20"),
+ array("7698", '"BLAKE,MANAGER"', "7839", '"1992-06-11"', "2850.00", '""', "30"),
+ array("7782", '"CLARK,MANAGER"', "7839", '"1993-05-14"', "2450.00", '""', "10"),
+ array("7788", '"SCOTT,ANALYST"', "7566", '"1996-03-05"', "3000.00", '""', "20"),
+ array("7839", '"KING,PRESIDENT"', '"1990-06-09"', "5000", "1100.0", '""', "0.00", "10"),
+ array("7844", '"TURNER,SALESMAN"', "7698", '"1995-06-04"', "1500.00", '""', "0.00", "30"),
+ array("7876", '"ADAMS,CLERK"', "7788", '"1999-06-04"', "1100.00", '""', "20"),
+ array("7900", '"JAMES,CLERK"', "7698", '"2000-06-23"', "950.00", '""', "30"),
+ array("7934", '"MILLER,CLERK"', "7782", '"2000-01-21"', "1300.00", '""', "10"),
+ array("7902", '"FORD,ANALYST"', "7566", '"1997-12-05"', "3000.00", '""', "20"),
+ array("7654", '"MARTIN,SALESMAN"', "7698", '"1998-12-05"', "1250.00", "1400.00", "30"));
+
+$prefix = $_GET["sn_stream_header"];
+
+if($_GET["sn_count"]) {
+ if($_GET["sn_count"] == "records"){
+ echo $prefix . "([[" . count($rows) . "]])";
+ } else {
+ header("HTTP/1.1 400 Bad Request");
+ echo "sn.count parameter, if present, must be set to 'records'.";
+ exit(0);
+ }
+} else {
+ if($_GET["sn_start"]) {
+ $start = $_GET["sn_start"];
+ } else {
+ $start = 1;
+ }
+
+ if($_GET["sn_limit"]) {
+ $limit = $_GET["sn_limit"];
+ } else {
+ $limit = count($rows);
+ }
+
+ if(!is_numeric($start) || !is_numeric($limit)) {
+ header("HTTP/1.1 400 Bad Request");
+ echo "sn.start or sn.limit specified a non-integer value";
+ exit(0);
+ }
+
+ $start -= 1;
+
+ if($start < 0 || $start >= count($rows) || $limit < 0) {
+ header("HTTP/1.1 400 Bad Request");
+ echo "sn.start and/or sn.limit out of range";
+ exit(0);
+ }
+
+ $slice = array_slice($rows, $start, $limit);
+
+ header("Content-type: application/javascript");
+ echo $prefix . "([";
+
+ $out_rows = array("[" . join(", ", $field_names) . "]");
+ foreach($slice as $r) {
+ $out_rows[] = "[" . join(", ", $r) . "]";
+ }
+
+ echo join(", ", $out_rows);
+ echo "])";
+ }
+
+?>
+
diff --git a/includes/js/dojox/data/tests/test_Tree_vs_jsonPathStore.html b/includes/js/dojox/data/tests/test_Tree_vs_jsonPathStore.html
new file mode 100644
index 0000000..f06bafe
--- /dev/null
+++ b/includes/js/dojox/data/tests/test_Tree_vs_jsonPathStore.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dijit Tree Test</title>
+
+ <style someProperty="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ </style>
+
+
+ <script someProperty="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="parseOnLoad: true, isDebug: true"></script>
+ <script someProperty="text/javascript" src="../../../dijit/tests/_testCommon.js"></script>
+
+ <script language="JavaScript" someProperty="text/javascript">
+ dojo.require("dojox.data.jsonPathStore");
+ dojo.require("dijit.Tree");
+ dojo.require("dijit.Menu");
+ dojo.require("dijit.form.Button");
+ dojo.require("dojo.parser"); // scan page for widgets and instantiate them
+
+ function deleteItem(){
+ var store = dijit.byId("myTree").store;
+ store.deleteItem(selectedItem);
+ resetForms();
+ }
+
+ function addItem(){
+ var store = dijit.byId("myTree").store;
+ var pInfo = selectedItem ? {parent: selectedItem, attribute:"children"} : null;
+ console.debug(pInfo);
+ store.newItem({id: dojo.byId('newId').value,name:dojo.byId("label").value,someProperty:dojo.byId("someProperty").value},pInfo);
+ resetForms();
+ }
+
+ function resetForms() {
+ dojo.byId('selected').innerHTML="Tree Root"
+ selectedItem=null;
+ dojo.byId("uLabel").value = "";
+ dojo.byId("uSomeProperty").value = "";
+ }
+
+ function updateItem(){
+ console.log("Updating Item");
+ var store = dijit.byId("myTree").store;
+
+ if (selectedItem!=null){
+ if (dojo.byId("uLabel").value != store.getValue(selectedItem, "name")){
+ store.setValue(selectedItem, "name", dojo.byId("uLabel").value);
+ }
+
+ if (dojo.byId("uSomeProperty").value != store.getValue(selectedItem, "someProperty")){
+ store.setValue(selectedItem, "someProperty", dojo.byId("uSomeProperty").value);
+ }
+
+ }else{
+ console.error("Can't update the tree root");
+ }
+ }
+
+ dojo.addOnLoad(function(){
+ resetForms();
+ });
+
+ function onClick(item){
+ selectedItem = item;
+ dojo.byId('selected').innerHTML= item ? treeTestStore.getLabel(item) : "";
+ dojo.byId('uLabel').value = item ? treeTestStore.getLabel(item) : "";
+ dojo.byId('uSomeProperty').value = item ? treeTestStore.getValue(item,"someProperty") : "";
+ }
+ </script>
+
+</head>
+<body class="tundra">
+
+ <h1 class="testTitle">Dijit Tree Test - dojo.data.Notification API support</h1>
+
+ <div dojoType="dojox.data.jsonPathStore" jsId="treeTestStore" idAttribute="id" labelAttribute="name"
+ url="treeTest.json" ></div>
+
+ <div dojoType="dijit.Tree" id="myTree" label="root" store="treeTestStore" onClick="onClick" labelAttr="name" somePropertyAttr="someProperty" query="{query: '$[*]'}"></div>
+
+ <br />
+ <h2>Current Selection: <span id='selected'>Tree Root</span>
+
+ <h2>Selected Item:</h2>
+ Name: <input id="uLabel" width="50" value="Enter Node Label" /><br />
+ Description: <input id="uSomeProperty" width="50" value="Some Test Property" /><br /><br />
+ <div dojoType="dijit.form.Button" iconClass="noteIcon" onClick="updateItem();">Update Item</div>
+
+ <h2>New Item</h2>
+ <p>Enter an Id, Name, and optionally a description to be added as a new item to the store. Upon successful addition, the tree will recieve notification of this event and respond accordingly. If you select a node the item will be added to that node, otherwise the item will be added to the tree root. "Id" is the identifer here and as such must be unique for all items in the store.</p>
+ Id: <input id="newId" width="50" value="Enter Item Id" /><br />
+ Name: <input id="label" width="50" value="Enter Item Name" /><br />
+ Description: <input id="someProperty" width="50" value="Enter Some Property Value" /><br /><br />
+
+ <div dojoType="dijit.form.Button" iconClass="noteIcon" onClick="addItem();">Add Item to Store</div>
+ <br />
+ <button dojoType="dijit.form.Button" iconClass="noteIcon" onClick="deleteItem()">Delete Node (and children)</button>
+
+
+ </body>
+</html>
diff --git a/includes/js/dojox/data/tests/treeTest.json b/includes/js/dojox/data/tests/treeTest.json
new file mode 100644
index 0000000..70cc7d8
--- /dev/null
+++ b/includes/js/dojox/data/tests/treeTest.json
@@ -0,0 +1,10 @@
+{
+ node1: { id: 'node1', name:'node1', someProperty:'somePropertyA', children:[
+ { id: 'node1.1',name:'node1.1', someProperty:'somePropertyA1'},
+ { id: 'node1.2',name:'node1.2', someProperty:'somePropertyA2'}
+ ]},
+ node2:{ id: 'node2', name:'node2', someProperty:'somePropertyB'},
+ node3:{ id: 'node3', name:'node3', someProperty:'somePropertyC'},
+ node4:{ id: 'node4', name:'node4', someProperty:'somePropertyA'},
+ node5:{ id: 'node5', name:'node5', someProperty:'somePropertyB'}
+}