From 96f31716f94d0e7691b85ca90e7ea977ca3adb4d Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 7 Jun 2019 00:17:49 +0300
Subject: slot-based emoji input/autocomplete component

---
 src/components/emoji-input/emoji-input.vue | 36 +++++++++---------------------
 1 file changed, 10 insertions(+), 26 deletions(-)

(limited to 'src/components/emoji-input/emoji-input.vue')

diff --git a/src/components/emoji-input/emoji-input.vue b/src/components/emoji-input/emoji-input.vue
index 338b77cd..eec33d1a 100644
--- a/src/components/emoji-input/emoji-input.vue
+++ b/src/components/emoji-input/emoji-input.vue
@@ -1,9 +1,7 @@
 <template>
   <div class="emoji-input">
-    <input
-      v-if="type !== 'textarea'"
+    <slot
       :class="classname"
-      :type="type"
       :value="value"
       :placeholder="placeholder"
       @input="onInput"
@@ -15,36 +13,22 @@
       @keydown.shift.tab="cycleBackward"
       @keydown.tab="cycleForward"
       @keydown.enter="replaceEmoji"
-    />
-    <textarea
-      v-else
-      :class="classname"
-      :value="value"
-      :placeholder="placeholder"
-      @input="onInput"
-      @click="setCaret"
-      @keyup="setCaret"
-      @keydown="onKeydown"
-      @keydown.down="cycleForward"
-      @keydown.up="cycleBackward"
-      @keydown.shift.tab="cycleBackward"
-      @keydown.tab="cycleForward"
-      @keydown.enter="replaceEmoji"
-    ></textarea>
+      >
+    </slot>
     <div class="autocomplete-panel" v-if="suggestions">
       <div class="autocomplete-panel-body">
         <div
-          v-for="(emoji, index) in suggestions"
+          v-for="(suggestion, index) in suggestions"
           :key="index"
-          @click="replace(emoji.utf || (emoji.shortcode + ' '))"
+          @click="replace(suggestion.replacement)"
           class="autocomplete-item"
-          :class="{ highlighted: emoji.highlighted }"
+          :class="{ highlighted: suggestion.highlighted }"
         >
-          <span v-if="emoji.img">
-            <img :src="emoji.img" />
+          <span v-if="suggestion.img">
+            <img :src="suggestion.img" />
           </span>
-          <span v-else>{{emoji.utf}}</span>
-          <span>{{emoji.shortcode}}</span>
+          <span v-else>{{suggestion.replacement}}</span>
+          <span>{{suggestion.shortcode}}</span>
         </div>
       </div>
     </div>
-- 
cgit v1.2.3-70-g09d2


From 8872b4802e2b0dff25eaaf884884d740ed016c98 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sat, 8 Jun 2019 16:23:58 +0300
Subject: standartized autocomplete panel suggesions format, fixed some bugs

---
 src/App.scss                                       |  4 -
 src/boot/after_store.js                            | 11 +--
 src/components/emoji-input/emoji-input.js          | 87 +++++++++++++++++-----
 src/components/emoji-input/emoji-input.vue         | 64 ++++++++--------
 src/components/emoji-input/suggestor.js            | 20 ++---
 .../post_status_form/post_status_form.js           | 37 ---------
 .../post_status_form/post_status_form.vue          | 18 +++--
 7 files changed, 129 insertions(+), 112 deletions(-)

(limited to 'src/components/emoji-input/emoji-input.vue')

diff --git a/src/App.scss b/src/App.scss
index 52a786ad..fd724979 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -809,14 +809,10 @@ nav {
 
 .autocomplete {
   &-panel {
-    position: relative;
-
     &-body {
       margin: 0 0.5em 0 0.5em;
       border-radius: $fallback--tooltipRadius;
       border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
-      position: absolute;
-      z-index: 1;
       box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
       // this doesn't match original but i don't care, making it uniform.
       box-shadow: var(--popupShadow);
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index ea5a3f58..c0faa0a2 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -154,9 +154,9 @@ const getStaticEmoji = async ({ store }) => {
       const values = await res.json()
       const emoji = Object.keys(values).map((key) => {
         return {
-          shortcode: key,
-          image_url: false,
-          'replacement': values[key]
+          displayText: key,
+          imageUrl: false,
+          replacement: values[key]
         }
       })
       store.dispatch('setInstanceOption', { name: 'emoji', value: emoji })
@@ -178,9 +178,10 @@ const getCustomEmoji = async ({ store }) => {
       const result = await res.json()
       const values = Array.isArray(result) ? Object.assign({}, ...result) : result
       const emoji = Object.keys(values).map((key) => {
+        const imageUrl = values[key].image_url
         return {
-          shortcode: key,
-          image_url: values[key].image_url || values[key],
+          displayText: key,
+          imageUrl: imageUrl ? store.state.instance.server + imageUrl : values[key],
           replacement: `:${key}: `
         }
       })
diff --git a/src/components/emoji-input/emoji-input.js b/src/components/emoji-input/emoji-input.js
index 466341c0..fb60d998 100644
--- a/src/components/emoji-input/emoji-input.js
+++ b/src/components/emoji-input/emoji-input.js
@@ -13,7 +13,19 @@ const EmojiInput = {
     return {
       input: undefined,
       highlighted: 0,
-      caret: 0
+      caret: 0,
+      focused: false,
+      popupOptions: {
+        placement: 'bottom-start',
+        trigger: 'hover',
+        // See: https://github.com/RobinCK/vue-popper/issues/63
+        'delay-on-mouse-over': 9999999,
+        'delay-on-mouse-out': 9999999,
+        modifiers: {
+          arrow: { enabled: true },
+          offset: { offset: '0, 5px' }
+        }
+      }
     }
   },
   computed: {
@@ -24,13 +36,17 @@ const EmojiInput = {
       if (matchedSuggestions.length <= 0) {
         return false
       }
-      return take(matchedSuggestions, 5).map(({shortcode, image_url, replacement}, index) => ({
-        shortcode,
-        replacement,
-        // eslint-disable-next-line camelcase
-        img: !image_url ? '' : this.$store.state.instance.server + image_url,
-        highlighted: index === this.highlighted
-      }))
+      return take(matchedSuggestions, 5)
+        .map(({ displayText, imageUrl, replacement }, index) => ({
+          displayText,
+          replacement,
+          // eslint-disable-next-line camelcase
+          img: imageUrl || '',
+          highlighted: index === this.highlighted
+        }))
+    },
+    showPopup () {
+      return this.focused && this.suggestions && this.suggestions.length > 0
     },
     textAtCaret () {
       return (this.wordAtCaret || {}).word || ''
@@ -40,25 +56,29 @@ const EmojiInput = {
         const word = Completion.wordAtPosition(this.value, this.caret - 1) || {}
         return word
       }
-    },
+    }
   },
   mounted () {
     const slots = this.$slots.default
-    if (slots.length === 0) return
+    if (!slots || slots.length === 0) return
     const input = slots.find(slot => ['input', 'textarea'].includes(slot.tag))
     if (!input) return
     this.input = input
-    input.elm.addEventListener('keyup', this.setCaret)
-    input.elm.addEventListener('paste', this.setCaret)
-    input.elm.addEventListener('focus', this.setCaret)
+    this.resize()
+    input.elm.addEventListener('blur', this.onBlur)
+    input.elm.addEventListener('focus', this.onFocus)
+    input.elm.addEventListener('paste', this.onPaste)
+    input.elm.addEventListener('keyup', this.onKeyUp)
     input.elm.addEventListener('keydown', this.onKeyDown)
   },
   unmounted () {
-    if (this.input) {
-      this.input.elm.removeEventListener('keyup', this.setCaret)
-      this.input.elm.removeEventListener('paste', this.setCaret)
-      this.input.elm.removeEventListener('focus', this.setCaret)
-      this.input.elm.removeEventListener('keydown', this.onKeyDown)
+    const { input } = this
+    if (input) {
+      input.elm.removeEventListener('blur', this.onBlur)
+      input.elm.removeEventListener('focus', this.onFocus)
+      input.elm.removeEventListener('paste', this.onPaste)
+      input.elm.removeEventListener('keyup', this.onKeyUp)
+      input.elm.removeEventListener('keydown', this.onKeyDown)
     }
   },
   methods: {
@@ -101,26 +121,49 @@ const EmojiInput = {
         this.highlighted = 0
       }
     },
+    onBlur (e) {
+      this.focused = false
+      this.setCaret(e)
+      this.resize(e)
+    },
+    onFocus (e) {
+      this.focused = true
+      this.setCaret(e)
+      this.resize(e)
+    },
+    onKeyUp (e) {
+      this.setCaret(e)
+      this.resize(e)
+    },
+    onPaste (e) {
+      this.setCaret(e)
+      this.resize(e)
+    },
     onKeyDown (e) {
       this.setCaret(e)
-      e.stopPropagation()
+      this.resize(e)
 
       const { ctrlKey, shiftKey, key } = e
       if (key === 'Tab') {
         if (shiftKey) {
           this.cycleBackward()
+          e.preventDefault()
         } else {
           this.cycleForward()
+          e.preventDefault()
         }
       }
       if (key === 'ArrowUp') {
         this.cycleBackward()
+        e.preventDefault()
       } else if (key === 'ArrowDown') {
         this.cycleForward()
+        e.preventDefault()
       }
       if (key === 'Enter') {
         if (!ctrlKey) {
           this.replaceText()
+          e.preventDefault()
         }
       }
     },
@@ -129,6 +172,12 @@ const EmojiInput = {
     },
     setCaret ({ target: { selectionStart, value } }) {
       this.caret = selectionStart
+    },
+    resize () {
+      const { panel } = this.$refs
+      if (!panel) return
+      const { offsetHeight, offsetTop } = this.input.elm
+      this.$refs.panel.style.top = (offsetTop + offsetHeight) + 'px'
     }
   }
 }
diff --git a/src/components/emoji-input/emoji-input.vue b/src/components/emoji-input/emoji-input.vue
index eec33d1a..0ca74322 100644
--- a/src/components/emoji-input/emoji-input.vue
+++ b/src/components/emoji-input/emoji-input.vue
@@ -1,38 +1,25 @@
 <template>
-  <div class="emoji-input">
-    <slot
-      :class="classname"
-      :value="value"
-      :placeholder="placeholder"
-      @input="onInput"
-      @click="setCaret"
-      @keyup="setCaret"
-      @keydown="onKeydown"
-      @keydown.down="cycleForward"
-      @keydown.up="cycleBackward"
-      @keydown.shift.tab="cycleBackward"
-      @keydown.tab="cycleForward"
-      @keydown.enter="replaceEmoji"
-      >
-    </slot>
-    <div class="autocomplete-panel" v-if="suggestions">
-      <div class="autocomplete-panel-body">
-        <div
-          v-for="(suggestion, index) in suggestions"
-          :key="index"
-          @click="replace(suggestion.replacement)"
-          class="autocomplete-item"
-          :class="{ highlighted: suggestion.highlighted }"
+<div class="emoji-input">
+  <slot></slot>
+  <div ref="panel" class="autocomplete-panel" :class="{ hide: suggestions}">
+    <div class="autocomplete-panel-body">
+      <div
+        v-for="(suggestion, index) in suggestions"
+        :key="index"
+        @click.stop.prevent="replace(suggestion.replacement)"
+        class="autocomplete-item"
+        :class="{ highlighted: suggestion.highlighted }"
         >
-          <span v-if="suggestion.img">
-            <img :src="suggestion.img" />
-          </span>
-          <span v-else>{{suggestion.replacement}}</span>
-          <span>{{suggestion.shortcode}}</span>
+        <span v-if="suggestion.img">
+          <img :src="suggestion.img" />
+        </span>
+        <span v-else>{{suggestion.replacement}}</span>
+        <span>{{suggestion.displayText}}</span>
+        <span>{{suggestion.detailText}}</span>
         </div>
-      </div>
     </div>
   </div>
+</div>
 </template>
 
 <script src="./emoji-input.js"></script>
@@ -41,8 +28,21 @@
 @import '../../_variables.scss';
 
 .emoji-input {
-  .form-control {
-    width: 100%;
+  display: flex;
+  flex-direction: column;
+
+  &.hide {
+    display: none
+  }
+
+  .autocomplete-panel {
+    position: absolute;
+    z-index: 9;
+    margin-top: 2px;
+  }
+
+  input, textarea {
+    flex: 1;
   }
 }
 </style>
diff --git a/src/components/emoji-input/suggestor.js b/src/components/emoji-input/suggestor.js
index f1a0d0da..54fd7f29 100644
--- a/src/components/emoji-input/suggestor.js
+++ b/src/components/emoji-input/suggestor.js
@@ -15,24 +15,26 @@ export default function suggest (data) {
 
 function suggestEmoji (emojis) {
   return input => {
-    const shortcode = input.toLowerCase().substr(1)
-    console.log(shortcode)
-    return emojis.filter(emoji => emoji.shortcode.toLowerCase().startsWith(shortcode))
+    const noPrefix = input.toLowerCase().substr(1)
+    return emojis
+      .filter(({ displayText }) => displayText.toLowerCase().startsWith(noPrefix))
   }
 }
 
 function suggestUsers (users) {
   return input => {
-    const shortcode = input.toLowerCase().substr(1)
+    const noPrefix = input.toLowerCase().substr(1)
     return users.filter(
       user =>
-        user.screen_name.toLowerCase().startsWith('@' + shortcode) ||
-        user.name.toLowerCase().startsWith(shortcode)
+        user.screen_name.toLowerCase().startsWith(noPrefix) ||
+        user.name.toLowerCase().startsWith(noPrefix)
+      /* eslint-disable camelcase */
     ).map(({ screen_name, name, profile_image_url_original }) => ({
-      shortcode: screen_name,
-      detail: name,
-      image_url: profile_image_url_original,
+      displayText: screen_name,
+      detailText: name,
+      imageUrl: profile_image_url_original,
       replacement: '@' + screen_name
     }))
+    /* eslint-enable camelcase */
   }
 }
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 1516dd43..008b821a 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -83,43 +83,6 @@ const PostStatusForm = {
     }
   },
   computed: {
-    candidates () {
-      const firstchar = this.textAtCaret.charAt(0)
-      if (firstchar === '@') {
-        const query = this.textAtCaret.slice(1).toUpperCase()
-        const matchedUsers = filter(this.users, (user) => {
-          return user.screen_name.toUpperCase().startsWith(query) ||
-            user.name && user.name.toUpperCase().startsWith(query)
-        })
-        if (matchedUsers.length <= 0) {
-          return false
-        }
-        // eslint-disable-next-line camelcase
-        return map(take(matchedUsers, 5), ({screen_name, name, profile_image_url_original}, index) => ({
-          // eslint-disable-next-line camelcase
-          screen_name: `@${screen_name}`,
-          name: name,
-          img: profile_image_url_original,
-          highlighted: index === this.highlighted
-        }))
-      } else if (firstchar === ':') {
-        if (this.textAtCaret === ':') { return }
-        const matchedEmoji = filter(this.emoji.concat(this.customEmoji), (emoji) => emoji.shortcode.startsWith(this.textAtCaret.slice(1)))
-        if (matchedEmoji.length <= 0) {
-          return false
-        }
-        return map(take(matchedEmoji, 5), ({shortcode, image_url, utf}, index) => ({
-          screen_name: `:${shortcode}:`,
-          name: '',
-          utf: utf || '',
-          // eslint-disable-next-line camelcase
-          img: utf ? '' : this.$store.state.instance.server + image_url,
-          highlighted: index === this.highlighted
-        }))
-      } else {
-        return false
-      }
-    },
     users () {
       return this.$store.state.users.users
     },
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index 507b14bf..a8a34265 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -32,24 +32,29 @@
         <span v-else>{{ $t('post_status.direct_warning_to_all') }}</span>
       </p>
       <emoji-input
-        :suggest="emojiSuggestor" v-model="newStatus.spoilerText"
         v-if="newStatus.spoilerText || alwaysShowSubject"
+        :suggest="emojiSuggestor"
+        v-model="newStatus.spoilerText"
+        class="form-control"
         >
         <input
 
           type="text"
           :placeholder="$t('post_status.content_warning')"
           v-model="newStatus.spoilerText"
-          classname="form-control"
+          class="form-post-subject"
           />
       </emoji-input>
-      <emoji-input :suggest="emojiUserSuggestor" v-model="newStatus.status">
+      <emoji-input
+        :suggest="emojiUserSuggestor"
+        v-model="newStatus.status"
+        class="form-control"
+        >
         <textarea
           ref="textarea"
           v-model="newStatus.status"
           :placeholder="$t('post_status.default')"
           rows="1"
-          class="form-control"
           @keydown.meta.enter="postStatus(newStatus)"
           @keyup.ctrl.enter="postStatus(newStatus)"
           @drop="fileDrop"
@@ -57,6 +62,7 @@
           @input="resize"
           @paste="paste"
           :disabled="posting"
+          class="form-post-body"
         >
         </textarea>
       </emoji-input>
@@ -251,7 +257,7 @@
     min-height: 1px;
   }
 
-  form textarea.form-control {
+  .form-post-body {
     line-height:16px;
     resize: none;
     overflow: hidden;
@@ -260,7 +266,7 @@
     box-sizing: content-box;
   }
 
-  form textarea.form-control:focus {
+  .form-post-body:focus {
     min-height: 48px;
   }
 
-- 
cgit v1.2.3-70-g09d2


From 0a778160cc7842ebd4ddfe8059a3ef81526637a2 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sat, 8 Jun 2019 17:15:42 +0300
Subject: styles

---
 src/App.scss                               | 47 ----------------
 src/components/emoji-input/emoji-input.js  |  5 +-
 src/components/emoji-input/emoji-input.vue | 89 +++++++++++++++++++++++++-----
 3 files changed, 78 insertions(+), 63 deletions(-)

(limited to 'src/components/emoji-input/emoji-input.vue')

diff --git a/src/App.scss b/src/App.scss
index fd724979..e4f58e4e 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -806,50 +806,3 @@ nav {
 .btn.btn-default {
   min-height: 28px;
 }
-
-.autocomplete {
-  &-panel {
-    &-body {
-      margin: 0 0.5em 0 0.5em;
-      border-radius: $fallback--tooltipRadius;
-      border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
-      box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
-      // this doesn't match original but i don't care, making it uniform.
-      box-shadow: var(--popupShadow);
-      min-width: 75%;
-      background: $fallback--bg;
-      background: var(--bg, $fallback--bg);
-      color: $fallback--lightText;
-      color: var(--lightText, $fallback--lightText);
-    }
-  }
-
-  &-item {
-    cursor: pointer;
-    padding: 0.2em 0.4em 0.2em 0.4em;
-    border-bottom: 1px solid rgba(0, 0, 0, 0.4);
-    display: flex;
-
-    img {
-      width: 24px;
-      height: 24px;
-      object-fit: contain;
-    }
-
-    span {
-      line-height: 24px;
-      margin: 0 0.1em 0 0.2em;
-    }
-
-    small {
-      margin-left: .5em;
-      color: $fallback--faint;
-      color: var(--faint, $fallback--faint);
-    }
-
-    &.highlighted {
-      background-color: $fallback--fg;
-      background-color: var(--lightBg, $fallback--fg);
-    }
-  }
-}
diff --git a/src/components/emoji-input/emoji-input.js b/src/components/emoji-input/emoji-input.js
index fb60d998..aae11a9b 100644
--- a/src/components/emoji-input/emoji-input.js
+++ b/src/components/emoji-input/emoji-input.js
@@ -37,9 +37,8 @@ const EmojiInput = {
         return false
       }
       return take(matchedSuggestions, 5)
-        .map(({ displayText, imageUrl, replacement }, index) => ({
-          displayText,
-          replacement,
+        .map(({ imageUrl, ...rest }, index) => ({
+          ...rest,
           // eslint-disable-next-line camelcase
           img: imageUrl || '',
           highlighted: index === this.highlighted
diff --git a/src/components/emoji-input/emoji-input.vue b/src/components/emoji-input/emoji-input.vue
index 0ca74322..dec71744 100644
--- a/src/components/emoji-input/emoji-input.vue
+++ b/src/components/emoji-input/emoji-input.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="emoji-input">
   <slot></slot>
-  <div ref="panel" class="autocomplete-panel" :class="{ hide: suggestions}">
+  <div ref="panel" class="autocomplete-panel" :class="{ hide: !showPopup }">
     <div class="autocomplete-panel-body">
       <div
         v-for="(suggestion, index) in suggestions"
@@ -10,13 +10,15 @@
         class="autocomplete-item"
         :class="{ highlighted: suggestion.highlighted }"
         >
-        <span v-if="suggestion.img">
-          <img :src="suggestion.img" />
+        <span class="image">
+          <img v-if="suggestion.img":src="suggestion.img" />
+          <span v-else>{{suggestion.replacement}}</span>
         </span>
-        <span v-else>{{suggestion.replacement}}</span>
-        <span>{{suggestion.displayText}}</span>
-        <span>{{suggestion.detailText}}</span>
+        <div class="label">
+          <span class="displayText">{{suggestion.displayText}}</span>
+          <span class="detailText">{{suggestion.detailText}}</span>
         </div>
+      </div>
     </div>
   </div>
 </div>
@@ -31,16 +33,77 @@
   display: flex;
   flex-direction: column;
 
-  &.hide {
-    display: none
-  }
+  .autocomplete {
+    &-panel {
+      position: absolute;
+      z-index: 9;
+      margin-top: 2px;
+
+      &.hide {
+        display: none
+      }
+
+      &-body {
+        margin: 0 0.5em 0 0.5em;
+        border-radius: $fallback--tooltipRadius;
+        border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
+        box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
+        box-shadow: var(--popupShadow);
+        min-width: 75%;
+        background: $fallback--bg;
+        background: var(--bg, $fallback--bg);
+        color: $fallback--lightText;
+        color: var(--lightText, $fallback--lightText);
+      }
+    }
+
+    &-item {
+      display: flex;
+      cursor: pointer;
+      padding: 0.2em 0.4em;
+      border-bottom: 1px solid rgba(0, 0, 0, 0.4);
+      height: 32px;
+
+      .image {
+        width: 32px;
+        height: 32px;
+        line-height: 32px;
+        text-align: center;
+        font-size: 32px;
+
+        margin-right: 4px;
 
-  .autocomplete-panel {
-    position: absolute;
-    z-index: 9;
-    margin-top: 2px;
+        img {
+          width: 32px;
+          height: 32px;
+          object-fit: contain;
+        }
+      }
+
+      .label {
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        margin: 0 0.1em 0 0.2em;
+
+        .displayText {
+          line-height: 1.5;
+        }
+
+        .detailText {
+          font-size: 9px;
+          line-height: 9px;
+        }
+      }
+
+      &.highlighted {
+        background-color: $fallback--fg;
+        background-color: var(--lightBg, $fallback--fg);
+      }
+    }
   }
 
+
   input, textarea {
     flex: 1;
   }
-- 
cgit v1.2.3-70-g09d2


From 4d12cd617aa39248227d5bde6483eb93e89646f3 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 9 Jun 2019 21:23:56 +0300
Subject: fix textarea not resizing properly

---
 src/components/emoji-input/emoji-input.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/components/emoji-input/emoji-input.vue')

diff --git a/src/components/emoji-input/emoji-input.vue b/src/components/emoji-input/emoji-input.vue
index dec71744..77562957 100644
--- a/src/components/emoji-input/emoji-input.vue
+++ b/src/components/emoji-input/emoji-input.vue
@@ -105,7 +105,7 @@
 
 
   input, textarea {
-    flex: 1;
+    flex: 1 0 auto;
   }
 }
 </style>
-- 
cgit v1.2.3-70-g09d2


From 0535d2c14cda3b490e5904a93afb5cf6dd2b741b Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 11 Jun 2019 21:18:09 +0300
Subject: fixed some bugs i found, also cleaned up some stuff + documentation

---
 src/components/emoji-input/emoji-input.js  | 20 +++++++++++++-------
 src/components/emoji-input/emoji-input.vue |  2 +-
 src/components/emoji-input/suggestor.js    | 19 +++++++++++++++++--
 3 files changed, 31 insertions(+), 10 deletions(-)

(limited to 'src/components/emoji-input/emoji-input.vue')

diff --git a/src/components/emoji-input/emoji-input.js b/src/components/emoji-input/emoji-input.js
index 2a32b33b..c425fdf5 100644
--- a/src/components/emoji-input/emoji-input.js
+++ b/src/components/emoji-input/emoji-input.js
@@ -31,11 +31,11 @@ const EmojiInput = {
        * Suggestion is an object containing following properties:
        * displayText: string. Main display text, what actual suggestion
        *    represents (user's screen name/emoji shortcode)
-       * replacementText: string. Text that should replace the textAtCaret
+       * replacement: string. Text that should replace the textAtCaret
        * detailText: string, optional. Subtitle text, providing additional info
        *    if present (user's nickname)
        * imageUrl: string, optional. Image to display alongside with suggestion,
-       *    currently if no image is provided, replacementText will be used (for
+       *    currently if no image is provided, replacement will be used (for
        *    unicode emojis)
        *
        * TODO: make it asynchronous when adding proper server-provided user
@@ -98,22 +98,22 @@ const EmojiInput = {
     if (!input) return
     this.input = input
     this.resize()
-    input.elm.addEventListener('transitionend', this.onTransition)
     input.elm.addEventListener('blur', this.onBlur)
     input.elm.addEventListener('focus', this.onFocus)
     input.elm.addEventListener('paste', this.onPaste)
     input.elm.addEventListener('keyup', this.onKeyUp)
     input.elm.addEventListener('keydown', this.onKeyDown)
+    input.elm.addEventListener('transitionend', this.onTransition)
   },
   unmounted () {
     const { input } = this
     if (input) {
-      input.elm.removeEventListener('transitionend', this.onTransition)
       input.elm.removeEventListener('blur', this.onBlur)
       input.elm.removeEventListener('focus', this.onFocus)
       input.elm.removeEventListener('paste', this.onPaste)
       input.elm.removeEventListener('keyup', this.onKeyUp)
       input.elm.removeEventListener('keydown', this.onKeyDown)
+      input.elm.removeEventListener('transitionend', this.onTransition)
     }
   },
   methods: {
@@ -132,6 +132,8 @@ const EmojiInput = {
         this.$emit('input', newValue)
         this.caret = 0
         this.highlighted = 0
+        // Re-focus inputbox after clicking suggestion
+        this.input.elm.focus()
         e.preventDefault()
       }
     },
@@ -163,9 +165,13 @@ const EmojiInput = {
       this.resize(e)
     },
     onBlur (e) {
-      this.focused = false
-      this.setCaret(e)
-      this.resize(e)
+      // Clicking on any suggestion removes focus from autocomplete,
+      // preventing click handler ever executing.
+      setTimeout(() => {
+        this.focused = false
+        this.setCaret(e)
+        this.resize(e)
+      }, 200)
     },
     onFocus (e) {
       this.focused = true
diff --git a/src/components/emoji-input/emoji-input.vue b/src/components/emoji-input/emoji-input.vue
index 77562957..8437a495 100644
--- a/src/components/emoji-input/emoji-input.vue
+++ b/src/components/emoji-input/emoji-input.vue
@@ -6,7 +6,7 @@
       <div
         v-for="(suggestion, index) in suggestions"
         :key="index"
-        @click.stop.prevent="replace(suggestion.replacement)"
+        @click.stop.prevent="replaceText"
         class="autocomplete-item"
         :class="{ highlighted: suggestion.highlighted }"
         >
diff --git a/src/components/emoji-input/suggestor.js b/src/components/emoji-input/suggestor.js
index 40c7aa3d..eb70f299 100644
--- a/src/components/emoji-input/suggestor.js
+++ b/src/components/emoji-input/suggestor.js
@@ -1,3 +1,13 @@
+/**
+ * suggest - generates a suggestor function to be used by emoji-input
+ * data: object providing source information for specific types of suggestions:
+ * data.emoji - optional, an array of all emoji available i.e.
+ *   (state.instance.emoji + state.instance.customEmoji)
+ * data.users - optional, an array of all known users
+ *
+ * Depending on data present one or both (or none) can be present, so if field
+ * doesn't support user linking you can just provide only emoji.
+ */
 export default function suggest (data) {
   return input => {
     const firstChar = input[0]
@@ -39,7 +49,11 @@ function suggestUsers (users) {
       user =>
         user.screen_name.toLowerCase().startsWith(noPrefix) ||
         user.name.toLowerCase().startsWith(noPrefix)
-      /* eslint-disable camelcase */
+
+      /* taking only 20 results so that sorting is a bit cheaper, we display
+       * only 5 anyway. could be inaccurate, but we ideally we should query
+       * backend anyway
+       */
     ).slice(0, 20).sort((a, b) => {
       let aScore = 0
       let bScore = 0
@@ -59,11 +73,12 @@ function suggestUsers (users) {
       const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
 
       return diff + nameAlphabetically + screenNameAlphabetically
+      /* eslint-disable camelcase */
     }).map(({ screen_name, name, profile_image_url_original }) => ({
       displayText: screen_name,
       detailText: name,
       imageUrl: profile_image_url_original,
-      replacement: '@' + screen_name
+      replacement: '@' + screen_name + ' '
     }))
     /* eslint-enable camelcase */
   }
-- 
cgit v1.2.3-70-g09d2

