diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js index cf6f45b34aa..b823f966fca 100644 --- a/app/javascript/flavours/glitch/features/composer/index.js +++ b/app/javascript/flavours/glitch/features/composer/index.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { defineMessages } from 'react-intl'; const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\S+)/i; @@ -49,6 +50,13 @@ import { assignHandlers } from 'flavours/glitch/util/react_helpers'; import { wrap } from 'flavours/glitch/util/redux_helpers'; import { privacyPreference } from 'flavours/glitch/util/privacy_preference'; +const messages = defineMessages({ + missingDescriptionMessage: { id: 'confirmations.missing_media_description.message', + defaultMessage: 'At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.' }, + missingDescriptionConfirm: { id: 'confirmations.missing_media_description.confirm', + defaultMessage: 'Send anyway' }, +}); + // State mapping. function mapStateToProps (state) { const spoilersAlwaysOn = state.getIn(['local_settings', 'always_show_spoilers_field']); @@ -93,11 +101,12 @@ function mapStateToProps (state) { text: state.getIn(['compose', 'text']), anyMedia: state.getIn(['compose', 'media_attachments']).size > 0, spoilersAlwaysOn: spoilersAlwaysOn, + mediaDescriptionConfirmation: state.getIn(['local_settings', 'confirm_missing_media_description']), }; }; // Dispatch mapping. -const mapDispatchToProps = (dispatch) => ({ +const mapDispatchToProps = (dispatch, { intl }) => ({ onCancelReply() { dispatch(cancelReplyCompose()); }, @@ -149,6 +158,13 @@ const mapDispatchToProps = (dispatch) => ({ onSelectSuggestion(position, token, suggestion) { dispatch(selectComposeSuggestion(position, token, suggestion)); }, + onMediaDescriptionConfirm() { + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.missingDescriptionMessage), + confirm: intl.formatMessage(messages.missingDescriptionConfirm), + onConfirm: () => dispatch(submitCompose()), + })); + }, onSubmit() { dispatch(submitCompose()); }, @@ -212,8 +228,11 @@ const handlers = { onSubmit, isSubmitting, isUploading, + media, anyMedia, text, + mediaDescriptionConfirmation, + onMediaDescriptionConfirm, } = this.props; // If something changes inside the textarea, then we update the @@ -227,8 +246,15 @@ const handlers = { return; } - // Submits the status. - if (onSubmit) { + // Submit unless there are media with missing descriptions + if (mediaDescriptionConfirmation && onMediaDescriptionConfirm && media && media.some(item => !item.get('description'))) { + const firstWithoutDescription = media.findIndex(item => !item.get('description')); + const inputs = document.querySelectorAll('.composer--upload_form--item input'); + if (inputs.length == media.size && firstWithoutDescription !== -1) { + inputs[firstWithoutDescription].focus(); + } + onMediaDescriptionConfirm(); + } else if (onSubmit) { onSubmit(); } }, @@ -495,6 +521,9 @@ Composer.propTypes = { suggestionToken: PropTypes.string, suggestions: ImmutablePropTypes.list, text: PropTypes.string, + anyMedia: PropTypes.bool, + spoilersAlwaysOn: PropTypes.bool, + mediaDescriptionConfirmation: PropTypes.bool, // Dispatch props. onCancelReply: PropTypes.func, @@ -517,8 +546,7 @@ Composer.propTypes = { onUndoUpload: PropTypes.func, onUnmount: PropTypes.func, onUpload: PropTypes.func, - anyMedia: PropTypes.bool, - spoilersAlwaysOn: PropTypes.bool, + onMediaDescriptionConfirm: PropTypes.func, }; // Connecting and export. diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js index ad5c1197948..1e61c67c0bb 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -83,6 +83,14 @@ export default class LocalSettingsPage extends React.PureComponent { > + + +