From b88755bdf6afeeade4570ff3b42406fff437ba4c Mon Sep 17 00:00:00 2001 From: mister-ben Date: Fri, 17 May 2024 16:02:03 +0200 Subject: [PATCH 1/2] refactor: Replace keycode dependency with event.key --- package.json | 1 - src/js/button.js | 3 +-- src/js/clickable-component.js | 3 +-- src/js/close-button.js | 3 +-- src/js/component.js | 3 +-- .../control-bar/progress-control/seek-bar.js | 15 +++++++------- src/js/control-bar/volume-panel.js | 5 ++--- src/js/menu/menu-button.js | 13 ++++++------ src/js/menu/menu-item.js | 4 +--- src/js/menu/menu-keys.js | 20 ------------------- src/js/menu/menu.js | 5 ++--- src/js/modal-dialog.js | 5 ++--- src/js/player.js | 9 ++++----- src/js/slider/slider.js | 13 ++++++------ src/js/spatial-navigation.js | 8 ++++---- 15 files changed, 38 insertions(+), 72 deletions(-) delete mode 100644 src/js/menu/menu-keys.js diff --git a/package.json b/package.json index c6b990a2cd..13faae68a4 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,6 @@ "@videojs/xhr": "2.6.0", "aes-decrypter": "^4.0.1", "global": "4.4.0", - "keycode": "2.2.0", "m3u8-parser": "^7.1.0", "mpd-parser": "^1.2.2", "mux.js": "^7.0.1", diff --git a/src/js/button.js b/src/js/button.js index d5335a28ae..41ce1fc8f5 100644 --- a/src/js/button.js +++ b/src/js/button.js @@ -4,7 +4,6 @@ import ClickableComponent from './clickable-component.js'; import Component from './component'; import log from './utils/log.js'; -import keycode from 'keycode'; import {createEl} from './utils/dom.js'; /** @@ -118,7 +117,7 @@ class Button extends ClickableComponent { // prevent the event from propagating through the DOM and triggering Player // hotkeys. We do not preventDefault here because we _want_ the browser to // handle it. - if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) { + if (event.key === ' ' || event.key === 'Enter') { event.stopPropagation(); return; } diff --git a/src/js/clickable-component.js b/src/js/clickable-component.js index 1956774bba..40dda6d71c 100644 --- a/src/js/clickable-component.js +++ b/src/js/clickable-component.js @@ -4,7 +4,6 @@ import Component from './component'; import * as Dom from './utils/dom.js'; import log from './utils/log.js'; -import keycode from 'keycode'; /** @import Player from './player' */ @@ -245,7 +244,7 @@ class ClickableComponent extends Component { // Support Space or Enter key operation to fire a click event. Also, // prevent the event from propagating through the DOM and triggering // Player hotkeys. - if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) { + if (event.key === ' ' || event.key === 'Enter') { event.preventDefault(); event.stopPropagation(); this.trigger('click'); diff --git a/src/js/close-button.js b/src/js/close-button.js index 66abc875ce..78b77c16cc 100644 --- a/src/js/close-button.js +++ b/src/js/close-button.js @@ -3,7 +3,6 @@ */ import Button from './button'; import Component from './component'; -import keycode from 'keycode'; /** @import Player from './player' */ @@ -80,7 +79,7 @@ class CloseButton extends Button { */ handleKeyDown(event) { // Esc button will trigger `click` event - if (keycode.isEventKey(event, 'Esc')) { + if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); this.trigger('click'); diff --git a/src/js/component.js b/src/js/component.js index cfcdd45835..69cb75275b 100644 --- a/src/js/component.js +++ b/src/js/component.js @@ -12,7 +12,6 @@ import * as Fn from './utils/fn.js'; import * as Guid from './utils/guid.js'; import {toTitleCase, toLowerCase} from './utils/str.js'; import {merge} from './utils/obj.js'; -import keycode from 'keycode'; /** @import Player from './player' */ @@ -1354,7 +1353,7 @@ class Component { // We only stop propagation here because we want unhandled events to fall // back to the browser. Exclude Tab for focus trapping, exclude also when spatialNavigation is enabled. - if (!keycode.isEventKey(event, 'Tab') && !(this.player_.options_.playerOptions.spatialNavigation && this.player_.options_.playerOptions.spatialNavigation.enabled)) { + if (event.key !== 'Tab' && !(this.player_.options_.playerOptions.spatialNavigation && this.player_.options_.playerOptions.spatialNavigation.enabled)) { event.stopPropagation(); } this.player_.handleKeyDown(event); diff --git a/src/js/control-bar/progress-control/seek-bar.js b/src/js/control-bar/progress-control/seek-bar.js index 539b80b2b6..b59a65534f 100644 --- a/src/js/control-bar/progress-control/seek-bar.js +++ b/src/js/control-bar/progress-control/seek-bar.js @@ -8,7 +8,6 @@ import * as Dom from '../../utils/dom.js'; import * as Fn from '../../utils/fn.js'; import {formatTime} from '../../utils/time.js'; import {silencePromise} from '../../utils/promise'; -import keycode from 'keycode'; import document from 'global/document'; /** @import Player from '../../player' */ @@ -438,15 +437,15 @@ class SeekBar extends Slider { handleKeyDown(event) { const liveTracker = this.player_.liveTracker; - if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) { + if (event.key === ' ' || event.key === 'Enter') { event.preventDefault(); event.stopPropagation(); this.handleAction(event); - } else if (keycode.isEventKey(event, 'Home')) { + } else if (event.key === 'Home') { event.preventDefault(); event.stopPropagation(); this.userSeek_(0); - } else if (keycode.isEventKey(event, 'End')) { + } else if (event.key === 'End') { event.preventDefault(); event.stopPropagation(); if (liveTracker && liveTracker.isLive()) { @@ -454,21 +453,21 @@ class SeekBar extends Slider { } else { this.userSeek_(this.player_.duration()); } - } else if (/^[0-9]$/.test(keycode(event))) { + } else if (/^[0-9]$/.test(event.key)) { event.preventDefault(); event.stopPropagation(); - const gotoFraction = (keycode.codes[keycode(event)] - keycode.codes['0']) * 10.0 / 100.0; + const gotoFraction = parseInt(event.key, 10) * 0.1; if (liveTracker && liveTracker.isLive()) { this.userSeek_(liveTracker.seekableStart() + (liveTracker.liveWindow() * gotoFraction)); } else { this.userSeek_(this.player_.duration() * gotoFraction); } - } else if (keycode.isEventKey(event, 'PgDn')) { + } else if (event.key === 'PageDown') { event.preventDefault(); event.stopPropagation(); this.userSeek_(this.player_.currentTime() - (STEP_SECONDS * PAGE_KEY_MULTIPLIER)); - } else if (keycode.isEventKey(event, 'PgUp')) { + } else if (event.key === 'PageUp') { event.preventDefault(); event.stopPropagation(); this.userSeek_(this.player_.currentTime() + (STEP_SECONDS * PAGE_KEY_MULTIPLIER)); diff --git a/src/js/control-bar/volume-panel.js b/src/js/control-bar/volume-panel.js index 5bbfa074d7..209b4935b1 100644 --- a/src/js/control-bar/volume-panel.js +++ b/src/js/control-bar/volume-panel.js @@ -4,7 +4,6 @@ import Component from '../component.js'; import {isPlain} from '../utils/obj'; import * as Events from '../utils/events.js'; -import keycode from 'keycode'; import document from 'global/document'; /** @import Player from './player' */ @@ -140,7 +139,7 @@ class VolumePanel extends Component { * @listens keyup */ handleVolumeControlKeyUp(event) { - if (keycode.isEventKey(event, 'Esc')) { + if (event.key === 'Escape') { this.muteToggle.focus(); } } @@ -185,7 +184,7 @@ class VolumePanel extends Component { * @listens keydown | keyup */ handleKeyPress(event) { - if (keycode.isEventKey(event, 'Esc')) { + if (event.key === 'Escape') { this.handleMouseOut(); } } diff --git a/src/js/menu/menu-button.js b/src/js/menu/menu-button.js index 4de500b1e3..73fecada36 100644 --- a/src/js/menu/menu-button.js +++ b/src/js/menu/menu-button.js @@ -9,7 +9,6 @@ import * as Events from '../utils/events.js'; import {toTitleCase} from '../utils/str.js'; import { IS_IOS } from '../utils/browser.js'; import document from 'global/document'; -import keycode from 'keycode'; /** @import Player from '../player' */ @@ -298,19 +297,19 @@ class MenuButton extends Component { handleKeyDown(event) { // Escape or Tab unpress the 'button' - if (keycode.isEventKey(event, 'Esc') || keycode.isEventKey(event, 'Tab')) { + if (event.key === 'Esc' || event.key === 'Tab') { if (this.buttonPressed_) { this.unpressButton(); } // Don't preventDefault for Tab key - we still want to lose focus - if (!keycode.isEventKey(event, 'Tab')) { + if (!event.key === 'Tab') { event.preventDefault(); // Set focus back to the menu button's button this.menuButton_.focus(); } // Up Arrow or Down Arrow also 'press' the button to open the menu - } else if ((keycode.isEventKey(event, 'Up') || keycode.isEventKey(event, 'Down')) && !(this.player_.options_.playerOptions.spatialNavigation && this.player_.options_.playerOptions.spatialNavigation.enabled)) { + } else if ((event.key === 'Up') || event.key === 'Down' && !(this.player_.options_.playerOptions.spatialNavigation && this.player_.options_.playerOptions.spatialNavigation.enabled)) { if (!this.buttonPressed_) { event.preventDefault(); this.pressButton(); @@ -329,7 +328,7 @@ class MenuButton extends Component { */ handleMenuKeyUp(event) { // Escape hides popup menu - if (keycode.isEventKey(event, 'Esc') || keycode.isEventKey(event, 'Tab')) { + if (event.key === 'Esc' || event.key === 'Tab') { this.removeClass('vjs-hover'); } } @@ -357,12 +356,12 @@ class MenuButton extends Component { */ handleSubmenuKeyDown(event) { // Escape or Tab unpress the 'button' - if (keycode.isEventKey(event, 'Esc') || keycode.isEventKey(event, 'Tab')) { + if (event.key === 'Esc' || event.key === 'Tab') { if (this.buttonPressed_) { this.unpressButton(); } // Don't preventDefault for Tab key - we still want to lose focus - if (!keycode.isEventKey(event, 'Tab')) { + if (!event.key === 'Tab') { event.preventDefault(); // Set focus back to the menu button's button this.menuButton_.focus(); diff --git a/src/js/menu/menu-item.js b/src/js/menu/menu-item.js index 415ab04897..dcee1bca09 100644 --- a/src/js/menu/menu-item.js +++ b/src/js/menu/menu-item.js @@ -3,8 +3,6 @@ */ import ClickableComponent from '../clickable-component.js'; import Component from '../component.js'; -import {MenuKeys} from './menu-keys.js'; -import keycode from 'keycode'; import {createEl} from '../utils/dom.js'; /** @import Player from '../player' */ @@ -96,7 +94,7 @@ class MenuItem extends ClickableComponent { * @listens keydown */ handleKeyDown(event) { - if (!MenuKeys.some((key) => keycode.isEventKey(event, key))) { + if (['Tab', 'Escape', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'ArrowDown'].includes(event.key)) { // Pass keydown handling up for unused keys super.handleKeyDown(event); } diff --git a/src/js/menu/menu-keys.js b/src/js/menu/menu-keys.js deleted file mode 100644 index 802c91178a..0000000000 --- a/src/js/menu/menu-keys.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @file menu-keys.js - */ - -/** - * All keys used for operation of a menu (`MenuButton`, `Menu`, and `MenuItem`) - * Note that 'Enter' and 'Space' are not included here (otherwise they would - * prevent the `MenuButton` and `MenuItem` from being keyboard-clickable) - * - * @typedef MenuKeys - * @array - */ -export const MenuKeys = [ - 'Tab', - 'Esc', - 'Up', - 'Down', - 'Right', - 'Left' -]; diff --git a/src/js/menu/menu.js b/src/js/menu/menu.js index 647d422274..14fd7912a5 100644 --- a/src/js/menu/menu.js +++ b/src/js/menu/menu.js @@ -5,7 +5,6 @@ import Component from '../component.js'; import document from 'global/document'; import * as Dom from '../utils/dom.js'; import * as Events from '../utils/events.js'; -import keycode from 'keycode'; /** @import Player from '../player' */ @@ -215,13 +214,13 @@ class Menu extends Component { handleKeyDown(event) { // Left and Down Arrows - if (keycode.isEventKey(event, 'Left') || keycode.isEventKey(event, 'Down')) { + if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') { event.preventDefault(); event.stopPropagation(); this.stepForward(); // Up and Right Arrows - } else if (keycode.isEventKey(event, 'Right') || keycode.isEventKey(event, 'Up')) { + } else if (event.key === 'ArrowRight' || event.key === 'ArrowUp') { event.preventDefault(); event.stopPropagation(); this.stepBack(); diff --git a/src/js/modal-dialog.js b/src/js/modal-dialog.js index d2bc31806c..5dd6844eff 100644 --- a/src/js/modal-dialog.js +++ b/src/js/modal-dialog.js @@ -5,7 +5,6 @@ import * as Dom from './utils/dom'; import Component from './component'; import window from 'global/window'; import document from 'global/document'; -import keycode from 'keycode'; /** @import Player from './player' */ /** @import { ContentDescriptor } from './utils/dom' */ @@ -470,14 +469,14 @@ class ModalDialog extends Component { // Do not allow keydowns to reach out of the modal dialog. event.stopPropagation(); - if (keycode.isEventKey(event, 'Escape') && this.closeable()) { + if (event.key === 'Escape' && this.closeable()) { event.preventDefault(); this.close(); return; } // exit early if it isn't a tab key - if (!keycode.isEventKey(event, 'Tab')) { + if (event.key !== 'Tab') { return; } diff --git a/src/js/player.js b/src/js/player.js index 00391e8459..3412ca3008 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -34,7 +34,6 @@ import filterSource from './utils/filter-source'; import {getMimetype, findMimetype} from './utils/mimetypes'; import {hooks} from './utils/hooks'; import {isObject} from './utils/obj'; -import keycode from 'keycode'; import icons from '../images/icons.svg'; import SpatialNavigation from './spatial-navigation.js'; @@ -3121,7 +3120,7 @@ class Player extends Component { * Event to check for key press */ fullWindowOnEscKey(event) { - if (keycode.isEventKey(event, 'Esc')) { + if (event.key === 'Escape') { if (this.isFullscreen() === true) { if (!this.isFullWindow) { this.exitFullscreen(); @@ -3371,9 +3370,9 @@ class Player extends Component { // set fullscreenKey, muteKey, playPauseKey from `hotkeys`, use defaults if not set const { - fullscreenKey = keydownEvent => keycode.isEventKey(keydownEvent, 'f'), - muteKey = keydownEvent => keycode.isEventKey(keydownEvent, 'm'), - playPauseKey = keydownEvent => (keycode.isEventKey(keydownEvent, 'k') || keycode.isEventKey(keydownEvent, 'Space')) + fullscreenKey = keydownEvent => (event.key.toLowerCase() === 'f'), + muteKey = keydownEvent => (event.key.toLowerCase() === 'm'), + playPauseKey = keydownEvent => (event.key.toLowerCase() === 'k' || event.key.toLowerCase() === ' ') } = hotkeys; if (fullscreenKey.call(this, event)) { diff --git a/src/js/slider/slider.js b/src/js/slider/slider.js index 6aef393c93..5a17435b49 100644 --- a/src/js/slider/slider.js +++ b/src/js/slider/slider.js @@ -5,7 +5,6 @@ import Component from '../component.js'; import * as Dom from '../utils/dom.js'; import {IS_CHROME} from '../utils/browser.js'; import {clamp} from '../utils/num.js'; -import keycode from 'keycode'; /** @import Player from '../player' */ @@ -315,13 +314,13 @@ class Slider extends Component { const horizontalSeek = spatialNavOptions && spatialNavOptions.horizontalSeek; if (spatialNavEnabled) { - if ((horizontalSeek && keycode.isEventKey(event, 'Left')) || - (!horizontalSeek && keycode.isEventKey(event, 'Down'))) { + if ((horizontalSeek && event.key === 'ArrowLeft') || + (!horizontalSeek && event.key === 'ArrowDown')) { event.preventDefault(); event.stopPropagation(); this.stepBack(); - } else if ((horizontalSeek && keycode.isEventKey(event, 'Right')) || - (!horizontalSeek && keycode.isEventKey(event, 'Up'))) { + } else if ((horizontalSeek && event.key === 'ArrowRight') || + (!horizontalSeek && event.key === 'ArrowUp')) { event.preventDefault(); event.stopPropagation(); this.stepForward(); @@ -330,13 +329,13 @@ class Slider extends Component { } // Left and Down Arrows - } else if (keycode.isEventKey(event, 'Left') || keycode.isEventKey(event, 'Down')) { + } else if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') { event.preventDefault(); event.stopPropagation(); this.stepBack(); // Up and Right Arrows - } else if (keycode.isEventKey(event, 'Right') || keycode.isEventKey(event, 'Up')) { + } else if (event.key === 'ArrowUp' || event.key === 'ArrowRight') { event.preventDefault(); event.stopPropagation(); this.stepForward(); diff --git a/src/js/spatial-navigation.js b/src/js/spatial-navigation.js index 4cfeacc968..aa37bbf5d1 100644 --- a/src/js/spatial-navigation.js +++ b/src/js/spatial-navigation.js @@ -2,7 +2,6 @@ * @file spatial-navigation.js */ import EventTarget from './event-target'; -import keycode from 'keycode'; import SpatialNavKeyCodes from './utils/spatial-navigation-key-codes'; /** @import Component from './component' */ @@ -82,14 +81,15 @@ class SpatialNavigation extends EventTarget { // Determine if the event is a custom modalKeydown event const actualEvent = event.originalEvent ? event.originalEvent : event; - if (keycode.isEventKey(actualEvent, 'left') || keycode.isEventKey(actualEvent, 'up') || - keycode.isEventKey(actualEvent, 'right') || keycode.isEventKey(actualEvent, 'down')) { + if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(actualEvent.key)) { // Handle directional navigation if (this.isPaused_) { return; } actualEvent.preventDefault(); - const direction = keycode(actualEvent); + + // "ArrowLeft" => "left" etc + const direction = actualEvent.key.substring(5).toLowerCase(); this.move(direction); } else if (SpatialNavKeyCodes.isEventKey(actualEvent, 'play') || SpatialNavKeyCodes.isEventKey(actualEvent, 'pause') || From 1059389c1483856c498932ff712311ae3c27cf8a Mon Sep 17 00:00:00 2001 From: mister-ben Date: Fri, 17 May 2024 16:16:55 +0200 Subject: [PATCH 2/2] updated tests --- test/unit/close-button.test.js | 1 + test/unit/modal-dialog.test.js | 1 + test/unit/player-fullscreen.test.js | 1 + test/unit/player-user-actions.test.js | 15 +++++++-------- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/test/unit/close-button.test.js b/test/unit/close-button.test.js index 2151126ba2..2ec34afd42 100644 --- a/test/unit/close-button.test.js +++ b/test/unit/close-button.test.js @@ -4,6 +4,7 @@ import sinon from 'sinon'; import TestHelpers from './test-helpers'; const getMockEscapeEvent = () => ({ + key: 'Escape', which: 27, preventDefault() {}, stopPropagation() {} diff --git a/test/unit/modal-dialog.test.js b/test/unit/modal-dialog.test.js index 9d6550a421..4536c56f69 100644 --- a/test/unit/modal-dialog.test.js +++ b/test/unit/modal-dialog.test.js @@ -6,6 +6,7 @@ import * as Dom from '../../src/js/utils/dom'; import TestHelpers from './test-helpers'; const getMockEscapeEvent = () => ({ + key: 'Escape', which: 27, preventDefault() {}, stopPropagation() {} diff --git a/test/unit/player-fullscreen.test.js b/test/unit/player-fullscreen.test.js index fcadd46047..5b1f1dd196 100644 --- a/test/unit/player-fullscreen.test.js +++ b/test/unit/player-fullscreen.test.js @@ -274,6 +274,7 @@ QUnit.test('fullwindow mode should exit when ESC event triggered', function(asse const evt = TestHelpers.createEvent('keydown'); + evt.key = 'Escape'; evt.keyCode = 27; evt.which = 27; player.boundFullWindowOnEscKey_(evt); diff --git a/test/unit/player-user-actions.test.js b/test/unit/player-user-actions.test.js index e002319a2a..4d46e5e1fe 100644 --- a/test/unit/player-user-actions.test.js +++ b/test/unit/player-user-actions.test.js @@ -1,6 +1,5 @@ /* eslint-env qunit */ import document from 'global/document'; -import keycode from 'keycode'; import sinon from 'sinon'; import TestHelpers from './test-helpers'; import FullscreenApi from '../../src/js/fullscreen-api.js'; @@ -254,7 +253,7 @@ const mockKeyDownEvent = (key) => { preventDefault() {}, stopPropagation() {}, type: 'keydown', - which: keycode.codes[key] + key }; }; @@ -354,7 +353,7 @@ const defaultKeyTests = { } paused = true; - player.handleKeyDown(mockKeyDownEvent('space')); + player.handleKeyDown(mockKeyDownEvent(' ')); if (positive) { assert.strictEqual(player.pause.callCount, 1, 'has paused'); @@ -365,7 +364,7 @@ const defaultKeyTests = { } paused = false; - player.handleKeyDown(mockKeyDownEvent('space')); + player.handleKeyDown(mockKeyDownEvent(' ')); if (positive) { assert.strictEqual(player.pause.callCount, 2, 'has paused twice'); @@ -425,7 +424,7 @@ QUnit.test('when userActions.hotkeys.fullscreenKey can be a function', function( controls: true, userActions: { hotkeys: { - fullscreenKey: sinon.spy((e) => keycode.isEventKey(e, 'x')) + fullscreenKey: sinon.spy((e) => e.key === 'x') } } }); @@ -460,7 +459,7 @@ QUnit.test('when userActions.hotkeys.muteKey can be a function', function(assert controls: true, userActions: { hotkeys: { - muteKey: sinon.spy((e) => keycode.isEventKey(e, 'x')) + muteKey: sinon.spy((e) => e.key === 'x') } } }); @@ -495,7 +494,7 @@ QUnit.test('when userActions.hotkeys.playPauseKey can be a function', function(a controls: true, userActions: { hotkeys: { - playPauseKey: sinon.spy((e) => keycode.isEventKey(e, 'x')) + playPauseKey: sinon.spy((e) => e.key === 'x') } } }); @@ -508,7 +507,7 @@ QUnit.test('when userActions.hotkeys.playPauseKey can be a function', function(a paused = true; this.player.handleKeyDown(mockKeyDownEvent('k')); - this.player.handleKeyDown(mockKeyDownEvent('space')); + this.player.handleKeyDown(mockKeyDownEvent(' ')); assert.strictEqual(this.player.pause.callCount, 0, 'has not paused'); assert.strictEqual(this.player.play.callCount, 0, 'has not played');