diff options
| author | Henry Jameson <me@hjkos.com> | 2021-06-10 12:08:31 +0300 |
|---|---|---|
| committer | Henry Jameson <me@hjkos.com> | 2021-06-10 12:29:58 +0300 |
| commit | aec867b30036fd039113e4197ca98566447efec6 (patch) | |
| tree | 556505243aff6bd951ef8115726f1dc2e03bfda7 /src/components/rich_content | |
| parent | 566964992a394f1d0462557f70e284f2493d82bf (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.jsx | 112 |
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('>')) { + // This checks if post has '>' at the beginning, excluding mentions so that @mention >impying works + return processHtml(html, (string) => { + if ( + string.includes('>') && string + .replace(/<[^>]+?>/gi, '') // remove all tags + .replace(/@\w+/gi, '') // remove mentions (even failed ones) + .trim() + .startsWith('>') + ) { + 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 } +} |
