a:76:{s:9:"#provides";s:24:"dojox.data.jsonPathStore";s:9:"#resource";s:21:"data/jsonPathStore.js";s:9:"#requires";a:4:{i:0;a:2:{i:0;s:6:"common";i:1;s:14:"dojox.jsonPath";}i:1;a:3:{i:0;s:6:"common";i:1;s:9:"dojo.date";i:2;s:4:"dojo";}i:2;a:3:{i:0;s:6:"common";i:1;s:16:"dojo.date.locale";i:2;s:4:"dojo";}i:3;a:3:{i:0;s:6:"common";i:1;s:15:"dojo.date.stamp";i:2;s:4:"dojo";}}s:24:"dojox.data.jsonPathStore";a:6:{s:4:"type";s:8:"Function";s:6:"chains";a:2:{s:9:"prototype";a:1:{i:0;s:343:"// The jsonPathStore implements dojo.data.read, write, notify, and identity api's. It is a local (in memory) store // and can take a javascript object with any arbitrary format and attach to it to provide a dojo.data interface to that object // data. It uses jsonPath as the query language to search agains this store. null";}s:4:"call";a:1:{i:0;s:343:"// The jsonPathStore implements dojo.data.read, write, notify, and identity api's. It is a local (in memory) store // and can take a javascript object with any arbitrary format and attach to it to provide a dojo.data interface to that object // data. It uses jsonPath as the query language to search agains this store. null";}}s:10:"parameters";a:1:{s:7:"options";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:5271:"dojo.provide("dojox.data.jsonPathStore"); dojo.require("dojox.jsonPath"); dojo.require("dojo.date"); dojo.require("dojo.date.locale"); dojo.require("dojo.date.stamp"); dojox.data.ASYNC_MODE = 0; dojox.data.SYNC_MODE = 1; dojo.declare("dojox.data.jsonPathStore", // summary: // The jsonPathStore implements dojo.data.read, write, notify, and identity api's. It is a local (in memory) store // and can take a javascript object with any arbitrary format and attach to it to provide a dojo.data interface to that object // data. It uses jsonPath as the query language to search agains this store. null, { mode: dojox.data.ASYNC_MODE, metaLabel: "_meta", hideMetaAttributes: false, autoIdPrefix: "_auto_", autoIdentity: true, idAttribute: "_id", indexOnLoad: true, labelAttribute: "", url: "", _replaceRegex: /\'\]/gi, noRevert : false, constructor: function(options){ //summary: // jsonPathStore constructor, instantiate a new jsonPathStore // // Takes a single optional parameter in the form of a Javascript object // containing one or more of the following properties. // // data: /*JSON String*/ || /* Javascript Object */, // JSON String or Javascript object this store will control // JSON is converted into an object, and an object passed to // the store will be used directly. If no data and no url // is provide, an empty object, {}, will be used as the initial // store. // // url: /* string url */ // Load data from this url in JSON format and use the Object // created from the data as the data source. // // indexOnLoad: /* boolean */ // Defaults to true, but this may change in the near future. // Parse the data object and set individual objects up as // appropriate. This will add meta data and assign // id's to objects that dont' have them as defined by the // idAttribute option. Disabling this option will keep this // parsing from happening until a query is performed at which // time only the top level of an item has meta info stored. // This might work in some situations, but you will almost // always want to indexOnLoad or use another option which // will create an index. In the future we will support a // generated index that maps by jsonPath allowing the // server to take some of this load for larger data sets. // // idAttribute: /* string */ // Defaults to '_id'. The name of the attribute that holds an objects id. // This can be a preexisting id provided by the server. // If an ID isn't already provided when an object // is fetched or added to the store, the autoIdentity system // will generate an id for it and add it to the index. There // are utility routines for exporting data from the store // that can clean any generated IDs before exporting and leave // preexisting id's in tact. // // metaLabel: /* string */ // Defaults to '_meta' overrides the attribute name that is used by the store // for attaching meta information to an object while // in the store's control. Defaults to '_meta'. // // hideMetaAttributes: /* boolean */ // Defaults to False. When enabled, calls to getAttributes() will not // include the meta attribute. // // autoIdPrefix: /*string*/ // Defaults to "_auto_". This string is used as the prefix to any // objects which have a generated id. A numeric index is appended // to this string to complete the ID // // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE // Defaults to ASYNC_MODE. This option sets the default mode for this store. // Sync calls return their data immediately from the calling function // instead of calling the callback functions. Functions such as // fetchItemByIdentity() and fetch() both accept a string parameter in addtion // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will // automatically be used even when the default mode of the system is ASYNC_MODE. // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also // include a mode property to override this setting for that one request. //setup a byId alias to the api call this.byId=this.fetchItemByIdentity; if (options){ dojo.mixin(this,options); } this._dirtyItems=[]; this._autoId=0; this._referenceId=0; this._references={}; this._fetchQueue=[]; this.index={}; //regex to identify when we're travelling down metaObject (which we don't want to do) var expr="("+this.metaLabel+"\'\])"; this.metaRegex = new RegExp(expr); //no data or url, start with an empty object for a store if (!this.data && !this.url){ this.setData({}); } //we have data, but no url, set the store as the data if (this.data && !this.url){ this.setData(this.data); //remove the original refernce, we're now using _data from here on out delete this.data; } //given a url, load json data from as the store if (this.url){ dojo.xhrGet({ url: options.url, handleAs: "json", load: dojo.hitch(this, "setData"), sync: this.mode }); }";s:7:"summary";s:0:"";s:9:"classlike";b:1;}s:29:"dojox.data.jsonPathStore.mode";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:34:"dojox.data.jsonPathStore.metaLabel";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:43:"dojox.data.jsonPathStore.hideMetaAttributes";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:37:"dojox.data.jsonPathStore.autoIdPrefix";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:37:"dojox.data.jsonPathStore.autoIdentity";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:36:"dojox.data.jsonPathStore.idAttribute";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:36:"dojox.data.jsonPathStore.indexOnLoad";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:39:"dojox.data.jsonPathStore.labelAttribute";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:28:"dojox.data.jsonPathStore.url";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:38:"dojox.data.jsonPathStore._replaceRegex";a:3:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"private";b:1;s:7:"summary";s:0:"";}s:33:"dojox.data.jsonPathStore.noRevert";a:2:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:7:"summary";s:0:"";}s:34:"dojox.data.jsonPathStore._loadData";a:6:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"data";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:298:" if (this._data){ delete this._data; } if (dojo.isString(data)){ this._data = dojo.fromJson(data); }else{ this._data = data; } if (this.indexOnLoad){ this.buildIndex(); } this._updateMeta(this._data, {path: "$"}); this.onLoadData(this._data);";s:7:"summary";s:50:"load data into the store. Index it if appropriate.";s:7:"private";b:1;}s:35:"dojox.data.jsonPathStore.onLoadData";a:5:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"data";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:5983:"dojo.provide("dojox.data.jsonPathStore"); dojo.require("dojox.jsonPath"); dojo.require("dojo.date"); dojo.require("dojo.date.locale"); dojo.require("dojo.date.stamp"); dojox.data.ASYNC_MODE = 0; dojox.data.SYNC_MODE = 1; dojo.declare("dojox.data.jsonPathStore", // summary: // The jsonPathStore implements dojo.data.read, write, notify, and identity api's. It is a local (in memory) store // and can take a javascript object with any arbitrary format and attach to it to provide a dojo.data interface to that object // data. It uses jsonPath as the query language to search agains this store. null, { mode: dojox.data.ASYNC_MODE, metaLabel: "_meta", hideMetaAttributes: false, autoIdPrefix: "_auto_", autoIdentity: true, idAttribute: "_id", indexOnLoad: true, labelAttribute: "", url: "", _replaceRegex: /\'\]/gi, noRevert : false, constructor: function(options){ //summary: // jsonPathStore constructor, instantiate a new jsonPathStore // // Takes a single optional parameter in the form of a Javascript object // containing one or more of the following properties. // // data: /*JSON String*/ || /* Javascript Object */, // JSON String or Javascript object this store will control // JSON is converted into an object, and an object passed to // the store will be used directly. If no data and no url // is provide, an empty object, {}, will be used as the initial // store. // // url: /* string url */ // Load data from this url in JSON format and use the Object // created from the data as the data source. // // indexOnLoad: /* boolean */ // Defaults to true, but this may change in the near future. // Parse the data object and set individual objects up as // appropriate. This will add meta data and assign // id's to objects that dont' have them as defined by the // idAttribute option. Disabling this option will keep this // parsing from happening until a query is performed at which // time only the top level of an item has meta info stored. // This might work in some situations, but you will almost // always want to indexOnLoad or use another option which // will create an index. In the future we will support a // generated index that maps by jsonPath allowing the // server to take some of this load for larger data sets. // // idAttribute: /* string */ // Defaults to '_id'. The name of the attribute that holds an objects id. // This can be a preexisting id provided by the server. // If an ID isn't already provided when an object // is fetched or added to the store, the autoIdentity system // will generate an id for it and add it to the index. There // are utility routines for exporting data from the store // that can clean any generated IDs before exporting and leave // preexisting id's in tact. // // metaLabel: /* string */ // Defaults to '_meta' overrides the attribute name that is used by the store // for attaching meta information to an object while // in the store's control. Defaults to '_meta'. // // hideMetaAttributes: /* boolean */ // Defaults to False. When enabled, calls to getAttributes() will not // include the meta attribute. // // autoIdPrefix: /*string*/ // Defaults to "_auto_". This string is used as the prefix to any // objects which have a generated id. A numeric index is appended // to this string to complete the ID // // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE // Defaults to ASYNC_MODE. This option sets the default mode for this store. // Sync calls return their data immediately from the calling function // instead of calling the callback functions. Functions such as // fetchItemByIdentity() and fetch() both accept a string parameter in addtion // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will // automatically be used even when the default mode of the system is ASYNC_MODE. // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also // include a mode property to override this setting for that one request. //setup a byId alias to the api call this.byId=this.fetchItemByIdentity; if (options){ dojo.mixin(this,options); } this._dirtyItems=[]; this._autoId=0; this._referenceId=0; this._references={}; this._fetchQueue=[]; this.index={}; //regex to identify when we're travelling down metaObject (which we don't want to do) var expr="("+this.metaLabel+"\'\])"; this.metaRegex = new RegExp(expr); //no data or url, start with an empty object for a store if (!this.data && !this.url){ this.setData({}); } //we have data, but no url, set the store as the data if (this.data && !this.url){ this.setData(this.data); //remove the original refernce, we're now using _data from here on out delete this.data; } //given a url, load json data from as the store if (this.url){ dojo.xhrGet({ url: options.url, handleAs: "json", load: dojo.hitch(this, "setData"), sync: this.mode }); } }, _loadData: function(data){ // summary: // load data into the store. Index it if appropriate. if (this._data){ delete this._data; } if (dojo.isString(data)){ this._data = dojo.fromJson(data); }else{ this._data = data; } if (this.indexOnLoad){ this.buildIndex(); } this._updateMeta(this._data, {path: "$"}); this.onLoadData(this._data); }, onLoadData: function(data){ // summary // Called after data has been loaded in the store. // If any requests happened while the startup is happening // then process them now. while (this._fetchQueue.length>0){ var req = this._fetchQueue.shift(); this.fetch(req); } ";s:7:"summary";s:0:"";}s:32:"dojox.data.jsonPathStore.setData";a:5:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"data";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:24:" this._loadData(data);";s:7:"summary";s:108:"set the stores' data to the supplied object and then load and/or setup that data with the required meta info";}s:35:"dojox.data.jsonPathStore.buildIndex";a:5:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"path";a:2:{s:4:"type";s:6:"string";s:7:"summary";s:68:"*/ jsonPath Query for the starting point of this index construction.";}s:4:"item";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:1276:" if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString();";s:7:"summary";s:0:"";}s:43:"dojox.data.jsonPathStore.getLabelAttributes";a:5:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"item";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:130:" item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute];";s:7:"summary";s:75:"returns an array of attributes that are used to create the label of an item";}s:29:"dojox.data.jsonPathStore.sort";a:5:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:1:"a";a:1:{s:4:"type";s:0:"";}s:1:"b";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:52:" console.log("TODO::implement default sort algo");";s:7:"summary";s:0:"";}s:36:"dojox.data.jsonPathStore.getIdentity";a:5:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"item";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:21276:"dojo.provide("dojox.data.jsonPathStore"); dojo.require("dojox.jsonPath"); dojo.require("dojo.date"); dojo.require("dojo.date.locale"); dojo.require("dojo.date.stamp"); dojox.data.ASYNC_MODE = 0; dojox.data.SYNC_MODE = 1; dojo.declare("dojox.data.jsonPathStore", // summary: // The jsonPathStore implements dojo.data.read, write, notify, and identity api's. It is a local (in memory) store // and can take a javascript object with any arbitrary format and attach to it to provide a dojo.data interface to that object // data. It uses jsonPath as the query language to search agains this store. null, { mode: dojox.data.ASYNC_MODE, metaLabel: "_meta", hideMetaAttributes: false, autoIdPrefix: "_auto_", autoIdentity: true, idAttribute: "_id", indexOnLoad: true, labelAttribute: "", url: "", _replaceRegex: /\'\]/gi, noRevert : false, constructor: function(options){ //summary: // jsonPathStore constructor, instantiate a new jsonPathStore // // Takes a single optional parameter in the form of a Javascript object // containing one or more of the following properties. // // data: /*JSON String*/ || /* Javascript Object */, // JSON String or Javascript object this store will control // JSON is converted into an object, and an object passed to // the store will be used directly. If no data and no url // is provide, an empty object, {}, will be used as the initial // store. // // url: /* string url */ // Load data from this url in JSON format and use the Object // created from the data as the data source. // // indexOnLoad: /* boolean */ // Defaults to true, but this may change in the near future. // Parse the data object and set individual objects up as // appropriate. This will add meta data and assign // id's to objects that dont' have them as defined by the // idAttribute option. Disabling this option will keep this // parsing from happening until a query is performed at which // time only the top level of an item has meta info stored. // This might work in some situations, but you will almost // always want to indexOnLoad or use another option which // will create an index. In the future we will support a // generated index that maps by jsonPath allowing the // server to take some of this load for larger data sets. // // idAttribute: /* string */ // Defaults to '_id'. The name of the attribute that holds an objects id. // This can be a preexisting id provided by the server. // If an ID isn't already provided when an object // is fetched or added to the store, the autoIdentity system // will generate an id for it and add it to the index. There // are utility routines for exporting data from the store // that can clean any generated IDs before exporting and leave // preexisting id's in tact. // // metaLabel: /* string */ // Defaults to '_meta' overrides the attribute name that is used by the store // for attaching meta information to an object while // in the store's control. Defaults to '_meta'. // // hideMetaAttributes: /* boolean */ // Defaults to False. When enabled, calls to getAttributes() will not // include the meta attribute. // // autoIdPrefix: /*string*/ // Defaults to "_auto_". This string is used as the prefix to any // objects which have a generated id. A numeric index is appended // to this string to complete the ID // // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE // Defaults to ASYNC_MODE. This option sets the default mode for this store. // Sync calls return their data immediately from the calling function // instead of calling the callback functions. Functions such as // fetchItemByIdentity() and fetch() both accept a string parameter in addtion // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will // automatically be used even when the default mode of the system is ASYNC_MODE. // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also // include a mode property to override this setting for that one request. //setup a byId alias to the api call this.byId=this.fetchItemByIdentity; if (options){ dojo.mixin(this,options); } this._dirtyItems=[]; this._autoId=0; this._referenceId=0; this._references={}; this._fetchQueue=[]; this.index={}; //regex to identify when we're travelling down metaObject (which we don't want to do) var expr="("+this.metaLabel+"\'\])"; this.metaRegex = new RegExp(expr); //no data or url, start with an empty object for a store if (!this.data && !this.url){ this.setData({}); } //we have data, but no url, set the store as the data if (this.data && !this.url){ this.setData(this.data); //remove the original refernce, we're now using _data from here on out delete this.data; } //given a url, load json data from as the store if (this.url){ dojo.xhrGet({ url: options.url, handleAs: "json", load: dojo.hitch(this, "setData"), sync: this.mode }); } }, _loadData: function(data){ // summary: // load data into the store. Index it if appropriate. if (this._data){ delete this._data; } if (dojo.isString(data)){ this._data = dojo.fromJson(data); }else{ this._data = data; } if (this.indexOnLoad){ this.buildIndex(); } this._updateMeta(this._data, {path: "$"}); this.onLoadData(this._data); }, onLoadData: function(data){ // summary // Called after data has been loaded in the store. // If any requests happened while the startup is happening // then process them now. while (this._fetchQueue.length>0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item");";s:7:"summary";s:0:"";}s:46:"dojox.data.jsonPathStore.getIdentityAttributes";a:5:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"item";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:29:" return [this.idAttribute];";s:7:"summary";s:109:"returns the attributes which are used to make up the identity of an item. Basically returns this.idAttribute";}s:44:"dojox.data.jsonPathStore.fetchItemByIdentity";a:5:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"args";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:720:" var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args;";s:7:"summary";s:578:"fetch an item by its identity. This store also provides a much more finger friendly alias, 'byId' which does the same thing as this function. If provided a string this call will be treated as a SYNC request and will return the identified item immediatly. Alternatively it takes a object as a set of keywordArgs: identity: /* string */ the id of the item you want to retrieve mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE overrides the default store fetch mode onItem: /* function */ Result call back. Passed the fetched item. onError: /* function */ error callback.";}s:38:"dojox.data.jsonPathStore._makeItAnItem";a:6:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"data";a:1:{s:4:"type";s:0:"";}s:5:"pInfo";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:24467:"dojo.provide("dojox.data.jsonPathStore"); dojo.require("dojox.jsonPath"); dojo.require("dojo.date"); dojo.require("dojo.date.locale"); dojo.require("dojo.date.stamp"); dojox.data.ASYNC_MODE = 0; dojox.data.SYNC_MODE = 1; dojo.declare("dojox.data.jsonPathStore", // summary: // The jsonPathStore implements dojo.data.read, write, notify, and identity api's. It is a local (in memory) store // and can take a javascript object with any arbitrary format and attach to it to provide a dojo.data interface to that object // data. It uses jsonPath as the query language to search agains this store. null, { mode: dojox.data.ASYNC_MODE, metaLabel: "_meta", hideMetaAttributes: false, autoIdPrefix: "_auto_", autoIdentity: true, idAttribute: "_id", indexOnLoad: true, labelAttribute: "", url: "", _replaceRegex: /\'\]/gi, noRevert : false, constructor: function(options){ //summary: // jsonPathStore constructor, instantiate a new jsonPathStore // // Takes a single optional parameter in the form of a Javascript object // containing one or more of the following properties. // // data: /*JSON String*/ || /* Javascript Object */, // JSON String or Javascript object this store will control // JSON is converted into an object, and an object passed to // the store will be used directly. If no data and no url // is provide, an empty object, {}, will be used as the initial // store. // // url: /* string url */ // Load data from this url in JSON format and use the Object // created from the data as the data source. // // indexOnLoad: /* boolean */ // Defaults to true, but this may change in the near future. // Parse the data object and set individual objects up as // appropriate. This will add meta data and assign // id's to objects that dont' have them as defined by the // idAttribute option. Disabling this option will keep this // parsing from happening until a query is performed at which // time only the top level of an item has meta info stored. // This might work in some situations, but you will almost // always want to indexOnLoad or use another option which // will create an index. In the future we will support a // generated index that maps by jsonPath allowing the // server to take some of this load for larger data sets. // // idAttribute: /* string */ // Defaults to '_id'. The name of the attribute that holds an objects id. // This can be a preexisting id provided by the server. // If an ID isn't already provided when an object // is fetched or added to the store, the autoIdentity system // will generate an id for it and add it to the index. There // are utility routines for exporting data from the store // that can clean any generated IDs before exporting and leave // preexisting id's in tact. // // metaLabel: /* string */ // Defaults to '_meta' overrides the attribute name that is used by the store // for attaching meta information to an object while // in the store's control. Defaults to '_meta'. // // hideMetaAttributes: /* boolean */ // Defaults to False. When enabled, calls to getAttributes() will not // include the meta attribute. // // autoIdPrefix: /*string*/ // Defaults to "_auto_". This string is used as the prefix to any // objects which have a generated id. A numeric index is appended // to this string to complete the ID // // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE // Defaults to ASYNC_MODE. This option sets the default mode for this store. // Sync calls return their data immediately from the calling function // instead of calling the callback functions. Functions such as // fetchItemByIdentity() and fetch() both accept a string parameter in addtion // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will // automatically be used even when the default mode of the system is ASYNC_MODE. // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also // include a mode property to override this setting for that one request. //setup a byId alias to the api call this.byId=this.fetchItemByIdentity; if (options){ dojo.mixin(this,options); } this._dirtyItems=[]; this._autoId=0; this._referenceId=0; this._references={}; this._fetchQueue=[]; this.index={}; //regex to identify when we're travelling down metaObject (which we don't want to do) var expr="("+this.metaLabel+"\'\])"; this.metaRegex = new RegExp(expr); //no data or url, start with an empty object for a store if (!this.data && !this.url){ this.setData({}); } //we have data, but no url, set the store as the data if (this.data && !this.url){ this.setData(this.data); //remove the original refernce, we're now using _data from here on out delete this.data; } //given a url, load json data from as the store if (this.url){ dojo.xhrGet({ url: options.url, handleAs: "json", load: dojo.hitch(this, "setData"), sync: this.mode }); } }, _loadData: function(data){ // summary: // load data into the store. Index it if appropriate. if (this._data){ delete this._data; } if (dojo.isString(data)){ this._data = dojo.fromJson(data); }else{ this._data = data; } if (this.indexOnLoad){ this.buildIndex(); } this._updateMeta(this._data, {path: "$"}); this.onLoadData(this._data); }, onLoadData: function(data){ // summary // Called after data has been loaded in the store. // If any requests happened while the startup is happening // then process them now. while (this._fetchQueue.length>0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ console.log("refs map: " , this._references); console.log("item to delete: ", item); var rid = item[this.metaLabel]["referenceIds"].pop(); var pInfo = this._references[rid]; console.log("deleteItem(): ", pInfo, pInfo.parent); var parentItem = pInfo.parent; var attribute = pInfo.attribute; if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ this._setDirty(parentItem); this.unsetAttribute(parentItem, attribute); delete parentItem[attribute]; } if (dojo.isArray(parentItem[attribute])){ console.log("Parent is array"); var oldValue = this._trimItem(parentItem[attribute]); var found=false; for (var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ console.log("refs map: " , this._references); console.log("item to delete: ", item); var rid = item[this.metaLabel]["referenceIds"].pop(); var pInfo = this._references[rid]; console.log("deleteItem(): ", pInfo, pInfo.parent); var parentItem = pInfo.parent; var attribute = pInfo.attribute; if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ this._setDirty(parentItem); this.unsetAttribute(parentItem, attribute); delete parentItem[attribute]; } if (dojo.isArray(parentItem[attribute])){ console.log("Parent is array"); var oldValue = this._trimItem(parentItem[attribute]); var found=false; for (var i=0; i 0){ var item = this._dirtyItems.pop()["item"]; var t = this._trimItem(item); var d; switch(kwArgs.format){ case "json": d = dojo.toJson(t); break; case "raw": default: d = t; } data.push(d); this._markClean(item); } this.onSave(data);";s:7:"summary";s:469:"Takes an optional set of keyword Args with some save options. Currently only format with options being "raw" or "json". This function goes through the dirty item lists, clones and trims the item down so that the items children are not part of the data (the children are replaced with reference objects). This data is compiled into a single array, the dirty objects are all marked as clean, and the new data is then passed on to the onSave handler.";}s:35:"dojox.data.jsonPathStore._markClean";a:6:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"item";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:31471:"dojo.provide("dojox.data.jsonPathStore"); dojo.require("dojox.jsonPath"); dojo.require("dojo.date"); dojo.require("dojo.date.locale"); dojo.require("dojo.date.stamp"); dojox.data.ASYNC_MODE = 0; dojox.data.SYNC_MODE = 1; dojo.declare("dojox.data.jsonPathStore", // summary: // The jsonPathStore implements dojo.data.read, write, notify, and identity api's. It is a local (in memory) store // and can take a javascript object with any arbitrary format and attach to it to provide a dojo.data interface to that object // data. It uses jsonPath as the query language to search agains this store. null, { mode: dojox.data.ASYNC_MODE, metaLabel: "_meta", hideMetaAttributes: false, autoIdPrefix: "_auto_", autoIdentity: true, idAttribute: "_id", indexOnLoad: true, labelAttribute: "", url: "", _replaceRegex: /\'\]/gi, noRevert : false, constructor: function(options){ //summary: // jsonPathStore constructor, instantiate a new jsonPathStore // // Takes a single optional parameter in the form of a Javascript object // containing one or more of the following properties. // // data: /*JSON String*/ || /* Javascript Object */, // JSON String or Javascript object this store will control // JSON is converted into an object, and an object passed to // the store will be used directly. If no data and no url // is provide, an empty object, {}, will be used as the initial // store. // // url: /* string url */ // Load data from this url in JSON format and use the Object // created from the data as the data source. // // indexOnLoad: /* boolean */ // Defaults to true, but this may change in the near future. // Parse the data object and set individual objects up as // appropriate. This will add meta data and assign // id's to objects that dont' have them as defined by the // idAttribute option. Disabling this option will keep this // parsing from happening until a query is performed at which // time only the top level of an item has meta info stored. // This might work in some situations, but you will almost // always want to indexOnLoad or use another option which // will create an index. In the future we will support a // generated index that maps by jsonPath allowing the // server to take some of this load for larger data sets. // // idAttribute: /* string */ // Defaults to '_id'. The name of the attribute that holds an objects id. // This can be a preexisting id provided by the server. // If an ID isn't already provided when an object // is fetched or added to the store, the autoIdentity system // will generate an id for it and add it to the index. There // are utility routines for exporting data from the store // that can clean any generated IDs before exporting and leave // preexisting id's in tact. // // metaLabel: /* string */ // Defaults to '_meta' overrides the attribute name that is used by the store // for attaching meta information to an object while // in the store's control. Defaults to '_meta'. // // hideMetaAttributes: /* boolean */ // Defaults to False. When enabled, calls to getAttributes() will not // include the meta attribute. // // autoIdPrefix: /*string*/ // Defaults to "_auto_". This string is used as the prefix to any // objects which have a generated id. A numeric index is appended // to this string to complete the ID // // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE // Defaults to ASYNC_MODE. This option sets the default mode for this store. // Sync calls return their data immediately from the calling function // instead of calling the callback functions. Functions such as // fetchItemByIdentity() and fetch() both accept a string parameter in addtion // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will // automatically be used even when the default mode of the system is ASYNC_MODE. // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also // include a mode property to override this setting for that one request. //setup a byId alias to the api call this.byId=this.fetchItemByIdentity; if (options){ dojo.mixin(this,options); } this._dirtyItems=[]; this._autoId=0; this._referenceId=0; this._references={}; this._fetchQueue=[]; this.index={}; //regex to identify when we're travelling down metaObject (which we don't want to do) var expr="("+this.metaLabel+"\'\])"; this.metaRegex = new RegExp(expr); //no data or url, start with an empty object for a store if (!this.data && !this.url){ this.setData({}); } //we have data, but no url, set the store as the data if (this.data && !this.url){ this.setData(this.data); //remove the original refernce, we're now using _data from here on out delete this.data; } //given a url, load json data from as the store if (this.url){ dojo.xhrGet({ url: options.url, handleAs: "json", load: dojo.hitch(this, "setData"), sync: this.mode }); } }, _loadData: function(data){ // summary: // load data into the store. Index it if appropriate. if (this._data){ delete this._data; } if (dojo.isString(data)){ this._data = dojo.fromJson(data); }else{ this._data = data; } if (this.indexOnLoad){ this.buildIndex(); } this._updateMeta(this._data, {path: "$"}); this.onLoadData(this._data); }, onLoadData: function(data){ // summary // Called after data has been loaded in the store. // If any requests happened while the startup is happening // then process them now. while (this._fetchQueue.length>0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ console.log("refs map: " , this._references); console.log("item to delete: ", item); var rid = item[this.metaLabel]["referenceIds"].pop(); var pInfo = this._references[rid]; console.log("deleteItem(): ", pInfo, pInfo.parent); var parentItem = pInfo.parent; var attribute = pInfo.attribute; if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ this._setDirty(parentItem); this.unsetAttribute(parentItem, attribute); delete parentItem[attribute]; } if (dojo.isArray(parentItem[attribute])){ console.log("Parent is array"); var oldValue = this._trimItem(parentItem[attribute]); var found=false; for (var i=0; i 0){ var item = this._dirtyItems.pop()["item"]; var t = this._trimItem(item); var d; switch(kwArgs.format){ case "json": d = dojo.toJson(t); break; case "raw": default: d = t; } data.push(d); this._markClean(item); } this.onSave(data); }, _markClean: function(item){ // summary // remove this meta information marking an item as "dirty" if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){ delete item[this.metaLabel]["isDirty"]; } ";s:7:"private";b:1;s:7:"summary";s:0:"";}s:31:"dojox.data.jsonPathStore.revert";a:4:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:6:"source";s:31720:"dojo.provide("dojox.data.jsonPathStore"); dojo.require("dojox.jsonPath"); dojo.require("dojo.date"); dojo.require("dojo.date.locale"); dojo.require("dojo.date.stamp"); dojox.data.ASYNC_MODE = 0; dojox.data.SYNC_MODE = 1; dojo.declare("dojox.data.jsonPathStore", // summary: // The jsonPathStore implements dojo.data.read, write, notify, and identity api's. It is a local (in memory) store // and can take a javascript object with any arbitrary format and attach to it to provide a dojo.data interface to that object // data. It uses jsonPath as the query language to search agains this store. null, { mode: dojox.data.ASYNC_MODE, metaLabel: "_meta", hideMetaAttributes: false, autoIdPrefix: "_auto_", autoIdentity: true, idAttribute: "_id", indexOnLoad: true, labelAttribute: "", url: "", _replaceRegex: /\'\]/gi, noRevert : false, constructor: function(options){ //summary: // jsonPathStore constructor, instantiate a new jsonPathStore // // Takes a single optional parameter in the form of a Javascript object // containing one or more of the following properties. // // data: /*JSON String*/ || /* Javascript Object */, // JSON String or Javascript object this store will control // JSON is converted into an object, and an object passed to // the store will be used directly. If no data and no url // is provide, an empty object, {}, will be used as the initial // store. // // url: /* string url */ // Load data from this url in JSON format and use the Object // created from the data as the data source. // // indexOnLoad: /* boolean */ // Defaults to true, but this may change in the near future. // Parse the data object and set individual objects up as // appropriate. This will add meta data and assign // id's to objects that dont' have them as defined by the // idAttribute option. Disabling this option will keep this // parsing from happening until a query is performed at which // time only the top level of an item has meta info stored. // This might work in some situations, but you will almost // always want to indexOnLoad or use another option which // will create an index. In the future we will support a // generated index that maps by jsonPath allowing the // server to take some of this load for larger data sets. // // idAttribute: /* string */ // Defaults to '_id'. The name of the attribute that holds an objects id. // This can be a preexisting id provided by the server. // If an ID isn't already provided when an object // is fetched or added to the store, the autoIdentity system // will generate an id for it and add it to the index. There // are utility routines for exporting data from the store // that can clean any generated IDs before exporting and leave // preexisting id's in tact. // // metaLabel: /* string */ // Defaults to '_meta' overrides the attribute name that is used by the store // for attaching meta information to an object while // in the store's control. Defaults to '_meta'. // // hideMetaAttributes: /* boolean */ // Defaults to False. When enabled, calls to getAttributes() will not // include the meta attribute. // // autoIdPrefix: /*string*/ // Defaults to "_auto_". This string is used as the prefix to any // objects which have a generated id. A numeric index is appended // to this string to complete the ID // // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE // Defaults to ASYNC_MODE. This option sets the default mode for this store. // Sync calls return their data immediately from the calling function // instead of calling the callback functions. Functions such as // fetchItemByIdentity() and fetch() both accept a string parameter in addtion // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will // automatically be used even when the default mode of the system is ASYNC_MODE. // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also // include a mode property to override this setting for that one request. //setup a byId alias to the api call this.byId=this.fetchItemByIdentity; if (options){ dojo.mixin(this,options); } this._dirtyItems=[]; this._autoId=0; this._referenceId=0; this._references={}; this._fetchQueue=[]; this.index={}; //regex to identify when we're travelling down metaObject (which we don't want to do) var expr="("+this.metaLabel+"\'\])"; this.metaRegex = new RegExp(expr); //no data or url, start with an empty object for a store if (!this.data && !this.url){ this.setData({}); } //we have data, but no url, set the store as the data if (this.data && !this.url){ this.setData(this.data); //remove the original refernce, we're now using _data from here on out delete this.data; } //given a url, load json data from as the store if (this.url){ dojo.xhrGet({ url: options.url, handleAs: "json", load: dojo.hitch(this, "setData"), sync: this.mode }); } }, _loadData: function(data){ // summary: // load data into the store. Index it if appropriate. if (this._data){ delete this._data; } if (dojo.isString(data)){ this._data = dojo.fromJson(data); }else{ this._data = data; } if (this.indexOnLoad){ this.buildIndex(); } this._updateMeta(this._data, {path: "$"}); this.onLoadData(this._data); }, onLoadData: function(data){ // summary // Called after data has been loaded in the store. // If any requests happened while the startup is happening // then process them now. while (this._fetchQueue.length>0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ console.log("refs map: " , this._references); console.log("item to delete: ", item); var rid = item[this.metaLabel]["referenceIds"].pop(); var pInfo = this._references[rid]; console.log("deleteItem(): ", pInfo, pInfo.parent); var parentItem = pInfo.parent; var attribute = pInfo.attribute; if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ this._setDirty(parentItem); this.unsetAttribute(parentItem, attribute); delete parentItem[attribute]; } if (dojo.isArray(parentItem[attribute])){ console.log("Parent is array"); var oldValue = this._trimItem(parentItem[attribute]); var found=false; for (var i=0; i 0){ var item = this._dirtyItems.pop()["item"]; var t = this._trimItem(item); var d; switch(kwArgs.format){ case "json": d = dojo.toJson(t); break; case "raw": default: d = t; } data.push(d); this._markClean(item); } this.onSave(data); }, _markClean: function(item){ // summary // remove this meta information marking an item as "dirty" if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){ delete item[this.metaLabel]["isDirty"]; } }, revert: function(){ // summary // returns any modified data to its original state prior to a save(); while (this._dirtyItems.length>0){ var d = this._dirtyItems.pop(); this._mixin(d.item, d.old); } this.onRevert();";s:7:"summary";s:0:"";}s:31:"dojox.data.jsonPathStore._mixin";a:6:{s:9:"prototype";s:24:"dojox.data.jsonPathStore";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:6:"target";a:1:{s:4:"type";s:0:"";}s:4:"data";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:1194:" var mix; if (dojo.isObject(data)){ if (dojo.isArray(data)){ while(target.length>0){target.pop();} for (var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ console.log("refs map: " , this._references); console.log("item to delete: ", item); var rid = item[this.metaLabel]["referenceIds"].pop(); var pInfo = this._references[rid]; console.log("deleteItem(): ", pInfo, pInfo.parent); var parentItem = pInfo.parent; var attribute = pInfo.attribute; if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ this._setDirty(parentItem); this.unsetAttribute(parentItem, attribute); delete parentItem[attribute]; } if (dojo.isArray(parentItem[attribute])){ console.log("Parent is array"); var oldValue = this._trimItem(parentItem[attribute]); var found=false; for (var i=0; i 0){ var item = this._dirtyItems.pop()["item"]; var t = this._trimItem(item); var d; switch(kwArgs.format){ case "json": d = dojo.toJson(t); break; case "raw": default: d = t; } data.push(d); this._markClean(item); } this.onSave(data); }, _markClean: function(item){ // summary // remove this meta information marking an item as "dirty" if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){ delete item[this.metaLabel]["isDirty"]; } }, revert: function(){ // summary // returns any modified data to its original state prior to a save(); while (this._dirtyItems.length>0){ var d = this._dirtyItems.pop(); this._mixin(d.item, d.old); } this.onRevert(); }, _mixin: function(target, data){ // summary: // specialized mixin that hooks up objects in the store where references are identified. var mix; if (dojo.isObject(data)){ if (dojo.isArray(data)){ while(target.length>0){target.pop();} for (var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ console.log("refs map: " , this._references); console.log("item to delete: ", item); var rid = item[this.metaLabel]["referenceIds"].pop(); var pInfo = this._references[rid]; console.log("deleteItem(): ", pInfo, pInfo.parent); var parentItem = pInfo.parent; var attribute = pInfo.attribute; if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ this._setDirty(parentItem); this.unsetAttribute(parentItem, attribute); delete parentItem[attribute]; } if (dojo.isArray(parentItem[attribute])){ console.log("Parent is array"); var oldValue = this._trimItem(parentItem[attribute]); var found=false; for (var i=0; i 0){ var item = this._dirtyItems.pop()["item"]; var t = this._trimItem(item); var d; switch(kwArgs.format){ case "json": d = dojo.toJson(t); break; case "raw": default: d = t; } data.push(d); this._markClean(item); } this.onSave(data); }, _markClean: function(item){ // summary // remove this meta information marking an item as "dirty" if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){ delete item[this.metaLabel]["isDirty"]; } }, revert: function(){ // summary // returns any modified data to its original state prior to a save(); while (this._dirtyItems.length>0){ var d = this._dirtyItems.pop(); this._mixin(d.item, d.old); } this.onRevert(); }, _mixin: function(target, data){ // summary: // specialized mixin that hooks up objects in the store where references are identified. var mix; if (dojo.isObject(data)){ if (dojo.isArray(data)){ while(target.length>0){target.pop();} for (var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ console.log("refs map: " , this._references); console.log("item to delete: ", item); var rid = item[this.metaLabel]["referenceIds"].pop(); var pInfo = this._references[rid]; console.log("deleteItem(): ", pInfo, pInfo.parent); var parentItem = pInfo.parent; var attribute = pInfo.attribute; if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ this._setDirty(parentItem); this.unsetAttribute(parentItem, attribute); delete parentItem[attribute]; } if (dojo.isArray(parentItem[attribute])){ console.log("Parent is array"); var oldValue = this._trimItem(parentItem[attribute]); var found=false; for (var i=0; i 0){ var item = this._dirtyItems.pop()["item"]; var t = this._trimItem(item); var d; switch(kwArgs.format){ case "json": d = dojo.toJson(t); break; case "raw": default: d = t; } data.push(d); this._markClean(item); } this.onSave(data); }, _markClean: function(item){ // summary // remove this meta information marking an item as "dirty" if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){ delete item[this.metaLabel]["isDirty"]; } }, revert: function(){ // summary // returns any modified data to its original state prior to a save(); while (this._dirtyItems.length>0){ var d = this._dirtyItems.pop(); this._mixin(d.item, d.old); } this.onRevert(); }, _mixin: function(target, data){ // summary: // specialized mixin that hooks up objects in the store where references are identified. var mix; if (dojo.isObject(data)){ if (dojo.isArray(data)){ while(target.length>0){target.pop();} for (var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ console.log("refs map: " , this._references); console.log("item to delete: ", item); var rid = item[this.metaLabel]["referenceIds"].pop(); var pInfo = this._references[rid]; console.log("deleteItem(): ", pInfo, pInfo.parent); var parentItem = pInfo.parent; var attribute = pInfo.attribute; if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ this._setDirty(parentItem); this.unsetAttribute(parentItem, attribute); delete parentItem[attribute]; } if (dojo.isArray(parentItem[attribute])){ console.log("Parent is array"); var oldValue = this._trimItem(parentItem[attribute]); var found=false; for (var i=0; i 0){ var item = this._dirtyItems.pop()["item"]; var t = this._trimItem(item); var d; switch(kwArgs.format){ case "json": d = dojo.toJson(t); break; case "raw": default: d = t; } data.push(d); this._markClean(item); } this.onSave(data); }, _markClean: function(item){ // summary // remove this meta information marking an item as "dirty" if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){ delete item[this.metaLabel]["isDirty"]; } }, revert: function(){ // summary // returns any modified data to its original state prior to a save(); while (this._dirtyItems.length>0){ var d = this._dirtyItems.pop(); this._mixin(d.item, d.old); } this.onRevert(); }, _mixin: function(target, data){ // summary: // specialized mixin that hooks up objects in the store where references are identified. var mix; if (dojo.isObject(data)){ if (dojo.isArray(data)){ while(target.length>0){target.pop();} for (var i=0; i0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i= args.count)) { continue; } var item = results[i]["value"]; var path = results[i]["path"]; if (!dojo.isObject(item)){continue;} if(this.metaRegex.exec(path)){continue;} //this automatically records the objects path this._updateMeta(item,{path: results[i].path}); //if autoIdentity and no id, generate one and add it to the item if(this.autoIdentity && !item[this.idAttribute]){ var newId = this.autoIdPrefix + this._autoId++; item[this.idAttribute]=newId; item[this.metaLabel].autoId=true; } //add item to the item index if appropriate if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} count++; tmp.push(item); } results = tmp; var scope = args.scope || dojo.global; if ("sort" in args){ console.log("TODO::add support for sorting in the fetch"); } if (args.mode==dojox.data.SYNC_MODE){ return results; }; if (args.onBegin){ args["onBegin"].call(scope, results.length, args); } if (args.onItem){ for (var i=0; i0) { label+=" ";} label += item[this.labelAttribute[i]]; } return label; }else{ return item[this.labelAttribute]; } } return item.toString(); }, getLabelAttributes: function(item){ // summary: // returns an array of attributes that are used to create the label of an item item = this._correctReference(item); return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; }, sort: function(a,b){ console.log("TODO::implement default sort algo"); }, //Identity API Support getIdentity: function(item){ // summary // returns the identity of an item or throws // a not found error. if (this.isItem(item)){ return item[this.idAttribute]; } throw new Error("Id not found for item"); }, getIdentityAttributes: function(item){ // summary: // returns the attributes which are used to make up the // identity of an item. Basically returns this.idAttribute return [this.idAttribute]; }, fetchItemByIdentity: function(args){ // summary: // fetch an item by its identity. This store also provides // a much more finger friendly alias, 'byId' which does the // same thing as this function. If provided a string // this call will be treated as a SYNC request and will // return the identified item immediatly. Alternatively it // takes a object as a set of keywordArgs: // // identity: /* string */ // the id of the item you want to retrieve // // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE // overrides the default store fetch mode // // onItem: /* function */ // Result call back. Passed the fetched item. // // onError: /* function */ // error callback. var id; if (dojo.isString(args)){ id = args; args = {identity: id, mode: dojox.data.SYNC_MODE} }else{ if (args){ id = args["identity"]; } if (!args.mode){args.mode = this.mode} } if (this.index && (this.index[id] || this.index["identity"])){ if (args.mode==dojox.data.SYNC_MODE){ return this.index[id]; } if (args.onItem){ args["onItem"].call(args.scope || dojo.global, this.index[id], args); } return args; }else{ if (args.mode==dojox.data.SYNC_MODE){ return false; } } if(args.onError){ args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); } return args; }, _makeItAnItem: function(data, pInfo){ // Summary: // add the meta data to the item and descendants var meta={}; if(this.idAttribute && !data[this.idAttribute]){ if(this.requireId){ throw new Error("requireId is enabled, new items must have an id defined to be added"); } if(this.autoIdentity){ var newId = this.autoIdPrefix + this._autoId++; data[this.idAttribute]=newId; meta.autoId=true; } } if(!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ throw new Error("Adding a new item requires, at a minimum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); } if(!pInfo.attribute){ pInfo.attribute = data[this.idAttribute]; } //add this item to the index if(data[this.idAttribute]){ this.index[data[this.idAttribute]]=data; } this._updateMeta(data, meta) //keep track of all references in the store so we can delete them as necessary this._addReference(data, {parent: pInfo.item, attribute: pInfo.attribute}); //mark this new item as dirty this._setDirty(data); //Itemize the children the children if any if(data[pInfo.attribute] && dojo.isArray(data[pInfo.attribute])){ for(var i=0; i0){ console.log("refs map: " , this._references); console.log("item to delete: ", item); var rid = item[this.metaLabel]["referenceIds"].pop(); var pInfo = this._references[rid]; console.log("deleteItem(): ", pInfo, pInfo.parent); var parentItem = pInfo.parent; var attribute = pInfo.attribute; if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ this._setDirty(parentItem); this.unsetAttribute(parentItem, attribute); delete parentItem[attribute]; } if (dojo.isArray(parentItem[attribute])){ console.log("Parent is array"); var oldValue = this._trimItem(parentItem[attribute]); var found=false; for (var i=0; i 0){ var item = this._dirtyItems.pop()["item"]; var t = this._trimItem(item); var d; switch(kwArgs.format){ case "json": d = dojo.toJson(t); break; case "raw": default: d = t; } data.push(d); this._markClean(item); } this.onSave(data); }, _markClean: function(item){ // summary // remove this meta information marking an item as "dirty" if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){ delete item[this.metaLabel]["isDirty"]; } }, revert: function(){ // summary // returns any modified data to its original state prior to a save(); while (this._dirtyItems.length>0){ var d = this._dirtyItems.pop(); this._mixin(d.item, d.old); } this.onRevert(); }, _mixin: function(target, data){ // summary: // specialized mixin that hooks up objects in the store where references are identified. var mix; if (dojo.isObject(data)){ if (dojo.isArray(data)){ while(target.length>0){target.pop();} for (var i=0; i