From 5494cc38911b878556e70f18631e17a8f3ccc95b Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 2 Aug 2018 09:04:48 +0200 Subject: [PATCH] MOBILE-2538 splitview: Handle ionViewCanLeave in details pages --- src/components/split-view/split-view.ts | 67 +++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/src/components/split-view/split-view.ts b/src/components/split-view/split-view.ts index eb866c36a..86eae75ce 100644 --- a/src/components/split-view/split-view.ts +++ b/src/components/split-view/split-view.ts @@ -14,8 +14,9 @@ // Code based on https://github.com/martinpritchardelevate/ionic-split-pane-demo -import { Component, ViewChild, Input, ElementRef, OnInit, Optional } from '@angular/core'; -import { NavController, Nav } from 'ionic-angular'; +import { Component, ViewChild, Input, ElementRef, OnInit, Optional, OnDestroy } from '@angular/core'; +import { NavController, Nav, ViewController } from 'ionic-angular'; +import { Subscription } from 'rxjs'; /** * Directive to create a split view layout. @@ -40,7 +41,7 @@ import { NavController, Nav } from 'ionic-angular'; selector: 'core-split-view', templateUrl: 'core-split-view.html' }) -export class CoreSplitViewComponent implements OnInit { +export class CoreSplitViewComponent implements OnInit, OnDestroy { @ViewChild('detailNav') detailNav: Nav; @Input() when?: string | boolean = 'md'; @@ -49,6 +50,9 @@ export class CoreSplitViewComponent implements OnInit { protected masterPageIndex = 0; protected loadDetailPage: any = false; protected element: HTMLElement; // Current element. + protected detailsDidEnterSubscription: Subscription; + protected masterCanLeaveOverridden = false; + protected originalMasterCanLeave: Function; // Empty placeholder for the 'detail' page. detailPage: any = null; @@ -65,6 +69,8 @@ export class CoreSplitViewComponent implements OnInit { this.masterPageName = this.masterNav.getActive().component.name; this.masterPageIndex = this.masterNav.indexOf(this.masterNav.getActive()); this.emptyDetails(); + + this.handleCanLeave(); } /** @@ -89,6 +95,54 @@ export class CoreSplitViewComponent implements OnInit { return this.masterNav; } + /** + * Handle ionViewCanLeave functions in details page. By default, this function isn't captured by Ionic when + * clicking the back button, it only uses the one in the master page. + */ + handleCanLeave(): void { + // Listen for the didEnter event on the details nav to detect everytime a page is loaded. + this.detailsDidEnterSubscription = this.detailNav.viewDidEnter.subscribe((detailsViewController: ViewController) => { + const masterViewController = this.masterNav.getActive(); + + if (this.masterCanLeaveOverridden) { + // We've overridden the can leave of the master page for a previous details page. Restore it. + masterViewController.instance.ionViewCanLeave = this.originalMasterCanLeave; + this.originalMasterCanLeave = undefined; + this.masterCanLeaveOverridden = false; + } + + if (detailsViewController && detailsViewController.instance && detailsViewController.instance.ionViewCanLeave) { + // The details page defines a canLeave function. Check if the master page also defines one. + if (masterViewController.instance.ionViewCanLeave) { + // Master page also defines a canLeave function, store it because it will be overridden. + this.originalMasterCanLeave = masterViewController.instance.ionViewCanLeave; + } + + // Override the master canLeave function so it also calls the details canLeave. + this.masterCanLeaveOverridden = true; + + masterViewController.instance.ionViewCanLeave = (): Promise => { + // Always return a Promise. + return Promise.resolve().then(() => { + if (this.originalMasterCanLeave) { + // First call the master canLeave. + const result = this.originalMasterCanLeave(); + if (typeof result == 'boolean' && !result) { + // User cannot leave, return a rejected promise so the details canLeave isn't executed. + return Promise.reject(null); + } else { + return result; + } + } + }).then(() => { + // User can leave the master page. Check if he can also leave the details page. + return detailsViewController.instance.ionViewCanLeave(); + }); + }; + } + }); + } + /** * Check if both panels are shown. It depends on screen width. * @@ -168,4 +222,11 @@ export class CoreSplitViewComponent implements OnInit { this.masterNav.insert(this.masterPageIndex + 1, detailView.component, detailView.data); } } + + /** + * Component being destroyed. + */ + ngOnDestroy(): void { + this.detailsDidEnterSubscription && this.detailsDidEnterSubscription.unsubscribe(); + } }