Skip to content

Commit d251e97

Browse files
misteroneillgkatsev
authored andcommitted
fix: make sure hotkeys are not triggered outside the player or in form fields within the player (#5969)
1 parent 47d60ae commit d251e97

17 files changed

+674
-275
lines changed

src/js/big-play-button.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,15 @@ class BigPlayButton extends Button {
4747
// exit early if clicked via the mouse
4848
if (this.mouseused_ && event.clientX && event.clientY) {
4949
silencePromise(playPromise);
50-
// call handleFocus manually to get hotkeys working
51-
this.player_.handleFocus({});
50+
this.player_.tech(true).focus();
5251
return;
5352
}
5453

5554
const cb = this.player_.getChild('controlBar');
5655
const playToggle = cb && cb.getChild('playToggle');
5756

5857
if (!playToggle) {
59-
this.player_.focus();
58+
this.player_.tech(true).focus();
6059
return;
6160
}
6261

@@ -69,10 +68,10 @@ class BigPlayButton extends Button {
6968
}
7069
}
7170

72-
handleKeyPress(event) {
71+
handleKeyDown(event) {
7372
this.mouseused_ = false;
7473

75-
super.handleKeyPress(event);
74+
super.handleKeyDown(event);
7675
}
7776

7877
handleMouseDown(event) {

src/js/button.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,20 @@ class Button extends ClickableComponent {
104104
*
105105
* @listens keydown
106106
*/
107-
handleKeyPress(event) {
108-
// Ignore Space or Enter key operation, which is handled by the browser for a button.
109-
if (!(keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter'))) {
110-
111-
// Pass keypress handling up for unsupported keys
112-
super.handleKeyPress(event);
107+
handleKeyDown(event) {
108+
109+
// Ignore Space or Enter key operation, which is handled by the browser for
110+
// a button - though not for its super class, ClickableComponent. Also,
111+
// prevent the event from propagating through the DOM and triggering Player
112+
// hotkeys. We do not preventDefault here because we _want_ the browser to
113+
// handle it.
114+
if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) {
115+
event.stopPropagation();
116+
return;
113117
}
118+
119+
// Pass keypress handling up for unsupported keys
120+
super.handleKeyDown(event);
114121
}
115122
}
116123

src/js/clickable-component.js

Lines changed: 22 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@
33
*/
44
import Component from './component';
55
import * as Dom from './utils/dom.js';
6-
import * as Events from './utils/events.js';
7-
import * as Fn from './utils/fn.js';
86
import log from './utils/log.js';
9-
import document from 'global/document';
107
import {assign} from './utils/obj';
118
import keycode from 'keycode';
129

1310
/**
14-
* Clickable Component which is clickable or keyboard actionable,
15-
* but is not a native HTML button.
11+
* Component which is clickable or keyboard actionable, but is not a
12+
* native HTML button.
1613
*
1714
* @extends Component
1815
*/
@@ -36,7 +33,7 @@ class ClickableComponent extends Component {
3633
}
3734

3835
/**
39-
* Create the `Component`s DOM element.
36+
* Create the `ClickableComponent`s DOM element.
4037
*
4138
* @param {string} [tag=div]
4239
* The element's node type.
@@ -83,7 +80,7 @@ class ClickableComponent extends Component {
8380
}
8481

8582
/**
86-
* Create a control text element on this `Component`
83+
* Create a control text element on this `ClickableComponent`
8784
*
8885
* @param {Element} [el]
8986
* Parent element for the control text.
@@ -109,7 +106,7 @@ class ClickableComponent extends Component {
109106
}
110107

111108
/**
112-
* Get or set the localize text to use for the controls on the `Component`.
109+
* Get or set the localize text to use for the controls on the `ClickableComponent`.
113110
*
114111
* @param {string} [text]
115112
* Control text for element.
@@ -146,7 +143,7 @@ class ClickableComponent extends Component {
146143
}
147144

148145
/**
149-
* Enable this `Component`s element.
146+
* Enable this `ClickableComponent`
150147
*/
151148
enable() {
152149
if (!this.enabled_) {
@@ -157,13 +154,12 @@ class ClickableComponent extends Component {
157154
this.el_.setAttribute('tabIndex', this.tabIndex_);
158155
}
159156
this.on(['tap', 'click'], this.handleClick);
160-
this.on('focus', this.handleFocus);
161-
this.on('blur', this.handleBlur);
157+
this.on('keydown', this.handleKeyDown);
162158
}
163159
}
164160

165161
/**
166-
* Disable this `Component`s element.
162+
* Disable this `ClickableComponent`
167163
*/
168164
disable() {
169165
this.enabled_ = false;
@@ -173,27 +169,15 @@ class ClickableComponent extends Component {
173169
this.el_.removeAttribute('tabIndex');
174170
}
175171
this.off(['tap', 'click'], this.handleClick);
176-
this.off('focus', this.handleFocus);
177-
this.off('blur', this.handleBlur);
172+
this.off('keydown', this.handleKeyDown);
178173
}
179174

180175
/**
181-
* This gets called when a `ClickableComponent` gets:
182-
* - Clicked (via the `click` event, listening starts in the constructor)
183-
* - Tapped (via the `tap` event, listening starts in the constructor)
184-
* - The following things happen in order:
185-
* 1. {@link ClickableComponent#handleFocus} is called via a `focus` event on the
186-
* `ClickableComponent`.
187-
* 2. {@link ClickableComponent#handleFocus} adds a listener for `keydown` on using
188-
* {@link ClickableComponent#handleKeyPress}.
189-
* 3. `ClickableComponent` has not had a `blur` event (`blur` means that focus was lost). The user presses
190-
* the space or enter key.
191-
* 4. {@link ClickableComponent#handleKeyPress} calls this function with the `keydown`
192-
* event as a parameter.
176+
* Event handler that is called when a `ClickableComponent` receives a
177+
* `click` or `tap` event.
193178
*
194179
* @param {EventTarget~Event} event
195-
* The `keydown`, `tap`, or `click` event that caused this function to be
196-
* called.
180+
* The `tap` or `click` event that caused this function to be called.
197181
*
198182
* @listens tap
199183
* @listens click
@@ -202,52 +186,31 @@ class ClickableComponent extends Component {
202186
handleClick(event) {}
203187

204188
/**
205-
* This gets called when a `ClickableComponent` gains focus via a `focus` event.
206-
* Turns on listening for `keydown` events. When they happen it
207-
* calls `this.handleKeyPress`.
189+
* Event handler that is called when a `ClickableComponent` receives a
190+
* `keydown` event.
208191
*
209-
* @param {EventTarget~Event} event
210-
* The `focus` event that caused this function to be called.
211-
*
212-
* @listens focus
213-
*/
214-
handleFocus(event) {
215-
Events.on(document, 'keydown', Fn.bind(this, this.handleKeyPress));
216-
}
217-
218-
/**
219-
* Called when this ClickableComponent has focus and a key gets pressed down. By
220-
* default it will call `this.handleClick` when the key is space or enter.
192+
* By default, if the key is Space or Enter, it will trigger a `click` event.
221193
*
222194
* @param {EventTarget~Event} event
223195
* The `keydown` event that caused this function to be called.
224196
*
225197
* @listens keydown
226198
*/
227-
handleKeyPress(event) {
228-
// Support Space or Enter key operation to fire a click event
199+
handleKeyDown(event) {
200+
201+
// Support Space or Enter key operation to fire a click event. Also,
202+
// prevent the event from propagating through the DOM and triggering
203+
// Player hotkeys.
229204
if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) {
230205
event.preventDefault();
206+
event.stopPropagation();
231207
this.trigger('click');
232208
} else {
233209

234210
// Pass keypress handling up for unsupported keys
235-
super.handleKeyPress(event);
211+
super.handleKeyDown(event);
236212
}
237213
}
238-
239-
/**
240-
* Called when a `ClickableComponent` loses focus. Turns off the listener for
241-
* `keydown` events. Which Stops `this.handleKeyPress` from getting called.
242-
*
243-
* @param {EventTarget~Event} event
244-
* The `blur` event that caused this function to be called.
245-
*
246-
* @listens blur
247-
*/
248-
handleBlur(event) {
249-
Events.off(document, 'keydown', Fn.bind(this, this.handleKeyPress));
250-
}
251214
}
252215

253216
Component.registerComponent('ClickableComponent', ClickableComponent);

src/js/close-button.js

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,10 @@ class CloseButton extends Button {
3636
return `vjs-close-button ${super.buildCSSClass()}`;
3737
}
3838

39-
/**
40-
* This gets called when a `CloseButton` has focus and `keydown` is triggered via a key
41-
* press.
42-
*
43-
* @param {EventTarget~Event} event
44-
* The event that caused this function to get called.
45-
*
46-
* @listens keydown
47-
*/
48-
handleKeyPress(event) {
49-
// Override the default `Button` behavior, and don't pass the keypress event
50-
// up to the player because this button is part of a `ModalDialog`, which
51-
// doesn't pass keypresses to the player either.
52-
}
53-
5439
/**
5540
* This gets called when a `CloseButton` gets clicked. See
56-
* {@link ClickableComponent#handleClick} for more information on when this will be
57-
* triggered
41+
* {@link ClickableComponent#handleClick} for more information on when
42+
* this will be triggered
5843
*
5944
* @param {EventTarget~Event} event
6045
* The `keydown`, `tap`, or `click` event that caused this function to be

src/js/component.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,18 +1078,35 @@ class Component {
10781078
}
10791079

10801080
/**
1081-
* When this Component receives a keydown event which it does not process,
1081+
* When this Component receives a `keydown` event which it does not process,
10821082
* it passes the event to the Player for handling.
10831083
*
10841084
* @param {EventTarget~Event} event
10851085
* The `keydown` event that caused this function to be called.
10861086
*/
1087-
handleKeyPress(event) {
1087+
handleKeyDown(event) {
10881088
if (this.player_) {
1089-
this.player_.handleKeyPress(event);
1089+
1090+
// We only stop propagation here because we want unhandled events to fall
1091+
// back to the browser.
1092+
event.stopPropagation();
1093+
this.player_.handleKeyDown(event);
10901094
}
10911095
}
10921096

1097+
/**
1098+
* Many components used to have a `handleKeyPress` method, which was poorly
1099+
* named because it listened to a `keydown` event. This method name now
1100+
* delegates to `handleKeyDown`. This means anyone calling `handleKeyPress`
1101+
* will not see their method calls stop working.
1102+
*
1103+
* @param {EventTarget~Event} event
1104+
* The event that caused this function to be called.
1105+
*/
1106+
handleKeyPress(event) {
1107+
this.handleKeyDown(event);
1108+
}
1109+
10931110
/**
10941111
* Emit a 'tap' events when touch event support gets detected. This gets used to
10951112
* support toggling the controls through a tap on the video. They get enabled

src/js/control-bar/progress-control/seek-bar.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,30 +407,36 @@ class SeekBar extends Slider {
407407
*
408408
* @listens keydown
409409
*/
410-
handleKeyPress(event) {
410+
handleKeyDown(event) {
411411
if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) {
412412
event.preventDefault();
413+
event.stopPropagation();
413414
this.handleAction(event);
414415
} else if (keycode.isEventKey(event, 'Home')) {
415416
event.preventDefault();
417+
event.stopPropagation();
416418
this.player_.currentTime(0);
417419
} else if (keycode.isEventKey(event, 'End')) {
418420
event.preventDefault();
421+
event.stopPropagation();
419422
this.player_.currentTime(this.player_.duration());
420423
} else if (/^[0-9]$/.test(keycode(event))) {
421424
event.preventDefault();
425+
event.stopPropagation();
422426
const gotoFraction = (keycode.codes[keycode(event)] - keycode.codes['0']) * 10.0 / 100.0;
423427

424428
this.player_.currentTime(this.player_.duration() * gotoFraction);
425429
} else if (keycode.isEventKey(event, 'PgDn')) {
426430
event.preventDefault();
431+
event.stopPropagation();
427432
this.player_.currentTime(this.player_.currentTime() - (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
428433
} else if (keycode.isEventKey(event, 'PgUp')) {
429434
event.preventDefault();
435+
event.stopPropagation();
430436
this.player_.currentTime(this.player_.currentTime() + (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
431437
} else {
432-
// Pass keypress handling up for unsupported keys
433-
super.handleKeyPress(event);
438+
// Pass keydown handling up for unsupported keys
439+
super.handleKeyDown(event);
434440
}
435441
}
436442
}

0 commit comments

Comments
 (0)