Improve fullscreen mode of the viewer #2515
8 changed files with 192 additions and 41 deletions
|
@ -4,6 +4,7 @@ import * as ICONS from 'constants/icons';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import Tooltip from 'component/common/tooltip';
|
import Tooltip from 'component/common/tooltip';
|
||||||
|
import { requestFullscreen, fullscreenElement } from 'util/full-screen';
|
||||||
|
|
||||||
type FileInfo = {
|
type FileInfo = {
|
||||||
claim_id: string,
|
claim_id: string,
|
||||||
|
@ -15,15 +16,32 @@ type Props = {
|
||||||
openModal: (id: string, { uri: string }) => void,
|
openModal: (id: string, { uri: string }) => void,
|
||||||
claimIsMine: boolean,
|
claimIsMine: boolean,
|
||||||
fileInfo: FileInfo,
|
fileInfo: FileInfo,
|
||||||
|
viewerContainer: React.Ref,
|
||||||
|
showFullscreen: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileActions extends React.PureComponent<Props> {
|
class FileActions extends React.PureComponent<Props> {
|
||||||
|
maximizeViewer = () => {
|
||||||
|
const { viewerContainer } = this.props;
|
||||||
|
const isFullscreen = fullscreenElement();
|
||||||
|
// Request fullscreen if viewer is ready
|
||||||
|
// And if there is no fullscreen element active
|
||||||
|
if (!isFullscreen && viewerContainer && viewerContainer.current !== null) {
|
||||||
|
requestFullscreen(viewerContainer.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { fileInfo, uri, openModal, claimIsMine, claimId } = this.props;
|
const { fileInfo, uri, openModal, claimIsMine, claimId, showFullscreen } = this.props;
|
||||||
const showDelete = claimIsMine || (fileInfo && Object.keys(fileInfo).length > 0);
|
const showDelete = claimIsMine || (fileInfo && Object.keys(fileInfo).length > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
{showFullscreen && (
|
||||||
|
<Tooltip onComponent body={__('Full screen (f)')}>
|
||||||
|
<Button button="alt" description={__('Fullscreen')} icon={ICONS.FULLSCREEN} onClick={this.maximizeViewer} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
{showDelete && (
|
{showDelete && (
|
||||||
<Tooltip onComponent body={__('Delete this file')}>
|
<Tooltip onComponent body={__('Delete this file')}>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
// @flow
|
// @flow
|
||||||
import '@babel/polyfill';
|
import '@babel/polyfill';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
// @if TARGET='app'
|
// @if TARGET='app'
|
||||||
import { remote } from 'electron';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import { remote } from 'electron';
|
||||||
// @endif
|
// @endif
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import player from 'render-media';
|
import player from 'render-media';
|
||||||
import FileRender from 'component/fileRender';
|
import FileRender from 'component/fileRender';
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
||||||
|
import { fullscreenElement, requestFullscreen, exitFullscreen } from 'util/full-screen';
|
||||||
|
|
||||||
|
// Shorcut key code for fullscreen (f)
|
||||||
|
const F_KEYCODE = 70;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
contentType: string,
|
contentType: string,
|
||||||
|
@ -23,6 +29,8 @@ type Props = {
|
||||||
onFinishCb: ?() => void,
|
onFinishCb: ?() => void,
|
||||||
savePosition: number => void,
|
savePosition: number => void,
|
||||||
changeVolume: number => void,
|
changeVolume: number => void,
|
||||||
|
viewerContainer: React.Ref,
|
||||||
|
searchBarFocused: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -69,7 +77,6 @@ class MediaPlayer extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
this.mediaContainer = React.createRef();
|
this.mediaContainer = React.createRef();
|
||||||
(this: any).togglePlay = this.togglePlay.bind(this);
|
(this: any).togglePlay = this.togglePlay.bind(this);
|
||||||
(this: any).toggleFullScreen = this.toggleFullScreen.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -91,25 +98,65 @@ class MediaPlayer extends React.PureComponent<Props, State> {
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
const mediaElement = this.mediaContainer.current.children[0];
|
const mediaElement = this.mediaContainer.current.children[0];
|
||||||
|
|
||||||
document.removeEventListener('keydown', this.togglePlay);
|
document.removeEventListener('keydown', this.handleKeyDown);
|
||||||
|
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
mediaElement.removeEventListener('click', this.togglePlay);
|
mediaElement.removeEventListener('click', this.togglePlay);
|
||||||
|
mediaElement.removeEventListener('dbclick', this.handleDoubleClick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleFullScreen() {
|
handleKeyDown = (event: SyntheticKeyboardEvent<*>) => {
|
||||||
const mediaElement = this.mediaContainer.current;
|
const { searchBarFocused } = this.props;
|
||||||
|
|
||||||
|
if (!searchBarFocused) {
|
||||||
|
// Handle fullscreen shortcut key (f)
|
||||||
|
if (event.keyCode === F_KEYCODE) {
|
||||||
|
this.toggleFullscreen();
|
||||||
|
}
|
||||||
|
// Handle toggle play
|
||||||
|
// @if TARGET='app'
|
||||||
|
this.togglePlay(event);
|
||||||
|
// @endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleDoubleClick = (event: SyntheticInputEvent<*>) => {
|
||||||
|
// Prevent pause / play
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
// Trigger fullscreen mode
|
||||||
|
this.toggleFullscreen();
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleFullscreen = () => {
|
||||||
|
const { viewerContainer } = this.props;
|
||||||
|
const isFullscreen = fullscreenElement();
|
||||||
|
const isSupportedFile = this.isSupportedFile();
|
||||||
|
const isPlayableType = this.playableType();
|
||||||
|
|
||||||
|
if (!isFullscreen) {
|
||||||
|
// Enter fullscreen mode if content is not playable
|
||||||
|
// Otherwise it should be handle internally on the video player
|
||||||
|
// or it will break the toggle fullscreen button
|
||||||
|
if (!isPlayableType && isSupportedFile && viewerContainer && viewerContainer.current !== null) {
|
||||||
|
requestFullscreen(viewerContainer.current);
|
||||||
|
}
|
||||||
|
// Request fullscreen mode for the media player (renderMedia)
|
||||||
|
// Don't use this with the new player
|
||||||
|
// @if TARGET='app'
|
||||||
|
else if (isPlayableType) {
|
||||||
|
const mediaContainer = this.mediaContainer.current;
|
||||||
|
const mediaElement = mediaContainer && mediaContainer.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
// $FlowFixMe
|
requestFullscreen(mediaElement);
|
||||||
if (document.webkitIsFullScreen) {
|
}
|
||||||
// $FlowFixMe
|
}
|
||||||
document.webkitExitFullscreen();
|
// @endif
|
||||||
} else {
|
} else {
|
||||||
mediaElement.webkitRequestFullScreen();
|
exitFullscreen();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
async playMedia() {
|
async playMedia() {
|
||||||
const container = this.mediaContainer.current;
|
const container = this.mediaContainer.current;
|
||||||
|
@ -165,7 +212,6 @@ class MediaPlayer extends React.PureComponent<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('keydown', this.togglePlay);
|
|
||||||
const mediaElement = container.children[0];
|
const mediaElement = container.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
if (position) {
|
if (position) {
|
||||||
|
@ -188,7 +234,7 @@ class MediaPlayer extends React.PureComponent<Props, State> {
|
||||||
changeVolume(mediaElement.volume);
|
changeVolume(mediaElement.volume);
|
||||||
});
|
});
|
||||||
mediaElement.volume = volume;
|
mediaElement.volume = volume;
|
||||||
mediaElement.addEventListener('dblclick', this.toggleFullScreen);
|
mediaElement.addEventListener('dblclick', this.handleDoubleClick);
|
||||||
}
|
}
|
||||||
// @endif
|
// @endif
|
||||||
|
|
||||||
|
@ -199,6 +245,9 @@ class MediaPlayer extends React.PureComponent<Props, State> {
|
||||||
this.renderFile();
|
this.renderFile();
|
||||||
}
|
}
|
||||||
// @endif
|
// @endif
|
||||||
|
|
||||||
|
// Fullscreen event for web and app
|
||||||
|
document.addEventListener('keydown', this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @if TARGET='app'
|
// @if TARGET='app'
|
||||||
|
|
|
@ -7,8 +7,10 @@ import LoadingScreen from 'component/common/loading-screen';
|
||||||
import PlayButton from './internal/play-button';
|
import PlayButton from './internal/play-button';
|
||||||
|
|
||||||
const Player = React.lazy(() =>
|
const Player = React.lazy(() =>
|
||||||
import(/* webpackChunkName: "player-legacy" */
|
import(
|
||||||
'./internal/player')
|
/* webpackChunkName: "player-legacy" */
|
||||||
|
'./internal/player'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const SPACE_BAR_KEYCODE = 32;
|
const SPACE_BAR_KEYCODE = 32;
|
||||||
|
@ -49,6 +51,8 @@ type Props = {
|
||||||
insufficientCredits: boolean,
|
insufficientCredits: boolean,
|
||||||
nsfw: boolean,
|
nsfw: boolean,
|
||||||
thumbnail: ?string,
|
thumbnail: ?string,
|
||||||
|
isPlayableType: boolean,
|
||||||
|
viewerContainer: React.Ref,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileViewer extends React.PureComponent<Props> {
|
class FileViewer extends React.PureComponent<Props> {
|
||||||
|
@ -125,11 +129,14 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
|
|
||||||
handleKeyDown(event: SyntheticKeyboardEvent<*>) {
|
handleKeyDown(event: SyntheticKeyboardEvent<*>) {
|
||||||
const { searchBarFocused } = this.props;
|
const { searchBarFocused } = this.props;
|
||||||
|
|||||||
if (!searchBarFocused && event.keyCode === SPACE_BAR_KEYCODE) {
|
|
||||||
|
if (!searchBarFocused) {
|
||||||
|
if (event.keyCode === SPACE_BAR_KEYCODE) {
|
||||||
event.preventDefault(); // prevent page scroll
|
event.preventDefault(); // prevent page scroll
|
||||||
this.playContent();
|
this.playContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleAutoplay = (props: Props) => {
|
handleAutoplay = (props: Props) => {
|
||||||
const { autoplay, playingUri, fileInfo, costInfo, isDownloading, uri, nsfw } = props;
|
const { autoplay, playingUri, fileInfo, costInfo, isDownloading, uri, nsfw } = props;
|
||||||
|
@ -222,6 +229,8 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
obscureNsfw,
|
obscureNsfw,
|
||||||
mediaType,
|
mediaType,
|
||||||
insufficientCredits,
|
insufficientCredits,
|
||||||
|
viewerContainer,
|
||||||
|
searchBarFocused,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
nsfw,
|
nsfw,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -257,7 +266,7 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
const layoverStyle = !shouldObscureNsfw && thumbnail ? { backgroundImage: `url("${thumbnail}")` } : {};
|
const layoverStyle = !shouldObscureNsfw && thumbnail ? { backgroundImage: `url("${thumbnail}")` } : {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames('video', {}, className)}>
|
<div className={classnames('video', {}, className)} ref={viewerContainer}>
|
||||||
{isPlaying && (
|
{isPlaying && (
|
||||||
<div className="content__view">
|
<div className="content__view">
|
||||||
{!isReadyToPlay ? (
|
{!isReadyToPlay ? (
|
||||||
|
@ -282,6 +291,8 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
onStartCb={this.onFileStartCb}
|
onStartCb={this.onFileStartCb}
|
||||||
onFinishCb={this.onFileFinishCb}
|
onFinishCb={this.onFileFinishCb}
|
||||||
playingUri={playingUri}
|
playingUri={playingUri}
|
||||||
|
searchBarFocused={searchBarFocused}
|
||||||
|
viewerContainer={viewerContainer}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -41,6 +41,7 @@ export const ACCOUNT = 'User';
|
||||||
export const SETTINGS = 'Settings';
|
export const SETTINGS = 'Settings';
|
||||||
export const INVITE = 'Users';
|
export const INVITE = 'Users';
|
||||||
export const FILE = 'File';
|
export const FILE = 'File';
|
||||||
|
export const FULLSCREEN = 'Maximize';
|
||||||
export const OPTIONS = 'Sliders';
|
export const OPTIONS = 'Sliders';
|
||||||
export const YES = 'ThumbsUp';
|
export const YES = 'ThumbsUp';
|
||||||
export const NO = 'ThumbsDown';
|
export const NO = 'ThumbsDown';
|
||||||
|
|
|
@ -157,6 +157,13 @@ ipcRenderer.on('window-is-focused', () => {
|
||||||
ipcRenderer.on('devtools-is-opened', () => {
|
ipcRenderer.on('devtools-is-opened', () => {
|
||||||
doLogWarningConsoleMessage();
|
doLogWarningConsoleMessage();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Force exit mode for html5 fullscreen api
|
||||||
|
// See: https://github.com/electron/electron/issues/18188
|
||||||
|
remote.getCurrentWindow().on('leave-full-screen', event => {
|
||||||
|
document.webkitExitFullscreen();
|
||||||
|
});
|
||||||
|
|
||||||
// @endif
|
// @endif
|
||||||
|
|
||||||
document.addEventListener('dragover', event => {
|
document.addEventListener('dragover', event => {
|
||||||
|
|
|
@ -62,16 +62,21 @@ class FilePage extends React.Component<Props> {
|
||||||
'application',
|
'application',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
(this: any).viewerContainer = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const {
|
const {
|
||||||
uri,
|
uri,
|
||||||
|
claim,
|
||||||
fetchFileInfo,
|
fetchFileInfo,
|
||||||
fetchCostInfo,
|
fetchCostInfo,
|
||||||
setViewed,
|
setViewed,
|
||||||
isSubscribed,
|
isSubscribed,
|
||||||
claimIsMine,
|
claimIsMine,
|
||||||
fetchViewCount,
|
fetchViewCount,
|
||||||
claim,
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (isSubscribed) {
|
if (isSubscribed) {
|
||||||
|
@ -92,21 +97,8 @@ class FilePage extends React.Component<Props> {
|
||||||
setViewed(uri);
|
setViewed(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps: Props) {
|
|
||||||
const { fetchFileInfo, uri, setViewed } = this.props;
|
|
||||||
// @if TARGET='app'
|
|
||||||
if (nextProps.fileInfo === undefined) {
|
|
||||||
fetchFileInfo(uri);
|
|
||||||
}
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
if (uri !== nextProps.uri) {
|
|
||||||
setViewed(nextProps.uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps: Props) {
|
componentDidUpdate(prevProps: Props) {
|
||||||
const { isSubscribed, claim, uri, fetchViewCount, claimIsMine } = this.props;
|
const { isSubscribed, claim, uri, fileInfo, setViewed, fetchViewCount, claimIsMine, fetchFileInfo } = this.props;
|
||||||
|
|
||||||
if (!prevProps.isSubscribed && isSubscribed) {
|
if (!prevProps.isSubscribed && isSubscribed) {
|
||||||
this.removeFromSubscriptionNotifications();
|
this.removeFromSubscriptionNotifications();
|
||||||
|
@ -115,6 +107,16 @@ class FilePage extends React.Component<Props> {
|
||||||
if (prevProps.uri !== uri && claimIsMine) {
|
if (prevProps.uri !== uri && claimIsMine) {
|
||||||
fetchViewCount(claim.claim_id);
|
fetchViewCount(claim.claim_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @if TARGET='app'
|
||||||
|
if (fileInfo === undefined) {
|
||||||
|
fetchFileInfo(uri);
|
||||||
|
}
|
||||||
|
// @endif
|
||||||
|
|
||||||
|
if (prevProps.uri !== uri) {
|
||||||
|
setViewed(uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFromSubscriptionNotifications() {
|
removeFromSubscriptionNotifications() {
|
||||||
|
@ -152,7 +154,9 @@ class FilePage extends React.Component<Props> {
|
||||||
const shouldObscureThumbnail = obscureNsfw && nsfw;
|
const shouldObscureThumbnail = obscureNsfw && nsfw;
|
||||||
const fileName = fileInfo ? fileInfo.file_name : null;
|
const fileName = fileInfo ? fileInfo.file_name : null;
|
||||||
const mediaType = getMediaType(contentType, fileName);
|
const mediaType = getMediaType(contentType, fileName);
|
||||||
const showFile = PLAYABLE_MEDIA_TYPES.includes(mediaType) || PREVIEW_MEDIA_TYPES.includes(mediaType);
|
const isPreviewType = PREVIEW_MEDIA_TYPES.includes(mediaType);
|
||||||
|
const isPlayableType = PLAYABLE_MEDIA_TYPES.includes(mediaType);
|
||||||
|
const showFile = isPlayableType || isPreviewType;
|
||||||
|
|
||||||
const speechShareable =
|
const speechShareable =
|
||||||
costInfo && costInfo.cost === 0 && contentType && ['video', 'image'].includes(contentType.split('/')[0]);
|
costInfo && costInfo.cost === 0 && contentType && ['video', 'image'].includes(contentType.split('/')[0]);
|
||||||
|
@ -199,10 +203,12 @@ class FilePage extends React.Component<Props> {
|
||||||
)}
|
)}
|
||||||
{showFile && (
|
{showFile && (
|
||||||
<FileViewer
|
<FileViewer
|
||||||
insufficientCredits={insufficientCredits}
|
|
||||||
className="content__embedded"
|
|
||||||
uri={uri}
|
uri={uri}
|
||||||
|
className="content__embedded"
|
||||||
mediaType={mediaType}
|
mediaType={mediaType}
|
||||||
|
isPlayableType={isPlayableType}
|
||||||
|
viewerContainer={this.viewerContainer}
|
||||||
|
insufficientCredits={insufficientCredits}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!showFile &&
|
{!showFile &&
|
||||||
|
@ -288,7 +294,12 @@ class FilePage extends React.Component<Props> {
|
||||||
|
|
||||||
<div className="media__action-group--large">
|
<div className="media__action-group--large">
|
||||||
<FileDownloadLink uri={uri} />
|
<FileDownloadLink uri={uri} />
|
||||||
<FileActions uri={uri} claimId={claim.claim_id} />
|
<FileActions
|
||||||
|
uri={uri}
|
||||||
|
claimId={claim.claim_id}
|
||||||
|
showFullscreen={isPreviewType}
|
||||||
|
viewerContainer={this.viewerContainer}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,11 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:-webkit-full-screen {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content__empty {
|
.content__empty {
|
||||||
|
|
49
src/ui/util/full-screen.js
Normal file
49
src/ui/util/full-screen.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
Polyfill functions for the HTML5 fullscreen api:
|
||||||
|
https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API
|
||||||
|
*/
|
||||||
|
|
||||||
|
const prefixes = {
|
||||||
|
exitFullscreen: ['exitFullscreen', 'msExitFullscreen', 'mozCancelFullScreen', 'webkitExitFullscreen'],
|
||||||
|
fullscreenChange: ['fullscreenChange', 'MSFullscreenChange', 'mozfullscreenchange', 'webkitfullscreenchange'],
|
||||||
|
fullscreenEnabled: ['fullscreenEnabled', 'msFullscreenEnabled', 'mozFullScreenEnabled', 'webkitFullscreenEnabled'],
|
||||||
|
fullscreenElement: ['fullscreenElement', 'msFullscreenElement', 'mozFullScreenElement', 'webkitFullscreenElement'],
|
||||||
|
requestFullscreen: ['requestFullscreen', 'msRequestFullscreen', 'mozRequestFullScreen', 'webkitRequestFullscreen'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPrefix = () => {
|
||||||
|
let prefixIndex = 0;
|
||||||
|
// validate prefix
|
||||||
|
prefixes.fullscreenEnabled.some((prefix, index) => {
|
||||||
|
if (document[prefix] || document[prefix] === false) {
|
||||||
|
prefixIndex = index;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// prefix vendor index
|
||||||
|
return prefixIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fullscreenElement = () => {
|
||||||
|
const index = getPrefix();
|
||||||
|
const prefix = prefixes.fullscreenElement[index];
|
||||||
|
return document[prefix];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const requestFullscreen = elem => {
|
||||||
|
const index = getPrefix();
|
||||||
|
const prefix = prefixes.requestFullscreen[index];
|
||||||
|
elem[prefix] && elem[prefix]();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const exitFullscreen = () => {
|
||||||
|
const index = getPrefix();
|
||||||
|
const prefix = prefixes.exitFullscreen[index];
|
||||||
|
document[prefix] && document[prefix]();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const onFullscreenChange = (event, callback) => {
|
||||||
|
const index = getPrefix();
|
||||||
|
const prefix = prefixes.fullscreenChange[index];
|
||||||
|
document[`${event}EventListener`](prefix, callback, false);
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue
this.container.current