UNPKG

ng2-encrm-components

Version:
153 lines (138 loc) 4.97 kB
import { KeyAttribute } from './common'; export class PositionService { /** * Provides read-only equivalent of jQuery's position function: * http://api.jquery.com/position/ */ public position(nativeEl: HTMLElement): {width: number, height: number, top: number, left: number} { let elBCR = this.offset(nativeEl); let offsetParentBCR = {top: 0, left: 0}; let offsetParentEl = this.parentOffsetEl(nativeEl); if (offsetParentEl !== this.document as any) { offsetParentBCR = this.offset(offsetParentEl); offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; } let boundingClientRect = nativeEl.getBoundingClientRect(); return { width: boundingClientRect.width || nativeEl.offsetWidth, height: boundingClientRect.height || nativeEl.offsetHeight, top: elBCR.top - offsetParentBCR.top, left: elBCR.left - offsetParentBCR.left }; } /** * Provides read-only equivalent of jQuery's offset function: * http://api.jquery.com/offset/ */ public offset(nativeEl: any): {width: number, height: number, top: number, left: number} { let boundingClientRect = nativeEl.getBoundingClientRect(); return { width: boundingClientRect.width || nativeEl.offsetWidth, height: boundingClientRect.height || nativeEl.offsetHeight, top: boundingClientRect.top + (this.window.pageYOffset || this.document.documentElement.scrollTop), left: boundingClientRect.left + (this.window.pageXOffset || this.document.documentElement.scrollLeft) }; } /** * Provides coordinates for the targetEl in relation to hostEl */ public positionElements(hostEl: HTMLElement, targetEl: HTMLElement, positionStr: string, appendToBody: boolean): {top: number, left: number} { let positionStrParts = positionStr.split('-'); let pos0 = positionStrParts[0]; let pos1 = positionStrParts[1] || 'center'; let hostElPos = appendToBody ? this.offset(hostEl) : this.position(hostEl); let targetElWidth = targetEl.offsetWidth; let targetElHeight = targetEl.offsetHeight; let shiftWidth: KeyAttribute = { center: function (): number { return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2; }, left: function (): number { return hostElPos.left; }, right: function (): number { return hostElPos.left + hostElPos.width; } }; let shiftHeight: KeyAttribute = { center: function (): number { return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2; }, top: function (): number { return hostElPos.top; }, bottom: function (): number { return hostElPos.top + hostElPos.height; } }; let targetElPos: {top: number, left: number}; switch (pos0) { case 'right': targetElPos = { top: shiftHeight[pos1](), left: shiftWidth[pos0]() }; break; case 'left': targetElPos = { top: shiftHeight[pos1](), left: hostElPos.left - targetElWidth }; break; case 'bottom': targetElPos = { top: shiftHeight[pos0](), left: shiftWidth[pos1]() }; break; default: targetElPos = { top: hostElPos.top - targetElHeight, left: shiftWidth[pos1]() }; break; } return targetElPos; } private get window(): Window { return window; } private get document(): Document { return window.document; } private getStyle(nativeEl: HTMLElement, cssProp: string): string { // IE if ((nativeEl as any).currentStyle) { return (nativeEl as any).currentStyle[cssProp]; } if (this.window.getComputedStyle) { return (this.window.getComputedStyle(nativeEl) as KeyAttribute)[cssProp]; } // finally try and get inline style return (nativeEl.style as KeyAttribute)[cssProp]; } /** * Checks if a given element is statically positioned * @param nativeEl - raw DOM element */ private isStaticPositioned(nativeEl: HTMLElement): boolean { return (this.getStyle(nativeEl, 'position') || 'static' ) === 'static'; } /** * returns the closest, non-statically positioned parentOffset of a given * element * @param nativeEl */ private parentOffsetEl(nativeEl: HTMLElement): any { let offsetParent: any = nativeEl.offsetParent || this.document; while (offsetParent && offsetParent !== this.document && this.isStaticPositioned(offsetParent)) { offsetParent = offsetParent.offsetParent; } return offsetParent || this.document; }; } export const positionService: PositionService = new PositionService();