-
Notifications
You must be signed in to change notification settings - Fork 406
/
Copy pathto-be-disabled.js
115 lines (101 loc) · 2.83 KB
/
to-be-disabled.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import {checkHtmlElement, getTag} from './utils'
// form elements that support 'disabled'
const FORM_TAGS = [
'fieldset',
'input',
'select',
'optgroup',
'option',
'button',
'textarea',
]
/*
* According to specification:
* If <fieldset> is disabled, the form controls that are its descendants,
* except descendants of its first optional <legend> element, are disabled
*
* https://html.spec.whatwg.org/multipage/form-elements.html#concept-fieldset-disabled
*
* This method tests whether element is first legend child of fieldset parent
*/
function isFirstLegendChildOfFieldset(element, parent) {
return (
getTag(element) === 'legend' &&
getTag(parent) === 'fieldset' &&
element.isSameNode(
Array.from(parent.children).find(child => getTag(child) === 'legend'),
)
)
}
function isElementDisabledByParent(element, parent) {
return (
isElementDisabled(parent) && !isFirstLegendChildOfFieldset(element, parent)
)
}
function isCustomElement(tag) {
return tag.includes('-')
}
/*
* Only certain form elements and custom elements can actually be disabled:
* https://html.spec.whatwg.org/multipage/semantics-other.html#disabled-elements
*/
function canElementBeDisabled(element) {
const tag = getTag(element)
return FORM_TAGS.includes(tag) || isCustomElement(tag)
}
function isElementDisabled(element) {
return canElementBeDisabled(element) && element.hasAttribute('disabled')
}
function isAncestorDisabled(element) {
const parent = element.parentElement
return (
Boolean(parent) &&
(isElementDisabledByParent(element, parent) || isAncestorDisabled(parent))
)
}
function isElementOrAncestorDisabled(element) {
return (
canElementBeDisabled(element) &&
(isElementDisabled(element) || isAncestorDisabled(element))
)
}
export function toBeDisabled(element) {
checkHtmlElement(element, toBeDisabled, this)
const isDisabled = isElementOrAncestorDisabled(element)
return {
pass: isDisabled,
message: () => {
const is = isDisabled ? 'is' : 'is not'
return [
this.utils.matcherHint(
`${this.isNot ? '.not' : ''}.toBeDisabled`,
'element',
'',
),
'',
`Received element ${is} disabled:`,
` ${this.utils.printReceived(element.cloneNode(false))}`,
].join('\n')
},
}
}
export function toBeEnabled(element) {
checkHtmlElement(element, toBeEnabled, this)
const isEnabled = !isElementOrAncestorDisabled(element)
return {
pass: isEnabled,
message: () => {
const is = isEnabled ? 'is' : 'is not'
return [
this.utils.matcherHint(
`${this.isNot ? '.not' : ''}.toBeEnabled`,
'element',
'',
),
'',
`Received element ${is} enabled:`,
` ${this.utils.printReceived(element.cloneNode(false))}`,
].join('\n')
},
}
}