summaryrefslogtreecommitdiff
path: root/js/dojo-1.6/dojox/data/ServiceStore.xd.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo-1.6/dojox/data/ServiceStore.xd.js')
-rw-r--r--js/dojo-1.6/dojox/data/ServiceStore.xd.js416
1 files changed, 416 insertions, 0 deletions
diff --git a/js/dojo-1.6/dojox/data/ServiceStore.xd.js b/js/dojo-1.6/dojox/data/ServiceStore.xd.js
new file mode 100644
index 0000000..a8118d0
--- /dev/null
+++ b/js/dojo-1.6/dojox/data/ServiceStore.xd.js
@@ -0,0 +1,416 @@
+/*
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.data.ServiceStore"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.data.ServiceStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.data.ServiceStore"] = true;
+dojo.provide("dojox.data.ServiceStore");
+
+
+
+// note that dojox.rpc.Service is not required, you can create your own services
+
+// A ServiceStore is a readonly data store that provides a data.data interface to an RPC service.
+// var myServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd"));
+// var serviceStore = new dojox.data.ServiceStore({service:myServices.ServiceStore});
+//
+// The ServiceStore also supports lazy loading. References can be made to objects that have not been loaded.
+// For example if a service returned:
+// {"name":"Example","lazyLoadedObject":{"$ref":"obj2"}}
+//
+// And this object has accessed using the dojo.data API:
+// var obj = serviceStore.getValue(myObject,"lazyLoadedObject");
+// The object would automatically be requested from the server (with an object id of "obj2").
+//
+
+dojo.declare("dojox.data.ServiceStore",
+ // ClientFilter is intentionally not required, ServiceStore does not need it, and is more
+ // lightweight without it, but if it is provided, the ServiceStore will use it.
+ dojox.data.ClientFilter||null,{
+ service: null,
+ constructor: function(options){
+ //summary:
+ // ServiceStore constructor, instantiate a new ServiceStore
+ // A ServiceStore can be configured from a JSON Schema. Queries are just
+ // passed through to the underlying services
+ //
+ // options:
+ // Keyword arguments
+ // The *schema* parameter
+ // This is a schema object for this store. This should be JSON Schema format.
+ //
+ // The *service* parameter
+ // This is the service object that is used to retrieve lazy data and save results
+ // The function should be directly callable with a single parameter of an object id to be loaded
+ //
+ // The *idAttribute* parameter
+ // 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.
+ //
+ // The *estimateCountFactor* parameter
+ // This parameter is used by the ServiceStore to estimate the total count. When
+ // paging is indicated in a fetch and the response includes the full number of items
+ // requested by the fetch's count parameter, then the total count will be estimated
+ // to be estimateCountFactor multiplied by the provided count. If this is 1, then it is assumed that the server
+ // does not support paging, and the response is the full set of items, where the
+ // total count is equal to the numer of items returned. If the server does support
+ // paging, an estimateCountFactor of 2 is a good value for estimating the total count
+ // It is also possible to override _processResults if the server can provide an exact
+ // total count.
+ //
+ // The *syncMode* parameter
+ // Setting this to true will set the store to using synchronous calls by default.
+ // Sync calls return their data immediately from the calling function, so
+ // callbacks are unnecessary. This will only work with a synchronous capable service.
+ //
+ // description:
+ // ServiceStore can do client side caching and result set updating if
+ // dojox.data.ClientFilter is loaded. Do this add:
+ // | dojo.require("dojox.data.ClientFilter")
+ // prior to loading the ServiceStore (ClientFilter must be loaded before ServiceStore).
+ // To utilize client side filtering with a subclass, you can break queries into
+ // client side and server side components by putting client side actions in
+ // clientFilter property in fetch calls. For example you could override fetch:
+ // | fetch: function(args){
+ // | // do the sorting and paging on the client side
+ // | args.clientFilter = {start:args.start, count: args.count, sort: args.sort};
+ // | // args.query will be passed to the service object for the server side handling
+ // | return this.inherited(arguments);
+ // | }
+ // When extending this class, if you would like to create lazy objects, you can follow
+ // the example from dojox.data.tests.stores.ServiceStore:
+ // | var lazyItem = {
+ // | _loadObject: function(callback){
+ // | this.name="loaded";
+ // | delete this._loadObject;
+ // | callback(this);
+ // | }
+ // | };
+ //setup a byId alias to the api call
+ this.byId=this.fetchItemByIdentity;
+ this._index = {};
+ // if the advanced json parser is enabled, we can pass through object updates as onSet events
+ if(options){
+ dojo.mixin(this,options);
+ }
+ // We supply a default idAttribute for parser driven construction, but if no id attribute
+ // is supplied, it should be null so that auto identification takes place properly
+ this.idAttribute = (options && options.idAttribute) || (this.schema && this.schema._idAttr);
+ },
+ schema: null,
+ idAttribute: "id",
+ labelAttribute: "label",
+ syncMode: false,
+ estimateCountFactor: 1,
+ getSchema: function(){
+ return this.schema;
+ },
+
+ loadLazyValues:true,
+
+ getValue: function(/*Object*/ item, /*String*/property, /*value?*/defaultValue){
+ // summary:
+ // Gets the value of an item's 'property'
+ //
+ // item:
+ // The item to get the value from
+ // property:
+ // property to look up value for
+ // defaultValue:
+ // the default value
+
+ var value = item[property];
+ return value || // return the plain value since it was found;
+ (property in item ? // a truthy value was not found, see if we actually have it
+ value : // we do, so we can return it
+ item._loadObject ? // property was not found, maybe because the item is not loaded, we will try to load it synchronously so we can get the property
+ (dojox.rpc._sync = true) && arguments.callee.call(this,dojox.data.ServiceStore.prototype.loadItem({item:item}) || {}, property, defaultValue) : // load the item and run getValue again
+ defaultValue);// not in item -> return default value
+ },
+ 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
+
+ var val = this.getValue(item,property);
+ if(val instanceof Array){
+ return val;
+ }
+ if(!this.isItemLoaded(val)){
+ dojox.rpc._sync = true;
+ val = this.loadItem({item:val});
+ }
+ return val instanceof Array ? val : val === undefined ? [] : [val];
+ },
+
+ getAttributes: function(item){
+ // summary:
+ // Gets the available attributes of an item's 'property' and returns
+ // it as an array.
+ //
+ // item: /* object */
+
+ var res = [];
+ for(var i in item){
+ if(item.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_')){
+ res.push(i);
+ }
+ }
+ return res;
+ },
+
+ hasAttribute: function(item,attribute){
+ // summary:
+ // Checks to see if item has attribute
+ //
+ // item: /* object */
+ // attribute: /* string */
+ return attribute in item;
+ },
+
+ containsValue: function(item, attribute, value){
+ // summary:
+ // Checks to see if 'item' has 'value' at 'attribute'
+ //
+ // item: /* object */
+ // attribute: /* string */
+ // value: /* anything */
+ return dojo.indexOf(this.getValues(item,attribute),value) > -1;
+ },
+
+
+ isItem: function(item){
+ // summary:
+ // Checks to see if the argument is an item
+ //
+ // item: /* object */
+ // attribute: /* string */
+
+ // we have no way of determining if it belongs, we just have object returned from
+ // service queries
+ return (typeof item == 'object') && item && !(item instanceof Date);
+ },
+
+ isItemLoaded: function(item){
+ // summary:
+ // Checks to see if the item is loaded.
+ //
+ // item: /* object */
+
+ return item && !item._loadObject;
+ },
+
+ loadItem: function(args){
+ // summary:
+ // Loads an item and calls the callback handler. Note, that this will call the callback
+ // handler even if the item is loaded. Consequently, you can use loadItem to ensure
+ // that an item is loaded is situations when the item may or may not be loaded yet.
+ // If you access a value directly through property access, you can use this to load
+ // a lazy value as well (doesn't need to be an item).
+ //
+ // example:
+ // store.loadItem({
+ // item: item, // this item may or may not be loaded
+ // onItem: function(item){
+ // // do something with the item
+ // }
+ // });
+
+ var item;
+ if(args.item._loadObject){
+ args.item._loadObject(function(result){
+ item = result; // in synchronous mode this can allow loadItem to return the value
+ delete item._loadObject;
+ var func = result instanceof Error ? args.onError : args.onItem;
+ if(func){
+ func.call(args.scope, result);
+ }
+ });
+ }else if(args.onItem){
+ // even if it is already loaded, we will use call the callback, this makes it easier to
+ // use when it is not known if the item is loaded (you can always safely call loadItem).
+ args.onItem.call(args.scope, args.item);
+ }
+ return item;
+ },
+ _currentId : 0,
+ _processResults : function(results, deferred){
+ // this should return an object with the items as an array and the total count of
+ // items (maybe more than currently in the result set).
+ // for example:
+ // | {totalCount:10, items: [{id:1},{id:2}]}
+
+ // index the results, assigning ids as necessary
+
+ if(results && typeof results == 'object'){
+ var id = results.__id;
+ if(!id){// if it hasn't been assigned yet
+ if(this.idAttribute){
+ // use the defined id if available
+ id = results[this.idAttribute];
+ }else{
+ id = this._currentId++;
+ }
+ if(id !== undefined){
+ var existingObj = this._index[id];
+ if(existingObj){
+ for(var j in existingObj){
+ delete existingObj[j]; // clear it so we can mixin
+ }
+ results = dojo.mixin(existingObj,results);
+ }
+ results.__id = id;
+ this._index[id] = results;
+ }
+ }
+ for(var i in results){
+ results[i] = this._processResults(results[i], deferred).items;
+ }
+ var count = results.length;
+ }
+ return {totalCount: deferred.request.count == count ? (deferred.request.start || 0) + count * this.estimateCountFactor : count, items: results};
+ },
+ close: function(request){
+ return request && request.abort && request.abort();
+ },
+ fetch: function(args){
+ // summary:
+ // See dojo.data.api.Read.fetch
+ //
+ // The *queryOptions.cache* parameter
+ // If true, indicates that the query result should be cached for future use. This is only available
+ // if dojox.data.ClientFilter has been loaded before the ServiceStore
+ //
+ // The *syncMode* parameter
+ // Indicates that the call should be fetch synchronously if possible (this is not always possible)
+ //
+ // The *clientFetch* parameter
+ // This is a fetch keyword argument for explicitly doing client side filtering, querying, and paging
+
+ args = args || {};
+
+ if("syncMode" in args ? args.syncMode : this.syncMode){
+ dojox.rpc._sync = true;
+ }
+ var self = this;
+
+ var scope = args.scope || self;
+ var defResult = this.cachingFetch ? this.cachingFetch(args) : this._doQuery(args);
+ defResult.request = args;
+ defResult.addCallback(function(results){
+ if(args.clientFetch){
+ results = self.clientSideFetch({query:args.clientFetch,sort:args.sort,start:args.start,count:args.count},results);
+ }
+ var resultSet = self._processResults(results, defResult);
+ results = args.results = resultSet.items;
+ if(args.onBegin){
+ args.onBegin.call(scope, resultSet.totalCount, args);
+ }
+ if(args.onItem){
+ for(var i=0; i<results.length;i++){
+ args.onItem.call(scope, results[i], args);
+ }
+ }
+ if(args.onComplete){
+ args.onComplete.call(scope, args.onItem ? null : results, args);
+ }
+ return results;
+ });
+ defResult.addErrback(args.onError && function(err){
+ return args.onError.call(scope, err, args);
+ });
+ args.abort = function(){
+ // abort the request
+ defResult.cancel();
+ };
+ args.store = this;
+ return args;
+ },
+ _doQuery: function(args){
+ var query= typeof args.queryStr == 'string' ? args.queryStr : args.query;
+ return this.service(query);
+ },
+ getFeatures: function(){
+ // summary:
+ // return the store feature set
+
+ return {
+ "dojo.data.api.Read": true,
+ "dojo.data.api.Identity": true,
+ "dojo.data.api.Schema": this.schema
+ };
+ },
+
+ getLabel: function(item){
+ // summary
+ // returns the label for an item. Just gets the "label" attribute.
+ //
+ return this.getValue(item,this.labelAttribute);
+ },
+
+ getLabelAttributes: function(item){
+ // summary:
+ // returns an array of attributes that are used to create the label of an item
+ return [this.labelAttribute];
+ },
+
+ //Identity API Support
+
+
+ getIdentity: function(item){
+ return item.__id;
+ },
+
+ 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, by looking in our index of what we have loaded
+ var item = this._index[(args._prefix || '') + args.identity];
+ if(item){
+ // the item exists in the index
+ if(item._loadObject){
+ // we have a handle on the item, but it isn't loaded yet, so we need to load it
+ args.item = item;
+ return this.loadItem(args);
+ }else if(args.onItem){
+ // it's already loaded, so we can immediately callback
+ args.onItem.call(args.scope, item);
+ }
+ }else{
+ // convert the different spellings
+ return this.fetch({
+ query: args.identity,
+ onComplete: args.onItem,
+ onError: args.onError,
+ scope: args.scope
+ }).results;
+ }
+ return item;
+ }
+
+ }
+);
+
+}
+
+}};});