📄 itemfilereadstore.js
字号:
if(!dojo._hasResource["dojo.data.ItemFileReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dojo.data.ItemFileReadStore"] = true;dojo.provide("dojo.data.ItemFileReadStore");dojo.require("dojo.data.util.filter");dojo.require("dojo.data.util.simpleFetch");dojo.require("dojo.date.stamp");dojo.declare("dojo.data.ItemFileReadStore", null,{ // summary: // The ItemFileReadStore implements the dojo.data.api.Read API and reads // data from JSON files that have contents in this format -- // { items: [ // { name:'Kermit', color:'green', age:12, friends:['Gonzo', {_reference:{name:'Fozzie Bear'}}]}, // { name:'Fozzie Bear', wears:['hat', 'tie']}, // { name:'Miss Piggy', pets:'Foo-Foo'} // ]} // Note that it can also contain an 'identifer' property that specified which attribute on the items // in the array of items that acts as the unique identifier for that item. // constructor: function(/* Object */ keywordParameters){ // summary: constructor // keywordParameters: {url: String} // keywordParameters: {data: jsonObject} // keywordParameters: {typeMap: object) // The structure of the typeMap object is as follows: // { // type0: function || object, // type1: function || object, // ... // typeN: function || object // } // Where if it is a function, it is assumed to be an object constructor that takes the // value of _value as the initialization parameters. If it is an object, then it is assumed // to be an object of general form: // { // type: function, //constructor. // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately. // } this._arrayOfAllItems = []; this._arrayOfTopLevelItems = []; this._loadFinished = false; this._jsonFileUrl = keywordParameters.url; this._jsonData = keywordParameters.data; this._datatypeMap = keywordParameters.typeMap || {}; if(!this._datatypeMap['Date']){ //If no default mapping for dates, then set this as default. //We use the dojo.date.stamp here because the ISO format is the 'dojo way' //of generically representing dates. this._datatypeMap['Date'] = { type: Date, deserialize: function(value){ return dojo.date.stamp.fromISOString(value); } }; } this._features = {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true}; this._itemsByIdentity = null; this._storeRefPropName = "_S"; // Default name for the store reference to attach to every item. this._itemNumPropName = "_0"; // Default Item Id for isItem to attach to every item. this._rootItemPropName = "_RI"; // Default Item Id for isItem to attach to every item. this._reverseRefMap = "_RRM"; // Default attribute for constructing a reverse reference map for use with reference integrity this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset. this._queuedFetches = []; }, url: "", // use "" rather than undefined for the benefit of the parser (#3539) _assertIsItem: function(/* item */ item){ // summary: // This function tests whether the item passed in is indeed an item in the store. // item: // The item to test for being contained by the store. if(!this.isItem(item)){ throw new Error("dojo.data.ItemFileReadStore: Invalid item argument."); } }, _assertIsAttribute: function(/* attribute-name-string */ attribute){ // summary: // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store. // attribute: // The attribute to test for being contained by the store. if(typeof attribute !== "string"){ throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument."); } }, getValue: function( /* item */ item, /* attribute-name-string */ attribute, /* value? */ defaultValue){ // summary: // See dojo.data.api.Read.getValue() var values = this.getValues(item, attribute); return (values.length > 0)?values[0]:defaultValue; // mixed }, getValues: function(/* item */ item, /* attribute-name-string */ attribute){ // summary: // See dojo.data.api.Read.getValues() this._assertIsItem(item); this._assertIsAttribute(attribute); return item[attribute] || []; // Array }, getAttributes: function(/* item */ item){ // summary: // See dojo.data.api.Read.getAttributes() this._assertIsItem(item); var attributes = []; for(var key in item){ // Save off only the real item attributes, not the special id marks for O(1) isItem. if((key !== this._storeRefPropName) && (key !== this._itemNumPropName) && (key !== this._rootItemPropName) && (key !== this._reverseRefMap)){ attributes.push(key); } } return attributes; // Array }, hasAttribute: function( /* item */ item, /* attribute-name-string */ attribute) { // summary: // See dojo.data.api.Read.hasAttribute() return this.getValues(item, attribute).length > 0; }, containsValue: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ value){ // summary: // See dojo.data.api.Read.containsValue() var regexp = undefined; if(typeof value === "string"){ regexp = dojo.data.util.filter.patternToRegExp(value, false); } return this._containsValue(item, attribute, value, regexp); //boolean. }, _containsValue: function( /* item */ item, /* attribute-name-string */ attribute, /* anything */ value, /* RegExp?*/ regexp){ // summary: // Internal function for looking at the values contained by the item. // description: // Internal function for looking at the values contained by the item. This // function allows for denoting if the comparison should be case sensitive for // strings or not (for handling filtering cases where string case should not matter) // // item: // The data item to examine for attribute values. // attribute: // The attribute to inspect. // value: // The value to match. // regexp: // Optional regular expression generated off value if value was of string type to handle wildcarding. // If present and attribute values are string, then it can be used for comparison instead of 'value' return dojo.some(this.getValues(item, attribute), function(possibleValue){ if(possibleValue !== null && !dojo.isObject(possibleValue) && regexp){ if(possibleValue.toString().match(regexp)){ return true; // Boolean } }else if(value === possibleValue){ return true; // Boolean } }); }, isItem: function(/* anything */ something){ // summary: // See dojo.data.api.Read.isItem() if(something && something[this._storeRefPropName] === this){ if(this._arrayOfAllItems[something[this._itemNumPropName]] === something){ return true; } } return false; // Boolean }, isItemLoaded: function(/* anything */ something){ // summary: // See dojo.data.api.Read.isItemLoaded() return this.isItem(something); //boolean }, loadItem: function(/* object */ keywordArgs){ // summary: // See dojo.data.api.Read.loadItem() this._assertIsItem(keywordArgs.item); }, getFeatures: function(){ // summary: // See dojo.data.api.Read.getFeatures() return this._features; //Object }, getLabel: function(/* item */ item){ // summary: // See dojo.data.api.Read.getLabel() if(this._labelAttr && this.isItem(item)){ return this.getValue(item,this._labelAttr); //String } return undefined; //undefined }, getLabelAttributes: function(/* item */ item){ // summary: // See dojo.data.api.Read.getLabelAttributes() if(this._labelAttr){ return [this._labelAttr]; //array } return null; //null }, _fetchItems: function( /* Object */ keywordArgs, /* Function */ findCallback, /* Function */ errorCallback){ // summary: // See dojo.data.util.simpleFetch.fetch() var self = this; var filter = function(requestArgs, arrayOfItems){ var items = []; if(requestArgs.query){ var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false; //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the //same value for each item examined. Much more efficient. var regexpList = {}; for(var key in requestArgs.query){ var value = requestArgs.query[key]; if(typeof value === "string"){ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase); } } for(var i = 0; i < arrayOfItems.length; ++i){ var match = true; var candidateItem = arrayOfItems[i]; if(candidateItem === null){ match = false; }else{ for(var key in requestArgs.query) { var value = requestArgs.query[key]; if (!self._containsValue(candidateItem, key, value, regexpList[key])){ match = false; } } } if(match){ items.push(candidateItem); } } findCallback(items, requestArgs); }else{ // We want a copy to pass back in case the parent wishes to sort the array. // We shouldn't allow resort of the internal list, so that multiple callers // can get lists and sort without affecting each other. We also need to // filter out any null values that have been left as a result of deleteItem() // calls in ItemFileWriteStore. for(var i = 0; i < arrayOfItems.length; ++i){ var item = arrayOfItems[i]; if(item !== null){ items.push(item); } } findCallback(items, requestArgs); } }; if(this._loadFinished){ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions)); }else{ if(this._jsonFileUrl){ //If fetches come in before the loading has finished, but while //a load is in progress, we have to defer the fetching to be //invoked in the callback. if(this._loadInProgress){ this._queuedFetches.push({args: keywordArgs, filter: filter}); }else{ this._loadInProgress = true; var getArgs = { url: self._jsonFileUrl, handleAs: "json-comment-optional" }; var getHandler = dojo.xhrGet(getArgs); getHandler.addCallback(function(data){ try{ self._getItemsFromLoadedData(data); self._loadFinished = true; self._loadInProgress = false; filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions)); self._handleQueuedFetches(); }catch(e){ self._loadFinished = true; self._loadInProgress = false; errorCallback(e, keywordArgs); } }); getHandler.addErrback(function(error){ self._loadInProgress = false; errorCallback(error, keywordArgs); }); } }else if(this._jsonData){ try{ this._loadFinished = true; this._getItemsFromLoadedData(this._jsonData); this._jsonData = null; filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions)); }catch(e){ errorCallback(e, keywordArgs); } }else{ errorCallback(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs); } } }, _handleQueuedFetches: function(){ // summary: // Internal function to execute delayed request in the store. //Execute any deferred fetches now. if (this._queuedFetches.length > 0) { for(var i = 0; i < this._queuedFetches.length; i++){ var fData = this._queuedFetches[i]; var delayedQuery = fData.args; var delayedFilter = fData.filter; if(delayedFilter){ delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions)); }else{ this.fetchItemByIdentity(delayedQuery); } } this._queuedFetches = []; } }, _getItemsArray: function(/*object?*/queryOptions){ // summary: // Internal function to determine which list of items to search over. // queryOptions: The query options parameter, if any. if(queryOptions && queryOptions.deep) { return this._arrayOfAllItems; } return this._arrayOfTopLevelItems; }, close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ // summary: // See dojo.data.api.Read.close() }, _getItemsFromLoadedData: function(/* Object */ dataObject){ // summary: // Function to parse the loaded data into item format and build the internal items array. // description: // Function to parse the loaded data into item format and build the internal items array. // // dataObject: // The JS data object containing the raw data to convery into item format. // // returns: array // Array of items in store item format. // First, we define a couple little utility functions... function valueIsAnItem(/* anything */ aValue){ // summary: // Given any sort of value that could be in the raw json data, // return true if we should interpret the value as being an // item itself, rather than a literal value or a reference. // example: // | false == valueIsAnItem("Kermit"); // | false == valueIsAnItem(42); // | false == valueIsAnItem(new Date()); // | false == valueIsAnItem({_type:'Date', _value:'May 14, 1802'});
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -