summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2019-10-10 05:21:38 +0200
committerGitHub <noreply@github.com>2019-10-10 05:21:38 +0200
commit6ebd74f4fa640b9616ebb2730d97722799c6ed56 (patch)
tree42fe837478cc6b3afc9da96eb226e5a7e959543f
parent915f3712ae7ae44c0cbe50c9694c25e3ee87a540 (diff)
Fix media editing modal changing dimensions when image loads (#12131)
-rw-r--r--app/javascript/mastodon/components/extended_video_player.js63
-rw-r--r--app/javascript/mastodon/components/gifv.js75
-rw-r--r--app/javascript/mastodon/features/ui/components/focal_point_modal.js36
-rw-r--r--app/javascript/mastodon/features/ui/components/media_modal.js6
-rw-r--r--app/javascript/styles/mastodon/components.scss3
5 files changed, 113 insertions, 70 deletions
diff --git a/app/javascript/mastodon/components/extended_video_player.js b/app/javascript/mastodon/components/extended_video_player.js
deleted file mode 100644
index 009c0d559ad..00000000000
--- a/app/javascript/mastodon/components/extended_video_player.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-export default class ExtendedVideoPlayer extends React.PureComponent {
-
- static propTypes = {
- src: PropTypes.string.isRequired,
- alt: PropTypes.string,
- width: PropTypes.number,
- height: PropTypes.number,
- time: PropTypes.number,
- controls: PropTypes.bool.isRequired,
- muted: PropTypes.bool.isRequired,
- onClick: PropTypes.func,
- };
-
- handleLoadedData = () => {
- if (this.props.time) {
- this.video.currentTime = this.props.time;
- }
- }
-
- componentDidMount () {
- this.video.addEventListener('loadeddata', this.handleLoadedData);
- }
-
- componentWillUnmount () {
- this.video.removeEventListener('loadeddata', this.handleLoadedData);
- }
-
- setRef = (c) => {
- this.video = c;
- }
-
- handleClick = e => {
- e.stopPropagation();
- const handler = this.props.onClick;
- if (handler) handler();
- }
-
- render () {
- const { src, muted, controls, alt } = this.props;
-
- return (
- <div className='extended-video-player'>
- <video
- ref={this.setRef}
- src={src}
- autoPlay
- role='button'
- tabIndex='0'
- aria-label={alt}
- title={alt}
- muted={muted}
- controls={controls}
- loop={!controls}
- onClick={this.handleClick}
- />
- </div>
- );
- }
-
-}
diff --git a/app/javascript/mastodon/components/gifv.js b/app/javascript/mastodon/components/gifv.js
new file mode 100644
index 00000000000..83cfae49c49
--- /dev/null
+++ b/app/javascript/mastodon/components/gifv.js
@@ -0,0 +1,75 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default class GIFV extends React.PureComponent {
+
+ static propTypes = {
+ src: PropTypes.string.isRequired,
+ alt: PropTypes.string,
+ width: PropTypes.number,
+ height: PropTypes.number,
+ onClick: PropTypes.func,
+ };
+
+ state = {
+ loading: true,
+ };
+
+ handleLoadedData = () => {
+ this.setState({ loading: false });
+ }
+
+ componentWillReceiveProps (nextProps) {
+ if (nextProps.src !== this.props.src) {
+ this.setState({ loading: true });
+ }
+ }
+
+ handleClick = e => {
+ const { onClick } = this.props;
+
+ if (onClick) {
+ e.stopPropagation();
+ onClick();
+ }
+ }
+
+ render () {
+ const { src, width, height, alt } = this.props;
+ const { loading } = this.state;
+
+ return (
+ <div className='gifv' style={{ position: 'relative' }}>
+ {loading && (
+ <canvas
+ width={width}
+ height={height}
+ role='button'
+ tabIndex='0'
+ aria-label={alt}
+ title={alt}
+ onClick={this.handleClick}
+ />
+ )}
+
+ <video
+ src={src}
+ width={width}
+ height={height}
+ role='button'
+ tabIndex='0'
+ aria-label={alt}
+ title={alt}
+ muted
+ loop
+ autoPlay
+ playsInline
+ onClick={this.handleClick}
+ onLoadedData={this.handleLoadedData}
+ style={{ position: loading ? 'absolute' : 'static', top: 0, left: 0 }}
+ />
+ </div>
+ );
+ }
+
+}
diff --git a/app/javascript/mastodon/features/ui/components/focal_point_modal.js b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
index 1ab79a21df2..3694ab9046a 100644
--- a/app/javascript/mastodon/features/ui/components/focal_point_modal.js
+++ b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
@@ -16,6 +16,7 @@ import UploadProgress from 'mastodon/features/compose/components/upload_progress
import CharacterCounter from 'mastodon/features/compose/components/character_counter';
import { length } from 'stringz';
import { Tesseract as fetchTesseract } from 'mastodon/features/ui/util/async-components';
+import GIFV from 'mastodon/components/gifv';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
@@ -41,6 +42,36 @@ const removeExtraLineBreaks = str => str.replace(/\n\n/g, '******')
const assetHost = process.env.CDN_HOST || '';
+class ImageLoader extends React.PureComponent {
+
+ static propTypes = {
+ src: PropTypes.string.isRequired,
+ width: PropTypes.number,
+ height: PropTypes.number,
+ };
+
+ state = {
+ loading: true,
+ };
+
+ componentDidMount() {
+ const image = new Image();
+ image.addEventListener('load', () => this.setState({ loading: false }));
+ image.src = this.props.src;
+ }
+
+ render () {
+ const { loading } = this.state;
+
+ if (loading) {
+ return <canvas width={this.props.width} height={this.props.height} />;
+ } else {
+ return <img {...this.props} alt='' />;
+ }
+ }
+
+}
+
export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class FocalPointModal extends ImmutablePureComponent {
@@ -60,6 +91,7 @@ class FocalPointModal extends ImmutablePureComponent {
description: '',
dirty: false,
progress: 0,
+ loading: true,
};
componentWillMount () {
@@ -242,8 +274,8 @@ class FocalPointModal extends ImmutablePureComponent {
<div className='focal-point-modal__content'>
{focals && (
<div className={classNames('focal-point', { dragging })} ref={this.setRef} onMouseDown={this.handleMouseDown} onTouchStart={this.handleTouchStart}>
- {media.get('type') === 'image' && <img src={media.get('url')} width={width} height={height} alt='' />}
- {media.get('type') === 'gifv' && <video src={media.get('url')} width={width} height={height} loop muted autoPlay />}
+ {media.get('type') === 'image' && <ImageLoader src={media.get('url')} width={width} height={height} alt='' />}
+ {media.get('type') === 'gifv' && <GIFV src={media.get('url')} width={width} height={height} />}
<div className='focal-point__preview'>
<strong><FormattedMessage id='upload_modal.preview_label' defaultMessage='Preview ({ratio})' values={{ ratio: '16:9' }} /></strong>
diff --git a/app/javascript/mastodon/features/ui/components/media_modal.js b/app/javascript/mastodon/features/ui/components/media_modal.js
index 98ebd4b413d..a785551c0fd 100644
--- a/app/javascript/mastodon/features/ui/components/media_modal.js
+++ b/app/javascript/mastodon/features/ui/components/media_modal.js
@@ -3,13 +3,13 @@ import ReactSwipeableViews from 'react-swipeable-views';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import Video from 'mastodon/features/video';
-import ExtendedVideoPlayer from 'mastodon/components/extended_video_player';
import classNames from 'classnames';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import IconButton from 'mastodon/components/icon_button';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImageLoader from './image_loader';
import Icon from 'mastodon/components/icon';
+import GIFV from 'mastodon/components/gifv';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
@@ -169,10 +169,8 @@ class MediaModal extends ImmutablePureComponent {
);
} else if (image.get('type') === 'gifv') {
return (
- <ExtendedVideoPlayer
+ <GIFV
src={image.get('url')}
- muted
- controls={false}
width={width}
height={height}
key={image.get('preview_url')}
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index d9182ade942..86425c47c4a 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -6092,7 +6092,8 @@ noscript {
background: $base-shadow-color;
img,
- video {
+ video,
+ canvas {
display: block;
max-height: 80vh;
width: 100%;