summaryrefslogtreecommitdiff
path: root/js/dojo/dojox/data/AppStore.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo/dojox/data/AppStore.js')
-rw-r--r--js/dojo/dojox/data/AppStore.js829
1 files changed, 829 insertions, 0 deletions
diff --git a/js/dojo/dojox/data/AppStore.js b/js/dojo/dojox/data/AppStore.js
new file mode 100644
index 0000000..b3c8a94
--- /dev/null
+++ b/js/dojo/dojox/data/AppStore.js
@@ -0,0 +1,829 @@
+//>>built
+define("dojox/data/AppStore", ["dojo", "dojox", "dojo/data/util/simpleFetch", "dojo/data/util/filter", "dojox/atom/io/Connection"], function(dojo, dojox) {
+
+dojo.experimental("dojox.data.AppStore");
+
+dojo.declare("dojox.data.AppStore",
+ null,{
+
+ // url: [public] string
+ // So the parser can instantiate the store via markup.
+ url: "",
+
+ // urlPreventCache: [public] boolean
+ // Whether or not to pass the preventCache parameter to the connection
+ urlPreventCache: false,
+
+ // xmethod: [public] boolean
+ // Whether to use X-Method-Override for PUT/DELETE.
+ xmethod: false,
+
+ _atomIO: null,
+ _feed: null,
+ _requests: null,
+ _processing: null,
+
+ _updates: null,
+ _adds: null,
+ _deletes: null,
+
+ constructor: function(/*Object*/args){
+ // summary:
+ // The APP data store.
+ // description:
+ // The APP Store is instantiated either in markup or programmatically by supplying a
+ // url of the Collection to be used.
+ //
+ // args:
+ // An anonymous object to initialize properties. It expects the following values:
+ // url: The url of the Collection to load.
+ // urlPreventCache: Whether or not to append on cache prevention params (as defined by dojo.xhr*)
+
+ if(args && args.url){
+ this.url = args.url;
+ }
+ if(args && args.urlPreventCache){
+ this.urlPreventCache = args.urlPreventCache;
+ }
+ if(!this.url){
+ throw new Error("A URL is required to instantiate an APP Store object");
+ }
+ },
+
+ _setFeed: function(feed, data){
+ // summary:
+ // Sets the internal feed using a dojox.atom.io.model.Feed object.
+ // description:
+ // Sets the internal feed using a dojox.atom.io.model.Feed object. Also adds
+ // a property to the entries to track that they belong to this store. It
+ // also parses stored requests (since we were waiting on a callback) and
+ // executes those as well.
+ //
+ // feed: dojox.atom.io.model.Feed object
+ // The Feed to use for this data store.
+ // data: unused
+ // Signature for this function is defined by AtomIO.getFeed, since this is a callback.
+ this._feed = feed;
+ var i;
+ for(i=0; i<this._feed.entries.length; i++){
+ this._feed.entries[i].store = this;
+ }
+ if(this._requests){
+ for(i=0; i<this._requests.length; i++){
+ var request = this._requests[i];
+ if(request.request && request.fh && request.eh){
+ this._finishFetchItems(request.request, request.fh, request.eh);
+ }else if(request.clear){
+ this._feed = null;
+ }else if(request.add){
+ this._feed.addEntry(request.add);
+ }else if(request.remove){
+ this._feed.removeEntry(request.remove);
+ }
+ }
+ }
+ this._requests = null;
+ },
+
+ _getAllItems: function(){
+ // summary:
+ // Function to return all entries in the Feed as an array of items.
+ // description:
+ // Function to return all entries in the Feed as an array of items.
+ //
+ // returns:
+ // Array of all entries in the feed.
+ var items = [];
+ for(var i=0; i<this._feed.entries.length; i++){
+ items.push(this._feed.entries[i]);
+ }
+ return items; //array
+ },
+
+ _assertIsItem: function(/* item */ item){
+ // summary:
+ // This function tests whether the item is an item.
+ // description:
+ // 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("This error message is provided when a function is called in the following form: "
+ + "getAttribute(argument, attributeName). The argument variable represents the member "
+ + "or owner of the object. The error is created when an item that does not belong "
+ + "to this store is specified as an argument.");
+ }
+ },
+
+ _assertIsAttribute: function(/* String */ attribute){
+ // summary:
+ // This function tests whether the item is an attribute.
+ // description:
+ // 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.
+ //
+ // returns:
+ // Returns a boolean indicating whether this is a valid attribute.
+ if(typeof attribute !== "string"){
+ throw new Error("The attribute argument must be a string. The error is created "
+ + "when a different type of variable is specified such as an array or object.");
+ }
+
+ for(var key in dojox.atom.io.model._actions){
+ if(key == attribute){
+ return true;
+ }
+ }
+ return false;
+ },
+
+ _addUpdate: function(/* Object */ update){
+ // summary:
+ // Internal function to add an updated entry to our updates array
+ // description:
+ // Internal function to add an updated entry to our updates array
+ //
+ // update: dojox.atom.io.model.Entry object
+ // The updated Entry we've changed.
+ if(!this._updates){
+ this._updates = [update];
+ }else{
+ this._updates.push(update);
+ }
+ },
+
+/***************************************
+ dojo.data.api.Read API
+***************************************/
+
+ 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; //Object || int || Boolean
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+
+ this._assertIsItem(item);
+ var flag = this._assertIsAttribute(attribute);
+
+ if(flag){
+ if((attribute === "author" || attribute === "contributor" || attribute === "link") && item[attribute+"s"]){
+ return item[attribute+"s"];
+ }
+ if(attribute === "category" && item.categories){
+ return item.categories;
+ }
+ if(item[attribute]){
+ item = item[attribute];
+ if(item.nodeType == "Content"){
+ return [item.value];
+ }
+ return [item] ;
+ }
+ }
+ return []; //Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ for(var key in dojox.atom.io.model._actions){
+ if(this.hasAttribute(item, key)){
+ 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,
+ /* Boolean?*/ trim){
+ // 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'
+ var values = this.getValues(item, attribute);
+ for(var i = 0; i < values.length; ++i){
+ var possibleValue = values[i];
+ if(typeof possibleValue === "string" && regexp){
+ if(trim){
+ possibleValue = possibleValue.replace(new RegExp(/^\s+/),""); // START
+ possibleValue = possibleValue.replace(new RegExp(/\s+$/),""); // END
+ }
+ possibleValue = possibleValue.replace(/\r|\n|\r\n/g, "");
+ return (possibleValue.match(regexp) !== null);
+ }else{
+ //Non-string matching.
+ if(value === possibleValue){
+ return true; // Boolean
+ }
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ return something && something.store && something.store === this; //boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(something);
+ },
+
+ loadItem: function(/* Object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ this._assertIsItem(keywordArgs.item);
+ },
+
+ _fetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Fetch items (Atom entries) that match to a query
+ // description:
+ // Fetch items (Atom entries) that match to a query
+ // request:
+ // A request object
+ // fetchHandler:
+ // A function to call for fetched items
+ // errorHandler:
+ // A function to call on error
+ if(this._feed){
+ this._finishFetchItems(request, fetchHandler, errorHandler);
+ }else{
+ var flag = false;
+ if(!this._requests){
+ this._requests = [];
+ flag = true;
+ }
+ this._requests.push({request: request, fh: fetchHandler, eh: errorHandler});
+ if(flag){
+ this._atomIO = new dojox.atom.io.Connection(false, this.urlPreventCache);
+ this._atomIO.getFeed(this.url,this._setFeed, null, this);
+ }
+ }
+ },
+
+ _finishFetchItems: function(request, fetchHandler, errorHandler){
+ // summary:
+ // Internal function for finishing a fetch request.
+ // description:
+ // Internal function for finishing a fetch request. Needed since the feed
+ // might not have been loaded, so we finish the fetch in a callback.
+ //
+ // request:
+ // A request object
+ // fetchHandler:
+ // A function to call for fetched items
+ // errorHandler:
+ // A function to call on error
+ var items = null;
+ var arrayOfAllItems = this._getAllItems();
+ if(request.query){
+ var ignoreCase = request.queryOptions ? request.queryOptions.ignoreCase : false;
+ items = [];
+
+ //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 = {};
+ var key;
+ var value;
+ for(key in request.query){
+ value = request.query[key]+'';
+ if(typeof value === "string"){
+ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+ }
+ }
+
+ for(var i = 0; i < arrayOfAllItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfAllItems[i];
+ for(key in request.query){
+ value = request.query[key]+'';
+ if(!this._containsValue(candidateItem, key, value, regexpList[key], request.trim)){
+ match = false;
+ }
+ }
+ if(match){
+ items.push(candidateItem);
+ }
+ }
+ }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 listsand sort without affecting each other.
+ if(arrayOfAllItems.length> 0){
+ items = arrayOfAllItems.slice(0,arrayOfAllItems.length);
+ }
+ }
+ try{
+ fetchHandler(items, request);
+ }catch(e){
+ errorHandler(e, request);
+ }
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Write': true,
+ 'dojo.data.api.Identity': true
+ };
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ // nothing to do here!
+ this._feed = null;
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if(this.isItem(item)){
+ return this.getValue(item, "title", "No Title");
+ }
+ return undefined;
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ return ["title"];
+ },
+
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ this._assertIsItem(item);
+ return this.getValue(item, "id");
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentityAttributes()
+ return ["id"];
+ },
+
+ fetchItemByIdentity: function(keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+
+ this._fetchItems({query:{id:keywordArgs.identity}, onItem: keywordArgs.onItem, scope: keywordArgs.scope},
+ function(items, request){
+ var scope = request.scope;
+ if(!scope){
+ scope = dojo.global;
+ }
+ if(items.length < 1){
+ request.onItem.call(scope, null);
+ }else{
+ request.onItem.call(scope, items[0]);
+ }
+ }, keywordArgs.onError);
+ },
+
+/***************************************
+ dojo.data.api.Identity API
+***************************************/
+
+ newItem: function(/* Object? */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Write.newItem()
+ var entry = new dojox.atom.io.model.Entry();
+ var value = null;
+ var temp = null;
+ var i;
+ for(var key in keywordArgs){
+ if(this._assertIsAttribute(key)){
+ value = keywordArgs[key];
+ switch(key){
+ case "link":
+ for(i in value){
+ temp = value[i];
+ entry.addLink(temp.href,temp.rel,temp.hrefLang,temp.title,temp.type);
+ }
+ break;
+ case "author":
+ for(i in value){
+ temp = value[i];
+ entry.addAuthor(temp.name, temp.email, temp.uri);
+ }
+ break;
+ case "contributor":
+ for(i in value){
+ temp = value[i];
+ entry.addContributor(temp.name, temp.email, temp.uri);
+ }
+ break;
+ case "category":
+ for(i in value){
+ temp = value[i];
+ entry.addCategory(temp.scheme, temp.term, temp.label);
+ }
+ break;
+ case "icon":
+ case "id":
+ case "logo":
+ case "xmlBase":
+ case "rights":
+ entry[key] = value;
+ break;
+ case "updated":
+ case "published":
+ case "issued":
+ case "modified":
+ entry[key] = dojox.atom.io.model.util.createDate(value);
+ break;
+ case "content":
+ case "summary":
+ case "title":
+ case "subtitle":
+ entry[key] = new dojox.atom.io.model.Content(key);
+ entry[key].value = value;
+ break;
+ default:
+ entry[key] = value;
+ break;
+ }
+ }
+ }
+ entry.store = this;
+ entry.isDirty = true;
+
+ if(!this._adds){
+ this._adds = [entry];
+ }else{
+ this._adds.push(entry);
+ }
+
+ if(this._feed){
+ this._feed.addEntry(entry);
+ }else{
+ if(this._requests){
+ this._requests.push({add:entry});
+ }else{
+ this._requests = [{add:entry}];
+ this._atomIO = new dojox.atom.io.Connection(false, this.urlPreventCache);
+ this._atomIO.getFeed(this.url,dojo.hitch(this,this._setFeed));
+ }
+ }
+ return true;
+ },
+
+ deleteItem: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Write.deleteItem()
+ this._assertIsItem(item);
+
+ if(!this._deletes){
+ this._deletes = [item];
+ }else{
+ this._deletes.push(item);
+ }
+
+ if(this._feed){
+ this._feed.removeEntry(item);
+ }else{
+ if(this._requests){
+ this._requests.push({remove:item});
+ }else{
+ this._requests = [{remove:item}];
+ this._atomIO = new dojox.atom.io.Connection(false, this.urlPreventCache);
+ this._atomIO.getFeed(this.url,dojo.hitch(this,this._setFeed));
+ }
+ }
+ item = null;
+ return true;
+ },
+
+ setValue: function( /* item */ item,
+ /* string */ attribute,
+ /* almost anything */ value){
+ // summary:
+ // See dojo.data.api.Write.setValue()
+ this._assertIsItem(item);
+
+ var update = {item: item};
+ if(this._assertIsAttribute(attribute)){
+ switch(attribute){
+ case "link":
+ update.links = item.links;
+ this._addUpdate(update);
+ item.links = null;
+ item.addLink(value.href,value.rel,value.hrefLang,value.title,value.type);
+ item.isDirty = true;
+ return true;
+ case "author":
+ update.authors = item.authors;
+ this._addUpdate(update);
+ item.authors = null;
+ item.addAuthor(value.name, value.email, value.uri);
+ item.isDirty = true;
+ return true;
+ case "contributor":
+ update.contributors = item.contributors;
+ this._addUpdate(update);
+ item.contributors = null;
+ item.addContributor(value.name, value.email, value.uri);
+ item.isDirty = true;
+ return true;
+ case "category":
+ update.categories = item.categories;
+ this._addUpdate(update);
+ item.categories = null;
+ item.addCategory(value.scheme, value.term, value.label);
+ item.isDirty = true;
+ return true;
+ case "icon":
+ case "id":
+ case "logo":
+ case "xmlBase":
+ case "rights":
+ update[attribute] = item[attribute];
+ this._addUpdate(update);
+ item[attribute] = value;
+ item.isDirty = true;
+ return true;
+ case "updated":
+ case "published":
+ case "issued":
+ case "modified":
+ update[attribute] = item[attribute];
+ this._addUpdate(update);
+ item[attribute] = dojox.atom.io.model.util.createDate(value);
+ item.isDirty = true;
+ return true;
+ case "content":
+ case "summary":
+ case "title":
+ case "subtitle":
+ update[attribute] = item[attribute];
+ this._addUpdate(update);
+ item[attribute] = new dojox.atom.io.model.Content(attribute);
+ item[attribute].value = value;
+ item.isDirty = true;
+ return true;
+ default:
+ update[attribute] = item[attribute];
+ this._addUpdate(update);
+ item[attribute] = value;
+ item.isDirty = true;
+ return true;
+ }
+ }
+ return false;
+ },
+
+ setValues: function(/* item */ item,
+ /* string */ attribute,
+ /* array */ values){
+ // summary:
+ // See dojo.data.api.Write.setValues()
+ if(values.length === 0){
+ return this.unsetAttribute(item, attribute);
+ }
+ this._assertIsItem(item);
+
+ var update = {item: item};
+ var value;
+ var i;
+ if(this._assertIsAttribute(attribute)){
+ switch(attribute){
+ case "link":
+ update.links = item.links;
+ item.links = null;
+ for(i in values){
+ value = values[i];
+ item.addLink(value.href,value.rel,value.hrefLang,value.title,value.type);
+ }
+ item.isDirty = true;
+ return true;
+ case "author":
+ update.authors = item.authors;
+ item.authors = null;
+ for(i in values){
+ value = values[i];
+ item.addAuthor(value.name, value.email, value.uri);
+ }
+ item.isDirty = true;
+ return true;
+ case "contributor":
+ update.contributors = item.contributors;
+ item.contributors = null;
+ for(i in values){
+ value = values[i];
+ item.addContributor(value.name, value.email, value.uri);
+ }
+ item.isDirty = true;
+ return true;
+ case "categories":
+ update.categories = item.categories;
+ item.categories = null;
+ for(i in values){
+ value = values[i];
+ item.addCategory(value.scheme, value.term, value.label);
+ }
+ item.isDirty = true;
+ return true;
+ case "icon":
+ case "id":
+ case "logo":
+ case "xmlBase":
+ case "rights":
+ update[attribute] = item[attribute];
+ item[attribute] = values[0];
+ item.isDirty = true;
+ return true;
+ case "updated":
+ case "published":
+ case "issued":
+ case "modified":
+ update[attribute] = item[attribute];
+ item[attribute] = dojox.atom.io.model.util.createDate(values[0]);
+ item.isDirty = true;
+ return true;
+ case "content":
+ case "summary":
+ case "title":
+ case "subtitle":
+ update[attribute] = item[attribute];
+ item[attribute] = new dojox.atom.io.model.Content(attribute);
+ item[attribute].values[0] = values[0];
+ item.isDirty = true;
+ return true;
+ default:
+ update[attribute] = item[attribute];
+ item[attribute] = values[0];
+ item.isDirty = true;
+ return true;
+ }
+ }
+ this._addUpdate(update);
+ return false;
+ },
+
+ unsetAttribute: function( /* item */ item,
+ /* string */ attribute){
+ // summary:
+ // See dojo.data.api.Write.unsetAttribute()
+ this._assertIsItem(item);
+ if(this._assertIsAttribute(attribute)){
+ if(item[attribute] !== null){
+ var update = {item: item};
+ switch(attribute){
+ case "author":
+ case "contributor":
+ case "link":
+ update[attribute+"s"] = item[attribute+"s"];
+ break;
+ case "category":
+ update.categories = item.categories;
+ break;
+ default:
+ update[attribute] = item[attribute];
+ break;
+ }
+ item.isDirty = true;
+ item[attribute] = null;
+ this._addUpdate(update);
+ return true;
+ }
+ }
+ return false; // boolean
+ },
+
+ save: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Write.save()
+ // keywordArgs:
+ // {
+ // onComplete: function
+ // onError: function
+ // scope: object
+ // }
+ var i;
+ for(i in this._adds){
+ this._atomIO.addEntry(this._adds[i], null, function(){}, keywordArgs.onError, false, keywordArgs.scope);
+ }
+
+ this._adds = null;
+
+ for(i in this._updates){
+ this._atomIO.updateEntry(this._updates[i].item, function(){}, keywordArgs.onError, false, this.xmethod, keywordArgs.scope);
+ }
+
+ this._updates = null;
+
+ for(i in this._deletes){
+ this._atomIO.removeEntry(this._deletes[i], function(){}, keywordArgs.onError, this.xmethod, keywordArgs.scope);
+ }
+
+ this._deletes = null;
+
+ this._atomIO.getFeed(this.url,dojo.hitch(this,this._setFeed));
+
+ if(keywordArgs.onComplete){
+ var scope = keywordArgs.scope || dojo.global;
+ keywordArgs.onComplete.call(scope);
+ }
+ },
+
+ revert: function(){
+ // summary:
+ // See dojo.data.api.Write.revert()
+ var i;
+ for(i in this._adds){
+ this._feed.removeEntry(this._adds[i]);
+ }
+
+ this._adds = null;
+
+ var update, item, key;
+ for(i in this._updates){
+ update = this._updates[i];
+ item = update.item;
+ for(key in update){
+ if(key !== "item"){
+ item[key] = update[key];
+ }
+ }
+ }
+ this._updates = null;
+
+ for(i in this._deletes){
+ this._feed.addEntry(this._deletes[i]);
+ }
+ this._deletes = null;
+ return true;
+ },
+
+ isDirty: function(/* item? */ item){
+ // summary:
+ // See dojo.data.api.Write.isDirty()
+ if(item){
+ this._assertIsItem(item);
+ return item.isDirty?true:false; //boolean
+ }
+ return (this._adds !== null || this._updates !== null); //boolean
+ }
+});
+dojo.extend(dojox.data.AppStore,dojo.data.util.simpleFetch);
+
+return dojox.data.AppStore;
+});