1 | /**
|
---|
2 | * --------------------------------------------------------------------------
|
---|
3 | * Bootstrap (v5.1.3): dom/selector-engine.js
|
---|
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
---|
5 | * --------------------------------------------------------------------------
|
---|
6 | */
|
---|
7 |
|
---|
8 | /**
|
---|
9 | * ------------------------------------------------------------------------
|
---|
10 | * Constants
|
---|
11 | * ------------------------------------------------------------------------
|
---|
12 | */
|
---|
13 |
|
---|
14 | import { isDisabled, isVisible } from '../util/index'
|
---|
15 |
|
---|
16 | const NODE_TEXT = 3
|
---|
17 |
|
---|
18 | const SelectorEngine = {
|
---|
19 | find(selector, element = document.documentElement) {
|
---|
20 | return [].concat(...Element.prototype.querySelectorAll.call(element, selector))
|
---|
21 | },
|
---|
22 |
|
---|
23 | findOne(selector, element = document.documentElement) {
|
---|
24 | return Element.prototype.querySelector.call(element, selector)
|
---|
25 | },
|
---|
26 |
|
---|
27 | children(element, selector) {
|
---|
28 | return [].concat(...element.children)
|
---|
29 | .filter(child => child.matches(selector))
|
---|
30 | },
|
---|
31 |
|
---|
32 | parents(element, selector) {
|
---|
33 | const parents = []
|
---|
34 |
|
---|
35 | let ancestor = element.parentNode
|
---|
36 |
|
---|
37 | while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) {
|
---|
38 | if (ancestor.matches(selector)) {
|
---|
39 | parents.push(ancestor)
|
---|
40 | }
|
---|
41 |
|
---|
42 | ancestor = ancestor.parentNode
|
---|
43 | }
|
---|
44 |
|
---|
45 | return parents
|
---|
46 | },
|
---|
47 |
|
---|
48 | prev(element, selector) {
|
---|
49 | let previous = element.previousElementSibling
|
---|
50 |
|
---|
51 | while (previous) {
|
---|
52 | if (previous.matches(selector)) {
|
---|
53 | return [previous]
|
---|
54 | }
|
---|
55 |
|
---|
56 | previous = previous.previousElementSibling
|
---|
57 | }
|
---|
58 |
|
---|
59 | return []
|
---|
60 | },
|
---|
61 |
|
---|
62 | next(element, selector) {
|
---|
63 | let next = element.nextElementSibling
|
---|
64 |
|
---|
65 | while (next) {
|
---|
66 | if (next.matches(selector)) {
|
---|
67 | return [next]
|
---|
68 | }
|
---|
69 |
|
---|
70 | next = next.nextElementSibling
|
---|
71 | }
|
---|
72 |
|
---|
73 | return []
|
---|
74 | },
|
---|
75 |
|
---|
76 | focusableChildren(element) {
|
---|
77 | const focusables = [
|
---|
78 | 'a',
|
---|
79 | 'button',
|
---|
80 | 'input',
|
---|
81 | 'textarea',
|
---|
82 | 'select',
|
---|
83 | 'details',
|
---|
84 | '[tabindex]',
|
---|
85 | '[contenteditable="true"]'
|
---|
86 | ].map(selector => `${selector}:not([tabindex^="-"])`).join(', ')
|
---|
87 |
|
---|
88 | return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))
|
---|
89 | }
|
---|
90 | }
|
---|
91 |
|
---|
92 | export default SelectorEngine
|
---|