From 48a95f7280735d6f8962fe8b17975b03e351710c Mon Sep 17 00:00:00 2001 From: alpadev <2838324+alpadev@users.noreply.github.com> Date: Tue, 2 Mar 2021 15:55:44 +0100 Subject: refactor: use a Map instead of an Object in dom/data (#32180) Co-authored-by: XhmikosR Co-authored-by: Rohit Sharma --- js/src/dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 590c74801..fea0b1919 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -357,7 +357,7 @@ class Dropdown extends BaseComponent { // Static static dropdownInterface(element, config) { - let data = Data.getData(element, DATA_KEY) + let data = Data.get(element, DATA_KEY) const _config = typeof config === 'object' ? config : null if (!data) { @@ -387,7 +387,7 @@ class Dropdown extends BaseComponent { const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE) for (let i = 0, len = toggles.length; i < len; i++) { - const context = Data.getData(toggles[i], DATA_KEY) + const context = Data.get(toggles[i], DATA_KEY) const relatedTarget = { relatedTarget: toggles[i] } -- cgit v1.2.3 From b9e51dc3c4400ede5e72991dd0efacf9dbcb694e Mon Sep 17 00:00:00 2001 From: Rohit Sharma Date: Tue, 2 Mar 2021 20:57:13 +0530 Subject: =?UTF-8?q?Dropdown=20=E2=80=94=20Drop=20`flip`=20option=20(#33198?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/src/dropdown.js | 3 --- 1 file changed, 3 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index fea0b1919..eeec9076d 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -73,7 +73,6 @@ const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start' const Default = { offset: [0, 2], - flip: true, boundary: 'clippingParents', reference: 'toggle', display: 'dynamic', @@ -82,7 +81,6 @@ const Default = { const DefaultType = { offset: '(array|string|function)', - flip: 'boolean', boundary: '(string|element)', reference: '(string|element|object)', display: 'string', @@ -328,7 +326,6 @@ class Dropdown extends BaseComponent { modifiers: [{ name: 'preventOverflow', options: { - altBoundary: this._config.flip, boundary: this._config.boundary } }, -- cgit v1.2.3 From 16bc47da3c5296ee7d39b112831d557732fdda95 Mon Sep 17 00:00:00 2001 From: Casey Holzer Date: Wed, 6 Jan 2021 03:07:43 +0200 Subject: Allow data-toggle="dropdown" and form click events to bubble * remove stopPropagation from button click event * test for delegated click events * ensure button children can open menu * test to ensure clicking button opens the menu * check current element and parents * allow dropdown form click events to bubble --- js/src/dropdown.js | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index eeec9076d..ae1aacb6b 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -59,7 +59,6 @@ const CLASS_NAME_DROPSTART = 'dropstart' const CLASS_NAME_NAVBAR = 'navbar' const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]' -const SELECTOR_FORM_CHILD = '.dropdown form' const SELECTOR_MENU = '.dropdown-menu' const SELECTOR_NAVBAR_NAV = '.navbar-nav' const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' @@ -253,7 +252,6 @@ class Dropdown extends BaseComponent { _addEventListeners() { EventHandler.on(this._element, EVENT_CLICK, event => { event.preventDefault() - event.stopPropagation() this.toggle() }) } @@ -377,8 +375,14 @@ class Dropdown extends BaseComponent { } static clearMenus(event) { - if (event && (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY))) { - return + if (event) { + if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) { + return + } + + if (/input|select|textarea|form/i.test(event.target.tagName)) { + return + } } const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE) @@ -402,11 +406,16 @@ class Dropdown extends BaseComponent { continue } - if (event && ((event.type === 'click' && - /input|textarea/i.test(event.target.tagName)) || - (event.type === 'keyup' && event.key === TAB_KEY)) && - dropdownMenu.contains(event.target)) { - continue + if (event) { + // Don't close the menu if the clicked element or one of its parents is the dropdown button + if ([context._element].some(element => event.composedPath().includes(element))) { + continue + } + + // Tab navigation through the dropdown menu shouldn't close the menu + if (event.type === 'keyup' && event.key === TAB_KEY && dropdownMenu.contains(event.target)) { + continue + } } const hideEvent = EventHandler.trigger(toggles[i], EVENT_HIDE, relatedTarget) @@ -519,10 +528,8 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus) EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus) EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { event.preventDefault() - event.stopPropagation() - Dropdown.dropdownInterface(this, 'toggle') + Dropdown.dropdownInterface(this) }) -EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => e.stopPropagation()) /** * ------------------------------------------------------------------------ -- cgit v1.2.3 From 220139a89ffc3864bbb6e1b35471667318eadc1f Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Tue, 23 Mar 2021 18:26:54 +0200 Subject: Release v5.0.0-beta3 (#33439) --- js/src/dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index ae1aacb6b..d00cff65c 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -1,6 +1,6 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.0-beta2): dropdown.js + * Bootstrap (v5.0.0-beta3): dropdown.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ -- cgit v1.2.3 From 8c3e6ebc6e3e4fe6e0c31470195704872ec125f7 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Tue, 30 Mar 2021 07:42:23 +0300 Subject: Use our `isDisabled` util on dropdown (#33456) --- js/src/dropdown.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index d00cff65c..97bf6e109 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -10,6 +10,7 @@ import * as Popper from '@popperjs/core' import { defineJQueryPlugin, getElementFromSelector, + isDisabled, isElement, isVisible, isRTL, @@ -51,7 +52,6 @@ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}` const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}` -const CLASS_NAME_DISABLED = 'disabled' const CLASS_NAME_SHOW = 'show' const CLASS_NAME_DROPUP = 'dropup' const CLASS_NAME_DROPEND = 'dropend' @@ -121,7 +121,7 @@ class Dropdown extends BaseComponent { // Public toggle() { - if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED)) { + if (isDisabled(this._element)) { return } @@ -137,7 +137,7 @@ class Dropdown extends BaseComponent { } show() { - if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED) || this._menu.classList.contains(CLASS_NAME_SHOW)) { + if (isDisabled(this._element) || this._menu.classList.contains(CLASS_NAME_SHOW)) { return } @@ -204,7 +204,7 @@ class Dropdown extends BaseComponent { } hide() { - if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED) || !this._menu.classList.contains(CLASS_NAME_SHOW)) { + if (isDisabled(this._element) || !this._menu.classList.contains(CLASS_NAME_SHOW)) { return } @@ -466,7 +466,7 @@ class Dropdown extends BaseComponent { event.preventDefault() event.stopPropagation() - if (this.disabled || this.classList.contains(CLASS_NAME_DISABLED)) { + if (isDisabled(this)) { return } -- cgit v1.2.3 From f36f8344533d3179b8d82af96e005b3106d9ab46 Mon Sep 17 00:00:00 2001 From: alpadev <2838324+alpadev@users.noreply.github.com> Date: Thu, 1 Apr 2021 20:44:04 +0200 Subject: Fix dropdown escape propagation (#33479) --- js/src/dropdown.js | 63 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 28 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 97bf6e109..605cbc64d 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -443,6 +443,31 @@ class Dropdown extends BaseComponent { } } + static selectMenuItem(parent, event) { + const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, parent).filter(isVisible) + + if (!items.length) { + return + } + + let index = items.indexOf(event.target) + + // Up + if (event.key === ARROW_UP_KEY && index > 0) { + index-- + } + + // Down + if (event.key === ARROW_DOWN_KEY && index < items.length - 1) { + index++ + } + + // index is -1 if the first keydown is an ArrowUp + index = index === -1 ? 0 : index + + items[index].focus() + } + static getParentFromElement(element) { return getElementFromSelector(element) || element.parentNode } @@ -463,6 +488,12 @@ class Dropdown extends BaseComponent { return } + const isActive = this.classList.contains(CLASS_NAME_SHOW) + + if (!isActive && event.key === ESCAPE_KEY) { + return + } + event.preventDefault() event.stopPropagation() @@ -470,19 +501,16 @@ class Dropdown extends BaseComponent { return } - const parent = Dropdown.getParentFromElement(this) - const isActive = this.classList.contains(CLASS_NAME_SHOW) + const getToggleButton = () => this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] if (event.key === ESCAPE_KEY) { - const button = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] - button.focus() + getToggleButton().focus() Dropdown.clearMenus() return } if (!isActive && (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY)) { - const button = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] - button.click() + getToggleButton().click() return } @@ -491,28 +519,7 @@ class Dropdown extends BaseComponent { return } - const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, parent).filter(isVisible) - - if (!items.length) { - return - } - - let index = items.indexOf(event.target) - - // Up - if (event.key === ARROW_UP_KEY && index > 0) { - index-- - } - - // Down - if (event.key === ARROW_DOWN_KEY && index < items.length - 1) { - index++ - } - - // index is -1 if the first keydown is an ArrowUp - index = index === -1 ? 0 : index - - items[index].focus() + Dropdown.selectMenuItem(Dropdown.getParentFromElement(this), event) } } -- cgit v1.2.3 From 20cfbdff79e19e77c24596cdca59c6694283e242 Mon Sep 17 00:00:00 2001 From: Rohit Sharma Date: Fri, 2 Apr 2021 00:21:55 +0530 Subject: Add missing things in `hide` method of dropdown (#33451) * Update `aria-expanded` attribute in `hide` method * Remove empty mouseover listeners added for iOS --- js/src/dropdown.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 605cbc64d..6b541ed15 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -218,12 +218,20 @@ class Dropdown extends BaseComponent { return } + // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + if ('ontouchstart' in document.documentElement) { + [].concat(...document.body.children) + .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop())) + } + if (this._popper) { this._popper.destroy() } this._menu.classList.toggle(CLASS_NAME_SHOW) this._element.classList.toggle(CLASS_NAME_SHOW) + this._element.setAttribute('aria-expanded', 'false') Manipulator.removeDataAttribute(this._menu, 'popper') EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget) } @@ -430,14 +438,13 @@ class Dropdown extends BaseComponent { .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop())) } - toggles[i].setAttribute('aria-expanded', 'false') - if (context._popper) { context._popper.destroy() } dropdownMenu.classList.remove(CLASS_NAME_SHOW) toggles[i].classList.remove(CLASS_NAME_SHOW) + toggles[i].setAttribute('aria-expanded', 'false') Manipulator.removeDataAttribute(dropdownMenu, 'popper') EventHandler.trigger(toggles[i], EVENT_HIDDEN, relatedTarget) } -- cgit v1.2.3 From b2bc159d722a640b684f12a1171d70c8d5284b4e Mon Sep 17 00:00:00 2001 From: Rohit Sharma Date: Sat, 27 Mar 2021 21:38:45 +0530 Subject: Use cached `noop` function everywhere --- js/src/dropdown.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 6b541ed15..3e1ef5fd4 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -192,7 +192,7 @@ class Dropdown extends BaseComponent { if ('ontouchstart' in document.documentElement && !parent.closest(SELECTOR_NAVBAR_NAV)) { [].concat(...document.body.children) - .forEach(elem => EventHandler.on(elem, 'mouseover', null, noop())) + .forEach(elem => EventHandler.on(elem, 'mouseover', null, noop)) } this._element.focus() @@ -222,7 +222,7 @@ class Dropdown extends BaseComponent { // empty mouseover listeners we added for iOS support if ('ontouchstart' in document.documentElement) { [].concat(...document.body.children) - .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop())) + .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop)) } if (this._popper) { @@ -435,7 +435,7 @@ class Dropdown extends BaseComponent { // empty mouseover listeners we added for iOS support if ('ontouchstart' in document.documentElement) { [].concat(...document.body.children) - .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop())) + .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop)) } if (context._popper) { -- cgit v1.2.3 From 5f946d3a86caa8c62a3a2bb279b4640f28c6930a Mon Sep 17 00:00:00 2001 From: Rohit Sharma Date: Sat, 27 Mar 2021 22:51:08 +0530 Subject: =?UTF-8?q?Dropdown=20=E2=80=94=20Don't=20use=20event=20delegation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/src/dropdown.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 3e1ef5fd4..7d5421a56 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -192,7 +192,7 @@ class Dropdown extends BaseComponent { if ('ontouchstart' in document.documentElement && !parent.closest(SELECTOR_NAVBAR_NAV)) { [].concat(...document.body.children) - .forEach(elem => EventHandler.on(elem, 'mouseover', null, noop)) + .forEach(elem => EventHandler.on(elem, 'mouseover', noop)) } this._element.focus() @@ -222,7 +222,7 @@ class Dropdown extends BaseComponent { // empty mouseover listeners we added for iOS support if ('ontouchstart' in document.documentElement) { [].concat(...document.body.children) - .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop)) + .forEach(elem => EventHandler.off(elem, 'mouseover', noop)) } if (this._popper) { @@ -435,7 +435,7 @@ class Dropdown extends BaseComponent { // empty mouseover listeners we added for iOS support if ('ontouchstart' in document.documentElement) { [].concat(...document.body.children) - .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop)) + .forEach(elem => EventHandler.off(elem, 'mouseover', noop)) } if (context._popper) { -- cgit v1.2.3 From 566451230f5c87c3d7515af02995895df610b8ac Mon Sep 17 00:00:00 2001 From: GeoSot Date: Sun, 11 Apr 2021 09:54:48 +0300 Subject: Remove element event listeners through base component (#33429) After some research, I found out that EventHandler saves all the custom events per element using namespace, and is capable of removing handlers using only the element and its namespace (`DATA_KEY`). So, probably is better to utilize the base-component to do the same job. --- js/src/dropdown.js | 1 - 1 file changed, 1 deletion(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 7d5421a56..b126d3196 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -237,7 +237,6 @@ class Dropdown extends BaseComponent { } dispose() { - EventHandler.off(this._element, EVENT_KEY) this._menu = null if (this._popper) { -- cgit v1.2.3 From ad10f00d5e073f60b8d86d03812742b97037c336 Mon Sep 17 00:00:00 2001 From: alpadev <2838324+alpadev@users.noreply.github.com> Date: Sun, 11 Apr 2021 17:34:46 +0200 Subject: refactor: make static `selectMenuItem` method private (#33589) --- js/src/dropdown.js | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index b126d3196..ae440e472 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -356,6 +356,31 @@ class Dropdown extends BaseComponent { } } + _selectMenuItem(event) { + const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible) + + if (!items.length) { + return + } + + let index = items.indexOf(event.target) + + // Up + if (event.key === ARROW_UP_KEY && index > 0) { + index-- + } + + // Down + if (event.key === ARROW_DOWN_KEY && index < items.length - 1) { + index++ + } + + // index is -1 if the first keydown is an ArrowUp + index = index === -1 ? 0 : index + + items[index].focus() + } + // Static static dropdownInterface(element, config) { @@ -449,31 +474,6 @@ class Dropdown extends BaseComponent { } } - static selectMenuItem(parent, event) { - const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, parent).filter(isVisible) - - if (!items.length) { - return - } - - let index = items.indexOf(event.target) - - // Up - if (event.key === ARROW_UP_KEY && index > 0) { - index-- - } - - // Down - if (event.key === ARROW_DOWN_KEY && index < items.length - 1) { - index++ - } - - // index is -1 if the first keydown is an ArrowUp - index = index === -1 ? 0 : index - - items[index].focus() - } - static getParentFromElement(element) { return getElementFromSelector(element) || element.parentNode } @@ -525,7 +525,7 @@ class Dropdown extends BaseComponent { return } - Dropdown.selectMenuItem(Dropdown.getParentFromElement(this), event) + Dropdown.getInstance(getToggleButton())._selectMenuItem(event) } } -- cgit v1.2.3 From 38a79ec64cf148cae16cd98f9f2c5bc174175cc9 Mon Sep 17 00:00:00 2001 From: Rohit Sharma Date: Wed, 24 Mar 2021 23:55:00 +0530 Subject: Refactor dropdown's hide functionality --- js/src/dropdown.js | 83 ++++++++++++++++++++++-------------------------------- 1 file changed, 33 insertions(+), 50 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index ae440e472..7561f9812 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -212,28 +212,7 @@ class Dropdown extends BaseComponent { relatedTarget: this._element } - const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget) - - if (hideEvent.defaultPrevented) { - return - } - - // If this is a touch-enabled device we remove the extra - // empty mouseover listeners we added for iOS support - if ('ontouchstart' in document.documentElement) { - [].concat(...document.body.children) - .forEach(elem => EventHandler.off(elem, 'mouseover', noop)) - } - - if (this._popper) { - this._popper.destroy() - } - - this._menu.classList.toggle(CLASS_NAME_SHOW) - this._element.classList.toggle(CLASS_NAME_SHOW) - this._element.setAttribute('aria-expanded', 'false') - Manipulator.removeDataAttribute(this._menu, 'popper') - EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget) + this._completeHide(relatedTarget) } dispose() { @@ -263,6 +242,30 @@ class Dropdown extends BaseComponent { }) } + _completeHide(relatedTarget) { + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget) + if (hideEvent.defaultPrevented) { + return + } + + // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + if ('ontouchstart' in document.documentElement) { + [].concat(...document.body.children) + .forEach(elem => EventHandler.off(elem, 'mouseover', noop)) + } + + if (this._popper) { + this._popper.destroy() + } + + this._menu.classList.toggle(CLASS_NAME_SHOW) + this._element.classList.toggle(CLASS_NAME_SHOW) + this._element.setAttribute('aria-expanded', 'false') + Manipulator.removeDataAttribute(this._menu, 'popper') + EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget) + } + _getConfig(config) { config = { ...this.constructor.Default, @@ -421,14 +424,6 @@ class Dropdown extends BaseComponent { for (let i = 0, len = toggles.length; i < len; i++) { const context = Data.get(toggles[i], DATA_KEY) - const relatedTarget = { - relatedTarget: toggles[i] - } - - if (event && event.type === 'click') { - relatedTarget.clickEvent = event - } - if (!context) { continue } @@ -438,6 +433,10 @@ class Dropdown extends BaseComponent { continue } + const relatedTarget = { + relatedTarget: toggles[i] + } + if (event) { // Don't close the menu if the clicked element or one of its parents is the dropdown button if ([context._element].some(element => event.composedPath().includes(element))) { @@ -448,29 +447,13 @@ class Dropdown extends BaseComponent { if (event.type === 'keyup' && event.key === TAB_KEY && dropdownMenu.contains(event.target)) { continue } - } - - const hideEvent = EventHandler.trigger(toggles[i], EVENT_HIDE, relatedTarget) - if (hideEvent.defaultPrevented) { - continue - } - // If this is a touch-enabled device we remove the extra - // empty mouseover listeners we added for iOS support - if ('ontouchstart' in document.documentElement) { - [].concat(...document.body.children) - .forEach(elem => EventHandler.off(elem, 'mouseover', noop)) - } - - if (context._popper) { - context._popper.destroy() + if (event.type === 'click') { + relatedTarget.clickEvent = event + } } - dropdownMenu.classList.remove(CLASS_NAME_SHOW) - toggles[i].classList.remove(CLASS_NAME_SHOW) - toggles[i].setAttribute('aria-expanded', 'false') - Manipulator.removeDataAttribute(dropdownMenu, 'popper') - EventHandler.trigger(toggles[i], EVENT_HIDDEN, relatedTarget) + context._completeHide(relatedTarget) } } -- cgit v1.2.3 From bce4684d3400c8ed49060d5888904d0486e51b0f Mon Sep 17 00:00:00 2001 From: Rohit Sharma Date: Wed, 14 Apr 2021 14:54:39 +0530 Subject: Use context properties --- js/src/dropdown.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 7561f9812..dac7368c2 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -428,13 +428,12 @@ class Dropdown extends BaseComponent { continue } - const dropdownMenu = context._menu - if (!toggles[i].classList.contains(CLASS_NAME_SHOW)) { + if (!context._element.classList.contains(CLASS_NAME_SHOW)) { continue } const relatedTarget = { - relatedTarget: toggles[i] + relatedTarget: context._element } if (event) { @@ -444,7 +443,7 @@ class Dropdown extends BaseComponent { } // Tab navigation through the dropdown menu shouldn't close the menu - if (event.type === 'keyup' && event.key === TAB_KEY && dropdownMenu.contains(event.target)) { + if (event.type === 'keyup' && event.key === TAB_KEY && context._menu.contains(event.target)) { continue } -- cgit v1.2.3 From 7eadf73f03eeb51160a455c6438a9ec16ad107a4 Mon Sep 17 00:00:00 2001 From: Rohit Sharma Date: Wed, 14 Apr 2021 15:27:33 +0530 Subject: Change `toggle` method to `remove` Since the class `.show` must be removed --- js/src/dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index dac7368c2..c314cbcdd 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -259,8 +259,8 @@ class Dropdown extends BaseComponent { this._popper.destroy() } - this._menu.classList.toggle(CLASS_NAME_SHOW) - this._element.classList.toggle(CLASS_NAME_SHOW) + this._menu.classList.remove(CLASS_NAME_SHOW) + this._element.classList.remove(CLASS_NAME_SHOW) this._element.setAttribute('aria-expanded', 'false') Manipulator.removeDataAttribute(this._menu, 'popper') EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget) -- cgit v1.2.3 From 6d312b37c264ac1e4ac244674e6fe700e75f6aa2 Mon Sep 17 00:00:00 2001 From: alpadev <2838324+alpadev@users.noreply.github.com> Date: Sun, 18 Apr 2021 08:01:23 +0200 Subject: fix: clicking an item in navbar dropdown collapses the dropdown in firefox (#33643) --- js/src/dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index c314cbcdd..2fc2cde21 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -415,7 +415,7 @@ class Dropdown extends BaseComponent { return } - if (/input|select|textarea|form/i.test(event.target.tagName)) { + if (/input|select|option|textarea|form/i.test(event.target.tagName)) { return } } -- cgit v1.2.3 From b59b75bc55ad9d5d2d0259f6b3364a7bcb82b033 Mon Sep 17 00:00:00 2001 From: Rohit Sharma Date: Tue, 20 Apr 2021 10:49:57 +0530 Subject: =?UTF-8?q?Dropdown=20=E2=80=94=20Add=20option=20to=20make=20the?= =?UTF-8?q?=20dropdown=20menu=20clickable=20(#33389)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/src/dropdown.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 2fc2cde21..d26fa96ca 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -75,7 +75,8 @@ const Default = { boundary: 'clippingParents', reference: 'toggle', display: 'dynamic', - popperConfig: null + popperConfig: null, + autoClose: true } const DefaultType = { @@ -83,7 +84,8 @@ const DefaultType = { boundary: '(string|element)', reference: '(string|element|object)', display: 'string', - popperConfig: '(null|object|function)' + popperConfig: '(null|object|function)', + autoClose: '(boolean|string)' } /** @@ -127,9 +129,8 @@ class Dropdown extends BaseComponent { const isActive = this._element.classList.contains(CLASS_NAME_SHOW) - Dropdown.clearMenus() - if (isActive) { + this.hide() return } @@ -424,7 +425,7 @@ class Dropdown extends BaseComponent { for (let i = 0, len = toggles.length; i < len; i++) { const context = Data.get(toggles[i], DATA_KEY) - if (!context) { + if (!context || context._config.autoClose === false) { continue } @@ -437,8 +438,13 @@ class Dropdown extends BaseComponent { } if (event) { - // Don't close the menu if the clicked element or one of its parents is the dropdown button - if ([context._element].some(element => event.composedPath().includes(element))) { + const composedPath = event.composedPath() + const isMenuTarget = composedPath.includes(context._menu) + if ( + composedPath.includes(context._element) || + (context._config.autoClose === 'inside' && !isMenuTarget) || + (context._config.autoClose === 'outside' && isMenuTarget) + ) { continue } -- cgit v1.2.3 From bf0936748602c8109fd916c64b4560799fa1c3f8 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Wed, 5 May 2021 22:32:12 +0300 Subject: Release v5.0.0 (#33647) * Bump version to 5.0.0 * Fix npm tag * Dist --- js/src/dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index d26fa96ca..bb2d01c27 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -1,6 +1,6 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.0-beta3): dropdown.js + * Bootstrap (v5.0.0): dropdown.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ -- cgit v1.2.3 From 03842b5f259d6007db02c465e6c55929e551e9cd Mon Sep 17 00:00:00 2001 From: GeoSot Date: Tue, 11 May 2021 09:04:42 +0300 Subject: Refactor: move disposing properties into the base class (#33740) Moves more functionality to `base-component`, transferring the responsibility of disposal to parent class. Each component, dusting disposal, sets its protected properties to `null`. So the same can be done in one place for all children components . --- js/src/dropdown.js | 3 --- 1 file changed, 3 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index bb2d01c27..8bd3f01e7 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -217,11 +217,8 @@ class Dropdown extends BaseComponent { } dispose() { - this._menu = null - if (this._popper) { this._popper.destroy() - this._popper = null } super.dispose() -- cgit v1.2.3 From 7647b8fe5b77120ba319e7119bb0515d91f734da Mon Sep 17 00:00:00 2001 From: alpadev <2838324+alpadev@users.noreply.github.com> Date: Tue, 11 May 2021 08:09:00 +0200 Subject: Fix: Click on input outside of dropdown-menu prevents dropdown from closing (#33920) * test: add test if user clicks on input not contained within dropdown-menu * fix: click on inputs that are not contained within dropdown-menu prevent dropdown from closing --- js/src/dropdown.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 8bd3f01e7..f56ab201b 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -408,14 +408,8 @@ class Dropdown extends BaseComponent { } static clearMenus(event) { - if (event) { - if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) { - return - } - - if (/input|select|option|textarea|form/i.test(event.target.tagName)) { - return - } + if (event && (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY))) { + return } const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE) @@ -445,8 +439,8 @@ class Dropdown extends BaseComponent { continue } - // Tab navigation through the dropdown menu shouldn't close the menu - if (event.type === 'keyup' && event.key === TAB_KEY && context._menu.contains(event.target)) { + // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu + if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) { continue } -- cgit v1.2.3 From 9fe36edf683af02574bf6bbd6c9b27de93bd31b1 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Tue, 11 May 2021 10:49:30 +0300 Subject: 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 --- js/src/dropdown.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index f56ab201b..8f501d811 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 -- cgit v1.2.3 From 6e1c9096f08ed21063fd6ba16aa998a3ac4149f9 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 13 May 2021 18:17:20 +0300 Subject: Move get element functionality to a helper (#33327) Looking around on js components I found out many checks, different expressed but with same purpose. Some of them are trying to parse string to element, others, jQuery element to js simple nodeElement etc With this Pr, I am trying to give a standard way to parse an element So this pr: * Creates `getElement` helper that tries to parse an argument to element or null * Changes `isElement` to make explicit checks and return Boolean * fixes tests deficiencies --- js/src/dropdown.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 8f501d811..3eb5891f8 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -9,6 +9,7 @@ import * as Popper from '@popperjs/core' import { defineJQueryPlugin, + getElement, getElementFromSelector, isDisabled, isElement, @@ -166,12 +167,7 @@ class Dropdown extends BaseComponent { if (this._config.reference === 'parent') { referenceElement = parent } else if (isElement(this._config.reference)) { - referenceElement = this._config.reference - - // Check if it's jQuery element - if (typeof this._config.reference.jquery !== 'undefined') { - referenceElement = this._config.reference[0] - } + referenceElement = getElement(this._config.reference) } else if (typeof this._config.reference === 'object') { referenceElement = this._config.reference } -- cgit v1.2.3 From 58b1be927f43c779377e478df2d119f2ddf956ca Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Thu, 13 May 2021 19:22:20 +0300 Subject: Release v5.0.1 (#33972) * Bump version to 5.0.1. * Dist --- js/src/dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 3eb5891f8..565edb892 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -1,6 +1,6 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.0): dropdown.js + * Bootstrap (v5.0.1): dropdown.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ -- cgit v1.2.3 From df72a21fa89a4885bb666f4a3bc0a9e757b870c2 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Wed, 19 May 2021 01:23:52 +0300 Subject: Add `getNextActiveElement` helper function to utils, replacing custom implementation through components (#33608) --- js/src/dropdown.js | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 565edb892..cab2d018b 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -16,6 +16,7 @@ import { isVisible, isRTL, noop, + getNextActiveElement, typeCheckConfig } from './util/index' import Data from './dom/data' @@ -354,28 +355,17 @@ class Dropdown extends BaseComponent { } _selectMenuItem(event) { - const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible) - - if (!items.length) { + if (![ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)) { return } - let index = items.indexOf(event.target) - - // Up - if (event.key === ARROW_UP_KEY && index > 0) { - index-- - } + const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible) - // Down - if (event.key === ARROW_DOWN_KEY && index < items.length - 1) { - index++ + if (!items.length) { + return } - // index is -1 if the first keydown is an ArrowUp - index = index === -1 ? 0 : index - - items[index].focus() + getNextActiveElement(items, event.target, event.key === ARROW_DOWN_KEY, false).focus() } // Static -- cgit v1.2.3 From b39b665072a2d36914e741b2c11620323924be89 Mon Sep 17 00:00:00 2001 From: alpadev <2838324+alpadev@users.noreply.github.com> Date: Sat, 22 May 2021 09:58:52 +0200 Subject: Automatically select an item in the dropdown when using arrow keys (#34052) --- js/src/dropdown.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index cab2d018b..34beb6512 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -354,18 +354,16 @@ class Dropdown extends BaseComponent { } } - _selectMenuItem(event) { - if (![ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)) { - return - } - + _selectMenuItem({ key, target }) { const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible) if (!items.length) { return } - getNextActiveElement(items, event.target, event.key === ARROW_DOWN_KEY, false).focus() + // if target isn't included in items (e.g. when expanding the dropdown) + // allow cycling to get the last item in case key equals ARROW_UP_KEY + getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus() } // Static @@ -480,17 +478,18 @@ class Dropdown extends BaseComponent { return } - if (!isActive && (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY)) { - getToggleButton().click() + if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) { + if (!isActive) { + getToggleButton().click() + } + + Dropdown.getInstance(getToggleButton())._selectMenuItem(event) return } if (!isActive || event.key === SPACE_KEY) { Dropdown.clearMenus() - return } - - Dropdown.getInstance(getToggleButton())._selectMenuItem(event) } } -- cgit v1.2.3 From c98657b8303150bfda3bdea750055b83a29b27a3 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 3 Jun 2021 18:53:27 +0300 Subject: Add `getOrCreateInstance` method in base-component (#33276) Co-authored-by: Rohit Sharma Co-authored-by: XhmikosR --- js/src/dropdown.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 34beb6512..e79ac4591 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -19,7 +19,6 @@ import { getNextActiveElement, typeCheckConfig } from './util/index' -import Data from './dom/data' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' @@ -369,12 +368,7 @@ class Dropdown extends BaseComponent { // Static static dropdownInterface(element, config) { - let data = Data.get(element, DATA_KEY) - const _config = typeof config === 'object' ? config : null - - if (!data) { - data = new Dropdown(element, _config) - } + const data = Dropdown.getOrCreateInstance(element, config) if (typeof config === 'string') { if (typeof data[config] === 'undefined') { @@ -399,7 +393,7 @@ class Dropdown extends BaseComponent { const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE) for (let i = 0, len = toggles.length; i < len; i++) { - const context = Data.get(toggles[i], DATA_KEY) + const context = Dropdown.getInstance(toggles[i]) if (!context || context._config.autoClose === false) { continue } -- cgit v1.2.3 From 688bce4fa695cc360a0d084e34f029b0c192b223 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Tue, 22 Jun 2021 21:29:16 +0300 Subject: Release v5.0.2 (#34276) * Bump version to v5.0.2. * Dist --- js/src/dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index e79ac4591..681369b48 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -1,6 +1,6 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.1): dropdown.js + * Bootstrap (v5.0.2): dropdown.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ -- cgit v1.2.3 From d3c6f25fd0cc811a681f3a6b88708c04b2c9b797 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 10 Jun 2021 17:51:01 +0300 Subject: Add `isShown` method and reuse it --- js/src/dropdown.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 681369b48..d9bd903c1 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -11,12 +11,12 @@ import { defineJQueryPlugin, getElement, getElementFromSelector, + getNextActiveElement, isDisabled, isElement, - isVisible, isRTL, + isVisible, noop, - getNextActiveElement, typeCheckConfig } from './util/index' import EventHandler from './dom/event-handler' @@ -128,7 +128,7 @@ class Dropdown extends BaseComponent { return } - const isActive = this._element.classList.contains(CLASS_NAME_SHOW) + const isActive = this._isShown() if (isActive) { this.hide() @@ -139,7 +139,7 @@ class Dropdown extends BaseComponent { } show() { - if (isDisabled(this._element) || this._menu.classList.contains(CLASS_NAME_SHOW)) { + if (isDisabled(this._element) || this._isShown(this._menu)) { return } @@ -201,7 +201,7 @@ class Dropdown extends BaseComponent { } hide() { - if (isDisabled(this._element) || !this._menu.classList.contains(CLASS_NAME_SHOW)) { + if (isDisabled(this._element) || !this._isShown(this._menu)) { return } @@ -279,6 +279,10 @@ class Dropdown extends BaseComponent { return config } + _isShown(element = this._element) { + return element.classList.contains(CLASS_NAME_SHOW) + } + _getMenuElement() { return SelectorEngine.next(this._element, SELECTOR_MENU)[0] } @@ -398,7 +402,7 @@ class Dropdown extends BaseComponent { continue } - if (!context._element.classList.contains(CLASS_NAME_SHOW)) { + if (!context._isShown()) { continue } -- cgit v1.2.3 From 3533e2d637d694b5b11a65c7911c3dc45d131e42 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 10 Jun 2021 17:56:43 +0300 Subject: Merge `dropdownInterface` to `jQueryInterface` --- js/src/dropdown.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index d9bd903c1..09414c97b 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -371,21 +371,19 @@ class Dropdown extends BaseComponent { // Static - static dropdownInterface(element, config) { - const data = Dropdown.getOrCreateInstance(element, config) + static jQueryInterface(config) { + return this.each(function () { + const data = Dropdown.getOrCreateInstance(this, config) + + if (typeof config !== 'string') { + return + } - if (typeof config === 'string') { if (typeof data[config] === 'undefined') { throw new TypeError(`No method named "${config}"`) } data[config]() - } - } - - static jQueryInterface(config) { - return this.each(function () { - Dropdown.dropdownInterface(this, config) }) } @@ -503,7 +501,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus) EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus) EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { event.preventDefault() - Dropdown.dropdownInterface(this) + Dropdown.getOrCreateInstance(this) }) /** -- cgit v1.2.3 From d130b00cad9552feb313cbd04486bd179b7295df Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 8 Jul 2021 17:42:09 +0300 Subject: simplify toggle --- js/src/dropdown.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 09414c97b..be561b128 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -124,18 +124,7 @@ class Dropdown extends BaseComponent { // Public toggle() { - if (isDisabled(this._element)) { - return - } - - const isActive = this._isShown() - - if (isActive) { - this.hide() - return - } - - this.show() + return this._isShown() ? this.hide() : this.show() } show() { -- cgit v1.2.3 From d01a08547def495cb1c814ffaecb9d36cad14acd Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 8 Jul 2021 17:54:15 +0300 Subject: use classList `add` instead of `toggle` on show --- js/src/dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index be561b128..1e0029a60 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -184,8 +184,8 @@ class Dropdown extends BaseComponent { this._element.focus() this._element.setAttribute('aria-expanded', true) - this._menu.classList.toggle(CLASS_NAME_SHOW) - this._element.classList.toggle(CLASS_NAME_SHOW) + this._menu.classList.add(CLASS_NAME_SHOW) + this._element.classList.add(CLASS_NAME_SHOW) EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget) } -- cgit v1.2.3 From b1dad0943f4fc8c6eb6bf58f5e38a5615dd78e5b Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 8 Jul 2021 17:59:18 +0300 Subject: handle click event in one place, remove undocumented click listener on element in case of not having the proper markup --- js/src/dropdown.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 1e0029a60..95752d998 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -48,7 +48,6 @@ const EVENT_HIDE = `hide${EVENT_KEY}` const EVENT_HIDDEN = `hidden${EVENT_KEY}` const EVENT_SHOW = `show${EVENT_KEY}` const EVENT_SHOWN = `shown${EVENT_KEY}` -const EVENT_CLICK = `click${EVENT_KEY}` const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}` const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}` @@ -103,8 +102,6 @@ class Dropdown extends BaseComponent { this._config = this._getConfig(config) this._menu = this._getMenuElement() this._inNavbar = this._detectNavbar() - - this._addEventListeners() } // Getters @@ -218,13 +215,6 @@ class Dropdown extends BaseComponent { // Private - _addEventListeners() { - EventHandler.on(this._element, EVENT_CLICK, event => { - event.preventDefault() - this.toggle() - }) - } - _completeHide(relatedTarget) { const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget) if (hideEvent.defaultPrevented) { @@ -490,7 +480,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus) EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus) EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { event.preventDefault() - Dropdown.getOrCreateInstance(this) + Dropdown.getOrCreateInstance(this).toggle() }) /** -- cgit v1.2.3 From 99161913115fa4637cb7ab723bbae3fd552d0d09 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 8 Jul 2021 18:23:54 +0300 Subject: extract createPopper method --- js/src/dropdown.js | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 95752d998..60a27dbb0 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -129,7 +129,6 @@ class Dropdown extends BaseComponent { return } - const parent = Dropdown.getParentFromElement(this._element) const relatedTarget = { relatedTarget: this._element } @@ -140,32 +139,12 @@ class Dropdown extends BaseComponent { return } + const parent = Dropdown.getParentFromElement(this._element) // Totally disable Popper for Dropdowns in Navbar if (this._inNavbar) { Manipulator.setDataAttribute(this._menu, 'popper', 'none') } else { - if (typeof Popper === 'undefined') { - throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)') - } - - let referenceElement = this._element - - if (this._config.reference === 'parent') { - referenceElement = parent - } else if (isElement(this._config.reference)) { - referenceElement = getElement(this._config.reference) - } else if (typeof this._config.reference === 'object') { - referenceElement = this._config.reference - } - - const popperConfig = this._getPopperConfig() - const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false) - - this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig) - - if (isDisplayStatic) { - Manipulator.setDataAttribute(this._menu, 'popper', 'static') - } + this._createPopper(parent) } // If this is a touch-enabled device we add extra @@ -258,6 +237,31 @@ class Dropdown extends BaseComponent { return config } + _createPopper(parent) { + if (typeof Popper === 'undefined') { + throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)') + } + + let referenceElement = this._element + + if (this._config.reference === 'parent') { + referenceElement = parent + } else if (isElement(this._config.reference)) { + referenceElement = getElement(this._config.reference) + } else if (typeof this._config.reference === 'object') { + referenceElement = this._config.reference + } + + const popperConfig = this._getPopperConfig() + const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false) + + this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig) + + if (isDisplayStatic) { + Manipulator.setDataAttribute(this._menu, 'popper', 'static') + } + } + _isShown(element = this._element) { return element.classList.contains(CLASS_NAME_SHOW) } -- cgit v1.2.3 From e85a6ed77c92ee43cf23b5c6ce479dbd0100be66 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 8 Jul 2021 18:44:58 +0300 Subject: make `dataApiKeydownHandler` to handle specific instance, avoiding extra manipulations --- js/src/dropdown.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 60a27dbb0..52c5339fa 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -449,20 +449,20 @@ class Dropdown extends BaseComponent { return } - const getToggleButton = () => this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] + const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] + const instance = Dropdown.getOrCreateInstance(getToggleButton) if (event.key === ESCAPE_KEY) { - getToggleButton().focus() - Dropdown.clearMenus() + instance.hide() return } if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) { if (!isActive) { - getToggleButton().click() + instance.show() } - Dropdown.getInstance(getToggleButton())._selectMenuItem(event) + instance._selectMenuItem(event) return } -- cgit v1.2.3 From f20fece3a8cdd0e76a42c2737524b7652bf54d26 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Wed, 4 Aug 2021 18:41:51 +0300 Subject: Prepare v5.1.0. (#34674) --- js/src/dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src/dropdown.js') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 52c5339fa..d1f573fc8 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -1,6 +1,6 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.2): dropdown.js + * Bootstrap (v5.1.0): dropdown.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ -- cgit v1.2.3