appupdate.js

1       // 3.0.2-SNAPSHOT
2       var exec = require('cordova/exec'),
3           channel = require('cordova/channel'),
4           logonFired = false, // Flag to determine if logon manager is done
5           promptActive = false, // Flag to prevent prompt from displaying more than once
6           bundle = null; // Internationalization. Loaded with device ready
7       
8       
9       // Event channels for AppUpdate
10      var channels = {
11          'checking': channel.create('checking'),
12          'noupdate': channel.create('noupdate'),
13          'downloading': channel.create('downloading'),
14          'progress': channel.create('progress'),
15          'error': channel.create('error'),
16          'updateready': channel.create('updateready')
17      };
18      
19      // Holds the dom 0 handlers that are registered for the channels
20      var domZeroHandlers = {};
21      
22      // Private callback that plugin calls for events
23      var _eventHandler = function (event) {
24          if (event.type) {
25              if (event.type in channels) {
26                  channels[event.type].fire(event);
27              }
28          }
29      };
30      
31      /** @namespace sap */
32      
33      /**
34       * Used to provide server-based updates to the application content.
35       * <br/><br/>
36       * The AppUpdate plugin updates the contents of the www folder of deployed Kapsel
37       * applications.  After an application successfully does a logon to an SAP Mobile Platform 3
38       * server, the AppUpdate plugin is able to download an available update. See Uploading Hybrid Apps in user documentation
39       * for information on how to upload an update to SAP Mobile Platform 3 server.
40       * <br/><br/>
41       * After an update is completely downloaded, the application user is 
42       * prompted to install the update and restart the application.  They can decline
43       * if they wish.
44       * <br/><br/>
45       * Once an update is installed, the application's revision number is updated.
46       * <br/><br/>
47       * <b>Adding and Removing the AppUpdate Plugin</b><br/>
48       * The AppUpdate plugin is added and removed using the
49       * <a href="http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface">Cordova CLI</a>.<br/>
50       * <br/>
51       * To add the AppUpdate plugin to your project, use the following command:<br/>
52       * cordova plugin add <path to directory containing Kapsel plugins>\appupdate<br/>
53       * <br/>
54       * To remove the AppUpdate plugin from your project, use the following command:<br/>
55       * cordova plugin rm com.sap.mp.cordova.plugins.appupdate
56       * <br/><br/>
57       * 
58       * <b>Hybrid App Revision Preference</b><br/>
59       * This is an optional preference that tells the AppUdate plugin if the local 
60       * assets are uploaded to the server, and at what number.  If this preference is 
61       * not provided, the default revision is 0.
62       * In your config.xml file you can add the following preference:<br/>
63       * <preference name="hybridapprevision" value="1" />
64      <br/>
65      <br/>
66       * This means that the local assets in your www folder are uploaded to the server 
67       * and the server is reporting revision 1 for them.  This allows the application 
68       * to receive a delta update when revision 2 is available instead of a full update.
69       * <br/><br/>
70       *
71       * <b>Caveats</b><br/>
72       * It is important to test that your update has valid HTML, Javascript, and CSS.  
73       * Otherwise, the update could prevent the application from functioning correctly, 
74       * and may no longer be updateable.  You can test the updated application in a 
75       * separate simulator or additional test device.  You can also validate your 
76       * Javascript with tools like <a href="http://www.jslint.com">JSLint</a>, or 
77       * <a href="http://www.jshint.com">JSHint</a>.  
78       * You can validate CSS with <a href="http://csslint.net">CSS Lint</a>.
79       * <br/><br/>
80       * 
81       * @namespace
82       * @alias AppUpdate
83       * @memberof sap
84       */
85      module.exports = {
86          /**
87           * Force an update check.  By default updates are done automatically during logon and resume.
88           * See events for what will be fired during this process. 
89           * @example
90           * sap.AppUpdate.update();
91           */
92          update: function () {
93              // Abort if logon event has not yet fired
94              if (logonFired) {
95                  sap.Logon.unlock(function (connectionInfo) {
96                      //Add application ID required for REST call
97                      connectionInfo.applicationId = sap.Logon.applicationId;
98      
99                      exec(_eventHandler, null, 'AppUpdate', 'update', [connectionInfo]);
100                 });
101             }
102         },
103     
104         /**
105          * Replaces the app resources with any newly downloaded resources.
106          * @example
107          * sap.AppUpdate.reloadApp();
108          */
109         reloadApp: function () {
110             exec(null, null, 'AppUpdate', 'reloadApp', []);
111         },
112     
113         /**
114          * Removes all local updates and loads the original web assets bundled with the app. Call this after delete registration.
115          * Reset calls error callback if called during the update process.
116          * @example
117          * sap.Logon.core.deleteRegistration(function() { 
118          *     sap.AppUpdate.reset();
119          * }, function() {});
120          */
121         reset: function (successCallback, errorCallback) {
122             exec(successCallback, errorCallback, 'AppUpdate', 'reset', []);
123         },
124     
125         /**
126          * Add a listener for an AppUpdate event.  See events for available event names.
127          * @param {string} eventname Name of the app update event.
128          * @param {function} f Function to call when event is fired.
129          * @example
130          * sap.AppUpdate.addEventListener('checking', function(e) {
131          *     console.log("Checking for update");
132          * });
133          */
134         addEventListener: function (eventname, f) {
135             if (eventname in channels) {
136                 channels[eventname].subscribe(f);
137             }
138         },
139     
140         /**
141          * Removes a listener for an AppUpdate event.  See events for available event names.
142          * @param {string} eventname Name of the app update event.
143          * @param {function} f Function that was registered.
144          * @example
145          * // Adding the listener
146          * var listener = function(e) {
147          *     console.log("Checking for update");
148          * });
149          * sap.AppUpdate.addEventListener('checking', listener);
150          *
151          * // Removing the listener
152          * sap.AppUpdate.removeEventListener('checking', listener);
153          */
154         removeEventListener: function (eventname, f) {
155             if (eventname in channels) {
156                 channels[eventname].unsubscribe(f);
157             }
158         }
159     
160         /**
161          * Event fired when AppUpdate is checking for an update.
162          *
163          * @event sap.AppUpdate#checking
164          * @type {object}
165          * @property {string} type - The name of the event.  Value will be checking. 
166          * @example
167          * sap.AppUpdate.addEventListener('checking', function(e) {
168          *     console.log("Checking for update");
169          * });
170          */
171     
172         /**
173          * Event fired when AppUpdate finds no available updates on server.
174          *
175          * @event sap.AppUpdate#noupdate
176          * @type {object}
177          * @property {string} type - The name of the event.  Value will be noupdate. 
178          * @example
179          * sap.AppUpdate.addEventListener('noupdate', function(e) {
180          *     console.log("No update");
181          * });
182          */
183     
184         /**
185          * Event fired when AppUpdate has found an update and is starting the download.
186          *
187          * @event sap.AppUpdate#downloading
188          * @type {object}
189          * @property {string} type - The name of the event.  Value will be downloading. 
190          * @example
191          * sap.AppUpdate.addEventListener('downloading', function(e) {
192          *     console.log("Downloading update");
193          * });
194          */
195     
196         
197         /**
198          * Event fired when AppUpdate has made progress downloading the update.
199          *
200          * @since 3.0.2
201          * @event sap.AppUpdate#progress
202          * @type {object}
203          * @property {string} type - The name of the event.  Value will be progress.
204          * @property {boolean} lengthComputable - Specifies whether or not the total size is known.
205          * @property {int} loaded - The number of bytes transferred so far.
206          * @property {int} total - The total number of bytes of content that will be transferred.  If total size is unknown, this value is zero.
207          * @example
208          * sap.AppUpdate.addEventListener('progress', function(e) {
209          *     if (e.lengthComputable) {
210          *          var percent = Math.round(e.loaded / e.total * 100);
211          *          console.log("Progress " + percent);
212          *     }
213          * });
214          */
215         
216         /**
217          * Event fired when AppUpdate encounters an error while checking for an update or downloading an update.
218          * The status code and status message are provided with this event.
219          *
220          * @event sap.AppUpdate#error
221          * @type {object}
222          * @property {string} type - The name of the event.  Value will be error. 
223          * @property {int} statusCode - The http error code.
224          * @property {string} statusMessage - The http status message.     
225          * @example
226          * sap.AppUpdate.addEventListener('error', function(e) {
227          *     console.log("Error downloading update. statusCode: " + e.statusCode + " statusMessage: " + e.statusMessage);
228          * });
229          */
230     
231         /**
232          * Event fired when AppUpdate has a newly downloaded update available.  
233          * A default handler is already added to sap.AppUpdate.onupdateready that will ask the user to reload the app.
234          * When handling this event you should call sap.AppUpdate.reloadApp() to apply the downloaded update.
235          *
236          * @event sap.AppUpdate#updateready
237          * @type {object}
238          * @property {string} type - The name of the event.  Value will be updateready.
239          * @property {int} revision - The revision that was downloaded.
240          * @example
241          *
242          * // This will listen for updateready event.  
243          * // Note: Use sap.AppUpdate.onupdateready if you want to override the default handler.
244          * sap.AppUpdate.addEventListener('updateready', function(e) {
245          *     console.log("Update ready");
246          * });
247          *
248          * // Override default handler so that we automatically load the update 
249          * // without first prompting the user for permission,
250          * sap.AppUpdate.onupdateready = function(e) {
251          *     // No notification just reload
252          *     console.log("Apply application update...");
253          *     sap.AppUpdate.reloadApp();
254          * };
255          *
256          * // Override default handler with custom prompt to warn the user that the 
257          * // application is ready to update.
258          * sap.AppUpdate.onupdateready = function() {
259          *     console.log("Confirming application update…");
260          *     navigator.notification.confirm('Update Available',
261          *        function(buttonIndex) {
262          *            if (buttonIndex === 2) {
263          *                console.log("Applying application update…");
264          *                sap.AppUpdate.reloadApp();
265          *            }
266          *        }, 
267          *        "Update", ["Later", "Relaunch Now"]);
268          * };
269          */
270     };
271     
272     // Add getter/setter for DOM0 style events
273     for (var type in channels) {
274         function defineSetGet(eventType) {
275             module.exports.__defineGetter__("on" + eventType, function () {
276                 return domZeroHandlers[eventType];
277             });
278     
279             module.exports.__defineSetter__("on" + eventType, function (val) {
280                 // Remove current handler
281                 if (domZeroHandlers[eventType]) {
282                     module.exports.removeEventListener(eventType, domZeroHandlers[eventType]);
283                 }
284     
285                 // Add new handler
286                 if (val) {
287                     domZeroHandlers[eventType] = val;
288                     module.exports.addEventListener(eventType, domZeroHandlers[eventType]);
289                 }
290             });
291         }
292     
293         defineSetGet(type);
294     }
295     
296     // Add default update ready implementation
297     module.exports.onupdateready = function () {
298         if (!promptActive) {
299             promptActive = true;
300     
301             var onConfirm = function (buttonIndex) {
302                 promptActive = false;
303                 if (buttonIndex === 2) {
304                     // Only reload if we are unlocked
305                     sap.Logon.unlock(function (connectionInfo) {
306                         //Add application ID required for REST call
307                         connectionInfo.applicationId = sap.Logon.applicationId;
308     
309                         module.exports.reloadApp();
310                     });
311                 }
312             }
313     
314             if (!bundle) {
315                 // Load required translations
316                 var i18n = require('com.sap.mp.cordova.plugins.i18n.i18n');
317                 bundle = i18n.load({
318                     path: "plugins/com.sap.mp.cordova.plugins.appupdate/www"
319                 });
320             }
321     
322             window.navigator.notification.confirm(
323                 bundle.get("update_available"),
324                 onConfirm,
325                 bundle.get("update"), [bundle.get("later"), bundle.get("relaunch_now")]);
326         }
327     }
328     
329     // When logon is ready an update check is started
330     document.addEventListener("onSapLogonSuccess", function () {
331         logonFired = true;
332         module.exports.update();
333     }, false);
334     
335     document.addEventListener("onSapResumeSuccess", module.exports.update, false);
336