Skip to content

Commit 2bc90a1

Browse files
committed
fix(fs): make sure there's only one fullscreenchange event (#5686)
Before the fullscreen API was un-prefixed, we listened to triggered a `fullscreenchange` event on the player manually. This worked fine because a prefixed `fullscreenchange` event was triggered on the player element itself. But when it was unprefixed, we ended up with two events now, the unprefixed event and the one we triggered. Instead, we should listen the event the browser supports and re-trigger it as the unprefixed event as necessary. We also make sure that the handler gets calls when the document level fullscreenchange handler gets called so that it is cancelled properly. Fixes #5685.
1 parent 05513f8 commit 2bc90a1

File tree

2 files changed

+66
-24
lines changed

2 files changed

+66
-24
lines changed

src/js/fullscreen-api.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const apiMap = [
6464

6565
const specApi = apiMap[0];
6666
let browserApi;
67+
let prefixedAPI = true;
6768

6869
// determine the supported set of functions
6970
for (let i = 0; i < apiMap.length; i++) {
@@ -79,6 +80,9 @@ if (browserApi) {
7980
for (let i = 0; i < browserApi.length; i++) {
8081
FullscreenApi[specApi[i]] = browserApi[i];
8182
}
83+
84+
prefixedAPI = browserApi[0] !== specApi[0];
8285
}
8386

8487
export default FullscreenApi;
88+
export { prefixedAPI };

src/js/player.js

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ import * as Dom from './utils/dom.js';
1515
import * as Fn from './utils/fn.js';
1616
import * as Guid from './utils/guid.js';
1717
import * as browser from './utils/browser.js';
18+
import {IE_VERSION} from './utils/browser.js';
1819
import log, { createLogger } from './utils/log.js';
1920
import toTitleCase, { titleCaseEquals } from './utils/to-title-case.js';
2021
import { createTimeRange } from './utils/time-ranges.js';
2122
import { bufferedPercent } from './utils/buffer.js';
2223
import * as stylesheet from './utils/stylesheet.js';
23-
import FullscreenApi from './fullscreen-api.js';
24+
import FullscreenApi, {prefixedAPI as prefixedFS} from './fullscreen-api.js';
2425
import MediaError from './media-error.js';
2526
import safeParseTuple from 'safe-json-parse/tuple';
2627
import {assign} from './utils/obj';
@@ -33,7 +34,6 @@ import * as middleware from './tech/middleware.js';
3334
import {ALL as TRACK_TYPES} from './tracks/track-types';
3435
import filterSource from './utils/filter-source';
3536
import {findMimetype} from './utils/mimetypes';
36-
import {IE_VERSION} from './utils/browser';
3737

3838
// The following imports are used only to ensure that the corresponding modules
3939
// are always included in the video.js package. Importing the modules will
@@ -524,7 +524,15 @@ class Player extends Component {
524524
this.reportUserActivity();
525525

526526
this.one('play', this.listenForUserActivity_);
527-
this.on('fullscreenchange', this.handleFullscreenChange_);
527+
528+
if (FullscreenApi.fullscreenchange) {
529+
this.on(FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
530+
531+
if (IE_VERSION || browser.IS_FIREFOX && prefixedFS) {
532+
this.on(document, FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
533+
}
534+
}
535+
528536
this.on('stageclick', this.handleStageClick_);
529537

530538
this.breakpoints(this.options_.breakpoints);
@@ -554,6 +562,11 @@ class Player extends Component {
554562
// prevent dispose from being called twice
555563
this.off('dispose');
556564

565+
// make sure to remove fs handler on IE from the document
566+
if (IE_VERSION || browser.IS_FIREFOX && prefixedFS) {
567+
this.off(document, FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
568+
}
569+
557570
if (this.styleEl_ && this.styleEl_.parentNode) {
558571
this.styleEl_.parentNode.removeChild(this.styleEl_);
559572
this.styleEl_ = null;
@@ -1913,29 +1926,60 @@ class Player extends Component {
19131926
event.preventDefault();
19141927
}
19151928

1929+
/**
1930+
* native click events on the SWF aren't triggered on IE11, Win8.1RT
1931+
* use stageclick events triggered from inside the SWF instead
1932+
*
1933+
* @private
1934+
* @listens stageclick
1935+
*/
1936+
handleStageClick_() {
1937+
this.reportUserActivity();
1938+
}
1939+
19161940
/**
19171941
* Fired when the player switches in or out of fullscreen mode
19181942
*
19191943
* @private
19201944
* @listens Player#fullscreenchange
1945+
* @listens Player#webkitfullscreenchange
1946+
* @listens Player#mozfullscreenchange
1947+
* @listens Player#MSFullscreenChange
1948+
* @fires Player#fullscreenchange
19211949
*/
1922-
handleFullscreenChange_() {
1950+
handleFullscreenChange_(event = {}, retriggerEvent = true) {
19231951
if (this.isFullscreen()) {
19241952
this.addClass('vjs-fullscreen');
19251953
} else {
19261954
this.removeClass('vjs-fullscreen');
19271955
}
1956+
1957+
if (prefixedFS && retriggerEvent) {
1958+
/**
1959+
* @event Player#fullscreenchange
1960+
* @type {EventTarget~Event}
1961+
*/
1962+
this.trigger('fullscreenchange');
1963+
}
19281964
}
19291965

19301966
/**
1931-
* native click events on the SWF aren't triggered on IE11, Win8.1RT
1932-
* use stageclick events triggered from inside the SWF instead
1933-
*
1934-
* @private
1935-
* @listens stageclick
1967+
* when the document fschange event triggers it calls this
19361968
*/
1937-
handleStageClick_() {
1938-
this.reportUserActivity();
1969+
documentFullscreenChange_(e) {
1970+
const fsApi = FullscreenApi;
1971+
1972+
this.isFullscreen(document[fsApi.fullscreenElement]);
1973+
1974+
// If cancelling fullscreen, remove event listener.
1975+
if (this.isFullscreen() === false) {
1976+
Events.off(document, fsApi.fullscreenchange, Fn.bind(this, this.documentFullscreenChange_));
1977+
if (prefixedFS) {
1978+
this.handleFullscreenChange_({}, false);
1979+
} else {
1980+
this.on(FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
1981+
}
1982+
}
19391983
}
19401984

19411985
/**
@@ -2546,24 +2590,16 @@ class Player extends Component {
25462590
// the browser supports going fullscreen at the element level so we can
25472591
// take the controls fullscreen as well as the video
25482592

2593+
if (!prefixedFS) {
2594+
this.off(FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
2595+
}
2596+
25492597
// Trigger fullscreenchange event after change
25502598
// We have to specifically add this each time, and remove
25512599
// when canceling fullscreen. Otherwise if there's multiple
25522600
// players on a page, they would all be reacting to the same fullscreen
25532601
// events
2554-
Events.on(document, fsApi.fullscreenchange, Fn.bind(this, function documentFullscreenChange(e) {
2555-
this.isFullscreen(document[fsApi.fullscreenElement]);
2556-
2557-
// If cancelling fullscreen, remove event listener.
2558-
if (this.isFullscreen() === false) {
2559-
Events.off(document, fsApi.fullscreenchange, documentFullscreenChange);
2560-
}
2561-
/**
2562-
* @event Player#fullscreenchange
2563-
* @type {EventTarget~Event}
2564-
*/
2565-
this.trigger('fullscreenchange');
2566-
}));
2602+
Events.on(document, fsApi.fullscreenchange, Fn.bind(this, this.documentFullscreenChange_));
25672603

25682604
this.el_[fsApi.requestFullscreen]();
25692605

@@ -2595,6 +2631,8 @@ class Player extends Component {
25952631

25962632
// Check for browser element fullscreen support
25972633
if (fsApi.requestFullscreen) {
2634+
// remove the document level handler if we're getting called directly.
2635+
Events.off(document, fsApi.fullscreenchange, Fn.bind(this, this.documentFullscreenChange_));
25982636
document[fsApi.exitFullscreen]();
25992637
} else if (this.tech_.supportsFullScreen()) {
26002638
this.techCall_('exitFullScreen');

0 commit comments

Comments
 (0)