diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js index ff0540e5d..c6b588765 100644 --- a/app/javascript/mastodon/components/scrollable_list.js +++ b/app/javascript/mastodon/components/scrollable_list.js @@ -6,6 +6,8 @@ import LoadMore from './load_more'; import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper'; import { throttle } from 'lodash'; import { List as ImmutableList } from 'immutable'; +import classNames from 'classnames'; +import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../features/ui/util/fullscreen'; export default class ScrollableList extends PureComponent { @@ -66,6 +68,7 @@ export default class ScrollableList extends PureComponent { componentDidMount () { this.attachScrollListener(); this.attachIntersectionObserver(); + attachFullscreenListener(this.onFullScreenChange); // Handle initial scroll posiiton this.handleScroll(); @@ -92,6 +95,11 @@ export default class ScrollableList extends PureComponent { componentWillUnmount () { this.detachScrollListener(); this.detachIntersectionObserver(); + detachFullscreenListener(this.onFullScreenChange); + } + + onFullScreenChange = () => { + this.setState({ fullscreen: isFullscreen() }); } attachIntersectionObserver () { @@ -165,6 +173,7 @@ export default class ScrollableList extends PureComponent { render () { const { children, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, emptyMessage } = this.props; + const { fullscreen } = this.state; const childrenCount = React.Children.count(children); const loadMore = (hasMore && childrenCount > 0) ? : null; @@ -172,7 +181,7 @@ export default class ScrollableList extends PureComponent { if (isLoading || childrenCount > 0 || !emptyMessage) { scrollableArea = ( -
+
{prepend} diff --git a/app/javascript/mastodon/features/ui/util/fullscreen.js b/app/javascript/mastodon/features/ui/util/fullscreen.js new file mode 100644 index 000000000..cf5d0cf98 --- /dev/null +++ b/app/javascript/mastodon/features/ui/util/fullscreen.js @@ -0,0 +1,46 @@ +// APIs for normalizing fullscreen operations. Note that Edge uses +// the WebKit-prefixed APIs currently (as of Edge 16). + +export const isFullscreen = () => document.fullscreenElement || + document.webkitFullscreenElement || + document.mozFullScreenElement; + +export const exitFullscreen = () => { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } +}; + +export const requestFullscreen = el => { + if (el.requestFullscreen) { + el.requestFullscreen(); + } else if (el.webkitRequestFullscreen) { + el.webkitRequestFullscreen(); + } else if (el.mozRequestFullScreen) { + el.mozRequestFullScreen(); + } +}; + +export const attachFullscreenListener = (listener) => { + if ('onfullscreenchange' in document) { + document.addEventListener('fullscreenchange', listener); + } else if ('onwebkitfullscreenchange' in document) { + document.addEventListener('webkitfullscreenchange', listener); + } else if ('onmozfullscreenchange' in document) { + document.addEventListener('mozfullscreenchange', listener); + } +}; + +export const detachFullscreenListener = (listener) => { + if ('onfullscreenchange' in document) { + document.removeEventListener('fullscreenchange', listener); + } else if ('onwebkitfullscreenchange' in document) { + document.removeEventListener('webkitfullscreenchange', listener); + } else if ('onmozfullscreenchange' in document) { + document.removeEventListener('mozfullscreenchange', listener); + } +}; diff --git a/app/javascript/mastodon/features/video/index.js b/app/javascript/mastodon/features/video/index.js index 069264ef5..7502dda8b 100644 --- a/app/javascript/mastodon/features/video/index.js +++ b/app/javascript/mastodon/features/video/index.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { throttle } from 'lodash'; import classNames from 'classnames'; +import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen'; const messages = defineMessages({ play: { id: 'video.play', defaultMessage: 'Play' }, @@ -69,35 +70,6 @@ const getPointerPosition = (el, event) => { return position; }; -const isFullscreen = () => document.fullscreenElement || - document.webkitFullscreenElement || - document.mozFullScreenElement || - document.msFullscreenElement; - -const exitFullscreen = () => { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if (document.webkitExitFullscreen) { - document.webkitExitFullscreen(); - } else if (document.mozCancelFullScreen) { - document.mozCancelFullScreen(); - } else if (document.msExitFullscreen) { - document.msExitFullscreen(); - } -}; - -const requestFullscreen = el => { - if (el.requestFullscreen) { - el.requestFullscreen(); - } else if (el.webkitRequestFullscreen) { - el.webkitRequestFullscreen(); - } else if (el.mozRequestFullScreen) { - el.mozRequestFullScreen(); - } else if (el.msRequestFullscreen) { - el.msRequestFullscreen(); - } -}; - @injectIntl export default class Video extends React.PureComponent { diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index caa7c0787..48d6e0c4d 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -1674,6 +1674,16 @@ &.optionally-scrollable { overflow-y: auto; } + + @supports(display: grid) { // hack to fix Chrome <57 + contain: strict; + } +} + +.scrollable.fullscreen { + @supports(display: grid) { // hack to fix Chrome <57 + contain: none; + } } .column-back-button {