forked from ember-template-lint/ember-template-lint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
is-interactive-element.js
115 lines (94 loc) · 2.27 KB
/
is-interactive-element.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
'use strict';
var ast = require('./ast-node-info');
var INTERACTIVE_TAG_NAMES = [
'button',
'details',
'embed',
'iframe',
'input',
'keygen',
'label',
'select',
'textarea'
];
// Spec: https://www.w3.org/TR/wai-aria/complete#widget_roles
var ARIA_WIDGET_ROLES = [
'alert',
'alertdialog',
'button',
'checkbox',
'dialog',
'gridcell',
'link',
'log',
'marquee',
'menuitem',
'menuitemcheckbox',
'menuitemradio',
'option',
'progressbar',
'radio',
'scrollbar',
'slider',
'spinbutton',
'status',
'tab',
'tabpanel',
'textbox',
'timer',
'tooltip',
'treeitem'
];
function isHyperLink(node) {
return node.tag === 'a' && ast.hasAttribute(node, 'href');
}
function isHiddenInput(node) {
if (node.tag !== 'input') { return false; }
var type = ast.findAttribute(node, 'type');
if (type && type.value && type.value.chars === 'hidden') {
return true;
}
return false;
}
function getInteractiveAriaRole(node) {
var role = ast.findAttribute(node, 'role');
if (role && role.value && ARIA_WIDGET_ROLES.indexOf(role.value.chars) > -1) {
return 'role="' + role.value.chars + '"';
}
return false;
}
/*
Spec: https://html.spec.whatwg.org/multipage/dom.html#interactive-content-2
`<label>` was omitted due to the ability nesting a label with an input tag.
`<audio>` and `<video>` also omitted because use legacy browser support
there is a need to use it nested with `<object>` and `<a>`
*/
function reason(node) {
if (!ast.isElementNode(node) && !ast.isComponentNode(node)) {
return null;
}
if (isHiddenInput(node)) {
return null;
}
if (INTERACTIVE_TAG_NAMES.indexOf(node.tag) > -1) {
return '<' + node.tag + '>';
}
var role;
if ((role = getInteractiveAriaRole(node))) {
return 'an element with `' + role + '`';
}
if (isHyperLink(node)) {
return 'an <a> element with the `href` attribute';
}
if (ast.hasAttribute(node, 'tabindex')) {
return 'an element with the `tabindex` attribute';
}
if ((node.tag === 'img' || node.tag === 'object') && ast.hasAttribute(node, 'usemap')) {
return 'an <' + node.tag + '> element with the `usemap` attribute';
}
return null;
}
module.exports = function isInteractive(node) {
return reason(node) !== null;
};
module.exports.reason = reason;