UNPKG

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