]>
git.ipfire.org Git - ipfire.org.git/blob - src/scss/bootstrap-4.0.0-alpha.6/js/src/dropdown.js
1 import Util
from './util'
5 * --------------------------------------------------------------------------
6 * Bootstrap (v4.0.0-alpha.6): dropdown.js
7 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
8 * --------------------------------------------------------------------------
11 const Dropdown
= (($) => {
15 * ------------------------------------------------------------------------
17 * ------------------------------------------------------------------------
20 const NAME
= 'dropdown'
21 const VERSION
= '4.0.0-alpha.6'
22 const DATA_KEY
= 'bs.dropdown'
23 const EVENT_KEY
= `.${DATA_KEY}`
24 const DATA_API_KEY
= '.data-api'
25 const JQUERY_NO_CONFLICT
= $.fn
[NAME
]
26 const ESCAPE_KEYCODE
= 27 // KeyboardEvent.which value for Escape (Esc) key
27 const ARROW_UP_KEYCODE
= 38 // KeyboardEvent.which value for up arrow key
28 const ARROW_DOWN_KEYCODE
= 40 // KeyboardEvent.which value for down arrow key
29 const RIGHT_MOUSE_BUTTON_WHICH
= 3 // MouseEvent.which value for the right button (assuming a right-handed mouse)
32 HIDE
: `hide${EVENT_KEY}`,
33 HIDDEN
: `hidden${EVENT_KEY}`,
34 SHOW
: `show${EVENT_KEY}`,
35 SHOWN
: `shown${EVENT_KEY}`,
36 CLICK
: `click${EVENT_KEY}`,
37 CLICK_DATA_API
: `click${EVENT_KEY}${DATA_API_KEY}`,
38 FOCUSIN_DATA_API
: `focusin${EVENT_KEY}${DATA_API_KEY}`,
39 KEYDOWN_DATA_API
: `keydown${EVENT_KEY}${DATA_API_KEY}`
43 BACKDROP
: 'dropdown-backdrop',
44 DISABLED
: 'disabled',
49 BACKDROP
: '.dropdown-backdrop',
50 DATA_TOGGLE
: '[data-toggle="dropdown"]',
51 FORM_CHILD
: '.dropdown form',
52 ROLE_MENU
: '[role="menu"]',
53 ROLE_LISTBOX
: '[role="listbox"]',
54 NAVBAR_NAV
: '.navbar-nav',
55 VISIBLE_ITEMS
: '[role="menu"] li:not(.disabled) a, '
56 + '[role="listbox"] li:not(.disabled) a'
61 * ------------------------------------------------------------------------
63 * ------------------------------------------------------------------------
68 constructor(element
) {
69 this._element
= element
71 this._addEventListeners()
77 static get VERSION() {
85 if (this.disabled
|| $(this).hasClass(ClassName
.DISABLED
)) {
89 const parent
= Dropdown
._getParentFromElement(this)
90 const isActive
= $(parent
).hasClass(ClassName
.SHOW
)
92 Dropdown
._clearMenus()
98 if ('ontouchstart' in document
.documentElement
&&
99 !$(parent
).closest(Selector
.NAVBAR_NAV
).length
) {
101 // if mobile we use a backdrop because click events don't delegate
102 const dropdown
= document
.createElement('div')
103 dropdown
.className
= ClassName
.BACKDROP
104 $(dropdown
).insertBefore(this)
105 $(dropdown
).on('click', Dropdown
._clearMenus
)
108 const relatedTarget
= {
111 const showEvent
= $.Event(Event
.SHOW
, relatedTarget
)
113 $(parent
).trigger(showEvent
)
115 if (showEvent
.isDefaultPrevented()) {
120 this.setAttribute('aria-expanded', true)
122 $(parent
).toggleClass(ClassName
.SHOW
)
123 $(parent
).trigger($.Event(Event
.SHOWN
, relatedTarget
))
129 $.removeData(this._element
, DATA_KEY
)
130 $(this._element
).off(EVENT_KEY
)
137 _addEventListeners() {
138 $(this._element
).on(Event
.CLICK
, this.toggle
)
144 static _jQueryInterface(config
) {
145 return this.each(function () {
146 let data
= $(this).data(DATA_KEY
)
149 data
= new Dropdown(this)
150 $(this).data(DATA_KEY
, data
)
153 if (typeof config
=== 'string') {
154 if (data
[config
] === undefined) {
155 throw new Error(`No method named "${config}"`)
157 data
[config
].call(this)
162 static _clearMenus(event
) {
163 if (event
&& event
.which
=== RIGHT_MOUSE_BUTTON_WHICH
) {
167 const backdrop
= $(Selector
.BACKDROP
)[0]
169 backdrop
.parentNode
.removeChild(backdrop
)
172 const toggles
= $.makeArray($(Selector
.DATA_TOGGLE
))
174 for (let i
= 0; i
< toggles
.length
; i
++) {
175 const parent
= Dropdown
._getParentFromElement(toggles
[i
])
176 const relatedTarget
= {
177 relatedTarget
: toggles
[i
]
180 if (!$(parent
).hasClass(ClassName
.SHOW
)) {
184 if (event
&& (event
.type
=== 'click' &&
185 /input|textarea/i.test(event
.target
.tagName
) || event
.type
=== 'focusin')
186 && $.contains(parent
, event
.target
)) {
190 const hideEvent
= $.Event(Event
.HIDE
, relatedTarget
)
191 $(parent
).trigger(hideEvent
)
192 if (hideEvent
.isDefaultPrevented()) {
196 toggles
[i
].setAttribute('aria-expanded', 'false')
199 .removeClass(ClassName
.SHOW
)
200 .trigger($.Event(Event
.HIDDEN
, relatedTarget
))
204 static _getParentFromElement(element
) {
206 const selector
= Util
.getSelectorFromElement(element
)
209 parent
= $(selector
)[0]
212 return parent
|| element
.parentNode
215 static _dataApiKeydownHandler(event
) {
216 if (!/(38|40|27|32)/.test(event
.which
) ||
217 /input|textarea/i.test(event
.target
.tagName
)) {
221 event
.preventDefault()
222 event
.stopPropagation()
224 if (this.disabled
|| $(this).hasClass(ClassName
.DISABLED
)) {
228 const parent
= Dropdown
._getParentFromElement(this)
229 const isActive
= $(parent
).hasClass(ClassName
.SHOW
)
231 if (!isActive
&& event
.which
!== ESCAPE_KEYCODE
||
232 isActive
&& event
.which
=== ESCAPE_KEYCODE
) {
234 if (event
.which
=== ESCAPE_KEYCODE
) {
235 const toggle
= $(parent
).find(Selector
.DATA_TOGGLE
)[0]
236 $(toggle
).trigger('focus')
239 $(this).trigger('click')
243 const items
= $(parent
).find(Selector
.VISIBLE_ITEMS
).get()
249 let index
= items
.indexOf(event
.target
)
251 if (event
.which
=== ARROW_UP_KEYCODE
&& index
> 0) { // up
255 if (event
.which
=== ARROW_DOWN_KEYCODE
&& index
< items
.length
- 1) { // down
270 * ------------------------------------------------------------------------
271 * Data Api implementation
272 * ------------------------------------------------------------------------
276 .on(Event
.KEYDOWN_DATA_API
, Selector
.DATA_TOGGLE
, Dropdown
._dataApiKeydownHandler
)
277 .on(Event
.KEYDOWN_DATA_API
, Selector
.ROLE_MENU
, Dropdown
._dataApiKeydownHandler
)
278 .on(Event
.KEYDOWN_DATA_API
, Selector
.ROLE_LISTBOX
, Dropdown
._dataApiKeydownHandler
)
279 .on(`${Event.CLICK_DATA_API} ${Event.FOCUSIN_DATA_API}`, Dropdown
._clearMenus
)
280 .on(Event
.CLICK_DATA_API
, Selector
.DATA_TOGGLE
, Dropdown
.prototype.toggle
)
281 .on(Event
.CLICK_DATA_API
, Selector
.FORM_CHILD
, (e
) => {
287 * ------------------------------------------------------------------------
289 * ------------------------------------------------------------------------
292 $.fn
[NAME
] = Dropdown
._jQueryInterface
293 $.fn
[NAME
].Constructor
= Dropdown
294 $.fn
[NAME
].noConflict = function () {
295 $.fn
[NAME
] = JQUERY_NO_CONFLICT
296 return Dropdown
._jQueryInterface
303 export default Dropdown