FIX: Properly convert quotes to Markdown (#8808)

* FIX: Properly convert quotes to Markdown

When quoting a quote it used to convert the quote header, including the
user avatar and username, into a image and some text and then the
contents. This also caused issues when quoting full paragraphs (or when
selecting paragraphs by triple-clicking) because the user avatar and
name from the following quote would also be included.

This commit implements the support necessary to convert
<aside class="quote"> elements to proper Discourse quotes.
This commit is contained in:
Bianca Nenciu 2020-02-07 17:25:23 +02:00 committed by GitHub
parent 6f3952e7f1
commit 88a4d5a2c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 12 deletions

View File

@ -48,23 +48,21 @@ export default Component.extend({
}
}
let opts;
let opts = { raw: true };
for (
let element = selectedElement();
element && element.tagName !== "ARTICLE";
element = element.parentElement
) {
if (element.tagName === "ASIDE" && element.classList.contains("quote")) {
opts = {
username:
opts.username =
element.dataset.username ||
element
.querySelector(".title")
.textContent.trim()
.replace(/:$/, ""),
post: element.dataset.post,
topic: element.dataset.topic
};
.replace(/:$/, "");
opts.post = element.dataset.post;
opts.topic = element.dataset.topic;
}
}

View File

@ -44,7 +44,6 @@ export class Tag {
return [
"address",
"article",
"aside",
"dd",
"div",
"dl",
@ -89,6 +88,7 @@ export class Tag {
...Tag.blocks(),
...Tag.headings(),
...Tag.slices(),
"aside",
"li",
"td",
"th",
@ -126,6 +126,45 @@ export class Tag {
};
}
static aside() {
return class extends Tag.block("aside") {
constructor() {
super();
}
toMarkdown() {
if (!/\bquote\b/.test(this.element.attributes.class)) {
return super.toMarkdown();
}
const blockquote = this.element.children.find(
child => child.name === "blockquote"
);
if (!blockquote) {
return super.toMarkdown();
}
let text = Element.parse([blockquote], this.element) || "";
text = text.trim().replace(/^>/g, "");
if (text.length === 0) {
return "";
}
const username = this.element.attributes["data-username"];
const post = this.element.attributes["data-post"];
const topic = this.element.attributes["data-topic"];
const prefix =
username && post && topic
? `[quote="${username}, post:${post}, topic:${topic}"]`
: "[quote]";
return `\n\n${prefix}\n${text}\n[/quote]\n\n`;
}
};
}
static heading(name, i) {
const prefix = `${[...Array(i)].map(() => "#").join("")} `;
return Tag.block(name, prefix, "");
@ -484,6 +523,7 @@ function tags() {
...Tag.slices().map(s => Tag.slice(s, "\n")),
...Tag.emphases().map(e => Tag.emphasis(e[0], e[1])),
...Tag.whitelists().map(t => Tag.whitelist(t)),
Tag.aside(),
Tag.cell("td"),
Tag.cell("th"),
Tag.replace("br", "\n"),

View File

@ -386,3 +386,30 @@ QUnit.test("converts image lightboxes to markdown", assert => {
assert.equal(toMarkdown(html), markdown);
});
QUnit.test("converts quotes to markdown", assert => {
let html = `
<p>there is a quote below</p>
<aside class="quote no-group" data-username="foo" data-post="1" data-topic="2">
<div class="title" style="cursor: pointer;">
<div class="quote-controls"><span class="svg-icon-title" title="expand/collapse"><svg class="fa d-icon d-icon-chevron-down svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use xlink:href="#chevron-down"></use></svg></span><a href="/t/hello-world-i-am-posting-an-image/158/1" title="go to the quoted post" class="back"><svg class="fa d-icon d-icon-arrow-up svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use xlink:href="#arrow-up"></use></svg></a></div>
<img alt="" width="20" height="20" src="" class="avatar"> foo:</div>
<blockquote>
<p>this is a quote</p>
</blockquote>
</aside>
<p>there is a quote above</p>
`;
let markdown = `
there is a quote below
[quote="foo, post:1, topic:2"]
this is a quote
[/quote]
there is a quote above
`;
assert.equal(toMarkdown(html), markdown.trim());
});