From 886b940796b3595a03b44230ca8b78197c5ee1c5 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Fri, 10 Dec 2021 18:18:18 +0200 Subject: Extract Component config functionality to a separate class (#33872) Co-authored-by: XhmikosR --- js/src/util/backdrop.js | 27 ++++++++++++------ js/src/util/config.js | 63 +++++++++++++++++++++++++++++++++++++++++ js/src/util/focustrap.js | 27 +++++++++++------- js/src/util/index.js | 16 +---------- js/src/util/swipe.js | 28 +++++++++++------- js/src/util/template-factory.js | 31 ++++++++++---------- 6 files changed, 130 insertions(+), 62 deletions(-) create mode 100644 js/src/util/config.js (limited to 'js/src/util') diff --git a/js/src/util/backdrop.js b/js/src/util/backdrop.js index fb1b2776bc..63f2b581c6 100644 --- a/js/src/util/backdrop.js +++ b/js/src/util/backdrop.js @@ -6,7 +6,8 @@ */ import EventHandler from '../dom/event-handler' -import { execute, executeAfterTransition, getElement, reflow, typeCheckConfig } from './index' +import { execute, executeAfterTransition, getElement, reflow } from './index' +import Config from './config' /** * Constants @@ -37,13 +38,27 @@ const DefaultType = { * Class definition */ -class Backdrop { +class Backdrop extends Config { constructor(config) { + super() this._config = this._getConfig(config) this._isAppended = false this._element = null } + // Getters + static get Default() { + return Default + } + + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + // Public show(callback) { if (!this._config.isVisible) { @@ -104,15 +119,9 @@ class Backdrop { return this._element } - _getConfig(config) { - config = { - ...Default, - ...(typeof config === 'object' ? config : {}) - } - + _configAfterMerge(config) { // use getElement() with the default "body" to get a fresh Element on each instantiation config.rootElement = getElement(config.rootElement) - typeCheckConfig(NAME, config, DefaultType) return config } diff --git a/js/src/util/config.js b/js/src/util/config.js new file mode 100644 index 0000000000..19d02955dd --- /dev/null +++ b/js/src/util/config.js @@ -0,0 +1,63 @@ +/** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): util/config.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + +import { isElement, toType } from './index' +import Manipulator from '../dom/manipulator' + +/** + * Class definition + */ + +class Config { + // Getters + static get Default() { + return {} + } + + static get DefaultType() { + return {} + } + + static get NAME() { + throw new Error('You have to implement the static method "NAME", for each component!') + } + + _getConfig(config) { + config = this._mergeConfigObj(config) + config = this._configAfterMerge(config) + this._typeCheckConfig(config) + return config + } + + _configAfterMerge(config) { + return config + } + + _mergeConfigObj(config, element) { + return { + ...this.constructor.Default, + ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}), + ...(typeof config === 'object' ? config : {}) + } + } + + _typeCheckConfig(config, configTypes = this.constructor.DefaultType) { + for (const property of Object.keys(configTypes)) { + const expectedTypes = configTypes[property] + const value = config[property] + const valueType = isElement(value) ? 'element' : toType(value) + + if (!new RegExp(expectedTypes).test(valueType)) { + throw new TypeError( + `${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".` + ) + } + } + } +} + +export default Config diff --git a/js/src/util/focustrap.js b/js/src/util/focustrap.js index a1975f4899..46727ecf8a 100644 --- a/js/src/util/focustrap.js +++ b/js/src/util/focustrap.js @@ -7,7 +7,7 @@ import EventHandler from '../dom/event-handler' import SelectorEngine from '../dom/selector-engine' -import { typeCheckConfig } from './index' +import Config from './config' /** * Constants @@ -37,13 +37,27 @@ const DefaultType = { * Class definition */ -class FocusTrap { +class FocusTrap extends Config { constructor(config) { + super() this._config = this._getConfig(config) this._isActive = false this._lastTabNavDirection = null } + // Getters + static get Default() { + return Default + } + + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + // Public activate() { const { trapElement, autofocus } = this._config @@ -99,15 +113,6 @@ class FocusTrap { this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD } - - _getConfig(config) { - config = { - ...Default, - ...(typeof config === 'object' ? config : {}) - } - typeCheckConfig(NAME, config, DefaultType) - return config - } } export default FocusTrap diff --git a/js/src/util/index.js b/js/src/util/index.js index 0407100d8b..8bd614d40c 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -123,20 +123,6 @@ const getElement = object => { return null } -const typeCheckConfig = (componentName, config, configTypes) => { - for (const property of Object.keys(configTypes)) { - const expectedTypes = configTypes[property] - const value = config[property] - const valueType = value && isElement(value) ? 'element' : toType(value) - - if (!new RegExp(expectedTypes).test(valueType)) { - throw new TypeError( - `${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".` - ) - } - } -} - const isVisible = element => { if (!isElement(element) || element.getClientRects().length === 0) { return false @@ -327,5 +313,5 @@ export { onDOMContentLoaded, reflow, triggerTransitionEnd, - typeCheckConfig + toType } diff --git a/js/src/util/swipe.js b/js/src/util/swipe.js index 87a5f7f5ae..ac09b6fa13 100644 --- a/js/src/util/swipe.js +++ b/js/src/util/swipe.js @@ -5,8 +5,9 @@ * -------------------------------------------------------------------------- */ +import Config from './config' import EventHandler from '../dom/event-handler' -import { execute, typeCheckConfig } from './index' +import { execute } from './index' /** * Constants @@ -40,8 +41,9 @@ const DefaultType = { * Class definition */ -class Swipe { +class Swipe extends Config { constructor(element, config) { + super() this._element = element if (!element || !Swipe.isSupported()) { @@ -54,6 +56,19 @@ class Swipe { this._initEvents() } + // Getters + static get Default() { + return Default + } + + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + // Public dispose() { EventHandler.off(this._element, EVENT_KEY) @@ -118,15 +133,6 @@ class Swipe { } } - _getConfig(config) { - config = { - ...Default, - ...(typeof config === 'object' ? config : {}) - } - typeCheckConfig(NAME, config, DefaultType) - return config - } - _eventIsPointerPenTouch(event) { return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH) } diff --git a/js/src/util/template-factory.js b/js/src/util/template-factory.js index a9cee1086c..8a8d4da798 100644 --- a/js/src/util/template-factory.js +++ b/js/src/util/template-factory.js @@ -6,8 +6,9 @@ */ import { DefaultAllowlist, sanitizeHtml } from './sanitizer' -import { getElement, isElement, typeCheckConfig } from '../util/index' +import { getElement, isElement } from '../util/index' import SelectorEngine from '../dom/selector-engine' +import Config from './config' /** * Constants @@ -44,20 +45,25 @@ const DefaultContentType = { * Class definition */ -class TemplateFactory { +class TemplateFactory extends Config { constructor(config) { + super() this._config = this._getConfig(config) } // Getters - static get NAME() { - return NAME - } - static get Default() { return Default } + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + // Public getContent() { return Object.values(this._config.content) @@ -94,21 +100,14 @@ class TemplateFactory { } // Private - _getConfig(config) { - config = { - ...Default, - ...(typeof config === 'object' ? config : {}) - } - - typeCheckConfig(NAME, config, DefaultType) + _typeCheckConfig(config) { + super._typeCheckConfig(config) this._checkContent(config.content) - - return config } _checkContent(arg) { for (const [selector, content] of Object.entries(arg)) { - typeCheckConfig(NAME, { selector, entry: content }, DefaultContentType) + super._typeCheckConfig({ selector, entry: content }, DefaultContentType) } } -- cgit v1.2.3