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.