Add confirmation dialog when posting media without description

Fixes #211
lolsob-rspec
Thibaut Girka 2018-08-29 15:26:24 +02:00 committed by ThibG
parent 08c26ab391
commit fa5f416270
3 changed files with 42 additions and 5 deletions

View File

@ -2,6 +2,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages } from 'react-intl';
const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\S+)/i; 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 { wrap } from 'flavours/glitch/util/redux_helpers';
import { privacyPreference } from 'flavours/glitch/util/privacy_preference'; 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. // State mapping.
function mapStateToProps (state) { function mapStateToProps (state) {
const spoilersAlwaysOn = state.getIn(['local_settings', 'always_show_spoilers_field']); const spoilersAlwaysOn = state.getIn(['local_settings', 'always_show_spoilers_field']);
@ -93,11 +101,12 @@ function mapStateToProps (state) {
text: state.getIn(['compose', 'text']), text: state.getIn(['compose', 'text']),
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0, anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
spoilersAlwaysOn: spoilersAlwaysOn, spoilersAlwaysOn: spoilersAlwaysOn,
mediaDescriptionConfirmation: state.getIn(['local_settings', 'confirm_missing_media_description']),
}; };
}; };
// Dispatch mapping. // Dispatch mapping.
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch, { intl }) => ({
onCancelReply() { onCancelReply() {
dispatch(cancelReplyCompose()); dispatch(cancelReplyCompose());
}, },
@ -149,6 +158,13 @@ const mapDispatchToProps = (dispatch) => ({
onSelectSuggestion(position, token, suggestion) { onSelectSuggestion(position, token, suggestion) {
dispatch(selectComposeSuggestion(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() { onSubmit() {
dispatch(submitCompose()); dispatch(submitCompose());
}, },
@ -212,8 +228,11 @@ const handlers = {
onSubmit, onSubmit,
isSubmitting, isSubmitting,
isUploading, isUploading,
media,
anyMedia, anyMedia,
text, text,
mediaDescriptionConfirmation,
onMediaDescriptionConfirm,
} = this.props; } = this.props;
// If something changes inside the textarea, then we update the // If something changes inside the textarea, then we update the
@ -227,8 +246,15 @@ const handlers = {
return; return;
} }
// Submits the status. // Submit unless there are media with missing descriptions
if (onSubmit) { 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(); onSubmit();
} }
}, },
@ -495,6 +521,9 @@ Composer.propTypes = {
suggestionToken: PropTypes.string, suggestionToken: PropTypes.string,
suggestions: ImmutablePropTypes.list, suggestions: ImmutablePropTypes.list,
text: PropTypes.string, text: PropTypes.string,
anyMedia: PropTypes.bool,
spoilersAlwaysOn: PropTypes.bool,
mediaDescriptionConfirmation: PropTypes.bool,
// Dispatch props. // Dispatch props.
onCancelReply: PropTypes.func, onCancelReply: PropTypes.func,
@ -517,8 +546,7 @@ Composer.propTypes = {
onUndoUpload: PropTypes.func, onUndoUpload: PropTypes.func,
onUnmount: PropTypes.func, onUnmount: PropTypes.func,
onUpload: PropTypes.func, onUpload: PropTypes.func,
anyMedia: PropTypes.bool, onMediaDescriptionConfirm: PropTypes.func,
spoilersAlwaysOn: PropTypes.bool,
}; };
// Connecting and export. // Connecting and export.

View File

@ -83,6 +83,14 @@ export default class LocalSettingsPage extends React.PureComponent {
> >
<FormattedMessage id='settings.always_show_spoilers_field' defaultMessage='Always enable the Content Warning field' /> <FormattedMessage id='settings.always_show_spoilers_field' defaultMessage='Always enable the Content Warning field' />
</LocalSettingsPageItem> </LocalSettingsPageItem>
<LocalSettingsPageItem
settings={settings}
item={['confirm_missing_media_description']}
id='mastodon-settings--confirm_missing_media_description'
onChange={onChange}
>
<FormattedMessage id='settings.confirm_missing_media_description' defaultMessage='Show confirmation dialog before sending toots lacking media descriptions' />
</LocalSettingsPageItem>
<LocalSettingsPageItem <LocalSettingsPageItem
settings={settings} settings={settings}
item={['side_arm']} item={['side_arm']}

View File

@ -13,6 +13,7 @@ const initialState = ImmutableMap({
side_arm_reply_mode : 'keep', side_arm_reply_mode : 'keep',
show_reply_count : false, show_reply_count : false,
always_show_spoilers_field: false, always_show_spoilers_field: false,
confirm_missing_media_description: false,
collapsed : ImmutableMap({ collapsed : ImmutableMap({
enabled : true, enabled : true,
auto : ImmutableMap({ auto : ImmutableMap({