From 8fe4355a6b84ae81b54228e6749a4ab82966ff2e Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 18 Jun 2021 21:29:47 +0300
Subject: [PATCH 1/3] fix rich images

---
 src/services/html_converter/html_line_converter.service.js | 2 ++
 .../services/html_converter/html_line_converter.spec.js    | 7 +++++++
 2 files changed, 9 insertions(+)

diff --git a/src/services/html_converter/html_line_converter.service.js b/src/services/html_converter/html_line_converter.service.js
index f43d162a..74103b02 100644
--- a/src/services/html_converter/html_line_converter.service.js
+++ b/src/services/html_converter/html_line_converter.service.js
@@ -114,6 +114,8 @@ export const convertHtmlToLines = (html) => {
           } else {
             handleOpen(tagFull)
           }
+        } else {
+          textBuffer += tagFull
         }
       } else {
         textBuffer += tagFull
diff --git a/test/unit/specs/services/html_converter/html_line_converter.spec.js b/test/unit/specs/services/html_converter/html_line_converter.spec.js
index de7c7fc2..86bd7e8b 100644
--- a/test/unit/specs/services/html_converter/html_line_converter.spec.js
+++ b/test/unit/specs/services/html_converter/html_line_converter.spec.js
@@ -69,6 +69,13 @@ describe('html_line_converter', () => {
       const comparableResult = result.map(mapOnlyText(processorKeep)).join('')
       expect(comparableResult).to.eql(inputOutput)
     })
+
+    it('fed with some recognized but not handled elements', () => {
+      const inputOutput = 'testing images\n\n<img src="benis.png">'
+      const result = convertHtmlToLines(inputOutput)
+      const comparableResult = result.map(mapOnlyText(processorKeep)).join('')
+      expect(comparableResult).to.eql(inputOutput)
+    })
   })
   describe('with processor that replaces lines with word "_" should match expected line when', () => {
     const processorReplace = (line) => '_'

From c6831a381033fa160fba95fa88b1179d3c670d9d Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 18 Jun 2021 21:42:46 +0300
Subject: [PATCH 2/3] fix not escaping some stuff

---
 src/components/rich_content/rich_content.jsx  | 13 ++++-------
 .../specs/components/rich_content.spec.js     | 23 +++++++++++++++++++
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx
index ce562f13..79acd1de 100644
--- a/src/components/rich_content/rich_content.jsx
+++ b/src/components/rich_content/rich_content.jsx
@@ -121,14 +121,13 @@ export default Vue.component('RichContent', {
         if (emptyText) {
           return encounteredText ? item : item.trim()
         }
-        let unescapedItem = unescape(item)
         if (!encounteredText) {
-          unescapedItem = unescapedItem.trimStart()
+          item = item.trimStart()
           encounteredText = true
         }
         if (item.includes(':')) {
-          unescapedItem = ['', processTextForEmoji(
-            unescapedItem,
+          item = ['', processTextForEmoji(
+            item,
             this.emoji,
             ({ shortcode, url }) => {
               return <StillImage
@@ -140,7 +139,7 @@ export default Vue.component('RichContent', {
             }
           )]
         }
-        return unescapedItem
+        return item
       }
 
       // Handle tag nodes
@@ -189,7 +188,7 @@ export default Vue.component('RichContent', {
         const emptyText = item.trim() === ''
         if (emptyText) return item
         if (!encounteredTextReverse) encounteredTextReverse = true
-        return item
+        return unescape(item)
       } else if (Array.isArray(item)) {
         // Handle tag nodes
         const [opener, children] = item
@@ -203,9 +202,7 @@ export default Vue.component('RichContent', {
               return renderHashtag(attrs, children, encounteredTextReverse)
             } else {
               attrs.target = '_blank'
-              html.includes('freenode') && console.log('PASS1', children)
               const newChildren = [...children].reverse().map(processItemReverse).reverse()
-              html.includes('freenode') && console.log('PASS1b', newChildren)
 
               return <a {...{ attrs }}>
                 { newChildren }
diff --git a/test/unit/specs/components/rich_content.spec.js b/test/unit/specs/components/rich_content.spec.js
index 96c480ea..fbf8973d 100644
--- a/test/unit/specs/components/rich_content.spec.js
+++ b/test/unit/specs/components/rich_content.spec.js
@@ -27,6 +27,29 @@ describe('RichContent', () => {
     expect(wrapper.html()).to.eql(compwrap(html))
   })
 
+  it('unescapes everything as needed', () => {
+    const html = [
+      p('Testing &#39;em all'),
+      'Testing &#39;em all'
+    ].join('')
+    const expected = [
+      p('Testing \'em all'),
+      'Testing \'em all'
+    ].join('')
+    const wrapper = shallowMount(RichContent, {
+      localVue,
+      propsData: {
+        hideMentions: true,
+        handleLinks: true,
+        greentext: true,
+        emoji: [],
+        html
+      }
+    })
+
+    expect(wrapper.html()).to.eql(compwrap(expected))
+  })
+
   it('removes mentions from the beginning of post', () => {
     const html = p(
       makeMention('John'),

From a258182522e85c31fe9dfbfbddf7a314ca36d0ca Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 22 Jun 2021 20:16:26 +0300
Subject: [PATCH 3/3] fix non-notifying mentions and original mention display

---
 src/components/mention_link/mention_link.vue |  3 ++-
 src/components/rich_content/rich_content.jsx | 12 ++++++++++--
 src/components/status_body/status_body.js    | 14 ++++++++++++++
 src/components/status_body/status_body.vue   |  3 ++-
 4 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue
index e4d395fa..514b7475 100644
--- a/src/components/mention_link/mention_link.vue
+++ b/src/components/mention_link/mention_link.vue
@@ -5,8 +5,9 @@
     <!-- eslint-disable vue/no-v-html -->
     <a
       v-if="!user"
-      href="url"
+      :href="url"
       class="original"
+      target="_blank"
       v-html="content"
     />
     <!-- eslint-enable vue/no-v-html -->
diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx
index 79acd1de..cd73f2e5 100644
--- a/src/components/rich_content/rich_content.jsx
+++ b/src/components/rich_content/rich_content.jsx
@@ -36,6 +36,10 @@ export default Vue.component('RichContent', {
       required: true,
       type: String
     },
+    attentions: {
+      required: false,
+      default: () => []
+    },
     // Emoji object, as in status.emojis, note the "s" at the end...
     emoji: {
       required: true,
@@ -91,8 +95,12 @@ export default Vue.component('RichContent', {
       </a>
     }
 
-    const renderMention = (attrs, children, encounteredText) => {
+    const renderMention = (attrs, children) => {
       const linkData = getLinkData(attrs, children, mentionIndex++)
+      linkData.notifying = this.attentions.some(a => a.statusnet_profile_url === linkData.url)
+      if (!linkData.notifying) {
+        encounteredText = true
+      }
       writtenMentions.push(linkData)
       if (!encounteredText) {
         firstMentions.push(linkData)
@@ -148,7 +156,7 @@ export default Vue.component('RichContent', {
         const Tag = getTagName(opener)
         const attrs = getAttrs(opener)
         switch (Tag) {
-          case 'span': // replace images with StillImage
+          case 'span': // Replace last mentions class with mentionsline
             if (attrs['class'] && attrs['class'].includes('lastMentions')) {
               if (firstMentions.length > 1 && lastMentions.length > 1) {
                 break
diff --git a/src/components/status_body/status_body.js b/src/components/status_body/status_body.js
index 601c963b..d1736ba3 100644
--- a/src/components/status_body/status_body.js
+++ b/src/components/status_body/status_body.js
@@ -85,6 +85,20 @@ const StatusContent = {
     })
   },
   methods: {
+    onParseReady (event) {
+      this.$emit('parseReady', event)
+      const { writtenMentions } = event
+      writtenMentions
+        .filter(mention => !mention.notifying)
+        .forEach(mention => {
+          const { content, url } = mention
+          const cleanedString = content.replace(/<[^>]+?>/gi, '') // remove all tags
+          if (!cleanedString.startsWith('@')) return
+          const handle = cleanedString.slice(1)
+          const host = url.replace(/^https?:\/\//, '').replace(/\/.+?$/, '')
+          this.$store.dispatch('fetchUserIfMissing', `${handle}@${host}`)
+        })
+    },
     toggleShowMore () {
       if (this.mightHideBecauseTall) {
         this.showingTall = !this.showingTall
diff --git a/src/components/status_body/status_body.vue b/src/components/status_body/status_body.vue
index 2be46303..d77ccd54 100644
--- a/src/components/status_body/status_body.vue
+++ b/src/components/status_body/status_body.vue
@@ -47,7 +47,8 @@
           :handle-links="true"
           :hide-mentions="hideMentions"
           :greentext="mergedConfig.greentext"
-          @parseReady="$emit('parseReady', $event)"
+          :attentions="status.attentions"
+          @parseReady="onParseReady"
         />
 
         <button