From: GeoSot Date: Fri, 10 Dec 2021 01:09:48 +0000 (+0200) Subject: Initial approach on generic triggering X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=5cfefe8d66cafb2fbdd5b9fae0305c3c72eddae0;p=thirdparty%2Fbootstrap.git Initial approach on generic triggering --- diff --git a/js/index.esm.js b/js/index.esm.js index 51a9ff8ea2..b94eaba403 100644 --- a/js/index.esm.js +++ b/js/index.esm.js @@ -5,6 +5,8 @@ * -------------------------------------------------------------------------- */ +import { enableMagicActions } from './src/dom/magic-actions' + export { default as Alert } from './src/alert' export { default as Button } from './src/button' export { default as Carousel } from './src/carousel' @@ -17,3 +19,5 @@ export { default as ScrollSpy } from './src/scrollspy' export { default as Tab } from './src/tab' export { default as Toast } from './src/toast' export { default as Tooltip } from './src/tooltip' + +enableMagicActions() diff --git a/js/index.umd.js b/js/index.umd.js index d6e587fb1d..a78b91743c 100644 --- a/js/index.umd.js +++ b/js/index.umd.js @@ -17,6 +17,7 @@ import ScrollSpy from './src/scrollspy' import Tab from './src/tab' import Toast from './src/toast' import Tooltip from './src/tooltip' +import { enableMagicActions } from './src/dom/magic-actions' export default { Alert, @@ -32,3 +33,5 @@ export default { Toast, Tooltip } + +enableMagicActions() diff --git a/js/src/alert.js b/js/src/alert.js index 7d4b555ea0..366de74757 100644 --- a/js/src/alert.js +++ b/js/src/alert.js @@ -8,7 +8,7 @@ import { defineJQueryPlugin } from './util/index' import EventHandler from './dom/event-handler' import BaseComponent from './base-component' -import { enableDismissTrigger } from './util/component-functions' +import { enableDismissTrigger } from './dom/magic-actions' /** * Constants diff --git a/js/src/dom/magic-actions.js b/js/src/dom/magic-actions.js new file mode 100644 index 0000000000..a7e7de419f --- /dev/null +++ b/js/src/dom/magic-actions.js @@ -0,0 +1,96 @@ +/** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): util/component-functions.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + +import EventHandler from './event-handler' +import { getElementFromSelector, isDisabled } from '../util/index' + +const parseAction = action => { + const split = action.split(':') + const pluginName = split[1] + return { + onEvent: split[0], + pluginName: pluginName.charAt(0).toUpperCase() + pluginName.slice(1), + method: split[2] + } +} + +const supportedEvents = [ + 'keyup', + 'keydown', + 'mousedown', + 'mouseup', + 'click', + 'mouseenter', + 'mouseleave', + 'click', + 'focus' +] + +const enableMagicActions = () => { + for (const eventName of supportedEvents) { + enableMagicActionForEvent(eventName) + } +} + +const enableMagicActionForEvent = onEvent => { + eventAction(onEvent, `[data-bs-act^="${onEvent}:"]`, data => { + const action = parseAction(data.event.target.getAttribute('data-bs-act')) + + const plugin = window.bootstrap[action.pluginName] || null + if (!plugin) { + throw new TypeError(`You are trying to use plugin "${action.pluginName}", which it doesn't exist in our library`) + } + + const instance = plugin.getOrCreateInstance(data.target) + instance[action.method]() + }) +} + +const eventActionOnPlugin = (Plugin, onEvent, stringSelector, method, callback = null) => { + eventAction(`${onEvent}.${Plugin.NAME}`, stringSelector, data => { + const instance = Plugin.getOrCreateInstance(data.target) + if (typeof callback === 'function') { + callback({ ...data, instance }) + } + + instance[method]() + }) +} + +const eventAction = (onEvent, stringSelector, callback) => { + EventHandler.on(document, onEvent, stringSelector, event => { + const eventTarget = event.target + + if (['A', 'AREA'].includes(eventTarget.tagName)) { + event.preventDefault() + } + + if (isDisabled(eventTarget)) { + return + } + + const target = getElementFromSelector(eventTarget) || eventTarget + callback({ target, event }) + }) +} + +const enableDismissTrigger = (component, method = 'hide') => { + const name = component.NAME + eventAction(`click.${name}`, `[data-bs-dismiss="${name}"]`, event => { + const target = getElementFromSelector(event.target) || event.target.closest(`.${name}`) + const instance = component.getOrCreateInstance(target) + + // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method + instance[method]() + }) +} + +export { + enableDismissTrigger, + enableMagicActions, + eventActionOnPlugin +} diff --git a/js/src/offcanvas.js b/js/src/offcanvas.js index 2735a9c2ae..e92b8177a6 100644 --- a/js/src/offcanvas.js +++ b/js/src/offcanvas.js @@ -7,8 +7,6 @@ import { defineJQueryPlugin, - getElementFromSelector, - isDisabled, isVisible } from './util/index' import ScrollBarHelper from './util/scrollbar' @@ -17,7 +15,7 @@ import BaseComponent from './base-component' import SelectorEngine from './dom/selector-engine' import Backdrop from './util/backdrop' import FocusTrap from './util/focustrap' -import { enableDismissTrigger } from './util/component-functions' +import { enableDismissTrigger, eventActionOnPlugin } from './dom/magic-actions' /** * Constants @@ -40,7 +38,6 @@ const EVENT_SHOW = `show${EVENT_KEY}` const EVENT_SHOWN = `shown${EVENT_KEY}` const EVENT_HIDE = `hide${EVENT_KEY}` const EVENT_HIDDEN = `hidden${EVENT_KEY}` -const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}` const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]' @@ -209,32 +206,19 @@ class Offcanvas extends BaseComponent { * Data API implementation */ -EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { - const target = getElementFromSelector(this) - - if (['A', 'AREA'].includes(this.tagName)) { - event.preventDefault() - } - - if (isDisabled(this)) { - return - } - - EventHandler.one(target, EVENT_HIDDEN, () => { +eventActionOnPlugin(Offcanvas, 'click', SELECTOR_DATA_TOGGLE, 'toggle', data => { + EventHandler.one(data.target, EVENT_HIDDEN, () => { // focus on trigger when it is closed - if (isVisible(this)) { - this.focus() + if (isVisible(data.event.target)) { + data.event.target.focus() } }) // avoid conflict when clicking a toggler of an offcanvas, while another is open const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR) - if (alreadyOpen && alreadyOpen !== target) { + if (alreadyOpen && alreadyOpen !== data.target) { Offcanvas.getInstance(alreadyOpen).hide() } - - const data = Offcanvas.getOrCreateInstance(target) - data.toggle(this) }) EventHandler.on(window, EVENT_LOAD_DATA_API, () => { diff --git a/js/src/toast.js b/js/src/toast.js index b85e20b605..4a4e0d0672 100644 --- a/js/src/toast.js +++ b/js/src/toast.js @@ -8,7 +8,7 @@ import { defineJQueryPlugin, reflow } from './util/index' import EventHandler from './dom/event-handler' import BaseComponent from './base-component' -import { enableDismissTrigger } from './util/component-functions' +import { enableDismissTrigger } from './dom/magic-actions' /** * Constants diff --git a/js/src/util/component-functions.js b/js/src/util/component-functions.js deleted file mode 100644 index bd44c3fdc4..0000000000 --- a/js/src/util/component-functions.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v5.1.3): util/component-functions.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -import EventHandler from '../dom/event-handler' -import { getElementFromSelector, isDisabled } from './index' - -const enableDismissTrigger = (component, method = 'hide') => { - const clickEvent = `click.dismiss${component.EVENT_KEY}` - const name = component.NAME - - EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) { - if (['A', 'AREA'].includes(this.tagName)) { - event.preventDefault() - } - - if (isDisabled(this)) { - return - } - - const target = getElementFromSelector(this) || this.closest(`.${name}`) - const instance = component.getOrCreateInstance(target) - - // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method - instance[method]() - }) -} - -export { - enableDismissTrigger -} diff --git a/js/tests/unit/util/component-functions.spec.js b/js/tests/unit/util/component-functions.spec.js index 16f910a633..e3729381a5 100644 --- a/js/tests/unit/util/component-functions.spec.js +++ b/js/tests/unit/util/component-functions.spec.js @@ -1,8 +1,8 @@ /* Test helpers */ import { clearFixture, createEvent, getFixture } from '../../helpers/fixture' -import { enableDismissTrigger } from '../../../src/util/component-functions' import BaseComponent from '../../../src/base-component' +import { enableDismissTrigger } from '../../../src/dom/magic-actions' class DummyClass2 extends BaseComponent { static get NAME() { diff --git a/site/content/docs/5.1/components/alerts.md b/site/content/docs/5.1/components/alerts.md index 27feda5775..fbc95dd253 100644 --- a/site/content/docs/5.1/components/alerts.md +++ b/site/content/docs/5.1/components/alerts.md @@ -8,6 +8,9 @@ toc: true ## Examples + +
Working example. Click on it
+
NOT working example. Click on it
Alerts are available for any length of text, as well as an optional close button. For proper styling, use one of the eight **required** contextual classes (e.g., `.alert-success`). For inline dismissal, use the [alerts JavaScript plugin](#dismissing). {{< example >}}