mirror of
https://github.com/twbs/bootstrap.git
synced 2022-11-09 12:25:43 -05:00
Extract static DATA_KEY
& EVENT_KEY
to base-component (#33635)
* Force each plugin that extends base-components to implement a static method `NAME()` * Remove redundant `NAME` argument from 'Utils.defineJQueryPlugin' & fix test
This commit is contained in:
parent
7647b8fe5b
commit
9fe36edf68
16 changed files with 167 additions and 53 deletions
|
@ -43,8 +43,8 @@ const CLASS_NAME_SHOW = 'show'
|
|||
class Alert extends BaseComponent {
|
||||
// Getters
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -127,6 +127,6 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DISMISS, Alert.handleDi
|
|||
* add .Alert to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Alert)
|
||||
defineJQueryPlugin(Alert)
|
||||
|
||||
export default Alert
|
||||
|
|
|
@ -35,7 +35,7 @@ class BaseComponent {
|
|||
|
||||
dispose() {
|
||||
Data.remove(this._element, this.constructor.DATA_KEY)
|
||||
EventHandler.off(this._element, `.${this.constructor.DATA_KEY}`)
|
||||
EventHandler.off(this._element, this.constructor.EVENT_KEY)
|
||||
|
||||
Object.getOwnPropertyNames(this).forEach(propertyName => {
|
||||
this[propertyName] = null
|
||||
|
@ -63,6 +63,18 @@ class BaseComponent {
|
|||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
|
||||
static get NAME() {
|
||||
throw new Error('You have to implement the static method "NAME", for each component!')
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return `bs.${this.NAME}`
|
||||
}
|
||||
|
||||
static get EVENT_KEY() {
|
||||
return `.${this.DATA_KEY}`
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseComponent
|
||||
|
|
|
@ -36,8 +36,8 @@ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
|
|||
class Button extends BaseComponent {
|
||||
// Getters
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -90,6 +90,6 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {
|
|||
* add .Button to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Button)
|
||||
defineJQueryPlugin(Button)
|
||||
|
||||
export default Button
|
||||
|
|
|
@ -127,8 +127,8 @@ class Carousel extends BaseComponent {
|
|||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -598,6 +598,6 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
|
|||
* add .Carousel to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Carousel)
|
||||
defineJQueryPlugin(Carousel)
|
||||
|
||||
export default Carousel
|
||||
|
|
|
@ -105,8 +105,8 @@ class Collapse extends BaseComponent {
|
|||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -390,6 +390,6 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
|
|||
* add .Collapse to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Collapse)
|
||||
defineJQueryPlugin(Collapse)
|
||||
|
||||
export default Collapse
|
||||
|
|
|
@ -116,8 +116,8 @@ class Dropdown extends BaseComponent {
|
|||
return DefaultType
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -530,6 +530,6 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
|
|||
* add .Dropdown to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Dropdown)
|
||||
defineJQueryPlugin(Dropdown)
|
||||
|
||||
export default Dropdown
|
||||
|
|
|
@ -93,8 +93,8 @@ class Modal extends BaseComponent {
|
|||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -441,6 +441,6 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
|
|||
* add .Modal to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Modal)
|
||||
defineJQueryPlugin(Modal)
|
||||
|
||||
export default Modal
|
||||
|
|
|
@ -78,12 +78,12 @@ class Offcanvas extends BaseComponent {
|
|||
|
||||
// Getters
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -271,6 +271,6 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Offcanvas)
|
||||
defineJQueryPlugin(Offcanvas)
|
||||
|
||||
export default Offcanvas
|
||||
|
|
|
@ -76,18 +76,10 @@ class Popover extends Tooltip {
|
|||
return NAME
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
static get Event() {
|
||||
return Event
|
||||
}
|
||||
|
||||
static get EVENT_KEY() {
|
||||
return EVENT_KEY
|
||||
}
|
||||
|
||||
static get DefaultType() {
|
||||
return DefaultType
|
||||
}
|
||||
|
@ -166,6 +158,6 @@ class Popover extends Tooltip {
|
|||
* add .Popover to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Popover)
|
||||
defineJQueryPlugin(Popover)
|
||||
|
||||
export default Popover
|
||||
|
|
|
@ -87,8 +87,8 @@ class ScrollSpy extends BaseComponent {
|
|||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -303,6 +303,6 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
|
|||
* add .ScrollSpy to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, ScrollSpy)
|
||||
defineJQueryPlugin(ScrollSpy)
|
||||
|
||||
export default ScrollSpy
|
||||
|
|
|
@ -55,8 +55,8 @@ const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active'
|
|||
class Tab extends BaseComponent {
|
||||
// Getters
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -220,6 +220,6 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
|
|||
* add .Tab to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Tab)
|
||||
defineJQueryPlugin(Tab)
|
||||
|
||||
export default Tab
|
||||
|
|
|
@ -81,8 +81,8 @@ class Toast extends BaseComponent {
|
|||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
// Public
|
||||
|
@ -243,6 +243,6 @@ class Toast extends BaseComponent {
|
|||
* add .Toast to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Toast)
|
||||
defineJQueryPlugin(Toast)
|
||||
|
||||
export default Toast
|
||||
|
|
|
@ -155,18 +155,10 @@ class Tooltip extends BaseComponent {
|
|||
return NAME
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
static get Event() {
|
||||
return Event
|
||||
}
|
||||
|
||||
static get EVENT_KEY() {
|
||||
return EVENT_KEY
|
||||
}
|
||||
|
||||
static get DefaultType() {
|
||||
return DefaultType
|
||||
}
|
||||
|
@ -774,6 +766,6 @@ class Tooltip extends BaseComponent {
|
|||
* add .Tooltip to jQuery only if jQuery is present
|
||||
*/
|
||||
|
||||
defineJQueryPlugin(NAME, Tooltip)
|
||||
defineJQueryPlugin(Tooltip)
|
||||
|
||||
export default Tooltip
|
||||
|
|
|
@ -214,11 +214,12 @@ const onDOMContentLoaded = callback => {
|
|||
|
||||
const isRTL = () => document.documentElement.dir === 'rtl'
|
||||
|
||||
const defineJQueryPlugin = (name, plugin) => {
|
||||
const defineJQueryPlugin = plugin => {
|
||||
onDOMContentLoaded(() => {
|
||||
const $ = getjQuery()
|
||||
/* istanbul ignore if */
|
||||
if ($) {
|
||||
const name = plugin.NAME
|
||||
const JQUERY_NO_CONFLICT = $.fn[name]
|
||||
$.fn[name] = plugin.jQueryInterface
|
||||
$.fn[name].Constructor = plugin
|
||||
|
|
116
js/tests/unit/base-component.spec.js
Normal file
116
js/tests/unit/base-component.spec.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
import BaseComponent from '../../src/base-component'
|
||||
import { clearFixture, getFixture } from '../helpers/fixture'
|
||||
import EventHandler from '../../src/dom/event-handler'
|
||||
import { noop } from '../../src/util'
|
||||
|
||||
class DummyClass extends BaseComponent {
|
||||
constructor(element) {
|
||||
super(element)
|
||||
|
||||
EventHandler.on(this._element, `click${DummyClass.EVENT_KEY}`, noop)
|
||||
}
|
||||
|
||||
static get NAME() {
|
||||
return 'dummy'
|
||||
}
|
||||
}
|
||||
|
||||
describe('Base Component', () => {
|
||||
let fixtureEl
|
||||
const name = 'dummy'
|
||||
let element
|
||||
let instance
|
||||
const createInstance = () => {
|
||||
fixtureEl.innerHTML = '<div id="foo"></div>'
|
||||
element = fixtureEl.querySelector('#foo')
|
||||
instance = new DummyClass(element)
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
fixtureEl = getFixture()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
clearFixture()
|
||||
})
|
||||
|
||||
describe('Static Methods', () => {
|
||||
describe('VERSION', () => {
|
||||
it('should return version', () => {
|
||||
expect(typeof DummyClass.VERSION).toEqual('string')
|
||||
})
|
||||
})
|
||||
|
||||
describe('DATA_KEY', () => {
|
||||
it('should return plugin data key', () => {
|
||||
expect(DummyClass.DATA_KEY).toEqual(`bs.${name}`)
|
||||
})
|
||||
})
|
||||
|
||||
describe('NAME', () => {
|
||||
it('should return plugin NAME', () => {
|
||||
expect(DummyClass.NAME).toEqual(name)
|
||||
})
|
||||
})
|
||||
|
||||
describe('EVENT_KEY', () => {
|
||||
it('should return plugin event key', () => {
|
||||
expect(DummyClass.EVENT_KEY).toEqual(`.bs.${name}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
describe('Public Methods', () => {
|
||||
describe('constructor', () => {
|
||||
it('should accept element, either passed as a CSS selector or DOM element', () => {
|
||||
fixtureEl.innerHTML = [
|
||||
'<div id="foo"></div>',
|
||||
'<div id="bar"></div>'
|
||||
].join('')
|
||||
|
||||
const el = fixtureEl.querySelector('#foo')
|
||||
const elInstance = new DummyClass(el)
|
||||
const selectorInstance = new DummyClass('#bar')
|
||||
|
||||
expect(elInstance._element).toEqual(el)
|
||||
expect(selectorInstance._element).toEqual(fixtureEl.querySelector('#bar'))
|
||||
})
|
||||
})
|
||||
describe('dispose', () => {
|
||||
it('should dispose an component', () => {
|
||||
createInstance()
|
||||
expect(DummyClass.getInstance(element)).not.toBeNull()
|
||||
|
||||
instance.dispose()
|
||||
|
||||
expect(DummyClass.getInstance(element)).toBeNull()
|
||||
expect(instance._element).toBeNull()
|
||||
})
|
||||
|
||||
it('should de-register element event listeners', () => {
|
||||
createInstance()
|
||||
spyOn(EventHandler, 'off')
|
||||
|
||||
instance.dispose()
|
||||
|
||||
expect(EventHandler.off).toHaveBeenCalledWith(element, DummyClass.EVENT_KEY)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getInstance', () => {
|
||||
it('should return an instance', () => {
|
||||
createInstance()
|
||||
|
||||
expect(DummyClass.getInstance(element)).toEqual(instance)
|
||||
expect(DummyClass.getInstance(element)).toBeInstanceOf(DummyClass)
|
||||
})
|
||||
|
||||
it('should return null when there is no instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
|
||||
expect(DummyClass.getInstance(div)).toEqual(null)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -560,9 +560,10 @@ describe('Util', () => {
|
|||
|
||||
it('should define a plugin on the jQuery instance', () => {
|
||||
const pluginMock = function () {}
|
||||
pluginMock.NAME = 'test'
|
||||
pluginMock.jQueryInterface = function () {}
|
||||
|
||||
Util.defineJQueryPlugin('test', pluginMock)
|
||||
Util.defineJQueryPlugin(pluginMock)
|
||||
expect(fakejQuery.fn.test).toBe(pluginMock.jQueryInterface)
|
||||
expect(fakejQuery.fn.test.Constructor).toBe(pluginMock)
|
||||
expect(typeof fakejQuery.fn.test.noConflict).toEqual('function')
|
||||
|
|
Loading…
Reference in a new issue