PageSourceSearch

https://poetter-brusch.de/js/bootstrap/collapse.js

js poetter-brusch.de collected 2026-10-06 22:16:32 UTC 10,403 bytes, 402 lines download raw bytes

1/**
2 * --------------------------------------------------------------------------
3 * Bootstrap (v4.3.1): collapse.js
4 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 * --------------------------------------------------------------------------
6 */
7
8import $ from 'jquery'
9import Util from './util'
10
11/**
12 * ------------------------------------------------------------------------
13 * Constants
14 * ------------------------------------------------------------------------
15 */
16
17const NAME                = 'collapse'
18const VERSION             = '4.3.1'
19const DATA_KEY            = 'bs.collapse'
20const EVENT_KEY           = `.${DATA_KEY}`
21const DATA_API_KEY        = '.data-api'
22const JQUERY_NO_CONFLICT  = $.fn[NAME]
23
24const Default = {
25  toggle : true,
26  parent : ''
27}
28
29const DefaultType = {
30  toggle : 'boolean',
31  parent : '(string|element)'
32}
33
34const Event = {
35  SHOW           : `show${EVENT_KEY}`,
36  SHOWN          : `shown${EVENT_KEY}`,
37  HIDE           : `hide${EVENT_KEY}`,
38  HIDDEN         : `hidden${EVENT_KEY}`,
39  CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}`
40}
41
42const ClassName = {
43  SHOW       : 'show',
44  COLLAPSE   : 'collapse',
45  COLLAPSING : 'collapsing',
46  COLLAPSED  : 'collapsed'
47}
48
49const Dimension = {
50  WIDTH  : 'width',
51  HEIGHT : 'height'
52}
53
54const Selector = {
55  ACTIVES     : '.show, .collapsing',
56  DATA_TOGGLE : '[data-toggle="collapse"]'
57}
58
59/**
60 * ------------------------------------------------------------------------
61 * Class Definition
62 * ------------------------------------------------------------------------
63 */
64
65class Collapse {
66  constructor(element, config) {
67    this._isTransitioning = false
68    this._element         = element
69    this._config          = this._getConfig(config)
70    this._triggerArray    = [].slice.call(document.querySelectorAll(
71      `[data-toggle="collapse"][href="#${element.id}"],` +
72      `[data-toggle="collapse"][data-target="#${element.id}"]`
73    ))
74
75    const toggleList = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE))
76    for (let i = 0, len = toggleList.length; i < len; i++) {
77      const elem = toggleList[i]
78      const selector = Util.getSelectorFromElement(elem)
79      const filterElement = [].slice.call(document.querySelectorAll(selector))
80        .filter((foundElem) => foundElem === element)
81
82      if (selector !== null && filterElement.length > 0) {
83        this._selector = selector
84        this._triggerArray.push(elem)
85      }
86    }
87
88    this._parent = this._config.parent ? this._getParent() : null
89
90    if (!this._config.parent) {
91      this._addAriaAndCollapsedClass(this._element, this._triggerArray)
92    }
93
94    if (this._config.toggle) {
95      this.toggle()
96    }
97  }
98
99  // Getters
100
101  static get VERSION() {
102    return VERSION
103  }
104
105  static get Default() {
106    return Default
107  }
108
109  // Public
110
111  toggle() {
112    if ($(this._element).hasClass(ClassName.SHOW)) {
113      this.hide()
114    } else {
115      this.show()
116    }
117  }
118
119  show() {
120    if (this._isTransitioning ||
121      $(this._element).hasClass(ClassName.SHOW)) {
122      return
123    }
124
125    let actives
126    let activesData
127
128    if (this._parent) {
129      actives = [].slice.call(this._parent.querySelectorAll(Selector.ACTIVES))
130        .filter((elem) => {
131          if (typeof this._config.parent === 'string') {
132            return elem.getAttribute('data-parent') === this._config.parent
133          }
134
135          return elem.classList.contains(ClassName.COLLAPSE)
136        })
137
138      if (actives.length === 0) {
139        actives = null
140      }
141    }
142
143    if (actives) {
144      activesData = $(actives).not(this._selector).data(DATA_KEY)
145      if (activesData && activesData._isTransitioning) {
146        return
147      }
148    }
149
150    const startEvent = $.Event(Event.SHOW)
151    $(this._element).trigger(startEvent)
152    if (startEvent.isDefaultPrevented()) {
153      return
154    }
155
156    if (actives) {
157      Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide')
158      if (!activesData) {
159        $(actives).data(DATA_KEY, null)
160      }
161    }
162
163    const dimension = this._getDimension()
164
165    $(this._element)
166      .removeClass(ClassName.COLLAPSE)
167      .addClass(ClassName.COLLAPSING)
168
169    this._element.style[dimension] = 0
170
171    if (this._triggerArray.length) {
172      $(this._triggerArray)
173        .removeClass(ClassName.COLLAPSED)
174        .attr('aria-expanded', true)
175    }
176
177    this.setTransitioning(true)
178
179    const complete = () => {
180      $(this._element)
181        .removeClass(ClassName.COLLAPSING)
182        .addClass(ClassName.COLLAPSE)
183        .addClass(ClassName.SHOW)
184
185      this._element.style[dimension] = ''
186
187      this.setTransitioning(false)
188
189      $(this._element).trigger(Event.SHOWN)
190    }
191
192    const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)
193    const scrollSize = `scroll${capitalizedDimension}`
194    const transitionDuration = Util.getTransitionDurationFromElement(this._element)
195
196    $(this._element)
197      .one(Util.TRANSITION_END, complete)
198      .emulateTransitionEnd(transitionDuration)
199
200    this._element.style[dimension] = `${this._element[scrollSize]}px`
201  }
202
203  hide() {
204    if (this._isTransitioning ||
205      !$(this._element).hasClass(ClassName.SHOW)) {
206      return
207    }
208
209    const startEvent = $.Event(Event.HIDE)
210    $(this._element).trigger(startEvent)
211    if (startEvent.isDefaultPrevented()) {
212      return
213    }
214
215    const dimension = this._getDimension()
216
217    this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`
218
219    Util.reflow(this._element)
220
221    $(this._element)
222      .addClass(ClassName.COLLAPSING)
223      .removeClass(ClassName.COLLAPSE)
224      .removeClass(ClassName.SHOW)
225
226    const triggerArrayLength = this._triggerArray.length
227    if (triggerArrayLength > 0) {
228      for (let i = 0; i < triggerArrayLength; i++) {
229        const trigger = this._triggerArray[i]
230        const selector = Util.getSelectorFromElement(trigger)
231
232        if (selector !== null) {
233          const $elem = $([].slice.call(document.querySelectorAll(selector)))
234          if (!$elem.hasClass(ClassName.SHOW)) {
235            $(trigger).addClass(ClassName.COLLAPSED)
236              .attr('aria-expanded', false)
237          }
238        }
239      }
240    }
241
242    this.setTransitioning(true)
243
244    const complete = () => {
245      this.setTransitioning(false)
246      $(this._element)
247        .removeClass(ClassName.COLLAPSING)
248        .addClass(ClassName.COLLAPSE)
249        .trigger(Event.HIDDEN)
250    }
251
252    this._element.style[dimension] = ''
253    const transitionDuration = Util.getTransitionDurationFromElement(this._element)
254
255    $(this._element)
256      .one(Util.TRANSITION_END, complete)
257      .emulateTransitionEnd(transitionDuration)
258  }
259
260  setTransitioning(isTransitioning) {
261    this._isTransitioning = isTransitioning
262  }
263
264  dispose() {
265    $.removeData(this._element, DATA_KEY)
266
267    this._config          = null
268    this._parent          = null
269    this._element         = null
270    this._triggerArray    = null
271    this._isTransitioning = null
272  }
273
274  // Private
275
276  _getConfig(config) {
277    config = {
278      ...Default,
279      ...config
280    }
281    config.toggle = Boolean(config.toggle) // Coerce string values
282    Util.typeCheckConfig(NAME, config, DefaultType)
283    return config
284  }
285
286  _getDimension() {
287    const hasWidth = $(this._element).hasClass(Dimension.WIDTH)
288    return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT
289  }
290
291  _getParent() {
292    let parent
293
294    if (Util.isElement(this._config.parent)) {
295      parent = this._config.parent
296
297      // It's a jQuery object
298      if (typeof this._config.parent.jquery !== 'undefined') {
299        parent = this._config.parent[0]
300      }
301    } else {
302      parent = document.querySelector(this._config.parent)
303    }
304
305    const selector =
306      `[data-toggle="collapse"][data-parent="${this._config.parent}"]`
307
308    const children = [].slice.call(parent.querySelectorAll(selector))
309    $(children).each((i, element) => {
310      this._addAriaAndCollapsedClass(
311        Collapse._getTargetFromElement(element),
312        [element]
313      )
314    })
315
316    return parent
317  }
318
319  _addAriaAndCollapsedClass(element, triggerArray) {
320    const isOpen = $(element).hasClass(ClassName.SHOW)
321
322    if (triggerArray.length) {
323      $(triggerArray)
324        .toggleClass(ClassName.COLLAPSED, !isOpen)
325        .attr('aria-expanded', isOpen)
326    }
327  }
328
329  // Static
330
331  static _getTargetFromElement(element) {
332    const selector = Util.getSelectorFromElement(element)
333    return selector ? document.querySelector(selector) : null
334  }
335
336  static _jQueryInterface(config) {
337    return this.each(function () {
338      const $this   = $(this)
339      let data      = $this.data(DATA_KEY)
340      const _config = {
341        ...Default,
342        ...$this.data(),
343        ...typeof config === 'object' && config ? config : {}
344      }
345
346      if (!data && _config.toggle && /show|hide/.test(config)) {
347        _config.toggle = false
348      }
349
350      if (!data) {
351        data = new Collapse(this, _config)
352        $this.data(DATA_KEY, data)
353      }
354
355      if (typeof config === 'string') {
356        if (typeof data[config] === 'undefined') {
357          throw new TypeError(`No method named "${config}"`)
358        }
359        data[config]()
360      }
361    })
362  }
363}
364
365/**
366 * ------------------------------------------------------------------------
367 * Data Api implementation
368 * ------------------------------------------------------------------------
369 */
370
371$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
372  // preventDefault only for <a> elements (which change the URL) not inside the collapsible element
373  if (event.currentTarget.tagName === 'A') {
374    event.preventDefault()
375  }
376
377  const $trigger = $(this)
378  const selector = Util.getSelectorFromElement(this)
379  const selectors = [].slice.call(document.querySelectorAll(selector))
380
381  $(selectors).each(function () {
382    const $target = $(this)
383    const data    = $target.data(DATA_KEY)
384    const config  = data ? 'toggle' : $trigger.data()
385    Collapse._jQueryInterface.call($target, config)
386  })
387})
388
389/**
390 * ------------------------------------------------------------------------
391 * jQuery
392 * ------------------------------------------------------------------------
393 */
394
395$.fn[NAME] = Collapse._jQueryInterface
396$.fn[NAME].Constructor = Collapse
397$.fn[NAME].noConflict = () => {
398  $.fn[NAME] = JQUERY_NO_CONFLICT
399  return Collapse._jQueryInterface
400}
401
402export default Collapse

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.