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 ( for (
let element = selectedElement(); let element = selectedElement();
element && element.tagName !== "ARTICLE"; element && element.tagName !== "ARTICLE";
element = element.parentElement element = element.parentElement
) { ) {
if (element.tagName === "ASIDE" && element.classList.contains("quote")) { if (element.tagName === "ASIDE" && element.classList.contains("quote")) {
opts = { opts.username =
username:
element.dataset.username || element.dataset.username ||
element element
.querySelector(".title") .querySelector(".title")
.textContent.trim() .textContent.trim()
.replace(/:$/, ""), .replace(/:$/, "");
post: element.dataset.post, opts.post = element.dataset.post;
topic: element.dataset.topic opts.topic = element.dataset.topic;
};
} }
} }

View File

@ -44,7 +44,6 @@ export class Tag {
return [ return [
"address", "address",
"article", "article",
"aside",
"dd", "dd",
"div", "div",
"dl", "dl",
@ -89,6 +88,7 @@ export class Tag {
...Tag.blocks(), ...Tag.blocks(),
...Tag.headings(), ...Tag.headings(),
...Tag.slices(), ...Tag.slices(),
"aside",
"li", "li",
"td", "td",
"th", "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) { static heading(name, i) {
const prefix = `${[...Array(i)].map(() => "#").join("")} `; const prefix = `${[...Array(i)].map(() => "#").join("")} `;
return Tag.block(name, prefix, ""); return Tag.block(name, prefix, "");
@ -484,6 +523,7 @@ function tags() {
...Tag.slices().map(s => Tag.slice(s, "\n")), ...Tag.slices().map(s => Tag.slice(s, "\n")),
...Tag.emphases().map(e => Tag.emphasis(e[0], e[1])), ...Tag.emphases().map(e => Tag.emphasis(e[0], e[1])),
...Tag.whitelists().map(t => Tag.whitelist(t)), ...Tag.whitelists().map(t => Tag.whitelist(t)),
Tag.aside(),
Tag.cell("td"), Tag.cell("td"),
Tag.cell("th"), Tag.cell("th"),
Tag.replace("br", "\n"), Tag.replace("br", "\n"),

View File

@ -386,3 +386,30 @@ QUnit.test("converts image lightboxes to markdown", assert => {
assert.equal(toMarkdown(html), markdown); 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());
});