mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 03:32:21 +08:00
refactor(all): avoid using export const enum (#16614)
* refactor(all): avoid using export const enum fixes #16497 * add tslint
This commit is contained in:
@ -53,7 +53,7 @@
|
|||||||
"stylelint-order": "~1.0.0",
|
"stylelint-order": "~1.0.0",
|
||||||
"swiper": "4.4.1",
|
"swiper": "4.4.1",
|
||||||
"tslint": "^5.10.0",
|
"tslint": "^5.10.0",
|
||||||
"tslint-ionic-rules": "0.0.20",
|
"tslint-ionic-rules": "0.0.21",
|
||||||
"tslint-react": "^3.6.0",
|
"tslint-react": "^3.6.0",
|
||||||
"typescript": "^2.9.2"
|
"typescript": "^2.9.2"
|
||||||
},
|
},
|
||||||
|
6
core/src/components.d.ts
vendored
6
core/src/components.d.ts
vendored
@ -2795,7 +2795,7 @@ export namespace Components {
|
|||||||
* Set the root for the current navigation stack.
|
* Set the root for the current navigation stack.
|
||||||
*/
|
*/
|
||||||
'setRoot': <T extends NavComponent>(component: T, componentProps?: ComponentProps<T> | null | undefined, opts?: NavOptions | null | undefined, done?: TransitionDoneFn | undefined) => Promise<boolean>;
|
'setRoot': <T extends NavComponent>(component: T, componentProps?: ComponentProps<T> | null | undefined, opts?: NavOptions | null | undefined, done?: TransitionDoneFn | undefined) => Promise<boolean>;
|
||||||
'setRouteId': (id: string, params: { [key: string]: any; } | undefined, direction: number) => Promise<RouteWrite>;
|
'setRouteId': (id: string, params: { [key: string]: any; } | undefined, direction: RouterDirection) => Promise<RouteWrite>;
|
||||||
/**
|
/**
|
||||||
* If the nav component should allow for swipe-to-go-back.
|
* If the nav component should allow for swipe-to-go-back.
|
||||||
*/
|
*/
|
||||||
@ -3626,7 +3626,7 @@ export namespace Components {
|
|||||||
'delegate'?: FrameworkDelegate;
|
'delegate'?: FrameworkDelegate;
|
||||||
'getRouteId': () => Promise<RouteID | undefined>;
|
'getRouteId': () => Promise<RouteID | undefined>;
|
||||||
'mode': Mode;
|
'mode': Mode;
|
||||||
'setRouteId': (id: string, params: { [key: string]: any; } | undefined, direction: number) => Promise<RouteWrite>;
|
'setRouteId': (id: string, params: { [key: string]: any; } | undefined, direction: RouterDirection) => Promise<RouteWrite>;
|
||||||
'swipeHandler'?: SwipeGestureHandler;
|
'swipeHandler'?: SwipeGestureHandler;
|
||||||
}
|
}
|
||||||
interface IonRouterOutletAttributes extends StencilHTMLAttributes {
|
interface IonRouterOutletAttributes extends StencilHTMLAttributes {
|
||||||
@ -3651,7 +3651,7 @@ export namespace Components {
|
|||||||
* Go back to previous page in the window.history.
|
* Go back to previous page in the window.history.
|
||||||
*/
|
*/
|
||||||
'goBack': () => Promise<void>;
|
'goBack': () => Promise<void>;
|
||||||
'navChanged': (intent: number) => Promise<boolean>;
|
'navChanged': (direction: RouterDirection) => Promise<boolean>;
|
||||||
'printDebug': () => void;
|
'printDebug': () => void;
|
||||||
/**
|
/**
|
||||||
* Navigate to the specified URL.
|
* Navigate to the specified URL.
|
||||||
|
5
core/src/components/nav/constants.ts
Normal file
5
core/src/components/nav/constants.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const LIFECYCLE_WILL_ENTER = 'ionViewWillEnter';
|
||||||
|
export const LIFECYCLE_DID_ENTER = 'ionViewDidEnter';
|
||||||
|
export const LIFECYCLE_WILL_LEAVE = 'ionViewWillLeave';
|
||||||
|
export const LIFECYCLE_DID_LEAVE = 'ionViewDidLeave';
|
||||||
|
export const LIFECYCLE_WILL_UNLOAD = 'ionViewWillUnload';
|
@ -1,4 +1,6 @@
|
|||||||
import { Animation, AnimationBuilder, ComponentRef, FrameworkDelegate, Mode, ViewController } from '../../interface';
|
import { Animation, AnimationBuilder, ComponentRef, FrameworkDelegate, Mode } from '../../interface';
|
||||||
|
|
||||||
|
import { ViewController } from './view-controller';
|
||||||
|
|
||||||
export type NavDirection = 'back' | 'forward';
|
export type NavDirection = 'back' | 'forward';
|
||||||
|
|
||||||
@ -62,3 +64,5 @@ export interface TransitionInstruction {
|
|||||||
leavingRequiresTransition?: boolean;
|
leavingRequiresTransition?: boolean;
|
||||||
enteringRequiresTransition?: boolean;
|
enteringRequiresTransition?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { ViewController };
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Build, Component, Element, Event, EventEmitter, Method, Prop, QueueApi, Watch } from '@stencil/core';
|
import { Build, Component, Element, Event, EventEmitter, Method, Prop, QueueApi, Watch } from '@stencil/core';
|
||||||
|
|
||||||
import { ViewLifecycle } from '../..';
|
import { Animation, AnimationBuilder, ComponentProps, Config, FrameworkDelegate, Gesture, Mode, NavComponent, NavOptions, NavOutlet, NavResult, RouteID, RouteWrite, RouterDirection, TransitionDoneFn, TransitionInstruction, ViewController } from '../../interface';
|
||||||
import { Animation, AnimationBuilder, ComponentProps, Config, FrameworkDelegate, Gesture, Mode, NavComponent, NavOptions, NavOutlet, NavResult, RouteID, RouteWrite, TransitionDoneFn, TransitionInstruction, ViewController } from '../../interface';
|
|
||||||
import { assert } from '../../utils/helpers';
|
import { assert } from '../../utils/helpers';
|
||||||
import { TransitionOptions, lifecycle, setPageHidden, transition } from '../../utils/transition';
|
import { TransitionOptions, lifecycle, setPageHidden, transition } from '../../utils/transition';
|
||||||
|
|
||||||
import { ViewState, convertToViews, matches } from './view-controller';
|
import { LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_LEAVE, LIFECYCLE_WILL_UNLOAD } from './constants';
|
||||||
|
import { VIEW_STATE_ATTACHED, VIEW_STATE_DESTROYED, VIEW_STATE_NEW, convertToViews, matches } from './view-controller';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-nav',
|
tag: 'ion-nav',
|
||||||
@ -124,7 +124,7 @@ export class Nav implements NavOutlet {
|
|||||||
|
|
||||||
componentDidUnload() {
|
componentDidUnload() {
|
||||||
for (const view of this.views) {
|
for (const view of this.views) {
|
||||||
lifecycle(view.element!, ViewLifecycle.WillUnload);
|
lifecycle(view.element!, LIFECYCLE_WILL_UNLOAD);
|
||||||
view._destroy();
|
view._destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,7 +324,7 @@ export class Nav implements NavOutlet {
|
|||||||
setRouteId(
|
setRouteId(
|
||||||
id: string,
|
id: string,
|
||||||
params: ComponentProps | undefined,
|
params: ComponentProps | undefined,
|
||||||
direction: number
|
direction: RouterDirection
|
||||||
): Promise<RouteWrite> {
|
): Promise<RouteWrite> {
|
||||||
const active = this.getActiveSync();
|
const active = this.getActiveSync();
|
||||||
if (matches(active, id, params)) {
|
if (matches(active, id, params)) {
|
||||||
@ -354,7 +354,7 @@ export class Nav implements NavOutlet {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (direction === 0) {
|
if (direction === 'root') {
|
||||||
finish = this.setRoot(id, params, commonOpts);
|
finish = this.setRoot(id, params, commonOpts);
|
||||||
} else {
|
} else {
|
||||||
const viewController = this.views.find(v => matches(v, id, params));
|
const viewController = this.views.find(v => matches(v, id, params));
|
||||||
@ -364,9 +364,9 @@ export class Nav implements NavOutlet {
|
|||||||
...commonOpts,
|
...commonOpts,
|
||||||
direction: 'back'
|
direction: 'back'
|
||||||
});
|
});
|
||||||
} else if (direction === 1) {
|
} else if (direction === 'forward') {
|
||||||
finish = this.push(id, params, commonOpts);
|
finish = this.push(id, params, commonOpts);
|
||||||
} else if (direction === -1) {
|
} else if (direction === 'back') {
|
||||||
finish = this.setRoot(id, params, {
|
finish = this.setRoot(id, params, {
|
||||||
...commonOpts,
|
...commonOpts,
|
||||||
direction: 'back',
|
direction: 'back',
|
||||||
@ -502,7 +502,7 @@ export class Nav implements NavOutlet {
|
|||||||
if (ti.opts!.updateURL !== false && this.useRouter) {
|
if (ti.opts!.updateURL !== false && this.useRouter) {
|
||||||
const router = this.win.document.querySelector('ion-router');
|
const router = this.win.document.querySelector('ion-router');
|
||||||
if (router) {
|
if (router) {
|
||||||
const direction = result.direction === 'back' ? -1 : 1;
|
const direction = result.direction === 'back' ? 'back' : 'forward';
|
||||||
router.navChanged(direction);
|
router.navChanged(direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -560,7 +560,7 @@ export class Nav implements NavOutlet {
|
|||||||
throw new Error('no views in the stack to be removed');
|
throw new Error('no views in the stack to be removed');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enteringView && enteringView.state === ViewState.New) {
|
if (enteringView && enteringView.state === VIEW_STATE_NEW) {
|
||||||
await enteringView.init(this.el);
|
await enteringView.init(this.el);
|
||||||
}
|
}
|
||||||
this.postViewInit(enteringView, leavingView, ti);
|
this.postViewInit(enteringView, leavingView, ti);
|
||||||
@ -645,7 +645,7 @@ export class Nav implements NavOutlet {
|
|||||||
if (nav && nav !== this) {
|
if (nav && nav !== this) {
|
||||||
throw new Error('inserted view was already inserted');
|
throw new Error('inserted view was already inserted');
|
||||||
}
|
}
|
||||||
if (view.state === ViewState.Destroyed) {
|
if (view.state === VIEW_STATE_DESTROYED) {
|
||||||
throw new Error('inserted view was already destroyed');
|
throw new Error('inserted view was already destroyed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -749,9 +749,9 @@ export class Nav implements NavOutlet {
|
|||||||
// let's make sure, callbacks are zoned
|
// let's make sure, callbacks are zoned
|
||||||
if (destroyQueue && destroyQueue.length > 0) {
|
if (destroyQueue && destroyQueue.length > 0) {
|
||||||
for (const view of destroyQueue) {
|
for (const view of destroyQueue) {
|
||||||
lifecycle(view.element, ViewLifecycle.WillLeave);
|
lifecycle(view.element, LIFECYCLE_WILL_LEAVE);
|
||||||
lifecycle(view.element, ViewLifecycle.DidLeave);
|
lifecycle(view.element, LIFECYCLE_DID_LEAVE);
|
||||||
lifecycle(view.element, ViewLifecycle.WillUnload);
|
lifecycle(view.element, LIFECYCLE_WILL_UNLOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// once all lifecycle events has been delivered, we can safely detroy the views
|
// once all lifecycle events has been delivered, we can safely detroy the views
|
||||||
@ -837,7 +837,7 @@ export class Nav implements NavOutlet {
|
|||||||
|
|
||||||
private removeView(view: ViewController) {
|
private removeView(view: ViewController) {
|
||||||
assert(
|
assert(
|
||||||
view.state === ViewState.Attached || view.state === ViewState.Destroyed,
|
view.state === VIEW_STATE_ATTACHED || view.state === VIEW_STATE_DESTROYED,
|
||||||
'view state should be loaded or destroyed'
|
'view state should be loaded or destroyed'
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -873,7 +873,7 @@ export class Nav implements NavOutlet {
|
|||||||
if (i > activeViewIndex) {
|
if (i > activeViewIndex) {
|
||||||
// this view comes after the active view
|
// this view comes after the active view
|
||||||
// let's unload it
|
// let's unload it
|
||||||
lifecycle(element, ViewLifecycle.WillUnload);
|
lifecycle(element, LIFECYCLE_WILL_UNLOAD);
|
||||||
this.destroyView(view);
|
this.destroyView(view);
|
||||||
} else if (i < activeViewIndex) {
|
} else if (i < activeViewIndex) {
|
||||||
// this view comes before the active view
|
// this view comes before the active view
|
||||||
|
@ -952,7 +952,7 @@ describe('NavController', () => {
|
|||||||
? win.document.createElement(enteringView.component)
|
? win.document.createElement(enteringView.component)
|
||||||
: enteringView.element = enteringView.component as HTMLElement;
|
: enteringView.element = enteringView.component as HTMLElement;
|
||||||
}
|
}
|
||||||
enteringView.state = ViewState.Attached;
|
enteringView.state = VIEW_STATE_ATTACHED;
|
||||||
};
|
};
|
||||||
return navI;
|
return navI;
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,13 @@ import { ComponentProps, FrameworkDelegate } from '../../interface';
|
|||||||
import { attachComponent } from '../../utils/framework-delegate';
|
import { attachComponent } from '../../utils/framework-delegate';
|
||||||
import { assert } from '../../utils/helpers';
|
import { assert } from '../../utils/helpers';
|
||||||
|
|
||||||
export const enum ViewState {
|
export const VIEW_STATE_NEW = 1;
|
||||||
New = 1,
|
export const VIEW_STATE_ATTACHED = 2;
|
||||||
Attached,
|
export const VIEW_STATE_DESTROYED = 3;
|
||||||
Destroyed
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ViewController {
|
export class ViewController {
|
||||||
|
|
||||||
state: ViewState = ViewState.New;
|
state = VIEW_STATE_NEW;
|
||||||
nav?: any;
|
nav?: any;
|
||||||
element?: HTMLElement;
|
element?: HTMLElement;
|
||||||
delegate?: FrameworkDelegate;
|
delegate?: FrameworkDelegate;
|
||||||
@ -21,7 +19,7 @@ export class ViewController {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async init(container: HTMLElement) {
|
async init(container: HTMLElement) {
|
||||||
this.state = ViewState.Attached;
|
this.state = VIEW_STATE_ATTACHED;
|
||||||
|
|
||||||
if (!this.element) {
|
if (!this.element) {
|
||||||
const component = this.component;
|
const component = this.component;
|
||||||
@ -33,7 +31,7 @@ export class ViewController {
|
|||||||
* DOM WRITE
|
* DOM WRITE
|
||||||
*/
|
*/
|
||||||
_destroy() {
|
_destroy() {
|
||||||
assert(this.state !== ViewState.Destroyed, 'view state must be ATTACHED');
|
assert(this.state !== VIEW_STATE_DESTROYED, 'view state must be ATTACHED');
|
||||||
|
|
||||||
const element = this.element;
|
const element = this.element;
|
||||||
if (element) {
|
if (element) {
|
||||||
@ -44,7 +42,7 @@ export class ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.nav = undefined;
|
this.nav = undefined;
|
||||||
this.state = ViewState.Destroyed;
|
this.state = VIEW_STATE_DESTROYED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, ComponentInterface, Element, Event, EventEmitter, Method, Prop, QueueApi, Watch } from '@stencil/core';
|
import { Component, ComponentInterface, Element, Event, EventEmitter, Method, Prop, QueueApi, Watch } from '@stencil/core';
|
||||||
|
|
||||||
import { Animation, AnimationBuilder, ComponentProps, ComponentRef, Config, FrameworkDelegate, Gesture, Mode, NavOutlet, RouteID, RouteWrite, RouterOutletOptions, SwipeGestureHandler } from '../../interface';
|
import { Animation, AnimationBuilder, ComponentProps, ComponentRef, Config, FrameworkDelegate, Gesture, Mode, NavOutlet, RouteID, RouteWrite, RouterDirection, RouterOutletOptions, SwipeGestureHandler } from '../../interface';
|
||||||
import { transition } from '../../utils';
|
import { transition } from '../../utils';
|
||||||
import { attachComponent, detachComponent } from '../../utils/framework-delegate';
|
import { attachComponent, detachComponent } from '../../utils/framework-delegate';
|
||||||
|
|
||||||
@ -102,10 +102,10 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@Method()
|
@Method()
|
||||||
async setRouteId(id: string, params: ComponentProps | undefined, direction: number): Promise<RouteWrite> {
|
async setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection): Promise<RouteWrite> {
|
||||||
const changed = await this.setRoot(id, params, {
|
const changed = await this.setRoot(id, params, {
|
||||||
duration: direction === 0 ? 0 : undefined,
|
duration: direction === 'root' ? 0 : undefined,
|
||||||
direction: direction === -1 ? 'back' : 'forward',
|
direction: direction === 'back' ? 'back' : 'forward',
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
changed,
|
changed,
|
||||||
|
@ -3,7 +3,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Me
|
|||||||
import { BackButtonEvent, Config, RouteChain, RouterDirection, RouterEventDetail } from '../../interface';
|
import { BackButtonEvent, Config, RouteChain, RouterDirection, RouterEventDetail } from '../../interface';
|
||||||
import { debounce } from '../../utils/helpers';
|
import { debounce } from '../../utils/helpers';
|
||||||
|
|
||||||
import { RouterIntent } from './utils/constants';
|
import { ROUTER_INTENT_BACK, ROUTER_INTENT_FORWARD, ROUTER_INTENT_NONE } from './utils/constants';
|
||||||
import { printRedirects, printRoutes } from './utils/debug';
|
import { printRedirects, printRoutes } from './utils/debug';
|
||||||
import { readNavState, waitUntilNavNode, writeNavState } from './utils/dom';
|
import { readNavState, waitUntilNavNode, writeNavState } from './utils/dom';
|
||||||
import { routeRedirect, routerIDsToChain, routerPathToChain } from './utils/matching';
|
import { routeRedirect, routerIDsToChain, routerPathToChain } from './utils/matching';
|
||||||
@ -97,9 +97,8 @@ export class Router implements ComponentInterface {
|
|||||||
console.debug('[ion-router] URL pushed -> updating nav', url, direction);
|
console.debug('[ion-router] URL pushed -> updating nav', url, direction);
|
||||||
|
|
||||||
const path = parsePath(url);
|
const path = parsePath(url);
|
||||||
const intent = DIRECTION_TO_INTENT[direction];
|
this.setPath(path, direction);
|
||||||
this.setPath(path, intent);
|
return this.writeNavStateRoot(path, direction);
|
||||||
return this.writeNavStateRoot(path, intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,7 +121,7 @@ export class Router implements ComponentInterface {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@Method()
|
@Method()
|
||||||
async navChanged(intent: number): Promise<boolean> {
|
async navChanged(direction: RouterDirection): Promise<boolean> {
|
||||||
if (this.busy) {
|
if (this.busy) {
|
||||||
console.warn('[ion-router] router is busy, navChanged was cancelled');
|
console.warn('[ion-router] router is busy, navChanged was cancelled');
|
||||||
return false;
|
return false;
|
||||||
@ -142,21 +141,21 @@ export class Router implements ComponentInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.debug('[ion-router] nav changed -> update URL', ids, path);
|
console.debug('[ion-router] nav changed -> update URL', ids, path);
|
||||||
this.setPath(path, intent);
|
this.setPath(path, direction);
|
||||||
|
|
||||||
await this.safeWriteNavState(outlet, chain, RouterIntent.None, path, null, ids.length);
|
await this.safeWriteNavState(outlet, chain, ROUTER_INTENT_NONE, path, null, ids.length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRedirectChanged() {
|
private onRedirectChanged() {
|
||||||
const path = this.getPath();
|
const path = this.getPath();
|
||||||
if (path && routeRedirect(path, readRedirects(this.el))) {
|
if (path && routeRedirect(path, readRedirects(this.el))) {
|
||||||
this.writeNavStateRoot(path, RouterIntent.None);
|
this.writeNavStateRoot(path, ROUTER_INTENT_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRoutesChanged() {
|
private onRoutesChanged() {
|
||||||
return this.writeNavStateRoot(this.getPath(), RouterIntent.None);
|
return this.writeNavStateRoot(this.getPath(), ROUTER_INTENT_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private historyDirection() {
|
private historyDirection() {
|
||||||
@ -172,15 +171,15 @@ export class Router implements ComponentInterface {
|
|||||||
this.lastState = state;
|
this.lastState = state;
|
||||||
|
|
||||||
if (state > lastState) {
|
if (state > lastState) {
|
||||||
return RouterIntent.Forward;
|
return ROUTER_INTENT_FORWARD;
|
||||||
} else if (state < lastState) {
|
} else if (state < lastState) {
|
||||||
return RouterIntent.Back;
|
return ROUTER_INTENT_BACK;
|
||||||
} else {
|
} else {
|
||||||
return RouterIntent.None;
|
return ROUTER_INTENT_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async writeNavStateRoot(path: string[] | null, intent: RouterIntent): Promise<boolean> {
|
private async writeNavStateRoot(path: string[] | null, direction: RouterDirection): Promise<boolean> {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
console.error('[ion-router] URL is not part of the routing set');
|
console.error('[ion-router] URL is not part of the routing set');
|
||||||
return false;
|
return false;
|
||||||
@ -191,7 +190,7 @@ export class Router implements ComponentInterface {
|
|||||||
const redirect = routeRedirect(path, redirects);
|
const redirect = routeRedirect(path, redirects);
|
||||||
let redirectFrom: string[] | null = null;
|
let redirectFrom: string[] | null = null;
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
this.setPath(redirect.to!, intent);
|
this.setPath(redirect.to!, direction);
|
||||||
redirectFrom = redirect.from;
|
redirectFrom = redirect.from;
|
||||||
path = redirect.to!;
|
path = redirect.to!;
|
||||||
}
|
}
|
||||||
@ -205,18 +204,18 @@ export class Router implements ComponentInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write DOM give
|
// write DOM give
|
||||||
return this.safeWriteNavState(this.win.document.body, chain, intent, path, redirectFrom);
|
return this.safeWriteNavState(this.win.document.body, chain, direction, path, redirectFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async safeWriteNavState(
|
private async safeWriteNavState(
|
||||||
node: HTMLElement | undefined, chain: RouteChain, intent: RouterIntent,
|
node: HTMLElement | undefined, chain: RouteChain, direction: RouterDirection,
|
||||||
path: string[], redirectFrom: string[] | null,
|
path: string[], redirectFrom: string[] | null,
|
||||||
index = 0
|
index = 0
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const unlock = await this.lock();
|
const unlock = await this.lock();
|
||||||
let changed = false;
|
let changed = false;
|
||||||
try {
|
try {
|
||||||
changed = await this.writeNavState(node, chain, intent, path, redirectFrom, index);
|
changed = await this.writeNavState(node, chain, direction, path, redirectFrom, index);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
@ -236,7 +235,7 @@ export class Router implements ComponentInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async writeNavState(
|
private async writeNavState(
|
||||||
node: HTMLElement | undefined, chain: RouteChain, intent: RouterIntent,
|
node: HTMLElement | undefined, chain: RouteChain, direction: RouterDirection,
|
||||||
path: string[], redirectFrom: string[] | null,
|
path: string[], redirectFrom: string[] | null,
|
||||||
index = 0
|
index = 0
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
@ -252,7 +251,7 @@ export class Router implements ComponentInterface {
|
|||||||
this.ionRouteWillChange.emit(routeEvent);
|
this.ionRouteWillChange.emit(routeEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
const changed = await writeNavState(node, chain, intent, index);
|
const changed = await writeNavState(node, chain, direction, index);
|
||||||
this.busy = false;
|
this.busy = false;
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
@ -266,9 +265,9 @@ export class Router implements ComponentInterface {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setPath(path: string[], intent: RouterIntent) {
|
private setPath(path: string[], direction: RouterDirection) {
|
||||||
this.state++;
|
this.state++;
|
||||||
writePath(this.win.history, this.root, this.useHash, path, intent, this.state);
|
writePath(this.win.history, this.root, this.useHash, path, direction, this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPath(): string[] | null {
|
private getPath(): string[] | null {
|
||||||
@ -290,9 +289,3 @@ export class Router implements ComponentInterface {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DIRECTION_TO_INTENT = {
|
|
||||||
'back': RouterIntent.Back,
|
|
||||||
'root': RouterIntent.None,
|
|
||||||
'forward': RouterIntent.Forward
|
|
||||||
};
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { RouterIntent } from '../utils/constants';
|
import { ROUTER_INTENT_FORWARD } from '../utils/constants';
|
||||||
import { RouteChain } from '../utils/interface';
|
import { RouteChain } from '../utils/interface';
|
||||||
import { chainToPath, generatePath, parsePath, readPath, writePath } from '../utils/path';
|
import { chainToPath, generatePath, parsePath, readPath, writePath } from '../utils/path';
|
||||||
|
|
||||||
@ -178,61 +178,61 @@ describe('readPath', () => {
|
|||||||
describe('writePath', () => {
|
describe('writePath', () => {
|
||||||
it('should write root path (no hash)', () => {
|
it('should write root path (no hash)', () => {
|
||||||
const history = mockHistory();
|
const history = mockHistory();
|
||||||
writePath(history, '', false, [''], RouterIntent.Forward, 123);
|
writePath(history, '', false, [''], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '/');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '/');
|
||||||
|
|
||||||
writePath(history, '', false, ['schedule'], RouterIntent.Forward, 123);
|
writePath(history, '', false, ['schedule'], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '/schedule');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '/schedule');
|
||||||
|
|
||||||
writePath(history, '/', false, [''], RouterIntent.Forward, 123);
|
writePath(history, '/', false, [''], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '/');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '/');
|
||||||
|
|
||||||
writePath(history, '/', false, ['to', 'schedule'], RouterIntent.Forward, 123);
|
writePath(history, '/', false, ['to', 'schedule'], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '/to/schedule');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '/to/schedule');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should write non root path (no hash)', () => {
|
it('should write non root path (no hash)', () => {
|
||||||
const history = mockHistory();
|
const history = mockHistory();
|
||||||
writePath(history, '/path', false, [''], RouterIntent.Forward, 2);
|
writePath(history, '/path', false, [''], ROUTER_INTENT_FORWARD, 2);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path');
|
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path');
|
||||||
|
|
||||||
writePath(history, '/path', false, ['to', 'page'], RouterIntent.Forward, 2);
|
writePath(history, '/path', false, ['to', 'page'], ROUTER_INTENT_FORWARD, 2);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/page');
|
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/page');
|
||||||
|
|
||||||
writePath(history, 'path/to', false, ['second', 'page'], RouterIntent.Forward, 2);
|
writePath(history, 'path/to', false, ['second', 'page'], ROUTER_INTENT_FORWARD, 2);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/second/page');
|
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/second/page');
|
||||||
|
|
||||||
writePath(history, '/path/to/', false, ['second', 'page'], RouterIntent.Forward, 2);
|
writePath(history, '/path/to/', false, ['second', 'page'], ROUTER_INTENT_FORWARD, 2);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/second/page');
|
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/second/page');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should write root path (no hash)', () => {
|
it('should write root path (no hash)', () => {
|
||||||
const history = mockHistory();
|
const history = mockHistory();
|
||||||
writePath(history, '', true, [''], RouterIntent.Forward, 123);
|
writePath(history, '', true, [''], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/');
|
||||||
|
|
||||||
writePath(history, '', true, ['schedule'], RouterIntent.Forward, 123);
|
writePath(history, '', true, ['schedule'], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/schedule');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/schedule');
|
||||||
|
|
||||||
writePath(history, '/', true, [''], RouterIntent.Forward, 123);
|
writePath(history, '/', true, [''], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/');
|
||||||
|
|
||||||
writePath(history, '/', true, ['to', 'schedule'], RouterIntent.Forward, 123);
|
writePath(history, '/', true, ['to', 'schedule'], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/to/schedule');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/to/schedule');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should write non root path (no hash)', () => {
|
it('should write non root path (no hash)', () => {
|
||||||
const history = mockHistory();
|
const history = mockHistory();
|
||||||
writePath(history, '/path', true, [''], RouterIntent.Forward, 123);
|
writePath(history, '/path', true, [''], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path');
|
||||||
|
|
||||||
writePath(history, '/path', true, ['to', 'page'], RouterIntent.Forward, 123);
|
writePath(history, '/path', true, ['to', 'page'], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/page');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/page');
|
||||||
|
|
||||||
writePath(history, 'path/to', true, ['second', 'page'], RouterIntent.Forward, 123);
|
writePath(history, 'path/to', true, ['second', 'page'], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/second/page');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/second/page');
|
||||||
|
|
||||||
writePath(history, '/path/to/', true, ['second', 'page'], RouterIntent.Forward, 123);
|
writePath(history, '/path/to/', true, ['second', 'page'], ROUTER_INTENT_FORWARD, 123);
|
||||||
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/second/page');
|
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/second/page');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
|
|
||||||
export const enum RouterIntent {
|
export const ROUTER_INTENT_NONE = 'root';
|
||||||
None = 0,
|
export const ROUTER_INTENT_FORWARD = 'forward';
|
||||||
Forward = 1,
|
export const ROUTER_INTENT_BACK = 'back';
|
||||||
Back = -1,
|
|
||||||
}
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { NavOutletElement, RouteChain, RouteID } from '../../../interface';
|
import { NavOutletElement, RouteChain, RouteID, RouterDirection } from '../../../interface';
|
||||||
|
|
||||||
import { RouterIntent } from './constants';
|
import { ROUTER_INTENT_NONE } from './constants';
|
||||||
|
|
||||||
export async function writeNavState(
|
export async function writeNavState(
|
||||||
root: HTMLElement | undefined,
|
root: HTMLElement | undefined,
|
||||||
chain: RouteChain,
|
chain: RouteChain,
|
||||||
intent: RouterIntent,
|
direction: RouterDirection,
|
||||||
index: number,
|
index: number,
|
||||||
changed = false
|
changed = false
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
@ -20,17 +20,17 @@ export async function writeNavState(
|
|||||||
await outlet.componentOnReady();
|
await outlet.componentOnReady();
|
||||||
|
|
||||||
const route = chain[index];
|
const route = chain[index];
|
||||||
const result = await outlet.setRouteId(route.id, route.params, intent);
|
const result = await outlet.setRouteId(route.id, route.params, direction);
|
||||||
|
|
||||||
// if the outlet changed the page, reset navigation to neutral (no direction)
|
// if the outlet changed the page, reset navigation to neutral (no direction)
|
||||||
// this means nested outlets will not animate
|
// this means nested outlets will not animate
|
||||||
if (result.changed) {
|
if (result.changed) {
|
||||||
intent = RouterIntent.None;
|
direction = ROUTER_INTENT_NONE;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// recursively set nested outlets
|
// recursively set nested outlets
|
||||||
changed = await writeNavState(result.element, chain, intent, index + 1, changed);
|
changed = await writeNavState(result.element, chain, direction, index + 1, changed);
|
||||||
|
|
||||||
// once all nested outlets are visible let's make the parent visible too,
|
// once all nested outlets are visible let's make the parent visible too,
|
||||||
// using markVisible prevents flickering
|
// using markVisible prevents flickering
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ComponentProps } from '../../../interface';
|
import { ComponentProps } from '../../../interface';
|
||||||
|
|
||||||
export interface NavOutlet {
|
export interface NavOutlet {
|
||||||
setRouteId(id: string, params: ComponentProps | undefined, direction: number): Promise<RouteWrite>;
|
setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection): Promise<RouteWrite>;
|
||||||
getRouteId(): Promise<RouteID | undefined>;
|
getRouteId(): Promise<RouteID | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { RouteChain } from '../../../interface';
|
import { RouteChain, RouterDirection } from '../../../interface';
|
||||||
|
|
||||||
import { RouterIntent } from './constants';
|
import { ROUTER_INTENT_FORWARD } from './constants';
|
||||||
|
|
||||||
export function generatePath(segments: string[]): string {
|
export function generatePath(segments: string[]): string {
|
||||||
const path = segments
|
const path = segments
|
||||||
@ -28,7 +28,7 @@ export function chainToPath(chain: RouteChain): string[] | null {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function writePath(history: History, root: string, useHash: boolean, path: string[], intent: RouterIntent, state: number) {
|
export function writePath(history: History, root: string, useHash: boolean, path: string[], direction: RouterDirection, state: number) {
|
||||||
let url = generatePath([
|
let url = generatePath([
|
||||||
...parsePath(root),
|
...parsePath(root),
|
||||||
...path
|
...path
|
||||||
@ -36,7 +36,7 @@ export function writePath(history: History, root: string, useHash: boolean, path
|
|||||||
if (useHash) {
|
if (useHash) {
|
||||||
url = '#' + url;
|
url = '#' + url;
|
||||||
}
|
}
|
||||||
if (intent === RouterIntent.Forward) {
|
if (direction === ROUTER_INTENT_FORWARD) {
|
||||||
history.pushState(state, '', url);
|
history.pushState(state, '', url);
|
||||||
} else {
|
} else {
|
||||||
history.replaceState(state, '', url);
|
history.replaceState(state, '', url);
|
||||||
|
@ -187,7 +187,7 @@ export class Tabs implements NavOutlet {
|
|||||||
if (this.useRouter) {
|
if (this.useRouter) {
|
||||||
const router = this.doc.querySelector('ion-router');
|
const router = this.doc.querySelector('ion-router');
|
||||||
if (router) {
|
if (router) {
|
||||||
return router.navChanged(1);
|
return router.navChanged('forward');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
|
7
core/src/components/virtual-scroll/constants.ts
Normal file
7
core/src/components/virtual-scroll/constants.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export const CELL_TYPE_ITEM = 'item';
|
||||||
|
export const CELL_TYPE_HEADER = 'header';
|
||||||
|
export const CELL_TYPE_FOOTER = 'footer';
|
||||||
|
|
||||||
|
export const NODE_CHANGE_NONE = 0;
|
||||||
|
export const NODE_CHANGE_POSITION = 1;
|
||||||
|
export const NODE_CHANGE_CELL = 2;
|
@ -1,6 +1,6 @@
|
|||||||
import { HeaderFn, ItemHeightFn, VirtualNode } from '../../../interface';
|
import { HeaderFn, ItemHeightFn, VirtualNode } from '../../../interface';
|
||||||
import { CellType } from '../virtual-scroll-interface';
|
|
||||||
import { Range, calcCells, calcHeightIndex, getRange, getShouldUpdate, getViewport, positionForIndex, resizeBuffer, updateVDom } from '../virtual-scroll-utils';
|
import { Range, calcCells, calcHeightIndex, getRange, getShouldUpdate, getViewport, positionForIndex, resizeBuffer, updateVDom } from '../virtual-scroll-utils';
|
||||||
|
import { CELL_TYPE_ITEM, CELL_TYPE_HEADER, CELL_TYPE_FOOTER } from '../constants';
|
||||||
|
|
||||||
describe('getViewport', () => {
|
describe('getViewport', () => {
|
||||||
it('should return viewport without margin', () => {
|
it('should return viewport without margin', () => {
|
||||||
@ -149,7 +149,7 @@ describe('calcCells', () => {
|
|||||||
const cells = calcCells(items, undefined, undefined, undefined, 10, 20, 30, 0, 0, items.length);
|
const cells = calcCells(items, undefined, undefined, undefined, 10, 20, 30, 0, 0, items.length);
|
||||||
expect(cells).toEqual([
|
expect(cells).toEqual([
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: '0',
|
value: '0',
|
||||||
i: 0,
|
i: 0,
|
||||||
index: 0,
|
index: 0,
|
||||||
@ -158,7 +158,7 @@ describe('calcCells', () => {
|
|||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: 2,
|
value: 2,
|
||||||
i: 1,
|
i: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
@ -167,7 +167,7 @@ describe('calcCells', () => {
|
|||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: 'hola',
|
value: 'hola',
|
||||||
i: 2,
|
i: 2,
|
||||||
index: 2,
|
index: 2,
|
||||||
@ -176,7 +176,7 @@ describe('calcCells', () => {
|
|||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: { data: 'hello' },
|
value: { data: 'hello' },
|
||||||
i: 3,
|
i: 3,
|
||||||
index: 3,
|
index: 3,
|
||||||
@ -200,7 +200,7 @@ describe('calcCells', () => {
|
|||||||
expect(called).toEqual(3);
|
expect(called).toEqual(3);
|
||||||
expect(cells).toEqual([
|
expect(cells).toEqual([
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: 10,
|
value: 10,
|
||||||
i: 0,
|
i: 0,
|
||||||
index: 0,
|
index: 0,
|
||||||
@ -209,7 +209,7 @@ describe('calcCells', () => {
|
|||||||
visible: true,
|
visible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: 9,
|
value: 9,
|
||||||
i: 1,
|
i: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
@ -218,7 +218,7 @@ describe('calcCells', () => {
|
|||||||
visible: true,
|
visible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: 8,
|
value: 8,
|
||||||
i: 2,
|
i: 2,
|
||||||
index: 2,
|
index: 2,
|
||||||
@ -258,7 +258,7 @@ describe('calcCells', () => {
|
|||||||
expect(footerCalled).toEqual(3);
|
expect(footerCalled).toEqual(3);
|
||||||
expect(cells).toEqual([
|
expect(cells).toEqual([
|
||||||
{
|
{
|
||||||
type: CellType.Header,
|
type: CELL_TYPE_HEADER,
|
||||||
value: 'my header',
|
value: 'my header',
|
||||||
i: 0,
|
i: 0,
|
||||||
index: 0,
|
index: 0,
|
||||||
@ -267,7 +267,7 @@ describe('calcCells', () => {
|
|||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: '10',
|
value: '10',
|
||||||
i: 1,
|
i: 1,
|
||||||
index: 0,
|
index: 0,
|
||||||
@ -276,7 +276,7 @@ describe('calcCells', () => {
|
|||||||
visible: true,
|
visible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: '9',
|
value: '9',
|
||||||
i: 2,
|
i: 2,
|
||||||
index: 1,
|
index: 1,
|
||||||
@ -285,7 +285,7 @@ describe('calcCells', () => {
|
|||||||
visible: true,
|
visible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: '8',
|
value: '8',
|
||||||
i: 3,
|
i: 3,
|
||||||
index: 2,
|
index: 2,
|
||||||
@ -294,7 +294,7 @@ describe('calcCells', () => {
|
|||||||
visible: true,
|
visible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: CellType.Footer,
|
type: CELL_TYPE_FOOTER,
|
||||||
value: 'my footer',
|
value: 'my footer',
|
||||||
i: 4,
|
i: 4,
|
||||||
index: 2,
|
index: 2,
|
||||||
|
@ -1,16 +1,4 @@
|
|||||||
|
|
||||||
export const enum CellType {
|
|
||||||
Item,
|
|
||||||
Header,
|
|
||||||
Footer
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum NodeChange {
|
|
||||||
NoChange,
|
|
||||||
Position,
|
|
||||||
Cell,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Cell {
|
export interface Cell {
|
||||||
i: number;
|
i: number;
|
||||||
index: number;
|
index: number;
|
||||||
@ -29,6 +17,8 @@ export interface VirtualNode {
|
|||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CellType = 'item' | 'header' | 'footer';
|
||||||
|
export type NodeChange = number;
|
||||||
export type HeaderFn = (item: any, index: number, items: any[]) => string | null | undefined;
|
export type HeaderFn = (item: any, index: number, items: any[]) => string | null | undefined;
|
||||||
export type ItemHeightFn = (item: any, index: number) => number;
|
export type ItemHeightFn = (item: any, index: number) => number;
|
||||||
export type ItemRenderFn = (el: HTMLElement | null, cell: Cell, domIndex: number) => HTMLElement;
|
export type ItemRenderFn = (el: HTMLElement | null, cell: Cell, domIndex: number) => HTMLElement;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Cell, HeaderFn, ItemHeightFn, ItemRenderFn, VirtualNode } from '../../interface';
|
import { Cell, HeaderFn, ItemHeightFn, ItemRenderFn, VirtualNode } from '../../interface';
|
||||||
|
|
||||||
import { CellType, NodeChange } from './virtual-scroll-interface';
|
import { CELL_TYPE_FOOTER, CELL_TYPE_HEADER, CELL_TYPE_ITEM, NODE_CHANGE_CELL, NODE_CHANGE_NONE, NODE_CHANGE_POSITION } from './constants';
|
||||||
|
import { CellType } from './virtual-scroll-interface';
|
||||||
|
|
||||||
export interface Viewport {
|
export interface Viewport {
|
||||||
top: number;
|
top: number;
|
||||||
@ -17,7 +18,7 @@ const MIN_READS = 2;
|
|||||||
export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells: Cell[], range: Range) {
|
export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells: Cell[], range: Range) {
|
||||||
// reset dom
|
// reset dom
|
||||||
for (const node of dom) {
|
for (const node of dom) {
|
||||||
node.change = NodeChange.NoChange;
|
node.change = NODE_CHANGE_NONE;
|
||||||
node.d = true;
|
node.d = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
|
|||||||
const top = heightIndex[i];
|
const top = heightIndex[i];
|
||||||
if (top !== node.top) {
|
if (top !== node.top) {
|
||||||
node.top = top;
|
node.top = top;
|
||||||
node.change = NodeChange.Position;
|
node.change = NODE_CHANGE_POSITION;
|
||||||
}
|
}
|
||||||
node.d = false;
|
node.d = false;
|
||||||
} else {
|
} else {
|
||||||
@ -48,7 +49,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
|
|||||||
const index = cell.index;
|
const index = cell.index;
|
||||||
if (node) {
|
if (node) {
|
||||||
node.d = false;
|
node.d = false;
|
||||||
node.change = NodeChange.Cell;
|
node.change = NODE_CHANGE_CELL;
|
||||||
node.cell = cell;
|
node.cell = cell;
|
||||||
node.top = heightIndex[index];
|
node.top = heightIndex[index];
|
||||||
} else {
|
} else {
|
||||||
@ -56,7 +57,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
|
|||||||
d: false,
|
d: false,
|
||||||
cell,
|
cell,
|
||||||
visible: true,
|
visible: true,
|
||||||
change: NodeChange.Cell,
|
change: NODE_CHANGE_CELL,
|
||||||
top: heightIndex[index],
|
top: heightIndex[index],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -64,7 +65,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
|
|||||||
dom
|
dom
|
||||||
.filter(n => n.d && n.top !== -9999)
|
.filter(n => n.d && n.top !== -9999)
|
||||||
.forEach(n => {
|
.forEach(n => {
|
||||||
n.change = NodeChange.Position;
|
n.change = NODE_CHANGE_POSITION;
|
||||||
n.top = -9999;
|
n.top = -9999;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -83,7 +84,7 @@ export function doRender(
|
|||||||
const cell = node.cell;
|
const cell = node.cell;
|
||||||
|
|
||||||
// the cell change, the content must be updated
|
// the cell change, the content must be updated
|
||||||
if (node.change === NodeChange.Cell) {
|
if (node.change === NODE_CHANGE_CELL) {
|
||||||
if (i < childrenNu) {
|
if (i < childrenNu) {
|
||||||
child = children[i] as HTMLElement;
|
child = children[i] as HTMLElement;
|
||||||
nodeRender(child, cell, i);
|
nodeRender(child, cell, i);
|
||||||
@ -99,7 +100,7 @@ export function doRender(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// only update position when it changes
|
// only update position when it changes
|
||||||
if (node.change !== NodeChange.NoChange) {
|
if (node.change !== NODE_CHANGE_NONE) {
|
||||||
child.style.transform = `translate3d(0,${node.top}px,0)`;
|
child.style.transform = `translate3d(0,${node.top}px,0)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,9 +133,9 @@ function createNode(el: HTMLElement, type: CellType): HTMLElement | null {
|
|||||||
|
|
||||||
function getTemplate(el: HTMLElement, type: CellType): HTMLTemplateElement | null {
|
function getTemplate(el: HTMLElement, type: CellType): HTMLTemplateElement | null {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CellType.Item: return el.querySelector('template:not([name])');
|
case CELL_TYPE_ITEM: return el.querySelector('template:not([name])');
|
||||||
case CellType.Header: return el.querySelector('template[name=header]');
|
case CELL_TYPE_HEADER: return el.querySelector('template[name=header]');
|
||||||
case CellType.Footer: return el.querySelector('template[name=footer]');
|
case CELL_TYPE_FOOTER: return el.querySelector('template[name=footer]');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +221,7 @@ export function calcCells(
|
|||||||
if (value != null) {
|
if (value != null) {
|
||||||
cells.push({
|
cells.push({
|
||||||
i: j++,
|
i: j++,
|
||||||
type: CellType.Header,
|
type: CELL_TYPE_HEADER,
|
||||||
value,
|
value,
|
||||||
index: i,
|
index: i,
|
||||||
height: approxHeaderHeight,
|
height: approxHeaderHeight,
|
||||||
@ -232,7 +233,7 @@ export function calcCells(
|
|||||||
|
|
||||||
cells.push({
|
cells.push({
|
||||||
i: j++,
|
i: j++,
|
||||||
type: CellType.Item,
|
type: CELL_TYPE_ITEM,
|
||||||
value: item,
|
value: item,
|
||||||
index: i,
|
index: i,
|
||||||
height: itemHeight ? itemHeight(item, i) : approxItemHeight,
|
height: itemHeight ? itemHeight(item, i) : approxItemHeight,
|
||||||
@ -245,7 +246,7 @@ export function calcCells(
|
|||||||
if (value != null) {
|
if (value != null) {
|
||||||
cells.push({
|
cells.push({
|
||||||
i: j++,
|
i: j++,
|
||||||
type: CellType.Footer,
|
type: CELL_TYPE_FOOTER,
|
||||||
value,
|
value,
|
||||||
index: i,
|
index: i,
|
||||||
height: approxFooterHeight,
|
height: approxFooterHeight,
|
||||||
@ -283,7 +284,7 @@ export function resizeBuffer(buf: Uint32Array | undefined, len: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function positionForIndex(index: number, cells: Cell[], heightIndex: Uint32Array): number {
|
export function positionForIndex(index: number, cells: Cell[], heightIndex: Uint32Array): number {
|
||||||
const cell = cells.find(c => c.type === CellType.Item && c.index === index);
|
const cell = cells.find(c => c.type === CELL_TYPE_ITEM && c.index === index);
|
||||||
if (cell) {
|
if (cell) {
|
||||||
return heightIndex[cell.i];
|
return heightIndex[cell.i];
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, EventListenerEnable, Functional
|
|||||||
|
|
||||||
import { Cell, DomRenderFn, HeaderFn, ItemHeightFn, ItemRenderFn, VirtualNode } from '../../interface';
|
import { Cell, DomRenderFn, HeaderFn, ItemHeightFn, ItemRenderFn, VirtualNode } from '../../interface';
|
||||||
|
|
||||||
import { CellType } from './virtual-scroll-interface';
|
import { CELL_TYPE_FOOTER, CELL_TYPE_HEADER, CELL_TYPE_ITEM } from './constants';
|
||||||
import { Range, calcCells, calcHeightIndex, doRender, findCellIndex, getRange, getShouldUpdate, getViewport, inplaceUpdate, positionForIndex, resizeBuffer, updateVDom } from './virtual-scroll-utils';
|
import { Range, calcCells, calcHeightIndex, doRender, findCellIndex, getRange, getShouldUpdate, getViewport, inplaceUpdate, positionForIndex, resizeBuffer, updateVDom } from './virtual-scroll-utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -411,9 +411,9 @@ export class VirtualScroll implements ComponentInterface {
|
|||||||
private renderVirtualNode(node: VirtualNode) {
|
private renderVirtualNode(node: VirtualNode) {
|
||||||
const { type, value, index } = node.cell;
|
const { type, value, index } = node.cell;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CellType.Item: return this.renderItem!(value, index);
|
case CELL_TYPE_ITEM: return this.renderItem!(value, index);
|
||||||
case CellType.Header: return this.renderHeader!(value, index);
|
case CELL_TYPE_HEADER: return this.renderHeader!(value, index);
|
||||||
case CellType.Footer: return this.renderFooter!(value, index);
|
case CELL_TYPE_FOOTER: return this.renderFooter!(value, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,2 @@
|
|||||||
|
|
||||||
// lifecycle
|
|
||||||
export const enum ViewLifecycle {
|
|
||||||
WillEnter = 'ionViewWillEnter',
|
|
||||||
DidEnter = 'ionViewDidEnter',
|
|
||||||
WillLeave = 'ionViewWillLeave',
|
|
||||||
DidLeave = 'ionViewDidLeave',
|
|
||||||
WillUnload = 'ionViewWillUnload',
|
|
||||||
}
|
|
||||||
|
|
||||||
// util functions
|
|
||||||
export * from './utils/platform';
|
export * from './utils/platform';
|
||||||
export * from './utils/config';
|
export * from './utils/config';
|
||||||
export * from './utils/gesture/swipe-back';
|
|
||||||
|
11
core/src/interface.d.ts
vendored
11
core/src/interface.d.ts
vendored
@ -4,18 +4,18 @@ export * from './index';
|
|||||||
export * from './components/animation-controller/animation-interface';
|
export * from './components/animation-controller/animation-interface';
|
||||||
export * from './components/alert/alert-interface';
|
export * from './components/alert/alert-interface';
|
||||||
export * from './components/action-sheet/action-sheet-interface';
|
export * from './components/action-sheet/action-sheet-interface';
|
||||||
|
export * from './components/content/content-interface';
|
||||||
export * from './components/datetime/datetime-interface';
|
export * from './components/datetime/datetime-interface';
|
||||||
|
export * from './components/loading/loading-interface';
|
||||||
export * from './components/menu/menu-interface';
|
export * from './components/menu/menu-interface';
|
||||||
export * from './components/modal/modal-interface';
|
export * from './components/modal/modal-interface';
|
||||||
export * from './components/picker/picker-interface';
|
|
||||||
export * from './components/loading/loading-interface';
|
|
||||||
export * from './components/popover/popover-interface';
|
|
||||||
export * from './components/nav/nav-interface';
|
export * from './components/nav/nav-interface';
|
||||||
export * from './components/router/utils/interface';
|
export * from './components/picker/picker-interface';
|
||||||
|
export * from './components/popover/popover-interface';
|
||||||
export * from './components/range/range-interface';
|
export * from './components/range/range-interface';
|
||||||
|
export * from './components/router/utils/interface';
|
||||||
export * from './components/refresher/refresher-interface';
|
export * from './components/refresher/refresher-interface';
|
||||||
export * from './components/reorder-group/reorder-group-interface';
|
export * from './components/reorder-group/reorder-group-interface';
|
||||||
export * from './components/content/content-interface';
|
|
||||||
export * from './components/segment-button/segment-button-interface';
|
export * from './components/segment-button/segment-button-interface';
|
||||||
export * from './components/select/select-interface';
|
export * from './components/select/select-interface';
|
||||||
export * from './components/select-popover/select-popover-interface';
|
export * from './components/select-popover/select-popover-interface';
|
||||||
@ -26,7 +26,6 @@ export * from './components/virtual-scroll/virtual-scroll-interface';
|
|||||||
|
|
||||||
// TODO: review how this types are exported
|
// TODO: review how this types are exported
|
||||||
// Other types
|
// Other types
|
||||||
export * from './components/nav/view-controller';
|
|
||||||
|
|
||||||
export { Gesture, GestureDetail } from './utils/gesture/gesture';
|
export { Gesture, GestureDetail } from './utils/gesture/gesture';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { QueueApi } from '@stencil/core';
|
import { QueueApi } from '@stencil/core';
|
||||||
|
|
||||||
import { ViewLifecycle } from '..';
|
import { LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE } from '../components/nav/constants';
|
||||||
import { Animation, AnimationBuilder, NavDirection, NavOptions } from '../interface';
|
import { Animation, AnimationBuilder, NavDirection, NavOptions } from '../interface';
|
||||||
|
|
||||||
const iosTransitionAnimation = () => import('./animations/ios.transition');
|
const iosTransitionAnimation = () => import('./animations/ios.transition');
|
||||||
@ -148,22 +148,22 @@ function playTransition(trans: Animation, opts: TransitionOptions): Promise<Anim
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fireWillEvents(enteringEl: HTMLElement | undefined, leavingEl: HTMLElement | undefined) {
|
function fireWillEvents(enteringEl: HTMLElement | undefined, leavingEl: HTMLElement | undefined) {
|
||||||
lifecycle(leavingEl, ViewLifecycle.WillLeave);
|
lifecycle(leavingEl, LIFECYCLE_WILL_LEAVE);
|
||||||
lifecycle(enteringEl, ViewLifecycle.WillEnter);
|
lifecycle(enteringEl, LIFECYCLE_WILL_ENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fireDidEvents(enteringEl: HTMLElement | undefined, leavingEl: HTMLElement | undefined) {
|
function fireDidEvents(enteringEl: HTMLElement | undefined, leavingEl: HTMLElement | undefined) {
|
||||||
lifecycle(enteringEl, ViewLifecycle.DidEnter);
|
lifecycle(enteringEl, LIFECYCLE_DID_ENTER);
|
||||||
lifecycle(leavingEl, ViewLifecycle.DidLeave);
|
lifecycle(leavingEl, LIFECYCLE_DID_LEAVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function lifecycle(el: HTMLElement | undefined, eventName: ViewLifecycle) {
|
export function lifecycle(el: HTMLElement | undefined, eventName: string) {
|
||||||
if (el) {
|
if (el) {
|
||||||
const event = new CustomEvent(eventName, {
|
const ev = new CustomEvent(eventName, {
|
||||||
bubbles: false,
|
bubbles: false,
|
||||||
cancelable: false,
|
cancelable: false,
|
||||||
});
|
});
|
||||||
el.dispatchEvent(event);
|
el.dispatchEvent(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"no-unbound-method": true,
|
"no-unbound-method": true,
|
||||||
"no-floating-promises": false,
|
"no-floating-promises": false,
|
||||||
"no-invalid-template-strings": true,
|
"no-invalid-template-strings": true,
|
||||||
|
"ban-export-const-enum": true,
|
||||||
|
|
||||||
"jsx-key": false,
|
"jsx-key": false,
|
||||||
"jsx-self-close": false,
|
"jsx-self-close": false,
|
||||||
|
Reference in New Issue
Block a user