diff --git a/packages/angular/src/di/di.ts b/packages/angular/src/di/di.ts deleted file mode 100644 index 217b2ab917..0000000000 --- a/packages/angular/src/di/di.ts +++ /dev/null @@ -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('NavControllerToken'); -export const NavParamsToken = new InjectionToken('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); -} diff --git a/packages/angular/src/directives/ion-nav.ts b/packages/angular/src/directives/ion-nav.ts deleted file mode 100644 index 40e1323d35..0000000000 --- a/packages/angular/src/directives/ion-nav.ts +++ /dev/null @@ -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, - data?: any, - classesToAdd?: string[], - escapeHatch: AngularEscapeHatch = {}): Promise { - - // 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); - } - -} diff --git a/packages/angular/src/providers/angular-component-mounter.ts b/packages/angular/src/providers/angular-component-mounter.ts deleted file mode 100644 index d605ed5b20..0000000000 --- a/packages/angular/src/providers/angular-component-mounter.ts +++ /dev/null @@ -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(); - -@Injectable() -export class AngularComponentMounter { - - constructor(private defaultCfr: ComponentFactoryResolver, private zone: NgZone, private appRef: ApplicationRef) { - } - - attachViewToDom(parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type, componentResolveFactory: ComponentFactoryResolver, injector: Injector, data: any, classesToAdd: string[]): Promise { - - 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 { - return new Promise((resolve) => { - this.zone.run(() => { - removeViewFromDom(parentElement, childElement); - resolve(); - }); - }); - } - - attachViewToDomImpl(crf: ComponentFactoryResolver, parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type, 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(); - } -} diff --git a/packages/angular/src/providers/app.ts b/packages/angular/src/providers/app.ts deleted file mode 100644 index 61392a0833..0000000000 --- a/packages/angular/src/providers/app.ts +++ /dev/null @@ -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 { - return getRootNavsAsyncImpl(this); - } - - getTopNavs(rootNavId?: number): PublicNav[] { - return getTopNavsImpl(this, rootNavId); - } - - getTopNavsAsync(rootNavId?: number): Promise { - return getTopNavsAsyncImpl(this, rootNavId); - } - - getNavByIdOrName(nameOrId: number | string): PublicNav { - return getNavByIdOrNameImpl(this, nameOrId); - } - - getNavByIdOrNameAsync(nameOrId: number | string): Promise { - 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 { - 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 { - return app._element.componentOnReady().then(() => { - return app._element.getNavByIdOrName(nameOrId); - }); -} diff --git a/packages/angular/src/providers/modal-controller.ts b/packages/angular/src/providers/modal-controller.ts index 64809a644e..204bd7e413 100644 --- a/packages/angular/src/providers/modal-controller.ts +++ b/packages/angular/src/providers/modal-controller.ts @@ -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, data?: any, classesToAdd?: string[]): Promise { - - 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) { diff --git a/packages/angular/src/providers/nav-controller.ts b/packages/angular/src/providers/nav-controller.ts deleted file mode 100644 index 483590761d..0000000000 --- a/packages/angular/src/providers/nav-controller.ts +++ /dev/null @@ -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 { - return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => { - return navElement.push(component, data, opts); - }); - } - - pop(opts?: NavOptions): Promise { - return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => { - return navElement.pop(opts); - }); - } - - setRoot(component: any, data?: any, opts?: NavOptions): Promise { - return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => { - return navElement.setRoot(component, data, opts); - }); - } - - insert(insertIndex: number, page: any, params?: any, opts?: NavOptions): Promise { - return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => { - return navElement.insert(insertIndex, page, params, opts); - }); - } - - insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions): Promise { - return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => { - return navElement.insertPages(insertIndex, insertPages, opts); - }); - } - - popToRoot(opts?: NavOptions): Promise { - return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => { - return navElement.popToRoot(opts); - }); - } - - popTo(indexOrViewCtrl: any, opts?: NavOptions): Promise { - return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => { - return navElement.popTo(indexOrViewCtrl, opts); - }); - } - - removeIndex(startIndex: number, removeCount?: number, opts?: NavOptions): Promise { - return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => { - return navElement.removeIndex(startIndex, removeCount, opts); - }); - } - - removeView(viewController: PublicViewController, opts?: NavOptions): Promise { - return hydrateElement(this.element).then((navElement: HTMLIonNavElement) => { - return navElement.removeView(viewController, opts); - }); - } - - setPages(componentDataPairs: any[], opts?: NavOptions): Promise { - 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 []; - } -} diff --git a/packages/angular/src/providers/nav-params.ts b/packages/angular/src/providers/nav-params.ts deleted file mode 100644 index 6e065aaeb6..0000000000 --- a/packages/angular/src/providers/nav-params.ts +++ /dev/null @@ -1,10 +0,0 @@ - -export class NavParams { - - constructor(public data: any = {}) { - } - - get(param: string): any { - return this.data[param]; - } -} diff --git a/packages/angular/src/providers/popover-controller.ts b/packages/angular/src/providers/popover-controller.ts index 51b99463ca..fe0488dbe7 100644 --- a/packages/angular/src/providers/popover-controller.ts +++ b/packages/angular/src/providers/popover-controller.ts @@ -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, data?: any, classesToAdd?: string[]): Promise { - - 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) { diff --git a/packages/angular/src/router/async-activated-routes.ts b/packages/angular/src/router/async-activated-routes.ts deleted file mode 100644 index 5cf9ef12d6..0000000000 --- a/packages/angular/src/router/async-activated-routes.ts +++ /dev/null @@ -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 { - 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, currNode: TreeNode|null, - contexts: ChildrenOutletContexts): Promise { - - const children: {[outletName: string]: TreeNode} = nodeChildrenAsMap(currNode); - - const promises = futureNode.children.map((futureChild: TreeNode) => { - 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[] = []; - // De-activate the routes that will not be re-used - forEach(children, (v: TreeNode) => { - promises.push(this.deactivateRouteAndItsChildren(v, contexts)); - }); - - return Promise.all(promises); - } - ); - } - - protected deactivateRoutes( - futureNode: TreeNode, currNode: TreeNode, - parentContext: ChildrenOutletContexts): Promise { - 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, parentContexts: ChildrenOutletContexts): Promise { - if (this.routeReuseStrategy.shouldDetach(route.value.snapshot)) { - return this.detachAndStoreRouteSubtree(route, parentContexts); - } else { - return this.deactivateRouteAndOutlet(route, parentContexts); - } - } - - protected detachAndStoreRouteSubtree( - route: TreeNode, parentContexts: ChildrenOutletContexts): Promise { - const context = parentContexts.getContext(route.value.outlet); - if (context && context.outlet) { - const componentRefOrPromise = context.outlet.detach(); - return Promise.resolve(componentRefOrPromise) - .then( - (componentRef: ComponentRef) => { - const contexts = context.children.onOutletDeactivated(); - this.routeReuseStrategy.store(route.value.snapshot, {componentRef, route, contexts}); - } - ); - } - return Promise.resolve(); - } - - protected deactivateRouteAndOutlet( - route: TreeNode, parentContexts: ChildrenOutletContexts): Promise { - 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[] = []; - 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, currNode: TreeNode|null, - contexts: ChildrenOutletContexts): Promise { - - const children: {[outlet: string]: any} = nodeChildrenAsMap(currNode); - - - const promises = futureNode.children.map((c: TreeNode) => { - 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, currNode: TreeNode, - parentContexts: ChildrenOutletContexts): Promise { - 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 = - (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): 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; - } -} diff --git a/packages/angular/src/router/monkey-patch-router.ts b/packages/angular/src/router/monkey-patch-router.ts deleted file mode 100644 index db816b5f35..0000000000 --- a/packages/angular/src/router/monkey-patch-router.ts +++ /dev/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) - .next(new NavigationEnd( - id, router.serializeUrl(url), router.serializeUrl(router.currentUrlTree))); - resolvePromise(true); - } else { - router.resetUrlToCurrentUrlTree(); - (router.events as Subject) - .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) - .next(new NavigationCancel(id, router.serializeUrl(url), e.message)); - - resolvePromise(false); - } else { - router.resetStateAndUrl(storedState, storedUrl, rawUrl); - (router.events as Subject) - .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'; diff --git a/packages/angular/src/router/outlet-injector.ts b/packages/angular/src/router/outlet-injector.ts deleted file mode 100644 index d3c52266cd..0000000000 --- a/packages/angular/src/router/outlet-injector.ts +++ /dev/null @@ -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); - } -} diff --git a/packages/angular/src/router/outlet.ts b/packages/angular/src/router/outlet.ts deleted file mode 100644 index 5d2a76a2f8..0000000000 --- a/packages/angular/src/router/outlet.ts +++ /dev/null @@ -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 = null; - public componentInstance: any = null; - public activatedRoute: ActivatedRoute = null; - public activatedRouteData: any = {}; - public activeComponentRef: ComponentRef = null; - private id: number = id++; - - @Output('activate') activateEvents = new EventEmitter(); - @Output('deactivate') deactivateEvents = new EventEmitter(); - - 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 { - return this.router.navigateByUrl(urlSegment); - } - - popUrlState(): Promise { - 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 { - - 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, data: any = {}, cfr: ComponentFactoryResolver, injector: Injector, isTopLevel: boolean): Promise { - - return getIonApp().then((ionApp) => { - if (!ionApp) { - return Promise.reject(new Error(` 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 { - const promises: Promise[] = []; - - 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 || {}); - }); - }); -} diff --git a/packages/angular/src/router/push-pop-outlet-contexts.ts b/packages/angular/src/router/push-pop-outlet-contexts.ts deleted file mode 100644 index 5bf5fa9278..0000000000 --- a/packages/angular/src/router/push-pop-outlet-contexts.ts +++ /dev/null @@ -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 { - 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; -} diff --git a/packages/angular/src/router/route-event-handler.ts b/packages/angular/src/router/route-event-handler.ts deleted file mode 100644 index f1dea439ab..0000000000 --- a/packages/angular/src/router/route-event-handler.ts +++ /dev/null @@ -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); - }); - } -} - diff --git a/packages/angular/src/router/router-module.ts b/packages/angular/src/router/router-module.ts deleted file mode 100644 index 1cfe9064b0..0000000000 --- a/packages/angular/src/router/router-module.ts +++ /dev/null @@ -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; -} diff --git a/packages/angular/src/router/router-utils.ts b/packages/angular/src/router/router-utils.ts deleted file mode 100644 index 5ece29495b..0000000000 --- a/packages/angular/src/router/router-utils.ts +++ /dev/null @@ -1,85 +0,0 @@ -export function nodeChildrenAsMap(node: TreeNode| null) { - const map: {[outlet: string]: TreeNode} = {}; - - 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 { - constructor(public value: T, public children: TreeNode[]) {} - - 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(arr: T[][]): T[] { - return Array.prototype.concat.apply([], arr); -} diff --git a/packages/angular/src/types/interfaces.ts b/packages/angular/src/types/interfaces.ts index 608affa7f0..6c18137dfa 100644 --- a/packages/angular/src/types/interfaces.ts +++ b/packages/angular/src/types/interfaces.ts @@ -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; - childInjector?: Injector; - componentRef?: ComponentRef; - instance?: any; - angularHostElement?: HTMLElement; -} - -export interface AngularEscapeHatch extends EscapeHatch { - activatedRoute?: ActivatedRoute; - cfr?: ComponentFactoryResolver; - injector?: Injector; -} export interface IonicGlobal { config: any; diff --git a/packages/angular/tslint.json b/packages/angular/tslint.json index aa8b53d98c..e22675d04b 100644 --- a/packages/angular/tslint.json +++ b/packages/angular/tslint.json @@ -1,3 +1,6 @@ { - "extends": "tslint-ionic-rules" + "extends": "tslint-ionic-rules", + "rules": { + "no-non-null-assertion": false + } }