Files
cbsnexora/src/app/configuration-wizard/popover/popover.service.ts
T
2022-09-02 17:03:13 +05:30

227 lines
6.3 KiB
TypeScript

/* Angular Imports */
import { ComponentType, Overlay, OriginConnectionPosition, OverlayConnectionPosition, ConnectionPositionPair } from '@angular/cdk/overlay';
import { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
import { Injectable, InjectionToken, Injector, TemplateRef, ElementRef } from '@angular/core';
/* Custom Imports */
import { PopoverConfig } from './popover-config';
import { PopoverRef } from './popover-ref';
import { PopoverComponent } from './popover.component';
/**
* Injection token that can be used to access the data that was passed in to a popover.
*
*/
export const POPOVER_DATA = new InjectionToken('popover.data');
const defaultConfig: PopoverConfig = {
backdropClass: '',
disableClose: false,
panelClass: '',
arrowOffset: 30,
arrowSize: 20
};
/**
* Service to open modal and manage popovers.
*/
@Injectable({
providedIn: 'root'
})
export class PopoverService {
/**
* @param {Injector} injector Injector.
* @param {overlay} overlay Overlay.
*/
constructor(private overlay: Overlay, private injector: Injector) { }
/**
* Opens the popover at target element
* @param {ComponentType<any> | TemplateRef<any>} componentOrTemplate ComponentType<any> | TemplateRef<any>.
* @param {ElementRef | HTMLElement} target ElementRef | HTMLElement.
* @param {string} position String.
* @param {Partial<PopoverConfig> = {}} config Partial<PopoverConfig> = {}.
*/
open<D = any>(componentOrTemplate: ComponentType<any> | TemplateRef<any>,
target: ElementRef | HTMLElement, position: string,
backdrop: boolean,
config: Partial<PopoverConfig> = {}): PopoverRef<D> {
const popoverConfig: PopoverConfig = Object.assign({}, defaultConfig, config);
const arrowSize = popoverConfig.arrowSize;
const arrowOffset = popoverConfig.arrowOffset;
const panelOffset = arrowSize / 2;
let showbackdrop: boolean;
let positions: ConnectionPositionPair[];
// preferred positions, in order of priority
if (position === 'bottom') {
positions = [
// bottom center
{
overlayX: 'center',
overlayY: 'top',
originX: 'center',
originY: 'bottom',
panelClass: ['top', 'center'],
offsetY: panelOffset
},
// bottom left
{
overlayX: 'start',
overlayY: 'top',
originX: 'center',
originY: 'bottom',
panelClass: ['top', 'left'],
offsetX: -1 * arrowOffset,
offsetY: panelOffset
},
// bottom right
{
overlayX: 'end',
overlayY: 'top',
originX: 'center',
originY: 'bottom',
panelClass: ['top', 'right'],
offsetX: arrowOffset,
offsetY: panelOffset
}
];
} else if (position === 'top') {
positions = [
// top center
{
overlayX: 'center',
overlayY: 'bottom',
originX: 'center',
originY: 'top',
panelClass: ['bottom', 'center'],
offsetY: -1 * panelOffset
},
// top left
{
overlayX: 'start',
overlayY: 'bottom',
originX: 'center',
originY: 'top',
panelClass: ['bottom', 'left'],
offsetX: -1 * arrowOffset,
offsetY: -1 * panelOffset
},
// top right
{
overlayX: 'end',
overlayY: 'bottom',
originX: 'center',
originY: 'top',
panelClass: ['bottom', 'right'],
offsetX: arrowOffset,
offsetY: -1 * panelOffset
}
];
} else if (position === 'right') {
positions = [
// right
{
originX : 'end',
originY : 'center',
overlayX: 'start',
overlayY: 'center',
panelClass: ['center', 'left'],
offsetX: 0.5 * arrowOffset,
offsetY: -1 * panelOffset
},
];
} else if (position === 'left') {
positions = [
// left
{
originX : 'start',
originY : 'center',
overlayX: 'end',
overlayY: 'center',
panelClass: ['center', 'right'],
offsetX: -0.5 * arrowOffset,
offsetY: -1 * panelOffset
},
];
}
if (backdrop === true) {
showbackdrop = true;
} else {
showbackdrop = false;
}
const positionStrategy = this.overlay
.position()
.flexibleConnectedTo(target)
.withPush(false)
.withFlexibleDimensions(false)
.withPositions(positions);
const overlayRef = this.overlay.create({
hasBackdrop: showbackdrop,
backdropClass: config.backdropClass,
panelClass: config.panelClass,
positionStrategy,
scrollStrategy: this.overlay.scrollStrategies.reposition()
});
const popoverRef = new PopoverRef(overlayRef, positionStrategy, popoverConfig);
const popover = overlayRef.attach(new ComponentPortal(
PopoverComponent,
null,
Injector.create({
parent: this.injector,
providers: [
{ provide: PopoverRef, useValue: popoverRef }
]
})
// new PortalInjector(
// this.injector,
// new WeakMap<any, any>([
// [PopoverRef, popoverRef]
// ])
// )
)).instance;
if (componentOrTemplate instanceof TemplateRef) {
// rendering a provided template dynamically
popover.attachTemplatePortal(
new TemplatePortal(
componentOrTemplate,
null,
{
$implicit: config.data,
popover: popoverRef
}
)
);
} else {
// rendering a provided component dynamically
popover.attachComponentPortal(
new ComponentPortal(
componentOrTemplate,
null,
Injector.create({
parent: this.injector,
providers: [
{ provide: POPOVER_DATA, useValue: config.data },
{ provide: PopoverRef, useValue: popoverRef },
]
})
// new PortalInjector(
// this.injector,
// new WeakMap<any, any>([
// [POPOVER_DATA, config.data],
// [PopoverRef, popoverRef]
// ])
// )
)
);
}
return popoverRef;
}
}