@@ -41,18 +41,28 @@ export class Platform {
41
41
private _readyPromise : Promise < any > ;
42
42
private _readyResolve : any ;
43
43
private _resizeTm : any ;
44
- private _zone : NgZone ;
44
+ private _bbActions : BackButtonAction [ ] = [ ] ;
45
+
46
+ zone : NgZone ;
45
47
46
48
constructor ( platforms : string [ ] = [ ] ) {
47
49
this . _platforms = platforms ;
48
50
this . _readyPromise = new Promise ( res => { this . _readyResolve = res ; } ) ;
51
+
52
+ this . backButton . subscribe ( ( ) => {
53
+ // the hardware back button event has been fired
54
+ console . debug ( 'hardware back button' ) ;
55
+
56
+ // decide which backbutton action should run
57
+ this . runBackButtonAction ( ) ;
58
+ } ) ;
49
59
}
50
60
51
61
/**
52
62
* @private
53
63
*/
54
64
setZone ( zone : NgZone ) {
55
- this . _zone = zone ;
65
+ this . zone = zone ;
56
66
}
57
67
58
68
@@ -212,7 +222,7 @@ export class Platform {
212
222
* such as Cordova or Electron, then it uses the default DOM ready.
213
223
*/
214
224
triggerReady ( readySource : string ) {
215
- this . _zone . run ( ( ) => {
225
+ this . zone . run ( ( ) => {
216
226
this . _readyResolve ( readySource ) ;
217
227
} ) ;
218
228
}
@@ -232,14 +242,14 @@ export class Platform {
232
242
}
233
243
234
244
/**
235
- * Set the app's language direction, which will update the `dir` attribute
236
- * on the app's root `<html>` element. We recommend the app's `index.html`
237
- * file already has the correct `dir` attribute value set, such as
238
- * `<html dir="ltr">` or `<html dir="rtl">`. This method is useful if the
239
- * direction needs to be dynamically changed per user/session.
240
- * [W3C: Structural markup and right-to-left text in HTML](http://www.w3.org/International/questions/qa-html-dir)
241
- * @param {string } dir Examples: `rtl`, `ltr`
242
- */
245
+ * Set the app's language direction, which will update the `dir` attribute
246
+ * on the app's root `<html>` element. We recommend the app's `index.html`
247
+ * file already has the correct `dir` attribute value set, such as
248
+ * `<html dir="ltr">` or `<html dir="rtl">`. This method is useful if the
249
+ * direction needs to be dynamically changed per user/session.
250
+ * [W3C: Structural markup and right-to-left text in HTML](http://www.w3.org/International/questions/qa-html-dir)
251
+ * @param {string } dir Examples: `rtl`, `ltr`
252
+ */
243
253
setDir ( dir : string , updateDocument : boolean ) {
244
254
this . _dir = ( dir || '' ) . toLowerCase ( ) ;
245
255
if ( updateDocument !== false ) {
@@ -270,14 +280,14 @@ export class Platform {
270
280
}
271
281
272
282
/**
273
- * Set the app's language and optionally the country code, which will update
274
- * the `lang` attribute on the app's root `<html>` element.
275
- * We recommend the app's `index.html` file already has the correct `lang`
276
- * attribute value set, such as `<html lang="en">`. This method is useful if
277
- * the language needs to be dynamically changed per user/session.
278
- * [W3C: Declaring language in HTML](http://www.w3.org/International/questions/qa-html-language-declarations)
279
- * @param {string } language Examples: `en-US`, `en-GB`, `ar`, `de`, `zh`, `es-MX`
280
- */
283
+ * Set the app's language and optionally the country code, which will update
284
+ * the `lang` attribute on the app's root `<html>` element.
285
+ * We recommend the app's `index.html` file already has the correct `lang`
286
+ * attribute value set, such as `<html lang="en">`. This method is useful if
287
+ * the language needs to be dynamically changed per user/session.
288
+ * [W3C: Declaring language in HTML](http://www.w3.org/International/questions/qa-html-language-declarations)
289
+ * @param {string } language Examples: `en-US`, `en-GB`, `ar`, `de`, `zh`, `es-MX`
290
+ */
281
291
setLang ( language : string , updateDocument : boolean ) {
282
292
this . _lang = language ;
283
293
if ( updateDocument !== false ) {
@@ -302,125 +312,171 @@ export class Platform {
302
312
// called by engines (the browser)that do not provide them
303
313
304
314
/**
305
- * @private
306
- */
315
+ * @private
316
+ */
307
317
exitApp ( ) { }
308
318
309
319
// Events meant to be triggered by the engine
310
320
// **********************************************
311
321
312
322
/**
313
- * The back button event is emitted when the user presses the native
314
- * platform's back button, also referred to as the "hardware" back button.
315
- * This event is only emitted within Cordova apps running on Android and
316
- * Windows platforms. This event is not fired on iOS since iOS doesn't come
317
- * with a hardware back button in the same sense an Android or Windows device
318
- * does. It's important to note that this event does not emit when the Ionic
319
- * app's back button within the navbar is clicked, but this event is only
320
- * referencing the platform's hardware back button.
321
- */
323
+ * @private
324
+ */
322
325
backButton : EventEmitter < Event > = new EventEmitter ( ) ;
323
326
324
327
/**
325
- * The pause event emits when the native platform puts the application
326
- * into the background, typically when the user switches to a different
327
- * application. This event would emit when a Cordova app is put into
328
- * the background, however, it would not fire on a standard web browser.
329
- */
328
+ * The pause event emits when the native platform puts the application
329
+ * into the background, typically when the user switches to a different
330
+ * application. This event would emit when a Cordova app is put into
331
+ * the background, however, it would not fire on a standard web browser.
332
+ */
330
333
pause : EventEmitter < Event > = new EventEmitter ( ) ;
331
334
332
335
/**
333
- * The resume event emits when the native platform pulls the application
334
- * out from the background. This event would emit when a Cordova app comes
335
- * out from the background, however, it would not fire on a standard web browser.
336
- */
336
+ * The resume event emits when the native platform pulls the application
337
+ * out from the background. This event would emit when a Cordova app comes
338
+ * out from the background, however, it would not fire on a standard web browser.
339
+ */
337
340
resume : EventEmitter < Event > = new EventEmitter ( ) ;
338
341
342
+ /**
343
+ * The back button event is triggered when the user presses the native
344
+ * platform's back button, also referred to as the "hardware" back button.
345
+ * This event is only used within Cordova apps running on Android and
346
+ * Windows platforms. This event is not fired on iOS since iOS doesn't come
347
+ * with a hardware back button in the same sense an Android or Windows device
348
+ * does.
349
+ *
350
+ * Registering a hardware back button action and setting a priority allows
351
+ * apps to control which action should be called when the hardware back
352
+ * button is pressed. This method decides which of the registered back button
353
+ * actions has the highest priority and should be called.
354
+ *
355
+ * @param {Function } callback Called when the back button is pressed,
356
+ * if this registered action has the highest priority.
357
+ * @param {number } priority Set the priority for this action. Only the highest priority will execute. Defaults to `0`.
358
+ * @returns {Function } A function that, when called, will unregister
359
+ * the its back button action.
360
+ */
361
+ registerBackButtonAction ( fn : Function , priority : number = 0 ) : Function {
362
+ let action : BackButtonAction = { fn, priority} ;
363
+
364
+ this . _bbActions . push ( action ) ;
365
+
366
+ // return a function to unregister this back button action
367
+ return ( ) => {
368
+ let index = this . _bbActions . indexOf ( action ) ;
369
+ if ( index > - 1 ) {
370
+ this . _bbActions . splice ( index , 1 ) ;
371
+ }
372
+ } ;
373
+ }
374
+
375
+ /**
376
+ * @private
377
+ */
378
+ runBackButtonAction ( ) {
379
+ // decide which one back button action should run
380
+ let winner : BackButtonAction = null ;
381
+ this . _bbActions . forEach ( ( action : BackButtonAction ) => {
382
+ if ( ! winner || action . priority >= winner . priority ) {
383
+ winner = action ;
384
+ }
385
+ } ) ;
386
+
387
+ // run the winning action if there is one
388
+ winner && winner . fn && winner . fn ( ) ;
389
+ }
390
+
339
391
340
392
// Getter/Setter Methods
341
393
// **********************************************
342
394
343
395
/**
344
- * @private
345
- */
396
+ * @private
397
+ */
346
398
setUrl ( url : string ) {
347
399
this . _url = url ;
348
400
this . _qs = getQuerystring ( url ) ;
349
401
}
350
402
351
403
/**
352
- * @private
353
- */
404
+ * @private
405
+ */
354
406
url ( ) : string {
355
407
return this . _url ;
356
408
}
357
409
358
410
/**
359
- * @private
360
- */
411
+ * @private
412
+ */
361
413
query ( key : string ) : string {
362
414
return ( this . _qs || { } ) [ key ] ;
363
415
}
364
416
365
417
/**
366
- * @private
367
- */
418
+ * @private
419
+ */
368
420
setUserAgent ( userAgent : string ) {
369
421
this . _ua = userAgent ;
370
422
}
371
423
372
424
/**
373
- * @private
374
- */
425
+ * @private
426
+ */
375
427
userAgent ( ) : string {
376
428
return this . _ua || '' ;
377
429
}
378
430
379
431
/**
380
- * @private
381
- */
432
+ * @private
433
+ */
382
434
setNavigatorPlatform ( navigatorPlatform : string ) {
383
435
this . _bPlt = navigatorPlatform ;
384
436
}
385
437
386
438
/**
387
- * @private
388
- */
439
+ * @private
440
+ */
389
441
navigatorPlatform ( ) : string {
390
442
return this . _bPlt || '' ;
391
443
}
392
444
393
445
/**
394
- * @private
395
- */
446
+ * Gets the width of the platform's viewport using `window.innerWidth`.
447
+ * Using this method is preferred since the dimension is a cached value,
448
+ * which reduces the chance of multiple and expensive DOM reads.
449
+ */
396
450
width ( ) : number {
397
451
return windowDimensions ( ) . width ;
398
452
}
399
453
400
454
/**
401
- * @private
402
- */
455
+ * Gets the height of the platform's viewport using `window.innerHeight`.
456
+ * Using this method is preferred since the dimension is a cached value,
457
+ * which reduces the chance of multiple and expensive DOM reads.
458
+ */
403
459
height ( ) : number {
404
460
return windowDimensions ( ) . height ;
405
461
}
406
462
407
463
/**
408
- * @private
409
- */
464
+ * Returns `true` if the app is in portait mode.
465
+ */
410
466
isPortrait ( ) : boolean {
411
467
return this . width ( ) < this . height ( ) ;
412
468
}
413
469
414
470
/**
415
- * @private
416
- */
471
+ * Returns `true` if the app is in landscape mode.
472
+ */
417
473
isLandscape ( ) : boolean {
418
474
return ! this . isPortrait ( ) ;
419
475
}
420
476
421
477
/**
422
- * @private
423
- */
478
+ * @private
479
+ */
424
480
windowResize ( ) {
425
481
let self = this ;
426
482
clearTimeout ( self . _resizeTm ) ;
@@ -440,7 +496,6 @@ export class Platform {
440
496
441
497
/**
442
498
* @private
443
- * @returns Unregister function
444
499
*/
445
500
onResize ( cb : Function ) : Function {
446
501
let self = this ;
@@ -466,8 +521,8 @@ export class Platform {
466
521
}
467
522
468
523
/**
469
- * @private
470
- */
524
+ * @private
525
+ */
471
526
static registry ( ) {
472
527
return platformRegistry ;
473
528
}
@@ -782,3 +837,8 @@ export interface PlatformVersion {
782
837
major ?: number ;
783
838
minor ?: number ;
784
839
}
840
+
841
+ interface BackButtonAction {
842
+ fn : Function ;
843
+ priority : number ;
844
+ }
0 commit comments