From ffc501eb236a7ec088c058d24396a2dccc8f3a8b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 11 Jun 2021 13:38:08 +0300 Subject: [PATCH 1/7] cleanup --- src/components/status_body/status_body.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/status_body/status_body.js b/src/components/status_body/status_body.js index 7433619ba..14558aca8 100644 --- a/src/components/status_body/status_body.js +++ b/src/components/status_body/status_body.js @@ -1,5 +1,5 @@ import fileType from 'src/services/file_type/file_type.service' -import RichContent, { getHeadTailLinks } from 'src/components/rich_content/rich_content.jsx' +import RichContent from 'src/components/rich_content/rich_content.jsx' import MentionsLine from 'src/components/mentions_line/mentions_line.vue' import { mapGetters } from 'vuex' import { library } from '@fortawesome/fontawesome-svg-core' From c1bd36dc6f5700eb13c4b86fcd353a07a7c2fc08 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 12 Jun 2021 16:15:22 +0300 Subject: [PATCH 2/7] change how "first" line is determined. Allow one mention in the beginning for hellthread style --- src/components/rich_content/rich_content.jsx | 5 +++-- src/components/status_body/status_body.vue | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index 78af0d9e5..a489689bb 100644 --- a/src/components/rich_content/rich_content.jsx +++ b/src/components/rich_content/rich_content.jsx @@ -126,7 +126,7 @@ export default Vue.component('RichContent', { switch (Tag) { case 'span': // replace images with StillImage if (attrs['class'] && attrs['class'].includes('lastMentions')) { - if (firstMentions.length > 0) { + if (firstMentions.length > 1) { break } else { return '' @@ -231,6 +231,7 @@ const getLinkData = (attrs, children, index) => { export const preProcessPerLine = (html, greentext) => { const lastMentions = [] + let nonEmptyIndex = 0 const newHtml = convertHtmlToLines(html).reverse().map((item, index, array) => { // Going over each line in reverse to detect last mentions, // keeping non-text stuff as-is @@ -295,7 +296,7 @@ export const preProcessPerLine = (html, greentext) => { const result = [...tree].map(process) // Only check last (first since list is reversed) line - if (hasMentions && !hasLooseText && index === 0) { + if (hasMentions && !hasLooseText && nonEmptyIndex++ === 0) { 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 45d899fbd..7e699a454 100644 --- a/src/components/status_body/status_body.vue +++ b/src/components/status_body/status_body.vue @@ -54,7 +54,7 @@ @parseReady="setHeadTailLinks" /> From 647e4476f90be087dda099c588f2f8acc089c1ee Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 12 Jun 2021 16:25:37 +0300 Subject: [PATCH 3/7] fix long post fader --- src/components/status_body/status_body.scss | 3 +-- src/components/status_body/status_body.vue | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/status_body/status_body.scss b/src/components/status_body/status_body.scss index 310185ae8..da5d4dd32 100644 --- a/src/components/status_body/status_body.scss +++ b/src/components/status_body/status_body.scss @@ -62,7 +62,7 @@ overflow-y: hidden; z-index: 1; - .text-wrapper { + .rich-content-wrapper { min-height: 0; mask: linear-gradient(to top, white, transparent) bottom/100% 70px no-repeat, @@ -123,5 +123,4 @@ vertical-align: middle; object-fit: contain; } - } diff --git a/src/components/status_body/status_body.vue b/src/components/status_body/status_body.vue index 7e699a454..b84541d7a 100644 --- a/src/components/status_body/status_body.vue +++ b/src/components/status_body/status_body.vue @@ -38,7 +38,10 @@ > {{ $t("general.show_more") }} - + Date: Sat, 12 Jun 2021 17:11:49 +0300 Subject: [PATCH 4/7] fix color of reply row, fix overflow in status-popover --- src/components/status/status.scss | 4 ++++ src/components/status/status.vue | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/status/status.scss b/src/components/status/status.scss index e68bc62cd..3805aa309 100644 --- a/src/components/status/status.scss +++ b/src/components/status/status.scss @@ -4,6 +4,7 @@ $status-margin: 0.75em; .Status { min-width: 0; + white-space: normal; &:hover { --_still-image-img-visibility: visible; @@ -166,6 +167,7 @@ $status-margin: 0.75em; line-height: 160%; max-width: 100%; align-items: stretch; + z-index: 2; } & .reply-to-popover, @@ -211,7 +213,9 @@ $status-margin: 0.75em; padding-right: 0.25em; } + & .mentions-text, & .reply-to-text { + color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; diff --git a/src/components/status/status.vue b/src/components/status/status.vue index be6458ae9..a5f347a64 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -247,7 +247,7 @@ flip="horizontal" /> {{ $t('status.reply_to') }} @@ -281,7 +281,7 @@ @click.prevent="gotoOriginal(status.in_reply_to_status_id)" > {{ $t('status.mentions') }} From ca6c7d5b10e48299dcb0ee65248de14f27ed78c8 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 12 Jun 2021 17:20:21 +0300 Subject: [PATCH 5/7] fix tags gluing --- src/components/rich_content/rich_content.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index a489689bb..ad77d6155 100644 --- a/src/components/rich_content/rich_content.jsx +++ b/src/components/rich_content/rich_content.jsx @@ -141,6 +141,7 @@ export default Vue.component('RichContent', { if (attrs['class'] && attrs['class'].includes('mention')) { return renderMention(attrs, children, encounteredText) } else if (attrs['class'] && attrs['class'].includes('hashtag')) { + encounteredText = true return item // We'll handle it later } else { attrs.target = '_blank' @@ -167,7 +168,7 @@ export default Vue.component('RichContent', { // Handle text nodes - just add emoji if (typeof item === 'string') { const emptyText = item.trim() === '' - if (emptyText) return encounteredTextReverse ? item : item.trim() + if (emptyText) return item if (!encounteredTextReverse) encounteredTextReverse = true return item } else if (Array.isArray(item)) { From cd4455675024a3dfc8930184114d5f92438d0466 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 12 Jun 2021 19:47:23 +0300 Subject: [PATCH 6/7] restructure and tests squash! restructure and tests --- src/components/rich_content/rich_content.jsx | 17 +- src/components/status_body/status_body.vue | 1 - .../html_line_converter.service.js | 8 +- .../html_tree_converter.service.js | 53 +-- .../html_converter/utility.service.js | 73 ++++ .../specs/components/rich_content.spec.js | 357 ++++++++++++++++++ .../html_line_converter.spec.js | 2 +- .../html_tree_converter.spec.js | 38 +- .../services/html_converter/utility.spec.js | 37 ++ 9 files changed, 481 insertions(+), 105 deletions(-) create mode 100644 src/services/html_converter/utility.service.js create mode 100644 test/unit/specs/components/rich_content.spec.js create mode 100644 test/unit/specs/services/html_converter/utility.spec.js diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index ad77d6155..ef15aaeba 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 { convertHtmlToTree, getTagName, processTextForEmoji, getAttrs } from 'src/services/html_converter/html_tree_converter.service.js' +import { getTagName, processTextForEmoji, getAttrs } from 'src/services/html_converter/utility.service.js' +import { convertHtmlToTree } from 'src/services/html_converter/html_tree_converter.service.js' import { convertHtmlToLines } from 'src/services/html_converter/html_line_converter.service.js' import StillImage from 'src/components/still-image/still-image.vue' import MentionLink from 'src/components/mention_link/mention_link.vue' @@ -31,18 +32,12 @@ export default Vue.component('RichContent', { required: false, type: Boolean, default: false - }, - // Whether to hide last mentions (hellthreads) - hideMentions: { - required: false, - type: Boolean, - default: false } }, // NEVER EVER TOUCH DATA INSIDE RENDER render (h) { // Pre-process HTML - const { newHtml: html, lastMentions } = preProcessPerLine(this.html, this.greentext, this.hideMentions) + const { newHtml: html, lastMentions } = preProcessPerLine(this.html, this.greentext, this.handleLinks) 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 @@ -228,8 +223,9 @@ const getLinkData = (attrs, children, index) => { * * @param {String} html - raw HTML to process * @param {Boolean} greentext - whether to enable greentexting or not + * @param {Boolean} handleLinks - whether to handle links or not */ -export const preProcessPerLine = (html, greentext) => { +export const preProcessPerLine = (html, greentext, handleLinks) => { const lastMentions = [] let nonEmptyIndex = 0 @@ -264,6 +260,7 @@ export const preProcessPerLine = (html, greentext) => { const tag = getTagName(opener) // If we have a link we probably have mentions if (tag === 'a') { + if (!handleLinks) return [opener, children, closer] const attrs = getAttrs(opener) if (attrs['class'] && attrs['class'].includes('mention')) { // Got mentions @@ -297,7 +294,7 @@ export const preProcessPerLine = (html, greentext) => { const result = [...tree].map(process) // Only check last (first since list is reversed) line - if (hasMentions && !hasLooseText && nonEmptyIndex++ === 0) { + if (handleLinks && hasMentions && !hasLooseText && nonEmptyIndex++ === 0) { 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 b84541d7a..aac44e42c 100644 --- a/src/components/status_body/status_body.vue +++ b/src/components/status_body/status_body.vue @@ -52,7 +52,6 @@ :html="status.raw_html" :emoji="status.emojis" :handle-links="true" - :hide-mentions="hideMentions" :greentext="mergedConfig.greentext" @parseReady="setHeadTailLinks" /> diff --git a/src/services/html_converter/html_line_converter.service.js b/src/services/html_converter/html_line_converter.service.js index d8f5ecb86..e448d5cd9 100644 --- a/src/services/html_converter/html_line_converter.service.js +++ b/src/services/html_converter/html_line_converter.service.js @@ -1,3 +1,5 @@ +import { getTagName } from './utility.service.js' + /** * This is a tiny purpose-built HTML parser/processor. This basically detects * any type of visual newline and converts entire HTML into a array structure. @@ -26,12 +28,6 @@ export const convertHtmlToLines = (html) => { let textBuffer = '' // Current line content let tagBuffer = null // Current tag buffer, if null = we are not currently reading a tag - // Extracts tag name from tag, i.e. => span - const getTagName = (tag) => { - const result = /(?:<\/(\w+)>|<(\w+)\s?[^/]*?\/?>)/gi.exec(tag) - return result && (result[1] || result[2]) - } - const flush = () => { // Processes current line buffer, adds it to output buffer and clears line buffer if (textBuffer.trim().length > 0 && !level.some(l => ignoredTags.has(l))) { buffer.push({ text: textBuffer }) diff --git a/src/services/html_converter/html_tree_converter.service.js b/src/services/html_converter/html_tree_converter.service.js index badd473a2..804d35d7b 100644 --- a/src/services/html_converter/html_tree_converter.service.js +++ b/src/services/html_converter/html_tree_converter.service.js @@ -1,3 +1,5 @@ +import { getTagName } from './utility.service.js' + /** * This is a not-so-tiny purpose-built HTML parser/processor. This parses html * and converts it into a tree structure representing tag openers/closers and @@ -93,54 +95,3 @@ export const convertHtmlToTree = (html) => { flushText() return buffer } - -// Extracts tag name from tag, i.e. => span -export const getTagName = (tag) => { - const result = /(?:<\/(\w+)>|<(\w+)\s?.*?\/?>)/gi.exec(tag) - return result && (result[1] || result[2]) -} - -export const processTextForEmoji = (text, emojis, processor) => { - const buffer = [] - let textBuffer = '' - for (let i = 0; i < text.length; i++) { - const char = text[i] - if (char === ':') { - const next = text.slice(i + 1) - let found = false - for (let emoji of emojis) { - if (next.slice(0, emoji.shortcode.length + 1) === (emoji.shortcode + ':')) { - found = emoji - break - } - } - if (found) { - buffer.push(textBuffer) - textBuffer = '' - buffer.push(processor(found)) - i += found.shortcode.length + 1 - } else { - textBuffer += char - } - } else { - textBuffer += char - } - } - if (textBuffer) buffer.push(textBuffer) - return buffer -} - -export const getAttrs = tag => { - const innertag = tag - .substring(1, tag.length - 1) - .replace(new RegExp('^' + getTagName(tag)), '') - .replace(/\/?$/, '') - .trim() - const attrs = Array.from(innertag.matchAll(/([a-z0-9-]+)(?:=("[^"]+?"|'[^']+?'))?/gi)) - .map(([trash, key, value]) => [key, value]) - .map(([k, v]) => { - if (!v) return [k, true] - return [k, v.substring(1, v.length - 1)] - }) - return Object.fromEntries(attrs) -} diff --git a/src/services/html_converter/utility.service.js b/src/services/html_converter/utility.service.js new file mode 100644 index 000000000..4d0c36c2b --- /dev/null +++ b/src/services/html_converter/utility.service.js @@ -0,0 +1,73 @@ +/** + * Extract tag name from tag opener/closer. + * + * @param {String} tag - tag string, i.e. '' + * @return {String} - tagname, i.e. "div" + */ +export const getTagName = (tag) => { + const result = /(?:<\/(\w+)>|<(\w+)\s?.*?\/?>)/gi.exec(tag) + return result && (result[1] || result[2]) +} + +/** + * Extract attributes from tag opener. + * + * @param {String} tag - tag string, i.e. '' + * @return {Object} - map of attributes key = attribute name, value = attribute value + * attributes without values represented as boolean true + */ +export const getAttrs = tag => { + const innertag = tag + .substring(1, tag.length - 1) + .replace(new RegExp('^' + getTagName(tag)), '') + .replace(/\/?$/, '') + .trim() + const attrs = Array.from(innertag.matchAll(/([a-z0-9-]+)(?:=("[^"]+?"|'[^']+?'))?/gi)) + .map(([trash, key, value]) => [key, value]) + .map(([k, v]) => { + if (!v) return [k, true] + return [k, v.substring(1, v.length - 1)] + }) + return Object.fromEntries(attrs) +} + +/** + * Finds shortcodes in text + * + * @param {String} text - original text to find emojis in + * @param {{ url: String, shortcode: Sring }[]} emoji - list of shortcodes to find + * @param {Function} processor - function to call on each encountered emoji, + * function is passed single object containing matching emoji ({ url, shortcode }) + * return value will be inserted into resulting array instead of :shortcode: + * @return {Array} resulting array with non-emoji parts of text and whatever {processor} + * returned for emoji + */ +export const processTextForEmoji = (text, emojis, processor) => { + const buffer = [] + let textBuffer = '' + for (let i = 0; i < text.length; i++) { + const char = text[i] + if (char === ':') { + const next = text.slice(i + 1) + let found = false + for (let emoji of emojis) { + if (next.slice(0, emoji.shortcode.length + 1) === (emoji.shortcode + ':')) { + found = emoji + break + } + } + if (found) { + buffer.push(textBuffer) + textBuffer = '' + buffer.push(processor(found)) + i += found.shortcode.length + 1 + } else { + textBuffer += char + } + } else { + textBuffer += char + } + } + if (textBuffer) buffer.push(textBuffer) + return buffer +} diff --git a/test/unit/specs/components/rich_content.spec.js b/test/unit/specs/components/rich_content.spec.js new file mode 100644 index 000000000..05c0b2595 --- /dev/null +++ b/test/unit/specs/components/rich_content.spec.js @@ -0,0 +1,357 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils' +import RichContent from 'src/components/rich_content/rich_content.jsx' + +const localVue = createLocalVue() + +const makeMention = (who) => `@${who}` +const stubMention = (who) => `` +const lastMentions = (...data) => `${data.join('')}` +const p = (...data) => `

${data.join('')}

` +const compwrap = (...data) => `${data.join('')}` +const removedMentionSpan = '' + +describe('RichContent', () => { + it('renders simple post without exploding', () => { + const html = p('Hello world!') + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: true, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(html)) + }) + + it('removes mentions from the beginning of post', () => { + const html = p( + makeMention('John'), + ' how are you doing thoday?' + ) + const expected = p( + removedMentionSpan, + 'how are you doing thoday?' + ) + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: true, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(expected)) + }) + + it('removes mentions from the end of the hellpost (

)', () => { + const html = [ + p('How are you doing today, fine gentlemen?'), + p( + makeMention('John'), + makeMention('Josh'), + makeMention('Jeremy') + ) + ].join('') + const expected = [ + p( + 'How are you doing today, fine gentlemen?' + ), + // TODO fix this extra line somehow? + p() + ].join('') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: true, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(expected)) + }) + + it('removes mentions from the end of the hellpost (
)', () => { + const html = [ + 'How are you doing today, fine gentlemen?', + [ + makeMention('John'), + makeMention('Josh'), + makeMention('Jeremy') + ].join('') + ].join('
') + const expected = [ + 'How are you doing today, fine gentlemen?', + // TODO fix this extra line somehow? + '
' + ].join('') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: true, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(expected)) + }) + + it('removes mentions from the end of the hellpost (\\n)', () => { + const html = [ + 'How are you doing today, fine gentlemen?', + [ + makeMention('John'), + makeMention('Josh'), + makeMention('Jeremy') + ].join('') + ].join('\n') + const expected = [ + 'How are you doing today, fine gentlemen?', + // TODO fix this extra line somehow? + '' + ].join('\n') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: true, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(expected)) + }) + + it('Does not remove mentions in the middle or at the end of text string', () => { + const html = [ + [ + makeMention('Jack'), + 'let\'s meet up with ', + makeMention('Janet') + ].join(''), + [ + 'cc: ', + makeMention('John'), + makeMention('Josh'), + makeMention('Jeremy') + ].join('') + ].join('\n') + const expected = [ + [ + removedMentionSpan, + 'let\'s meet up with ', + stubMention('Janet') + ].join(''), + [ + 'cc: ', + stubMention('John'), + stubMention('Josh'), + stubMention('Jeremy') + ].join('') + ].join('\n') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: true, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(expected)) + }) + + it('removes mentions from the end if there\'s only one first mention', () => { + const html = [ + p( + makeMention('Todd'), + 'so anyway you are wrong' + ), + p( + makeMention('Tom'), + makeMention('Trace'), + makeMention('Theodor') + ) + ].join('') + const expected = [ + p( + removedMentionSpan, + 'so anyway you are wrong' + ), + // TODO fix this extra line somehow? + p() + ].join('') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: true, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(expected)) + }) + + it('does not remove mentions from the end if there\'s more than one first mention', () => { + const html = [ + p( + makeMention('Zacharie'), + makeMention('Zinaide'), + 'you guys have cool names, and so do these guys: ' + ), + p( + makeMention('Watson'), + makeMention('Wallace'), + makeMention('Wakamoto') + ) + ].join('') + const expected = [ + p( + removedMentionSpan, + removedMentionSpan, + 'you guys have cool names, and so do these guys: ' + ), + p( + lastMentions( + stubMention('Watson'), + stubMention('Wallace'), + stubMention('Wakamoto') + ) + ) + ].join('') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: true, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(expected)) + }) + + it('Does not touch links if link handling is disabled', () => { + const html = [ + [ + makeMention('Jack'), + 'let\'s meet up with ', + makeMention('Janet') + ].join(''), + [ + makeMention('John'), + makeMention('Josh'), + makeMention('Jeremy') + ].join('') + ].join('\n') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: false, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(html)) + }) + + it('Adds greentext and cyantext to the post', () => { + const html = [ + '>preordering videogames', + '>any year' + ].join('\n') + const expected = [ + '>preordering videogames', + '>any year' + ].join('\n') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: false, + greentext: true, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(expected)) + }) + + it('Does not add greentext and cyantext if setting is set to false', () => { + const html = [ + '>preordering videogames', + '>any year' + ].join('\n') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: false, + greentext: false, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(html)) + }) + + it('Adds emoji to post', () => { + const html = p('Ebin :DDDD :spurdo:') + const expected = p( + 'Ebin :DDDD ', + '' + ) + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: false, + greentext: false, + emoji: [{ url: 'about:blank', shortcode: 'spurdo' }], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(expected)) + }) + + it('Doesn\'t add nonexistent emoji to post', () => { + const html = p('Lol :lol:') + + const wrapper = shallowMount(RichContent, { + localVue, + propsData: { + handleLinks: false, + greentext: false, + emoji: [], + html + } + }) + + expect(wrapper.html()).to.eql(compwrap(html)) + }) +}) 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 532ea187b..9485233fc 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 @@ -2,7 +2,7 @@ import { convertHtmlToLines } from 'src/services/html_converter/html_line_conver const mapOnlyText = (processor) => (input) => input.text ? processor(input.text) : input -describe('TinyPostHTMLProcessor', () => { +describe('html_line_converter', () => { describe('with processor that keeps original line should not make any changes to HTML when', () => { const processorKeep = (line) => line it('fed with regular HTML with newlines', () => { diff --git a/test/unit/specs/services/html_converter/html_tree_converter.spec.js b/test/unit/specs/services/html_converter/html_tree_converter.spec.js index a54745c34..7283021b2 100644 --- a/test/unit/specs/services/html_converter/html_tree_converter.spec.js +++ b/test/unit/specs/services/html_converter/html_tree_converter.spec.js @@ -1,6 +1,6 @@ -import { convertHtmlToTree, processTextForEmoji, getAttrs } from 'src/services/html_converter/html_tree_converter.service.js' +import { convertHtmlToTree } from 'src/services/html_converter/html_tree_converter.service.js' -describe('MiniHtmlConverter', () => { +describe('html_tree_converter', () => { describe('convertHtmlToTree', () => { it('converts html into a tree structure', () => { const input = '1

2

345' @@ -129,38 +129,4 @@ describe('MiniHtmlConverter', () => { ]) }) }) - - describe('processTextForEmoji', () => { - it('processes all emoji in text', () => { - const input = 'Hello from finland! :lol: We have best water! :lmao:' - const emojis = [ - { shortcode: 'lol', src: 'LOL' }, - { shortcode: 'lmao', src: 'LMAO' } - ] - const processor = ({ shortcode, src }) => ({ shortcode, src }) - expect(processTextForEmoji(input, emojis, processor)).to.eql([ - 'Hello from finland! ', - { shortcode: 'lol', src: 'LOL' }, - ' We have best water! ', - { shortcode: 'lmao', src: 'LMAO' } - ]) - }) - it('leaves text as is', () => { - const input = 'Number one: that\'s terror' - const emojis = [] - const processor = ({ shortcode, src }) => ({ shortcode, src }) - expect(processTextForEmoji(input, emojis, processor)).to.eql([ - 'Number one: that\'s terror' - ]) - }) - }) - - describe('getAttrs', () => { - it('extracts arguments from tag', () => { - const input = '' - const output = { src: 'boop', cool: true, ebin: 'true' } - - expect(getAttrs(input)).to.eql(output) - }) - }) }) diff --git a/test/unit/specs/services/html_converter/utility.spec.js b/test/unit/specs/services/html_converter/utility.spec.js new file mode 100644 index 000000000..cf6fd99b4 --- /dev/null +++ b/test/unit/specs/services/html_converter/utility.spec.js @@ -0,0 +1,37 @@ +import { processTextForEmoji, getAttrs } from 'src/services/html_converter/utility.service.js' + +describe('html_converter utility', () => { + describe('processTextForEmoji', () => { + it('processes all emoji in text', () => { + const input = 'Hello from finland! :lol: We have best water! :lmao:' + const emojis = [ + { shortcode: 'lol', src: 'LOL' }, + { shortcode: 'lmao', src: 'LMAO' } + ] + const processor = ({ shortcode, src }) => ({ shortcode, src }) + expect(processTextForEmoji(input, emojis, processor)).to.eql([ + 'Hello from finland! ', + { shortcode: 'lol', src: 'LOL' }, + ' We have best water! ', + { shortcode: 'lmao', src: 'LMAO' } + ]) + }) + it('leaves text as is', () => { + const input = 'Number one: that\'s terror' + const emojis = [] + const processor = ({ shortcode, src }) => ({ shortcode, src }) + expect(processTextForEmoji(input, emojis, processor)).to.eql([ + 'Number one: that\'s terror' + ]) + }) + }) + + describe('getAttrs', () => { + it('extracts arguments from tag', () => { + const input = '' + const output = { src: 'boop', cool: true, ebin: 'true' } + + expect(getAttrs(input)).to.eql(output) + }) + }) +}) From 90a188f2c3c16b926c75bf4aa749633e6967e5a0 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 12 Jun 2021 19:54:03 +0300 Subject: [PATCH 7/7] cleanup --- src/components/chat_list_item/chat_list_item.js | 3 +-- src/components/chat_message/chat_message.js | 3 +-- src/components/status_body/status_body.js | 2 +- .../entity_normalizer/entity_normalizer.service.js | 5 ++--- .../services/entity_normalizer/entity_normalizer.spec.js | 9 --------- 5 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/components/chat_list_item/chat_list_item.js b/src/components/chat_list_item/chat_list_item.js index e01b9bd4d..e5032176f 100644 --- a/src/components/chat_list_item/chat_list_item.js +++ b/src/components/chat_list_item/chat_list_item.js @@ -40,12 +40,11 @@ const ChatListItem = { const message = this.chat.lastMessage const messageEmojis = message ? message.emojis : [] const isYou = message && message.account_id === this.currentUser.id - const content = message ? (this.attachmentInfo || message.content_raw) : '' + const content = message ? (this.attachmentInfo || message.content) : '' const messagePreview = isYou ? `${this.$t('chats.you')} ${content}` : content return { summary: '', emojis: messageEmojis, - statusnet_html: messagePreview, raw_html: messagePreview, text: messagePreview, attachments: [] diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js index d126d453a..9a2d1e7de 100644 --- a/src/components/chat_message/chat_message.js +++ b/src/components/chat_message/chat_message.js @@ -58,8 +58,7 @@ const ChatMessage = { return { summary: '', emojis: this.message.emojis, - raw_html: this.message.content_raw, - statusnet_html: this.message.content, + raw_html: this.message.content, text: this.message.content, attachments: this.message.attachments } diff --git a/src/components/status_body/status_body.js b/src/components/status_body/status_body.js index 14558aca8..26491e1b4 100644 --- a/src/components/status_body/status_body.js +++ b/src/components/status_body/status_body.js @@ -53,7 +53,7 @@ const StatusContent = { // Using max-height + overflow: auto for status components resulted in false positives // very often with japanese characters, and it was very annoying. tallStatus () { - const lengthScore = this.status.statusnet_html.split(/ 20 }, longSubject () { diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 13162dcff..613ed566d 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -267,7 +267,6 @@ export const parseStatus = (data) => { output.type = data.reblog ? 'retweet' : 'status' output.nsfw = data.sensitive - output.statusnet_html = addEmojis(data.content, data.emojis) output.raw_html = data.content output.emojis = data.emojis @@ -329,7 +328,7 @@ export const parseStatus = (data) => { output.nsfw = data.nsfw } - output.statusnet_html = data.statusnet_html + output.raw_html = data.statusnet_html output.text = data.text output.in_reply_to_status_id = data.in_reply_to_status_id @@ -449,7 +448,7 @@ export const parseChatMessage = (message) => { output.created_at = new Date(message.created_at) output.chat_id = message.chat_id output.emojis = message.emojis - output.content_raw = message.content + output.content = message.content if (message.content) { output.content = addEmojis(message.content, message.emojis) } else { diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js index 759539e0c..c8965785c 100644 --- a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js +++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js @@ -23,7 +23,6 @@ const makeMockStatusQvitter = (overrides = {}) => { repeat_num: 0, repeated: false, statusnet_conversation_id: '16300488', - statusnet_html: '

haha benis

', summary: null, tags: [], text: 'haha benis', @@ -233,14 +232,6 @@ describe('API Entities normalizer', () => { expect(parsedRepeat).to.have.deep.property('retweeted_status.id', 'deadbeef') }) - it('adds emojis to post content', () => { - const post = makeMockStatusMasto({ emojis: makeMockEmojiMasto(), content: 'Makes you think :thinking:' }) - - const parsedPost = parseStatus(post) - - expect(parsedPost).to.have.property('statusnet_html').that.contains(' { const post = makeMockStatusMasto({ emojis: makeMockEmojiMasto(), spoiler_text: 'CW: 300 IQ :thinking:' })