fix: preserve newlines correctly in delete-and-redraft (#845)
fixes #830
This commit is contained in:
parent
d5eac4e119
commit
27da387a01
24
src/routes/_actions/deleteAndRedraft.js
Normal file
24
src/routes/_actions/deleteAndRedraft.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { statusHtmlToPlainText } from '../_utils/statusHtmlToPlainText'
|
||||
import { importShowComposeDialog } from '../_components/dialog/asyncDialogs'
|
||||
import { doDeleteStatus } from './delete'
|
||||
import { store } from '../_store/store'
|
||||
|
||||
export async function deleteAndRedraft (status) {
|
||||
let deleteStatusPromise = doDeleteStatus(status.id)
|
||||
let dialogPromise = importShowComposeDialog()
|
||||
await deleteStatusPromise
|
||||
|
||||
store.setComposeData('dialog', {
|
||||
text: statusHtmlToPlainText(status.content, status.mentions),
|
||||
contentWarningShown: !!status.spoiler_text,
|
||||
contentWarning: status.spoiler_text || '',
|
||||
postPrivacy: status.visibility,
|
||||
media: status.media_attachments && status.media_attachments.map(_ => ({
|
||||
description: _.description || '',
|
||||
data: _
|
||||
})),
|
||||
inReplyToId: status.in_reply_to_id
|
||||
})
|
||||
let showComposeDialog = await dialogPromise
|
||||
showComposeDialog()
|
||||
}
|
|
@ -20,8 +20,7 @@ import { setAccountMuted } from '../../../_actions/mute'
|
|||
import { setStatusPinnedOrUnpinned } from '../../../_actions/pin'
|
||||
import { setConversationMuted } from '../../../_actions/muteConversation'
|
||||
import { copyText } from '../../../_actions/copyText'
|
||||
import { statusHtmlToPlainText } from '../../../_utils/statusHtmlToPlainText'
|
||||
import { importShowComposeDialog } from '../asyncDialogs'
|
||||
import { deleteAndRedraft } from '../../../_actions/deleteAndRedraft'
|
||||
|
||||
export default {
|
||||
oncreate,
|
||||
|
@ -189,24 +188,8 @@ export default {
|
|||
},
|
||||
async onRedraft () {
|
||||
let { status } = this.get()
|
||||
let deleteStatusPromise = doDeleteStatus(status.id)
|
||||
let dialogPromise = importShowComposeDialog()
|
||||
await deleteStatusPromise
|
||||
|
||||
this.store.setComposeData('dialog', {
|
||||
text: statusHtmlToPlainText(status.content, status.mentions),
|
||||
contentWarningShown: !!status.spoiler_text,
|
||||
contentWarning: status.spoiler_text || '',
|
||||
postPrivacy: status.visibility,
|
||||
media: status.media_attachments && status.media_attachments.map(_ => ({
|
||||
description: _.description || '',
|
||||
data: _
|
||||
})),
|
||||
inReplyToId: status.in_reply_to_id
|
||||
})
|
||||
await deleteAndRedraft(status)
|
||||
this.close()
|
||||
let showComposeDialog = await dialogPromise
|
||||
showComposeDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,8 @@ import { mark, stop } from './marks'
|
|||
|
||||
let domParser = process.browser && new DOMParser()
|
||||
|
||||
export function statusHtmlToPlainText (html, mentions) {
|
||||
if (!html) {
|
||||
return ''
|
||||
}
|
||||
mark('statusHtmlToPlainText')
|
||||
let doc = domParser.parseFromString(html, 'text/html')
|
||||
// mentions like "@foo" have to be expanded to "@foo@example.com"
|
||||
// mentions like "@foo" have to be expanded to "@foo@example.com"
|
||||
function massageMentions (doc, mentions) {
|
||||
let anchors = doc.querySelectorAll('a.mention')
|
||||
for (let i = 0; i < anchors.length; i++) {
|
||||
let anchor = anchors[i]
|
||||
|
@ -18,7 +13,29 @@ export function statusHtmlToPlainText (html, mentions) {
|
|||
anchor.innerText = `@${mention.acct}`
|
||||
}
|
||||
}
|
||||
let res = doc.documentElement.textContent
|
||||
}
|
||||
|
||||
// paragraphs should be separated by double newlines
|
||||
// single <br/>s should become single newlines
|
||||
function innerTextRetainingNewlines (doc) {
|
||||
let paragraphs = doc.querySelectorAll('p')
|
||||
return Array.from(paragraphs).map(paragraph => {
|
||||
let brs = paragraph.querySelectorAll('br')
|
||||
Array.from(brs).forEach(br => {
|
||||
br.parentNode.replaceChild(doc.createTextNode('\n'), br)
|
||||
})
|
||||
return paragraph.textContent
|
||||
}).join('\n\n')
|
||||
}
|
||||
|
||||
export function statusHtmlToPlainText (html, mentions) {
|
||||
if (!html) {
|
||||
return ''
|
||||
}
|
||||
mark('statusHtmlToPlainText')
|
||||
let doc = domParser.parseFromString(html, 'text/html')
|
||||
massageMentions(doc, mentions)
|
||||
let res = innerTextRetainingNewlines(doc)
|
||||
stop('statusHtmlToPlainText')
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -145,3 +145,20 @@ test('delete and redraft reply within thread', async t => {
|
|||
})
|
||||
.expect(getNthStatus(2).exists).notOk()
|
||||
})
|
||||
|
||||
test('multiple paragraphs', async t => {
|
||||
let text = 'hey ho\n\ndouble newline!\njust one newline\njust another newline\n\nanother double newline!'
|
||||
await postAs('foobar', text)
|
||||
await loginAsFoobar(t)
|
||||
await t
|
||||
.hover(getNthStatus(0))
|
||||
.expect(getNthStatusContent(0).innerText).contains(text)
|
||||
.click(getNthStatusOptionsButton(0))
|
||||
.click(dialogOptionsOption.withText('Delete and redraft'))
|
||||
.expect(modalDialog.hasAttribute('aria-hidden')).notOk()
|
||||
.expect(composeModalInput.value).eql(text)
|
||||
.typeText(composeModalInput, '\n\nwoot', { paste: true })
|
||||
.click(composeModalComposeButton)
|
||||
.expect(modalDialog.exists).notOk()
|
||||
.expect(getNthStatusContent(0).innerText).contains(text + '\n\nwoot')
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue