aboutsummaryrefslogtreecommitdiff
path: root/src/components/rich_content
diff options
context:
space:
mode:
authorHenry Jameson <me@hjkos.com>2021-06-10 12:08:31 +0300
committerHenry Jameson <me@hjkos.com>2021-06-10 12:29:58 +0300
commitaec867b30036fd039113e4197ca98566447efec6 (patch)
tree556505243aff6bd951ef8115726f1dc2e03bfda7 /src/components/rich_content
parent566964992a394f1d0462557f70e284f2493d82bf (diff)
Moved greentext to RichContent, improved how first mentions are
restored, now shows mentions not uh, mention in post body
Diffstat (limited to 'src/components/rich_content')
-rw-r--r--src/components/rich_content/rich_content.jsx112
1 files changed, 110 insertions, 2 deletions
diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx
index bb7ae739..db24ca0e 100644
--- a/src/components/rich_content/rich_content.jsx
+++ b/src/components/rich_content/rich_content.jsx
@@ -1,6 +1,7 @@
import Vue from 'vue'
import { unescape, flattenDeep } from 'lodash'
import { convertHtml, getTagName, processTextForEmoji, getAttrs } from 'src/services/mini_html_converter/mini_html_converter.service.js'
+import { processHtml } from 'src/services/tiny_post_html_processor/tiny_post_html_processor.service.js'
import StillImage from 'src/components/still-image/still-image.vue'
import MentionLink from 'src/components/mention_link/mention_link.vue'
@@ -24,15 +25,25 @@ export default Vue.component('RichContent', {
required: false,
type: Boolean,
default: false
+ },
+ // Meme arrows
+ greentext: {
+ required: false,
+ type: Boolean,
+ default: false
}
},
render (h) {
+ // Pre-process HTML
+ const html = this.greentext ? addGreentext(this.html) : this.html
+
const renderImage = (tag) => {
return <StillImage
{...{ attrs: getAttrs(tag) }}
class="img"
/>
}
+
const renderMention = (attrs, children, encounteredText) => {
return <MentionLink
url={attrs.href}
@@ -41,10 +52,12 @@ export default Vue.component('RichContent', {
/>
}
+ // We stop treating mentions as "first" ones when we encounter
+ // non-whitespace text
let encounteredText = false
// Processor to use with mini_html_converter
const processItem = (item) => {
- // Handle text noes - just add emoji
+ // Handle text nodes - just add emoji
if (typeof item === 'string') {
const emptyText = item.trim() === ''
if (emptyText) {
@@ -72,6 +85,7 @@ export default Vue.component('RichContent', {
return unescapedItem
}
}
+
// Handle tag nodes
if (Array.isArray(item)) {
const [opener, children] = item
@@ -84,8 +98,14 @@ export default Vue.component('RichContent', {
const attrs = getAttrs(opener)
if (attrs['class'] && attrs['class'].includes('mention')) {
return renderMention(attrs, children, encounteredText)
+ } else {
+ attrs.target = '_blank'
+ return <a {...{ attrs }}>
+ { children.map(processItem) }
+ </a>
}
}
+
// Render tag as is
if (children !== undefined) {
return <Tag {...{ attrs: getAttrs(opener) }}>
@@ -97,7 +117,95 @@ export default Vue.component('RichContent', {
}
}
return <span class="RichContent">
- { convertHtml(this.html).map(processItem) }
+ { this.$slots.prefix }
+ { convertHtml(html).map(processItem) }
+ { this.$slots.suffix }
</span>
}
})
+
+export const addGreentext = (html) => {
+ try {
+ if (html.includes('&gt;')) {
+ // This checks if post has '>' at the beginning, excluding mentions so that @mention >impying works
+ return processHtml(html, (string) => {
+ if (
+ string.includes('&gt;') && string
+ .replace(/<[^>]+?>/gi, '') // remove all tags
+ .replace(/@\w+/gi, '') // remove mentions (even failed ones)
+ .trim()
+ .startsWith('&gt;')
+ ) {
+ return `<span class='greentext'>${string}</span>`
+ } else {
+ return string
+ }
+ })
+ } else {
+ return html
+ }
+ } catch (e) {
+ console.error('Failed to process status html', e)
+ return html
+ }
+}
+
+export const getHeadTailLinks = (html) => {
+ // Exported object properties
+ const firstMentions = [] // Mentions that appear in the beginning of post body
+ const lastTags = [] // Tags that appear at the end of post body
+ const writtenMentions = [] // All mentions that appear in post body
+ const writtenTags = [] // All tags that appear in post body
+
+ let encounteredText = false
+ let processingFirstMentions = true
+ let index = 0 // unique index for vue "tag" property
+
+ const getLinkData = (attrs, children, index) => {
+ return {
+ index,
+ url: attrs.href,
+ hashtag: attrs['data-tag'],
+ content: flattenDeep(children).join('')
+ }
+ }
+
+ // Processor to use with mini_html_converter
+ const processItem = (item) => {
+ // Handle text nodes - stop treating mentions as "first" when text encountered
+ if (typeof item === 'string') {
+ const emptyText = item.trim() === ''
+ if (emptyText) return
+ if (!encounteredText) {
+ encounteredText = true
+ processingFirstMentions = false
+ }
+ // Encountered text? That means tags we've been collectings aren't "last"!
+ lastTags.splice(0)
+ return
+ }
+ // Handle tag nodes
+ if (Array.isArray(item)) {
+ const [opener, children] = item
+ const Tag = getTagName(opener)
+ if (Tag !== 'a') return children && children.forEach(processItem)
+ const attrs = getAttrs(opener)
+ if (attrs['class']) {
+ const linkData = getLinkData(attrs, children, index++)
+ if (attrs['class'].includes('mention')) {
+ if (processingFirstMentions) {
+ firstMentions.push(linkData)
+ }
+ writtenMentions.push(linkData)
+ } else if (attrs['class'].includes('hashtag')) {
+ lastTags.push(linkData)
+ writtenTags.push(linkData)
+ }
+ return // Stop processing, we don't care about link's contents
+ }
+ children && children.forEach(processItem)
+ }
+ }
+ convertHtml(html).forEach(processItem)
+ return { firstMentions, writtenMentions, writtenTags, lastTags }
+}