UNPKG

positioning

Version:

The ng-bootstrap Positioning class as a standalone module

215 lines 10.1 kB
// previous version: // https://github.com/angular-ui/bootstrap/blob/07c31d0731f7cb068a1932b8e01d2312b796b4ec/src/position/position.js var Positioning = /** @class */ (function () { function Positioning() { } Positioning.prototype.getAllStyles = function (element) { return window.getComputedStyle(element); }; Positioning.prototype.getStyle = function (element, prop) { return this.getAllStyles(element)[prop]; }; Positioning.prototype.isStaticPositioned = function (element) { return (this.getStyle(element, 'position') || 'static') === 'static'; }; Positioning.prototype.offsetParent = function (element) { var offsetParentEl = element.offsetParent || document.documentElement; while (offsetParentEl && offsetParentEl !== document.documentElement && this.isStaticPositioned(offsetParentEl)) { offsetParentEl = offsetParentEl.offsetParent; } return offsetParentEl || document.documentElement; }; Positioning.prototype.position = function (element, round) { if (round === void 0) { round = true; } var elPosition; var parentOffset = { width: 0, height: 0, top: 0, bottom: 0, left: 0, right: 0 }; if (this.getStyle(element, 'position') === 'fixed') { elPosition = element.getBoundingClientRect(); elPosition = { top: elPosition.top, bottom: elPosition.bottom, left: elPosition.left, right: elPosition.right, height: elPosition.height, width: elPosition.width }; } else { var 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; }; Positioning.prototype.offset = function (element, round) { if (round === void 0) { round = true; } var elBcr = element.getBoundingClientRect(); var viewportOffset = { top: window.pageYOffset - document.documentElement.clientTop, left: window.pageXOffset - document.documentElement.clientLeft }; var 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; }; /* Return false if the element to position is outside the viewport */ Positioning.prototype.positionElements = function (hostElement, targetElement, placement, appendToBody) { var _a = placement.split('-'), _b = _a[0], placementPrimary = _b === void 0 ? 'top' : _b, _c = _a[1], placementSecondary = _c === void 0 ? 'center' : _c; var hostElPosition = appendToBody ? this.offset(hostElement, false) : this.position(hostElement, false); var targetElStyles = this.getAllStyles(targetElement); var marginTop = parseFloat(targetElStyles.marginTop); var marginBottom = parseFloat(targetElStyles.marginBottom); var marginLeft = parseFloat(targetElStyles.marginLeft); var marginRight = parseFloat(targetElStyles.marginRight); var topPosition = 0; var leftPosition = 0; switch (placementPrimary) { case 'top': topPosition = (hostElPosition.top - (targetElement.offsetHeight + marginTop + marginBottom)); break; case 'bottom': topPosition = (hostElPosition.top + hostElPosition.height); break; case 'left': leftPosition = (hostElPosition.left - (targetElement.offsetWidth + marginLeft + marginRight)); break; case 'right': leftPosition = (hostElPosition.left + hostElPosition.width); break; } switch (placementSecondary) { case 'top': topPosition = hostElPosition.top; break; case 'bottom': topPosition = hostElPosition.top + hostElPosition.height - targetElement.offsetHeight; break; case 'left': leftPosition = hostElPosition.left; break; case 'right': leftPosition = hostElPosition.left + hostElPosition.width - targetElement.offsetWidth; break; case 'center': if (placementPrimary === 'top' || placementPrimary === 'bottom') { leftPosition = (hostElPosition.left + hostElPosition.width / 2 - targetElement.offsetWidth / 2); } else { topPosition = (hostElPosition.top + hostElPosition.height / 2 - targetElement.offsetHeight / 2); } break; } /// The translate3d/gpu acceleration render a blurry text on chrome, the next line is commented until a browser fix // targetElement.style.transform = `translate3d(${Math.round(leftPosition)}px, ${Math.floor(topPosition)}px, 0px)`; targetElement.style.transform = "translate(" + Math.round(leftPosition) + "px, " + Math.round(topPosition) + "px)"; // Check if the targetElement is inside the viewport var targetElBCR = targetElement.getBoundingClientRect(); var html = document.documentElement; var windowHeight = window.innerHeight || html.clientHeight; var windowWidth = window.innerWidth || html.clientWidth; return targetElBCR.left >= 0 && targetElBCR.top >= 0 && targetElBCR.right <= windowWidth && targetElBCR.bottom <= windowHeight; }; return Positioning; }()); export { Positioning }; var placementSeparator = /\s+/; var positionService = new Positioning(); /* * Accept the placement array and applies the appropriate placement dependent on the viewport. * Returns the applied placement. * In case of auto placement, placements are selected in order * 'top', 'bottom', 'left', 'right', * 'top-left', 'top-right', * 'bottom-left', 'bottom-right', * 'left-top', 'left-bottom', * 'right-top', 'right-bottom'. * */ export function positionElements(hostElement, targetElement, placement, appendToBody, baseClass) { var placementVals = Array.isArray(placement) ? placement : placement.split(placementSeparator); var allowedPlacements = [ 'top', 'bottom', 'left', 'right', 'top-left', 'top-right', 'bottom-left', 'bottom-right', 'left-top', 'left-bottom', 'right-top', 'right-bottom' ]; var classList = targetElement.classList; var addClassesToTarget = function (targetPlacement) { var _a = targetPlacement.split('-'), primary = _a[0], secondary = _a[1]; var classes = []; if (baseClass) { classes.push(baseClass + "-" + primary); if (secondary) { classes.push(baseClass + "-" + primary + "-" + secondary); } classes.forEach(function (classname) { classList.add(classname); }); } return classes; }; // Remove old placement classes to avoid issues if (baseClass) { allowedPlacements.forEach(function (placementToRemove) { classList.remove(baseClass + "-" + placementToRemove); }); } // replace auto placement with other placements var hasAuto = placementVals.findIndex(function (val) { return val === 'auto'; }); if (hasAuto >= 0) { allowedPlacements.forEach(function (obj) { if (placementVals.find(function (val) { return val.search('^' + obj) !== -1; }) == null) { placementVals.splice(hasAuto++, 1, obj); } }); } // coordinates where to position // Required for transform: var style = targetElement.style; style.position = 'absolute'; style.top = '0'; style.left = '0'; style['will-change'] = 'transform'; var testPlacement; var isInViewport = false; for (var _i = 0, placementVals_1 = placementVals; _i < placementVals_1.length; _i++) { testPlacement = placementVals_1[_i]; var addedClasses = addClassesToTarget(testPlacement); if (positionService.positionElements(hostElement, targetElement, testPlacement, appendToBody)) { isInViewport = true; break; } // Remove the baseClasses for further calculation if (baseClass) { addedClasses.forEach(function (classname) { classList.remove(classname); }); } } if (!isInViewport) { // If nothing match, the first placement is the default one testPlacement = placementVals[0]; addClassesToTarget(testPlacement); positionService.positionElements(hostElement, targetElement, testPlacement, appendToBody); } return testPlacement; } //# sourceMappingURL=positioning.js.map