summaryrefslogtreecommitdiff
path: root/js/dojo-1.7.2/dojox/data
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo-1.7.2/dojox/data')
-rw-r--r--js/dojo-1.7.2/dojox/data/AndOrReadStore.js1047
-rw-r--r--js/dojo-1.7.2/dojox/data/AndOrWriteStore.js812
-rw-r--r--js/dojo-1.7.2/dojox/data/AppStore.js829
-rw-r--r--js/dojo-1.7.2/dojox/data/AtomReadStore.js551
-rw-r--r--js/dojo-1.7.2/dojox/data/CdfStore.js600
-rw-r--r--js/dojo-1.7.2/dojox/data/ClientFilter.js293
-rw-r--r--js/dojo-1.7.2/dojox/data/CouchDBRestStore.js83
-rw-r--r--js/dojo-1.7.2/dojox/data/CssClassStore.js162
-rw-r--r--js/dojo-1.7.2/dojox/data/CssRuleStore.js462
-rw-r--r--js/dojo-1.7.2/dojox/data/CsvStore.js727
-rw-r--r--js/dojo-1.7.2/dojox/data/FileStore.js431
-rw-r--r--js/dojo-1.7.2/dojox/data/FlickrRestStore.js486
-rw-r--r--js/dojo-1.7.2/dojox/data/FlickrStore.js285
-rw-r--r--js/dojo-1.7.2/dojox/data/GoogleFeedStore.js81
-rw-r--r--js/dojo-1.7.2/dojox/data/GoogleSearchStore.js657
-rw-r--r--js/dojo-1.7.2/dojox/data/HtmlStore.js565
-rw-r--r--js/dojo-1.7.2/dojox/data/HtmlTableStore.js473
-rw-r--r--js/dojo-1.7.2/dojox/data/ItemExplorer.js631
-rw-r--r--js/dojo-1.7.2/dojox/data/JsonQueryRestStore.js15
-rw-r--r--js/dojo-1.7.2/dojox/data/JsonRestStore.js510
-rw-r--r--js/dojo-1.7.2/dojox/data/KeyValueStore.js393
-rw-r--r--js/dojo-1.7.2/dojox/data/OpenSearchStore.js373
-rw-r--r--js/dojo-1.7.2/dojox/data/OpmlStore.js526
-rw-r--r--js/dojo-1.7.2/dojox/data/PersevereStore.js113
-rw-r--r--js/dojo-1.7.2/dojox/data/PicasaStore.js274
-rw-r--r--js/dojo-1.7.2/dojox/data/QueryReadStore.js519
-rw-r--r--js/dojo-1.7.2/dojox/data/README127
-rw-r--r--js/dojo-1.7.2/dojox/data/RailsStore.js169
-rw-r--r--js/dojo-1.7.2/dojox/data/S3Store.js35
-rw-r--r--js/dojo-1.7.2/dojox/data/ServiceStore.js395
-rw-r--r--js/dojo-1.7.2/dojox/data/SnapLogicStore.js329
-rw-r--r--js/dojo-1.7.2/dojox/data/StoreExplorer.js196
-rw-r--r--js/dojo-1.7.2/dojox/data/WikipediaStore.js118
-rw-r--r--js/dojo-1.7.2/dojox/data/XmlItem.js44
-rw-r--r--js/dojo-1.7.2/dojox/data/XmlStore.js1472
-rw-r--r--js/dojo-1.7.2/dojox/data/css.js107
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/GoogleFeedTemplate.html26
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/GoogleTemplate.html7
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/GoogleTemplateBlog.html7
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/GoogleTemplateImage.html7
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/GoogleTemplateLocal.html7
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/GoogleTemplateVideo.html7
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_CssStores_combo_tree_grid.html94
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_DataDemoTable.html143
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_FileStore_dojotree.html119
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_FileStore_dojoxdata_combo_grid.html157
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_FlickrRestStore.html236
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_FlickrStore.html161
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_GoogleFeedStore.html113
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_GoogleSearchStore.html125
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_GoogleSearchStore_Grid.html71
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_LazyLoad.html66
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_MultiStores.html116
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_OpenSearchStore.html215
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_PicasaStore.html190
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_ComboBox.html58
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html56
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_grid.html110
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/demo_WikipediaStore.html82
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography.json45
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography.xml51
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Argentina/data.json5
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Brazil/data.json5
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Canada/Ottawa/data.json6
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Canada/Toronto/data.json6
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Canada/data.json10
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/China/data.json4
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Commonwealth of Australia/data.json5
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Egypt/data.json5
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/France/data.json4
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Germany/data.json4
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/India/data.json4
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Italy/data.json4
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Kenya/Mombasa/data.json5
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Kenya/Nairobi/data.json5
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Kenya/data.json9
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Mexico/Guadalajara/data.json7
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Mexico/Mexico City/data.json6
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Mexico/data.json10
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Mongolia/data.json4
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Russia/data.json4
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Spain/data.json4
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Sudan/Khartoum/data.json5
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/Sudan/data.json6
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/United States of America/data.json4
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography/root.json39
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/geography2.xml44
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/openSearchProxy.php33
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/picasaDemo.css44
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/stores/LazyLoadJSIStore.js143
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/stores/filestore_dojotree.php179
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/stores/filestore_dojoxdata.php179
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/stores/filestore_funcs.php366
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/widgets/FileView.js45
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/widgets/FlickrViewList.js35
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/widgets/PicasaView.js38
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/widgets/PicasaViewList.js38
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/widgets/templates/FileView.html62
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/widgets/templates/FlickrViewList.html20
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/widgets/templates/PicasaView.html35
-rw-r--r--js/dojo-1.7.2/dojox/data/demos/widgets/templates/PicasaViewList.html2
-rw-r--r--js/dojo-1.7.2/dojox/data/dom.js102
-rw-r--r--js/dojo-1.7.2/dojox/data/restListener.js53
-rw-r--r--js/dojo-1.7.2/dojox/data/s3/README41
-rw-r--r--js/dojo-1.7.2/dojox/data/s3/proxy.example-php74
-rw-r--r--js/dojo-1.7.2/dojox/data/util/JsonQuery.js99
106 files changed, 18961 insertions, 0 deletions
diff --git a/js/dojo-1.7.2/dojox/data/AndOrReadStore.js b/js/dojo-1.7.2/dojox/data/AndOrReadStore.js
new file mode 100644
index 0000000..6c4122d
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/AndOrReadStore.js
@@ -0,0 +1,1047 @@
+//>>built
+define("dojox/data/AndOrReadStore", ["dojo/_base/kernel", "dojo/_base/declare", "dojo/_base/lang", "dojo/data/util/filter", "dojo/data/util/simpleFetch",
+ "dojo/_base/array", "dojo/date/stamp", "dojo/_base/json", "dojo/_base/window", "dojo/_base/xhr"],
+ function(kernel, declare, lang, filterUtil, simpleFetch, array, dateStamp, json, winUtil, xhr) {
+
+var AndOrReadStore = declare("dojox.data.AndOrReadStore", null, {
+ // summary:
+ // AndOrReadStore uses ItemFileReadStore as a base, modifying only the query (_fetchItems) section.
+ // Supports queries of the form: query:"id:1* OR dept:'Sales Department' || (id:2* && NOT dept:S*)"
+ // Includes legacy/widget support via:
+ // query:{complexQuery:"id:1* OR dept:'Sales Department' || (id:2* && NOT dept:S*)"}
+ // The ItemFileReadStore implements the dojo.data.api.Read API and reads
+ // data from JSON files that have contents in this format --
+ // { items: [
+ // { name:'Kermit', color:'green', age:12, friends:['Gonzo', {_reference:{name:'Fozzie Bear'}}]},
+ // { name:'Fozzie Bear', wears:['hat', 'tie']},
+ // { name:'Miss Piggy', pets:'Foo-Foo'}
+ // ]}
+ // Note that it can also contain an 'identifer' property that specified which attribute on the items
+ // in the array of items that acts as the unique identifier for that item.
+ //
+ constructor: function(/* Object */ keywordParameters){
+ // summary: constructor
+ // keywordParameters: {url: String}
+ // keywordParameters: {data: jsonObject}
+ // keywordParameters: {typeMap: object)
+ // The structure of the typeMap object is as follows:
+ // {
+ // type0: function || object,
+ // type1: function || object,
+ // ...
+ // typeN: function || object
+ // }
+ // Where if it is a function, it is assumed to be an object constructor that takes the
+ // value of _value as the initialization parameters. If it is an object, then it is assumed
+ // to be an object of general form:
+ // {
+ // type: function, //constructor.
+ // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately.
+ // }
+
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = [];
+ this._loadFinished = false;
+ this._jsonFileUrl = keywordParameters.url;
+ this._ccUrl = keywordParameters.url;
+ this.url = keywordParameters.url;
+ this._jsonData = keywordParameters.data;
+ this.data = null;
+ this._datatypeMap = keywordParameters.typeMap || {};
+ if(!this._datatypeMap['Date']){
+ //If no default mapping for dates, then set this as default.
+ //We use the dojo.date.stamp here because the ISO format is the 'dojo way'
+ //of generically representing dates.
+ this._datatypeMap['Date'] = {
+ type: Date,
+ deserialize: function(value){
+ return dateStamp.fromISOString(value);
+ }
+ };
+ }
+ this._features = {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true};
+ this._itemsByIdentity = null;
+ this._storeRefPropName = "_S"; // Default name for the store reference to attach to every item.
+ this._itemNumPropName = "_0"; // Default Item Id for isItem to attach to every item.
+ this._rootItemPropName = "_RI"; // Default Item Id for isItem to attach to every item.
+ this._reverseRefMap = "_RRM"; // Default attribute for constructing a reverse reference map for use with reference integrity
+ this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset.
+ this._queuedFetches = [];
+
+ if(keywordParameters.urlPreventCache !== undefined){
+ this.urlPreventCache = keywordParameters.urlPreventCache?true:false;
+ }
+ if(keywordParameters.hierarchical !== undefined){
+ this.hierarchical = keywordParameters.hierarchical?true:false;
+ }
+ if(keywordParameters.clearOnClose){
+ this.clearOnClose = true;
+ }
+ },
+
+ url: "", // use "" rather than undefined for the benefit of the parser (#3539)
+
+ //Internal var, crossCheckUrl. Used so that setting either url or _jsonFileUrl, can still trigger a reload
+ //when clearOnClose and close is used.
+ _ccUrl: "",
+
+ data: null, //Make this parser settable.
+
+ typeMap: null, //Make this parser settable.
+
+ //Parameter to allow users to specify if a close call should force a reload or not.
+ //By default, it retains the old behavior of not clearing if close is called. But
+ //if set true, the store will be reset to default state. Note that by doing this,
+ //all item handles will become invalid and a new fetch must be issued.
+ clearOnClose: false,
+
+ //Parameter to allow specifying if preventCache should be passed to the xhrGet call or not when loading data from a url.
+ //Note this does not mean the store calls the server on each fetch, only that the data load has preventCache set as an option.
+ //Added for tracker: #6072
+ urlPreventCache: false,
+
+ //Parameter to indicate to process data from the url as hierarchical
+ //(data items can contain other data items in js form). Default is true
+ //for backwards compatibility. False means only root items are processed
+ //as items, all child objects outside of type-mapped objects and those in
+ //specific reference format, are left straight JS data objects.
+ hierarchical: true,
+
+ _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.AndOrReadStore: 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.AndOrReadStore: Invalid attribute argument.");
+ }
+ },
+
+ 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; // mixed
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ var arr = item[attribute] || [];
+ // Clone it before returning. refs: #10474
+ return arr.slice(0, arr.length); // Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ for(var key in item){
+ // Save off only the real item attributes, not the special id marks for O(1) isItem.
+ if((key !== this._storeRefPropName) && (key !== this._itemNumPropName) && (key !== this._rootItemPropName) && (key !== this._reverseRefMap)){
+ attributes.push(key);
+ }
+ }
+ return attributes; // Array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ return (attribute in item);
+ },
+
+ 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 = filterUtil.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'
+ return array.some(this.getValues(item, attribute), function(possibleValue){
+ if(possibleValue !== null && !lang.isObject(possibleValue) && regexp){
+ if(possibleValue.toString().match(regexp)){
+ return true; // Boolean
+ }
+ } else if(value === possibleValue){
+ return true; // Boolean
+ } else {
+ return false;
+ }
+ });
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(something && something[this._storeRefPropName] === this){
+ if(this._arrayOfAllItems[something[this._itemNumPropName]] === something){
+ return true;
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(something); //boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ this._assertIsItem(keywordArgs.item);
+ },
+
+ 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._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( /* Object */ keywordArgs,
+ /* Function */ findCallback,
+ /* Function */ errorCallback){
+ // summary:
+ // See dojo.data.util.simpleFetch.fetch()
+ // filter modified to permit complex queries where
+ // logical operators are case insensitive:
+ // , NOT AND OR ( ) ! && ||
+ // Note: "," included for quoted/string legacy queries.
+ var self = this;
+ var filter = function(requestArgs, arrayOfItems){
+ var items = [];
+ if(requestArgs.query){
+ //Complete copy, we may have to mess with it.
+ //Safer than clone, which does a shallow copy, I believe.
+ var query = json.fromJson(json.toJson(requestArgs.query));
+ //Okay, object form query, we have to check to see if someone mixed query methods (such as using FilteringSelect
+ //with a complexQuery). In that case, the params need to be anded to the complex query statement.
+ //See defect #7980
+ if(typeof query == "object" ){
+ var count = 0;
+ var p;
+ for(p in query){
+ count++;
+ }
+ if(count > 1 && query.complexQuery){
+ var cq = query.complexQuery;
+ var wrapped = false;
+ for(p in query){
+ if(p !== "complexQuery"){
+ //We should wrap this in () as it should and with the entire complex query
+ //Not just part of it.
+ if(!wrapped){
+ cq = "( " + cq + " )";
+ wrapped = true;
+ }
+ //Make sure strings are quoted when going into complexQuery merge.
+ var v = requestArgs.query[p];
+ if(lang.isString(v)){
+ v = "'" + v + "'";
+ }
+ cq += " AND " + p + ":" + v;
+ delete query[p];
+
+ }
+ }
+ query.complexQuery = cq;
+ }
+ }
+
+ var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false;
+ //for complex queries only: pattern = query[:|=]"NOT id:23* AND (type:'test*' OR dept:'bob') && !filed:true"
+ //logical operators are case insensitive: , NOT AND OR ( ) ! && || // "," included for quoted/string legacy queries.
+ if(typeof query != "string"){
+ query = json.toJson(query);
+ query = query.replace(/\\\\/g,"\\"); //counter toJson expansion of backslashes, e.g., foo\\*bar test.
+ }
+ query = query.replace(/\\"/g,"\""); //ditto, for embedded \" in lieu of " availability.
+ var complexQuery = lang.trim(query.replace(/{|}/g,"")); //we can handle these, too.
+ var pos2, i;
+ if(complexQuery.match(/"? *complexQuery *"?:/)){ //case where widget required a json object, so use complexQuery:'the real query'
+ complexQuery = lang.trim(complexQuery.replace(/"?\s*complexQuery\s*"?:/,""));
+ var quotes = ["'",'"'];
+ var pos1,colon;
+ var flag = false;
+ for(i = 0; i<quotes.length; i++){
+ pos1 = complexQuery.indexOf(quotes[i]);
+ pos2 = complexQuery.indexOf(quotes[i],1);
+ colon = complexQuery.indexOf(":",1);
+ if(pos1 === 0 && pos2 != -1 && colon < pos2){
+ flag = true;
+ break;
+ } //first two sets of quotes don't occur before the first colon.
+ }
+ if(flag){ //dojo.toJson, and maybe user, adds surrounding quotes, which we need to remove.
+ complexQuery = complexQuery.replace(/^\"|^\'|\"$|\'$/g,"");
+ }
+ } //end query="{complexQuery:'id:1* || dept:Sales'}" parsing (for when widget required json object query).
+ var complexQuerySave = complexQuery;
+ //valid logical operators.
+ var begRegExp = /^,|^NOT |^AND |^OR |^\(|^\)|^!|^&&|^\|\|/i; //trailing space on some tokens on purpose.
+ var sQuery = ""; //will be eval'ed for each i-th candidateItem, based on query components.
+ var op = "";
+ var val = "";
+ var pos = -1;
+ var err = false;
+ var key = "";
+ var value = "";
+ var tok = "";
+ pos2 = -1;
+ for(i = 0; i < arrayOfItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfItems[i];
+ if(candidateItem === null){
+ match = false;
+ }else{
+ //process entire string for this i-th candidateItem.
+ complexQuery = complexQuerySave; //restore query for next candidateItem.
+ sQuery = "";
+ //work left to right, finding either key:value pair or logical operator at the beginning of the complexQuery string.
+ //when found, concatenate to sQuery and remove from complexQuery and loop back.
+ while(complexQuery.length > 0 && !err){
+ op = complexQuery.match(begRegExp);
+
+ //get/process/append one or two leading logical operators.
+ while(op && !err){ //look for leading logical operators.
+ complexQuery = lang.trim(complexQuery.replace(op[0],""));
+ op = lang.trim(op[0]).toUpperCase();
+ //convert some logical operators to their javascript equivalents for later eval.
+ op = op == "NOT" ? "!" : op == "AND" || op == "," ? "&&" : op == "OR" ? "||" : op;
+ op = " " + op + " ";
+ sQuery += op;
+ op = complexQuery.match(begRegExp);
+ }//end op && !err
+
+ //now get/process/append one key:value pair.
+ if(complexQuery.length > 0){
+ pos = complexQuery.indexOf(":");
+ if(pos == -1){
+ err = true;
+ break;
+ }else{
+ key = lang.trim(complexQuery.substring(0,pos).replace(/\"|\'/g,""));
+ complexQuery = lang.trim(complexQuery.substring(pos + 1));
+ tok = complexQuery.match(/^\'|^\"/); //quoted?
+ if(tok){
+ tok = tok[0];
+ pos = complexQuery.indexOf(tok);
+ pos2 = complexQuery.indexOf(tok,pos + 1);
+ if(pos2 == -1){
+ err = true;
+ break;
+ }
+ value = complexQuery.substring(pos + 1,pos2);
+ if(pos2 == complexQuery.length - 1){ //quote is last character
+ complexQuery = "";
+ }else{
+ complexQuery = lang.trim(complexQuery.substring(pos2 + 1));
+ }
+ sQuery += self._containsValue(candidateItem, key, value, filterUtil.patternToRegExp(value, ignoreCase));
+ }
+ else{ //not quoted, so a space, comma, or closing parens (or the end) will be the break.
+ tok = complexQuery.match(/\s|\)|,/);
+ if(tok){
+ var pos3 = new Array(tok.length);
+ for(var j = 0;j<tok.length;j++){
+ pos3[j] = complexQuery.indexOf(tok[j]);
+ }
+ pos = pos3[0];
+ if(pos3.length > 1){
+ for(var j=1;j<pos3.length;j++){
+ pos = Math.min(pos,pos3[j]);
+ }
+ }
+ value = lang.trim(complexQuery.substring(0,pos));
+ complexQuery = lang.trim(complexQuery.substring(pos));
+ }else{ //not a space, so must be at the end of the complexQuery.
+ value = lang.trim(complexQuery);
+ complexQuery = "";
+ } //end inner if(tok) else
+ sQuery += self._containsValue(candidateItem, key, value, filterUtil.patternToRegExp(value, ignoreCase));
+ } //end outer if(tok) else
+ } //end found ":"
+ } //end if(complexQuery.length > 0)
+ } //end while complexQuery.length > 0 && !err, so finished the i-th item.
+ match = eval(sQuery);
+ } //end else is non-null candidateItem.
+ if(match){
+ items.push(candidateItem);
+ }
+ } //end for/next of all items.
+ if(err){
+ //soft fail.
+ items = [];
+ console.log("The store's _fetchItems failed, probably due to a syntax error in query.");
+ }
+ findCallback(items, requestArgs);
+ }else{
+ // No query...
+ // 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. We also need to
+ // filter out any null values that have been left as a result of deleteItem()
+ // calls in ItemFileWriteStore.
+ for(var i = 0; i < arrayOfItems.length; ++i){
+ var item = arrayOfItems[i];
+ if(item !== null){
+ items.push(item);
+ }
+ }
+ findCallback(items, requestArgs);
+ } //end if there is a query.
+ }; //end filter function
+
+ if(this._loadFinished){
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }else{
+ if(this._jsonFileUrl !== this._ccUrl){
+ kernel.deprecated("dojox.data.AndOrReadStore: ",
+ "To change the url, set the url property of the store," +
+ " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
+ this._ccUrl = this._jsonFileUrl;
+ this.url = this._jsonFileUrl;
+ }else if(this.url !== this._ccUrl){
+ this._jsonFileUrl = this.url;
+ this._ccUrl = this.url;
+ }
+ //See if there was any forced reset of data.
+ if(this.data != null && this._jsonData == null){
+ this._jsonData = this.data;
+ this.data = null;
+ }
+ if(this._jsonFileUrl){
+ //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._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ preventCache: this.urlPreventCache
+ };
+ var getHandler = xhr.get(getArgs);
+ getHandler.addCallback(function(data){
+ try{
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ self._loadInProgress = false;
+
+ filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
+ self._handleQueuedFetches();
+ }catch(e){
+ self._loadFinished = true;
+ self._loadInProgress = false;
+ errorCallback(e, keywordArgs);
+ }
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ errorCallback(error, keywordArgs);
+ });
+
+ //Wire up the cancel to abort of the request
+ //This call cancel on the deferred if it hasn't been called
+ //yet and then will chain to the simple abort of the
+ //simpleFetch keywordArgs
+ var oldAbort = null;
+ if(keywordArgs.abort){
+ oldAbort = keywordArgs.abort;
+ }
+ keywordArgs.abort = function(){
+ var df = getHandler;
+ if(df && df.fired === -1){
+ df.cancel();
+ df = null;
+ }
+ if(oldAbort){
+ oldAbort.call(keywordArgs);
+ }
+ };
+ }
+ }else if(this._jsonData){
+ try{
+ this._loadFinished = true;
+ this._getItemsFromLoadedData(this._jsonData);
+ this._jsonData = null;
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }catch(e){
+ errorCallback(e, keywordArgs);
+ }
+ }else{
+ errorCallback(new Error("dojox.data.AndOrReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
+ }
+ } //end deferred fetching.
+ }, //end _fetchItems
+
+ _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 = [];
+ }
+ },
+
+ _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;
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ if(this.clearOnClose &&
+ this._loadFinished &&
+ !this._loadInProgress){
+ //Reset all internalsback to default state. This will force a reload
+ //on next fetch. This also checks that the data or url param was set
+ //so that the store knows it can get data. Without one of those being set,
+ //the next fetch will trigger an error.
+
+ if(((this._jsonFileUrl == "" || this._jsonFileUrl == null) &&
+ (this.url == "" || this.url == null)
+ ) && this.data == null){
+ console.debug("dojox.data.AndOrReadStore: WARNING! Data reload " +
+ " information has not been provided." +
+ " Please set 'url' or 'data' to the appropriate value before" +
+ " the next fetch");
+ }
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = [];
+ this._loadFinished = false;
+ this._itemsByIdentity = null;
+ this._loadInProgress = false;
+ this._queuedFetches = [];
+ }
+ },
+
+ _getItemsFromLoadedData: function(/* Object */ dataObject){
+ // summary:
+ // Function to parse the loaded data into item format and build the internal items array.
+ // description:
+ // Function to parse the loaded data into item format and build the internal items array.
+ //
+ // dataObject:
+ // The JS data object containing the raw data to convery into item format.
+ //
+ // returns: array
+ // Array of items in store item format.
+
+ // First, we define a couple little utility functions...
+
+ var self = this;
+ function valueIsAnItem(/* anything */ aValue){
+ // summary:
+ // Given any sort of value that could be in the raw json data,
+ // return true if we should interpret the value as being an
+ // item itself, rather than a literal value or a reference.
+ // example:
+ // | false == valueIsAnItem("Kermit");
+ // | false == valueIsAnItem(42);
+ // | false == valueIsAnItem(new Date());
+ // | false == valueIsAnItem({_type:'Date', _value:'May 14, 1802'});
+ // | false == valueIsAnItem({_reference:'Kermit'});
+ // | true == valueIsAnItem({name:'Kermit', color:'green'});
+ // | true == valueIsAnItem({iggy:'pop'});
+ // | true == valueIsAnItem({foo:42});
+ var isItem = (
+ (aValue !== null) &&
+ (typeof aValue === "object") &&
+ (!lang.isArray(aValue)) &&
+ (!lang.isFunction(aValue)) &&
+ (aValue.constructor == Object) &&
+ (typeof aValue._reference === "undefined") &&
+ (typeof aValue._type === "undefined") &&
+ (typeof aValue._value === "undefined") &&
+ self.hierarchical
+ );
+ return isItem;
+ }
+
+ function addItemAndSubItemsToArrayOfAllItems(/* Item */ anItem){
+ self._arrayOfAllItems.push(anItem);
+ for(var attribute in anItem){
+ var valueForAttribute = anItem[attribute];
+ if(valueForAttribute){
+ if(lang.isArray(valueForAttribute)){
+ var valueArray = valueForAttribute;
+ for(var k = 0; k < valueArray.length; ++k){
+ var singleValue = valueArray[k];
+ if(valueIsAnItem(singleValue)){
+ addItemAndSubItemsToArrayOfAllItems(singleValue);
+ }
+ }
+ }else{
+ if(valueIsAnItem(valueForAttribute)){
+ addItemAndSubItemsToArrayOfAllItems(valueForAttribute);
+ }
+ }
+ }
+ }
+ }
+
+ this._labelAttr = dataObject.label;
+
+ // We need to do some transformations to convert the data structure
+ // that we read from the file into a format that will be convenient
+ // to work with in memory.
+
+ // Step 1: Walk through the object hierarchy and build a list of all items
+ var i;
+ var item;
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = dataObject.items;
+
+ for(i = 0; i < this._arrayOfTopLevelItems.length; ++i){
+ item = this._arrayOfTopLevelItems[i];
+ addItemAndSubItemsToArrayOfAllItems(item);
+ item[this._rootItemPropName]=true;
+ }
+
+ // Step 2: Walk through all the attribute values of all the items,
+ // and replace single values with arrays. For example, we change this:
+ // { name:'Miss Piggy', pets:'Foo-Foo'}
+ // into this:
+ // { name:['Miss Piggy'], pets:['Foo-Foo']}
+ //
+ // We also store the attribute names so we can validate our store
+ // reference and item id special properties for the O(1) isItem
+ var allAttributeNames = {};
+ var key;
+
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ for(key in item){
+ if(key !== this._rootItemPropName){
+ var value = item[key];
+ if(value !== null){
+ if(!lang.isArray(value)){
+ item[key] = [value];
+ }
+ }else{
+ item[key] = [null];
+ }
+ }
+ allAttributeNames[key]=key;
+ }
+ }
+
+ // Step 3: Build unique property names to use for the _storeRefPropName and _itemNumPropName
+ // This should go really fast, it will generally never even run the loop.
+ while(allAttributeNames[this._storeRefPropName]){
+ this._storeRefPropName += "_";
+ }
+ while(allAttributeNames[this._itemNumPropName]){
+ this._itemNumPropName += "_";
+ }
+ while(allAttributeNames[this._reverseRefMap]){
+ this._reverseRefMap += "_";
+ }
+
+ // Step 4: Some data files specify an optional 'identifier', which is
+ // the name of an attribute that holds the identity of each item.
+ // If this data file specified an identifier attribute, then build a
+ // hash table of items keyed by the identity of the items.
+ var arrayOfValues;
+
+ var identifier = dataObject.identifier;
+ if(identifier){
+ this._itemsByIdentity = {};
+ this._features['dojo.data.api.Identity'] = identifier;
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ arrayOfValues = item[identifier];
+ var identity = arrayOfValues[0];
+ if(!this._itemsByIdentity[identity]){
+ this._itemsByIdentity[identity] = item;
+ }else{
+ if(this._jsonFileUrl){
+ throw new Error("dojox.data.AndOrReadStore: The json data as specified by: [" + this._jsonFileUrl + "] is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
+ }else if(this._jsonData){
+ throw new Error("dojox.data.AndOrReadStore: The json data provided by the creation arguments is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
+ }
+ }
+ }
+ }else{
+ this._features['dojo.data.api.Identity'] = Number;
+ }
+
+ // Step 5: Walk through all the items, and set each item's properties
+ // for _storeRefPropName and _itemNumPropName, so that store.isItem() will return true.
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ item[this._storeRefPropName] = this;
+ item[this._itemNumPropName] = i;
+ }
+
+ // Step 6: We walk through all the attribute values of all the items,
+ // looking for type/value literals and item-references.
+ //
+ // We replace item-references with pointers to items. For example, we change:
+ // { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ // into this:
+ // { name:['Kermit'], friends:[miss_piggy] }
+ // (where miss_piggy is the object representing the 'Miss Piggy' item).
+ //
+ // We replace type/value pairs with typed-literals. For example, we change:
+ // { name:['Nelson Mandela'], born:[{_type:'Date', _value:'July 18, 1918'}] }
+ // into this:
+ // { name:['Kermit'], born:(new Date('July 18, 1918')) }
+ //
+ // We also generate the associate map for all items for the O(1) isItem function.
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i]; // example: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ for(key in item){
+ arrayOfValues = item[key]; // example: [{_reference:{name:'Miss Piggy'}}]
+ for(var j = 0; j < arrayOfValues.length; ++j){
+ value = arrayOfValues[j]; // example: {_reference:{name:'Miss Piggy'}}
+ if(value !== null && typeof value == "object"){
+ if(("_type" in value) && ("_value" in value)){
+ var type = value._type; // examples: 'Date', 'Color', or 'ComplexNumber'
+ var mappingObj = this._datatypeMap[type]; // examples: Date, dojo.Color, foo.math.ComplexNumber, {type: dojo.Color, deserialize(value){ return new dojo.Color(value)}}
+ if(!mappingObj){
+ throw new Error("dojox.data.AndOrReadStore: in the typeMap constructor arg, no object class was specified for the datatype '" + type + "'");
+ }else if(lang.isFunction(mappingObj)){
+ arrayOfValues[j] = new mappingObj(value._value);
+ }else if(lang.isFunction(mappingObj.deserialize)){
+ arrayOfValues[j] = mappingObj.deserialize(value._value);
+ }else{
+ throw new Error("dojox.data.AndOrReadStore: Value provided in typeMap was neither a constructor, nor a an object with a deserialize function");
+ }
+ }
+ if(value._reference){
+ var referenceDescription = value._reference; // example: {name:'Miss Piggy'}
+ if(!lang.isObject(referenceDescription)){
+ // example: 'Miss Piggy'
+ // from an item like: { name:['Kermit'], friends:[{_reference:'Miss Piggy'}]}
+ arrayOfValues[j] = this._getItemByIdentity(referenceDescription);
+ }else{
+ // example: {name:'Miss Piggy'}
+ // from an item like: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ for(var k = 0; k < this._arrayOfAllItems.length; ++k){
+ var candidateItem = this._arrayOfAllItems[k];
+ var found = true;
+ for(var refKey in referenceDescription){
+ if(candidateItem[refKey] != referenceDescription[refKey]){
+ found = false;
+ }
+ }
+ if(found){
+ arrayOfValues[j] = candidateItem;
+ }
+ }
+ }
+ if(this.referenceIntegrity){
+ var refItem = arrayOfValues[j];
+ if(this.isItem(refItem)){
+ this._addReferenceToMap(refItem, item, key);
+ }
+ }
+ }else if(this.isItem(value)){
+ //It's a child item (not one referenced through _reference).
+ //We need to treat this as a referenced item, so it can be cleaned up
+ //in a write store easily.
+ if(this.referenceIntegrity){
+ this._addReferenceToMap(value, item, key);
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ _addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
+ // summary:
+ // Method to add an reference map entry for an item and attribute.
+ // description:
+ // Method to add an reference map entry for an item and attribute. //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item that holds the new reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the new reference.
+
+ //Stub function, does nothing. Real processing is in ItemFileWriteStore.
+ },
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ var identifier = this._features['dojo.data.api.Identity'];
+ if(identifier === Number){
+ return item[this._itemNumPropName]; // Number
+ }else{
+ var arrayOfValues = item[identifier];
+ if(arrayOfValues){
+ return arrayOfValues[0]; // Object || 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._jsonFileUrl !== this._ccUrl){
+ kernel.deprecated("dojox.data.AndOrReadStore: ",
+ "To change the url, set the url property of the store," +
+ " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
+ this._ccUrl = this._jsonFileUrl;
+ this.url = this._jsonFileUrl;
+ }else if(this.url !== this._ccUrl){
+ this._jsonFileUrl = this.url;
+ this._ccUrl = this.url;
+ }
+ //See if there was any forced reset of data.
+ if(this.data != null && this._jsonData == null){
+ this._jsonData = this.data;
+ this.data = null;
+ }
+ if(this._jsonFileUrl){
+
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ preventCache: this.urlPreventCache
+ };
+ var getHandler = xhr.get(getArgs);
+ getHandler.addCallback(function(data){
+ var scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
+ try{
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ self._loadInProgress = false;
+ var item = self._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ self._handleQueuedFetches();
+ }catch(error){
+ self._loadInProgress = false;
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ }
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ if(keywordArgs.onError){
+ var scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+ }
+
+ }else if(this._jsonData){
+ // Passed in data, no need to xhr.
+ self._getItemsFromLoadedData(self._jsonData);
+ self._jsonData = null;
+ self._loadFinished = true;
+ var item = self._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ var scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }else{
+ // Already loaded. We can just look it up and call back.
+ var item = this._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ var scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ },
+
+ _getItemByIdentity: function(/* Object */ identity){
+ // summary:
+ // Internal function to look an item up by its identity map.
+ var item = null;
+ if(this._itemsByIdentity){
+ item = this._itemsByIdentity[identity];
+ }else{
+ item = this._arrayOfAllItems[identity];
+ }
+ if(item === undefined){
+ item = null;
+ }
+ return item; // Object
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentifierAttributes()
+
+ var identifier = this._features['dojo.data.api.Identity'];
+ if(identifier === Number){
+ // If (identifier === Number) it means getIdentity() just returns
+ // an integer item-number for each item. The dojo.data.api.Identity
+ // spec says we need to return null if the identity is not composed
+ // of attributes
+ return null; // null
+ }else{
+ return [identifier]; // Array
+ }
+ },
+
+ _forceLoad: function(){
+ // summary:
+ // Internal function to force a load of the store if it hasn't occurred yet. This is required
+ // for specific functions to work properly.
+ var self = this;
+ if(this._jsonFileUrl !== this._ccUrl){
+ kernel.deprecated("dojox.data.AndOrReadStore: ",
+ "To change the url, set the url property of the store," +
+ " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
+ this._ccUrl = this._jsonFileUrl;
+ this.url = this._jsonFileUrl;
+ }else if(this.url !== this._ccUrl){
+ this._jsonFileUrl = this.url;
+ this._ccUrl = this.url;
+ }
+ //See if there was any forced reset of data.
+ if(this.data != null && this._jsonData == null){
+ this._jsonData = this.data;
+ this.data = null;
+ }
+ if(this._jsonFileUrl){
+ var getArgs = {
+ url: self._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ preventCache: this.urlPreventCache,
+ sync: true
+ };
+ var getHandler = xhr.get(getArgs);
+ getHandler.addCallback(function(data){
+ try{
+ //Check to be sure there wasn't another load going on concurrently
+ //So we don't clobber data that comes in on it. If there is a load going on
+ //then do not save this data. It will potentially clobber current data.
+ //We mainly wanted to sync/wait here.
+ //TODO: Revisit the loading scheme of this store to improve multi-initial
+ //request handling.
+ if(self._loadInProgress !== true && !self._loadFinished){
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ }else if(self._loadInProgress){
+ //Okay, we hit an error state we can't recover from. A forced load occurred
+ //while an async load was occurring. Since we cannot block at this point, the best
+ //that can be managed is to throw an error.
+ throw new Error("dojox.data.AndOrReadStore: Unable to perform a synchronous load, an async load is in progress.");
+ }
+ }catch(e){
+ console.log(e);
+ throw e;
+ }
+ });
+ getHandler.addErrback(function(error){
+ throw error;
+ });
+ }else if(this._jsonData){
+ self._getItemsFromLoadedData(self._jsonData);
+ self._jsonData = null;
+ self._loadFinished = true;
+ }
+ }
+});
+//Mix in the simple fetch implementation to this class.
+lang.extend(AndOrReadStore, simpleFetch);
+
+return AndOrReadStore;
+});
+
+
diff --git a/js/dojo-1.7.2/dojox/data/AndOrWriteStore.js b/js/dojo-1.7.2/dojox/data/AndOrWriteStore.js
new file mode 100644
index 0000000..6a884c4
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/AndOrWriteStore.js
@@ -0,0 +1,812 @@
+//>>built
+define("dojox/data/AndOrWriteStore", ["dojo/_base/declare","dojo/_base/lang","dojo/_base/array", "dojo/_base/json", "dojo/date/stamp",
+ "dojo/_base/window", "./AndOrReadStore"],
+ function(declare, lang, arrayUtil, json, dateStamp, winUtil, AndOrReadStore) {
+/*===== var AndOrReadStore = dojox.data.AndOrReadStore; =====*/
+
+return declare("dojox.data.AndOrWriteStore", AndOrReadStore, {
+ constructor: function(/* object */ keywordParameters){
+ // keywordParameters: {typeMap: object)
+ // The structure of the typeMap object is as follows:
+ // {
+ // type0: function || object,
+ // type1: function || object,
+ // ...
+ // typeN: function || object
+ // }
+ // Where if it is a function, it is assumed to be an object constructor that takes the
+ // value of _value as the initialization parameters. It is serialized assuming object.toString()
+ // serialization. If it is an object, then it is assumed
+ // to be an object of general form:
+ // {
+ // type: function, //constructor.
+ // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately.
+ // serialize: function(object) //The function that converts the object back into the proper file format form.
+ // }
+
+ // AndOrWriteStore duplicates ItemFileWriteStore, except extends AndOrReadStore, which offers complex queries.
+ // ItemFileWriteStore extends ItemFileReadStore to implement these additional dojo.data APIs
+ this._features['dojo.data.api.Write'] = true;
+ this._features['dojo.data.api.Notification'] = true;
+
+ // For keeping track of changes so that we can implement isDirty and revert
+ this._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+
+ if(!this._datatypeMap['Date'].serialize){
+ this._datatypeMap['Date'].serialize = function(obj){
+ return dateStamp.toISOString(obj, {zulu:true});
+ };
+ }
+ //Disable only if explicitly set to false.
+ if(keywordParameters && (keywordParameters.referenceIntegrity === false)){
+ this.referenceIntegrity = false;
+ }
+
+ // this._saveInProgress is set to true, briefly, from when save() is first called to when it completes
+ this._saveInProgress = false;
+ },
+
+ referenceIntegrity: true, //Flag that defaultly enabled reference integrity tracking. This way it can also be disabled pogrammatially or declaratively.
+
+ _assert: function(/* boolean */ condition){
+ if(!condition){
+ throw new Error("assertion failed in ItemFileWriteStore");
+ }
+ },
+
+ _getIdentifierAttribute: function(){
+ var identifierAttribute = this.getFeatures()['dojo.data.api.Identity'];
+ // this._assert((identifierAttribute === Number) || (dojo.isString(identifierAttribute)));
+ return identifierAttribute;
+ },
+
+
+/* dojo.data.api.Write */
+
+ newItem: function(/* Object? */ keywordArgs, /* Object? */ parentInfo){
+ // summary: See dojo.data.api.Write.newItem()
+
+ this._assert(!this._saveInProgress);
+
+ if(!this._loadFinished){
+ // We need to do this here so that we'll be able to find out what
+ // identifierAttribute was specified in the data file.
+ this._forceLoad();
+ }
+
+ if(typeof keywordArgs != "object" && typeof keywordArgs != "undefined"){
+ throw new Error("newItem() was passed something other than an object");
+ }
+ var newIdentity = null;
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(identifierAttribute === Number){
+ newIdentity = this._arrayOfAllItems.length;
+ }else{
+ newIdentity = keywordArgs[identifierAttribute];
+ if(typeof newIdentity === "undefined"){
+ throw new Error("newItem() was not passed an identity for the new item");
+ }
+ if(lang.isArray(newIdentity)){
+ throw new Error("newItem() was not passed an single-valued identity");
+ }
+ }
+
+ // make sure this identity is not already in use by another item, if identifiers were
+ // defined in the file. Otherwise it would be the item count,
+ // which should always be unique in this case.
+ if(this._itemsByIdentity){
+ this._assert(typeof this._itemsByIdentity[newIdentity] === "undefined");
+ }
+ this._assert(typeof this._pending._newItems[newIdentity] === "undefined");
+ this._assert(typeof this._pending._deletedItems[newIdentity] === "undefined");
+
+ var newItem = {};
+ newItem[this._storeRefPropName] = this;
+ newItem[this._itemNumPropName] = this._arrayOfAllItems.length;
+ if(this._itemsByIdentity){
+ this._itemsByIdentity[newIdentity] = newItem;
+ //We have to set the identifier now, otherwise we can't look it
+ //up at calls to setValueorValues in parentInfo handling.
+ newItem[identifierAttribute] = [newIdentity];
+ }
+ this._arrayOfAllItems.push(newItem);
+
+ //We need to construct some data for the onNew call too...
+ var pInfo = null;
+
+ // Now we need to check to see where we want to assign this thingm if any.
+ if(parentInfo && parentInfo.parent && parentInfo.attribute){
+ pInfo = {
+ item: parentInfo.parent,
+ attribute: parentInfo.attribute,
+ oldValue: undefined
+ };
+
+ //See if it is multi-valued or not and handle appropriately
+ //Generally, all attributes are multi-valued for this store
+ //So, we only need to append if there are already values present.
+ var values = this.getValues(parentInfo.parent, parentInfo.attribute);
+ if(values && values.length > 0){
+ var tempValues = values.slice(0, values.length);
+ if(values.length === 1){
+ pInfo.oldValue = values[0];
+ }else{
+ pInfo.oldValue = values.slice(0, values.length);
+ }
+ tempValues.push(newItem);
+ this._setValueOrValues(parentInfo.parent, parentInfo.attribute, tempValues, false);
+ pInfo.newValue = this.getValues(parentInfo.parent, parentInfo.attribute);
+ }else{
+ this._setValueOrValues(parentInfo.parent, parentInfo.attribute, newItem, false);
+ pInfo.newValue = newItem;
+ }
+ }else{
+ //Toplevel item, add to both top list as well as all list.
+ newItem[this._rootItemPropName]=true;
+ this._arrayOfTopLevelItems.push(newItem);
+ }
+
+ this._pending._newItems[newIdentity] = newItem;
+
+ //Clone over the properties to the new item
+ for(var key in keywordArgs){
+ if(key === this._storeRefPropName || key === this._itemNumPropName){
+ // Bummer, the user is trying to do something like
+ // newItem({_S:"foo"}). Unfortunately, our superclass,
+ // ItemFileReadStore, is already using _S in each of our items
+ // to hold private info. To avoid a naming collision, we
+ // need to move all our private info to some other property
+ // of all the items/objects. So, we need to iterate over all
+ // the items and do something like:
+ // item.__S = item._S;
+ // item._S = undefined;
+ // But first we have to make sure the new "__S" variable is
+ // not in use, which means we have to iterate over all the
+ // items checking for that.
+ throw new Error("encountered bug in ItemFileWriteStore.newItem");
+ }
+ var value = keywordArgs[key];
+ if(!lang.isArray(value)){
+ value = [value];
+ }
+ newItem[key] = value;
+ if(this.referenceIntegrity){
+ for(var i = 0; i < value.length; i++){
+ var val = value[i];
+ if(this.isItem(val)){
+ this._addReferenceToMap(val, newItem, key);
+ }
+ }
+ }
+ }
+ this.onNew(newItem, pInfo); // dojo.data.api.Notification call
+ return newItem; // item
+ },
+
+ _removeArrayElement: function(/* Array */ array, /* anything */ element){
+ var index = arrayUtil.indexOf(array, element);
+ if(index != -1){
+ array.splice(index, 1);
+ return true;
+ }
+ return false;
+ },
+
+ deleteItem: function(/* item */ item){
+ // summary: See dojo.data.api.Write.deleteItem()
+ this._assert(!this._saveInProgress);
+ this._assertIsItem(item);
+
+ // Remove this item from the _arrayOfAllItems, but leave a null value in place
+ // of the item, so as not to change the length of the array, so that in newItem()
+ // we can still safely do: newIdentity = this._arrayOfAllItems.length;
+ var indexInArrayOfAllItems = item[this._itemNumPropName];
+ var identity = this.getIdentity(item);
+
+ //If we have reference integrity on, we need to do reference cleanup for the deleted item
+ if(this.referenceIntegrity){
+ //First scan all the attributes of this items for references and clean them up in the map
+ //As this item is going away, no need to track its references anymore.
+
+ //Get the attributes list before we generate the backup so it
+ //doesn't pollute the attributes list.
+ var attributes = this.getAttributes(item);
+
+ //Backup the map, we'll have to restore it potentially, in a revert.
+ if(item[this._reverseRefMap]){
+ item["backup_" + this._reverseRefMap] = lang.clone(item[this._reverseRefMap]);
+ }
+
+ //TODO: This causes a reversion problem. This list won't be restored on revert since it is
+ //attached to the 'value'. item, not ours. Need to back tese up somehow too.
+ //Maybe build a map of the backup of the entries and attach it to the deleted item to be restored
+ //later. Or just record them and call _addReferenceToMap on them in revert.
+ arrayUtil.forEach(attributes, function(attribute){
+ arrayUtil.forEach(this.getValues(item, attribute), function(value){
+ if(this.isItem(value)){
+ //We have to back up all the references we had to others so they can be restored on a revert.
+ if(!item["backupRefs_" + this._reverseRefMap]){
+ item["backupRefs_" + this._reverseRefMap] = [];
+ }
+ item["backupRefs_" + this._reverseRefMap].push({id: this.getIdentity(value), attr: attribute});
+ this._removeReferenceFromMap(value, item, attribute);
+ }
+ }, this);
+ }, this);
+
+ //Next, see if we have references to this item, if we do, we have to clean them up too.
+ var references = item[this._reverseRefMap];
+ if(references){
+ //Look through all the items noted as references to clean them up.
+ for(var itemId in references){
+ var containingItem = null;
+ if(this._itemsByIdentity){
+ containingItem = this._itemsByIdentity[itemId];
+ }else{
+ containingItem = this._arrayOfAllItems[itemId];
+ }
+ //We have a reference to a containing item, now we have to process the
+ //attributes and clear all references to the item being deleted.
+ if(containingItem){
+ for(var attribute in references[itemId]){
+ var oldValues = this.getValues(containingItem, attribute) || [];
+ var newValues = arrayUtil.filter(oldValues, function(possibleItem){
+ return !(this.isItem(possibleItem) && this.getIdentity(possibleItem) == identity);
+ }, this);
+ //Remove the note of the reference to the item and set the values on the modified attribute.
+ this._removeReferenceFromMap(item, containingItem, attribute);
+ if(newValues.length < oldValues.length){
+ this._setValueOrValues(containingItem, attribute, newValues);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ this._arrayOfAllItems[indexInArrayOfAllItems] = null;
+
+ item[this._storeRefPropName] = null;
+ if(this._itemsByIdentity){
+ delete this._itemsByIdentity[identity];
+ }
+ this._pending._deletedItems[identity] = item;
+
+ //Remove from the toplevel items, if necessary...
+ if(item[this._rootItemPropName]){
+ this._removeArrayElement(this._arrayOfTopLevelItems, item);
+ }
+ this.onDelete(item); // dojo.data.api.Notification call
+ return true;
+ },
+
+ setValue: function(/* item */ item, /* attribute-name-string */ attribute, /* almost anything */ value){
+ // summary: See dojo.data.api.Write.set()
+ return this._setValueOrValues(item, attribute, value, true); // boolean
+ },
+
+ setValues: function(/* item */ item, /* attribute-name-string */ attribute, /* array */ values){
+ // summary: See dojo.data.api.Write.setValues()
+ return this._setValueOrValues(item, attribute, values, true); // boolean
+ },
+
+ unsetAttribute: function(/* item */ item, /* attribute-name-string */ attribute){
+ // summary: See dojo.data.api.Write.unsetAttribute()
+ return this._setValueOrValues(item, attribute, [], true);
+ },
+
+ _setValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ newValueOrValues, /*boolean?*/ callOnSet){
+ this._assert(!this._saveInProgress);
+
+ // Check for valid arguments
+ this._assertIsItem(item);
+ this._assert(lang.isString(attribute));
+ this._assert(typeof newValueOrValues !== "undefined");
+
+ // Make sure the user isn't trying to change the item's identity
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(attribute == identifierAttribute){
+ throw new Error("ItemFileWriteStore does not have support for changing the value of an item's identifier.");
+ }
+
+ // To implement the Notification API, we need to make a note of what
+ // the old attribute value was, so that we can pass that info when
+ // we call the onSet method.
+ var oldValueOrValues = this._getValueOrValues(item, attribute);
+
+ var identity = this.getIdentity(item);
+ if(!this._pending._modifiedItems[identity]){
+ // Before we actually change the item, we make a copy of it to
+ // record the original state, so that we'll be able to revert if
+ // the revert method gets called. If the item has already been
+ // modified then there's no need to do this now, since we already
+ // have a record of the original state.
+ var copyOfItemState = {};
+ for(var key in item){
+ if((key === this._storeRefPropName) || (key === this._itemNumPropName) || (key === this._rootItemPropName)){
+ copyOfItemState[key] = item[key];
+ }else if(key === this._reverseRefMap){
+ copyOfItemState[key] = lang.clone(item[key]);
+ }else{
+ copyOfItemState[key] = item[key].slice(0, item[key].length);
+ }
+ }
+ // Now mark the item as dirty, and save the copy of the original state
+ this._pending._modifiedItems[identity] = copyOfItemState;
+ }
+
+ // Okay, now we can actually change this attribute on the item
+ var success = false;
+
+ if(lang.isArray(newValueOrValues) && newValueOrValues.length === 0){
+
+ // If we were passed an empty array as the value, that counts
+ // as "unsetting" the attribute, so we need to remove this
+ // attribute from the item.
+ success = delete item[attribute];
+ newValueOrValues = undefined; // used in the onSet Notification call below
+
+ if(this.referenceIntegrity && oldValueOrValues){
+ var oldValues = oldValueOrValues;
+ if(!lang.isArray(oldValues)){
+ oldValues = [oldValues];
+ }
+ for(var i = 0; i < oldValues.length; i++){
+ var value = oldValues[i];
+ if(this.isItem(value)){
+ this._removeReferenceFromMap(value, item, attribute);
+ }
+ }
+ }
+ }else{
+ var newValueArray;
+ if(lang.isArray(newValueOrValues)){
+ var newValues = newValueOrValues;
+ // Unfortunately, it's not safe to just do this:
+ // newValueArray = newValues;
+ // Instead, we need to copy the array, which slice() does very nicely.
+ // This is so that our internal data structure won't
+ // get corrupted if the user mucks with the values array *after*
+ // calling setValues().
+ newValueArray = newValueOrValues.slice(0, newValueOrValues.length);
+ }else{
+ newValueArray = [newValueOrValues];
+ }
+
+ //We need to handle reference integrity if this is on.
+ //In the case of set, we need to see if references were added or removed
+ //and update the reference tracking map accordingly.
+ if(this.referenceIntegrity){
+ if(oldValueOrValues){
+ var oldValues = oldValueOrValues;
+ if(!lang.isArray(oldValues)){
+ oldValues = [oldValues];
+ }
+ //Use an associative map to determine what was added/removed from the list.
+ //Should be O(n) performant. First look at all the old values and make a list of them
+ //Then for any item not in the old list, we add it. If it was already present, we remove it.
+ //Then we pass over the map and any references left it it need to be removed (IE, no match in
+ //the new values list).
+ var map = {};
+ arrayUtil.forEach(oldValues, function(possibleItem){
+ if(this.isItem(possibleItem)){
+ var id = this.getIdentity(possibleItem);
+ map[id.toString()] = true;
+ }
+ }, this);
+ arrayUtil.forEach(newValueArray, function(possibleItem){
+ if(this.isItem(possibleItem)){
+ var id = this.getIdentity(possibleItem);
+ if(map[id.toString()]){
+ delete map[id.toString()];
+ }else{
+ this._addReferenceToMap(possibleItem, item, attribute);
+ }
+ }
+ }, this);
+ for(var rId in map){
+ var removedItem;
+ if(this._itemsByIdentity){
+ removedItem = this._itemsByIdentity[rId];
+ }else{
+ removedItem = this._arrayOfAllItems[rId];
+ }
+ this._removeReferenceFromMap(removedItem, item, attribute);
+ }
+ }else{
+ //Everything is new (no old values) so we have to just
+ //insert all the references, if any.
+ for(var i = 0; i < newValueArray.length; i++){
+ var value = newValueArray[i];
+ if(this.isItem(value)){
+ this._addReferenceToMap(value, item, attribute);
+ }
+ }
+ }
+ }
+ item[attribute] = newValueArray;
+ success = true;
+ }
+
+ // Now we make the dojo.data.api.Notification call
+ if(callOnSet){
+ this.onSet(item, attribute, oldValueOrValues, newValueOrValues);
+ }
+ return success; // boolean
+ },
+
+ _addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
+ // summary:
+ // Method to add an reference map entry for an item and attribute.
+ // description:
+ // Method to add an reference map entry for an item and attribute. //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item that holds the new reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the new reference.
+
+ var parentId = this.getIdentity(parentItem);
+ var references = refItem[this._reverseRefMap];
+
+ if(!references){
+ references = refItem[this._reverseRefMap] = {};
+ }
+ var itemRef = references[parentId];
+ if(!itemRef){
+ itemRef = references[parentId] = {};
+ }
+ itemRef[attribute] = true;
+ },
+
+ _removeReferenceFromMap: function(/* item */ refItem, /* item */ parentItem, /*strin*/ attribute){
+ // summary:
+ // Method to remove an reference map entry for an item and attribute.
+ // description:
+ // Method to remove an reference map entry for an item and attribute. This will
+ // also perform cleanup on the map such that if there are no more references at all to
+ // the item, its reference object and entry are removed.
+ //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item holding a reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the reference.
+ var identity = this.getIdentity(parentItem);
+ var references = refItem[this._reverseRefMap];
+ var itemId;
+ if(references){
+ for(itemId in references){
+ if(itemId == identity){
+ delete references[itemId][attribute];
+ if(this._isEmpty(references[itemId])){
+ delete references[itemId];
+ }
+ }
+ }
+ if(this._isEmpty(references)){
+ delete refItem[this._reverseRefMap];
+ }
+ }
+ },
+
+ _dumpReferenceMap: function(){
+ // summary:
+ // Function to dump the reverse reference map of all items in the store for debug purposes.
+ // description:
+ // Function to dump the reverse reference map of all items in the store for debug purposes.
+ var i;
+ for(i = 0; i < this._arrayOfAllItems.length; i++){
+ var item = this._arrayOfAllItems[i];
+ if(item && item[this._reverseRefMap]){
+ console.log("Item: [" + this.getIdentity(item) + "] is referenced by: " + json.toJson(item[this._reverseRefMap]));
+ }
+ }
+ },
+
+ _getValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute){
+ var valueOrValues = undefined;
+ if(this.hasAttribute(item, attribute)){
+ var valueArray = this.getValues(item, attribute);
+ if(valueArray.length == 1){
+ valueOrValues = valueArray[0];
+ }else{
+ valueOrValues = valueArray;
+ }
+ }
+ return valueOrValues;
+ },
+
+ _flatten: function(/* anything */ value){
+ if(this.isItem(value)){
+ var item = value;
+ // Given an item, return an serializable object that provides a
+ // reference to the item.
+ // For example, given kermit:
+ // var kermit = store.newItem({id:2, name:"Kermit"});
+ // we want to return
+ // {_reference:2}
+ var identity = this.getIdentity(item);
+ var referenceObject = {_reference: identity};
+ return referenceObject;
+ }else{
+ if(typeof value === "object"){
+ for(var type in this._datatypeMap){
+ var typeMap = this._datatypeMap[type];
+ if(lang.isObject(typeMap) && !lang.isFunction(typeMap)){
+ if(value instanceof typeMap.type){
+ if(!typeMap.serialize){
+ throw new Error("ItemFileWriteStore: No serializer defined for type mapping: [" + type + "]");
+ }
+ return {_type: type, _value: typeMap.serialize(value)};
+ }
+ } else if(value instanceof typeMap){
+ //SImple mapping, therefore, return as a toString serialization.
+ return {_type: type, _value: value.toString()};
+ }
+ }
+ }
+ return value;
+ }
+ },
+
+ _getNewFileContentString: function(){
+ // summary:
+ // Generate a string that can be saved to a file.
+ // The result should look similar to:
+ // http://trac.dojotoolkit.org/browser/dojo/trunk/tests/data/countries.json
+ var serializableStructure = {};
+
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(identifierAttribute !== Number){
+ serializableStructure.identifier = identifierAttribute;
+ }
+ if(this._labelAttr){
+ serializableStructure.label = this._labelAttr;
+ }
+ serializableStructure.items = [];
+ for(var i = 0; i < this._arrayOfAllItems.length; ++i){
+ var item = this._arrayOfAllItems[i];
+ if(item !== null){
+ var serializableItem = {};
+ for(var key in item){
+ if(key !== this._storeRefPropName && key !== this._itemNumPropName && key !== this._reverseRefMap && key !== this._rootItemPropName){
+ var attribute = key;
+ var valueArray = this.getValues(item, attribute);
+ if(valueArray.length == 1){
+ serializableItem[attribute] = this._flatten(valueArray[0]);
+ }else{
+ var serializableArray = [];
+ for(var j = 0; j < valueArray.length; ++j){
+ serializableArray.push(this._flatten(valueArray[j]));
+ serializableItem[attribute] = serializableArray;
+ }
+ }
+ }
+ }
+ serializableStructure.items.push(serializableItem);
+ }
+ }
+ var prettyPrint = true;
+ return json.toJson(serializableStructure, prettyPrint);
+ },
+
+ _isEmpty: function(something){
+ // summary:
+ // Function to determine if an array or object has no properties or values.
+ // something:
+ // The array or object to examine.
+ var empty = true;
+ if(lang.isObject(something)){
+ var i;
+ for(i in something){
+ empty = false;
+ break;
+ }
+ }else if(lang.isArray(something)){
+ if(something.length > 0){
+ empty = false;
+ }
+ }
+ return empty; //boolean
+ },
+
+ save: function(/* object */ keywordArgs){
+ // summary: See dojo.data.api.Write.save()
+ this._assert(!this._saveInProgress);
+
+ // this._saveInProgress is set to true, briefly, from when save is first called to when it completes
+ this._saveInProgress = true;
+
+ var self = this;
+ var saveCompleteCallback = function(){
+ self._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+
+ self._saveInProgress = false; // must come after this._pending is cleared, but before any callbacks
+ if(keywordArgs && keywordArgs.onComplete){
+ var scope = keywordArgs.scope || winUtil.global;
+ keywordArgs.onComplete.call(scope);
+ }
+ };
+ var saveFailedCallback = function(){
+ self._saveInProgress = false;
+ if(keywordArgs && keywordArgs.onError){
+ var scope = keywordArgs.scope || winUtil.global;
+ keywordArgs.onError.call(scope);
+ }
+ };
+
+ if(this._saveEverything){
+ var newFileContentString = this._getNewFileContentString();
+ this._saveEverything(saveCompleteCallback, saveFailedCallback, newFileContentString);
+ }
+ if(this._saveCustom){
+ this._saveCustom(saveCompleteCallback, saveFailedCallback);
+ }
+ if(!this._saveEverything && !this._saveCustom){
+ // Looks like there is no user-defined save-handler function.
+ // That's fine, it just means the datastore is acting as a "mock-write"
+ // store -- changes get saved in memory but don't get saved to disk.
+ saveCompleteCallback();
+ }
+ },
+
+ revert: function(){
+ // summary: See dojo.data.api.Write.revert()
+ this._assert(!this._saveInProgress);
+
+ var identity;
+ for(identity in this._pending._modifiedItems){
+ // find the original item and the modified item that replaced it
+ var copyOfItemState = this._pending._modifiedItems[identity];
+ var modifiedItem = null;
+ if(this._itemsByIdentity){
+ modifiedItem = this._itemsByIdentity[identity];
+ }else{
+ modifiedItem = this._arrayOfAllItems[identity];
+ }
+
+ // Restore the original item into a full-fledged item again, we want to try to
+ // keep the same object instance as if we don't it, causes bugs like #9022.
+ copyOfItemState[this._storeRefPropName] = this;
+ for(key in modifiedItem){
+ delete modifiedItem[key];
+ }
+ lang.mixin(modifiedItem, copyOfItemState);
+ }
+ var deletedItem;
+ for(identity in this._pending._deletedItems){
+ deletedItem = this._pending._deletedItems[identity];
+ deletedItem[this._storeRefPropName] = this;
+ var index = deletedItem[this._itemNumPropName];
+
+ //Restore the reverse refererence map, if any.
+ if(deletedItem["backup_" + this._reverseRefMap]){
+ deletedItem[this._reverseRefMap] = deletedItem["backup_" + this._reverseRefMap];
+ delete deletedItem["backup_" + this._reverseRefMap];
+ }
+ this._arrayOfAllItems[index] = deletedItem;
+ if(this._itemsByIdentity){
+ this._itemsByIdentity[identity] = deletedItem;
+ }
+ if(deletedItem[this._rootItemPropName]){
+ this._arrayOfTopLevelItems.push(deletedItem);
+ }
+ }
+ //We have to pass through it again and restore the reference maps after all the
+ //undeletes have occurred.
+ for(identity in this._pending._deletedItems){
+ deletedItem = this._pending._deletedItems[identity];
+ if(deletedItem["backupRefs_" + this._reverseRefMap]){
+ arrayUtil.forEach(deletedItem["backupRefs_" + this._reverseRefMap], function(reference){
+ var refItem;
+ if(this._itemsByIdentity){
+ refItem = this._itemsByIdentity[reference.id];
+ }else{
+ refItem = this._arrayOfAllItems[reference.id];
+ }
+ this._addReferenceToMap(refItem, deletedItem, reference.attr);
+ }, this);
+ delete deletedItem["backupRefs_" + this._reverseRefMap];
+ }
+ }
+
+ for(identity in this._pending._newItems){
+ var newItem = this._pending._newItems[identity];
+ newItem[this._storeRefPropName] = null;
+ // null out the new item, but don't change the array index so
+ // so we can keep using _arrayOfAllItems.length.
+ this._arrayOfAllItems[newItem[this._itemNumPropName]] = null;
+ if(newItem[this._rootItemPropName]){
+ this._removeArrayElement(this._arrayOfTopLevelItems, newItem);
+ }
+ if(this._itemsByIdentity){
+ delete this._itemsByIdentity[identity];
+ }
+ }
+
+ this._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+ return true; // boolean
+ },
+
+ isDirty: function(/* item? */ item){
+ // summary: See dojo.data.api.Write.isDirty()
+ if(item){
+ // return true if the item is dirty
+ var identity = this.getIdentity(item);
+ return new Boolean(this._pending._newItems[identity] ||
+ this._pending._modifiedItems[identity] ||
+ this._pending._deletedItems[identity]).valueOf(); // boolean
+ }else{
+ // return true if the store is dirty -- which means return true
+ // if there are any new items, dirty items, or modified items
+ if(!this._isEmpty(this._pending._newItems) ||
+ !this._isEmpty(this._pending._modifiedItems) ||
+ !this._isEmpty(this._pending._deletedItems)){
+ return true;
+ }
+ return false; // boolean
+ }
+ },
+
+/* dojo.data.api.Notification */
+
+ onSet: function(/* item */ item,
+ /*attribute-name-string*/ attribute,
+ /*object | array*/ oldValue,
+ /*object | array*/ newValue){
+ // summary: See dojo.data.api.Notification.onSet()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ onNew: function(/* item */ newItem, /*object?*/ parentInfo){
+ // summary: See dojo.data.api.Notification.onNew()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ onDelete: function(/* item */ deletedItem){
+ // summary: See dojo.data.api.Notification.onDelete()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ close: function(/* object? */ request){
+ // summary:
+ // Over-ride of base close function of ItemFileReadStore to add in check for store state.
+ // description:
+ // Over-ride of base close function of ItemFileReadStore to add in check for store state.
+ // If the store is still dirty (unsaved changes), then an error will be thrown instead of
+ // clearing the internal state for reload from the url.
+
+ //Clear if not dirty ... or throw an error
+ if(this.clearOnClose){
+ if(!this.isDirty()){
+ this.inherited(arguments);
+ }else{
+ //Only throw an error if the store was dirty and we were loading from a url (cannot reload from url until state is saved).
+ throw new Error("dojox.data.AndOrWriteStore: There are unsaved changes present in the store. Please save or revert the changes before invoking close.");
+ }
+ }
+ }
+});
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/AppStore.js b/js/dojo-1.7.2/dojox/data/AppStore.js
new file mode 100644
index 0000000..b3c8a94
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/AppStore.js
@@ -0,0 +1,829 @@
+//>>built
+define("dojox/data/AppStore", ["dojo", "dojox", "dojo/data/util/simpleFetch", "dojo/data/util/filter", "dojox/atom/io/Connection"], function(dojo, dojox) {
+
+dojo.experimental("dojox.data.AppStore");
+
+dojo.declare("dojox.data.AppStore",
+ null,{
+
+ // url: [public] string
+ // So the parser can instantiate the store via markup.
+ url: "",
+
+ // urlPreventCache: [public] boolean
+ // Whether or not to pass the preventCache parameter to the connection
+ urlPreventCache: false,
+
+ // xmethod: [public] boolean
+ // Whether to use X-Method-Override for PUT/DELETE.
+ xmethod: false,
+
+ _atomIO: null,
+ _feed: null,
+ _requests: null,
+ _processing: null,
+
+ _updates: null,
+ _adds: null,
+ _deletes: null,
+
+ constructor: function(/*Object*/args){
+ // summary:
+ // The APP data store.
+ // description:
+ // The APP Store is instantiated either in markup or programmatically by supplying a
+ // url of the Collection to be used.
+ //
+ // args:
+ // An anonymous object to initialize properties. It expects the following values:
+ // url: The url of the Collection to load.
+ // urlPreventCache: Whether or not to append on cache prevention params (as defined by dojo.xhr*)
+
+ if(args && args.url){
+ this.url = args.url;
+ }
+ if(args && args.urlPreventCache){
+ this.urlPreventCache = args.urlPreventCache;
+ }
+ if(!this.url){
+ throw new Error("A URL is required to instantiate an APP Store object");
+ }
+ },
+
+ _setFeed: function(feed, data){
+ // summary:
+ // Sets the internal feed using a dojox.atom.io.model.Feed object.
+ // description:
+ // Sets the internal feed using a dojox.atom.io.model.Feed object. Also adds
+ // a property to the entries to track that they belong to this store. It
+ // also parses stored requests (since we were waiting on a callback) and
+ // executes those as well.
+ //
+ // feed: dojox.atom.io.model.Feed object
+ // The Feed to use for this data store.
+ // data: unused
+ // Signature for this function is defined by AtomIO.getFeed, since this is a callback.
+ this._feed = feed;
+ var i;
+ for(i=0; i<this._feed.entries.length; i++){
+ this._feed.entries[i].store = this;
+ }
+ if(this._requests){
+ for(i=0; i<this._requests.length; i++){
+ var request = this._requests[i];
+ if(request.request && request.fh && request.eh){
+ this._finishFetchItems(request.request, request.fh, request.eh);
+ }else if(request.clear){
+ this._feed = null;
+ }else if(request.add){
+ this._feed.addEntry(request.add);
+ }else if(request.remove){
+ this._feed.removeEntry(request.remove);
+ }
+ }
+ }
+ this._requests = null;
+ },
+
+ _getAllItems: function(){
+ // summary:
+ // Function to return all entries in the Feed as an array of items.
+ // description:
+ // Function to return all entries in the Feed as an array of items.
+ //
+ // returns:
+ // Array of all entries in the feed.
+ var items = [];
+ for(var i=0; i<this._feed.entries.length; i++){
+ items.push(this._feed.entries[i]);
+ }
+ return items; //array
+ },
+
+ _assertIsItem: function(/* item */ item){
+ // summary:
+ // This function tests whether the item is an item.
+ // description:
+ // 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("This error message is provided when a function is called in the following form: "
+ + "getAttribute(argument, attributeName). The argument variable represents the member "
+ + "or owner of the object. The error is created when an item that does not belong "
+ + "to this store is specified as an argument.");
+ }
+ },
+
+ _assertIsAttribute: function(/* String */ attribute){
+ // summary:
+ // This function tests whether the item is an attribute.
+ // description:
+ // 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 a boolean indicating whether this is a valid attribute.
+ if(typeof attribute !== "string"){
+ throw new Error("The attribute argument must be a string. The error is created "
+ + "when a different type of variable is specified such as an array or object.");
+ }
+
+ for(var key in dojox.atom.io.model._actions){
+ if(key == attribute){
+ return true;
+ }
+ }
+ return false;
+ },
+
+ _addUpdate: function(/* Object */ update){
+ // summary:
+ // Internal function to add an updated entry to our updates array
+ // description:
+ // Internal function to add an updated entry to our updates array
+ //
+ // update: dojox.atom.io.model.Entry object
+ // The updated Entry we've changed.
+ if(!this._updates){
+ this._updates = [update];
+ }else{
+ this._updates.push(update);
+ }
+ },
+
+/***************************************
+ 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 flag = this._assertIsAttribute(attribute);
+
+ if(flag){
+ if((attribute === "author" || attribute === "contributor" || attribute === "link") && item[attribute+"s"]){
+ return item[attribute+"s"];
+ }
+ if(attribute === "category" && item.categories){
+ return item.categories;
+ }
+ if(item[attribute]){
+ item = item[attribute];
+ if(item.nodeType == "Content"){
+ return [item.value];
+ }
+ return [item] ;
+ }
+ }
+ return []; //Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ for(var key in dojox.atom.io.model._actions){
+ if(this.hasAttribute(item, key)){
+ attributes.push(key);
+ }
+ }
+ 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,
+ /* Boolean?*/ trim){
+ // 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){
+ if(trim){
+ possibleValue = possibleValue.replace(new RegExp(/^\s+/),""); // START
+ possibleValue = possibleValue.replace(new RegExp(/\s+$/),""); // END
+ }
+ possibleValue = possibleValue.replace(/\r|\n|\r\n/g, "");
+ 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()
+ return something && something.store && something.store === this; //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 (Atom entries) that match to a query
+ // description:
+ // Fetch items (Atom entries) 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(this._feed){
+ this._finishFetchItems(request, fetchHandler, errorHandler);
+ }else{
+ var flag = false;
+ if(!this._requests){
+ this._requests = [];
+ flag = true;
+ }
+ this._requests.push({request: request, fh: fetchHandler, eh: errorHandler});
+ if(flag){
+ this._atomIO = new dojox.atom.io.Connection(false, this.urlPreventCache);
+ this._atomIO.getFeed(this.url,this._setFeed, null, this);
+ }
+ }
+ },
+
+ _finishFetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Internal function for finishing a fetch request.
+ // description:
+ // Internal function for finishing a fetch request. Needed since the feed
+ // might not have been loaded, so we finish the fetch in a callback.
+ //
+ // request:
+ // A request object
+ // fetchHandler:
+ // A function to call for fetched items
+ // errorHandler:
+ // A function to call on error
+ 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], request.trim)){
+ 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 listsand sort without affecting each other.
+ if(arrayOfAllItems.length> 0){
+ items = arrayOfAllItems.slice(0,arrayOfAllItems.length);
+ }
+ }
+ try{
+ fetchHandler(items, request);
+ }catch(e){
+ errorHandler(e, request);
+ }
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Write': 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!
+ this._feed = null;
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if(this.isItem(item)){
+ return this.getValue(item, "title", "No Title");
+ }
+ return undefined;
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return ["title"];
+ },
+
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ this._assertIsItem(item);
+ return this.getValue(item, "id");
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentityAttributes()
+ return ["id"];
+ },
+
+ fetchItemByIdentity: function(keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+
+ this._fetchItems({query:{id:keywordArgs.identity}, onItem: keywordArgs.onItem, scope: keywordArgs.scope},
+ function(items, request){
+ var scope = request.scope;
+ if(!scope){
+ scope = dojo.global;
+ }
+ if(items.length < 1){
+ request.onItem.call(scope, null);
+ }else{
+ request.onItem.call(scope, items[0]);
+ }
+ }, keywordArgs.onError);
+ },
+
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+
+ newItem: function(/* Object? */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Write.newItem()
+ var entry = new dojox.atom.io.model.Entry();
+ var value = null;
+ var temp = null;
+ var i;
+ for(var key in keywordArgs){
+ if(this._assertIsAttribute(key)){
+ value = keywordArgs[key];
+ switch(key){
+ case "link":
+ for(i in value){
+ temp = value[i];
+ entry.addLink(temp.href,temp.rel,temp.hrefLang,temp.title,temp.type);
+ }
+ break;
+ case "author":
+ for(i in value){
+ temp = value[i];
+ entry.addAuthor(temp.name, temp.email, temp.uri);
+ }
+ break;
+ case "contributor":
+ for(i in value){
+ temp = value[i];
+ entry.addContributor(temp.name, temp.email, temp.uri);
+ }
+ break;
+ case "category":
+ for(i in value){
+ temp = value[i];
+ entry.addCategory(temp.scheme, temp.term, temp.label);
+ }
+ break;
+ case "icon":
+ case "id":
+ case "logo":
+ case "xmlBase":
+ case "rights":
+ entry[key] = value;
+ break;
+ case "updated":
+ case "published":
+ case "issued":
+ case "modified":
+ entry[key] = dojox.atom.io.model.util.createDate(value);
+ break;
+ case "content":
+ case "summary":
+ case "title":
+ case "subtitle":
+ entry[key] = new dojox.atom.io.model.Content(key);
+ entry[key].value = value;
+ break;
+ default:
+ entry[key] = value;
+ break;
+ }
+ }
+ }
+ entry.store = this;
+ entry.isDirty = true;
+
+ if(!this._adds){
+ this._adds = [entry];
+ }else{
+ this._adds.push(entry);
+ }
+
+ if(this._feed){
+ this._feed.addEntry(entry);
+ }else{
+ if(this._requests){
+ this._requests.push({add:entry});
+ }else{
+ this._requests = [{add:entry}];
+ this._atomIO = new dojox.atom.io.Connection(false, this.urlPreventCache);
+ this._atomIO.getFeed(this.url,dojo.hitch(this,this._setFeed));
+ }
+ }
+ return true;
+ },
+
+ deleteItem: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Write.deleteItem()
+ this._assertIsItem(item);
+
+ if(!this._deletes){
+ this._deletes = [item];
+ }else{
+ this._deletes.push(item);
+ }
+
+ if(this._feed){
+ this._feed.removeEntry(item);
+ }else{
+ if(this._requests){
+ this._requests.push({remove:item});
+ }else{
+ this._requests = [{remove:item}];
+ this._atomIO = new dojox.atom.io.Connection(false, this.urlPreventCache);
+ this._atomIO.getFeed(this.url,dojo.hitch(this,this._setFeed));
+ }
+ }
+ item = null;
+ return true;
+ },
+
+ setValue: function( /* item */ item,
+ /* string */ attribute,
+ /* almost anything */ value){
+ // summary:
+ // See dojo.data.api.Write.setValue()
+ this._assertIsItem(item);
+
+ var update = {item: item};
+ if(this._assertIsAttribute(attribute)){
+ switch(attribute){
+ case "link":
+ update.links = item.links;
+ this._addUpdate(update);
+ item.links = null;
+ item.addLink(value.href,value.rel,value.hrefLang,value.title,value.type);
+ item.isDirty = true;
+ return true;
+ case "author":
+ update.authors = item.authors;
+ this._addUpdate(update);
+ item.authors = null;
+ item.addAuthor(value.name, value.email, value.uri);
+ item.isDirty = true;
+ return true;
+ case "contributor":
+ update.contributors = item.contributors;
+ this._addUpdate(update);
+ item.contributors = null;
+ item.addContributor(value.name, value.email, value.uri);
+ item.isDirty = true;
+ return true;
+ case "category":
+ update.categories = item.categories;
+ this._addUpdate(update);
+ item.categories = null;
+ item.addCategory(value.scheme, value.term, value.label);
+ item.isDirty = true;
+ return true;
+ case "icon":
+ case "id":
+ case "logo":
+ case "xmlBase":
+ case "rights":
+ update[attribute] = item[attribute];
+ this._addUpdate(update);
+ item[attribute] = value;
+ item.isDirty = true;
+ return true;
+ case "updated":
+ case "published":
+ case "issued":
+ case "modified":
+ update[attribute] = item[attribute];
+ this._addUpdate(update);
+ item[attribute] = dojox.atom.io.model.util.createDate(value);
+ item.isDirty = true;
+ return true;
+ case "content":
+ case "summary":
+ case "title":
+ case "subtitle":
+ update[attribute] = item[attribute];
+ this._addUpdate(update);
+ item[attribute] = new dojox.atom.io.model.Content(attribute);
+ item[attribute].value = value;
+ item.isDirty = true;
+ return true;
+ default:
+ update[attribute] = item[attribute];
+ this._addUpdate(update);
+ item[attribute] = value;
+ item.isDirty = true;
+ return true;
+ }
+ }
+ return false;
+ },
+
+ setValues: function(/* item */ item,
+ /* string */ attribute,
+ /* array */ values){
+ // summary:
+ // See dojo.data.api.Write.setValues()
+ if(values.length === 0){
+ return this.unsetAttribute(item, attribute);
+ }
+ this._assertIsItem(item);
+
+ var update = {item: item};
+ var value;
+ var i;
+ if(this._assertIsAttribute(attribute)){
+ switch(attribute){
+ case "link":
+ update.links = item.links;
+ item.links = null;
+ for(i in values){
+ value = values[i];
+ item.addLink(value.href,value.rel,value.hrefLang,value.title,value.type);
+ }
+ item.isDirty = true;
+ return true;
+ case "author":
+ update.authors = item.authors;
+ item.authors = null;
+ for(i in values){
+ value = values[i];
+ item.addAuthor(value.name, value.email, value.uri);
+ }
+ item.isDirty = true;
+ return true;
+ case "contributor":
+ update.contributors = item.contributors;
+ item.contributors = null;
+ for(i in values){
+ value = values[i];
+ item.addContributor(value.name, value.email, value.uri);
+ }
+ item.isDirty = true;
+ return true;
+ case "categories":
+ update.categories = item.categories;
+ item.categories = null;
+ for(i in values){
+ value = values[i];
+ item.addCategory(value.scheme, value.term, value.label);
+ }
+ item.isDirty = true;
+ return true;
+ case "icon":
+ case "id":
+ case "logo":
+ case "xmlBase":
+ case "rights":
+ update[attribute] = item[attribute];
+ item[attribute] = values[0];
+ item.isDirty = true;
+ return true;
+ case "updated":
+ case "published":
+ case "issued":
+ case "modified":
+ update[attribute] = item[attribute];
+ item[attribute] = dojox.atom.io.model.util.createDate(values[0]);
+ item.isDirty = true;
+ return true;
+ case "content":
+ case "summary":
+ case "title":
+ case "subtitle":
+ update[attribute] = item[attribute];
+ item[attribute] = new dojox.atom.io.model.Content(attribute);
+ item[attribute].values[0] = values[0];
+ item.isDirty = true;
+ return true;
+ default:
+ update[attribute] = item[attribute];
+ item[attribute] = values[0];
+ item.isDirty = true;
+ return true;
+ }
+ }
+ this._addUpdate(update);
+ return false;
+ },
+
+ unsetAttribute: function( /* item */ item,
+ /* string */ attribute){
+ // summary:
+ // See dojo.data.api.Write.unsetAttribute()
+ this._assertIsItem(item);
+ if(this._assertIsAttribute(attribute)){
+ if(item[attribute] !== null){
+ var update = {item: item};
+ switch(attribute){
+ case "author":
+ case "contributor":
+ case "link":
+ update[attribute+"s"] = item[attribute+"s"];
+ break;
+ case "category":
+ update.categories = item.categories;
+ break;
+ default:
+ update[attribute] = item[attribute];
+ break;
+ }
+ item.isDirty = true;
+ item[attribute] = null;
+ this._addUpdate(update);
+ return true;
+ }
+ }
+ return false; // boolean
+ },
+
+ save: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Write.save()
+ // keywordArgs:
+ // {
+ // onComplete: function
+ // onError: function
+ // scope: object
+ // }
+ var i;
+ for(i in this._adds){
+ this._atomIO.addEntry(this._adds[i], null, function(){}, keywordArgs.onError, false, keywordArgs.scope);
+ }
+
+ this._adds = null;
+
+ for(i in this._updates){
+ this._atomIO.updateEntry(this._updates[i].item, function(){}, keywordArgs.onError, false, this.xmethod, keywordArgs.scope);
+ }
+
+ this._updates = null;
+
+ for(i in this._deletes){
+ this._atomIO.removeEntry(this._deletes[i], function(){}, keywordArgs.onError, this.xmethod, keywordArgs.scope);
+ }
+
+ this._deletes = null;
+
+ this._atomIO.getFeed(this.url,dojo.hitch(this,this._setFeed));
+
+ if(keywordArgs.onComplete){
+ var scope = keywordArgs.scope || dojo.global;
+ keywordArgs.onComplete.call(scope);
+ }
+ },
+
+ revert: function(){
+ // summary:
+ // See dojo.data.api.Write.revert()
+ var i;
+ for(i in this._adds){
+ this._feed.removeEntry(this._adds[i]);
+ }
+
+ this._adds = null;
+
+ var update, item, key;
+ for(i in this._updates){
+ update = this._updates[i];
+ item = update.item;
+ for(key in update){
+ if(key !== "item"){
+ item[key] = update[key];
+ }
+ }
+ }
+ this._updates = null;
+
+ for(i in this._deletes){
+ this._feed.addEntry(this._deletes[i]);
+ }
+ this._deletes = null;
+ return true;
+ },
+
+ isDirty: function(/* item? */ item){
+ // summary:
+ // See dojo.data.api.Write.isDirty()
+ if(item){
+ this._assertIsItem(item);
+ return item.isDirty?true:false; //boolean
+ }
+ return (this._adds !== null || this._updates !== null); //boolean
+ }
+});
+dojo.extend(dojox.data.AppStore,dojo.data.util.simpleFetch);
+
+return dojox.data.AppStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/AtomReadStore.js b/js/dojo-1.7.2/dojox/data/AtomReadStore.js
new file mode 100644
index 0000000..0c16131
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/AtomReadStore.js
@@ -0,0 +1,551 @@
+//>>built
+define("dojox/data/AtomReadStore", ["dojo", "dojox", "dojo/data/util/filter", "dojo/data/util/simpleFetch", "dojo/date/stamp"], function(dojo, dojox) {
+dojo.experimental("dojox.data.AtomReadStore");
+
+dojo.declare("dojox.data.AtomReadStore", null, {
+ // summary:
+ // A read only data store for Atom XML based services or documents
+ // description:
+ // A data store for Atom XML based services or documents. This store is still under development
+ // and doesn't support wildcard filtering yet. Attribute filtering is limited to category or id.
+
+ constructor: function(/* object */ args){
+ // summary:
+ // Constructor for the AtomRead store.
+ // args:
+ // An anonymous object to initialize properties. It expects the following values:
+ // url: The url to a service or an XML document that represents the store
+ // unescapeHTML: A boolean to specify whether or not to unescape HTML text
+ // sendQuery: A boolean indicate to add a query string to the service URL
+
+ if(args){
+ this.url = args.url;
+ this.rewriteUrl = args.rewriteUrl;
+ this.label = args.label || this.label;
+ this.sendQuery = (args.sendQuery || args.sendquery || this.sendQuery);
+ this.unescapeHTML = args.unescapeHTML;
+ if("urlPreventCache" in args){
+ this.urlPreventCache = args.urlPreventCache?true:false;
+ }
+ }
+ if(!this.url){
+ throw new Error("AtomReadStore: a URL must be specified when creating the data store");
+ }
+ },
+
+ //Values that may be set by the parser.
+ //Ergo, have to be instantiated to something
+ //So the parser knows how to set them.
+ url: "",
+
+ label: "title",
+
+ sendQuery: false,
+
+ unescapeHTML: false,
+
+ //Configurable preventCache option for the URL.
+ urlPreventCache: false,
+
+ /* dojo.data.api.Read */
+
+ getValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue){
+ // summary:
+ // Return an attribute value
+ // description:
+ // 'item' must be an instance of an object created by the AtomReadStore instance.
+ // Accepted attributes are id, subtitle, title, summary, content, author, updated,
+ // published, category, link and alternate
+ // item:
+ // An item returned by a call to the 'fetch' method.
+ // attribute:
+ // A attribute of the Atom Entry
+ // defaultValue:
+ // A default value
+ // returns:
+ // An attribute value found, otherwise 'defaultValue'
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ this._initItem(item);
+ attribute = attribute.toLowerCase();
+ //If the attribute has previously been retrieved, then return it
+ if(!item._attribs[attribute] && !item._parsed){
+ this._parseItem(item);
+ item._parsed = true;
+ }
+ var retVal = item._attribs[attribute];
+
+ if(!retVal && attribute == "summary"){
+ var content = this.getValue(item, "content");
+ var regexp = new RegExp("/(<([^>]+)>)/g", "i");
+ var text = content.text.replace(regexp,"");
+ retVal = {
+ text: text.substring(0, Math.min(400, text.length)),
+ type: "text"
+ };
+ item._attribs[attribute] = retVal;
+ }
+
+ if(retVal && this.unescapeHTML){
+ if((attribute == "content" || attribute == "summary" || attribute == "subtitle") && !item["_"+attribute+"Escaped"]){
+ retVal.text = this._unescapeHTML(retVal.text);
+ item["_"+attribute+"Escaped"] = true;
+ }
+ }
+ return retVal ? dojo.isArray(retVal) ? retVal[0]: retVal : defaultValue;
+ },
+
+ getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
+ // summary:
+ // Return an attribute value
+ // description:
+ // 'item' must be an instance of an object created by the AtomReadStore instance.
+ // Accepted attributes are id, subtitle, title, summary, content, author, updated,
+ // published, category, link and alternate
+ // item:
+ // An item returned by a call to the 'fetch' method.
+ // attribute:
+ // A attribute of the Atom Entry
+ // returns:
+ // An array of values for the attribute value found, otherwise 'defaultValue'
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ this._initItem(item);
+ attribute = attribute.toLowerCase();
+ //If the attribute has previously been retrieved, then return it
+ if(!item._attribs[attribute]){
+ this._parseItem(item);
+ }
+ var retVal = item._attribs[attribute];
+ return retVal ? ((retVal.length !== undefined && typeof(retVal) !== "string") ? retVal : [retVal]) : undefined;
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // Return an array of attribute names
+ // description:
+ // 'item' must be have been created by the AtomReadStore instance.
+ // tag names of child elements and XML attribute names of attributes
+ // specified to the element are returned along with special attribute
+ // names applicable to the element including "tagName", "childNodes"
+ // if the element has child elements, "text()" if the element has
+ // child text nodes, and attribute names in '_attributeMap' that match
+ // the tag name of the element.
+ // item:
+ // An XML element
+ // returns:
+ // An array of attributes found
+ this._assertIsItem(item);
+ if(!item._attribs){
+ this._initItem(item);
+ this._parseItem(item);
+ }
+ var attrNames = [];
+ for(var x in item._attribs){
+ attrNames.push(x);
+ }
+ return attrNames; //array
+ },
+
+ hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
+ // summary:
+ // Check whether an element has the attribute
+ // item:
+ // 'item' must be created by the AtomReadStore instance.
+ // attribute:
+ // An attribute of an Atom Entry item.
+ // returns:
+ // True if the element has the attribute, otherwise false
+ return (this.getValue(item, attribute) !== undefined); //boolean
+ },
+
+ containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value){
+ // summary:
+ // Check whether the attribute values contain the value
+ // item:
+ // 'item' must be an instance of a dojox.data.XmlItem from the store instance.
+ // attribute:
+ // A tag name of a child element, An XML attribute name or one of
+ // special names
+ // returns:
+ // True if the attribute values contain the value, otherwise false
+ var values = this.getValues(item, attribute);
+ for(var i = 0; i < values.length; i++){
+ if((typeof value === "string")){
+ if(values[i].toString && values[i].toString() === value){
+ return true;
+ }
+ }else if(values[i] === value){
+ return true; //boolean
+ }
+ }
+ return false;//boolean
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // Check whether the object is an item (XML element)
+ // item:
+ // An object to check
+ // returns:
+ // True if the object is an XML element, otherwise false
+ if(something && something.element && something.store && something.store === this){
+ return true; //boolean
+ }
+ return false; //boolran
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // Check whether the object is an item (XML element) and loaded
+ // item:
+ // An object to check
+ // returns:
+ // True if the object is an XML element, otherwise false
+ return this.isItem(something); //boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // Load an item (XML element)
+ // keywordArgs:
+ // object containing the args for loadItem. See dojo.data.api.Read.loadItem()
+ },
+
+ getFeatures: function(){
+ // summary:
+ // Return supported data APIs
+ // returns:
+ // "dojo.data.api.Read" and "dojo.data.api.Write"
+ var features = {
+ "dojo.data.api.Read": true
+ };
+ return features; //array
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if((this.label !== "") && this.isItem(item)){
+ var label = this.getValue(item,this.label);
+ if(label && label.text){
+ return label.text;
+ }else if(label){
+ return label.toString();
+ }else{
+ return undefined;
+ }
+ }
+ return undefined; //undefined
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ if(this.label !== ""){
+ return [this.label]; //array
+ }
+ return null; //null
+ },
+
+ getFeedValue: function(attribute, defaultValue){
+ // summary:
+ // Non-API method for retrieving values regarding the Atom feed,
+ // rather than the Atom entries.
+ var values = this.getFeedValues(attribute, defaultValue);
+ if(dojo.isArray(values)){
+ return values[0];
+ }
+ return values;
+ },
+
+ getFeedValues: function(attribute, defaultValue){
+ // summary:
+ // Non-API method for retrieving values regarding the Atom feed,
+ // rather than the Atom entries.
+ if(!this.doc){
+ return defaultValue;
+ }
+ if(!this._feedMetaData){
+ this._feedMetaData = {
+ element: this.doc.getElementsByTagName("feed")[0],
+ store: this,
+ _attribs: {}
+ };
+ this._parseItem(this._feedMetaData);
+ }
+ return this._feedMetaData._attribs[attribute] || defaultValue;
+ },
+
+ _initItem: function(item){
+ // summary:
+ // Initializes an item before it can be parsed.
+ if(!item._attribs){
+ item._attribs = {};
+ }
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Retrieves the items from the Atom XML document.
+ var url = this._getFetchUrl(request);
+ if(!url){
+ errorHandler(new Error("No URL specified."));
+ return;
+ }
+ var localRequest = (!this.sendQuery ? request : null); // use request for _getItems()
+
+ var _this = this;
+ var docHandler = function(data){
+ _this.doc = data;
+ var items = _this._getItems(data, localRequest);
+ var query = request.query;
+ if(query){
+ if(query.id){
+ items = dojo.filter(items, function(item){
+ return (_this.getValue(item, "id") == query.id);
+ });
+ }else if(query.category){
+ items = dojo.filter(items, function(entry){
+ var cats = _this.getValues(entry, "category");
+ if(!cats){
+ return false;
+ }
+ return dojo.some(cats, "return item.term=='"+query.category+"'");
+ });
+ }
+ }
+
+ if(items && items.length > 0){
+ fetchHandler(items, request);
+ }else{
+ fetchHandler([], request);
+ }
+ };
+
+ if(this.doc){
+ docHandler(this.doc);
+ }else{
+ var getArgs = {
+ url: url,
+ handleAs: "xml",
+ preventCache: this.urlPreventCache
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(docHandler);
+
+ getHandler.addErrback(function(data){
+ errorHandler(data, request);
+ });
+ }
+ },
+
+ _getFetchUrl: function(request){
+ if(!this.sendQuery){
+ return this.url;
+ }
+ var query = request.query;
+ if(!query){
+ return this.url;
+ }
+ if(dojo.isString(query)){
+ return this.url + query;
+ }
+ var queryString = "";
+ for(var name in query){
+ var value = query[name];
+ if(value){
+ if(queryString){
+ queryString += "&";
+ }
+ queryString += (name + "=" + value);
+ }
+ }
+ if(!queryString){
+ return this.url;
+ }
+ //Check to see if the URL already has query params or not.
+ var fullUrl = this.url;
+ if(fullUrl.indexOf("?") < 0){
+ fullUrl += "?";
+ }else{
+ fullUrl += "&";
+ }
+ return fullUrl + queryString;
+ },
+
+ _getItems: function(document, request){
+ // summary:
+ // Parses the document in a first pass
+ if(this._items){
+ return this._items;
+ }
+ var items = [];
+ var nodes = [];
+
+ if(document.childNodes.length < 1){
+ this._items = items;
+ console.log("dojox.data.AtomReadStore: Received an invalid Atom document. Check the content type header");
+ return items;
+ }
+
+ var feedNodes = dojo.filter(document.childNodes, "return item.tagName && item.tagName.toLowerCase() == 'feed'");
+
+ var query = request.query;
+
+ if(!feedNodes || feedNodes.length != 1){
+ console.log("dojox.data.AtomReadStore: Received an invalid Atom document, number of feed tags = " + (feedNodes? feedNodes.length : 0));
+ return items;
+ }
+
+ nodes = dojo.filter(feedNodes[0].childNodes, "return item.tagName && item.tagName.toLowerCase() == 'entry'");
+
+ if(request.onBegin){
+ request.onBegin(nodes.length, this.sendQuery ? request : {});
+ }
+
+ for(var i = 0; i < nodes.length; i++){
+ var node = nodes[i];
+ if(node.nodeType != 1 /*ELEMENT_NODE*/){
+ continue;
+ }
+ items.push(this._getItem(node));
+ }
+ this._items = items;
+ return items;
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ },
+
+/* internal API */
+
+ _getItem: function(element){
+ return {
+ element: element,
+ store: this
+ };
+ },
+
+ _parseItem: function(item){
+ var attribs = item._attribs;
+ var _this = this;
+ var text, type;
+
+ function getNodeText(node){
+ var txt = node.textContent || node.innerHTML || node.innerXML;
+ if(!txt && node.childNodes[0]){
+ var child = node.childNodes[0];
+ if(child && (child.nodeType == 3 || child.nodeType == 4)){
+ txt = node.childNodes[0].nodeValue;
+ }
+ }
+ return txt;
+ }
+ function parseTextAndType(node){
+ return {text: getNodeText(node),type: node.getAttribute("type")};
+ }
+ dojo.forEach(item.element.childNodes, function(node){
+ var tagName = node.tagName ? node.tagName.toLowerCase() : "";
+ switch(tagName){
+ case "title":
+ attribs[tagName] = {
+ text: getNodeText(node),
+ type: node.getAttribute("type")
+ }; break;
+ case "subtitle":
+ case "summary":
+ case "content":
+ attribs[tagName] = parseTextAndType(node);
+ break;
+ case "author":
+ var nameNode ,uriNode;
+ dojo.forEach(node.childNodes, function(child){
+ if(!child.tagName){
+ return;
+ }
+ switch(child.tagName.toLowerCase()){
+ case "name":
+ nameNode = child;
+ break;
+ case "uri":
+ uriNode = child;
+ break;
+ }
+ });
+ var author = {};
+ if(nameNode && nameNode.length == 1){
+ author.name = getNodeText(nameNode[0]);
+ }
+ if(uriNode && uriNode.length == 1){
+ author.uri = getNodeText(uriNode[0]);
+ }
+ attribs[tagName] = author;
+ break;
+ case "id":
+ attribs[tagName] = getNodeText(node);
+ break;
+ case "updated":
+ attribs[tagName] = dojo.date.stamp.fromISOString(getNodeText(node) );
+ break;
+ case "published":
+ attribs[tagName] = dojo.date.stamp.fromISOString(getNodeText(node));
+ break;
+ case "category":
+ if(!attribs[tagName]){
+ attribs[tagName] = [];
+ }
+ attribs[tagName].push({scheme:node.getAttribute("scheme"), term: node.getAttribute("term")});
+ break;
+ case "link":
+ if(!attribs[tagName]){
+ attribs[tagName] = [];
+ }
+ var link = {
+ rel: node.getAttribute("rel"),
+ href: node.getAttribute("href"),
+ type: node.getAttribute("type")};
+ attribs[tagName].push(link);
+
+ if(link.rel == "alternate"){
+ attribs["alternate"] = link;
+ }
+ break;
+ default:
+ break;
+ }
+ });
+ },
+
+ _unescapeHTML : function(text){
+ //Replace HTML character codes with their unencoded equivalents, e.g. &#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);
+
+return dojox.data.AtomReadStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/CdfStore.js b/js/dojo-1.7.2/dojox/data/CdfStore.js
new file mode 100644
index 0000000..d702da3
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/CdfStore.js
@@ -0,0 +1,600 @@
+//>>built
+define("dojox/data/CdfStore", ["dojo", "dojox", "dojo/data/util/sorter"], function(dojo, dojox) {
+
+dojox.data.ASYNC_MODE = 0;
+dojox.data.SYNC_MODE = 1;
+
+dojo.declare("dojox.data.CdfStore", null, {
+ // summary:
+ // IMPORTANT: The CDF Store is designed to work with Tibco GI, and references Tibco's
+ // JSX3 JavaScript library and will not work without it.
+ //
+ // The CDF Store implements dojo.data.Read, Write, and Identity api's. It is a local
+ // (in memory) store that handles XML documents formatted according to the
+ // Common Data Format (CDF) spec:
+ // http://www.tibco.com/devnet/resources/gi/3_1/tips_and_techniques/CommonDataFormatCDF.pdf
+ //
+ // The purpose of this store is to provide a glue between a jsx3 CDF file and a Dijit.
+ //
+ // While a CDF document is an XML file, other than the initial input, all data returned
+ // from and written to this store should be in object format.
+ //
+ // identity: [const] String
+ // The unique identifier for each item. Defaults to "jsxid" which is standard for a CDF
+ // document. Should not be changed.
+ identity: "jsxid",
+ //
+ // url : String
+ // The location from which to fetch the XML (CDF) document.
+ url: "",
+ //
+ // xmlStr: String
+ // A string that can be parsed into an XML document and should be formatted according
+ // to the CDF spec.
+ // example:
+ // | '<data jsxid="jsxroot"><record jsxtext="A"/><record jsxtext="B" jsxid="2" jsxid="2"/></data>'
+ xmlStr:"",
+ //
+ // data: Object
+ // A object that will be converted into the xmlStr property, and then parsed into a CDF.
+ data:null,
+ //
+ // label: String
+ // The property within each item used to define the item.
+ label: "",
+ //
+ // mode [const]: dojox.data.ASYNC_MODE | dojox.data.SYNC_MODE
+ // This store supports syncronous fetches if this property is set to dojox.data.SYNC_MODE.
+ mode:dojox.data.ASYNC_MODE,
+
+ constructor: function(/* Object */ args){
+ // summary:
+ // Constructor for the CDF store. Instantiate a new CdfStore.
+ //
+ if(args){
+ this.url = args.url;
+ this.xmlStr = args.xmlStr || args.str;
+ if(args.data){
+ this.xmlStr = this._makeXmlString(args.data);
+ }
+ this.identity = args.identity || this.identity;
+ this.label = args.label || this.label;
+ this.mode = args.mode !== undefined ? args.mode : this.mode;
+ }
+ this._modifiedItems = {};
+
+ this.byId = this.fetchItemByIdentity;
+ },
+
+ /* dojo.data.api.Read */
+
+ getValue: function(/* jsx3.xml.Entity */ item, /* String */ property, /* value? */ defaultValue){
+ // summary:
+ // Return an property value of an item
+ //
+ return item.getAttribute(property) || defaultValue; // anything
+ },
+
+ getValues: function(/* jsx3.xml.Entity */ item, /* String */ property){
+ // summary:
+ // Return an array of values
+ //
+ // TODO!!! Can't find an example of an array in any CDF files
+ //
+ var v = this.getValue(item, property, []);
+ return dojo.isArray(v) ? v : [v];
+ },
+
+ getAttributes: function(/* jsx3.xml.Entity */ item){
+ // summary:
+ // Return an array of property names
+ //
+ return item.getAttributeNames(); // Array
+ },
+
+ hasAttribute: function(/* jsx3.xml.Entity */ item, /* String */ property){
+ // summary:
+ // Check whether an item has a property
+ //
+ return (this.getValue(item, property) !== undefined); // Boolean
+ },
+
+ hasProperty: function(/* jsx3.xml.Entity */ item, /* String */ property){
+ // summary:
+ // Alias for hasAttribute
+ return this.hasAttribute(item, property);
+ },
+
+ containsValue: function(/* jsx3.xml.Entity */ item, /* String */ property, /* anything */ value){
+ // summary:
+ // Check whether an item contains a value
+ //
+ var values = this.getValues(item, property);
+ for(var i = 0; i < values.length; i++){
+ if(values[i] === null){ continue; }
+ 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 (jsx3.xml.Entity)
+ //
+ if(something.getClass && something.getClass().equals(jsx3.xml.Entity.jsxclass)){
+ return true; //boolean
+ }
+ return false; //boolran
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // Check whether the object is a jsx3.xml.Entity object and loaded
+ //
+ return this.isItem(something); // Boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // Load an item
+ // description:
+ // The store always loads all items, so if it's an item, then it's loaded.
+ },
+
+ getFeatures: function(){
+ // summary:
+ // Return supported data APIs
+ //
+ return {
+ "dojo.data.api.Read": true,
+ "dojo.data.api.Write": true,
+ "dojo.data.api.Identity":true
+ }; // Object
+ },
+
+ getLabel: function(/* jsx3.xml.Entity */ 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(/* jsx3.xml.Entity */ item){
+ // summary:
+ // returns an array of what properties of the item that were used
+ // to generate its label
+ // See dojo.data.api.Read.getLabelAttributes()
+ //
+ if(this.label !== ""){
+ return [this.label]; //array
+ }
+ return null; //null
+ },
+
+
+ fetch: function(/* Object? */ request){
+ // summary:
+ // Returns an Array of items based on the request arguments.
+ // description:
+ // Returns an Array of items based on the request arguments.
+ // If the store is in ASYNC mode, the items should be expected in an onComplete
+ // method passed in the request object. If store is in SYNC mode, the items will
+ // be return directly as well as within the onComplete method.
+ // note:
+ // The mode can be set on store initialization or during a fetch as one of the
+ // parameters.
+ //
+ // query: String
+ // The items in the store are treated as objects, but this is reading an XML
+ // document. Further, the actual querying of the items takes place in Tibco GI's
+ // jsx3.xml.Entity. Therefore, we are using their syntax which is xpath.
+ // Note:
+ // As conforming to a CDF document, most, if not all nodes are considered "records"
+ // and their tagNames are as such. The root node is named "data".
+ //
+ // examples:
+ // All items:
+ // | store.fetch({query:"*"});
+ // Item with a jsxid attribute equal to "1" (note you could use byId for this)
+ // | store.fetch({query:"//record[@jsxid='1']"});
+ // All items with any jsxid attribute:
+ // | "//record[@jsxid='*']"
+ // The items with a jsxid of '1' or '4':
+ // | "//record[@jsxid='4' or @jsxid='1']"
+ // All children within a "group" node (could be multiple group nodes):
+ // "//group/record"
+ // All children within a specific group node:
+ // "//group[@name='mySecondGroup']/record"
+ // Any record, anywhere in the document:
+ // | "//record"
+ // Only the records beneath the root (data) node:
+ // | "//data/record"
+ //
+ // See:
+ // http://www.tibco.com/devnet/resources/gi/3_7/api/html/jsx3/xml/Entity.html#method:selectNodes
+ // http://www.w3.org/TR/xpath
+ // http://msdn.microsoft.com/en-us/library/ms256086.aspx
+ //
+ // See dojo.data.Read.fetch():
+ // onBegin
+ // onComplete
+ // onItem
+ // onError
+ // scope
+ // start
+ // count
+ // sort
+ //
+ request = request || {};
+ if(!request.store){
+ request.store = this;
+ }
+ if(request.mode !== undefined){
+ this.mode = request.mode;
+ }
+ var self = this;
+
+ var errorHandler = function(errorData){
+ if(request.onError){
+ var scope = request.scope || dojo.global;
+ request.onError.call(scope, errorData, request);
+ }else{
+ console.error("cdfStore Error:", errorData);
+ }
+ };
+
+ var fetchHandler = function(items, requestObject){
+ requestObject = requestObject || request;
+ var oldAbortFunction = requestObject.abort || null;
+ var aborted = false;
+
+ var startIndex = requestObject.start?requestObject.start:0;
+ var endIndex = (requestObject.count && (requestObject.count !== Infinity))?(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, items.length, requestObject);
+ }
+ if(requestObject.sort){
+ 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){
+ if(!requestObject.onItem){
+ items = items.slice(startIndex, endIndex);
+ if(requestObject.byId){
+ items = items[0];
+ }
+ }
+ requestObject.onComplete.call(scope, items, requestObject);
+ }else{
+ items = items.slice(startIndex, endIndex);
+ if(requestObject.byId){
+ items = items[0];
+ }
+ }
+ return items;
+ };
+
+ if(!this.url && !this.data && !this.xmlStr){
+ errorHandler(new Error("No URL or data specified."));
+ return false;
+ }
+ var localRequest = request || "*"; // use request for _getItems()
+
+ if(this.mode == dojox.data.SYNC_MODE){
+ // sync mode. items returned directly
+ var res = this._loadCDF();
+ if(res instanceof Error){
+ if(request.onError){
+ request.onError.call(request.scope || dojo.global, res, request);
+ }else{
+ console.error("CdfStore Error:", res);
+ }
+ return res;
+ }
+ this.cdfDoc = res;
+
+ var items = this._getItems(this.cdfDoc, localRequest);
+ if(items && items.length > 0){
+ items = fetchHandler(items, request);
+ }else{
+ items = fetchHandler([], request);
+ }
+ return items;
+
+ }else{
+
+ // async mode. Return a Deferred.
+ var dfd = this._loadCDF();
+ dfd.addCallbacks(dojo.hitch(this, function(cdfDoc){
+ var items = this._getItems(this.cdfDoc, localRequest);
+ if(items && items.length > 0){
+ fetchHandler(items, request);
+ }else{
+ fetchHandler([], request);
+ }
+ }),
+ dojo.hitch(this, function(err){
+ errorHandler(err, request);
+ }));
+
+ return dfd; // Object
+ }
+ },
+
+
+ _loadCDF: function(){
+ // summary:
+ // Internal method.
+ // If a cdfDoc exists, return it. Otherwise, get one from JSX3,
+ // load the data or url, and return the doc or a deferred.
+ var dfd = new dojo.Deferred();
+ if(this.cdfDoc){
+ if(this.mode == dojox.data.SYNC_MODE){
+ return this.cdfDoc; // jsx3.xml.CDF
+ }else{
+ setTimeout(dojo.hitch(this, function(){
+ dfd.callback(this.cdfDoc);
+ }), 0);
+ return dfd; // dojo.Deferred
+ }
+ }
+
+ this.cdfDoc = jsx3.xml.CDF.Document.newDocument();
+ this.cdfDoc.subscribe("response", this, function(evt){
+ dfd.callback(this.cdfDoc);
+ });
+ this.cdfDoc.subscribe("error", this, function(err){
+ dfd.errback(err);
+ });
+
+ this.cdfDoc.setAsync(!this.mode);
+ if(this.url){
+ this.cdfDoc.load(this.url);
+ }else if(this.xmlStr){
+ this.cdfDoc.loadXML(this.xmlStr);
+ if(this.cdfDoc.getError().code){
+ return new Error(this.cdfDoc.getError().description); // Error
+ }
+ }
+
+ if(this.mode == dojox.data.SYNC_MODE){
+ return this.cdfDoc; // jsx3.xml.CDF
+ }else{
+ return dfd; // dojo.Deferred
+ }
+ },
+
+ _getItems: function(/* jsx3.xml.Entity */cdfDoc, /* Object */request){
+ // summary:
+ // Internal method.
+ // Requests the items from jsx3.xml.Entity with an xpath query.
+ //
+ var itr = cdfDoc.selectNodes(request.query, false, 1);
+ var items = [];
+ while(itr.hasNext()){
+ items.push(itr.next());
+ }
+ 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, /* object? || String? */parentInfo){
+ // summary:
+ // Creates a jsx3.xml.Entity item and inserts it either inside the
+ // parent or appends it to the root
+ //
+ keywordArgs = (keywordArgs || {});
+ if(keywordArgs.tagName){
+ // record tagName is automatic and this would add it
+ // as a property
+ if(keywordArgs.tagName!="record"){
+ // TODO: How about some sort of group?
+ console.warn("Only record inserts are supported at this time");
+ }
+ delete keywordArgs.tagName;
+ }
+ keywordArgs.jsxid = keywordArgs.jsxid || this.cdfDoc.getKey();
+ if(this.isItem(parentInfo)){
+ parentInfo = this.getIdentity(parentInfo);
+ }
+ var item = this.cdfDoc.insertRecord(keywordArgs, parentInfo);
+
+ this._makeDirty(item);
+
+ return item; // jsx3.xml.Entity
+ },
+
+ deleteItem: function(/* jsx3.xml.Entity */ item){
+ // summary:
+ // Delete an jsx3.xml.Entity (wrapper to a XML element).
+ //
+ this.cdfDoc.deleteRecord(this.getIdentity(item));
+ this._makeDirty(item);
+ return true; //boolean
+ },
+
+ setValue: function(/* jsx3.xml.Entity */ item, /* String */ property, /* almost anything */ value){
+ // summary:
+ // Set an property value
+ //
+ this._makeDirty(item);
+ item.setAttribute(property, value);
+ return true; // Boolean
+ },
+
+ setValues: function(/* jsx3.xml.Entity */ item, /* String */ property, /*array*/ values){
+ // summary:
+ // Set property values
+ // TODO: Needs to be fully implemented.
+ //
+ this._makeDirty(item);
+ console.warn("cdfStore.setValues only partially implemented.");
+ return item.setAttribute(property, values);
+
+ },
+
+ unsetAttribute: function(/* jsx3.xml.Entity */ item, /* String */ property){
+ // summary:
+ // Remove an property
+ //
+ this._makeDirty(item);
+ item.removeAttribute(property);
+ return true; // Boolean
+ },
+
+ revert: function(){
+ // summary:
+ // Invalidate changes (new and/or modified elements)
+ // Resets data by simply deleting the reference to the cdfDoc.
+ // Subsequent fetches will load the new data.
+ // Note:
+ // Any items outside the store will no longer be valid and may cause errors.
+ //
+ delete this.cdfDoc;
+ this._modifiedItems = {};
+ return true; //boolean
+ },
+
+ isDirty: function(/* jsx3.xml.Entity ? */ item){
+ // summary:
+ // Check whether an item is new, modified or deleted.
+ // If no item is passed, checks if anything in the store has changed.
+ //
+ if(item){
+ return !!this._modifiedItems[this.getIdentity(item)]; // Boolean
+ }else{
+ var _dirty = false;
+ for(var nm in this._modifiedItems){ _dirty = true; break; }
+ return _dirty; // Boolean
+ }
+ },
+
+
+
+/* internal API */
+
+ _makeDirty: function(item){
+ // summary:
+ // Internal method.
+ // Marks items as modified, deleted or new.
+ var id = this.getIdentity(item);
+ this._modifiedItems[id] = item;
+ },
+
+
+ _makeXmlString: function(obj){
+ // summary:
+ // Internal method.
+ // Converts an object into an XML string.
+ //
+ var parseObj = function(obj, name){
+ var xmlStr = "";
+ var nm;
+ if(dojo.isArray(obj)){
+ for(var i=0;i<obj.length;i++){
+ xmlStr += parseObj(obj[i], name);
+ }
+ }else if(dojo.isObject(obj)){
+ xmlStr += '<'+name+' ';
+ for(nm in obj){
+ if(!dojo.isObject(obj[nm])){
+ xmlStr += nm+'="'+obj[nm]+'" ';
+ }
+ }
+ xmlStr +='>';
+ for(nm in obj){
+ if(dojo.isObject(obj[nm])){
+ xmlStr += parseObj(obj[nm], nm);
+ }
+ }
+ xmlStr += '</'+name+'>';
+ }
+ return xmlStr;
+ };
+ return parseObj(obj, "data");
+ },
+
+ /*************************************
+ * Dojo.data Identity implementation *
+ *************************************/
+ getIdentity: function(/* jsx3.xml.Entity */ item){
+ // summary:
+ // Returns the identifier for an item.
+ //
+ return this.getValue(item, this.identity); // String
+ },
+
+ getIdentityAttributes: function(/* jsx3.xml.Entity */ item){
+ // summary:
+ // Returns the property used for the identity.
+ //
+ return [this.identity]; // Array
+ },
+
+
+ fetchItemByIdentity: function(/* Object || String */ args){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity(keywordArgs)
+ //
+ // Note:
+ // This method can be synchronous if mode is set.
+ // Also, there is a more finger friendly alias of this method, byId();
+ if(dojo.isString(args)){
+ var id = args;
+ args = {query:"//record[@jsxid='"+id+"']", mode: dojox.data.SYNC_MODE};
+ }else{
+ if(args){
+ args.query = "//record[@jsxid='"+args.identity+"']";
+ }
+ if(!args.mode){args.mode = this.mode;}
+ }
+ args.byId = true;
+ return this.fetch(args); // dojo.Deferred || Array
+ },
+ byId: function(/* Object || String */ args){
+ // stub. See fetchItemByIdentity
+ }
+
+});
+
+return dojox.data.CdfStore;
+});
+
diff --git a/js/dojo-1.7.2/dojox/data/ClientFilter.js b/js/dojo-1.7.2/dojox/data/ClientFilter.js
new file mode 100644
index 0000000..042466b
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/ClientFilter.js
@@ -0,0 +1,293 @@
+//>>built
+define("dojox/data/ClientFilter", ["dojo/_base/declare", "dojo/_base/lang", "dojo/_base/array", "dojo/_base/Deferred", "dojo/data/util/filter"],
+ function(declare, lang, array, Deferred, filter) {
+
+// This is an abstract data store module for adding updateable result set functionality to an existing data store class
+
+ var addUpdate = function(store,create,remove){
+ // create a handler that adds to the list of notifications
+ return function(item){
+ store._updates.push({
+ create:create && item,
+ remove:remove && item
+ });
+ ClientFilter.onUpdate();
+ }
+ };
+ var ClientFilter = declare("dojox.data.ClientFilter", null, {
+ cacheByDefault: false,
+ constructor: function(){
+ // summary:
+ // This is an abstract class that data stores can extend to add updateable result set functionality
+ // as well as client side querying capabilities. This enables
+ // widgets to be aware of how active results change in response to the modifications/notifications.
+ //
+ // description:
+ // To a update a result set after a notification (onNew, onSet, and onDelete),
+ // widgets can call the updateResultSet method. Widgets can use the updated
+ // result sets to determine how to react to notifications, and how to update their displayed results
+ // based on changes.
+ //
+ // This module will use the best available information to update result sets, using query attribute
+ // objects to determine if items are in a result set, and using the sort arrays to maintain sort
+ // information. However, queries can be opaque strings, and this module can not update
+ // results by itself in this case. In this situations, data stores can provide a isUpdateable(request) function
+ // and matchesQuery(item,request) function. If a data store can handle a query, it can return true from
+ // isUpdateable and if an item matches a query, it can return true from matchesQuery. Here is
+ // definition of isUpdateable and matchesQuery
+ // isUpdateable(request) - request is the keywords arguments as is passed to the fetch function.
+ // matchesQuery(item,request) - item is the item to test, and request is the value arguments object
+ // for the fetch function.
+ //
+ // You can define a property on this object instance "cacheByDefault" to a value of true that will
+ // cause all queries to be cached by default unless the cache queryOption is explicitly set to false.
+ // This can be defined in the constructor options for ServiceStore/JsonRestStore and subtypes.
+ //
+ // example:
+ // to make a updated-result-set data store from an existing data store:
+ // | dojo.declare("dojox.data.MyLiveDataStore",
+ // | dojox.data.MyDataStore,dojox.data.ClientFilter], // subclass LiveResultSets if available
+ // | {}
+ // | );
+ this.onSet = addUpdate(this,true,true);
+ this.onNew = addUpdate(this,true,false);
+ this.onDelete = addUpdate(this,false,true);
+ this._updates= [];
+ this._fetchCache = [];
+ },
+ clearCache: function(){
+ // summary:
+ // Clears the cache of client side queries
+ this._fetchCache = [];
+ },
+ updateResultSet: function(/*Array*/ resultSet, /*Object*/ request){
+ // summary:
+ // Attempts to update the given result set based on previous notifications
+ // resultSet:
+ // The result set array that should be updated
+ // request:
+ // This object follows the same meaning as the keywordArgs passed to a dojo.data.api.Read.fetch.
+ // description:
+ // This will attempt to update the provide result based on previous notification, adding new items
+ // from onNew calls, removing deleted items, and updating modified items, and properly removing
+ // and adding items as required by the query and sort parameters. This function will return:
+ // 0: Indicates it could not successfully update the result set
+ // 1: Indicates it could successfully handle all the notifications, but no changes were made to the result set
+ // 2: Indicates it successfully handled all the notifications and result set has been updated.
+ if(this.isUpdateable(request)){
+ // we try to avoid rerunning notification updates more than once on the same object for performance
+ for(var i = request._version || 0; i < this._updates.length;i++){
+ // for each notification,we will update the result set
+ var create = this._updates[i].create;
+ var remove = this._updates[i].remove;
+ if(remove){
+ for(var j = 0; j < resultSet.length;j++){
+ if(this.getIdentity(resultSet[j]) == this.getIdentity(remove)){
+ resultSet.splice(j--,1);
+ var updated = true;
+ }
+ }
+ }
+ if(create && this.matchesQuery(create,request) && // if there is a new/replacement item and it matches the query
+ array.indexOf(resultSet,create) == -1){ // and it doesn't already exist in query
+ resultSet.push(create); // should this go at the beginning by default instead?
+ updated = true;
+ }
+ }
+ if(request.sort && updated){
+ // do the sort if needed
+ resultSet.sort(this.makeComparator(request.sort.concat()));
+ }
+ resultSet._fullLength = resultSet.length;
+ if(request.count && updated && request.count !== Infinity){
+ // do we really need to do this?
+ // make sure we still find within the defined paging set
+ resultSet.splice(request.count, resultSet.length);
+ }
+ request._version = this._updates.length;
+ return updated ? 2 : 1;
+ }
+ return 0;
+ },
+ querySuperSet: function(argsSuper, argsSub){
+ // summary:
+ // Determines whether the provided arguments are super/sub sets of each other
+ // argsSuper:
+ // Dojo Data Fetch arguments
+ // argsSub:
+ // Dojo Data Fetch arguments
+ if(argsSuper.query == argsSub.query){
+ return {};
+ }
+ if(!(argsSub.query instanceof Object && // sub query must be an object
+ // super query must be non-existent or an object
+ (!argsSuper.query || typeof argsSuper.query == 'object'))){
+ return false;
+ }
+ var clientQuery = lang.mixin({},argsSub.query);
+ for(var i in argsSuper.query){
+ if(clientQuery[i] == argsSuper.query[i]){
+ delete clientQuery[i];
+ }else if(!(typeof argsSuper.query[i] == 'string' &&
+ // if it is a pattern, we can test to see if it is a sub-pattern
+ // FIXME: This is not technically correct, but it will work for the majority of cases
+ filter.patternToRegExp(argsSuper.query[i]).test(clientQuery[i]))){
+ return false;
+ }
+ }
+ return clientQuery;
+ },
+ // This is the point in the version notification history at which it is known that the server is in sync, this should
+ // be updated to this._updates.length on commit operations.
+ serverVersion: 0,
+
+ cachingFetch: function(args){
+ var self = this;
+ for(var i = 0; i < this._fetchCache.length;i++){
+ var cachedArgs = this._fetchCache[i];
+ var clientQuery = this.querySuperSet(cachedArgs,args);
+ if(clientQuery !== false){
+ var defResult = cachedArgs._loading;
+ if(!defResult){
+ defResult = new Deferred();
+ defResult.callback(cachedArgs.cacheResults);
+ }
+ defResult.addCallback(function(results){
+ results = self.clientSideFetch(lang.mixin(lang.mixin({}, args),{query:clientQuery}), results);
+ defResult.fullLength = results._fullLength;
+ return results;
+ });
+ args._version = cachedArgs._version;
+ break;
+ }
+ }
+ if(!defResult){
+ var serverArgs = lang.mixin({}, args);
+ var putInCache = (args.queryOptions || 0).cache;
+ var fetchCache = this._fetchCache;
+ if(putInCache === undefined ? this.cacheByDefault : putInCache){
+ // we are caching this request, so we want to get all the data, and page on the client side
+ if(args.start || args.count){
+ delete serverArgs.start;
+ delete serverArgs.count;
+ args.clientQuery = lang.mixin(args.clientQuery || {}, {
+ start: args.start,
+ count: args.count
+ });
+ }
+ args = serverArgs;
+ fetchCache.push(args);
+ }
+ defResult= args._loading = this._doQuery(args);
+
+ defResult.addErrback(function(){
+ fetchCache.splice(array.indexOf(fetchCache, args), 1);
+ });
+ }
+ var version = this.serverVersion;
+
+ defResult.addCallback(function(results){
+ delete args._loading;
+ // update the result set in case anything changed while we were waiting for the fetch
+ if(results){
+ args._version = typeof args._version == "number" ? args._version : version;
+ self.updateResultSet(results,args);
+ args.cacheResults = results;
+ if(!args.count || results.length < args.count){
+ defResult.fullLength = ((args.start)?args.start:0) + results.length;
+ }
+ }
+ return results;
+ });
+ return defResult;
+ },
+ isUpdateable: function(/*Object*/ request){
+ // summary:
+ // Returns whether the provide fetch arguments can be used to update an existing list
+ // request:
+ // See dojo.data.api.Read.fetch request
+
+ return typeof request.query == "object";
+ },
+ clientSideFetch: function(/*Object*/ request,/*Array*/ baseResults){
+ // summary:
+ // Performs a query on the client side and returns the results as an array
+ //
+ // request:
+ // See dojo.data.api.Read.fetch request
+ //
+ // baseResults:
+ // This provides the result set to start with for client side querying
+ if(request.queryOptions && request.queryOptions.results){
+ baseResults = request.queryOptions.results;
+ }
+ if(request.query){
+ // filter by the query
+ var results = [];
+ for(var i = 0; i < baseResults.length; i++){
+ var value = baseResults[i];
+ if(value && this.matchesQuery(value,request)){
+ results.push(baseResults[i]);
+ }
+ }
+ }else{
+ results = request.sort ? baseResults.concat() : baseResults; // we don't want to mutate the baseResults if we are doing a sort
+ }
+ if(request.sort){
+ // do the sort if needed
+ results.sort(this.makeComparator(request.sort.concat()));
+ }
+ return this.clientSidePaging(request, results);
+ },
+ clientSidePaging: function(/*Object*/ request,/*Array*/ baseResults){
+ var start = request.start || 0;
+ var finalResults = (start || request.count) ? baseResults.slice(start,start + (request.count || baseResults.length)) : baseResults;
+ finalResults._fullLength = baseResults.length;
+ return finalResults;
+ },
+ matchesQuery: function(item,request){
+ var query = request.query;
+ var ignoreCase = request.queryOptions && request.queryOptions.ignoreCase;
+ for(var i in query){
+ // if anything doesn't match, than this should be in the query
+ var match = query[i];
+ var value = this.getValue(item,i);
+ if((typeof match == 'string' && (match.match(/[\*\.]/) || ignoreCase)) ?
+ !filter.patternToRegExp(match, ignoreCase).test(value) :
+ value != match){
+ return false;
+ }
+ }
+ return true;
+ },
+ makeComparator: function(sort){
+ // summary:
+ // returns a comparator function for the given sort order array
+ // sort:
+ // See dojox.data.api.Read.fetch
+ var current = sort.shift();
+ if(!current){
+ // sort order for ties and no sort orders
+ return function(){
+ return 0;// keep the order unchanged
+ };
+ }
+ var attribute = current.attribute;
+ var descending = !!current.descending;
+ var next = this.makeComparator(sort);
+ var store = this;
+ return function(a,b){
+ var av = store.getValue(a,attribute);
+ var bv = store.getValue(b,attribute);
+ if(av != bv){
+ return av < bv == descending ? 1 : -1;
+ }
+ return next(a,b);
+ };
+ }
+ }
+ );
+ ClientFilter.onUpdate = function(){};
+
+ return ClientFilter;
+});
diff --git a/js/dojo-1.7.2/dojox/data/CouchDBRestStore.js b/js/dojo-1.7.2/dojox/data/CouchDBRestStore.js
new file mode 100644
index 0000000..c11b204
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/CouchDBRestStore.js
@@ -0,0 +1,83 @@
+//>>built
+define("dojox/data/CouchDBRestStore", ["dojo", "dojox", "dojox/data/JsonRestStore"], function(dojo, dojox) {
+
+// A CouchDBRestStore is an extension of JsonRestStore to handle CouchDB's idiosyncrasies, special features,
+// and deviations from standard HTTP Rest.
+// NOTE: CouchDB is not designed to be run on a public facing network. There is no access control
+// on database documents, and you should NOT rely on client side control to implement security.
+
+
+dojo.declare("dojox.data.CouchDBRestStore",
+ dojox.data.JsonRestStore,
+ {
+ save: function(kwArgs){
+ var actions = this.inherited(arguments); // do the default save and then update for version numbers
+ var prefix = this.service.servicePath;
+ for(var i = 0; i < actions.length; i++){
+ // need to update the item's version number after it has been committed
+ (function(item,dfd){
+ dfd.addCallback(function(result){
+ if(result){
+ item.__id = prefix + result.id; // update the object with the results of the post
+ item._rev = result.rev;
+ }
+ return result;
+ });
+ })(actions[i].content,actions[i].deferred);
+ }
+ },
+ fetch: function(args){
+ // summary:
+ // This only differs from JsonRestStore in that it, will put the query string the query part of the URL and it handles start and count
+ args.query = args.query || '_all_docs?';
+ if(args.start){
+ args.query = (args.query ? (args.query + '&') : '') + 'startkey=' + args.start;
+ delete args.start;
+ }
+ if(args.count){
+ args.query = (args.query ? (args.query + '&') : '') + 'limit=' + args.count;
+ delete args.count;
+ }
+ return this.inherited(arguments);
+ },
+ _processResults: function(results){
+ var rows = results.rows;
+ if(rows){
+ var prefix = this.service.servicePath;
+ var self = this;
+ for(var i = 0; i < rows.length;i++){
+ var realItem = rows[i].value;
+ realItem.__id= prefix + rows[i].id;
+ realItem._id= rows[i].id;
+ realItem._loadObject= dojox.rpc.JsonRest._loader;
+ rows[i] = realItem;
+ }
+ return {totalCount:results.total_rows, items:results.rows};
+ }else{
+ return {items:results};
+ }
+
+ }
+ }
+);
+
+// create a set of stores
+dojox.data.CouchDBRestStore.getStores = function(couchServerUrl){
+ var dfd = dojo.xhrGet({
+ url: couchServerUrl+"_all_dbs",
+ handleAs: "json",
+ sync: true
+ });
+ var stores = {};
+ dfd.addBoth(function(dbs){
+ for(var i = 0; i < dbs.length; i++){
+ stores[dbs[i]] = new dojox.data.CouchDBRestStore({target:couchServerUrl + dbs[i],idAttribute:"_id"});
+ }
+ return stores;
+ });
+ return stores;
+};
+
+return dojox.data.CouchDBRestStore;
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/CssClassStore.js b/js/dojo-1.7.2/dojox/data/CssClassStore.js
new file mode 100644
index 0000000..ab554cf
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/CssClassStore.js
@@ -0,0 +1,162 @@
+//>>built
+define("dojox/data/CssClassStore", ["dojo/_base/declare","dojox/data/CssRuleStore"],
+ function(declare, CssRuleStore) {
+
+/*===== var CssRuleStore = dojox.data.CssRuleStore =====*/
+
+return declare("dojox.data.CssClassStore", CssRuleStore, {
+ // summary:
+ // Basic store to display CSS information.
+ // description:
+ // The CssClassStore allows users to get information about active Css classes in the page running the CssClassStore.
+ // It can also filter out classes from specific stylesheets. The attributes it exposes on classes are as follows:
+ // class: The classname, including the '.'.
+ // classSans: The classname without the '.'.
+
+ _labelAttribute: 'class', // text representation of the Item [label and identifier may need to stay due to method names]
+ _idAttribute: 'class',
+ _cName: "dojox.data.CssClassStore",
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ "dojo.data.api.Read" : true,
+ "dojo.data.api.Identity" : true
+ };
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ return ['class', 'classSans'];
+ },
+
+ getValue: function(item, attribute, defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ if(values && values.length > 0){
+ return values[0];
+ }
+ return defaultValue;
+ },
+
+ getValues: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ var value = [];
+ if(attribute === "class"){
+ value = [item.className];
+ }else if(attribute === "classSans"){
+ value = [item.className.replace(/\./g,'')];
+ }
+ return value;
+ },
+
+ _handleRule: function(rule, styleSheet, href){
+ // summary:
+ // Handles the creation of an item based on the passed rule. In this store, this implies
+ // parsing out all available class names.
+ var obj = {};
+ var s = rule['selectorText'].split(" ");
+ for(var j=0; j<s.length; j++){
+ var tmp = s[j];
+ var first = tmp.indexOf('.');
+ if(tmp && tmp.length > 0 && first !== -1){
+ var last = tmp.indexOf(',') || tmp.indexOf('[');
+ tmp = tmp.substring(first, ((last !== -1 && last > first)?last:tmp.length));
+ obj[tmp] = true;
+ }
+ }
+ for(var key in obj){
+ if(!this._allItems[key]){
+ var item = {};
+ item.className = key;
+ item[this._storeRef] = this;
+ this._allItems[key] = item;
+ }
+ }
+ },
+
+ _handleReturn: function(){
+ // summary:
+ // Handles the return from a fetching action. Delegates requests to act on the resulting
+ // item set to eitehr the _handleFetchReturn or _handleFetchByIdentityReturn depending on
+ // where the request originated.
+ var _inProgress = [];
+
+ var items = {};
+ for(var i in this._allItems){
+ items[i] = this._allItems[i];
+ }
+ var requestInfo;
+ // One-level deep clone (can't use dojo.clone, since we don't want to clone all those store refs!)
+ while(this._pending.length){
+ requestInfo = this._pending.pop();
+ requestInfo.request._items = items;
+ _inProgress.push(requestInfo);
+ }
+
+ while(_inProgress.length){
+ requestInfo = _inProgress.pop();
+ if(requestInfo.fetch){
+ this._handleFetchReturn(requestInfo.request);
+ }else{
+ this._handleFetchByIdentityReturn(requestInfo.request);
+ }
+ }
+ },
+
+ _handleFetchByIdentityReturn: function(request){
+ // summary:
+ // Handles a fetchByIdentity request by finding the correct item.
+ var items = request._items;
+ // Per https://bugs.webkit.org/show_bug.cgi?id=17935 , Safari 3.x always returns the selectorText
+ // of a rule in full lowercase.
+ var item = items[request.identity];
+ if(!this.isItem(item)){
+ item = null;
+ }
+ if(request.onItem){
+ var scope = request.scope || dojo.global;
+ request.onItem.call(scope, item);
+ }
+ },
+
+ /* Identity API */
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ this._assertIsItem(item);
+ return this.getValue(item, this._idAttribute);
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentityAttributes()
+ this._assertIsItem(item);
+ return [this._idAttribute];
+ },
+
+ fetchItemByIdentity: function(/* request */ request){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+ request = request || {};
+ if(!request.store){
+ request.store = this;
+ }
+ if(this._pending && this._pending.length > 0){
+ this._pending.push({request: request});
+ }else{
+ this._pending = [{request: request}];
+ this._fetch(request);
+ }
+ return request;
+ }
+});
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/CssRuleStore.js b/js/dojo-1.7.2/dojox/data/CssRuleStore.js
new file mode 100644
index 0000000..9bb5f74
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/CssRuleStore.js
@@ -0,0 +1,462 @@
+//>>built
+define("dojox/data/CssRuleStore", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "dojo/_base/json","dojo/_base/window", "dojo/_base/sniff", "dojo/data/util/sorter", "dojo/data/util/filter", "./css"],
+ function(lang, declare, array, jsonUtil, winUtil, has, sorter, filter, css) {
+
+return declare("dojox.data.CssRuleStore", null, {
+ // summary:
+ // Basic store to display CSS information.
+ // description:
+ // The CssRuleStore allows users to get information about active CSS rules in the page running the CssRuleStore.
+ // It can also filter out rules from specific stylesheets. The attributes it exposes on rules are as follows:
+ // selector: The selector text.
+ // classes: An array of classes present in this selector.
+ // rule: The actual DOM Rule object.
+ // style: The actual DOM CSSStyleDeclaration object.
+ // cssText: The cssText string provided on the rule object.
+ // styleSheet: The originating DOM Stylesheet object.
+ // parentStyleSheet: The parent stylesheet to the sheet this rule originates from.
+ // parentStyleSheetHref: The href of the parent stylesheet.
+ // AND every style attribute denoted as style.*, such as style.textAlign or style.backgroundColor
+
+ _storeRef: '_S',
+ _labelAttribute: 'selector', // text representation of the Item [label and identifier may need to stay due to method names]
+
+ _cache: null,
+
+ _browserMap: null,
+
+ _cName: "dojox.data.CssRuleStore",
+
+ constructor: function(/* Object */ keywordParameters){
+ // Initializes this store
+ if(keywordParameters){
+ lang.mixin(this, keywordParameters);
+ }
+ this._cache = {};
+ this._allItems = null;
+ this._waiting = [];
+ this.gatherHandle = null;
+ var self = this;
+ // CSS files may not be finished loading by the time the store is constructed. We need to
+ // give them a little time, so setting the stylesheet loading to retry every 250ms.
+ function gatherRules(){
+ try{
+ // Funkiness here is due to css that may still be loading. This throws an DOM Access
+ // error if css isnt completely loaded.
+ self.context = css.determineContext(self.context);
+ if(self.gatherHandle){
+ clearInterval(self.gatherHandle);
+ self.gatherHandle = null;
+ }
+ // Handle any fetches that have been queued while we've been waiting on the CSS files
+ // to finish
+ while(self._waiting.length){
+ var item = self._waiting.pop();
+ css.rules.forEach(item.forFunc, null, self.context);
+ item.finishFunc();
+ }
+ }catch(e){}
+ }
+ this.gatherHandle = setInterval(gatherRules,250);
+ },
+
+ setContext: function(/* Array */ context){
+ // Sets the context in which queries are executed
+ // context: Array - Array of CSS string paths to execute queries within
+ if(context){
+ this.close();
+ this.context = css.determineContext(context);
+ }
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ "dojo.data.api.Read" : true
+ };
+ },
+
+ isItem: function(item){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(item && item[this._storeRef] == this){
+ return true;
+ }
+ return false;
+ },
+
+ hasAttribute: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ var attrs = this.getAttributes(item);
+ if(array.indexOf(attrs, attribute) != -1){
+ return true;
+ }
+ return false;
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attrs = ['selector', 'classes', 'rule', 'style', 'cssText', 'styleSheet', 'parentStyleSheet', 'parentStyleSheetHref'];
+ var style = item.rule.style;
+ if(style){
+ var key;
+ for(key in style){
+ attrs.push("style." + key);
+ }
+ }
+ return attrs;
+ },
+
+ getValue: function(item, attribute, defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ var value = defaultValue;
+ if(values && values.length > 0){
+ return values[0];
+ }
+ return defaultValue;
+ },
+
+ getValues: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ var value = null;
+ if(attribute === "selector"){
+ value = item.rule["selectorText"];
+ if(value && lang.isString(value)){
+ value = value.split(",");
+ }
+ }else if(attribute === "classes"){
+ value = item.classes;
+ }else if(attribute === "rule"){
+ value = item.rule.rule;
+ }else if(attribute === "style"){
+ value = item.rule.style;
+ }else if(attribute === "cssText"){
+ if(has("ie")){
+ if(item.rule.style){
+ value = item.rule.style.cssText;
+ if(value){
+ value = "{ " + value.toLowerCase() + " }";
+ }
+ }
+ }else{
+ value = item.rule.cssText;
+ if(value){
+ value = value.substring(value.indexOf("{"), value.length);
+ }
+ }
+ }else if(attribute === "styleSheet"){
+ value = item.rule.styleSheet;
+ }else if(attribute === "parentStyleSheet"){
+ value = item.rule.parentStyleSheet;
+ }else if(attribute === "parentStyleSheetHref"){
+ if(item.href){
+ value = item.href;
+ }
+ }else if(attribute.indexOf("style.") === 0){
+ var attr = attribute.substring(attribute.indexOf("."), attribute.length);
+ value = item.rule.style[attr];
+ }else{
+ value = [];
+ }
+ if(value !== undefined){
+ if(!lang.isArray(value)){
+ value = [value];
+ }
+ }
+ return value;
+ },
+
+ getLabel: function(item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ this._assertIsItem(item);
+ return this.getValue(item, this._labelAttribute);
+ },
+
+ getLabelAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return [this._labelAttribute];
+ },
+
+ 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 = filter.patternToRegExp(value, false);
+ }
+ return this._containsValue(item, attribute, value, regexp); //boolean.
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(something); //boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ this._assertIsItem(keywordArgs.item);
+ },
+
+ fetch: function(request){
+ // summary:
+ // See dojo.data.api.Read.fetch()
+ request = request || {};
+ if(!request.store){
+ request.store = this;
+ }
+
+ var scope = request.scope || winUtil.global;
+ if(this._pending && this._pending.length > 0){
+ this._pending.push({request: request, fetch: true});
+ }else{
+ this._pending = [{request: request, fetch: true}];
+ this._fetch(request);
+ }
+ return request;
+ },
+
+ _fetch: function(request){
+ // summary:
+ // Populates the _allItems object with unique class names
+ var scope = request.scope || winUtil.global;
+ if(this._allItems === null){
+ this._allItems = {};
+ try{
+ if(this.gatherHandle){
+ this._waiting.push({'forFunc': lang.hitch(this, this._handleRule), 'finishFunc': lang.hitch(this, this._handleReturn)});
+ }else{
+ css.rules.forEach(lang.hitch(this, this._handleRule), null, this.context);
+ this._handleReturn();
+ }
+ }catch(e){
+ if(request.onError){
+ request.onError.call(scope, e, request);
+ }
+ }
+ }else{
+ this._handleReturn();
+ }
+ },
+
+ _handleRule: function(rule, styleSheet, href){
+ // summary:
+ // Handles the creation of an item based on the passed rule. In this store, this implies
+ // parsing out all available class names.
+ var selector = rule['selectorText'];
+ var s = selector.split(" ");
+ var classes = [];
+ for(var j=0; j<s.length; j++){
+ var tmp = s[j];
+ var first = tmp.indexOf('.');
+ if(tmp && tmp.length > 0 && first !== -1){
+ var last = tmp.indexOf(',') || tmp.indexOf('[');
+ tmp = tmp.substring(first, ((last !== -1 && last > first)?last:tmp.length));
+ classes.push(tmp);
+ }
+ }
+ var item = {};
+ item.rule = rule;
+ item.styleSheet = styleSheet;
+ item.href = href;
+ item.classes = classes;
+ item[this._storeRef] = this;
+ if(!this._allItems[selector]){
+ this._allItems[selector] = [];
+ }
+ this._allItems[selector].push(item);
+ },
+
+ _handleReturn: function(){
+ // summary:
+ // Handles the return from a fetching action. Delegates requests to act on the resulting
+ // item set to eitehr the _handleFetchReturn or _handleFetchByIdentityReturn depending on
+ // where the request originated.
+ var _inProgress = [];
+
+ var items = [];
+ var item = null;
+ for(var i in this._allItems){
+ item = this._allItems[i];
+ for(var j in item){
+ items.push(item[j]);
+ }
+ }
+
+ var requestInfo;
+ // One-level deep clone (can't use dojo.clone, since we don't want to clone all those store refs!)
+ while(this._pending.length){
+ requestInfo = this._pending.pop();
+ requestInfo.request._items = items;
+ _inProgress.push(requestInfo);
+ }
+
+ while(_inProgress.length){
+ requestInfo = _inProgress.pop();
+ this._handleFetchReturn(requestInfo.request);
+ }
+ },
+
+ _handleFetchReturn: function(/*Request */ request){
+ // summary:
+ // Handles a fetchByIdentity request by finding the correct items.
+ var scope = request.scope || winUtil.global;
+ var items = [];
+ //Check to see if we've looked this query up before
+ //If so, just reuse it, much faster. Only regen if query changes.
+ var cacheKey = "all";
+ var i;
+ if(request.query){
+ cacheKey = jsonUtil.toJson(request.query);
+ }
+ if(this._cache[cacheKey]){
+ items = this._cache[cacheKey];
+ }else if(request.query){
+ for(i in request._items){
+ var item = request._items[i];
+ // Per https://bugs.webkit.org/show_bug.cgi?id=17935 , Safari 3.x always returns the selectorText
+ // of a rule in full lowercase.
+ var ignoreCase = (request.queryOptions ? request.queryOptions.ignoreCase : false);
+ var regexpList = {};
+ var key;
+ var value;
+ for(key in request.query){
+ value = request.query[key];
+ if(typeof value === "string"){
+ regexpList[key] = filter.patternToRegExp(value, ignoreCase);
+ }
+ }
+ var match = true;
+ for(key in request.query){
+ value = request.query[key];
+ if(!this._containsValue(item, key, value, regexpList[key])){
+ match = false;
+ }
+ }
+ if(match){
+ items.push(item);
+ }
+ }
+ this._cache[cacheKey] = items;
+ }else{
+ for(i in request._items){
+ items.push(request._items[i]);
+ }
+ }
+ var total = items.length;
+
+ //Sort it if we need to.
+ if(request.sort){
+ items.sort(sorter.createSortFunction(request.sort, this));
+ }
+ var start = 0;
+ var count = items.length;
+ if(request.start > 0 && request.start < items.length){
+ start = request.start;
+ }
+ if(request.count && request.count){
+ count = request.count;
+ }
+ var endIdx = start + count;
+ if(endIdx > items.length){
+ endIdx = items.length;
+ }
+
+ items = items.slice(start, endIdx);
+
+ if(request.onBegin){
+ request.onBegin.call(scope, total, request);
+ }
+ if(request.onItem){
+ if(lang.isArray(items)){
+ for(i = 0; i < items.length; i++){
+ request.onItem.call(scope, items[i], request);
+ }
+ if(request.onComplete){
+ request.onComplete.call(scope, null, request);
+ }
+ }
+ }else if(request.onComplete){
+ request.onComplete.call(scope, items, request);
+ }
+ return request;
+ },
+
+ close: function(){
+ // summary:
+ // See dojo.data.api.Read.close()
+ // Clears out the cache and allItems objects, meaning all future fetches will requery
+ // the stylesheets.
+ this._cache = {};
+ this._allItems = null;
+ },
+
+ _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(this._cName + ": 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._cName + ": Invalid attribute argument.");
+ }
+ },
+
+ _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'
+ return array.some(this.getValues(item, attribute), function(possibleValue){
+ if(possibleValue !== null && !lang.isObject(possibleValue) && regexp){
+ if(possibleValue.toString().match(regexp)){
+ return true; // Boolean
+ }
+ }else if(value === possibleValue){
+ return true; // Boolean
+ }
+ return false;
+ });
+ }
+});
+});
diff --git a/js/dojo-1.7.2/dojox/data/CsvStore.js b/js/dojo-1.7.2/dojox/data/CsvStore.js
new file mode 100644
index 0000000..65e838c
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/CsvStore.js
@@ -0,0 +1,727 @@
+//>>built
+define("dojox/data/CsvStore", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/xhr", "dojo/_base/window","dojo/data/util/filter", "dojo/data/util/simpleFetch"],
+ function(lang, declare, xhr, winUtil, filterUtil, simpleFetch) {
+
+var CsvStore = 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.
+ // keywordParameters: {identifier: String} The column label for the column to use for the identity. Optional. If not set, the identity is the row number.
+
+ 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 = [];
+ this.identifier = keywordParameters.identifier;
+ if(this.identifier === ""){
+ delete this.identifier;
+ }else{
+ this._idMap = {};
+ }
+ if("separator" in keywordParameters){
+ this.separator = keywordParameters.separator;
+ }
+ if("urlPreventCache" in keywordParameters){
+ this.urlPreventCache = keywordParameters.urlPreventCache?true:false;
+ }
+ },
+
+ // url: [public] string
+ // Declarative hook for setting Csv source url.
+ url: "",
+
+ // label: [public] string
+ // Declarative hook for setting the label attribute.
+ label: "",
+
+ // identifier: [public] string
+ // Declarative hook for setting the identifier.
+ identifier: "",
+
+ // separator: [public] string
+ // Declatative and programmatic hook for defining the separator
+ // character used in the Csv style file.
+ separator: ",",
+
+ // separator: [public] string
+ // Parameter to allow specifying if preventCache should be passed to
+ // the xhrGet call or not when loading data from a url.
+ // Note this does not mean the store calls the server on each fetch,
+ // only that the data load has preventCache set as an option.
+ urlPreventCache: false,
+
+ _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(this.declaredClass + ": a function was passed an item argument that was not an item");
+ }
+ },
+
+ _getIndex: function(item){
+ // summary:
+ // Internal function to get the internal index to the item data from the item handle
+ // item:
+ // The idem handle to get the index for.
+ var idx = this.getIdentity(item);
+ if(this.identifier){
+ idx = this._idMap[idx];
+ }
+ return idx;
+ },
+
+/***************************************
+ 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);
+ var itemValue = defaultValue;
+ if(typeof attribute === "string"){
+ var ai = this._attributeIndexes[attribute];
+ if(ai != null){
+ var itemData = this._dataArray[this._getIndex(item)];
+ itemValue = itemData[ai] || defaultValue;
+ }
+ }else{
+ throw new Error(this.declaredClass + ": a function was passed an attribute argument that was not a string");
+ }
+ 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._getIndex(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-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);
+ if(typeof attribute === "string"){
+ var attributeIndex = this._attributeIndexes[attribute];
+ var itemData = this._dataArray[this._getIndex(item)];
+ return (typeof attributeIndex !== "undefined" && attributeIndex < itemData.length && itemData[attributeIndex] !== ""); //Boolean
+ }else{
+ throw new Error(this.declaredClass + ": a function was passed an attribute argument that was not a string");
+ }
+ },
+
+ 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 = filterUtil.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'
+ // tags:
+ // private
+ 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 an identifier was specified, we have to look it up via that and the mapping,
+ //otherwise, just use row number.
+ if(this.identifier){
+ var data = this._dataArray[this._idMap[identity]];
+ if(data){
+ return true;
+ }
+ }else{
+ 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()
+ // tags:
+ // protected
+ var self = this;
+ var filter = function(requestArgs, arrayOfAllItems){
+ var items = null;
+ if(requestArgs.query){
+ var key, value;
+ 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(key in requestArgs.query){
+ value = requestArgs.query[key];
+ if(typeof value === "string"){
+ regexpList[key] = filterUtil.patternToRegExp(value, ignoreCase);
+ }
+ }
+
+ for(var i = 0; i < arrayOfAllItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfAllItems[i];
+ for(key in requestArgs.query){
+ 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.
+ 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",
+ preventCache: self.urlPreventCache
+ };
+ var getHandler = xhr.get(getArgs);
+ getHandler.addCallback(function(data){
+ try{
+ self._processData(data);
+ filter(keywordArgs, self._arrayOfAllItems);
+ self._handleQueuedFetches();
+ }catch(e){
+ errorCallback(e, keywordArgs);
+ }
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ if(errorCallback){
+ errorCallback(error, keywordArgs);
+ }else{
+ throw error;
+ }
+ });
+ //Wire up the cancel to abort of the request
+ //This call cancel on the deferred if it hasn't been called
+ //yet and then will chain to the simple abort of the
+ //simpleFetch keywordArgs
+ var oldAbort = null;
+ if(keywordArgs.abort){
+ oldAbort = keywordArgs.abort;
+ }
+ keywordArgs.abort = function(){
+ var df = getHandler;
+ if(df && df.fired === -1){
+ df.cancel();
+ df = null;
+ }
+ if(oldAbort){
+ oldAbort.call(keywordArgs);
+ }
+ };
+ }
+ }else if(this._csvData){
+ try{
+ this._processData(this._csvData);
+ this._csvData = null;
+ filter(keywordArgs, this._arrayOfAllItems);
+ }catch(e){
+ errorCallback(e, keywordArgs);
+ }
+ }else{
+ var error = new Error(this.declaredClass + ": 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 }
+ // tags:
+ // private
+ if(lang.isString(csvFileContents)){
+ var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g');
+ var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g');
+ var doubleQuotes = new RegExp('""','g');
+ var arrayOfOutputRecords = [];
+ var i;
+
+ var arrayOfInputLines = this._splitLines(csvFileContents);
+ for(i = 0; i < arrayOfInputLines.length; ++i){
+ var singleLine = arrayOfInputLines[i];
+ if(singleLine.length > 0){
+ var listOfFields = singleLine.split(this.separator);
+ 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
+ }
+ var nextField = listOfFields[j+1];
+ listOfFields[j] = field_space + this.separator + 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(i = 0; i<this._attributes.length; i++){
+ // Store the index of each attribute
+ this._attributeIndexes[this._attributes[i]] = i;
+ }
+ this._dataArray = arrayOfOutputRecords; //Array
+ }
+ },
+
+ _splitLines: function(csvContent){
+ // summary:
+ // Function to split the CSV file contents into separate lines.
+ // Since line breaks can occur inside quotes, a Regexp didn't
+ // work as well. A quick passover parse should be just as efficient.
+ // tags:
+ // private
+ var split = [];
+ var i;
+ var line = "";
+ var inQuotes = false;
+ for(i = 0; i < csvContent.length; i++){
+ var c = csvContent.charAt(i);
+ switch(c){
+ case '\"':
+ inQuotes = !inQuotes;
+ line += c;
+ break;
+ case '\r':
+ if(inQuotes){
+ line += c;
+ }else{
+ split.push(line);
+ line = "";
+ if(i < (csvContent.length - 1) && csvContent.charAt(i + 1) == '\n'){
+ i++; //Skip it, it's CRLF
+ }
+ }
+ break;
+ case '\n':
+ if(inQuotes){
+ line += c;
+ }else{
+ split.push(line);
+ line = "";
+ }
+ break;
+ default:
+ line +=c;
+ }
+ }
+ if(line !== ""){
+ split.push(line);
+ }
+ return split;
+ },
+
+ _processData: function(/* String */ data){
+ // summary:
+ // Function for processing the string data from the server.
+ // data: String
+ // The CSV data.
+ // tags:
+ // private
+ this._getArrayOfArraysFromCsvFileContents(data);
+ this._arrayOfAllItems = [];
+
+ //Check that the specified Identifier is actually a column title, if provided.
+ if(this.identifier){
+ if(this._attributeIndexes[this.identifier] === undefined){
+ throw new Error(this.declaredClass + ": Identity specified is not a column header in the data set.");
+ }
+ }
+
+ for(var i=0; i<this._dataArray.length; i++){
+ var id = i;
+ //Associate the identifier to a row in this case
+ //for o(1) lookup.
+ if(this.identifier){
+ var iData = this._dataArray[i];
+ id = iData[this._attributeIndexes[this.identifier]];
+ this._idMap[id] = i;
+ }
+ this._arrayOfAllItems.push(this._createItemFromIdentity(id));
+ }
+ this._loadFinished = true;
+ this._loadInProgress = false;
+ },
+
+ _createItemFromIdentity: function(/* String */ identity){
+ // summary:
+ // Function for creating a new item from its identifier.
+ // identity: String
+ // The identity
+ // tags:
+ // private
+ 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()
+ // tags:
+ // public
+ if(this.isItem(item)){
+ return item[this._idProp]; //String
+ }
+ return null; //null
+ },
+
+ fetchItemByIdentity: function(/* Object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+ // tags:
+ // public
+ var item;
+ var scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
+ //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 = xhr.get(getArgs);
+ getHandler.addCallback(function(data){
+ 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){
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+ }
+ }else if(this._csvData){
+ try{
+ self._processData(self._csvData);
+ self._csvData = null;
+ item = self._createItemFromIdentity(keywordArgs.identity);
+ if(!self.isItem(item)){
+ item = null;
+ }
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ }catch(e){
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, e);
+ }
+ }
+ }
+ }else{
+ //Already loaded. We can just look it up and call back.
+ item = this._createItemFromIdentity(keywordArgs.identity);
+ if(!this.isItem(item)){
+ item = null;
+ }
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentifierAttributes()
+ // tags:
+ // public
+
+ //Identity isn't a public attribute in the item, it's the row position index.
+ //So, return null.
+ if(this.identifier){
+ return [this.identifier];
+ }else{
+ return null;
+ }
+ },
+
+ _handleQueuedFetches: function(){
+ // summary:
+ // Internal function to execute delayed request in the store.
+ // tags:
+ // private
+
+ //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.
+lang.extend(CsvStore, simpleFetch);
+
+return CsvStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/FileStore.js b/js/dojo-1.7.2/dojox/data/FileStore.js
new file mode 100644
index 0000000..c3b6568
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/FileStore.js
@@ -0,0 +1,431 @@
+//>>built
+define("dojox/data/FileStore", ["dojo/_base/declare", "dojo/_base/lang", "dojo/_base/window", "dojo/_base/json", "dojo/_base/xhr"],
+ function(declare, lang, winUtil, jsonUtil, xhr) {
+
+return declare("dojox.data.FileStore", null, {
+ constructor: function(/*Object*/args){
+ // summary:
+ // A simple store that provides a datastore interface to a filesystem.
+ // description:
+ // A simple store that provides a datastore interface to a filesystem. It takes a few parameters
+ // for initialization:
+ // url: The URL of the service which provides the file store serverside implementation.
+ // label: The attribute of the file to use as the huma-readable text. Default is 'name'.
+ // The purpose of this store is to represent a file as a datastore item. The
+ // datastore item by default has the following attributes that can be examined on it.
+ // directory: Boolean indicating if the file item represents a directory.
+ // name: The filename with no path informatiom.
+ // path: The file complete file path including name, relative to the location the
+ // file service scans from
+ // size: The size of the file, in bytes.
+ // parentDir: The parent directory path.
+ // children: Any child files contained by a directory file item.
+ //
+ // Note that the store's server call pattern is RESTlike.
+ //
+ // The store also supports the passing of configurable options to the back end service, such as
+ // expanding all child files (no lazy load), displaying hidden files, displaying only directories, and so on.
+ // These are defined through a comma-separated list in declarative, or through setting the options array in programmatic.
+ // example: options="expand,dirsOnly,showHiddenFiles"
+ if(args && args.label){
+ this.label = args.label;
+ }
+ if(args && args.url){
+ this.url = args.url;
+ }
+ if(args && args.options){
+ if(lang.isArray(args.options)){
+ this.options = args.options;
+ }else{
+ if(lang.isString(args.options)){
+ this.options = args.options.split(",");
+ }
+ }
+ }
+ if(args && args.pathAsQueryParam){
+ this.pathAsQueryParam = true;
+ }
+ if(args && "urlPreventCache" in args){
+ this.urlPreventCache = args.urlPreventCache?true:false;
+ }
+ },
+
+ // url: [public] string
+ // The URL to the file path service.
+ url: "",
+
+ // _storeRef: [private] string
+ // Internal variable used to denote an item came from this store instance.
+ _storeRef: "_S",
+
+ // label: [public] string
+ // Default attribute to use to represent the item as a user-readable
+ // string. Public, so users can change it.
+ label: "name",
+
+ // _identifier: [private] string
+ // Default attribute to use to represent the item's identifier.
+ // Path should always be unique in the store instance.
+ _identifier: "path",
+
+ // _attributes: [private] string
+ // Internal variable of attributes all file items should have.
+ _attributes: ["children", "directory", "name", "path", "modified", "size", "parentDir"], //
+
+ // pathSeparator: [public] string
+ // The path separator to use when chaining requests for children
+ // Can be overriden by the server on initial load
+ pathSeparator: "/",
+
+ // options: [public] array
+ // Array of options to always send when doing requests.
+ // Back end service controls this, like 'dirsOnly', 'showHiddenFiles', 'expandChildren', etc.
+ options: [],
+
+ // failOk: [public] boolean
+ // Flag to pass on to xhr functions to check if we are OK to fail the call silently
+ failOk: false,
+
+ // urlPreventCache: [public] string
+ // Flag to dennote if preventCache should be passed to xhrGet.
+ urlPreventCache: true,
+
+ _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.FileStore: 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.FileStore: a function was passed an attribute argument that was not an attribute name string");
+ }
+ },
+
+ pathAsQueryParam: false, //Function to switch between REST style URL lookups and passing the path to specific items as a query param: 'path'.
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true, 'dojo.data.api.Identity':true
+ };
+ },
+
+ getValue: function(item, attribute, defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ if(values && values.length > 0){
+ return values[0];
+ }
+ return defaultValue;
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ return this._attributes;
+ },
+
+ hasAttribute: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ return (attribute in item);
+ },
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ return this.getValue(item, this._identifier);
+ },
+
+ getIdentityAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return [this._identifier];
+ },
+
+
+ isItemLoaded: function(item){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ var loaded = this.isItem(item);
+ if(loaded && typeof item._loaded == "boolean" && !item._loaded){
+ loaded = false;
+ }
+ return loaded;
+ },
+
+ loadItem: function(keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ var item = keywordArgs.item;
+ var self = this;
+ var scope = keywordArgs.scope || winUtil.global;
+
+ var content = {};
+
+ if(this.options.length > 0){
+ content.options = jsonUtil.toJson(this.options);
+ }
+
+ if(this.pathAsQueryParam){
+ content.path = item.parentPath + this.pathSeparator + item.name;
+ }
+ var xhrData = {
+ url: this.pathAsQueryParam? this.url : this.url + "/" + item.parentPath + "/" + item.name,
+ handleAs: "json-comment-optional",
+ content: content,
+ preventCache: this.urlPreventCache,
+ failOk: this.failOk
+ };
+
+ var deferred = xhr.get(xhrData);
+ deferred.addErrback(function(error){
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+
+ deferred.addCallback(function(data){
+ delete item.parentPath;
+ delete item._loaded;
+ lang.mixin(item, data);
+ self._processItem(item);
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ });
+ },
+
+ 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);
+
+ var value = item[attribute];
+ if(typeof value !== "undefined" && !lang.isArray(value)){
+ value = [value];
+ }else if(typeof value === "undefined"){
+ value = [];
+ }
+ return value;
+ },
+
+ 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()
+ },
+
+ fetch: function(request){
+ // summary:
+ // Fetch items that match to a query
+ // request:
+ // A request object
+
+ request = request || {};
+ if(!request.store){
+ request.store = this;
+ }
+ var self = this;
+ var scope = request.scope || winUtil.global;
+
+ //Generate what will be sent over.
+ var reqParams = {};
+ if(request.query){
+ reqParams.query = jsonUtil.toJson(request.query);
+ }
+
+ if(request.sort){
+ reqParams.sort = jsonUtil.toJson(request.sort);
+ }
+
+ if(request.queryOptions){
+ reqParams.queryOptions = jsonUtil.toJson(request.queryOptions);
+ }
+
+ if(typeof request.start == "number"){
+ reqParams.start = "" + request.start;
+ }
+ if(typeof request.count == "number"){
+ reqParams.count = "" + request.count;
+ }
+
+ if(this.options.length > 0){
+ reqParams.options = jsonUtil.toJson(this.options);
+ }
+
+ var getArgs = {
+ url: this.url,
+ preventCache: this.urlPreventCache,
+ failOk: this.failOk,
+ handleAs: "json-comment-optional",
+ content: reqParams
+ };
+
+
+ var deferred = xhr.get(getArgs);
+
+ deferred.addCallback(function(data){self._processResult(data, request);});
+ deferred.addErrback(function(error){
+ if(request.onError){
+ request.onError.call(scope, error, request);
+ }
+ });
+ },
+
+ fetchItemByIdentity: function(keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ var path = keywordArgs.identity;
+ var self = this;
+ var scope = keywordArgs.scope || winUtil.global;
+
+ var content = {};
+
+ if(this.options.length > 0){
+ content.options = jsonUtil.toJson(this.options);
+ }
+
+ if(this.pathAsQueryParam){
+ content.path = path;
+ }
+ var xhrData = {
+ url: this.pathAsQueryParam? this.url : this.url + "/" + path,
+ handleAs: "json-comment-optional",
+ content: content,
+ preventCache: this.urlPreventCache,
+ failOk: this.failOk
+ };
+
+ var deferred = xhr.get(xhrData);
+ deferred.addErrback(function(error){
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+
+ deferred.addCallback(function(data){
+ var item = self._processItem(data);
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ });
+ },
+
+ _processResult: function(data, request){
+ var scope = request.scope || winUtil.global;
+ try{
+ //If the data contains a path separator, set ours
+ if(data.pathSeparator){
+ this.pathSeparator = data.pathSeparator;
+ }
+ //Invoke the onBegin handler, if any, to return the
+ //size of the dataset as indicated by the service.
+ if(request.onBegin){
+ request.onBegin.call(scope, data.total, request);
+ }
+ //Now process all the returned items thro
+ var items = this._processItemArray(data.items);
+ if(request.onItem){
+ var i;
+ for(i = 0; i < items.length; i++){
+ request.onItem.call(scope, items[i], request);
+ }
+ items = null;
+ }
+ if(request.onComplete){
+ request.onComplete.call(scope, items, request);
+ }
+ }catch (e){
+ if(request.onError){
+ request.onError.call(scope, e, request);
+ }else{
+ console.log(e);
+ }
+ }
+ },
+
+ _processItemArray: function(itemArray){
+ // summary:
+ // Internal function for processing an array of items for return.
+ var i;
+ for(i = 0; i < itemArray.length; i++){
+ this._processItem(itemArray[i]);
+ }
+ return itemArray;
+ },
+
+ _processItem: function(item){
+ // summary:
+ // Internal function for processing an item returned from the store.
+ // It sets up the store ref as well as sets up the attributes necessary
+ // to invoke a lazy load on a child, if there are any.
+ if(!item){return null;}
+ item[this._storeRef] = this;
+ if(item.children && item.directory){
+ if(lang.isArray(item.children)){
+ var children = item.children;
+ var i;
+ for(i = 0; i < children.length; i++ ){
+ var name = children[i];
+ if(lang.isObject(name)){
+ children[i] = this._processItem(name);
+ }else{
+ children[i] = {name: name, _loaded: false, parentPath: item.path};
+ children[i][this._storeRef] = this;
+ }
+ }
+ }else{
+ delete item.children;
+ }
+ }
+ return item;
+ }
+});
+});
diff --git a/js/dojo-1.7.2/dojox/data/FlickrRestStore.js b/js/dojo-1.7.2/dojox/data/FlickrRestStore.js
new file mode 100644
index 0000000..3d96b41
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/FlickrRestStore.js
@@ -0,0 +1,486 @@
+//>>built
+define("dojox/data/FlickrRestStore", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "dojo/io/script", "dojox/data/FlickrStore", "dojo/_base/connect"],
+ function(lang, declare, array, scriptIO, FlickrStore, connect) {
+
+/*===== var FlickrStore = dojox.data.FlickrStore; =====*/
+
+var FlickrRestStore = declare("dojox.data.FlickrRestStore",
+ 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){
+ 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 = 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( /*Object*/ request,
+ /*Function*/ fetchHandler,
+ /*Function*/ 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 {
+ lang.mixin(query, request.query);
+ }
+
+ var primaryKey = [];
+ var secondaryKey = [];
+
+ //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"
+ };
+ var isRest = false;
+ if(query.userid){
+ isRest = true;
+ content.user_id = request.query.userid;
+ primaryKey.push("userid"+request.query.userid);
+ }
+
+ if(query.groupid){
+ isRest = true;
+ content.group_id = query.groupid;
+ primaryKey.push("groupid" + query.groupid);
+ }
+
+ if(query.apikey){
+ isRest = true;
+ content.api_key = request.query.apikey;
+ secondaryKey.push("api"+request.query.apikey);
+ }else if(content.api_key){
+ isRest = true;
+ request.query.apikey = content.api_key;
+ secondaryKey.push("api"+content.api_key);
+ }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(("start" in request) && 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);
+ }
+
+ if(query.setid){
+ content.method = "flickr.photosets.getPhotos";
+ content.photoset_id = request.query.setid;
+ primaryKey.push("set" + request.query.setid);
+ }
+
+ 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 handle = null;
+ var getArgs = {
+ url: this._flickrRestUrl,
+ preventCache: this.urlPreventCache,
+ content: content,
+ callbackParamName: "jsoncallback"
+ };
+
+ var doHandle = lang.hitch(this, function(processedData, data, handler){
+ var onBegin = handler.request.onBegin;
+ handler.request.onBegin = null;
+ var maxPhotos;
+ var req = handler.request;
+
+ if(("_realStart" in req) && 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){
+ var photos = null;
+ if(data){
+ photos = (data.photoset ? data.photoset : data.photos);
+ }
+ if(photos && ("perpage" in photos) && ("pages" in photos)){
+ if(photos.perpage * 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 + 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 = photos.perpage * photos.pages;
+ }
+ this._maxPhotosPerUser[primaryKey] = maxPhotos;
+ onBegin(maxPhotos, handler.request);
+ }else if(this._maxPhotosPerUser[primaryKey]){
+ onBegin(this._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 = lang.hitch(this, 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 = this._handlers[requestKey];
+ if(!handlers){
+ console.log("FlickrRestStore: no handlers for data", data);
+ return;
+ }
+
+ this._handlers[requestKey] = null;
+ this._prevRequests[requestKey] = data;
+
+ //Process the data once.
+ var processedData = this._processFlickrData(data, request, primaryKey);
+ if(!this._prevRequestRanges[primaryKey]){
+ this._prevRequestRanges[primaryKey] = [];
+ }
+ this._prevRequestRanges[primaryKey].push({
+ start: request.start,
+ end: request.start + (data.photoset ? data.photoset.photo.length : data.photos.photo.length)
+ });
+
+ //Iterate through the array of handlers, calling each one.
+ array.forEach(handlers, function(i){
+ doHandle(processedData, data, 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;
+ }
+
+ var deferred = scriptIO.get(getArgs);
+ deferred.addCallback(myHandler);
+
+ //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){
+ connect.disconnect(handle);
+ errorHandler(error, request);
+ });
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ return [
+ "title", "author", "imageUrl", "imageUrlSmall", "imageUrlMedium",
+ "imageUrlThumb", "imageUrlLarge", "imageUrlOriginal", "link", "dateTaken", "datePublished"
+ ];
+ },
+
+ getValues: function(item, attribute){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+
+ switch(attribute){
+ case "title":
+ return [ this._unescapeHtml(item.title) ]; // String
+ case "author":
+ return [ item.ownername ]; // String
+ case "imageUrlSmall":
+ return [ item.media.s ]; // String
+ case "imageUrl":
+ return [ item.media.l ]; // String
+ case "imageUrlOriginal":
+ return [ item.media.o ]; // String
+ case "imageUrlLarge":
+ return [ item.media.l ]; // String
+ case "imageUrlMedium":
+ return [ item.media.m ]; // String
+ case "imageUrlThumb":
+ return [ item.media.t ]; // String
+ case "link":
+ return [ "http://www.flickr.com/photos/" + item.owner + "/" + item.id ]; // String
+ case "dateTaken":
+ return [ item.datetaken ];
+ case "datePublished":
+ return [ item.datepublished ];
+ default:
+ 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 FlickrStore.prototype._processFlickrData.apply(this,arguments);
+ }
+ var template = ["http://farm", null, ".static.flickr.com/", null, "/", null, "_", null];
+
+ var items = [];
+ var photos = (data.photoset ? data.photoset : data.photos);
+ if(data.stat == "ok" && photos && photos.photo){
+ items = 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",
+ o: base + "_o.jpg"
+ };
+ if(!item.owner && data.photoset){
+ item.owner = data.photoset.owner;
+ }
+ }
+ }
+ var start = request.start ? request.start : 0;
+ var arr = this._cache[cacheKey];
+ if(!arr){
+ this._cache[cacheKey] = arr = [];
+ }
+ array.forEach(items, function(i, idx){
+ arr[idx+ start] = i;
+ });
+
+ return arr; // Array
+ },
+
+ _checkPrevRanges: function(primaryKey, start, count){
+ var end = start + count;
+ var arr = this._prevRequestRanges[primaryKey];
+ return (!!arr) && array.some(arr, function(item){
+ return ((start >= item.start)&&(end <= item.end));
+ });
+ }
+});
+return FlickrRestStore;
+});
+
diff --git a/js/dojo-1.7.2/dojox/data/FlickrStore.js b/js/dojo-1.7.2/dojox/data/FlickrStore.js
new file mode 100644
index 0000000..e020956
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/FlickrStore.js
@@ -0,0 +1,285 @@
+//>>built
+define("dojox/data/FlickrStore", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "dojo/data/util/simpleFetch", "dojo/io/script",
+ "dojo/_base/connect", "dojo/date/stamp", "dojo/AdapterRegistry"],
+ function(lang, declare, array, simpleFetch, scriptIO, connect, dateStamp, AdapterRegistry) {
+
+var FlickrStore = 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;
+ }
+ if(args && "urlPreventCache" in args){
+ this.urlPreventCache = args.urlPreventCache?true:false;
+ }
+ },
+
+ _storeRef: "_S",
+
+ label: "title",
+
+ //Flag to allor control of if cache prevention is enabled or not.
+ urlPreventCache: true,
+
+ _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, defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ if(values && values.length > 0){
+ return values[0];
+ }
+ return defaultValue;
+ },
+
+ 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()
+ var v = this.getValue(item,attribute);
+ if(v || v === "" || v === false){
+ 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);
+ var u = lang.hitch(this, "_unescapeHtml");
+ var s = lang.hitch(dateStamp, "fromISOString");
+ switch(attribute){
+ case "title":
+ return [ u(item.title) ];
+ case "author":
+ return [ u(item.author) ];
+ case "datePublished":
+ return [ s(item.published) ];
+ case "dateTaken":
+ return [ s(item.date_taken) ];
+ case "imageUrlSmall":
+ return [ item.media.m.replace(/_m\./, "_s.") ];
+ case "imageUrl":
+ return [ item.media.m.replace(/_m\./, ".") ];
+ case "imageUrlMedium":
+ return [ item.media.m ];
+ case "link":
+ return [ item.link ];
+ case "tags":
+ return item.tags.split(" ");
+ case "description":
+ return [ u(item.description) ];
+ default:
+ return [];
+ }
+ },
+
+ 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
+
+ var rq = request.query = request.query || {};
+
+ //Build up the content to send the request for.
+ var content = {
+ format: "json",
+ tagmode:"any"
+ };
+
+ array.forEach(
+ [ "tags", "tagmode", "lang", "id", "ids" ],
+ function(i){
+ if(rq[i]){ content[i] = rq[i]; }
+ }
+ );
+
+ content.id = rq.id || rq.userid || rq.groupid;
+
+ if(rq.userids){
+ content.ids = rq.userids;
+ }
+
+ //Linking this up to Flickr is a PAIN!
+ var handle = null;
+ var getArgs = {
+ url: dojox.data.FlickrStore.urlRegistry.match(request),
+ preventCache: this.urlPreventCache,
+ content: content
+ };
+ var myHandler = lang.hitch(this, function(data){
+ if(!!handle){
+ connect.disconnect(handle);
+ }
+
+ //Process the items...
+ fetchHandler(this._processFlickrData(data), request);
+ });
+ handle = connect.connect("jsonFlickrFeed", myHandler);
+ var deferred = scriptIO.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){
+ connect.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(/*String*/ str){
+ // summary:
+ // 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
+ return str.replace(/&amp;/gm, "&").
+ replace(/&lt;/gm, "<").
+ replace(/&gt;/gm, ">").
+ replace(/&quot;/gm, "\"").
+ replace(/&#39;/gm, "'");
+ }
+});
+
+lang.extend(FlickrStore, simpleFetch);
+
+var feedsUrl = "http://api.flickr.com/services/feeds/";
+
+var reg = FlickrStore.urlRegistry = new AdapterRegistry(true);
+
+reg.register("group pool",
+ function(request){ return !!request.query["groupid"]; },
+ feedsUrl+"groups_pool.gne"
+);
+
+reg.register("default",
+ function(request){ return true; },
+ feedsUrl+"photos_public.gne"
+);
+
+//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){};
+}
+
+return FlickrStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/GoogleFeedStore.js b/js/dojo-1.7.2/dojox/data/GoogleFeedStore.js
new file mode 100644
index 0000000..2b5c320
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/GoogleFeedStore.js
@@ -0,0 +1,81 @@
+//>>built
+define("dojox/data/GoogleFeedStore", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojox/data/GoogleSearchStore"],
+ function(dojo, lang, declare, GoogleSearchStore) {
+
+dojo.experimental("dojox.data.GoogleFeedStore");
+
+/*===== var Search = dojox.data.GoogleSearchStore =====*/
+var Search = GoogleSearchStore.Search;
+
+return declare("dojox.data.GoogleFeedStore", Search,{
+ // summary:
+ // A data store for retrieving RSS and Atom feeds from Google. The
+ // feeds can come from any source, which is specified in the "url"
+ // parameter of the query passed to the "fetch" function.
+ // The following attributes are supported on each item:
+ // <ul>
+ // <li>title - The feed entry title.</li>
+ // <li>link - The URL for the HTML version of the feed entry.</li>
+ // <li>content - The full content of the blog post, in HTML format</li>
+ // <li>summary - A snippet of information about the feed entry, in plain text</li>
+ // <li>published - The string date on which the entry was published.
+ // You can parse the date with new Date(store.getValue(item, "published")</li>
+ // <li>categories - An array of string tags for the entry</li>
+ // </ul>
+ // The query accepts one parameter: url - The URL of the feed to retrieve
+ _type: "",
+ _googleUrl: "http://ajax.googleapis.com/ajax/services/feed/load",
+ _attributes: ["title", "link", "author", "published",
+ "content", "summary", "categories"],
+ _queryAttrs: {
+ "url":"q"
+ },
+
+ 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(lang.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._feedMetaData){
+ return defaultValue;
+ }
+ return this._feedMetaData[attribute] || defaultValue;
+ },
+
+ _processItem: function(item, request) {
+ this.inherited(arguments);
+ item["summary"] = item["contentSnippet"];
+ item["published"] = item["publishedDate"];
+ },
+
+ _getItems: function(data){
+ if(data['feed']){
+ this._feedMetaData = {
+ title: data.feed.title,
+ desc: data.feed.description,
+ url: data.feed.link,
+ author: data.feed.author
+ };
+ return data.feed.entries;
+ }
+ return null;
+ },
+
+ _createContent: function(query, callback, request){
+ var cb = this.inherited(arguments);
+ cb.num = (request.count || 10) + (request.start || 0);
+ return cb;
+ }
+});
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/GoogleSearchStore.js b/js/dojo-1.7.2/dojox/data/GoogleSearchStore.js
new file mode 100644
index 0000000..b6f1674
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/GoogleSearchStore.js
@@ -0,0 +1,657 @@
+//>>built
+define("dojox/data/GoogleSearchStore", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/window", "dojo/_base/query",
+ "dojo/dom-construct","dojo/io/script"],
+ function(dojo, lang, declare, winUtil, domQuery, domConstruct, scriptIO) {
+
+dojo.experimental("dojox.data.GoogleSearchStore");
+
+var SearchStore = declare("dojox.data.GoogleSearchStore",null,{
+ // summary:
+ // A data store for retrieving search results from Google.
+ // This data store acts as a base class for Google searches,
+ // and has a number of child data stores that implement different
+ // searches. This store defaults to searching the web, and is functionally
+ // identical to the dojox.data.GoogleWebSearchStore object.
+ // The following attributes are supported on each item:
+ // <ul>
+ // <li>url - The URL for the item</li>
+ // <li>unescapedUrl - The URL for the item, with URL escaping. This is often more readable</li>
+ // <li>visibleUrl - The URL with no protocol specified.
+ // <li>cacheUrl - The URL to the copy of the document cached by Google
+ // <li>title - The page title in HTML format.</li>
+ // <li>titleNoFormatting - The page title in plain text</li>
+ // <li>content - A snippet of information about the page</li>
+ // </ul>
+ // The query accepts one parameter: text - The string to search for
+ constructor: function(/*Object*/args){
+ // summary:
+ // Initializer for the GoogleSearchStore store.
+ // description:
+ // The GoogleSearchStore is a Datastore interface to
+ // the Google search service. The constructor accepts the following arguments:
+ // <ul>
+ // <li>label - the label attribute to use. Defaults to titleNoFormatting</li>
+ // <li>key - The API key to use. This is optional</li>
+ // <li>lang - The language locale to use. Defaults to the browser locale</li>
+ // </ul>
+
+ if(args){
+ if(args.label){
+ this.label = args.label;
+ }
+ if(args.key){
+ this._key = args.key;
+ }
+ if(args.lang){
+ this._lang = args.lang;
+ }
+ if("urlPreventCache" in args){
+ this.urlPreventCache = args.urlPreventCache?true:false;
+ }
+ }
+ this._id = dojox.data.GoogleSearchStore.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 GoogleSearchStore will use.
+ _requestCount: 0,
+
+ // _googleUrl: String
+ // The URL to Googles search web service.
+ _googleUrl: "http://ajax.googleapis.com/ajax/services/search/",
+
+ // _storeRef: String
+ // The internal reference added to each item pointing at the store which owns it.
+ _storeRef: "_S",
+
+ // _attributes: Array
+ // The list of attributes that this store supports
+ _attributes: [ "unescapedUrl", "url", "visibleUrl", "cacheUrl", "title",
+ "titleNoFormatting", "content", "estimatedResultCount"],
+
+ // _aggregtedAttributes: Hash
+ // Maps per-query aggregated attributes that this store supports to the result keys that they come from.
+ _aggregatedAttributes: {
+ estimatedResultCount: "cursor.estimatedResultCount"
+ },
+
+ // label: String
+ // The default attribute which acts as a label for each item.
+ label: "titleNoFormatting",
+
+ // type: String
+ // The type of search. Valid values are "web", "local", "video", "blogs", "news", "books", "images".
+ // This should not be set directly. Instead use one of the child classes.
+ _type: "web",
+
+ // urlPreventCache: boolean
+ // Sets whether or not to pass preventCache to dojo.io.script.
+ urlPreventCache: true,
+
+
+ // _queryAttrs: Hash
+ // Maps query hash keys to Google query parameters.
+ _queryAttrs: {
+ text: 'q'
+ },
+
+ _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.GoogleSearchStore: 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.GoogleSearchStore: 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, defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ if(values && values.length > 0){
+ return values[0];
+ }
+ return defaultValue;
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ return this._attributes;
+ },
+
+ 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);
+ var val = item[attribute];
+ if(lang.isArray(val)) {
+ return val;
+ }else if(val !== undefined){
+ return [val];
+ }else{
+ return [];
+ }
+ },
+
+ 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()
+ },
+
+ _format: function(item, name){
+ return item;//base implementation does not format any items
+ },
+
+ fetch: function(request){
+ // summary:
+ // Fetch Google search 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
+ request = request || {};
+
+ var scope = request.scope || winUtil.global;
+
+ if(!request.query){
+ if(request.onError){
+ request.onError.call(scope, new Error(this.declaredClass +
+ ": A query must be specified."));
+ return;
+ }
+ }
+ //Make a copy of the request object, in case it is
+ //modified outside the store in the middle of a request
+ var query = {};
+ for(var attr in this._queryAttrs) {
+ query[attr] = request.query[attr];
+ }
+ request = {
+ query: query,
+ onComplete: request.onComplete,
+ onError: request.onError,
+ onItem: request.onItem,
+ onBegin: request.onBegin,
+ start: request.start,
+ count: request.count
+ };
+
+ //Google's web api will only return a max of 8 results per page.
+ var pageSize = 8;
+
+ //Generate a unique function to be called back
+ var callbackFn = "GoogleSearchStoreCallback_" + this._id + "_" + (++this._requestCount);
+
+ //Build up the content to send the request for.
+ //rsz is the result size, "large" gives 8 results each time
+ var content = this._createContent(query, callbackFn, request);
+
+ var firstRequest;
+
+ if(typeof(request.start) === "undefined" || request.start === null){
+ request.start = 0;
+ }
+
+ if(!request.count){
+ request.count = pageSize;
+ }
+ firstRequest = {start: request.start - request.start % pageSize};
+
+ var _this = this;
+ var searchUrl = this._googleUrl + this._type;
+
+ var getArgs = {
+ url: searchUrl,
+ preventCache: this.urlPreventCache,
+ content: content
+ };
+
+ var items = [];
+ var successfulReq = 0;
+ var finished = false;
+ var lastOnItem = request.start -1;
+ var numRequests = 0;
+ var scriptIds = [];
+
+ // Performs the remote request.
+ function doRequest(req){
+ //Record how many requests have been made.
+ numRequests ++;
+ getArgs.content.context = getArgs.content.start = req.start;
+
+ var deferred = scriptIO.get(getArgs);
+ scriptIds.push(deferred.ioArgs.id);
+
+ //We only set up the errback, because the callback isn't ever really used because we have
+ //to link to the jsonp callback function....
+ deferred.addErrback(function(error){
+ if(request.onError){
+ request.onError.call(scope, error, request);
+ }
+ });
+ }
+
+ // Function to handle returned data.
+ var myHandler = function(start, data){
+ if (scriptIds.length > 0) {
+ // Delete the script node that was created.
+ domQuery("#" + scriptIds.splice(0,1)).forEach(domConstruct.destroy);
+ }
+ if(finished){return;}
+
+ var results = _this._getItems(data);
+ var cursor = data ? data['cursor']: null;
+
+ if(results){
+ //Process the results, adding the store reference to them
+ for(var i = 0; i < results.length && i + start < request.count + request.start; i++) {
+ _this._processItem(results[i], data);
+ items[i + start] = results[i];
+ }
+ successfulReq ++;
+ if(successfulReq == 1){
+ // After the first request, we know how many results exist.
+ // So perform any follow up requests to retrieve more data.
+ var pages = cursor ? cursor.pages : null;
+ var firstStart = pages ? Number(pages[pages.length - 1].start) : 0;
+
+ //Call the onBegin method if it exists
+ if (request.onBegin){
+ var est = cursor ? cursor.estimatedResultCount : results.length;
+ var total = est ? Math.min(est, firstStart + results.length) : firstStart + results.length;
+ request.onBegin.call(scope, total, request);
+ }
+
+ // Request the next pages.
+ var nextPage = (request.start - request.start % pageSize) + pageSize;
+ var page = 1;
+ while(pages){
+ if(!pages[page] || Number(pages[page].start) >= request.start + request.count){
+ break;
+ }
+ if(Number(pages[page].start) >= nextPage) {
+ doRequest({start: pages[page].start});
+ }
+ page++;
+ }
+ }
+
+ // Call the onItem function on all retrieved items.
+ if(request.onItem && items[lastOnItem + 1]){
+ do{
+ lastOnItem++;
+ request.onItem.call(scope, items[lastOnItem], request);
+ }while(items[lastOnItem + 1] && lastOnItem < request.start + request.count);
+ }
+
+ //If this is the last request, call final fetch handler.
+ if(successfulReq == numRequests){
+ //Process the items...
+ finished = true;
+ //Clean up the function, it should never be called again
+ winUtil.global[callbackFn] = null;
+ if(request.onItem){
+ request.onComplete.call(scope, null, request);
+ }else{
+ items = items.slice(request.start, request.start + request.count);
+ request.onComplete.call(scope, items, request);
+ }
+
+ }
+ }
+ };
+
+ var callbacks = [];
+ var lastCallback = firstRequest.start - 1;
+
+ // Attach a callback function to the global namespace, where Google can call it.
+ winUtil.global[callbackFn] = function(start, data, responseCode, errorMsg){
+ try {
+ if(responseCode != 200){
+ if(request.onError){
+ request.onError.call(scope, new Error("Response from Google was: " + responseCode), request);
+ }
+ winUtil.global[callbackFn] = function(){};//an error occurred, do not return anything else.
+ return;
+ }
+
+ if(start == lastCallback + 1){
+ myHandler(Number(start), data);
+ lastCallback += pageSize;
+
+ //make sure that the callbacks happen in the correct sequence
+ if(callbacks.length > 0){
+ callbacks.sort(_this._getSort());
+ //In case the requsts do not come back in order, sort the returned results.
+ while(callbacks.length > 0 && callbacks[0].start == lastCallback + 1){
+ myHandler(Number(callbacks[0].start), callbacks[0].data);
+ callbacks.splice(0,1);
+ lastCallback += pageSize;
+ }
+ }
+ }else{
+ callbacks.push({start:start, data: data});
+ }
+ } catch (e) {
+ request.onError.call(scope, e, request);
+ }
+ };
+
+ // Perform the first request. When this has finished
+ // we will have a list of pages, which can then be
+ // gone through
+ doRequest(firstRequest);
+ },
+
+ _getSort: function() {
+ return function(a,b){
+ if(a.start < b.start){return -1;}
+ if(b.start < a.start){return 1;}
+ return 0;
+ };
+ },
+
+ _processItem: function(item, data) {
+ item[this._storeRef] = this;
+ // Copy aggregated attributes from query results to the item.
+ for(var attribute in this._aggregatedAttributes) {
+ item[attribute] = lang.getObject(this._aggregatedAttributes[attribute], false, data);
+ }
+ },
+
+ _getItems: function(data){
+ return data['results'] || data;
+ },
+
+ _createContent: function(query, callback, request){
+ var content = {
+ v: "1.0",
+ rsz: "large",
+ callback: callback,
+ key: this._key,
+ hl: this._lang
+ };
+ for(var attr in this._queryAttrs) {
+ content[this._queryAttrs[attr]] = query[attr];
+ }
+ return content;
+ }
+});
+
+var WebSearchStore = declare("dojox.data.GoogleWebSearchStore", SearchStore,{
+ // Summary:
+ // A data store for retrieving search results from Google.
+ // The following attributes are supported on each item:
+ // <ul>
+ // <li>title - The page title in HTML format.</li>
+ // <li>titleNoFormatting - The page title in plain text</li>
+ // <li>content - A snippet of information about the page</li>
+ // <li>url - The URL for the item</li>
+ // <li>unescapedUrl - The URL for the item, with URL escaping. This is often more readable</li>
+ // <li>visibleUrl - The URL with no protocol specified.</li>
+ // <li>cacheUrl - The URL to the copy of the document cached by Google</li>
+ // <li>estimatedResultCount - (aggregated per-query) estimated number of results</li>
+ // </ul>
+ // The query accepts one parameter: text - The string to search for
+});
+
+var BlogSearchStore = declare("dojox.data.GoogleBlogSearchStore", SearchStore,{
+ // Summary:
+ // A data store for retrieving search results from Google.
+ // The following attributes are supported on each item:
+ // <ul>
+ // <li>title - The blog post title in HTML format.</li>
+ // <li>titleNoFormatting - The blog post title in plain text</li>
+ // <li>content - A snippet of information about the blog post</li>
+ // <li>blogUrl - The URL for the blog</li>
+ // <li>postUrl - The URL for the a single blog post</li>
+ // <li>visibleUrl - The URL with no protocol specified.
+ // <li>cacheUrl - The URL to the copy of the document cached by Google
+ // <li>author - The author of the blog post</li>
+ // <li>publishedDate - The published date, in RFC-822 format</li>
+ // </ul>
+ // The query accepts one parameter: text - The string to search for
+ _type: "blogs",
+ _attributes: ["blogUrl", "postUrl", "title", "titleNoFormatting", "content",
+ "author", "publishedDate"],
+ _aggregatedAttributes: { }
+});
+
+
+var LocalSearchStore = declare("dojox.data.GoogleLocalSearchStore", SearchStore,{
+ // summary:
+ // A data store for retrieving search results from Google.
+ // The following attributes are supported on each item:
+ // <ul>
+ // <li>title - The blog post title in HTML format.</li>
+ // <li>titleNoFormatting - The blog post title in plain text</li>
+ // <li>content - A snippet of information about the blog post</li>
+ // <li>url - The URL for the item</li>
+ // <li>lat - The latitude.</li>
+ // <li>lng - The longtitude.</li>
+ // <li>streetAddress - The street address</li>
+ // <li>city - The city</li>
+ // <li>region - The region</li>
+ // <li>country - The country</li>
+ // <li>phoneNumbers - Phone numbers associated with this address. Can be one or more.</li>
+ // <li>ddUrl - A URL that can be used to provide driving directions from the center of the search results to this search results</li>
+ // <li>ddUrlToHere - A URL that can be used to provide driving directions from this search result to a user specified location</li>
+ // <li>staticMapUrl - The published date, in RFC-822 format</li>
+ // <li>viewport - Recommended viewport for the query results (same for all results in a query)
+ // <ul>
+ // <li>center - contains lat, lng properties</li>
+ // <li>span - lat, lng properties for the viewport span</li>
+ // <li>ne, sw - lat, lng properties for the viewport corners<li>
+ // </ul>
+ // </li>
+ // </ul>
+ // The query accepts the following parameters:
+ // <ul>
+ // <li>text - The string to search for</li>
+ // <li>centerLatLong - Comma-separated lat & long for the center of the search (e.g. "48.8565,2.3509")</li>
+ // <li>searchSpan - Comma-separated lat & long degrees indicating the size of the desired search area (e.g. "0.065165,0.194149")</li>
+ // </ul>
+ _type: "local",
+ _attributes: ["title", "titleNoFormatting", "url", "lat", "lng", "streetAddress",
+ "city", "region", "country", "phoneNumbers", "ddUrl", "ddUrlToHere",
+ "ddUrlFromHere", "staticMapUrl", "viewport"],
+ _aggregatedAttributes: {
+ viewport: "viewport"
+ },
+ _queryAttrs: {
+ text: 'q',
+ centerLatLong: 'sll',
+ searchSpan: 'sspn'
+ }
+});
+
+var VideoSearchStore = declare("dojox.data.GoogleVideoSearchStore", SearchStore,{
+ // summary:
+ // A data store for retrieving search results from Google.
+ // The following attributes are supported on each item:
+ // <ul>
+ // <li>title - The blog post title in HTML format.</li>
+ // <li>titleNoFormatting - The blog post title in plain text</li>
+ // <li>content - A snippet of information about the blog post</li>
+ // <li>url - The URL for the item</li>
+ // <li>published - The published date, in RFC-822 format.</li>
+ // <li>publisher - The name of the publisher.</li>
+ // <li>duration - The approximate duration, in seconds, of the video.</li>
+ // <li>tbWidth - The width in pixels of the video.</li>
+ // <li>tbHeight - The height in pixels of the video</li>
+ // <li>tbUrl - The URL to a thumbnail representation of the video.</li>
+ // <li>playUrl - If present, supplies the url of the flash version of the video that can be played inline on your page. To play this video simply create and <embed> element on your page using this value as the src attribute and using application/x-shockwave-flash as the type attribute. If you want the video to play right away, make sure to append &autoPlay=true to the url..</li>
+ // </ul>
+ // The query accepts one parameter: text - The string to search for
+ _type: "video",
+ _attributes: ["title", "titleNoFormatting", "content", "url", "published", "publisher",
+ "duration", "tbWidth", "tbHeight", "tbUrl", "playUrl"],
+ _aggregatedAttributes: { }
+});
+
+var NewsSearchStore = declare("dojox.data.GoogleNewsSearchStore", SearchStore,{
+ // summary:
+ // A data store for retrieving search results from Google.
+ // The following attributes are supported on each item:
+ // <ul>
+ // <li>title - The news story title in HTML format.</li>
+ // <li>titleNoFormatting - The news story title in plain text</li>
+ // <li>content - A snippet of information about the news story</li>
+ // <li>url - The URL for the item</li>
+ // <li>unescapedUrl - The URL for the item, with URL escaping. This is often more readable</li>
+ // <li>publisher - The name of the publisher</li>
+ // <li>clusterUrl - A URL pointing to a page listing related storied.</li>
+ // <li>location - The location of the news story.</li>
+ // <li>publishedDate - The date of publication, in RFC-822 format.</li>
+ // <li>relatedStories - An optional array of objects specifying related stories.
+ // Each object has the following subset of properties:
+ // "title", "titleNoFormatting", "url", "unescapedUrl", "publisher", "location", "publishedDate".
+ // </li>
+ // </ul>
+ // The query accepts one parameter: text - The string to search for
+ _type: "news",
+ _attributes: ["title", "titleNoFormatting", "content", "url", "unescapedUrl", "publisher",
+ "clusterUrl", "location", "publishedDate", "relatedStories" ],
+ _aggregatedAttributes: { }
+});
+
+var BookSearchStore = declare("dojox.data.GoogleBookSearchStore", SearchStore,{
+ // summary:
+ // A data store for retrieving search results from Google.
+ // The following attributes are supported on each item:
+ // <ul>
+ // <li>title - The book title in HTML format.</li>
+ // <li>titleNoFormatting - The book title in plain text</li>
+ // <li>authors - An array of authors</li>
+ // <li>url - The URL for the item</li>
+ // <li>unescapedUrl - The URL for the item, with URL escaping. This is often more readable</li>
+ // <li>bookId - An identifier for the book, usually an ISBN.</li>
+ // <li>pageCount - The number of pages in the book.</li>
+ // <li>publishedYear - The year of publication.</li>
+ // </ul>
+ // The query accepts one parameter: text - The string to search for
+ _type: "books",
+ _attributes: ["title", "titleNoFormatting", "authors", "url", "unescapedUrl", "bookId",
+ "pageCount", "publishedYear"],
+ _aggregatedAttributes: { }
+});
+
+var ImageSearchStore = declare("dojox.data.GoogleImageSearchStore", SearchStore,{
+ // summary:
+ // A data store for retrieving search results from Google.
+ // The following attributes are supported on each item:
+ // <ul>
+ // <li>title - The image title in HTML format.</li>
+ // <li>titleNoFormatting - The image title in plain text</li>
+ // <li>url - The URL for the image</li>
+ // <li>unescapedUrl - The URL for the image, with URL escaping. This is often more readable</li>
+ // <li>tbUrl - The URL for the image thumbnail</li>
+ // <li>visibleUrl - A shortened version of the URL associated with the result, stripped of a protocol and path</li>
+ // <li>originalContextUrl - The URL of the page containing the image.</li>
+ // <li>width - The width of the image in pixels.</li>
+ // <li>height - The height of the image in pixels.</li>
+ // <li>tbWidth - The width of the image thumbnail in pixels.</li>
+ // <li>tbHeight - The height of the image thumbnail in pixels.</li>
+ // <li>content - A snippet of information about the image, in HTML format</li>
+ // <li>contentNoFormatting - A snippet of information about the image, in plain text</li>
+ // </ul>
+ // The query accepts one parameter: text - The string to search for
+ _type: "images",
+ _attributes: ["title", "titleNoFormatting", "visibleUrl", "url", "unescapedUrl",
+ "originalContextUrl", "width", "height", "tbWidth", "tbHeight",
+ "tbUrl", "content", "contentNoFormatting"],
+ _aggregatedAttributes: { }
+});
+
+return {
+ Search: SearchStore,
+ ImageSearch: ImageSearchStore,
+ BookSearch: BookSearchStore,
+ NewsSearch: NewsSearchStore,
+ VideoSearch: VideoSearchStore,
+ LocalSearch: LocalSearchStore,
+ BlogSearch: BlogSearchStore,
+ WebSearch: WebSearchStore
+ }
+});
diff --git a/js/dojo-1.7.2/dojox/data/HtmlStore.js b/js/dojo-1.7.2/dojox/data/HtmlStore.js
new file mode 100644
index 0000000..a5689d2
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/HtmlStore.js
@@ -0,0 +1,565 @@
+//>>built
+define("dojox/data/HtmlStore", ["dojo/_base/declare", "dojo/_base/array", "dojo/_base/lang", "dojo/dom", "dojo/_base/xhr", "dojo/_base/window",
+ "dojo/data/util/simpleFetch", "dojo/data/util/filter", "dojox/xml/parser"],
+ function(declare, array, lang, dom, xhr, winUtil, simpleFetch, filter, xmlParser) {
+
+var HtmlStore = 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 list in 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
+ // and the option:
+ // trimWhitespace: Trim off any surrounding whitespace from the headers (attribute
+ // names) and text content of the items in question. Default is false for
+ // backwards compatibility.
+ if(args && "urlPreventCache" in args){
+ this.urlPreventCache = args.urlPreventCache?true:false;
+ }
+ if(args && "trimWhitespace" in args){
+ this.trimWhitespace = args.trimWhitespace?true:false;
+ }
+ 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.dataId = args.dataId;
+ }
+ }
+ if(args && "fetchOnCreate" in args){
+ this.fetchOnCreate = args.fetchOnCreate?true:false;
+ }
+ if(this.fetchOnCreate && this.dataId){
+ this.fetch();
+ }
+ },
+
+ // url: [public] string
+ // The URL from which to load an HTML document for data loading
+ url: "",
+
+ // dataId: [public] string
+ // The id in the document for an element from which to get the data.
+ dataId: "",
+
+ // trimWhitepace: [public] boolean
+ // Boolean flag to denote if the store should trim whitepace around
+ // header and data content of a node. This matters if reformatters
+ // alter the white spacing around the tags. The default is false for
+ // backwards compat.
+ trimWhitespace: false,
+
+ // urlPreventCache: [public] boolean
+ // Flag to denote if peventCache should be used on xhrGet calls.
+ urlPreventCache: false,
+
+ // fetchOnCreate: [public] boolean
+ // Flag to denote if it should try to load from a data id (nested in the page)
+ // The moment the store is created, instead of waiting for first
+ // fetch call.
+ fetchOnCreate: false,
+
+ _indexItems: function(){
+ // summary:
+ // Function to index items found under the id.
+ // tags:
+ // private
+ 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]._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]._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){
+ array.forEach(this._rootNode.tHead.rows[0].cells, lang.hitch(this, function(th){
+ var text = xmlParser.textContent(th);
+ this._headings.push(this.trimWhitespace?lang.trim(text):text);
+ }));
+ }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 array.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){
+ var text;
+ if(item.cells){
+ text = xmlParser.textContent(item.cells[index]);
+ }else{//return Value for lists
+ text = xmlParser.textContent(item);
+ }
+ return [this.trimWhitespace?lang.trim(text):text];
+ }
+ 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 = 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()
+ return something && dom.isDescendant(something, this._rootNode);
+ },
+
+ 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 = dom.byId(this.dataId);
+ this._indexItems();
+ this._finishFetchItems(request, fetchHandler, errorHandler);
+ }else{
+ var getArgs = {
+ url: this.url,
+ handleAs: "text",
+ preventCache: this.urlPreventCache
+ };
+ var self = this;
+ var getHandler = xhr.get(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 = [];
+ 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] = 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 = dom.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 === xmlParser.textContent(self._rootNode.childNodes[i])){
+ item = self._rootNode.childNodes[i];
+ }
+ }
+ }
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+
+ }else{
+ var getArgs = {
+ url: this.url,
+ handleAs: "text"
+ };
+ var getHandler = xhr.get(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 === xmlParser.textContent(self._rootNode.childNodes[i])){
+ item = self._rootNode.childNodes[i];
+ break;
+ }
+ }
+ }
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ });
+ getHandler.addErrback(function(error){
+ if(keywordArgs.onError){
+ scope = keywordArgs.scope?keywordArgs.scope:winUtil.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:winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }
+ }
+});
+lang.extend(HtmlStore, simpleFetch);
+return HtmlStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/HtmlTableStore.js b/js/dojo-1.7.2/dojox/data/HtmlTableStore.js
new file mode 100644
index 0000000..a0e9b7b
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/HtmlTableStore.js
@@ -0,0 +1,473 @@
+//>>built
+define("dojox/data/HtmlTableStore", ["dojo/_base/kernel", "dojo/_base/declare", "dojo/_base/lang", "dojo/dom", "dojo/_base/array",
+ "dojo/_base/xhr", "dojo/_base/sniff", "dojo/_base/window", "dojo/data/util/simpleFetch",
+ "dojo/data/util/filter", "dojox/xml/parser"],
+ function(kernel, declare, lang, dom, array, xhr, has, winUtil, simpleFetch, filter, xmlParser) {
+
+var HtmlTableStore = declare("dojox.data.HtmlTableStore", null, {
+ constructor: function(/*Object*/args){
+ kernel.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 = dom.byId(args.tableId);
+ this.tableId = this._rootNode.id;
+ }else{
+ this._rootNode = dom.byId(this.tableId);
+ }
+ this._getHeadings();
+ for(var i=0; i<this._rootNode.rows.length; i++){
+ this._rootNode.rows[i].store = this;
+ }
+ }
+ },
+
+ // url: [public] string
+ // The URL from which to load an HTML document for data loading
+ url: "",
+
+ // tableId: [public] string
+ // The id of the table to load as store contents.
+ tableId: "",
+
+ _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 = [];
+ array.forEach(this._rootNode.tHead.rows[0].cells, lang.hitch(this, function(th){
+ this._headings.push(xmlParser.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 array.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 [xmlParser.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 = 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 = dom.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 = xhr.get(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] = 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(!has("opera")){
+ return item.sectionRowIndex; // int
+ }else{
+ return (array.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 = dom.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:winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+
+ }else{
+ var getArgs = {
+ url: this.url,
+ handleAs: "text"
+ };
+ var getHandler = xhr.get(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:winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ });
+ getHandler.addErrback(function(error){
+ if(keywordArgs.onError){
+ scope = keywordArgs.scope?keywordArgs.scope:winUtil.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:winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }
+ }
+});
+lang.extend(HtmlTableStore,simpleFetch);
+
+return HtmlTableStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/ItemExplorer.js b/js/dojo-1.7.2/dojox/data/ItemExplorer.js
new file mode 100644
index 0000000..fcc6343
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/ItemExplorer.js
@@ -0,0 +1,631 @@
+//>>built
+// wrapped by build app
+define("dojox/data/ItemExplorer", ["dijit","dojo","dojox","dojo/require!dijit/Tree,dijit/Dialog,dijit/Menu,dijit/form/ValidationTextBox,dijit/form/Textarea,dijit/form/Button,dijit/form/RadioButton,dijit/form/FilteringSelect"], function(dijit,dojo,dojox){
+dojo.provide("dojox.data.ItemExplorer");
+dojo.require("dijit.Tree");
+dojo.require("dijit.Dialog");
+dojo.require("dijit.Menu");
+dojo.require("dijit.form.ValidationTextBox");
+dojo.require("dijit.form.Textarea");
+dojo.require("dijit.form.Button");
+dojo.require("dijit.form.RadioButton");
+dojo.require("dijit.form.FilteringSelect");
+
+(function(){
+ var getValue = function(store, item, prop){
+ var value = store.getValues(item, prop);
+ if(value.length < 2){
+ value = store.getValue(item, prop);
+ }
+ return value;
+ }
+
+dojo.declare("dojox.data.ItemExplorer", dijit.Tree, {
+ useSelect: false,
+ refSelectSearchAttr: null,
+ constructor: function(options){
+ dojo.mixin(this, options);
+ var self = this;
+ var initialRootValue = {};
+ var root = (this.rootModelNode = {value:initialRootValue,id:"root"});
+
+ this._modelNodeIdMap = {};
+ this._modelNodePropMap = {};
+ var nextId = 1;
+ this.model = {
+ getRoot: function(onItem){
+ onItem(root);
+ },
+ mayHaveChildren: function(modelNode){
+ return modelNode.value && typeof modelNode.value == 'object' && !(modelNode.value instanceof Date);
+ },
+ getChildren: function(parentModelNode, onComplete, onError){
+ var keys, parent, item = parentModelNode.value;
+ var children = [];
+ if(item == initialRootValue){
+ onComplete([]);
+ return;
+ }
+ var isItem = self.store && self.store.isItem(item, true);
+ if(isItem && !self.store.isItemLoaded(item)){
+ // if it is not loaded, do so now.
+ self.store.loadItem({
+ item:item,
+ onItem:function(loadedItem){
+ item = loadedItem;
+ enumerate();
+ }
+ });
+ }else{
+ enumerate();
+ }
+ function enumerate(){
+ // once loaded, enumerate the keys
+ if(isItem){
+ // get the properties through the dojo data API
+ keys = self.store.getAttributes(item);
+ parent = item;
+ }else if(item && typeof item == 'object'){
+ parent = parentModelNode.value;
+ keys = [];
+ // also we want to be able to drill down into plain JS objects/arrays
+ for(var i in item){
+ if(item.hasOwnProperty(i) && i != '__id' && i != '__clientId'){
+ keys.push(i);
+ }
+ }
+ }
+ if(keys){
+ for(var key, k=0; key = keys[k++];){
+ children.push({
+ property:key,
+ value: isItem ? getValue(self.store, item, key) : item[key],
+ parent: parent});
+ }
+ children.push({addNew:true, parent: parent, parentNode : parentModelNode});
+ }
+ onComplete(children);
+ }
+ },
+ getIdentity: function(modelNode){
+ if(!modelNode.id){
+ if(modelNode.addNew){
+ modelNode.property = "--addNew";
+ }
+ modelNode.id = nextId++;
+ if(self.store){
+ if(self.store.isItem(modelNode.value)){
+ var identity = self.store.getIdentity(modelNode.value);
+ (self._modelNodeIdMap[identity] = self._modelNodeIdMap[identity] || []).push(modelNode);
+ }
+ if(modelNode.parent){
+ identity = self.store.getIdentity(modelNode.parent) + '.' + modelNode.property;
+ (self._modelNodePropMap[identity] = self._modelNodePropMap[identity] || []).push(modelNode);
+ }
+ }
+ }
+ return modelNode.id;
+ },
+ getLabel: function(modelNode){
+ return modelNode === root ?
+ "Object Properties" :
+ modelNode.addNew ? (modelNode.parent instanceof Array ? "Add new value" : "Add new property") :
+ modelNode.property + ": " +
+ (modelNode.value instanceof Array ? "(" + modelNode.value.length + " elements)" : modelNode.value);
+ },
+ onChildrenChange: function(modelNode){
+ },
+ onChange: function(modelNode){
+ }
+ };
+ },
+ postCreate: function(){
+ this.inherited(arguments);
+ // handle the clicking on the "add new property item"
+ dojo.connect(this, "onClick", function(modelNode, treeNode){
+ this.lastFocused = treeNode;
+ if(modelNode.addNew){
+ //this.focusNode(treeNode.getParent());
+ this._addProperty();
+ }else{
+ this._editProperty();
+ }
+ });
+ var contextMenu = new dijit.Menu({
+ targetNodeIds: [this.rootNode.domNode],
+ id: "contextMenu"
+ });
+ dojo.connect(contextMenu, "_openMyself", this, function(e){
+ var node = dijit.getEnclosingWidget(e.target);
+ if(node){
+ var item = node.item;
+ if(this.store.isItem(item.value, true) && !item.parent){
+ dojo.forEach(contextMenu.getChildren(), function(widget){
+ widget.attr("disabled", (widget.label != "Add"));
+ });
+ this.lastFocused = node;
+ // TODO: Root Node - allow Edit when mutli-value editing is possible
+ }else if(item.value && typeof item.value == 'object' && !(item.value instanceof Date)){
+ // an object that's not a Date - could be a store item
+ dojo.forEach(contextMenu.getChildren(), function(widget){
+ widget.attr("disabled", (widget.label != "Add") && (widget.label != "Delete"));
+ });
+ this.lastFocused = node;
+ // TODO: Object - allow Edit when mutli-value editing is possible
+ }else if(item.property && dojo.indexOf(this.store.getIdentityAttributes(), item.property) >= 0){ // id node
+ this.focusNode(node);
+ alert("Cannot modify an Identifier node.");
+ }else if(item.addNew){
+ this.focusNode(node);
+ }else{
+ dojo.forEach(contextMenu.getChildren(), function(widget){
+ widget.attr("disabled", (widget.label != "Edit") && (widget.label != "Delete"));
+ })
+ // this won't focus the node but gives us a way to reference the node
+ this.lastFocused = node;
+ }
+ }
+ });
+ contextMenu.addChild(new dijit.MenuItem({label: "Add", onClick: dojo.hitch(this, "_addProperty")}));
+ contextMenu.addChild(new dijit.MenuItem({label: "Edit", onClick: dojo.hitch(this, "_editProperty")}));
+ contextMenu.addChild(new dijit.MenuItem({label: "Delete", onClick: dojo.hitch(this, "_destroyProperty")}));
+ contextMenu.startup();
+ },
+ store: null,
+ setStore: function(store){
+ this.store = store;
+ var self = this;
+ if(this._editDialog){
+ this._editDialog.destroyRecursive();
+ delete this._editDialog;
+ }
+ // i think we should just destroy this._editDialog and let _createEditDialog take care of everything
+ // once it gets called again by either _editProperty or _addProperty - it will create everything again
+ // using the new store. this way we don't need to keep track of what is in the dialog if we change it.
+ /*if(this._editDialog && this.useSelect){
+ dojo.query(".reference [widgetId]", this._editDialog.containerNode).forEach(function(node){
+ dijit.getEnclosingWidget(node).attr("store", store);
+ });
+ }*/
+ dojo.connect(store, "onSet", function(item, attribute, oldValue, newValue){
+ var nodes, i, identity = self.store.getIdentity(item);
+ nodes = self._modelNodeIdMap[identity];
+
+ if(nodes &&
+ (oldValue === undefined || newValue === undefined ||
+ oldValue instanceof Array || newValue instanceof Array || typeof oldValue == 'object' || typeof newValue == 'object')){
+ for(i = 0; i < nodes.length; i++){
+ (function(node){
+ self.model.getChildren(node, function(children){
+ self.model.onChildrenChange(node, children);
+ });
+ })(nodes[i]);
+ }
+ }
+ nodes = self._modelNodePropMap[identity + "." + attribute];
+
+ if(nodes){
+ for(i = 0; i < nodes.length; i++){
+ nodes[i].value = newValue;
+ self.model.onChange(nodes[i]);
+ }
+ }
+ });
+ this.rootNode.setChildItems([]);
+ },
+ setItem: function(item){
+ // this is called to show a different item
+
+ // reset the maps, for the root getIdentity is not called, so we pre-initialize it here
+ (this._modelNodeIdMap = {})[this.store.getIdentity(item)] = [this.rootModelNode];
+ this._modelNodePropMap = {};
+
+ this.rootModelNode.value = item;
+ var self = this;
+ this.model.getChildren(this.rootModelNode, function(children){
+ self.rootNode.setChildItems(children);
+ });
+
+ },
+ refreshItem: function(){
+ this.setItem(this.rootModelNode.value);
+ },
+ _createEditDialog: function(){
+ this._editDialog = new dijit.Dialog({
+ title: "Edit Property",
+ execute: dojo.hitch(this, "_updateItem"),
+ preload: true
+ });
+ this._editDialog.placeAt(dojo.body());
+ this._editDialog.startup();
+
+ // handle for dialog content
+ var pane = dojo.doc.createElement('div');
+
+ // label for property
+ var labelProp = dojo.doc.createElement('label');
+ dojo.attr(labelProp, "for", "property");
+ dojo.style(labelProp, "fontWeight", "bold");
+ dojo.attr(labelProp, "innerHTML", "Property:")
+ pane.appendChild(labelProp);
+
+ // property name field
+ var propName = new dijit.form.ValidationTextBox({
+ name: "property",
+ value: "",
+ required: true,
+ disabled: true
+ }).placeAt(pane);
+
+ pane.appendChild(dojo.doc.createElement("br"));
+ pane.appendChild(dojo.doc.createElement("br"));
+
+ // radio button for "value"
+ var value = new dijit.form.RadioButton({
+ name: "itemType",
+ value: "value",
+ onClick: dojo.hitch(this, function(){this._enableFields("value");})
+ }).placeAt(pane);
+
+ // label for value
+ var labelVal = dojo.doc.createElement('label');
+ dojo.attr(labelVal, "for", "value");
+ dojo.attr(labelVal, "innerHTML", "Value (JSON):")
+ pane.appendChild(labelVal);
+
+ // container for value fields
+ var valueDiv = dojo.doc.createElement("div");
+ dojo.addClass(valueDiv, "value");
+
+ // textarea
+ var textarea = new dijit.form.Textarea({
+ name: "jsonVal"
+ }).placeAt(valueDiv);
+ pane.appendChild(valueDiv);
+
+ // radio button for "reference"
+ var reference = new dijit.form.RadioButton({
+ name: "itemType",
+ value: "reference",
+ onClick: dojo.hitch(this, function(){this._enableFields("reference");})
+ }).placeAt(pane);
+
+ // label for reference
+ var labelRef = dojo.doc.createElement('label');
+ dojo.attr(labelRef, "for", "_reference");
+ dojo.attr(labelRef, "innerHTML", "Reference (ID):")
+ pane.appendChild(labelRef);
+ pane.appendChild(dojo.doc.createElement("br"));
+
+ // container for reference fields
+ var refDiv = dojo.doc.createElement("div");
+ dojo.addClass(refDiv, "reference");
+
+ if(this.useSelect){
+ // filteringselect
+ // TODO: see if there is a way to sort the items in this list
+ var refSelect = new dijit.form.FilteringSelect({
+ name: "_reference",
+ store: this.store,
+ searchAttr: this.refSelectSearchAttr || this.store.getIdentityAttributes()[0],
+ required: false,
+ value: null, // need to file a ticket about the fetch that happens when declared with value: null
+ pageSize: 10
+ }).placeAt(refDiv);
+ }else{
+ var refTextbox = new dijit.form.ValidationTextBox({
+ name: "_reference",
+ value: "",
+ promptMessage: "Enter the ID of the item to reference",
+ isValid: dojo.hitch(this, function(isFocused){
+ // don't validate while it's focused
+ return true;//isFocused || this.store.getItemByIdentity(this._editDialog.attr("value")._reference);
+ })
+ }).placeAt(refDiv);
+ }
+ pane.appendChild(refDiv);
+ pane.appendChild(dojo.doc.createElement("br"));
+ pane.appendChild(dojo.doc.createElement("br"));
+
+ // buttons
+ var buttons = document.createElement('div');
+ buttons.setAttribute("dir", "rtl");
+ var cancelButton = new dijit.form.Button({type: "reset", label: "Cancel"}).placeAt(buttons);
+ cancelButton.onClick = dojo.hitch(this._editDialog, "onCancel");
+ var okButton = new dijit.form.Button({type: "submit", label: "OK"}).placeAt(buttons);
+ pane.appendChild(buttons);
+
+ this._editDialog.attr("content", pane);
+ },
+ _enableFields: function(selection){
+ // enables/disables fields based on whether the value in this._editDialog is a reference or a primitive value
+ switch(selection){
+ case "reference":
+ dojo.query(".value [widgetId]", this._editDialog.containerNode).forEach(function(node){
+ dijit.getEnclosingWidget(node).attr("disabled", true);
+ });
+ dojo.query(".reference [widgetId]", this._editDialog.containerNode).forEach(function(node){
+ dijit.getEnclosingWidget(node).attr("disabled", false);
+ });
+ break;
+ case "value":
+ dojo.query(".value [widgetId]", this._editDialog.containerNode).forEach(function(node){
+ dijit.getEnclosingWidget(node).attr("disabled", false);
+ });
+ dojo.query(".reference [widgetId]", this._editDialog.containerNode).forEach(function(node){
+ dijit.getEnclosingWidget(node).attr("disabled", true);
+ });
+ break;
+ }
+ },
+ _updateItem: function(vals){
+ // a single "execute" function that handles adding and editing of values and references.
+ var node, item, val, storeItemVal, editingItem = this._editDialog.attr("title") == "Edit Property";
+ var editDialog = this._editDialog;
+ var store = this.store;
+ function setValue(){
+ try{
+ var itemVal, propPath = [];
+ var prop = vals.property;
+ if(editingItem){
+ while(!store.isItem(item.parent, true)){
+ node = node.getParent();
+ propPath.push(item.property);
+ item = node.item;
+ }
+ if(propPath.length == 0){
+ // working with an item attribute already
+ store.setValue(item.parent, item.property, val);
+ }else{
+ // need to walk back down the item property to the object
+ storeItemVal = getValue(store, item.parent, item.property);
+ if(storeItemVal instanceof Array){
+ // create a copy for modification
+ storeItemVal = storeItemVal.concat();
+ }
+ itemVal = storeItemVal;
+ while(propPath.length > 1){
+ itemVal = itemVal[propPath.pop()];
+ }
+ itemVal[propPath] = val; // this change is reflected in storeItemVal as well
+ store.setValue(item.parent, item.property, storeItemVal);
+ }
+ }else{
+ // adding a property
+ if(store.isItem(value, true)){
+ // adding a top-level property to an item
+ if(!store.isItemLoaded(value)){
+ // fetch the value and see if it is an array
+ store.loadItem({
+ item: value,
+ onItem: function(loadedItem){
+ if(loadedItem instanceof Array){
+ prop = loadedItem.length;
+ }
+ store.setValue(loadedItem, prop, val);
+ }
+ });
+ }else{
+ if(value instanceof Array){
+ prop = value.length;
+ }
+ store.setValue(value, prop, val);
+ }
+ }else{
+ // adding a property to a lower level in an item
+ if(item.value instanceof Array){
+ propPath.push(item.value.length);
+ }else{
+ propPath.push(vals.property);
+ }
+ while(!store.isItem(item.parent, true)){
+ node = node.getParent();
+ propPath.push(item.property);
+ item = node.item;
+ }
+ storeItemVal = getValue(store, item.parent, item.property);
+ itemVal = storeItemVal;
+ while(propPath.length > 1){
+ itemVal = itemVal[propPath.pop()];
+ }
+ itemVal[propPath] = val;
+ store.setValue(item.parent, item.property, storeItemVal);
+ }
+ }
+ }catch(e){
+ alert(e);
+ }
+ }
+
+ if(editDialog.validate()){
+ node = this.lastFocused;
+ item = node.item;
+ var value = item.value;
+ // var property = null;
+ if(item.addNew){
+ // we are adding a property to the parent item
+ // the real value of the parent is in the parent property of the lastFocused item
+ // this.lastFocused.getParent().item.value may be a reference to an item
+ value = node.item.parent;
+ node = node.getParent();
+ item = node.item;
+ }
+ val = null;
+ switch(vals.itemType){
+ case "reference":
+ this.store.fetchItemByIdentity({identity:vals._reference,
+ onItem:function(item){
+ val = item;
+ setValue();
+ },
+ onError:function(){
+ alert("The id could not be found");
+ }
+ });
+ break;
+ case "value":
+ var jsonVal = vals.jsonVal;
+ val = dojo.fromJson(jsonVal);
+ // ifit is a function we want to preserve the source (comments, et al)
+ if(typeof val == 'function'){
+ val.toString = function(){
+ return jsonVal;
+ }
+ }
+ setValue();
+ break;
+ }
+ }else{
+ // the form didn't validate - show it again.
+ editDialog.show();
+ }
+ },
+ _editProperty: function(){
+ // this mixin stops us polluting the tree item with jsonVal etc.
+ // FIXME: if a store identifies items by instanceof checks, this will fail
+ var item = dojo.mixin({}, this.lastFocused.item);
+ // create the dialog or reset it if it already exists
+ if(!this._editDialog){
+ this._createEditDialog();
+ }else{
+ this._editDialog.reset();
+ }
+ // not allowed to edit an item's id - so check for that and stop it.
+ if(dojo.indexOf(this.store.getIdentityAttributes(), item.property) >= 0){
+ alert("Cannot Edit an Identifier!");
+ }else{
+ this._editDialog.attr("title", "Edit Property");
+ // make sure the property input is disabled
+ dijit.getEnclosingWidget(dojo.query("input", this._editDialog.containerNode)[0]).attr("disabled", true);
+ if(this.store.isItem(item.value, true)){
+ // root node || Item reference
+ if(item.parent){
+ // Item reference
+ item.itemType = "reference";
+ this._enableFields(item.itemType);
+ item._reference = this.store.getIdentity(item.value);
+ this._editDialog.attr("value", item);
+ this._editDialog.show();
+ } // else root node
+ }else{
+ if(item.value && typeof item.value == 'object' && !(item.value instanceof Date)){
+ // item.value is an object but it's NOT an item from the store - no-op
+ // only allow editing on a property not on the node that represents the object/array
+ }else{
+ // this is a primitive
+ item.itemType = "value";
+ this._enableFields(item.itemType);
+ item.jsonVal = typeof item.value == 'function' ?
+ // use the plain toString for functions, dojo.toJson doesn't support functions
+ item.value.toString() :
+ item.value instanceof Date ?
+ // A json-ish form of a date:
+ 'new Date("' + item.value + '")' :
+ dojo.toJson(item.value);
+ this._editDialog.attr("value", item);
+ this._editDialog.show();
+ }
+ }
+ }
+ },
+ _destroyProperty: function(){
+ var node = this.lastFocused;
+ var item = node.item;
+ var propPath = [];
+ // we have to walk up the tree to the item before we can know if we're working with the identifier
+ while(!this.store.isItem(item.parent, true) || item.parent instanceof Array){
+ node = node.getParent();
+ propPath.push(item.property);
+ item = node.item;
+ }
+ // this will prevent any part of the identifier from being changed
+ if(dojo.indexOf(this.store.getIdentityAttributes(), item.property) >= 0){
+ alert("Cannot Delete an Identifier!");
+ }else{
+ try{
+ if(propPath.length > 0){
+ // not deleting a top-level property of an item so get the top-level store item to change
+ var itemVal, storeItemVal = getValue(this.store, item.parent, item.property);
+ itemVal = storeItemVal;
+ // walk back down the object if needed
+ while(propPath.length > 1){
+ itemVal = itemVal[propPath.pop()];
+ }
+ // delete the property
+ if(dojo.isArray(itemVal)){
+ // the value being deleted represents an array element
+ itemVal.splice(propPath, 1);
+ }else{
+ // object property
+ delete itemVal[propPath];
+ }
+ // save it back to the store
+ this.store.setValue(item.parent, item.property, storeItemVal);
+ }else{
+ // deleting an item property
+ this.store.unsetAttribute(item.parent, item.property);
+ }
+ }catch(e){
+ alert(e);
+ }
+ }
+ },
+ _addProperty: function(){
+ // item is what we are adding a property to
+ var item = this.lastFocused.item;
+ // value is the real value of the item - not a reference to a store item
+ var value = item.value;
+ var showDialog = dojo.hitch(this, function(){
+ var property = null;
+ if(!this._editDialog){
+ this._createEditDialog();
+ }else{
+ this._editDialog.reset();
+ }
+ // are we adding another item to an array?
+ if(value instanceof Array){
+ // preset the property to the next index in the array and disable the property field
+ property = value.length;
+ dijit.getEnclosingWidget(dojo.query("input", this._editDialog.containerNode)[0]).attr("disabled", true);
+ }else{
+ // enable the property TextBox
+ dijit.getEnclosingWidget(dojo.query("input", this._editDialog.containerNode)[0]).attr("disabled", false);
+ }
+ this._editDialog.attr("title", "Add Property");
+ // default to a value type
+ this._enableFields("value");
+ this._editDialog.attr("value", {itemType: "value", property: property});
+ this._editDialog.show();
+ });
+
+ if(item.addNew){
+ // we are adding a property to the parent item
+ item = this.lastFocused.getParent().item;
+ // the real value of the parent is in the parent property of the lastFocused item
+ // this.lastFocused.getParent().item.value may be a reference to an item
+ value = this.lastFocused.item.parent;
+ }
+ if(item.property && dojo.indexOf(this.store.getIdentityAttributes(), item.property) >= 0){
+ alert("Cannot add properties to an ID node!");
+ }else{
+ // ifthe value is an item then we need to get the item's value
+ if(this.store.isItem(value, true) && !this.store.isItemLoaded(value)){
+ // fetch the value and see if it is an array
+ this.store.loadItem({
+ item: value,
+ onItem: function(loadedItem){
+ value = loadedItem;
+ showDialog();
+ }
+ });
+ }else{
+ showDialog();
+ }
+//
+ }
+ }
+});
+})();
+
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/JsonQueryRestStore.js b/js/dojo-1.7.2/dojox/data/JsonQueryRestStore.js
new file mode 100644
index 0000000..125fffa
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/JsonQueryRestStore.js
@@ -0,0 +1,15 @@
+//>>built
+define("dojox/data/JsonQueryRestStore", ["dojo", "dojox", "dojox/data/JsonRestStore", "dojox/data/util/JsonQuery", "dojox/data/ClientFilter", "dojox/json/query"], function(dojo, dojox) {
+
+// this is an extension of JsonRestStore to convert object attribute queries to
+// JSONQuery/JSONPath syntax to be sent to the server. This also enables
+// JSONQuery/JSONPath queries to be performed locally if dojox.data.ClientFilter
+// has been loaded
+dojo.declare("dojox.data.JsonQueryRestStore",[dojox.data.JsonRestStore,dojox.data.util.JsonQuery],{
+ matchesQuery: function(item,request){
+ return item.__id && (item.__id.indexOf("#") == -1) && this.inherited(arguments);
+ }
+});
+
+return dojox.data.JsonQueryRestStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/JsonRestStore.js b/js/dojo-1.7.2/dojox/data/JsonRestStore.js
new file mode 100644
index 0000000..27e16f6
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/JsonRestStore.js
@@ -0,0 +1,510 @@
+//>>built
+define("dojox/data/JsonRestStore", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojox/rpc/Rest",
+ "dojox/rpc/JsonRest", "dojox/json/schema", "dojox/data/ServiceStore"],
+ function(lang, declare, connect, rpcRest, rpcJsonRest, jsonSchema, ServiceStore) {
+
+/*=====
+var ServiceStore = dojox.data.ServiceStore;
+=====*/
+
+var JsonRestStore = declare("dojox.data.JsonRestStore", ServiceStore,
+ {
+ constructor: function(options){
+ //summary:
+ // JsonRestStore is a Dojo Data store interface to JSON HTTP/REST web
+ // storage services that support read and write through GET, PUT, POST, and DELETE.
+ // options:
+ // Keyword arguments
+ //
+ // The *schema* parameter
+ // This is a schema object for this store. This should be JSON Schema format.
+ //
+ // The *service* parameter
+ // This is the service object that is used to retrieve lazy data and save results
+ // The function should be directly callable with a single parameter of an object id to be loaded
+ // The function should also have the following methods:
+ // put(id,value) - puts the value at the given id
+ // post(id,value) - posts (appends) the value at the given id
+ // delete(id) - deletes the value corresponding to the given id
+ // Note that it is critical that the service parses responses as JSON.
+ // If you are using dojox.rpc.Service, the easiest way to make sure this
+ // happens is to make the responses have a content type of
+ // application/json. If you are creating your own service, make sure you
+ // use handleAs: "json" with your XHR requests.
+ //
+ // The *target* parameter
+ // This is the target URL for this Service store. This may be used in place
+ // of a service parameter to connect directly to RESTful URL without
+ // using a dojox.rpc.Service object.
+ //
+ // The *idAttribute* parameter
+ // 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.
+ //
+ // The *syncMode* parameter
+ // Setting this to true will set the store to using synchronous calls by default.
+ // Sync calls return their data immediately from the calling function, so
+ // callbacks are unnecessary
+ //
+ // description:
+ // The JsonRestStore will cause all saved modifications to be sent to the server using Rest commands (PUT, POST, or DELETE).
+ // When using a Rest store on a public network, it is important to implement proper security measures to
+ // control access to resources.
+ // On the server side implementing a REST interface means providing GET, PUT, POST, and DELETE handlers.
+ // GET - Retrieve an object or array/result set, this can be by id (like /table/1) or with a
+ // query (like /table/?name=foo).
+ // PUT - This should modify a object, the URL will correspond to the id (like /table/1), and the body will
+ // provide the modified object
+ // POST - This should create a new object. The URL will correspond to the target store (like /table/)
+ // and the body should be the properties of the new object. The server's response should include a
+ // Location header that indicates the id of the newly created object. This id will be used for subsequent
+ // PUT and DELETE requests. JsonRestStore also includes a Content-Location header that indicates
+ // the temporary randomly generated id used by client, and this location is used for subsequent
+ // PUT/DELETEs if no Location header is provided by the server or if a modification is sent prior
+ // to receiving a response from the server.
+ // DELETE - This should delete an object by id.
+ // These articles include more detailed information on using the JsonRestStore:
+ // http://www.sitepen.com/blog/2008/06/13/restful-json-dojo-data/
+ // http://blog.medryx.org/2008/07/24/jsonreststore-overview/
+ //
+ // example:
+ // A JsonRestStore takes a REST service or a URL and uses it the remote communication for a
+ // read/write dojo.data implementation. A JsonRestStore can be created with a simple URL like:
+ // | new JsonRestStore({target:"/MyData/"});
+ // example:
+ // To use a JsonRestStore with a service, you should create a
+ // service with a REST transport. This can be configured with an SMD:
+ // | {
+ // | services: {
+ // | jsonRestStore: {
+ // | transport: "REST",
+ // | envelope: "URL",
+ // | target: "store.php",
+ // | contentType:"application/json",
+ // | parameters: [
+ // | {name: "location", type: "string", optional: true}
+ // | ]
+ // | }
+ // | }
+ // | }
+ // The SMD can then be used to create service, and the service can be passed to a JsonRestStore. For example:
+ // | var myServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd"));
+ // | var jsonStore = new dojox.data.JsonRestStore({service:myServices.jsonRestStore});
+ // example:
+ // The JsonRestStore also supports lazy loading. References can be made to objects that have not been loaded.
+ // For example if a service returned:
+ // | {"name":"Example","lazyLoadedObject":{"$ref":"obj2"}}
+ // And this object has accessed using the dojo.data API:
+ // | var obj = jsonStore.getValue(myObject,"lazyLoadedObject");
+ // The object would automatically be requested from the server (with an object id of "obj2").
+ //
+
+ connect.connect(rpcRest._index,"onUpdate",this,function(obj,attrName,oldValue,newValue){
+ var prefix = this.service.servicePath;
+ if(!obj.__id){
+ console.log("no id on updated object ", obj);
+ }else if(obj.__id.substring(0,prefix.length) == prefix){
+ this.onSet(obj,attrName,oldValue,newValue);
+ }
+ });
+ this.idAttribute = this.idAttribute || 'id';// no options about it, we have to have identity
+
+ if(typeof options.target == 'string'){
+ options.target = options.target.match(/\/$/) || this.allowNoTrailingSlash ? options.target : (options.target + '/');
+ if(!this.service){
+ this.service = rpcJsonRest.services[options.target] ||
+ rpcRest(options.target, true);
+ // create a default Rest service
+ }
+ }
+
+ rpcJsonRest.registerService(this.service, options.target, this.schema);
+ this.schema = this.service._schema = this.schema || this.service._schema || {};
+ // wrap the service with so it goes through JsonRest manager
+ this.service._store = this;
+ this.service.idAsRef = this.idAsRef;
+ this.schema._idAttr = this.idAttribute;
+ var constructor = rpcJsonRest.getConstructor(this.service);
+ var self = this;
+ this._constructor = function(data){
+ constructor.call(this, data);
+ self.onNew(this);
+ }
+ this._constructor.prototype = constructor.prototype;
+ this._index = rpcRest._index;
+ },
+
+ // summary:
+ // Will load any schemas referenced content-type header or in Link headers
+ loadReferencedSchema: true,
+ // summary:
+ // Treat objects in queries as partially loaded objects
+ idAsRef: false,
+ referenceIntegrity: true,
+ target:"",
+ // summary:
+ // Allow no trailing slash on target paths. This is generally discouraged since
+ // it creates prevents simple scalar values from being used a relative URLs.
+ // Disabled by default.
+ allowNoTrailingSlash: false,
+ //Write API Support
+ newItem: function(data, parentInfo){
+ // 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.
+ data = new this._constructor(data);
+ if(parentInfo){
+ // get the previous value or any empty array
+ var values = this.getValue(parentInfo.parent,parentInfo.attribute,[]);
+ // set the new value
+ values = values.concat([data]);
+ data.__parent = values;
+ this.setValue(parentInfo.parent, parentInfo.attribute, values);
+ }
+ return data;
+ },
+ deleteItem: function(item){
+ // summary:
+ // deletes item and any references to that item from the store.
+ //
+ // item:
+ // item to delete
+ //
+
+ // If the desire is to delete only one reference, unsetAttribute or
+ // setValue is the way to go.
+ var checked = [];
+ var store = dataExtCfg._getStoreForItem(item) || this;
+ if(this.referenceIntegrity){
+ // cleanup all references
+ rpcJsonRest._saveNotNeeded = true;
+ var index = rpcRest._index;
+ var fixReferences = function(parent){
+ var toSplice;
+ // keep track of the checked ones
+ checked.push(parent);
+ // mark it checked so we don't run into circular loops when encountering cycles
+ parent.__checked = 1;
+ for(var i in parent){
+ if(i.substring(0,2) != "__"){
+ var value = parent[i];
+ if(value == item){
+ if(parent != index){ // make sure we are just operating on real objects
+ if(parent instanceof Array){
+ // mark it as needing to be spliced, don't do it now or it will mess up the index into the array
+ (toSplice = toSplice || []).push(i);
+ }else{
+ // property, just delete it.
+ (dataExtCfg._getStoreForItem(parent) || store).unsetAttribute(parent, i);
+ }
+ }
+ }else{
+ if((typeof value == 'object') && value){
+ if(!value.__checked){
+ // recursively search
+ fixReferences(value);
+ }
+ if(typeof value.__checked == 'object' && parent != index){
+ // if it is a modified array, we will replace it
+ (dataExtCfg._getStoreForItem(parent) || store).setValue(parent, i, value.__checked);
+ }
+ }
+ }
+ }
+ }
+ if(toSplice){
+ // we need to splice the deleted item out of these arrays
+ i = toSplice.length;
+ parent = parent.__checked = parent.concat(); // indicates that the array is modified
+ while(i--){
+ parent.splice(toSplice[i], 1);
+ }
+ return parent;
+ }
+ return null;
+ };
+ // start with the index
+ fixReferences(index);
+ rpcJsonRest._saveNotNeeded = false;
+ var i = 0;
+ while(checked[i]){
+ // remove the checked marker
+ delete checked[i++].__checked;
+ }
+ }
+ rpcJsonRest.deleteObject(item);
+
+ store.onDelete(item);
+ },
+ changing: function(item,_deleting){
+ // 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.
+ rpcJsonRest.changing(item,_deleting);
+ },
+ cancelChanging : function(object){
+ // summary:
+ // Removes an object from the list of dirty objects
+ // This will prevent that object from being saved to the server on the next save
+ // object:
+ // The item to cancel changes on
+ if(!object.__id){
+ return;
+ }
+ dirtyObjects = dirty=rpcJsonRest.getDirtyObjects();
+ for(var i=0; i<dirtyObjects.length; i++){
+ var dirty = dirtyObjects[i];
+ if(object==dirty.object){
+ dirtyObjects.splice(i, 1);
+ return;
+ }
+ }
+
+ },
+
+ setValue: function(item, attribute, value){
+ // summary:
+ // sets 'attribute' on 'item' to 'value'
+
+ var old = item[attribute];
+ var store = item.__id ? dataExtCfg._getStoreForItem(item) : this;
+ if(jsonSchema && store.schema && store.schema.properties){
+ // if we have a schema and schema validator available we will validate the property change
+ jsonSchema.mustBeValid(jsonSchema.checkPropertyChange(value,store.schema.properties[attribute]));
+ }
+ if(attribute == store.idAttribute){
+ throw new Error("Can not change the identity attribute for an item");
+ }
+ store.changing(item);
+ item[attribute]=value;
+ if(value && !value.__parent){
+ value.__parent = item;
+ }
+ store.onSet(item,attribute,old,value);
+ },
+ setValues: function(item, attribute, values){
+ // summary:
+ // sets 'attribute' on 'item' to 'value' value
+ // must be an array.
+
+
+ if(!lang.isArray(values)){
+ throw new Error("setValues expects to be passed an Array object as its value");
+ }
+ this.setValue(item,attribute,values);
+ },
+
+ unsetAttribute: function(item, attribute){
+ // summary:
+ // unsets 'attribute' on 'item'
+
+ this.changing(item);
+ var old = item[attribute];
+ delete item[attribute];
+ this.onSet(item,attribute,old,undefined);
+ },
+ save: function(kwArgs){
+ // summary:
+ // Saves the dirty data using REST Ajax methods. See dojo.data.api.Write for API.
+ //
+ // kwArgs.global:
+ // This will cause the save to commit the dirty data for all
+ // JsonRestStores as a single transaction.
+ //
+ // kwArgs.revertOnError
+ // This will cause the changes to be reverted if there is an
+ // error on the save. By default a revert is executed unless
+ // a value of false is provide for this parameter.
+ //
+ // kwArgs.incrementalUpdates
+ // For items that have been updated, if this is enabled, the server will be sent a POST request
+ // with a JSON object containing the changed properties. By default this is
+ // not enabled, and a PUT is used to deliver an update, and will include a full
+ // serialization of all the properties of the item/object.
+ // If this is true, the POST request body will consist of a JSON object with
+ // only the changed properties. The incrementalUpdates parameter may also
+ // be a function, in which case it will be called with the updated and previous objects
+ // and an object update representation can be returned.
+ //
+ // kwArgs.alwaysPostNewItems
+ // If this is true, new items will always be sent with a POST request. By default
+ // this is not enabled, and the JsonRestStore will send a POST request if
+ // the item does not include its identifier (expecting server assigned location/
+ // identifier), and will send a PUT request if the item does include its identifier
+ // (the PUT will be sent to the URI corresponding to the provided identifier).
+
+ if(!(kwArgs && kwArgs.global)){
+ (kwArgs = kwArgs || {}).service = this.service;
+ }
+ if("syncMode" in kwArgs ? kwArgs.syncMode : this.syncMode){
+ rpcConfig._sync = true;
+ }
+
+ var actions = rpcJsonRest.commit(kwArgs);
+ this.serverVersion = this._updates && this._updates.length;
+ return actions;
+ },
+
+ revert: function(kwArgs){
+ // summary
+ // returns any modified data to its original state prior to a save();
+ //
+ // kwArgs.global:
+ // This will cause the revert to undo all the changes for all
+ // JsonRestStores in a single operation.
+ rpcJsonRest.revert(kwArgs && kwArgs.global && this.service);
+ },
+
+ isDirty: function(item){
+ // summary
+ // returns true if the item is marked as dirty.
+ return rpcJsonRest.isDirty(item, this);
+ },
+ isItem: function(item, anyStore){
+ // summary:
+ // Checks to see if a passed 'item'
+ // really belongs to this JsonRestStore.
+ //
+ // item: /* object */
+ // The value to test for being an item
+ // anyStore: /* boolean*/
+ // If true, this will return true if the value is an item for any JsonRestStore,
+ // not just this instance
+ return item && item.__id && (anyStore || this.service == rpcJsonRest.getServiceAndId(item.__id).service);
+ },
+ _doQuery: function(args){
+ var query= typeof args.queryStr == 'string' ? args.queryStr : args.query;
+ var deferred = rpcJsonRest.query(this.service,query, args);
+ var self = this;
+ if(this.loadReferencedSchema){
+ deferred.addCallback(function(result){
+ var contentType = deferred.ioArgs && deferred.ioArgs.xhr && deferred.ioArgs.xhr.getResponseHeader("Content-Type");
+ var schemaRef = contentType && contentType.match(/definedby\s*=\s*([^;]*)/);
+ if(contentType && !schemaRef){
+ schemaRef = deferred.ioArgs.xhr.getResponseHeader("Link");
+ schemaRef = schemaRef && schemaRef.match(/<([^>]*)>;\s*rel="?definedby"?/);
+ }
+ schemaRef = schemaRef && schemaRef[1];
+ if(schemaRef){
+ var serviceAndId = rpcJsonRest.getServiceAndId((self.target + schemaRef).replace(/^(.*\/)?(\w+:\/\/)|[^\/\.]+\/\.\.\/|^.*\/(\/)/,"$2$3"));
+ var schemaDeferred = rpcJsonRest.byId(serviceAndId.service, serviceAndId.id);
+ schemaDeferred.addCallbacks(function(newSchema){
+ lang.mixin(self.schema, newSchema);
+ return result;
+ }, function(error){
+ console.error(error); // log it, but don't let it cause the main request to fail
+ return result;
+ });
+ return schemaDeferred;
+ }
+ return undefined;//don't change anything, and deal with the stupid post-commit lint complaints
+ });
+ }
+ return deferred;
+ },
+ _processResults: function(results, deferred){
+ // index the results
+ var count = results.length;
+ // if we don't know the length, and it is partial result, we will guess that it is twice as big, that will work for most widgets
+ return {totalCount:deferred.fullLength || (deferred.request.count == count ? (deferred.request.start || 0) + count * 2 : count), items: results};
+ },
+
+ getConstructor: function(){
+ // summary:
+ // Gets the constructor for objects from this store
+ return this._constructor;
+ },
+ getIdentity: function(item){
+ var id = item.__clientId || item.__id;
+ if(!id){
+ return id;
+ }
+ var prefix = this.service.servicePath.replace(/[^\/]*$/,'');
+ // support for relative or absolute referencing with ids
+ return id.substring(0,prefix.length) != prefix ? id : id.substring(prefix.length); // String
+ },
+ fetchItemByIdentity: function(args){
+ var id = args.identity;
+ var store = this;
+ // if it is an absolute id, we want to find the right store to query
+ if(id.toString().match(/^(\w*:)?\//)){
+ var serviceAndId = rpcJsonRest.getServiceAndId(id);
+ store = serviceAndId.service._store;
+ args.identity = serviceAndId.id;
+ }
+ args._prefix = store.service.servicePath.replace(/[^\/]*$/,'');
+ return store.inherited(arguments);
+ },
+ //Notifcation Support
+
+ onSet: function(){},
+ onNew: function(){},
+ onDelete: function(){},
+
+ getFeatures: function(){
+ // summary:
+ // return the store feature set
+ var features = this.inherited(arguments);
+ features["dojo.data.api.Write"] = true;
+ features["dojo.data.api.Notification"] = true;
+ return features;
+ },
+
+ getParent: function(item){
+ // summary:
+ // Returns the parent item (or query) for the given item
+ // item:
+ // The item to find the parent of
+
+ return item && item.__parent;
+ }
+
+
+ }
+);
+JsonRestStore.getStore = function(options, Class){
+ // summary:
+ // Will retrieve or create a store using the given options (the same options
+ // that are passed to JsonRestStore constructor. Returns a JsonRestStore instance
+ // options:
+ // See the JsonRestStore constructor
+ // Class:
+ // Constructor to use (for creating stores from JsonRestStore subclasses).
+ // This is optional and defaults to JsonRestStore.
+ if(typeof options.target == 'string'){
+ options.target = options.target.match(/\/$/) || options.allowNoTrailingSlash ?
+ options.target : (options.target + '/');
+ var store = (rpcJsonRest.services[options.target] || {})._store;
+ if(store){
+ return store;
+ }
+ }
+ return new (Class || JsonRestStore)(options);
+};
+
+var dataExtCfg = lang.getObject("dojox.data",true);
+dataExtCfg._getStoreForItem = function(item){
+ if(item.__id){
+ var serviceAndId = rpcJsonRest.getServiceAndId(item.__id);
+ if(serviceAndId && serviceAndId.service._store){
+ return serviceAndId.service._store;
+ }else{
+ var servicePath = item.__id.toString().match(/.*\//)[0];
+ return new JsonRestStore({target:servicePath});
+ }
+ }
+ return null;
+};
+var jsonRefConfig = lang.getObject("dojox.json.ref", true);
+jsonRefConfig._useRefs = true; // Use referencing when identifiable objects are referenced
+
+return JsonRestStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/KeyValueStore.js b/js/dojo-1.7.2/dojox/data/KeyValueStore.js
new file mode 100644
index 0000000..83af824
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/KeyValueStore.js
@@ -0,0 +1,393 @@
+//>>built
+define("dojox/data/KeyValueStore", ["dojo/_base/declare", "dojo/_base/lang", "dojo/_base/xhr", "dojo/_base/window",
+ "dojo/data/util/simpleFetch", "dojo/data/util/filter"],
+ function(declare, lang, xhr, winUtil, simpleFetch, filterUtil) {
+
+var KeyValueStore = 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 = [];
+ if(keywordParameters && "urlPreventCache" in keywordParameters){
+ this.urlPreventCache = keywordParameters.urlPreventCache?true:false;
+ }
+ },
+
+ url: "",
+ data: "",
+
+ //urlPreventCache: boolean
+ //Controls if urlPreventCache should be used with underlying xhrGet.
+ urlPreventCache: false,
+
+ _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(!lang.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);
+ var value;
+ if(attribute == this._keyAttribute){ // Looking for key
+ value = item[this._keyAttribute];
+ }else{
+ value = item[this._valueAttribute]; // Otherwise, attribute == ('value' || the actual key )
+ }
+ if(value === undefined){
+ value = defaultValue;
+ }
+ return value;
+ },
+
+ 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 = filterUtil.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] = filterUtil.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",
+ preventCache: this.urlPreventCache
+ };
+ var getHandler = xhr.get(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 || winUtil.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.
+lang.extend(KeyValueStore,simpleFetch);
+return KeyValueStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/OpenSearchStore.js b/js/dojo-1.7.2/dojox/data/OpenSearchStore.js
new file mode 100644
index 0000000..1009e57
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/OpenSearchStore.js
@@ -0,0 +1,373 @@
+//>>built
+define("dojox/data/OpenSearchStore", [
+ "dojo/_base/kernel", // dojo.experimental
+ "dojo/_base/lang", // dojo.extend
+ "dojo/_base/declare", // dojo.declare
+ "dojo/_base/xhr", // dojo.xhrGet
+ "dojo/_base/array", // dojo.forEach
+ "dojo/_base/window", // dojo.doc
+ "dojo/query",
+ "dojo/data/util/simpleFetch",
+ "dojox/xml/parser"], function (kernel, lang, declare, dxhr, array, window, query, simpleFetch, parser) {
+kernel.experimental("dojox.data.OpenSearchStore");
+
+var OpenSearchStore = declare("dojox.data.OpenSearchStore", null, {
+ constructor: function(/*Object*/args){
+ // summary:
+ // Initializer for the OpenSearchStore store.
+ // description:
+ // The OpenSearchStore is a Datastore interface to any search
+ // engine that implements the open search specifications.
+ if(args){
+ this.label = args.label;
+ this.url = args.url;
+ this.itemPath = args.itemPath;
+ if("urlPreventCache" in args){
+ this.urlPreventCache = args.urlPreventCache?true:false;
+ }
+ }
+ var def = dxhr.get({
+ url: this.url,
+ handleAs: "xml",
+ sync: true,
+ preventCache: this.urlPreventCache
+ });
+ def.addCallback(this, "_processOsdd");
+ def.addErrback(function(){
+ throw new Error("Unable to load OpenSearch Description document from " . args.url);
+ });
+ },
+
+ // URL to the open search description document
+ url: "",
+ itemPath: "",
+ _storeRef: "_S",
+ urlElement: null,
+ iframeElement: null,
+
+ //urlPreventCache: boolean
+ //Flag denoting if xhrGet calls should use the preventCache option.
+ urlPreventCache: true,
+
+ ATOM_CONTENT_TYPE: 3,
+ ATOM_CONTENT_TYPE_STRING: "atom",
+ RSS_CONTENT_TYPE: 2,
+ RSS_CONTENT_TYPE_STRING: "rss",
+ XML_CONTENT_TYPE: 1,
+ XML_CONTENT_TYPE_STRING: "xml",
+
+ _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.OpenSearchStore: 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.OpenSearchStore: 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, defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ if(values){
+ return values[0];
+ }
+ return defaultValue;
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ return ["content"];
+ },
+
+ 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 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()
+ 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);
+ var value = this.processItem(item, attribute);
+ if(value){
+ return [value];
+ }
+ 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()
+ },
+
+ process: function(data){
+ // This should return an array of items. This would be the function to override if the
+ // developer wanted to customize the processing/parsing of the entire batch of search
+ // results.
+ return this["_processOSD"+this.contentType](data);
+ },
+
+ processItem: function(item, attribute){
+ // This returns the text that represents the item. If a developer wanted to customize
+ // how an individual item is rendered/parsed, they'd override this function.
+ return this["_processItem"+this.contentType](item.node, attribute);
+ },
+
+ _createSearchUrl: function(request){
+ var template = this.urlElement.attributes.getNamedItem("template").nodeValue;
+ var attrs = this.urlElement.attributes;
+ var index = template.indexOf("{searchTerms}");
+ template = template.substring(0, index) + request.query.searchTerms + template.substring(index+13);
+
+ array.forEach([ {'name': 'count', 'test': request.count, 'def': '10'},
+ {'name': 'startIndex', 'test': request.start, 'def': this.urlElement.attributes.getNamedItem("indexOffset")?this.urlElement.attributes.getNamedItem("indexOffset").nodeValue:0},
+ {'name': 'startPage', 'test': request.startPage, 'def': this.urlElement.attributes.getNamedItem("pageOffset")?this.urlElement.attributes.getNamedItem("pageOffset").nodeValue:0},
+ {'name': 'language', 'test': request.language, 'def': "*"},
+ {'name': 'inputEncoding', 'test': request.inputEncoding, 'def': 'UTF-8'},
+ {'name': 'outputEncoding', 'test': request.outputEncoding, 'def': 'UTF-8'}
+ ], function(item){
+ template = template.replace('{'+item.name+'}', item.test || item.def);
+ template = template.replace('{'+item.name+'?}', item.test || item.def);
+ });
+ return template;
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Fetch OpenSearch 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 using information from the request
+ var self = this;
+ var url = this._createSearchUrl(request);
+ var getArgs = {
+ url: url,
+ preventCache: this.urlPreventCache
+ };
+
+ // Change to fetch the query results.
+ var xhr = dxhr.get(getArgs);
+
+ xhr.addErrback(function(error){
+ errorHandler(error, request);
+ });
+
+ xhr.addCallback(function(data){
+ var items = [];
+ if(data){
+ //Process the items...
+ items = self.process(data);
+ for(var i=0; i < items.length; i++){
+ items[i] = {node: items[i]};
+ items[i][self._storeRef] = self;
+ }
+ }
+ fetchHandler(items, request);
+ });
+ },
+
+ _processOSDxml: function(data){
+ var div = window.doc.createElement("div");
+ div.innerHTML = data;
+ return query(this.itemPath, div);
+ },
+
+ _processItemxml: function(item, attribute){
+ if(attribute === "content"){
+ return item.innerHTML;
+ }
+ return undefined;
+ },
+
+ _processOSDatom: function(data){
+ return this._processOSDfeed(data, "entry");
+ },
+
+ _processItematom: function(item, attribute){
+ return this._processItemfeed(item, attribute, "content");
+ },
+
+ _processOSDrss: function(data){
+ return this._processOSDfeed(data, "item");
+ },
+
+ _processItemrss: function(item, attribute){
+ return this._processItemfeed(item, attribute, "description");
+ },
+
+ _processOSDfeed: function(data, type){
+ data = dojox.xml.parser.parse(data);
+ var items = [];
+ var nodeList = data.getElementsByTagName(type);
+ for(var i=0; i<nodeList.length; i++){
+ items.push(nodeList.item(i));
+ }
+ return items;
+ },
+
+ _processItemfeed: function(item, attribute, type){
+ if(attribute === "content"){
+ var content = item.getElementsByTagName(type).item(0);
+ return this._getNodeXml(content, true);
+ }
+ return undefined;
+ },
+
+ _getNodeXml: function(node, skipFirst){
+ var i;
+ switch(node.nodeType){
+ case 1:
+ var xml = [];
+ if(!skipFirst){
+ xml.push("<"+node.tagName);
+ var attr;
+ for(i=0; i<node.attributes.length; i++){
+ attr = node.attributes.item(i);
+ xml.push(" "+attr.nodeName+"=\""+attr.nodeValue+"\"");
+ }
+ xml.push(">");
+ }
+ for(i=0; i<node.childNodes.length; i++){
+ xml.push(this._getNodeXml(node.childNodes.item(i)));
+ }
+ if(!skipFirst){
+ xml.push("</"+node.tagName+">\n");
+ }
+ return xml.join("");
+ case 3:
+ case 4:
+ return node.nodeValue;
+ }
+ return undefined;
+ },
+
+ _processOsdd: function(doc){
+ var urlnodes = doc.getElementsByTagName("Url");
+ //TODO: Check all the urlnodes and determine what our best one is...
+ var types = [];
+ var contentType;
+ var i;
+ for(i=0; i<urlnodes.length; i++){
+ contentType = urlnodes[i].attributes.getNamedItem("type").nodeValue;
+ switch(contentType){
+ case "application/rss+xml":
+ types[i] = this.RSS_CONTENT_TYPE;
+ break;
+ case "application/atom+xml":
+ types[i] = this.ATOM_CONTENT_TYPE;
+ break;
+ default:
+ types[i] = this.XML_CONTENT_TYPE;
+ break;
+ }
+ }
+ var index = 0;
+ var currentType = types[0];
+ for(i=1; i<urlnodes.length; i++){
+ if(types[i]>currentType){
+ index = i;
+ currentType = types[i];
+ }
+ }
+
+ // We'll be using urlnodes[index] as it's the best option (ATOM > RSS > XML)
+ var label = urlnodes[index].nodeName.toLowerCase();
+ if(label == 'url'){
+ var urlattrs = urlnodes[index].attributes;
+ this.urlElement = urlnodes[index];
+ switch(types[index]){
+ case this.ATOM_CONTENT_TYPE:
+ this.contentType = this.ATOM_CONTENT_TYPE_STRING;
+ break;
+ case this.RSS_CONTENT_TYPE:
+ this.contentType = this.RSS_CONTENT_TYPE_STRING;
+ break;
+ case this.XML_CONTENT_TYPE:
+ this.contentType = this.XML_CONTENT_TYPE_STRING;
+ break;
+ }
+ }
+ }
+});
+return lang.extend(OpenSearchStore,simpleFetch);
+}); \ No newline at end of file
diff --git a/js/dojo-1.7.2/dojox/data/OpmlStore.js b/js/dojo-1.7.2/dojox/data/OpmlStore.js
new file mode 100644
index 0000000..b3d6111
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/OpmlStore.js
@@ -0,0 +1,526 @@
+//>>built
+define("dojox/data/OpmlStore", ["dojo/_base/declare", "dojo/_base/lang", "dojo/_base/xhr", "dojo/data/util/simpleFetch", "dojo/data/util/filter",
+ "dojo/_base/window"],
+ function(declare, lang, xhr, simpleFetch, filterUtil, winUtil) {
+
+var OpmlStore = 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";
+ if(keywordParameters && "urlPreventCache" in keywordParameters){
+ this.urlPreventCache = keywordParameters.urlPreventCache?true:false;
+ }
+ },
+
+ // label: [public] string
+ // The attribute of the Opml item to act as a label.
+ label: "text",
+
+ // url: [public] string
+ // The location from which to fetch the Opml document.
+ url: "",
+
+ // urlPreventCache: [public] boolean
+ // Flag to denote if the underlying xhrGet call should set preventCache.
+ urlPreventCache: false,
+
+ _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(!lang.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 = filterUtil.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] = filterUtil.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",
+ preventCache: self.urlPreventCache
+ };
+ var getHandler = xhr.get(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 = xhr.get(getArgs);
+ getHandler.addCallback(function(data){
+ var scope = keywordArgs.scope ? keywordArgs.scope : winUtil.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 : winUtil.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 : winUtil.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 : winUtil.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.
+lang.extend(OpmlStore, simpleFetch);
+
+return OpmlStore;
+});
+
diff --git a/js/dojo-1.7.2/dojox/data/PersevereStore.js b/js/dojo-1.7.2/dojox/data/PersevereStore.js
new file mode 100644
index 0000000..9818001
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/PersevereStore.js
@@ -0,0 +1,113 @@
+//>>built
+define("dojox/data/PersevereStore", ["dojo", "dojox", "require", "dojox/data/JsonQueryRestStore", "dojox/rpc/Client", "dojo/_base/url"], function(dojo, dojox, require) {
+
+// PersevereStore is an extension of JsonRestStore to handle Persevere's special features
+
+dojox.json.ref.serializeFunctions = true; // Persevere supports persisted functions
+
+dojo.declare("dojox.data.PersevereStore",dojox.data.JsonQueryRestStore,{
+ useFullIdInQueries: true, // in JSONQuerys use the full id
+ jsonQueryPagination: false // use the Range headers instead
+});
+
+dojox.data.PersevereStore.getStores = function(/*String?*/path,/*Boolean?*/sync){
+ // summary:
+ // Creates Dojo data stores for all the table/classes on a Persevere server
+ // path:
+ // URL of the Persevere server's root, this normally just "/"
+ // which is the default value if the target is not provided
+ // sync:
+ // Indicates that the operation should happen synchronously.
+ // return:
+ // A map/object of datastores will be returned if it is performed asynchronously,
+ // otherwise it will return a Deferred object that will provide the map/object.
+ // The name of each property is a the name of a store,
+ // and the value is the actual data store object.
+ path = (path && (path.match(/\/$/) ? path : (path + '/'))) || '/';
+ if(path.match(/^\w*:\/\//)){
+ // if it is cross-domain, we will use window.name for communication
+ require("dojox/io/xhrScriptPlugin");
+ dojox.io.xhrScriptPlugin(path, "callback", dojox.io.xhrPlugins.fullHttpAdapter);
+ }
+ var plainXhr = dojo.xhr;
+ dojo.xhr = function(method,args){
+ (args.headers = args.headers || {})['Server-Methods'] = "false";
+ return plainXhr.apply(dojo,arguments);
+ }
+ var rootService= dojox.rpc.Rest(path,true);
+ dojox.rpc._sync = sync;
+ var dfd = rootService("Class/");//dojo.xhrGet({url: target, sync:!callback, handleAs:'json'});
+ var results;
+ var stores = {};
+ var callId = 0;
+ dfd.addCallback(function(schemas){
+ dojox.json.ref.resolveJson(schemas, {
+ index: dojox.rpc.Rest._index,
+ idPrefix: "/Class/",
+ assignAbsoluteIds: true
+ });
+ function setupHierarchy(schema){
+ if(schema['extends'] && schema['extends'].prototype){
+ if(!schema.prototype || !schema.prototype.isPrototypeOf(schema['extends'].prototype)){
+ setupHierarchy(schema['extends']);
+ dojox.rpc.Rest._index[schema.prototype.__id] = schema.prototype = dojo.mixin(dojo.delegate(schema['extends'].prototype), schema.prototype);
+ }
+ }
+ }
+ function setupMethods(methodsDefinitions, methodsTarget){
+ if(methodsDefinitions && methodsTarget){
+ for(var j in methodsDefinitions){
+ var methodDef = methodsDefinitions[j];
+ // if any method definitions indicate that the method should run on the server, than add
+ // it to the prototype as a JSON-RPC method
+ if(methodDef.runAt != "client" && !methodsTarget[j]){
+ methodsTarget[j] = (function(methodName){
+ return function(){
+ // execute a JSON-RPC call
+ var deferred = dojo.rawXhrPost({
+ url: this.__id,
+ // the JSON-RPC call
+ postData: dojox.json.ref.toJson({
+ method: methodName,
+ id: callId++,
+ params: dojo._toArray(arguments)
+ }),
+ handleAs: "json"
+ });
+ deferred.addCallback(function(response){
+ // handle the response
+ return response.error ?
+ new Error(response.error) :
+ response.result;
+ });
+ return deferred;
+ }
+ })(j);
+ }
+ }
+ }
+ }
+ for(var i in schemas){
+ if(typeof schemas[i] == 'object'){
+ var schema = schemas[i];
+ setupHierarchy(schema);
+ setupMethods(schema.methods, schema.prototype = schema.prototype || {});
+ setupMethods(schema.staticMethods, schema);
+ stores[schemas[i].id] = new dojox.data.PersevereStore({target:new dojo._Url(path,schemas[i].id) + '/',schema:schema});
+ }
+ }
+ return (results = stores);
+ });
+ dojo.xhr = plainXhr;
+ return sync ? results : dfd;
+};
+dojox.data.PersevereStore.addProxy = function(){
+ // summary:
+ // Invokes the XHR proxy plugin. Call this if you will be using x-site data.
+ require("dojox/io/xhrPlugins"); // also not necessary, but we can register that Persevere supports proxying
+ dojox.io.xhrPlugins.addProxy("/proxy/");
+};
+
+return dojox.data.PersevereStore;
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/PicasaStore.js b/js/dojo-1.7.2/dojox/data/PicasaStore.js
new file mode 100644
index 0000000..12527f1
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/PicasaStore.js
@@ -0,0 +1,274 @@
+//>>built
+define("dojox/data/PicasaStore", ["dojo/_base/lang","dojo/_base/declare", "dojo/_base/connect", "dojo/io/script", "dojo/data/util/simpleFetch", "dojo/date/stamp"],
+ function(lang, declare, connect, scriptIO, simpleFetch, dateStamp) {
+
+var PicasaStore = 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;
+ }
+ if(args && "urlPreventCache" in args){
+ this.urlPreventCache = args.urlPreventCache?true:false;
+ }
+ if(args && "maxResults" in args){
+ this.maxResults = parseInt(args.maxResults);
+ if(!this.maxResults){
+ this.maxResults = 20;
+ }
+ }
+ },
+
+ _picasaUrl: "http://picasaweb.google.com/data/feed/api/all",
+
+ _storeRef: "_S",
+
+ //label: string
+ //The attribute to use from the picasa item as its label.
+ label: "title",
+
+ //urlPreventCache: boolean
+ //Flag denoting if preventCache should be passed to io.script.
+ urlPreventCache: false,
+
+ //maxResults: Define out how many results to return for a fetch.
+ maxResults: 20,
+
+ _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, defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ if(values && values.length > 0){
+ return values[0];
+ }
+ return defaultValue;
+ },
+
+ 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", "imageUrlSmall", "imageUrlMedium",
+ "imageUrl", "datePublished", "dateTaken","description"];
+ },
+
+ 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 [dateAtamp.fromISOString(item.published)];
+ }else if(attribute === "dateTaken"){
+ return [dateStamp.fromISOString(item.published)];
+ }else if(attribute === "updated"){
+ return [dateStamp.fromISOString(item.updated)];
+ }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 [];
+ },
+
+ 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;
+ }
+ content['max-results'] = this.maxResults;
+
+ //Linking this up to Picasa is a JOY!
+ var self = this;
+ var handle = null;
+ var myHandler = function(data){
+ if(handle !== null){
+ connect.disconnect(handle);
+ }
+
+ //Process the items...
+ fetchHandler(self._processPicasaData(data), request);
+ };
+ var getArgs = {
+ url: this._picasaUrl,
+ preventCache: this.urlPreventCache,
+ content: content,
+ callbackParamName: 'callback',
+ handle: myHandler
+ };
+ var deferred = scriptIO.get(getArgs);
+
+ deferred.addErrback(function(error){
+ connect.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
+ if(str){
+ str = str.replace(/&amp;/gm, "&").replace(/&lt;/gm, "<").replace(/&gt;/gm, ">").replace(/&quot;/gm, "\"");
+ str = str.replace(/&#39;/gm, "'");
+ }
+ return str;
+ }
+});
+lang.extend(PicasaStore, simpleFetch);
+
+return PicasaStore;
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/QueryReadStore.js b/js/dojo-1.7.2/dojox/data/QueryReadStore.js
new file mode 100644
index 0000000..372048a
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/QueryReadStore.js
@@ -0,0 +1,519 @@
+//>>built
+define("dojox/data/QueryReadStore", ["dojo", "dojox", "dojo/data/util/sorter", "dojo/string"], function(dojo, dojox) {
+
+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.
+ //
+ // example:
+ // | // 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 how many rows we have so that we can pass it to a clientPaging handler
+ _numRows:-1,
+
+ // 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;
+ }
+ }
+ 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 && self.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
+ },
+
+ _xhrFetchHandler: function(data, request, fetchHandler, errorHandler){
+ 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;
+ var i;
+ 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 = this._numRows = (numRows === -1) ? this._items.length : numRows;
+ fetchHandler(this._items, request, numRows);
+ this._numRows = numRows;
+ },
+
+ _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 && request.sort){
+ var sortInfo = [];
+ dojo.forEach(request.sort, function(sort){
+ if(sort && sort.attribute){
+ sortInfo.push((sort.descending ? "-" : "") + sort.attribute);
+ }
+ });
+ serverQuery.sort = sortInfo.join(',');
+ }
+ // 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)
+ ){
+ this._numRows = (this._numRows === -1) ? this._items.length : this._numRows;
+ fetchHandler(this._items, request, this._numRows);
+ }else{
+ var xhrFunc = this.requestMethod.toLowerCase() == "post" ? dojo.xhrPost : dojo.xhrGet;
+ var xhrHandler = xhrFunc({url:this.url, handleAs:"json-comment-optional", content:serverQuery, failOk: true});
+ request.abort = function(){
+ xhrHandler.cancel();
+ };
+ xhrHandler.addCallback(dojo.hitch(this, function(data){
+ this._xhrFetchHandler(data, request, fetchHandler, errorHandler);
+ }));
+ 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, errorData);
+ }
+ };
+
+ // 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];
+ }
+ }
+);
+
+return dojox.data.QueryReadStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/README b/js/dojo-1.7.2/dojox/data/README
new file mode 100644
index 0000000..4641983
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/README
@@ -0,0 +1,127 @@
+-------------------------------------------------------------------------------
+DojoX Data
+-------------------------------------------------------------------------------
+Version 1.1
+Release date: 03/18/2008
+-------------------------------------------------------------------------------
+Project state: production
+-------------------------------------------------------------------------------
+Project authors
+ Jared Jurkiewicz (jared.jurkiewicz@gmail.com) (FileStore, HtmlStore, XmlStore, FlickrStore, CssRuleStore, CssClassStore, AppStore, others).
+ Shane O'Sullivan (shaneosullivan1@gmail.com) (FlickrRestStore, AtomReadStore, GoogleSeachStore, GoogleFeedStore)
+ Wolfram Kriesing (wolfram@kriesing.de) (QueryReadStore)
+ Dustin Machi (dmachi@dojotolkit.org) (jsonPathStore);
+ Russell Jones (KeyValueStore) (CLA)
+ Benjamin Schell (KeyValueStore, CssRuleStore, CssClassStore, AppStore, OpenSearchStore) (Corporate CLA)
+ Kurt Stutsman (kurt@snaplogic.org) (SnapLogicStore)
+ Kris Zyp (kzyp@dojotoolkit.org) (JsonRestStore, PersevereStore, S3JsonRestStore, CouchDBRestStore)
+ Frank Fortson (frank.fortson@equorum.com) (AndOrReadStore, AndOrWriteStore)
+
+
+-------------------------------------------------------------------------------
+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), dojox.xml for XmlStore
+and dojox.data.dom(deprecated) 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.
+
+ dojox.data.JsonRestStore - Store to interface with RESTful HTTP/JSON web services.
+ dojox.data.PersevereStore - Extension of JsonRestStore for Persevere
+ dojox.data.CouchDBRestStore - Extension of JsonRestStore for CouchDB
+ dojox.data.S3JsonRestStore - Extension of JsonRestStore for Amazon S3
+ dojox.data.GoogleSearchStore - Store to interface Google's AJAX search services.
+ There are many subclasses of this store for particular types of searches:
+ dojox.data.GoogleWebSearchStore
+ dojox.data.GoogleBlogSearchStore
+ dojox.data.GoogleLocalSearchStore
+ dojox.data.GoogleVideoSearchStore
+ dojox.data.GoogleNewsSearchStore
+ dojox.data.GoogleBookSearchStore
+ dojox.data.GoogleImageSearchStore
+
+ dojox.data.AndOrReadStore - Demonstrating a more complex query format allowing AND/OR.
+ Based directly on dojo.data.ItemFileReadStore.
+
+ dojox.data.AndOrWriteStore - Demonstrating a more complex query format allowing AND/OR.
+ Based directly on dojo.data.ItemFileWriteStore.
+
+ dojox.data.FileStore - A lazy-loading store designed for searching filesystems with a provided
+ PHP back end. Implements dojo.data.api.Read and dojo.data.api.Identity
+
+ dojox.data.CssRuleStore - A store that allows searching/querying over Css rules loaded in the page in
+ the browser.
+
+ dojox.data.CssClassStore - A store that allows searching/querying over what classes are defined in the page in
+ the browser.
+
+ dojox.data.AppStore - A store that implements full read, write, and identity APIs for working with ATOM documents.
+ The store uses the full APP protocol.
+
+ dojox.data.OpenSearchStore - A store that implements OpenSearch provider search capability.
+
diff --git a/js/dojo-1.7.2/dojox/data/RailsStore.js b/js/dojo-1.7.2/dojox/data/RailsStore.js
new file mode 100644
index 0000000..74ece87
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/RailsStore.js
@@ -0,0 +1,169 @@
+//>>built
+define("dojox/data/RailsStore", ["dojo", "dojox", "dojox/data/JsonRestStore"], function(dojo, dojox) {
+
+// Contains code donated by Travis Tilley under CLA
+dojo.declare("dojox.data.RailsStore", dojox.data.JsonRestStore, {
+ constructor: function(){
+ // summary:
+ // RailsStore is a data store for interacting with RESTful Rails controllers
+ },
+ preamble: function(options){
+ if(typeof options.target == 'string' && !options.service){
+ var target = options.target.replace(/\/$/g, '');
+
+ // Special getRequest handler for handling content type negotiation via
+ // the Rails format extension, as well as properly setting the ID param
+ // in the URL.
+ var getRequest = function(id, args){
+ args = args || {};
+ var url = target;
+ var query;
+ var ident;
+
+ if(dojo.isObject(id)){
+ ident = '';
+ query = '?' + dojo.objectToQuery(id);
+ }else if(args.queryStr && args.queryStr.indexOf('?') != -1){
+ ident = args.queryStr.replace(/\?.*/, '');
+ query = args.queryStr.replace(/[^?]*\?/g, '?');
+ }else if(dojo.isString(args.query) && args.query.indexOf('?') != -1){
+ ident = args.query.replace(/\?.*/, '');
+ query = args.query.replace(/[^?]*\?/g, '?');
+ }else{
+ ident = id ? id.toString() : '';
+ query = '';
+ }
+
+ if(ident.indexOf('=') != -1){
+ query = ident;
+ ident = '';
+ }
+
+ if(ident){
+ url = url + '/' + ident + '.json' + query;
+ }else{
+ url = url + '.json' + query;
+ }
+
+ var isSync = dojox.rpc._sync;
+ dojox.rpc._sync = false;
+
+ return {
+ url : url,
+ handleAs : 'json',
+ contentType : 'application/json',
+ sync : isSync,
+ headers : {
+ Accept : 'application/json,application/javascript',
+ Range : args && (args.start >= 0 || args.count >= 0)
+ ? "items="
+ + (args.start || '0')
+ + '-'
+ + ((args.count && (args.count
+ + (args.start || 0) - 1)) || '')
+ : undefined
+ }
+ };
+ };
+
+ options.service = dojox.rpc.Rest(this.target, true, null,
+ getRequest);
+ }
+ },
+ fetch: function(args){
+ args = args || {};
+ function addToQueryStr(obj){
+ function buildInitialQueryString(){
+ if(args.queryStr == null){
+ args.queryStr = '';
+ }
+ if(dojo.isObject(args.query)){
+ args.queryStr = '?' + dojo.objectToQuery(args.query);
+ }else if(dojo.isString(args.query)){
+ args.queryStr = args.query;
+ }
+ }
+ function separator(){
+ if(args.queryStr.indexOf('?') == -1){
+ return '?';
+ }else{
+ return '&';
+ }
+ }
+ if(args.queryStr == null){
+ buildInitialQueryString();
+ }
+ args.queryStr = args.queryStr + separator() + dojo.objectToQuery(obj);
+ }
+ if(args.start || args.count){
+ // in addition to the content range headers, also provide query parameters for use
+ // with the will_paginate plugin if so desired.
+ if((args.start || 0) % args.count){
+ throw new Error("The start parameter must be a multiple of the count parameter");
+ }
+ addToQueryStr({
+ page: ((args.start || 0) / args.count) + 1,
+ per_page: args.count
+ });
+ }
+ if(args.sort){
+ // make the sort into query parameters
+ var queryObj = {
+ sortBy : [],
+ sortDir : []
+ };
+
+ dojo.forEach(args.sort, function(item){
+ queryObj.sortBy.push(item.attribute);
+ queryObj.sortDir.push(!!item.descending ? 'DESC' : 'ASC');
+ });
+
+ addToQueryStr(queryObj);
+ delete args.sort;
+ }
+
+ return this.inherited(arguments);
+ },
+ _processResults: function(results, deferred){
+ var items;
+
+ /*
+ * depending on the ActiveRecord::Base.include_root_in_json setting,
+ * you might get back an array of attribute objects, or an array of
+ * objects with the attribute object nested under an attribute having
+ * the same name as the (remote and unguessable) model class.
+ *
+ * 'Example' without root_in_json: [{'id':1, 'text':'first'}]
+ * 'Example' with root_in_json: [{'example':{'id':1, 'text':'first'}}]
+ */
+ if((typeof this.rootAttribute == 'undefined') && results[0]){
+ if(results[0][this.idAttribute]){
+ this.rootAttribute = false;
+ console.debug('RailsStore: without root_in_json');
+ }else{
+ for(var attribute in results[0]){
+ if(results[0][attribute][this.idAttribute]){
+ this.rootAttribute = attribute;
+ console.debug('RailsStore: with root_in_json, attribute: ' + attribute);
+ }
+ }
+ }
+ }
+
+ if(this.rootAttribute){
+ items = dojo.map(results, function(item){
+ return item[this.rootAttribute];
+ }, this);
+ }else{
+ items = results;
+ }
+
+ // index the results
+ var count = results.length;
+ // if we don't know the length, and it is partial result, we will guess that it is twice as big, that will work for most widgets
+ return {totalCount:deferred.fullLength || (deferred.request.count == count ? (deferred.request.start || 0) + count * 2 : count), items: items};
+ }
+});
+
+return dojox.data.RailsStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/S3Store.js b/js/dojo-1.7.2/dojox/data/S3Store.js
new file mode 100644
index 0000000..0a32385
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/S3Store.js
@@ -0,0 +1,35 @@
+//>>built
+define("dojox/data/S3Store", ["dojo/_base/declare", "dojox/data/JsonRestStore", "dojox/rpc/ProxiedPath"],
+ function(declare, JsonRestStore, ProxiedPath) {
+
+// S3JsonRestStore is an extension of JsonRestStore to handle
+// Amazon's S3 service using JSON data
+/*===== var JsonRestStore = dojox.data.JsonRestStore =====*/
+return declare("dojox.data.S3Store", JsonRestStore,
+ {
+ _processResults : function(results){
+ // unfortunately, S3 returns query results in XML form
+ var keyElements = results.getElementsByTagName("Key");
+ var jsResults = [];
+ var self = this;
+ for(var i=0; i <keyElements.length;i++){
+ var keyElement = keyElements[i];
+ // manually create lazy loaded Deferred items for each item in the result array
+ var val = {
+ _loadObject: (function(key,val){
+ return function(callback){
+ // when a callback is added we will fetch it
+ delete this._loadObject;
+ self.service(key).addCallback(callback);
+ };
+ })(keyElement.firstChild.nodeValue,val)
+ };
+ jsResults.push(val);
+ }
+
+ return {totalCount:jsResults.length, items: jsResults};
+ }
+ }
+);
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/ServiceStore.js b/js/dojo-1.7.2/dojox/data/ServiceStore.js
new file mode 100644
index 0000000..1fe2b33
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/ServiceStore.js
@@ -0,0 +1,395 @@
+//>>built
+define("dojox/data/ServiceStore", ["dojo/_base/declare", "dojo/_base/lang", "dojo/_base/array"],
+ function(declare, lang, array) {
+
+// note that dojox.rpc.Service is not required, you can create your own services
+
+// A ServiceStore is a readonly data store that provides a data.data interface to an RPC service.
+// var myServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd"));
+// var serviceStore = new dojox.data.ServiceStore({service:myServices.ServiceStore});
+//
+// The ServiceStore also supports lazy loading. References can be made to objects that have not been loaded.
+// For example if a service returned:
+// {"name":"Example","lazyLoadedObject":{"$ref":"obj2"}}
+//
+// And this object has accessed using the dojo.data API:
+// var obj = serviceStore.getValue(myObject,"lazyLoadedObject");
+// The object would automatically be requested from the server (with an object id of "obj2").
+//
+
+return declare("dojox.data.ServiceStore",
+ // ClientFilter is intentionally not required, ServiceStore does not need it, and is more
+ // lightweight without it, but if it is provided, the ServiceStore will use it.
+ lang.getObject("dojox.data.ClientFilter", 0)||null,{
+ service: null,
+ constructor: function(options){
+ //summary:
+ // ServiceStore constructor, instantiate a new ServiceStore
+ // A ServiceStore can be configured from a JSON Schema. Queries are just
+ // passed through to the underlying services
+ //
+ // options:
+ // Keyword arguments
+ // The *schema* parameter
+ // This is a schema object for this store. This should be JSON Schema format.
+ //
+ // The *service* parameter
+ // This is the service object that is used to retrieve lazy data and save results
+ // The function should be directly callable with a single parameter of an object id to be loaded
+ //
+ // The *idAttribute* parameter
+ // 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.
+ //
+ // The *estimateCountFactor* parameter
+ // This parameter is used by the ServiceStore to estimate the total count. When
+ // paging is indicated in a fetch and the response includes the full number of items
+ // requested by the fetch's count parameter, then the total count will be estimated
+ // to be estimateCountFactor multiplied by the provided count. If this is 1, then it is assumed that the server
+ // does not support paging, and the response is the full set of items, where the
+ // total count is equal to the numer of items returned. If the server does support
+ // paging, an estimateCountFactor of 2 is a good value for estimating the total count
+ // It is also possible to override _processResults if the server can provide an exact
+ // total count.
+ //
+ // The *syncMode* parameter
+ // Setting this to true will set the store to using synchronous calls by default.
+ // Sync calls return their data immediately from the calling function, so
+ // callbacks are unnecessary. This will only work with a synchronous capable service.
+ //
+ // description:
+ // ServiceStore can do client side caching and result set updating if
+ // dojox.data.ClientFilter is loaded. Do this add:
+ // | dojo.require("dojox.data.ClientFilter")
+ // prior to loading the ServiceStore (ClientFilter must be loaded before ServiceStore).
+ // To utilize client side filtering with a subclass, you can break queries into
+ // client side and server side components by putting client side actions in
+ // clientFilter property in fetch calls. For example you could override fetch:
+ // | fetch: function(args){
+ // | // do the sorting and paging on the client side
+ // | args.clientFilter = {start:args.start, count: args.count, sort: args.sort};
+ // | // args.query will be passed to the service object for the server side handling
+ // | return this.inherited(arguments);
+ // | }
+ // When extending this class, if you would like to create lazy objects, you can follow
+ // the example from dojox.data.tests.stores.ServiceStore:
+ // | var lazyItem = {
+ // | _loadObject: function(callback){
+ // | this.name="loaded";
+ // | delete this._loadObject;
+ // | callback(this);
+ // | }
+ // | };
+ //setup a byId alias to the api call
+ this.byId=this.fetchItemByIdentity;
+ this._index = {};
+ // if the advanced json parser is enabled, we can pass through object updates as onSet events
+ if(options){
+ lang.mixin(this,options);
+ }
+ // We supply a default idAttribute for parser driven construction, but if no id attribute
+ // is supplied, it should be null so that auto identification takes place properly
+ this.idAttribute = (options && options.idAttribute) || (this.schema && this.schema._idAttr);
+ },
+ schema: null,
+ idAttribute: "id",
+ labelAttribute: "label",
+ syncMode: false,
+ estimateCountFactor: 1,
+ getSchema: function(){
+ return this.schema;
+ },
+
+ loadLazyValues:true,
+
+ getValue: function(/*Object*/ item, /*String*/property, /*value?*/defaultValue){
+ // summary:
+ // Gets the value of an item's 'property'
+ //
+ // item:
+ // The item to get the value from
+ // property:
+ // property to look up value for
+ // defaultValue:
+ // the default value
+
+ var value = item[property];
+ return value || // return the plain value since it was found;
+ (property in item ? // a truthy value was not found, see if we actually have it
+ value : // we do, so we can return it
+ item._loadObject ? // property was not found, maybe because the item is not loaded, we will try to load it synchronously so we can get the property
+ (dojox.rpc._sync = true) && arguments.callee.call(this,dojox.data.ServiceStore.prototype.loadItem({item:item}) || {}, property, defaultValue) : // load the item and run getValue again
+ defaultValue);// not in item -> return default value
+ },
+ 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
+
+ var val = this.getValue(item,property);
+ return val instanceof Array ? val : val === undefined ? [] : [val];
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // Gets the available attributes of an item's 'property' and returns
+ // it as an array.
+ //
+ // item: /* object */
+
+ var res = [];
+ for(var i in item){
+ if(item.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_')){
+ res.push(i);
+ }
+ }
+ return res;
+ },
+
+ hasAttribute: function(item,attribute){
+ // summary:
+ // Checks to see if item has attribute
+ //
+ // item: /* object */
+ // attribute: /* string */
+ return attribute in item;
+ },
+
+ containsValue: function(item, attribute, value){
+ // summary:
+ // Checks to see if 'item' has 'value' at 'attribute'
+ //
+ // item: /* object */
+ // attribute: /* string */
+ // value: /* anything */
+ return array.indexOf(this.getValues(item,attribute),value) > -1;
+ },
+
+
+ isItem: function(item){
+ // summary:
+ // Checks to see if the argument is an item
+ //
+ // item: /* object */
+ // attribute: /* string */
+
+ // we have no way of determining if it belongs, we just have object returned from
+ // service queries
+ return (typeof item == 'object') && item && !(item instanceof Date);
+ },
+
+ isItemLoaded: function(item){
+ // summary:
+ // Checks to see if the item is loaded.
+ //
+ // item: /* object */
+
+ return item && !item._loadObject;
+ },
+
+ loadItem: function(args){
+ // summary:
+ // Loads an item and calls the callback handler. Note, that this will call the callback
+ // handler even if the item is loaded. Consequently, you can use loadItem to ensure
+ // that an item is loaded is situations when the item may or may not be loaded yet.
+ // If you access a value directly through property access, you can use this to load
+ // a lazy value as well (doesn't need to be an item).
+ //
+ // example:
+ // store.loadItem({
+ // item: item, // this item may or may not be loaded
+ // onItem: function(item){
+ // // do something with the item
+ // }
+ // });
+
+ var item;
+ if(args.item._loadObject){
+ args.item._loadObject(function(result){
+ item = result; // in synchronous mode this can allow loadItem to return the value
+ delete item._loadObject;
+ var func = result instanceof Error ? args.onError : args.onItem;
+ if(func){
+ func.call(args.scope, result);
+ }
+ });
+ }else if(args.onItem){
+ // even if it is already loaded, we will use call the callback, this makes it easier to
+ // use when it is not known if the item is loaded (you can always safely call loadItem).
+ args.onItem.call(args.scope, args.item);
+ }
+ return item;
+ },
+ _currentId : 0,
+ _processResults : function(results, deferred){
+ // this should return an object with the items as an array and the total count of
+ // items (maybe more than currently in the result set).
+ // for example:
+ // | {totalCount:10, items: [{id:1},{id:2}]}
+
+ // index the results, assigning ids as necessary
+
+ if(results && typeof results == 'object'){
+ var id = results.__id;
+ if(!id){// if it hasn't been assigned yet
+ if(this.idAttribute){
+ // use the defined id if available
+ id = results[this.idAttribute];
+ }else{
+ id = this._currentId++;
+ }
+ if(id !== undefined){
+ var existingObj = this._index[id];
+ if(existingObj){
+ for(var j in existingObj){
+ delete existingObj[j]; // clear it so we can mixin
+ }
+ results = lang.mixin(existingObj,results);
+ }
+ results.__id = id;
+ this._index[id] = results;
+ }
+ }
+ for(var i in results){
+ results[i] = this._processResults(results[i], deferred).items;
+ }
+ var count = results.length;
+ }
+ return {totalCount: deferred.request.count == count ? (deferred.request.start || 0) + count * this.estimateCountFactor : count, items: results};
+ },
+ close: function(request){
+ return request && request.abort && request.abort();
+ },
+ fetch: function(args){
+ // summary:
+ // See dojo.data.api.Read.fetch
+ //
+ // The *queryOptions.cache* parameter
+ // If true, indicates that the query result should be cached for future use. This is only available
+ // if dojox.data.ClientFilter has been loaded before the ServiceStore
+ //
+ // The *syncMode* parameter
+ // Indicates that the call should be fetch synchronously if possible (this is not always possible)
+ //
+ // The *clientFetch* parameter
+ // This is a fetch keyword argument for explicitly doing client side filtering, querying, and paging
+
+ args = args || {};
+
+ if("syncMode" in args ? args.syncMode : this.syncMode){
+ dojox.rpc._sync = true;
+ }
+ var self = this;
+
+ var scope = args.scope || self;
+ var defResult = this.cachingFetch ? this.cachingFetch(args) : this._doQuery(args);
+ defResult.request = args;
+ defResult.addCallback(function(results){
+ if(args.clientFetch){
+ results = self.clientSideFetch({query:args.clientFetch,sort:args.sort,start:args.start,count:args.count},results);
+ }
+ var resultSet = self._processResults(results, defResult);
+ results = args.results = resultSet.items;
+ if(args.onBegin){
+ args.onBegin.call(scope, resultSet.totalCount, 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, args.onItem ? null : results, args);
+ }
+ return results;
+ });
+ defResult.addErrback(args.onError && function(err){
+ return args.onError.call(scope, err, args);
+ });
+ args.abort = function(){
+ // abort the request
+ defResult.cancel();
+ };
+ args.store = this;
+ return args;
+ },
+ _doQuery: function(args){
+ var query= typeof args.queryStr == 'string' ? args.queryStr : args.query;
+ return this.service(query);
+ },
+ getFeatures: function(){
+ // summary:
+ // return the store feature set
+
+ return {
+ "dojo.data.api.Read": true,
+ "dojo.data.api.Identity": true,
+ "dojo.data.api.Schema": this.schema
+ };
+ },
+
+ getLabel: function(item){
+ // summary
+ // returns the label for an item. Just gets the "label" attribute.
+ //
+ return this.getValue(item,this.labelAttribute);
+ },
+
+ getLabelAttributes: function(item){
+ // summary:
+ // returns an array of attributes that are used to create the label of an item
+ return [this.labelAttribute];
+ },
+
+ //Identity API Support
+
+
+ getIdentity: function(item){
+ return item.__id;
+ },
+
+ 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, by looking in our index of what we have loaded
+ var item = this._index[(args._prefix || '') + args.identity];
+ if(item){
+ // the item exists in the index
+ if(item._loadObject){
+ // we have a handle on the item, but it isn't loaded yet, so we need to load it
+ args.item = item;
+ return this.loadItem(args);
+ }else if(args.onItem){
+ // it's already loaded, so we can immediately callback
+ args.onItem.call(args.scope, item);
+ }
+ }else{
+ // convert the different spellings
+ return this.fetch({
+ query: args.identity,
+ onComplete: args.onItem,
+ onError: args.onError,
+ scope: args.scope
+ }).results;
+ }
+ return item;
+ }
+
+ }
+);
+});
diff --git a/js/dojo-1.7.2/dojox/data/SnapLogicStore.js b/js/dojo-1.7.2/dojox/data/SnapLogicStore.js
new file mode 100644
index 0000000..993f361
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/SnapLogicStore.js
@@ -0,0 +1,329 @@
+//>>built
+define("dojox/data/SnapLogicStore", ["dojo", "dojox", "dojo/io/script", "dojo/data/util/sorter"], function(dojo, dojox) {
+
+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, defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ var i = dojo.indexOf(item.attributes, attribute);
+ if(i !== -1){
+ return item.values[i];
+ }
+ return defaultValue;
+ },
+
+ 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);
+ var i = dojo.indexOf(item.attributes, attribute);
+ if(i !== -1){
+ return [item.values[i]]; // Array
+ }
+ return [];
+ },
+
+ 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){
+ var 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.
+ var 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
+ }
+});
+
+return dojox.data.SnapLogicStore;
+});
+
diff --git a/js/dojo-1.7.2/dojox/data/StoreExplorer.js b/js/dojo-1.7.2/dojox/data/StoreExplorer.js
new file mode 100644
index 0000000..14581b6
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/StoreExplorer.js
@@ -0,0 +1,196 @@
+//>>built
+// wrapped by build app
+define("dojox/data/StoreExplorer", ["dijit","dojo","dojox","dojo/require!dojox/grid/DataGrid,dojox/data/ItemExplorer,dijit/layout/BorderContainer,dijit/layout/ContentPane"], function(dijit,dojo,dojox){
+dojo.provide("dojox.data.StoreExplorer");
+dojo.require("dojox.grid.DataGrid");
+dojo.require("dojox.data.ItemExplorer");
+dojo.require("dijit.layout.BorderContainer");
+dojo.require("dijit.layout.ContentPane");
+
+dojo.declare("dojox.data.StoreExplorer", dijit.layout.BorderContainer, {
+ constructor: function(options){
+ dojo.mixin(this, options);
+ },
+ store: null,
+ columnWidth: '',
+ stringQueries: false,
+ showAllColumns: false,
+ postCreate: function(){
+ var self = this;
+ this.inherited(arguments);
+ var contentPane = new dijit.layout.ContentPane({
+ region:'top'
+ }).placeAt(this);
+ function addButton(name, action){
+ var button = new dijit.form.Button({label: name});
+ contentPane.containerNode.appendChild(button.domNode);
+ button.onClick = action;
+ return button;
+ }
+ var queryText = contentPane.containerNode.appendChild(document.createElement("span"));
+ queryText.innerHTML = "Enter query: &nbsp;";
+ queryText.id = "queryText";
+ var queryTextBox = contentPane.containerNode.appendChild(document.createElement("input"));
+ queryTextBox.type = "text";
+ queryTextBox.id = "queryTextBox";
+ addButton("Query",function(){
+ var query = queryTextBox.value;
+ self.setQuery(self.stringQueries ? query : dojo.fromJson(query));
+ });
+ contentPane.containerNode.appendChild(document.createElement("span")).innerHTML = "&nbsp;&nbsp;&nbsp;";
+ var createNewButton = addButton("Create New", dojo.hitch(this, "createNew"));
+ var deleteButton = addButton("Delete",function(){
+ var items = grid.selection.getSelected();
+ for(var i = 0; i < items.length; i++){
+ self.store.deleteItem(items[i]);
+ }
+ });
+ this.setItemName = function(name){
+ createNewButton.attr('label',"<img style='width:12px; height:12px' src='" + dojo.moduleUrl("dijit.themes.tundra.images","dndCopy.png") + "' /> Create New " + name);
+ deleteButton.attr('label',"Delete " + name);
+ };
+ addButton("Save",function(){
+ self.store.save({onError:function(error){
+ alert(error);
+ }});
+ //refresh the tree
+ self.tree.refreshItem();
+ });
+ addButton("Revert",function(){
+ self.store.revert();
+ });
+ addButton("Add Column", function(){
+ var columnName = prompt("Enter column name:","property");
+ if(columnName){
+ self.gridLayout.push({
+ field: columnName,
+ name: columnName,
+ formatter: dojo.hitch(self,"_formatCell"),
+ editable: true
+ });
+ self.grid.attr("structure",self.gridLayout);
+ }
+ });
+ var centerCP = new dijit.layout.ContentPane({
+ region:'center'
+ }).placeAt(this);
+ var grid = this.grid = new dojox.grid.DataGrid(
+ {store: this.store}
+ );
+ centerCP.attr("content", grid);
+ grid.canEdit = function(inCell, inRowIndex){
+ var value = this._copyAttr(inRowIndex, inCell.field);
+ return !(value && typeof value == 'object') || value instanceof Date;
+ }
+
+ var trailingCP = new dijit.layout.ContentPane({
+ region: 'trailing',
+ splitter: true,
+ style: "width: 300px"
+ }).placeAt(this);
+
+ var tree = this.tree = new dojox.data.ItemExplorer({
+ store: this.store}
+ );
+ trailingCP.attr("content", tree);
+
+ dojo.connect(grid, "onCellClick", function(){
+ var selected = grid.selection.getSelected()[0];
+ tree.setItem(selected);
+ });
+
+ this.gridOnFetchComplete = grid._onFetchComplete;
+ this.setStore(this.store);
+ },
+ setQuery: function(query, options){
+ this.grid.setQuery(query, options);
+ },
+ _formatCell: function(value){
+ if(this.store.isItem(value)){
+ return this.store.getLabel(value) || this.store.getIdentity(value);
+ }
+ return value;
+ },
+ setStore: function(store){
+ this.store = store;
+ var self = this;
+ var grid = this.grid;
+ grid._pending_requests[0] = false;
+ function formatCell(value){
+ return self._formatCell(value);
+ }
+ var defaultOnComplete = this.gridOnFetchComplete;
+ grid._onFetchComplete = function(items, req){
+ var layout = self.gridLayout = [];
+ var column, key, item, i, j, k, idAttributes = store.getIdentityAttributes();
+ for(i = 0; i < idAttributes.length; i++){
+ key = idAttributes[i];
+ layout.push({
+ field: key,
+ name: key,
+ _score: 100,
+ formatter: formatCell,
+ editable: false
+ });
+
+ }
+ for(i=0; item = items[i++];){
+ var keys = store.getAttributes(item);
+ for(k=0; key = keys[k++];){
+ var found = false;
+ for(j=0; column = layout[j++];){
+ if(column.field == key){
+ column._score++;
+ found = true;
+ break;
+ }
+ }
+ if(!found){
+ layout.push({
+ field: key,
+ name: key,
+ _score: 1,
+ formatter: formatCell,
+ styles: "white-space:nowrap; ",
+ editable: true
+ });
+ }
+ }
+ }
+ layout = layout.sort(function(a, b){
+ return b._score - a._score;
+ });
+ if(!self.showAllColumns){
+ for(j=0; column=layout[j]; j++){
+ if(column._score < items.length/40 * j) {
+ layout.splice(j, layout.length-j);
+ break;
+ }
+ }
+ }
+ for(j=0; column = layout[j++];){
+ column.width=self.columnWidth || Math.round(100/layout.length) + '%';
+ }
+ grid._onFetchComplete = defaultOnComplete;
+ grid.attr("structure",layout);
+ var retValue = defaultOnComplete.apply(this, arguments);
+
+ }
+ grid.setStore(store);
+ this.queryOptions = {cache:true};
+ this.tree.setStore(store);
+ },
+ createNew: function(){
+ var props = prompt("Enter any properties (in JSON literal form) to put in the new item (passed to the newItem constructor):","{ }");
+ if(props){
+ try{
+ this.store.newItem(dojo.fromJson(props));
+ }catch(e){
+ alert(e);
+ }
+
+ }
+ }
+});
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/WikipediaStore.js b/js/dojo-1.7.2/dojox/data/WikipediaStore.js
new file mode 100644
index 0000000..d38d4c5
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/WikipediaStore.js
@@ -0,0 +1,118 @@
+//>>built
+define("dojox/data/WikipediaStore", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/io/script",
+ "dojo/io-query", "dojox/rpc/Service", "dojox/data/ServiceStore"],
+ function(kernel, lang, declare, scriptIO, ioQuery, Service, ServiceStore) {
+
+kernel.experimental("dojox.data.WikipediaStore");
+
+/*===== var ServiceStore = dojox.data.ServiceStore; =====*/
+
+return declare("dojox.data.WikipediaStore", ServiceStore, {
+ // summary:
+ // Initializer for the Wikipedia data store interface.
+ // description:
+ // The WikipediaStore is a data store interface to Wikipedia, using the
+ // Wikipedia SMD spec from dojox.rpc. It currently is useful only for
+ // finding articles that contain some particular text or grabbing single
+ // articles by full name; no wildcards or other filtering are supported.
+ // example:
+ // | var store = new dojox.data.WikipediaStore();
+ // | store.fetch({
+ // | query: {title:"Dojo Toolkit"},
+ // | onItem: function(item){
+ // | dojo.byId("somediv").innerHTML = item.text["*"];
+ // | }
+ // | });
+ constructor: function(options){
+ if(options && options.service){
+ this.service = options.service;
+ }else{
+ var svc = new Service(require.toUrl("dojox/rpc/SMDLibrary/wikipedia.smd"));
+ this.service = svc.query;
+ }
+
+ this.idAttribute = this.labelAttribute = "title";
+ },
+
+ fetch: function(/* object */ request){
+ // summary:
+ // Fetch a page or some partially-loaded search results from
+ // Wikipedia. Note that there isn't a way to sort data coming
+ // in from the API, so we just ignore the *sort* parameter.
+ // example:
+ // Loading a page:
+ // | store.fetch({
+ // | query: {title:"Dojo Toolkit"},
+ // | // define your handlers here
+ // | });
+ // example:
+ // Searching for pages containing "dojo":
+ // | store.fetch({
+ // | query: {
+ // | action: "query",
+ // | text: "dojo"
+ // | },
+ // | // define your handlers here
+ // | });
+ // example:
+ // Searching for the next 50 pages containing "dojo":
+ // | store.fetch({
+ // | query: {
+ // | action: "query",
+ // | text: "dojo",
+ // | start: 10,
+ // | count: 50 // max 500; will be capped if necessary
+ // | },
+ // | // define your handlers here
+ // | });
+ var rq = lang.mixin({}, request.query);
+ if(rq && (!rq.action || rq.action === "parse")){
+ // default to a single page fetch
+ rq.action = "parse";
+ rq.page = rq.title;
+ delete rq.title;
+
+ }else if(rq.action === "query"){
+ // perform a full text search on page content
+ rq.list = "search";
+ rq.srwhat = "text";
+ rq.srsearch = rq.text;
+ if(request.start){
+ rq.sroffset = request.start-1;
+ }
+ if(request.count){
+ rq.srlimit = request.count >= 500 ? 500 : request.count;
+ }
+ delete rq.text;
+ }
+ request.query = rq;
+ return this.inherited(arguments);
+ },
+
+ _processResults: function(results, def){
+ if(results.parse){
+ // loading a complete page
+ results.parse.title = ioQuery.queryToObject(def.ioArgs.url.split("?")[1]).page;
+ results = [results.parse];
+
+ }else if(results.query && results.query.search){
+ // loading some search results; all we have here is page titles,
+ // so we mark our items as incomplete
+ results = results.query.search;
+ var _thisStore = this;
+ for(var i in results){
+ results[i]._loadObject = function(callback){
+ _thisStore.fetch({
+ query: { action:"parse", title:this.title },
+ onItem: callback
+ });
+ delete this._loadObject;
+ }
+ }
+ }
+ return this.inherited(arguments);
+ }
+});
+
+});
+
diff --git a/js/dojo-1.7.2/dojox/data/XmlItem.js b/js/dojo-1.7.2/dojox/data/XmlItem.js
new file mode 100644
index 0000000..ff08964
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/XmlItem.js
@@ -0,0 +1,44 @@
+//>>built
+define("dojox/data/XmlItem", ["dojo/_base/declare"],
+ function(declare) {
+
+return declare("dojox.data.XmlItem", null, {
+ constructor: function(element, store, query){
+ // summary:
+ // Initialize with an XML element
+ // element:
+ // An XML element
+ // store:
+ // The containing store, if any.
+ // query:
+ // The query to use to look up a specific element.
+ // Usually an XPath or dojo.query statement.
+ this.element = element;
+ this.store = store;
+ this.q = query;
+ },
+ // 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 || node.nodeType === 4){
+ str += node.nodeValue;
+ }
+ }
+ }
+ return str; //String
+ }
+});
+});
diff --git a/js/dojo-1.7.2/dojox/data/XmlStore.js b/js/dojo-1.7.2/dojox/data/XmlStore.js
new file mode 100644
index 0000000..d9dc91a
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/XmlStore.js
@@ -0,0 +1,1472 @@
+//>>built
+define("dojox/data/XmlStore", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/xhr", "dojo/data/util/simpleFetch",
+ "dojo/_base/query", "dojo/_base/array", "dojo/_base/window", "dojo/data/util/filter", "dojox/xml/parser",
+ "dojox/data/XmlItem"],
+ function(lang, declare, xhr, simpleFetch, domQuery, array, winUtil, filter, xmlParser, XmlItem) {
+
+var XmlStore = 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 identity (unique identifier)
+ // Required for serverside fetchByIdentity, etc. Not required for
+ // client side fetchItemBIdentity, as it will use an XPath-like
+ // structure if keyAttribute was not specified. Recommended to always
+ // set this, though, for consistent identity behavior.
+ // 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.
+ // Default is false.
+ // urlPreventCache: Parameter to indicate whether or not URL calls should apply
+ // the preventCache option to the xhr request.
+ 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);
+ if("urlPreventCache" in args){
+ this.urlPreventCache = args.urlPreventCache?true:false;
+ }
+ }
+ 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: "",
+
+ // A tag name for XML tags to be considered root items in the hierarchy
+ rootItem: "",
+
+ // An attribute name for a key or an identity (unique identifier)
+ // Required for serverside fetchByIdentity, etc. Not required for
+ // client side fetchItemBIdentity, as it will use an XPath-like
+ // structure if keyAttribute was not specified. Recommended to always
+ // set this, though, for consistent identity behavior.
+ keyAttribute: "",
+
+ // An attribute of the item to use as the label.
+ label: "",
+
+ // A boolean indicate to add a query string to the service URL.
+ // Default is false.
+ sendQuery: false,
+
+ // An anonymous object that contains properties for attribute mapping,
+ // for example {"tag_name.item_attribute_name": "@xml_attribute_name", ...}.
+ // This is optional. This is done so that attributes which are actual
+ // XML tag attributes (and not sub-tags of an XML tag), can be referenced.
+ attributeMap: null,
+
+ // Parameter to indicate whether or not URL calls should apply the preventCache option to the xhr request.
+ urlPreventCache: true,
+
+ /* 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;
+ var i;
+ var node;
+ if(attribute === "tagName"){
+ return element.nodeName;
+ }else if(attribute === "childNodes"){
+ for(i = 0; i < element.childNodes.length; i++){
+ node = element.childNodes[i];
+ if(node.nodeType === 1 /*ELEMENT_NODE*/){
+ return this._getItem(node); //object
+ }
+ }
+ return defaultValue;
+ }else if(attribute === "text()"){
+ for(i = 0; i < element.childNodes.length; i++){
+ 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);
+ //Note that getAttribute will return null or empty string for undefined/unset
+ //attributes, therefore, we should just check the return was valid
+ //non-empty string and not null.
+ return (value) ? value : defaultValue; //object
+ }else{
+ for(i = 0; i < element.childNodes.length; i++){
+ 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;
+ var values = [];
+ var i;
+ var node;
+ if(attribute === "tagName"){
+ return [element.nodeName];
+ }else if(attribute === "childNodes"){
+ for(i = 0; i < element.childNodes.length; i++){
+ node = element.childNodes[i];
+ if(node.nodeType === 1 /*ELEMENT_NODE*/){
+ values.push(this._getItem(node));
+ }
+ }
+ return values; //array
+ }else if(attribute === "text()"){
+ var ec = element.childNodes;
+ for(i = 0; i < ec.length; i++){
+ node = ec[i];
+ if(node.nodeType === 3 || node.nodeType === 4){
+ 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{
+ for(i = 0; i < element.childNodes.length; i++){
+ 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 = [];
+ var i;
+ attributes.push("tagName");
+ if(element.childNodes.length > 0){
+ var names = {};
+ var childNodes = true;
+ var text = false;
+ for(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(i = 0; i < element.attributes.length; i++){
+ attributes.push("@" + element.attributes[i].nodeName);
+ }
+ if(this._attributeMap){
+ for(var key in this._attributeMap){
+ 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
+ };
+
+ //Local XML parsing can implement Identity fairly simple via
+ if(!this.sendQuery || this.keyAttribute !== ""){
+ features["dojo.data.api.Identity"] = 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);
+ if(!url){
+ errorHandler(new Error("No URL specified."), request);
+ return;
+ }
+ var localRequest = (!this.sendQuery ? request : {}); // use request for _getItems()
+
+ var self = this;
+ var getArgs = {
+ url: url,
+ handleAs: "xml",
+ preventCache: self.urlPreventCache
+ };
+ var getHandler = xhr.get(getArgs);
+ getHandler.addCallback(function(data){
+ var items = self._getItems(data, localRequest);
+ 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(lang.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;
+
+ if(this.rootItem !== ""){
+ nodes = domQuery(this.rootItem, document);
+ }else{
+ nodes = document.documentElement.childNodes;
+ }
+
+ var deep = request.queryOptions ? request.queryOptions.deep : false;
+ if(deep){
+ nodes = this._flattenNodes(nodes);
+ }
+ 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 ignoreCase = request.queryOptions ? request.queryOptions.ignoreCase : false;
+ var value;
+ var match = false;
+ var j;
+ var emptyQuery = true;
+
+ //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){
+ value = query[key];
+ if(typeof value === "string"){
+ regexpList[key] = filter.patternToRegExp(value, ignoreCase);
+ }else if(value){
+ // It's an object, possibly regexp, so treat it as one.
+ regexpList[key] = value;
+ }
+ }
+ for(var attribute in query){
+ emptyQuery = false;
+ var values = this.getValues(item, attribute);
+ for(j = 0; j < values.length; j++){
+ value = values[j];
+ if(value){
+ var queryValue = query[attribute];
+ if((typeof value) === "string" &&
+ (regexpList[attribute])){
+ if((value.match(regexpList[attribute])) !== null){
+ match = true;
+ }else{
+ match = false;
+ }
+ }else if((typeof value) === "object"){
+ if( value.toString &&
+ (regexpList[attribute])){
+ var stringValue = value.toString();
+ if((stringValue.match(regexpList[attribute])) !== null){
+ match = true;
+ }else{
+ match = false;
+ }
+ }else{
+ if(queryValue === "*" || queryValue === value){
+ match = true;
+ }else{
+ match = false;
+ }
+ }
+ }
+ }
+ //One of the multiValue values matched,
+ //so quit looking.
+ if(match){
+ break;
+ }
+ }
+ if(!match){
+ break;
+ }
+ }
+ //Either the query was an empty object {}, which is match all, or
+ //was an actual match.
+ if(emptyQuery || match){
+ items.push(item);
+ }
+ }else{
+ //No query, everything matches.
+ items.push(item);
+ }
+ }
+ array.forEach(items,function(item){
+ if(item.element.parentNode){
+ item.element.parentNode.removeChild(item.element); // make it root
+ }
+ },this);
+ return items;
+ },
+
+ _flattenNodes: function(nodes){
+ // Summary:
+ // Function used to flatten a hierarchy of XML nodes into a single list for
+ // querying over. Used when deep = true;
+ var flattened = [];
+ if(nodes){
+ var i;
+ for(i = 0; i < nodes.length; i++){
+ var node = nodes[i];
+ flattened.push(node);
+ if(node.childNodes && node.childNodes.length > 0){
+ flattened = flattened.concat(this._flattenNodes(node.childNodes));
+ }
+ }
+ }
+ return flattened;
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ },
+
+/* dojo.data.api.Write */
+
+ newItem: function(/* object? */ keywordArgs, parentInfo){
+ // 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
+ 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){
+ var text;
+ if(attribute === "tagName"){
+ continue;
+ }else if(attribute === "text()"){
+ 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);
+ text = document.createTextNode(keywordArgs[attribute]);
+ child.appendChild(text);
+ element.appendChild(child);
+ }
+ }
+ }
+
+ var item = this._getItem(element);
+ this._newItems.push(item);
+
+ var pInfo = null;
+ if(parentInfo && parentInfo.parent && parentInfo.attribute){
+ pInfo = {
+ item: parentInfo.parent,
+ attribute: parentInfo.attribute,
+ oldValue: undefined
+ };
+
+ //See if it is multi-valued or not and handle appropriately
+ //Generally, all attributes are multi-valued for this store
+ //So, we only need to append if there are already values present.
+ var values = this.getValues(parentInfo.parent, parentInfo.attribute);
+ if(values && values.length > 0){
+ var tempValues = values.slice(0, values.length);
+ if(values.length === 1){
+ pInfo.oldValue = values[0];
+ }else{
+ pInfo.oldValue = values.slice(0, values.length);
+ }
+ tempValues.push(item);
+ this.setValues(parentInfo.parent, parentInfo.attribute, tempValues);
+ pInfo.newValue = this.getValues(parentInfo.parent, parentInfo.attribute);
+ }else{
+ this.setValue(parentInfo.parent, parentInfo.attribute, item);
+ pInfo.newValue = 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
+ 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;
+ var child;
+ var text;
+ if(attribute === "childNodes"){
+ child = value.element;
+ element.appendChild(child);
+ }else if(attribute === "text()"){
+ while(element.firstChild){
+ element.removeChild(element.firstChild);
+ }
+ 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{
+ 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);
+ }
+ 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
+ // notify:
+ // A non-API optional argument, used to indicate if notification API should be called
+ // or not.
+
+ // returns:
+ // False for "tagName", otherwise true
+ if(attribute === "tagName"){
+ return false; //boolean
+ }
+
+ this._backupItem(item);
+
+ var element = item.element;
+ var i;
+ var child;
+ var text;
+ if(attribute === "childNodes"){
+ while(element.firstChild){
+ element.removeChild(element.firstChild);
+ }
+ for(i = 0; i < values.length; i++){
+ child = values[i].element;
+ element.appendChild(child);
+ }
+ }else if(attribute === "text()"){
+ while(element.firstChild){
+ element.removeChild(element.firstChild);
+ }
+ var value = "";
+ for(i = 0; i < values.length; i++){
+ value += values[i];
+ }
+ 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(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(i = 0; i < values.length; i++){
+ child = document.createElement(attribute);
+ 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 = {};
+ }
+ var i;
+ for(i = 0; i < this._modifiedItems.length; i++){
+ this._saveItem(this._modifiedItems[i], keywordArgs, "PUT");
+ }
+ for(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(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
+ 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){
+ var url;
+ var scope;
+ 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){
+ scope = keywordArgs.scope || winUtil.global;
+ keywordArgs.onError.call(scope, new Error("No URL for saving content: " + this._getPostContent(item)));
+ }
+ return;
+ }
+
+ var saveArgs = {
+ url: url,
+ method: (method || "POST"),
+ contentType: "text/xml",
+ handleAs: "xml"
+ };
+ var saveHandler;
+ if(method === "PUT"){
+ saveArgs.putData = this._getPutContent(item);
+ saveHandler = xhr.put(saveArgs);
+ }else if(method === "DELETE"){
+ saveHandler = xhr.del(saveArgs);
+ }else{ // POST
+ saveArgs.postData = this._getPostContent(item);
+ saveHandler = xhr.post(saveArgs);
+ }
+ scope = (keywordArgs.scope || winUtil. 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
+ return "<?xml version=\'1.0\'?>" + xmlParser.innerXML(item.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
+ return "<?xml version='1.0'?>" + xmlParser.innerXML(item.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){
+ try{
+ var q = null;
+ //Avoid function call if possible.
+ if(this.keyAttribute === ""){
+ q = this._getXPath(element);
+ }
+ return new XmlItem(element, this, q); //object
+ }catch (e){
+ console.log(e);
+ }
+ return null;
+ },
+
+ _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){
+
+ array.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 xmlParser.parse(); // DOMDocument
+ }
+ return null; //null
+ },
+
+ _getRootElement: function(element){
+ while(element.parentNode){
+ element = element.parentNode;
+ }
+ return element; //DOMElement
+ },
+
+ _getXPath: function(element){
+ // summary:
+ // A function to compute the xpath of a node in a DOM document.
+ // description:
+ // A function to compute the xpath of a node in a DOM document. Used for
+ // Client side query handling and identity.
+ var xpath = null;
+ if(!this.sendQuery){
+ //xpath should be null for any server queries, as we don't have the entire
+ //XML dom to figure it out.
+ var node = element;
+ xpath = "";
+ while(node && node != element.ownerDocument){
+ var pos = 0;
+ var sibling = node;
+ var name = node.nodeName;
+ while(sibling){
+ sibling = sibling.previousSibling;
+ if(sibling && sibling.nodeName === name){
+ pos++;
+ }
+ }
+ var temp = "/" + name + "[" + pos + "]";
+ if(xpath){
+ xpath = temp + xpath;
+ }else{
+ xpath = temp;
+ }
+ node = node.parentNode;
+ }
+ }
+ return xpath; //string
+ },
+
+ /*************************************
+ * Dojo.data Identity implementation *
+ *************************************/
+ getIdentity: function(/* item */ item){
+ // summary:
+ // Returns a unique identifier for an item.
+ // item:
+ // The XML Item from the store from which to obtain its identifier.
+ if(!this.isItem(item)){
+ throw new Error("dojox.data.XmlStore: Object supplied to getIdentity is not an item");
+ }else{
+ var id = null;
+ if(this.sendQuery && this.keyAttribute !== ""){
+ id = this.getValue(item, this.keyAttribute).toString();
+ }else if(!this.serverQuery){
+ if(this.keyAttribute !== ""){
+ id = this.getValue(item,this.keyAttribute).toString();
+ }else{
+ //No specified identity, so return the dojo.query/xpath
+ //for the node as fallback.
+ id = item.q;
+ }
+ }
+ return id; //String.
+ }
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // Returns an array of attribute names that are used to generate the identity.
+ // description:
+ // For XmlStore, if sendQuery is false and no keyAttribute was set, then this function
+ // returns null, as xpath is used for the identity, which is not a public attribute of
+ // the item. If sendQuery is true and keyAttribute is set, then this function
+ // returns an array of one attribute name: keyAttribute. This means the server side
+ // implementation must apply a keyAttribute to a returned node that always allows
+ // it to be looked up again.
+ // item:
+ // The item from the store from which to obtain the array of public attributes that
+ // compose the identifier, if any.
+ if(!this.isItem(item)){
+ throw new Error("dojox.data.XmlStore: Object supplied to getIdentity is not an item");
+ }else{
+ if(this.keyAttribute !== ""){
+ return [this.keyAttribute]; //array
+ }else{
+ //Otherwise it's either using xpath (not an attribute), or the remote store
+ //doesn't support identity.
+ return null; //null
+ }
+ }
+ },
+
+
+ fetchItemByIdentity: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity(keywordArgs)
+ var handleDocument = null;
+ var scope = null;
+ var self = this;
+ var url = null;
+ var getArgs = null;
+ var getHandler = null;
+
+ if(!self.sendQuery){
+ handleDocument = function(data){
+ if(data){
+ if(self.keyAttribute !== ""){
+ //We have a key attribute specified. So ... we can process the items and locate the item
+ //that contains a matching key attribute. Its identity, as it were.
+ var request = {};
+ request.query={};
+ request.query[self.keyAttribute] = keywordArgs.identity;
+ request.queryOptions = {deep: true};
+ var items = self._getItems(data,request);
+ scope = keywordArgs.scope || winUtil.global;
+ if(items.length === 1){
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, items[0]);
+ }
+ }else if(items.length === 0){
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, null);
+ }
+ }else{
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, new Error("Items array size for identity lookup greater than 1, invalid keyAttribute."));
+ }
+ }
+ }else{
+ //Since dojo.query doesn't really support the functions needed
+ //to do child node selection on IE well and since xpath support
+ //is flakey across browsers, it's simpler to implement a
+ //pseudo-xpath parser here.
+ var qArgs = keywordArgs.identity.split("/");
+ var i;
+ var node = data;
+ for(i = 0; i < qArgs.length; i++){
+ if(qArgs[i] && qArgs[i] !== ""){
+ var section = qArgs[i];
+ section = section.substring(0,section.length - 1);
+ var vals = section.split("[");
+ var tag = vals[0];
+ var index = parseInt(vals[1], 10);
+ var pos = 0;
+ if(node){
+ var cNodes = node.childNodes;
+ if(cNodes){
+ var j;
+ var foundNode = null;
+ for(j = 0; j < cNodes.length; j++){
+ var pNode = cNodes[j];
+ if(pNode.nodeName === tag){
+ if(pos < index){
+ pos++;
+ }else{
+ foundNode = pNode;
+ break;
+ }
+ }
+ }
+ if(foundNode){
+ node = foundNode;
+ }else{
+ node = null;
+ }
+ }else{
+ node = null;
+ }
+ }else{
+ break;
+ }
+ }
+ }
+ //Return what we found, if any.
+ var item = null;
+ if(node){
+ item = self._getItem(node);
+ if(item.element.parentNode){
+ item.element.parentNode.removeChild(item.element);
+ }
+ }
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope || winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }
+ };
+ url = this._getFetchUrl(null);
+ getArgs = {
+ url: url,
+ handleAs: "xml",
+ preventCache: self.urlPreventCache
+ };
+ getHandler = xhr.get(getArgs);
+
+ //Add in the callbacks for completion of data load.
+ getHandler.addCallback(handleDocument);
+ if(keywordArgs.onError){
+ getHandler.addErrback(function(error){
+ var s = keywordArgs.scope || winUtil.global;
+ keywordArgs.onError.call(s, error);
+ });
+ }
+ }else{
+ //Server side querying, so need to pass the keyAttribute back to the server and let it return
+ //what it will. It SHOULD be only one item.
+ if(self.keyAttribute !== ""){
+ var request = {query:{}};
+ request.query[self.keyAttribute] = keywordArgs.identity;
+ url = this._getFetchUrl(request);
+ handleDocument = function(data){
+ var item = null;
+ if(data){
+ var items = self._getItems(data, {});
+ if(items.length === 1){
+ item = items[0];
+ }else{
+ if(keywordArgs.onError){
+ var scope = keywordArgs.scope || winUtil.global;
+ keywordArgs.onError.call(scope, new Error("More than one item was returned from the server for the denoted identity"));
+ }
+ }
+ }
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope || winUtil.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ };
+
+ getArgs = {
+ url: url,
+ handleAs: "xml",
+ preventCache: self.urlPreventCache
+ };
+ getHandler = xhr.get(getArgs);
+
+ //Add in the callbacks for completion of data load.
+ getHandler.addCallback(handleDocument);
+ if(keywordArgs.onError){
+ getHandler.addErrback(function(error){
+ var s = keywordArgs.scope || winUtil.global;
+ keywordArgs.onError.call(s, error);
+ });
+ }
+ }else{
+ if(keywordArgs.onError){
+ var s = keywordArgs.scope || winUtil.global;
+ keywordArgs.onError.call(s, new Error("XmlStore is not told that the server to provides identity support. No keyAttribute specified."));
+ }
+ }
+ }
+ }
+});
+
+lang.extend(XmlStore,simpleFetch);
+
+return XmlStore;
+});
diff --git a/js/dojo-1.7.2/dojox/data/css.js b/js/dojo-1.7.2/dojox/data/css.js
new file mode 100644
index 0000000..790ad96
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/css.js
@@ -0,0 +1,107 @@
+//>>built
+define("dojox/data/css", ["dojo/_base/lang", "dojo/_base/array"],
+ function(lang, array) {
+
+var css = lang.getObject("dojox.data.css",true)
+
+css.rules = {};
+
+css.rules.forEach = function(fn,ctx,context){
+ if(context){
+ var _processSS = function(styleSheet){
+ //iterate across rules in the stylesheet
+ array.forEach(styleSheet[styleSheet.cssRules?"cssRules":"rules"], function(rule){
+ if(!rule.type || rule.type !== 3){// apply fn to current rule with approp ctx. rule is arg (all browsers)
+ var href = "";
+ if(styleSheet && styleSheet.href){
+ href = styleSheet.href;
+ }
+ fn.call(ctx?ctx:this,rule, styleSheet, href);
+ }
+ });
+ //process any child stylesheets
+ };
+ array.forEach(context,_processSS);
+ }
+};
+
+css.findStyleSheets = function(sheets){
+ // Takes an array of stylesheet paths and finds the currently loaded StyleSheet objects matching
+ // those names
+ var sheetObjects = [];
+ var _processSS = function(styleSheet){
+ var s = css.findStyleSheet(styleSheet);
+ if(s){
+ array.forEach(s, function(sheet){
+ if(array.indexOf(sheetObjects, sheet) === -1){
+ sheetObjects.push(sheet);
+ }
+ });
+ }
+ };
+ array.forEach(sheets, _processSS);
+ return sheetObjects;
+};
+
+css.findStyleSheet = function(sheet){
+ // Takes a stylesheet path and finds the currently loaded StyleSheet objects matching
+ // those names (and it's parent(s), if it is imported from another)
+ var sheetObjects = [];
+ if(sheet.charAt(0) === '.'){
+ sheet = sheet.substring(1);
+ }
+ var _processSS = function(styleSheet){
+ if(styleSheet.href && styleSheet.href.match(sheet)){
+ sheetObjects.push(styleSheet);
+ return true;
+ }
+ if(styleSheet.imports){
+ return array.some(styleSheet.imports, function(importedSS){ //IE stylesheet has imports[] containing @import'ed rules
+ //console.debug("Processing IE @import rule",importedSS);
+ return _processSS(importedSS);
+ });
+ }
+ //iterate across rules in the stylesheet
+ return array.some(styleSheet[styleSheet.cssRules?"cssRules":"rules"], function(rule){
+ if(rule.type && rule.type === 3 && _processSS(rule.styleSheet)){// CSSImportRule (firefox)
+ //sheetObjects.push(styleSheet);
+ return true;
+ }
+ return false;
+ });
+ };
+ array.some(document.styleSheets, _processSS);
+ return sheetObjects;
+};
+
+css.determineContext = function(initialStylesheets){
+ // Takes an array of stylesheet paths and returns an array of all stylesheets that fall in the
+ // given context. If no paths are given, all stylesheets are returned.
+ var ret = [];
+ if(initialStylesheets && initialStylesheets.length > 0){
+ initialStylesheets = css.findStyleSheets(initialStylesheets);
+ }else{
+ initialStylesheets = document.styleSheets;
+ }
+ var _processSS = function(styleSheet){
+ ret.push(styleSheet);
+ if(styleSheet.imports){
+ array.forEach(styleSheet.imports, function(importedSS){ //IE stylesheet has imports[] containing @import'ed rules
+ //console.debug("Processing IE @import rule",importedSS);
+ _processSS(importedSS);
+ });
+ }
+ //iterate across rules in the stylesheet
+ array.forEach(styleSheet[styleSheet.cssRules?"cssRules":"rules"], function(rule){
+ if(rule.type && rule.type === 3){// CSSImportRule (firefox)
+ _processSS(rule.styleSheet);
+ }
+ });
+ };
+ array.forEach(initialStylesheets,_processSS);
+ return ret;
+};
+
+return css;
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/demos/GoogleFeedTemplate.html b/js/dojo-1.7.2/dojox/data/demos/GoogleFeedTemplate.html
new file mode 100644
index 0000000..2d18fca
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/GoogleFeedTemplate.html
@@ -0,0 +1,26 @@
+{% load dojox.dtl.contrib.data %}
+{% bind_data items to store as google %}
+<ul>
+{% for item in google %}
+<li class="search-result">
+ <div>
+ <a href="{{item.link}}">{{item.title}}</a>
+ <div style="display:none" class="content">
+ <h2>{{item.title}}</h2>
+ {{item.content}}
+ </div>
+ </div>
+ <div class="summary">
+ {{item.summary}}
+ </div>
+ <div class="tags">
+ <!--{% if item.categories %}-->
+ Tags:
+ <!--{% for cat in item.categories %}-->
+ {{cat}}
+ <!--{% endfor %}-->
+ <!--{% endif %}-->
+ </div>
+</li>
+{% endfor %}
+</ul> \ No newline at end of file
diff --git a/js/dojo-1.7.2/dojox/data/demos/GoogleTemplate.html b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplate.html
new file mode 100644
index 0000000..a87d107
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplate.html
@@ -0,0 +1,7 @@
+{% load dojox.dtl.contrib.data %}
+{% bind_data items to store as google %}
+{% for item in google %}
+<span class="search-result">
+ <a href="{{item.unescapedUrl}}">{{item.titleNoFormatting}}</a>
+</span>
+{% endfor %}
diff --git a/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateBlog.html b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateBlog.html
new file mode 100644
index 0000000..4d67548
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateBlog.html
@@ -0,0 +1,7 @@
+{% load dojox.dtl.contrib.data %}
+{% bind_data items to store as google %}
+{% for item in google %}
+<span class="search-result">
+ <a href="{{item.postUrl}}">{{item.titleNoFormatting}}</a>
+</span>
+{% endfor %}
diff --git a/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateImage.html b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateImage.html
new file mode 100644
index 0000000..37088d8
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateImage.html
@@ -0,0 +1,7 @@
+{% load dojox.dtl.contrib.data %}
+{% bind_data items to store as google %}
+{% for item in google %}
+<span class="search-result">
+ <a href="{{item.unescapedUrl}}"><img src="{{item.tbUrl}}" alt="{{item.contentNoFormatting}}"></a>
+</span>
+{% endfor %}
diff --git a/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateLocal.html b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateLocal.html
new file mode 100644
index 0000000..da37f90
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateLocal.html
@@ -0,0 +1,7 @@
+{% load dojox.dtl.contrib.data %}
+{% bind_data items to store as google %}
+{% for item in google %}
+<span class="search-result">
+ <a href="{{item.url}}"><img src="{{item.staticMapUrl}}"></a>
+</span>
+{% endfor %}
diff --git a/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateVideo.html b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateVideo.html
new file mode 100644
index 0000000..0600db0
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/GoogleTemplateVideo.html
@@ -0,0 +1,7 @@
+{% load dojox.dtl.contrib.data %}
+{% bind_data items to store as google %}
+{% for item in google %}
+<span class="search-result">
+ <a href="{{item.url}}"><img src="{{item.tbUrl}}" width="100" height="75"></a>
+</span>
+{% endfor %}
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_CssStores_combo_tree_grid.html b/js/dojo-1.7.2/dojox/data/demos/demo_CssStores_combo_tree_grid.html
new file mode 100644
index 0000000..22cf65a
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_CssStores_combo_tree_grid.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+ Demo application showing The CssClassStore.
+-->
+<html>
+<head>
+ <title>Demo: dojox.data.CssClassStore</title>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "../../grid/resources/tundraGrid.css";
+ </style>
+
+ <!--
+ The following script tag instantiates the dojo library and sets some basic properties. In this case, the application
+ is told that debug mode is off, and to parse all dojoType widgets when it has fully loaded.
+ -->
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: false, parseOnLoad: true"></script>
+ <script>
+ dojo.require("dijit.Tree");
+ dojo.require("dijit.tree.ForestStoreModel");
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dojox.data.CssRuleStore");
+ dojo.require("dojox.data.CssClassStore");
+ dojo.require("dojox.grid.DataGrid");
+
+ var layoutCss = [
+ [
+ { field: "selector", name: "Selector", width: 20 },
+ { field: "parentStyleSheetHref", name: "StyleSheet", width: 20 },
+ { field: "cssText", name: "CSS", width: 'auto' }
+ ]
+ ];
+
+ function init() {
+ var combo = dijit.byId("classCombo");
+ var grid = dijit.byId("cssGrid");
+
+ function requery() {
+ var val = combo.getValue();
+ val = "." + val;
+ var query = {
+ selector: "*" + val + "*"
+ }
+ grid.filter(query,true);
+ }
+ dojo.connect(combo, "onChange", requery);
+ }
+ dojo.addOnLoad(init);
+
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>
+ Demo: Demo of using the Css Stores to browse the loaded CSS classes and associated rules.
+ </h1>
+ <p>This demo demonstrates hooking up the Css*Stores to the various digit widgets to browse the Css loaded for the page.</p>
+ <hr>
+
+ <div dojoType="dojox.data.CssRuleStore" jsId="ruleStore"></div>
+ <div dojoType="dojox.data.CssClassStore" jsId="classStore"></div>
+
+
+ <div dojoType="dijit.tree.ForestStoreModel"
+ jsId="classModel"
+ store="classStore"
+ query="{}"
+ rootId="Loaded Classes"
+ rootLabel="Loaded Classes"
+ childrenAttrs="children">
+ </div>
+
+ <h2>dojox.data.CssClassStore connected to ComboBox and querying on classSans:</h2>
+ <div id="classCombo" dojoType="dijit.form.ComboBox" store="classStore" searchAttr="classSans"></div>
+
+ <h2>dojox.data.CssRuleStore:</h2>
+ <i>Displays the list of CSS rules filtered by the class selected in the ComboBox.</i>
+ <div id="cssGrid"
+ jsId="cssGrid"
+ dojoType="dojox.grid.DataGrid"
+ query="{}"
+ rowsPerPage="20"
+ store="ruleStore"
+ structure="layoutCss"
+ style="width: 100%; height: 400px;">
+ </div>
+
+ <h2>dojox.data.CssClassStore connected to Tree:</h2>
+ <span id="tree" dojoType="dijit.Tree" model="classModel"> </span>
+ <hr>
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_DataDemoTable.html b/js/dojo-1.7.2/dojox/data/demos/demo_DataDemoTable.html
new file mode 100644
index 0000000..9c594c1
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_DataDemoTable.html
@@ -0,0 +1,143 @@
+<!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(\""+require.toUrl("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: { groupid: '27475260@N00' } }">
+ <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>
+ <span dojoType="demo.Table" store="flickrStore"
+ query="{ query: { tags: 'dojotoolkit' } }">
+ <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/js/dojo-1.7.2/dojox/data/demos/demo_FileStore_dojotree.html b/js/dojo-1.7.2/dojox/data/demos/demo_FileStore_dojotree.html
new file mode 100644
index 0000000..e134361
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_FileStore_dojotree.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+ Demo application showing LazyLoading File store.
+-->
+<html>
+<head>
+ <title>Demo: dojox.data.FileStore</title>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+
+ .fileView {
+ margin: 5px;
+ width: 100%;
+
+ }
+ .fileView .fileViewTitle{
+ color: white;
+ background-color: black;
+ font-size: larger;
+ font-weight: bold;
+
+ }
+
+ .fileView .fileViewTable {
+ border-width: 2px;
+ border-style: solid;
+ width: 100%;
+ }
+
+ .fileView .fileViewTable tr td {
+ border-width: 1px;
+ border-style: solid;
+ border-color: lightgray;
+ width: 50%;
+ vertical-align: top;
+ }
+
+ .fileView .fileName {
+ background-color: lightgray;
+ }
+
+ </style>
+
+ <!--
+ The following script tag instantiates the dojo library and sets some basic properties. In this case, the application
+ is told that debug mode is off, and to parse all dojoType widgets when it has fully loaded.
+ -->
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: false, parseOnLoad: true, useCommentedJson: true"></script>
+ <script>
+ dojo.require("dijit.Tree");
+ dojo.require("dijit.tree.ForestStoreModel");
+ dojo.require("dojox.data.FileStore");
+ dojo.require("dojox.data.demos.widgets.FileView");
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>
+ Demo: Lazy Loading File Browsing Store
+ </h1>
+ <p>The tree below uses the dojox.data.FileStore and a PHP implementation for the serverside to browse the dojo tree hierarchy in a lazy-load fashion.</p>
+ <p><i><b>This demo must be run from a web-server with PHP support enabled. Without PHP support, this demo cannot function. The Demo also requires PHP
+ support for json_encode and json_decode. Please be sure to have those packages installed in your PHP environment.</b></i></p>
+ <hr>
+ <i>Clicking on a file in the tree will display the details about that file.</i>
+ <div dojoType="dojox.data.FileStore" url="stores/filestore_dojotree.php" jsId="fileStore" pathAsQueryParam="true"></div>
+ <div dojoType="dijit.tree.ForestStoreModel" jsId="fileModel"
+ store="fileStore" query="{}"
+ rootId="DojoFiles" rootLabel="Dojo Files" childrenAttrs="children"></div>
+
+ <table style="width: 100%;">
+ <tbody>
+ <tr style="width: 100%;">
+ <td style="width: 50%; vertical-align: top;">
+ <span id="tree" dojoType="dijit.Tree" model="fileModel" >
+ <script type="dojo/method" event="onClick" args="item">
+ if (fileStore.isItem(item)){
+ var attachPt = dojo.byId("fileInfo");
+ if (attachPt) {
+ while(attachPt.firstChild) {
+ attachPt.removeChild(attachPt.firstChild);
+ }
+ var newArgs = {};
+ newArgs.name = fileStore.getValue(item, "name");
+ newArgs.path = fileStore.getValue(item, "path");
+ newArgs.size = fileStore.getValue(item, "size");
+ newArgs.directory = fileStore.getValue(item, "directory");
+ newArgs.parentDir = fileStore.getValue(item, "parentDir");
+ var children = fileStore.getValues(item, "children");
+ if (children && children.length > 0) {
+ newArgs.children = [];
+ var i;
+ for (i = 0; i < children.length; i++) {
+ //Note here that even though the store is lazy-loading, the unloaded items for children still
+ //have the 'name' attribute, since it is used as part of the info to load the full item. Generally
+ //you should not access properties of an item that has not been fully inflated yet. It just works
+ //well in this case for this store.
+ newArgs.children.push(fileStore.getValue(children[i], "name"));
+ }
+ }
+ var fInfo = new dojox.data.demos.widgets.FileView(newArgs);
+ attachPt.appendChild(fInfo.domNode);
+ fInfo.startup();
+ }
+ }
+ </script>
+ </span>
+ </td>
+ <td id="fileInfo" STYLE="width: 50%; vertical-align: top;">
+ </td>
+ </tr>
+
+ </tbody>
+ </table>
+ <hr>
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_FileStore_dojoxdata_combo_grid.html b/js/dojo-1.7.2/dojox/data/demos/demo_FileStore_dojoxdata_combo_grid.html
new file mode 100644
index 0000000..c4eae5a
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_FileStore_dojoxdata_combo_grid.html
@@ -0,0 +1,157 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+ Demo application showing LazyLoading File store.
+-->
+<html>
+<head>
+ <title>Demo: dojox.data.FileStore</title>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "../../../dojox/grid/resources/tundraGrid.css";
+
+ .fileView {
+ margin: 5px;
+ width: 100%;
+
+ }
+ .fileView .fileViewTitle{
+ color: white;
+ background-color: black;
+ font-size: larger;
+ font-weight: bold;
+
+ }
+
+ .fileView .fileViewTable {
+ border-width: 2px;
+ border-style: solid;
+ width: 100%;
+ }
+
+ .fileView .fileViewTable tr td {
+ border-width: 1px;
+ border-style: solid;
+ border-color: lightgray;
+ width: 50%;
+ vertical-align: top;
+ }
+
+ .fileView .fileName {
+ background-color: lightgray;
+ }
+
+ .tundra .dojoxGrid-cell {
+ text-indent: 3px;
+ }
+ </style>
+
+ <!--
+ The following script tag instantiates the dojo library and sets some basic properties. In this case, the application
+ is told that debug mode is off, and to parse all dojoType widgets when it has fully loaded.
+ -->
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: false, parseOnLoad: true, useCommentedJson: true"></script>
+ <script>
+ dojo.require("dijit.Tree");
+ dojo.require("dijit.tree.ForestStoreModel");
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dojox.data.FileStore");
+ dojo.require("dojox.grid.DataGrid");
+ dojo.require("dojox.data.demos.widgets.FileView");
+
+ var layoutFiles = [
+ [
+ { field: "name", name: "Filename", width: 20 },
+ { field: "size", name: "File Size (bytes)", width: 10 },
+ { field: "directory", name: "Is Directory", width: 10 },
+ { field: "path", name: "Path", width: 'auto' }
+ ]
+ ];
+
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>
+ Demo: Lazy Loading File Browsing Store connected to multiple widgets
+ </h1>
+ <p>All the widgets used in this demo connect to the same filestore instance. It is talking to a filestore rooted in the dojox/data/ sub-directory to make it fast handling when querying across all files.</p>
+ <p><i><b>This demo must be run from a web-server with PHP support enabled. Without PHP support, this demo cannot function. The Demo also requires PHP
+ support for json_encode and json_decode. Please be sure to have those packages installed in your PHP environment.</b></i></p>
+ <hr>
+
+ <div dojoType="dojox.data.FileStore" url="stores/filestore_dojoxdata.php" jsId="fileStore" pathAsQueryParam="true"></div>
+ <div dojoType="dijit.tree.ForestStoreModel" jsId="fileModel"
+ store="fileStore" query="{}"
+ rootId="./dojox/data" rootLabel="./dojox/data" childrenAttrs="children"></div>
+
+
+ <h2>dojox.data.FileStore connected to ComboBox and querying on path:</h2>
+ <div dojoType="dijit.form.ComboBox" store="fileStore" searchAttr="path" value="./demos"></div>
+
+
+ <h2>dojox.data.FileStore connected to Grid and displaying all files:</h2>
+ <div style="width: 100%; height: 300px;">
+ <div id="grid"
+ dojoType="dojox.grid.DataGrid"
+ store="fileStore"
+ structure="layoutFiles"
+ queryOptions="{deep:true}"
+ query="{}"
+ sortFields="[{'attribute':'path', 'descending': false}]"
+ rowsPerPage="40">
+
+ </div>
+ </div>
+
+
+ <h2>dojox.data.FileStore connected to Tree:</h2>
+ <i>Clicking on a file in the tree will display the details about that file.</i>
+ <table style="width: 100%;">
+ <tbody>
+ <tr style="width: 100%;">
+ <td style="width: 50%; vertical-align: top;">
+ <span id="tree" dojoType="dijit.Tree" model="fileModel">
+ <script type="dojo/method" event="onClick" args="item">
+ if (fileStore.isItem(item)){
+ var attachPt = dojo.byId("fileInfo");
+ if (attachPt) {
+ while(attachPt.firstChild) {
+ attachPt.removeChild(attachPt.firstChild);
+ }
+ var newArgs = {};
+ newArgs.name = fileStore.getValue(item, "name");
+ newArgs.path = fileStore.getValue(item, "path");
+ newArgs.size = fileStore.getValue(item, "size");
+ newArgs.directory = fileStore.getValue(item, "directory");
+ newArgs.parentDir = fileStore.getValue(item, "parentDir");
+ var children = fileStore.getValues(item, "children");
+ if (children && children.length > 0) {
+ newArgs.children = [];
+ var i;
+ for (i = 0; i < children.length; i++) {
+ //Note here that even though the store is lazy-loading, the unloaded items for children still
+ //have the 'name' attribute, since it is used as part of the info to load the full item. Generally
+ //you should not access properties of an item that has not been fully inflated yet. It just works
+ //well in this case for this store.
+ newArgs.children.push(fileStore.getValue(children[i], "name"));
+ }
+ }
+ var fInfo = new dojox.data.demos.widgets.FileView(newArgs);
+ attachPt.appendChild(fInfo.domNode);
+ fInfo.startup();
+ }
+ }
+ </script>
+ </span>
+ </td>
+ <td id="fileInfo" STYLE="width: 50%; vertical-align: top;">
+ </td>
+ </tr>
+
+ </tbody>
+ </table>
+ <hr>
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_FlickrRestStore.html b/js/dojo-1.7.2/dojox/data/demos/demo_FlickrRestStore.html
new file mode 100644
index 0000000..5774c76
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_FlickrRestStore.html
@@ -0,0 +1,236 @@
+<!--
+ 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";
+ </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("dojox.data.FlickrStore");
+ dojo.require("dojox.data.FlickrRestStore");
+ dojo.require("dojox.data.demos.widgets.FlickrViewList");
+
+ function init(){
+ //Function to invoke the search of the FlickrStore
+ function invokeSearch(){
+ var request = {
+ query: {
+ apikey: "8c6803164dbc395fb7131c9d54843627"
+ }
+ };
+
+ if(idWidget){
+ var userid = idWidget.getValue();
+ if(userid && userid !== ""){
+ request.query.userid = userid;
+ }
+ }
+ if(tagsWidget){
+ request.query.tags = (tagsWidget.getValue()||"").split(" ").join(",");
+ }
+ if(tagmodeWidget){
+ request.query.tagmode = tagmodeWidget.getValue()||"";
+ }
+
+ 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);
+ flickrViewsWidget.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/>
+ </blockquote>
+ <div dojoType="dojox.data.FlickrRestStore" jsId="flickrStore" label="title"></div>
+ <div dojoType="dojox.data.demos.widgets.FlickrViewList"
+ store="flickrStore"
+ id="flickrViews"
+ jsId="flickrViewsWidget"></div>
+
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_FlickrStore.html b/js/dojo-1.7.2/dojox/data/demos/demo_FlickrStore.html
new file mode 100644
index 0000000..0adf8d2
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_FlickrStore.html
@@ -0,0 +1,161 @@
+<html>
+<head>
+ <!--
+ 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.
+ -->
+ <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";
+ </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("dojox.data.FlickrStore");
+ dojo.require("dojox.data.demos.widgets.FlickrViewList");
+
+ function init(){
+ //Function to invoke the search of the FlickrStore
+ var invokeSearch = function(){
+ var request = { query: {} };
+
+ if(idWidget){
+ var id = idWidget.getValue() || "";
+ if(id && id.length){
+ request.query.userid = id;
+ }
+ }
+
+ if(tagsWidget){
+ request.query.tags = (tagsWidget.getValue()||"").split(" ").join(",");
+ }
+
+
+ if(tagmodeWidget){
+ request.query.tagmode = tagmodeWidget.getValue()||"";
+ }
+
+ if(countWidget){
+ request.count = countWidget.getValue();
+ }
+ flickrViewsWidget.fetch(request);
+ }
+
+ dojo.connect(flickrViewsWidget, "fetch", function() {
+ statusWidget.setValue("PROCESSING REQUEST");
+ });
+
+ dojo.connect(flickrViewsWidget, "onComplete", function() {
+ statusWidget.setValue("PROCESSING COMPLETE.");
+ });
+
+ dojo.connect(flickrViewsWidget, "onError", function() {
+ statusWidget.setValue("ERROR!");
+ });
+
+ //Lastly, link up the search event.
+ var button = dijit.byId("searchButton");
+ dojo.connect(button, "onClick", invokeSearch);
+ }
+ dojo.addOnLoad(init);
+ dojo.addOnLoad(function(){ dijit.byId("searchButton").onClick(); });
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>
+ DEMO: FlickrStore Search
+ </h1>
+ <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>
+ <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="nature"></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>
+ <!--
+ The store instance used by this demo.
+ -->
+ <div dojoType="dojox.data.FlickrStore" jsId="flickrStore" label="title"></div>
+ <div dojoType="dojox.data.demos.widgets.FlickrViewList"
+ store="flickrStore"
+ id="flickrViews"
+ jsId="flickrViewsWidget"></div>
+
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_GoogleFeedStore.html b/js/dojo-1.7.2/dojox/data/demos/demo_GoogleFeedStore.html
new file mode 100644
index 0000000..6a4d115
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_GoogleFeedStore.html
@@ -0,0 +1,113 @@
+<!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";
+
+ #output {
+ width: 400px;
+ position: absolute;
+ top: 50px;
+ }
+ #entryContent {
+ margin-left: 450px;
+ position: absolute;
+ top: 50px;
+ background-color: #eee;
+ height: 800px;
+ padding: 2px;
+ }
+ .search-result {
+ width: 100%;
+ border: 2px dashed;
+ padding: 4px;
+ }
+ #entryContent h2 {
+ text-decoration: underline;
+ }
+ .summary {
+ font-weight: bolder;
+ }
+ .tags {
+ background-color: lightGrey;
+ }
+ </style>
+
+ <title>Google Feed Store</title>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dijit.form.FilteringSelect");
+ dojo.require("dojox.dtl");
+ dojo.require("dojox.dtl.ext-dojo.NodeList");
+ dojo.require("dojox.data.GoogleSearchStore");
+ dojo.require("dojox.data.GoogleFeedStore");
+
+ dojo.addOnLoad(function(){
+ dojo.connect(dojo.byId("output"), "onclick", function(evt) {
+ if(evt.target.tagName != "A"){return true;}
+ dojo.stopEvent(evt);
+
+ dojo.byId("entryContent").innerHTML = dojo.query(".content", evt.target.parentNode)[0].innerHTML;
+
+ return false;
+ })
+
+ });
+
+ function doSearch() {
+ var query = {
+ url: dojo.byId("searchText").value
+ };
+ var request = {query:query};
+
+ var itemBuffer = [];
+ var maxBufSize = 8;
+ var outNode = dojo.byId("output");
+ outNode.innerHTML = "Searching...";
+ var count = 0;
+ var template = "GoogleFeedTemplate.html";
+ testStore = new dojox.data.GoogleFeedStore();
+ function doAppend(items){
+ var node = document.createElement("div");
+ node.id = "res" + (count++);
+ outNode.appendChild(node);
+ dojo.query("#"+node.id).dtl(template, { items: items , store: testStore});
+ }
+
+ request.onBegin = function(numItems){
+ outNode.innerHTML += ".. found " + numItems + " results";
+ };
+
+ request.onComplete = doAppend;
+
+ var count = dojo.byId("count").value;
+ request.count = count ? Number(count) : 8;
+
+ testStore.fetch(request);
+ }
+ </script>
+</head>
+<body class="tundra" style="margin:20px;">
+ <form>
+ Text: <select id="searchText" >
+ <option value="http://shaneosullivan.wordpress.com/feed/">http://shaneosullivan.wordpress.com/feed/</option>
+ <option value="http://dojocampus.org/content/category/dojo-cookies/feed/">http://dojocampus.org/content/category/dojo-cookies/feed/</option>
+ <option value="http://www.dojotoolkit.org/aggregator/rss">http://www.dojotoolkit.org/aggregator/rss</option>
+ </select>
+ Count: <input id="count" type="text" value="10" width=20/>
+ <input id="searchButton" type="button" value="store.fetch()" onclick="doSearch()" />
+
+ <div id="output">
+
+ </div>
+ <div id="entryContent">
+
+ </div>
+ </form>
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_GoogleSearchStore.html b/js/dojo-1.7.2/dojox/data/demos/demo_GoogleSearchStore.html
new file mode 100644
index 0000000..b82b334
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_GoogleSearchStore.html
@@ -0,0 +1,125 @@
+<!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";
+
+ .search-result {
+ float: left;
+ width: 150px;
+ border: 2px dashed;
+ padding: 4px;
+ }
+ </style>
+
+ <title>Google Search store</title>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojox.data.GoogleSearchStore");
+ dojo.require("dijit.form.ComboBox");
+ dojo.require("dijit.form.FilteringSelect");
+ dojo.require("dojox.dtl");
+ dojo.require("dojox.dtl.ext-dojo.NodeList");
+
+ function doSearch() {
+ var queryOptions = {};
+
+ var query = {};
+ query.text = dojo.byId("searchText").value;
+ query.type = dojo.byId("typeText").value;
+ var request = {query:query};
+
+ var itemBuffer = [];
+ var maxBufSize = 8;
+ var outNode = dojo.byId("output");
+ outNode.innerHTML = "Searching...";
+ var count = 0;
+ var template = "GoogleTemplate.html";
+ switch(query.type) {
+ case "web" :
+ testStore = new dojox.data.GoogleSearchStore();
+ break;
+ case "blogs":
+ testStore = new dojox.data.GoogleBlogSearchStore();
+ template = "GoogleTemplateBlog.html";
+ break;
+ case "local":
+ testStore = new dojox.data.GoogleLocalSearchStore();
+ template = "GoogleTemplateLocal.html";
+ break;
+ case "video":
+ testStore = new dojox.data.GoogleVideoSearchStore();
+ template = "GoogleTemplateVideo.html";
+ break;
+ case "news":
+ testStore = new dojox.data.GoogleNewsSearchStore();
+ break;
+ case "books":
+ testStore = new dojox.data.GoogleBookSearchStore();
+ break;
+ case "images":
+ testStore = new dojox.data.GoogleImageSearchStore();
+ template = "GoogleTemplateImage.html";
+ break;
+ }
+
+ function doAppend(){
+ var node = document.createElement("span");
+ node.id = "res" + (count++);
+ outNode.appendChild(node);
+ dojo.query("#"+node.id).dtl(template, { items: itemBuffer , store: testStore});
+ }
+
+ request.onBegin = function(numItems){
+ outNode.innerHTML += ".. found " + numItems + " results";
+ };
+
+ request.onItem = function(item){
+ itemBuffer.push(item);
+ if(itemBuffer.length >= maxBufSize){
+ console.log("onItem, buffer length = " + itemBuffer.length + " & maxBufSize = " + maxBufSize);
+ doAppend();
+ itemBuffer = [];
+ } else {
+ console.log("onItem, buffer length = " + itemBuffer.length);
+ }
+ };
+
+ request.onComplete = function (items) {
+ if (itemBuffer.length > 0) {
+ doAppend();
+ }
+ };
+
+ var count = dojo.byId("count").value;
+ request.count = count ? Number(count) : 8;
+
+ testStore.fetch(request);
+ }
+ </script>
+</head>
+<body class="tundra" style="margin:20px;">
+ <form>
+ Text: <input id="searchText" type="text" value="dojo ajax"/>
+ Count: <input id="count" type="text" value="8" width=20/>
+ <input id="searchButton" type="button" value="store.fetch()" onclick="doSearch()" />
+ Type
+ <select id="typeText" name="typeText">
+ <option selected value="web">Web</option>
+ <option value="local">Local</option>
+ <option value="video">Video</option>
+ <option value="blogs">Blogs</option>
+ <option value="news">News</option>
+ <option value="books">Books</option>
+ <option value="images">Images</option>
+ </select>
+ <div id="output">
+
+ </div>
+ </form>
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_GoogleSearchStore_Grid.html b/js/dojo-1.7.2/dojox/data/demos/demo_GoogleSearchStore_Grid.html
new file mode 100644
index 0000000..99dacaa
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_GoogleSearchStore_Grid.html
@@ -0,0 +1,71 @@
+<!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";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "../../../dojox/grid/resources/tundraGrid.css";
+ </style>
+
+ <title>Google Search Store with Grid</title>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojox.grid.DataGrid");
+ dojo.require("dijit.form.TextBox");
+ dojo.require("dijit.form.Button");
+ dojo.require("dojox.wire.ml.Invocation");
+ dojo.require("dojox.wire.ml.Transfer");
+ dojo.require("dojox.wire.ml.Action");
+ dojo.require("dojox.data.GoogleSearchStore");
+
+ var href = function(value) {
+ return "<a href=\"" + value + "\" target=\"_blank\">" + value + "</a>";
+ }
+ var layoutResults = [
+ [
+ { name: "Title", field: "title", width: 10 },
+ { name: "Summary", field: "content", width: "auto"},
+ { name: "URL", field: "url", width: 20, formatter: href }
+ ]
+ ];
+ var newQuery = {text: 'dojo ajax' };
+ </script>
+</head>
+<body class="tundra" style="margin:20px;">
+ <h1>dojox.data.GoogleSearchStore:</h1>
+ <i>Displays a list of results from a google query.</i>
+ <div dojoType="dojox.data.GoogleSearchStore" jsId="googleStore"></div>
+ <br>
+ <br>
+ <div dojoType="dijit.form.TextBox" id="searchText" value="dojo ajax"></div>
+ <button dojoType="dijit.form.Button" id="searchButton">Search</button>
+ <br>
+ <br>
+ <br>
+
+ <div dojoType="dojox.grid.DataGrid"
+ rowsPerPage="8"
+ store="googleStore"
+ structure="layoutResults"
+ query="{ text: 'dojo ajax' }"
+ jsId="grid"
+ style="width: 800px; height: 500px;"
+ >
+ </div>
+
+ <!--
+ Link the button to updating the query, then triggering the refresh of the grid.
+ Handy use of dojox.wire!
+ -->
+ <div dojoType="dojox.wire.ml.Action"
+ trigger="searchButton"
+ triggerEvent="onClick">
+ <div dojoType="dojox.wire.ml.Transfer" source="searchText.value" target="newQuery.text"></div>
+ <div dojoType="dojox.wire.ml.Invocation" object="grid" method="setQuery" parameters="newQuery"></div>
+ </div>
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_LazyLoad.html b/js/dojo-1.7.2/dojox/data/demos/demo_LazyLoad.html
new file mode 100644
index 0000000..358ce84
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/demo_MultiStores.html b/js/dojo-1.7.2/dojox/data/demos/demo_MultiStores.html
new file mode 100644
index 0000000..29ede27
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_MultiStores.html
@@ -0,0 +1,116 @@
+<!--
+ 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.form.FilteringSelect");
+ dojo.require("dijit.Tree");
+ dojo.require("dijit.tree.ForestStoreModel");
+
+ dojo.require("dojox.data.OpmlStore");
+ dojo.require("dojox.data.XmlStore");
+ 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>
+ <div dojoType="dojox.data.XmlStore" url="geography2.xml" label="text" attributeMap="{'text': '@text'}" jsId="xmlGeoStore"></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>Filtering Select:</b><br>
+ <input dojoType="dijit.form.FilteringSelect" id="fs1" name="fs1" class="medium" store="opmlGeoStore" searchAttr="text" query="{}"></input>
+ <br>
+ <br>
+
+ <b>Tree:</b><br>
+ <div dojoType="dijit.tree.ForestStoreModel" jsId="opmlModel"
+ store="opmlGeoStore" query="{}"
+ rootId="Continents" rootLabel="Continents" childrenAttrs="children">
+ </div>
+ <div dojoType="dijit.Tree" id="tree1" model="opmlModel"></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>Filtering Select:</b><br>
+ <input dojoType="dijit.form.FilteringSelect" id="fs2" name="fs2" class="medium" store="ifrGeoStore" searchAttr="text" query="{}"></input>
+ <br>
+ <br>
+
+ <b>Tree:</b><br>
+ <div dojoType="dijit.tree.ForestStoreModel" jsId="ifrModel"
+ store="ifrGeoStore" query="{}"
+ rootId="Continents" rootLabel="Continents" childrenAttrs="children">
+ </div>
+ <div dojoType="dijit.Tree" id="tree2" model="ifrModel"></div>
+ </blockquote>
+
+ <h3>
+ Widgets using XmlStore:
+ </h3>
+ <blockquote>
+ <b>ComboBox:</b><br>
+ <input dojoType="dijit.form.ComboBox" id="combo3" name="combo3" class="medium" store="xmlGeoStore" searchAttr="text" query="{}"></input>
+ <br>
+ <br>
+
+ <b>Filtering Select:</b><br>
+ <input dojoType="dijit.form.FilteringSelect" id="fs3" name="fs3" class="medium" store="xmlGeoStore" searchAttr="text" query="{}"></input>
+ <br>
+ <br>
+
+ <b>Tree:</b><br>
+ <div dojoType="dijit.tree.ForestStoreModel" jsId="xmlModel"
+ store="xmlGeoStore" query="{}"
+ rootId="Continents" rootLabel="Continents" childrenAttrs="childNodes">
+ </div>
+ <div dojoType="dijit.Tree" id="tree3" model="xmlModel"></div>
+ </blockquote>
+ </blockquote>
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_OpenSearchStore.html b/js/dojo-1.7.2/dojox/data/demos/demo_OpenSearchStore.html
new file mode 100644
index 0000000..e8bcc13
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_OpenSearchStore.html
@@ -0,0 +1,215 @@
+<!--
+ This file is a demo of the OpenSearchStore, a simple wrapper to any OpenSearch compliant
+ search engine.
+
+ Note, the simple proxy requires a curl-enabled PHP install
+-->
+<html>
+<head>
+ <title>Demo of OpenSearchStore</title>
+ <style type="text/css">
+
+ @import "../../../dijit/themes/tundra/tundra.css";
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "./openSearchDemo.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.FilteringSelect");
+ dojo.require("dijit.form.CheckBox");
+ dojo.require("dijit.form.NumberSpinner");
+ dojo.require("dijit.Tree");
+ dojo.require("dojox.data.OpenSearchStore");
+
+ function init(){
+ var fViewWidgets = [];
+
+ //Set up an onComplete handler for OpenSearchData
+ function onComplete(items, request){
+ if(items.length > 0){
+ var ul = dojo.byId("searchResults");
+ var test;
+ var li;
+ for(var i=0; i<items.length; i++){
+ li = dojo.doc.createElement("li");
+ li.innerHTML = openSearchStore.getValue(items[i], "content");
+ ul.appendChild(li);
+ }
+ }
+ statusWidget.attr('value', "PROCESSING COMPLETE.");
+ }
+ //What to do if a search fails...
+ function onError(error, request){
+ statusWidget.attr('value', "PROCESSING ERROR.");
+ }
+
+ //Function to invoke the search of the openSearchStore
+ function invokeSearch(){
+ var tbody = dojo.byId("searchResults");
+ while(tbody.childNodes.length){
+ var node = tbody.childNodes.item(0);
+ node.parentNode.removeChild(node);
+ }
+ var request = {
+ query: {},
+ onComplete: onComplete,
+ onError: onError
+ };
+ if(searchTermsWidget){
+ var searchTerms = searchTermsWidget.attr('value');
+ if(searchTerms && searchTerms !== ""){
+ var searchTermsArray = searchTerms.split(" ");
+ searchTerms = "";
+ for(var i = 0; i < searchTermsArray.length; i++){
+ searchTerms = searchTerms + searchTermsArray[i];
+ if(i < (searchTermsArray.length - 1)){
+ searchTerms += ","
+ }
+ }
+ request.query.searchTerms = searchTerms;
+ }
+ }
+
+ if(countWidget){
+ request.count = countWidget.attr('value');
+ }
+
+ if(statusWidget){
+ statusWidget.attr('value', "PROCESSING REQUEST");
+ }
+
+ openSearchStore.fetch(request);
+ }
+
+ //Lastly, link up the search event.
+ dojo.connect(dijit.byId("searchButton"), 'onClick', invokeSearch);
+ var currentArgs = {url: 'http://intertwingly.net/search/'};
+ var oldProcess = null;
+ function setTransform(state){
+ if(state){
+ oldProcess = openSearchStore.processItem;
+ switch(currentArgs.url){
+ case 'http://intertwingly.net/search/':
+ openSearchStore.processItem = intertwinglyTransform;
+ break;
+ case 'http://www.shutterpoint.com/opensearch.xml':
+ openSearchStore.processItem = shutterpointTransform;
+ break;
+ case 'http://technorati.com/osd.xml':
+ openSearchStore.processItem = technoratiTransform;
+ break;
+ }
+ }else if(oldProcess !== null){
+ openSearchStore.processItem = oldProcess;
+ }
+ }
+ dojo.connect(dijit.byId('transformItem'), 'onChange', function(state){
+ setTransform(state);
+ });
+ dojo.connect(dijit.byId('urlSelector'), 'onChange', function(args){
+ currentArgs = dojo.fromJson(args);
+ currentArgs.url = 'openSearchProxy.php?osd=true&url='+currentArgs.url;
+ openSearchStore.close();
+ openSearchStore = new dojox.data.OpenSearchStore(currentArgs);
+ if(dijit.byId('transformItem').checked){
+ setTransform(true);
+ }
+ });
+
+ var intertwinglyTransform = function(item, attribute){
+ function removeAll(/*NodeList*/list){
+ while(list.length) {
+ var node = list.item(0);
+ node.parentNode.removeChild(node);
+ }
+ }
+ var content = item.node.getElementsByTagName("content").item(0);
+ // Remove all blockquote elements
+ removeAll(content.getElementsByTagName("blockquote"));
+ // Remove all pre-formatted elements
+ removeAll(content.getElementsByTagName("pre"));
+ return openSearchStore._getNodeXml(content, true);
+ };
+
+ var shutterpointTransform = function(item, attribute){
+ var description = item.node.getElementsByTagName("description").item(0);
+ var div = dojo.doc.createElement("div");
+ div.innerHTML = description.childNodes.item(0).nodeValue;
+ //Of the description children, remove the divs (to only leave the images)
+ for(var i=0; i<div.childNodes.length; i++){
+ var node = div.childNodes.item(i);
+ if(node.tagName.toLowerCase() === "div")
+ node.parentNode.removeChild(node);
+ }
+ return openSearchStore._getNodeXml(div, true);
+ };
+
+ var technoratiTransform = function(item, attribute){
+ function removeAll(/*NodeList*/list){
+ while(list.length) {
+ var node = list.item(0);
+ node.parentNode.removeChild(node);
+ }
+ }
+ removeAll(item.node.getElementsByTagName("blockquote"));
+ return item.innerHTML;
+ };
+ }
+ dojo.addOnLoad(init);
+ </script>
+</head>
+
+<body class="tundra">
+ <h1>DEMO: OpenSearchStore Search</h1>
+ <hr />
+ <h3>Description:</h3>
+ <p>
+ This simple demo shows how services, such as an OpenSearch compliant search service, can be wrapped by the datastore API. In this demo, you can search public search engines through a simple OpenSearchStore by specifying a series of search terms (separated by spaces) to search on. The results will be displayed below the search box.
+ </p>
+ <p>
+ <b>NOTE: This demo makes use of a simple PHP based proxy script. The proxy script requires cURL support in PHP. Without cURL support, the demo will throw errors.</b>
+ </p>
+ <label for="urlSelector">URL of OpenSearchDocument:</label>
+ <select dojoType="dijit.form.FilteringSelect"
+ id="urlSelector"
+ name="urlSelector"
+ autoComplete="true">
+ <option value="{url: 'http://intertwingly.net/search/'}">http://intertwingly.net/search/</option>
+ <option value="{url: 'http://www.shutterpoint.com/opensearch.xml'}">http://www.shutterpoint.com/opensearch.xml</option>
+ <option value="{url: 'http://technorati.com/osd.xml', itemPath: '.hentry'}">http://technorati.com/osd.xml</option>
+ </select>
+ <label for="transformItem">Apply transform function?</label>
+ <input dojoType="dijit.form.CheckBox"
+ type="checkbox"
+ id="transformItem"
+ name="transformItem">
+ </input>
+ <hr />
+ <label for="status">Status:</label>
+ <div dojoType="dijit.form.TextBox" maxLength="50" id="status" name="status" jsId="statusWidget" disabled="true"></div>
+ <label for="searchTerms">Search For:</label>
+ <div dojoType="dijit.form.TextBox" maxLength="50" id="searchTerms" name="searchTerms" jsId="searchTermsWidget" value="javascript"></div>
+ <label for="count">Number of Results:</label>
+ <div id="count"
+ name="count"
+ jsId="countWidget"
+ dojoType="dijit.form.NumberSpinner"
+ value="20"
+ constraints="{min:1,max:20}">
+ </div>
+ <div dojoType="dijit.form.Button" label="Search" id="searchButton" jsId="searchButtonWidget"></div>
+ <hr/>
+ <div dojoType="dojox.data.OpenSearchStore"
+ url="openSearchProxy.php?osd=true&url=http://intertwingly.net/search/"
+ jsId="openSearchStore">
+ </div>
+ <ul id="searchResults"></ul>
+
+</body>
+</html> \ No newline at end of file
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_PicasaStore.html b/js/dojo-1.7.2/dojox/data/demos/demo_PicasaStore.html
new file mode 100644
index 0000000..47f73a4
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_PicasaStore.html
@@ -0,0 +1,190 @@
+<!--
+ 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 picasaData
+ function onComplete(items, request){
+ picasaViewsWidget.clearList();
+ if(items.length > 0){
+ for(var i = 0; i < items.length; i++){
+ var picasaData = {
+ title: picasaStore.getValue(items[i],"title"),
+ author: picasaStore.getValue(items[i],"author"),
+ description: picasaStore.getValue(items[i],"description"),
+ iconUrl: picasaStore.getValue(items[i],"imageUrlSmall"),
+ imageUrl: picasaStore.getValue(items[i],"imageUrl")
+ }
+ picasaViewsWidget.addView(picasaData);
+ }
+ }
+ statusWidget.attr("value", "PROCESSING COMPLETE.");
+
+ }
+ //What to do if a search fails...
+ function onError(error, request){
+ console.debug(error);
+ picasaViewsWidget.clearList();
+ statusWidget.attr("value", "PROCESSING ERROR.");
+ }
+
+ //Function to invoke the search of the PicasaStore
+ function invokeSearch(){
+ var request = {
+ query: {},
+ onComplete: onComplete,
+ onError: onError
+ };
+
+ if(idWidget){
+ var userid = idWidget.attr("value");
+ if(userid && userid !== ""){
+ request.query.userid = userid;
+ }
+ }
+ if(tagsWidget){
+ var tags = tagsWidget.attr("value");
+ 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.attr("value");
+ }
+
+ if(startWidget){
+ request.query.start = startWidget.attr("value");
+ }
+
+ if(statusWidget){
+ statusWidget.attr("value","PROCESSING REQUEST");
+ }
+
+ picasaStore.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 Picasa, can be wrapped by the datastore API. In this demo, you can search public Picasa images through a simple PicasaStore 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/>
+ </blockquote>
+ <div dojoType="dojox.data.PicasaStore" jsId="picasaStore" label="title"></div>
+ <div dojoType="dojox.data.demos.widgets.PicasaViewList" id="picasaViews" jsId="picasaViewsWidget"></div>
+
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_ComboBox.html b/js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_ComboBox.html
new file mode 100644
index 0000000..6be9265
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_ComboBox.html
@@ -0,0 +1,58 @@
+<!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 class="dijitContainer">
+ <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" autoComplete="false"></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.attr("displayedValue")
+ <br /><input id="isValid1" type="text" /> = w.isValid()
+ <br /><button dojoType="dijit.form.Button" onclick="refresh1()">refresh</button>
+ </div>
+ </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.attr("displayedValue");
+ 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/js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html b/js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html
new file mode 100644
index 0000000..6f89167
--- /dev/null
+++ b/js/dojo-1.7.2/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" autoComplete="false"></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/js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_grid.html b/js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_grid.html
new file mode 100644
index 0000000..7035ebd
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_QueryReadStore_grid.html
@@ -0,0 +1,110 @@
+<!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
+ grid looks so strange (or even think that it doesnt work) */
+ @import "../../../dojox/grid/resources/tundraGrid.css";
+ </style>
+
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug:true, parseOnLoad: true, useCommentedJson: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojox.grid.DataGrid");
+ dojo.require("dojox.data.QueryReadStore");
+ dojo.require("dojo.parser"); // scan page for widgets and instantiate them
+ var gridLayout = [
+ new dojox.grid.cells.RowIndex({ name: "row #", width: 5, styles: "text-align: right;" }),
+ {
+ 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 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 store = null;
+ dojo.addOnLoad(function() {
+ store = new dojox.data.QueryReadStore({
+ url:"../tests/stores/QueryReadStore.php",
+ requestMethod:"post"
+ });
+ grid1.setStore(store);
+ grid1.setStructure(gridLayout);
+ });
+
+ var lastSearchValue = "";
+ function doSearch(el) {
+ if (el.value!=lastSearchValue) {
+ lastSearchValue = el.value;
+ grid1.filter({name:el.value});
+ grid2.filter({name:el.value});
+ }
+ }
+ </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, 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" jsid="grid1" dojoType="dojox.grid.DataGrid" query="{ name: '*' }" rowsPerPage="30" 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.DataGrid"
+ id="grid2" jsid="grid2"
+ store="store2"
+ query="{ name: '*' }"
+ rowsPerPage="30"
+ structure="gridLayout"
+ style="height:300px; width:800px;"></div>
+
+
+
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/demo_WikipediaStore.html b/js/dojo-1.7.2/dojox/data/demos/demo_WikipediaStore.html
new file mode 100644
index 0000000..bc290b0
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/demo_WikipediaStore.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Wikipedia Data Store</title>
+<style type="text/css">
+@import "../../../dojo/resources/dojo.css";
+@import "../../../dijit/themes/tundra/tundra.css";
+h1 { margin-bottom: 1em; }
+</style>
+<script type="text/javascript">
+//<![CDATA[
+djConfig = { isDebug: true };
+//]]>
+</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+//<![CDATA[
+dojo.require("dojox.data.WikipediaStore");
+var store = new dojox.data.WikipediaStore();
+
+function doSearch(){
+ var outNode = dojo.byId("output");
+ outNode.innerHTML = "Searching...";
+
+ function loadArticle(article){
+ var request = {
+ query: {
+ title: article
+ },
+ onItem: function(item, req){
+ var title = store.getValue(item, "title");
+ var text = store.getValue(item, "text")["*"];
+ outNode.innerHTML = "<h1>" + title + "</h1>" + text;
+ }
+ };
+ console.log("Article request: ", request);
+ store.fetch(request);
+ }
+
+
+ var request = {
+ query: {
+ action: "query",
+ text: dojo.byId("searchText").value
+ },
+ count: dojo.byId("count").value,
+ onBegin: function(count){
+ outNode.innerHTML += " found " + count + " results.<br>Click one to load the article.";
+ },
+ onItem: function(item, req){
+ console.debug(item);
+ var node = document.createElement("a");
+ node.href = "#";
+ node.onclick = function(){
+ console.log("clicked ", this.innerHTML);
+ loadArticle(this.innerHTML);
+ };
+ node.style.padding = "6px";
+ node.style.display = "block";
+ node.innerHTML = store.getValue(item, "title");
+ outNode.appendChild(node);
+ }
+ };
+ console.log("Request: ", request);
+ store.fetch(request);
+}
+//]]>
+</script>
+</head>
+<body class="tundra" style="margin:20px;">
+ <form action="#">
+ <p>
+ Text: <input id="searchText" type="text" value="dojo toolkit">
+ Count: <input id="count" type="text" value="8" size="3">
+ <input id="searchButton" type="button" value="store.fetch()" onclick="doSearch()">
+ </p>
+
+ <div id="output" style="padding:0 20px;">
+ </div>
+ </form>
+</body>
+</html>
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography.json b/js/dojo-1.7.2/dojox/data/demos/geography.json
new file mode 100644
index 0000000..c2f01bb
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography.xml b/js/dojo-1.7.2/dojox/data/demos/geography.xml
new file mode 100644
index 0000000..070a8c1
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography/Argentina/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Argentina/data.json
new file mode 100644
index 0000000..17ba291
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Argentina/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Argentina',
+ type:'country',
+ population:'40 million'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Brazil/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Brazil/data.json
new file mode 100644
index 0000000..a326c24
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Brazil/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Brazil',
+ type:'country',
+ population:'186 million'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Canada/Ottawa/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Canada/Ottawa/data.json
new file mode 100644
index 0000000..df3bbc8
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography/Canada/Toronto/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Canada/Toronto/data.json
new file mode 100644
index 0000000..534409b
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography/Canada/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Canada/data.json
new file mode 100644
index 0000000..6ef34ed
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography/China/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/China/data.json
new file mode 100644
index 0000000..72c29cc
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/China/data.json
@@ -0,0 +1,4 @@
+{
+ name:'China',
+ type:'country'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Commonwealth of Australia/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Commonwealth of Australia/data.json
new file mode 100644
index 0000000..e093295
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography/Egypt/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Egypt/data.json
new file mode 100644
index 0000000..d355537
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Egypt/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Egypt',
+ type:'country'
+}
+
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/France/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/France/data.json
new file mode 100644
index 0000000..5b5f3c3
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/France/data.json
@@ -0,0 +1,4 @@
+{
+ name:'France',
+ type:'country'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Germany/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Germany/data.json
new file mode 100644
index 0000000..1656257
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Germany/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Germany',
+ type:'country'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/India/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/India/data.json
new file mode 100644
index 0000000..3103f89
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/India/data.json
@@ -0,0 +1,4 @@
+{
+ name:'India',
+ type:'country'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Italy/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Italy/data.json
new file mode 100644
index 0000000..6e6b076
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Italy/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Italy',
+ type:'country'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Kenya/Mombasa/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Kenya/Mombasa/data.json
new file mode 100644
index 0000000..28aa849
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Kenya/Mombasa/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Mombasa',
+ type:'city',
+ population: "Unknown"
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Kenya/Nairobi/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Kenya/Nairobi/data.json
new file mode 100644
index 0000000..f5658ec
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Kenya/Nairobi/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Nairobi',
+ type:'city',
+ population: "Unknown"
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Kenya/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Kenya/data.json
new file mode 100644
index 0000000..9253c25
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Kenya/data.json
@@ -0,0 +1,9 @@
+{
+ name:'Kenya',
+ type:'country',
+ children:[
+ {stub:'Nairobi'},
+ {stub:'Mombasa'}
+ ]
+}
+
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Mexico/Guadalajara/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Mexico/Guadalajara/data.json
new file mode 100644
index 0000000..059fc82
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography/Mexico/Mexico City/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Mexico/Mexico City/data.json
new file mode 100644
index 0000000..8c67622
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography/Mexico/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Mexico/data.json
new file mode 100644
index 0000000..aa381e4
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography/Mongolia/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Mongolia/data.json
new file mode 100644
index 0000000..4c60b22
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Mongolia/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Mongolia',
+ type:'country'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Russia/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Russia/data.json
new file mode 100644
index 0000000..5d9a6ba
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Russia/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Russia',
+ type:'country'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Spain/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Spain/data.json
new file mode 100644
index 0000000..d9a1210
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Spain/data.json
@@ -0,0 +1,4 @@
+{
+ name:'Spain',
+ type:'country'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Sudan/Khartoum/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Sudan/Khartoum/data.json
new file mode 100644
index 0000000..befa3c7
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Sudan/Khartoum/data.json
@@ -0,0 +1,5 @@
+{
+ name:'Khartoum',
+ type:'city'
+}
+
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/Sudan/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/Sudan/data.json
new file mode 100644
index 0000000..fe7585b
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/Sudan/data.json
@@ -0,0 +1,6 @@
+{
+ name:'Sudan',
+ type:'country',
+ children:{stub:'Khartoum'}
+}
+
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/United States of America/data.json b/js/dojo-1.7.2/dojox/data/demos/geography/United States of America/data.json
new file mode 100644
index 0000000..7dbdd61
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography/United States of America/data.json
@@ -0,0 +1,4 @@
+{
+ name:'United States of America',
+ type:'country'
+}
diff --git a/js/dojo-1.7.2/dojox/data/demos/geography/root.json b/js/dojo-1.7.2/dojox/data/demos/geography/root.json
new file mode 100644
index 0000000..dda74f5
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/geography2.xml b/js/dojo-1.7.2/dojox/data/demos/geography2.xml
new file mode 100644
index 0000000..b82c110
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/geography2.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<geography>
+ <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>
+</geography>
+
diff --git a/js/dojo-1.7.2/dojox/data/demos/openSearchProxy.php b/js/dojo-1.7.2/dojox/data/demos/openSearchProxy.php
new file mode 100644
index 0000000..4f66307
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/openSearchProxy.php
@@ -0,0 +1,33 @@
+<?php
+// A simple proxy for testing the OpenSearchStore
+// Note, this simple proxy requires a curl-enabled PHP install
+if(!$_GET['url']){ return; }
+
+$url = str_replace(array(';;;;', '%%%%'), array('?', '&'), $_GET['url']);
+if(stripos($url, "http://intertwingly.net/") === 0 ||
+ stripos($url, "http://www.intertwingly.net/") === 0 ||
+ stripos($url, "http://www.shutterpoint.com/") === 0 ||
+ stripos($url, "http://technorati.com/") === 0){
+ $ch = curl_init($url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ $results = curl_exec($ch);
+ header('HTTP/1.1 ' . curl_getinfo($ch, CURLINFO_HTTP_CODE) . ' OK');
+ if($_GET['osd'] === 'true'){
+ $xml = new SimpleXMLElement($results);
+ if($xml->Url){
+ foreach($xml->Url as $url){
+ $url['template'] = $_SERVER['SCRIPT_NAME'].'?url='.str_replace(array('?', '&'), array(';;;;', '%%%%'), $url['template']);
+ }
+ header('Content-Type: text/xml');
+ print $xml->asXML();
+ }
+ }else{
+ header('Content-Type: '.curl_getinfo($ch, CURLINFO_CONTENT_TYPE));
+ print $results;
+ }
+}else{
+ header("HTTP/1.0 403 Forbidden");
+ header("Status: 403 Forbidden");
+ print "Provided URL not allowed by this demo proxy.";
+}
+
diff --git a/js/dojo-1.7.2/dojox/data/demos/picasaDemo.css b/js/dojo-1.7.2/dojox/data/demos/picasaDemo.css
new file mode 100644
index 0000000..e274f87
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/picasaDemo.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/js/dojo-1.7.2/dojox/data/demos/stores/LazyLoadJSIStore.js b/js/dojo-1.7.2/dojox/data/demos/stores/LazyLoadJSIStore.js
new file mode 100644
index 0000000..7a867a4
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/stores/LazyLoadJSIStore.js
@@ -0,0 +1,143 @@
+//>>built
+// wrapped by build app
+define("dojox/data/demos/stores/LazyLoadJSIStore", ["dijit","dojo","dojox","dojo/require!dojo/data/ItemFileReadStore"], function(dijit,dojo,dojox){
+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 (var 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 = 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/js/dojo-1.7.2/dojox/data/demos/stores/filestore_dojotree.php b/js/dojo-1.7.2/dojox/data/demos/stores/filestore_dojotree.php
new file mode 100644
index 0000000..5e19385
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/stores/filestore_dojotree.php
@@ -0,0 +1,179 @@
+<?php
+ //Define the root directory to use for this service.
+ //All file lookups are relative to this path.
+ $rootDir = "../../../..";
+
+ require_once("filestore_funcs.php");
+
+ //Extract the query, if any.
+ $query = false;
+ if (array_key_exists("query", $_GET)) {
+ $query = $_GET['query'];
+ $query = str_replace("\\\"", "\"", $query);
+ $query = json_decode($query, true);
+ }
+ //Extract relevant query options.
+ $queryOptions = json_decode("{}");
+ $deep = false;
+ $ignoreCase = false;
+ if (array_key_exists("queryOptions", $_GET)) {
+ $queryOptions = $_GET['queryOptions'];
+ $queryOptions = str_replace("\\\"", "\"", $queryOptions);
+ $queryOptions = json_decode($queryOptions);
+ if (property_exists($queryOptions, "deep")) {
+ $deep = $queryOptions->deep;
+ }
+ if (property_exists($queryOptions, "ignoreCase")) {
+ $ignoreCase = $queryOptions->ignoreCase;
+ }
+ }
+
+ //Extract non-dojo.data spec config options.
+ $expand = false;
+ $dirsOnly = false;
+ $showHiddenFiles = false;
+ $options = array();
+ if (array_key_exists("options", $_GET)) {
+ $options = $_GET['options'];
+ $options = str_replace("\\\"", "\"", $options);
+ $options = json_decode($options);
+ if (array_search("expand", $options) > -1) {
+ $expand = true;
+ }
+ if (array_search("dirsOnly", $options) > -1) {
+ $dirsOnly = true;
+ }
+ if (array_search("showHiddenFiles", $options) > -1) {
+ $showHiddenFiles = true;
+ }
+ }
+
+
+ //See if a specific file was requested, or if it is just a query for files.
+ $path = false;
+ if (array_key_exists("path", $_GET)) {
+ $path = $_GET['path'];
+ }
+
+ if (!is_string($path)) {
+
+ $files = array();
+
+ //Handle query for files. Must try to generate patterns over the query
+ //attributes.
+ $patterns = array();
+ if (is_array($query)) {
+ //Generate a series of RegExp patterns as necessary.
+ $keys = array_keys($query);
+ $total = count($keys);
+ if ($total > 0) {
+ for ($i = 0; $i < $total; $i++) {
+ $key = $keys[$i];
+ $pattern = $query[$key];
+ if (is_string($pattern)) {
+ $patterns[$key] = patternToRegExp($pattern);
+ }
+ }
+ $files = matchFiles($query, $patterns, $ignoreCase, ".", $rootDir, $deep, $dirsOnly, $expand, $showHiddenFiles);
+ } else {
+ $files = getAllFiles(".",$rootDir,$deep,$dirsOnly,$expand,$showHiddenFiles);
+ }
+ }else{
+ $files = getAllFiles(".",$rootDir,$deep,$dirsOnly,$expand,$showHiddenFiles);
+ }
+
+ $total = count($files);
+
+ //Handle the sorting and paging.
+ $sortSpec = false;
+ if (array_key_exists("sort", $_GET)) {
+ $sortSpec = $_GET['sort'];
+ $sortSpec = str_replace("\\\"", "\"", $sortSpec);
+ $sortSpec = json_decode($sortSpec);
+ }
+
+ if ($sortSpec != null) {
+ $comparator = createComparator($sortSpec);
+ usort($files,array($comparator, "compare"));
+ }
+
+ //Page, if necessary.
+ if (array_key_exists("start", $_GET)) {
+ $start = $_GET['start'];
+ if (!is_numeric($start)) {
+ $start = 0;
+ }
+ $files = array_slice($files, $start);
+ }
+ if (array_key_exists("count", $_GET)) {
+ $count = $_GET['count'];
+ if (!is_numeric($count)) {
+ $count = $total;
+ }
+ $files = array_slice($files, 0, $count);
+ }
+
+ $result = new stdClass();
+ $result->total = $total;
+ $result->items = $files;
+ header("Content-Type", "text/json");
+ print("/* ".json_encode($result)." */");
+ } else {
+ //Query of a specific file (useful for fetchByIdentity and loadItem)
+
+ //Make sure the path isn't trying to walk out of the rooted directory
+ //As defined by $rootDir in the top of the php script.
+ $rootPath = realPath($rootDir);
+ $fullPath = realPath($rootPath."/".$path);
+
+ if ($fullPath !== false) {
+ if (strpos($fullPath,$rootPath) === 0) {
+ //Root the path into the tree cleaner.
+ if (strlen($fullPath) == strlen($rootPath)) {
+ $path = ".";
+ } else {
+ //Fix the path to relative of root and put back into UNIX style (even if windows).
+ $path = substr($fullPath,(strlen($rootPath) + 1),strlen($fullPath));
+ $path = str_replace("\\", "/", $path);
+ }
+
+ if (file_exists($fullPath)) {
+ $arr = explode("/", $path);
+ $size = count($arr);
+
+ if ($size > 0) {
+ $fName = $arr[$size - 1];
+ if ($size == 1) {
+ print("Setting path to: .");
+ $path = ".";
+ } else {
+ $path = $arr[0];
+ }
+ for ($i = 1; $i < ($size - 1); $i++) {
+ $path = $path."/".$arr[$i];
+ }
+ $file = generateFileObj($fName, $path, $rootDir, $expand,$showHiddenFiles);
+ header("Content-Type", "text/json");
+ print("/* ".json_encode($file)." */");
+ } else {
+ header("HTTP/1.0 404 Not Found");
+ header("Status: 404 Not Found");
+ print("<b>Cannot access file: [".htmlentities($path)."]<b>");
+ }
+ } else {
+ header("HTTP/1.0 404 Not Found");
+ header("Status: 404 Not Found");
+ print("<b>Cannot access file: [".htmlentities($path)."]<b>");
+ }
+ } else {
+ header("HTTP/1.0 403 Forbidden");
+ header("Status: 403 Forbidden");
+ print("<b>Cannot access file: [".htmlentities($path)."]. It is outside of the root of the file service.<b>");
+ }
+ } else {
+ header("HTTP/1.0 404 Not Found");
+ header("Status: 404 Not Found");
+ print("<b>Cannot access file: [".htmlentities($path)."]<b>");
+ }
+ }
+?>
diff --git a/js/dojo-1.7.2/dojox/data/demos/stores/filestore_dojoxdata.php b/js/dojo-1.7.2/dojox/data/demos/stores/filestore_dojoxdata.php
new file mode 100644
index 0000000..0360049
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/stores/filestore_dojoxdata.php
@@ -0,0 +1,179 @@
+<?php
+ //Define the root directory to use for this service.
+ //All file lookups are relative to this path.
+ $rootDir = "../..";
+
+ require_once("filestore_funcs.php");
+
+ //Extract the query, if any.
+ $query = false;
+ if (array_key_exists("query", $_GET)) {
+ $query = $_GET['query'];
+ $query = str_replace("\\\"", "\"", $query);
+ $query = json_decode($query, true);
+ }
+ //Extract relevant query options.
+ $queryOptions = json_decode("{}");
+ $deep = false;
+ $ignoreCase = false;
+ if (array_key_exists("queryOptions", $_GET)) {
+ $queryOptions = $_GET['queryOptions'];
+ $queryOptions = str_replace("\\\"", "\"", $queryOptions);
+ $queryOptions = json_decode($queryOptions);
+ if (property_exists($queryOptions, "deep")) {
+ $deep = $queryOptions->deep;
+ }
+ if (property_exists($queryOptions, "ignoreCase")) {
+ $ignoreCase = $queryOptions->ignoreCase;
+ }
+ }
+
+ //Extract non-dojo.data spec config options.
+ $expand = false;
+ $dirsOnly = false;
+ $showHiddenFiles = false;
+ $options = array();
+ if (array_key_exists("options", $_GET)) {
+ $options = $_GET['options'];
+ $options = str_replace("\\\"", "\"", $options);
+ $options = json_decode($options);
+ if (array_search("expand", $options) > -1) {
+ $expand = true;
+ }
+ if (array_search("dirsOnly", $options) > -1) {
+ $dirsOnly = true;
+ }
+ if (array_search("showHiddenFiles", $options) > -1) {
+ $showHiddenFiles = true;
+ }
+ }
+
+
+ //See if a specific file was requested, or if it is just a query for files.
+ $path = false;
+ if (array_key_exists("path", $_GET)) {
+ $path = $_GET['path'];
+ }
+
+ if (!is_string($path)) {
+
+ $files = array();
+
+ //Handle query for files. Must try to generate patterns over the query
+ //attributes.
+ $patterns = array();
+ if (is_array($query)) {
+ //Generate a series of RegExp patterns as necessary.
+ $keys = array_keys($query);
+ $total = count($keys);
+ if ($total > 0) {
+ for ($i = 0; $i < $total; $i++) {
+ $key = $keys[$i];
+ $pattern = $query[$key];
+ if (is_string($pattern)) {
+ $patterns[$key] = patternToRegExp($pattern);
+ }
+ }
+ $files = matchFiles($query, $patterns, $ignoreCase, ".", $rootDir, $deep, $dirsOnly, $expand, $showHiddenFiles);
+ } else {
+ $files = getAllFiles(".",$rootDir,$deep,$dirsOnly,$expand,$showHiddenFiles);
+ }
+ }else{
+ $files = getAllFiles(".",$rootDir,$deep,$dirsOnly,$expand,$showHiddenFiles);
+ }
+
+ $total = count($files);
+
+ //Handle the sorting and paging.
+ $sortSpec = false;
+ if (array_key_exists("sort", $_GET)) {
+ $sortSpec = $_GET['sort'];
+ $sortSpec = str_replace("\\\"", "\"", $sortSpec);
+ $sortSpec = json_decode($sortSpec);
+ }
+
+ if ($sortSpec != null) {
+ $comparator = createComparator($sortSpec);
+ usort($files,array($comparator, "compare"));
+ }
+
+ //Page, if necessary.
+ if (array_key_exists("start", $_GET)) {
+ $start = $_GET['start'];
+ if (!is_numeric($start)) {
+ $start = 0;
+ }
+ $files = array_slice($files, $start);
+ }
+ if (array_key_exists("count", $_GET)) {
+ $count = $_GET['count'];
+ if (!is_numeric($count)) {
+ $count = $total;
+ }
+ $files = array_slice($files, 0, $count);
+ }
+
+ $result;
+ $result->total = $total;
+ $result->items = $files;
+ header("Content-Type", "text/json");
+ print("/* ".json_encode($result)." */");
+ } else {
+ //Query of a specific file (useful for fetchByIdentity and loadItem)
+
+ //Make sure the path isn't trying to walk out of the rooted directory
+ //As defined by $rootDir in the top of the php script.
+ $rootPath = realPath($rootDir);
+ $fullPath = realPath($rootPath."/".$path);
+
+ if ($fullPath !== false) {
+ if (strpos($fullPath,$rootPath) === 0) {
+ //Root the path into the tree cleaner.
+ if (strlen($fullPath) == strlen($rootPath)) {
+ $path = ".";
+ } else {
+ //Fix the path to relative of root and put back into UNIX style (even if windows).
+ $path = substr($fullPath,(strlen($rootPath) + 1),strlen($fullPath));
+ $path = str_replace("\\", "/", $path);
+ }
+
+ if (file_exists($fullPath)) {
+ $arr = split("/", $path);
+ $size = count($arr);
+
+ if ($size > 0) {
+ $fName = $arr[$size - 1];
+ if ($size == 1) {
+ print("Setting path to: .");
+ $path = ".";
+ } else {
+ $path = $arr[0];
+ }
+ for ($i = 1; $i < ($size - 1); $i++) {
+ $path = $path."/".$arr[$i];
+ }
+ $file = generateFileObj($fName, $path, $rootDir, $expand,$showHiddenFiles);
+ header("Content-Type", "text/json");
+ print("/* ".json_encode($file)." */");
+ } else {
+ header("HTTP/1.0 404 Not Found");
+ header("Status: 404 Not Found");
+ print("<b>Cannot access file: [".htmlentities($path)."]<b>");
+ }
+ } else {
+ header("HTTP/1.0 404 Not Found");
+ header("Status: 404 Not Found");
+ print("<b>Cannot access file: [".htmlentities($path)."]<b>");
+ }
+ } else {
+ header("HTTP/1.0 403 Forbidden");
+ header("Status: 403 Forbidden");
+ print("<b>Cannot access file: [".htmlentities($path)."]. It is outside of the root of the file service.<b>");
+ }
+ } else {
+ header("HTTP/1.0 404 Not Found");
+ header("Status: 404 Not Found");
+ print("<b>Cannot access file: [".htmlentities($path)."]<b>");
+ }
+ }
+?>
diff --git a/js/dojo-1.7.2/dojox/data/demos/stores/filestore_funcs.php b/js/dojo-1.7.2/dojox/data/demos/stores/filestore_funcs.php
new file mode 100644
index 0000000..ff61139
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/stores/filestore_funcs.php
@@ -0,0 +1,366 @@
+<?php
+ /**
+ * Helper function to convert a simple pattern to a regular expression for matching.
+ *
+ * Returns a regular expression object that conforms to the defined conversion rules.
+ * For example:
+ * ca* -> /^ca.*$/
+ * *ca* -> /^.*ca.*$/
+ * *c\*a* -> /^.*c\*a.*$/
+ * *c\*a?* -> /^.*c\*a..*$/
+ * and so on.
+ *
+ * @param pattern: string
+ * A simple matching pattern to convert that follows basic rules:
+ * * Means match anything, so ca* means match anything starting with ca
+ * ? Means match single character. So, b?b will match to bob and bab, and so on.
+ * \ is an escape character. So for example, \* means do not treat * as a match, but literal character *.
+ * To use a \ as a character in the string, it must be escaped. So in the pattern it should be
+ * represented by \\ to be treated as an ordinary \ character instead of an escape.
+ */
+ function patternToRegExp(/*String*/$pattern){
+ $rxp = "^";
+ $c = "";
+ $len = strlen($pattern);
+ for ($i = 0; $i < $len; $i++) {
+ $c = $pattern[$i];
+ switch ($c) {
+ case '\\':
+ $rxp = $rxp.$c;
+ $i++;
+ $rxp = $rxp.$pattern[$i];
+ break;
+ case '*':
+ $rxp = $rxp.".*"; break;
+ case '?':
+ $rxp = $rxp."."; break;
+ case '$':
+ case '^':
+ case '/':
+ case '+':
+ case '.':
+ case '|':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ $rxp = $rxp."\\"; //fallthrough
+ default:
+ $rxp = $rxp.$c;
+ }
+ }
+ return "(".$rxp."$)";
+ }
+
+ /**
+ * Function to load all file info from a particular directory.
+ *
+ * @param $dir The dir to seach from, relative to $rootDir.
+ * @param $rootDir The directory where the file service is rooted, used as separate var to allow easier checking and prevention of ../ing out of the tree.
+ * @param $recurse Whether or not to deep scan the dir and return all subfiles, or just return the toplevel files.
+ * @param $dirsOnly boolean to enote to only return directory names, not filenames.
+ * @param $expand boolean to indicate whether or not to inflate all children files along a path/file, or leave them as stubs.
+ * @param $showHiddenFiles boolean to indicate to return hidden files as part of the list.
+ */
+ function getAllfiles($dir, $rootDir, $recurse, $dirsOnly, $expand, $showHiddenFiles) {
+ // summary:
+ // A function to obtain all the files in a particular directory (file or dir)
+ $files = array();
+ $dirHandle = opendir($rootDir."/".$dir);
+ if ($dirHandle) {
+ while($file = readdir($dirHandle)) {
+ if ($file) {
+ if ($file != ".." && $file != ".") {
+ $path = $dir."/".$file;
+ $fileObj = generateFileObj($file, $dir, $rootDir,$expand,$showHiddenFiles);
+ if (is_dir($rootDir."/".$path)) {
+ if ($recurse) {
+ if ($showHiddenFiles || $fileObj["name"][0] != '.') {
+ $subfiles = getAllfiles($path,$rootDir,$recurse,$dirsOnly,$expand,$showHiddenFiles);
+ $length = count($subfiles);
+ for ($i = 0; $i < $length; $i++) {
+ $files[] = $subfiles[$i];
+ }
+ }
+ }
+ }
+ if (!$dirsOnly || $fileObj["directory"]) {
+ if ($showHiddenFiles || $fileObj["name"][0] !== '.') {
+ $files[] = $fileObj;
+ }
+ }
+ }
+ }
+ }
+ }
+ closedir($dirHandle);
+ return $files;
+ }
+
+ /**
+ * Function to generate an associative map of data about a specific file.
+ * @param $file The name of the file this object represents.
+ * @param $dir The sub-path that contains the file defined by $file
+ * @param $rootDir The directory from which to append dir and name to get the full path to the file.
+ * @param $expand boolean to denote that if the file is a directory, expand all children in the children attribute
+ * to a a full object
+ * @param $showHiddenFiles boolean to denote if hidden files should be shown in-view or not.
+ *
+ * @return Associative Map. The details about the file:
+ * $file["name"] - Returns the shortname of the file.
+ * $file["parentDir"] - Returns the relative path from the service root for the parent directory containing file $file["name"]
+ * $file["path"] - The relative path to the file.
+ * $file["directory"] - Boolean indicator if the file represents a directory.
+ * $file["size"] - The size of the file, in bytes.
+ * $file["modified] - The modified date of the file in milliseconds since Jan 1st, 1970.
+ * $file["children"] - Children files of a directory. Empty if a standard file.
+ */
+ function generateFileObj($file, $dir, $rootDir, $expand, $showHiddenFiles) {
+ // summary:
+ // Function to generate an object representation of a disk file.
+ $path = $file;
+ if ($dir != "." && $dir != "./") {
+ $path = $dir."/".$file;
+ }
+
+ $fullPath = $rootDir."/".$path;
+
+ $atts = stat($fullPath);
+
+ $rootPath = realPath($rootDir);
+ $resolvedDir = realPath($rootDir."/".$dir);
+ $resolvedFullPath = realPath($fullPath);
+
+ //Try to normalize down the paths so it does a consistent return.
+ if (strcmp($rootPath, $resolvedDir) === 0) {
+ $dir = ".";
+ } else {
+ $dir = substr($resolvedDir, (strlen($rootPath) + 1), strlen($resolvedDir));
+ $dir = "./".str_replace("\\","/",$dir);
+ }
+ if (strcmp($rootPath, $resolvedFullPath) === 0) {
+ $path = ".";
+ } else {
+ $path = substr($resolvedFullPath, (strlen($rootPath) + 1), strlen($resolvedFullPath));
+ $path = "./".str_replace("\\","/",$path);
+ }
+
+ $fObj = array();
+ $fObj["name"] = $file;
+ $fObj["parentDir"] = $dir;
+ $fObj["path"] = $path;
+ $fObj["directory"] = is_dir($fullPath);
+ $fObj["size"] = filesize($fullPath);
+ $fObj["modified"] = $atts[9];
+
+ if (is_dir($fullPath)) {
+ $children = array();
+ $dirHandle = opendir($fullPath);
+ while($cFile = readdir($dirHandle)) {
+ if ($cFile) {
+ if ($cFile != ".." && $cFile != ".") {
+ if ($showHiddenFiles || $cFile[0] != '.') {
+ if (!$expand) {
+ $children[] = $cFile;
+ }else{
+ $children[] = generateFileObj($cFile, $path, $rootDir, $expand, $showHiddenFiles);
+ }
+ }
+ }
+ }
+ }
+ closedir($dirHandle);
+ $fObj["children"] = $children;
+ }
+ return $fObj;
+ }
+
+ /**
+ * A field comparator class, whose role it is to define which fields on an associaive map to compare on
+ * and provide the comparison function to do so.
+ */
+ class FieldComparator {
+ var $field;
+ var $descending = false;
+
+ /**
+ * Constructor.
+ * @param $f The field of the item to compare.
+ * @param $d Parameter denoting whether it should be ascending or descending. Default is ascending.
+ */
+ function FieldComparator($f, $d) {
+ $this->field = $f;
+ $this->descending = $d;
+ }
+
+ /**
+ * Function to compare file objects A and B on the field defined by $this->field.
+ * @param $fileA The first file to compare.
+ * @param #fileB The second file to compare.
+ */
+ function compare($fileA,$fileB){
+ $f = $this->field;
+ $a = $fileA[$f];
+ $b = $fileB[$f];
+
+ $ret = 0;
+ if (is_string($a) && is_string($b)) {
+ $ret = strcmp($a,$b);
+ } else if($a > $b || $a === null){
+ $ret = 1;
+ }else if($a < $b || $b === null){
+ $ret = -1;
+ }
+
+ if (property_exists($this, "descending") && $this->descending == true) {
+ $ret = $ret * -1;
+ }
+
+ if ($ret > 0) {
+ $ret = 1;
+ } else if ($ret < 0) {
+ $ret = -1;
+ }
+ return $ret; //int, {-1,0,1}
+ }
+ }
+
+ /**
+ * A compound comparator class, whose role it is to sequentially call a set of comparators on two objects and
+ * return the combined result of the comparison.
+ */
+ class CompoundComparator {
+ //Comparator chain.
+ var $comparators = array();
+
+ /**
+ * Function to compare two objects $a and $b, using the chain of comparators.
+ * @param $a The first object to compare.
+ * @param $b The second object to compare.
+ * @returns -1, 0, 1. -1 if a < b, 1 if a > b, and 0 if a = b.
+ */
+ function compare($a, $b) {
+ $ret = 0;
+ $size = count($this->comparators);
+ for ($i = 0; $i < $size; $i++) {
+ $comp = $this->comparators[$i];
+ $ret = $comp->compare($a, $b);
+ if ($ret != 0) {
+ break;
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Function to add a comparator to the chain.
+ * @param $comp The comparator to add.
+ */
+ function addComparator($comp){
+ $this->comparators[] = $comp;
+ }
+ }
+
+ /**
+ * A function to create a Comparator class with chained comparators based off the sort specification passed into the store.
+ * @param $sortSpec The Sort specification, which is an array of sort objects containing ( attribute: "someStr": descending: true|fase}
+ * @returns The constructed comparator.
+ */
+ function createComparator($sortSpec) {
+ //Function to construct the class that handles chained comparisons.
+ $comparator = new CompoundComparator();
+ $size = count($sortSpec);
+ for ($i = 0; $i < $size; $i++) {
+ $sort = $sortSpec[$i];
+ $desc = false;
+ if(property_exists($sort, "descending")){
+ $desc = $sort->descending;
+ }
+ $fileComp = new FieldComparator($sort->attribute,$desc);
+ $comparator->addComparator($fileComp);
+ }
+ return $comparator;
+ }
+
+ /**
+ * Function to match a set of queries against a directory and possibly all subfiles.
+ * @param query The Query send in to process and test against.
+ * @param patterns The set of regexp patterns generated off the query.
+ * @param dir the directory to search in.
+ * @param recurse Whether or not to recurse into subdirs and test files there too.
+ *
+ * @return Array. Returns an array of all matches of the query.
+ */
+ function matchFiles($query, $patterns, $ignoreCase, $dir, $rootDir, $recurse, $dirsOnly, $expand, $showHiddenFiles) {
+ $files = array();
+ $fullDir = $rootDir."/".$dir;
+
+ if ($fullDir != null && is_dir($fullDir)) {
+
+ $dirHandle = opendir($fullDir);
+ while ($file = readdir($dirHandle)) {
+ if ($file != "." && $file != "..") {
+ $item = generateFileObj($file, $dir, $rootDir, $expand,$showHiddenFiles);
+ $keys = array_keys($patterns);
+ $total = count($keys);
+ for ($i = 0; $i < $total; $i++) {
+ $key = $keys[$i];
+ $pattern = $query[$key];
+ $matched = containsValue($item,$key,$query[$key],$patterns[$key], $ignoreCase);
+ if (!$matched) {
+ break;
+ }
+ }
+ if ($matched) {
+ if (!$dirsOnly || $item["directory"]) {
+ if ($showHiddenFiles || $item["name"][0] != '.') {
+ $files[] = $item;
+ }
+ }
+ }
+
+ if (is_dir($rootDir."/".$item["path"]) && $recurse) {
+ if ($showHiddenFiles || $item["name"][0] != '.') {
+ $files = array_merge($files, matchFiles($query, $patterns, $ignoreCase, $item["path"], $rootDir, $recurse, $dirsOnly, $expand, $showHiddenFiles));
+ }
+ }
+ }
+ }
+ closedir($dirHandle);
+ }
+ return $files;
+ }
+
+ /**
+ * Function to handle comparing the value of an attribute on a file item.
+ * @param item The item to examine.
+ * @param attr The attribute of the tem to examine.
+ * @parma value The value to compare it to.
+ * @param rExp A regular Expression pattern object generated off 'value' if any.
+ *
+ * @returns boolean denoting if the value was matched or not.
+ */
+ function containsValue($item, $attr, $value, $rExp, $ignoreCase) {
+ $matched = false;
+ $possibleValue = $item[$attr];
+ if ($possibleValue === null && $value === null) {
+ $matched = true;
+ } else {
+ if ($rExp != null && is_string($possibleValue)) {
+ if ($ignoreCase) {
+ $matched = eregi($rExp, $possibleValue);
+ } else {
+ $matched = ereg($rExp, $possibleValue);
+ }
+
+ } else {
+ if ($value != null && $possibleValue != null) {
+ $matched = ($value == $possibleValue);
+ }
+ }
+ }
+ return $matched;
+ }
+// No closing PHP tag on purpose. Do not want it to print whitepace and thus not allow setting headers later.
diff --git a/js/dojo-1.7.2/dojox/data/demos/widgets/FileView.js b/js/dojo-1.7.2/dojox/data/demos/widgets/FileView.js
new file mode 100644
index 0000000..5fa9e46
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/widgets/FileView.js
@@ -0,0 +1,45 @@
+//>>built
+// wrapped by build app
+define("dojox/data/demos/widgets/FileView", ["dijit","dojo","dojox","dojo/require!dijit/_Templated,dijit/_Widget"], function(dijit,dojo,dojox){
+dojo.provide("dojox.data.demos.widgets.FileView");
+dojo.require("dijit._Templated");
+dojo.require("dijit._Widget");
+
+dojo.declare("dojox.data.demos.widgets.FileView", [dijit._Widget, dijit._Templated], {
+ //Simple demo widget for representing a view of a Flickr Item.
+
+ templateString: dojo.cache("dojox", "data/demos/widgets/templates/FileView.html", "<div class=\"fileView\">\n\t<div class=\"fileViewTitle\">File Details:</div>\n\t<table class=\"fileViewTable\">\n\t\t<tbody>\n\t\t\t<tr class=\"fileName\">\n\t\t\t\t<td>\n\t\t\t\t\t<b>\n\t\t\t\t\t\tName:\n\t\t\t\t\t</b>\n\t\t\t\t</td>\n\t\t\t\t<td dojoAttachPoint=\"nameNode\">\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>\n\t\t\t\t\t<b>\n\t\t\t\t\t\tPath:\n\t\t\t\t\t</b>\n\t\t\t\t</td>\n\t\t\t\t<td dojoAttachPoint=\"pathNode\">\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>\n\t\t\t\t\t<b>\n\t\t\t\t\t\tSize:\n\t\t\t\t\t</b>\n\t\t\t\t</td>\n\t\t\t\t<td>\n\t\t\t\t\t<span dojoAttachPoint=\"sizeNode\"></span>&nbsp;bytes.\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>\n\t\t\t\t\t<b>\n\t\t\t\t\t\tIs Directory:\n\t\t\t\t\t</b>\n\t\t\t\t</td>\n\t\t\t\t<td dojoAttachPoint=\"directoryNode\">\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>\n\t\t\t\t\t<b>\n\t\t\t\t\t\tParent Directory:\n\t\t\t\t\t</b>\n\t\t\t\t</td>\n\t\t\t\t<td dojoAttachPoint=\"parentDirNode\">\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>\n\t\t\t\t\t<b>\n\t\t\t\t\t\tChildren:\n\t\t\t\t\t</b>\n\t\t\t\t</td>\n\t\t\t\t<td dojoAttachPoint=\"childrenNode\">\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t</tbody>\n\t</table>\n</div>\n"),
+
+ //Attach points for reference.
+ titleNode: null,
+ descriptionNode: null,
+ imageNode: null,
+ authorNode: null,
+
+ name: "",
+ path: "",
+ size: 0,
+ directory: false,
+ parentDir: "",
+ children: [],
+
+ postCreate: function(){
+ this.nameNode.appendChild(document.createTextNode(this.name));
+ this.pathNode.appendChild(document.createTextNode(this.path));
+ this.sizeNode.appendChild(document.createTextNode(this.size));
+ this.directoryNode.appendChild(document.createTextNode(this.directory));
+ this.parentDirNode.appendChild(document.createTextNode(this.parentDir));
+ if (this.children && this.children.length > 0) {
+ var i;
+ for (i = 0; i < this.children.length; i++) {
+ var tNode = document.createTextNode(this.children[i]);
+ this.childrenNode.appendChild(tNode);
+ if (i < (this.children.length - 1)) {
+ this.childrenNode.appendChild(document.createElement("br"));
+ }
+ }
+ }
+ }
+});
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/demos/widgets/FlickrViewList.js b/js/dojo-1.7.2/dojox/data/demos/widgets/FlickrViewList.js
new file mode 100644
index 0000000..294a7d6
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/widgets/FlickrViewList.js
@@ -0,0 +1,35 @@
+//>>built
+// wrapped by build app
+define("dojox/data/demos/widgets/FlickrViewList", ["dijit","dojo","dojox","dojo/require!dojox/dtl/_Templated,dijit/_Widget"], function(dijit,dojo,dojox){
+dojo.provide("dojox.data.demos.widgets.FlickrViewList");
+dojo.require("dojox.dtl._Templated");
+dojo.require("dijit._Widget");
+
+dojo.declare("dojox.data.demos.widgets.FlickrViewList",
+ [ dijit._Widget, dojox.dtl._Templated ],
+ {
+ store: null,
+ items: null,
+
+ templateString: dojo.cache("dojox", "data/demos/widgets/templates/FlickrViewList.html", "{% load dojox.dtl.contrib.data %}\n{% bind_data items to store as flickr %}\n<div dojoAttachPoint=\"list\">\n\t{% for item in flickr %}\n\t<div style=\"display: inline-block; align: top;\">\n\t\t<h5>{{ item.title }}</h5>\n\t\t<a href=\"{{ item.link }}\" style=\"border: none;\">\n\t\t\t<img src=\"{{ item.imageUrlMedium }}\">\n\t\t</a>\n\t\t<p>{{ item.author }}</p>\n\n\t\t<!--\n\t\t<img src=\"{{ item.imageUrl }}\">\n\t\t<p>{{ item.imageUrl }}</p>\n\t\t<img src=\"{{ item.imageUrlSmall }}\">\n\t\t-->\n\t</div>\n\t{% endfor %}\n</div>\n\n"),
+
+ fetch: function(request){
+ request.onComplete = dojo.hitch(this, "onComplete");
+ request.onError = dojo.hitch(this, "onError");
+ return this.store.fetch(request);
+ },
+
+ onError: function(){
+ console.trace();
+ this.items = [];
+ this.render();
+ },
+
+ onComplete: function(items, request){
+ this.items = items||[];
+ this.render();
+ }
+ }
+);
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/demos/widgets/PicasaView.js b/js/dojo-1.7.2/dojox/data/demos/widgets/PicasaView.js
new file mode 100644
index 0000000..79b54bf
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/widgets/PicasaView.js
@@ -0,0 +1,38 @@
+//>>built
+// wrapped by build app
+define("dojox/data/demos/widgets/PicasaView", ["dijit","dojo","dojox","dojo/require!dijit/_Templated,dijit/_Widget"], function(dijit,dojo,dojox){
+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: dojo.cache("dojox", "data/demos/widgets/templates/PicasaView.html", "<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/js/dojo-1.7.2/dojox/data/demos/widgets/PicasaViewList.js b/js/dojo-1.7.2/dojox/data/demos/widgets/PicasaViewList.js
new file mode 100644
index 0000000..36b26dd
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/widgets/PicasaViewList.js
@@ -0,0 +1,38 @@
+//>>built
+// wrapped by build app
+define("dojox/data/demos/widgets/PicasaViewList", ["dijit","dojo","dojox","dojo/require!dijit/_Templated,dijit/_Widget,dojox/data/demos/widgets/PicasaView"], function(dijit,dojo,dojox){
+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: dojo.cache("dojox", "data/demos/widgets/templates/PicasaViewList.html", "<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/js/dojo-1.7.2/dojox/data/demos/widgets/templates/FileView.html b/js/dojo-1.7.2/dojox/data/demos/widgets/templates/FileView.html
new file mode 100644
index 0000000..a83fd28
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/widgets/templates/FileView.html
@@ -0,0 +1,62 @@
+<div class="fileView">
+ <div class="fileViewTitle">File Details:</div>
+ <table class="fileViewTable">
+ <tbody>
+ <tr class="fileName">
+ <td>
+ <b>
+ Name:
+ </b>
+ </td>
+ <td dojoAttachPoint="nameNode">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>
+ Path:
+ </b>
+ </td>
+ <td dojoAttachPoint="pathNode">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>
+ Size:
+ </b>
+ </td>
+ <td>
+ <span dojoAttachPoint="sizeNode"></span>&nbsp;bytes.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>
+ Is Directory:
+ </b>
+ </td>
+ <td dojoAttachPoint="directoryNode">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>
+ Parent Directory:
+ </b>
+ </td>
+ <td dojoAttachPoint="parentDirNode">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <b>
+ Children:
+ </b>
+ </td>
+ <td dojoAttachPoint="childrenNode">
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</div>
diff --git a/js/dojo-1.7.2/dojox/data/demos/widgets/templates/FlickrViewList.html b/js/dojo-1.7.2/dojox/data/demos/widgets/templates/FlickrViewList.html
new file mode 100644
index 0000000..e9fe02f
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/widgets/templates/FlickrViewList.html
@@ -0,0 +1,20 @@
+{% load dojox.dtl.contrib.data %}
+{% bind_data items to store as flickr %}
+<div dojoAttachPoint="list">
+ {% for item in flickr %}
+ <div style="display: inline-block; align: top;">
+ <h5>{{ item.title }}</h5>
+ <a href="{{ item.link }}" style="border: none;">
+ <img src="{{ item.imageUrlMedium }}">
+ </a>
+ <p>{{ item.author }}</p>
+
+ <!--
+ <img src="{{ item.imageUrl }}">
+ <p>{{ item.imageUrl }}</p>
+ <img src="{{ item.imageUrlSmall }}">
+ -->
+ </div>
+ {% endfor %}
+</div>
+
diff --git a/js/dojo-1.7.2/dojox/data/demos/widgets/templates/PicasaView.html b/js/dojo-1.7.2/dojox/data/demos/widgets/templates/PicasaView.html
new file mode 100644
index 0000000..88dbb31
--- /dev/null
+++ b/js/dojo-1.7.2/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/js/dojo-1.7.2/dojox/data/demos/widgets/templates/PicasaViewList.html b/js/dojo-1.7.2/dojox/data/demos/widgets/templates/PicasaViewList.html
new file mode 100644
index 0000000..3a9f565
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/demos/widgets/templates/PicasaViewList.html
@@ -0,0 +1,2 @@
+<div dojoAttachPoint="list"></div>
+
diff --git a/js/dojo-1.7.2/dojox/data/dom.js b/js/dojo-1.7.2/dojox/data/dom.js
new file mode 100644
index 0000000..a9d7c08
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/dom.js
@@ -0,0 +1,102 @@
+//>>built
+define("dojox/data/dom", ["dojo/_base/kernel", "dojo/_base/lang", "dojox/xml/parser"],
+ function(kernel, lang, xmlParser) {
+
+//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;
+
+//This file contains internal/helper APIs as holders for people who used them. They have been migrated to
+//a better project, dojox.xml and experimental has been removed there. Please update usage to the new package.
+dojo.deprecated("dojox.data.dom", "Use dojox.xml.parser instead.", "2.0");
+
+var dataDom = lang.getObject("dojox.data.dom",true);
+
+dataDom.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.
+ // If str is empty string "", then a new empty document will be created.
+ // mimetype:
+ // Optional mimetype of the text. Typically, this is text/xml. Will be defaulted to text/xml if not provided.
+ dojo.deprecated("dojox.data.dom.createDocument()", "Use dojox.xml.parser.parse() instead.", "2.0");
+ try{
+ return xmlParser.parse(str,mimetype); //DOMDocument.
+ }catch(e){
+ /*Squeltch errors like the old parser did.*/
+ return null;
+ }
+};
+
+dataDom.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.
+ dojo.deprecated("dojox.data.dom.textContent()", "Use dojox.xml.parser.textContent() instead.", "2.0");
+ if(arguments.length> 1){
+ return xmlParser.textContent(node, text); //string
+ }else{
+ return xmlParser.textContent(node); //string
+ }
+};
+
+dataDom.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.
+ dojo.deprecated("dojox.data.dom.replaceChildren()", "Use dojox.xml.parser.replaceChildren() instead.", "2.0");
+ xmlParser.replaceChildren(node, newChildren);
+};
+
+dataDom.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.
+ dojo.deprecated("dojox.data.dom.removeChildren()", "Use dojox.xml.parser.removeChildren() instead.", "2.0");
+ return dojox.xml.parser.removeChildren(node); //int
+};
+
+dataDom.innerXML = function(/*Node*/node){
+ // summary:
+ // Implementation of MS's innerXML function.
+ // node:
+ // The node from which to generate the XML text representation.
+ dojo.deprecated("dojox.data.dom.innerXML()", "Use dojox.xml.parser.innerXML() instead.", "2.0");
+ return xmlParser.innerXML(node); //string||null
+};
+
+return dataDom;
+
+});
+
diff --git a/js/dojo-1.7.2/dojox/data/restListener.js b/js/dojo-1.7.2/dojox/data/restListener.js
new file mode 100644
index 0000000..4086c9f
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/restListener.js
@@ -0,0 +1,53 @@
+//>>built
+// wrapped by build app
+define("dojox/data/restListener", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){
+dojo.provide("dojox.data.restListener");
+
+dojox.data.restListener = function(message){
+ // summary:
+ // this function can be used to receive REST notifications, from Comet or from another frame
+ // description:
+ // Example:
+ // | dojo.connect(window,"onMessage",null,function(event) {
+ // | var data = dojo.fromJson(event.data);
+ // | dojox.restListener(data);
+ // | });
+ var channel = message.channel;
+ var jr = dojox.rpc.JsonRest;
+ var service = jr.getServiceAndId(channel).service;
+ var result = dojox.json.ref.resolveJson(message.result, {
+ defaultId: message.event == 'put' && channel,
+ index: dojox.rpc.Rest._index,
+ idPrefix: service.servicePath.replace(/[^\/]*$/,''),
+ idAttribute: jr.getIdAttribute(service),
+ schemas: jr.schemas,
+ loader: jr._loader,
+ assignAbsoluteIds: true
+ });
+ var target = dojox.rpc.Rest._index && dojox.rpc.Rest._index[channel];
+ var onEvent = 'on' + message.event.toLowerCase();
+ var store = service && service._store;
+ if(target){
+ if(target[onEvent]){
+ target[onEvent](result); // call the REST handler if available
+ return;
+ }
+ }
+ // this is how we respond to different events
+ if(store){
+ switch(onEvent){
+ case 'onpost':
+ store.onNew(result); // call onNew for the store;
+ break;
+ case 'ondelete':
+ store.onDelete(target);
+ break;
+ // put is handled by JsonReferencing
+ //TODO: we may want to bring the JsonReferencing capability into here...
+ // that is really tricky though because JsonReferencing handles sub object,
+ // it would be expensive to do full object graph searches from here
+ }
+ }
+};
+
+});
diff --git a/js/dojo-1.7.2/dojox/data/s3/README b/js/dojo-1.7.2/dojox/data/s3/README
new file mode 100644
index 0000000..cfa2347
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/s3/README
@@ -0,0 +1,41 @@
+Using Amazon S3 with Dojo has the following prerequisites:
+ * You must be signed up to use Amazon S3. You can sign up for Amazon S3 at http://aws.amazon.com/s3.
+ * Use the provided proxy (/dojox/rpc/s3/proxy.php) with PHP 5.
+ * proxy.php requires the following modules:
+ o Crypt_HMAC
+ o HTTP_Request
+
+
+To use S3 from Dojo, you need a proxy. You can use the provided proxy example file by renaming
+proxy.example-php to proxy.php and then you must enter your Amazon access key and secret access key
+into the proxy.php file on line 3 and 4:
+
+$accessKey = "access key";
+$secretAccessKey = "secret access key";
+
+You then use the Dojo RPC service with the "PROXIED-PATH" envelope:
+
+dojo.require("dojox.rpc.Service");
+dojo.require("dojox.rpc.ProxiedPath");
+var s3Buckets = new dojox.rpc.Service({
+ target:"http://s3.amazonaws.com/",
+ proxyUrl:"../s3/proxy.php", // the path to the proxy
+ transport:"REST",
+ envelope:"PROXIED-PATH",
+ contentType:"application/json",
+ services:{
+ myBucket:{
+ target:"myBucket",
+ parameters:[{type:"string"}]
+ }
+ }
+});
+
+
+To use the S3 as a Dojo data store you can use the S3JsonRestStore module. First setup an RPC service
+as shown above and then pass the RPC service to the S3JsonRestStore:
+
+dojo.require("dojox.data.S3JsonRestStore");
+s3Store = new dojox.data.S3JsonRestStore({service:s3Buckets.myBucket}); // and create a store for it
+
+You can then use the s3Store as a normal Read/Write Dojo Data store.
diff --git a/js/dojo-1.7.2/dojox/data/s3/proxy.example-php b/js/dojo-1.7.2/dojox/data/s3/proxy.example-php
new file mode 100644
index 0000000..e5b57e1
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/s3/proxy.example-php
@@ -0,0 +1,74 @@
+<?php
+// enter your Amazon S3 secret key and access key here:
+$accessKey = "access key";
+$secretAccessKey = "secret access key";
+
+
+
+$TARGET_WS = "http://s3.amazonaws.com";
+
+ob_start();
+
+require_once 'Crypt/HMAC.php';
+require_once 'HTTP/Request.php';
+
+$method = $_SERVER["REQUEST_METHOD"];
+if ($method == "PUT") {
+ $contentType = $_SERVER['CONTENT_TYPE'];
+}
+else {
+ $contentType ='';
+}
+$resource = str_replace($TARGET_WS, '', $_REQUEST['url']);
+$queryIndex = strpos($resource,'?'); // remove the query string
+if ($queryIndex) {
+ $resource = substr($resource,0,$queryIndex);
+}
+
+if (substr($resource,strlen($resource)-1,strlen($resource)) == '/') {
+ // remove the last slash
+ $resource = substr($resource,0,strlen($resource)-1);
+}
+$content = file_get_contents('php://input');
+
+$httpDate = gmdate("D, d M Y H:i:s T");
+$acl = "private";
+$stringToSign = "$method\n\n$contentType\n$httpDate\nx-amz-acl:$acl\n$resource";
+$hashObj =& new Crypt_HMAC($secretAccessKey, "sha1");
+$signature = hexTob64($hashObj->hash($stringToSign));
+
+$req =& new HTTP_Request($TARGET_WS . $resource);
+$req->setMethod($method);
+$req->addHeader("content-type", $contentType);
+$req->addHeader("Date", $httpDate);
+$req->addHeader("x-amz-acl", $acl);
+$req->addHeader("Authorization", "AWS " . $accessKey . ":" . $signature);
+if ($content != "") {
+ $req->setBody($content);
+}
+
+$req->sendRequest();
+
+$contentType = $req->getResponseHeader("content-type");
+header("content-type: $contentType");
+header('HTTP/1.1 ' . $req->getResponseCode() . ' Ok');
+
+ob_end_flush();
+
+$content = $req->getResponseBody();
+if ($content) {
+ print($content);
+}
+else {
+ print("\"success\"");
+}
+
+function hexTob64($str) {
+ $raw = '';
+ for ($i=0; $i < strlen($str); $i+=2) {
+ $raw .= chr(hexdec(substr($str, $i, 2)));
+ }
+ return base64_encode($raw);
+}
+
+?> \ No newline at end of file
diff --git a/js/dojo-1.7.2/dojox/data/util/JsonQuery.js b/js/dojo-1.7.2/dojox/data/util/JsonQuery.js
new file mode 100644
index 0000000..bd90f35
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/data/util/JsonQuery.js
@@ -0,0 +1,99 @@
+//>>built
+define("dojox/data/util/JsonQuery", ["dojo", "dojox"], function(dojo, dojox) {
+
+// this is a mixin to convert object attribute queries to
+// JSONQuery/JSONPath syntax to be sent to the server.
+dojo.declare("dojox.data.util.JsonQuery", null, {
+ useFullIdInQueries: false,
+ _toJsonQuery: function(args, jsonQueryPagination){
+ var first = true;
+ var self = this;
+ function buildQuery(path, query){
+ var isDataItem = query.__id;
+ if(isDataItem){
+ // it is a reference to a persisted object, need to make it a query by id
+ var newQuery = {};
+ newQuery[self.idAttribute] = self.useFullIdInQueries ? query.__id : query[self.idAttribute];
+ query = newQuery;
+ }
+ for(var i in query){
+ // iterate through each property, adding them to the overall query
+ var value = query[i];
+ var newPath = path + (/^[a-zA-Z_][\w_]*$/.test(i) ? '.' + i : '[' + dojo._escapeString(i) + ']');
+ if(value && typeof value == "object"){
+ buildQuery(newPath, value);
+ }else if(value!="*"){ // full wildcards can be ommitted
+ jsonQuery += (first ? "" : "&") + newPath +
+ ((!isDataItem && typeof value == "string" && args.queryOptions && args.queryOptions.ignoreCase) ? "~" : "=") +
+ (self.simplifiedQuery ? encodeURIComponent(value) : dojo.toJson(value));
+ first = false;
+ }
+ }
+ }
+ // performs conversion of Dojo Data query objects and sort arrays to JSONQuery strings
+ if(args.query && typeof args.query == "object"){
+ // convert Dojo Data query objects to JSONQuery
+ var jsonQuery = "[?(";
+ buildQuery("@", args.query);
+ if(!first){
+ // use ' instead of " for quoting in JSONQuery, and end with ]
+ jsonQuery += ")]";
+ }else{
+ jsonQuery = "";
+ }
+ args.queryStr = jsonQuery.replace(/\\"|"/g,function(t){return t == '"' ? "'" : t;});
+ }else if(!args.query || args.query == '*'){
+ args.query = "";
+ }
+
+ var sort = args.sort;
+ if(sort){
+ // if we have a sort order, add that to the JSONQuery expression
+ args.queryStr = args.queryStr || (typeof args.query == 'string' ? args.query : "");
+ first = true;
+ for(i = 0; i < sort.length; i++){
+ args.queryStr += (first ? '[' : ',') + (sort[i].descending ? '\\' : '/') + "@[" + dojo._escapeString(sort[i].attribute) + "]";
+ first = false;
+ }
+ args.queryStr += ']';
+ }
+ // this is optional because with client side paging JSONQuery doesn't yield the total count
+ if(jsonQueryPagination && (args.start || args.count)){
+ // pagination
+ args.queryStr = (args.queryStr || (typeof args.query == 'string' ? args.query : "")) +
+ '[' + (args.start || '') + ':' + (args.count ? (args.start || 0) + args.count : '') + ']';
+ }
+ if(typeof args.queryStr == 'string'){
+ args.queryStr = args.queryStr.replace(/\\"|"/g,function(t){return t == '"' ? "'" : t;});
+ return args.queryStr;
+ }
+ return args.query;
+ },
+ jsonQueryPagination: true,
+ fetch: function(args){
+ this._toJsonQuery(args, this.jsonQueryPagination);
+ return this.inherited(arguments);
+ },
+ isUpdateable: function(){
+ return true;
+ },
+ matchesQuery: function(item,request){
+ request._jsonQuery = request._jsonQuery || dojox.json.query(this._toJsonQuery(request));
+ return request._jsonQuery([item]).length;
+ },
+ clientSideFetch: function(/*Object*/ request,/*Array*/ baseResults){
+ request._jsonQuery = request._jsonQuery || dojox.json.query(this._toJsonQuery(request));
+ // we use client side paging function here instead of JSON Query because we must also determine the total count
+ return this.clientSidePaging(request, request._jsonQuery(baseResults));
+ },
+ querySuperSet: function(argsSuper,argsSub){
+ if(!argsSuper.query){
+ return argsSub.query;
+ }
+ return this.inherited(arguments);
+ }
+
+});
+
+return dojox.data.util.JsonQuery;
+});