Changeset 7969
- Timestamp:
- 04/06/07 19:55:05 (21 months ago)
- Location:
- dojo/trunk/data
- Files:
-
- 6 copied
-
api/Identity.js (copied) (copied from trunk/src/data/core/Identity.js)
-
api/Read.js (copied) (copied from trunk/src/data/core/Read.js)
-
api/Result.js (copied) (copied from trunk/src/data/core/Result.js)
-
api/Write.js (copied) (copied from trunk/src/data/core/Write.js)
-
JsonItemStore.js (copied) (copied from trunk/src/data/JsonItemStore.js) (5 diffs)
-
util/simpleFetch.js (copied) (copied from trunk/src/data/core/SimpleBaseStore.js) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
dojo/trunk/data/JsonItemStore.js
r7391 r7969 1 1 dojo.provide("dojo.data.JsonItemStore"); 2 2 3 dojo.require("dojo.data.core.SimpleBaseStore"); 4 dojo.require("dojo.lang.declare"); 5 dojo.require("dojo.io.common"); 6 dojo.require("dojo.lang.common"); 7 dojo.require("dojo.experimental"); 8 dojo.experimental("dojo.data.JsonItemStore"); 9 10 dojo.declare("dojo.data.JsonItemStore", dojo.data.core.SimpleBaseStore, 11 function(/* object */ keywordParameters) { 3 dojo.require("dojo.data.util.filter"); 4 dojo.require("dojo.data.util.simpleFetch"); 5 //FIXME: Replace with the port to the new xhr when available. 6 //dojo.require("dojo.io.common"); 7 8 dojo.declare("dojo.data.JsonItemStore", 9 null, 10 function(/* Object */ keywordParameters){ 12 11 // summary: initializer 13 12 // keywordParameters: {url: String} … … 17 16 this._jsonFileUrl = keywordParameters.url; 18 17 this._jsonData = keywordParameters.data; 19 this._features = { 'dojo.data. core.Read': true};18 this._features = { 'dojo.data.api.Read': true}; 20 19 this._itemsByIdentity = null; 21 }, { 22 /* summary: 23 * The JsonItemStore implements the dojo.data.core.Read API and reads 24 * data from JSON files that have contents in this format -- 25 * { items: [ 26 * { name:'Kermit', color:'green', age:12, friends:['Gonzo', {reference:{name:'Fozzie Bear'}}]}, 27 * { name:'Fozzie Bear', wears:['hat', 'tie']}, 28 * { name:'Miss Piggy', pets:'Foo-Foo'} 29 * ]} 30 */ 31 32 _assertIsItem: function(/* item */ item) { 33 if (!this.isItem(item)) { 20 this._itemMap = {}; // Simple associative map for making an O(1) isItem. 21 this._storeRef = "_S"; //Default name for the store reference to attach to every item. 22 this._itemId = "_0"; //Default Item Id for isItem to attach to every item. 23 },{ 24 // summary: 25 // The JsonItemStore implements the dojo.data.api.Read API and reads 26 // data from JSON files that have contents in this format -- 27 // { items: [ 28 // { name:'Kermit', color:'green', age:12, friends:['Gonzo', {reference:{name:'Fozzie Bear'}}]}, 29 // { name:'Fozzie Bear', wears:['hat', 'tie']}, 30 // { name:'Miss Piggy', pets:'Foo-Foo'} 31 // ]} 32 // Note that it can also contain an 'identifer' property that specified which attribute on the items 33 // in the array of items that acts as the unique identifier for that item. 34 // 35 36 _assertIsItem: function(/* item */ item){ 37 // summary: 38 // This function tests whether the item passed in is indeed an item in the store. 39 // item: 40 // The item to test for being contained by the store. 41 if(!this.isItem(item)){ 34 42 throw new Error("dojo.data.JsonItemStore: a function was passed an item argument that was not an item"); 35 43 } 36 44 }, 37 38 getValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue) { 39 // summary: See dojo.data.core.Read.getValue() 45 46 _assertIsAttribute: function(/* item || String */ attribute){ 47 // summary: 48 // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store. 49 // attribute: 50 // The attribute to test for being contained by the store. 51 if(!this.isItem(attribute)){ 52 throw new Error("dojo.data.JsonItemStore: a function was passed an attribute argument that was not an attribute object nor an attribute name string"); 53 } 54 }, 55 56 getValue: function( /* item */ item, 57 /* attribute || attribute-name-string */ attribute, 58 /* value? */ defaultValue){ 59 // summary: 60 // See dojo.data.api.Read.getValue() 40 61 var values = this.getValues(item, attribute); 41 var value = (values.length > 0) ? values[0] : defaultValue; 42 return value; 43 }, 44 45 getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute) { 46 // summary: See dojo.data.core.Read.getValues() 62 return (values.length > 0)?values[0]:defaultValue; //Object || int || Boolean 63 }, 64 65 getValues: function(/* item */ item, 66 /* attribute || attribute-name-string */ attribute){ 67 // summary: 68 // See dojo.data.api.Read.getValues() 69 if(typeof attribute !== "string"){ 70 this._assertIsAttribute(attribute); 71 attribute = this.getIdentity(attribute); 72 } 47 73 this._assertIsItem(item); 48 var arrayOfValues = item[attribute] || [];49 return arrayOfValues;50 }, 51 52 getAttributes: function(/* item */ item) {53 // summary: See dojo.data.core.Read.getAttributes()74 return item[attribute] || []; //Array 75 }, 76 77 getAttributes: function(/* item */ item){ 78 // summary: 79 // See dojo.data.api.Read.getAttributes() 54 80 this._assertIsItem(item); 55 81 var attributes = []; 56 for (var key in item) { 57 attributes.push(key); 58 } 59 return attributes; 60 }, 61 62 hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute) { 63 // summary: See dojo.data.core.Read.hasAttribute() 64 return (this.getValues(item, attribute).length > 0); 65 }, 66 67 containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value) { 68 // summary: See dojo.data.core.Read.containsValue() 82 for(var key in item){ 83 //Save off only the real item attributes, not the special id marks for O(1) isItem. 84 if((key !== this._storeRef) && (key !== this._itemId)){ 85 attributes.push(key); 86 } 87 } 88 return attributes; //Array 89 }, 90 91 hasAttribute: function( /* item */ item, 92 /* attribute || attribute-name-string */ attribute) { 93 // summary: 94 // See dojo.data.api.Read.hasAttribute() 95 return this.getValues(item, attribute).length > 0; 96 }, 97 98 containsValue: function(/* item */ item, 99 /* attribute || attribute-name-string */ attribute, 100 /* anything */ value){ 101 // summary: 102 // See dojo.data.api.Read.containsValue() 69 103 var values = this.getValues(item, attribute); 70 for (var i = 0; i < values.length; ++i){104 for(var i = 0; i < values.length; ++i){ 71 105 var possibleValue = values[i]; 72 if (value == possibleValue) { 106 if(typeof value === "string" && typeof possibleValue === "string"){ 107 return (possibleValue.match(dojo.data.util.filter.patternToRegExp(value)) !== null); 108 }else{ 109 //Non-string matching. 110 if(value === possibleValue){ 111 return true; // Boolean 112 } 113 } 114 } 115 return false; // Boolean 116 }, 117 118 isItem: function(/* anything */ something){ 119 // summary: 120 // See dojo.data.api.Read.isItem() 121 if(something && something[this._storeRef] === this){ 122 if(this._itemMap[something[this._itemId]] === something){ 73 123 return true; 74 124 } 75 125 } 76 return false; // boolean 77 }, 78 79 isItem: function(/* anything */ something) { 80 // summary: See dojo.data.core.Read.isItem() 81 for (var i = 0; i < this._arrayOfAllItems.length; ++i) { 82 var possibleItem = this._arrayOfAllItems[i]; 83 if (something == possibleItem) { 84 return true; 85 } 86 } 87 return false; // boolean 88 }, 89 90 isItemLoaded: function(/* anything */ something) { 91 // summary: See dojo.data.core.Read.isItemLoaded() 92 return this.isItem(something); 93 }, 94 95 loadItem: function(/* item */ item) { 96 // summary: See dojo.data.core.Read.loadItem() 126 return false; // Boolean 127 }, 128 129 isItemLoaded: function(/* anything */ something){ 130 // summary: 131 // See dojo.data.api.Read.isItemLoaded() 132 return this.isItem(something); //boolean 133 }, 134 135 loadItem: function(/* item */ item){ 136 // summary: 137 // See dojo.data.api.Read.loadItem() 97 138 this._assertIsItem(item); 98 return item; 99 }, 100 101 // find: function(/* object? */ keywordArgs) { 102 // /* find() is implemented in dojo.data.core.SimpleBaseStore */ 103 // }, 104 105 getFeatures: function() { 106 // summary: See dojo.data.core.Read.getFeatures() 107 return this._features; 108 }, 109 110 _findItems: function(/* object? */ keywordArgs, /* function */ findCallback, /* function */ errorCallback) { 139 return item; //object 140 }, 141 142 getFeatures: function(){ 143 // summary: 144 // See dojo.data.api.Read.getFeatures() 145 if (!this._loadFinished){ 146 // This has to happen to meet the property that the identity functions are 147 // denoted to work only if the store has been loaded and it had an identifier 148 // property in the JSON. So, for the feature to be found, the load had to have 149 // happened. 150 this._forceLoad(); 151 } 152 return this._features; //Object 153 }, 154 155 _fetchItems: function( /* Object */ keywordArgs, 156 /* Function */ findCallback, 157 /* Function */ errorCallback){ 158 // summary: 159 // See dojo.data.util.simpleFetch.fetch() 111 160 var self = this; 112 var filter = function(keywordArgs, arrayOfAllItems) { 113 if (keywordArgs.query) { 114 var items = []; 115 for (var i = 0; i < arrayOfAllItems.length; ++i) { 161 var filter = function(resultArgs, arrayOfAllItems){ 162 var items = null; 163 if(resultArgs.query) { 164 items = []; 165 for(var i = 0; i < arrayOfAllItems.length; ++i){ 116 166 var match = true; 117 167 var candidateItem = arrayOfAllItems[i]; 118 for (var key in keywordArgs.query) {119 var value = keywordArgs.query[key];120 if (!self.containsValue(candidateItem, key, value)) {168 for(var key in resultArgs.query) { 169 var value = resultArgs.query[key]; 170 if (!self.containsValue(candidateItem, key, value)){ 121 171 match = false; 122 172 } 123 173 } 124 if (match){174 if(match){ 125 175 items.push(candidateItem); 126 176 } 127 177 } 128 keywordArgs.items = items; 129 findCallback(keywordArgs); 130 } else { 131 keywordArgs.items = self._arrayOfAllItems; 132 findCallback(keywordArgs); 178 findCallback(resultArgs, items); 179 }else{ 180 // We want a copy to pass back in case the parent wishes to sort the array. We shouldn't allow resort 181 // of the internal list so that multiple callers can get listsand sort without affecting each other. 182 if(self._arrayOfAllItems.length> 0){ 183 items = self._arrayOfAllItems.slice(0,self._arrayOfAllItems.length); 184 } 185 findCallback(resultArgs, items); 133 186 } 134 187 }; 135 var bindHandler = function(type, data, evt) { 136 if (type == "load") { 188 189 var bindHandler = function(type, data, evt){ 190 if(type == "load") { 137 191 self._loadFinished = true; 138 192 self._arrayOfAllItems = self._getItemsFromLoadedData(data); 139 193 filter(keywordArgs, self._arrayOfAllItems); 140 } else if(type == "error" || type == 'timeout'){194 }else if(type == "error" || type == 'timeout'){ 141 195 var errorObject = data; 142 196 errorCallback(errorObject); 143 197 } 144 198 }; 145 if (this._loadFinished) { 146 filter(keywordArgs, this._arrayOfAllItems) 147 } else { 148 if (this._jsonFileUrl) { 149 var bindArgs = { 199 200 if(this._loadFinished){ 201 filter(keywordArgs, this._arrayOfAllItems); 202 }else{ 203 if(this._jsonFileUrl){ 204 var bindArgs ={ 150 205 url: this._jsonFileUrl, // example: "muppets.json", 151 206 handle: bindHandler, 152 207 mimetype: "text/json" 153 208 }; 154 if (keywordArgs.sync) { 155 bindArgs.sync = keywordArgs.sync; 156 } 157 var bindRequest = dojo.io.bind(bindArgs); 158 keywordArgs.abort = bindRequest.abort; 159 } else if (this._jsonData) { 209 //FIXME: replace with new xhr when available. May require changes to the above as well. 210 //var bindRequest = dojo.io.bind(bindArgs); 211 //keywordArgs.abort = bindRequest.abort; 212 }else if(this._jsonData){ 160 213 this._loadFinished = true; 161 214 this._arrayOfAllItems = this._getItemsFromLoadedData(this._jsonData); 162 215 this._jsonData = null; 163 216 filter(keywordArgs, this._arrayOfAllItems); 164 } else { 165 // FIXME: error condition? 166 } 167 } 168 }, 169 170 _getItemsFromLoadedData: function(/* object */ dataObject) { 217 }else{ 218 throw new Error("dojo.data.JsonItemStore: No JSON source data was provided as either URL or a nested Javascript object."); 219 } 220 } 221 }, 222 223 close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ 224 // summary: 225 // See dojo.data.api.Read.close() 226 }, 227 228 _getItemsFromLoadedData: function(/* Object */ dataObject){ 229 // summary: 230 // Function to parse the loaded data into item format and build the internal items array. 231 // description: 232 // Function to parse the loaded data into item format and build the internal items array. 233 // 234 // dataObject: 235 // The JS data object containing the raw data to convery into item format. 236 // 237 // returns: array 238 // Array of items in store item format. 239 171 240 var arrayOfItems = dataObject.items; 172 241 var i; 242 var item; 243 var attrNames = {}; 244 173 245 // We need to do some transformations to convert the data structure 174 246 // that we read from the file into a format that will be convenient 175 247 // to work with in memory.. 176 248 177 249 // Step 1: We walk through all the attribute values of all the items, 178 250 // and replace single values with arrays. For example, we change this: 179 // { name:'Miss Piggy', pets:'Foo-Foo'}251 // { name:'Miss Piggy', pets:'Foo-Foo'} 180 252 // into this: 181 // { name:['Miss Piggy'], pets:['Foo-Foo']} 182 183 for (var i = 0; i < arrayOfItems.length; ++i) { 184 var item = arrayOfItems[i]; 185 for (var key in item) { 253 // { name:['Miss Piggy'], pets:['Foo-Foo']} 254 // Also store off the keys so we can validate our store reference and item 255 // id special properties for the O(1) isItem 256 for(i = 0; i < arrayOfItems.length; ++i){ 257 item = arrayOfItems[i]; 258 for(var key in item){ 186 259 var value = item[key]; 187 if (!dojo.lang.isArray(value)){260 if(!dojo.isArray(value)){ 188 261 item[key] = [value]; 189 262 } 190 } 191 } 192 263 attrNames[key]=key; 264 } 265 } 266 267 //Build unique keys for id and store ref. 268 //This should go really fast, it will generally 269 // never even run the loop.. 270 while(attrNames[this._storeRef]){ 271 this._storeRef += "_"; 272 } 273 while(attrNames[this._itemId]){ 274 this._itemId += "_"; 275 } 276 193 277 // Step 2: Some data files specify an optional 'identifier', which is 194 278 // the name of an attribute that holds the identity of each item. If … … 196 280 // hash table of items keyed by the identity of the items. 197 281 var identifier = dataObject.identifier; 198 if (identifier) { 199 this._features['dojo.data.core.Identity'] = identifier; 282 var arrayOfValues = null; 283 if(identifier){ 284 this._features['dojo.data.api.Identity'] = identifier; 200 285 this._itemsByIdentity = {}; 201 for (i = 0; i < arrayOfItems.length; ++i){286 for(var i = 0; i < arrayOfItems.length; ++i){ 202 287 item = arrayOfItems[i]; 203 288 arrayOfValues = item[identifier]; 204 289 identity = arrayOfValues[0]; 205 this._itemsByIdentity[identity] = item; 290 if(!this._itemsByIdentity[identity]){ 291 this._itemsByIdentity[identity] = item; 292 }else{ 293 if(this._jsonFileUrl){ 294 throw new Error("dojo.data.JsonItemStore: The json data as specified by: [" + this._jsonFileUrl + "] is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]"); 295 }else if(this._jsonData){ 296 throw new Error("dojo.data.JsonItemStore: The json data provided by the creation arguments is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]"); 297 } 298 } 299 206 300 } 207 301 } … … 209 303 // Step 3: We walk through all the attribute values of all the items, 210 304 // and replace references with pointers to items. For example, we change: 211 //{ name:['Kermit'], friends:[{reference:{name:'Miss Piggy'}}] }305 // { name:['Kermit'], friends:[{reference:{name:'Miss Piggy'}}] } 212 306 // into this: 213 //{ name:['Kermit'], friends:[miss_piggy] }307 // { name:['Kermit'], friends:[miss_piggy] } 214 308 // (where miss_piggy is the object representing the 'Miss Piggy' item). 215 for (i = 0; i < arrayOfItems.length; ++i) { 216 item = arrayOfItems[i]; // example: { name:['Kermit'], friends:[{reference:{name:'Miss Piggy'}}] } 217 for (key in item) { 218 var arrayOfValues = item[key]; // example: [{reference:{name:'Miss Piggy'}}] 219 for (var j = 0; j < arrayOfItems.length; ++j) { 309 // Also generate the associate map for all items for the O(1) isItem function. 310 for(i = 0; i < arrayOfItems.length; ++i){ 311 item = arrayOfItems[i]; // example: { name:['Kermit'], friends:[{reference:{name:'Miss Piggy'}}] } 312 item[this._storeRef] = this; 313 item[this._itemId] = i; 314 this._itemMap[i] = item; 315 this._itemMap.lastItem = i; 316 for(key in item){ 317 arrayOfValues = item[key]; // example: [{reference:{name:'Miss Piggy'}}] 318 for(var j = 0; j < arrayOfItems.length; ++j) { 220 319 value = arrayOfValues[j]; // example: {reference:{name:'Miss Piggy'}} 221 if (typeof value == "object" && value.reference){320 if(typeof value == "object" && value.reference){ 222 321 var referenceDescription = value.reference; // example: {name:'Miss Piggy'} 223 if (dojo.lang.isString(referenceDescription)){322 if(dojo.isString(referenceDescription)){ 224 323 // example: 'Miss Piggy' 225 324 // from an item like: { name:['Kermit'], friends:[{reference:'Miss Piggy'}]} 226 325 arrayOfValues[j] = this._itemsByIdentity[referenceDescription]; 227 } else{326 }else{ 228 327 // example: {name:'Miss Piggy'} 229 328 // from an item like: { name:['Kermit'], friends:[{reference:{name:'Miss Piggy'}}] } 230 for (var k = 0; k < arrayOfItems.length; ++k){329 for(var k = 0; k < arrayOfItems.length; ++k){ 231 330 var candidateItem = arrayOfItems[k]; 232 331 var found = true; 233 for (var refKey in referenceDescription){234 if (candidateItem[refKey] != referenceDescription[refKey]){332 for(var refKey in referenceDescription){ 333 if(candidateItem[refKey] != referenceDescription[refKey]){ 235 334 found = false; 236 335 } 237 336 } 238 if (found){337 if(found){ 239 338 arrayOfValues[j] = candidateItem; 240 339 } … … 245 344 } 246 345 } 247 248 return arrayOfItems;249 }, 250 251 getIdentity: function(/* item */ item) {252 // summary: See dojo.data.core.Identity.getIdentity()253 var identifier = this._features['dojo.data. core.Identity'];346 return arrayOfItems; //Array 347 }, 348 349 getIdentity: function(/* item */ item){ 350 // summary: 351 // See dojo.data.api.Identity.getIdentity() 352 var identifier = this._features['dojo.data.api.Identity']; 254 353 var arrayOfValues = item[identifier];