mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
456 lines
13 KiB
456 lines
13 KiB
import * as i0 from '@angular/core';
|
|
import { ElementRef, NgModuleRef, EnvironmentInjector, createComponent, Injector, inject, TemplateRef, ViewContainerRef, Directive, DOCUMENT, EventEmitter, Input, Output, NgModule } from '@angular/core';
|
|
|
|
function throwNullPortalError() {
|
|
throw Error('Must provide a portal to attach');
|
|
}
|
|
function throwPortalAlreadyAttachedError() {
|
|
throw Error('Host already has a portal attached');
|
|
}
|
|
function throwPortalOutletAlreadyDisposedError() {
|
|
throw Error('This PortalOutlet has already been disposed');
|
|
}
|
|
function throwUnknownPortalTypeError() {
|
|
throw Error('Attempting to attach an unknown Portal type. BasePortalOutlet accepts either ' + 'a ComponentPortal or a TemplatePortal.');
|
|
}
|
|
function throwNullPortalOutletError() {
|
|
throw Error('Attempting to attach a portal to a null PortalOutlet');
|
|
}
|
|
function throwNoPortalAttachedError() {
|
|
throw Error('Attempting to detach a portal that is not attached to a host');
|
|
}
|
|
|
|
class Portal {
|
|
_attachedHost = null;
|
|
attach(host) {
|
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
if (host == null) {
|
|
throwNullPortalOutletError();
|
|
}
|
|
if (host.hasAttached()) {
|
|
throwPortalAlreadyAttachedError();
|
|
}
|
|
}
|
|
this._attachedHost = host;
|
|
return host.attach(this);
|
|
}
|
|
detach() {
|
|
let host = this._attachedHost;
|
|
if (host != null) {
|
|
this._attachedHost = null;
|
|
host.detach();
|
|
} else if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
throwNoPortalAttachedError();
|
|
}
|
|
}
|
|
get isAttached() {
|
|
return this._attachedHost != null;
|
|
}
|
|
setAttachedHost(host) {
|
|
this._attachedHost = host;
|
|
}
|
|
}
|
|
class ComponentPortal extends Portal {
|
|
component;
|
|
viewContainerRef;
|
|
injector;
|
|
projectableNodes;
|
|
constructor(component, viewContainerRef, injector, projectableNodes) {
|
|
super();
|
|
this.component = component;
|
|
this.viewContainerRef = viewContainerRef;
|
|
this.injector = injector;
|
|
this.projectableNodes = projectableNodes;
|
|
}
|
|
}
|
|
class TemplatePortal extends Portal {
|
|
templateRef;
|
|
viewContainerRef;
|
|
context;
|
|
injector;
|
|
constructor(templateRef, viewContainerRef, context, injector) {
|
|
super();
|
|
this.templateRef = templateRef;
|
|
this.viewContainerRef = viewContainerRef;
|
|
this.context = context;
|
|
this.injector = injector;
|
|
}
|
|
get origin() {
|
|
return this.templateRef.elementRef;
|
|
}
|
|
attach(host, context = this.context) {
|
|
this.context = context;
|
|
return super.attach(host);
|
|
}
|
|
detach() {
|
|
this.context = undefined;
|
|
return super.detach();
|
|
}
|
|
}
|
|
class DomPortal extends Portal {
|
|
element;
|
|
constructor(element) {
|
|
super();
|
|
this.element = element instanceof ElementRef ? element.nativeElement : element;
|
|
}
|
|
}
|
|
class BasePortalOutlet {
|
|
_attachedPortal = null;
|
|
_disposeFn = null;
|
|
_isDisposed = false;
|
|
hasAttached() {
|
|
return !!this._attachedPortal;
|
|
}
|
|
attach(portal) {
|
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
if (!portal) {
|
|
throwNullPortalError();
|
|
}
|
|
if (this.hasAttached()) {
|
|
throwPortalAlreadyAttachedError();
|
|
}
|
|
if (this._isDisposed) {
|
|
throwPortalOutletAlreadyDisposedError();
|
|
}
|
|
}
|
|
if (portal instanceof ComponentPortal) {
|
|
this._attachedPortal = portal;
|
|
return this.attachComponentPortal(portal);
|
|
} else if (portal instanceof TemplatePortal) {
|
|
this._attachedPortal = portal;
|
|
return this.attachTemplatePortal(portal);
|
|
} else if (this.attachDomPortal && portal instanceof DomPortal) {
|
|
this._attachedPortal = portal;
|
|
return this.attachDomPortal(portal);
|
|
}
|
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
throwUnknownPortalTypeError();
|
|
}
|
|
}
|
|
attachDomPortal = null;
|
|
detach() {
|
|
if (this._attachedPortal) {
|
|
this._attachedPortal.setAttachedHost(null);
|
|
this._attachedPortal = null;
|
|
}
|
|
this._invokeDisposeFn();
|
|
}
|
|
dispose() {
|
|
if (this.hasAttached()) {
|
|
this.detach();
|
|
}
|
|
this._invokeDisposeFn();
|
|
this._isDisposed = true;
|
|
}
|
|
setDisposeFn(fn) {
|
|
this._disposeFn = fn;
|
|
}
|
|
_invokeDisposeFn() {
|
|
if (this._disposeFn) {
|
|
this._disposeFn();
|
|
this._disposeFn = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
class DomPortalOutlet extends BasePortalOutlet {
|
|
outletElement;
|
|
_appRef;
|
|
_defaultInjector;
|
|
constructor(outletElement, _appRef, _defaultInjector) {
|
|
super();
|
|
this.outletElement = outletElement;
|
|
this._appRef = _appRef;
|
|
this._defaultInjector = _defaultInjector;
|
|
}
|
|
attachComponentPortal(portal) {
|
|
let componentRef;
|
|
if (portal.viewContainerRef) {
|
|
const injector = portal.injector || portal.viewContainerRef.injector;
|
|
const ngModuleRef = injector.get(NgModuleRef, null, {
|
|
optional: true
|
|
}) || undefined;
|
|
componentRef = portal.viewContainerRef.createComponent(portal.component, {
|
|
index: portal.viewContainerRef.length,
|
|
injector,
|
|
ngModuleRef,
|
|
projectableNodes: portal.projectableNodes || undefined
|
|
});
|
|
this.setDisposeFn(() => componentRef.destroy());
|
|
} else {
|
|
if ((typeof ngDevMode === 'undefined' || ngDevMode) && !this._appRef) {
|
|
throw Error('Cannot attach component portal to outlet without an ApplicationRef.');
|
|
}
|
|
const appRef = this._appRef;
|
|
const elementInjector = portal.injector || this._defaultInjector || Injector.NULL;
|
|
const environmentInjector = elementInjector.get(EnvironmentInjector, appRef.injector);
|
|
componentRef = createComponent(portal.component, {
|
|
elementInjector,
|
|
environmentInjector,
|
|
projectableNodes: portal.projectableNodes || undefined
|
|
});
|
|
appRef.attachView(componentRef.hostView);
|
|
this.setDisposeFn(() => {
|
|
if (appRef.viewCount > 0) {
|
|
appRef.detachView(componentRef.hostView);
|
|
}
|
|
componentRef.destroy();
|
|
});
|
|
}
|
|
this.outletElement.appendChild(this._getComponentRootNode(componentRef));
|
|
this._attachedPortal = portal;
|
|
return componentRef;
|
|
}
|
|
attachTemplatePortal(portal) {
|
|
let viewContainer = portal.viewContainerRef;
|
|
let viewRef = viewContainer.createEmbeddedView(portal.templateRef, portal.context, {
|
|
injector: portal.injector
|
|
});
|
|
viewRef.rootNodes.forEach(rootNode => this.outletElement.appendChild(rootNode));
|
|
viewRef.detectChanges();
|
|
this.setDisposeFn(() => {
|
|
let index = viewContainer.indexOf(viewRef);
|
|
if (index !== -1) {
|
|
viewContainer.remove(index);
|
|
}
|
|
});
|
|
this._attachedPortal = portal;
|
|
return viewRef;
|
|
}
|
|
attachDomPortal = portal => {
|
|
const element = portal.element;
|
|
if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw Error('DOM portal content must be attached to a parent node.');
|
|
}
|
|
const anchorNode = this.outletElement.ownerDocument.createComment('dom-portal');
|
|
element.parentNode.insertBefore(anchorNode, element);
|
|
this.outletElement.appendChild(element);
|
|
this._attachedPortal = portal;
|
|
super.setDisposeFn(() => {
|
|
if (anchorNode.parentNode) {
|
|
anchorNode.parentNode.replaceChild(element, anchorNode);
|
|
}
|
|
});
|
|
};
|
|
dispose() {
|
|
super.dispose();
|
|
this.outletElement.remove();
|
|
}
|
|
_getComponentRootNode(componentRef) {
|
|
return componentRef.hostView.rootNodes[0];
|
|
}
|
|
}
|
|
|
|
class CdkPortal extends TemplatePortal {
|
|
constructor() {
|
|
const templateRef = inject(TemplateRef);
|
|
const viewContainerRef = inject(ViewContainerRef);
|
|
super(templateRef, viewContainerRef);
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkPortal,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: CdkPortal,
|
|
isStandalone: true,
|
|
selector: "[cdkPortal]",
|
|
exportAs: ["cdkPortal"],
|
|
usesInheritance: true,
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkPortal,
|
|
decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: '[cdkPortal]',
|
|
exportAs: 'cdkPortal'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
class CdkPortalOutlet extends BasePortalOutlet {
|
|
_moduleRef = inject(NgModuleRef, {
|
|
optional: true
|
|
});
|
|
_document = inject(DOCUMENT);
|
|
_viewContainerRef = inject(ViewContainerRef);
|
|
_isInitialized = false;
|
|
_attachedRef = null;
|
|
constructor() {
|
|
super();
|
|
}
|
|
get portal() {
|
|
return this._attachedPortal;
|
|
}
|
|
set portal(portal) {
|
|
if (this.hasAttached() && !portal && !this._isInitialized) {
|
|
return;
|
|
}
|
|
if (this.hasAttached()) {
|
|
super.detach();
|
|
}
|
|
if (portal) {
|
|
super.attach(portal);
|
|
}
|
|
this._attachedPortal = portal || null;
|
|
}
|
|
attached = new EventEmitter();
|
|
get attachedRef() {
|
|
return this._attachedRef;
|
|
}
|
|
ngOnInit() {
|
|
this._isInitialized = true;
|
|
}
|
|
ngOnDestroy() {
|
|
super.dispose();
|
|
this._attachedRef = this._attachedPortal = null;
|
|
}
|
|
attachComponentPortal(portal) {
|
|
portal.setAttachedHost(this);
|
|
const viewContainerRef = portal.viewContainerRef != null ? portal.viewContainerRef : this._viewContainerRef;
|
|
const ref = viewContainerRef.createComponent(portal.component, {
|
|
index: viewContainerRef.length,
|
|
injector: portal.injector || viewContainerRef.injector,
|
|
projectableNodes: portal.projectableNodes || undefined,
|
|
ngModuleRef: this._moduleRef || undefined
|
|
});
|
|
if (viewContainerRef !== this._viewContainerRef) {
|
|
this._getRootNode().appendChild(ref.hostView.rootNodes[0]);
|
|
}
|
|
super.setDisposeFn(() => ref.destroy());
|
|
this._attachedPortal = portal;
|
|
this._attachedRef = ref;
|
|
this.attached.emit(ref);
|
|
return ref;
|
|
}
|
|
attachTemplatePortal(portal) {
|
|
portal.setAttachedHost(this);
|
|
const viewRef = this._viewContainerRef.createEmbeddedView(portal.templateRef, portal.context, {
|
|
injector: portal.injector
|
|
});
|
|
super.setDisposeFn(() => this._viewContainerRef.clear());
|
|
this._attachedPortal = portal;
|
|
this._attachedRef = viewRef;
|
|
this.attached.emit(viewRef);
|
|
return viewRef;
|
|
}
|
|
attachDomPortal = portal => {
|
|
const element = portal.element;
|
|
if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw Error('DOM portal content must be attached to a parent node.');
|
|
}
|
|
const anchorNode = this._document.createComment('dom-portal');
|
|
portal.setAttachedHost(this);
|
|
element.parentNode.insertBefore(anchorNode, element);
|
|
this._getRootNode().appendChild(element);
|
|
this._attachedPortal = portal;
|
|
super.setDisposeFn(() => {
|
|
if (anchorNode.parentNode) {
|
|
anchorNode.parentNode.replaceChild(element, anchorNode);
|
|
}
|
|
});
|
|
};
|
|
_getRootNode() {
|
|
const nativeElement = this._viewContainerRef.element.nativeElement;
|
|
return nativeElement.nodeType === nativeElement.ELEMENT_NODE ? nativeElement : nativeElement.parentNode;
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkPortalOutlet,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: CdkPortalOutlet,
|
|
isStandalone: true,
|
|
selector: "[cdkPortalOutlet]",
|
|
inputs: {
|
|
portal: ["cdkPortalOutlet", "portal"]
|
|
},
|
|
outputs: {
|
|
attached: "attached"
|
|
},
|
|
exportAs: ["cdkPortalOutlet"],
|
|
usesInheritance: true,
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkPortalOutlet,
|
|
decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: '[cdkPortalOutlet]',
|
|
exportAs: 'cdkPortalOutlet'
|
|
}]
|
|
}],
|
|
ctorParameters: () => [],
|
|
propDecorators: {
|
|
portal: [{
|
|
type: Input,
|
|
args: ['cdkPortalOutlet']
|
|
}],
|
|
attached: [{
|
|
type: Output
|
|
}]
|
|
}
|
|
});
|
|
class PortalModule {
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: PortalModule,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.NgModule
|
|
});
|
|
static ɵmod = i0.ɵɵngDeclareNgModule({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: PortalModule,
|
|
imports: [CdkPortal, CdkPortalOutlet],
|
|
exports: [CdkPortal, CdkPortalOutlet]
|
|
});
|
|
static ɵinj = i0.ɵɵngDeclareInjector({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: PortalModule
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: PortalModule,
|
|
decorators: [{
|
|
type: NgModule,
|
|
args: [{
|
|
imports: [CdkPortal, CdkPortalOutlet],
|
|
exports: [CdkPortal, CdkPortalOutlet]
|
|
}]
|
|
}]
|
|
});
|
|
|
|
export { BasePortalOutlet, CdkPortal, CdkPortalOutlet, ComponentPortal, DomPortal, DomPortalOutlet, Portal, PortalModule, TemplatePortal };
|
|
//# sourceMappingURL=portal.mjs.map
|
|
|