1 | define(["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojox/rpc/Rest", |
---|
2 | "dojox/rpc/JsonRest", "dojox/json/schema", "dojox/data/ServiceStore"], |
---|
3 | function(lang, declare, connect, rpcRest, rpcJsonRest, jsonSchema, ServiceStore) { |
---|
4 | |
---|
5 | var rpc = lang.getObject("dojox.rpc", true); |
---|
6 | |
---|
7 | var JsonRestStore = declare("dojox.data.JsonRestStore", ServiceStore, |
---|
8 | { |
---|
9 | constructor: function(options){ |
---|
10 | // summary: |
---|
11 | // JsonRestStore is a Dojo Data store interface to JSON HTTP/REST web |
---|
12 | // storage services that support read and write through GET, PUT, POST, and DELETE. |
---|
13 | // options: |
---|
14 | // Keyword arguments |
---|
15 | // |
---|
16 | // ####The *schema* parameter |
---|
17 | // |
---|
18 | // This is a schema object for this store. This should be JSON Schema format. |
---|
19 | // |
---|
20 | // ####The *service* parameter |
---|
21 | // |
---|
22 | // This is the service object that is used to retrieve lazy data and save results |
---|
23 | // The function should be directly callable with a single parameter of an object id to be loaded |
---|
24 | // The function should also have the following methods: |
---|
25 | // |
---|
26 | // - put(id,value) - puts the value at the given id |
---|
27 | // - post(id,value) - posts (appends) the value at the given id |
---|
28 | // - delete(id) - deletes the value corresponding to the given id |
---|
29 | // |
---|
30 | // Note that it is critical that the service parses responses as JSON. |
---|
31 | // If you are using dojox.rpc.Service, the easiest way to make sure this |
---|
32 | // happens is to make the responses have a content type of |
---|
33 | // application/json. If you are creating your own service, make sure you |
---|
34 | // use handleAs: "json" with your XHR requests. |
---|
35 | // |
---|
36 | // ####The *target* parameter |
---|
37 | // |
---|
38 | // This is the target URL for this Service store. This may be used in place |
---|
39 | // of a service parameter to connect directly to RESTful URL without |
---|
40 | // using a dojox.rpc.Service object. |
---|
41 | // |
---|
42 | // ####The *idAttribute* parameter |
---|
43 | // |
---|
44 | // Defaults to 'id'. The name of the attribute that holds an objects id. |
---|
45 | // This can be a preexisting id provided by the server. |
---|
46 | // If an ID isn't already provided when an object |
---|
47 | // is fetched or added to the store, the autoIdentity system |
---|
48 | // will generate an id for it and add it to the index. |
---|
49 | // |
---|
50 | // ####The *syncMode* parameter |
---|
51 | // |
---|
52 | // Setting this to true will set the store to using synchronous calls by default. |
---|
53 | // Sync calls return their data immediately from the calling function, so |
---|
54 | // callbacks are unnecessary |
---|
55 | // description: |
---|
56 | // The JsonRestStore will cause all saved modifications to be sent to the server using Rest commands (PUT, POST, or DELETE). |
---|
57 | // When using a Rest store on a public network, it is important to implement proper security measures to |
---|
58 | // control access to resources. |
---|
59 | // |
---|
60 | // On the server side implementing a REST interface means providing GET, PUT, POST, and DELETE handlers. |
---|
61 | // |
---|
62 | // - GET - Retrieve an object or array/result set, this can be by id (like /table/1) or with a |
---|
63 | // query (like /table/?name=foo). |
---|
64 | // - PUT - This should modify a object, the URL will correspond to the id (like /table/1), and the body will |
---|
65 | // provide the modified object |
---|
66 | // - POST - This should create a new object. The URL will correspond to the target store (like /table/) |
---|
67 | // and the body should be the properties of the new object. The server's response should include a |
---|
68 | // Location header that indicates the id of the newly created object. This id will be used for subsequent |
---|
69 | // PUT and DELETE requests. JsonRestStore also includes a Content-Location header that indicates |
---|
70 | // the temporary randomly generated id used by client, and this location is used for subsequent |
---|
71 | // PUT/DELETEs if no Location header is provided by the server or if a modification is sent prior |
---|
72 | // to receiving a response from the server. |
---|
73 | // - DELETE - This should delete an object by id. |
---|
74 | // |
---|
75 | // These articles include more detailed information on using the JsonRestStore: |
---|
76 | // |
---|
77 | // - http://www.sitepen.com/blog/2008/06/13/restful-json-dojo-data/ |
---|
78 | // - http://blog.medryx.org/2008/07/24/jsonreststore-overview/ |
---|
79 | // example: |
---|
80 | // A JsonRestStore takes a REST service or a URL and uses it the remote communication for a |
---|
81 | // read/write dojo.data implementation. A JsonRestStore can be created with a simple URL like: |
---|
82 | // | new JsonRestStore({target:"/MyData/"}); |
---|
83 | // example: |
---|
84 | // To use a JsonRestStore with a service, you should create a |
---|
85 | // service with a REST transport. This can be configured with an SMD: |
---|
86 | // | { |
---|
87 | // | services: { |
---|
88 | // | jsonRestStore: { |
---|
89 | // | transport: "REST", |
---|
90 | // | envelope: "URL", |
---|
91 | // | target: "store.php", |
---|
92 | // | contentType:"application/json", |
---|
93 | // | parameters: [ |
---|
94 | // | {name: "location", type: "string", optional: true} |
---|
95 | // | ] |
---|
96 | // | } |
---|
97 | // | } |
---|
98 | // | } |
---|
99 | // The SMD can then be used to create service, and the service can be passed to a JsonRestStore. For example: |
---|
100 | // | var myServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd")); |
---|
101 | // | var jsonStore = new dojox.data.JsonRestStore({service:myServices.jsonRestStore}); |
---|
102 | // example: |
---|
103 | // The JsonRestStore also supports lazy loading. References can be made to objects that have not been loaded. |
---|
104 | // For example if a service returned: |
---|
105 | // | {"name":"Example","lazyLoadedObject":{"$ref":"obj2"}} |
---|
106 | // And this object has accessed using the dojo.data API: |
---|
107 | // | var obj = jsonStore.getValue(myObject,"lazyLoadedObject"); |
---|
108 | // The object would automatically be requested from the server (with an object id of "obj2"). |
---|
109 | |
---|
110 | connect.connect(rpcRest._index,"onUpdate",this,function(obj,attrName,oldValue,newValue){ |
---|
111 | var prefix = this.service.servicePath; |
---|
112 | if(!obj.__id){ |
---|
113 | console.log("no id on updated object ", obj); |
---|
114 | }else if(obj.__id.substring(0,prefix.length) == prefix){ |
---|
115 | this.onSet(obj,attrName,oldValue,newValue); |
---|
116 | } |
---|
117 | }); |
---|
118 | this.idAttribute = this.idAttribute || 'id';// no options about it, we have to have identity |
---|
119 | |
---|
120 | if(typeof options.target == 'string'){ |
---|
121 | options.target = options.target.match(/\/$/) || this.allowNoTrailingSlash ? options.target : (options.target + '/'); |
---|
122 | if(!this.service){ |
---|
123 | this.service = rpcJsonRest.services[options.target] || |
---|
124 | rpcRest(options.target, true); |
---|
125 | // create a default Rest service |
---|
126 | } |
---|
127 | } |
---|
128 | |
---|
129 | rpcJsonRest.registerService(this.service, options.target, this.schema); |
---|
130 | this.schema = this.service._schema = this.schema || this.service._schema || {}; |
---|
131 | // wrap the service with so it goes through JsonRest manager |
---|
132 | this.service._store = this; |
---|
133 | this.service.idAsRef = this.idAsRef; |
---|
134 | this.schema._idAttr = this.idAttribute; |
---|
135 | var constructor = rpcJsonRest.getConstructor(this.service); |
---|
136 | var self = this; |
---|
137 | this._constructor = function(data){ |
---|
138 | constructor.call(this, data); |
---|
139 | self.onNew(this); |
---|
140 | } |
---|
141 | this._constructor.prototype = constructor.prototype; |
---|
142 | this._index = rpcRest._index; |
---|
143 | }, |
---|
144 | |
---|
145 | // loadReferencedSchema: Boolean |
---|
146 | // Will load any schemas referenced content-type header or in Link headers |
---|
147 | loadReferencedSchema: true, |
---|
148 | |
---|
149 | // idAsRef: Boolean |
---|
150 | // Treat objects in queries as partially loaded objects |
---|
151 | idAsRef: false, |
---|
152 | |
---|
153 | referenceIntegrity: true, |
---|
154 | target:"", |
---|
155 | |
---|
156 | // allowNoTrailingSlash: Boolean |
---|
157 | // Allow no trailing slash on target paths. This is generally discouraged since |
---|
158 | // it creates prevents simple scalar values from being used a relative URLs. |
---|
159 | // Disabled by default. |
---|
160 | allowNoTrailingSlash: false, |
---|
161 | |
---|
162 | //Write API Support |
---|
163 | newItem: function(data, parentInfo){ |
---|
164 | // summary: |
---|
165 | // adds a new item to the store at the specified point. |
---|
166 | // Takes two parameters, data, and options. |
---|
167 | // data: Object |
---|
168 | // The data to be added in as an item. |
---|
169 | data = new this._constructor(data); |
---|
170 | if(parentInfo){ |
---|
171 | // get the previous value or any empty array |
---|
172 | var values = this.getValue(parentInfo.parent,parentInfo.attribute,[]); |
---|
173 | // set the new value |
---|
174 | values = values.concat([data]); |
---|
175 | data.__parent = values; |
---|
176 | this.setValue(parentInfo.parent, parentInfo.attribute, values); |
---|
177 | } |
---|
178 | return data; |
---|
179 | }, |
---|
180 | deleteItem: function(item){ |
---|
181 | // summary: |
---|
182 | // deletes item and any references to that item from the store. |
---|
183 | // item: |
---|
184 | // item to delete |
---|
185 | |
---|
186 | // If the desire is to delete only one reference, unsetAttribute or |
---|
187 | // setValue is the way to go. |
---|
188 | var checked = []; |
---|
189 | var store = dataExtCfg._getStoreForItem(item) || this; |
---|
190 | if(this.referenceIntegrity){ |
---|
191 | // cleanup all references |
---|
192 | rpcJsonRest._saveNotNeeded = true; |
---|
193 | var index = rpcRest._index; |
---|
194 | var fixReferences = function(parent){ |
---|
195 | var toSplice; |
---|
196 | // keep track of the checked ones |
---|
197 | checked.push(parent); |
---|
198 | // mark it checked so we don't run into circular loops when encountering cycles |
---|
199 | parent.__checked = 1; |
---|
200 | for(var i in parent){ |
---|
201 | if(i.substring(0,2) != "__"){ |
---|
202 | var value = parent[i]; |
---|
203 | if(value == item){ |
---|
204 | if(parent != index){ // make sure we are just operating on real objects |
---|
205 | if(parent instanceof Array){ |
---|
206 | // mark it as needing to be spliced, don't do it now or it will mess up the index into the array |
---|
207 | (toSplice = toSplice || []).push(i); |
---|
208 | }else{ |
---|
209 | // property, just delete it. |
---|
210 | (dataExtCfg._getStoreForItem(parent) || store).unsetAttribute(parent, i); |
---|
211 | } |
---|
212 | } |
---|
213 | }else{ |
---|
214 | if((typeof value == 'object') && value){ |
---|
215 | if(!value.__checked){ |
---|
216 | // recursively search |
---|
217 | fixReferences(value); |
---|
218 | } |
---|
219 | if(typeof value.__checked == 'object' && parent != index){ |
---|
220 | // if it is a modified array, we will replace it |
---|
221 | (dataExtCfg._getStoreForItem(parent) || store).setValue(parent, i, value.__checked); |
---|
222 | } |
---|
223 | } |
---|
224 | } |
---|
225 | } |
---|
226 | } |
---|
227 | if(toSplice){ |
---|
228 | // we need to splice the deleted item out of these arrays |
---|
229 | i = toSplice.length; |
---|
230 | parent = parent.__checked = parent.concat(); // indicates that the array is modified |
---|
231 | while(i--){ |
---|
232 | parent.splice(toSplice[i], 1); |
---|
233 | } |
---|
234 | return parent; |
---|
235 | } |
---|
236 | return null; |
---|
237 | }; |
---|
238 | // start with the index |
---|
239 | fixReferences(index); |
---|
240 | rpcJsonRest._saveNotNeeded = false; |
---|
241 | var i = 0; |
---|
242 | while(checked[i]){ |
---|
243 | // remove the checked marker |
---|
244 | delete checked[i++].__checked; |
---|
245 | } |
---|
246 | } |
---|
247 | rpcJsonRest.deleteObject(item); |
---|
248 | |
---|
249 | store.onDelete(item); |
---|
250 | }, |
---|
251 | changing: function(item,_deleting){ |
---|
252 | // summary: |
---|
253 | // adds an item to the list of dirty items. This item |
---|
254 | // contains a reference to the item itself as well as a |
---|
255 | // cloned and trimmed version of old item for use with |
---|
256 | // revert. |
---|
257 | rpcJsonRest.changing(item,_deleting); |
---|
258 | }, |
---|
259 | cancelChanging : function(object){ |
---|
260 | // summary: |
---|
261 | // Removes an object from the list of dirty objects |
---|
262 | // This will prevent that object from being saved to the server on the next save |
---|
263 | // object: |
---|
264 | // The item to cancel changes on |
---|
265 | if(!object.__id){ |
---|
266 | return; |
---|
267 | } |
---|
268 | dirtyObjects = dirty=rpcJsonRest.getDirtyObjects(); |
---|
269 | for(var i=0; i<dirtyObjects.length; i++){ |
---|
270 | var dirty = dirtyObjects[i]; |
---|
271 | if(object==dirty.object){ |
---|
272 | dirtyObjects.splice(i, 1); |
---|
273 | return; |
---|
274 | } |
---|
275 | } |
---|
276 | |
---|
277 | }, |
---|
278 | |
---|
279 | setValue: function(item, attribute, value){ |
---|
280 | // summary: |
---|
281 | // sets 'attribute' on 'item' to 'value' |
---|
282 | |
---|
283 | var old = item[attribute]; |
---|
284 | var store = item.__id ? dataExtCfg._getStoreForItem(item) : this; |
---|
285 | if(jsonSchema && store.schema && store.schema.properties){ |
---|
286 | // if we have a schema and schema validator available we will validate the property change |
---|
287 | jsonSchema.mustBeValid(jsonSchema.checkPropertyChange(value,store.schema.properties[attribute])); |
---|
288 | } |
---|
289 | if(attribute == store.idAttribute){ |
---|
290 | throw new Error("Can not change the identity attribute for an item"); |
---|
291 | } |
---|
292 | store.changing(item); |
---|
293 | item[attribute]=value; |
---|
294 | if(value && !value.__parent){ |
---|
295 | value.__parent = item; |
---|
296 | } |
---|
297 | store.onSet(item,attribute,old,value); |
---|
298 | }, |
---|
299 | setValues: function(item, attribute, values){ |
---|
300 | // summary: |
---|
301 | // sets 'attribute' on 'item' to 'value' value |
---|
302 | // must be an array. |
---|
303 | |
---|
304 | |
---|
305 | if(!lang.isArray(values)){ |
---|
306 | throw new Error("setValues expects to be passed an Array object as its value"); |
---|
307 | } |
---|
308 | this.setValue(item,attribute,values); |
---|
309 | }, |
---|
310 | |
---|
311 | unsetAttribute: function(item, attribute){ |
---|
312 | // summary: |
---|
313 | // unsets 'attribute' on 'item' |
---|
314 | |
---|
315 | this.changing(item); |
---|
316 | var old = item[attribute]; |
---|
317 | delete item[attribute]; |
---|
318 | this.onSet(item,attribute,old,undefined); |
---|
319 | }, |
---|
320 | save: function(kwArgs){ |
---|
321 | // summary: |
---|
322 | // Saves the dirty data using REST Ajax methods. See dojo/data/api/Write for API. |
---|
323 | // kwArgs: |
---|
324 | // - global: |
---|
325 | // This will cause the save to commit the dirty data for all |
---|
326 | // JsonRestStores as a single transaction. |
---|
327 | // - revertOnError: |
---|
328 | // This will cause the changes to be reverted if there is an |
---|
329 | // error on the save. By default a revert is executed unless |
---|
330 | // a value of false is provide for this parameter. |
---|
331 | // - incrementalUpdates: |
---|
332 | // For items that have been updated, if this is enabled, the server will be sent a POST request |
---|
333 | // with a JSON object containing the changed properties. By default this is |
---|
334 | // not enabled, and a PUT is used to deliver an update, and will include a full |
---|
335 | // serialization of all the properties of the item/object. |
---|
336 | // If this is true, the POST request body will consist of a JSON object with |
---|
337 | // only the changed properties. The incrementalUpdates parameter may also |
---|
338 | // be a function, in which case it will be called with the updated and previous objects |
---|
339 | // and an object update representation can be returned. |
---|
340 | // - alwaysPostNewItems: |
---|
341 | // If this is true, new items will always be sent with a POST request. By default |
---|
342 | // this is not enabled, and the JsonRestStore will send a POST request if |
---|
343 | // the item does not include its identifier (expecting server assigned location/ |
---|
344 | // identifier), and will send a PUT request if the item does include its identifier |
---|
345 | // (the PUT will be sent to the URI corresponding to the provided identifier). |
---|
346 | |
---|
347 | if(!(kwArgs && kwArgs.global)){ |
---|
348 | (kwArgs = kwArgs || {}).service = this.service; |
---|
349 | } |
---|
350 | if("syncMode" in kwArgs ? kwArgs.syncMode : this.syncMode){ |
---|
351 | rpc._sync = true; |
---|
352 | } |
---|
353 | |
---|
354 | var actions = rpcJsonRest.commit(kwArgs); |
---|
355 | this.serverVersion = this._updates && this._updates.length; |
---|
356 | return actions; |
---|
357 | }, |
---|
358 | |
---|
359 | revert: function(kwArgs){ |
---|
360 | // summary: |
---|
361 | // returns any modified data to its original state prior to a save(); |
---|
362 | // kwArgs: |
---|
363 | // - global: |
---|
364 | // This will cause the revert to undo all the changes for all |
---|
365 | // JsonRestStores in a single operation. |
---|
366 | rpcJsonRest.revert(!(kwArgs && kwArgs.global) && this.service); |
---|
367 | }, |
---|
368 | |
---|
369 | isDirty: function(item){ |
---|
370 | // summary: |
---|
371 | // returns true if the item is marked as dirty. |
---|
372 | return rpcJsonRest.isDirty(item, this); |
---|
373 | }, |
---|
374 | isItem: function(item, anyStore){ |
---|
375 | // summary: |
---|
376 | // Checks to see if a passed 'item' |
---|
377 | // really belongs to this JsonRestStore. |
---|
378 | // item: Object |
---|
379 | // The value to test for being an item |
---|
380 | // anyStore: Boolean |
---|
381 | // If true, this will return true if the value is an item for any JsonRestStore, |
---|
382 | // not just this instance |
---|
383 | return item && item.__id && (anyStore || this.service == rpcJsonRest.getServiceAndId(item.__id).service); |
---|
384 | }, |
---|
385 | _doQuery: function(args){ |
---|
386 | var query= typeof args.queryStr == 'string' ? args.queryStr : args.query; |
---|
387 | var deferred = rpcJsonRest.query(this.service,query, args); |
---|
388 | var self = this; |
---|
389 | if(this.loadReferencedSchema){ |
---|
390 | deferred.addCallback(function(result){ |
---|
391 | var contentType = deferred.ioArgs && deferred.ioArgs.xhr && deferred.ioArgs.xhr.getResponseHeader("Content-Type"); |
---|
392 | var schemaRef = contentType && contentType.match(/definedby\s*=\s*([^;]*)/); |
---|
393 | if(contentType && !schemaRef){ |
---|
394 | schemaRef = deferred.ioArgs.xhr.getResponseHeader("Link"); |
---|
395 | schemaRef = schemaRef && schemaRef.match(/<([^>]*)>;\s*rel="?definedby"?/); |
---|
396 | } |
---|
397 | schemaRef = schemaRef && schemaRef[1]; |
---|
398 | if(schemaRef){ |
---|
399 | var serviceAndId = rpcJsonRest.getServiceAndId((self.target + schemaRef).replace(/^(.*\/)?(\w+:\/\/)|[^\/\.]+\/\.\.\/|^.*\/(\/)/,"$2$3")); |
---|
400 | var schemaDeferred = rpcJsonRest.byId(serviceAndId.service, serviceAndId.id); |
---|
401 | schemaDeferred.addCallbacks(function(newSchema){ |
---|
402 | lang.mixin(self.schema, newSchema); |
---|
403 | return result; |
---|
404 | }, function(error){ |
---|
405 | console.error(error); // log it, but don't let it cause the main request to fail |
---|
406 | return result; |
---|
407 | }); |
---|
408 | return schemaDeferred; |
---|
409 | } |
---|
410 | return undefined;//don't change anything, and deal with the stupid post-commit lint complaints |
---|
411 | }); |
---|
412 | } |
---|
413 | return deferred; |
---|
414 | }, |
---|
415 | _processResults: function(results, deferred){ |
---|
416 | // index the results |
---|
417 | var count = results.length; |
---|
418 | // if we don't know the length, and it is partial result, we will guess that it is twice as big, that will work for most widgets |
---|
419 | return {totalCount:deferred.fullLength || (deferred.request.count == count ? (deferred.request.start || 0) + count * 2 : count), items: results}; |
---|
420 | }, |
---|
421 | |
---|
422 | getConstructor: function(){ |
---|
423 | // summary: |
---|
424 | // Gets the constructor for objects from this store |
---|
425 | return this._constructor; |
---|
426 | }, |
---|
427 | getIdentity: function(item){ |
---|
428 | var id = item.__clientId || item.__id; |
---|
429 | if(!id){ |
---|
430 | return id; |
---|
431 | } |
---|
432 | var prefix = this.service.servicePath.replace(/[^\/]*$/,''); |
---|
433 | // support for relative or absolute referencing with ids |
---|
434 | return id.substring(0,prefix.length) != prefix ? id : id.substring(prefix.length); // String |
---|
435 | }, |
---|
436 | fetchItemByIdentity: function(args){ |
---|
437 | var id = args.identity; |
---|
438 | var store = this; |
---|
439 | // if it is an absolute id, we want to find the right store to query |
---|
440 | if(id.toString().match(/^(\w*:)?\//)){ |
---|
441 | var serviceAndId = rpcJsonRest.getServiceAndId(id); |
---|
442 | store = serviceAndId.service._store; |
---|
443 | args.identity = serviceAndId.id; |
---|
444 | } |
---|
445 | args._prefix = store.service.servicePath.replace(/[^\/]*$/,''); |
---|
446 | return store.inherited(arguments); |
---|
447 | }, |
---|
448 | //Notifcation Support |
---|
449 | |
---|
450 | onSet: function(){}, |
---|
451 | onNew: function(){}, |
---|
452 | onDelete: function(){}, |
---|
453 | |
---|
454 | getFeatures: function(){ |
---|
455 | // summary: |
---|
456 | // return the store feature set |
---|
457 | var features = this.inherited(arguments); |
---|
458 | features["dojo.data.api.Write"] = true; |
---|
459 | features["dojo.data.api.Notification"] = true; |
---|
460 | return features; |
---|
461 | }, |
---|
462 | |
---|
463 | getParent: function(item){ |
---|
464 | // summary: |
---|
465 | // Returns the parent item (or query) for the given item |
---|
466 | // item: |
---|
467 | // The item to find the parent of |
---|
468 | |
---|
469 | return item && item.__parent; |
---|
470 | } |
---|
471 | |
---|
472 | |
---|
473 | } |
---|
474 | ); |
---|
475 | JsonRestStore.getStore = function(options, Class){ |
---|
476 | // summary: |
---|
477 | // Will retrieve or create a store using the given options (the same options |
---|
478 | // that are passed to JsonRestStore constructor. Returns a JsonRestStore instance |
---|
479 | // options: |
---|
480 | // See the JsonRestStore constructor |
---|
481 | // Class: |
---|
482 | // Constructor to use (for creating stores from JsonRestStore subclasses). |
---|
483 | // This is optional and defaults to JsonRestStore. |
---|
484 | if(typeof options.target == 'string'){ |
---|
485 | options.target = options.target.match(/\/$/) || options.allowNoTrailingSlash ? |
---|
486 | options.target : (options.target + '/'); |
---|
487 | var store = (rpcJsonRest.services[options.target] || {})._store; |
---|
488 | if(store){ |
---|
489 | return store; |
---|
490 | } |
---|
491 | } |
---|
492 | return new (Class || JsonRestStore)(options); |
---|
493 | }; |
---|
494 | |
---|
495 | var dataExtCfg = lang.getObject("dojox.data",true); |
---|
496 | dataExtCfg._getStoreForItem = function(item){ |
---|
497 | if(item.__id){ |
---|
498 | var serviceAndId = rpcJsonRest.getServiceAndId(item.__id); |
---|
499 | if(serviceAndId && serviceAndId.service._store){ |
---|
500 | return serviceAndId.service._store; |
---|
501 | }else{ |
---|
502 | var servicePath = item.__id.toString().match(/.*\//)[0]; |
---|
503 | return new JsonRestStore({target:servicePath}); |
---|
504 | } |
---|
505 | } |
---|
506 | return null; |
---|
507 | }; |
---|
508 | var jsonRefConfig = lang.getObject("dojox.json.ref", true); |
---|
509 | jsonRefConfig._useRefs = true; // Use referencing when identifiable objects are referenced |
---|
510 | |
---|
511 | return JsonRestStore; |
---|
512 | }); |
---|