fix: preserve newlines correctly in delete-and-redraft (#845)

fixes #830
This commit is contained in:
Nolan Lawson 2018-12-19 00:57:56 -08:00 committed by GitHub
parent d5eac4e119
commit 27da387a01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 27 deletions

View 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()
}

View file

@ -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()
}
}
}

View file

@ -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"
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
}

View file

@ -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')
})