diff options
author | GeoSot <geo.sotis@gmail.com> | 2021-06-06 09:26:36 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-06 09:26:36 +0300 |
commit | cb47b8c9640abcc19c17908475153849b9d4ad60 (patch) | |
tree | 574ef4e05facb52e35d4a939e4d69d963106a43b /js/src | |
parent | 08139c2280d60e4904f2bb7c7477f05cc3d34b1a (diff) |
Refactor scrollbar.js to be used as a Class (#33947)
Diffstat (limited to 'js/src')
-rw-r--r-- | js/src/modal.js | 9 | ||||
-rw-r--r-- | js/src/offcanvas.js | 6 | ||||
-rw-r--r-- | js/src/util/scrollbar.js | 121 |
3 files changed, 75 insertions, 61 deletions
diff --git a/js/src/modal.js b/js/src/modal.js index 74b608303f..1d23b3d89d 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -16,7 +16,7 @@ import { import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' -import { getWidth as getScrollBarWidth, hide as scrollBarHide, reset as scrollBarReset } from './util/scrollbar' +import ScrollBarHelper from './util/scrollbar' import BaseComponent from './base-component' import Backdrop from './util/backdrop' @@ -83,6 +83,7 @@ class Modal extends BaseComponent { this._isShown = false this._ignoreBackdropClick = false this._isTransitioning = false + this._scrollBar = new ScrollBarHelper() } // Getters @@ -120,7 +121,7 @@ class Modal extends BaseComponent { this._isTransitioning = true } - scrollBarHide() + this._scrollBar.hide() document.body.classList.add(CLASS_NAME_OPEN) @@ -301,7 +302,7 @@ class Modal extends BaseComponent { this._backdrop.hide(() => { document.body.classList.remove(CLASS_NAME_OPEN) this._resetAdjustments() - scrollBarReset() + this._scrollBar.reset() EventHandler.trigger(this._element, EVENT_HIDDEN) }) } @@ -368,7 +369,7 @@ class Modal extends BaseComponent { _adjustDialog() { const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight - const scrollbarWidth = getScrollBarWidth() + const scrollbarWidth = this._scrollBar.getWidth() const isBodyOverflowing = scrollbarWidth > 0 if ((!isBodyOverflowing && isModalOverflowing && !isRTL()) || (isBodyOverflowing && !isModalOverflowing && isRTL())) { diff --git a/js/src/offcanvas.js b/js/src/offcanvas.js index f990ff1998..71e47668f6 100644 --- a/js/src/offcanvas.js +++ b/js/src/offcanvas.js @@ -12,7 +12,7 @@ import { isVisible, typeCheckConfig } from './util/index' -import { hide as scrollBarHide, reset as scrollBarReset } from './util/scrollbar' +import ScrollBarHelper from './util/scrollbar' import EventHandler from './dom/event-handler' import BaseComponent from './base-component' import SelectorEngine from './dom/selector-engine' @@ -108,7 +108,7 @@ class Offcanvas extends BaseComponent { this._backdrop.show() if (!this._config.scroll) { - scrollBarHide() + new ScrollBarHelper().hide() this._enforceFocusOnElement(this._element) } @@ -148,7 +148,7 @@ class Offcanvas extends BaseComponent { this._element.style.visibility = 'hidden' if (!this._config.scroll) { - scrollBarReset() + new ScrollBarHelper().reset() } EventHandler.trigger(this._element, EVENT_HIDDEN) diff --git a/js/src/util/scrollbar.js b/js/src/util/scrollbar.js index 79a3b12c78..e23415f1dc 100644 --- a/js/src/util/scrollbar.js +++ b/js/src/util/scrollbar.js @@ -7,78 +7,91 @@ import SelectorEngine from '../dom/selector-engine' import Manipulator from '../dom/manipulator' +import { isElement } from './index' const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top' const SELECTOR_STICKY_CONTENT = '.sticky-top' -const 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) -} +class ScrollBarHelper { + constructor() { + this._element = document.body + } -const hide = (width = getWidth()) => { - _disableOverFlow() - // give padding to element to balances the hidden scrollbar width - _setElementAttributes('body', 'paddingRight', calculatedValue => calculatedValue + width) - // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements, to keep shown fullwidth - _setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width) - _setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width) -} + 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) + } -const _disableOverFlow = () => { - const actualValue = document.body.style.overflow - if (actualValue) { - Manipulator.setDataAttribute(document.body, 'overflow', actualValue) + hide() { + const width = this.getWidth() + this._disableOverFlow() + // give padding to element to balance the hidden scrollbar width + this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width) + // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth + this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width) + this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width) } - document.body.style.overflow = 'hidden' -} + _disableOverFlow() { + this._saveInitialAttribute(this._element, 'overflow') + this._element.style.overflow = 'hidden' + } -const _setElementAttributes = (selector, styleProp, callback) => { - const scrollbarWidth = getWidth() - SelectorEngine.find(selector) - .forEach(element => { - if (element !== document.body && window.innerWidth > element.clientWidth + scrollbarWidth) { + _setElementAttributes(selector, styleProp, callback) { + const scrollbarWidth = this.getWidth() + const manipulationCallBack = element => { + if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) { return } - const actualValue = element.style[styleProp] - if (actualValue) { - Manipulator.setDataAttribute(element, styleProp, actualValue) - } - + this._saveInitialAttribute(element, styleProp) const calculatedValue = window.getComputedStyle(element)[styleProp] element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px` - }) -} + } -const reset = () => { - _resetElementAttributes('body', 'overflow') - _resetElementAttributes('body', 'paddingRight') - _resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight') - _resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight') -} + this._applyManipulationCallback(selector, manipulationCallBack) + } + + reset() { + this._resetElementAttributes(this._element, 'overflow') + this._resetElementAttributes(this._element, 'paddingRight') + this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight') + this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight') + } + + _saveInitialAttribute(element, styleProp) { + const actualValue = element.style[styleProp] + if (actualValue) { + Manipulator.setDataAttribute(element, styleProp, actualValue) + } + } + + _resetElementAttributes(selector, styleProp) { + const manipulationCallBack = element => { + const value = Manipulator.getDataAttribute(element, styleProp) + if (typeof value === 'undefined') { + element.style.removeProperty(styleProp) + } else { + Manipulator.removeDataAttribute(element, styleProp) + element.style[styleProp] = value + } + } -const _resetElementAttributes = (selector, styleProp) => { - SelectorEngine.find(selector).forEach(element => { - const value = Manipulator.getDataAttribute(element, styleProp) - if (typeof value === 'undefined') { - element.style.removeProperty(styleProp) + this._applyManipulationCallback(selector, manipulationCallBack) + } + + _applyManipulationCallback(selector, callBack) { + if (isElement(selector)) { + callBack(selector) } else { - Manipulator.removeDataAttribute(element, styleProp) - element.style[styleProp] = value + SelectorEngine.find(selector, this._element).forEach(callBack) } - }) -} + } -const isBodyOverflowing = () => { - return getWidth() > 0 + isOverflowing() { + return this.getWidth() > 0 + } } -export { - getWidth, - hide, - isBodyOverflowing, - reset -} +export default ScrollBarHelper |