From 3ea39841c8049525e31e9f4d6300f0c60cdb42de Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Tue, 24 Jan 2023 13:33:51 +0100 Subject: Adding upstream version 5.2.3+dfsg. Signed-off-by: Daniel Baumann --- js/src/util/scrollbar.js | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 js/src/util/scrollbar.js (limited to 'js/src/util/scrollbar.js') diff --git a/js/src/util/scrollbar.js b/js/src/util/scrollbar.js new file mode 100644 index 0000000..5cac7b6 --- /dev/null +++ b/js/src/util/scrollbar.js @@ -0,0 +1,114 @@ +/** + * -------------------------------------------------------------------------- + * Bootstrap (v5.2.3): util/scrollBar.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + +import SelectorEngine from '../dom/selector-engine' +import Manipulator from '../dom/manipulator' +import { isElement } from './index' + +/** + * Constants + */ + +const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top' +const SELECTOR_STICKY_CONTENT = '.sticky-top' +const PROPERTY_PADDING = 'padding-right' +const PROPERTY_MARGIN = 'margin-right' + +/** + * Class definition + */ + +class ScrollBarHelper { + constructor() { + this._element = document.body + } + + // Public + getWidth() { + // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes + const documentWidth = document.documentElement.clientWidth + return Math.abs(window.innerWidth - documentWidth) + } + + hide() { + const width = this.getWidth() + this._disableOverFlow() + // give padding to element to balance the hidden scrollbar width + this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width) + // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth + this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width) + this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width) + } + + reset() { + this._resetElementAttributes(this._element, 'overflow') + this._resetElementAttributes(this._element, PROPERTY_PADDING) + this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING) + this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN) + } + + isOverflowing() { + return this.getWidth() > 0 + } + + // Private + _disableOverFlow() { + this._saveInitialAttribute(this._element, 'overflow') + this._element.style.overflow = 'hidden' + } + + _setElementAttributes(selector, styleProperty, callback) { + const scrollbarWidth = this.getWidth() + const manipulationCallBack = element => { + if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) { + return + } + + this._saveInitialAttribute(element, styleProperty) + const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty) + element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`) + } + + this._applyManipulationCallback(selector, manipulationCallBack) + } + + _saveInitialAttribute(element, styleProperty) { + const actualValue = element.style.getPropertyValue(styleProperty) + if (actualValue) { + Manipulator.setDataAttribute(element, styleProperty, actualValue) + } + } + + _resetElementAttributes(selector, styleProperty) { + const manipulationCallBack = element => { + const value = Manipulator.getDataAttribute(element, styleProperty) + // We only want to remove the property if the value is `null`; the value can also be zero + if (value === null) { + element.style.removeProperty(styleProperty) + return + } + + Manipulator.removeDataAttribute(element, styleProperty) + element.style.setProperty(styleProperty, value) + } + + this._applyManipulationCallback(selector, manipulationCallBack) + } + + _applyManipulationCallback(selector, callBack) { + if (isElement(selector)) { + callBack(selector) + return + } + + for (const sel of SelectorEngine.find(selector, this._element)) { + callBack(sel) + } + } +} + +export default ScrollBarHelper -- cgit v1.2.3