forked from AkkomaGang/akkoma-fe
Merge branch 'better-still-emoji' into proper-attachments
* better-still-emoji: fix non-notifying mentions and original mention display fix not escaping some stuff fix rich images
This commit is contained in:
commit
dd3fe61cf3
7 changed files with 65 additions and 12 deletions
|
@ -5,8 +5,9 @@
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<a
|
<a
|
||||||
v-if="!user"
|
v-if="!user"
|
||||||
href="url"
|
:href="url"
|
||||||
class="original"
|
class="original"
|
||||||
|
target="_blank"
|
||||||
v-html="content"
|
v-html="content"
|
||||||
/>
|
/>
|
||||||
<!-- eslint-enable vue/no-v-html -->
|
<!-- eslint-enable vue/no-v-html -->
|
||||||
|
|
|
@ -36,6 +36,10 @@ export default Vue.component('RichContent', {
|
||||||
required: true,
|
required: true,
|
||||||
type: String
|
type: String
|
||||||
},
|
},
|
||||||
|
attentions: {
|
||||||
|
required: false,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
// Emoji object, as in status.emojis, note the "s" at the end...
|
// Emoji object, as in status.emojis, note the "s" at the end...
|
||||||
emoji: {
|
emoji: {
|
||||||
required: true,
|
required: true,
|
||||||
|
@ -91,8 +95,12 @@ export default Vue.component('RichContent', {
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderMention = (attrs, children, encounteredText) => {
|
const renderMention = (attrs, children) => {
|
||||||
const linkData = getLinkData(attrs, children, mentionIndex++)
|
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)
|
writtenMentions.push(linkData)
|
||||||
if (!encounteredText) {
|
if (!encounteredText) {
|
||||||
firstMentions.push(linkData)
|
firstMentions.push(linkData)
|
||||||
|
@ -121,14 +129,13 @@ export default Vue.component('RichContent', {
|
||||||
if (emptyText) {
|
if (emptyText) {
|
||||||
return encounteredText ? item : item.trim()
|
return encounteredText ? item : item.trim()
|
||||||
}
|
}
|
||||||
let unescapedItem = unescape(item)
|
|
||||||
if (!encounteredText) {
|
if (!encounteredText) {
|
||||||
unescapedItem = unescapedItem.trimStart()
|
item = item.trimStart()
|
||||||
encounteredText = true
|
encounteredText = true
|
||||||
}
|
}
|
||||||
if (item.includes(':')) {
|
if (item.includes(':')) {
|
||||||
unescapedItem = ['', processTextForEmoji(
|
item = ['', processTextForEmoji(
|
||||||
unescapedItem,
|
item,
|
||||||
this.emoji,
|
this.emoji,
|
||||||
({ shortcode, url }) => {
|
({ shortcode, url }) => {
|
||||||
return <StillImage
|
return <StillImage
|
||||||
|
@ -140,7 +147,7 @@ export default Vue.component('RichContent', {
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
return unescapedItem
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle tag nodes
|
// Handle tag nodes
|
||||||
|
@ -149,7 +156,7 @@ export default Vue.component('RichContent', {
|
||||||
const Tag = getTagName(opener)
|
const Tag = getTagName(opener)
|
||||||
const attrs = getAttrs(opener)
|
const attrs = getAttrs(opener)
|
||||||
switch (Tag) {
|
switch (Tag) {
|
||||||
case 'span': // replace images with StillImage
|
case 'span': // Replace last mentions class with mentionsline
|
||||||
if (attrs['class'] && attrs['class'].includes('lastMentions')) {
|
if (attrs['class'] && attrs['class'].includes('lastMentions')) {
|
||||||
if (firstMentions.length > 1 && lastMentions.length > 1) {
|
if (firstMentions.length > 1 && lastMentions.length > 1) {
|
||||||
break
|
break
|
||||||
|
@ -189,7 +196,7 @@ export default Vue.component('RichContent', {
|
||||||
const emptyText = item.trim() === ''
|
const emptyText = item.trim() === ''
|
||||||
if (emptyText) return item
|
if (emptyText) return item
|
||||||
if (!encounteredTextReverse) encounteredTextReverse = true
|
if (!encounteredTextReverse) encounteredTextReverse = true
|
||||||
return item
|
return unescape(item)
|
||||||
} else if (Array.isArray(item)) {
|
} else if (Array.isArray(item)) {
|
||||||
// Handle tag nodes
|
// Handle tag nodes
|
||||||
const [opener, children] = item
|
const [opener, children] = item
|
||||||
|
@ -203,9 +210,7 @@ export default Vue.component('RichContent', {
|
||||||
return renderHashtag(attrs, children, encounteredTextReverse)
|
return renderHashtag(attrs, children, encounteredTextReverse)
|
||||||
} else {
|
} else {
|
||||||
attrs.target = '_blank'
|
attrs.target = '_blank'
|
||||||
html.includes('freenode') && console.log('PASS1', children)
|
|
||||||
const newChildren = [...children].reverse().map(processItemReverse).reverse()
|
const newChildren = [...children].reverse().map(processItemReverse).reverse()
|
||||||
html.includes('freenode') && console.log('PASS1b', newChildren)
|
|
||||||
|
|
||||||
return <a {...{ attrs }}>
|
return <a {...{ attrs }}>
|
||||||
{ newChildren }
|
{ newChildren }
|
||||||
|
|
|
@ -86,6 +86,20 @@ const StatusContent = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
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 () {
|
toggleShowMore () {
|
||||||
if (this.mightHideBecauseTall) {
|
if (this.mightHideBecauseTall) {
|
||||||
this.showingTall = !this.showingTall
|
this.showingTall = !this.showingTall
|
||||||
|
|
|
@ -50,7 +50,8 @@
|
||||||
:handle-links="true"
|
:handle-links="true"
|
||||||
:hide-mentions="hideMentions"
|
:hide-mentions="hideMentions"
|
||||||
:greentext="mergedConfig.greentext"
|
:greentext="mergedConfig.greentext"
|
||||||
@parseReady="$emit('parseReady', $event)"
|
:attentions="status.attentions"
|
||||||
|
@parseReady="onParseReady"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -114,6 +114,8 @@ export const convertHtmlToLines = (html) => {
|
||||||
} else {
|
} else {
|
||||||
handleOpen(tagFull)
|
handleOpen(tagFull)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
textBuffer += tagFull
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
textBuffer += tagFull
|
textBuffer += tagFull
|
||||||
|
|
|
@ -27,6 +27,29 @@ describe('RichContent', () => {
|
||||||
expect(wrapper.html()).to.eql(compwrap(html))
|
expect(wrapper.html()).to.eql(compwrap(html))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('unescapes everything as needed', () => {
|
||||||
|
const html = [
|
||||||
|
p('Testing 'em all'),
|
||||||
|
'Testing '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', () => {
|
it('removes mentions from the beginning of post', () => {
|
||||||
const html = p(
|
const html = p(
|
||||||
makeMention('John'),
|
makeMention('John'),
|
||||||
|
|
|
@ -69,6 +69,13 @@ describe('html_line_converter', () => {
|
||||||
const comparableResult = result.map(mapOnlyText(processorKeep)).join('')
|
const comparableResult = result.map(mapOnlyText(processorKeep)).join('')
|
||||||
expect(comparableResult).to.eql(inputOutput)
|
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', () => {
|
describe('with processor that replaces lines with word "_" should match expected line when', () => {
|
||||||
const processorReplace = (line) => '_'
|
const processorReplace = (line) => '_'
|
||||||
|
|
Loading…
Reference in a new issue