UNPKG

nativescript-angular

Version:

An Angular renderer that lets you build mobile apps with NativeScript.

409 lines • 18.4 kB
Object.defineProperty(exports, "__esModule", { value: true }); var core_1 = require("@angular/core"); var router_1 = require("@angular/router"); var frame_1 = require("tns-core-modules/ui/frame"); var page_1 = require("tns-core-modules/ui/page"); var profiling_1 = require("tns-core-modules/profiling"); var rxjs_1 = require("rxjs"); var platform_providers_1 = require("../platform-providers"); var trace_1 = require("../trace"); var detached_loader_1 = require("../common/detached-loader"); var view_util_1 = require("../view-util"); var ns_location_strategy_1 = require("./ns-location-strategy"); var ns_route_reuse_strategy_1 = require("./ns-route-reuse-strategy"); var PageRoute = /** @class */ (function () { function PageRoute(startRoute) { this.activatedRoute = new rxjs_1.BehaviorSubject(startRoute); } return PageRoute; }()); exports.PageRoute = PageRoute; // Used to "mark" ActivatedRoute snapshots that are handled in PageRouterOutlet exports.pageRouterActivatedSymbol = Symbol("page-router-activated"); exports.loaderRefSymbol = Symbol("loader-ref"); function destroyComponentRef(componentRef) { if (componentRef) { var loaderRef = componentRef[exports.loaderRefSymbol]; if (loaderRef) { loaderRef.destroy(); } componentRef.destroy(); } } exports.destroyComponentRef = destroyComponentRef; var ChildInjector = /** @class */ (function () { function ChildInjector(providers, parent) { this.providers = providers; this.parent = parent; } ChildInjector.prototype.get = function (token, notFoundValue) { var localValue = this.providers.get(token); if (localValue) { return localValue; } return this.parent.get(token, notFoundValue); }; return ChildInjector; }()); /** * There are cases where multiple activatedRoute nodes should be associated/handled by the same PageRouterOutlet. * We can gat additional ActivatedRoutes nodes when there is: * - Lazy loading - there is an additional ActivatedRoute node for the RouteConfig with the `loadChildren` setup * - Componentless routes - there is an additional ActivatedRoute node for the componentless RouteConfig * * Example: * R <-- root * | * feature (lazy module) <-- RouteConfig: { path: "lazy", loadChildren: "./feature/feature.module#FeatureModule" } * | * module (componentless route) <-- RouteConfig: { path: "module", children: [...] } // Note: No 'component' * | * home <-- RouteConfig: { path: "module", component: MyComponent } - this is what we get as activatedRoute param * * In these cases we will mark the top-most node (feature). NSRouteReuseStrategy will detach the tree there and * use this ActivateRoute as a kay for caching. */ function findTopActivatedRouteNodeForOutlet(activatedRoute) { var outletActivatedRoute = activatedRoute; while (outletActivatedRoute.parent && outletActivatedRoute.parent.routeConfig && !outletActivatedRoute.parent.routeConfig.component) { outletActivatedRoute = outletActivatedRoute.parent; } return outletActivatedRoute; } exports.findTopActivatedRouteNodeForOutlet = findTopActivatedRouteNodeForOutlet; function routeToString(activatedRoute) { return activatedRoute.pathFromRoot.join("->"); } var PageRouterOutlet = /** @class */ (function () { function PageRouterOutlet(parentContexts, location, name, actionBarVisibility, isEmptyOutlet, locationStrategy, componentFactoryResolver, resolver, changeDetector, device, pageFactory, routeReuseStrategy, elRef) { this.parentContexts = parentContexts; this.location = location; this.locationStrategy = locationStrategy; this.componentFactoryResolver = componentFactoryResolver; this.resolver = resolver; this.changeDetector = changeDetector; this.pageFactory = pageFactory; this.routeReuseStrategy = routeReuseStrategy; this.activated = null; this._activatedRoute = null; this.activateEvents = new core_1.EventEmitter(); // tslint:disable-line:no-output-rename this.deactivateEvents = new core_1.EventEmitter(); // tslint:disable-line:no-output-rename this.isEmptyOutlet = isEmptyOutlet; this.frame = elRef.nativeElement; this.setActionBarVisibility(actionBarVisibility); if (trace_1.isLogEnabled()) { trace_1.routerLog("PageRouterOutlet.constructor frame: " + this.frame); } this.name = name || router_1.PRIMARY_OUTLET; parentContexts.onChildOutletCreated(this.name, this); this.viewUtil = new view_util_1.ViewUtil(device); this.detachedLoaderFactory = resolver.resolveComponentFactory(detached_loader_1.DetachedLoader); } Object.defineProperty(PageRouterOutlet.prototype, "locationInjector", { /** @deprecated from Angular since v4 */ get: function () { return this.location.injector; }, enumerable: true, configurable: true }); Object.defineProperty(PageRouterOutlet.prototype, "locationFactoryResolver", { /** @deprecated from Angular since v4 */ get: function () { return this.resolver; }, enumerable: true, configurable: true }); Object.defineProperty(PageRouterOutlet.prototype, "isActivated", { get: function () { return !!this.activated; }, enumerable: true, configurable: true }); Object.defineProperty(PageRouterOutlet.prototype, "component", { get: function () { if (!this.activated) { if (trace_1.isLogEnabled()) { trace_1.routerLog("Outlet is not activated"); } return; } return this.activated.instance; }, enumerable: true, configurable: true }); Object.defineProperty(PageRouterOutlet.prototype, "activatedRoute", { get: function () { if (!this.activated) { if (trace_1.isLogEnabled()) { trace_1.routerLog("Outlet is not activated"); } return; } return this._activatedRoute; }, enumerable: true, configurable: true }); PageRouterOutlet.prototype.setActionBarVisibility = function (actionBarVisibility) { switch (actionBarVisibility) { case "always": case "never": this.frame.actionBarVisibility = actionBarVisibility; return; default: this.frame.actionBarVisibility = "auto"; } }; PageRouterOutlet.prototype.ngOnDestroy = function () { var _this = this; // Clear accumulated modal view page cache when page-router-outlet // destroyed on modal view closing this.parentContexts.onChildOutletDestroyed(this.name); if (this.outlet) { this.outlet.outletKeys.forEach(function (key) { _this.routeReuseStrategy.clearModalCache(key); }); this.locationStrategy.clearOutlet(this.frame); } else { trace_1.routerLog("PageRouterOutlet.ngOnDestroy: no outlet available for page-router-outlet"); } if (this.isActivated) { var c = this.activated.instance; this.activated.hostView.detach(); destroyComponentRef(this.activated); this.deactivateEvents.emit(c); this.activated = null; } }; PageRouterOutlet.prototype.deactivate = function () { if (!this.outlet || !this.outlet.isPageNavigationBack) { if (trace_1.isLogEnabled()) { trace_1.routerLog("Currently not in page back navigation - component should be detached instead of deactivated."); } return; } if (trace_1.isLogEnabled()) { trace_1.routerLog("PageRouterOutlet.deactivate() while going back - should destroy"); } if (!this.isActivated) { return; } var c = this.activated.instance; destroyComponentRef(this.activated); this.activated = null; this._activatedRoute = null; this.deactivateEvents.emit(c); }; /** * Called when the `RouteReuseStrategy` instructs to detach the subtree */ PageRouterOutlet.prototype.detach = function () { if (!this.isActivated) { if (trace_1.isLogEnabled()) { trace_1.routerLog("Outlet is not activated"); } return; } if (trace_1.isLogEnabled()) { trace_1.routerLog("PageRouterOutlet.detach() - " + routeToString(this._activatedRoute)); } // Detach from ChangeDetection this.activated.hostView.detach(); var component = this.activated; this.activated = null; this._activatedRoute = null; return component; }; /** * Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree */ PageRouterOutlet.prototype.attach = function (ref, activatedRoute) { if (trace_1.isLogEnabled()) { trace_1.routerLog("PageRouterOutlet.attach() - " + routeToString(activatedRoute)); } this.activated = ref; // reattach to ChangeDetection this.activated.hostView.markForCheck(); this.activated.hostView.reattach(); this._activatedRoute = activatedRoute; this.markActivatedRoute(activatedRoute); this.locationStrategy._finishBackPageNavigation(this.frame); }; /** * Called by the Router to instantiate a new component during the commit phase of a navigation. * This method in turn is responsible for calling the `routerOnActivate` hook of its child. */ PageRouterOutlet.prototype.activateWith = function (activatedRoute, resolver) { this.outlet = this.outlet || this.getOutlet(activatedRoute.snapshot); if (!this.outlet) { if (trace_1.isLogEnabled()) { trace_1.routerError("No outlet found relative to activated route"); } return; } this.outlet.isNSEmptyOutlet = this.isEmptyOutlet; this.locationStrategy.updateOutletFrame(this.outlet, this.frame, this.isEmptyOutlet); if (this.outlet && this.outlet.isPageNavigationBack) { if (trace_1.isLogEnabled()) { trace_1.routerLog("Currently in page back navigation - component should be reattached instead of activated."); } this.locationStrategy._finishBackPageNavigation(this.frame); } if (trace_1.isLogEnabled()) { trace_1.routerLog("PageRouterOutlet.activateWith() - " + routeToString(activatedRoute)); } this._activatedRoute = activatedRoute; this.markActivatedRoute(activatedRoute); resolver = resolver || this.resolver; this.activateOnGoForward(activatedRoute, resolver); this.activateEvents.emit(this.activated.instance); }; PageRouterOutlet.prototype.activateOnGoForward = function (activatedRoute, loadedResolver) { if (trace_1.isLogEnabled()) { trace_1.routerLog("PageRouterOutlet.activate() forward navigation - " + "create detached loader in the loader container"); } var factory = this.getComponentFactory(activatedRoute, loadedResolver); var page = this.pageFactory({ isNavigation: true, componentType: factory.componentType, }); var providers = new Map(); providers.set(page_1.Page, page); providers.set(frame_1.Frame, this.frame); providers.set(PageRoute, new PageRoute(activatedRoute)); providers.set(router_1.ActivatedRoute, activatedRoute); providers.set(router_1.ChildrenOutletContexts, this.parentContexts.getOrCreateContext(this.name).children); var childInjector = new ChildInjector(providers, this.location.injector); var loaderRef = this.location.createComponent(this.detachedLoaderFactory, this.location.length, childInjector, []); this.changeDetector.markForCheck(); this.activated = loaderRef.instance.loadWithFactory(factory); this.loadComponentInPage(page, this.activated); this.activated[exports.loaderRefSymbol] = loaderRef; }; PageRouterOutlet.prototype.loadComponentInPage = function (page, componentRef) { var _this = this; // Component loaded. Find its root native view. var componentView = componentRef.location.nativeElement; // Remove it from original native parent. this.viewUtil.removeChild(componentView.parent, componentView); // Add it to the new page this.viewUtil.insertChild(page, componentView); var navigatedFromCallback = global.Zone.current.wrap(function (args) { if (args.isBackNavigation) { _this.locationStrategy._beginBackPageNavigation(_this.frame); _this.locationStrategy.back(null, _this.frame); } }); page.on(page_1.Page.navigatedFromEvent, navigatedFromCallback); componentRef.onDestroy(function () { if (page) { page.off(page_1.Page.navigatedFromEvent, navigatedFromCallback); page = null; } }); var navOptions = this.locationStrategy._beginPageNavigation(this.frame); // Clear refCache if navigation with clearHistory if (navOptions.clearHistory) { var clearCallback = function () { return setTimeout(function () { if (_this.outlet) { _this.routeReuseStrategy.clearCache(_this.outlet.outletKeys[0]); } }); }; page.once(page_1.Page.navigatedToEvent, clearCallback); } this.frame.navigate({ create: function () { return page; }, clearHistory: navOptions.clearHistory, animated: navOptions.animated, transition: navOptions.transition }); }; // Find and mark the top activated route as an activated one. // In ns-location-strategy we are reusing components only if their corresponing routes // are marked as activated from this method. PageRouterOutlet.prototype.markActivatedRoute = function (activatedRoute) { var queue = []; queue.push(activatedRoute.snapshot); var currentRoute = queue.shift(); while (currentRoute) { currentRoute.children.forEach(function (childRoute) { queue.push(childRoute); }); var topActivatedRoute = findTopActivatedRouteNodeForOutlet(currentRoute); var outletKey = this.locationStrategy.getRouteFullPath(topActivatedRoute); var outlet = this.locationStrategy.findOutlet(outletKey, topActivatedRoute); if (outlet && outlet.frames.length) { topActivatedRoute[exports.pageRouterActivatedSymbol] = true; if (trace_1.isLogEnabled()) { trace_1.routerLog("Activated route marked as page: " + routeToString(topActivatedRoute)); } } currentRoute = queue.shift(); } }; PageRouterOutlet.prototype.getComponentFactory = function (activatedRoute, loadedResolver) { var component = activatedRoute.routeConfig.component; return loadedResolver ? loadedResolver.resolveComponentFactory(component) : this.componentFactoryResolver.resolveComponentFactory(component); }; PageRouterOutlet.prototype.getOutlet = function (activatedRouteSnapshot) { var topActivatedRoute = findTopActivatedRouteNodeForOutlet(activatedRouteSnapshot); var outletKey = this.locationStrategy.getRouteFullPath(topActivatedRoute); var outlet = this.locationStrategy.findOutlet(outletKey, topActivatedRoute); // Named lazy loaded outlet. if (!outlet && this.isEmptyOutlet) { var parentOutletKey = this.locationStrategy.getRouteFullPath(topActivatedRoute.parent); outlet = this.locationStrategy.findOutlet(parentOutletKey, topActivatedRoute.parent); if (outlet) { outlet.outletKeys.push(outletKey); } } return outlet; }; __decorate([ core_1.Output("activate"), __metadata("design:type", Object) ], PageRouterOutlet.prototype, "activateEvents", void 0); __decorate([ core_1.Output("deactivate"), __metadata("design:type", Object) ], PageRouterOutlet.prototype, "deactivateEvents", void 0); __decorate([ profiling_1.profile, __metadata("design:type", Function), __metadata("design:paramtypes", [router_1.ActivatedRoute, core_1.ComponentFactoryResolver]), __metadata("design:returntype", void 0) ], PageRouterOutlet.prototype, "activateWith", null); __decorate([ profiling_1.profile, __metadata("design:type", Function), __metadata("design:paramtypes", [page_1.Page, core_1.ComponentRef]), __metadata("design:returntype", void 0) ], PageRouterOutlet.prototype, "loadComponentInPage", null); PageRouterOutlet = __decorate([ core_1.Directive({ selector: "page-router-outlet" }) // tslint:disable-line:directive-selector , __param(2, core_1.Attribute("name")), __param(3, core_1.Attribute("actionBarVisibility")), __param(4, core_1.Attribute("isEmptyOutlet")), __param(9, core_1.Inject(platform_providers_1.DEVICE)), __param(10, core_1.Inject(platform_providers_1.PAGE_FACTORY)), __metadata("design:paramtypes", [router_1.ChildrenOutletContexts, core_1.ViewContainerRef, String, String, Boolean, ns_location_strategy_1.NSLocationStrategy, core_1.ComponentFactoryResolver, core_1.ComponentFactoryResolver, core_1.ChangeDetectorRef, Object, Function, ns_route_reuse_strategy_1.NSRouteReuseStrategy, core_1.ElementRef]) ], PageRouterOutlet); return PageRouterOutlet; }()); exports.PageRouterOutlet = PageRouterOutlet; //# sourceMappingURL=page-router-outlet.js.map