about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch/features/composer/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours/glitch/features/composer/index.js')
-rw-r--r--app/javascript/flavours/glitch/features/composer/index.js49
1 files changed, 43 insertions, 6 deletions
diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js
index cf6f45b34..bc409f0a3 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());
   },
@@ -206,14 +222,17 @@ const handlers = {
 
   //  Submits the status.
   handleSubmit () {
-    const { textarea: { value } } = this;
+    const { textarea: { value }, uploadForm } = this;
     const {
       onChangeText,
       onSubmit,
       isSubmitting,
       isUploading,
+      media,
       anyMedia,
       text,
+      mediaDescriptionConfirmation,
+      onMediaDescriptionConfirm,
     } = this.props;
 
     //  If something changes inside the textarea, then we update the
@@ -227,12 +246,26 @@ 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'));
+      if (uploadForm) {
+        const inputs = uploadForm.querySelectorAll('.composer--upload_form--item input');
+        if (inputs.length == media.size && firstWithoutDescription !== -1) {
+          inputs[firstWithoutDescription].focus();
+        }
+      }
+      onMediaDescriptionConfirm();
+    } else if (onSubmit) {
       onSubmit();
     }
   },
 
+  //  Sets a reference to the upload form.
+  handleRefUploadForm (uploadFormComponent) {
+    this.uploadForm = uploadFormComponent;
+  },
+
   //  Sets a reference to the textarea.
   handleRefTextarea (textareaComponent) {
     if (textareaComponent) {
@@ -339,6 +372,7 @@ class Composer extends React.Component {
       handleSecondarySubmit,
       handleSelect,
       handleSubmit,
+      handleRefUploadForm,
       handleRefTextarea,
       handleRefSpoilerText,
     } = this.handlers;
@@ -429,6 +463,7 @@ class Composer extends React.Component {
             onRemove={onUndoUpload}
             progress={progress}
             uploading={isUploading}
+            handleRef={handleRefUploadForm}
           />
         ) : null}
         <ComposerOptions
@@ -495,6 +530,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 +555,7 @@ Composer.propTypes = {
   onUndoUpload: PropTypes.func,
   onUnmount: PropTypes.func,
   onUpload: PropTypes.func,
-  anyMedia: PropTypes.bool,
-  spoilersAlwaysOn: PropTypes.bool,
+  onMediaDescriptionConfirm: PropTypes.func,
 };
 
 //  Connecting and export.