From 76e99b7bea379a4838fc210a8d03168767341276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Javier=20Villase=C3=B1or=20Castillo?= Date: Mon, 22 Jul 2024 16:43:20 -0600 Subject: [PATCH] fix(spatial-navigation): keep navigation going when player has an error (#8805) ## Description The bug: Focus is lost when playback error is displayed. This small PR will update the spatial-navigation logic so when the error modal is shown the spatial-navigation will try to focus the components present in the error modal, in most cases this will be the vjs close button. ## Specific Changes proposed Keep navigation working when player shows the error modal by focusing a component in that modal. ## Requirements Checklist - [x] Feature implemented / Bug fixed - [ ] If necessary, more likely in a feature request than a bug fix - [ ] Change has been verified in an actual browser (Chrome, Firefox, IE) - [ ] Unit Tests updated or fixed - [ ] Docs/guides updated - [ ] Example created ([starter template on JSBin](https://codepen.io/gkatsev/pen/GwZegv?editors=1000#0)) - [ ] Has no DOM changes which impact accessiblilty or trigger warnings (e.g. Chrome issues tab) - [ ] Has no changes to JSDoc which cause `npm run docs:api` to error - [ ] Reviewed by Two Core Contributors --- src/js/spatial-navigation.js | 17 ++++++++++++++--- test/unit/spatial-navigation.test.js | 11 +++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/js/spatial-navigation.js b/src/js/spatial-navigation.js index aa37bbf5d1..4f0e38c90b 100644 --- a/src/js/spatial-navigation.js +++ b/src/js/spatial-navigation.js @@ -56,6 +56,9 @@ class SpatialNavigation extends EventTarget { this.player_.on('modalclose', () => { this.refocusComponent(); }); + this.player_.on('error', () => { + this.focus(this.updateFocusableComponents()[0]); + }); this.player_.on('focusin', this.handlePlayerFocus_.bind(this)); this.player_.on('focusout', this.handlePlayerBlur_.bind(this)); this.isListening_ = true; @@ -196,7 +199,7 @@ class SpatialNavigation extends EventTarget { } if (!(event.currentTarget.contains(event.relatedTarget)) && !isChildrenOfPlayer || !nextFocusedElement) { - if (currentComponent.name() === 'CloseButton') { + if (currentComponent && currentComponent.name() === 'CloseButton') { this.refocusComponent(); } else { this.pause(); @@ -307,7 +310,11 @@ class SpatialNavigation extends EventTarget { return null; } - return searchForSuitableChild(component.el()); + if (component.el()) { + return searchForSuitableChild(component.el()); + } + return null; + } /** @@ -464,7 +471,7 @@ class SpatialNavigation extends EventTarget { */ refocusComponent() { if (this.lastFocusedComponent_) { - // If use is not active, set it to active. + // If user is not active, set it to active. if (!this.player_.userActive()) { this.player_.userActive(true); } @@ -492,6 +499,10 @@ class SpatialNavigation extends EventTarget { * @param {Component} component - The component to be focused. */ focus(component) { + if (typeof component !== 'object') { + return; + } + if (component.getIsAvailableToBeFocused(component.el())) { component.focus(); } else if (this.findSuitableDOMChild(component)) { diff --git a/test/unit/spatial-navigation.test.js b/test/unit/spatial-navigation.test.js index 0a28a58bea..08ade281a8 100644 --- a/test/unit/spatial-navigation.test.js +++ b/test/unit/spatial-navigation.test.js @@ -44,6 +44,7 @@ QUnit.test('start method initializes event listeners', function(assert) { assert.ok(onSpy.calledWith('loadedmetadata'), 'loadedmetadata event listener added'); assert.ok(onSpy.calledWith('modalKeydown'), 'modalKeydown event listener added'); assert.ok(onSpy.calledWith('modalclose'), 'modalclose event listener added'); + assert.ok(onSpy.calledWith('error'), 'error event listener added'); // Additionally, check if isListening_ flag is set assert.ok(this.spatialNav.isListening_, 'isListening_ flag is set'); @@ -491,3 +492,13 @@ QUnit.test('should call `searchForTrackSelect()` if spatial navigation is enable assert.ok(trackSelectSpy.calledOnce); }); + +QUnit.test('error on player calls updateFocusableComponents', function(assert) { + const updateFocusableComponentsSpy = sinon.spy(this.spatialNav, 'updateFocusableComponents'); + + this.spatialNav.start(); + + this.player.error('Error 1'); + + assert.ok(updateFocusableComponentsSpy.calledOnce, 'on error event spatial navigation should call "updateFocusableComponents"'); +});