diff options
Diffstat (limited to 'includes/js/dojox/off/sync.js')
-rw-r--r-- | includes/js/dojox/off/sync.js | 690 |
1 files changed, 0 insertions, 690 deletions
diff --git a/includes/js/dojox/off/sync.js b/includes/js/dojox/off/sync.js deleted file mode 100644 index 9927fbe..0000000 --- a/includes/js/dojox/off/sync.js +++ /dev/null @@ -1,690 +0,0 @@ -if(!dojo._hasResource["dojox.off.sync"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. -dojo._hasResource["dojox.off.sync"] = true; -dojo.provide("dojox.off.sync"); - -dojo.require("dojox.storage.GearsStorageProvider"); -dojo.require("dojox.off._common"); -dojo.require("dojox.off.files"); - -// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org - -// summary: -// Exposes syncing functionality to offline applications -dojo.mixin(dojox.off.sync, { - // isSyncing: boolean - // Whether we are in the middle of a syncing session. - isSyncing: false, - - // cancelled: boolean - // Whether we were cancelled during our last sync request or not. If - // we are cancelled, then successful will be false. - cancelled: false, - - // successful: boolean - // Whether the last sync was successful or not. If false, an error - // occurred. - successful: true, - - // details: String[] - // Details on the sync. If the sync was successful, this will carry - // any conflict or merging messages that might be available; if the - // sync was unsuccessful, this will have an error message. For both - // of these, this should be an array of Strings, where each string - // carries details on the sync. - // Example: - // dojox.off.sync.details = ["The document 'foobar' had conflicts - yours one", - // "The document 'hello world' was automatically merged"]; - details: [], - - // error: boolean - // Whether an error occurred during the syncing process. - error: false, - - // actions: dojox.off.sync.ActionLog - // Our ActionLog that we store offline actions into for later - // replaying when we go online - actions: null, - - // autoSync: boolean - // For advanced usage; most developers can ignore this. - // Whether we do automatically sync on page load or when we go online. - // If true we do, if false syncing must be manually initiated. - // Defaults to true. - autoSync: true, - - // summary: - // An event handler that is called during the syncing process with - // the state of syncing. It is important that you connect to this - // method and respond to certain sync events, especially the - // "download" event. - // description: - // This event handler is called during the syncing process. You can - // do a dojo.connect to receive sync feedback: - // - // dojo.connect(dojox.off.sync, "onSync", someFunc); - // - // You will receive one argument, which is the type of the event - // and which can have the following values. - // - // The most common two types that you need to care about are "download" - // and "finished", especially if you are using the default - // Dojo Offline UI widget that does the hard work of informing - // the user through the UI about what is occuring during syncing. - // - // If you receive the "download" event, you should make a network call - // to retrieve and store your data somehow for offline access. The - // "finished" event indicates that syncing is done. An example: - // - // dojo.connect(dojox.off.sync, "onSync", function(type){ - // if(type == "download"){ - // // make a network call to download some data - // // for use offline - // dojo.xhrGet({ - // url: "downloadData.php", - // handleAs: "javascript", - // error: function(err){ - // dojox.off.sync.finishedDownloading(false, "Can't download data"); - // }, - // load: function(data){ - // // store our data - // dojox.storage.put("myData", data); - // - // // indicate we are finished downloading - // dojox.off.sync.finishedDownloading(true); - // } - // }); - // }else if(type == "finished"){ - // // update UI somehow to indicate we are finished, - // // such as using the download data to change the - // // available data - // } - // }) - // - // Here is the full list of event types if you want to do deep - // customization, such as updating your UI to display the progress - // of syncing (note that the default Dojo Offline UI widget does - // this for you if you choose to pull that in). Most of these - // are only appropriate for advanced usage and can be safely - // ignored: - // - // * "start" - // syncing has started - // * "refreshFiles" - // syncing will begin refreshing - // our offline file cache - // * "upload" - // syncing will begin uploading - // any local data changes we have on the client. - // This event is fired before we fire - // the dojox.off.sync.actions.onReplay event for - // each action to replay; use it to completely - // over-ride the replaying behavior and prevent - // it entirely, perhaps rolling your own sync - // protocol if needed. - // * "download" - // syncing will begin downloading any new data that is - // needed into persistent storage. Applications are required to - // implement this themselves, storing the required data into - // persistent local storage using Dojo Storage. - // * "finished" - // syncing is finished; this - // will be called whether an error ocurred or not; check - // dojox.off.sync.successful and dojox.off.sync.error for sync details - // * "cancel" - // Fired when canceling has been initiated; canceling will be - // attempted, followed by the sync event "finished". - onSync: function(/* String */ type){}, - - synchronize: function(){ /* void */ - // summary: Starts synchronizing - - //dojo.debug("synchronize"); - if(this.isSyncing || dojox.off.goingOnline || (!dojox.off.isOnline)){ - return; - } - - this.isSyncing = true; - this.successful = false; - this.details = []; - this.cancelled = false; - - this.start(); - }, - - cancel: function(){ /* void */ - // summary: - // Attempts to cancel this sync session - - if(!this.isSyncing){ return; } - - this.cancelled = true; - if(dojox.off.files.refreshing){ - dojox.off.files.abortRefresh(); - } - - this.onSync("cancel"); - }, - - finishedDownloading: function(successful /* boolean? */, - errorMessage /* String? */){ - // summary: - // Applications call this method from their - // after getting a "download" event in - // dojox.off.sync.onSync to signal that - // they are finished downloading any data - // that should be available offline - // successful: boolean? - // Whether our downloading was successful or not. - // If not present, defaults to true. - // errorMessage: String? - // If unsuccessful, a message explaining why - if(typeof successful == "undefined"){ - successful = true; - } - - if(!successful){ - this.successful = false; - this.details.push(errorMessage); - this.error = true; - } - - this.finished(); - }, - - start: function(){ /* void */ - // summary: - // For advanced usage; most developers can ignore this. - // Called at the start of the syncing process. Advanced - // developers can over-ride this method to use their - // own sync mechanism to start syncing. - - if(this.cancelled){ - this.finished(); - return; - } - this.onSync("start"); - this.refreshFiles(); - }, - - refreshFiles: function(){ /* void */ - // summary: - // For advanced usage; most developers can ignore this. - // Called when we are going to refresh our list - // of offline files during syncing. Advanced developers - // can over-ride this method to do some advanced magic related to - // refreshing files. - - //dojo.debug("refreshFiles"); - if(this.cancelled){ - this.finished(); - return; - } - - this.onSync("refreshFiles"); - - dojox.off.files.refresh(dojo.hitch(this, function(error, errorMessages){ - if(error){ - this.error = true; - this.successful = false; - for(var i = 0; i < errorMessages.length; i++){ - this.details.push(errorMessages[i]); - } - - // even if we get an error while syncing files, - // keep syncing so we can upload and download - // data - } - - this.upload(); - })); - }, - - upload: function(){ /* void */ - // summary: - // For advanced usage; most developers can ignore this. - // Called when syncing wants to upload data. Advanced - // developers can over-ride this method to completely - // throw away the Action Log and replaying system - // and roll their own advanced sync mechanism if needed. - - if(this.cancelled){ - this.finished(); - return; - } - - this.onSync("upload"); - - // when we are done uploading start downloading - dojo.connect(this.actions, "onReplayFinished", this, this.download); - - // replay the actions log - this.actions.replay(); - }, - - download: function(){ /* void */ - // summary: - // For advanced usage; most developers can ignore this. - // Called when syncing wants to download data. Advanced - // developers can over-ride this method to use their - // own sync mechanism. - - if(this.cancelled){ - this.finished(); - return; - } - - // apps should respond to the "download" - // event to download their data; when done - // they must call dojox.off.sync.finishedDownloading() - this.onSync("download"); - }, - - finished: function(){ /* void */ - // summary: - // For advanced usage; most developers can ignore this. - // Called when syncing is finished. Advanced - // developers can over-ride this method to clean - // up after finishing their own sync - // mechanism they might have rolled. - this.isSyncing = false; - - this.successful = (!this.cancelled && !this.error); - - this.onSync("finished"); - }, - - _save: function(callback){ - this.actions._save(function(){ - callback(); - }); - }, - - _load: function(callback){ - this.actions._load(function(){ - callback(); - }); - } -}); - - -// summary: -// A class that records actions taken by a user when they are offline, -// suitable for replaying when the network reappears. -// description: -// The basic idea behind this method is to record user actions that would -// normally have to contact a server into an action log when we are -// offline, so that later when we are online we can simply replay this log -// in the order user actions happened so that they can be executed against -// the server, causing synchronization to happen. -// -// When we replay, for each of the actions that were added, we call a -// method named onReplay that applications should connect to and -// which will be called over and over for each of our actions -- -// applications should take the offline action -// information and use it to talk to a server to have this action -// actually happen online, 'syncing' themselves with the server. -// -// For example, if the action was "update" with the item that was updated, we -// might call some RESTian server API that exists for updating an item in -// our application. The server could either then do sophisticated merging -// and conflict resolution on the server side, for example, allowing you -// to pop up a custom merge UI, or could do automatic merging or nothing -// of the sort. When you are finished with this particular action, your -// application is then required to call continueReplay() on the actionLog object -// passed to onReplay() to continue replaying the action log, or haltReplay() -// with the reason for halting to completely stop the syncing/replaying -// process. -// -// For example, imagine that we have a web application that allows us to add -// contacts. If we are offline, and we update a contact, we would add an action; -// imagine that the user has to click an Update button after changing the values -// for a given contact: -// -// dojox.off.whenOffline(dojo.byId("updateButton"), "onclick", function(evt){ -// // get the updated customer values -// var customer = getCustomerValues(); -// -// // we are offline -- just record this action -// var action = {name: "update", customer: customer}; -// dojox.off.sync.actions.add(action) -// -// // persist this customer data into local storage as well -// dojox.storage.put(customer.name, customer); -// }) -// -// Then, when we go back online, the dojox.off.sync.actions.onReplay event -// will fire over and over, once for each action that was recorded while offline: -// -// dojo.connect(dojox.off.sync.actions, "onReplay", function(action, actionLog){ -// // called once for each action we added while offline, in the order -// // they were added -// if(action.name == "update"){ -// var customer = action.customer; -// -// // call some network service to update this customer -// dojo.xhrPost({ -// url: "updateCustomer.php", -// content: {customer: dojo.toJson(customer)}, -// error: function(err){ -// actionLog.haltReplay(err); -// }, -// load: function(data){ -// actionLog.continueReplay(); -// } -// }) -// } -// }) -// -// Note that the actions log is always automatically persisted locally while using it, so -// that if the user closes the browser or it crashes the actions will safely be stored -// for later replaying. -dojo.declare("dojox.off.sync.ActionLog", null, { - // entries: Array - // An array of our action entries, where each one is simply a custom - // object literal that were passed to add() when this action entry - // was added. - entries: [], - - // reasonHalted: String - // If we halted, the reason why - reasonHalted: null, - - // isReplaying: boolean - // If true, we are in the middle of replaying a command log; if false, - // then we are not - isReplaying: false, - - // autoSave: boolean - // Whether we automatically save the action log after each call to - // add(); defaults to true. For applications that are rapidly adding - // many action log entries in a short period of time, it can be - // useful to set this to false and simply call save() yourself when - // you are ready to persist your command log -- otherwise performance - // could be slow as the default action is to attempt to persist the - // actions log constantly with calls to add(). - autoSave: true, - - add: function(action /* Object */){ /* void */ - // summary: - // Adds an action to our action log - // description: - // This method will add an action to our - // action log, later to be replayed when we - // go from offline to online. 'action' - // will be available when this action is - // replayed and will be passed to onReplay. - // - // Example usage: - // - // dojox.off.sync.log.add({actionName: "create", itemType: "document", - // {title: "Message", content: "Hello World"}}); - // - // The object literal is simply a custom object appropriate - // for our application -- it can be anything that preserves the state - // of a user action that will be executed when we go back online - // and replay this log. In the above example, - // "create" is the name of this action; "documents" is the - // type of item this command is operating on, such as documents, contacts, - // tasks, etc.; and the final argument is the document that was created. - - if(this.isReplaying){ - throw "Programming error: you can not call " - + "dojox.off.sync.actions.add() while " - + "we are replaying an action log"; - } - - this.entries.push(action); - - // save our updated state into persistent - // storage - if(this.autoSave){ - this._save(); - } - }, - - onReplay: function(action /* Object */, - actionLog /* dojox.off.sync.ActionLog */){ /* void */ - // summary: - // Called when we replay our log, for each of our action - // entries. - // action: Object - // A custom object literal representing an action for this - // application, such as - // {actionName: "create", item: {title: "message", content: "hello world"}} - // actionLog: dojox.off.sync.ActionLog - // A reference to the dojox.off.sync.actions log so that developers - // can easily call actionLog.continueReplay() or actionLog.haltReplay(). - // description: - // This callback should be connected to by applications so that - // they can sync themselves when we go back online: - // - // dojo.connect(dojox.off.sync.actions, "onReplay", function(action, actionLog){ - // // do something - // }) - // - // When we replay our action log, this callback is called for each - // of our action entries in the order they were added. The - // 'action' entry that was passed to add() for this action will - // also be passed in to onReplay, so that applications can use this information - // to do their syncing, such as contacting a server web-service - // to create a new item, for example. - // - // Inside the method you connected to onReplay, you should either call - // actionLog.haltReplay(reason) if an error occurred and you would like to halt - // action replaying or actionLog.continueReplay() to have the action log - // continue replaying its log and proceed to the next action; - // the reason you must call these is the action you execute inside of - // onAction will probably be asynchronous, since it will be talking on - // the network, and you should call one of these two methods based on - // the result of your network call. - }, - - length: function(){ /* Number */ - // summary: - // Returns the length of this - // action log - return this.entries.length; - }, - - haltReplay: function(reason /* String */){ /* void */ - // summary: Halts replaying this command log. - // reason: String - // The reason we halted. - // description: - // This method is called as we are replaying an action log; it - // can be called from dojox.off.sync.actions.onReplay, for - // example, for an application to indicate an error occurred - // while replaying this action, halting further processing of - // the action log. Note that any action log entries that - // were processed before have their effects retained (i.e. - // they are not rolled back), while the action entry that was - // halted stays in our list of actions to later be replayed. - if(!this.isReplaying){ - return; - } - - if(reason){ - this.reasonHalted = reason.toString(); - } - - // save the state of our action log, then - // tell anyone who is interested that we are - // done when we are finished saving - if(this.autoSave){ - var self = this; - this._save(function(){ - self.isReplaying = false; - self.onReplayFinished(); - }); - }else{ - this.isReplaying = false; - this.onReplayFinished(); - } - }, - - continueReplay: function(){ /* void */ - // summary: - // Indicates that we should continue processing out list of - // actions. - // description: - // This method is called by applications that have overridden - // dojox.off.sync.actions.onReplay() to continue replaying our - // action log after the application has finished handling the - // current action. - if(!this.isReplaying){ - return; - } - - // shift off the old action we just ran - this.entries.shift(); - - // are we done? - if(!this.entries.length){ - // save the state of our action log, then - // tell anyone who is interested that we are - // done when we are finished saving - if(this.autoSave){ - var self = this; - this._save(function(){ - self.isReplaying = false; - self.onReplayFinished(); - }); - return; - }else{ - this.isReplaying = false; - this.onReplayFinished(); - return; - } - } - - // get the next action - var nextAction = this.entries[0]; - this.onReplay(nextAction, this); - }, - - clear: function(){ /* void */ - // summary: - // Completely clears this action log of its entries - - if(this.isReplaying){ - return; - } - - this.entries = []; - - // save our updated state into persistent - // storage - if(this.autoSave){ - this._save(); - } - }, - - replay: function(){ /* void */ - // summary: - // For advanced usage; most developers can ignore this. - // Replays all of the commands that have been - // cached in this command log when we go back online; - // onCommand will be called for each command we have - - if(this.isReplaying){ - return; - } - - this.reasonHalted = null; - - if(!this.entries.length){ - this.onReplayFinished(); - return; - } - - this.isReplaying = true; - - var nextAction = this.entries[0]; - this.onReplay(nextAction, this); - }, - - // onReplayFinished: Function - // For advanced usage; most developers can ignore this. - // Called when we are finished replaying our commands; - // called if we have successfully exhausted all of our - // commands, or if an error occurred during replaying. - // The default implementation simply continues the - // synchronization process. Connect to this to register - // for the event: - // - // dojo.connect(dojox.off.sync.actions, "onReplayFinished", - // someFunc) - onReplayFinished: function(){ - }, - - toString: function(){ - var results = ""; - results += "["; - - for(var i = 0; i < this.entries.length; i++){ - results += "{"; - for(var j in this.entries[i]){ - results += j + ": \"" + this.entries[i][j] + "\""; - results += ", "; - } - results += "}, "; - } - - results += "]"; - - return results; - }, - - _save: function(callback){ - if(!callback){ - callback = function(){}; - } - - try{ - var self = this; - var resultsHandler = function(status, key, message){ - //console.debug("resultsHandler, status="+status+", key="+key+", message="+message); - if(status == dojox.storage.FAILED){ - dojox.off.onFrameworkEvent("save", - {status: dojox.storage.FAILED, - isCoreSave: true, - key: key, - value: message, - namespace: dojox.off.STORAGE_NAMESPACE}); - callback(); - }else if(status == dojox.storage.SUCCESS){ - callback(); - } - }; - - dojox.storage.put("actionlog", this.entries, resultsHandler, - dojox.off.STORAGE_NAMESPACE); - }catch(exp){ - console.debug("dojox.off.sync._save: " + exp.message||exp); - dojox.off.onFrameworkEvent("save", - {status: dojox.storage.FAILED, - isCoreSave: true, - key: "actionlog", - value: this.entries, - namespace: dojox.off.STORAGE_NAMESPACE}); - callback(); - } - }, - - _load: function(callback){ - var entries = dojox.storage.get("actionlog", dojox.off.STORAGE_NAMESPACE); - - if(!entries){ - entries = []; - } - - this.entries = entries; - - callback(); - } - } -); - -dojox.off.sync.actions = new dojox.off.sync.ActionLog(); - -} |