UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

328 lines (325 loc) • 14.3 kB
/** * DevExtreme (esm/__internal/core/utils/m_size.js) * Version: 24.2.6 * Build date: Mon Mar 17 2025 * * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import domAdapter from "../../../core/dom_adapter"; import { isNumeric, isRenderer, isString, isWindow } from "../../../core/utils/type"; import { getWindow } from "../../../core/utils/window"; const window = getWindow(); const SPECIAL_HEIGHT_VALUES = ["auto", "none", "inherit", "initial"]; const getSizeByStyles = function(elementStyles, styles) { let result = 0; styles.forEach((function(style) { result += parseFloat(elementStyles[style]) || 0 })); return result }; export const getElementBoxParams = function(name, elementStyles) { const beforeName = "width" === name ? "Left" : "Top"; const afterName = "width" === name ? "Right" : "Bottom"; return { padding: getSizeByStyles(elementStyles, [`padding${beforeName}`, `padding${afterName}`]), border: getSizeByStyles(elementStyles, [`border${beforeName}Width`, `border${afterName}Width`]), margin: getSizeByStyles(elementStyles, [`margin${beforeName}`, `margin${afterName}`]) } }; const getElementComputedStyle = function(element) { var _element$ownerDocumen; const view = (null === element || void 0 === element || null === (_element$ownerDocumen = element.ownerDocument) || void 0 === _element$ownerDocumen ? void 0 : _element$ownerDocumen.defaultView) || window; return view.getComputedStyle && view.getComputedStyle(element) }; const getCSSProperty = function(element, styles, name, defaultValue) { var _element$style; return (null === styles || void 0 === styles ? void 0 : styles[name]) || (null === (_element$style = element.style) || void 0 === _element$style ? void 0 : _element$style[name]) || defaultValue }; const boxIndices = { content: 0, padding: 1, border: 2, margin: 3, "content-box": 0, "border-box": 2 }; const dimensionComponents = { width: ["left", "right"], height: ["top", "bottom"] }; function getComponentThickness(elem, dimension, component, styles) { const get = (elem, styles, field) => parseFloat(getCSSProperty(elem, styles, field, "0")) || 0; const suffix = "border" === component ? "-width" : ""; return get(elem, styles, `${component}-${dimensionComponents[dimension][0]}${suffix}`) + get(elem, styles, `${component}-${dimensionComponents[dimension][1]}${suffix}`) } export const getSize = function(element, dimension, box) { const offsetFieldName = "width" === dimension ? "offsetWidth" : "offsetHeight"; const styles = getElementComputedStyle(element); let result = getCSSProperty(element, styles, dimension); if ("" === result || "auto" === result) { result = element[offsetFieldName] } result = parseFloat(result) || 0; const currentBox = getCSSProperty(element, styles, "boxSizing", "content-box"); const targetBox = box || currentBox; let targetBoxIndex = boxIndices[targetBox]; let currentBoxIndex = boxIndices[currentBox]; if (void 0 === targetBoxIndex || void 0 === currentBoxIndex) { throw new Error } if (currentBoxIndex === targetBoxIndex) { return result } const coeff = Math.sign(targetBoxIndex - currentBoxIndex); let padding = false; let border = false; let margin = false; let scrollThickness = false; if (1 === coeff) { targetBoxIndex += 1; currentBoxIndex += 1 } for (let boxPart = currentBoxIndex; boxPart !== targetBoxIndex; boxPart += coeff) { switch (boxPart) { case boxIndices.content: break; case boxIndices.padding: padding = coeff * getComponentThickness(element, dimension, "padding", styles); break; case boxIndices.border: border = coeff * getComponentThickness(element, dimension, "border", styles); break; case boxIndices.margin: margin = coeff * getComponentThickness(element, dimension, "margin", styles) } } if (padding || border) { const paddingAndBorder = (false === padding ? coeff * getComponentThickness(element, dimension, "padding", styles) : padding) + (false === border ? coeff * getComponentThickness(element, dimension, "border", styles) : border); scrollThickness = coeff * Math.max(0, Math.floor(element[offsetFieldName] - result - coeff * paddingAndBorder)) || 0 } return result + margin + padding + border + scrollThickness }; const getContainerHeight = function(container) { return isWindow(container) ? container.innerHeight : container.offsetHeight }; export const parseHeight = function(value, container, element) { if (value.indexOf("px") > 0) { value = parseInt(value.replace("px", "")) } else if (value.indexOf("%") > 0) { value = parseInt(value.replace("%", "")) * getContainerHeight(container) / 100 } else if (!isNaN(value)) { value = parseInt(value) } else if (value.indexOf("vh") > 0) { value = window.innerHeight / 100 * parseInt(value.replace("vh", "")) } else if (element && value.indexOf("em") > 0) { value = parseFloat(value.replace("em", "")) * parseFloat(window.getComputedStyle(element).fontSize) } return value }; const getHeightWithOffset = function(value, offset, container) { if (!value) { return null } if (SPECIAL_HEIGHT_VALUES.includes(value)) { return offset ? null : value } if (isString(value)) { value = parseHeight(value, container) } if (isNumeric(value)) { return Math.max(0, value + offset) } const operationString = offset < 0 ? " - " : " "; return `calc(${value}${operationString}${Math.abs(offset)}px)` }; export const addOffsetToMaxHeight = function(value, offset, container) { const maxHeight = getHeightWithOffset(value, offset, container); return null !== maxHeight ? maxHeight : "none" }; export const addOffsetToMinHeight = function(value, offset, container) { const minHeight = getHeightWithOffset(value, offset, container); return null !== minHeight ? minHeight : 0 }; export const getVerticalOffsets = function(element, withMargins) { if (!element) { return 0 } const boxParams = getElementBoxParams("height", window.getComputedStyle(element)); return boxParams.padding + boxParams.border + (withMargins ? boxParams.margin : 0) }; export const getVisibleHeight = function(element) { if (element) { var _element$getBoundingC; const boundingClientRect = null === (_element$getBoundingC = element.getBoundingClientRect) || void 0 === _element$getBoundingC ? void 0 : _element$getBoundingC.call(element); if (null !== boundingClientRect && void 0 !== boundingClientRect && boundingClientRect.height) { return boundingClientRect.height } } return 0 }; export const implementationsMap = { getWidth: function() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key] } return elementSizeHelper("width", ...args) }, setWidth: function() { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2] } return elementSizeHelper("width", ...args) }, getHeight: function() { for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3] } return elementSizeHelper("height", ...args) }, setHeight: function() { for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4] } return elementSizeHelper("height", ...args) }, getOuterWidth: function() { for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { args[_key5] = arguments[_key5] } return elementSizeHelper("outerWidth", ...args) }, setOuterWidth: function() { for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { args[_key6] = arguments[_key6] } return elementSizeHelper("outerWidth", ...args) }, getOuterHeight: function() { for (var _len7 = arguments.length, args = new Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { args[_key7] = arguments[_key7] } return elementSizeHelper("outerHeight", ...args) }, setOuterHeight: function() { for (var _len8 = arguments.length, args = new Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { args[_key8] = arguments[_key8] } return elementSizeHelper("outerHeight", ...args) }, getInnerWidth: function() { for (var _len9 = arguments.length, args = new Array(_len9), _key9 = 0; _key9 < _len9; _key9++) { args[_key9] = arguments[_key9] } return elementSizeHelper("innerWidth", ...args) }, setInnerWidth: function() { for (var _len10 = arguments.length, args = new Array(_len10), _key10 = 0; _key10 < _len10; _key10++) { args[_key10] = arguments[_key10] } return elementSizeHelper("innerWidth", ...args) }, getInnerHeight: function() { for (var _len11 = arguments.length, args = new Array(_len11), _key11 = 0; _key11 < _len11; _key11++) { args[_key11] = arguments[_key11] } return elementSizeHelper("innerHeight", ...args) }, setInnerHeight: function() { for (var _len12 = arguments.length, args = new Array(_len12), _key12 = 0; _key12 < _len12; _key12++) { args[_key12] = arguments[_key12] } return elementSizeHelper("innerHeight", ...args) } }; function elementSizeHelper(sizeProperty, el, value) { return 2 === arguments.length ? elementSize(el, sizeProperty) : elementSize(el, sizeProperty, value) } export const getWidth = el => implementationsMap.getWidth(el); export const setWidth = (el, value) => implementationsMap.setWidth(el, value); export const getHeight = el => implementationsMap.getHeight(el); export const setHeight = (el, value) => implementationsMap.setHeight(el, value); export const getOuterWidth = (el, includeMargin) => implementationsMap.getOuterWidth(el, includeMargin || false); export const setOuterWidth = (el, value) => implementationsMap.setOuterWidth(el, value); export const getOuterHeight = (el, includeMargin) => implementationsMap.getOuterHeight(el, includeMargin || false); export const setOuterHeight = (el, value) => implementationsMap.setOuterHeight(el, value); export const getInnerWidth = el => implementationsMap.getInnerWidth(el); export const setInnerWidth = (el, value) => implementationsMap.setInnerWidth(el, value); export const getInnerHeight = el => implementationsMap.getInnerHeight(el); export const setInnerHeight = (el, value) => implementationsMap.setInnerHeight(el, value); const elementSize = function(el, sizeProperty, value) { const partialName = sizeProperty.toLowerCase().indexOf("width") >= 0 ? "Width" : "Height"; const propName = partialName.toLowerCase(); const isOuter = 0 === sizeProperty.indexOf("outer"); const isInner = 0 === sizeProperty.indexOf("inner"); const isGetter = 2 === arguments.length || "boolean" === typeof value; if (isRenderer(el)) { if (el.length > 1 && !isGetter) { for (let i = 0; i < el.length; i++) { elementSize(el[i], sizeProperty, value) } return } el = el[0] } if (!el) { return } if (isWindow(el)) { return isOuter ? el[`inner${partialName}`] : domAdapter.getDocumentElement()[`client${partialName}`] } if (domAdapter.isDocument(el)) { const documentElement = domAdapter.getDocumentElement(); const body = domAdapter.getBody(); return Math.max(body[`scroll${partialName}`], body[`offset${partialName}`], documentElement[`scroll${partialName}`], documentElement[`offset${partialName}`], documentElement[`client${partialName}`]) } if (isGetter) { let box = "content"; if (isOuter) { box = value ? "margin" : "border" } if (isInner) { box = "padding" } return getSize(el, propName, box) } if (isNumeric(value)) { const elementStyles = getElementComputedStyle(el); const sizeAdjustment = getElementBoxParams(propName, elementStyles); const isBorderBox = "border-box" === elementStyles.boxSizing; value = Number(value); if (isOuter) { value -= isBorderBox ? 0 : sizeAdjustment.border + sizeAdjustment.padding } else if (isInner) { value += isBorderBox ? sizeAdjustment.border : -sizeAdjustment.padding } else if (isBorderBox) { value += sizeAdjustment.border + sizeAdjustment.padding } } value += isNumeric(value) ? "px" : ""; domAdapter.setStyle(el, propName, value); return null }; export const getWindowByElement = el => isWindow(el) ? el : el.defaultView; export const getOffset = el => { if (!el.getClientRects().length) { return { top: 0, left: 0 } } const rect = el.getBoundingClientRect(); const win = getWindowByElement(el.ownerDocument); const docElem = el.ownerDocument.documentElement; return { top: rect.top + win.pageYOffset - docElem.clientTop, left: rect.left + win.pageXOffset - docElem.clientLeft } };