mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-21 04:53:58 +08:00
refactor(navigation): ion-nav and ion-nav-controller are separate components
* nav-nav-nav-nav-nav * wipit * holy async batman
This commit is contained in:
@ -5,6 +5,7 @@ export interface AnimationController {
|
||||
export interface Animation {
|
||||
new (): Animation;
|
||||
parent: Animation;
|
||||
hasChildren: boolean;
|
||||
addElement(elm: Node|Node[]|NodeList): Animation;
|
||||
add(childAnimation: Animation): Animation;
|
||||
duration(milliseconds: number): Animation;
|
||||
@ -34,6 +35,9 @@ export interface Animation {
|
||||
progressEnd(shouldComplete: boolean, currentStepValue: number, dur: number): void;
|
||||
onFinish(callback: (animation?: Animation) => void, opts?: {oneTimeCallback?: boolean, clearExistingCallacks?: boolean}): Animation;
|
||||
destroy(): void;
|
||||
isRoot(): boolean;
|
||||
create(): Animation;
|
||||
hasCompleted: boolean;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1240,4 +1240,7 @@ export class Animator {
|
||||
return (this._hasTweenEffect && this._hasDur && this._elementTotal ? this._elements[0] : null);
|
||||
}
|
||||
|
||||
create() {
|
||||
return new Animator();
|
||||
}
|
||||
}
|
||||
|
123
packages/core/src/components/nav-controller/nav-controller.tsx
Normal file
123
packages/core/src/components/nav-controller/nav-controller.tsx
Normal file
@ -0,0 +1,123 @@
|
||||
import { Component, Element, Method, Prop } from '@stencil/core';
|
||||
import { AnimationController, Config } from '../..';
|
||||
import { ComponentDataPair, FrameworkDelegate, Nav, NavController, NavOptions, ViewController } from '../../navigation/nav-interfaces';
|
||||
|
||||
import { isReady } from '../../utils/helpers';
|
||||
|
||||
import {
|
||||
insert as insertImpl,
|
||||
insertPages as insertPagesImpl,
|
||||
pop as popImpl,
|
||||
popTo as popToImpl,
|
||||
popToRoot as popToRootImpl,
|
||||
push as pushImpl,
|
||||
remove as removeImpl,
|
||||
removeView as removeViewImpl,
|
||||
setPages as setPagesImpl,
|
||||
setRoot as setRootImpl,
|
||||
} from '../../navigation/nav-controller-functions';
|
||||
|
||||
let defaultDelegate: FrameworkDelegate = null;
|
||||
|
||||
@Component({
|
||||
tag: 'ion-nav-controller',
|
||||
})
|
||||
export class NavControllerImpl implements NavController {
|
||||
|
||||
@Element() element: HTMLElement;
|
||||
|
||||
@Prop({ connect: 'ion-animation-controller' }) animationCtrl: AnimationController;
|
||||
@Prop({ context: 'config' }) config: Config;
|
||||
@Prop() delegate: FrameworkDelegate;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
@Method()
|
||||
push(nav: Nav, component: any, data?: any, opts?: NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return pushImpl(nav, delegate, component, data, opts);
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
pop(nav: Nav, opts?: NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return popImpl(nav, delegate, opts);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Method()
|
||||
setRoot(nav: Nav, component: any, data?: any, opts?: NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return setRootImpl(nav, delegate, component, data, opts);
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
insert(nav: Nav, insertIndex: number, page: any, params?: any, opts?: NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return insertImpl(nav, delegate, insertIndex, page, params, opts);
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
insertPages(nav: Nav, insertIndex: number, insertPages: any[], opts?: NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return insertPagesImpl(nav, delegate, insertIndex, insertPages, opts);
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
popToRoot(nav: Nav, opts?: NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return popToRootImpl(nav, delegate, opts);
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
popTo(nav: Nav, indexOrViewCtrl: any, opts?: NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return popToImpl(nav, delegate, indexOrViewCtrl, opts);
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
remove(nav: Nav, startIndex: number, removeCount?: number, opts?: NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return removeImpl(nav, delegate, startIndex, removeCount, opts);
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
removeView(nav: Nav, viewController: ViewController, opts?: NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return removeViewImpl(nav, delegate, viewController, opts);
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
setPages(nav: Nav, componentDataPairs: ComponentDataPair[], opts? : NavOptions): Promise<any> {
|
||||
return getDelegate(this).then((delegate) => {
|
||||
return setPagesImpl(nav, delegate, componentDataPairs, opts);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return <slot></slot>;
|
||||
}
|
||||
}
|
||||
|
||||
export function getDelegate(navController: NavController): Promise<FrameworkDelegate> {
|
||||
if (navController.delegate) {
|
||||
return Promise.resolve(navController.delegate);
|
||||
}
|
||||
// no delegate is set, so fall back to inserting the stencil-ion-nav-delegate
|
||||
const element = document.createElement('stencil-ion-nav-delegate');
|
||||
document.body.appendChild(element);
|
||||
return isReady(element).then(() => {
|
||||
defaultDelegate = element as any as FrameworkDelegate;
|
||||
return defaultDelegate;
|
||||
})
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { Component, Method } from '@stencil/core';
|
||||
|
||||
import { StencilElement } from '../..';
|
||||
import { FrameworkDelegate, Nav, ViewController } from '../../navigation/nav-interfaces';
|
||||
|
||||
@Component({
|
||||
tag: 'stencil-ion-nav-delegate'
|
||||
})
|
||||
export class StencilNavDelegate implements FrameworkDelegate {
|
||||
|
||||
@Method()
|
||||
attachViewToDom(nav: Nav, enteringView: ViewController): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
const usersElement = document.createElement(enteringView.component);
|
||||
const ionPage = document.createElement('ion-page');
|
||||
enteringView.element = ionPage;
|
||||
ionPage.appendChild(usersElement);
|
||||
nav.element.appendChild(ionPage);
|
||||
(ionPage as StencilElement).componentOnReady(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
removeViewFromDom(nav: Nav, leavingView: ViewController): Promise<any> {
|
||||
nav.element.removeChild(leavingView.element);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
@ -1,16 +1,18 @@
|
||||
import { Component, Element, Method, Prop } from '@stencil/core';
|
||||
import { FrameworkDelegate, NavController, NavOptions, ViewController } from '../../navigation/nav-interfaces';
|
||||
import { getNextNavId, getViews, pop, push, setRoot } from '../../navigation/nav-controller-functions';
|
||||
import { AnimationController, Config } from '../..';
|
||||
import { ComponentDataPair, FrameworkDelegate, Nav, NavController, NavOptions, ViewController } from '../../navigation/nav-interfaces';
|
||||
|
||||
import { delegate as defaultStencilDelegate } from '../../navigation/stencil-framework-delegate';
|
||||
import { getActiveImpl, getFirstView, getPreviousImpl, getViews, init } from '../../navigation/nav-utils';
|
||||
import { isReady } from '../../utils/helpers';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-nav',
|
||||
})
|
||||
export class Nav implements NavController {
|
||||
export class IonNav implements Nav {
|
||||
|
||||
@Element() element: HTMLElement;
|
||||
id: number;
|
||||
parent: Nav;
|
||||
views: ViewController[];
|
||||
transitioning?: boolean;
|
||||
destroyed?: boolean;
|
||||
@ -18,10 +20,13 @@ export class Nav implements NavController {
|
||||
isViewInitialized?: boolean;
|
||||
isPortal: boolean;
|
||||
swipeToGoBackTransition: any; // TODO Transition
|
||||
childNavs?: NavController[];
|
||||
childNavs?: Nav[];
|
||||
navController?: NavController;
|
||||
|
||||
@Prop() root: any;
|
||||
@Prop() delegate: FrameworkDelegate;
|
||||
@Prop({ connect: 'ion-animation-controller' }) animationCtrl: AnimationController;
|
||||
@Prop({ context: 'config' }) config: Config;
|
||||
|
||||
constructor() {
|
||||
init(this);
|
||||
@ -35,22 +40,79 @@ export class Nav implements NavController {
|
||||
return getViews(this);
|
||||
}
|
||||
|
||||
getParent(): NavController {
|
||||
return null; // TODO
|
||||
@Method()
|
||||
push(component: any, data?: any, opts?: NavOptions) {
|
||||
return pushImpl(this, component, data, opts);
|
||||
}
|
||||
|
||||
@Method()
|
||||
push(component: any, data?: any, opts: NavOptions = {}) {
|
||||
return push(this, this.delegate || defaultStencilDelegate, component, data, opts);
|
||||
pop(opts?: NavOptions) {
|
||||
return popImpl(this, opts);
|
||||
}
|
||||
|
||||
@Method()
|
||||
pop(opts: NavOptions = {}) {
|
||||
return pop(this, this.delegate || defaultStencilDelegate, opts);
|
||||
setRoot(component: any, data?: any, opts?: NavOptions) {
|
||||
return setRootImpl(this, component, data, opts);
|
||||
}
|
||||
|
||||
setRoot(component: any, data?: any, opts: NavOptions = {}) {
|
||||
return setRoot(this, this.delegate || defaultStencilDelegate, component, data, opts);
|
||||
@Method()
|
||||
insert(insertIndex: number, page: any, params?: any, opts?: NavOptions) {
|
||||
return insertImpl(this, insertIndex, page, params, opts);
|
||||
}
|
||||
|
||||
@Method()
|
||||
insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions) {
|
||||
return insertPagesImpl(this, insertIndex, insertPages, opts);
|
||||
}
|
||||
|
||||
@Method()
|
||||
popToRoot(opts?: NavOptions) {
|
||||
return popToRootImpl(this, opts);
|
||||
}
|
||||
|
||||
@Method()
|
||||
popTo(indexOrViewCtrl: any, opts?: NavOptions) {
|
||||
return popToImpl(this, indexOrViewCtrl, opts);
|
||||
}
|
||||
|
||||
@Method()
|
||||
remove(startIndex: number, removeCount?: number, opts?: NavOptions) {
|
||||
return removeImpl(this, startIndex, removeCount, opts);
|
||||
}
|
||||
|
||||
@Method()
|
||||
removeView(viewController: ViewController, opts?: NavOptions) {
|
||||
return removeViewImpl(this, viewController, opts);
|
||||
}
|
||||
|
||||
@Method()
|
||||
setPages(componentDataPairs: ComponentDataPair[], opts? : NavOptions) {
|
||||
return setPagesImpl(this, componentDataPairs, opts);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getActive(): ViewController {
|
||||
return getActiveImpl(this);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getPrevious(view?: ViewController): ViewController {
|
||||
return getPreviousImpl(this, view);
|
||||
}
|
||||
|
||||
@Method()
|
||||
canGoBack(nav: Nav) {
|
||||
return nav.views && nav.views.length > 0;
|
||||
}
|
||||
|
||||
@Method()
|
||||
canSwipeBack() {
|
||||
return true; // TODO, implement this for real
|
||||
}
|
||||
|
||||
@Method()
|
||||
getFirstView() {
|
||||
return getFirstView(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -58,7 +120,70 @@ export class Nav implements NavController {
|
||||
}
|
||||
}
|
||||
|
||||
export function init(nav: NavController) {
|
||||
nav.id = getNextNavId();
|
||||
nav.views = [];
|
||||
export function pushImpl(nav: Nav, component: any, data: any, opts: NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.push(nav, component, data, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function popImpl(nav: Nav, opts: NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.pop(nav, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function setRootImpl(nav: Nav, component: any, data: any, opts: NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.setRoot(nav, component, data, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function insertImpl(nav: Nav, insertIndex: number, page: any, params: any, opts: NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.insert(nav, insertIndex, page, params, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function insertPagesImpl(nav: Nav, insertIndex: number, insertPages: any[], opts: NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.insertPages(nav, insertIndex, insertPages, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function popToRootImpl(nav: Nav, opts: NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.popToRoot(nav, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function popToImpl(nav: Nav, indexOrViewCtrl: any, opts: NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.popTo(nav, indexOrViewCtrl, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function removeImpl(nav: Nav, startIndex: number, removeCount: number, opts: NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.remove(nav, startIndex, removeCount, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function removeViewImpl(nav: Nav, viewController: ViewController, opts?: NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.removeView(nav, viewController, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function setPagesImpl(nav: Nav, componentDataPairs: ComponentDataPair[], opts? : NavOptions) {
|
||||
return getNavController(nav).then(() => {
|
||||
return nav.navController.setPages(nav, componentDataPairs, opts);
|
||||
});
|
||||
}
|
||||
|
||||
export function getNavController(nav: Nav): Promise<any> {
|
||||
if (nav.navController) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
nav.navController = document.querySelector('ion-nav-controller') as any as NavController;
|
||||
return isReady(nav.navController as any as HTMLElement);
|
||||
}
|
@ -7,6 +7,8 @@
|
||||
<script src="/dist/ionic.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<ion-nav-delegate></ion-nav-delegate>
|
||||
<ion-nav-controller delegateType="stencil"></ion-nav-controller>
|
||||
<ion-app>
|
||||
<ion-nav root="page-one"></ion-nav>
|
||||
</ion-app>
|
||||
|
@ -14,4 +14,12 @@ ion-page {
|
||||
height: 100%;
|
||||
|
||||
contain: strict;
|
||||
|
||||
// do not show, but still render so we can get dimensions
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
ion-page.show-page {
|
||||
// show the page now that it's ready
|
||||
opacity: 1;
|
||||
}
|
12
packages/core/src/index.d.ts
vendored
12
packages/core/src/index.d.ts
vendored
@ -1,4 +1,6 @@
|
||||
import { Animation, AnimationBuilder, AnimationController } from './components/animation-controller/animation-interface';
|
||||
import * as Stencil from '@stencil/core';
|
||||
|
||||
import { Animation, AnimationBuilder, AnimationController, AnimationOptions } from './components/animation-controller/animation-interface';
|
||||
import { ActionSheet, ActionSheetButton, ActionSheetEvent, ActionSheetOptions } from './components/action-sheet/action-sheet';
|
||||
import { ActionSheetController } from './components/action-sheet-controller/action-sheet-controller';
|
||||
import { Alert, AlertButton, AlertEvent, AlertInput, AlertOptions } from './components/alert/alert';
|
||||
@ -19,12 +21,12 @@ import { PopoverController } from './components/popover-controller/popover-contr
|
||||
import { Scroll, ScrollCallback, ScrollDetail } from './components/scroll/scroll';
|
||||
import { Segment } from './components/segment/segment';
|
||||
import { SegmentButton, SegmentButtonEvent } from './components/segment-button/segment-button';
|
||||
|
||||
import { Toast, ToastEvent, ToastOptions } from './components/toast/toast'
|
||||
import { ToastController } from './components/toast-controller/toast-controller'
|
||||
|
||||
import * as Stencil from '@stencil/core';
|
||||
|
||||
import { TransitionBuilder } from './navigation/nav-interfaces';
|
||||
|
||||
export interface Config {
|
||||
get: (key: string, fallback?: any) => any;
|
||||
@ -67,6 +69,7 @@ export {
|
||||
Animation,
|
||||
AnimationBuilder,
|
||||
AnimationController,
|
||||
AnimationOptions,
|
||||
Backdrop,
|
||||
GestureCallback,
|
||||
GestureDetail,
|
||||
@ -91,8 +94,13 @@ export {
|
||||
Segment,
|
||||
SegmentButton,
|
||||
SegmentButtonEvent,
|
||||
TransitionBuilder,
|
||||
Toast,
|
||||
ToastEvent,
|
||||
ToastOptions,
|
||||
ToastController
|
||||
}
|
||||
|
||||
export interface StencilElement extends HTMLElement {
|
||||
componentOnReady?: (cb: (elm?: StencilElement) => void) => void;
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
import { AnimationOptions } from '../components/animation-controller/animation-interface';
|
||||
import { Animation, AnimationOptions } from '../components/animation-controller/animation-interface';
|
||||
import {
|
||||
ComponentDataPair,
|
||||
FrameworkDelegate,
|
||||
NavController,
|
||||
Nav,
|
||||
NavOptions,
|
||||
NavResult,
|
||||
Transition,
|
||||
TransitionInstruction,
|
||||
ViewController
|
||||
} from './nav-interfaces';
|
||||
@ -14,47 +15,31 @@ import {
|
||||
DIRECTION_FORWARD,
|
||||
STATE_ATTACHED,
|
||||
STATE_DESTROYED,
|
||||
STATE_INITIALIZED,
|
||||
STATE_NEW,
|
||||
VIEW_ID_START,
|
||||
destroyTransition,
|
||||
getHydratedTransition,
|
||||
getNextTransitionId,
|
||||
getParentTransitionId,
|
||||
isViewController,
|
||||
setZIndex,
|
||||
toggleHidden
|
||||
toggleHidden,
|
||||
transitionFactory,
|
||||
} from './nav-utils';
|
||||
|
||||
|
||||
import { ViewControllerImpl } from './view-controller-impl';
|
||||
|
||||
import { assert, isDef, isNumber } from '../utils/helpers';
|
||||
import { NAV_ID_START, VIEW_ID_START } from '../utils/ids';
|
||||
|
||||
import { buildIOSTransition } from './transitions/transition.ios';
|
||||
import { buildMdTransition } from './transitions/transition.md';
|
||||
|
||||
const queueMap = new Map<number, TransitionInstruction[]>();
|
||||
|
||||
// public api
|
||||
export function canGoBack(nav: NavController) {
|
||||
return nav.views && nav.views.length > 0;
|
||||
}
|
||||
|
||||
export function canSwipeBack() {
|
||||
return true;
|
||||
// TODO - implement this for real
|
||||
}
|
||||
|
||||
export function getFirstView(nav: NavController): ViewController {
|
||||
return nav.views && nav.views.length > 0 ? nav.views[0] : null;
|
||||
}
|
||||
|
||||
export function getActiveView(nav: NavController): ViewController {
|
||||
return nav.views && nav.views.length > 0 ? nav.views[nav.views.length - 1] : null;
|
||||
}
|
||||
|
||||
export function getActiveChildNavs(nav: NavController): NavController[] {
|
||||
return nav.childNavs ? nav.childNavs : [];
|
||||
}
|
||||
|
||||
export function getViews(nav: NavController): ViewController[] {
|
||||
return nav.views ? nav.views : [];
|
||||
}
|
||||
|
||||
export function push(nav: NavController, delegate: FrameworkDelegate, component: any, data?: any, opts?: NavOptions, done? : () => void): Promise<any> {
|
||||
export function push(nav: Nav, delegate: FrameworkDelegate, component: any, data?: any, opts?: NavOptions, done? : () => void): Promise<any> {
|
||||
return queueTransaction({
|
||||
insertStart: -1,
|
||||
insertViews: [{page: component, params: data}],
|
||||
@ -65,7 +50,7 @@ export function push(nav: NavController, delegate: FrameworkDelegate, component:
|
||||
}, done);
|
||||
}
|
||||
|
||||
export function insert(nav: NavController, delegate: FrameworkDelegate, insertIndex: number, page: any, params?: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
export function insert(nav: Nav, delegate: FrameworkDelegate, insertIndex: number, page: any, params?: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
return queueTransaction({
|
||||
insertStart: insertIndex,
|
||||
insertViews: [{ page: page, params: params }],
|
||||
@ -76,7 +61,7 @@ export function insert(nav: NavController, delegate: FrameworkDelegate, insertIn
|
||||
}, done);
|
||||
}
|
||||
|
||||
export function insertPages(nav: NavController, delegate: FrameworkDelegate, insertIndex: number, insertPages: any[], opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
export function insertPages(nav: Nav, delegate: FrameworkDelegate, insertIndex: number, insertPages: any[], opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
return queueTransaction({
|
||||
insertStart: insertIndex,
|
||||
insertViews: insertPages,
|
||||
@ -87,7 +72,7 @@ export function insertPages(nav: NavController, delegate: FrameworkDelegate, ins
|
||||
}, done);
|
||||
}
|
||||
|
||||
export function pop(nav: NavController, delegate: FrameworkDelegate, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
export function pop(nav: Nav, delegate: FrameworkDelegate, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
return queueTransaction({
|
||||
removeStart: -1,
|
||||
removeCount: 1,
|
||||
@ -98,7 +83,7 @@ export function pop(nav: NavController, delegate: FrameworkDelegate, opts?: NavO
|
||||
}, done);
|
||||
}
|
||||
|
||||
export function popToRoot(nav: NavController, delegate: FrameworkDelegate, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
export function popToRoot(nav: Nav, delegate: FrameworkDelegate, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
return queueTransaction({
|
||||
removeStart: 1,
|
||||
removeCount: -1,
|
||||
@ -109,7 +94,7 @@ export function popToRoot(nav: NavController, delegate: FrameworkDelegate, opts?
|
||||
}, done);
|
||||
}
|
||||
|
||||
export function popTo(nav: NavController, delegate: FrameworkDelegate, indexOrViewCtrl: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
export function popTo(nav: Nav, delegate: FrameworkDelegate, indexOrViewCtrl: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
const config: TransitionInstruction = {
|
||||
removeStart: -1,
|
||||
removeCount: -1,
|
||||
@ -127,7 +112,7 @@ export function popTo(nav: NavController, delegate: FrameworkDelegate, indexOrVi
|
||||
return queueTransaction(config, done);
|
||||
}
|
||||
|
||||
export function remove(nav: NavController, delegate: FrameworkDelegate, startIndex: number, removeCount: number = 1, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
export function remove(nav: Nav, delegate: FrameworkDelegate, startIndex: number, removeCount: number = 1, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
return queueTransaction({
|
||||
removeStart: startIndex,
|
||||
removeCount: removeCount,
|
||||
@ -138,7 +123,7 @@ export function remove(nav: NavController, delegate: FrameworkDelegate, startInd
|
||||
}, done);
|
||||
}
|
||||
|
||||
export function removeView(nav: NavController, delegate: FrameworkDelegate, viewController: ViewController, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
export function removeView(nav: Nav, delegate: FrameworkDelegate, viewController: ViewController, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
return queueTransaction({
|
||||
removeView: viewController,
|
||||
removeStart: 0,
|
||||
@ -150,11 +135,11 @@ export function removeView(nav: NavController, delegate: FrameworkDelegate, view
|
||||
}, done);
|
||||
}
|
||||
|
||||
export function setRoot(nav: NavController, delegate: FrameworkDelegate, page: any, params?: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
export function setRoot(nav: Nav, delegate: FrameworkDelegate, page: any, params?: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
return setPages(nav, delegate, [{ page: page, params: params }], opts, done);
|
||||
}
|
||||
|
||||
export function setPages(nav: NavController, delegate: FrameworkDelegate, componentDataPars: ComponentDataPair[], opts? : NavOptions, done?: () => void): Promise<any> {
|
||||
export function setPages(nav: Nav, delegate: FrameworkDelegate, componentDataPars: ComponentDataPair[], opts? : NavOptions, done?: () => void): Promise<any> {
|
||||
if (!isDef(opts)) {
|
||||
opts = {};
|
||||
}
|
||||
@ -207,7 +192,7 @@ export function queueTransaction(ti: TransitionInstruction, done: () => void): P
|
||||
return promise;
|
||||
}
|
||||
|
||||
export function nextTransaction(nav: NavController): Promise<any> {
|
||||
export function nextTransaction(nav: Nav): Promise<any> {
|
||||
|
||||
if (nav.transitioning) {
|
||||
return Promise.resolve();
|
||||
@ -218,7 +203,13 @@ export function nextTransaction(nav: NavController): Promise<any> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return initializeViewBeforeTransition(topTransaction).then(([enteringView, leavingView]) => {
|
||||
let enteringView: ViewController;
|
||||
let leavingView: ViewController;
|
||||
return initializeViewBeforeTransition(topTransaction).then(([_enteringView, _leavingView]) => {
|
||||
enteringView = _enteringView;
|
||||
leavingView = _leavingView;
|
||||
return attachViewToDom(nav, enteringView, topTransaction.delegate);
|
||||
}).then(() => {
|
||||
return loadViewAndTransition(nav, enteringView, leavingView, topTransaction);
|
||||
}).then((result: NavResult) => {
|
||||
return successfullyTransitioned(result, topTransaction);
|
||||
@ -253,7 +244,6 @@ export function successfullyTransitioned(result: NavResult, ti: TransitionInstru
|
||||
);
|
||||
}
|
||||
ti.resolve(result.hasCompleted);
|
||||
console.log('success');
|
||||
}
|
||||
|
||||
export function transitionFailed(error: Error, ti: TransitionInstruction) {
|
||||
@ -274,7 +264,6 @@ export function transitionFailed(error: Error, ti: TransitionInstruction) {
|
||||
nextTransaction(ti.nav);
|
||||
|
||||
fireError(error, ti);
|
||||
console.log('fail');
|
||||
}
|
||||
|
||||
export function fireError(error: Error, ti: TransitionInstruction) {
|
||||
@ -288,7 +277,7 @@ export function fireError(error: Error, ti: TransitionInstruction) {
|
||||
}
|
||||
}
|
||||
|
||||
export function loadViewAndTransition(nav: NavController, enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction) {
|
||||
export function loadViewAndTransition(nav: Nav, enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction) {
|
||||
if (!ti.requiresTransition) {
|
||||
// transition is not required, so we are already done!
|
||||
// they're inserting/removing the views somewhere in the middle or
|
||||
@ -300,8 +289,9 @@ export function loadViewAndTransition(nav: NavController, enteringView: ViewCont
|
||||
});
|
||||
}
|
||||
|
||||
// TODO - transitionId
|
||||
nav.transitionId = 1; //getRootTransitionId(nav) || nextId();
|
||||
let transition: Transition = null;
|
||||
const transitionId = getParentTransitionId(nav);
|
||||
nav.transitionId = transitionId >= 0 ? transitionId : getNextTransitionId();
|
||||
|
||||
// create the transition options
|
||||
const animationOpts: AnimationOptions = {
|
||||
@ -313,12 +303,11 @@ export function loadViewAndTransition(nav: NavController, enteringView: ViewCont
|
||||
ev: ti.opts.event,
|
||||
};
|
||||
|
||||
// TODO - need transition here
|
||||
const transition: any = {
|
||||
opts: animationOpts
|
||||
};// new DanTransition(enteringView, leavingView, animationOpts);
|
||||
|
||||
//const transition = getTransition(stateData.transitionId, enteringView, animationOpts);
|
||||
return nav.animationCtrl.create().then((animation: Animation) => {
|
||||
const emptyTransition = transitionFactory(animation);
|
||||
console.log('nav.config: ', nav.config);
|
||||
console.log('mode: ', nav.config.get('mode'));
|
||||
transition = getHydratedTransition(animationOpts.animation, nav.config, nav.transitionId, emptyTransition, enteringView, leavingView, animationOpts, buildMdTransition);
|
||||
|
||||
if (nav.swipeToGoBackTransition) {
|
||||
nav.swipeToGoBackTransition.destroy();
|
||||
@ -330,30 +319,17 @@ export function loadViewAndTransition(nav: NavController, enteringView: ViewCont
|
||||
nav.swipeToGoBackTransition = transition;
|
||||
}
|
||||
|
||||
// use the resolve function of this promise to trigger the
|
||||
// beginTransitioning method
|
||||
const promiseToReturn = new Promise<any>((resolve) => {
|
||||
transition.registerStart(resolve);
|
||||
});
|
||||
|
||||
|
||||
return attachViewToDom(nav, enteringView, ti.delegate).then(() => {
|
||||
if (!transition.hasChildren) {
|
||||
// lowest level transition, so kick it off and let it bubble up to start all of them
|
||||
transition.start();
|
||||
}
|
||||
return promiseToReturn;
|
||||
}).then(() => {
|
||||
// TODO - get the shouldAnimate param from the config
|
||||
return executeAsyncTransition(nav, transition, enteringView, leavingView, ti.opts, false);
|
||||
return executeAsyncTransition(nav, transition, enteringView, leavingView, ti.delegate, ti.opts, ti.nav.config.getBoolean('animate'));
|
||||
});
|
||||
}
|
||||
|
||||
// TODO - transition type
|
||||
export function executeAsyncTransition(nav: NavController, transition: any, enteringView: ViewController, leavingView: ViewController, opts: NavOptions, configShouldAnimate: boolean): Promise<NavResult> {
|
||||
export function executeAsyncTransition(nav: Nav, transition: Transition, enteringView: ViewController, leavingView: ViewController, delegate: FrameworkDelegate, opts: NavOptions, configShouldAnimate: boolean): Promise<NavResult> {
|
||||
assert(nav.transitioning, 'must be transitioning');
|
||||
nav.transitionId = null;
|
||||
setZIndex(nav.isPortal, enteringView, leavingView, opts.direction);
|
||||
setZIndex(nav, enteringView, leavingView, opts.direction);
|
||||
|
||||
// always ensure the entering view is viewable
|
||||
// ******** DOM WRITE ****************
|
||||
@ -364,15 +340,13 @@ export function executeAsyncTransition(nav: NavController, transition: any, ente
|
||||
// ******** DOM WRITE ****************
|
||||
leavingView && toggleHidden(leavingView.element, true, true);
|
||||
|
||||
// initialize the transition
|
||||
transition.init()
|
||||
|
||||
const shouldNotAnimate = (!nav.isViewInitialized && nav.views.length === 1) && !nav.isPortal;
|
||||
if (configShouldAnimate === false || shouldNotAnimate) {
|
||||
const isFirstPage = !nav.isViewInitialized && nav.views.length === 1;
|
||||
const shouldNotAnimate = isFirstPage && !nav.isPortal;
|
||||
if (configShouldAnimate || shouldNotAnimate) {
|
||||
opts.animate = false;
|
||||
}
|
||||
|
||||
if (!opts.animate) {
|
||||
if (opts.animate === false) {
|
||||
// if it was somehow set to not animation, then make the duration zero
|
||||
transition.duration(0);
|
||||
}
|
||||
@ -412,25 +386,27 @@ export function executeAsyncTransition(nav: NavController, transition: any, ente
|
||||
}
|
||||
|
||||
return transitionCompletePromise.then(() => {
|
||||
return transitionFinish(nav, transition, opts);
|
||||
return transitionFinish(nav, transition, delegate, opts);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO - transition type
|
||||
export function transitionFinish(nav: NavController, transition: any, opts: NavOptions): NavResult {
|
||||
export function transitionFinish(nav: Nav, transition: Transition, delegate: FrameworkDelegate, opts: NavOptions): Promise<NavResult> {
|
||||
|
||||
let promise: Promise<any> = null;
|
||||
|
||||
if (transition.hasCompleted) {
|
||||
transition.enteringView && transition.enteringView.didEnter();
|
||||
transition.leavingView && transition.leavingView.didLeave();
|
||||
|
||||
cleanUpView(nav, transition.enteringView);
|
||||
promise = cleanUpView(nav, delegate, transition.enteringView);
|
||||
} else {
|
||||
cleanUpView(nav, transition.leavingView);
|
||||
promise = cleanUpView(nav, delegate, transition.leavingView);
|
||||
}
|
||||
|
||||
return promise.then(() => {
|
||||
if (transition.isRoot()) {
|
||||
|
||||
// TODO - destroy the transition object
|
||||
//destroy(transition.transitionId);
|
||||
destroyTransition(transition.transitionId);
|
||||
|
||||
// TODO - enable app
|
||||
|
||||
@ -448,19 +424,23 @@ export function transitionFinish(nav: NavController, transition: any, opts: NavO
|
||||
requiresTransition: true,
|
||||
direction: opts.direction
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function cleanUpView(nav: NavController, activeViewController: ViewController) {
|
||||
export function cleanUpView(nav: Nav, delegate: FrameworkDelegate, activeViewController: ViewController): Promise<any> {
|
||||
|
||||
if (nav.destroyed) {
|
||||
return;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const activeIndex = nav.views.indexOf(activeViewController);
|
||||
const promises: Promise<any>[] = [];
|
||||
for (let i = nav.views.length - 1; i >= 0; i--) {
|
||||
const inactiveViewController = nav.views[i];
|
||||
if (i > activeIndex) {
|
||||
// this view comes after the active view
|
||||
inactiveViewController.willUnload();
|
||||
destroyView(nav, inactiveViewController);
|
||||
promises.push(destroyView(nav, delegate, inactiveViewController));
|
||||
} else if ( i < activeIndex && !nav.isPortal) {
|
||||
// this view comes before the active view
|
||||
// and it is not a portal then ensure it is hidden
|
||||
@ -468,6 +448,7 @@ export function cleanUpView(nav: NavController, activeViewController: ViewContro
|
||||
}
|
||||
// TODO - review existing z index code!
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
|
||||
@ -476,8 +457,14 @@ export function fireViewWillLifecycles(enteringView: ViewController, leavingView
|
||||
enteringView && enteringView.willEnter();
|
||||
}
|
||||
|
||||
export function attachViewToDom(nav: NavController, enteringView: ViewController, delegate: FrameworkDelegate) {
|
||||
return delegate.attachViewToDom(nav, enteringView);
|
||||
export function attachViewToDom(nav: Nav, enteringView: ViewController, delegate: FrameworkDelegate) {
|
||||
if (enteringView && enteringView.state === STATE_NEW) {
|
||||
return delegate.attachViewToDom(nav, enteringView).then(() => {
|
||||
enteringView.state = STATE_ATTACHED;
|
||||
});
|
||||
}
|
||||
// it's in the wrong state, so don't attach and just return
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export function initializeViewBeforeTransition(ti: TransitionInstruction): Promise<ViewController[]> {
|
||||
@ -486,7 +473,7 @@ export function initializeViewBeforeTransition(ti: TransitionInstruction): Promi
|
||||
return startTransaction(ti).then(() => {
|
||||
const viewControllers = convertComponentToViewController(ti);
|
||||
ti.insertViews = viewControllers;
|
||||
leavingView = getActiveView(ti.nav);
|
||||
leavingView = ti.nav.getActive();
|
||||
enteringView = getEnteringView(ti, ti.nav, leavingView);
|
||||
|
||||
if (!leavingView && !enteringView) {
|
||||
@ -494,7 +481,7 @@ export function initializeViewBeforeTransition(ti: TransitionInstruction): Promi
|
||||
}
|
||||
|
||||
// mark state as initialized
|
||||
enteringView.state = STATE_INITIALIZED;
|
||||
//enteringView.state = STATE_INITIALIZED;
|
||||
ti.requiresTransition = (ti.enteringRequiresTransition || ti.leavingRequiresTransition) && enteringView !== leavingView;
|
||||
return testIfViewsCanLeaveAndEnter(enteringView, leavingView, ti);
|
||||
}).then(() => {
|
||||
@ -570,7 +557,7 @@ export function updateNavStacks(enteringView: ViewController, leavingView: ViewC
|
||||
|
||||
const destroyQueuePromises: Promise<any>[] = [];
|
||||
for (const viewController of destroyQueue) {
|
||||
destroyQueuePromises.push(destroyView(ti.nav, viewController));
|
||||
destroyQueuePromises.push(destroyView(ti.nav, ti.delegate, viewController));
|
||||
}
|
||||
return Promise.all(destroyQueuePromises);
|
||||
}
|
||||
@ -587,13 +574,13 @@ export function updateNavStacks(enteringView: ViewController, leavingView: ViewC
|
||||
});
|
||||
}
|
||||
|
||||
export function destroyView(nav: NavController, viewController: ViewController) {
|
||||
return viewController.destroy().then(() => {
|
||||
export function destroyView(nav: Nav, delegate: FrameworkDelegate, viewController: ViewController) {
|
||||
return viewController.destroy(delegate).then(() => {
|
||||
return removeViewFromList(nav, viewController);
|
||||
});
|
||||
}
|
||||
|
||||
export function removeViewFromList(nav: NavController, viewController: ViewController) {
|
||||
export function removeViewFromList(nav: Nav, viewController: ViewController) {
|
||||
assert(viewController.state === STATE_ATTACHED || viewController.state === STATE_DESTROYED, 'view state should be loaded or destroyed');
|
||||
const index = nav.views.indexOf(viewController);
|
||||
assert(index > -1, 'view must be part of the stack');
|
||||
@ -602,7 +589,7 @@ export function removeViewFromList(nav: NavController, viewController: ViewContr
|
||||
}
|
||||
}
|
||||
|
||||
export function insertViewIntoNav(nav: NavController, view: ViewController, index: number) {
|
||||
export function insertViewIntoNav(nav: Nav, view: ViewController, index: number) {
|
||||
const existingIndex = nav.views.indexOf(view);
|
||||
if (existingIndex > -1) {
|
||||
// this view is already in the stack!!
|
||||
@ -709,7 +696,7 @@ export function startTransaction(ti: TransitionInstruction): Promise<any> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export function getEnteringView(ti: TransitionInstruction, nav: NavController, leavingView: ViewController): ViewController {
|
||||
export function getEnteringView(ti: TransitionInstruction, nav: Nav, leavingView: ViewController): ViewController {
|
||||
if (ti.insertViews && ti.insertViews.length) {
|
||||
// grab the very last view of the views to be inserted
|
||||
// and initialize it as the new entering view
|
||||
@ -732,8 +719,7 @@ export function convertViewsToViewControllers(views: any[]): ViewController[] {
|
||||
if (isViewController(view)) {
|
||||
return view as ViewController;
|
||||
}
|
||||
// TODO - make this clean
|
||||
return (new ViewControllerImpl(view.page, view.params) as any) as ViewController;
|
||||
return new ViewControllerImpl(view.page, view.params);
|
||||
}
|
||||
return null;
|
||||
}).filter(view => !!view);
|
||||
@ -786,10 +772,6 @@ export function getTopTransaction(id: number) {
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
export function getNextNavId() {
|
||||
return navControllerIds++;
|
||||
}
|
||||
|
||||
let navControllerIds = NAV_ID_START;
|
||||
let viewIds = VIEW_ID_START;
|
||||
const DISABLE_APP_MINIMUM_DURATION = 64;
|
64
packages/core/src/navigation/nav-interfaces.d.ts
vendored
64
packages/core/src/navigation/nav-interfaces.d.ts
vendored
@ -1,21 +1,47 @@
|
||||
import {
|
||||
Animation,
|
||||
AnimationController,
|
||||
AnimationOptions,
|
||||
Config
|
||||
} from '..';
|
||||
|
||||
export interface FrameworkDelegate {
|
||||
attachViewToDom(navController: NavController, enteringView: ViewController): Promise<any>;
|
||||
removeViewFromDom(navController: NavController, leavingView: ViewController): Promise<any>;
|
||||
destroy(viewController: ViewController): Promise<any>;
|
||||
attachViewToDom(navController: Nav, enteringView: ViewController): Promise<any>;
|
||||
removeViewFromDom(navController: Nav, leavingView: ViewController): Promise<any>;
|
||||
}
|
||||
|
||||
export interface NavController {
|
||||
id: number;
|
||||
element: HTMLElement;
|
||||
export interface Nav {
|
||||
id?: number;
|
||||
element?: HTMLElement;
|
||||
views?: ViewController[];
|
||||
transitioning?: boolean;
|
||||
destroyed?: boolean;
|
||||
transitionId?: number;
|
||||
isViewInitialized?: boolean;
|
||||
isPortal?: boolean;
|
||||
zIndexOffset?: number;
|
||||
swipeToGoBackTransition?: any; // TODO Transition
|
||||
getParent(): NavController;
|
||||
childNavs?: NavController[]; // TODO - make nav container
|
||||
navController?: NavController;
|
||||
parent?: Nav;
|
||||
getActive(): ViewController;
|
||||
getPrevious(view?: ViewController): ViewController;
|
||||
childNavs?: Nav[]; // TODO - make nav container
|
||||
animationCtrl?: AnimationController;
|
||||
config?: Config;
|
||||
}
|
||||
|
||||
export interface NavController {
|
||||
push(nav: Nav, component: any, data: any, opts: NavOptions): Promise<any>;
|
||||
pop(nav: Nav, opts: NavOptions): Promise<any>;
|
||||
setRoot(nav: Nav, component: any, data: any, opts: NavOptions): Promise<any>;
|
||||
insert(nav: Nav, insertIndex: number, page: any, params: any, opts: NavOptions): Promise<any>;
|
||||
insertPages(nav: Nav, insertIndex: number, insertPages: any[], opts?: NavOptions): Promise<any>;
|
||||
popToRoot(nav: Nav, opts: NavOptions): Promise<any>;
|
||||
popTo(nav: Nav, indexOrViewCtrl: any, opts?: NavOptions): Promise<any>;
|
||||
remove(nav: Nav, startIndex: number, removeCount: number, opts: NavOptions): Promise<any>;
|
||||
removeView(nav: Nav, viewController: ViewController, opts?: NavOptions): Promise<any>;
|
||||
setPages(nav: Nav, componentDataPairs: ComponentDataPair[], opts? : NavOptions): Promise<any>;
|
||||
delegate?: FrameworkDelegate;
|
||||
}
|
||||
|
||||
export interface ViewController {
|
||||
@ -25,9 +51,9 @@ export interface ViewController {
|
||||
element: HTMLElement;
|
||||
instance: any;
|
||||
state: number;
|
||||
nav: NavController;
|
||||
frameworkDelegate: FrameworkDelegate;
|
||||
nav: Nav;
|
||||
dismissProxy?: any;
|
||||
zIndex: number;
|
||||
|
||||
// life cycle events
|
||||
willLeave(unload: boolean): void;
|
||||
@ -38,7 +64,7 @@ export interface ViewController {
|
||||
didLoad(): void;
|
||||
willUnload():void;
|
||||
|
||||
destroy(): Promise<any>;
|
||||
destroy(delegate?: FrameworkDelegate): Promise<any>;
|
||||
getTransitionName(direction: string): string;
|
||||
onDidDismiss: (data: any, role: string) => void;
|
||||
onWillDismiss: (data: any, role: string) => void;
|
||||
@ -81,7 +107,7 @@ export interface TransitionInstruction {
|
||||
enteringRequiresTransition?: boolean;
|
||||
requiresTransition?: boolean;
|
||||
id?: number;
|
||||
nav?: NavController;
|
||||
nav?: Nav;
|
||||
delegate?: FrameworkDelegate;
|
||||
}
|
||||
|
||||
@ -95,3 +121,17 @@ export interface ComponentDataPair {
|
||||
page: any;
|
||||
params: any;
|
||||
}
|
||||
|
||||
export interface Transition extends Animation {
|
||||
enteringView?: ViewController;
|
||||
leavingView?: ViewController;
|
||||
transitionStartFunction?: Function;
|
||||
transitionId?: number;
|
||||
registerTransitionStart(callback: Function): void;
|
||||
start(): void;
|
||||
originalDestroy(): void; // this is intended to be private, don't use this bad boy
|
||||
}
|
||||
|
||||
export interface TransitionBuilder {
|
||||
(rootTransition: Transition, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions ): Transition;
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
import { ViewController } from './nav-interfaces';
|
||||
import { Nav, Transition, ViewController } from './nav-interfaces';
|
||||
import { Animation, AnimationOptions, Config, TransitionBuilder } from '..';
|
||||
import { isDef } from '../utils/helpers'
|
||||
|
||||
export const STATE_NEW = 1;
|
||||
export const STATE_INITIALIZED = 2;
|
||||
@ -6,6 +8,7 @@ export const STATE_ATTACHED = 3;
|
||||
export const STATE_DESTROYED = 4;
|
||||
|
||||
export const INIT_ZINDEX = 100;
|
||||
export const PORTAL_Z_INDEX_OFFSET = 0;
|
||||
|
||||
export const DIRECTION_BACK = 'back';
|
||||
export const DIRECTION_FORWARD = 'forward';
|
||||
@ -14,14 +17,49 @@ export const DIRECTION_SWITCH = 'switch';
|
||||
export const NAV = 'nav';
|
||||
export const TABS = 'tabs';
|
||||
|
||||
export let NAV_ID_START = 1000;
|
||||
export let VIEW_ID_START = 2000;
|
||||
|
||||
let transitionIds = 0;
|
||||
let activeTransitions = new Map<number, any>();
|
||||
|
||||
let portalZindex = 9999;
|
||||
|
||||
export function isViewController(object: any): boolean {
|
||||
return !!(object && object.didLoad && object.willUnload);
|
||||
}
|
||||
|
||||
export function setZIndex(_isPortal: boolean, _enteringView: ViewController, _leavingView: ViewController, _direction: string) {
|
||||
// TODO
|
||||
export function setZIndex(nav: Nav, enteringView: ViewController, leavingView: ViewController, direction: string) {
|
||||
if (enteringView) {
|
||||
if (nav.isPortal) {
|
||||
if (direction === DIRECTION_FORWARD) {
|
||||
updateZIndex(enteringView, nav.zIndexOffset + portalZindex);
|
||||
}
|
||||
portalZindex++;
|
||||
return;
|
||||
}
|
||||
|
||||
leavingView = leavingView || nav.getPrevious(enteringView);
|
||||
|
||||
if (leavingView && isDef(leavingView.zIndex)) {
|
||||
if (direction === DIRECTION_BACK) {
|
||||
updateZIndex(enteringView, leavingView.zIndex - 1);
|
||||
|
||||
} else {
|
||||
updateZIndex(enteringView, leavingView.zIndex + 1);
|
||||
}
|
||||
|
||||
} else {
|
||||
updateZIndex(enteringView, INIT_ZINDEX + nav.zIndexOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function updateZIndex(viewController: ViewController, newZIndex: number) {
|
||||
if (newZIndex !== viewController.zIndex) {
|
||||
viewController.zIndex = newZIndex;
|
||||
viewController.element.style.zIndex = '' + newZIndex;
|
||||
}
|
||||
}
|
||||
|
||||
export function toggleHidden(element: HTMLElement, isVisible: Boolean, shouldBeVisible: boolean) {
|
||||
@ -29,3 +67,125 @@ export function toggleHidden(element: HTMLElement, isVisible: Boolean, shouldBeV
|
||||
element.hidden = shouldBeVisible;
|
||||
}
|
||||
}
|
||||
|
||||
export function canNavGoBack(nav: Nav) {
|
||||
if (!nav) {
|
||||
return false;
|
||||
}
|
||||
return !!nav.getPrevious();
|
||||
}
|
||||
|
||||
export function transitionFactory(animation: Animation): Transition {
|
||||
(animation as any).registerTransitionStart = (callback: Function) => {
|
||||
(animation as any).transitionStartFunction = callback;
|
||||
}
|
||||
|
||||
(animation as any).start = function() {
|
||||
this.transitionStartFunction && this.transitionStartFunction();
|
||||
this.transitionStartFunction = null;
|
||||
transitionStartImpl(animation as Transition);
|
||||
};
|
||||
|
||||
(animation as any).originalDestroy = animation.destroy;
|
||||
|
||||
(animation as any).destroy = function() {
|
||||
transitionDestroyImpl(animation as Transition);
|
||||
};
|
||||
|
||||
return animation as Transition;
|
||||
}
|
||||
|
||||
export function transitionStartImpl(transition: Transition) {
|
||||
transition.transitionStartFunction && transition.transitionStartFunction();
|
||||
transition.transitionStartFunction = null;
|
||||
transition.parent && (transition.parent as Transition).start();
|
||||
}
|
||||
|
||||
export function transitionDestroyImpl(transition: Transition) {
|
||||
transition.originalDestroy();
|
||||
transition.parent = transition.enteringView = transition.leavingView = transition.transitionStartFunction = null;
|
||||
}
|
||||
|
||||
export function getParentTransitionId(nav: Nav) {
|
||||
nav = nav.parent
|
||||
while (nav) {
|
||||
const transitionId = nav.transitionId;
|
||||
if (isDef(transitionId)) {
|
||||
return transitionId;
|
||||
}
|
||||
nav = nav.parent
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
export function getNextTransitionId() {
|
||||
return transitionIds++;
|
||||
}
|
||||
|
||||
export function destroyTransition(transitionId: number) {
|
||||
const transition = activeTransitions.get(transitionId);
|
||||
if (transition) {
|
||||
transition.destroy();
|
||||
activeTransitions.delete(transitionId);
|
||||
}
|
||||
}
|
||||
|
||||
export function getHydratedTransition(name: string, config: Config, transitionId: number, emptyTransition: Transition, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions, defaultTransitionFactory: TransitionBuilder) {
|
||||
|
||||
const transitionFactory = config.get(name) as TransitionBuilder || defaultTransitionFactory;
|
||||
const hydratedTransition = transitionFactory(emptyTransition, enteringView, leavingView, opts);
|
||||
hydratedTransition.transitionId = transitionId;
|
||||
|
||||
if (!activeTransitions.has(transitionId)) {
|
||||
// sweet, this is the root transition
|
||||
activeTransitions.set(transitionId, hydratedTransition);
|
||||
} else {
|
||||
// we've got a parent transition going
|
||||
// just append this transition to the existing one
|
||||
activeTransitions.get(transitionId).add(hydratedTransition);
|
||||
}
|
||||
|
||||
return hydratedTransition;
|
||||
}
|
||||
|
||||
export function canGoBack(nav: Nav) {
|
||||
return nav.views && nav.views.length > 0;
|
||||
}
|
||||
|
||||
export function canSwipeBack(_nav: Nav) {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function getFirstView(nav: Nav): ViewController {
|
||||
return nav.views && nav.views.length > 0 ? nav.views[0] : null;
|
||||
}
|
||||
|
||||
export function getActiveChildNavs(nav: Nav): Nav[] {
|
||||
return nav.childNavs ? nav.childNavs : [];
|
||||
}
|
||||
|
||||
export function getViews(nav: Nav): ViewController[] {
|
||||
return nav.views ? nav.views : [];
|
||||
}
|
||||
|
||||
export function init(nav: Nav) {
|
||||
nav.id = getNextNavId();
|
||||
nav.views = [];
|
||||
}
|
||||
|
||||
export function getActiveImpl(nav: Nav): ViewController {
|
||||
return nav.views && nav.views.length > 0 ? nav.views[nav.views.length - 1] : null;
|
||||
}
|
||||
|
||||
export function getPreviousImpl(nav: Nav, viewController: ViewController): ViewController {
|
||||
if (!viewController) {
|
||||
viewController = nav.getActive();
|
||||
}
|
||||
return nav.views[nav.views.indexOf(viewController) - 1];
|
||||
}
|
||||
|
||||
export function getNextNavId() {
|
||||
return navControllerIds++;
|
||||
}
|
||||
|
||||
let navControllerIds = NAV_ID_START;
|
@ -1,32 +0,0 @@
|
||||
import { NavController, ViewController } from './nav-interfaces';
|
||||
|
||||
export function attachViewToDom(nav: NavController, enteringView: ViewController): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
const usersElement = document.createElement(enteringView.component);
|
||||
const ionPage = document.createElement('ion-page');
|
||||
enteringView.element = ionPage;
|
||||
ionPage.appendChild(usersElement);
|
||||
(ionPage as any).componentDidLoad = () => {
|
||||
resolve();
|
||||
};
|
||||
|
||||
nav.element.appendChild(ionPage);
|
||||
});
|
||||
}
|
||||
|
||||
export function removeViewFromDom(nav: NavController, leavingView: ViewController): Promise<any> {
|
||||
nav.element.removeChild(leavingView.element);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export function destroy(_viewController: ViewController) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const delegate = {
|
||||
attachViewToDom: attachViewToDom,
|
||||
removeViewFromDom: removeViewFromDom,
|
||||
destroy: destroy
|
||||
};
|
||||
|
||||
export { delegate };
|
181
packages/core/src/navigation/transitions/transition.ios.ts
Normal file
181
packages/core/src/navigation/transitions/transition.ios.ts
Normal file
@ -0,0 +1,181 @@
|
||||
import { AnimationOptions } from '../..';
|
||||
import { Transition, ViewController } from '../nav-interfaces';
|
||||
import { canNavGoBack } from '../nav-utils';
|
||||
|
||||
import { isDef } from '../../utils/helpers';
|
||||
|
||||
const DURATION = 500;
|
||||
const EASING = 'cubic-bezier(0.36,0.66,0.04,1)';
|
||||
const OPACITY = 'opacity';
|
||||
const TRANSFORM = 'transform';
|
||||
const TRANSLATEX = 'translateX';
|
||||
const CENTER = '0%';
|
||||
const OFF_OPACITY = 0.8;
|
||||
const SHOW_BACK_BTN_CSS = 'show-back-button';
|
||||
|
||||
export function buildIOSTransition(rootTransition: Transition, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions): Transition {
|
||||
|
||||
rootTransition.enteringView = enteringView;
|
||||
rootTransition.leavingView = leavingView;
|
||||
|
||||
const isRTL = document.dir === 'rtl';
|
||||
const OFF_RIGHT = isRTL ? '-99.5%' : '99.5%';
|
||||
const OFF_LEFT = isRTL ? '33%' : '-33%';
|
||||
|
||||
rootTransition.duration(isDef(opts.duration) ? opts.duration : DURATION);
|
||||
rootTransition.easing(isDef(opts.easing) ? opts.easing : EASING);
|
||||
|
||||
|
||||
rootTransition.addElement(enteringView.element);
|
||||
rootTransition.beforeAddClass('show-page');
|
||||
|
||||
const backDirection = (opts.direction === 'back');
|
||||
|
||||
if (enteringView) {
|
||||
const enteringContent = rootTransition.create();
|
||||
enteringContent.addElement(enteringView.element.querySelectorAll('ion-header > *:not(ion-navbar),ion-footer > *'));
|
||||
|
||||
rootTransition.add(enteringContent);
|
||||
|
||||
if (backDirection) {
|
||||
enteringContent.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true).fromTo(OPACITY, OFF_OPACITY, 1, true);
|
||||
} else {
|
||||
// entering content, forward direction
|
||||
enteringContent.beforeClearStyles([OPACITY]).fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
|
||||
}
|
||||
|
||||
const enteringNavbarEle = enteringView.element.querySelector('ion-navbar');
|
||||
if (enteringNavbarEle) {
|
||||
const enteringNavBar = rootTransition.create();
|
||||
enteringNavBar.addElement(enteringNavbarEle);
|
||||
|
||||
rootTransition.add(enteringNavBar);
|
||||
|
||||
const enteringTitle = rootTransition.create();
|
||||
enteringTitle.addElement(enteringNavbarEle.querySelector('ion-title'));
|
||||
const enteringNavbarItems = rootTransition.create();
|
||||
enteringNavbarItems.addElement(enteringNavbarEle.querySelectorAll('ion-buttons,[menuToggle]'));
|
||||
const enteringNavbarBg = rootTransition.create();
|
||||
enteringNavbarBg.addElement(enteringNavbarEle.querySelector('.toolbar-background'));
|
||||
const enteringBackButton = rootTransition.create();
|
||||
enteringBackButton.addElement(enteringNavbarEle.querySelector('.back-button'));
|
||||
|
||||
enteringNavBar
|
||||
.add(enteringTitle)
|
||||
.add(enteringNavbarItems)
|
||||
.add(enteringNavbarBg)
|
||||
.add(enteringBackButton);
|
||||
|
||||
enteringTitle.fromTo(OPACITY, 0.01, 1, true);
|
||||
enteringNavbarItems.fromTo(OPACITY, 0.01, 1, true);
|
||||
|
||||
if (backDirection) {
|
||||
enteringTitle.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true);
|
||||
|
||||
if (canNavGoBack(enteringView.nav)) {
|
||||
// back direction, entering page has a back button
|
||||
enteringBackButton.beforeAddClass(SHOW_BACK_BTN_CSS).fromTo(OPACITY, 0.01, 1, true);
|
||||
}
|
||||
} else {
|
||||
// entering navbar, forward direction
|
||||
enteringTitle.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
|
||||
|
||||
enteringNavbarBg.beforeClearStyles([OPACITY]).fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
|
||||
|
||||
if (canNavGoBack(enteringView.nav)) {
|
||||
// forward direction, entering page has a back button
|
||||
enteringBackButton.beforeAddClass(SHOW_BACK_BTN_CSS).fromTo(OPACITY, 0.01, 1, true);
|
||||
|
||||
|
||||
const enteringBackBtnText = rootTransition.create();
|
||||
enteringBackBtnText.addElement(enteringNavbarEle.querySelector('.back-button-text'));
|
||||
|
||||
enteringBackBtnText.fromTo(TRANSLATEX, (isRTL ? '-100px' : '100px'), '0px');
|
||||
enteringNavBar.add(enteringBackBtnText);
|
||||
|
||||
} else {
|
||||
enteringBackButton.beforeRemoveClass(SHOW_BACK_BTN_CSS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup leaving view
|
||||
if (leavingView) {
|
||||
|
||||
const leavingContent = rootTransition.create();
|
||||
leavingContent.addElement(leavingView.element);
|
||||
leavingContent.addElement(leavingView.element.querySelectorAll('ion-header > *:not(ion-navbar),ion-footer > *'));
|
||||
|
||||
rootTransition.add(leavingContent);
|
||||
|
||||
if (backDirection) {
|
||||
// leaving content, back direction
|
||||
leavingContent.beforeClearStyles([OPACITY]).fromTo(TRANSLATEX, CENTER, (isRTL ? '-100%' : '100%'));
|
||||
|
||||
} else {
|
||||
// leaving content, forward direction
|
||||
leavingContent
|
||||
.fromTo(TRANSLATEX, CENTER, OFF_LEFT)
|
||||
.fromTo(OPACITY, 1, OFF_OPACITY)
|
||||
.afterClearStyles([TRANSFORM, OPACITY]);
|
||||
}
|
||||
|
||||
const leavingNavbarEle = leavingView.element.querySelector('ion-navbar');
|
||||
if (leavingNavbarEle) {
|
||||
const leavingNavBar = rootTransition.create();
|
||||
leavingNavBar.addElement(leavingNavbarEle)
|
||||
|
||||
const leavingTitle = rootTransition.create();
|
||||
leavingTitle.addElement(leavingNavbarEle.querySelector('ion-title'));
|
||||
|
||||
const leavingNavbarItems = rootTransition.create();
|
||||
leavingNavbarItems.addElement(leavingNavbarEle.querySelectorAll('ion-buttons,[menuToggle]'));
|
||||
|
||||
const leavingNavbarBg = rootTransition.create();
|
||||
leavingNavbarBg.addElement(leavingNavbarEle.querySelector('.toolbar-background'));
|
||||
|
||||
const leavingBackButton = rootTransition.create();
|
||||
leavingBackButton.addElement(leavingNavbarEle.querySelector('.back-button'));
|
||||
|
||||
leavingNavBar
|
||||
.add(leavingTitle)
|
||||
.add(leavingNavbarItems)
|
||||
.add(leavingBackButton)
|
||||
.add(leavingNavbarBg);
|
||||
this.add(leavingNavBar);
|
||||
|
||||
// fade out leaving navbar items
|
||||
leavingBackButton.fromTo(OPACITY, 0.99, 0);
|
||||
leavingTitle.fromTo(OPACITY, 0.99, 0);
|
||||
leavingNavbarItems.fromTo(OPACITY, 0.99, 0);
|
||||
|
||||
if (backDirection) {
|
||||
// leaving navbar, back direction
|
||||
leavingTitle.fromTo(TRANSLATEX, CENTER, (isRTL ? '-100%' : '100%'));
|
||||
|
||||
// leaving navbar, back direction, and there's no entering navbar
|
||||
// should just slide out, no fading out
|
||||
leavingNavbarBg
|
||||
.beforeClearStyles([OPACITY])
|
||||
.fromTo(TRANSLATEX, CENTER, (isRTL ? '-100%' : '100%'));
|
||||
|
||||
const leavingBackBtnText = rootTransition.create();
|
||||
leavingBackBtnText.addElement(leavingNavbarEle.querySelector('.back-button-text'));
|
||||
leavingBackBtnText.fromTo(TRANSLATEX, CENTER, (isRTL ? -300 : 300) + 'px');
|
||||
leavingNavBar.add(leavingBackBtnText);
|
||||
|
||||
} else {
|
||||
// leaving navbar, forward direction
|
||||
leavingTitle
|
||||
.fromTo(TRANSLATEX, CENTER, OFF_LEFT)
|
||||
.afterClearStyles([TRANSFORM]);
|
||||
|
||||
leavingBackButton.afterClearStyles([OPACITY]);
|
||||
leavingTitle.afterClearStyles([OPACITY]);
|
||||
leavingNavbarItems.afterClearStyles([OPACITY]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rootTransition;
|
||||
}
|
60
packages/core/src/navigation/transitions/transition.md.ts
Normal file
60
packages/core/src/navigation/transitions/transition.md.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { AnimationOptions } from '../..';
|
||||
import { Transition, ViewController } from '../nav-interfaces';
|
||||
import { canNavGoBack } from '../nav-utils';
|
||||
|
||||
import { isDef } from '../../utils/helpers';
|
||||
|
||||
const TRANSLATEY = 'translateY';
|
||||
const OFF_BOTTOM = '40px';
|
||||
const CENTER = '0px';
|
||||
const SHOW_BACK_BTN_CSS = 'show-back-button';
|
||||
|
||||
export function buildMdTransition(rootTransition: Transition, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions): Transition {
|
||||
|
||||
rootTransition.enteringView = enteringView;
|
||||
rootTransition.leavingView = leavingView;
|
||||
|
||||
rootTransition.addElement(enteringView.element);
|
||||
rootTransition.beforeAddClass('show-page');
|
||||
|
||||
const backDirection = (opts.direction === 'back');
|
||||
if (enteringView) {
|
||||
if (backDirection) {
|
||||
rootTransition.duration(isDef(opts.duration) ? opts.duration : 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
|
||||
} else {
|
||||
rootTransition.duration(isDef(opts.duration) ? opts.duration : 280).easing('cubic-bezier(0.36,0.66,0.04,1)');
|
||||
|
||||
rootTransition
|
||||
.fromTo(TRANSLATEY, OFF_BOTTOM, CENTER, true)
|
||||
.fromTo('opacity', 0.01, 1, true);
|
||||
}
|
||||
|
||||
const enteringNavbarEle = enteringView.element.querySelector('ion-navbar');
|
||||
if (enteringNavbarEle) {
|
||||
const enteringNavBar = rootTransition.create();
|
||||
enteringNavBar.addElement(enteringNavbarEle);
|
||||
rootTransition.add(enteringNavBar);
|
||||
|
||||
const enteringBackButton = rootTransition.create();
|
||||
enteringBackButton.addElement(enteringNavbarEle.querySelector('.back-button'));
|
||||
rootTransition.add(enteringBackButton);
|
||||
|
||||
if (canNavGoBack(enteringView.nav)) {
|
||||
enteringBackButton.beforeAddClass(SHOW_BACK_BTN_CSS);
|
||||
} else {
|
||||
enteringBackButton.beforeRemoveClass(SHOW_BACK_BTN_CSS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup leaving view
|
||||
if (leavingView && backDirection) {
|
||||
// leaving content
|
||||
rootTransition.duration(opts.duration || 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
|
||||
const leavingPage = rootTransition.create();
|
||||
leavingPage.addElement(leavingView.element);
|
||||
rootTransition.add(leavingPage.fromTo(TRANSLATEY, CENTER, OFF_BOTTOM).fromTo('opacity', 1, 0));
|
||||
}
|
||||
|
||||
return rootTransition;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { FrameworkDelegate, NavController, ViewController } from './nav-interfaces';
|
||||
import { STATE_ATTACHED, STATE_DESTROYED, STATE_INITIALIZED } from './nav-utils';
|
||||
import { FrameworkDelegate, Nav, ViewController } from './nav-interfaces';
|
||||
import { STATE_ATTACHED, STATE_DESTROYED, STATE_NEW, STATE_INITIALIZED } from './nav-utils';
|
||||
|
||||
import { assert } from '../utils/helpers';
|
||||
|
||||
@ -10,16 +10,17 @@ export class ViewControllerImpl implements ViewController {
|
||||
element: HTMLElement;
|
||||
instance: any;
|
||||
state: number;
|
||||
nav: NavController;
|
||||
nav: Nav;
|
||||
overlay: boolean;
|
||||
zIndex: number;
|
||||
dismissProxy: any;
|
||||
frameworkDelegate: FrameworkDelegate;
|
||||
|
||||
|
||||
onDidDismiss: (data: any, role: string) => void;
|
||||
onWillDismiss: (data: any, role: string) => void;
|
||||
|
||||
constructor(public component: any, data?: any) {
|
||||
this.data = data || {};
|
||||
initializeNewViewController(this, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,8 +63,8 @@ export class ViewControllerImpl implements ViewController {
|
||||
willUnloadImpl(this);
|
||||
}
|
||||
|
||||
destroy(): Promise<any> {
|
||||
return destroy(this);
|
||||
destroy(delegate?: FrameworkDelegate): Promise<any> {
|
||||
return destroy(this, delegate);
|
||||
}
|
||||
|
||||
getTransitionName(_direction: string): string {
|
||||
@ -96,21 +97,15 @@ export function dismiss(navCtrl: any, dismissProxy: any, data?: any, role?: stri
|
||||
return navCtrl.removeView(this, options).then(() => data);
|
||||
}
|
||||
|
||||
export function destroy(viewController: ViewController): Promise<any> {
|
||||
return Promise.resolve().then(() => {
|
||||
export function destroy(viewController: ViewController, delegate?: FrameworkDelegate): Promise<any> {
|
||||
assert(viewController.state !== STATE_DESTROYED, 'view state must be attached');
|
||||
return delegate ? delegate.removeViewFromDom(viewController.nav, viewController) : Promise.resolve().then(() => {
|
||||
|
||||
if (viewController.component) {
|
||||
// TODO - consider removing classes and styles as thats what we do in ionic-angular
|
||||
}
|
||||
|
||||
if (viewController.frameworkDelegate) {
|
||||
return viewController.frameworkDelegate.destroy(viewController);
|
||||
}
|
||||
|
||||
return null;
|
||||
}).then(() => {
|
||||
viewController.id = viewController.data = viewController.element = viewController.instance = viewController.nav = viewController.dismissProxy = viewController.frameworkDelegate = null;
|
||||
viewController.id = viewController.data = viewController.element = viewController.instance = viewController.nav = viewController.dismissProxy = null;
|
||||
viewController.state = STATE_DESTROYED;
|
||||
});
|
||||
}
|
||||
@ -162,3 +157,8 @@ export function didLoadImpl(viewController: ViewController) {
|
||||
assert(viewController.state === STATE_ATTACHED, 'view state must be ATTACHED');
|
||||
callLifeCycleFunction(viewController.instance, 'ionViewDidLoad');
|
||||
}
|
||||
|
||||
export function initializeNewViewController(viewController: ViewController, data: any) {
|
||||
viewController.state = STATE_NEW;
|
||||
viewController.data = data || {};
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
import { StencilElement } from '..';
|
||||
|
||||
export function isDef(v: any): boolean { return v !== undefined && v !== null; }
|
||||
|
||||
export function isUndef(v: any): boolean { return v === undefined || v === null; }
|
||||
@ -155,10 +157,16 @@ export function swipeShouldReset(isResetDirection: boolean, isMovingFast: boolea
|
||||
// 1 | 1 | 0 || 1
|
||||
// 1 | 1 | 1 || 1
|
||||
// The resulting expression was generated by resolving the K-map (Karnaugh map):
|
||||
let shouldClose = (!isMovingFast && isOnResetZone) || (isResetDirection && isMovingFast);
|
||||
return shouldClose;
|
||||
return (!isMovingFast && isOnResetZone) || (isResetDirection && isMovingFast);
|
||||
}
|
||||
|
||||
export function isReady(element: HTMLElement) {
|
||||
return new Promise((resolve) => {
|
||||
(element as StencilElement).componentOnReady((elm: HTMLElement) => {
|
||||
resolve(elm);
|
||||
});
|
||||
});
|
||||
|
||||
/** @hidden */
|
||||
export function deepCopy(obj: any) {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
|
@ -1,3 +0,0 @@
|
||||
|
||||
export let NAV_ID_START = 1000;
|
||||
export let VIEW_ID_START = 2000;
|
@ -29,8 +29,8 @@ exports.config = {
|
||||
{ components: ['ion-spinner'] },
|
||||
{ components: ['ion-tabs', 'ion-tab', 'ion-tab-bar', 'ion-tab-button', 'ion-tab-highlight'] },
|
||||
{ components: ['ion-toggle'] },
|
||||
{ components: ['ion-nav', 'ion-nav-controller', 'stencil-ion-nav-delegate','page-one', 'page-two', 'page-three'] },
|
||||
{ components: ['ion-toast', 'ion-toast-controller'] },
|
||||
{ components: ['ion-nav', 'page-one', 'page-two', 'page-three'] }
|
||||
],
|
||||
preamble: '(C) Ionic http://ionicframework.com - MIT License',
|
||||
global: 'src/global/ionic-global.ts'
|
||||
|
Reference in New Issue
Block a user