Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 1... Línea 1...
1
/**
1
/**
2
 * --------------------------------------------------------------------------
2
 * --------------------------------------------------------------------------
3
 * Bootstrap (v4.6.2): dropdown.js
3
 * Bootstrap dropdown.js
4
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
4
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
 * --------------------------------------------------------------------------
5
 * --------------------------------------------------------------------------
6
 */
6
 */
Línea 7... Línea 7...
7
 
7
 
8
import $ from 'jquery'
8
import * as Popper from 'core/popper2'
-
 
9
import BaseComponent from './base-component'
9
import Popper from 'core/popper'
10
import EventHandler from './dom/event-handler'
-
 
11
import Manipulator from './dom/manipulator'
-
 
12
import SelectorEngine from './dom/selector-engine'
-
 
13
import {
-
 
14
  defineJQueryPlugin,
-
 
15
  execute,
-
 
16
  getElement,
-
 
17
  getNextActiveElement,
-
 
18
  isDisabled,
-
 
19
  isElement,
-
 
20
  isRTL,
-
 
21
  isVisible,
-
 
22
  noop
Línea 10... Línea 23...
10
import Util from './util'
23
} from './util/index'
11
 
24
 
12
/**
25
/**
Línea 13... Línea 26...
13
 * Constants
26
 * Constants
14
 */
-
 
15
 
27
 */
16
const NAME = 'dropdown'
28
 
17
const VERSION = '4.6.2'
29
const NAME = 'dropdown'
18
const DATA_KEY = 'bs.dropdown'
-
 
19
const EVENT_KEY = `.${DATA_KEY}`
-
 
20
const DATA_API_KEY = '.data-api'
-
 
21
const JQUERY_NO_CONFLICT = $.fn[NAME]
-
 
22
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
-
 
23
const SPACE_KEYCODE = 32 // KeyboardEvent.which value for space key
-
 
24
const TAB_KEYCODE = 9 // KeyboardEvent.which value for tab key
-
 
25
const ARROW_UP_KEYCODE = 38 // KeyboardEvent.which value for up arrow key
-
 
Línea 26... Línea 30...
26
const ARROW_DOWN_KEYCODE = 40 // KeyboardEvent.which value for down arrow key
30
const DATA_KEY = 'bs.dropdown'
27
const RIGHT_MOUSE_BUTTON_WHICH = 3 // MouseEvent.which value for the right button (assuming a right-handed mouse)
31
const EVENT_KEY = `.${DATA_KEY}`
28
const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEYCODE}|${ARROW_DOWN_KEYCODE}|${ESCAPE_KEYCODE}`)
32
const DATA_API_KEY = '.data-api'
29
 
-
 
30
const CLASS_NAME_DISABLED = 'disabled'
33
 
31
const CLASS_NAME_SHOW = 'show'
34
const ESCAPE_KEY = 'Escape'
32
const CLASS_NAME_DROPUP = 'dropup'
-
 
Línea 33... Línea 35...
33
const CLASS_NAME_DROPRIGHT = 'dropright'
35
const TAB_KEY = 'Tab'
34
const CLASS_NAME_DROPLEFT = 'dropleft'
36
const ARROW_UP_KEY = 'ArrowUp'
35
const CLASS_NAME_MENURIGHT = 'dropdown-menu-right'
37
const ARROW_DOWN_KEY = 'ArrowDown'
36
const CLASS_NAME_POSITION_STATIC = 'position-static'
38
const RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button
37
 
-
 
38
const EVENT_HIDE = `hide${EVENT_KEY}`
39
 
39
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
40
const EVENT_HIDE = `hide${EVENT_KEY}`
40
const EVENT_SHOW = `show${EVENT_KEY}`
41
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
Línea -... Línea 42...
-
 
42
const EVENT_SHOW = `show${EVENT_KEY}`
-
 
43
const EVENT_SHOWN = `shown${EVENT_KEY}`
41
const EVENT_SHOWN = `shown${EVENT_KEY}`
44
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
-
 
45
const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
-
 
46
const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`
42
const EVENT_CLICK = `click${EVENT_KEY}`
47
 
-
 
48
const CLASS_NAME_SHOW = 'show'
-
 
49
const CLASS_NAME_DROPUP = 'dropup'
-
 
50
const CLASS_NAME_DROPEND = 'dropend'
43
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
51
const CLASS_NAME_DROPSTART = 'dropstart'
-
 
52
const CLASS_NAME_DROPUP_CENTER = 'dropup-center'
44
const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
53
const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'
45
const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`
54
 
Línea 46... Línea 55...
46
 
55
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)'
47
const SELECTOR_DATA_TOGGLE = '[data-toggle="dropdown"]'
56
const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`
48
const SELECTOR_FORM_CHILD = '.dropdown form'
57
const SELECTOR_MENU = '.dropdown-menu'
49
const SELECTOR_MENU = '.dropdown-menu'
58
const SELECTOR_NAVBAR = '.navbar'
50
const SELECTOR_NAVBAR_NAV = '.navbar-nav'
59
const SELECTOR_NAVBAR_NAV = '.navbar-nav'
-
 
60
const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
51
const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
61
 
-
 
62
const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'
Línea 52... Línea 63...
52
 
63
const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'
53
const PLACEMENT_TOP = 'top-start'
-
 
54
const PLACEMENT_TOPEND = 'top-end'
64
const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'
55
const PLACEMENT_BOTTOM = 'bottom-start'
65
const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'
56
const PLACEMENT_BOTTOMEND = 'bottom-end'
-
 
57
const PLACEMENT_RIGHT = 'right-start'
66
const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'
-
 
67
const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'
58
const PLACEMENT_LEFT = 'left-start'
68
const PLACEMENT_TOPCENTER = 'top'
-
 
69
const PLACEMENT_BOTTOMCENTER = 'bottom'
59
 
70
 
Línea 60... Línea 71...
60
const Default = {
71
const Default = {
61
  offset: 0,
72
  autoClose: true,
62
  flip: true,
-
 
63
  boundary: 'scrollParent',
73
  boundary: 'clippingParents',
64
  reference: 'toggle',
-
 
65
  display: 'dynamic',
74
  display: 'dynamic',
-
 
75
  offset: [0, 2],
66
  popperConfig: null
76
  popperConfig: null,
-
 
77
  reference: 'toggle'
67
}
78
}
Línea 68... Línea 79...
68
 
79
 
69
const DefaultType = {
80
const DefaultType = {
70
  offset: '(number|string|function)',
81
  autoClose: '(boolean|string)',
Línea 71... Línea 82...
71
  flip: 'boolean',
82
  boundary: '(string|element)',
72
  boundary: '(string|element)',
83
  display: 'string',
73
  reference: '(string|element)',
84
  offset: '(array|string|function)',
-
 
85
  popperConfig: '(null|object|function)',
74
  display: 'string',
86
  reference: '(string|element|object)'
75
  popperConfig: '(null|object)'
87
}
-
 
88
 
76
}
89
/**
-
 
90
 * Class definition
-
 
91
 */
77
 
92
 
78
/**
-
 
79
 * Class definition
-
 
80
 */
93
class Dropdown extends BaseComponent {
Línea 81... Línea 94...
81
 
94
  constructor(element, config) {
82
class Dropdown {
-
 
83
  constructor(element, config) {
-
 
84
    this._element = element
-
 
85
    this._popper = null
-
 
86
    this._config = this._getConfig(config)
95
    super(element, config)
87
    this._menu = this._getMenuElement()
96
 
88
    this._inNavbar = this._detectNavbar()
97
    this._popper = null
Línea 89... Línea 98...
89
 
98
    this._parent = this._element.parentNode // dropdown wrapper
90
    this._addEventListeners()
99
    // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
91
  }
100
    this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||
Línea -... Línea 101...
-
 
101
      SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||
-
 
102
      SelectorEngine.findOne(SELECTOR_MENU, this._parent)
-
 
103
    this._inNavbar = this._detectNavbar()
-
 
104
  }
92
 
105
 
93
  // Getters
106
  // Getters
94
  static get VERSION() {
-
 
95
    return VERSION
-
 
96
  }
-
 
97
 
-
 
98
  static get Default() {
107
  static get Default() {
99
    return Default
-
 
100
  }
-
 
101
 
-
 
102
  static get DefaultType() {
-
 
103
    return DefaultType
-
 
104
  }
-
 
105
 
-
 
106
  // Public
-
 
107
  toggle() {
108
    return Default
Línea 108... Línea 109...
108
    if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED)) {
109
  }
109
      return
110
 
110
    }
111
  static get DefaultType() {
111
 
112
    return DefaultType
Línea 112... Línea 113...
112
    const isActive = $(this._menu).hasClass(CLASS_NAME_SHOW)
113
  }
113
 
114
 
114
    Dropdown._clearMenus()
115
  static get NAME() {
115
 
-
 
116
    if (isActive) {
-
 
Línea 117... Línea 116...
117
      return
116
    return NAME
Línea 118... Línea 117...
118
    }
117
  }
119
 
118
 
120
    this.show(true)
119
  // Public
Línea 121... Línea -...
121
  }
-
 
122
 
120
  toggle() {
123
  show(usePopper = false) {
-
 
124
    if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || $(this._menu).hasClass(CLASS_NAME_SHOW)) {
-
 
125
      return
-
 
126
    }
-
 
127
 
-
 
128
    const relatedTarget = {
-
 
129
      relatedTarget: this._element
-
 
130
    }
-
 
131
    const showEvent = $.Event(EVENT_SHOW, relatedTarget)
-
 
132
    const parent = Dropdown._getParentFromElement(this._element)
-
 
133
 
-
 
134
    $(parent).trigger(showEvent)
-
 
135
 
-
 
136
    if (showEvent.isDefaultPrevented()) {
-
 
137
      return
-
 
138
    }
-
 
139
 
-
 
140
    // Totally disable Popper for Dropdowns in Navbar
-
 
141
    if (!this._inNavbar && usePopper) {
-
 
142
      // Check for Popper dependency
-
 
143
      if (typeof Popper === 'undefined') {
-
 
144
        throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)')
-
 
145
      }
-
 
146
 
-
 
147
      let referenceElement = this._element
-
 
148
 
-
 
149
      if (this._config.reference === 'parent') {
-
 
Línea 150... Línea 121...
150
        referenceElement = parent
121
    return this._isShown() ? this.hide() : this.show()
151
      } else if (Util.isElement(this._config.reference)) {
122
  }
152
        referenceElement = this._config.reference
123
 
153
 
124
  show() {
154
        // Check if it's jQuery element
125
    if (isDisabled(this._element) || this._isShown()) {
155
        if (typeof this._config.reference.jquery !== 'undefined') {
126
      return
156
          referenceElement = this._config.reference[0]
127
    }
-
 
128
 
157
        }
129
    const relatedTarget = {
Línea 158... Línea 130...
158
      }
130
      relatedTarget: this._element
159
 
131
    }
Línea 160... Línea 132...
160
      // If boundary is not `scrollParent`, then set position to `static`
132
 
161
      // to allow the menu to "escape" the scroll parent's boundaries
-
 
162
      // https://github.com/twbs/bootstrap/issues/24251
133
    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)
163
      if (this._config.boundary !== 'scrollParent') {
134
 
164
        $(parent).addClass(CLASS_NAME_POSITION_STATIC)
135
    if (showEvent.defaultPrevented) {
Línea 165... Línea 136...
165
      }
136
      return
166
 
137
    }
167
      this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig())
138
 
168
    }
139
    this._createPopper()
Línea 169... Línea 140...
169
 
140
 
170
    // If this is a touch-enabled device we add extra
141
    // If this is a touch-enabled device we add extra
171
    // empty mouseover listeners to the body's immediate children;
142
    // empty mouseover listeners to the body's immediate children;
172
    // only needed because of broken event delegation on iOS
-
 
173
    // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
-
 
Línea 174... Línea -...
174
    if ('ontouchstart' in document.documentElement &&
-
 
175
        $(parent).closest(SELECTOR_NAVBAR_NAV).length === 0) {
-
 
176
      $(document.body).children().on('mouseover', null, $.noop)
-
 
177
    }
-
 
178
 
-
 
179
    this._element.focus()
-
 
180
    this._element.setAttribute('aria-expanded', true)
-
 
181
 
143
    // only needed because of broken event delegation on iOS
182
    $(this._menu).toggleClass(CLASS_NAME_SHOW)
-
 
183
    $(parent)
-
 
184
      .toggleClass(CLASS_NAME_SHOW)
-
 
185
      .trigger($.Event(EVENT_SHOWN, relatedTarget))
-
 
186
  }
-
 
187
 
-
 
188
  hide() {
144
    // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
Línea 189... Línea 145...
189
    if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || !$(this._menu).hasClass(CLASS_NAME_SHOW)) {
145
    if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {
190
      return
-
 
191
    }
-
 
192
 
-
 
193
    const relatedTarget = {
-
 
194
      relatedTarget: this._element
146
      for (const element of [].concat(...document.body.children)) {
195
    }
147
        EventHandler.on(element, 'mouseover', noop)
196
    const hideEvent = $.Event(EVENT_HIDE, relatedTarget)
-
 
197
    const parent = Dropdown._getParentFromElement(this._element)
148
      }
-
 
149
    }
-
 
150
 
198
 
151
    this._element.focus()
Línea 199... Línea 152...
199
    $(parent).trigger(hideEvent)
152
    this._element.setAttribute('aria-expanded', true)
200
 
153
 
201
    if (hideEvent.isDefaultPrevented()) {
154
    this._menu.classList.add(CLASS_NAME_SHOW)
202
      return
155
    this._element.classList.add(CLASS_NAME_SHOW)
203
    }
156
    EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)
204
 
157
  }
Línea 205... Línea 158...
205
    if (this._popper) {
158
 
206
      this._popper.destroy()
159
  hide() {
-
 
160
    if (isDisabled(this._element) || !this._isShown()) {
207
    }
161
      return
208
 
162
    }
-
 
163
 
-
 
164
    const relatedTarget = {
-
 
165
      relatedTarget: this._element
-
 
166
    }
-
 
167
 
-
 
168
    this._completeHide(relatedTarget)
-
 
169
  }
-
 
170
 
-
 
171
  dispose() {
-
 
172
    if (this._popper) {
209
    $(this._menu).toggleClass(CLASS_NAME_SHOW)
173
      this._popper.destroy()
210
    $(parent)
174
    }
211
      .toggleClass(CLASS_NAME_SHOW)
175
 
-
 
176
    super.dispose()
-
 
177
  }
-
 
178
 
-
 
179
  update() {
-
 
180
    this._inNavbar = this._detectNavbar()
-
 
181
    if (this._popper) {
212
      .trigger($.Event(EVENT_HIDDEN, relatedTarget))
182
      this._popper.update()
Línea 213... Línea 183...
213
  }
183
    }
214
 
-
 
215
  dispose() {
-
 
216
    $.removeData(this._element, DATA_KEY)
184
  }
217
    $(this._element).off(EVENT_KEY)
-
 
218
    this._element = null
-
 
Línea -... Línea 185...
-
 
185
 
219
    this._menu = null
186
  // Private
220
    if (this._popper !== null) {
187
  _completeHide(relatedTarget) {
221
      this._popper.destroy()
-
 
222
      this._popper = null
188
    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)
-
 
189
    if (hideEvent.defaultPrevented) {
223
    }
190
      return
Línea 224... Línea 191...
224
  }
191
    }
225
 
192
 
Línea 226... Línea 193...
226
  update() {
193
    // If this is a touch-enabled device we remove the extra
227
    this._inNavbar = this._detectNavbar()
194
    // empty mouseover listeners we added for iOS support
228
    if (this._popper !== null) {
195
    if ('ontouchstart' in document.documentElement) {
-
 
196
      for (const element of [].concat(...document.body.children)) {
Línea 229... Línea 197...
229
      this._popper.scheduleUpdate()
197
        EventHandler.off(element, 'mouseover', noop)
-
 
198
      }
230
    }
199
    }
231
  }
200
 
-
 
201
    if (this._popper) {
-
 
202
      this._popper.destroy()
-
 
203
    }
-
 
204
 
232
 
205
    this._menu.classList.remove(CLASS_NAME_SHOW)
Línea 233... Línea 206...
233
  // Private
206
    this._element.classList.remove(CLASS_NAME_SHOW)
-
 
207
    this._element.setAttribute('aria-expanded', 'false')
-
 
208
    Manipulator.removeDataAttribute(this._menu, 'popper')
-
 
209
    EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
-
 
210
  }
-
 
211
 
234
  _addEventListeners() {
212
  _getConfig(config) {
Línea 235... Línea 213...
235
    $(this._element).on(EVENT_CLICK, event => {
213
    config = super._getConfig(config)
236
      event.preventDefault()
214
 
-
 
215
    if (typeof config.reference === 'object' && !isElement(config.reference) &&
-
 
216
      typeof config.reference.getBoundingClientRect !== 'function'
-
 
217
    ) {
-
 
218
      // Popper virtual elements require a getBoundingClientRect method
-
 
219
      throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`)
-
 
220
    }
237
      event.stopPropagation()
221
 
-
 
222
    return config
-
 
223
  }
-
 
224
 
-
 
225
  _createPopper() {
-
 
226
    if (typeof Popper === 'undefined') {
Línea 238... Línea -...
238
      this.toggle()
-
 
239
    })
227
      throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)')
240
  }
-
 
241
 
-
 
242
  _getConfig(config) {
-
 
243
    config = {
-
 
244
      ...this.constructor.Default,
-
 
245
      ...$(this._element).data(),
-
 
246
      ...config
-
 
247
    }
-
 
248
 
228
    }
249
    Util.typeCheckConfig(
229
 
Línea -... Línea 230...
-
 
230
    let referenceElement = this._element
-
 
231
 
-
 
232
    if (this._config.reference === 'parent') {
-
 
233
      referenceElement = this._parent
250
      NAME,
234
    } else if (isElement(this._config.reference)) {
-
 
235
      referenceElement = getElement(this._config.reference)
-
 
236
    } else if (typeof this._config.reference === 'object') {
-
 
237
      referenceElement = this._config.reference
251
      config,
238
    }
Línea 252... Línea 239...
252
      this.constructor.DefaultType
239
 
253
    )
240
    const popperConfig = this._getPopperConfig()
254
 
241
    this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)
Línea 255... Línea 242...
255
    return config
242
  }
256
  }
243
 
Línea 257... Línea 244...
257
 
244
  _isShown() {
258
  _getMenuElement() {
-
 
259
    if (!this._menu) {
-
 
260
      const parent = Dropdown._getParentFromElement(this._element)
-
 
261
 
245
    return this._menu.classList.contains(CLASS_NAME_SHOW)
262
      if (parent) {
246
  }
Línea 263... Línea 247...
263
        this._menu = parent.querySelector(SELECTOR_MENU)
247
 
264
      }
-
 
265
    }
-
 
266
 
248
  _getPlacement() {
267
    return this._menu
249
    const parentDropdown = this._parent
Línea 268... Línea 250...
268
  }
250
 
269
 
251
    if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
Línea 270... Línea 252...
270
  _getPlacement() {
252
      return PLACEMENT_RIGHT
271
    const $parentDropdown = $(this._element.parentNode)
253
    }
272
    let placement = PLACEMENT_BOTTOM
254
 
273
 
255
    if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {
274
    // Handle dropup
256
      return PLACEMENT_LEFT
275
    if ($parentDropdown.hasClass(CLASS_NAME_DROPUP)) {
257
    }
276
      placement = $(this._menu).hasClass(CLASS_NAME_MENURIGHT) ?
-
 
277
        PLACEMENT_TOPEND :
-
 
278
        PLACEMENT_TOP
-
 
279
    } else if ($parentDropdown.hasClass(CLASS_NAME_DROPRIGHT)) {
258
 
280
      placement = PLACEMENT_RIGHT
259
    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {
281
    } else if ($parentDropdown.hasClass(CLASS_NAME_DROPLEFT)) {
260
      return PLACEMENT_TOPCENTER
-
 
261
    }
-
 
262
 
-
 
263
    if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {
-
 
264
      return PLACEMENT_BOTTOMCENTER
-
 
265
    }
-
 
266
 
282
      placement = PLACEMENT_LEFT
267
    // We need to trim the value because custom properties can also include spaces
Línea 283... Línea 268...
283
    } else if ($(this._menu).hasClass(CLASS_NAME_MENURIGHT)) {
268
    const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'
284
      placement = PLACEMENT_BOTTOMEND
269
 
-
 
270
    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
285
    }
271
      return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP
-
 
272
    }
286
 
273
 
287
    return placement
274
    return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM
288
  }
275
  }
Línea 289... Línea 276...
289
 
276
 
290
  _detectNavbar() {
277
  _detectNavbar() {
291
    return $(this._element).closest('.navbar').length > 0
278
    return this._element.closest(SELECTOR_NAVBAR) !== null
292
  }
279
  }
293
 
280
 
Línea -... Línea 281...
-
 
281
  _getOffset() {
-
 
282
    const { offset } = this._config
-
 
283
 
-
 
284
    if (typeof offset === 'string') {
-
 
285
      return offset.split(',').map(value => Number.parseInt(value, 10))
-
 
286
    }
-
 
287
 
-
 
288
    if (typeof offset === 'function') {
-
 
289
      return popperData => offset(popperData, this._element)
-
 
290
    }
-
 
291
 
-
 
292
    return offset
294
  _getOffset() {
293
  }
295
    const offset = {}
294
 
296
 
295
  _getPopperConfig() {
297
    if (typeof this._config.offset === 'function') {
-
 
298
      offset.fn = data => {
296
    const defaultBsPopperConfig = {
Línea 299... Línea -...
299
        data.offsets = {
-
 
300
          ...data.offsets,
297
      placement: this._getPlacement(),
301
          ...this._config.offset(data.offsets, this._element)
298
      modifiers: [{
302
        }
299
        name: 'preventOverflow',
Línea 303... Línea -...
303
 
-
 
304
        return data
300
        options: {
305
      }
301
          boundary: this._config.boundary
306
    } else {
-
 
307
      offset.offset = this._config.offset
-
 
308
    }
-
 
309
 
302
        }
-
 
303
      },
-
 
304
      {
310
    return offset
305
        name: 'offset',
311
  }
306
        options: {
Línea 312... Línea 307...
312
 
307
          offset: this._getOffset()
313
  _getPopperConfig() {
-
 
314
    const popperConfig = {
308
        }
315
      placement: this._getPlacement(),
309
      }]
316
      modifiers: {
310
    }
Línea 317... Línea 311...
317
        offset: this._getOffset(),
311
 
Línea 318... Línea 312...
318
        flip: {
312
    // Disable Popper if we have a static display or Dropdown is in Navbar
319
          enabled: this._config.flip
313
    if (this._inNavbar || this._config.display === 'static') {
320
        },
-
 
321
        preventOverflow: {
-
 
322
          boundariesElement: this._config.boundary
-
 
323
        }
-
 
324
      }
-
 
325
    }
314
      Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove
326
 
-
 
327
    // Disable Popper if we have a static display
-
 
328
    if (this._config.display === 'static') {
-
 
329
      popperConfig.modifiers.applyStyle = {
-
 
330
        enabled: false
315
      defaultBsPopperConfig.modifiers = [{
331
      }
316
        name: 'applyStyles',
Línea -... Línea 317...
-
 
317
        enabled: false
332
    }
318
      }]
-
 
319
    }
333
 
320
 
-
 
321
    return {
-
 
322
      ...defaultBsPopperConfig,
-
 
323
      ...execute(this._config.popperConfig, [defaultBsPopperConfig])
334
    return {
324
    }
335
      ...popperConfig,
325
  }
Línea 336... Línea 326...
336
      ...this._config.popperConfig
326
 
337
    }
327
  _selectMenuItem({ key, target }) {
338
  }
-
 
339
 
328
    const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))
340
  // Static
329
 
Línea 341... Línea 330...
341
  static _jQueryInterface(config) {
330
    if (!items.length) {
342
    return this.each(function () {
-
 
343
      let data = $(this).data(DATA_KEY)
-
 
344
      const _config = typeof config === 'object' ? config : null
-
 
345
 
-
 
Línea 346... Línea -...
346
      if (!data) {
-
 
347
        data = new Dropdown(this, _config)
-
 
348
        $(this).data(DATA_KEY, data)
-
 
349
      }
-
 
350
 
-
 
351
      if (typeof config === 'string') {
-
 
352
        if (typeof data[config] === 'undefined') {
-
 
353
          throw new TypeError(`No method named "${config}"`)
-
 
354
        }
331
      return
355
 
332
    }
356
        data[config]()
333
 
Línea 357... Línea -...
357
      }
-
 
358
    })
-
 
359
  }
-
 
360
 
334
    // if target isn't included in items (e.g. when expanding the dropdown)
361
  static _clearMenus(event) {
335
    // allow cycling to get the last item in case key equals ARROW_UP_KEY
362
    if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH ||
336
    getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()
Línea 363... Línea 337...
363
      event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
337
  }
364
      return
338
 
365
    }
339
  // Static
Línea 366... Línea 340...
366
 
340
  static jQueryInterface(config) {
367
    const toggles = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE))
341
    return this.each(function () {
368
 
-
 
369
    for (let i = 0, len = toggles.length; i < len; i++) {
-
 
370
      const parent = Dropdown._getParentFromElement(toggles[i])
342
      const data = Dropdown.getOrCreateInstance(this, config)
371
      const context = $(toggles[i]).data(DATA_KEY)
-
 
Línea 372... Línea -...
372
      const relatedTarget = {
-
 
373
        relatedTarget: toggles[i]
343
 
374
      }
-
 
375
 
-
 
376
      if (event && event.type === 'click') {
-
 
377
        relatedTarget.clickEvent = event
-
 
378
      }
-
 
379
 
-
 
380
      if (!context) {
-
 
381
        continue
-
 
382
      }
-
 
383
 
-
 
384
      const dropdownMenu = context._menu
-
 
385
      if (!$(parent).hasClass(CLASS_NAME_SHOW)) {
344
      if (typeof config !== 'string') {
386
        continue
345
        return
Línea 387... Línea -...
387
      }
-
 
388
 
-
 
389
      if (event && (event.type === 'click' &&
-
 
390
          /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) &&
-
 
391
          $.contains(parent, event.target)) {
-
 
392
        continue
-
 
393
      }
-
 
394
 
346
      }
395
      const hideEvent = $.Event(EVENT_HIDE, relatedTarget)
347
 
396
      $(parent).trigger(hideEvent)
348
      if (typeof data[config] === 'undefined') {
Línea 397... Línea 349...
397
      if (hideEvent.isDefaultPrevented()) {
349
        throw new TypeError(`No method named "${config}"`)
398
        continue
-
 
Línea 399... Línea 350...
399
      }
350
      }
400
 
-
 
401
      // If this is a touch-enabled device we remove the extra
351
 
402
      // empty mouseover listeners we added for iOS support
352
      data[config]()
403
      if ('ontouchstart' in document.documentElement) {
-
 
404
        $(document.body).children().off('mouseover', null, $.noop)
353
    })
405
      }
354
  }
406
 
-
 
-
 
355
 
Línea 407... Línea 356...
407
      toggles[i].setAttribute('aria-expanded', 'false')
356
  static clearMenus(event) {
408
 
-
 
Línea 409... Línea 357...
409
      if (context._popper) {
357
    if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {
-
 
358
      return
-
 
359
    }
-
 
360
 
410
        context._popper.destroy()
361
    const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)
411
      }
362
 
Línea 412... Línea -...
412
 
-
 
413
      $(dropdownMenu).removeClass(CLASS_NAME_SHOW)
-
 
414
      $(parent)
363
    for (const toggle of openToggles) {
415
        .removeClass(CLASS_NAME_SHOW)
364
      const context = Dropdown.getInstance(toggle)
416
        .trigger($.Event(EVENT_HIDDEN, relatedTarget))
-
 
417
    }
-
 
418
  }
-
 
419
 
365
      if (!context || context._config.autoClose === false) {
420
  static _getParentFromElement(element) {
-
 
421
    let parent
-
 
422
    const selector = Util.getSelectorFromElement(element)
366
        continue
423
 
-
 
424
    if (selector) {
367
      }
425
      parent = document.querySelector(selector)
-
 
426
    }
-
 
427
 
368
 
428
    return parent || element.parentNode
369
      const composedPath = event.composedPath()
Línea 429... Línea 370...
429
  }
370
      const isMenuTarget = composedPath.includes(context._menu)
430
 
371
      if (
431
  // eslint-disable-next-line complexity
372
        composedPath.includes(context._element) ||
Línea 432... Línea -...
432
  static _dataApiKeydownHandler(event) {
-
 
433
    // If not input/textarea:
373
        (context._config.autoClose === 'inside' && !isMenuTarget) ||
434
    //  - And not a key in REGEXP_KEYDOWN => not a dropdown command
374
        (context._config.autoClose === 'outside' && isMenuTarget)
-
 
375
      ) {
435
    // If input/textarea:
376
        continue
436
    //  - If space key => not a dropdown command
377
      }
437
    //  - If key is other than escape
378
 
438
    //    - If key is not up or down => not a dropdown command
-
 
439
    //    - If trigger inside the menu => not a dropdown command
379
      // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
440
    if (/input|textarea/i.test(event.target.tagName) ?
-
 
441
      event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE &&
-
 
442
      (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE ||
-
 
443
        $(event.target).closest(SELECTOR_MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {
380
      if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {
Línea 444... Línea 381...
444
      return
381
        continue
445
    }
382
      }
446
 
383
 
Línea 447... Línea -...
447
    if (this.disabled || $(this).hasClass(CLASS_NAME_DISABLED)) {
-
 
448
      return
384
      const relatedTarget = { relatedTarget: context._element }
449
    }
-
 
450
 
-
 
451
    const parent = Dropdown._getParentFromElement(this)
-
 
452
    const isActive = $(parent).hasClass(CLASS_NAME_SHOW)
-
 
Línea 453... Línea 385...
453
 
385