about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch/features/composer
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours/glitch/features/composer')
-rw-r--r--app/javascript/flavours/glitch/features/composer/index.js8
-rw-r--r--app/javascript/flavours/glitch/features/composer/options/index.js16
-rw-r--r--app/javascript/flavours/glitch/features/composer/textarea/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js68
4 files changed, 53 insertions, 41 deletions
diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js
index f312e9d59..cf6f45b34 100644
--- a/app/javascript/flavours/glitch/features/composer/index.js
+++ b/app/javascript/flavours/glitch/features/composer/index.js
@@ -51,6 +51,7 @@ import { privacyPreference } from 'flavours/glitch/util/privacy_preference';
 
 //  State mapping.
 function mapStateToProps (state) {
+  const spoilersAlwaysOn = state.getIn(['local_settings', 'always_show_spoilers_field']);
   const inReplyTo = state.getIn(['compose', 'in_reply_to']);
   const replyPrivacy = inReplyTo ? state.getIn(['statuses', inReplyTo, 'visibility']) : null;
   const sideArmBasePrivacy = state.getIn(['local_settings', 'side_arm']);
@@ -85,12 +86,13 @@ function mapStateToProps (state) {
     sideArm: sideArmPrivacy,
     sensitive: state.getIn(['compose', 'sensitive']),
     showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
-    spoiler: state.getIn(['compose', 'spoiler']),
+    spoiler: spoilersAlwaysOn || state.getIn(['compose', 'spoiler']),
     spoilerText: state.getIn(['compose', 'spoiler_text']),
     suggestionToken: state.getIn(['compose', 'suggestion_token']),
     suggestions: state.getIn(['compose', 'suggestions']),
     text: state.getIn(['compose', 'text']),
     anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
+    spoilersAlwaysOn: spoilersAlwaysOn,
   };
 };
 
@@ -376,6 +378,7 @@ class Composer extends React.Component {
       spoilerText,
       suggestions,
       text,
+      spoilersAlwaysOn,
     } = this.props;
 
     let disabledButton = isSubmitting || isUploading || (!!text.length && !text.trim().length && !anyMedia);
@@ -443,7 +446,7 @@ class Composer extends React.Component {
           onDoodleOpen={onOpenDoodleModal}
           onModalClose={onCloseModal}
           onModalOpen={onOpenActionsModal}
-          onToggleSpoiler={onChangeSpoilerness}
+          onToggleSpoiler={spoilersAlwaysOn ? null : onChangeSpoilerness}
           onUpload={onUpload}
           privacy={privacy}
           resetFileKey={resetFileKey}
@@ -515,6 +518,7 @@ Composer.propTypes = {
   onUnmount: PropTypes.func,
   onUpload: PropTypes.func,
   anyMedia: PropTypes.bool,
+  spoilersAlwaysOn: PropTypes.bool,
 };
 
 //  Connecting and export.
diff --git a/app/javascript/flavours/glitch/features/composer/options/index.js b/app/javascript/flavours/glitch/features/composer/options/index.js
index c129622bc..05cbe24c9 100644
--- a/app/javascript/flavours/glitch/features/composer/options/index.js
+++ b/app/javascript/flavours/glitch/features/composer/options/index.js
@@ -285,13 +285,15 @@ export default class ComposerOptions extends React.PureComponent {
           title={intl.formatMessage(messages.change_privacy)}
           value={privacy}
         />
-        <TextIconButton
-          active={spoiler}
-          ariaControls='glitch.composer.spoiler.input'
-          label='CW'
-          onClick={onToggleSpoiler}
-          title={intl.formatMessage(messages.spoiler)}
-        />
+        {onToggleSpoiler && (
+          <TextIconButton
+            active={spoiler}
+            ariaControls='glitch.composer.spoiler.input'
+            label='CW'
+            onClick={onToggleSpoiler}
+            title={intl.formatMessage(messages.spoiler)}
+          />
+        )}
         <Dropdown
           active={advancedOptions && advancedOptions.some(value => !!value)}
           disabled={disabled}
diff --git a/app/javascript/flavours/glitch/features/composer/textarea/index.js b/app/javascript/flavours/glitch/features/composer/textarea/index.js
index 51d44a83b..50e46fc78 100644
--- a/app/javascript/flavours/glitch/features/composer/textarea/index.js
+++ b/app/javascript/flavours/glitch/features/composer/textarea/index.js
@@ -58,7 +58,7 @@ const handlers = {
     const right = value.slice(selectionStart).search(/[\s\u200B]/);
     const token = function () {
       switch (true) {
-      case left < 0 || !/[@:]/.test(value[left]):
+      case left < 0 || !/[@:#]/.test(value[left]):
         return null;
       case right < 0:
         return value.slice(left);
diff --git a/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js b/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js
index f55640bcf..331692398 100644
--- a/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js
+++ b/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js
@@ -57,6 +57,42 @@ export default class ComposerTextareaSuggestionsItem extends React.Component {
     } = this.props;
     const computedClass = classNames('composer--textarea--suggestions--item', { selected });
 
+    //  If the suggestion is an object, then we render an emoji.
+    //  Otherwise, we render a hashtag if it starts with #, or an account.
+    let inner;
+    if (typeof suggestion === 'object') {
+      let url;
+      if (suggestion.custom) {
+        url = suggestion.imageUrl;
+      } else {
+        const mapping = unicodeMapping[suggestion.native] || unicodeMapping[suggestion.native.replace(/\uFE0F$/, '')];
+        if (mapping) {
+          url = `${assetHost}/emoji/${mapping.filename}.svg`;
+        }
+      }
+      if (url) {
+        inner = (
+          <div className='emoji'>
+            <img
+              alt={suggestion.native || suggestion.colons}
+              className='emojione'
+              src={url}
+            />
+            {suggestion.colons}
+          </div>
+        );
+      }
+    } else if (suggestion[0] === '#') {
+      inner = suggestion;
+    } else {
+      inner = (
+        <AccountContainer
+          id={suggestion}
+          small
+        />
+      );
+    }
+
     //  The result.
     return (
       <div
@@ -66,37 +102,7 @@ export default class ComposerTextareaSuggestionsItem extends React.Component {
         role='button'
         tabIndex='0'
       >
-        { //  If the suggestion is an object, then we render an emoji.
-          //  Otherwise, we render an account.
-          typeof suggestion === 'object' ? function () {
-            const url = function () {
-              if (suggestion.custom) {
-                return suggestion.imageUrl;
-              } else {
-                const mapping = unicodeMapping[suggestion.native] || unicodeMapping[suggestion.native.replace(/\uFE0F$/, '')];
-                if (!mapping) {
-                  return null;
-                }
-                return `${assetHost}/emoji/${mapping.filename}.svg`;
-              }
-            }();
-            return url ? (
-              <div className='emoji'>
-                <img
-                  alt={suggestion.native || suggestion.colons}
-                  className='emojione'
-                  src={url}
-                />
-                {suggestion.colons}
-              </div>
-            ) : null;
-          }() : (
-            <AccountContainer
-              id={suggestion}
-              small
-            />
-          )
-        }
+        { inner }
       </div>
     );
   }