a:51:{s:9:"#provides";s:14:"dojox.off.sync";s:9:"#resource";s:11:"off/sync.js";s:9:"#requires";a:3:{i:0;a:2:{i:0;s:6:"common";i:1;s:34:"dojox.storage.GearsStorageProvider";}i:1;a:2:{i:0;s:6:"common";i:1;s:17:"dojox.off._common";}i:2;a:2:{i:0;s:6:"common";i:1;s:15:"dojox.off.files";}}s:24:"dojox.off.sync.ActionLog";a:3:{s:4:"type";s:8:"Function";s:9:"classlike";b:1;s:7:"summary";s:0:"";}s:32:"dojox.off.sync.ActionLog.entries";a:4:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:8:"instance";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:5:"Array";s:7:"summary";s:140:"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.";}s:37:"dojox.off.sync.ActionLog.reasonHalted";a:4:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:8:"instance";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:6:"String";s:7:"summary";s:28:"If we halted, the reason why";}s:36:"dojox.off.sync.ActionLog.isReplaying";a:4:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:8:"instance";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:7:"boolean";s:7:"summary";s:83:"If true, we are in the middle of replaying a command log; if false, then we are not";}s:33:"dojox.off.sync.ActionLog.autoSave";a:3:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:7:"boolean";s:7:"summary";s:431:"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().";}s:28:"dojox.off.sync.ActionLog.add";a:5:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:6:"action";a:1:{s:4:"type";s:6:"Object";}}s:6:"source";s:14849:"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(); }";s:7:"summary";s:0:"";}s:33:"dojox.off.sync.ActionLog.onReplay";a:5:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:6:"action";a:1:{s:4:"type";s:6:"Object";}s:9:"actionLog";a:1:{s:4:"type";s:24:"dojox.off.sync.ActionLog";}}s:6:"source";s:16665:"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.";s:7:"summary";s:0:"";}s:31:"dojox.off.sync.ActionLog.length";a:4:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:6:"source";s:16806:"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;";s:7:"summary";s:0:"";}s:35:"dojox.off.sync.ActionLog.haltReplay";a:5:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:6:"reason";a:1:{s:4:"type";s:6:"String";}}s:6:"source";s:17969:"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(); }";s:7:"summary";s:0:"";}s:39:"dojox.off.sync.ActionLog.continueReplay";a:4:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:6:"source";s:19019:"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);";s:7:"summary";s:0:"";}s:30:"dojox.off.sync.ActionLog.clear";a:4:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:6:"source";s:19313:"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(); }";s:7:"summary";s:0:"";}s:31:"dojox.off.sync.ActionLog.replay";a:4:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:6:"source";s:19863:"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);";s:7:"summary";s:0:"";}s:41:"dojox.off.sync.ActionLog.onReplayFinished";a:4:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:6:"source";s:0:"";s:7:"summary";s:0:"";}s:33:"dojox.off.sync.ActionLog.toString";a:4:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:6:"source";s:307:" 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;";s:7:"summary";s:0:"";}s:30:"dojox.off.sync.ActionLog._save";a:6:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:8:"callback";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:1000:" 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(); }";s:7:"private";b:1;s:7:"summary";s:0:"";}s:30:"dojox.off.sync.ActionLog._load";a:6:{s:9:"prototype";s:24:"dojox.off.sync.ActionLog";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:8:"callback";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:174:" var entries = dojox.storage.get("actionlog", dojox.off.STORAGE_NAMESPACE); if(!entries){ entries = []; } this.entries = entries; callback();";s:7:"private";b:1;s:7:"summary";s:0:"";}s:24:"dojox.off.sync.isSyncing";a:1:{s:7:"summary";s:0:"";}s:24:"dojox.off.sync.cancelled";a:1:{s:7:"summary";s:0:"";}s:25:"dojox.off.sync.successful";a:1:{s:7:"summary";s:0:"";}s:22:"dojox.off.sync.details";a:1:{s:7:"summary";s:0:"";}s:20:"dojox.off.sync.error";a:1:{s:7:"summary";s:0:"";}s:22:"dojox.off.sync.actions";a:1:{s:7:"summary";s:0:"";}s:23:"dojox.off.sync.autoSync";a:1:{s:7:"summary";s:0:"";}s:21:"dojox.off.sync.onSync";a:4:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"type";a:1:{s:4:"type";s:6:"String";}}s:6:"source";s:3:"} ";s:7:"summary";s:0:"";}s:26:"dojox.off.sync.synchronize";a:3:{s:4:"type";s:8:"Function";s:6:"source";s:5370:"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();";s:7:"summary";s:0:"";}s:36:"dojox.off.sync.synchronize.isSyncing";a:2:{s:8:"instance";s:26:"dojox.off.sync.synchronize";s:7:"summary";s:0:"";}s:37:"dojox.off.sync.synchronize.successful";a:2:{s:8:"instance";s:26:"dojox.off.sync.synchronize";s:7:"summary";s:0:"";}s:34:"dojox.off.sync.synchronize.details";a:2:{s:8:"instance";s:26:"dojox.off.sync.synchronize";s:7:"summary";s:0:"";}s:36:"dojox.off.sync.synchronize.cancelled";a:2:{s:8:"instance";s:26:"dojox.off.sync.synchronize";s:7:"summary";s:0:"";}s:21:"dojox.off.sync.cancel";a:3:{s:4:"type";s:8:"Function";s:6:"source";s:5633:"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");";s:7:"summary";s:0:"";}s:31:"dojox.off.sync.cancel.cancelled";a:2:{s:8:"instance";s:21:"dojox.off.sync.cancel";s:7:"summary";s:0:"";}s:34:"dojox.off.sync.finishedDownloading";a:4:{s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:10:"successful";a:3:{s:8:"optional";b:1;s:4:"type";s:7:"boolean";s:7:"summary";s:80:"Whether our downloading was successful or not. If not present, defaults to true.";}s:12:"errorMessage";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"String";s:7:"summary";s:41:"If unsuccessful, a message explaining why";}}s:6:"source";s:201:" if(typeof successful == "undefined"){ successful = true; } if(!successful){ this.successful = false; this.details.push(errorMessage); this.error = true; } this.finished();";s:7:"summary";s:195:"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";}s:45:"dojox.off.sync.finishedDownloading.successful";a:3:{s:8:"instance";s:34:"dojox.off.sync.finishedDownloading";s:4:"type";s:8:"boolean?";s:7:"summary";s:80:"Whether our downloading was successful or not. If not present, defaults to true.";}s:40:"dojox.off.sync.finishedDownloading.error";a:2:{s:8:"instance";s:34:"dojox.off.sync.finishedDownloading";s:7:"summary";s:0:"";}s:20:"dojox.off.sync.start";a:3:{s:4:"type";s:8:"Function";s:6:"source";s:6737:"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();";s:7:"summary";s:0:"";}s:27:"dojox.off.sync.refreshFiles";a:3:{s:4:"type";s:8:"Function";s:6:"source";s:7581:"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(); }));";s:7:"summary";s:0:"";}s:33:"dojox.off.sync.refreshFiles.error";a:2:{s:8:"instance";s:27:"dojox.off.sync.refreshFiles";s:7:"summary";s:0:"";}s:38:"dojox.off.sync.refreshFiles.successful";a:2:{s:8:"instance";s:27:"dojox.off.sync.refreshFiles";s:7:"summary";s:0:"";}s:21:"dojox.off.sync.upload";a:3:{s:4:"type";s:8:"Function";s:6:"source";s:8187:"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();";s:7:"summary";s:0:"";}s:23:"dojox.off.sync.download";a:3:{s:4:"type";s:8:"Function";s:6:"source";s:8675:"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");";s:7:"summary";s:0:"";}s:23:"dojox.off.sync.finished";a:3:{s:4:"type";s:8:"Function";s:6:"source";s:9079:"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");";s:7:"summary";s:0:"";}s:33:"dojox.off.sync.finished.isSyncing";a:2:{s:8:"instance";s:23:"dojox.off.sync.finished";s:7:"summary";s:0:"";}s:34:"dojox.off.sync.finished.successful";a:2:{s:8:"instance";s:23:"dojox.off.sync.finished";s:7:"summary";s:0:"";}s:20:"dojox.off.sync._save";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:8:"callback";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:53:" this.actions._save(function(){ callback(); });";s:7:"private";b:1;s:7:"summary";s:0:"";}s:20:"dojox.off.sync._load";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:8:"callback";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:53:" this.actions._load(function(){ callback(); });";s:7:"private";b:1;s:7:"summary";s:0:"";}s:14:"dojox.off.sync";a:2:{s:4:"type";s:6:"Object";s:7:"summary";s:0:"";}s:9:"dojox.off";a:2:{s:4:"type";s:6:"Object";s:7:"summary";s:0:"";}s:5:"dojox";a:2:{s:4:"type";s:6:"Object";s:7:"summary";s:0:"";}}