ng2-encrm-components
Version:
153 lines (138 loc) • 4.97 kB
text/typescript
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();