[6a3a178] | 1 | /**
|
---|
| 2 | * --------------------------------------------------------------------------
|
---|
| 3 | * Bootstrap (v5.1.3): tab.js
|
---|
| 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
---|
| 5 | * --------------------------------------------------------------------------
|
---|
| 6 | */
|
---|
| 7 |
|
---|
| 8 | import {
|
---|
| 9 | defineJQueryPlugin,
|
---|
| 10 | getElementFromSelector,
|
---|
| 11 | isDisabled,
|
---|
| 12 | reflow
|
---|
| 13 | } from './util/index'
|
---|
| 14 | import EventHandler from './dom/event-handler'
|
---|
| 15 | import SelectorEngine from './dom/selector-engine'
|
---|
| 16 | import BaseComponent from './base-component'
|
---|
| 17 |
|
---|
| 18 | /**
|
---|
| 19 | * ------------------------------------------------------------------------
|
---|
| 20 | * Constants
|
---|
| 21 | * ------------------------------------------------------------------------
|
---|
| 22 | */
|
---|
| 23 |
|
---|
| 24 | const NAME = 'tab'
|
---|
| 25 | const DATA_KEY = 'bs.tab'
|
---|
| 26 | const EVENT_KEY = `.${DATA_KEY}`
|
---|
| 27 | const DATA_API_KEY = '.data-api'
|
---|
| 28 |
|
---|
| 29 | const EVENT_HIDE = `hide${EVENT_KEY}`
|
---|
| 30 | const EVENT_HIDDEN = `hidden${EVENT_KEY}`
|
---|
| 31 | const EVENT_SHOW = `show${EVENT_KEY}`
|
---|
| 32 | const EVENT_SHOWN = `shown${EVENT_KEY}`
|
---|
| 33 | const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
|
---|
| 34 |
|
---|
| 35 | const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu'
|
---|
| 36 | const CLASS_NAME_ACTIVE = 'active'
|
---|
| 37 | const CLASS_NAME_FADE = 'fade'
|
---|
| 38 | const CLASS_NAME_SHOW = 'show'
|
---|
| 39 |
|
---|
| 40 | const SELECTOR_DROPDOWN = '.dropdown'
|
---|
| 41 | const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'
|
---|
| 42 | const SELECTOR_ACTIVE = '.active'
|
---|
| 43 | const SELECTOR_ACTIVE_UL = ':scope > li > .active'
|
---|
| 44 | const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'
|
---|
| 45 | const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'
|
---|
| 46 | const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active'
|
---|
| 47 |
|
---|
| 48 | /**
|
---|
| 49 | * ------------------------------------------------------------------------
|
---|
| 50 | * Class Definition
|
---|
| 51 | * ------------------------------------------------------------------------
|
---|
| 52 | */
|
---|
| 53 |
|
---|
| 54 | class Tab extends BaseComponent {
|
---|
| 55 | // Getters
|
---|
| 56 |
|
---|
| 57 | static get NAME() {
|
---|
| 58 | return NAME
|
---|
| 59 | }
|
---|
| 60 |
|
---|
| 61 | // Public
|
---|
| 62 |
|
---|
| 63 | show() {
|
---|
| 64 | if ((this._element.parentNode &&
|
---|
| 65 | this._element.parentNode.nodeType === Node.ELEMENT_NODE &&
|
---|
| 66 | this._element.classList.contains(CLASS_NAME_ACTIVE))) {
|
---|
| 67 | return
|
---|
| 68 | }
|
---|
| 69 |
|
---|
| 70 | let previous
|
---|
| 71 | const target = getElementFromSelector(this._element)
|
---|
| 72 | const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP)
|
---|
| 73 |
|
---|
| 74 | if (listElement) {
|
---|
| 75 | const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE
|
---|
| 76 | previous = SelectorEngine.find(itemSelector, listElement)
|
---|
| 77 | previous = previous[previous.length - 1]
|
---|
| 78 | }
|
---|
| 79 |
|
---|
| 80 | const hideEvent = previous ?
|
---|
| 81 | EventHandler.trigger(previous, EVENT_HIDE, {
|
---|
| 82 | relatedTarget: this._element
|
---|
| 83 | }) :
|
---|
| 84 | null
|
---|
| 85 |
|
---|
| 86 | const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {
|
---|
| 87 | relatedTarget: previous
|
---|
| 88 | })
|
---|
| 89 |
|
---|
| 90 | if (showEvent.defaultPrevented || (hideEvent !== null && hideEvent.defaultPrevented)) {
|
---|
| 91 | return
|
---|
| 92 | }
|
---|
| 93 |
|
---|
| 94 | this._activate(this._element, listElement)
|
---|
| 95 |
|
---|
| 96 | const complete = () => {
|
---|
| 97 | EventHandler.trigger(previous, EVENT_HIDDEN, {
|
---|
| 98 | relatedTarget: this._element
|
---|
| 99 | })
|
---|
| 100 | EventHandler.trigger(this._element, EVENT_SHOWN, {
|
---|
| 101 | relatedTarget: previous
|
---|
| 102 | })
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | if (target) {
|
---|
| 106 | this._activate(target, target.parentNode, complete)
|
---|
| 107 | } else {
|
---|
| 108 | complete()
|
---|
| 109 | }
|
---|
| 110 | }
|
---|
| 111 |
|
---|
| 112 | // Private
|
---|
| 113 |
|
---|
| 114 | _activate(element, container, callback) {
|
---|
| 115 | const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ?
|
---|
| 116 | SelectorEngine.find(SELECTOR_ACTIVE_UL, container) :
|
---|
| 117 | SelectorEngine.children(container, SELECTOR_ACTIVE)
|
---|
| 118 |
|
---|
| 119 | const active = activeElements[0]
|
---|
| 120 | const isTransitioning = callback && (active && active.classList.contains(CLASS_NAME_FADE))
|
---|
| 121 |
|
---|
| 122 | const complete = () => this._transitionComplete(element, active, callback)
|
---|
| 123 |
|
---|
| 124 | if (active && isTransitioning) {
|
---|
| 125 | active.classList.remove(CLASS_NAME_SHOW)
|
---|
| 126 | this._queueCallback(complete, element, true)
|
---|
| 127 | } else {
|
---|
| 128 | complete()
|
---|
| 129 | }
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | _transitionComplete(element, active, callback) {
|
---|
| 133 | if (active) {
|
---|
| 134 | active.classList.remove(CLASS_NAME_ACTIVE)
|
---|
| 135 |
|
---|
| 136 | const dropdownChild = SelectorEngine.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode)
|
---|
| 137 |
|
---|
| 138 | if (dropdownChild) {
|
---|
| 139 | dropdownChild.classList.remove(CLASS_NAME_ACTIVE)
|
---|
| 140 | }
|
---|
| 141 |
|
---|
| 142 | if (active.getAttribute('role') === 'tab') {
|
---|
| 143 | active.setAttribute('aria-selected', false)
|
---|
| 144 | }
|
---|
| 145 | }
|
---|
| 146 |
|
---|
| 147 | element.classList.add(CLASS_NAME_ACTIVE)
|
---|
| 148 | if (element.getAttribute('role') === 'tab') {
|
---|
| 149 | element.setAttribute('aria-selected', true)
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | reflow(element)
|
---|
| 153 |
|
---|
| 154 | if (element.classList.contains(CLASS_NAME_FADE)) {
|
---|
| 155 | element.classList.add(CLASS_NAME_SHOW)
|
---|
| 156 | }
|
---|
| 157 |
|
---|
| 158 | let parent = element.parentNode
|
---|
| 159 | if (parent && parent.nodeName === 'LI') {
|
---|
| 160 | parent = parent.parentNode
|
---|
| 161 | }
|
---|
| 162 |
|
---|
| 163 | if (parent && parent.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {
|
---|
| 164 | const dropdownElement = element.closest(SELECTOR_DROPDOWN)
|
---|
| 165 |
|
---|
| 166 | if (dropdownElement) {
|
---|
| 167 | SelectorEngine.find(SELECTOR_DROPDOWN_TOGGLE, dropdownElement)
|
---|
| 168 | .forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE))
|
---|
| 169 | }
|
---|
| 170 |
|
---|
| 171 | element.setAttribute('aria-expanded', true)
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | if (callback) {
|
---|
| 175 | callback()
|
---|
| 176 | }
|
---|
| 177 | }
|
---|
| 178 |
|
---|
| 179 | // Static
|
---|
| 180 |
|
---|
| 181 | static jQueryInterface(config) {
|
---|
| 182 | return this.each(function () {
|
---|
| 183 | const data = Tab.getOrCreateInstance(this)
|
---|
| 184 |
|
---|
| 185 | if (typeof config === 'string') {
|
---|
| 186 | if (typeof data[config] === 'undefined') {
|
---|
| 187 | throw new TypeError(`No method named "${config}"`)
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 | data[config]()
|
---|
| 191 | }
|
---|
| 192 | })
|
---|
| 193 | }
|
---|
| 194 | }
|
---|
| 195 |
|
---|
| 196 | /**
|
---|
| 197 | * ------------------------------------------------------------------------
|
---|
| 198 | * Data Api implementation
|
---|
| 199 | * ------------------------------------------------------------------------
|
---|
| 200 | */
|
---|
| 201 |
|
---|
| 202 | EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
|
---|
| 203 | if (['A', 'AREA'].includes(this.tagName)) {
|
---|
| 204 | event.preventDefault()
|
---|
| 205 | }
|
---|
| 206 |
|
---|
| 207 | if (isDisabled(this)) {
|
---|
| 208 | return
|
---|
| 209 | }
|
---|
| 210 |
|
---|
| 211 | const data = Tab.getOrCreateInstance(this)
|
---|
| 212 | data.show()
|
---|
| 213 | })
|
---|
| 214 |
|
---|
| 215 | /**
|
---|
| 216 | * ------------------------------------------------------------------------
|
---|
| 217 | * jQuery
|
---|
| 218 | * ------------------------------------------------------------------------
|
---|
| 219 | * add .Tab to jQuery only if jQuery is present
|
---|
| 220 | */
|
---|
| 221 |
|
---|
| 222 | defineJQueryPlugin(Tab)
|
---|
| 223 |
|
---|
| 224 | export default Tab
|
---|