Fix UI crash in moderation interface when opening the media modal (#24816)
This commit is contained in:
		
					parent
					
						
							
								a610a02d4f
							
						
					
				
			
			
				commit
				
					
						5241f7b2fd
					
				
			
		
					 10 changed files with 39 additions and 38 deletions
				
			
		|  | @ -256,7 +256,7 @@ class MediaGallery extends React.PureComponent { | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   handleClick = (index) => { |   handleClick = (index) => { | ||||||
|     this.props.onOpenMedia(this.props.media, index); |     this.props.onOpenMedia(this.props.media, index, this.props.lang); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   handleRef = c => { |   handleRef = c => { | ||||||
|  |  | ||||||
|  | @ -194,11 +194,12 @@ class Status extends ImmutablePureComponent { | ||||||
| 
 | 
 | ||||||
|   handleOpenVideo = (options) => { |   handleOpenVideo = (options) => { | ||||||
|     const status = this._properStatus(); |     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) => { |   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 => { |   handleHotkeyOpenMedia = e => { | ||||||
|  | @ -208,10 +209,11 @@ class Status extends ImmutablePureComponent { | ||||||
|     e.preventDefault(); |     e.preventDefault(); | ||||||
| 
 | 
 | ||||||
|     if (status.get('media_attachments').size > 0) { |     if (status.get('media_attachments').size > 0) { | ||||||
|  |       const lang = status.get('language'); | ||||||
|       if (status.getIn(['media_attachments', 0, 'type']) === 'video') { |       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 { |       } else { | ||||||
|         onOpenMedia(status.get('id'), status.get('media_attachments'), 0); |         onOpenMedia(status.get('id'), status.get('media_attachments'), 0, lang); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  | @ -29,19 +29,20 @@ export default class MediaContainer extends PureComponent { | ||||||
|   state = { |   state = { | ||||||
|     media: null, |     media: null, | ||||||
|     index: null, |     index: null, | ||||||
|  |     lang: null, | ||||||
|     time: null, |     time: null, | ||||||
|     backgroundColor: null, |     backgroundColor: null, | ||||||
|     options: null, |     options: null, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   handleOpenMedia = (media, index) => { |   handleOpenMedia = (media, index, lang) => { | ||||||
|     document.body.classList.add('with-modals--active'); |     document.body.classList.add('with-modals--active'); | ||||||
|     document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; |     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 { components } = this.props; | ||||||
|     const { media } = JSON.parse(components[options.componentIndex].getAttribute('data-props')); |     const { media } = JSON.parse(components[options.componentIndex].getAttribute('data-props')); | ||||||
|     const mediaList = fromJS(media); |     const mediaList = fromJS(media); | ||||||
|  | @ -49,7 +50,7 @@ export default class MediaContainer extends PureComponent { | ||||||
|     document.body.classList.add('with-modals--active'); |     document.body.classList.add('with-modals--active'); | ||||||
|     document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; |     document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; | ||||||
| 
 | 
 | ||||||
|     this.setState({ media: mediaList, options }); |     this.setState({ media: mediaList, lang, options }); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   handleCloseMedia = () => { |   handleCloseMedia = () => { | ||||||
|  | @ -105,6 +106,7 @@ export default class MediaContainer extends PureComponent { | ||||||
|               <MediaModal |               <MediaModal | ||||||
|                 media={this.state.media} |                 media={this.state.media} | ||||||
|                 index={this.state.index || 0} |                 index={this.state.index || 0} | ||||||
|  |                 lang={this.state.lang} | ||||||
|                 currentTime={this.state.options?.startTime} |                 currentTime={this.state.options?.startTime} | ||||||
|                 autoPlay={this.state.options?.autoPlay} |                 autoPlay={this.state.options?.autoPlay} | ||||||
|                 volume={this.state.options?.defaultVolume} |                 volume={this.state.options?.defaultVolume} | ||||||
|  |  | ||||||
|  | @ -182,12 +182,12 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ | ||||||
|     dispatch(mentionCompose(account, router)); |     dispatch(mentionCompose(account, router)); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   onOpenMedia (statusId, media, index) { |   onOpenMedia (statusId, media, index, lang) { | ||||||
|     dispatch(openModal('MEDIA', { statusId, media, index })); |     dispatch(openModal('MEDIA', { statusId, media, index, lang })); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   onOpenVideo (statusId, media, options) { |   onOpenVideo (statusId, media, lang, options) { | ||||||
|     dispatch(openModal('VIDEO', { statusId, media, options })); |     dispatch(openModal('VIDEO', { statusId, media, lang, options })); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   onBlock (status) { |   onBlock (status) { | ||||||
|  |  | ||||||
|  | @ -136,16 +136,17 @@ class AccountGallery extends ImmutablePureComponent { | ||||||
|   handleOpenMedia = attachment => { |   handleOpenMedia = attachment => { | ||||||
|     const { dispatch } = this.props; |     const { dispatch } = this.props; | ||||||
|     const statusId = attachment.getIn(['status', 'id']); |     const statusId = attachment.getIn(['status', 'id']); | ||||||
|  |     const lang = attachment.getIn(['status', 'language']); | ||||||
| 
 | 
 | ||||||
|     if (attachment.get('type') === 'video') { |     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') { |     } 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 { |     } else { | ||||||
|       const media = attachment.getIn(['status', 'media_attachments']); |       const media = attachment.getIn(['status', 'media_attachments']); | ||||||
|       const index = media.findIndex(x => x.get('id') === attachment.get('id')); |       const index = media.findIndex(x => x.get('id') === attachment.get('id')); | ||||||
| 
 | 
 | ||||||
|       dispatch(openModal('MEDIA', { media, index, statusId })); |       dispatch(openModal('MEDIA', { media, index, statusId, lang })); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -128,12 +128,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ | ||||||
|     dispatch(mentionCompose(account, router)); |     dispatch(mentionCompose(account, router)); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   onOpenMedia (media, index) { |   onOpenMedia (media, index, lang) { | ||||||
|     dispatch(openModal('MEDIA', { media, index })); |     dispatch(openModal('MEDIA', { media, index, lang })); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   onOpenVideo (media, options) { |   onOpenVideo (media, lang, options) { | ||||||
|     dispatch(openModal('VIDEO', { media, options })); |     dispatch(openModal('VIDEO', { media, lang, options })); | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   onBlock (status) { |   onBlock (status) { | ||||||
|  |  | ||||||
|  | @ -345,12 +345,12 @@ class Status extends ImmutablePureComponent { | ||||||
|     this.props.dispatch(mentionCompose(account, router)); |     this.props.dispatch(mentionCompose(account, router)); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   handleOpenMedia = (media, index) => { |   handleOpenMedia = (media, index, lang) => { | ||||||
|     this.props.dispatch(openModal('MEDIA', { statusId: this.props.status.get('id'), media, index })); |     this.props.dispatch(openModal('MEDIA', { statusId: this.props.status.get('id'), media, index, lang })); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   handleOpenVideo = (media, options) => { |   handleOpenVideo = (media, lang, options) => { | ||||||
|     this.props.dispatch(openModal('VIDEO', { statusId: this.props.status.get('id'), media, options })); |     this.props.dispatch(openModal('VIDEO', { statusId: this.props.status.get('id'), media, lang, options })); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   handleHotkeyOpenMedia = e => { |   handleHotkeyOpenMedia = e => { | ||||||
|  |  | ||||||
|  | @ -3,7 +3,6 @@ import ReactSwipeableViews from 'react-swipeable-views'; | ||||||
| import ImmutablePropTypes from 'react-immutable-proptypes'; | import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||||
| import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||||
| import Video from 'mastodon/features/video'; | import Video from 'mastodon/features/video'; | ||||||
| import { connect } from 'react-redux'; |  | ||||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||||
| import { defineMessages, injectIntl } from 'react-intl'; | import { defineMessages, injectIntl } from 'react-intl'; | ||||||
| import { IconButton } from 'mastodon/components/icon_button'; | import { IconButton } from 'mastodon/components/icon_button'; | ||||||
|  | @ -21,15 +20,12 @@ const messages = defineMessages({ | ||||||
|   next: { id: 'lightbox.next', defaultMessage: 'Next' }, |   next: { id: 'lightbox.next', defaultMessage: 'Next' }, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const mapStateToProps = (state, { statusId }) => ({ |  | ||||||
|   language: state.getIn(['statuses', statusId, 'language']), |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| class MediaModal extends ImmutablePureComponent { | class MediaModal extends ImmutablePureComponent { | ||||||
| 
 | 
 | ||||||
|   static propTypes = { |   static propTypes = { | ||||||
|     media: ImmutablePropTypes.list.isRequired, |     media: ImmutablePropTypes.list.isRequired, | ||||||
|     statusId: PropTypes.string, |     statusId: PropTypes.string, | ||||||
|  |     lang: PropTypes.string, | ||||||
|     index: PropTypes.number.isRequired, |     index: PropTypes.number.isRequired, | ||||||
|     onClose: PropTypes.func.isRequired, |     onClose: PropTypes.func.isRequired, | ||||||
|     intl: PropTypes.object.isRequired, |     intl: PropTypes.object.isRequired, | ||||||
|  | @ -133,7 +129,7 @@ class MediaModal extends ImmutablePureComponent { | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   render () { |   render () { | ||||||
|     const { media, language, statusId, intl, onClose } = this.props; |     const { media, statusId, lang, intl, onClose } = this.props; | ||||||
|     const { navigationHidden } = this.state; |     const { navigationHidden } = this.state; | ||||||
| 
 | 
 | ||||||
|     const index = this.getIndex(); |     const index = this.getIndex(); | ||||||
|  | @ -153,7 +149,7 @@ class MediaModal extends ImmutablePureComponent { | ||||||
|             width={width} |             width={width} | ||||||
|             height={height} |             height={height} | ||||||
|             alt={image.get('description')} |             alt={image.get('description')} | ||||||
|             lang={language} |             lang={lang} | ||||||
|             key={image.get('url')} |             key={image.get('url')} | ||||||
|             onClick={this.toggleNavigation} |             onClick={this.toggleNavigation} | ||||||
|             zoomButtonHidden={this.state.zoomButtonHidden} |             zoomButtonHidden={this.state.zoomButtonHidden} | ||||||
|  | @ -176,7 +172,7 @@ class MediaModal extends ImmutablePureComponent { | ||||||
|             onCloseVideo={onClose} |             onCloseVideo={onClose} | ||||||
|             detailed |             detailed | ||||||
|             alt={image.get('description')} |             alt={image.get('description')} | ||||||
|             lang={language} |             lang={lang} | ||||||
|             key={image.get('url')} |             key={image.get('url')} | ||||||
|           /> |           /> | ||||||
|         ); |         ); | ||||||
|  | @ -188,7 +184,7 @@ class MediaModal extends ImmutablePureComponent { | ||||||
|             height={height} |             height={height} | ||||||
|             key={image.get('url')} |             key={image.get('url')} | ||||||
|             alt={image.get('description')} |             alt={image.get('description')} | ||||||
|             lang={language} |             lang={lang} | ||||||
|             onClick={this.toggleNavigation} |             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); | ||||||
|  |  | ||||||
|  | @ -469,7 +469,7 @@ class Video extends React.PureComponent { | ||||||
|   handleOpenVideo = () => { |   handleOpenVideo = () => { | ||||||
|     this.video.pause(); |     this.video.pause(); | ||||||
| 
 | 
 | ||||||
|     this.props.onOpenVideo({ |     this.props.onOpenVideo(this.props.lang, { | ||||||
|       startTime: this.video.currentTime, |       startTime: this.video.currentTime, | ||||||
|       autoPlay: !this.state.paused, |       autoPlay: !this.state.paused, | ||||||
|       defaultVolume: this.state.volume, |       defaultVolume: this.state.volume, | ||||||
|  |  | ||||||
|  | @ -1,8 +1,8 @@ | ||||||
| - if status.ordered_media_attachments.first.video? | - if status.ordered_media_attachments.first.video? | ||||||
|   - video = status.ordered_media_attachments.first |   - 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? | - elsif status.ordered_media_attachments.first.audio? | ||||||
|   - audio = status.ordered_media_attachments.first |   - 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 | - 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 } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue