/**
* @file picture-in-picture-toggle.js
*/
import Button from '../button.js';
import Component from '../component.js';
import document from 'global/document';
import window from 'global/window';
/**
* Toggle Picture-in-Picture mode
*
* @extends Button
*/
class PictureInPictureToggle extends Button {
/**
* Creates an instance of this class.
*
* @param { import('./player').default } player
* The `Player` that this class should be attached to.
*
* @param {Object} [options]
* The key/value store of player options.
*
* @listens Player#enterpictureinpicture
* @listens Player#leavepictureinpicture
*/
constructor(player, options) {
super(player, options);
this.on(player, ['enterpictureinpicture', 'leavepictureinpicture'], (e) => this.handlePictureInPictureChange(e));
this.on(player, ['disablepictureinpicturechanged', 'loadedmetadata'], (e) => this.handlePictureInPictureEnabledChange(e));
this.on(player, ['loadedmetadata', 'audioonlymodechange', 'audiopostermodechange'], () => {
// This audio detection will not detect HLS or DASH audio-only streams because there was no reliable way to detect them at the time
const isSourceAudio = player.currentType().substring(0, 5) === 'audio';
if (isSourceAudio || player.audioPosterMode() || player.audioOnlyMode()) {
if (player.isInPictureInPicture()) {
player.exitPictureInPicture();
}
this.hide();
} else {
this.show();
}
});
// TODO: Deactivate button on player emptied event.
this.disable();
}
/**
* Builds the default DOM `className`.
*
* @return {string}
* The DOM `className` for this object.
*/
buildCSSClass() {
return `vjs-picture-in-picture-control ${super.buildCSSClass()}`;
}
/**
* Enables or disables button based on availability of a Picture-In-Picture mode.
*
* Enabled if
* - `player.options().enableDocumentPictureInPicture` is true and
* window.documentPictureInPicture is available; or
* - `player.disablePictureInPicture()` is false and
* element.requestPictureInPicture is available
*/
handlePictureInPictureEnabledChange() {
if (
(document.pictureInPictureEnabled && this.player_.disablePictureInPicture() === false) ||
(this.player_.options_.enableDocumentPictureInPicture && 'documentPictureInPicture' in window)
) {
this.enable();
} else {
this.disable();
}
}
/**
* Handles enterpictureinpicture and leavepictureinpicture on the player and change control text accordingly.
*
* @param {Event} [event]
* The {@link Player#enterpictureinpicture} or {@link Player#leavepictureinpicture} event that caused this function to be
* called.
*
* @listens Player#enterpictureinpicture
* @listens Player#leavepictureinpicture
*/
handlePictureInPictureChange(event) {
if (this.player_.isInPictureInPicture()) {
this.controlText('Exit Picture-in-Picture');
} else {
this.controlText('Picture-in-Picture');
}
this.handlePictureInPictureEnabledChange();
}
/**
* This gets called when an `PictureInPictureToggle` is "clicked". See
* {@link ClickableComponent} for more detailed information on what a click can be.
*
* @param {Event} [event]
* The `keydown`, `tap`, or `click` event that caused this function to be
* called.
*
* @listens tap
* @listens click
*/
handleClick(event) {
if (!this.player_.isInPictureInPicture()) {
this.player_.requestPictureInPicture();
} else {
this.player_.exitPictureInPicture();
}
}
}
/**
* The text that should display over the `PictureInPictureToggle`s controls. Added for localization.
*
* @type {string}
* @protected
*/
PictureInPictureToggle.prototype.controlText_ = 'Picture-in-Picture';
Component.registerComponent('PictureInPictureToggle', PictureInPictureToggle);
export default PictureInPictureToggle;