📄 jsonpathstore.js
字号:
if(!dojo._hasResource["dojox.data.jsonPathStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dojox.data.jsonPathStore"] = true;dojo.provide("dojox.data.jsonPathStore");dojo.require("dojox.jsonPath");dojo.require("dojo.date");dojo.require("dojo.date.locale");dojo.require("dojo.date.stamp");dojox.data.ASYNC_MODE = 0;dojox.data.SYNC_MODE = 1;dojo.declare("dojox.data.jsonPathStore", null, { mode: dojox.data.ASYNC_MODE, metaLabel: "_meta", hideMetaAttributes: false, autoIdPrefix: "_auto_", autoIdentity: true, idAttribute: "_id", indexOnLoad: true, labelAttribute: "", url: "", _replaceRegex: /\'\]/gi, constructor: function(options){ //summary: // jsonPathStore constructor, instantiate a new jsonPathStore // // Takes a single optional parameter in the form of a Javascript object // containing one or more of the following properties. // // data: /*JSON String*/ || /* Javascript Object */, // JSON String or Javascript object this store will control // JSON is converted into an object, and an object passed to // the store will be used directly. If no data and no url // is provide, an empty object, {}, will be used as the initial // store. // // url: /* string url */ // Load data from this url in JSON format and use the Object // created from the data as the data source. // // indexOnLoad: /* boolean */ // Defaults to true, but this may change in the near future. // Parse the data object and set individual objects up as // appropriate. This will add meta data and assign // id's to objects that dont' have them as defined by the // idAttribute option. Disabling this option will keep this // parsing from happening until a query is performed at which // time only the top level of an item has meta info stored. // This might work in some situations, but you will almost // always want to indexOnLoad or use another option which // will create an index. In the future we will support a // generated index that maps by jsonPath allowing the // server to take some of this load for larger data sets. // // idAttribute: /* string */ // Defaults to '_id'. The name of the attribute that holds an objects id. // This can be a preexisting id provided by the server. // If an ID isn't already provided when an object // is fetched or added to the store, the autoIdentity system // will generate an id for it and add it to the index. There // are utility routines for exporting data from the store // that can clean any generated IDs before exporting and leave // preexisting id's in tact. // // metaLabel: /* string */ // Defaults to '_meta' overrides the attribute name that is used by the store // for attaching meta information to an object while // in the store's control. Defaults to '_meta'. // // hideMetaAttributes: /* boolean */ // Defaults to False. When enabled, calls to getAttributes() will not // include the meta attribute. // // autoIdPrefix: /*string*/ // Defaults to "_auto_". This string is used as the prefix to any // objects which have a generated id. A numeric index is appended // to this string to complete the ID // // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE // Defaults to ASYNC_MODE. This option sets the default mode for this store. // Sync calls return their data immediately from the calling function // instead of calling the callback functions. Functions such as // fetchItemByIdentity() and fetch() both accept a string parameter in addtion // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will // automatically be used even when the default mode of the system is ASYNC_MODE. // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also // include a mode property to override this setting for that one request. //setup a byId alias to the api call this.byId=this.fetchItemByIdentity; if (options){ dojo.mixin(this,options); } this._dirtyItems=[]; this._autoId=0; this._referenceId=0; this._references={}; this._fetchQueue=[]; this.index={}; //regex to identify when we're travelling down metaObject (which we don't want to do) var expr="("+this.metaLabel+"\'\])"; this.metaRegex = new RegExp(expr); //no data or url, start with an empty object for a store if (!this.data && !this.url){ this.setData({}); } //we have data, but no url, set the store as the data if (this.data && !this.url){ this.setData(this.data); //remove the original refernce, we're now using _data from here on out delete this.data; } //given a url, load json data from as the store if (this.url){ dojo.xhrGet({ url: options.url, handleAs: "json", load: dojo.hitch(this, "setData"), sync: this.mode }); } }, _loadData: function(data){ // summary: // load data into the store. Index it if appropriate. if (this._data){ delete this._data; } if (dojo.isString(data)){ this._data = dojo.fromJson(data); }else{ this._data = data; } if (this.indexOnLoad){ this.buildIndex(); } this._updateMeta(this._data, {path: "$"}); this.onLoadData(this._data); }, onLoadData: function(data){ // summary // Called after data has been loaded in the store. // If any requests happened while the startup is happening // then process them now. while (this._fetchQueue.length>0){ var req = this._fetchQueue.shift(); this.fetch(req); } }, setData: function(data){ // summary: // set the stores' data to the supplied object and then // load and/or setup that data with the required meta info this._loadData(data); }, buildIndex: function(path, item){ //summary: // parse the object structure, and turn any objects into // jsonPathStore items. Basically this just does a recursive // series of fetches which itself already examines any items // as they are retrieved and setups up the required meta information. // // path: /* string */ // jsonPath Query for the starting point of this index construction. if (!this.idAttribute){ throw new Error("buildIndex requires idAttribute for the store"); } item = item || this._data; var origPath = path; path = path||"$"; path += "[*]"; var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); for(var i=0; i<data.length;i++){ if(dojo.isObject(data[i])){ var newPath = data[i][this.metaLabel]["path"]; if (origPath){ //console.log("newPath: ", newPath); //console.log("origPath: ", origPath); //console.log("path: ", path); //console.log("data[i]: ", data[i]); var parts = origPath.split("\[\'"); var attribute = parts[parts.length-1].replace(this._replaceRegex,''); //console.log("attribute: ", attribute); //console.log("ParentItem: ", item, attribute); if (!dojo.isArray(data[i])){ this._addReference(data[i], {parent: item, attribute:attribute}); this.buildIndex(newPath, data[i]); }else{ this.buildIndex(newPath,item); } }else{ var parts = newPath.split("\[\'"); var attribute = parts[parts.length-1].replace(this._replaceRegex,''); this._addReference(data[i], {parent: this._data, attribute:attribute}); this.buildIndex(newPath, data[i]); } } } }, _correctReference: function(item){ // summary: // make sure we have an reference to the item in the store // and not a clone. Takes an item, matches it to the corresponding // item in the store and if it is the same, returns itself, otherwise // it returns the item from the store. if (this.index[item[this.idAttribute]][this.metaLabel]===item[this.metaLabel]){ return this.index[item[this.idAttribute]]; } return item; }, getValue: function(item, property){ // summary: // Gets the value of an item's 'property' // // item: /* object */ // property: /* string */ // property to look up value for item = this._correctReference(item); return item[property]; }, getValues: function(item, property){ // summary: // Gets the value of an item's 'property' and returns // it. If this value is an array it is just returned, // if not, the value is added to an array and that is returned. // // item: /* object */ // property: /* string */ // property to look up value for item = this._correctReference(item); return dojo.isArray(item[property]) ? item[property] : [item[property]]; }, getAttributes: function(item){ // summary: // Gets the available attributes of an item's 'property' and returns // it as an array. If the store has 'hideMetaAttributes' set to true // the attributed identified by 'metaLabel' will not be included. // // item: /* object */ item = this._correctReference(item); var res = []; for (var i in item){ if (this.hideMetaAttributes && (i==this.metaLabel)){continue;} res.push(i); } return res; }, hasAttribute: function(item,attribute){ // summary: // Checks to see if item has attribute // // item: /* object */ // attribute: /* string */ item = this._correctReference(item); if (attribute in item){return true;} return false; }, containsValue: function(item, attribute, value){ // summary: // Checks to see if 'item' has 'value' at 'attribute' // // item: /* object */ // attribute: /* string */ // value: /* anything */ item = this._correctReference(item); if (item[attribute] && item[attribute]==value){return true} if (dojo.isObject(item[attribute]) || dojo.isObject(value)){ if (this._shallowCompare(item[attribute],value)){return true} } return false; }, _shallowCompare: function(a, b){ //summary does a simple/shallow compare of properties on an object //to the same named properties on the given item. Returns //true if all props match. It will not descend into child objects //but it will compare child date objects if ((dojo.isObject(a) && !dojo.isObject(b))|| (dojo.isObject(b) && !dojo.isObject(a))) { return false; } if ( a["getFullYear"] || b["getFullYear"] ){ //confirm that both are dates if ( (a["getFullYear"] && !b["getFullYear"]) || (b["getFullYear"] && !a["getFullYear"]) ){ return false; }else{ if (!dojo.date.compare(a,b)){ return true; } return false; } } for (var i in b){ if (dojo.isObject(b[i])){ if (!a[i] || !dojo.isObject(a[i])){return false} if (b[i]["getFullYear"]){ if(!a[i]["getFullYear"]){return false} if (dojo.date.compare(a,b)){return false} }else{ if (!this._shallowCompare(a[i],b[i])){return false} } }else{ if (!b[i] || (a[i]!=b[i])){return false} } } //make sure there werent props on a that aren't on b, if there aren't, then //the previous section will have already evaluated things. for (var i in a){ if (!b[i]){return false} } return true; }, isItem: function(item){ // summary: // Checks to see if a passed 'item' // is really a jsonPathStore item. Currently // it only verifies structure. It does not verify // that it belongs to this store at this time. // // item: /* object */ // attribute: /* string */ if (!dojo.isObject(item) || !item[this.metaLabel]){return false} if (this.requireId && this._hasId && !item[this._id]){return false} return true; }, isItemLoaded: function(item){ // summary: // returns isItem() :) // // item: /* object */ item = this._correctReference(item); return this.isItem(item); }, loadItem: function(item){ // summary: // returns true. Future implementatins might alter this return true; }, _updateMeta: function(item, props){ // summary: // verifies that 'item' has a meta object attached // and if not it creates it by setting it to 'props' // if the meta attribute already exists, mix 'props' // into it. if (item && item[this.metaLabel]){ dojo.mixin(item[this.metaLabel], props); return; } item[this.metaLabel]=props; },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -