Layout von Websiten mit Bootstrap und Foundation
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tab.js 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /**
  2. * --------------------------------------------------------------------------
  3. * Bootstrap (v4.5.0): tab.js
  4. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  5. * --------------------------------------------------------------------------
  6. */
  7. import $ from 'jquery'
  8. import Util from './util'
  9. /**
  10. * ------------------------------------------------------------------------
  11. * Constants
  12. * ------------------------------------------------------------------------
  13. */
  14. const NAME = 'tab'
  15. const VERSION = '4.5.0'
  16. const DATA_KEY = 'bs.tab'
  17. const EVENT_KEY = `.${DATA_KEY}`
  18. const DATA_API_KEY = '.data-api'
  19. const JQUERY_NO_CONFLICT = $.fn[NAME]
  20. const EVENT_HIDE = `hide${EVENT_KEY}`
  21. const EVENT_HIDDEN = `hidden${EVENT_KEY}`
  22. const EVENT_SHOW = `show${EVENT_KEY}`
  23. const EVENT_SHOWN = `shown${EVENT_KEY}`
  24. const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
  25. const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu'
  26. const CLASS_NAME_ACTIVE = 'active'
  27. const CLASS_NAME_DISABLED = 'disabled'
  28. const CLASS_NAME_FADE = 'fade'
  29. const CLASS_NAME_SHOW = 'show'
  30. const SELECTOR_DROPDOWN = '.dropdown'
  31. const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'
  32. const SELECTOR_ACTIVE = '.active'
  33. const SELECTOR_ACTIVE_UL = '> li > .active'
  34. const SELECTOR_DATA_TOGGLE = '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]'
  35. const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'
  36. const SELECTOR_DROPDOWN_ACTIVE_CHILD = '> .dropdown-menu .active'
  37. /**
  38. * ------------------------------------------------------------------------
  39. * Class Definition
  40. * ------------------------------------------------------------------------
  41. */
  42. class Tab {
  43. constructor(element) {
  44. this._element = element
  45. }
  46. // Getters
  47. static get VERSION() {
  48. return VERSION
  49. }
  50. // Public
  51. show() {
  52. if (this._element.parentNode &&
  53. this._element.parentNode.nodeType === Node.ELEMENT_NODE &&
  54. $(this._element).hasClass(CLASS_NAME_ACTIVE) ||
  55. $(this._element).hasClass(CLASS_NAME_DISABLED)) {
  56. return
  57. }
  58. let target
  59. let previous
  60. const listElement = $(this._element).closest(SELECTOR_NAV_LIST_GROUP)[0]
  61. const selector = Util.getSelectorFromElement(this._element)
  62. if (listElement) {
  63. const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE
  64. previous = $.makeArray($(listElement).find(itemSelector))
  65. previous = previous[previous.length - 1]
  66. }
  67. const hideEvent = $.Event(EVENT_HIDE, {
  68. relatedTarget: this._element
  69. })
  70. const showEvent = $.Event(EVENT_SHOW, {
  71. relatedTarget: previous
  72. })
  73. if (previous) {
  74. $(previous).trigger(hideEvent)
  75. }
  76. $(this._element).trigger(showEvent)
  77. if (showEvent.isDefaultPrevented() ||
  78. hideEvent.isDefaultPrevented()) {
  79. return
  80. }
  81. if (selector) {
  82. target = document.querySelector(selector)
  83. }
  84. this._activate(
  85. this._element,
  86. listElement
  87. )
  88. const complete = () => {
  89. const hiddenEvent = $.Event(EVENT_HIDDEN, {
  90. relatedTarget: this._element
  91. })
  92. const shownEvent = $.Event(EVENT_SHOWN, {
  93. relatedTarget: previous
  94. })
  95. $(previous).trigger(hiddenEvent)
  96. $(this._element).trigger(shownEvent)
  97. }
  98. if (target) {
  99. this._activate(target, target.parentNode, complete)
  100. } else {
  101. complete()
  102. }
  103. }
  104. dispose() {
  105. $.removeData(this._element, DATA_KEY)
  106. this._element = null
  107. }
  108. // Private
  109. _activate(element, container, callback) {
  110. const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL')
  111. ? $(container).find(SELECTOR_ACTIVE_UL)
  112. : $(container).children(SELECTOR_ACTIVE)
  113. const active = activeElements[0]
  114. const isTransitioning = callback && (active && $(active).hasClass(CLASS_NAME_FADE))
  115. const complete = () => this._transitionComplete(
  116. element,
  117. active,
  118. callback
  119. )
  120. if (active && isTransitioning) {
  121. const transitionDuration = Util.getTransitionDurationFromElement(active)
  122. $(active)
  123. .removeClass(CLASS_NAME_SHOW)
  124. .one(Util.TRANSITION_END, complete)
  125. .emulateTransitionEnd(transitionDuration)
  126. } else {
  127. complete()
  128. }
  129. }
  130. _transitionComplete(element, active, callback) {
  131. if (active) {
  132. $(active).removeClass(CLASS_NAME_ACTIVE)
  133. const dropdownChild = $(active.parentNode).find(
  134. SELECTOR_DROPDOWN_ACTIVE_CHILD
  135. )[0]
  136. if (dropdownChild) {
  137. $(dropdownChild).removeClass(CLASS_NAME_ACTIVE)
  138. }
  139. if (active.getAttribute('role') === 'tab') {
  140. active.setAttribute('aria-selected', false)
  141. }
  142. }
  143. $(element).addClass(CLASS_NAME_ACTIVE)
  144. if (element.getAttribute('role') === 'tab') {
  145. element.setAttribute('aria-selected', true)
  146. }
  147. Util.reflow(element)
  148. if (element.classList.contains(CLASS_NAME_FADE)) {
  149. element.classList.add(CLASS_NAME_SHOW)
  150. }
  151. if (element.parentNode && $(element.parentNode).hasClass(CLASS_NAME_DROPDOWN_MENU)) {
  152. const dropdownElement = $(element).closest(SELECTOR_DROPDOWN)[0]
  153. if (dropdownElement) {
  154. const dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(SELECTOR_DROPDOWN_TOGGLE))
  155. $(dropdownToggleList).addClass(CLASS_NAME_ACTIVE)
  156. }
  157. element.setAttribute('aria-expanded', true)
  158. }
  159. if (callback) {
  160. callback()
  161. }
  162. }
  163. // Static
  164. static _jQueryInterface(config) {
  165. return this.each(function () {
  166. const $this = $(this)
  167. let data = $this.data(DATA_KEY)
  168. if (!data) {
  169. data = new Tab(this)
  170. $this.data(DATA_KEY, data)
  171. }
  172. if (typeof config === 'string') {
  173. if (typeof data[config] === 'undefined') {
  174. throw new TypeError(`No method named "${config}"`)
  175. }
  176. data[config]()
  177. }
  178. })
  179. }
  180. }
  181. /**
  182. * ------------------------------------------------------------------------
  183. * Data Api implementation
  184. * ------------------------------------------------------------------------
  185. */
  186. $(document)
  187. .on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
  188. event.preventDefault()
  189. Tab._jQueryInterface.call($(this), 'show')
  190. })
  191. /**
  192. * ------------------------------------------------------------------------
  193. * jQuery
  194. * ------------------------------------------------------------------------
  195. */
  196. $.fn[NAME] = Tab._jQueryInterface
  197. $.fn[NAME].Constructor = Tab
  198. $.fn[NAME].noConflict = () => {
  199. $.fn[NAME] = JQUERY_NO_CONFLICT
  200. return Tab._jQueryInterface
  201. }
  202. export default Tab