From 636dbdaba8375cb991368620419e2997df0f57a9 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 13 Jun 2021 22:22:59 +0300
Subject: [PATCH] more fixes

---
 src/components/rich_content/rich_content.jsx  | 19 ++--
 src/components/status_body/status_body.vue    |  2 +-
 .../specs/components/rich_content.spec.js     | 99 +++++++++++++++++++
 3 files changed, 113 insertions(+), 7 deletions(-)

diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx
index 328e9201..ffb36f50 100644
--- a/src/components/rich_content/rich_content.jsx
+++ b/src/components/rich_content/rich_content.jsx
@@ -140,7 +140,7 @@ export default Vue.component('RichContent', {
         switch (Tag) {
           case 'span': // replace images with StillImage
             if (attrs['class'] && attrs['class'].includes('lastMentions')) {
-              if (firstMentions.length > 1) {
+              if (firstMentions.length > 1 && lastMentions.length > 1) {
                 break
               } else {
                 return ''
@@ -249,7 +249,9 @@ export const preProcessPerLine = (html, greentext, handleLinks) => {
   const greentextHandle = new Set(['p', 'div'])
 
   let nonEmptyIndex = -1
-  const newHtml = convertHtmlToLines(html).reverse().map((item, index, array) => {
+  const lines = convertHtmlToLines(html)
+  const linesNum = lines.filter(c => c.text).length
+  const newHtml = lines.reverse().map((item, index, array) => {
     // Going over each line in reverse to detect last mentions,
     // keeping non-text stuff as-is
     if (!item.text) return item
@@ -281,7 +283,7 @@ export const preProcessPerLine = (html, greentext, handleLinks) => {
     // If line has loose text, i.e. text outside a mention or a tag
     // we won't touch mentions.
     let hasLooseText = false
-    let hasMentions = false
+    let mentionsNum = 0
     const process = (item) => {
       if (Array.isArray(item)) {
         const [opener, children, closer] = item
@@ -292,7 +294,7 @@ export const preProcessPerLine = (html, greentext, handleLinks) => {
           const attrs = getAttrs(opener)
           if (attrs['class'] && attrs['class'].includes('mention')) {
             // Got mentions
-            hasMentions = true
+            mentionsNum++
             return [opener, children, closer]
           } else {
             // Not a mention? Means we have loose text or whatever
@@ -321,8 +323,13 @@ export const preProcessPerLine = (html, greentext, handleLinks) => {
     // We now processed our tree, now we need to mark line as lastMentions
     const result = [...tree].map(process)
 
-    // Only check last (first since list is reversed) line
-    if (handleLinks && hasMentions && !hasLooseText && nonEmptyIndex++ === 0) {
+    if (
+      handleLinks && // Do we handle links at all?
+        mentionsNum > 1 && // Does it have more than one mention?
+        !hasLooseText && // Don't do anything if it has something besides mentions
+        nonEmptyIndex === 0 && // Only check last (first since list is reversed) line
+        nonEmptyIndex !== linesNum - 1 // Don't do anything if there's only one line
+    ) {
       let mentionIndex = 0
       const process = (item) => {
         if (Array.isArray(item)) {
diff --git a/src/components/status_body/status_body.vue b/src/components/status_body/status_body.vue
index 0eb11ad0..3dc4916c 100644
--- a/src/components/status_body/status_body.vue
+++ b/src/components/status_body/status_body.vue
@@ -56,7 +56,7 @@
             @parseReady="setHeadTailLinks"
           />
           <MentionsLine
-            v-if="!hideMentions && lastMentions.length > 0 && firstMentions.length <= 1"
+            v-if="!hideMentions && lastMentions.length > 1 && firstMentions.length <= 1"
             :mentions="lastMentions"
           />
         </span>
diff --git a/test/unit/specs/components/rich_content.spec.js b/test/unit/specs/components/rich_content.spec.js
index ff491a3a..835fbea2 100644
--- a/test/unit/specs/components/rich_content.spec.js
+++ b/test/unit/specs/components/rich_content.spec.js
@@ -416,4 +416,103 @@ describe('RichContent', () => {
 
     expect(wrapper.html()).to.eql(compwrap(expected))
   })
+
+  it('Don\'t remove last mention if it\'s the only one', () => {
+    const html = [
+      'Bruh',
+      'Bruh',
+      makeMention('foo'),
+      makeMention('bar'),
+      makeMention('baz')
+    ].join('<br>')
+
+    const wrapper = shallowMount(RichContent, {
+      localVue,
+      propsData: {
+        handleLinks: true,
+        greentext: true,
+        emoji: [],
+        html
+      }
+    })
+
+    expect(wrapper.html()).to.eql(compwrap(html))
+  })
+
+  it('Don\'t remove last mentions if there are more than one first mention - remove first instead', () => {
+    const html = [
+      [
+        makeMention('foo'),
+        makeMention('bar')
+      ].join(' '),
+      'Bruh',
+      'Bruh',
+      [
+        makeMention('foo'),
+        makeMention('bar'),
+        makeMention('baz')
+      ].join(' ')
+    ].join('\n')
+
+    const expected = [
+      [
+        removedMentionSpan,
+        removedMentionSpan,
+        'Bruh' // Due to trim we remove extra newline
+      ].join(''),
+      'Bruh',
+      lastMentions([
+        stubMention('foo'),
+        stubMention('bar'),
+        stubMention('baz')
+      ].join(' '))
+    ].join('\n')
+
+    const wrapper = shallowMount(RichContent, {
+      localVue,
+      propsData: {
+        handleLinks: true,
+        greentext: true,
+        emoji: [],
+        html
+      }
+    })
+
+    expect(wrapper.html()).to.eql(compwrap(expected))
+  })
+
+  it('Remove last mentions if there\'s just one first mention - remove all', () => {
+    const html = [
+      [
+        makeMention('foo')
+      ].join(' '),
+      'Bruh',
+      'Bruh',
+      [
+        makeMention('foo'),
+        makeMention('bar'),
+        makeMention('baz')
+      ].join(' ')
+    ].join('\n')
+
+    const expected = [
+      [
+        removedMentionSpan,
+        'Bruh' // Due to trim we remove extra newline
+      ].join(''),
+      'Bruh\n' // Can't remove this one yet
+    ].join('\n')
+
+    const wrapper = shallowMount(RichContent, {
+      localVue,
+      propsData: {
+        handleLinks: true,
+        greentext: true,
+        emoji: [],
+        html
+      }
+    })
+
+    expect(wrapper.html()).to.eql(compwrap(expected))
+  })
 })