diff options
author | GeoSot <geo.sotis@gmail.com> | 2022-02-19 23:39:07 +0300 |
---|---|---|
committer | GeoSot <geo.sotis@gmail.com> | 2022-05-20 02:10:15 +0300 |
commit | 7a1473aaa4f6025fb244c1d2a038b38286d34364 (patch) | |
tree | 2774e655e961227a76300ee0ba2e145f7b710413 | |
parent | 416f4905f13c2ca3096343e0a5a4934c8c0ced3f (diff) |
Provide a simple attribute toggling plugings/make-simple-attribute-toggler
-rw-r--r-- | js/index.esm.js | 1 | ||||
-rw-r--r-- | js/index.umd.js | 2 | ||||
-rw-r--r-- | js/src/toggler.js | 104 | ||||
-rw-r--r-- | js/src/util/component-functions.js | 33 | ||||
-rw-r--r-- | site/content/docs/5.1/components/toggler.md | 168 | ||||
-rw-r--r-- | site/data/sidebar.yml | 1 |
6 files changed, 307 insertions, 2 deletions
diff --git a/js/index.esm.js b/js/index.esm.js index 0c03cb2ecb..0470ec260b 100644 --- a/js/index.esm.js +++ b/js/index.esm.js @@ -16,4 +16,5 @@ export { default as Popover } from './src/popover' export { default as ScrollSpy } from './src/scrollspy' export { default as Tab } from './src/tab' export { default as Toast } from './src/toast' +export { default as Toggler } from './src/toggler' export { default as Tooltip } from './src/tooltip' diff --git a/js/index.umd.js b/js/index.umd.js index d4a5ee338d..c03a7e1f40 100644 --- a/js/index.umd.js +++ b/js/index.umd.js @@ -16,6 +16,7 @@ import Popover from './src/popover' import ScrollSpy from './src/scrollspy' import Tab from './src/tab' import Toast from './src/toast' +import Toggler from './src/toggler' import Tooltip from './src/tooltip' export default { @@ -30,5 +31,6 @@ export default { ScrollSpy, Tab, Toast, + Toggler, Tooltip } diff --git a/js/src/toggler.js b/js/src/toggler.js new file mode 100644 index 0000000000..d778bfaa6c --- /dev/null +++ b/js/src/toggler.js @@ -0,0 +1,104 @@ +/** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): toggler.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + +import { defineJQueryPlugin } from './util/index' +import EventHandler from './dom/event-handler' +import BaseComponent from './base-component' +import { eventActionOnPlugin } from './util/component-functions' + +/** + * Constants + */ + +const NAME = 'toggler' +const DATA_KEY = 'bs.toggle' +const EVENT_KEY = `.${DATA_KEY}` + +const EVENT_TOGGLE = `toggle${EVENT_KEY}` +const EVENT_TOGGLED = `toggled${EVENT_KEY}` +const EVENT_CLICK = 'click' + +const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="toggler"]' + +const DefaultType = { + attribute: 'string', + value: '(string|number|boolean)' +} + +const Default = { + attribute: 'class', + value: null +} + +/** + * Class definition + */ + +class Toggler extends BaseComponent { + // Getters + static get Default() { + return Default + } + + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + + _configAfterMerge(config) { + return config + } + + // Private + toggle() { + const toggleEvent = EventHandler.trigger(this._element, EVENT_TOGGLE) + + if (toggleEvent.defaultPrevented) { + return + } + + this._execute() + + EventHandler.trigger(this._element, EVENT_TOGGLED) + } + + _execute() { + const { attribute, value } = this._config + + if (attribute === 'id') { + return // You have to be kidding + } + + if (attribute === 'class') { + this._element.classList.toggle(value) + return + } + + if (this._element.getAttribute(attribute) === value) { + this._element.removeAttribute(attribute) + return + } + + this._element.setAttribute(attribute, value) + } +} + +/** + * Data API implementation + */ + +eventActionOnPlugin(Toggler, EVENT_CLICK, SELECTOR_DATA_TOGGLE, 'toggle') +/** + * jQuery + */ + +defineJQueryPlugin(Toggler) + +export default Toggler diff --git a/js/src/util/component-functions.js b/js/src/util/component-functions.js index f1f0701c55..4966387879 100644 --- a/js/src/util/component-functions.js +++ b/js/src/util/component-functions.js @@ -6,7 +6,8 @@ */ import EventHandler from '../dom/event-handler' -import { getElementFromSelector, isDisabled } from './index' +import { getElementFromSelector, getSelectorFromElement, isDisabled } from './index' +import SelectorEngine from '../dom/selector-engine' const enableDismissTrigger = (component, method = 'hide') => { const clickEvent = `click.dismiss${component.EVENT_KEY}` @@ -29,6 +30,34 @@ const enableDismissTrigger = (component, method = 'hide') => { }) } +const eventActionOnPlugin = (Plugin, onEvent, stringSelector, method, callback = null) => { + eventAction(`${onEvent}.${Plugin.NAME}`, stringSelector, data => { + const instances = data.targets.filter(Boolean).map(element => Plugin.getOrCreateInstance(element)) + if (typeof callback === 'function') { + callback({ ...data, instances }) + } + + for (const instance of instances) { + instance[method]() + } + }) +} + +const eventAction = (onEvent, stringSelector, callback) => { + const selector = `${stringSelector}:not(.disabled):not(:disabled)` + EventHandler.on(document, onEvent, selector, function (event) { + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault() + } + + const selector = getSelectorFromElement(this) + const targets = selector ? SelectorEngine.find(selector) : [this] + + callback({ targets, event }) + }) +} + export { - enableDismissTrigger + enableDismissTrigger, + eventActionOnPlugin } diff --git a/site/content/docs/5.1/components/toggler.md b/site/content/docs/5.1/components/toggler.md new file mode 100644 index 0000000000..80dd768eba --- /dev/null +++ b/site/content/docs/5.1/components/toggler.md @@ -0,0 +1,168 @@ +--- +layout: docs +title: Attribute Toggler +description: Toggle attributes or classes, using simple html markup +group: components +toc: true +--- + +## How it works + +Attribute Toggler is a simple component, that preferable can be used to avoid writing small JavaScript snippets handle attributes toggling, during `click` events. +Manipulation id done on the same element or on a targeted element + +**Heads up!** Toggler may handle all attributes, except `id's` + + +## Examples + +### Toggle class + +Below are some examples of class manipulation + +{{< example >}} +<div class="card" data-bs-toggle="toggler" data-bs-value="bg-warning" data-bs-attribute="class"> + <div class="card-body">Click this card, to change `bg-color`</div> +</div> + +<div class="card mt-2" data-bs-toggle="toggler" data-bs-value="text-danger" data-bs-attribute="class"> + <div class="card-body">Click this card, to change `text-color`</div> +</div> +{{< /example >}} + + +### Toggle class of another element + +Using `data-bs-toggle`, combined with `data-bs-target`, can manipulate another element's attribute + +{{< example >}} +<button class="btn btn-outline-primary" data-bs-toggle="toggler" data-bs-target="#togglerExample1">Click me</button> + +<div id="togglerExample1" class="card mt-2" data-bs-value="bg-info" data-bs-attribute="class"> + <div class="card-body">Click this card, to change `bg-color`</div> +</div> +{{< /example >}} + +### Toggle class of multiple elements + +Using `data-bs-toggle`, combined with `data-bs-target`, can manipulate another element's attribute + +{{< example >}} +<button class="btn btn-outline-primary" data-bs-toggle="toggler" data-bs-target=".togglerExampleClass1">Click me</button> + +<div class="card mt-2 togglerExampleClass1" data-bs-value="bg-info" data-bs-attribute="class"> + <div class="card-body">Click this card, to change `bg-color`</div> +</div> + +<div class="card mt-2 togglerExampleClass1" data-bs-value="bg-warning" data-bs-attribute="class"> + <div class="card-body">Click this card, to change `bg-color`</div> +</div> + +<div class="card mt-2 togglerExampleClass1" data-bs-value="bg-info" data-bs-attribute="class"> + <div class="card-body">Click this card, to change `bg-color`</div> +</div> + +{{< /example >}} + + +### Toggle attributes + +Below are some examples of attributes manipulation + +{{< example >}} +<div class="card" data-bs-toggle="toggler" data-bs-value="true" data-bs-attribute="hidden"> + <div class="card-body">Click this card, to change `hidden` attribute</div> +</div> +{{< /example >}} + +### Toggle attributes of another element + +Using `data-bs-toggle`, combined with `data-bs-target`, can manipulate another element's attribute + +{{< example >}} +<button class="btn btn-outline-primary" data-bs-toggle="toggler" data-bs-target="#togglerExample2">Click to toggle `disabled` attribute on fieldset</button> + +<fieldset class="mt-3" id="togglerExample2" data-bs-value="disabled" data-bs-attribute="disabled"> + <div class="mb-3"> + <label for="disabledTextInput" class="form-label">Input</label> + <input type="text" id="disabledTextInput" class="form-control" placeholder="Disabled input"> + </div> + <div class="mb-3"> + <label for="disabledSelect" class="form-label">Disabled select menu</label> + <select id="disabledSelect" class="form-select"> + <option>Select</option> + </select> + </div> + <button type="submit" class="btn btn-primary">Submit</button> +</fieldset> + +{{< /example >}} + + + +### Via data attributes + +#### Toggle + +Add `data-bs-toggle="toggler"` to the element to automatically. +The `data-bs-target` is optional, and attribute accepts a CSS selector to apply the toggler functionality to. +Be sure to add the `data-bs-attribute` and `data-bs-value` attributes on the toggled element's markup + + +### Via JavaScript + +Using this component, programmatically is a bit of redundant, as the initial purpose of it is to avoid use js. +However, enable manually with: + +```js +var togglerElementList = Array.prototype.slice.call(document.querySelectorAll('[data-bs-toggle="toggler"]')) +var togglerList = togglerElementList.map(function (togglerEl) { + return new bootstrap.Toggler(togglerEl) +}) +``` + +### Options + +Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-bs-`, as in `data-bs-value="foo"`. + +{{< bs-table "table" >}} +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `attribute` | string | `class` | The attribute which will be toggled on each click | +| `value` | string | null | Allow body scrolling while toggler is open | +{{< /bs-table >}} + +### Methods + +You can create a toggler instance using the constructor, for example: + +```js +var myToggler = document.getElementById('myToggler') +var bsToggler = new bootstrap.Toggler(myToggler) +``` + +{{< bs-table "table" >}} +| Method | Description | +| --- | --- | +| `toggle` | Toggles a toggler element chosen attribute | +| `getInstance` | *Static* method which allows you to get the toggler instance associated with a DOM element | +| `getOrCreateInstance` | *Static* method which allows you to get the toggler instance associated with a DOM element, or create a new one in case it wasn't initialized | +{{< /bs-table >}} + +### Events + +Bootstrap's toggler class exposes a few events for hooking into toggler functionality. + +{{< bs-table "table" >}} +| Event type | Description | +| --- | --- | +| `toggle.bs.toggler` | This event fires immediately when the `toggle` instance method is called. | +| `toggled.bs.toggler` | This event is fired when the instance's element attribute has been changed. | +{{< /bs-table >}} + +```js +var myToggler = document.getElementById('myToggler') +myToggler.addEventListener('toggle.bs.toggler', function () { + // do something... +}) +``` diff --git a/site/data/sidebar.yml b/site/data/sidebar.yml index cdf0b04d8b..3d4c5c1643 100644 --- a/site/data/sidebar.yml +++ b/site/data/sidebar.yml @@ -93,6 +93,7 @@ - title: Scrollspy - title: Spinners - title: Toasts + - title: Toggler - title: Tooltips - title: Helpers |