Skip to content

Commit 2f00a68

Browse files
authored
fix(fs): make sure there's only one fullscreenchange event (videojs#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 videojs#5685.
1 parent 513168f commit 2f00a68

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 {getMimetype, 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
@@ -519,7 +519,15 @@ class Player extends Component {
519519
this.reportUserActivity();
520520

521521
this.one('play', this.listenForUserActivity_);
522-
this.on('fullscreenchange', this.handleFullscreenChange_);
522+
523+
if (FullscreenApi.fullscreenchange) {
524+
this.on(FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
525+
526+
if (IE_VERSION || browser.IS_FIREFOX && prefixedFS) {
527+
this.on(document, FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
528+
}
529+
}
530+
523531
this.on('stageclick', this.handleStageClick_);
524532

525533
this.breakpoints(this.options_.breakpoints);
@@ -549,6 +557,11 @@ class Player extends Component {
549557
// prevent dispose from being called twice
550558
this.off('dispose');
551559

560+
// make sure to remove fs handler on IE from the document
561+
if (IE_VERSION || browser.IS_FIREFOX && prefixedFS) {
562+
this.off(document, FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
563+
}
564+
552565
if (this.styleEl_ && this.styleEl_.parentNode) {
553566
this.styleEl_.parentNode.removeChild(this.styleEl_);
554567
this.styleEl_ = null;
@@ -1908,29 +1921,60 @@ class Player extends Component {
19081921
event.preventDefault();
19091922
}
19101923

1924+
/**
1925+
* native click events on the SWF aren't triggered on IE11, Win8.1RT
1926+
* use stageclick events triggered from inside the SWF instead
1927+
*
1928+
* @private
1929+
* @listens stageclick
1930+
*/
1931+
handleStageClick_() {
1932+
this.reportUserActivity();
1933+
}
1934+
19111935
/**
19121936
* Fired when the player switches in or out of fullscreen mode
19131937
*
19141938
* @private
19151939
* @listens Player#fullscreenchange
1940+
* @listens Player#webkitfullscreenchange
1941+
* @listens Player#mozfullscreenchange
1942+
* @listens Player#MSFullscreenChange
1943+
* @fires Player#fullscreenchange
19161944
*/
1917-
handleFullscreenChange_() {
1945+
handleFullscreenChange_(event = {}, retriggerEvent = true) {
19181946
if (this.isFullscreen()) {
19191947
this.addClass('vjs-fullscreen');
19201948
} else {
19211949
this.removeClass('vjs-fullscreen');
19221950
}
1951+
1952+
if (prefixedFS && retriggerEvent) {
1953+
/**
1954+
* @event Player#fullscreenchange
1955+
* @type {EventTarget~Event}
1956+
*/
1957+
this.trigger('fullscreenchange');
1958+
}
19231959
}
19241960

19251961
/**
1926-
* native click events on the SWF aren't triggered on IE11, Win8.1RT
1927-
* use stageclick events triggered from inside the SWF instead
1928-
*
1929-
* @private
1930-
* @listens stageclick
1962+
* when the document fschange event triggers it calls this
19311963
*/
1932-
handleStageClick_() {
1933-
this.reportUserActivity();
1964+
documentFullscreenChange_(e) {
1965+
const fsApi = FullscreenApi;
1966+
1967+
this.isFullscreen(document[fsApi.fullscreenElement]);
1968+
1969+
// If cancelling fullscreen, remove event listener.
1970+
if (this.isFullscreen() === false) {
1971+
Events.off(document, fsApi.fullscreenchange, Fn.bind(this, this.documentFullscreenChange_));
1972+
if (prefixedFS) {
1973+
this.handleFullscreenChange_({}, false);
1974+
} else {
1975+
this.on(FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
1976+
}
1977+
}
19341978
}
19351979

19361980
/**
@@ -2568,24 +2612,16 @@ class Player extends Component {
25682612
// the browser supports going fullscreen at the element level so we can
25692613
// take the controls fullscreen as well as the video
25702614

2615+
if (!prefixedFS) {
2616+
this.off(FullscreenApi.fullscreenchange, this.handleFullscreenChange_);
2617+
}
2618+
25712619
// Trigger fullscreenchange event after change
25722620
// We have to specifically add this each time, and remove
25732621
// when canceling fullscreen. Otherwise if there's multiple
25742622
// players on a page, they would all be reacting to the same fullscreen
25752623
// events
2576-
Events.on(document, fsApi.fullscreenchange, Fn.bind(this, function documentFullscreenChange(e) {
2577-
this.isFullscreen(document[fsApi.fullscreenElement]);
2578-
2579-
// If cancelling fullscreen, remove event listener.
2580-
if (this.isFullscreen() === false) {
2581-
Events.off(document, fsApi.fullscreenchange, documentFullscreenChange);
2582-
}
2583-
/**
2584-
* @event Player#fullscreenchange
2585-
* @type {EventTarget~Event}
2586-
*/
2587-
this.trigger('fullscreenchange');
2588-
}));
2624+
Events.on(document, fsApi.fullscreenchange, Fn.bind(this, this.documentFullscreenChange_));
25892625

25902626
this.el_[fsApi.requestFullscreen]();
25912627

@@ -2617,6 +2653,8 @@ class Player extends Component {
26172653

26182654
// Check for browser element fullscreen support
26192655
if (fsApi.requestFullscreen) {
2656+
// remove the document level handler if we're getting called directly.
2657+
Events.off(document, fsApi.fullscreenchange, Fn.bind(this, this.documentFullscreenChange_));
26202658
document[fsApi.exitFullscreen]();
26212659
} else if (this.tech_.supportsFullScreen()) {
26222660
this.techCall_('exitFullScreen');

0 commit comments

Comments
 (0)