* --------------------------------------------------------------------------
*/
+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'
export { default as Tab } from './src/tab'
export { default as Toast } from './src/toast'
export { default as Tooltip } from './src/tooltip'
+
+enableMagicActions()
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,
Toast,
Tooltip
}
+
+enableMagicActions()
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
--- /dev/null
+/**
+ * --------------------------------------------------------------------------
+ * 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
+}
import {
defineJQueryPlugin,
- getElementFromSelector,
- isDisabled,
isVisible
} from './util/index'
import ScrollBarHelper from './util/scrollbar'
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
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"]'
* 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, () => {
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
+++ /dev/null
-/**
- * --------------------------------------------------------------------------
- * 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
-}
/* 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() {
## Examples
+
+<div class="alert alert-primary" data-bs-act="click:alert:close">Working example. Click on it</div>
+<div class="alert alert-danger" data-bs-act="click:kalert:close">NOT working example. Click on it</div>
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 >}}