0
0
mirror of https://github.com/twbs/bootstrap.git synced 2024-12-01 13:24:25 +01:00

Extract Component config functionality to a separate class (#33872)

Co-authored-by: XhmikosR <xhmikosr@gmail.com>
This commit is contained in:
GeoSot 2021-12-10 18:18:18 +02:00 committed by GitHub
parent 68f226750d
commit 886b940796
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 283 additions and 240 deletions

View File

@ -6,11 +6,9 @@
*/ */
import Data from './dom/data' import Data from './dom/data'
import { import { executeAfterTransition, getElement } from './util/index'
executeAfterTransition,
getElement
} from './util/index'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
import Config from './util/config'
/** /**
* Constants * Constants
@ -22,15 +20,18 @@ const VERSION = '5.1.3'
* Class definition * Class definition
*/ */
class BaseComponent { class BaseComponent extends Config {
constructor(element) { constructor(element, config) {
element = getElement(element) super()
element = getElement(element)
if (!element) { if (!element) {
return return
} }
this._element = element this._element = element
this._config = this._getConfig(config)
Data.set(this._element, this.constructor.DATA_KEY, this) Data.set(this._element, this.constructor.DATA_KEY, this)
} }
@ -48,6 +49,13 @@ class BaseComponent {
executeAfterTransition(callback, element, isAnimated) executeAfterTransition(callback, element, isAnimated)
} }
_getConfig(config) {
config = this._mergeConfigObj(config, this._element)
config = this._configAfterMerge(config)
this._typeCheckConfig(config)
return config
}
// Static // Static
static getInstance(element) { static getInstance(element) {
return Data.get(getElement(element), this.DATA_KEY) return Data.get(getElement(element), this.DATA_KEY)
@ -61,10 +69,6 @@ class BaseComponent {
return VERSION return VERSION
} }
static get NAME() {
throw new Error('You have to implement the static method "NAME" for each component!')
}
static get DATA_KEY() { static get DATA_KEY() {
return `bs.${this.NAME}` return `bs.${this.NAME}`
} }

View File

@ -12,8 +12,7 @@ import {
isRTL, isRTL,
isVisible, isVisible,
reflow, reflow,
triggerTransitionEnd, triggerTransitionEnd
typeCheckConfig
} from './util/index' } from './util/index'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator' import Manipulator from './dom/manipulator'
@ -95,7 +94,7 @@ const DefaultType = {
class Carousel extends BaseComponent { class Carousel extends BaseComponent {
constructor(element, config) { constructor(element, config) {
super(element) super(element, config)
this._items = null this._items = null
this._interval = null this._interval = null
@ -105,7 +104,6 @@ class Carousel extends BaseComponent {
this.touchTimeout = null this.touchTimeout = null
this._swipeHelper = null this._swipeHelper = null
this._config = this._getConfig(config)
this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element) this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)
this._addEventListeners() this._addEventListeners()
} }
@ -115,6 +113,10 @@ class Carousel extends BaseComponent {
return Default return Default
} }
static get DefaultType() {
return DefaultType
}
static get NAME() { static get NAME() {
return NAME return NAME
} }
@ -205,16 +207,6 @@ class Carousel extends BaseComponent {
} }
// Private // Private
_getConfig(config) {
config = {
...Default,
...Manipulator.getDataAttributes(this._element),
...(typeof config === 'object' ? config : {})
}
typeCheckConfig(NAME, config, DefaultType)
return config
}
_addEventListeners() { _addEventListeners() {
if (this._config.keyboard) { if (this._config.keyboard) {
EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event)) EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))

View File

@ -10,11 +10,9 @@ import {
getElement, getElement,
getElementFromSelector, getElementFromSelector,
getSelectorFromElement, getSelectorFromElement,
reflow, reflow
typeCheckConfig
} from './util/index' } from './util/index'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
import SelectorEngine from './dom/selector-engine' import SelectorEngine from './dom/selector-engine'
import BaseComponent from './base-component' import BaseComponent from './base-component'
@ -62,10 +60,9 @@ const DefaultType = {
class Collapse extends BaseComponent { class Collapse extends BaseComponent {
constructor(element, config) { constructor(element, config) {
super(element) super(element, config)
this._isTransitioning = false this._isTransitioning = false
this._config = this._getConfig(config)
this._triggerArray = [] this._triggerArray = []
const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE) const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)
@ -96,6 +93,10 @@ class Collapse extends BaseComponent {
return Default return Default
} }
static get DefaultType() {
return DefaultType
}
static get NAME() { static get NAME() {
return NAME return NAME
} }
@ -210,15 +211,9 @@ class Collapse extends BaseComponent {
} }
// Private // Private
_getConfig(config) { _configAfterMerge(config) {
config = {
...Default,
...Manipulator.getDataAttributes(this._element),
...config
}
config.toggle = Boolean(config.toggle) // Coerce string values config.toggle = Boolean(config.toggle) // Coerce string values
config.parent = getElement(config.parent) config.parent = getElement(config.parent)
typeCheckConfig(NAME, config, DefaultType)
return config return config
} }

View File

@ -15,8 +15,7 @@ import {
isElement, isElement,
isRTL, isRTL,
isVisible, isVisible,
noop, noop
typeCheckConfig
} from './util/index' } from './util/index'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator' import Manipulator from './dom/manipulator'
@ -88,10 +87,9 @@ const DefaultType = {
class Dropdown extends BaseComponent { class Dropdown extends BaseComponent {
constructor(element, config) { constructor(element, config) {
super(element) super(element, config)
this._popper = null this._popper = null
this._config = this._getConfig(config)
this._menu = this._getMenuElement() this._menu = this._getMenuElement()
this._inNavbar = this._detectNavbar() this._inNavbar = this._detectNavbar()
} }
@ -205,13 +203,7 @@ class Dropdown extends BaseComponent {
} }
_getConfig(config) { _getConfig(config) {
config = { config = super._getConfig(config)
...this.constructor.Default,
...Manipulator.getDataAttributes(this._element),
...config
}
typeCheckConfig(NAME, config, this.constructor.DefaultType)
if (typeof config.reference === 'object' && !isElement(config.reference) && if (typeof config.reference === 'object' && !isElement(config.reference) &&
typeof config.reference.getBoundingClientRect !== 'function' typeof config.reference.getBoundingClientRect !== 'function'

View File

@ -5,16 +5,8 @@
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
*/ */
import { import { defineJQueryPlugin, getElementFromSelector, isRTL, isVisible, reflow } from './util/index'
defineJQueryPlugin,
getElementFromSelector,
isRTL,
isVisible,
reflow,
typeCheckConfig
} from './util/index'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
import SelectorEngine from './dom/selector-engine' import SelectorEngine from './dom/selector-engine'
import ScrollBarHelper from './util/scrollbar' import ScrollBarHelper from './util/scrollbar'
import BaseComponent from './base-component' import BaseComponent from './base-component'
@ -70,9 +62,8 @@ const DefaultType = {
class Modal extends BaseComponent { class Modal extends BaseComponent {
constructor(element, config) { constructor(element, config) {
super(element) super(element, config)
this._config = this._getConfig(config)
this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element) this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)
this._backdrop = this._initializeBackDrop() this._backdrop = this._initializeBackDrop()
this._focustrap = this._initializeFocusTrap() this._focustrap = this._initializeFocusTrap()
@ -86,6 +77,10 @@ class Modal extends BaseComponent {
return Default return Default
} }
static get DefaultType() {
return DefaultType
}
static get NAME() { static get NAME() {
return NAME return NAME
} }
@ -175,16 +170,6 @@ class Modal extends BaseComponent {
}) })
} }
_getConfig(config) {
config = {
...Default,
...Manipulator.getDataAttributes(this._element),
...(typeof config === 'object' ? config : {})
}
typeCheckConfig(NAME, config, DefaultType)
return config
}
_showElement(relatedTarget) { _showElement(relatedTarget) {
// try to append dynamic modal // try to append dynamic modal
if (!document.body.contains(this._element)) { if (!document.body.contains(this._element)) {

View File

@ -9,14 +9,12 @@ import {
defineJQueryPlugin, defineJQueryPlugin,
getElementFromSelector, getElementFromSelector,
isDisabled, isDisabled,
isVisible, isVisible
typeCheckConfig
} from './util/index' } from './util/index'
import ScrollBarHelper from './util/scrollbar' import ScrollBarHelper from './util/scrollbar'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
import BaseComponent from './base-component' import BaseComponent from './base-component'
import SelectorEngine from './dom/selector-engine' import SelectorEngine from './dom/selector-engine'
import Manipulator from './dom/manipulator'
import Backdrop from './util/backdrop' import Backdrop from './util/backdrop'
import FocusTrap from './util/focustrap' import FocusTrap from './util/focustrap'
import { enableDismissTrigger } from './util/component-functions' import { enableDismissTrigger } from './util/component-functions'
@ -63,9 +61,8 @@ const DefaultType = {
class Offcanvas extends BaseComponent { class Offcanvas extends BaseComponent {
constructor(element, config) { constructor(element, config) {
super(element) super(element, config)
this._config = this._getConfig(config)
this._isShown = false this._isShown = false
this._backdrop = this._initializeBackDrop() this._backdrop = this._initializeBackDrop()
this._focustrap = this._initializeFocusTrap() this._focustrap = this._initializeFocusTrap()
@ -73,14 +70,18 @@ class Offcanvas extends BaseComponent {
} }
// Getters // Getters
static get NAME() {
return NAME
}
static get Default() { static get Default() {
return Default return Default
} }
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
// Public // Public
toggle(relatedTarget) { toggle(relatedTarget) {
return this._isShown ? this.hide() : this.show(relatedTarget) return this._isShown ? this.hide() : this.show(relatedTarget)
@ -162,16 +163,6 @@ class Offcanvas extends BaseComponent {
} }
// Private // Private
_getConfig(config) {
config = {
...Default,
...Manipulator.getDataAttributes(this._element),
...(typeof config === 'object' ? config : {})
}
typeCheckConfig(NAME, config, DefaultType)
return config
}
_initializeBackDrop() { _initializeBackDrop() {
return new Backdrop({ return new Backdrop({
className: CLASS_NAME_BACKDROP, className: CLASS_NAME_BACKDROP,

View File

@ -60,6 +60,10 @@ class Popover extends Tooltip {
return Default return Default
} }
static get DefaultType() {
return DefaultType
}
static get NAME() { static get NAME() {
return NAME return NAME
} }
@ -68,10 +72,6 @@ class Popover extends Tooltip {
return Event return Event
} }
static get DefaultType() {
return DefaultType
}
// Overrides // Overrides
_isWithContent() { _isWithContent() {
return this._getTitle() || this._getContent() return this._getTitle() || this._getContent()

View File

@ -8,8 +8,7 @@
import { import {
defineJQueryPlugin, defineJQueryPlugin,
getElement, getElement,
getSelectorFromElement, getSelectorFromElement
typeCheckConfig
} from './util/index' } from './util/index'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator' import Manipulator from './dom/manipulator'
@ -62,9 +61,8 @@ const DefaultType = {
class ScrollSpy extends BaseComponent { class ScrollSpy extends BaseComponent {
constructor(element, config) { constructor(element, config) {
super(element) super(element, config)
this._scrollElement = this._element.tagName === 'BODY' ? window : this._element this._scrollElement = this._element.tagName === 'BODY' ? window : this._element
this._config = this._getConfig(config)
this._offsets = [] this._offsets = []
this._targets = [] this._targets = []
this._activeTarget = null this._activeTarget = null
@ -81,6 +79,10 @@ class ScrollSpy extends BaseComponent {
return Default return Default
} }
static get DefaultType() {
return DefaultType
}
static get NAME() { static get NAME() {
return NAME return NAME
} }
@ -135,17 +137,10 @@ class ScrollSpy extends BaseComponent {
} }
// Private // Private
_getConfig(config) {
config = {
...Default,
...Manipulator.getDataAttributes(this._element),
...(typeof config === 'object' && config ? config : {})
}
_configAfterMerge(config) {
config.target = getElement(config.target) || document.documentElement config.target = getElement(config.target) || document.documentElement
typeCheckConfig(NAME, config, DefaultType)
return config return config
} }

View File

@ -5,9 +5,8 @@
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
*/ */
import { defineJQueryPlugin, reflow, typeCheckConfig } from './util/index' import { defineJQueryPlugin, reflow } from './util/index'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
import BaseComponent from './base-component' import BaseComponent from './base-component'
import { enableDismissTrigger } from './util/component-functions' import { enableDismissTrigger } from './util/component-functions'
@ -51,9 +50,8 @@ const Default = {
class Toast extends BaseComponent { class Toast extends BaseComponent {
constructor(element, config) { constructor(element, config) {
super(element) super(element, config)
this._config = this._getConfig(config)
this._timeout = null this._timeout = null
this._hasMouseInteraction = false this._hasMouseInteraction = false
this._hasKeyboardInteraction = false this._hasKeyboardInteraction = false
@ -61,14 +59,14 @@ class Toast extends BaseComponent {
} }
// Getters // Getters
static get DefaultType() {
return DefaultType
}
static get Default() { static get Default() {
return Default return Default
} }
static get DefaultType() {
return DefaultType
}
static get NAME() { static get NAME() {
return NAME return NAME
} }
@ -133,17 +131,6 @@ class Toast extends BaseComponent {
} }
// Private // Private
_getConfig(config) {
config = {
...Default,
...Manipulator.getDataAttributes(this._element),
...(typeof config === 'object' && config ? config : {})
}
typeCheckConfig(NAME, config, this.constructor.DefaultType)
return config
}
_maybeScheduleHide() { _maybeScheduleHide() {
if (!this._config.autohide) { if (!this._config.autohide) {

View File

@ -12,8 +12,7 @@ import {
getElement, getElement,
getUID, getUID,
isRTL, isRTL,
noop, noop
typeCheckConfig
} from './util/index' } from './util/index'
import { DefaultAllowlist } from './util/sanitizer' import { DefaultAllowlist } from './util/sanitizer'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
@ -140,6 +139,10 @@ class Tooltip extends BaseComponent {
return Default return Default
} }
static get DefaultType() {
return DefaultType
}
static get NAME() { static get NAME() {
return NAME return NAME
} }
@ -148,10 +151,6 @@ class Tooltip extends BaseComponent {
return Event return Event
} }
static get DefaultType() {
return DefaultType
}
// Public // Public
enable() { enable() {
this._isEnabled = true this._isEnabled = true
@ -571,11 +570,16 @@ class Tooltip extends BaseComponent {
} }
config = { config = {
...this.constructor.Default,
...dataAttributes, ...dataAttributes,
...(typeof config === 'object' && config ? config : {}) ...(typeof config === 'object' && config ? config : {})
} }
config = this._mergeConfigObj(config)
config = this._configAfterMerge(config)
this._typeCheckConfig(config)
return config
}
_configAfterMerge(config) {
config.container = config.container === false ? document.body : getElement(config.container) config.container = config.container === false ? document.body : getElement(config.container)
if (typeof config.delay === 'number') { if (typeof config.delay === 'number') {
@ -595,7 +599,6 @@ class Tooltip extends BaseComponent {
config.content = config.content.toString() config.content = config.content.toString()
} }
typeCheckConfig(NAME, config, this.constructor.DefaultType)
return config return config
} }

View File

@ -6,7 +6,8 @@
*/ */
import EventHandler from '../dom/event-handler' 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 * Constants
@ -37,13 +38,27 @@ const DefaultType = {
* Class definition * Class definition
*/ */
class Backdrop { class Backdrop extends Config {
constructor(config) { constructor(config) {
super()
this._config = this._getConfig(config) this._config = this._getConfig(config)
this._isAppended = false this._isAppended = false
this._element = null this._element = null
} }
// Getters
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
// Public // Public
show(callback) { show(callback) {
if (!this._config.isVisible) { if (!this._config.isVisible) {
@ -104,15 +119,9 @@ class Backdrop {
return this._element return this._element
} }
_getConfig(config) { _configAfterMerge(config) {
config = {
...Default,
...(typeof config === 'object' ? config : {})
}
// use getElement() with the default "body" to get a fresh Element on each instantiation // use getElement() with the default "body" to get a fresh Element on each instantiation
config.rootElement = getElement(config.rootElement) config.rootElement = getElement(config.rootElement)
typeCheckConfig(NAME, config, DefaultType)
return config return config
} }

63
js/src/util/config.js Normal file
View File

@ -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

View File

@ -7,7 +7,7 @@
import EventHandler from '../dom/event-handler' import EventHandler from '../dom/event-handler'
import SelectorEngine from '../dom/selector-engine' import SelectorEngine from '../dom/selector-engine'
import { typeCheckConfig } from './index' import Config from './config'
/** /**
* Constants * Constants
@ -37,13 +37,27 @@ const DefaultType = {
* Class definition * Class definition
*/ */
class FocusTrap { class FocusTrap extends Config {
constructor(config) { constructor(config) {
super()
this._config = this._getConfig(config) this._config = this._getConfig(config)
this._isActive = false this._isActive = false
this._lastTabNavDirection = null this._lastTabNavDirection = null
} }
// Getters
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
// Public // Public
activate() { activate() {
const { trapElement, autofocus } = this._config const { trapElement, autofocus } = this._config
@ -99,15 +113,6 @@ class FocusTrap {
this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD 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 export default FocusTrap

View File

@ -123,20 +123,6 @@ const getElement = object => {
return null 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 => { const isVisible = element => {
if (!isElement(element) || element.getClientRects().length === 0) { if (!isElement(element) || element.getClientRects().length === 0) {
return false return false
@ -327,5 +313,5 @@ export {
onDOMContentLoaded, onDOMContentLoaded,
reflow, reflow,
triggerTransitionEnd, triggerTransitionEnd,
typeCheckConfig toType
} }

View File

@ -5,8 +5,9 @@
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
*/ */
import Config from './config'
import EventHandler from '../dom/event-handler' import EventHandler from '../dom/event-handler'
import { execute, typeCheckConfig } from './index' import { execute } from './index'
/** /**
* Constants * Constants
@ -40,8 +41,9 @@ const DefaultType = {
* Class definition * Class definition
*/ */
class Swipe { class Swipe extends Config {
constructor(element, config) { constructor(element, config) {
super()
this._element = element this._element = element
if (!element || !Swipe.isSupported()) { if (!element || !Swipe.isSupported()) {
@ -54,6 +56,19 @@ class Swipe {
this._initEvents() this._initEvents()
} }
// Getters
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
// Public // Public
dispose() { dispose() {
EventHandler.off(this._element, EVENT_KEY) 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) { _eventIsPointerPenTouch(event) {
return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH) return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)
} }

View File

@ -6,8 +6,9 @@
*/ */
import { DefaultAllowlist, sanitizeHtml } from './sanitizer' 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 SelectorEngine from '../dom/selector-engine'
import Config from './config'
/** /**
* Constants * Constants
@ -44,20 +45,25 @@ const DefaultContentType = {
* Class definition * Class definition
*/ */
class TemplateFactory { class TemplateFactory extends Config {
constructor(config) { constructor(config) {
super()
this._config = this._getConfig(config) this._config = this._getConfig(config)
} }
// Getters // Getters
static get NAME() {
return NAME
}
static get Default() { static get Default() {
return Default return Default
} }
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
// Public // Public
getContent() { getContent() {
return Object.values(this._config.content) return Object.values(this._config.content)
@ -94,21 +100,14 @@ class TemplateFactory {
} }
// Private // Private
_getConfig(config) { _typeCheckConfig(config) {
config = { super._typeCheckConfig(config)
...Default,
...(typeof config === 'object' ? config : {})
}
typeCheckConfig(NAME, config, DefaultType)
this._checkContent(config.content) this._checkContent(config.content)
return config
} }
_checkContent(arg) { _checkContent(arg) {
for (const [selector, content] of Object.entries(arg)) { for (const [selector, content] of Object.entries(arg)) {
typeCheckConfig(NAME, { selector, entry: content }, DefaultContentType) super._typeCheckConfig({ selector, entry: content }, DefaultContentType)
} }
} }

View File

@ -0,0 +1,78 @@
import Config from '../../../src/util/config'
class DummyConfigClass extends Config {
static get NAME() {
return 'dummy'
}
}
describe('Config', () => {
const name = 'dummy'
describe('NAME', () => {
it('should return plugin NAME', () => {
expect(DummyConfigClass.NAME).toEqual(name)
})
})
describe('DefaultType', () => {
it('should return plugin default type', () => {
expect(DummyConfigClass.DefaultType).toEqual(jasmine.any(Object))
})
})
describe('Default', () => {
it('should return plugin defaults', () => {
expect(DummyConfigClass.Default).toEqual(jasmine.any(Object))
})
})
describe('typeCheckConfig', () => {
it('should check type of the config object', () => {
spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({
toggle: 'boolean',
parent: '(string|element)'
})
const config = {
toggle: true,
parent: 777
}
const obj = new DummyConfigClass()
expect(() => {
obj._typeCheckConfig(config)
}).toThrowError(TypeError, obj.constructor.NAME.toUpperCase() + ': Option "parent" provided type "number" but expected type "(string|element)".')
})
it('should return null stringified when null is passed', () => {
spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({
toggle: 'boolean',
parent: '(null|element)'
})
const obj = new DummyConfigClass()
const config = {
toggle: true,
parent: null
}
obj._typeCheckConfig(config)
expect().nothing()
})
it('should return undefined stringified when undefined is passed', () => {
spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({
toggle: 'boolean',
parent: '(undefined|element)'
})
const obj = new DummyConfigClass()
const config = {
toggle: true,
parent: undefined
}
obj._typeCheckConfig(config)
expect().nothing()
})
})
})

View File

@ -223,53 +223,6 @@ describe('Util', () => {
}) })
}) })
describe('typeCheckConfig', () => {
const namePlugin = 'collapse'
it('should check type of the config object', () => {
const defaultType = {
toggle: 'boolean',
parent: '(string|element)'
}
const config = {
toggle: true,
parent: 777
}
expect(() => {
Util.typeCheckConfig(namePlugin, config, defaultType)
}).toThrowError(TypeError, 'COLLAPSE: Option "parent" provided type "number" but expected type "(string|element)".')
})
it('should return null stringified when null is passed', () => {
const defaultType = {
toggle: 'boolean',
parent: '(null|element)'
}
const config = {
toggle: true,
parent: null
}
Util.typeCheckConfig(namePlugin, config, defaultType)
expect().nothing()
})
it('should return undefined stringified when undefined is passed', () => {
const defaultType = {
toggle: 'boolean',
parent: '(undefined|element)'
}
const config = {
toggle: true,
parent: undefined
}
Util.typeCheckConfig(namePlugin, config, defaultType)
expect().nothing()
})
})
describe('isVisible', () => { describe('isVisible', () => {
it('should return false if the element is not defined', () => { it('should return false if the element is not defined', () => {
expect(Util.isVisible(null)).toBeFalse() expect(Util.isVisible(null)).toBeFalse()