~cytrogen/masto-fe

5241f7b2fde593e27bc6ba13ec5b33d95f9768f8 — Christian Schmidt 2 years ago a610a02
Fix UI crash in moderation interface when opening the media modal (#24816)

M app/javascript/mastodon/components/media_gallery.jsx => app/javascript/mastodon/components/media_gallery.jsx +1 -1
@@ 256,7 256,7 @@ class MediaGallery extends React.PureComponent {
  };

  handleClick = (index) => {
    this.props.onOpenMedia(this.props.media, index);
    this.props.onOpenMedia(this.props.media, index, this.props.lang);
  };

  handleRef = c => {

M app/javascript/mastodon/components/status.jsx => app/javascript/mastodon/components/status.jsx +6 -4
@@ 194,11 194,12 @@ class Status extends ImmutablePureComponent {

  handleOpenVideo = (options) => {
    const status = this._properStatus();
    this.props.onOpenVideo(status.get('id'), status.getIn(['media_attachments', 0]), options);
    this.props.onOpenVideo(status.get('id'), status.getIn(['media_attachments', 0]), status.get('language'), options);
  };

  handleOpenMedia = (media, index) => {
    this.props.onOpenMedia(this._properStatus().get('id'), media, index);
    const status = this._properStatus();
    this.props.onOpenMedia(status.get('id'), media, index, status.get('language'));
  };

  handleHotkeyOpenMedia = e => {


@@ 208,10 209,11 @@ class Status extends ImmutablePureComponent {
    e.preventDefault();

    if (status.get('media_attachments').size > 0) {
      const lang = status.get('language');
      if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
        onOpenVideo(status.get('id'), status.getIn(['media_attachments', 0]), { startTime: 0 });
        onOpenVideo(status.get('id'), status.getIn(['media_attachments', 0]), lang, { startTime: 0 });
      } else {
        onOpenMedia(status.get('id'), status.get('media_attachments'), 0);
        onOpenMedia(status.get('id'), status.get('media_attachments'), 0, lang);
      }
    }
  };

M app/javascript/mastodon/containers/media_container.jsx => app/javascript/mastodon/containers/media_container.jsx +6 -4
@@ 29,19 29,20 @@ export default class MediaContainer extends PureComponent {
  state = {
    media: null,
    index: null,
    lang: null,
    time: null,
    backgroundColor: null,
    options: null,
  };

  handleOpenMedia = (media, index) => {
  handleOpenMedia = (media, index, lang) => {
    document.body.classList.add('with-modals--active');
    document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;

    this.setState({ media, index });
    this.setState({ media, index, lang });
  };

  handleOpenVideo = (options) => {
  handleOpenVideo = (lang, options) => {
    const { components } = this.props;
    const { media } = JSON.parse(components[options.componentIndex].getAttribute('data-props'));
    const mediaList = fromJS(media);


@@ 49,7 50,7 @@ export default class MediaContainer extends PureComponent {
    document.body.classList.add('with-modals--active');
    document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;

    this.setState({ media: mediaList, options });
    this.setState({ media: mediaList, lang, options });
  };

  handleCloseMedia = () => {


@@ 105,6 106,7 @@ export default class MediaContainer extends PureComponent {
              <MediaModal
                media={this.state.media}
                index={this.state.index || 0}
                lang={this.state.lang}
                currentTime={this.state.options?.startTime}
                autoPlay={this.state.options?.autoPlay}
                volume={this.state.options?.defaultVolume}

M app/javascript/mastodon/containers/status_container.jsx => app/javascript/mastodon/containers/status_container.jsx +4 -4
@@ 182,12 182,12 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
    dispatch(mentionCompose(account, router));
  },

  onOpenMedia (statusId, media, index) {
    dispatch(openModal('MEDIA', { statusId, media, index }));
  onOpenMedia (statusId, media, index, lang) {
    dispatch(openModal('MEDIA', { statusId, media, index, lang }));
  },

  onOpenVideo (statusId, media, options) {
    dispatch(openModal('VIDEO', { statusId, media, options }));
  onOpenVideo (statusId, media, lang, options) {
    dispatch(openModal('VIDEO', { statusId, media, lang, options }));
  },

  onBlock (status) {

M app/javascript/mastodon/features/account_gallery/index.jsx => app/javascript/mastodon/features/account_gallery/index.jsx +4 -3
@@ 136,16 136,17 @@ class AccountGallery extends ImmutablePureComponent {
  handleOpenMedia = attachment => {
    const { dispatch } = this.props;
    const statusId = attachment.getIn(['status', 'id']);
    const lang = attachment.getIn(['status', 'language']);

    if (attachment.get('type') === 'video') {
      dispatch(openModal('VIDEO', { media: attachment, statusId, options: { autoPlay: true } }));
      dispatch(openModal('VIDEO', { media: attachment, statusId, lang, options: { autoPlay: true } }));
    } else if (attachment.get('type') === 'audio') {
      dispatch(openModal('AUDIO', { media: attachment, statusId, options: { autoPlay: true } }));
      dispatch(openModal('AUDIO', { media: attachment, statusId, lang, options: { autoPlay: true } }));
    } else {
      const media = attachment.getIn(['status', 'media_attachments']);
      const index = media.findIndex(x => x.get('id') === attachment.get('id'));

      dispatch(openModal('MEDIA', { media, index, statusId }));
      dispatch(openModal('MEDIA', { media, index, statusId, lang }));
    }
  };


M app/javascript/mastodon/features/status/containers/detailed_status_container.js => app/javascript/mastodon/features/status/containers/detailed_status_container.js +4 -4
@@ 128,12 128,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
    dispatch(mentionCompose(account, router));
  },

  onOpenMedia (media, index) {
    dispatch(openModal('MEDIA', { media, index }));
  onOpenMedia (media, index, lang) {
    dispatch(openModal('MEDIA', { media, index, lang }));
  },

  onOpenVideo (media, options) {
    dispatch(openModal('VIDEO', { media, options }));
  onOpenVideo (media, lang, options) {
    dispatch(openModal('VIDEO', { media, lang, options }));
  },

  onBlock (status) {

M app/javascript/mastodon/features/status/index.jsx => app/javascript/mastodon/features/status/index.jsx +4 -4
@@ 345,12 345,12 @@ class Status extends ImmutablePureComponent {
    this.props.dispatch(mentionCompose(account, router));
  };

  handleOpenMedia = (media, index) => {
    this.props.dispatch(openModal('MEDIA', { statusId: this.props.status.get('id'), media, index }));
  handleOpenMedia = (media, index, lang) => {
    this.props.dispatch(openModal('MEDIA', { statusId: this.props.status.get('id'), media, index, lang }));
  };

  handleOpenVideo = (media, options) => {
    this.props.dispatch(openModal('VIDEO', { statusId: this.props.status.get('id'), media, options }));
  handleOpenVideo = (media, lang, options) => {
    this.props.dispatch(openModal('VIDEO', { statusId: this.props.status.get('id'), media, lang, options }));
  };

  handleHotkeyOpenMedia = e => {

M app/javascript/mastodon/features/ui/components/media_modal.jsx => app/javascript/mastodon/features/ui/components/media_modal.jsx +6 -10
@@ 3,7 3,6 @@ import ReactSwipeableViews from 'react-swipeable-views';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import Video from 'mastodon/features/video';
import { connect } from 'react-redux';
import classNames from 'classnames';
import { defineMessages, injectIntl } from 'react-intl';
import { IconButton } from 'mastodon/components/icon_button';


@@ 21,15 20,12 @@ const messages = defineMessages({
  next: { id: 'lightbox.next', defaultMessage: 'Next' },
});

const mapStateToProps = (state, { statusId }) => ({
  language: state.getIn(['statuses', statusId, 'language']),
});

class MediaModal extends ImmutablePureComponent {

  static propTypes = {
    media: ImmutablePropTypes.list.isRequired,
    statusId: PropTypes.string,
    lang: PropTypes.string,
    index: PropTypes.number.isRequired,
    onClose: PropTypes.func.isRequired,
    intl: PropTypes.object.isRequired,


@@ 133,7 129,7 @@ class MediaModal extends ImmutablePureComponent {
  };

  render () {
    const { media, language, statusId, intl, onClose } = this.props;
    const { media, statusId, lang, intl, onClose } = this.props;
    const { navigationHidden } = this.state;

    const index = this.getIndex();


@@ 153,7 149,7 @@ class MediaModal extends ImmutablePureComponent {
            width={width}
            height={height}
            alt={image.get('description')}
            lang={language}
            lang={lang}
            key={image.get('url')}
            onClick={this.toggleNavigation}
            zoomButtonHidden={this.state.zoomButtonHidden}


@@ 176,7 172,7 @@ class MediaModal extends ImmutablePureComponent {
            onCloseVideo={onClose}
            detailed
            alt={image.get('description')}
            lang={language}
            lang={lang}
            key={image.get('url')}
          />
        );


@@ 188,7 184,7 @@ class MediaModal extends ImmutablePureComponent {
            height={height}
            key={image.get('url')}
            alt={image.get('description')}
            lang={language}
            lang={lang}
            onClick={this.toggleNavigation}
          />
        );


@@ 256,4 252,4 @@ class MediaModal extends ImmutablePureComponent {

}

export default connect(mapStateToProps, null, null, { forwardRef: true })(injectIntl(MediaModal));
export default injectIntl(MediaModal);

M app/javascript/mastodon/features/video/index.jsx => app/javascript/mastodon/features/video/index.jsx +1 -1
@@ 469,7 469,7 @@ class Video extends React.PureComponent {
  handleOpenVideo = () => {
    this.video.pause();

    this.props.onOpenVideo({
    this.props.onOpenVideo(this.props.lang, {
      startTime: this.video.currentTime,
      autoPlay: !this.state.paused,
      defaultVolume: this.state.volume,

M app/views/admin/reports/_media_attachments.html.haml => app/views/admin/reports/_media_attachments.html.haml +3 -3
@@ 1,8 1,8 @@
- if status.ordered_media_attachments.first.video?
  - video = status.ordered_media_attachments.first
  = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), frameRate: video.file.meta.dig('original', 'frame_rate'), blurhash: video.blurhash, sensitive: status.sensitive?, visible: false, width: 610, height: 343, inline: true, alt: video.description, media: [ActiveModelSerializers::SerializableResource.new(video, serializer: REST::MediaAttachmentSerializer)].as_json
  = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), frameRate: video.file.meta.dig('original', 'frame_rate'), blurhash: video.blurhash, sensitive: status.sensitive?, visible: false, width: 610, height: 343, inline: true, alt: video.description, lang: status.language, media: [ActiveModelSerializers::SerializableResource.new(video, serializer: REST::MediaAttachmentSerializer)].as_json
- elsif status.ordered_media_attachments.first.audio?
  - audio = status.ordered_media_attachments.first
  = react_component :audio, src: audio.file.url(:original), height: 110, alt: audio.description, duration: audio.file.meta.dig(:original, :duration)
  = react_component :audio, src: audio.file.url(:original), height: 110, alt: audio.description, lang: status.language, duration: audio.file.meta.dig(:original, :duration)
- else
  = react_component :media_gallery, height: 343, sensitive: status.sensitive?, visible: false, media: status.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
  = react_component :media_gallery, height: 343, sensitive: status.sensitive?, visible: false, lang: status.language, media: status.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }