UNPKG

ionic-angular

Version:

A powerful framework for building mobile and progressive web apps with JavaScript and Angular

1,056 lines 42.9 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); import { EventEmitter, Input, ReflectiveInjector } from '@angular/core'; import { DIRECTION_BACK, DIRECTION_FORWARD, INIT_ZINDEX, STATE_ATTACHED, STATE_DESTROYED, STATE_INITIALIZED, STATE_NEW, convertToViews, } from './nav-util'; import { setZIndex } from './nav-util'; import { isBlank, isNumber, isPresent, isTrueProperty } from '../util/util'; import { ViewController, isViewController } from './view-controller'; import { Ion } from '../components/ion'; import { NavController } from './nav-controller'; import { NavParams } from './nav-params'; import { SwipeBackGesture } from './swipe-back'; /** * @hidden * This class is for internal use only. It is not exported publicly. */ var NavControllerBase = (function (_super) { __extends(NavControllerBase, _super); function NavControllerBase(parent, _app, config, plt, elementRef, _zone, renderer, _cfr, _gestureCtrl, _trnsCtrl, _linker, _domCtrl, _errHandler) { var _this = _super.call(this, config, elementRef, renderer) || this; _this.parent = parent; _this._app = _app; _this.config = config; _this.plt = plt; _this._zone = _zone; _this._cfr = _cfr; _this._gestureCtrl = _gestureCtrl; _this._trnsCtrl = _trnsCtrl; _this._linker = _linker; _this._domCtrl = _domCtrl; _this._errHandler = _errHandler; _this._ids = -1; _this._init = false; _this._queue = []; _this._trnsId = null; _this._trnsTm = false; _this._views = []; _this._zIndexOffset = 0; _this.viewDidLoad = new EventEmitter(); _this.viewWillEnter = new EventEmitter(); _this.viewDidEnter = new EventEmitter(); _this.viewWillLeave = new EventEmitter(); _this.viewDidLeave = new EventEmitter(); _this.viewWillUnload = new EventEmitter(); _this._sbEnabled = config.getBoolean('swipeBackEnabled'); _this._children = []; _this.id = 'n' + (++ctrlIds); _this._destroyed = false; return _this; } Object.defineProperty(NavControllerBase.prototype, "swipeBackEnabled", { get: function () { return this._sbEnabled; }, set: function (val) { this._sbEnabled = isTrueProperty(val); this._swipeBackCheck(); }, enumerable: true, configurable: true }); NavControllerBase.prototype.push = function (page, params, opts, done) { return this._queueTrns({ insertStart: -1, insertViews: [{ page: page, params: params }], opts: opts, }, done); }; NavControllerBase.prototype.insert = function (insertIndex, page, params, opts, done) { return this._queueTrns({ insertStart: insertIndex, insertViews: [{ page: page, params: params }], opts: opts, }, done); }; NavControllerBase.prototype.insertPages = function (insertIndex, insertPages, opts, done) { return this._queueTrns({ insertStart: insertIndex, insertViews: insertPages, opts: opts, }, done); }; NavControllerBase.prototype.pop = function (opts, done) { return this._queueTrns({ removeStart: -1, removeCount: 1, opts: opts, }, done); }; NavControllerBase.prototype.popTo = function (indexOrViewCtrl, opts, done) { var config = { removeStart: -1, removeCount: -1, opts: opts }; if (isViewController(indexOrViewCtrl)) { config.removeView = indexOrViewCtrl; config.removeStart = 1; } else if (isNumber(indexOrViewCtrl)) { config.removeStart = indexOrViewCtrl + 1; } return this._queueTrns(config, done); }; NavControllerBase.prototype.popToRoot = function (opts, done) { return this._queueTrns({ removeStart: 1, removeCount: -1, opts: opts, }, done); }; NavControllerBase.prototype.popAll = function () { var promises = []; for (var i = this._views.length - 1; i >= 0; i--) { promises.push(this.pop(null)); } return Promise.all(promises); }; NavControllerBase.prototype.remove = function (startIndex, removeCount, opts, done) { if (removeCount === void 0) { removeCount = 1; } return this._queueTrns({ removeStart: startIndex, removeCount: removeCount, opts: opts, }, done); }; NavControllerBase.prototype.removeView = function (viewController, opts, done) { return this._queueTrns({ removeView: viewController, removeStart: 0, removeCount: 1, opts: opts, }, done); }; NavControllerBase.prototype.setRoot = function (pageOrViewCtrl, params, opts, done) { return this.setPages([{ page: pageOrViewCtrl, params: params }], opts, done); }; NavControllerBase.prototype.setPages = function (viewControllers, opts, done) { if (isBlank(opts)) { opts = {}; } // if animation wasn't set to true then default it to NOT animate if (opts.animate !== true) { opts.animate = false; } return this._queueTrns({ insertStart: 0, insertViews: viewControllers, removeStart: 0, removeCount: -1, opts: opts }, done); }; // _queueTrns() adds a navigation stack change to the queue and schedules it to run: // 1. _nextTrns(): consumes the next transition in the queue // 2. _viewInit(): initializes enteringView if required // 3. _viewTest(): ensures canLeave/canEnter returns true, so the operation can continue // 4. _postViewInit(): add/remove the views from the navigation stack // 5. _transitionInit(): initializes the visual transition if required and schedules it to run // 6. _viewAttachToDOM(): attaches the enteringView to the DOM // 7. _transitionStart(): called once the transition actually starts, it initializes the Animation underneath. // 8. _transitionFinish(): called once the transition finishes // 9. _cleanup(): syncs the navigation internal state with the DOM. For example it removes the pages from the DOM or hides/show them. NavControllerBase.prototype._queueTrns = function (ti, done) { var promise = new Promise(function (resolve, reject) { ti.resolve = resolve; ti.reject = reject; }); ti.done = done; // Normalize empty if (ti.insertViews && ti.insertViews.length === 0) { ti.insertViews = undefined; } // Enqueue transition instruction this._queue.push(ti); // if there isn't a transition already happening // then this will kick off this transition this._nextTrns(); return promise; }; NavControllerBase.prototype._success = function (result, ti) { if (this._queue === null) { this._fireError('nav controller was destroyed', ti); return; } this._init = true; this._trnsId = null; // ensure we're not transitioning here this.setTransitioning(false); this._swipeBackCheck(); // let's see if there's another to kick off this._nextTrns(); if (ti.done) { ti.done(result.hasCompleted, result.requiresTransition, result.enteringName, result.leavingName, result.direction); } ti.resolve(result.hasCompleted); }; NavControllerBase.prototype._failed = function (rejectReason, ti) { if (this._queue === null) { this._fireError('nav controller was destroyed', ti); return; } this._trnsId = null; this._queue.length = 0; // let's see if there's another to kick off this.setTransitioning(false); this._swipeBackCheck(); this._nextTrns(); this._fireError(rejectReason, ti); }; NavControllerBase.prototype._fireError = function (rejectReason, ti) { if (ti.done) { ti.done(false, false, rejectReason); } if (ti.reject && !this._destroyed) { ti.reject(rejectReason); } else { ti.resolve(false); } }; NavControllerBase.prototype._nextTrns = function () { var _this = this; // this is the framework's bread 'n butta function // only one transition is allowed at any given time if (this.isTransitioning()) { return false; } // there is no transition happening right now // get the next instruction var ti = this._queue.shift(); if (!ti) { return false; } // set that this nav is actively transitioning var enteringView; var leavingView; this._startTI(ti) .then(function () { return _this._loadLazyLoading(ti); }) .then(function () { leavingView = _this.getActive(); enteringView = _this._getEnteringView(ti, leavingView); if (!leavingView && !enteringView) { throw 'no views in the stack to be removed'; } if (enteringView && enteringView._state === STATE_NEW) { _this._viewInit(enteringView); } // Needs transition? ti.requiresTransition = (ti.enteringRequiresTransition || ti.leavingRequiresTransition) && enteringView !== leavingView; }) .then(function () { return _this._viewTest(enteringView, leavingView, ti); }) .then(function () { return _this._postViewInit(enteringView, leavingView, ti); }) .then(function () { return _this._transition(enteringView, leavingView, ti); }) .then(function (result) { return _this._success(result, ti); }) .catch(function (rejectReason) { return _this._failed(rejectReason, ti); }); return true; }; NavControllerBase.prototype._startTI = function (ti) { var viewsLength = this._views.length; if (isPresent(ti.removeView)) { (void 0) /* assert */; (void 0) /* assert */; var index = this.indexOf(ti.removeView); if (index < 0) { return Promise.reject('removeView was not found'); } ti.removeStart += index; } if (isPresent(ti.removeStart)) { if (ti.removeStart < 0) { ti.removeStart = (viewsLength - 1); } if (ti.removeCount < 0) { ti.removeCount = (viewsLength - ti.removeStart); } ti.leavingRequiresTransition = (ti.removeCount > 0) && ((ti.removeStart + ti.removeCount) === viewsLength); } if (ti.insertViews) { // allow -1 to be passed in to auto push it on the end // and clean up the index if it's larger then the size of the stack if (ti.insertStart < 0 || ti.insertStart > viewsLength) { ti.insertStart = viewsLength; } ti.enteringRequiresTransition = (ti.insertStart === viewsLength); } this.setTransitioning(true); return Promise.resolve(); }; NavControllerBase.prototype._loadLazyLoading = function (ti) { var _this = this; var insertViews = ti.insertViews; if (insertViews) { (void 0) /* assert */; return convertToViews(this._linker, insertViews).then(function (viewControllers) { (void 0) /* assert */; viewControllers = viewControllers.filter(function (v) { return v !== null; }); if (viewControllers.length === 0) { throw 'invalid views to insert'; } // Check all the inserted view are correct for (var i = 0; i < viewControllers.length; i++) { var view = viewControllers[i]; var nav = view._nav; if (nav && nav !== _this) { throw 'inserted view was already inserted'; } if (view._state === STATE_DESTROYED) { throw 'inserted view was already destroyed'; } } ti.insertViews = viewControllers; }); } return Promise.resolve(); }; NavControllerBase.prototype._getEnteringView = function (ti, leavingView) { var insertViews = ti.insertViews; if (insertViews) { // grab the very last view of the views to be inserted // and initialize it as the new entering view return insertViews[insertViews.length - 1]; } var removeStart = ti.removeStart; if (isPresent(removeStart)) { var views = this._views; var removeEnd = removeStart + ti.removeCount; var i; var view; for (i = views.length - 1; i >= 0; i--) { view = views[i]; if ((i < removeStart || i >= removeEnd) && view !== leavingView) { return view; } } } return null; }; NavControllerBase.prototype._postViewInit = function (enteringView, leavingView, ti) { var _this = this; (void 0) /* assert */; (void 0) /* assert */; (void 0) /* assert */; var opts = ti.opts || {}; var insertViews = ti.insertViews; var removeStart = ti.removeStart; var removeCount = ti.removeCount; var view; var i; var destroyQueue; // there are views to remove if (isPresent(removeStart)) { (void 0) /* assert */; (void 0) /* assert */; destroyQueue = []; for (i = 0; i < removeCount; i++) { view = this._views[i + removeStart]; if (view && view !== enteringView && view !== leavingView) { destroyQueue.push(view); } } // default the direction to "back" opts.direction = opts.direction || DIRECTION_BACK; } var finalBalance = this._views.length + (insertViews ? insertViews.length : 0) - (removeCount ? removeCount : 0); (void 0) /* assert */; if (finalBalance === 0 && !this._isPortal) { console.warn("You can't remove all the pages in the navigation stack. nav.pop() is probably called too many times.", this, this.getNativeElement()); throw 'navigation stack needs at least one root page'; } // At this point the transition can not be rejected, any throw should be an error // there are views to insert if (insertViews) { // manually set the new view's id if an id was passed in the options if (isPresent(opts.id)) { enteringView.id = opts.id; } // add the views to the for (i = 0; i < insertViews.length; i++) { view = insertViews[i]; this._insertViewAt(view, ti.insertStart + i); } if (ti.enteringRequiresTransition) { // default to forward if not already set opts.direction = opts.direction || DIRECTION_FORWARD; } } // if the views to be removed are in the beginning or middle // and there is not a view that needs to visually transition out // then just destroy them and don't transition anything // batch all of lifecycles together // let's make sure, callbacks are zoned if (destroyQueue && destroyQueue.length > 0) { this._zone.run(function () { for (i = 0; i < destroyQueue.length; i++) { view = destroyQueue[i]; _this._willLeave(view, true); _this._didLeave(view); _this._willUnload(view); } }); // once all lifecycle events has been delivered, we can safely detroy the views for (i = 0; i < destroyQueue.length; i++) { this._destroyView(destroyQueue[i]); } } // set which animation it should use if it wasn't set yet if (ti.requiresTransition && !opts.animation) { if (isPresent(ti.removeStart)) { opts.animation = (leavingView || enteringView).getTransitionName(opts.direction); } else { opts.animation = (enteringView || leavingView).getTransitionName(opts.direction); } } ti.opts = opts; }; /** * DOM WRITE */ NavControllerBase.prototype._viewInit = function (enteringView) { (void 0) /* assert */; (void 0) /* assert */; // render the entering view, and all child navs and views // entering view has not been initialized yet var componentProviders = ReflectiveInjector.resolve([ { provide: NavController, useValue: this }, { provide: ViewController, useValue: enteringView }, { provide: NavParams, useValue: enteringView.getNavParams() } ]); var componentFactory = this._linker.resolveComponent(enteringView.component); var childInjector = ReflectiveInjector.fromResolvedProviders(componentProviders, this._viewport.parentInjector); // create ComponentRef and set it to the entering view enteringView.init(componentFactory.create(childInjector, [])); enteringView._state = STATE_INITIALIZED; this._preLoad(enteringView); }; NavControllerBase.prototype._viewAttachToDOM = function (view, componentRef, viewport) { (void 0) /* assert */; (void 0) /* assert */; // fire willLoad before change detection runs this._willLoad(view); // render the component ref instance to the DOM // ******** DOM WRITE **************** viewport.insert(componentRef.hostView, viewport.length); view._state = STATE_ATTACHED; if (view._cssClass) { // the ElementRef of the actual ion-page created var pageElement = componentRef.location.nativeElement; // ******** DOM WRITE **************** this._renderer.setElementClass(pageElement, view._cssClass, true); } componentRef.changeDetectorRef.detectChanges(); // successfully finished loading the entering view // fire off the "didLoad" lifecycle events this._zone.run(this._didLoad.bind(this, view)); }; NavControllerBase.prototype._viewTest = function (enteringView, leavingView, ti) { // Only test canLeave/canEnter if there is transition if (!ti.requiresTransition) { return Promise.resolve(); } var promises = []; if (leavingView) { promises.push(leavingView._lifecycleTest('Leave')); } if (enteringView) { promises.push(enteringView._lifecycleTest('Enter')); } if (promises.length === 0) { return Promise.resolve(); } // darn, async promises, gotta wait for them to resolve return Promise.all(promises).then(function (values) { if (values.some(function (result) { return result === false; })) { throw 'canEnter/Leave returned false'; } }).catch(function (reason) { // Do not ti.reject = null; throw reason; }); }; NavControllerBase.prototype._transition = function (enteringView, leavingView, ti) { var _this = this; if (!ti.requiresTransition) { // transition is not required, so we are already done! // they're inserting/removing the views somewhere in the middle or // beginning, so visually nothing needs to animate/transition // resolve immediately because there's no animation that's happening return Promise.resolve({ hasCompleted: true, requiresTransition: false }); } var opts = ti.opts; // figure out if this transition is the root one or a // child of a parent nav that has the root transition this._trnsId = this._trnsCtrl.getRootTrnsId(this); if (this._trnsId === null) { // this is the root transition, meaning all child navs and their views // should be added as a child transition to this one this._trnsId = this._trnsCtrl.nextId(); } // create the transition options var animationOpts = { animation: opts.animation, direction: opts.direction, duration: (opts.animate === false ? 0 : opts.duration), easing: opts.easing, isRTL: this._config.plt.isRTL, ev: opts.ev, }; // create the transition animation from the TransitionController // this will either create the root transition, or add it as a child transition var transition = this._trnsCtrl.get(this._trnsId, enteringView, leavingView, animationOpts); // ensure any swipeback transitions are cleared out this._sbTrns && this._sbTrns.destroy(); this._sbTrns = null; // swipe to go back root transition if (transition.isRoot() && opts.progressAnimation) { this._sbTrns = transition; } // transition start has to be registered before attaching the view to the DOM! var promise = new Promise(function (resolve) { return transition.registerStart(resolve); }).then(function () { return _this._transitionStart(transition, enteringView, leavingView, opts); }); if (enteringView && (enteringView._state === STATE_INITIALIZED)) { // render the entering component in the DOM // this would also render new child navs/views // which may have their very own async canEnter/Leave tests // ******** DOM WRITE **************** this._viewAttachToDOM(enteringView, enteringView._cmp, this._viewport); } if (!transition.hasChildren) { // lowest level transition, so kick it off and let it bubble up to start all of them transition.start(); } return promise; }; NavControllerBase.prototype._transitionStart = function (transition, enteringView, leavingView, opts) { var _this = this; (void 0) /* assert */; this._trnsId = null; // set the correct zIndex for the entering and leaving views // ******** DOM WRITE **************** setZIndex(this, enteringView, leavingView, opts.direction, this._renderer); // always ensure the entering view is viewable // ******** DOM WRITE **************** enteringView && enteringView._domShow(true, this._renderer); // always ensure the leaving view is viewable // ******** DOM WRITE **************** leavingView && leavingView._domShow(true, this._renderer); // initialize the transition transition.init(); // we should animate (duration > 0) if the pushed page is not the first one (startup) // or if it is a portal (modal, actionsheet, etc.) var isFirstPage = !this._init && this._views.length === 1; var shouldNotAnimate = isFirstPage && !this._isPortal; var canNotAnimate = this._config.get('animate') === false; if (shouldNotAnimate || canNotAnimate) { opts.animate = false; } if (opts.animate === false) { // if it was somehow set to not animation, then make the duration zero transition.duration(0); } // create a callback that needs to run within zone // that will fire off the willEnter/Leave lifecycle events at the right time transition.beforeAddRead(this._viewsWillLifecycles.bind(this, enteringView, leavingView)); // get the set duration of this transition var duration = transition.getDuration(); // create a callback for when the animation is done var promise = new Promise(function (resolve) { transition.onFinish(resolve); }); if (transition.isRoot()) { // this is the top most, or only active transition, so disable the app // add XXms to the duration the app is disabled when the keyboard is open if (duration > DISABLE_APP_MINIMUM_DURATION && opts.disableApp !== false) { // if this transition has a duration and this is the root transition // then set that the app is actively disabled this._app.setEnabled(false, duration + ACTIVE_TRANSITION_OFFSET, opts.minClickBlockDuration); } else { (void 0) /* console.debug */; } // cool, let's do this, start the transition if (opts.progressAnimation) { // this is a swipe to go back, just get the transition progress ready // kick off the swipe animation start transition.progressStart(); } else { // only the top level transition should actually start "play" // kick it off and let it play through // ******** DOM WRITE **************** transition.play(); } } return promise.then(function () { return _this._zone.run(function () { return _this._transitionFinish(transition, opts); }); }); }; NavControllerBase.prototype._transitionFinish = function (transition, opts) { var hasCompleted = transition.hasCompleted; var enteringView = transition.enteringView; var leavingView = transition.leavingView; // mainly for testing var enteringName; var leavingName; if (hasCompleted) { // transition has completed (went from 0 to 1) if (enteringView) { enteringName = enteringView.name; this._didEnter(enteringView); } if (leavingView) { leavingName = leavingView.name; this._didLeave(leavingView); } this._cleanup(enteringView); /** * On iOS 12.2 there is a bug that * causes scrolling to not * be re-enabled unless there * is some kind of CSS reflow triggered */ var platform_1 = this.plt; if (enteringView && enteringView.getIONContentRef && enteringView.getIONContentRef() && platform_1.is('ios')) { platform_1.timeout(function () { platform_1.raf(function () { var content = enteringView.getIONContentRef().nativeElement; content.style.zIndex = '1'; platform_1.raf(function () { content.style.zIndex = ''; }); }); }, 500); } } else { // If transition does not complete, we have to cleanup anyway, because // previous pages in the stack are not hidden probably. this._cleanup(leavingView); } if (transition.isRoot()) { // this is the root transition // it's safe to destroy this transition this._trnsCtrl.destroy(transition.trnsId); // it's safe to enable the app again this._app.setEnabled(true); // mark ourselves as not transitioning - `deepLinker navchange` requires this // TODO - probably could be resolved in a better way this.setTransitioning(false); if (!this.hasChildren() && opts.updateUrl !== false) { // notify deep linker of the nav change // if a direction was provided and should update url this._linker.navChange(opts.direction); } if (opts.keyboardClose !== false) { // the keyboard is still open! // no problem, let's just close for them this.plt.focusOutActiveElement(); } } return { hasCompleted: hasCompleted, requiresTransition: true, enteringName: enteringName, leavingName: leavingName, direction: opts.direction }; }; NavControllerBase.prototype._viewsWillLifecycles = function (enteringView, leavingView) { var _this = this; if (enteringView || leavingView) { this._zone.run(function () { // Here, the order is important. WillLeave must be called before WillEnter. if (leavingView) { var willUnload = enteringView ? leavingView.index > enteringView.index : true; _this._willLeave(leavingView, willUnload); } enteringView && _this._willEnter(enteringView); }); } }; NavControllerBase.prototype._insertViewAt = function (view, index) { var existingIndex = this._views.indexOf(view); if (existingIndex > -1) { // this view is already in the stack!! // move it to its new location (void 0) /* assert */; this._views.splice(index, 0, this._views.splice(existingIndex, 1)[0]); } else { (void 0) /* assert */; // this is a new view to add to the stack // create the new entering view view._setNav(this); // give this inserted view an ID this._ids++; if (!view.id) { view.id = this.id + "-" + this._ids; } // insert the entering view into the correct index in the stack this._views.splice(index, 0, view); } }; NavControllerBase.prototype._removeView = function (view) { (void 0) /* assert */; var views = this._views; var index = views.indexOf(view); (void 0) /* assert */; if (index >= 0) { views.splice(index, 1); } }; NavControllerBase.prototype._destroyView = function (view) { view._destroy(this._renderer); this._removeView(view); }; /** * DOM WRITE */ NavControllerBase.prototype._cleanup = function (activeView) { // ok, cleanup time!! Destroy all of the views that are // INACTIVE and come after the active view // only do this if the views exist, though if (!this._destroyed) { var activeViewIndex = this._views.indexOf(activeView); var views = this._views; var reorderZIndexes = false; var view = void 0; var i = void 0; for (i = views.length - 1; i >= 0; i--) { view = views[i]; if (i > activeViewIndex) { // this view comes after the active view // let's unload it this._willUnload(view); this._destroyView(view); } else if (i < activeViewIndex && !this._isPortal) { // this view comes before the active view // and it is not a portal then ensure it is hidden view._domShow(false, this._renderer); } if (view._zIndex <= 0) { reorderZIndexes = true; } } if (!this._isPortal && reorderZIndexes) { for (i = 0; i < views.length; i++) { view = views[i]; // ******** DOM WRITE **************** view._setZIndex(view._zIndex + INIT_ZINDEX + 1, this._renderer); } } } }; NavControllerBase.prototype._preLoad = function (view) { (void 0) /* assert */; view._preLoad(); }; NavControllerBase.prototype._willLoad = function (view) { (void 0) /* assert */; try { view._willLoad(); } catch (e) { this._errHandler && this._errHandler.handleError(e); } }; NavControllerBase.prototype._didLoad = function (view) { (void 0) /* assert */; (void 0) /* assert */; try { view._didLoad(); this.viewDidLoad.emit(view); this._app.viewDidLoad.emit(view); } catch (e) { this._errHandler && this._errHandler.handleError(e); } }; NavControllerBase.prototype._willEnter = function (view) { (void 0) /* assert */; (void 0) /* assert */; try { view._willEnter(); this.viewWillEnter.emit(view); this._app.viewWillEnter.emit(view); } catch (e) { this._errHandler && this._errHandler.handleError(e); } }; NavControllerBase.prototype._didEnter = function (view) { (void 0) /* assert */; (void 0) /* assert */; try { view._didEnter(); this.viewDidEnter.emit(view); this._app.viewDidEnter.emit(view); } catch (e) { this._errHandler && this._errHandler.handleError(e); } }; NavControllerBase.prototype._willLeave = function (view, willUnload) { (void 0) /* assert */; (void 0) /* assert */; try { view._willLeave(willUnload); this.viewWillLeave.emit(view); this._app.viewWillLeave.emit(view); } catch (e) { this._errHandler && this._errHandler.handleError(e); } }; NavControllerBase.prototype._didLeave = function (view) { (void 0) /* assert */; (void 0) /* assert */; try { view._didLeave(); this.viewDidLeave.emit(view); this._app.viewDidLeave.emit(view); } catch (e) { this._errHandler && this._errHandler.handleError(e); } }; NavControllerBase.prototype._willUnload = function (view) { (void 0) /* assert */; (void 0) /* assert */; try { view._willUnload(); this.viewWillUnload.emit(view); this._app.viewWillUnload.emit(view); } catch (e) { this._errHandler && this._errHandler.handleError(e); } }; NavControllerBase.prototype.hasChildren = function () { return this._children && this._children.length > 0; }; NavControllerBase.prototype.getActiveChildNavs = function () { return this._children; }; NavControllerBase.prototype.getAllChildNavs = function () { return this._children; }; NavControllerBase.prototype.registerChildNav = function (container) { this._children.push(container); }; NavControllerBase.prototype.unregisterChildNav = function (nav) { this._children = this._children.filter(function (child) { return child !== nav; }); }; NavControllerBase.prototype.destroy = function () { var views = this._views; var view; for (var i = 0; i < views.length; i++) { view = views[i]; view._willUnload(); view._destroy(this._renderer); } // release swipe back gesture and transition this._sbGesture && this._sbGesture.destroy(); this._sbTrns && this._sbTrns.destroy(); this._queue = this._views = this._sbGesture = this._sbTrns = null; // Unregister navcontroller if (this.parent && this.parent.unregisterChildNav) { this.parent.unregisterChildNav(this); } else if (this._app) { this._app.unregisterRootNav(this); } this._destroyed = true; }; NavControllerBase.prototype.swipeBackStart = function () { if (this.isTransitioning() || this._queue.length > 0) { return; } // default the direction to "back"; var opts = { direction: DIRECTION_BACK, progressAnimation: true }; this._queueTrns({ removeStart: -1, removeCount: 1, opts: opts, }, null); }; NavControllerBase.prototype.swipeBackProgress = function (stepValue) { if (this._sbTrns && this._sbGesture) { // continue to disable the app while actively dragging this._app.setEnabled(false, ACTIVE_TRANSITION_DEFAULT); this.setTransitioning(true); // set the transition animation's progress this._sbTrns.progressStep(stepValue); } }; NavControllerBase.prototype.swipeBackEnd = function (shouldComplete, currentStepValue, velocity) { if (this._sbTrns && this._sbGesture) { // the swipe back gesture has ended var dur = this._sbTrns.getDuration() / (Math.abs(velocity) + 1); this._sbTrns.progressEnd(shouldComplete, currentStepValue, dur); } }; NavControllerBase.prototype._swipeBackCheck = function () { if (this.canSwipeBack()) { if (!this._sbGesture) { this._sbGesture = new SwipeBackGesture(this.plt, this, this._gestureCtrl, this._domCtrl); } this._sbGesture.listen(); } else if (this._sbGesture) { this._sbGesture.unlisten(); } }; NavControllerBase.prototype.canSwipeBack = function () { return (this._sbEnabled && !this._isPortal && !this._children.length && !this.isTransitioning() && this._app.isEnabled() && this.canGoBack()); }; NavControllerBase.prototype.canGoBack = function () { var activeView = this.getActive(); return !!(activeView && activeView.enableBack()); }; NavControllerBase.prototype.isTransitioning = function () { return this._trnsTm; }; NavControllerBase.prototype.setTransitioning = function (isTransitioning) { this._trnsTm = isTransitioning; }; NavControllerBase.prototype.getActive = function () { return this._views[this._views.length - 1]; }; NavControllerBase.prototype.isActive = function (view) { return (view === this.getActive()); }; NavControllerBase.prototype.getByIndex = function (index) { return this._views[index]; }; NavControllerBase.prototype.getPrevious = function (view) { // returns the view controller which is before the given view controller. if (!view) { view = this.getActive(); } var views = this._views; var index = views.indexOf(view); return (index > 0) ? views[index - 1] : null; }; NavControllerBase.prototype.first = function () { // returns the first view controller in this nav controller's stack. return this._views[0]; }; NavControllerBase.prototype.last = function () { // returns the last page in this nav controller's stack. var views = this._views; return views[views.length - 1]; }; NavControllerBase.prototype.indexOf = function (view) { // returns the index number of the given view controller. return this._views.indexOf(view); }; NavControllerBase.prototype.length = function () { return this._views.length; }; NavControllerBase.prototype.getViews = function () { return this._views; }; /** * Return a view controller */ NavControllerBase.prototype.getViewById = function (id) { for (var _i = 0, _a = this._views; _i < _a.length; _i++) { var vc = _a[_i]; if (vc && vc.id === id) { return vc; } } return null; }; NavControllerBase.prototype.isSwipeBackEnabled = function () { return this._sbEnabled; }; NavControllerBase.prototype.dismissPageChangeViews = function () { for (var _i = 0, _a = this._views; _i < _a.length; _i++) { var view = _a[_i]; if (view.data && view.data.dismissOnPageChange) { view.dismiss().catch(function () { }); } } }; NavControllerBase.prototype.setViewport = function (val) { this._viewport = val; }; NavControllerBase.prototype.resize = function () { var active = this.getActive(); if (!active) { return; } var content = active.getIONContent(); content && content.resize(); }; NavControllerBase.prototype.goToRoot = function (_opts) { return Promise.reject(new Error('goToRoot needs to be implemented by child class')); }; /* * @private */ NavControllerBase.prototype.getType = function () { return 'nav'; }; /* * @private */ NavControllerBase.prototype.getSecondaryIdentifier = function () { return null; }; /** * Returns the active child navigation. */ NavControllerBase.prototype.getActiveChildNav = function () { console.warn('(getActiveChildNav) is deprecated and will be removed in the next major release. Use getActiveChildNavs instead.'); return this._children[this._children.length - 1]; }; NavControllerBase.propDecorators = { 'swipeBackEnabled': [{ type: Input },], }; return NavControllerBase; }(Ion)); export { NavControllerBase }; var ctrlIds = -1; var DISABLE_APP_MINIMUM_DURATION = 64; var ACTIVE_TRANSITION_DEFAULT = 5000; var ACTIVE_TRANSITION_OFFSET = 2000; //# sourceMappingURL=nav-controller-base.js.map