fixed bug with hashtags

This commit is contained in:
Henry Jameson 2021-06-15 14:43:44 +03:00
parent 7309f8ce1a
commit 4aac0125e5
2 changed files with 57 additions and 12 deletions

View file

@ -85,7 +85,6 @@ export default Vue.component('RichContent', {
attrs.target = '_blank' attrs.target = '_blank'
if (!encounteredTextReverse) { if (!encounteredTextReverse) {
lastTags.push(linkData) lastTags.push(linkData)
attrs['data-parser-last'] = true
} }
return <a {...{ attrs }}> return <a {...{ attrs }}>
{ children.map(processItem) } { children.map(processItem) }
@ -128,7 +127,7 @@ export default Vue.component('RichContent', {
encounteredText = true encounteredText = true
} }
if (item.includes(':')) { if (item.includes(':')) {
unescapedItem = processTextForEmoji( unescapedItem = ['', processTextForEmoji(
unescapedItem, unescapedItem,
this.emoji, this.emoji,
({ shortcode, url }) => { ({ shortcode, url }) => {
@ -139,14 +138,14 @@ export default Vue.component('RichContent', {
alt={`:${shortcode}:`} alt={`:${shortcode}:`}
/> />
} }
) )]
} }
return unescapedItem return unescapedItem
} }
// Handle tag nodes // Handle tag nodes
if (Array.isArray(item)) { if (Array.isArray(item)) {
const [opener, children] = item const [opener, children, closer] = item
const Tag = getTagName(opener) const Tag = getTagName(opener)
const attrs = getAttrs(opener) const attrs = getAttrs(opener)
switch (Tag) { switch (Tag) {
@ -176,14 +175,10 @@ export default Vue.component('RichContent', {
</a> </a>
} }
} }
// Render tag as is
if (children !== undefined) { if (children !== undefined) {
return <Tag {...{ attrs: getAttrs(opener) }}> return [opener, children.map(processItem), closer]
{ children.map(processItem) }
</Tag>
} else { } else {
return <Tag/> return item
} }
} }
} }
@ -200,7 +195,7 @@ export default Vue.component('RichContent', {
} else if (Array.isArray(item)) { } else if (Array.isArray(item)) {
// Handle tag nodes // Handle tag nodes
const [opener, children] = item const [opener, children] = item
const Tag = getTagName(opener) const Tag = opener === '' ? '' : getTagName(opener)
switch (Tag) { switch (Tag) {
case 'a': // replace mentions with MentionLink case 'a': // replace mentions with MentionLink
if (!this.handleLinks) break if (!this.handleLinks) break
@ -209,16 +204,30 @@ export default Vue.component('RichContent', {
if (attrs['class'] && attrs['class'].includes('hashtag')) { if (attrs['class'] && attrs['class'].includes('hashtag')) {
return renderHashtag(attrs, children, encounteredTextReverse) return renderHashtag(attrs, children, encounteredTextReverse)
} }
break
case '':
return [...children].reverse().map(processItemReverse).reverse()
}
// Render tag as is
if (children !== undefined) {
return <Tag {...{ attrs: getAttrs(opener) }}>
{ Array.isArray(children) ? [...children].reverse().map(processItemReverse).reverse() : children }
</Tag>
} else {
return <Tag/>
} }
} }
return item return item
} }
const pass1 = convertHtmlToTree(html).map(processItem)
const pass2 = [...pass1].reverse().map(processItemReverse).reverse()
// DO NOT USE SLOTS they cause a re-render feedback loop here. // DO NOT USE SLOTS they cause a re-render feedback loop here.
// slots updated -> rerender -> emit -> update up the tree -> rerender -> ... // slots updated -> rerender -> emit -> update up the tree -> rerender -> ...
// at least until vue3? // at least until vue3?
const result = <span class="RichContent"> const result = <span class="RichContent">
{ convertHtmlToTree(html).map(processItem).reverse().map(processItemReverse).reverse() } { pass2 }
</span> </span>
const event = { const event = {

View file

@ -603,4 +603,40 @@ describe('RichContent', () => {
expect(wrapper.html()).to.eql(compwrap(expected)) expect(wrapper.html()).to.eql(compwrap(expected))
}) })
it('buggy example/hashtags', () => {
const html = [
'<p>',
'<a href="http://macrochan.org/images/N/H/NHCMDUXJPPZ6M3Z2CQ6D2EBRSWGE7MZY.jpg">',
'NHCMDUXJPPZ6M3Z2CQ6D2EBRSWGE7MZY.jpg</a>',
' <a class="hashtag" data-tag="nou" href="https://shitposter.club/tag/nou">',
'#nou</a>',
' <a class="hashtag" data-tag="screencap" href="https://shitposter.club/tag/screencap">',
'#screencap</a>',
' </p>'
].join('')
const expected = [
'<p>',
'<a href="http://macrochan.org/images/N/H/NHCMDUXJPPZ6M3Z2CQ6D2EBRSWGE7MZY.jpg" target="_blank">',
'NHCMDUXJPPZ6M3Z2CQ6D2EBRSWGE7MZY.jpg</a>',
' <a class="hashtag" data-tag="nou" href="https://shitposter.club/tag/nou" target="_blank">',
'#nou</a>',
' <a class="hashtag" data-tag="screencap" href="https://shitposter.club/tag/screencap" target="_blank">',
'#screencap</a>',
' </p>'
].join('')
const wrapper = shallowMount(RichContent, {
localVue,
propsData: {
hideMentions: true,
handleLinks: true,
greentext: true,
emoji: [],
html
}
})
expect(wrapper.html()).to.eql(compwrap(expected))
})
}) })