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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
/**
* @file menu-item.js
*/
import ClickableComponent from '../clickable-component.js';
import Component from '../component.js';
import {createEl} from '../utils/dom.js';
/** @import Player from '../player' */
/**
* The component for a menu item. `<li>`
*
* @extends ClickableComponent
*/
class MenuItem extends ClickableComponent {
/**
* Creates an instance of the this class.
*
* @param {Player} player
* The `Player` that this class should be attached to.
*
* @param {Object} [options={}]
* The key/value store of player options.
*
*/
constructor(player, options) {
super(player, options);
this.selectable = options.selectable;
this.isSelected_ = options.selected || false;
this.multiSelectable = options.multiSelectable;
this.selected(this.isSelected_);
if (this.selectable) {
if (this.multiSelectable) {
this.el_.setAttribute('role', 'menuitemcheckbox');
} else {
this.el_.setAttribute('role', 'menuitemradio');
}
} else {
this.el_.setAttribute('role', 'menuitem');
}
}
/**
* Create the `MenuItem's DOM element
*
* @param {string} [type=li]
* Element's node type, not actually used, always set to `li`.
*
* @param {Object} [props={}]
* An object of properties that should be set on the element
*
* @param {Object} [attrs={}]
* An object of attributes that should be set on the element
*
* @return {Element}
* The element that gets created.
*/
createEl(type, props, attrs) {
// The control is textual, not just an icon
this.nonIconControl = true;
const el = super.createEl('li', Object.assign({
className: 'vjs-menu-item',
tabIndex: -1
}, props), attrs);
// swap icon with menu item text.
const menuItemEl = createEl('span', {
className: 'vjs-menu-item-text',
textContent: this.localize(this.options_.label)
});
// If using SVG icons, the element with vjs-icon-placeholder will be added separately.
if (this.player_.options_.experimentalSvgIcons) {
el.appendChild(menuItemEl);
} else {
el.replaceChild(menuItemEl, el.querySelector('.vjs-icon-placeholder'));
}
return el;
}
/**
* Ignore keys which are used by the menu, but pass any other ones up. See
* {@link ClickableComponent#handleKeyDown} for instances where this is called.
*
* @param {KeyboardEvent} event
* The `keydown` event that caused this function to be called.
*
* @listens keydown
*/
handleKeyDown(event) {
if (!['Tab', 'Escape', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'ArrowDown'].includes(event.key)) {
// Pass keydown handling up for unused keys
super.handleKeyDown(event);
}
}
/**
* Any click on a `MenuItem` puts it into the selected state.
* See {@link ClickableComponent#handleClick} for instances where this is called.
*
* @param {Event} event
* The `keydown`, `tap`, or `click` event that caused this function to be
* called.
*
* @listens tap
* @listens click
*/
handleClick(event) {
this.selected(true);
}
/**
* Set the state for this menu item as selected or not.
*
* @param {boolean} selected
* if the menu item is selected or not
*/
selected(selected) {
if (this.selectable) {
if (selected) {
this.addClass('vjs-selected');
this.el_.setAttribute('aria-checked', 'true');
// aria-checked isn't fully supported by browsers/screen readers,
// so indicate selected state to screen reader in the control text.
this.controlText(', selected');
this.isSelected_ = true;
} else {
this.removeClass('vjs-selected');
this.el_.setAttribute('aria-checked', 'false');
// Indicate un-selected state to screen reader
this.controlText('');
this.isSelected_ = false;
}
}
}
}
Component.registerComponent('MenuItem', MenuItem);
export default MenuItem;
|