1 | import * as i0 from '@angular/core';
|
2 | import { ElementRef, Injector, Directive, EventEmitter, Inject, Output, NgModule } from '@angular/core';
|
3 | import { DOCUMENT } from '@angular/common';
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | function throwNullPortalError() {
|
10 | throw Error('Must provide a portal to attach');
|
11 | }
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | function throwPortalAlreadyAttachedError() {
|
17 | throw Error('Host already has a portal attached');
|
18 | }
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | function throwPortalOutletAlreadyDisposedError() {
|
24 | throw Error('This PortalOutlet has already been disposed');
|
25 | }
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | function throwUnknownPortalTypeError() {
|
31 | throw Error('Attempting to attach an unknown Portal type. BasePortalOutlet accepts either ' +
|
32 | 'a ComponentPortal or a TemplatePortal.');
|
33 | }
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | function throwNullPortalOutletError() {
|
39 | throw Error('Attempting to attach a portal to a null PortalOutlet');
|
40 | }
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | function throwNoPortalAttachedError() {
|
46 | throw Error('Attempting to detach a portal that is not attached to a host');
|
47 | }
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 | class Portal {
|
54 |
|
55 | attach(host) {
|
56 | if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
57 | if (host == null) {
|
58 | throwNullPortalOutletError();
|
59 | }
|
60 | if (host.hasAttached()) {
|
61 | throwPortalAlreadyAttachedError();
|
62 | }
|
63 | }
|
64 | this._attachedHost = host;
|
65 | return host.attach(this);
|
66 | }
|
67 |
|
68 | detach() {
|
69 | let host = this._attachedHost;
|
70 | if (host != null) {
|
71 | this._attachedHost = null;
|
72 | host.detach();
|
73 | }
|
74 | else if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
75 | throwNoPortalAttachedError();
|
76 | }
|
77 | }
|
78 |
|
79 | get isAttached() {
|
80 | return this._attachedHost != null;
|
81 | }
|
82 | |
83 |
|
84 |
|
85 |
|
86 | setAttachedHost(host) {
|
87 | this._attachedHost = host;
|
88 | }
|
89 | }
|
90 |
|
91 |
|
92 |
|
93 | class ComponentPortal extends Portal {
|
94 | constructor(component, viewContainerRef, injector, componentFactoryResolver, projectableNodes) {
|
95 | super();
|
96 | this.component = component;
|
97 | this.viewContainerRef = viewContainerRef;
|
98 | this.injector = injector;
|
99 | this.componentFactoryResolver = componentFactoryResolver;
|
100 | this.projectableNodes = projectableNodes;
|
101 | }
|
102 | }
|
103 |
|
104 |
|
105 |
|
106 | class TemplatePortal extends Portal {
|
107 | constructor(
|
108 | /** The embedded template that will be used to instantiate an embedded View in the host. */
|
109 | templateRef,
|
110 | /** Reference to the ViewContainer into which the template will be stamped out. */
|
111 | viewContainerRef,
|
112 | /** Contextual data to be passed in to the embedded view. */
|
113 | context,
|
114 | /** The injector to use for the embedded view. */
|
115 | injector) {
|
116 | super();
|
117 | this.templateRef = templateRef;
|
118 | this.viewContainerRef = viewContainerRef;
|
119 | this.context = context;
|
120 | this.injector = injector;
|
121 | }
|
122 | get origin() {
|
123 | return this.templateRef.elementRef;
|
124 | }
|
125 | |
126 |
|
127 |
|
128 |
|
129 |
|
130 | attach(host, context = this.context) {
|
131 | this.context = context;
|
132 | return super.attach(host);
|
133 | }
|
134 | detach() {
|
135 | this.context = undefined;
|
136 | return super.detach();
|
137 | }
|
138 | }
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 | class DomPortal extends Portal {
|
145 | constructor(element) {
|
146 | super();
|
147 | this.element = element instanceof ElementRef ? element.nativeElement : element;
|
148 | }
|
149 | }
|
150 |
|
151 |
|
152 |
|
153 |
|
154 | class BasePortalOutlet {
|
155 | constructor() {
|
156 |
|
157 | this._isDisposed = false;
|
158 |
|
159 | this.attachDomPortal = null;
|
160 | }
|
161 |
|
162 | hasAttached() {
|
163 | return !!this._attachedPortal;
|
164 | }
|
165 |
|
166 | attach(portal) {
|
167 | if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
168 | if (!portal) {
|
169 | throwNullPortalError();
|
170 | }
|
171 | if (this.hasAttached()) {
|
172 | throwPortalAlreadyAttachedError();
|
173 | }
|
174 | if (this._isDisposed) {
|
175 | throwPortalOutletAlreadyDisposedError();
|
176 | }
|
177 | }
|
178 | if (portal instanceof ComponentPortal) {
|
179 | this._attachedPortal = portal;
|
180 | return this.attachComponentPortal(portal);
|
181 | }
|
182 | else if (portal instanceof TemplatePortal) {
|
183 | this._attachedPortal = portal;
|
184 | return this.attachTemplatePortal(portal);
|
185 |
|
186 | }
|
187 | else if (this.attachDomPortal && portal instanceof DomPortal) {
|
188 | this._attachedPortal = portal;
|
189 | return this.attachDomPortal(portal);
|
190 | }
|
191 | if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
192 | throwUnknownPortalTypeError();
|
193 | }
|
194 | }
|
195 |
|
196 | detach() {
|
197 | if (this._attachedPortal) {
|
198 | this._attachedPortal.setAttachedHost(null);
|
199 | this._attachedPortal = null;
|
200 | }
|
201 | this._invokeDisposeFn();
|
202 | }
|
203 |
|
204 | dispose() {
|
205 | if (this.hasAttached()) {
|
206 | this.detach();
|
207 | }
|
208 | this._invokeDisposeFn();
|
209 | this._isDisposed = true;
|
210 | }
|
211 |
|
212 | setDisposeFn(fn) {
|
213 | this._disposeFn = fn;
|
214 | }
|
215 | _invokeDisposeFn() {
|
216 | if (this._disposeFn) {
|
217 | this._disposeFn();
|
218 | this._disposeFn = null;
|
219 | }
|
220 | }
|
221 | }
|
222 |
|
223 |
|
224 |
|
225 |
|
226 | class BasePortalHost extends BasePortalOutlet {
|
227 | }
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 | class DomPortalOutlet extends BasePortalOutlet {
|
234 | |
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 | constructor(
|
246 | /** Element into which the content is projected. */
|
247 | outletElement, _componentFactoryResolver, _appRef, _defaultInjector,
|
248 | /**
|
249 | * @deprecated `_document` Parameter to be made required.
|
250 | * @breaking-change 10.0.0
|
251 | */
|
252 | _document) {
|
253 | super();
|
254 | this.outletElement = outletElement;
|
255 | this._componentFactoryResolver = _componentFactoryResolver;
|
256 | this._appRef = _appRef;
|
257 | this._defaultInjector = _defaultInjector;
|
258 | |
259 |
|
260 |
|
261 |
|
262 |
|
263 |
|
264 | this.attachDomPortal = (portal) => {
|
265 |
|
266 |
|
267 | if (!this._document && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
268 | throw Error('Cannot attach DOM portal without _document constructor parameter');
|
269 | }
|
270 | const element = portal.element;
|
271 | if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
272 | throw Error('DOM portal content must be attached to a parent node.');
|
273 | }
|
274 |
|
275 |
|
276 | const anchorNode = this._document.createComment('dom-portal');
|
277 | element.parentNode.insertBefore(anchorNode, element);
|
278 | this.outletElement.appendChild(element);
|
279 | this._attachedPortal = portal;
|
280 | super.setDisposeFn(() => {
|
281 |
|
282 | if (anchorNode.parentNode) {
|
283 | anchorNode.parentNode.replaceChild(element, anchorNode);
|
284 | }
|
285 | });
|
286 | };
|
287 | this._document = _document;
|
288 | }
|
289 | |
290 |
|
291 |
|
292 |
|
293 |
|
294 | attachComponentPortal(portal) {
|
295 | const resolver = (portal.componentFactoryResolver || this._componentFactoryResolver);
|
296 | if ((typeof ngDevMode === 'undefined' || ngDevMode) && !resolver) {
|
297 | throw Error('Cannot attach component portal to outlet without a ComponentFactoryResolver.');
|
298 | }
|
299 | const componentFactory = resolver.resolveComponentFactory(portal.component);
|
300 | let componentRef;
|
301 |
|
302 |
|
303 |
|
304 |
|
305 | if (portal.viewContainerRef) {
|
306 | componentRef = portal.viewContainerRef.createComponent(componentFactory, portal.viewContainerRef.length, portal.injector || portal.viewContainerRef.injector, portal.projectableNodes || undefined);
|
307 | this.setDisposeFn(() => componentRef.destroy());
|
308 | }
|
309 | else {
|
310 | if ((typeof ngDevMode === 'undefined' || ngDevMode) && !this._appRef) {
|
311 | throw Error('Cannot attach component portal to outlet without an ApplicationRef.');
|
312 | }
|
313 | componentRef = componentFactory.create(portal.injector || this._defaultInjector || Injector.NULL);
|
314 | this._appRef.attachView(componentRef.hostView);
|
315 | this.setDisposeFn(() => {
|
316 |
|
317 |
|
318 | if (this._appRef.viewCount > 0) {
|
319 | this._appRef.detachView(componentRef.hostView);
|
320 | }
|
321 | componentRef.destroy();
|
322 | });
|
323 | }
|
324 |
|
325 |
|
326 | this.outletElement.appendChild(this._getComponentRootNode(componentRef));
|
327 | this._attachedPortal = portal;
|
328 | return componentRef;
|
329 | }
|
330 | |
331 |
|
332 |
|
333 |
|
334 |
|
335 | attachTemplatePortal(portal) {
|
336 | let viewContainer = portal.viewContainerRef;
|
337 | let viewRef = viewContainer.createEmbeddedView(portal.templateRef, portal.context, {
|
338 | injector: portal.injector,
|
339 | });
|
340 |
|
341 |
|
342 |
|
343 |
|
344 | viewRef.rootNodes.forEach(rootNode => this.outletElement.appendChild(rootNode));
|
345 |
|
346 |
|
347 |
|
348 | viewRef.detectChanges();
|
349 | this.setDisposeFn(() => {
|
350 | let index = viewContainer.indexOf(viewRef);
|
351 | if (index !== -1) {
|
352 | viewContainer.remove(index);
|
353 | }
|
354 | });
|
355 | this._attachedPortal = portal;
|
356 |
|
357 | return viewRef;
|
358 | }
|
359 | |
360 |
|
361 |
|
362 | dispose() {
|
363 | super.dispose();
|
364 | this.outletElement.remove();
|
365 | }
|
366 |
|
367 | _getComponentRootNode(componentRef) {
|
368 | return componentRef.hostView.rootNodes[0];
|
369 | }
|
370 | }
|
371 |
|
372 |
|
373 |
|
374 |
|
375 | class DomPortalHost extends DomPortalOutlet {
|
376 | }
|
377 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 | class CdkPortal extends TemplatePortal {
|
383 | constructor(templateRef, viewContainerRef) {
|
384 | super(templateRef, viewContainerRef);
|
385 | }
|
386 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: CdkPortal, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
387 | static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: CdkPortal, selector: "[cdkPortal]", exportAs: ["cdkPortal"], usesInheritance: true, ngImport: i0 }); }
|
388 | }
|
389 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: CdkPortal, decorators: [{
|
390 | type: Directive,
|
391 | args: [{
|
392 | selector: '[cdkPortal]',
|
393 | exportAs: 'cdkPortal',
|
394 | }]
|
395 | }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }]; } });
|
396 |
|
397 |
|
398 |
|
399 |
|
400 | class TemplatePortalDirective extends CdkPortal {
|
401 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TemplatePortalDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
402 | static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: TemplatePortalDirective, selector: "[cdk-portal], [portal]", providers: [
|
403 | {
|
404 | provide: CdkPortal,
|
405 | useExisting: TemplatePortalDirective,
|
406 | },
|
407 | ], exportAs: ["cdkPortal"], usesInheritance: true, ngImport: i0 }); }
|
408 | }
|
409 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TemplatePortalDirective, decorators: [{
|
410 | type: Directive,
|
411 | args: [{
|
412 | selector: '[cdk-portal], [portal]',
|
413 | exportAs: 'cdkPortal',
|
414 | providers: [
|
415 | {
|
416 | provide: CdkPortal,
|
417 | useExisting: TemplatePortalDirective,
|
418 | },
|
419 | ],
|
420 | }]
|
421 | }] });
|
422 |
|
423 |
|
424 |
|
425 |
|
426 |
|
427 |
|
428 |
|
429 | class CdkPortalOutlet extends BasePortalOutlet {
|
430 | constructor(_componentFactoryResolver, _viewContainerRef,
|
431 | /**
|
432 | * @deprecated `_document` parameter to be made required.
|
433 | * @breaking-change 9.0.0
|
434 | */
|
435 | _document) {
|
436 | super();
|
437 | this._componentFactoryResolver = _componentFactoryResolver;
|
438 | this._viewContainerRef = _viewContainerRef;
|
439 |
|
440 | this._isInitialized = false;
|
441 |
|
442 | this.attached = new EventEmitter();
|
443 | |
444 |
|
445 |
|
446 |
|
447 |
|
448 |
|
449 | this.attachDomPortal = (portal) => {
|
450 |
|
451 |
|
452 | if (!this._document && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
453 | throw Error('Cannot attach DOM portal without _document constructor parameter');
|
454 | }
|
455 | const element = portal.element;
|
456 | if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
457 | throw Error('DOM portal content must be attached to a parent node.');
|
458 | }
|
459 |
|
460 |
|
461 | const anchorNode = this._document.createComment('dom-portal');
|
462 | portal.setAttachedHost(this);
|
463 | element.parentNode.insertBefore(anchorNode, element);
|
464 | this._getRootNode().appendChild(element);
|
465 | this._attachedPortal = portal;
|
466 | super.setDisposeFn(() => {
|
467 | if (anchorNode.parentNode) {
|
468 | anchorNode.parentNode.replaceChild(element, anchorNode);
|
469 | }
|
470 | });
|
471 | };
|
472 | this._document = _document;
|
473 | }
|
474 |
|
475 | get portal() {
|
476 | return this._attachedPortal;
|
477 | }
|
478 | set portal(portal) {
|
479 |
|
480 |
|
481 |
|
482 |
|
483 | if (this.hasAttached() && !portal && !this._isInitialized) {
|
484 | return;
|
485 | }
|
486 | if (this.hasAttached()) {
|
487 | super.detach();
|
488 | }
|
489 | if (portal) {
|
490 | super.attach(portal);
|
491 | }
|
492 | this._attachedPortal = portal || null;
|
493 | }
|
494 |
|
495 | get attachedRef() {
|
496 | return this._attachedRef;
|
497 | }
|
498 | ngOnInit() {
|
499 | this._isInitialized = true;
|
500 | }
|
501 | ngOnDestroy() {
|
502 | super.dispose();
|
503 | this._attachedRef = this._attachedPortal = null;
|
504 | }
|
505 | |
506 |
|
507 |
|
508 |
|
509 |
|
510 |
|
511 | attachComponentPortal(portal) {
|
512 | portal.setAttachedHost(this);
|
513 |
|
514 |
|
515 | const viewContainerRef = portal.viewContainerRef != null ? portal.viewContainerRef : this._viewContainerRef;
|
516 | const resolver = portal.componentFactoryResolver || this._componentFactoryResolver;
|
517 | const componentFactory = resolver.resolveComponentFactory(portal.component);
|
518 | const ref = viewContainerRef.createComponent(componentFactory, viewContainerRef.length, portal.injector || viewContainerRef.injector, portal.projectableNodes || undefined);
|
519 |
|
520 |
|
521 |
|
522 | if (viewContainerRef !== this._viewContainerRef) {
|
523 | this._getRootNode().appendChild(ref.hostView.rootNodes[0]);
|
524 | }
|
525 | super.setDisposeFn(() => ref.destroy());
|
526 | this._attachedPortal = portal;
|
527 | this._attachedRef = ref;
|
528 | this.attached.emit(ref);
|
529 | return ref;
|
530 | }
|
531 | |
532 |
|
533 |
|
534 |
|
535 |
|
536 | attachTemplatePortal(portal) {
|
537 | portal.setAttachedHost(this);
|
538 | const viewRef = this._viewContainerRef.createEmbeddedView(portal.templateRef, portal.context, {
|
539 | injector: portal.injector,
|
540 | });
|
541 | super.setDisposeFn(() => this._viewContainerRef.clear());
|
542 | this._attachedPortal = portal;
|
543 | this._attachedRef = viewRef;
|
544 | this.attached.emit(viewRef);
|
545 | return viewRef;
|
546 | }
|
547 |
|
548 | _getRootNode() {
|
549 | const nativeElement = this._viewContainerRef.element.nativeElement;
|
550 |
|
551 |
|
552 | return (nativeElement.nodeType === nativeElement.ELEMENT_NODE
|
553 | ? nativeElement
|
554 | : nativeElement.parentNode);
|
555 | }
|
556 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: CdkPortalOutlet, deps: [{ token: i0.ComponentFactoryResolver }, { token: i0.ViewContainerRef }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive }); }
|
557 | static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: { portal: ["cdkPortalOutlet", "portal"] }, outputs: { attached: "attached" }, exportAs: ["cdkPortalOutlet"], usesInheritance: true, ngImport: i0 }); }
|
558 | }
|
559 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: CdkPortalOutlet, decorators: [{
|
560 | type: Directive,
|
561 | args: [{
|
562 | selector: '[cdkPortalOutlet]',
|
563 | exportAs: 'cdkPortalOutlet',
|
564 | inputs: ['portal: cdkPortalOutlet'],
|
565 | }]
|
566 | }], ctorParameters: function () { return [{ type: i0.ComponentFactoryResolver }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
|
567 | type: Inject,
|
568 | args: [DOCUMENT]
|
569 | }] }]; }, propDecorators: { attached: [{
|
570 | type: Output
|
571 | }] } });
|
572 |
|
573 |
|
574 |
|
575 |
|
576 | class PortalHostDirective extends CdkPortalOutlet {
|
577 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: PortalHostDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
578 | static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: PortalHostDirective, selector: "[cdkPortalHost], [portalHost]", inputs: { portal: ["cdkPortalHost", "portal"] }, providers: [
|
579 | {
|
580 | provide: CdkPortalOutlet,
|
581 | useExisting: PortalHostDirective,
|
582 | },
|
583 | ], exportAs: ["cdkPortalHost"], usesInheritance: true, ngImport: i0 }); }
|
584 | }
|
585 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: PortalHostDirective, decorators: [{
|
586 | type: Directive,
|
587 | args: [{
|
588 | selector: '[cdkPortalHost], [portalHost]',
|
589 | exportAs: 'cdkPortalHost',
|
590 | inputs: ['portal: cdkPortalHost'],
|
591 | providers: [
|
592 | {
|
593 | provide: CdkPortalOutlet,
|
594 | useExisting: PortalHostDirective,
|
595 | },
|
596 | ],
|
597 | }]
|
598 | }] });
|
599 | class PortalModule {
|
600 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: PortalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
601 | static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.0", ngImport: i0, type: PortalModule, declarations: [CdkPortal, CdkPortalOutlet, TemplatePortalDirective, PortalHostDirective], exports: [CdkPortal, CdkPortalOutlet, TemplatePortalDirective, PortalHostDirective] }); }
|
602 | static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: PortalModule }); }
|
603 | }
|
604 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: PortalModule, decorators: [{
|
605 | type: NgModule,
|
606 | args: [{
|
607 | exports: [CdkPortal, CdkPortalOutlet, TemplatePortalDirective, PortalHostDirective],
|
608 | declarations: [CdkPortal, CdkPortalOutlet, TemplatePortalDirective, PortalHostDirective],
|
609 | }]
|
610 | }] });
|
611 |
|
612 |
|
613 |
|
614 |
|
615 |
|
616 |
|
617 |
|
618 |
|
619 | class PortalInjector {
|
620 | constructor(_parentInjector, _customTokens) {
|
621 | this._parentInjector = _parentInjector;
|
622 | this._customTokens = _customTokens;
|
623 | }
|
624 | get(token, notFoundValue) {
|
625 | const value = this._customTokens.get(token);
|
626 | if (typeof value !== 'undefined') {
|
627 | return value;
|
628 | }
|
629 | return this._parentInjector.get(token, notFoundValue);
|
630 | }
|
631 | }
|
632 |
|
633 |
|
634 |
|
635 |
|
636 |
|
637 | export { BasePortalHost, BasePortalOutlet, CdkPortal, CdkPortalOutlet, ComponentPortal, DomPortal, DomPortalHost, DomPortalOutlet, Portal, PortalHostDirective, PortalInjector, PortalModule, TemplatePortal, TemplatePortalDirective };
|
638 |
|