From 5241f7b2fde593e27bc6ba13ec5b33d95f9768f8 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Thu, 11 May 2023 12:41:55 +0200 Subject: [PATCH] Fix UI crash in moderation interface when opening the media modal (#24816) --- .../mastodon/components/media_gallery.jsx | 2 +- app/javascript/mastodon/components/status.jsx | 10 ++++++---- .../mastodon/containers/media_container.jsx | 10 ++++++---- .../mastodon/containers/status_container.jsx | 8 ++++---- .../mastodon/features/account_gallery/index.jsx | 7 ++++--- .../containers/detailed_status_container.js | 8 ++++---- .../mastodon/features/status/index.jsx | 8 ++++---- .../features/ui/components/media_modal.jsx | 16 ++++++---------- app/javascript/mastodon/features/video/index.jsx | 2 +- .../admin/reports/_media_attachments.html.haml | 6 +++--- 10 files changed, 39 insertions(+), 38 deletions(-) diff --git a/app/javascript/mastodon/components/media_gallery.jsx b/app/javascript/mastodon/components/media_gallery.jsx index 1eeb63fa450..6653f8632d6 100644 --- a/app/javascript/mastodon/components/media_gallery.jsx +++ b/app/javascript/mastodon/components/media_gallery.jsx @@ -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 => { diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 8cd322edabf..070ec4672aa 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -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); } } }; diff --git a/app/javascript/mastodon/containers/media_container.jsx b/app/javascript/mastodon/containers/media_container.jsx index f9244f8dd39..0b5ff99dda5 100644 --- a/app/javascript/mastodon/containers/media_container.jsx +++ b/app/javascript/mastodon/containers/media_container.jsx @@ -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 { ({ 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) { diff --git a/app/javascript/mastodon/features/account_gallery/index.jsx b/app/javascript/mastodon/features/account_gallery/index.jsx index b876df6a294..8c44fa346f8 100644 --- a/app/javascript/mastodon/features/account_gallery/index.jsx +++ b/app/javascript/mastodon/features/account_gallery/index.jsx @@ -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 })); } }; diff --git a/app/javascript/mastodon/features/status/containers/detailed_status_container.js b/app/javascript/mastodon/features/status/containers/detailed_status_container.js index bfed1662007..835bb41b51a 100644 --- a/app/javascript/mastodon/features/status/containers/detailed_status_container.js +++ b/app/javascript/mastodon/features/status/containers/detailed_status_container.js @@ -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) { diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index e77d687e8d3..5f1715c27e0 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -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 => { diff --git a/app/javascript/mastodon/features/ui/components/media_modal.jsx b/app/javascript/mastodon/features/ui/components/media_modal.jsx index e8293c2e78f..594f5cf64f7 100644 --- a/app/javascript/mastodon/features/ui/components/media_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/media_modal.jsx @@ -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); diff --git a/app/javascript/mastodon/features/video/index.jsx b/app/javascript/mastodon/features/video/index.jsx index 3d9d1aec6ce..560dbc6d6ae 100644 --- a/app/javascript/mastodon/features/video/index.jsx +++ b/app/javascript/mastodon/features/video/index.jsx @@ -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, diff --git a/app/views/admin/reports/_media_attachments.html.haml b/app/views/admin/reports/_media_attachments.html.haml index d0b7d52c325..2305805a751 100644 --- a/app/views/admin/reports/_media_attachments.html.haml +++ b/app/views/admin/reports/_media_attachments.html.haml @@ -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 }