UNPKG

@syncfusion/ej2-popups

Version:

A package of Essential JS 2 popup components such as Dialog and Tooltip that is used to display information or messages in separate pop-ups.

461 lines (460 loc) 15.8 kB
/** * Collision module. */ import { calculatePosition } from './position'; import { isNullOrUndefined } from '@syncfusion/ej2-base'; var parentDocument; var targetContainer; /** * * @param {HTMLElement} element - specifies the element * @param {HTMLElement} viewPortElement - specifies the element * @param {CollisionCoordinates} axis - specifies the collision coordinates * @param {OffsetPosition} position - specifies the position * @returns {void} */ export function fit(element, viewPortElement, axis, position) { if (viewPortElement === void 0) { viewPortElement = null; } if (axis === void 0) { axis = { X: false, Y: false }; } if (!axis.Y && !axis.X) { return { left: 0, top: 0 }; } var elemData = element.getBoundingClientRect(); targetContainer = viewPortElement; parentDocument = element.ownerDocument; if (!position) { position = calculatePosition(element, 'left', 'top'); } if (axis.X) { var containerWidth = targetContainer ? getTargetContainerWidth() : getViewPortWidth(); var containerLeft = ContainerLeft(); var containerRight = ContainerRight(); var overLeft = containerLeft - position.left; var overRight = position.left + elemData.width - containerRight; if (elemData.width > containerWidth) { if (overLeft > 0 && overRight <= 0) { position.left = containerRight - elemData.width; } else if (overRight > 0 && overLeft <= 0) { position.left = containerLeft; } else { position.left = overLeft > overRight ? (containerRight - elemData.width) : containerLeft; } } else if (overLeft > 0) { position.left += overLeft; } else if (overRight > 0) { position.left -= overRight; } } if (axis.Y) { var containerHeight = targetContainer ? getTargetContainerHeight() : getViewPortHeight(); var containerTop = ContainerTop(); var containerBottom = ContainerBottom(); var overTop = containerTop - position.top; var overBottom = position.top + elemData.height - containerBottom; if (elemData.height > containerHeight) { if (overTop > 0 && overBottom <= 0) { position.top = containerBottom - elemData.height; } else if (overBottom > 0 && overTop <= 0) { position.top = containerTop; } else { position.top = overTop > overBottom ? (containerBottom - elemData.height) : containerTop; } } else if (overTop > 0) { position.top += overTop; } else if (overBottom > 0) { position.top -= overBottom; } } return position; } /** * * @param {HTMLElement} element - specifies the html element * @param {HTMLElement} viewPortElement - specifies the html element * @param {number} x - specifies the number * @param {number} y - specifies the number * @returns {string[]} - returns the string value */ export function isCollide(element, viewPortElement, x, y) { if (viewPortElement === void 0) { viewPortElement = null; } var elemOffset = calculatePosition(element, 'left', 'top'); if (x) { elemOffset.left = x; } if (y) { elemOffset.top = y; } var data = []; targetContainer = viewPortElement; parentDocument = element.ownerDocument; var elementRect = element.getBoundingClientRect(); var top = elemOffset.top; var left = elemOffset.left; var right = elemOffset.left + elementRect.width; var bottom = elemOffset.top + elementRect.height; var yAxis = topCollideCheck(top, bottom); var xAxis = leftCollideCheck(left, right); if (yAxis.topSide) { data.push('top'); } if (xAxis.rightSide) { data.push('right'); } if (xAxis.leftSide) { data.push('left'); } if (yAxis.bottomSide) { data.push('bottom'); } return data; } /** * * @param {HTMLElement} element - specifies the element * @param {HTMLElement} target - specifies the element * @param {number} offsetX - specifies the number * @param {number} offsetY - specifies the number * @param {string} positionX - specifies the string value * @param {string} positionY - specifies the string value * @param {HTMLElement} viewPortElement - specifies the element * @param {CollisionCoordinates} axis - specifies the collision axis * @param {boolean} fixedParent - specifies the boolean * @returns {void} */ export function flip(element, target, offsetX, offsetY, positionX, positionY, viewPortElement, /* eslint-disable */ axis, fixedParent) { if (viewPortElement === void 0) { viewPortElement = null; } if (axis === void 0) { axis = { X: true, Y: true }; } if (!target || !element || !positionX || !positionY || (!axis.X && !axis.Y)) { return; } var tEdge = { TL: null, TR: null, BL: null, BR: null }, eEdge = { TL: null, TR: null, BL: null, BR: null /* eslint-enable */ }; var elementRect; if (window.getComputedStyle(element).display === 'none') { var oldVisibility = element.style.visibility; element.style.visibility = 'hidden'; element.style.display = 'block'; elementRect = element.getBoundingClientRect(); element.style.removeProperty('display'); element.style.visibility = oldVisibility; } else { elementRect = element.getBoundingClientRect(); } var pos = { posX: positionX, posY: positionY, offsetX: offsetX, offsetY: offsetY, position: { left: 0, top: 0 } }; targetContainer = viewPortElement; parentDocument = target.ownerDocument; updateElementData(target, tEdge, pos, fixedParent, elementRect); setPosition(eEdge, pos, elementRect); if (axis.X) { leftFlip(target, eEdge, tEdge, pos, elementRect, true); } if (axis.Y && tEdge.TL.top > -1) { topFlip(target, eEdge, tEdge, pos, elementRect, true); } setPopup(element, pos, elementRect); } /** * * @param {HTMLElement} element - specifies the element * @param {PositionLocation} pos - specifies the location * @param {ClientRect} elementRect - specifies the client rect * @returns {void} */ function setPopup(element, pos, elementRect) { var left = 0; var top = 0; if (element.offsetParent != null && (getComputedStyle(element.offsetParent).position === 'absolute' || getComputedStyle(element.offsetParent).position === 'relative')) { var data = calculatePosition(element.offsetParent, 'left', 'top', false, elementRect); left = data.left; top = data.top; } var scaleX = 1; var scaleY = 1; var tranformElement = getTransformElement(element); if (tranformElement) { var transformStyle = getComputedStyle(tranformElement).transform; if (transformStyle !== 'none') { var matrix = new DOMMatrix(transformStyle); scaleX = matrix.a; scaleY = matrix.d; } var zoomStyle = getComputedStyle(tranformElement).zoom; if (zoomStyle !== 'none') { var bodyZoom = getZoomValue(document.body); scaleX = bodyZoom * scaleX; scaleY = bodyZoom * scaleY; } } element.style.top = ((pos.position.top / scaleY) + pos.offsetY - (top / scaleY)) + 'px'; element.style.left = ((pos.position.left / scaleX) + pos.offsetX - (left / scaleX)) + 'px'; } export function getZoomValue(element) { var zoomValue = getComputedStyle(element).zoom; return parseFloat(zoomValue) || 1; // Default zoom value is 1 (no zoom) } /** * * @param {HTMLElement} element - specifies the element * @returns {HTMLElement} The modified element. */ export function getTransformElement(element) { while (element) { var transform = window.getComputedStyle(element).transform; var zoom = getZoomValue(document.body); if ((transform && transform !== 'none') || (zoom && zoom !== 1)) { return element; } if (element === document.body) { return null; } element = (element.offsetParent || element.parentElement); } return null; } /** * * @param {HTMLElement} target - specifies the element * @param {EdgeOffset} edge - specifies the offset * @param {PositionLocation} pos - specifies theloaction * @param {boolean} fixedParent - specifies the boolean * @param {ClientRect} elementRect - specifies the client rect * @returns {void} */ function updateElementData(target, edge, pos, fixedParent, elementRect) { pos.position = calculatePosition(target, pos.posX, pos.posY, fixedParent, elementRect); edge.TL = calculatePosition(target, 'left', 'top', fixedParent, elementRect); edge.TR = calculatePosition(target, 'right', 'top', fixedParent, elementRect); edge.BR = calculatePosition(target, 'left', 'bottom', fixedParent, elementRect); edge.BL = calculatePosition(target, 'right', 'bottom', fixedParent, elementRect); } /** * * @param {EdgeOffset} eStatus - specifies the status * @param {PositionLocation} pos - specifies the location * @param {ClientRect} elementRect - specifies the client * @returns {void} */ function setPosition(eStatus, pos, elementRect) { eStatus.TL = { top: pos.position.top + pos.offsetY, left: pos.position.left + pos.offsetX }; eStatus.TR = { top: eStatus.TL.top, left: eStatus.TL.left + elementRect.width }; eStatus.BL = { top: eStatus.TL.top + elementRect.height, left: eStatus.TL.left }; eStatus.BR = { top: eStatus.TL.top + elementRect.height, left: eStatus.TL.left + elementRect.width }; } /** * * @param {number} left - specifies the number * @param {number} right - specifies the number * @returns {LeftCorners} - returns the value */ function leftCollideCheck(left, right) { //eslint-disable-next-line var leftSide = false, rightSide = false; if (((left - getBodyScrollLeft()) < ContainerLeft())) { leftSide = true; } if (right > ContainerRight()) { rightSide = true; } return { leftSide: leftSide, rightSide: rightSide }; } /** * * @param {HTMLElement} target - specifies the element * @param {EdgeOffset} edge - specifes the element * @param {EdgeOffset} tEdge - specifies the edge offset * @param {PositionLocation} pos - specifes the location * @param {ClientRect} elementRect - specifies the client * @param {boolean} deepCheck - specifies the boolean value * @returns {void} */ function leftFlip(target, edge, tEdge, pos, elementRect, deepCheck) { var collideSide = leftCollideCheck(edge.TL.left, edge.TR.left); if ((tEdge.TL.left - getBodyScrollLeft()) <= ContainerLeft()) { collideSide.leftSide = false; } if (tEdge.TR.left > ContainerRight()) { collideSide.rightSide = false; } if ((collideSide.leftSide && !collideSide.rightSide) || (!collideSide.leftSide && collideSide.rightSide)) { if (pos.posX === 'right') { pos.posX = 'left'; } else { pos.posX = 'right'; } pos.offsetX = pos.offsetX + elementRect.width; pos.offsetX = -1 * pos.offsetX; pos.position = calculatePosition(target, pos.posX, pos.posY, false); setPosition(edge, pos, elementRect); if (deepCheck) { leftFlip(target, edge, tEdge, pos, elementRect, false); } } } /** * * @param {HTMLElement} target - specifies the element * @param {EdgeOffset} edge - specifies the offset * @param {EdgeOffset} tEdge - specifies the offset * @param {PositionLocation} pos - specifies the location * @param {ClientRect} elementRect - specifies the client rect * @param {boolean} deepCheck - specifies the boolean * @returns {void} */ function topFlip(target, edge, tEdge, pos, elementRect, deepCheck) { var collideSide = topCollideCheck(edge.TL.top, edge.BL.top); if ((tEdge.TL.top - getBodyScrollTop()) <= ContainerTop()) { collideSide.topSide = false; } if (tEdge.BL.top >= ContainerBottom() && target.getBoundingClientRect().bottom < window.innerHeight) { collideSide.bottomSide = false; } if ((collideSide.topSide && !collideSide.bottomSide) || (!collideSide.topSide && collideSide.bottomSide)) { if (pos.posY === 'top') { pos.posY = 'bottom'; } else { pos.posY = 'top'; } pos.offsetY = pos.offsetY + elementRect.height; pos.offsetY = -1 * pos.offsetY; pos.position = calculatePosition(target, pos.posX, pos.posY, false, elementRect); setPosition(edge, pos, elementRect); if (deepCheck) { topFlip(target, edge, tEdge, pos, elementRect, false); } } } /** * * @param {number} top - specifies the number * @param {number} bottom - specifies the number * @returns {TopCorners} - retyrns the value */ function topCollideCheck(top, bottom) { //eslint-disable-next-line var topSide = false, bottomSide = false; if ((top - getBodyScrollTop()) < ContainerTop()) { topSide = true; } if (bottom > ContainerBottom()) { bottomSide = true; } return { topSide: topSide, bottomSide: bottomSide }; } /** * @returns {void} */ function getTargetContainerWidth() { return targetContainer.getBoundingClientRect().width; } /** * @returns {void} */ function getTargetContainerHeight() { return targetContainer.getBoundingClientRect().height; } /** * @returns {void} */ function getTargetContainerLeft() { return targetContainer.getBoundingClientRect().left; } /** * @returns {void} */ function getTargetContainerTop() { return targetContainer.getBoundingClientRect().top; } //eslint-disable-next-line function ContainerTop() { if (targetContainer) { return getTargetContainerTop(); } return 0; } //eslint-disable-next-line function ContainerLeft() { if (targetContainer) { return getTargetContainerLeft(); } return 0; } //eslint-disable-next-line function ContainerRight() { if (targetContainer) { return (getBodyScrollLeft() + getTargetContainerLeft() + getTargetContainerWidth()); } return (getBodyScrollLeft() + getViewPortWidth()); } //eslint-disable-next-line function ContainerBottom() { if (targetContainer) { return (getBodyScrollTop() + getTargetContainerTop() + getTargetContainerHeight()); } return (getBodyScrollTop() + getViewPortHeight()); } /** * @returns {number} - returns the scroll top value */ function getBodyScrollTop() { // if(targetContainer) // return targetContainer.scrollTop; return parentDocument.documentElement.scrollTop || parentDocument.body.scrollTop; } /** * @returns {number} - returns the scroll left value */ function getBodyScrollLeft() { // if(targetContainer) // return targetContainer.scrollLeft; return parentDocument.documentElement.scrollLeft || parentDocument.body.scrollLeft; } /** * @returns {number} - returns the viewport height */ function getViewPortHeight() { return window.innerHeight; } /** * @returns {number} - returns the viewport width */ function getViewPortWidth() { var windowWidth = window.innerWidth; var documentReact = document.documentElement.getBoundingClientRect(); var offsetWidth = (isNullOrUndefined(document.documentElement)) ? 0 : documentReact.width; return windowWidth - (windowWidth - offsetWidth); } /** * @returns {void} */ export function destroy() { targetContainer = null; parentDocument = null; }