Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/bootstrap.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeoSot <geo.sotis@gmail.com>2021-05-11 10:49:30 +0300
committerGitHub <noreply@github.com>2021-05-11 10:49:30 +0300
commit9fe36edf683af02574bf6bbd6c9b27de93bd31b1 (patch)
tree111d2b788e990a58277ff4543cfd44c5815ac795
parent7647b8fe5b77120ba319e7119bb0515d91f734da (diff)
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
-rw-r--r--js/src/alert.js6
-rw-r--r--js/src/base-component.js14
-rw-r--r--js/src/button.js6
-rw-r--r--js/src/carousel.js6
-rw-r--r--js/src/collapse.js6
-rw-r--r--js/src/dropdown.js6
-rw-r--r--js/src/modal.js6
-rw-r--r--js/src/offcanvas.js10
-rw-r--r--js/src/popover.js10
-rw-r--r--js/src/scrollspy.js6
-rw-r--r--js/src/tab.js6
-rw-r--r--js/src/toast.js6
-rw-r--r--js/src/tooltip.js10
-rw-r--r--js/src/util/index.js3
-rw-r--r--js/tests/unit/base-component.spec.js116
-rw-r--r--js/tests/unit/util/index.spec.js3
16 files changed, 167 insertions, 53 deletions
diff --git a/js/src/alert.js b/js/src/alert.js
index 8d0838737a..db58d7426b 100644
--- a/js/src/alert.js
+++ b/js/src/alert.js
@@ -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
diff --git a/js/src/base-component.js b/js/src/base-component.js
index 588a59d756..eacc8420bc 100644
--- a/js/src/base-component.js
+++ b/js/src/base-component.js
@@ -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
diff --git a/js/src/button.js b/js/src/button.js
index 45c691dd43..4932c19552 100644
--- a/js/src/button.js
+++ b/js/src/button.js
@@ -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
diff --git a/js/src/carousel.js b/js/src/carousel.js
index 92733637e9..0e45fed761 100644
--- a/js/src/carousel.js
+++ b/js/src/carousel.js
@@ -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
diff --git a/js/src/collapse.js b/js/src/collapse.js
index 0d1b91be55..1c8f53ebd6 100644
--- a/js/src/collapse.js
+++ b/js/src/collapse.js
@@ -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
diff --git a/js/src/dropdown.js b/js/src/dropdown.js
index f56ab201b7..8f501d8113 100644
--- a/js/src/dropdown.js
+++ b/js/src/dropdown.js
@@ -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
diff --git a/js/src/modal.js b/js/src/modal.js
index 44f2a0cbb2..058d4a36b2 100644
--- a/js/src/modal.js
+++ b/js/src/modal.js
@@ -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
diff --git a/js/src/offcanvas.js b/js/src/offcanvas.js
index 8ddb776b1f..65d1e6ba75 100644
--- a/js/src/offcanvas.js
+++ b/js/src/offcanvas.js
@@ -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
diff --git a/js/src/popover.js b/js/src/popover.js
index 58b3623280..c105ee2a14 100644
--- a/js/src/popover.js
+++ b/js/src/popover.js
@@ -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
diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js
index 7c59dabcff..d22f489570 100644
--- a/js/src/scrollspy.js
+++ b/js/src/scrollspy.js
@@ -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
diff --git a/js/src/tab.js b/js/src/tab.js
index 8ee2738113..34107bac03 100644
--- a/js/src/tab.js
+++ b/js/src/tab.js
@@ -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
diff --git a/js/src/toast.js b/js/src/toast.js
index cf869cd5a3..e427ea6569 100644
--- a/js/src/toast.js
+++ b/js/src/toast.js
@@ -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
diff --git a/js/src/tooltip.js b/js/src/tooltip.js
index 7226d31234..632115d72e 100644
--- a/js/src/tooltip.js
+++ b/js/src/tooltip.js
@@ -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
diff --git a/js/src/util/index.js b/js/src/util/index.js
index a5144f15e4..0dd6b1d454 100644
--- a/js/src/util/index.js
+++ b/js/src/util/index.js
@@ -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
diff --git a/js/tests/unit/base-component.spec.js b/js/tests/unit/base-component.spec.js
new file mode 100644
index 0000000000..7a849be062
--- /dev/null
+++ b/js/tests/unit/base-component.spec.js
@@ -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)
+ })
+ })
+ })
+})
diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js
index 11b6f7fa49..a7c1c28982 100644
--- a/js/tests/unit/util/index.spec.js
+++ b/js/tests/unit/util/index.spec.js
@@ -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')