diff options
Diffstat (limited to 'sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util')
4 files changed, 312 insertions, 0 deletions
diff --git a/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/popup.ts b/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/popup.ts new file mode 100644 index 00000000..56c26d62 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/popup.ts @@ -0,0 +1,58 @@ +import { + Injector, + TemplateRef, + ViewRef, + ViewContainerRef, + Renderer, + ComponentRef, + ComponentFactory, + ComponentFactoryResolver +} from '@angular/core'; + +export class ContentRef { + constructor(public nodes: any[], public viewRef?: ViewRef, public componentRef?: ComponentRef<any>) {} +} + +export class PopupService<T> { + private _windowFactory: ComponentFactory<T>; + private _windowRef: ComponentRef<T>; + private _contentRef: ContentRef; + + constructor( + type: any, private _injector: Injector, private _viewContainerRef: ViewContainerRef, private _renderer: Renderer, + componentFactoryResolver: ComponentFactoryResolver) { + this._windowFactory = componentFactoryResolver.resolveComponentFactory<T>(type); + } + + public open(content?: string | TemplateRef<any>, context?: any): ComponentRef<T> { + if (!this._windowRef) { + this._contentRef = this._getContentRef(content, context); + this._windowRef = + this._viewContainerRef.createComponent(this._windowFactory, 0, this._injector, this._contentRef.nodes); + } + return this._windowRef; + } + + public close() { + if (this._windowRef) { + this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._windowRef.hostView)); + this._windowRef = null; + + if (this._contentRef.viewRef) { + this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._contentRef.viewRef)); + this._contentRef = null; + } + } + } + + private _getContentRef(content: string | TemplateRef<any>, context?: any): ContentRef { + if (!content) { + return new ContentRef([]); + } else if (content instanceof TemplateRef) { + const viewRef = this._viewContainerRef.createEmbeddedView(<TemplateRef<T>>content, context); + return new ContentRef([viewRef.rootNodes], viewRef); + } else { + return new ContentRef([[this._renderer.createText(null, `${content}`)]]); + } + } +} diff --git a/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/positioning.ts b/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/positioning.ts new file mode 100644 index 00000000..ed9005c1 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/positioning.ts @@ -0,0 +1,153 @@ +// previous version: +// https://github.com/angular-ui/bootstrap/blob/07c31d0731f7cb068a1932b8e01d2312b796b4ec/src/position/position.js +export class Positioning { + private getStyle(element: HTMLElement, prop: string): string { return window.getComputedStyle(element)[prop]; } + + private isStaticPositioned(element: HTMLElement): boolean { + return (this.getStyle(element, 'position') || 'static') === 'static'; + } + + private offsetParent(element: HTMLElement): HTMLElement { + let offsetParentEl = <HTMLElement>element.offsetParent || document.documentElement; + + while (offsetParentEl && offsetParentEl !== document.documentElement && this.isStaticPositioned(offsetParentEl)) { + offsetParentEl = <HTMLElement>offsetParentEl.offsetParent; + } + + return offsetParentEl || document.documentElement; + } + + public position(element: HTMLElement, round = true): ClientRect { + let elPosition: ClientRect; + let parentOffset: ClientRect = {width: 0, height: 0, top: 0, bottom: 0, left: 0, right: 0}; + + if (this.getStyle(element, 'position') === 'fixed') { + elPosition = element.getBoundingClientRect(); + } else { + const offsetParentEl = this.offsetParent(element); + + elPosition = this.offset(element, false); + + if (offsetParentEl !== document.documentElement) { + parentOffset = this.offset(offsetParentEl, false); + } + + parentOffset.top += offsetParentEl.clientTop; + parentOffset.left += offsetParentEl.clientLeft; + } + + elPosition.top -= parentOffset.top; + elPosition.bottom -= parentOffset.top; + elPosition.left -= parentOffset.left; + elPosition.right -= parentOffset.left; + + if (round) { + elPosition.top = Math.round(elPosition.top); + elPosition.bottom = Math.round(elPosition.bottom); + elPosition.left = Math.round(elPosition.left); + elPosition.right = Math.round(elPosition.right); + } + + return elPosition; + } + + public offset(element: HTMLElement, round = true): ClientRect { + const elBcr = element.getBoundingClientRect(); + const viewportOffset = { + top: window.pageYOffset - document.documentElement.clientTop, + left: window.pageXOffset - document.documentElement.clientLeft + }; + + let elOffset = { + height: elBcr.height || element.offsetHeight, + width: elBcr.width || element.offsetWidth, + top: elBcr.top + viewportOffset.top, + bottom: elBcr.bottom + viewportOffset.top, + left: elBcr.left + viewportOffset.left, + right: elBcr.right + viewportOffset.left + }; + + if (round) { + elOffset.height = Math.round(elOffset.height); + elOffset.width = Math.round(elOffset.width); + elOffset.top = Math.round(elOffset.top); + elOffset.bottom = Math.round(elOffset.bottom); + elOffset.left = Math.round(elOffset.left); + elOffset.right = Math.round(elOffset.right); + } + + return elOffset; + } + + public positionElements(hostElement: HTMLElement, targetElement: HTMLElement, placement: string, appendToBody?: boolean): + ClientRect { + const hostElPosition = appendToBody ? this.offset(hostElement, false) : this.position(hostElement, false); + const shiftWidth: any = { + left: hostElPosition.left, + left2: (hostElPosition.left - 85), + center: hostElPosition.left + hostElPosition.width / 2 - targetElement.offsetWidth / 2, + right: hostElPosition.left + hostElPosition.width + }; + const shiftHeight: any = { + top: hostElPosition.top, + center: hostElPosition.top + hostElPosition.height / 2 - targetElement.offsetHeight / 2, + bottom: hostElPosition.top + hostElPosition.height + }; + const targetElBCR = targetElement.getBoundingClientRect(); + const placementPrimary = placement.split('-')[0] || 'top'; + const placementSecondary = placement.split('-')[1] || 'center'; + + let targetElPosition: ClientRect = { + height: targetElBCR.height || targetElement.offsetHeight, + width: targetElBCR.width || targetElement.offsetWidth, + top: 0, + bottom: targetElBCR.height || targetElement.offsetHeight, + left: 0, + right: targetElBCR.width || targetElement.offsetWidth + }; + + switch (placementPrimary) { + case 'top': + targetElPosition.top = hostElPosition.top - targetElement.offsetHeight; + targetElPosition.bottom += hostElPosition.top - targetElement.offsetHeight; + targetElPosition.left = shiftWidth[placementSecondary]; + targetElPosition.right += shiftWidth[placementSecondary]; + break; + case 'bottom': + targetElPosition.top = shiftHeight[placementPrimary]; + targetElPosition.bottom += shiftHeight[placementPrimary]; + targetElPosition.left = shiftWidth[placementSecondary]; + targetElPosition.right += shiftWidth[placementSecondary]; + break; + case 'left': + targetElPosition.top = shiftHeight[placementSecondary]; + targetElPosition.bottom += shiftHeight[placementSecondary]; + targetElPosition.left = hostElPosition.left - targetElement.offsetWidth; + targetElPosition.right += hostElPosition.left - targetElement.offsetWidth; + break; + case 'right': + targetElPosition.top = shiftHeight[placementSecondary]; + targetElPosition.bottom += shiftHeight[placementSecondary]; + targetElPosition.left = shiftWidth[placementPrimary]; + targetElPosition.right += shiftWidth[placementPrimary]; + break; + + } + + targetElPosition.top = Math.round(targetElPosition.top); + targetElPosition.bottom = Math.round(targetElPosition.bottom); + targetElPosition.left = Math.round(targetElPosition.left); + targetElPosition.right = Math.round(targetElPosition.right); + + return targetElPosition; + } +} + +const positionService = new Positioning(); +export function positionElements( + hostElement: HTMLElement, targetElement: HTMLElement, placement: string, appendToBody?: boolean): void { + const pos = positionService.positionElements(hostElement, targetElement, placement, appendToBody); + + targetElement.style.top = `${pos.top}px`; + targetElement.style.left = `${pos.left}px`; +} diff --git a/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/triggers.ts b/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/triggers.ts new file mode 100644 index 00000000..8197de5b --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/triggers.ts @@ -0,0 +1,62 @@ +export class Trigger { + constructor(public open: string, public close?: string) { + if (!close) { + this.close = open; + } + } + + public isManual() { return this.open === 'manual' || this.close === 'manual'; } +} + +const DEFAULT_ALIASES = { + hover: ['mouseenter', 'mouseleave'] +}; + +export function parseTriggers(triggers: string, aliases = DEFAULT_ALIASES): Trigger[] { + const trimmedTriggers = (triggers || '').trim(); + + if (trimmedTriggers.length === 0) { + return []; + } + + const parsedTriggers = trimmedTriggers.split(/\s+/).map(trigger => trigger.split(':')).map((triggerPair) => { + let alias = aliases[triggerPair[0]] || triggerPair; + return new Trigger(alias[0], alias[1]); + }); + + const manualTriggers = parsedTriggers.filter(triggerPair => triggerPair.isManual()); + + if (manualTriggers.length > 1) { + throw 'Triggers parse error: only one manual trigger is allowed'; + } + + if (manualTriggers.length === 1 && parsedTriggers.length > 1) { + throw 'Triggers parse error: manual trigger can\'t be mixed with other triggers'; + } + + return parsedTriggers; +} + +const noopFn = () => { + // TO DO +}; + +export function listenToTriggers(renderer: any, nativeElement: any, triggers: string, openFn, closeFn, toggleFn) { + const parsedTriggers = parseTriggers(triggers); + const listeners = []; + + if (parsedTriggers.length === 1 && parsedTriggers[0].isManual()) { + return noopFn; + } + + parsedTriggers.forEach((trigger: Trigger) => { + if (trigger.open === trigger.close) { + listeners.push(renderer.listen(nativeElement, trigger.open, toggleFn)); + } else { + listeners.push( + renderer.listen(nativeElement, trigger.open, openFn), renderer.listen(nativeElement, trigger.close, closeFn)); + } + }); + + return () => { listeners.forEach(unsubscribeFn => unsubscribeFn()); }; +} diff --git a/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/util.ts b/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/util.ts new file mode 100644 index 00000000..fcabe960 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/paletx/plx-datepicker/util/util.ts @@ -0,0 +1,39 @@ +export function toInteger(value: any): number { + return parseInt(`${value}`, 10); +} + +export function toString(value: any): string { + return (value !== undefined && value !== null) ? `${value}` : ''; +} + +export function getValueInRange(value: number, max: number, min = 0): number { + return Math.max(Math.min(value, max), min); +} + +export function isString(value: any): boolean { + return typeof value === 'string'; +} + +export function isNumber(value: any): boolean { + return !isNaN(toInteger(value)); +} + +export function isInteger(value: any): boolean { + return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; +} + +export function isDefined(value: any): boolean { + return value !== undefined && value !== null; +} + +export function padNumber(value: number) { + if (isNumber(value)) { + return value > 9? `${value}`.slice(-2):'0' + `${value}`.slice(-2); + } else { + return ''; + } +} + +export function regExpEscape(text) { + return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); +} |