From 14df84d89bfc58f564697b7d72d7c66134c64697 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 8 Sep 2019 15:51:17 +0300
Subject: [PATCH] fixed some bugs, added spam mode, minor collateral fixes

---
 src/components/emoji_input/emoji_input.js     | 28 ++++++++++++----
 src/components/emoji_picker/emoji_picker.js   |  7 ++--
 src/components/emoji_picker/emoji_picker.scss | 33 +++++++++++++++----
 src/components/emoji_picker/emoji_picker.vue  | 16 +++++++--
 .../post_status_form/post_status_form.js      |  2 +-
 .../post_status_form/post_status_form.vue     |  2 +-
 src/components/status/status.vue              |  2 +-
 src/components/user_panel/user_panel.vue      |  2 +-
 src/i18n/en.json                              |  1 +
 9 files changed, 69 insertions(+), 24 deletions(-)

diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js
index 5ff27b20..b1640753 100644
--- a/src/components/emoji_input/emoji_input.js
+++ b/src/components/emoji_input/emoji_input.js
@@ -77,7 +77,9 @@ const EmojiInput = {
       caret: 0,
       focused: false,
       blurTimeout: null,
-      showPicker: false
+      showPicker: false,
+      spamMode: false,
+      disableClickOutside: false
     }
   },
   components: {
@@ -100,7 +102,7 @@ const EmojiInput = {
         }))
     },
     showSuggestions () {
-      return this.focused && this.suggestions && this.suggestions.length > 0
+      return this.focused && this.suggestions && this.suggestions.length > 0 && !this.showPicker
     },
     textAtCaret () {
       return (this.wordAtCaret || {}).word || ''
@@ -142,6 +144,13 @@ const EmojiInput = {
   methods: {
     triggerShowPicker () {
       this.showPicker = true
+      // This temporarily disables "click outside" handler
+      // since external trigger also means click originates
+      // from outside, thus preventing picker from opening
+      this.disableClickOutside = true
+      setTimeout(() => {
+        this.disableClickOutside = false
+      }, 0)
     },
     togglePicker () {
       this.showPicker = !this.showPicker
@@ -151,12 +160,13 @@ const EmojiInput = {
       this.$emit('input', newValue)
       this.caret = 0
     },
-    insert (insertion) {
+    insert ({ insertion, spamMode }) {
       const newValue = [
         this.value.substring(0, this.caret),
         insertion,
         this.value.substring(this.caret)
       ].join('')
+      this.spamMode = spamMode
       this.$emit('input', newValue)
       const position = this.caret + insertion.length
 
@@ -191,7 +201,7 @@ const EmojiInput = {
     },
     cycleBackward (e) {
       const len = this.suggestions.length || 0
-      if (len > 0) {
+      if (len > 1) {
         this.highlighted -= 1
         if (this.highlighted < 0) {
           this.highlighted = this.suggestions.length - 1
@@ -203,7 +213,7 @@ const EmojiInput = {
     },
     cycleForward (e) {
       const len = this.suggestions.length || 0
-      if (len > 0) {
+      if (len > 1) {
         this.highlighted += 1
         if (this.highlighted >= len) {
           this.highlighted = 0
@@ -234,7 +244,10 @@ const EmojiInput = {
         this.blurTimeout = null
       }
 
-      this.showPicker = false
+      console.log(this.spamMode)
+      if (!this.spamMode) {
+        this.showPicker = false
+      }
       this.focused = true
       this.setCaret(e)
       this.resize()
@@ -280,7 +293,8 @@ const EmojiInput = {
       this.resize()
       this.$emit('input', e.target.value)
     },
-    onClickOutside () {
+    onClickOutside (e) {
+      if (this.disableClickOutside) return
       this.showPicker = false
     },
     onStickerUploaded (e) {
diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
index 0a64f759..bce5026e 100644
--- a/src/components/emoji_picker/emoji_picker.js
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -13,9 +13,11 @@ const EmojiPicker = {
   },
   data () {
     return {
+      labelKey: String(Math.random() * 100000),
       keyword: '',
       activeGroup: 'custom',
-      showingStickers: false
+      showingStickers: false,
+      spamMode: false
     }
   },
   components: {
@@ -24,8 +26,7 @@ const EmojiPicker = {
   methods: {
     onEmoji (emoji) {
       const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement
-      this.$emit('emoji', ` ${value} `)
-      this.open = false
+      this.$emit('emoji', { insertion: ` ${value} `, spamMode: this.spamMode })
     },
     highlight (key) {
       const ref = this.$refs['group-' + key]
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
index 6c13e82b..079eb362 100644
--- a/src/components/emoji_picker/emoji_picker.scss
+++ b/src/components/emoji_picker/emoji_picker.scss
@@ -10,29 +10,48 @@
   margin: 0 !important;
   z-index: 1;
 
-  .panel-body {
+  .spam-mode {
+    padding: 7px;
+    line-height: normal;
+  }
+  .spam-mode-label {
+    padding: 7px;
+  }
+
+  .heading {
+    display: flex;
+    height: 32px;
+    padding: 10px 7px 5px;
+  }
+
+  .content {
     display: flex;
     flex-direction: column;
     flex: 1 1 0;
     min-height: 0px;
   }
 
+  .emoji-tabs {
+    flex-grow: 1;
+  }
+
   .additional-tabs {
     border-left: 1px solid;
     border-left-color: $fallback--icon;
     border-left-color: var(--icon, $fallback--icon);
-    padding-left: 5px;
+    padding-left: 7px;
     flex: 0 0 0;
   }
 
-  .emoji-tabs {
-    flex: 1 1 0;
-  }
-
   .additional-tabs,
   .emoji-tabs {
+    display: block;
+    min-width: 0;
+    flex-basis: auto;
+    flex-shrink: 1;
+
     &-item {
-      padding: 0 5px;
+      padding: 0 7px;
       cursor: pointer;
       font-size: 24px;
 
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index 12b1569e..901520aa 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -1,6 +1,6 @@
 <template>
-  <div class="emoji-picker panel panel-default">
-    <div class="panel-heading">
+  <div class="emoji-picker panel panel-default panel-body">
+    <div class="heading">
       <span class="emoji-tabs">
         <span
           v-for="group in emojis"
@@ -30,7 +30,7 @@
         </span>
       </span>
     </div>
-    <div class="panel-body">
+    <div class="content">
       <div
         class="emoji-content"
         :class="{hidden: showingStickers}"
@@ -74,6 +74,16 @@
             </span>
           </div>
         </div>
+        <div
+          class="spam-mode"
+          >
+          <input
+            :id="labelKey + 'spam-mode'"
+            v-model="spamMode"
+            type="checkbox"
+            >
+          <label class="spam-mode-label" :for="labelKey + 'spam-mode'">{{ $t('emoji.spam') }}</label>
+        </div>
       </div>
       <div
         v-if="showingStickers"
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 1359e75a..d468be76 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -282,7 +282,7 @@ const PostStatusForm = {
         target.style.height = null
       }
     },
-    showEmoji () {
+    showEmojiPicker () {
       this.$refs['textarea'].focus()
       this.$refs['emoji-input'].triggerShowPicker()
     },
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index ad2c2218..026cb8fe 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -170,7 +170,7 @@
             <i
               :title="$t('emoji.add_emoji')"
               class="icon-smile btn btn-default"
-              @click.stop.prevent="showEmoji"
+              @click="showEmojiPicker"
             />
           </div>
           <div
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 64218f6e..771615f3 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -413,7 +413,7 @@
         v-if="replying"
         class="container"
       >
-        <post-status-form
+        <PostStatusForm
           class="reply-body"
           :reply-to="status.id"
           :attentions="status.attentions"
diff --git a/src/components/user_panel/user_panel.vue b/src/components/user_panel/user_panel.vue
index c92630e3..5cdb2914 100644
--- a/src/components/user_panel/user_panel.vue
+++ b/src/components/user_panel/user_panel.vue
@@ -11,7 +11,7 @@
         rounded="top"
       />
       <div class="panel-footer">
-        <post-status-form v-if="user" />
+        <PostStatusForm v-if="user" />
       </div>
     </div>
     <auth-form
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 12920b92..e74469ed 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -109,6 +109,7 @@
   "emoji": {
     "stickers": "Stickers",
     "emoji": "Emoji",
+    "spam": "Keep open after adding emoji",
     "search_emoji": "Search for an emoji",
     "add_emoji": "Insert emoji",
     "custom": "Custom emoji",