From 1a0a0858efa0e1e3c6bebd38058df8ad39ca27a5 Mon Sep 17 00:00:00 2001 From: Martijn Cuppens Date: Sat, 2 May 2020 11:11:24 +0200 Subject: Remove checkbox/radio toggle from button plugin in favor of a CSS only solution --- js/src/button.js | 78 ++------------------- js/tests/unit/button.spec.js | 161 ------------------------------------------- 2 files changed, 5 insertions(+), 234 deletions(-) (limited to 'js') diff --git a/js/src/button.js b/js/src/button.js index 67f3b96279..fd29e5218b 100644 --- a/js/src/button.js +++ b/js/src/button.js @@ -8,7 +8,6 @@ import { getjQuery } from './util/index' import Data from './dom/data' import EventHandler from './dom/event-handler' -import SelectorEngine from './dom/selector-engine' /** * ------------------------------------------------------------------------ @@ -23,18 +22,10 @@ const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' const CLASS_NAME_ACTIVE = 'active' -const CLASS_NAME_DISABLED = 'disabled' -const CLASS_NAME_FOCUS = 'focus' -const SELECTOR_DATA_TOGGLE_CARROT = '[data-toggle^="button"]' -const SELECTOR_DATA_TOGGLE = '[data-toggle="buttons"]' -const SELECTOR_INPUT = 'input:not([type="hidden"])' -const SELECTOR_ACTIVE = '.active' -const SELECTOR_BUTTON = '.btn' +const SELECTOR_DATA_TOGGLE = '[data-toggle="button"]' const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` -const EVENT_FOCUS_DATA_API = `focus${EVENT_KEY}${DATA_API_KEY}` -const EVENT_BLUR_DATA_API = `blur${EVENT_KEY}${DATA_API_KEY}` /** * ------------------------------------------------------------------------ @@ -57,51 +48,8 @@ class Button { // Public toggle() { - let triggerChangeEvent = true - let addAriaPressed = true - - const rootElement = this._element.closest(SELECTOR_DATA_TOGGLE) - - if (rootElement) { - const input = SelectorEngine.findOne(SELECTOR_INPUT, this._element) - - if (input && input.type === 'radio') { - if (input.checked && - this._element.classList.contains(CLASS_NAME_ACTIVE)) { - triggerChangeEvent = false - } else { - const activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE, rootElement) - - if (activeElement) { - activeElement.classList.remove(CLASS_NAME_ACTIVE) - } - } - - if (triggerChangeEvent) { - if (input.hasAttribute('disabled') || - rootElement.hasAttribute('disabled') || - input.classList.contains(CLASS_NAME_DISABLED) || - rootElement.classList.contains(CLASS_NAME_DISABLED)) { - return - } - - input.checked = !this._element.classList.contains(CLASS_NAME_ACTIVE) - EventHandler.trigger(input, 'change') - } - - input.focus() - addAriaPressed = false - } - } - - if (addAriaPressed) { - this._element.setAttribute('aria-pressed', - !this._element.classList.contains(CLASS_NAME_ACTIVE)) - } - - if (triggerChangeEvent) { - this._element.classList.toggle(CLASS_NAME_ACTIVE) - } + // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method + this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE)) } dispose() { @@ -136,10 +84,10 @@ class Button { * ------------------------------------------------------------------------ */ -EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => { +EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => { event.preventDefault() - const button = event.target.closest(SELECTOR_BUTTON) + const button = event.target.closest(SELECTOR_DATA_TOGGLE) let data = Data.getData(button, DATA_KEY) if (!data) { @@ -149,22 +97,6 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, eve data.toggle() }) -EventHandler.on(document, EVENT_FOCUS_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => { - const button = event.target.closest(SELECTOR_BUTTON) - - if (button) { - button.classList.add(CLASS_NAME_FOCUS) - } -}) - -EventHandler.on(document, EVENT_BLUR_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => { - const button = event.target.closest(SELECTOR_BUTTON) - - if (button) { - button.classList.remove(CLASS_NAME_FOCUS) - } -}) - const $ = getjQuery() /** diff --git a/js/tests/unit/button.spec.js b/js/tests/unit/button.spec.js index f7caf23f62..ac32b4b897 100644 --- a/js/tests/unit/button.spec.js +++ b/js/tests/unit/button.spec.js @@ -1,11 +1,9 @@ import Button from '../../src/button' -import EventHandler from '../../src/dom/event-handler' /** Test helpers */ import { getFixture, clearFixture, - createEvent, jQueryMock } from '../helpers/fixture' @@ -51,144 +49,6 @@ describe('Button', () => { expect(btnTestParent.classList.contains('active')).toEqual(true) }) - - it('should trigger input change event when toggled button has input field', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ].join('') - - const input = fixtureEl.querySelector('input') - const label = fixtureEl.querySelector('label') - - input.addEventListener('change', () => { - expect().nothing() - done() - }) - - label.click() - }) - - it('should not trigger input change event when input already checked and button is active', () => { - fixtureEl.innerHTML = [ - '' - ].join('') - - const button = fixtureEl.querySelector('button') - - spyOn(EventHandler, 'trigger') - - button.click() - - expect(EventHandler.trigger).not.toHaveBeenCalled() - }) - - it('should remove active when an other radio button is clicked', () => { - fixtureEl.innerHTML = [ - '
', - ' ', - ' ', - ' ', - '
' - ].join('') - - const option1 = fixtureEl.querySelector('#option1') - const option2 = fixtureEl.querySelector('#option2') - - expect(option1.checked).toEqual(true) - expect(option1.parentElement.classList.contains('active')).toEqual(true) - - const clickEvent = createEvent('click') - - option2.dispatchEvent(clickEvent) - - expect(option1.checked).toEqual(false) - expect(option1.parentElement.classList.contains('active')).toEqual(false) - expect(option2.checked).toEqual(true) - expect(option2.parentElement.classList.contains('active')).toEqual(true) - }) - - it('should do nothing if the child is not an input', () => { - fixtureEl.innerHTML = [ - '
', - ' ', - ' ', - ' ', - '
' - ].join('') - - const option2 = fixtureEl.querySelector('#option2') - const clickEvent = createEvent('click') - - option2.dispatchEvent(clickEvent) - - expect().nothing() - }) - - it('should add focus class on focus event', () => { - fixtureEl.innerHTML = '' - - const btn = fixtureEl.querySelector('.btn') - const input = fixtureEl.querySelector('input') - - const focusEvent = createEvent('focus') - input.dispatchEvent(focusEvent) - - expect(btn.classList.contains('focus')).toEqual(true) - }) - - it('should not add focus class', () => { - fixtureEl.innerHTML = '' - - const btn = fixtureEl.querySelector('button') - const input = fixtureEl.querySelector('input') - - const focusEvent = createEvent('focus') - input.dispatchEvent(focusEvent) - - expect(btn.classList.contains('focus')).toEqual(false) - }) - - it('should remove focus class on blur event', () => { - fixtureEl.innerHTML = '' - - const btn = fixtureEl.querySelector('.btn') - const input = fixtureEl.querySelector('input') - - const focusEvent = createEvent('blur') - input.dispatchEvent(focusEvent) - - expect(btn.classList.contains('focus')).toEqual(false) - }) - - it('should not remove focus class on blur event', () => { - fixtureEl.innerHTML = '' - - const btn = fixtureEl.querySelector('button') - const input = fixtureEl.querySelector('input') - - const focusEvent = createEvent('blur') - input.dispatchEvent(focusEvent) - - expect(btn.classList.contains('focus')).toEqual(true) - }) }) describe('toggle', () => { @@ -206,27 +66,6 @@ describe('Button', () => { expect(btnEl.getAttribute('aria-pressed')).toEqual('true') expect(btnEl.classList.contains('active')).toEqual(true) }) - - it('should handle disabled attribute on non-button elements', () => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ].join('') - - const btnGroupEl = fixtureEl.querySelector('.btn-group') - const btnDanger = fixtureEl.querySelector('.btn-danger') - const input = fixtureEl.querySelector('input') - - const button = new Button(btnGroupEl) - - button.toggle() - - expect(btnDanger.hasAttribute('disabled')).toEqual(true) - expect(input.checked).toEqual(false) - }) }) describe('dispose', () => { -- cgit v1.2.3