mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +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:
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';
|
||||
|
||||
@@ -62,3 +64,5 @@ export interface TransitionInstruction {
|
||||
leavingRequiresTransition?: boolean;
|
||||
enteringRequiresTransition?: boolean;
|
||||
}
|
||||
|
||||
export { ViewController };
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
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, TransitionDoneFn, TransitionInstruction, ViewController } from '../../interface';
|
||||
import { Animation, AnimationBuilder, ComponentProps, Config, FrameworkDelegate, Gesture, Mode, NavComponent, NavOptions, NavOutlet, NavResult, RouteID, RouteWrite, RouterDirection, TransitionDoneFn, TransitionInstruction, ViewController } from '../../interface';
|
||||
import { assert } from '../../utils/helpers';
|
||||
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({
|
||||
tag: 'ion-nav',
|
||||
@@ -124,7 +124,7 @@ export class Nav implements NavOutlet {
|
||||
|
||||
componentDidUnload() {
|
||||
for (const view of this.views) {
|
||||
lifecycle(view.element!, ViewLifecycle.WillUnload);
|
||||
lifecycle(view.element!, LIFECYCLE_WILL_UNLOAD);
|
||||
view._destroy();
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ export class Nav implements NavOutlet {
|
||||
setRouteId(
|
||||
id: string,
|
||||
params: ComponentProps | undefined,
|
||||
direction: number
|
||||
direction: RouterDirection
|
||||
): Promise<RouteWrite> {
|
||||
const active = this.getActiveSync();
|
||||
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);
|
||||
} else {
|
||||
const viewController = this.views.find(v => matches(v, id, params));
|
||||
@@ -364,9 +364,9 @@ export class Nav implements NavOutlet {
|
||||
...commonOpts,
|
||||
direction: 'back'
|
||||
});
|
||||
} else if (direction === 1) {
|
||||
} else if (direction === 'forward') {
|
||||
finish = this.push(id, params, commonOpts);
|
||||
} else if (direction === -1) {
|
||||
} else if (direction === 'back') {
|
||||
finish = this.setRoot(id, params, {
|
||||
...commonOpts,
|
||||
direction: 'back',
|
||||
@@ -502,7 +502,7 @@ export class Nav implements NavOutlet {
|
||||
if (ti.opts!.updateURL !== false && this.useRouter) {
|
||||
const router = this.win.document.querySelector('ion-router');
|
||||
if (router) {
|
||||
const direction = result.direction === 'back' ? -1 : 1;
|
||||
const direction = result.direction === 'back' ? 'back' : 'forward';
|
||||
router.navChanged(direction);
|
||||
}
|
||||
}
|
||||
@@ -560,7 +560,7 @@ export class Nav implements NavOutlet {
|
||||
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);
|
||||
}
|
||||
this.postViewInit(enteringView, leavingView, ti);
|
||||
@@ -645,7 +645,7 @@ export class Nav implements NavOutlet {
|
||||
if (nav && nav !== this) {
|
||||
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');
|
||||
}
|
||||
}
|
||||
@@ -749,9 +749,9 @@ export class Nav implements NavOutlet {
|
||||
// let's make sure, callbacks are zoned
|
||||
if (destroyQueue && destroyQueue.length > 0) {
|
||||
for (const view of destroyQueue) {
|
||||
lifecycle(view.element, ViewLifecycle.WillLeave);
|
||||
lifecycle(view.element, ViewLifecycle.DidLeave);
|
||||
lifecycle(view.element, ViewLifecycle.WillUnload);
|
||||
lifecycle(view.element, LIFECYCLE_WILL_LEAVE);
|
||||
lifecycle(view.element, LIFECYCLE_DID_LEAVE);
|
||||
lifecycle(view.element, LIFECYCLE_WILL_UNLOAD);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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'
|
||||
);
|
||||
|
||||
@@ -873,7 +873,7 @@ export class Nav implements NavOutlet {
|
||||
if (i > activeViewIndex) {
|
||||
// this view comes after the active view
|
||||
// let's unload it
|
||||
lifecycle(element, ViewLifecycle.WillUnload);
|
||||
lifecycle(element, LIFECYCLE_WILL_UNLOAD);
|
||||
this.destroyView(view);
|
||||
} else if (i < activeViewIndex) {
|
||||
// this view comes before the active view
|
||||
|
||||
@@ -952,7 +952,7 @@ describe('NavController', () => {
|
||||
? win.document.createElement(enteringView.component)
|
||||
: enteringView.element = enteringView.component as HTMLElement;
|
||||
}
|
||||
enteringView.state = ViewState.Attached;
|
||||
enteringView.state = VIEW_STATE_ATTACHED;
|
||||
};
|
||||
return navI;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,13 @@ import { ComponentProps, FrameworkDelegate } from '../../interface';
|
||||
import { attachComponent } from '../../utils/framework-delegate';
|
||||
import { assert } from '../../utils/helpers';
|
||||
|
||||
export const enum ViewState {
|
||||
New = 1,
|
||||
Attached,
|
||||
Destroyed
|
||||
}
|
||||
export const VIEW_STATE_NEW = 1;
|
||||
export const VIEW_STATE_ATTACHED = 2;
|
||||
export const VIEW_STATE_DESTROYED = 3;
|
||||
|
||||
export class ViewController {
|
||||
|
||||
state: ViewState = ViewState.New;
|
||||
state = VIEW_STATE_NEW;
|
||||
nav?: any;
|
||||
element?: HTMLElement;
|
||||
delegate?: FrameworkDelegate;
|
||||
@@ -21,7 +19,7 @@ export class ViewController {
|
||||
) {}
|
||||
|
||||
async init(container: HTMLElement) {
|
||||
this.state = ViewState.Attached;
|
||||
this.state = VIEW_STATE_ATTACHED;
|
||||
|
||||
if (!this.element) {
|
||||
const component = this.component;
|
||||
@@ -33,7 +31,7 @@ export class ViewController {
|
||||
* DOM WRITE
|
||||
*/
|
||||
_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;
|
||||
if (element) {
|
||||
@@ -44,7 +42,7 @@ export class ViewController {
|
||||
}
|
||||
}
|
||||
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 { 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 { attachComponent, detachComponent } from '../../utils/framework-delegate';
|
||||
|
||||
@@ -102,10 +102,10 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
|
||||
|
||||
/** @internal */
|
||||
@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, {
|
||||
duration: direction === 0 ? 0 : undefined,
|
||||
direction: direction === -1 ? 'back' : 'forward',
|
||||
duration: direction === 'root' ? 0 : undefined,
|
||||
direction: direction === 'back' ? 'back' : 'forward',
|
||||
});
|
||||
return {
|
||||
changed,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Me
|
||||
import { BackButtonEvent, Config, RouteChain, RouterDirection, RouterEventDetail } from '../../interface';
|
||||
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 { readNavState, waitUntilNavNode, writeNavState } from './utils/dom';
|
||||
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);
|
||||
|
||||
const path = parsePath(url);
|
||||
const intent = DIRECTION_TO_INTENT[direction];
|
||||
this.setPath(path, intent);
|
||||
return this.writeNavStateRoot(path, intent);
|
||||
this.setPath(path, direction);
|
||||
return this.writeNavStateRoot(path, direction);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +121,7 @@ export class Router implements ComponentInterface {
|
||||
|
||||
/** @internal */
|
||||
@Method()
|
||||
async navChanged(intent: number): Promise<boolean> {
|
||||
async navChanged(direction: RouterDirection): Promise<boolean> {
|
||||
if (this.busy) {
|
||||
console.warn('[ion-router] router is busy, navChanged was cancelled');
|
||||
return false;
|
||||
@@ -142,21 +141,21 @@ export class Router implements ComponentInterface {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private onRedirectChanged() {
|
||||
const path = this.getPath();
|
||||
if (path && routeRedirect(path, readRedirects(this.el))) {
|
||||
this.writeNavStateRoot(path, RouterIntent.None);
|
||||
this.writeNavStateRoot(path, ROUTER_INTENT_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
private onRoutesChanged() {
|
||||
return this.writeNavStateRoot(this.getPath(), RouterIntent.None);
|
||||
return this.writeNavStateRoot(this.getPath(), ROUTER_INTENT_NONE);
|
||||
}
|
||||
|
||||
private historyDirection() {
|
||||
@@ -172,15 +171,15 @@ export class Router implements ComponentInterface {
|
||||
this.lastState = state;
|
||||
|
||||
if (state > lastState) {
|
||||
return RouterIntent.Forward;
|
||||
return ROUTER_INTENT_FORWARD;
|
||||
} else if (state < lastState) {
|
||||
return RouterIntent.Back;
|
||||
return ROUTER_INTENT_BACK;
|
||||
} 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) {
|
||||
console.error('[ion-router] URL is not part of the routing set');
|
||||
return false;
|
||||
@@ -191,7 +190,7 @@ export class Router implements ComponentInterface {
|
||||
const redirect = routeRedirect(path, redirects);
|
||||
let redirectFrom: string[] | null = null;
|
||||
if (redirect) {
|
||||
this.setPath(redirect.to!, intent);
|
||||
this.setPath(redirect.to!, direction);
|
||||
redirectFrom = redirect.from;
|
||||
path = redirect.to!;
|
||||
}
|
||||
@@ -205,18 +204,18 @@ export class Router implements ComponentInterface {
|
||||
}
|
||||
|
||||
// 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(
|
||||
node: HTMLElement | undefined, chain: RouteChain, intent: RouterIntent,
|
||||
node: HTMLElement | undefined, chain: RouteChain, direction: RouterDirection,
|
||||
path: string[], redirectFrom: string[] | null,
|
||||
index = 0
|
||||
): Promise<boolean> {
|
||||
const unlock = await this.lock();
|
||||
let changed = false;
|
||||
try {
|
||||
changed = await this.writeNavState(node, chain, intent, path, redirectFrom, index);
|
||||
changed = await this.writeNavState(node, chain, direction, path, redirectFrom, index);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -236,7 +235,7 @@ export class Router implements ComponentInterface {
|
||||
}
|
||||
|
||||
private async writeNavState(
|
||||
node: HTMLElement | undefined, chain: RouteChain, intent: RouterIntent,
|
||||
node: HTMLElement | undefined, chain: RouteChain, direction: RouterDirection,
|
||||
path: string[], redirectFrom: string[] | null,
|
||||
index = 0
|
||||
): Promise<boolean> {
|
||||
@@ -252,7 +251,7 @@ export class Router implements ComponentInterface {
|
||||
this.ionRouteWillChange.emit(routeEvent);
|
||||
}
|
||||
|
||||
const changed = await writeNavState(node, chain, intent, index);
|
||||
const changed = await writeNavState(node, chain, direction, index);
|
||||
this.busy = false;
|
||||
|
||||
if (changed) {
|
||||
@@ -266,9 +265,9 @@ export class Router implements ComponentInterface {
|
||||
return changed;
|
||||
}
|
||||
|
||||
private setPath(path: string[], intent: RouterIntent) {
|
||||
private setPath(path: string[], direction: RouterDirection) {
|
||||
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 {
|
||||
@@ -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 { chainToPath, generatePath, parsePath, readPath, writePath } from '../utils/path';
|
||||
|
||||
@@ -178,61 +178,61 @@ describe('readPath', () => {
|
||||
describe('writePath', () => {
|
||||
it('should write root path (no hash)', () => {
|
||||
const history = mockHistory();
|
||||
writePath(history, '', false, [''], RouterIntent.Forward, 123);
|
||||
writePath(history, '', false, [''], ROUTER_INTENT_FORWARD, 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');
|
||||
|
||||
writePath(history, '/', false, [''], RouterIntent.Forward, 123);
|
||||
writePath(history, '/', false, [''], ROUTER_INTENT_FORWARD, 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');
|
||||
});
|
||||
|
||||
it('should write non root path (no hash)', () => {
|
||||
const history = mockHistory();
|
||||
writePath(history, '/path', false, [''], RouterIntent.Forward, 2);
|
||||
writePath(history, '/path', false, [''], ROUTER_INTENT_FORWARD, 2);
|
||||
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');
|
||||
|
||||
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');
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
it('should write root path (no hash)', () => {
|
||||
const history = mockHistory();
|
||||
writePath(history, '', true, [''], RouterIntent.Forward, 123);
|
||||
writePath(history, '', true, [''], ROUTER_INTENT_FORWARD, 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');
|
||||
|
||||
writePath(history, '/', true, [''], RouterIntent.Forward, 123);
|
||||
writePath(history, '/', true, [''], ROUTER_INTENT_FORWARD, 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');
|
||||
});
|
||||
|
||||
it('should write non root path (no hash)', () => {
|
||||
const history = mockHistory();
|
||||
writePath(history, '/path', true, [''], RouterIntent.Forward, 123);
|
||||
writePath(history, '/path', true, [''], ROUTER_INTENT_FORWARD, 123);
|
||||
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');
|
||||
|
||||
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');
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
|
||||
export const enum RouterIntent {
|
||||
None = 0,
|
||||
Forward = 1,
|
||||
Back = -1,
|
||||
}
|
||||
export const ROUTER_INTENT_NONE = 'root';
|
||||
export const ROUTER_INTENT_FORWARD = 'forward';
|
||||
export const ROUTER_INTENT_BACK = 'back';
|
||||
|
||||
@@ -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(
|
||||
root: HTMLElement | undefined,
|
||||
chain: RouteChain,
|
||||
intent: RouterIntent,
|
||||
direction: RouterDirection,
|
||||
index: number,
|
||||
changed = false
|
||||
): Promise<boolean> {
|
||||
@@ -20,17 +20,17 @@ export async function writeNavState(
|
||||
await outlet.componentOnReady();
|
||||
|
||||
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)
|
||||
// this means nested outlets will not animate
|
||||
if (result.changed) {
|
||||
intent = RouterIntent.None;
|
||||
direction = ROUTER_INTENT_NONE;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// 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,
|
||||
// using markVisible prevents flickering
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ComponentProps } from '../../../interface';
|
||||
|
||||
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>;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
const path = segments
|
||||
@@ -28,7 +28,7 @@ export function chainToPath(chain: RouteChain): string[] | null {
|
||||
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([
|
||||
...parsePath(root),
|
||||
...path
|
||||
@@ -36,7 +36,7 @@ export function writePath(history: History, root: string, useHash: boolean, path
|
||||
if (useHash) {
|
||||
url = '#' + url;
|
||||
}
|
||||
if (intent === RouterIntent.Forward) {
|
||||
if (direction === ROUTER_INTENT_FORWARD) {
|
||||
history.pushState(state, '', url);
|
||||
} else {
|
||||
history.replaceState(state, '', url);
|
||||
|
||||
@@ -187,7 +187,7 @@ export class Tabs implements NavOutlet {
|
||||
if (this.useRouter) {
|
||||
const router = this.doc.querySelector('ion-router');
|
||||
if (router) {
|
||||
return router.navChanged(1);
|
||||
return router.navChanged('forward');
|
||||
}
|
||||
}
|
||||
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 { CellType } from '../virtual-scroll-interface';
|
||||
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', () => {
|
||||
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);
|
||||
expect(cells).toEqual([
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: '0',
|
||||
i: 0,
|
||||
index: 0,
|
||||
@@ -158,7 +158,7 @@ describe('calcCells', () => {
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: 2,
|
||||
i: 1,
|
||||
index: 1,
|
||||
@@ -167,7 +167,7 @@ describe('calcCells', () => {
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: 'hola',
|
||||
i: 2,
|
||||
index: 2,
|
||||
@@ -176,7 +176,7 @@ describe('calcCells', () => {
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: { data: 'hello' },
|
||||
i: 3,
|
||||
index: 3,
|
||||
@@ -200,7 +200,7 @@ describe('calcCells', () => {
|
||||
expect(called).toEqual(3);
|
||||
expect(cells).toEqual([
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: 10,
|
||||
i: 0,
|
||||
index: 0,
|
||||
@@ -209,7 +209,7 @@ describe('calcCells', () => {
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: 9,
|
||||
i: 1,
|
||||
index: 1,
|
||||
@@ -218,7 +218,7 @@ describe('calcCells', () => {
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: 8,
|
||||
i: 2,
|
||||
index: 2,
|
||||
@@ -258,7 +258,7 @@ describe('calcCells', () => {
|
||||
expect(footerCalled).toEqual(3);
|
||||
expect(cells).toEqual([
|
||||
{
|
||||
type: CellType.Header,
|
||||
type: CELL_TYPE_HEADER,
|
||||
value: 'my header',
|
||||
i: 0,
|
||||
index: 0,
|
||||
@@ -267,7 +267,7 @@ describe('calcCells', () => {
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: '10',
|
||||
i: 1,
|
||||
index: 0,
|
||||
@@ -276,7 +276,7 @@ describe('calcCells', () => {
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: '9',
|
||||
i: 2,
|
||||
index: 1,
|
||||
@@ -285,7 +285,7 @@ describe('calcCells', () => {
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: '8',
|
||||
i: 3,
|
||||
index: 2,
|
||||
@@ -294,7 +294,7 @@ describe('calcCells', () => {
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: CellType.Footer,
|
||||
type: CELL_TYPE_FOOTER,
|
||||
value: 'my footer',
|
||||
i: 4,
|
||||
index: 2,
|
||||
|
||||
@@ -1,16 +1,4 @@
|
||||
|
||||
export const enum CellType {
|
||||
Item,
|
||||
Header,
|
||||
Footer
|
||||
}
|
||||
|
||||
export const enum NodeChange {
|
||||
NoChange,
|
||||
Position,
|
||||
Cell,
|
||||
}
|
||||
|
||||
export interface Cell {
|
||||
i: number;
|
||||
index: number;
|
||||
@@ -29,6 +17,8 @@ export interface VirtualNode {
|
||||
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 ItemHeightFn = (item: any, index: number) => number;
|
||||
export type ItemRenderFn = (el: HTMLElement | null, cell: Cell, domIndex: number) => HTMLElement;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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 {
|
||||
top: number;
|
||||
@@ -17,7 +18,7 @@ const MIN_READS = 2;
|
||||
export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells: Cell[], range: Range) {
|
||||
// reset dom
|
||||
for (const node of dom) {
|
||||
node.change = NodeChange.NoChange;
|
||||
node.change = NODE_CHANGE_NONE;
|
||||
node.d = true;
|
||||
}
|
||||
|
||||
@@ -32,7 +33,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
|
||||
const top = heightIndex[i];
|
||||
if (top !== node.top) {
|
||||
node.top = top;
|
||||
node.change = NodeChange.Position;
|
||||
node.change = NODE_CHANGE_POSITION;
|
||||
}
|
||||
node.d = false;
|
||||
} else {
|
||||
@@ -48,7 +49,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
|
||||
const index = cell.index;
|
||||
if (node) {
|
||||
node.d = false;
|
||||
node.change = NodeChange.Cell;
|
||||
node.change = NODE_CHANGE_CELL;
|
||||
node.cell = cell;
|
||||
node.top = heightIndex[index];
|
||||
} else {
|
||||
@@ -56,7 +57,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
|
||||
d: false,
|
||||
cell,
|
||||
visible: true,
|
||||
change: NodeChange.Cell,
|
||||
change: NODE_CHANGE_CELL,
|
||||
top: heightIndex[index],
|
||||
});
|
||||
}
|
||||
@@ -64,7 +65,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
|
||||
dom
|
||||
.filter(n => n.d && n.top !== -9999)
|
||||
.forEach(n => {
|
||||
n.change = NodeChange.Position;
|
||||
n.change = NODE_CHANGE_POSITION;
|
||||
n.top = -9999;
|
||||
});
|
||||
}
|
||||
@@ -83,7 +84,7 @@ export function doRender(
|
||||
const cell = node.cell;
|
||||
|
||||
// the cell change, the content must be updated
|
||||
if (node.change === NodeChange.Cell) {
|
||||
if (node.change === NODE_CHANGE_CELL) {
|
||||
if (i < childrenNu) {
|
||||
child = children[i] as HTMLElement;
|
||||
nodeRender(child, cell, i);
|
||||
@@ -99,7 +100,7 @@ export function doRender(
|
||||
}
|
||||
|
||||
// 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)`;
|
||||
}
|
||||
|
||||
@@ -132,9 +133,9 @@ function createNode(el: HTMLElement, type: CellType): HTMLElement | null {
|
||||
|
||||
function getTemplate(el: HTMLElement, type: CellType): HTMLTemplateElement | null {
|
||||
switch (type) {
|
||||
case CellType.Item: return el.querySelector('template:not([name])');
|
||||
case CellType.Header: return el.querySelector('template[name=header]');
|
||||
case CellType.Footer: return el.querySelector('template[name=footer]');
|
||||
case CELL_TYPE_ITEM: return el.querySelector('template:not([name])');
|
||||
case CELL_TYPE_HEADER: return el.querySelector('template[name=header]');
|
||||
case CELL_TYPE_FOOTER: return el.querySelector('template[name=footer]');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +221,7 @@ export function calcCells(
|
||||
if (value != null) {
|
||||
cells.push({
|
||||
i: j++,
|
||||
type: CellType.Header,
|
||||
type: CELL_TYPE_HEADER,
|
||||
value,
|
||||
index: i,
|
||||
height: approxHeaderHeight,
|
||||
@@ -232,7 +233,7 @@ export function calcCells(
|
||||
|
||||
cells.push({
|
||||
i: j++,
|
||||
type: CellType.Item,
|
||||
type: CELL_TYPE_ITEM,
|
||||
value: item,
|
||||
index: i,
|
||||
height: itemHeight ? itemHeight(item, i) : approxItemHeight,
|
||||
@@ -245,7 +246,7 @@ export function calcCells(
|
||||
if (value != null) {
|
||||
cells.push({
|
||||
i: j++,
|
||||
type: CellType.Footer,
|
||||
type: CELL_TYPE_FOOTER,
|
||||
value,
|
||||
index: i,
|
||||
height: approxFooterHeight,
|
||||
@@ -283,7 +284,7 @@ export function resizeBuffer(buf: Uint32Array | undefined, len: 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) {
|
||||
return heightIndex[cell.i];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, EventListenerEnable, Functional
|
||||
|
||||
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';
|
||||
|
||||
@Component({
|
||||
@@ -411,9 +411,9 @@ export class VirtualScroll implements ComponentInterface {
|
||||
private renderVirtualNode(node: VirtualNode) {
|
||||
const { type, value, index } = node.cell;
|
||||
switch (type) {
|
||||
case CellType.Item: return this.renderItem!(value, index);
|
||||
case CellType.Header: return this.renderHeader!(value, index);
|
||||
case CellType.Footer: return this.renderFooter!(value, index);
|
||||
case CELL_TYPE_ITEM: return this.renderItem!(value, index);
|
||||
case CELL_TYPE_HEADER: return this.renderHeader!(value, index);
|
||||
case CELL_TYPE_FOOTER: return this.renderFooter!(value, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user