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