aboutsummaryrefslogtreecommitdiffstats
path: root/src/js/fullscreen.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/fullscreen.js')
-rw-r--r--src/js/fullscreen.js204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/js/fullscreen.js b/src/js/fullscreen.js
new file mode 100644
index 00000000..6d90bd6e
--- /dev/null
+++ b/src/js/fullscreen.js
@@ -0,0 +1,204 @@
+// ==========================================================================
+// Fullscreen wrapper
+// ==========================================================================
+
+import utils from './utils';
+
+const browser = utils.getBrowser();
+
+function onChange() {
+ if (!this.enabled) {
+ return;
+ }
+
+ // Update toggle button
+ const button = this.player.elements.buttons.fullscreen;
+ if (utils.is.element(button)) {
+ utils.toggleState(button, this.active);
+ }
+
+ // Trigger an event
+ utils.dispatchEvent(this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
+
+ // Trap focus in container
+ if (!browser.isIos) {
+ utils.trapFocus.call(this.player, this.target, this.active);
+ }
+}
+
+function toggleFallback(toggle = false) {
+ // Store or restore scroll position
+ if (toggle) {
+ this.scrollPosition = {
+ x: window.scrollX || 0,
+ y: window.scrollY || 0,
+ };
+ } else {
+ window.scrollTo(this.scrollPosition.x, this.scrollPosition.y);
+ }
+
+ // Toggle scroll
+ document.body.style.overflow = toggle ? 'hidden' : '';
+
+ // Toggle class hook
+ utils.toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle);
+
+ // Toggle button and fire events
+ onChange.call(this);
+}
+
+class Fullscreen {
+ constructor(player) {
+ // Keep reference to parent
+ this.player = player;
+
+ // Get prefix
+ this.prefix = Fullscreen.prefix;
+
+ // Scroll position
+ this.scrollPosition = { x: 0, y: 0 };
+
+ // Register event listeners
+ // Handle event (incase user presses escape etc)
+ utils.on(document, this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`, () => {
+ // TODO: Filter for target??
+ onChange.call(this);
+ });
+
+ // Fullscreen toggle on double click
+ utils.on(this.player.elements.container, 'dblclick', () => {
+ this.toggle();
+ });
+
+ // Prevent double click on controls bubbling up
+ utils.on(this.player.elements.controls, 'dblclick', event => event.stopPropagation());
+
+ // Update the UI
+ this.update();
+ }
+
+ // Determine if native supported
+ static get native() {
+ return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled);
+ }
+
+ // Get the prefix for handlers
+ static get prefix() {
+ // No prefix
+ if (utils.is.function(document.cancelFullScreen)) {
+ return false;
+ }
+
+ // Check for fullscreen support by vendor prefix
+ let value = '';
+ const prefixes = [
+ 'webkit',
+ 'moz',
+ 'ms',
+ ];
+
+ prefixes.some(pre => {
+ if (utils.is.function(document[`${pre}CancelFullScreen`])) {
+ value = pre;
+ return true;
+ } else if (utils.is.function(document.msExitFullscreen)) {
+ value = 'ms';
+ return true;
+ }
+
+ return false;
+ });
+
+ return value;
+ }
+
+ // Determine if fullscreen is enabled
+ get enabled() {
+ const fallback = this.player.config.fullscreen.fallback && !utils.inFrame();
+
+ return (Fullscreen.native || fallback) && this.player.config.fullscreen.enabled && this.player.supported.ui && this.player.isVideo;
+ }
+
+ // Get active state
+ get active() {
+ if (!this.enabled) {
+ return false;
+ }
+
+ // Fallback using classname
+ if (!Fullscreen.native) {
+ return utils.hasClass(this.target, this.player.config.classNames.fullscreen.fallback);
+ }
+
+ const element = !this.prefix ? document.fullscreenElement : document[`${this.prefix}FullscreenElement`];
+
+ return element === this.target;
+ }
+
+ // Get target element
+ get target() {
+ return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
+ }
+
+ // Update UI
+ update() {
+ if (this.enabled) {
+ this.player.debug.log(`${Fullscreen.native ? 'Native' : 'Fallback'} fullscreen enabled`);
+ } else {
+ this.player.debug.log('Fullscreen not supported and fallback disabled');
+ }
+
+ // Add styling hook to show button
+ utils.toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.enabled);
+ }
+
+ // Make an element fullscreen
+ enter() {
+ if (!this.enabled) {
+ return;
+ }
+
+ // iOS native fullscreen doesn't need the request step
+ if (browser.isIos && this.player.config.fullscreen.iosNative) {
+ if (this.player.playing) {
+ this.target.webkitEnterFullscreen();
+ }
+ } else if (!Fullscreen.native) {
+ toggleFallback.call(this, true);
+ } else if (!this.prefix) {
+ this.target.requestFullScreen();
+ } else if (!utils.is.empty(this.prefix)) {
+ this.target[`${this.prefix}${this.prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen'}`]();
+ }
+ }
+
+ // Bail from fullscreen
+ exit() {
+ if (!this.enabled) {
+ return;
+ }
+
+ // iOS native fullscreen
+ if (browser.isIos && this.player.config.fullscreen.iosNative) {
+ this.target.webkitExitFullscreen();
+ this.player.play();
+ } else if (!Fullscreen.native) {
+ toggleFallback.call(this, false);
+ } else if (!this.prefix) {
+ document.cancelFullScreen();
+ } else if (!utils.is.empty(this.prefix)) {
+ document[`${this.prefix}${this.prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen'}`]();
+ }
+ }
+
+ // Toggle state
+ toggle() {
+ if (!this.active) {
+ this.enter();
+ } else {
+ this.exit();
+ }
+ }
+}
+
+export default Fullscreen;