UNPKG

67.5 kBJavaScriptView Raw
1/**
2 * @license Framing v0.8.20
3 * Copyright 2016-2017 Biznas Innovations, Inc. http://biznas.io
4 * License: Apache License, Version 2.0
5 */
6import { ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectorRef, Component, ComponentFactoryResolver, Directive, EventEmitter, Injectable, Injector, Input, NgModule, NgModuleFactory, Output, Type, ViewContainerRef } from '@angular/core';
7import { ActivatedRoute, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router, RouterModule } from '@angular/router';
8import { assign, camelCase, clone, defaults, differenceWith, each, filter, find, isArray, isEmpty, isEqual, isNil, keys, merge, reject, uniqWith } from 'lodash';
9import * as _ from 'lodash';
10import { BehaviorSubject } from 'rxjs/BehaviorSubject';
11import { ReplaySubject, Subject } from 'rxjs';
12import { ReplaySubject as ReplaySubject$1 } from 'rxjs/Rx';
13import { CommonModule } from '@angular/common';
14import { FormsModule } from '@angular/forms';
15import { BrowserModule } from '@angular/platform-browser';
16
17class Component$1 {
18 constructor(controller, injector) {
19 this.controller = controller;
20 this.changeDetectorRef = injector.get(ChangeDetectorRef);
21 this.subscriptions = [];
22 this.subscriptions.push(controller.model$.subscribe((model) => this.updateModel(model)), controller.view$.subscribe((view) => this.updateView(view)), controller.markForCheck$.subscribe(() => this.changeDetectorRef.markForCheck()));
23 this.controller.attach();
24 }
25 ngOnInit() {
26 }
27 ngOnDestroy() {
28 this.controller.detach();
29 this.subscriptions.forEach((s) => s.unsubscribe());
30 this.subscriptions = null;
31 this.changeDetectorRef = null;
32 this.controller = null;
33 this.model = null;
34 this.view = null;
35 }
36 updateModel(model) {
37 this.model = model;
38 this.changeDetectorRef.markForCheck();
39 }
40 updateView(view) {
41 this.view = view;
42 this.changeDetectorRef.markForCheck();
43 }
44}
45
46var __decorate$2 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
47 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
48 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
49 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
50 return c > 3 && r && Object.defineProperty(target, key, r), r;
51};
52// import { Subject } from 'rxjs/Subject';
53let Controller = class Controller {
54 // import { Subject } from 'rxjs/Subject';
55 constructor() {
56 // ========================================
57 // private properties
58 // ========================================
59 this._refCount = 0;
60 }
61 // ========================================
62 // public methods
63 // ========================================
64 /**
65 * Model observable accessor.
66 */
67 get model$() { return this._model$; }
68 /**
69 * Model accessor.
70 */
71 get model() { return this._model; }
72 /**
73 * View observable accessor.
74 */
75 get view$() { return this._view$; }
76 /**
77 * View accessor.
78 */
79 get view() { return this._view; }
80 /**
81 * Mark for check observable accessor.
82 */
83 get markForCheck$() { return this._markForCheck$; }
84 /**
85 * Frame accessor.
86 */
87 get frame() { return this._frame; }
88 /**
89 * Model accessor.
90 */
91 get injector() { return this._injector; }
92 /**
93 * Called after controller is initialized with model, view & frame from framing.
94 */
95 onControllerInit() { }
96 /**
97 * Called when the controller's route starts resolving.
98 */
99 onResolveStart() { }
100 /**
101 * Called when the controller's route end resolving.
102 */
103 onResolveEnd() { }
104 /**
105 * Called when the controller's route resolve is cancelled.
106 */
107 onResolveCancel() { }
108 /**
109 * Called by framing after construction to link the model, view & frame for this controller.
110 */
111 initController(model, view, frame, framerName, injector) {
112 this._modelSubject = new BehaviorSubject(model);
113 this._viewSubject = new BehaviorSubject(view);
114 this._model$ = this._modelSubject.asObservable();
115 this._view$ = this._viewSubject.asObservable();
116 this._model = model;
117 this._view = view;
118 this._markForCheckSubject = new BehaviorSubject(true);
119 this._markForCheck$ = this._markForCheckSubject.asObservable();
120 this._frame = frame;
121 this._injector = injector;
122 this._framerName = framerName;
123 if (this._frame) {
124 this._frame.resolveStart$.subscribe(() => { this.onResolveStart(); });
125 this._frame.resolveEnd$.subscribe(() => { this.onResolveEnd(); });
126 this._frame.resolveCancel$.subscribe(() => { this.onResolveCancel(); });
127 }
128 this.onControllerInit();
129 console.log('initController');
130 console.log(this);
131 }
132 updateModel(model, replace = false) {
133 if (replace) {
134 this._model = clone(model);
135 }
136 else {
137 this._model = assign({}, this._model, model);
138 }
139 this._modelSubject.next(this._model);
140 }
141 updateView(view, replace = false) {
142 if (replace) {
143 this._view = clone(view);
144 }
145 else {
146 this._view = assign({}, this._view, view);
147 }
148 this._viewSubject.next(this._view);
149 }
150 markForCheck() {
151 this._markForCheckSubject.next(true);
152 }
153 attach() {
154 this._refCount++;
155 if (this._refCount === 1) {
156 setTimeout(() => {
157 this.onAttached();
158 });
159 }
160 }
161 detach() {
162 this._refCount--;
163 if (this._refCount === 0) {
164 setTimeout(() => {
165 this.onDetached();
166 });
167 }
168 }
169 onAttached() { }
170 onDetached() { }
171};
172Controller = __decorate$2([
173 Injectable()
174], Controller);
175
176/**
177 * Dev tool class used for framing integration with Redux DevTools
178 *
179 * @class FramingTools
180 */
181/**
182 * Dev tool class used for framing integration with Redux DevTools
183 *
184 * @class FramingTools
185 */ class FramingTools {
186 constructor() {
187 this.instantiatedControllers = {};
188 }
189 static get Instance() {
190 return this._instance || (this._instance = new this());
191 }
192 addController(framerName, controller) {
193 this.instantiatedControllers[framerName] = controller;
194 }
195 getAllControllers() {
196 return this.instantiatedControllers;
197 }
198 getControllerByKey(key) {
199 return this.instantiatedControllers[key] ? this.instantiatedControllers[key] : null;
200 }
201}
202
203let framingTools = FramingTools.Instance;
204let stateRoot = {};
205let onLoad = true;
206// let controllers: any[] = [];
207const devTools = _createReduxDevtoolsExtension();
208let isListening = false;
209/* tslint:disable */
210function Action(description = null, log = true) {
211 return function (target, propertyKey, descriptor) {
212 if (descriptor === undefined) {
213 descriptor = Object.getOwnPropertyDescriptor(target, propertyKey);
214 }
215 let originalMethod = descriptor.value;
216 descriptor.value = function () {
217 let args = [];
218 let controller = this;
219 // let controllerIndex: number;
220 // if (controllers.indexOf(controller) <= -1) {
221 // controllers.push(controller);
222 // controllerIndex = controllers.length - 1;
223 // } else {
224 // controllerIndex = controllers.indexOf(controller);
225 // }
226 for (let _i = 0; _i < arguments.length; _i++) {
227 args[_i] = arguments[_i];
228 }
229 try {
230 listenForChanges();
231 }
232 catch (e) {
233 console.log('Listen to Devtools failed: ');
234 console.log(e);
235 }
236 // Send the initial state if this is the first time connecting to the dev tools
237 if (onLoad && log && devTools) {
238 onLoad = !onLoad;
239 stateRoot[controller._framerName] = controller.model;
240 let state = {
241 framerName: controller._framerName,
242 value: stateRoot,
243 };
244 try {
245 devTools.send((description || propertyKey), state);
246 }
247 catch (e) {
248 console.log('Send to Devtools failed: ');
249 console.log(e);
250 }
251 }
252 originalMethod.apply(controller, args);
253 // Need to log after the method has been ran and state is updated
254 if (log && devTools) {
255 stateRoot[controller._framerName] = controller.model;
256 let state = {
257 framerName: controller._framerName,
258 // controllerIndex: controllerIndex,
259 value: stateRoot,
260 };
261 try {
262 devTools.send((description || propertyKey), state);
263 }
264 catch (e) {
265 console.log('Send to Devtools failed: ');
266 console.log(e);
267 }
268 }
269 controller.markForCheck();
270 };
271 return descriptor;
272 };
273}
274/**
275 * Listen for message events being broadcast from the redux devTools
276 * Changes state on the correct controller to match the state changes broadcast
277 */
278function listenForChanges() {
279 if (isListening || !devTools)
280 return;
281 isListening = true;
282 let connection = devTools.connect();
283 connection.subscribe((message) => {
284 if (!!message.state) {
285 let messageState = JSON.parse(message.state);
286 let messageController = framingTools.getControllerByKey(messageState.framerName);
287 if (messageController) {
288 for (let prop in messageController.model) {
289 messageController.model[prop] = messageState.value[messageState.framerName][prop];
290 }
291 messageController.markForCheck();
292 }
293 }
294 });
295}
296/**
297 * Returns correct instance of redux dev tools installed
298 *
299 * @export
300 * @returns
301 */
302function _createReduxDevtoolsExtension() {
303 const legacyExtensionKey = 'devToolsExtension';
304 const extensionKey = '__REDUX_DEVTOOLS_EXTENSION__';
305 if (typeof window === 'object' && typeof window[legacyExtensionKey] !== 'undefined') {
306 return window[legacyExtensionKey];
307 }
308 else if (typeof window === 'object' && typeof window[extensionKey] !== 'undefined') {
309 return window[extensionKey];
310 }
311 else {
312 return null;
313 }
314}
315
316var __decorate$1 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
317 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
318 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
319 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
320 return c > 3 && r && Object.defineProperty(target, key, r), r;
321};
322var __metadata$1 = (undefined && undefined.__metadata) || function (k, v) {
323 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
324};
325let FramingDevToolsController = class FramingDevToolsController extends Controller {
326 constructor(router) {
327 super();
328 this.router = router;
329 this.replayNavigation = false;
330 }
331 onControllerInit() {
332 this.router.events.subscribe((event) => {
333 this.handleRouterEvents(event);
334 });
335 this.markForCheck$.subscribe((data) => {
336 if (this.model.snapshotUrl && this.model.snapshotUrl !== this.router.routerState.snapshot.url) {
337 this.replayNavigation = true;
338 this.router.navigate([this.model.snapshotUrl]);
339 }
340 }, (err) => console.error(err));
341 }
342 trackRouterState() {
343 this.model.snapshotUrl = this.router.routerState.snapshot.url;
344 }
345 handleRouterEvents(event) {
346 if (event instanceof NavigationEnd) {
347 if (!this.replayNavigation) {
348 this.trackRouterState();
349 }
350 this.replayNavigation = false;
351 }
352 }
353};
354__decorate$1([
355 Action(),
356 __metadata$1("design:type", Function),
357 __metadata$1("design:paramtypes", []),
358 __metadata$1("design:returntype", void 0)
359], FramingDevToolsController.prototype, "trackRouterState", null);
360FramingDevToolsController = __decorate$1([
361 Injectable(),
362 __metadata$1("design:paramtypes", [Router])
363], FramingDevToolsController);
364
365var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
366 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
367 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
368 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
369 return c > 3 && r && Object.defineProperty(target, key, r), r;
370};
371var __metadata = (undefined && undefined.__metadata) || function (k, v) {
372 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
373};
374let FramingDevToolsComponent = class FramingDevToolsComponent extends Component$1 {
375 constructor(controller, injector) {
376 super(controller, injector);
377 }
378};
379FramingDevToolsComponent = __decorate([
380 Component({}),
381 __metadata("design:paramtypes", [FramingDevToolsController, Injector])
382], FramingDevToolsComponent);
383
384class Frame {
385 constructor() {
386 // ========================================
387 // public properties
388 // ========================================
389 /**
390 * Subjects
391 */
392 this.routeUrlSubject = new ReplaySubject();
393 this.resolveStartSubject = new Subject();
394 this.resolveEndSubject = new Subject();
395 this.resolveCancelSubject = new Subject();
396 }
397 /**
398 * An observable of the route url of the route that this controllerr is attached to, if any.
399 */
400 get routeUrl$() { return this.routeUrlSubject; }
401 /**
402 * Emitted when the frame resolve method starts if this controller is attached to a route.
403 */
404 get resolveStart$() { return this.resolveStartSubject; }
405 /**
406 * Emitted when the frame resolve method ends if this controller is attached to a route.
407 */
408 get resolveEnd$() { return this.resolveEndSubject; }
409 /**
410 * Emitted when the frame resolve method is cancelled if this controller is attached to a route.
411 */
412 get resolveCancel$() { return this.resolveCancelSubject; }
413}
414
415/**
416 * @description This is a description
417 */
418class Framer {
419 // ========================================
420 // constructor
421 // ========================================
422 /**
423 * Contructor.
424 */
425 constructor(model, view, controller) {
426 this.framingDevTools = FramingTools.Instance;
427 /**
428 * True if framing() has been called.
429 */
430 this._framed = false;
431 this.construct(model, view, controller);
432 }
433 /**
434 * Model accessor.
435 */
436 get theModel() { return this._model; }
437 /**
438 * View accessor.
439 */
440 get theView() { return this._view; }
441 /**
442 * Controller accessor.
443 */
444 get theController() { return this._controller; }
445 /**
446 * When true, framing will create a frame for this framer.
447 */
448 get createFrame() { return true; }
449 /**
450 * When true, framing will use multi on all providers so multiple framers of the same type can be setup on the same module.
451 */
452 get multiFramer() { return false; }
453 /**
454 * When true, framing will setup the controller as a provider by its type.
455 */
456 get provideControllerByType() { return true; }
457 /**
458 * When true, framing will add the model to the route data.
459 */
460 get addModelToRouteData() { return false; }
461 /**
462 * When true, framing will add the view to the route data.
463 */
464 get addViewToRouteData() { return false; }
465 /**
466 * When true, framing will add the frame to the route data.
467 */
468 get addFrameToRouteData() { return false; }
469 /**
470 * The default model.
471 */
472 get defaultModel() { return undefined; }
473 /**
474 * The default view.
475 */
476 get defaultView() { return undefined; }
477 /**
478 * The default controller.
479 */
480 get defaultController() { return undefined; }
481 /**
482 * 'require': framing will attach the default route, creating it if it doesn't yet exist, if not route is attached to this framer (default behavior)
483 * 'auto': framing will attach the default route if available if not route is attached to this framer
484 * 'none': framing will not attach a route to this framer
485 */
486 get routeRule() { return 'require'; }
487 /**
488 * A unique framer id for this framer.
489 */
490 get framerId() { return this._framerId; }
491 /**
492 * A unique identifier string for this framer instance.
493 */
494 get framerIdent() { return `${this.framerName}Framer-${this._framerId}`; }
495 /**
496 * True if framing() has been called.
497 */
498 get framed() { return this._framed; }
499 /**
500 * The injector (available on and after framerOnResolveRoute or framerOnControllerInit, whichever comes first)
501 */
502 get injector() { return this._injector; }
503 /**
504 * The framer's route, if attached to a route, otherwise undefined
505 * Valid ONLY during the runFraming() and framing() functions
506 */
507 get route() { return this._route; }
508 // ========================================
509 // public static methods
510 // ========================================
511 /**
512 * Helper function to build the URL of an ActivatedRouteSnapshot
513 */
514 static buildUrlLink(route) {
515 if (!route) {
516 return '/';
517 }
518 let urls = [];
519 /* tslint:disable:no-param-reassign */
520 for (; route.parent; route = route.parent) {
521 /* tslint:enable:no-param-reassign */
522 urls = urls.concat(route.url.reverse());
523 }
524 urls = urls.reverse();
525 return '/' + urls.join('/');
526 }
527 // ========================================
528 // public methods
529 // ========================================
530 /**
531 * Model chaining function.
532 */
533 model(model) {
534 merge(this._model, model);
535 return this;
536 }
537 /**
538 * View chaining function.
539 */
540 view(view) {
541 merge(this._view, view);
542 return this;
543 }
544 /**
545 * Controller chaining function.
546 */
547 controller(controller) {
548 if (controller) {
549 this._controller = controller;
550 }
551 return this;
552 }
553 /**
554 * Framer on resolve route function called when framer's route is resolved.
555 * Injector is set before during this call.
556 * Not called if framer is not attached to a route.
557 * To be overwritten if needed.
558 */
559 framerOnResolveRoute() { }
560 /**
561 * Framer on controller init function is called when the controller is first injected.
562 * To be overwritten if needed.
563 */
564 framerOnControllerInit(controller) { }
565 /**
566 * Calls derived framing()
567 */
568 runFraming(framing, routeParam) {
569 if (this._framed) {
570 console.warn(`runFraming() called multiple times on framer '${this.framerIdent}'`);
571 return;
572 }
573 this._framed = true; // mark this framer to framed
574 if (this.routeRule === 'auto') {
575 // set the framer's attached route (if any)
576 this._route = routeParam;
577 }
578 else if (this.routeRule === 'require') {
579 // set the framer's attached route to the supplied route or create one if it doesn not exist
580 if (routeParam) {
581 this._route = routeParam;
582 }
583 else {
584 /* tslint:disable:no-param-reassign */
585 this._route = routeParam = framing.getOrAddRoute();
586 /* tslint:enable:no-param-reassign */
587 }
588 }
589 this._framing = framing; // set _framing to framing ONLY for the duration of the controller() function
590 try {
591 this.frame(framing);
592 }
593 catch (e) {
594 console.error(`Exception when framing ${this.framerIdent} :`, e);
595 this._model = undefined;
596 this._view = undefined;
597 this._controller = undefined;
598 }
599 this._framing = undefined;
600 if (this.routeRule === 'auto') {
601 this._route = routeParam;
602 }
603 const self = this;
604 if (this._controller) {
605 // FUTURE
606 // this.provideTypeByName(framing, this.framerName + 'Controller', this._controller);
607 if (this.provideControllerByType) {
608 let controllerInstance;
609 framing
610 .provide({
611 provide: this.framerIdent + '-ControllerInternal',
612 useClass: this._controller,
613 })
614 .provide({
615 provide: this.framerIdent + '-Controller',
616 useFactory: (injector) => {
617 if (controllerInstance) {
618 this.framingDevTools.addController(this.framerName, controllerInstance);
619 return controllerInstance;
620 }
621 self._injector = injector;
622 controllerInstance = injector.get(this.framerIdent + '-ControllerInternal');
623 controllerInstance.initController(this._model, this._view, this._frame, this.framerName, injector);
624 this.framerOnControllerInit(controllerInstance);
625 this.framingDevTools.addController(this.framerName, controllerInstance);
626 return controllerInstance;
627 },
628 deps: [Injector],
629 })
630 .provide({
631 provide: this._controller,
632 useExisting: this.framerIdent + '-Controller',
633 multi: this.multiFramer && this._controller === this.defaultController,
634 });
635 /* tslint:disable:no-console */
636 console.info(`Providing controller for framer ${this.framerIdent} by type`);
637 /* tslint:enable:no-console */
638 if (this.defaultController && this._controller !== this.defaultController) {
639 framing.provide({
640 provide: this.defaultController,
641 useExisting: this.framerIdent + '-Controller',
642 multi: this.multiFramer,
643 });
644 /* tslint:disable:no-console */
645 console.info(`Providing controller overload for framer ${this.framerIdent} by default controller type`);
646 /* tslint:enable:no-console */
647 }
648 }
649 }
650 // FUTURE: frame, model & view provided by name
651 // this.provideValueByName(framing, this.framerName + 'Frame', this._frame);
652 // this.provideValueByName(framing, this.framerName + 'Model', this._model);
653 // this.provideValueByName(framing, this.framerName + 'View', this._view);
654 // FUTURE: model & view provided by type
655 // this.provideInstanceByType(framing, this._model);
656 // this.provideInstanceByType(framing, this._view);
657 if (this.route) {
658 if (this.addFrameToRouteData) {
659 this.addRouteData(framing, this.framerName + 'Frame', this._frame);
660 }
661 if (this.addModelToRouteData) {
662 this.addRouteData(framing, this.framerName + 'Model', this._model);
663 }
664 if (this.addViewToRouteData) {
665 this.addRouteData(framing, this.framerName + 'View', this._view);
666 }
667 if (this._frame) {
668 class FrameResolver {
669 constructor(router, route, injector) {
670 this.router = router;
671 this.route = route;
672 self._injector = injector;
673 }
674 resolve(routeSnapshot, routeStateSnapshot) {
675 self._frame.resolveStartSubject.next();
676 const routeUrl = Framer.buildUrlLink(routeSnapshot);
677 const sub = this.router.events.subscribe((event) => {
678 if (event instanceof NavigationStart) {
679 console.error('Unexpected NavigationStart');
680 }
681 else if (event instanceof NavigationEnd) {
682 /* tslint:disable:no-console */
683 console.info(`Route url for framer ${self.framerIdent} changed to ${routeUrl}`);
684 /* tslint:enable:no-console */
685 self._frame.routeSnapshot = self.findActivateRouteSnapshot(this.route);
686 self._frame.routeUrl = routeUrl;
687 self._frame.routeUrlSubject.next(routeUrl);
688 self.framerOnResolveRoute();
689 self._frame.resolveEndSubject.next();
690 }
691 else if (event instanceof NavigationError) {
692 self._frame.resolveCancelSubject.next();
693 }
694 else if (event instanceof NavigationCancel) {
695 self._frame.resolveCancelSubject.next();
696 }
697 sub.unsubscribe();
698 });
699 return self._frame;
700 }
701 }
702 framing
703 .resolve(this.framerIdent, FrameResolver, this.route)
704 .provide({
705 provide: FrameResolver,
706 useFactory: (r, a, i) => new FrameResolver(r, a, i),
707 deps: [Router, ActivatedRoute, Injector]
708 });
709 }
710 }
711 this._route = undefined; // clear the route so we're not holding any references to its properties
712 }
713 /**
714 * Protected construct function for derived construction help.
715 */
716 construct(model, view, controller) {
717 this._framerId = Framer._nextId++;
718 if (this.createFrame) {
719 this._frame = new Frame();
720 }
721 const defaultModel = this.defaultModel;
722 this._model = defaultModel ? merge(defaultModel, model) : model;
723 const defaultView = this.defaultView;
724 this._view = defaultView ? merge(defaultView, view) : view;
725 this._controller = controller || this.defaultController;
726 }
727 /**
728 * Protected construct function for derived construction help.
729 */
730 findActivateRouteSnapshot(route) {
731 if (!route) {
732 console.error('Failed to find activated route snapshot');
733 return undefined;
734 }
735 if (route.snapshot && route.snapshot.data && route.snapshot.data.hasOwnProperty(this.framerIdent)) {
736 return route.snapshot;
737 }
738 return this.findActivateRouteSnapshot(route.firstChild);
739 }
740 /**
741 * FUTURE
742 */
743 // private provideTypeByName(framing: FramingNgModule, name: string, type: any): void {
744 // if (type) {
745 // framing.provide({ provide: name, useClass: type });
746 // /* tslint:disable:no-console */
747 // console.info(`Providing ${name} for framer ${this.framerIdent} by name`);
748 // /* tslint:enable:no-console */
749 // }
750 // }
751 /**
752 * FUTURE
753 */
754 // private provideInstanceByType(framing: FramingNgModule, instance: any): void {
755 // if (instance &&
756 // (instance as any).__proto__ &&
757 // (instance as any).__proto__.constructor &&
758 // (instance as any).__proto__.constructor.name !== 'Object') {
759 // framing.provide({ provide: (instance as any).__proto__.constructor, useValue: instance });
760 // /* tslint:disable:no-console */
761 // console.info(`Providing ${(instance as any).__proto__.constructor.name} for framer ${this.framerIdent} by type`);
762 // /* tslint:enable:no-console */
763 // }
764 // }
765 /**
766 * FUTURE
767 */
768 // private provideValueByName(framing: FramingNgModule, name: string, value: any): void {
769 // if (value) {
770 // framing.provide({ provide: name, useValue: value });
771 // /* tslint:disable:no-console */
772 // console.info(`Providing ${name} for framer ${this.framerIdent} by name`);
773 // /* tslint:enable:no-console */
774 // }
775 // }
776 addRouteData(framing, name, value) {
777 if (value) {
778 const routeConfig = framing.getOrAddRoute(this.route);
779 if (routeConfig.data && routeConfig.data[name]) {
780 console.warn(`Failed to add ${name} route data for framer ${this.framerIdent}. Data item already exists.`);
781 }
782 else {
783 framing.datum(name, value, this.route);
784 /* tslint:disable:no-console */
785 console.info(`Adding ${name} route data for framer ${this.framerIdent}`);
786 /* tslint:enable:no-console */
787 }
788 }
789 }
790}
791Framer._nextId = 1;
792
793class FramingDevToolsFeature extends Framer {
794 get defaultModel() {
795 return {};
796 }
797 get defaultView() {
798 return {};
799 }
800 frame(framing) { }
801 framerOnResolveRoute() {
802 let framingDevToolsController;
803 framingDevToolsController = this.injector.get(FramingDevToolsController);
804 }
805 // ========================================
806 // internal framing methods (don't touch!)
807 // ========================================
808 get framerName() { return 'FramingDevTools'; }
809 get defaultController() { return FramingDevToolsController; }
810}
811
812var __decorate$3 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
813 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
814 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
815 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
816 return c > 3 && r && Object.defineProperty(target, key, r), r;
817};
818var __metadata$2 = (undefined && undefined.__metadata) || function (k, v) {
819 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
820};
821let FramingComponentOutletDirective = class FramingComponentOutletDirective {
822 constructor(_view) {
823 this._view = _view;
824 this.onComponent = new EventEmitter();
825 }
826 isActivated() { return !!this._componentRef; }
827 ngOnChanges(changes) {
828 let activate = false;
829 if (changes.ngModuleFactory) {
830 if (this._moduleRef) {
831 this._moduleRef.destroy();
832 }
833 if (this.ngModuleFactory) {
834 const injector = this.injector || this._view.parentInjector;
835 this._moduleRef = this.ngModuleFactory.create(injector);
836 }
837 else {
838 this._moduleRef = undefined;
839 }
840 activate = true;
841 }
842 if (changes.framingComponentOutlet.currentValue !== changes.framingComponentOutlet.previousValue) {
843 activate = true;
844 }
845 if (activate) {
846 this.activate(this.framingComponentOutlet);
847 }
848 }
849 ngOnDestroy() {
850 this.deactivate();
851 if (this._moduleRef) {
852 this._moduleRef.destroy();
853 }
854 }
855 activate(component) {
856 this.deactivate();
857 if (!component) {
858 return;
859 }
860 try {
861 const injector = this.injector || this._view.parentInjector;
862 const factory = injector.get(ComponentFactoryResolver).resolveComponentFactory(component);
863 this._componentRef = this._view.createComponent(factory, this._view.length, injector, this.content);
864 this.onComponent.emit(this._componentRef);
865 try {
866 this._componentRef.changeDetectorRef.detectChanges();
867 }
868 catch (e) {
869 console.error(`detectChanges failed on activated component in FramingComponentOutlet`, { e, component });
870 return;
871 }
872 }
873 catch (e) {
874 console.error(`Failed to activate component in FramingComponentOutlet`, { e, component });
875 return;
876 }
877 }
878 deactivate() {
879 if (this._componentRef) {
880 this._view.remove(this._view.indexOf(this._componentRef.hostView));
881 this._componentRef.destroy();
882 }
883 this._view.clear();
884 this._componentRef = undefined;
885 }
886};
887__decorate$3([
888 Input(),
889 __metadata$2("design:type", Type)
890], FramingComponentOutletDirective.prototype, "framingComponentOutlet", void 0);
891__decorate$3([
892 Input(),
893 __metadata$2("design:type", Injector)
894], FramingComponentOutletDirective.prototype, "injector", void 0);
895__decorate$3([
896 Input(),
897 __metadata$2("design:type", Array)
898], FramingComponentOutletDirective.prototype, "content", void 0);
899__decorate$3([
900 Input(),
901 __metadata$2("design:type", NgModuleFactory)
902], FramingComponentOutletDirective.prototype, "ngModuleFactory", void 0);
903__decorate$3([
904 Output(),
905 __metadata$2("design:type", EventEmitter)
906], FramingComponentOutletDirective.prototype, "onComponent", void 0);
907FramingComponentOutletDirective = __decorate$3([
908 Directive({
909 selector: '[framingComponentOutlet]',
910 }),
911 __metadata$2("design:paramtypes", [ViewContainerRef])
912], FramingComponentOutletDirective);
913
914var __decorate$4 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
915 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
916 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
917 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
918 return c > 3 && r && Object.defineProperty(target, key, r), r;
919};
920let FramingComponentOutletModule = FramingComponentOutletModule_1 = class FramingComponentOutletModule {
921 static withEntryComponents(...components) {
922 return {
923 ngModule: FramingComponentOutletModule_1,
924 providers: [
925 { provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: components, multi: true },
926 ],
927 };
928 }
929};
930FramingComponentOutletModule = FramingComponentOutletModule_1 = __decorate$4([
931 NgModule({
932 declarations: [FramingComponentOutletDirective],
933 exports: [FramingComponentOutletDirective],
934 })
935], FramingComponentOutletModule);
936var FramingComponentOutletModule_1;
937
938var __decorate$6 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
939 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
940 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
941 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
942 return c > 3 && r && Object.defineProperty(target, key, r), r;
943};
944var __metadata$4 = (undefined && undefined.__metadata) || function (k, v) {
945 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
946};
947let FramingContainerOutletService = class FramingContainerOutletService {
948 constructor(router) {
949 this.router = router;
950 this.contentsSubject = new ReplaySubject$1();
951 this.contents = [];
952 this.routeContents = [];
953 this.subscriptions = [];
954 this.subscriptions.push(this.router.events.subscribe((event) => {
955 if (event instanceof NavigationEnd) {
956 this.onNavigationEnd();
957 }
958 }));
959 }
960 get contents$() { return this.contentsSubject.asObservable(); }
961 hasContent(container) {
962 return !!this.contents.filter((c) => isEqual(c.container, container)).length;
963 }
964 activate(content) {
965 this.contents.push(content);
966 this.contentsSubject.next(clone(this.contents));
967 return () => { this.deactivate(content); };
968 }
969 deactivate(content) {
970 this.contents = this.contents.filter((e) => e !== content);
971 this.contentsSubject.next(clone(this.contents));
972 }
973 onNavigationEnd() {
974 let newRouteContents = [];
975 this.resolveRouteContents(this.router.routerState.snapshot.root, newRouteContents);
976 newRouteContents = uniqWith(newRouteContents, isEqual);
977 const newContents = differenceWith(newRouteContents, this.routeContents, isEqual);
978 const removedContents = differenceWith(this.routeContents, newRouteContents, isEqual);
979 newContents.forEach((c) => this.activate(c));
980 removedContents.forEach((c) => this.deactivate(c));
981 this.routeContents = newRouteContents;
982 }
983 resolveRouteContents(snapshot, routeContents) {
984 if (snapshot.data && snapshot.data.containers) {
985 const containers = snapshot.data.containers;
986 for (const container of containers) {
987 routeContents.push(container);
988 }
989 }
990 for (let child of snapshot.children) {
991 this.resolveRouteContents(child, routeContents);
992 }
993 }
994};
995FramingContainerOutletService = __decorate$6([
996 Injectable(),
997 __metadata$4("design:paramtypes", [Router])
998], FramingContainerOutletService);
999
1000var __decorate$5 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
1001 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1002 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1003 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1004 return c > 3 && r && Object.defineProperty(target, key, r), r;
1005};
1006var __metadata$3 = (undefined && undefined.__metadata) || function (k, v) {
1007 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1008};
1009let FramingContainerOutletDirective = class FramingContainerOutletDirective {
1010 constructor(_view, _containerService, _router) {
1011 this._view = _view;
1012 this._containerService = _containerService;
1013 this._router = _router;
1014 this.onComponents = new EventEmitter();
1015 this._activated = [];
1016 this._subscriptions = [];
1017 }
1018 containerName() { return this.framingContainerOutlet; }
1019 isActivated() { return this._activated.length > 0; }
1020 ngOnInit() {
1021 if (!this.framingContainerOutlet) {
1022 console.warn('FramingContainerOutlet without a container name');
1023 }
1024 else {
1025 if (this.framingContainerOutlet[0] === '\'') {
1026 console.warn(`FramingContainerOutlet name "${this.framingContainerOutlet}" starts with a qoute`);
1027 }
1028 this._subscriptions.push(this._containerService.contents$.subscribe((contents) => this.onContent(contents)));
1029 }
1030 this._subscriptions.push(this._router.events.subscribe((event) => {
1031 if (event instanceof NavigationEnd) {
1032 if (!this.optionalContainer && !this.isActivated()) {
1033 console.warn(`No content for required FramingContainerOutlet '${this.framingContainerOutlet}' found`);
1034 }
1035 }
1036 }));
1037 }
1038 ngOnDestroy() {
1039 this._activated.forEach((a) => this.deactivate(a));
1040 this._subscriptions.forEach((s) => s.unsubscribe());
1041 }
1042 onContent(allContents) {
1043 const contents = allContents.filter((c) => isEqual(c.container, this.framingContainerOutlet));
1044 // remove all content that is no longer active
1045 this._activated.forEach((a) => {
1046 if (contents.findIndex((content) => content === a.content) === -1) {
1047 this.deactivate(a);
1048 }
1049 });
1050 this._activated = this._activated.filter((a) => !!a.ref);
1051 // now setup the new activated components
1052 let i = 0;
1053 for (let content of contents) {
1054 if (this._activated.length > i) {
1055 if (this._activated[i].content !== content) {
1056 // look for this content
1057 const activatedIndex = this._activated.findIndex((a) => a.content === content);
1058 if (activatedIndex === -1) {
1059 // activate this content at i
1060 this._activated.splice(i, 0, { content, ref: this.activate(content) });
1061 }
1062 else if (activatedIndex > i) {
1063 // move content from activatedIndex to i
1064 const _activated = this._activated.splice(activatedIndex, 1);
1065 this._activated.splice(i, 0, ..._activated);
1066 const view = this._view.detach(activatedIndex);
1067 this._view.insert(view, i);
1068 }
1069 else {
1070 console.error('Logic error in FramingContainerOutlet!');
1071 }
1072 }
1073 }
1074 else {
1075 // activate this content
1076 const ref = this.activate(content);
1077 if (ref) {
1078 this._activated.push({ content, ref });
1079 }
1080 }
1081 i++;
1082 }
1083 this.onComponents.emit(this._activated.map((a) => a.ref));
1084 }
1085 activate(content, i) {
1086 try {
1087 const injector = (!this.useViewInjector && content.injector) ? content.injector : this._view.parentInjector;
1088 const factory = injector.get(ComponentFactoryResolver).resolveComponentFactory(content.component);
1089 let ref = this._view.createComponent(factory, i, injector, this.content);
1090 try {
1091 ref.changeDetectorRef.detectChanges();
1092 }
1093 catch (e) {
1094 console.error(`detectChanges failed on activated component in FramingContainerOutlet '${this.framingContainerOutlet}'`, { e, component: content.component });
1095 }
1096 return ref;
1097 }
1098 catch (e) {
1099 console.error(`Failed to activate component in FramingContainerOutlet '${this.framingContainerOutlet}'`, { e, component: content.component });
1100 return undefined;
1101 }
1102 }
1103 deactivate(activated) {
1104 activated.ref.destroy();
1105 activated.ref = null;
1106 }
1107};
1108__decorate$5([
1109 Input(),
1110 __metadata$3("design:type", String)
1111], FramingContainerOutletDirective.prototype, "framingContainerOutlet", void 0);
1112__decorate$5([
1113 Input(),
1114 __metadata$3("design:type", Boolean)
1115], FramingContainerOutletDirective.prototype, "optionalContainer", void 0);
1116__decorate$5([
1117 Input(),
1118 __metadata$3("design:type", Boolean)
1119], FramingContainerOutletDirective.prototype, "useViewInjector", void 0);
1120__decorate$5([
1121 Input(),
1122 __metadata$3("design:type", Array)
1123], FramingContainerOutletDirective.prototype, "content", void 0);
1124__decorate$5([
1125 Output(),
1126 __metadata$3("design:type", EventEmitter)
1127], FramingContainerOutletDirective.prototype, "onComponents", void 0);
1128FramingContainerOutletDirective = __decorate$5([
1129 Directive({
1130 selector: '[framingContainerOutlet]',
1131 }),
1132 __metadata$3("design:paramtypes", [ViewContainerRef,
1133 FramingContainerOutletService,
1134 Router])
1135], FramingContainerOutletDirective);
1136
1137var __decorate$7 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
1138 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1139 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1140 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1141 return c > 3 && r && Object.defineProperty(target, key, r), r;
1142};
1143let FramingContainerOutletModule = FramingContainerOutletModule_1 = class FramingContainerOutletModule {
1144 static withEntryComponents(...components) {
1145 return {
1146 ngModule: FramingContainerOutletModule_1,
1147 providers: [
1148 { provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: components, multi: true },
1149 ],
1150 };
1151 }
1152 static forRoot() {
1153 return {
1154 ngModule: FramingContainerOutletModule_1,
1155 providers: [FramingContainerOutletService],
1156 };
1157 }
1158};
1159FramingContainerOutletModule = FramingContainerOutletModule_1 = __decorate$7([
1160 NgModule({
1161 declarations: [FramingContainerOutletDirective],
1162 exports: [FramingContainerOutletDirective],
1163 })
1164], FramingContainerOutletModule);
1165var FramingContainerOutletModule_1;
1166
1167var __decorate$8 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
1168 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1169 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1170 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1171 return c > 3 && r && Object.defineProperty(target, key, r), r;
1172};
1173var __metadata$5 = (undefined && undefined.__metadata) || function (k, v) {
1174 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1175};
1176let FramingContainerOutletResolver = class FramingContainerOutletResolver {
1177 constructor(containers, injector) {
1178 this.containers = containers;
1179 this.injector = injector;
1180 }
1181 /**
1182 * Resolve hook.
1183 */
1184 resolve(route, state) {
1185 // set the injector in each container
1186 for (let container of this.containers) {
1187 container.injector = this.injector;
1188 }
1189 return this.containers;
1190 }
1191};
1192FramingContainerOutletResolver = __decorate$8([
1193 Injectable(),
1194 __metadata$5("design:paramtypes", [Array, Injector])
1195], FramingContainerOutletResolver);
1196
1197var __decorate$9 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
1198 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1199 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1200 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1201 return c > 3 && r && Object.defineProperty(target, key, r), r;
1202};
1203/**
1204 * @experimental
1205 */
1206let FramingEmptyParentComponent = class FramingEmptyParentComponent {
1207};
1208FramingEmptyParentComponent = __decorate$9([
1209 Component({
1210 selector: 'empty-parent-component',
1211 template: '<router-outlet></router-outlet>',
1212 })
1213], FramingEmptyParentComponent);
1214
1215var __decorate$11 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
1216 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1217 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1218 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1219 return c > 3 && r && Object.defineProperty(target, key, r), r;
1220};
1221let FramingRootComponent = class FramingRootComponent {
1222};
1223FramingRootComponent = __decorate$11([
1224 Component({
1225 selector: 'app-root',
1226 template: '<router-outlet></router-outlet>',
1227 })
1228], FramingRootComponent);
1229
1230var __decorate$10 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
1231 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1232 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1233 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1234 return c > 3 && r && Object.defineProperty(target, key, r), r;
1235};
1236let FramingComponentsModule = class FramingComponentsModule {
1237};
1238FramingComponentsModule = __decorate$10([
1239 NgModule({
1240 imports: [
1241 RouterModule,
1242 ],
1243 declarations: [
1244 FramingEmptyParentComponent,
1245 FramingRootComponent,
1246 ],
1247 exports: [
1248 FramingEmptyParentComponent,
1249 FramingRootComponent,
1250 ],
1251 })
1252], FramingComponentsModule);
1253
1254class FramerHelper {
1255 // ========================================
1256 // constructor
1257 // ========================================
1258 constructor() {
1259 this.framerHelperId = FramerHelper._nextId++;
1260 }
1261 /**
1262 * A unique identifier string for this framer helper instance.
1263 */
1264 get framerHelperIdent() {
1265 return camelCase(`framerHelper-${this.__proto__.constructor.name}-${this.framerHelperId}`);
1266 }
1267}
1268FramerHelper._nextId = 1;
1269
1270/**
1271 *
1272 */
1273class FramingNgModule {
1274 constructor() {
1275 // ========================================
1276 // private properties
1277 // ========================================
1278 this._ngModule = {
1279 imports: [],
1280 declarations: [],
1281 exports: [],
1282 providers: [],
1283 bootstrap: [],
1284 entryComponents: [],
1285 };
1286 this._root = false;
1287 this._routes = [];
1288 }
1289 static get defaultPathMatch() { return 'prefix'; }
1290 // ========================================
1291 // public methods
1292 // ========================================
1293 ngModule(ngModule) {
1294 if (ngModule) {
1295 defaults(this._ngModule, ngModule);
1296 each(filter(keys(ngModule), (key) => { return isArray(ngModule[key]); }), (key) => {
1297 this._ngModule[key] = uniqWith(this._ngModule[key].concat(reject(ngModule[key], isNil)), isEqual);
1298 });
1299 }
1300 return this;
1301 }
1302 bootstrap(bootstrap) {
1303 const flattened = [].concat.apply([], bootstrap);
1304 this._ngModule.bootstrap = uniqWith(this._ngModule.bootstrap.concat(reject(flattened, isNil)), isEqual);
1305 return this;
1306 }
1307 child(child, parent) {
1308 let parentRoute = this.getOrAddRouteOverload(parent);
1309 if (!parentRoute.children) {
1310 parentRoute.children = [];
1311 }
1312 if (!parentRoute.component) {
1313 parentRoute.component = FramingEmptyParentComponent;
1314 }
1315 this.getOrAddRoute(child, parentRoute.children);
1316 return this;
1317 }
1318 children(children, parent) {
1319 each(children, (child) => {
1320 this.child(child, parent);
1321 });
1322 return this;
1323 }
1324 component(component, route) {
1325 if (component) {
1326 let routeConfig = this.getOrAddRouteOverload(route);
1327 routeConfig.component = component;
1328 }
1329 return this;
1330 }
1331 componentAndDeclare(component, route) {
1332 return this.componentAndDeclaration(component, route);
1333 }
1334 componentAndDeclaration(component, route) {
1335 this.component(component, route);
1336 if (component) {
1337 this.declare(component);
1338 }
1339 return this;
1340 }
1341 container(container, components, route) {
1342 let containers = {};
1343 containers[container] = components;
1344 this.containers(containers, route);
1345 return this;
1346 }
1347 containers(containers, route) {
1348 for (let key in containers) {
1349 if (containers.hasOwnProperty(key)) {
1350 if (isNil(containers[key])) {
1351 delete containers[key];
1352 }
1353 }
1354 }
1355 const routeConfig = this.getOrAddRoute(route);
1356 if (!routeConfig.resolve) {
1357 routeConfig.resolve = {};
1358 }
1359 if (!routeConfig.resolve.containers) {
1360 routeConfig.resolve.containers = [];
1361 }
1362 for (let key in containers) {
1363 if (containers.hasOwnProperty(key)) {
1364 const components = containers[key];
1365 if (isArray(components)) {
1366 for (const component of components) {
1367 routeConfig.resolve.containers.push({ container: key, component });
1368 }
1369 }
1370 else {
1371 routeConfig.resolve.containers.push({ container: key, component: components });
1372 }
1373 }
1374 }
1375 return this;
1376 }
1377 datum(key, datum, route) {
1378 let data = {};
1379 data[key] = datum;
1380 this.data(data, route);
1381 return this;
1382 }
1383 data(data, route) {
1384 let routeConfig = this.getOrAddRouteOverload(route);
1385 if (!routeConfig.data) {
1386 routeConfig.data = {};
1387 }
1388 merge(routeConfig.data, data);
1389 return this;
1390 }
1391 resolve(key, resolve, route) {
1392 let resolves = {};
1393 resolves[key] = resolve;
1394 this.resolves(resolves, route);
1395 return this;
1396 }
1397 resolves(resolves, route) {
1398 let routeConfig = this.getOrAddRouteOverload(route);
1399 if (!routeConfig.resolve) {
1400 routeConfig.resolve = {};
1401 }
1402 merge(routeConfig.resolve, resolves);
1403 return this;
1404 }
1405 declare(declaration) {
1406 return this.declaration(declaration);
1407 }
1408 declaration(declaration) {
1409 return this.declarations(isArray(declaration) ? declaration : [declaration]);
1410 }
1411 declarations(declarations) {
1412 const flattened = [].concat.apply([], declarations);
1413 this._ngModule.declarations = uniqWith(this._ngModule.declarations.concat(reject(flattened, isNil)), isEqual);
1414 return this;
1415 }
1416 declareAndExport(declaration) {
1417 return this.declarationAndExport(declaration);
1418 }
1419 declarationAndExport(declaration) {
1420 return this.declarationsAndExports(isArray(declaration) ? declaration : [declaration]);
1421 }
1422 declarationsAndExports(declarations) {
1423 this.declarations(declarations);
1424 this.exports(declarations);
1425 return this;
1426 }
1427 declareAndEntryComponent(declaration) {
1428 return this.declarationAndEntryComponent(declaration);
1429 }
1430 declarationAndEntryComponent(declaration) {
1431 return this.declarationsAndEntryComponents(isArray(declaration) ? declaration : [declaration]);
1432 }
1433 declarationsAndEntryComponents(declarations) {
1434 this.declarations(declarations);
1435 this.entryComponents(declarations);
1436 return this;
1437 }
1438 entryComponent(entryComponent) {
1439 return this.entryComponents(isArray(entryComponent) ? entryComponent : [entryComponent]);
1440 }
1441 entryComponents(entryComponents) {
1442 const flattened = [].concat.apply([], entryComponents);
1443 this._ngModule.entryComponents = uniqWith(this._ngModule.entryComponents.concat(reject(flattened, isNil)), isEqual);
1444 return this;
1445 }
1446 export(e) {
1447 return this.exports(isArray(e) ? e : [e]);
1448 }
1449 exports(exports) {
1450 const flattened = [].concat.apply([], exports);
1451 this._ngModule.exports = uniqWith(this._ngModule.exports.concat(reject(flattened, isNil)), isEqual);
1452 return this;
1453 }
1454 import(i) {
1455 return this.imports(isArray(i) ? i : [i]);
1456 }
1457 imports(imports) {
1458 const flattened = [].concat.apply([], imports);
1459 this._ngModule.imports = uniqWith(this._ngModule.imports.concat(reject(flattened, isNil)), isEqual);
1460 return this;
1461 }
1462 importAndExport(m) {
1463 return this.importsAndExports(isArray(m) ? m : [m]);
1464 }
1465 importsAndExports(modules) {
1466 this.imports(modules);
1467 this.exports(modules);
1468 return this;
1469 }
1470 provide(provider) {
1471 return this.provider(provider);
1472 }
1473 provider(provider) {
1474 return this.providers(isArray(provider) ? provider : [provider]);
1475 }
1476 providers(providers) {
1477 const flattened = [].concat.apply([], providers);
1478 this._ngModule.providers = uniqWith(this._ngModule.providers.concat(reject(flattened, isNil)), isEqual);
1479 return this;
1480 }
1481 /**
1482 * Adds component to bootstrap
1483 * Defaults route to path '', pathMatch: 'full'
1484 */
1485 root(rootComponent, config) {
1486 this._root = true;
1487 this._rootComponentConfig = config || {};
1488 defaults(this._rootComponentConfig, { hybrid: false });
1489 this._rootComponent = rootComponent || FramingRootComponent;
1490 return this;
1491 }
1492 /**
1493 * Creates Routes array with single route
1494 * Adds RouterModule.forRoot(routes) or RouterModule.forChild(routes) to imports
1495 * Adds all resolve services as providers
1496 */
1497 route(route, config) {
1498 this.getOrAddRoute(route);
1499 if (this._routeConfig) {
1500 if (config) {
1501 merge(this._routeConfig, config);
1502 }
1503 }
1504 else {
1505 this._routeConfig = config || {};
1506 defaults(this._routeConfig, { forRoot: false });
1507 }
1508 return this;
1509 }
1510 routes(routes, config) {
1511 each(routes, (route) => {
1512 this.route(route, config);
1513 });
1514 return this;
1515 }
1516 frameRoute(route, ...framers) {
1517 this.buildFramers(framers, this.getOrAddRouteOverload(route));
1518 return this;
1519 }
1520 /**
1521 * Returns the route if it exists.
1522 */
1523 getRoute(route = {}, array) {
1524 /* tslint:disable:no-param-reassign */
1525 if (!array) {
1526 array = this._routes;
1527 }
1528 /* tslint:enable:no-param-reassign */
1529 defaults(route, { path: '', pathMatch: FramingNgModule.defaultPathMatch });
1530 return find(array, (m) => { return m.path === route.path && m.pathMatch === route.pathMatch; });
1531 }
1532 /**
1533 * Returns the route. Creates it if it does not exist.
1534 */
1535 getOrAddRoute(route = {}, array) {
1536 /* tslint:disable:no-param-reassign */
1537 if (!array) {
1538 array = this._routes;
1539 }
1540 /* tslint:enable:no-param-reassign */
1541 defaults(route, { path: '', pathMatch: FramingNgModule.defaultPathMatch });
1542 let r = find(array, (m) => { return m.path === route.path && m.pathMatch === route.pathMatch; });
1543 if (r) {
1544 merge(r, route);
1545 return r;
1546 }
1547 else {
1548 array.push(route);
1549 return route;
1550 }
1551 }
1552 /**
1553 * Run framers.
1554 */
1555 frame(...framers) {
1556 this.buildFramers(framers);
1557 return this;
1558 }
1559 use(...framers) {
1560 return this.frame(...framers);
1561 }
1562 /**
1563 * Builds @NgModule() config in the following order:
1564 * - Route framers
1565 * - Root
1566 * - Route
1567 */
1568 build() {
1569 this.buildRouteFramers(this._routes);
1570 this.buildRoot();
1571 this.buildContainers(this._routes);
1572 this.buildRoute();
1573 this.inspectModule();
1574 return this._ngModule;
1575 }
1576 // ========================================
1577 // private methods
1578 // ========================================
1579 inspectModule() {
1580 this._routes.forEach((r) => this.inspectRoute(r));
1581 }
1582 inspectRoute(route) {
1583 if (route.component === undefined && route.redirectTo === undefined && isEmpty(route.children) && route.loadChildren === undefined) {
1584 console.error(`Looks like you have a badly configured route in a framed module.
1585 One of the following must be provided: component, redirectTo, children or loadChildren`, { route, self: this });
1586 }
1587 if (route.children) {
1588 route.children.forEach((c) => this.inspectRoute(c));
1589 }
1590 }
1591 buildRoot() {
1592 let m = this._ngModule;
1593 if (this._root) {
1594 m.imports = uniqWith(m.imports.concat([
1595 BrowserModule.withServerTransition({
1596 appId: 'app',
1597 }),
1598 FormsModule,
1599 ]), isEqual);
1600 m.bootstrap = uniqWith(m.bootstrap.concat([this._rootComponent]), isEqual);
1601 }
1602 else {
1603 m.imports = uniqWith(m.imports.concat([
1604 CommonModule,
1605 ]), isEqual);
1606 }
1607 m.imports = uniqWith(m.imports.concat([FramingComponentsModule]), isEqual);
1608 }
1609 buildFramers(framers, route) {
1610 for (let framer of framers) {
1611 this.buildFramer(framer, route);
1612 }
1613 }
1614 buildFramer(framer, route) {
1615 if (!framer.framed) {
1616 framer.runFraming(this, route || this.getRoute());
1617 }
1618 }
1619 /**
1620 * Builds framers that were manually added to route data.
1621 */
1622 buildRouteFramers(routes) {
1623 for (let route of routes) {
1624 if (route.data) {
1625 for (let key in route.data) {
1626 if (route.data.hasOwnProperty(key)) {
1627 let prop = route.data[key];
1628 if (prop && prop._frame !== undefined) {
1629 // this is a framer attached to route data
1630 this.buildFramer(prop, route);
1631 }
1632 }
1633 }
1634 }
1635 if (route.children) {
1636 this.buildRouteFramers(route.children);
1637 }
1638 }
1639 }
1640 buildContainers(routes) {
1641 for (let route of routes) {
1642 if (route.resolve && route.resolve.containers) {
1643 const containers = route.resolve.containers;
1644 for (const container of containers) {
1645 const containerId = FramingNgModule._nextId++;
1646 container.id = '' + containerId;
1647 }
1648 const resolveId = FramingNgModule._nextId++;
1649 this.provide({
1650 provide: 'containerResolver' + resolveId,
1651 useFactory: (i) => new FramingContainerOutletResolver(containers, i),
1652 deps: [Injector],
1653 });
1654 route.resolve.containers = 'containerResolver' + resolveId;
1655 }
1656 if (route.children) {
1657 this.buildContainers(route.children);
1658 }
1659 }
1660 }
1661 buildRoute() {
1662 if (this._routes.length > 0) {
1663 // re-order routes so that full routes are first
1664 let fullRoutes = [];
1665 let prefixRoutes = [];
1666 this._routes.forEach((route) => {
1667 if (route.pathMatch && route.pathMatch === 'full') {
1668 fullRoutes.push(route);
1669 }
1670 else if (!route.pathMatch || route.pathMatch === 'prefix') {
1671 prefixRoutes.push(route);
1672 }
1673 else {
1674 console.warn('Unknown pathMatch on route', route);
1675 }
1676 this._routes = [];
1677 this._routes = this._routes.concat(fullRoutes);
1678 this._routes = this._routes.concat(prefixRoutes);
1679 });
1680 const routing = this._root || (this._routeConfig && this._routeConfig.forRoot) ?
1681 RouterModule.forRoot(this._routes, this._routeConfig ? this._routeConfig.extraRootRouterOptions : undefined) :
1682 RouterModule.forChild(this._routes);
1683 this.imports([routing]);
1684 if (this._routeConfig && this._routeConfig.forRoot && !this._root) {
1685 this.exports([RouterModule]); // export RouterModule from AppRoutingModule
1686 }
1687 }
1688 }
1689 getOrAddRouteOverload(route) {
1690 if (isArray(route)) {
1691 if (route.length) {
1692 let result;
1693 /* tslint:disable:prefer-for-of */
1694 result = this.getOrAddRoute(route[0]);
1695 for (let i = 1; i < route.length; i++) {
1696 if (!result.children) {
1697 result.children = [];
1698 }
1699 result = this.getOrAddRoute(route[i], result.children);
1700 }
1701 /* tslint:enable:prefer-for-of */
1702 return result;
1703 }
1704 else {
1705 return this.getOrAddRoute();
1706 }
1707 }
1708 else {
1709 return this.getOrAddRoute(route);
1710 }
1711 }
1712}
1713FramingNgModule._nextId = 1;
1714
1715/* tslint:disable:variable-name */
1716const Framing = (ngModuleBuilder) => {
1717 /* tslint:enable:variable-name */
1718 let framing = ngModuleBuilder(new FramingNgModule());
1719 if (!framing) {
1720 console.error('Framing must return a FramingNgModule');
1721 return {};
1722 }
1723 return framing.build();
1724};
1725
1726/**
1727 * A framer with no route, model, view, controller or frame.
1728 * To be used for leveraging the frame() function only.
1729 */
1730class SimpleFramer extends Framer {
1731 get framerName() { return 'Simple'; }
1732 get createFrame() { return false; }
1733 get routeRule() { return 'none'; }
1734}
1735
1736export { FramingDevToolsComponent, FramingDevToolsController, FramingDevToolsFeature, Action, _createReduxDevtoolsExtension, FramingComponentOutletDirective, FramingComponentOutletModule, FramingContainerOutletDirective, FramingContainerOutletModule, FramingContainerOutletResolver, FramingContainerOutletService, FramingEmptyParentComponent, FramingComponentsModule, FramingRootComponent, Component$1 as Component, Controller, FramingTools, Frame, FramerHelper, Framer, FramingNgModule, Framing, SimpleFramer };
1737//# sourceMappingURL=ng-core.js.map