mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 09:34:19 +08:00
chore(cleanup): remove unused code
This commit is contained in:
@ -1,37 +0,0 @@
|
||||
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { NavController } from '../providers/nav-controller';
|
||||
import { NavParams } from '../providers/nav-params';
|
||||
|
||||
export const NavControllerToken = new InjectionToken<any>('NavControllerToken');
|
||||
export const NavParamsToken = new InjectionToken<any>('NavParamsToken');
|
||||
|
||||
export function getProviders(element: HTMLElement, data: any) {
|
||||
const nearestNavElement = (element.tagName.toLowerCase() === 'ion-nav' ? element : element.closest('ion-nav')) as HTMLIonNavElement;
|
||||
|
||||
return [
|
||||
{
|
||||
provide: NavControllerToken, useValue: nearestNavElement
|
||||
},
|
||||
|
||||
{
|
||||
provide: NavController, useFactory: provideNavControllerInjectable, deps: [NavControllerToken]
|
||||
},
|
||||
|
||||
{
|
||||
provide: NavParamsToken, useValue: data
|
||||
},
|
||||
|
||||
{
|
||||
provide: NavParams, useFactory: provideNavParamsInjectable, deps: [NavParamsToken]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function provideNavControllerInjectable(element: HTMLIonNavElement) {
|
||||
return new NavController(element);
|
||||
}
|
||||
|
||||
export function provideNavParamsInjectable(data: any) {
|
||||
return new NavParams(data);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import {
|
||||
ComponentFactoryResolver,
|
||||
Directive,
|
||||
ElementRef,
|
||||
Injector,
|
||||
Type,
|
||||
} from '@angular/core';
|
||||
|
||||
import { FrameworkDelegate } from '@ionic/core';
|
||||
|
||||
import { AngularComponentMounter, AngularEscapeHatch } from '..';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-nav',
|
||||
})
|
||||
export class IonNav implements FrameworkDelegate {
|
||||
|
||||
constructor(
|
||||
public elementRef: ElementRef,
|
||||
protected angularComponentMounter: AngularComponentMounter,
|
||||
protected cfr: ComponentFactoryResolver,
|
||||
protected injector: Injector
|
||||
) {
|
||||
|
||||
this.elementRef.nativeElement.delegate = this;
|
||||
}
|
||||
|
||||
attachViewToDom(elementOrContainerToMountTo: HTMLIonNavElement,
|
||||
elementOrComponentToMount: Type<any>,
|
||||
data?: any,
|
||||
classesToAdd?: string[],
|
||||
escapeHatch: AngularEscapeHatch = {}): Promise<any> {
|
||||
|
||||
// wrap whatever the user provides in an ion-page
|
||||
const cfr = escapeHatch.cfr || this.cfr;
|
||||
const injector = escapeHatch.injector || this.injector;
|
||||
return this.angularComponentMounter.attachViewToDom(elementOrContainerToMountTo,
|
||||
null, elementOrComponentToMount, cfr, injector, data, classesToAdd);
|
||||
}
|
||||
|
||||
removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement) {
|
||||
return this.angularComponentMounter.removeViewFromDom(parentElement, childElement);
|
||||
}
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
import {
|
||||
ApplicationRef,
|
||||
ComponentFactoryResolver,
|
||||
Injectable,
|
||||
Injector,
|
||||
NgZone,
|
||||
Type
|
||||
} from '@angular/core';
|
||||
|
||||
import { getProviders } from '../di/di';
|
||||
import { AngularMountingData } from '../types/interfaces';
|
||||
|
||||
const elementToComponentRefMap = new Map<HTMLElement, AngularMountingData>();
|
||||
|
||||
@Injectable()
|
||||
export class AngularComponentMounter {
|
||||
|
||||
constructor(private defaultCfr: ComponentFactoryResolver, private zone: NgZone, private appRef: ApplicationRef) {
|
||||
}
|
||||
|
||||
attachViewToDom(parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type<any>, componentResolveFactory: ComponentFactoryResolver, injector: Injector, data: any, classesToAdd: string[]): Promise<AngularMountingData> {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.zone.run(() => {
|
||||
|
||||
const crf = componentResolveFactory ? componentResolveFactory : this.defaultCfr;
|
||||
|
||||
const mountingData = this.attachViewToDomImpl(crf, parentElement, hostElement, componentToMount, injector, this.appRef, data, classesToAdd);
|
||||
resolve(mountingData);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
this.zone.run(() => {
|
||||
removeViewFromDom(parentElement, childElement);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
attachViewToDomImpl(crf: ComponentFactoryResolver, parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type<any>, injector: Injector, appRef: ApplicationRef, data: any, classesToAdd: string[]): AngularMountingData {
|
||||
|
||||
|
||||
const componentFactory = crf.resolveComponentFactory(componentToMount);
|
||||
if (!hostElement) {
|
||||
hostElement = document.createElement(componentFactory.selector);
|
||||
}
|
||||
|
||||
const childInjector = Injector.create(getProviders(parentElement, data), injector);
|
||||
const componentRef = componentFactory.create(childInjector, [], hostElement);
|
||||
for (const clazz of classesToAdd) {
|
||||
hostElement.classList.add(clazz);
|
||||
}
|
||||
|
||||
parentElement.appendChild(hostElement);
|
||||
|
||||
appRef.attachView(componentRef.hostView);
|
||||
|
||||
const mountingData = {
|
||||
component: componentToMount,
|
||||
componentFactory,
|
||||
childInjector,
|
||||
componentRef,
|
||||
instance: componentRef.instance,
|
||||
angularHostElement: componentRef.location.nativeElement,
|
||||
element: hostElement,
|
||||
data
|
||||
};
|
||||
|
||||
elementToComponentRefMap.set(hostElement, mountingData);
|
||||
|
||||
return mountingData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function removeViewFromDom(_parentElement: HTMLElement, childElement: HTMLElement) {
|
||||
const mountingData = elementToComponentRefMap.get(childElement);
|
||||
if (mountingData) {
|
||||
mountingData.componentRef.destroy();
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
import { PublicNav } from '@ionic/core';
|
||||
|
||||
export class App {
|
||||
|
||||
_element: HTMLIonAppElement;
|
||||
constructor() {
|
||||
this._element = document.querySelector('ion-app');
|
||||
}
|
||||
|
||||
setTitle(title: string) {
|
||||
document.title = title;
|
||||
}
|
||||
|
||||
getRootNavs(): PublicNav[] {
|
||||
return getRootNavsImpl(this);
|
||||
}
|
||||
|
||||
getRootNavsAsync(): Promise<PublicNav[]> {
|
||||
return getRootNavsAsyncImpl(this);
|
||||
}
|
||||
|
||||
getTopNavs(rootNavId?: number): PublicNav[] {
|
||||
return getTopNavsImpl(this, rootNavId);
|
||||
}
|
||||
|
||||
getTopNavsAsync(rootNavId?: number): Promise<PublicNav[]> {
|
||||
return getTopNavsAsyncImpl(this, rootNavId);
|
||||
}
|
||||
|
||||
getNavByIdOrName(nameOrId: number | string): PublicNav {
|
||||
return getNavByIdOrNameImpl(this, nameOrId);
|
||||
}
|
||||
|
||||
getNavByIdOrNameAsync(nameOrId: number | string): Promise<PublicNav> {
|
||||
return getNavByIdOrNameAsyncImpl(this, nameOrId);
|
||||
}
|
||||
|
||||
registerBackButtonAction(fn: Function, priority = 0): Promise<() => void> {
|
||||
return this._element.componentOnReady().then(() => {
|
||||
return this._element.registerBackButtonAction(fn, priority);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getRootNavsImpl(app: App) {
|
||||
if (app._element && app._element.getRootNavs) {
|
||||
return app._element.getRootNavs();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function getRootNavsAsyncImpl(app: App) {
|
||||
return app._element.componentOnReady().then(() => {
|
||||
return app._element.getRootNavs();
|
||||
});
|
||||
}
|
||||
|
||||
export function getTopNavsImpl(app: App, rootNavId?: number): PublicNav[] {
|
||||
if (app._element && app._element.getTopNavs) {
|
||||
return app._element.getTopNavs(rootNavId);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function getTopNavsAsyncImpl(app: App, rootNavId?: number): Promise<PublicNav[]> {
|
||||
return app._element.componentOnReady().then(() => {
|
||||
return app._element.getTopNavs(rootNavId);
|
||||
});
|
||||
}
|
||||
|
||||
export function getNavByIdOrNameImpl(app: App, nameOrId: number | string): PublicNav {
|
||||
if (app._element && app._element.getNavByIdOrName) {
|
||||
return app._element.getNavByIdOrName(nameOrId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getNavByIdOrNameAsyncImpl(app: App, nameOrId: number | string): Promise<PublicNav> {
|
||||
return app._element.componentOnReady().then(() => {
|
||||
return app._element.getNavByIdOrName(nameOrId);
|
||||
});
|
||||
}
|
@ -1,31 +1,20 @@
|
||||
import {
|
||||
ComponentFactoryResolver,
|
||||
Injectable,
|
||||
Injector,
|
||||
Type,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
FrameworkDelegate,
|
||||
ModalDismissEvent,
|
||||
ModalOptions
|
||||
} from '@ionic/core';
|
||||
|
||||
import { AngularComponentMounter } from '../providers/angular-component-mounter';
|
||||
import { AngularMountingData } from '../types/interfaces';
|
||||
|
||||
import { ensureElementInBody, hydrateElement } from '../util/util';
|
||||
|
||||
let modalId = 0;
|
||||
|
||||
@Injectable()
|
||||
export class ModalController implements FrameworkDelegate {
|
||||
|
||||
constructor(private angularComponentMounter: AngularComponentMounter, private componentResolveFactory: ComponentFactoryResolver, private injector: Injector) {
|
||||
}
|
||||
export class ModalController {
|
||||
|
||||
create(opts?: ModalOptions): ModalProxy {
|
||||
opts.delegate = this;
|
||||
return getModalProxy(opts);
|
||||
}
|
||||
|
||||
@ -36,14 +25,6 @@ export class ModalController implements FrameworkDelegate {
|
||||
});
|
||||
}
|
||||
|
||||
attachViewToDom(elementOrContainerToMountTo: HTMLElement, elementOrComponentToMount: Type<any>, data?: any, classesToAdd?: string[]): Promise<AngularMountingData> {
|
||||
|
||||
return this.angularComponentMounter.attachViewToDom(elementOrContainerToMountTo, null, elementOrComponentToMount, this.componentResolveFactory, this.injector, data, classesToAdd);
|
||||
}
|
||||
|
||||
removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement) {
|
||||
return this.angularComponentMounter.removeViewFromDom(parentElement, childElement);
|
||||
}
|
||||
}
|
||||
|
||||
export function getModalProxy(opts: ModalOptions) {
|
||||
|
@ -1,123 +0,0 @@
|
||||
import { NavOptions, PublicNav, PublicViewController } from '@ionic/core';
|
||||
import { hydrateElement } from '../util/util';
|
||||
|
||||
export class NavController implements PublicNav {
|
||||
constructor(public element: HTMLIonNavElement) {
|
||||
}
|
||||
|
||||
push(component: any, data?: any, opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.push(component, data, opts);
|
||||
});
|
||||
}
|
||||
|
||||
pop(opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.pop(opts);
|
||||
});
|
||||
}
|
||||
|
||||
setRoot(component: any, data?: any, opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.setRoot(component, data, opts);
|
||||
});
|
||||
}
|
||||
|
||||
insert(insertIndex: number, page: any, params?: any, opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.insert(insertIndex, page, params, opts);
|
||||
});
|
||||
}
|
||||
|
||||
insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.insertPages(insertIndex, insertPages, opts);
|
||||
});
|
||||
}
|
||||
|
||||
popToRoot(opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.popToRoot(opts);
|
||||
});
|
||||
}
|
||||
|
||||
popTo(indexOrViewCtrl: any, opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.popTo(indexOrViewCtrl, opts);
|
||||
});
|
||||
}
|
||||
|
||||
removeIndex(startIndex: number, removeCount?: number, opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.removeIndex(startIndex, removeCount, opts);
|
||||
});
|
||||
}
|
||||
|
||||
removeView(viewController: PublicViewController, opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.removeView(viewController, opts);
|
||||
});
|
||||
}
|
||||
|
||||
setPages(componentDataPairs: any[], opts?: NavOptions): Promise<any> {
|
||||
return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => {
|
||||
return navElement.setPages(componentDataPairs, opts);
|
||||
});
|
||||
}
|
||||
|
||||
getActive(): PublicViewController {
|
||||
if (this.element.getActive) {
|
||||
return this.element.getActive();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getPrevious(view?: PublicViewController): PublicViewController {
|
||||
if (this.element.getPrevious) {
|
||||
return this.element.getPrevious(view);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
canGoBack(): boolean {
|
||||
if (this.element.canGoBack) {
|
||||
return this.element.canGoBack();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
canSwipeBack(): boolean {
|
||||
if (this.element.canSwipeBack) {
|
||||
return this.element.canSwipeBack();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
first(): PublicViewController {
|
||||
if (this.element.first) {
|
||||
return this.element.first();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
last(): PublicViewController {
|
||||
if (this.element.last) {
|
||||
return this.element.last();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getViews(): PublicViewController[] {
|
||||
if (this.element.getViews) {
|
||||
return this.element.getViews();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
getChildNavs(): PublicNav[] {
|
||||
if (this.element.getChildNavs) {
|
||||
return this.element.getChildNavs();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
|
||||
export class NavParams {
|
||||
|
||||
constructor(public data: any = {}) {
|
||||
}
|
||||
|
||||
get(param: string): any {
|
||||
return this.data[param];
|
||||
}
|
||||
}
|
@ -1,31 +1,20 @@
|
||||
import {
|
||||
ComponentFactoryResolver,
|
||||
Injectable,
|
||||
Injector,
|
||||
Type,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
FrameworkDelegate,
|
||||
PopoverDismissEvent,
|
||||
PopoverOptions
|
||||
} from '@ionic/core';
|
||||
|
||||
import { AngularComponentMounter } from '../providers/angular-component-mounter';
|
||||
import { AngularMountingData } from '../types/interfaces';
|
||||
|
||||
import { ensureElementInBody, hydrateElement } from '../util/util';
|
||||
|
||||
let popoverId = 0;
|
||||
|
||||
@Injectable()
|
||||
export class PopoverController implements FrameworkDelegate {
|
||||
|
||||
constructor(private angularComponentMounter: AngularComponentMounter, private componentResolveFactory: ComponentFactoryResolver, private injector: Injector) {
|
||||
}
|
||||
export class PopoverController {
|
||||
|
||||
create(opts?: PopoverOptions): PopoverProxy {
|
||||
opts.delegate = this;
|
||||
return getPopoverProxy(opts);
|
||||
}
|
||||
|
||||
@ -35,15 +24,6 @@ export class PopoverController implements FrameworkDelegate {
|
||||
return popoverController.dismiss(data, role, id);
|
||||
});
|
||||
}
|
||||
|
||||
attachViewToDom(elementOrContainerToMountTo: HTMLElement, elementOrComponentToMount: Type<any>, data?: any, classesToAdd?: string[]): Promise<AngularMountingData> {
|
||||
|
||||
return this.angularComponentMounter.attachViewToDom(elementOrContainerToMountTo, null, elementOrComponentToMount, this.componentResolveFactory, this.injector, data, classesToAdd);
|
||||
}
|
||||
|
||||
removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement) {
|
||||
return this.angularComponentMounter.removeViewFromDom(parentElement, childElement);
|
||||
}
|
||||
}
|
||||
|
||||
export function getPopoverProxy(opts: PopoverOptions) {
|
||||
|
@ -1,276 +0,0 @@
|
||||
import {
|
||||
ComponentRef
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
ActivatedRoute,
|
||||
ActivatedRouteSnapshot,
|
||||
ActivationEnd,
|
||||
ChildActivationEnd,
|
||||
ChildrenOutletContexts,
|
||||
Event,
|
||||
RouteReuseStrategy,
|
||||
RouterState,
|
||||
} from '@angular/router';
|
||||
|
||||
import {
|
||||
TreeNode,
|
||||
advanceActivatedRoute,
|
||||
forEach,
|
||||
nodeChildrenAsMap
|
||||
} from './router-utils';
|
||||
|
||||
export class AsyncActivateRoutes {
|
||||
constructor(
|
||||
protected routeReuseStrategy: RouteReuseStrategy, protected futureState: RouterState,
|
||||
protected currState: RouterState, protected forwardEvent: (evt: Event) => void) {}
|
||||
|
||||
activate(parentContexts: ChildrenOutletContexts): void | Promise<void> {
|
||||
const futureRoot = (this.futureState as any)._root;
|
||||
const currRoot = this.currState ? (this.currState as any)._root : null;
|
||||
|
||||
const result = this.deactivateChildRoutes(futureRoot, currRoot, parentContexts);
|
||||
return Promise.resolve(result)
|
||||
.then(
|
||||
() => {
|
||||
advanceActivatedRoute(this.futureState.root);
|
||||
return this.activateChildRoutes(futureRoot, currRoot, parentContexts);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// De-activate the child route that are not re-used for the future state
|
||||
protected deactivateChildRoutes(
|
||||
futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null,
|
||||
contexts: ChildrenOutletContexts): Promise<any> {
|
||||
|
||||
const children: {[outletName: string]: TreeNode<ActivatedRoute>} = nodeChildrenAsMap(currNode);
|
||||
|
||||
const promises = futureNode.children.map((futureChild: TreeNode<ActivatedRoute>) => {
|
||||
const childOutletName = futureChild.value.outlet;
|
||||
const promise = this.deactivateRoutes(futureChild, children[childOutletName], contexts);
|
||||
promise
|
||||
.then(
|
||||
() => {
|
||||
delete children[childOutletName];
|
||||
}
|
||||
);
|
||||
return promise;
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(
|
||||
() => {
|
||||
const promises: Promise<void>[] = [];
|
||||
// De-activate the routes that will not be re-used
|
||||
forEach(children, (v: TreeNode<ActivatedRoute>) => {
|
||||
promises.push(this.deactivateRouteAndItsChildren(v, contexts));
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected deactivateRoutes(
|
||||
futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>,
|
||||
parentContext: ChildrenOutletContexts): Promise<void> {
|
||||
const future = futureNode.value;
|
||||
const curr = currNode ? currNode.value : null;
|
||||
|
||||
if (future === curr) {
|
||||
// Reusing the node, check to see if the children need to be de-activated
|
||||
if (future.component) {
|
||||
// If we have a normal route, we need to go through an outlet.
|
||||
const context = parentContext.getContext(future.outlet);
|
||||
if (context) {
|
||||
return this.deactivateChildRoutes(futureNode, currNode, context.children);
|
||||
}
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
// if we have a componentless route, we recurse but keep the same outlet map.
|
||||
return this.deactivateChildRoutes(futureNode, currNode, parentContext);
|
||||
}
|
||||
} else {
|
||||
if (curr) {
|
||||
// Deactivate the current route which will not be re-used
|
||||
return this.deactivateRouteAndItsChildren(currNode, parentContext);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
protected deactivateRouteAndItsChildren(
|
||||
route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): Promise<void> {
|
||||
if (this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {
|
||||
return this.detachAndStoreRouteSubtree(route, parentContexts);
|
||||
} else {
|
||||
return this.deactivateRouteAndOutlet(route, parentContexts);
|
||||
}
|
||||
}
|
||||
|
||||
protected detachAndStoreRouteSubtree(
|
||||
route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): Promise<void> {
|
||||
const context = parentContexts.getContext(route.value.outlet);
|
||||
if (context && context.outlet) {
|
||||
const componentRefOrPromise = context.outlet.detach();
|
||||
return Promise.resolve(componentRefOrPromise)
|
||||
.then(
|
||||
(componentRef: ComponentRef<any>) => {
|
||||
const contexts = context.children.onOutletDeactivated();
|
||||
this.routeReuseStrategy.store(route.value.snapshot, {componentRef, route, contexts});
|
||||
}
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
protected deactivateRouteAndOutlet(
|
||||
route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): Promise<void> {
|
||||
const context = parentContexts.getContext(route.value.outlet);
|
||||
|
||||
if (context) {
|
||||
const children: {[outletName: string]: any} = nodeChildrenAsMap(route);
|
||||
const contexts = route.value.component ? context.children : parentContexts;
|
||||
|
||||
const promises: Promise<void>[] = [];
|
||||
forEach(children, (v: any) => {
|
||||
promises.push(this.deactivateRouteAndItsChildren(v, contexts));
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(
|
||||
() => {
|
||||
if (context.outlet) {
|
||||
// Destroy the component
|
||||
const result = context.outlet.deactivate();
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
context.children.onOutletDeactivated();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
protected activateChildRoutes(
|
||||
futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null,
|
||||
contexts: ChildrenOutletContexts): Promise<void> {
|
||||
|
||||
const children: {[outlet: string]: any} = nodeChildrenAsMap(currNode);
|
||||
|
||||
|
||||
const promises = futureNode.children.map((c: TreeNode<ActivatedRoute>) => {
|
||||
const promise = this.activateRoutes(c, children[c.value.outlet], contexts);
|
||||
promise
|
||||
.then(
|
||||
() => {
|
||||
this.forwardEvent(new ActivationEnd(c.value.snapshot));
|
||||
}
|
||||
);
|
||||
return promise;
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(
|
||||
() => {
|
||||
if (futureNode.children.length) {
|
||||
this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected activateRoutes(
|
||||
futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>,
|
||||
parentContexts: ChildrenOutletContexts): Promise<void> {
|
||||
const future = futureNode.value;
|
||||
const curr = currNode ? currNode.value : null;
|
||||
|
||||
advanceActivatedRoute(future);
|
||||
|
||||
// reusing the node
|
||||
if (future === curr) {
|
||||
if (future.component) {
|
||||
// If we have a normal route, we need to go through an outlet.
|
||||
const context = parentContexts.getOrCreateContext(future.outlet);
|
||||
return this.activateChildRoutes(futureNode, currNode, context.children);
|
||||
} else {
|
||||
// if we have a componentless route, we recurse but keep the same outlet map.
|
||||
return this.activateChildRoutes(futureNode, currNode, parentContexts);
|
||||
}
|
||||
} else {
|
||||
if (future.component) {
|
||||
// if we have a normal route, we need to place the component into the outlet and recurse.
|
||||
const context = parentContexts.getOrCreateContext(future.outlet);
|
||||
|
||||
if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
|
||||
const stored =
|
||||
(<any>this.routeReuseStrategy.retrieve(future.snapshot));
|
||||
this.routeReuseStrategy.store(future.snapshot, null);
|
||||
context.children.onOutletReAttached(stored.contexts);
|
||||
context.attachRef = stored.componentRef;
|
||||
context.route = stored.route.value;
|
||||
if (context.outlet) {
|
||||
// Attach right away when the outlet has already been instantiated
|
||||
// Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated
|
||||
const result = context.outlet.attach(stored.componentRef, stored.route.value);
|
||||
return Promise.resolve(result)
|
||||
.then(
|
||||
() => {
|
||||
return this.advanceActivatedRouteNodeAndItsChildren(stored.route);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve(this.advanceActivatedRouteNodeAndItsChildren(stored.route));
|
||||
|
||||
} else {
|
||||
const config = this.parentLoadedConfig(future.snapshot);
|
||||
const cmpFactoryResolver = config ? config.module.componentFactoryResolver : null;
|
||||
|
||||
context.route = future;
|
||||
context.resolver = cmpFactoryResolver;
|
||||
if (context.outlet) {
|
||||
// Activate the outlet when it has already been instantiated
|
||||
// Otherwise it will get activated from its `ngOnInit` when instantiated
|
||||
const result = context.outlet.activateWith(future, cmpFactoryResolver);
|
||||
return Promise.resolve(result)
|
||||
.then(
|
||||
() => {
|
||||
return this.activateChildRoutes(futureNode, null, context.children);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return this.activateChildRoutes(futureNode, null, context.children);
|
||||
}
|
||||
} else {
|
||||
// if we have a componentless route, we recurse but keep the same outlet map.
|
||||
return this.activateChildRoutes(futureNode, null, parentContexts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
advanceActivatedRouteNodeAndItsChildren(node: TreeNode<ActivatedRoute>): void {
|
||||
advanceActivatedRoute(node.value);
|
||||
node.children.forEach(this.advanceActivatedRouteNodeAndItsChildren);
|
||||
}
|
||||
|
||||
parentLoadedConfig(snapshot: ActivatedRouteSnapshot): any|null {
|
||||
for (let s = snapshot.parent; s; s = s.parent) {
|
||||
const route = s.routeConfig as any;
|
||||
if (route && route._loadedConfig) return route._loadedConfig;
|
||||
if (route && route.component) return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
import {
|
||||
Event,
|
||||
NavigationCancel,
|
||||
NavigationEnd,
|
||||
NavigationError,
|
||||
RouterState,
|
||||
UrlTree
|
||||
} from '@angular/router';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import {Subject} from 'rxjs/Subject';
|
||||
|
||||
import { AsyncActivateRoutes } from './async-activated-routes';
|
||||
|
||||
export function monkeyPatchRouter(router: any) {
|
||||
router.activateRoutes = (state: Observable<{appliedUrl: string, state: RouterState, shouldActivate: boolean}>, storedState: RouterState,
|
||||
storedUrl: UrlTree, id: number, url: UrlTree, rawUrl: UrlTree, skipLocationChange: boolean, replaceUrl: boolean, resolvePromise: any, rejectPromise: any) => {
|
||||
|
||||
// applied the new router state
|
||||
// this operation has side effects
|
||||
let navigationIsSuccessful: boolean;
|
||||
|
||||
const routes: AsyncActivateRoutes[] = [];
|
||||
state
|
||||
.forEach(({appliedUrl, state, shouldActivate}: any) => {
|
||||
if (!shouldActivate || id !== router.navigationId) {
|
||||
navigationIsSuccessful = false;
|
||||
return;
|
||||
}
|
||||
|
||||
router.currentUrlTree = appliedUrl;
|
||||
router.rawUrlTree = router.urlHandlingStrategy.merge(router.currentUrlTree, rawUrl);
|
||||
|
||||
(router as{routerState: RouterState}).routerState = state;
|
||||
|
||||
if (!skipLocationChange) {
|
||||
const path = router.urlSerializer.serialize(router.rawUrlTree);
|
||||
if (router.location.isCurrentPathEqualTo(path) || replaceUrl) {
|
||||
router.location.replaceState(path, '');
|
||||
} else {
|
||||
router.location.go(path, '');
|
||||
}
|
||||
}
|
||||
|
||||
routes.push(new AsyncActivateRoutes(router.routeReuseStrategy, state, storedState, (evt: Event) => router.triggerEvent(evt)));
|
||||
|
||||
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const promises = routes.map(activatedRoute => activatedRoute.activate(router.rootContexts));
|
||||
return Promise.all(promises)
|
||||
.then(
|
||||
() => {
|
||||
navigationIsSuccessful = true;
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
if (navigationIsSuccessful) {
|
||||
router.navigated = true;
|
||||
router.lastSuccessfulId = id;
|
||||
(router.events as Subject<Event>)
|
||||
.next(new NavigationEnd(
|
||||
id, router.serializeUrl(url), router.serializeUrl(router.currentUrlTree)));
|
||||
resolvePromise(true);
|
||||
} else {
|
||||
router.resetUrlToCurrentUrlTree();
|
||||
(router.events as Subject<Event>)
|
||||
.next(new NavigationCancel(id, router.serializeUrl(url), ''));
|
||||
resolvePromise(false);
|
||||
}
|
||||
},
|
||||
(e: any) => {
|
||||
if (isNavigationCancelingError(e)) {
|
||||
router.navigated = true;
|
||||
router.resetStateAndUrl(storedState, storedUrl, rawUrl);
|
||||
(router.events as Subject<Event>)
|
||||
.next(new NavigationCancel(id, router.serializeUrl(url), e.message));
|
||||
|
||||
resolvePromise(false);
|
||||
} else {
|
||||
router.resetStateAndUrl(storedState, storedUrl, rawUrl);
|
||||
(router.events as Subject<Event>)
|
||||
.next(new NavigationError(id, router.serializeUrl(url), e));
|
||||
try {
|
||||
resolvePromise(router.errorHandler(e));
|
||||
} catch (ee) {
|
||||
rejectPromise(ee);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
function isNavigationCancelingError(error: any) {
|
||||
return error && (/** @type {?} */ (error))[NAVIGATION_CANCELING_ERROR];
|
||||
}
|
||||
|
||||
const NAVIGATION_CANCELING_ERROR = 'ngNavigationCancelingError';
|
@ -1,23 +0,0 @@
|
||||
import { Injector } from '@angular/core';
|
||||
import {
|
||||
ActivatedRoute,
|
||||
ChildrenOutletContexts
|
||||
} from '@angular/router';
|
||||
|
||||
export class OutletInjector implements Injector {
|
||||
|
||||
constructor(private route: ActivatedRoute, private childContexts: ChildrenOutletContexts, private parent: Injector) {
|
||||
}
|
||||
|
||||
get(token: any, notFoundValue?: any): any {
|
||||
if (token === ActivatedRoute) {
|
||||
return this.route;
|
||||
}
|
||||
|
||||
if (token === ChildrenOutletContexts) {
|
||||
return this.childContexts;
|
||||
}
|
||||
|
||||
return this.parent.get(token, notFoundValue);
|
||||
}
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
import {
|
||||
Attribute,
|
||||
ChangeDetectorRef,
|
||||
ComponentFactoryResolver,
|
||||
ComponentRef,
|
||||
Directive,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Injector,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
Type,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
ActivatedRoute,
|
||||
ChildrenOutletContexts,
|
||||
PRIMARY_OUTLET,
|
||||
Router
|
||||
} from '@angular/router';
|
||||
|
||||
import { RouterDelegate } from '@ionic/core';
|
||||
|
||||
import { OutletInjector } from './outlet-injector';
|
||||
import { RouteEventHandler } from './route-event-handler';
|
||||
|
||||
import { AngularComponentMounter, AngularEscapeHatch } from '..';
|
||||
import { getIonApp } from '../util/util';
|
||||
|
||||
let id = 0;
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-nav',
|
||||
})
|
||||
export class RouterOutlet implements OnDestroy, OnInit, RouterDelegate {
|
||||
|
||||
public name: string;
|
||||
public activationStatus = NOT_ACTIVATED;
|
||||
public componentConstructor: Type<any> = null;
|
||||
public componentInstance: any = null;
|
||||
public activatedRoute: ActivatedRoute = null;
|
||||
public activatedRouteData: any = {};
|
||||
public activeComponentRef: ComponentRef<any> = null;
|
||||
private id: number = id++;
|
||||
|
||||
@Output('activate') activateEvents = new EventEmitter<any>();
|
||||
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
|
||||
|
||||
constructor(
|
||||
public location: ViewContainerRef,
|
||||
public changeDetector: ChangeDetectorRef,
|
||||
public elementRef: ElementRef,
|
||||
protected angularComponentMounter: AngularComponentMounter,
|
||||
protected parentContexts: ChildrenOutletContexts,
|
||||
protected cfr: ComponentFactoryResolver,
|
||||
protected injector: Injector,
|
||||
protected router: Router,
|
||||
private routeEventHandler: RouteEventHandler,
|
||||
@Attribute('name') name: string) {
|
||||
|
||||
(this.elementRef.nativeElement as HTMLIonNavElement).routerDelegate = this;
|
||||
this.name = name || PRIMARY_OUTLET;
|
||||
parentContexts.onChildOutletCreated(this.name, this as any);
|
||||
}
|
||||
|
||||
pushUrlState(urlSegment: string): Promise<any> {
|
||||
return this.router.navigateByUrl(urlSegment);
|
||||
}
|
||||
|
||||
popUrlState(): Promise<any> {
|
||||
window.history.back();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
console.debug(`Nav ${this.id} ngOnDestroy`);
|
||||
this.parentContexts.onChildOutletDestroyed(this.name);
|
||||
}
|
||||
|
||||
get isActivated(): boolean {
|
||||
return this.activationStatus === ACTIVATION_IN_PROGRESS
|
||||
|| this.activationStatus === ACTIVATED;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.isActivated) {
|
||||
// If the outlet was not instantiated at the time the route got activated we need to populate
|
||||
// the outlet when it is initialized (ie inside a NgIf)
|
||||
const context = this.parentContexts.getContext(this.name);
|
||||
if (context && context.route) {
|
||||
// the component defined in the configuration is created
|
||||
// otherwise the component defined in the configuration is created
|
||||
this.activateWith(context.route, context.resolver || null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get component(): Object {
|
||||
return this.componentInstance;
|
||||
}
|
||||
|
||||
deactivate(): void {
|
||||
console.debug(`outlet ${this.id} is being deactivated`);
|
||||
this.activationStatus = NOT_ACTIVATED;
|
||||
this.deactivateEvents.emit(this.componentConstructor);
|
||||
}
|
||||
|
||||
activateWith(activatedRoute: ActivatedRoute, cfr: ComponentFactoryResolver): Promise<void> {
|
||||
|
||||
if (this.activationStatus !== NOT_ACTIVATED) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.activationStatus = ACTIVATION_IN_PROGRESS;
|
||||
this.activatedRoute = activatedRoute;
|
||||
const snapshot = (activatedRoute as any)._futureSnapshot;
|
||||
const component = snapshot.routeConfig ? snapshot.routeConfig.component : null;
|
||||
cfr = cfr || this.cfr;
|
||||
const childContexts = this.parentContexts.getOrCreateContext(this.name).children;
|
||||
const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector);
|
||||
|
||||
const isTopLevel = !hasChildComponent(activatedRoute);
|
||||
|
||||
return this.routeEventHandler.externalNavStart().then(() => {
|
||||
return getDataFromRoute(activatedRoute);
|
||||
}).then((dataObj: any) => {
|
||||
return activateRoute(this.elementRef.nativeElement, component, dataObj, cfr, injector, isTopLevel).then(() => {
|
||||
this.changeDetector.markForCheck();
|
||||
this.activateEvents.emit(null);
|
||||
this.activationStatus = ACTIVATED;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function activateRoute(navElement: HTMLIonNavElement,
|
||||
component: Type<any>, data: any = {}, cfr: ComponentFactoryResolver, injector: Injector, isTopLevel: boolean): Promise<any> {
|
||||
|
||||
return getIonApp().then((ionApp) => {
|
||||
if (!ionApp) {
|
||||
return Promise.reject(new Error(`<ion-app> element is required for angular router integration`));
|
||||
}
|
||||
const escapeHatch = getEscapeHatch(cfr, injector);
|
||||
return navElement.componentOnReady().then(() => {
|
||||
return navElement.reconcileFromExternalRouter(component, data, escapeHatch, isTopLevel);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const NOT_ACTIVATED = 0;
|
||||
export const ACTIVATION_IN_PROGRESS = 1;
|
||||
export const ACTIVATED = 2;
|
||||
|
||||
export function hasChildComponent(activatedRoute: ActivatedRoute): boolean {
|
||||
// don't worry about recursion for now, that's a future problem that may or may not manifest itself
|
||||
for (const childRoute of activatedRoute.children) {
|
||||
if (childRoute.component) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getEscapeHatch(cfr: ComponentFactoryResolver, injector: Injector): AngularEscapeHatch {
|
||||
return {
|
||||
cfr,
|
||||
injector,
|
||||
fromExternalRouter: true,
|
||||
url: location.pathname
|
||||
};
|
||||
}
|
||||
|
||||
export function getDataFromRoute(activatedRoute: ActivatedRoute): Promise<any> {
|
||||
const promises: Promise<any>[] = [];
|
||||
|
||||
promises.push(getDataFromObservable(activatedRoute));
|
||||
promises.push(getDataFromParams(activatedRoute));
|
||||
return Promise.all(promises).then(([data, params]: any[]) => {
|
||||
const combined = {};
|
||||
Object.assign(combined, data, params);
|
||||
return combined;
|
||||
});
|
||||
}
|
||||
|
||||
export function getDataFromObservable(activatedRoute: ActivatedRoute) {
|
||||
return new Promise((resolve) => {
|
||||
activatedRoute.data.subscribe((data: any) => {
|
||||
resolve(data || {});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getDataFromParams(activatedRoute: ActivatedRoute) {
|
||||
return new Promise((resolve) => {
|
||||
activatedRoute.params.subscribe((data: any) => {
|
||||
resolve(data || {});
|
||||
});
|
||||
});
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
import {
|
||||
ComponentFactoryResolver,
|
||||
ComponentRef
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
ActivatedRoute,
|
||||
ChildrenOutletContexts,
|
||||
OutletContext,
|
||||
RouterOutlet
|
||||
} from '@angular/router';
|
||||
|
||||
export class PushPopOutletContexts extends ChildrenOutletContexts {
|
||||
|
||||
// this method is a public api, but the members in the ChildrenOutletContexts are private
|
||||
// so we're gonna cheat, 'cause we play to win
|
||||
onOutletDeactivated(): Map<string, OutletContext> {
|
||||
return (this as any).contexts;
|
||||
}
|
||||
|
||||
getOrCreateContext(childName: string): OutletContext {
|
||||
let context = this.getContext(childName) as any;
|
||||
|
||||
if (!context) {
|
||||
context = {
|
||||
children: new PushPopOutletContexts()
|
||||
};
|
||||
(this as any).contexts.set(childName, context);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
export interface PushPopOutletContext {
|
||||
outlet?: RouterOutlet;
|
||||
route?: ActivatedRoute;
|
||||
resolver?: ComponentFactoryResolver;
|
||||
children?: PushPopOutletContexts;
|
||||
attachRef: ComponentRef<any>;
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
Event,
|
||||
NavigationEnd,
|
||||
Router
|
||||
} from '@angular/router';
|
||||
|
||||
import { getIonApp } from '../util/util';
|
||||
|
||||
@Injectable()
|
||||
export class RouteEventHandler {
|
||||
|
||||
constructor(public router: Router) {
|
||||
|
||||
router.events.subscribe((event: Event) => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
getIonApp().then((appElement) => {
|
||||
appElement.updateExternalNavOccuring(false);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
externalNavStart() {
|
||||
return getIonApp().then((appElement) => {
|
||||
appElement.updateExternalNavOccuring(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,115 +0,0 @@
|
||||
import {
|
||||
Location
|
||||
} from '@angular/common';
|
||||
|
||||
import {
|
||||
ApplicationRef,
|
||||
Compiler,
|
||||
Injector,
|
||||
ModuleWithProviders,
|
||||
NgModule,
|
||||
NgModuleFactoryLoader,
|
||||
Optional,
|
||||
} from '@angular/core';
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/platform-browser';
|
||||
|
||||
import {
|
||||
ChildrenOutletContexts,
|
||||
ExtraOptions,
|
||||
ROUTER_CONFIGURATION,
|
||||
ROUTES,
|
||||
Route,
|
||||
RouteReuseStrategy,
|
||||
Router,
|
||||
UrlHandlingStrategy,
|
||||
UrlSerializer
|
||||
} from '@angular/router';
|
||||
|
||||
import { IonicAngularModule } from '../module';
|
||||
|
||||
import { PushPopOutletContexts } from './push-pop-outlet-contexts';
|
||||
import { monkeyPatchRouter } from './monkey-patch-router';
|
||||
import { RouteEventHandler } from './route-event-handler';
|
||||
import { RouterOutlet } from './outlet';
|
||||
import { flatten } from './router-utils';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
RouterOutlet
|
||||
],
|
||||
imports: [
|
||||
IonicAngularModule
|
||||
],
|
||||
exports: [
|
||||
RouterOutlet
|
||||
]
|
||||
})
|
||||
export class IonicRouterModule {
|
||||
static forRoot(): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: IonicRouterModule,
|
||||
providers: [
|
||||
{
|
||||
provide: ChildrenOutletContexts,
|
||||
useClass: PushPopOutletContexts
|
||||
},
|
||||
{
|
||||
provide: Router,
|
||||
useFactory: setupRouter,
|
||||
deps: [
|
||||
ApplicationRef, UrlSerializer, ChildrenOutletContexts, Location, Injector,
|
||||
NgModuleFactoryLoader, Compiler, ROUTES, ROUTER_CONFIGURATION,
|
||||
[UrlHandlingStrategy, new Optional()], [RouteReuseStrategy, new Optional()]
|
||||
]
|
||||
},
|
||||
RouteEventHandler
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function setupRouter(
|
||||
_ref: ApplicationRef, urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts,
|
||||
location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler,
|
||||
config: Route[][], opts: ExtraOptions = {}, urlHandlingStrategy?: UrlHandlingStrategy,
|
||||
routeReuseStrategy?: RouteReuseStrategy) {
|
||||
|
||||
const router = new Router(
|
||||
null, urlSerializer, contexts, location, injector, loader, compiler, flatten(config));
|
||||
|
||||
monkeyPatchRouter(router);
|
||||
|
||||
|
||||
if (urlHandlingStrategy) {
|
||||
router.urlHandlingStrategy = urlHandlingStrategy;
|
||||
}
|
||||
|
||||
if (routeReuseStrategy) {
|
||||
router.routeReuseStrategy = routeReuseStrategy;
|
||||
}
|
||||
|
||||
if (opts.errorHandler) {
|
||||
router.errorHandler = opts.errorHandler;
|
||||
}
|
||||
|
||||
if (opts.enableTracing) {
|
||||
const dom = getDOM();
|
||||
router.events.subscribe((e: any) => {
|
||||
dom.logGroup(`Router Event: ${(e.constructor).name}`);
|
||||
dom.log(e.toString());
|
||||
dom.log(e);
|
||||
dom.logGroupEnd();
|
||||
});
|
||||
}
|
||||
|
||||
if (opts.onSameUrlNavigation) {
|
||||
router.onSameUrlNavigation = opts.onSameUrlNavigation;
|
||||
}
|
||||
|
||||
if (opts.paramsInheritanceStrategy) {
|
||||
router.paramsInheritanceStrategy = opts.paramsInheritanceStrategy;
|
||||
}
|
||||
|
||||
return router;
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
export function nodeChildrenAsMap<T extends{outlet: string}>(node: TreeNode<T>| null) {
|
||||
const map: {[outlet: string]: TreeNode<T>} = {};
|
||||
|
||||
if (node) {
|
||||
node.children.forEach(child => map[child.value.outlet] = child);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
export function forEach<_K, V>(map: {[key: string]: V}, callback: (v: V, k: string) => void): void {
|
||||
for (const prop in map) {
|
||||
if (map.hasOwnProperty(prop)) {
|
||||
callback(map[prop], prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TreeNode<T> {
|
||||
constructor(public value: T, public children: TreeNode<T>[]) {}
|
||||
|
||||
toString(): string { return `TreeNode(${this.value})`; }
|
||||
}
|
||||
|
||||
/**
|
||||
* The expectation is that the activate route is created with the right set of parameters.
|
||||
* So we push new values into the observables only when they are not the initial values.
|
||||
* And we detect that by checking if the snapshot field is set.
|
||||
*/
|
||||
export function advanceActivatedRoute(route: any): void {
|
||||
if (route.snapshot) {
|
||||
const currentSnapshot = route.snapshot;
|
||||
const nextSnapshot = (route)._futureSnapshot;
|
||||
route.snapshot = nextSnapshot;
|
||||
if (!shallowEqual(currentSnapshot.queryParams, nextSnapshot.queryParams)) {
|
||||
(route.queryParams).next(nextSnapshot.queryParams);
|
||||
}
|
||||
if (currentSnapshot.fragment !== nextSnapshot.fragment) {
|
||||
(route.fragment).next(nextSnapshot.fragment);
|
||||
}
|
||||
if (!shallowEqual(currentSnapshot.params, nextSnapshot.params)) {
|
||||
(route.params).next(nextSnapshot.params);
|
||||
}
|
||||
if (!shallowEqualArrays(currentSnapshot.url, nextSnapshot.url)) {
|
||||
(route.url).next(nextSnapshot.url);
|
||||
}
|
||||
if (!shallowEqual(currentSnapshot.data, nextSnapshot.data)) {
|
||||
(route.data).next(nextSnapshot.data);
|
||||
}
|
||||
} else {
|
||||
route.snapshot = (route)._futureSnapshot;
|
||||
|
||||
// this is for resolved data
|
||||
(route.data).next((route)._futureSnapshot.data);
|
||||
}
|
||||
}
|
||||
|
||||
export function shallowEqualArrays(a: any[], b: any[]): boolean {
|
||||
if (a.length !== b.length) return false;
|
||||
for (let i = 0; i < a.length; ++i) {
|
||||
if (!shallowEqual(a[i], b[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function shallowEqual(a: {[x: string]: any}, b: {[x: string]: any}): boolean {
|
||||
const k1 = Object.keys(a);
|
||||
const k2 = Object.keys(b);
|
||||
/*tslint:disable*/
|
||||
if (k1.length != k2.length) {
|
||||
return false;
|
||||
}
|
||||
let key: string;
|
||||
for (let i = 0; i < k1.length; i++) {
|
||||
key = k1[i];
|
||||
if (a[key] !== b[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function flatten<T>(arr: T[][]): T[] {
|
||||
return Array.prototype.concat.apply([], arr);
|
||||
}
|
@ -1,26 +1,3 @@
|
||||
import {
|
||||
ComponentFactory,
|
||||
ComponentFactoryResolver,
|
||||
ComponentRef,
|
||||
Injector
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { EscapeHatch, FrameworkMountingData} from '@ionic/core';
|
||||
|
||||
export interface AngularMountingData extends FrameworkMountingData {
|
||||
componentFactory?: ComponentFactory<any>;
|
||||
childInjector?: Injector;
|
||||
componentRef?: ComponentRef<any>;
|
||||
instance?: any;
|
||||
angularHostElement?: HTMLElement;
|
||||
}
|
||||
|
||||
export interface AngularEscapeHatch extends EscapeHatch {
|
||||
activatedRoute?: ActivatedRoute;
|
||||
cfr?: ComponentFactoryResolver;
|
||||
injector?: Injector;
|
||||
}
|
||||
|
||||
export interface IonicGlobal {
|
||||
config: any;
|
||||
|
Reference in New Issue
Block a user