diff --git a/app/assets/javascripts/discourse/lib/to-markdown.js.es6 b/app/assets/javascripts/discourse/lib/to-markdown.js.es6
index 4fb5b92b126..8f81536f226 100644
--- a/app/assets/javascripts/discourse/lib/to-markdown.js.es6
+++ b/app/assets/javascripts/discourse/lib/to-markdown.js.es6
@@ -29,9 +29,8 @@ class Tag {
}
static blocks() {
- return ["address", "article", "aside", "dd", "div", "dl", "dt", "fieldset",
- "figcaption", "figure", "footer", "form", "header", "hgroup", "hr", "main", "nav",
- "ol", "p", "pre", "section", "table", "ul"];
+ return ["address", "article", "aside", "dd", "div", "dl", "dt", "fieldset", "figcaption", "figure",
+ "footer", "form", "header", "hgroup", "hr", "main", "nav", "p", "pre", "section", "ul"];
}
static headings() {
@@ -47,7 +46,7 @@ class Tag {
}
static trimmable() {
- return [...Tag.blocks(), ...Tag.headings(), ...Tag.slices(), "li", "td", "th", "br", "hr", "blockquote"];
+ return [...Tag.blocks(), ...Tag.headings(), ...Tag.slices(), "li", "td", "th", "br", "hr", "blockquote", "table", "ol"];
}
static block(name, prefix, suffix) {
@@ -116,7 +115,7 @@ class Tag {
decorate(text) {
const attr = this.element.attributes;
- if (attr && attr.href && text !== attr.href) {
+ if (attr.href && text !== attr.href) {
text = text.replace(/\n{2,}/g, "\n");
return "[" + text + "](" + attr.href + ")";
}
@@ -134,7 +133,7 @@ class Tag {
toMarkdown() {
const e = this.element;
- const attr = e.attributes || {};
+ const attr = e.attributes;
const pAttr = (e.parent && e.parent.attributes) || {};
const src = attr.src || pAttr.src;
@@ -171,13 +170,31 @@ class Tag {
}
static cell(name) {
- return Tag.slice(name, " ");
+ return class extends Tag {
+ constructor() {
+ super(name, "|");
+ }
+
+ toMarkdown() {
+ const text = this.element.innerMarkdown().trim();
+
+ if (text.includes("\n") || text.includes("[![")) {
+ throw "Unsupported format inside Markdown table cells";
+ }
+
+ if (!this.element.next) {
+ this.suffix = "|";
+ }
+
+ return this.decorate(text);
+ }
+ };
}
static li() {
return class extends Tag.slice("li", "\n") {
decorate(text) {
- const indent = this.element.filterParentNames("ul").slice(1).map(() => " ").join("");
+ const indent = this.element.filterParentNames(["ol", "ul"]).slice(1).map(() => " ").join("");
return super.decorate(`${indent}* ${trimLeft(text)}`);
}
};
@@ -214,6 +231,32 @@ class Tag {
};
}
+ static table() {
+ return class extends Tag.block("table") {
+ decorate(text) {
+ text = super.decorate(text);
+ const splitterRow = text.split("|\n")[0].match(/\|/g).map(() => "| --- ").join("") + "|\n";
+ text = text.replace("|\n", "|\n" + splitterRow).replace(/\|\n{2,}\|/g, "|\n|");
+ return text;
+ }
+ };
+ }
+
+ static ol() {
+ return class extends Tag.block("ol") {
+ decorate(text) {
+ text = "\n" + text;
+ const bullet = text.match(/\n *\*/)[0];
+
+ for (let i = parseInt(this.element.attributes.start || 1); text.includes(bullet); i++) {
+ text = text.replace(bullet, bullet.replace("*", `${i}.`));
+ }
+
+ return super.decorate(text.slice(1));
+ }
+ };
+ }
+
}
const tags = [
@@ -224,10 +267,7 @@ const tags = [
Tag.cell("td"), Tag.cell("th"),
Tag.replace("br", "\n"), Tag.replace("hr", "\n---\n"), Tag.replace("head", ""),
Tag.keep("ins"), Tag.keep("del"), Tag.keep("small"), Tag.keep("big"),
- Tag.li(), Tag.link(), Tag.image(), Tag.code(), Tag.blockquote(),
-
- // TO-DO CREATE: tbody
- // UPDATE: ol, thead, th, td
+ Tag.li(), Tag.link(), Tag.image(), Tag.code(), Tag.blockquote(), Tag.table(),, Tag.ol(),
];
class Element {
@@ -236,7 +276,7 @@ class Element {
this.type = element.type;
this.data = element.data;
this.children = element.children;
- this.attributes = element.attributes;
+ this.attributes = element.attributes || {};
if (parent) {
this.parent = parent;
@@ -294,8 +334,8 @@ class Element {
}
}
- filterParentNames(name) {
- return this.parentNames.filter(p => p === name);
+ filterParentNames(names) {
+ return this.parentNames.filter(p => names.includes(p));
}
static toMarkdown(element, parent, prev, next) {
diff --git a/test/javascripts/lib/to-markdown-test.js.es6 b/test/javascripts/lib/to-markdown-test.js.es6
index 9cf2707c511..4ebb94ec9ae 100644
--- a/test/javascripts/lib/to-markdown-test.js.es6
+++ b/test/javascripts/lib/to-markdown-test.js.es6
@@ -67,7 +67,7 @@ QUnit.test("converts heading tags", assert => {
assert.equal(toMarkdown(html), markdown);
});
-QUnit.test("converts ul and ol list tags", assert => {
+QUnit.test("converts ul list tag", assert => {
const html = `
- Item 1
@@ -95,7 +95,7 @@ QUnit.test("stripes unwanted inline tags", assert => {
assert.equal(toMarkdown(html), markdown);
});
-QUnit.test("converts table as readable", assert => {
+QUnit.test("converts table tags", assert => {
const html = `
Discourse Avenuelaboris
Heading 1 | Head 2 |
@@ -104,10 +104,21 @@ QUnit.test("converts table as readable", assert => {
dolor | sit amet |
`;
- const markdown = `Discourse Avenue\n\n**laboris**\n\nHeading 1 Head 2\n\nLorem ipsum\n**dolor** _sit amet_`;
+ const markdown = `Discourse Avenue\n\n**laboris**\n\n|Heading 1|Head 2|\n| --- | --- |\n|Lorem|ipsum|\n|**dolor**|_sit amet_|`;
assert.equal(toMarkdown(html), markdown);
});
+QUnit.test("returns empty string if table format not supported", assert => {
+ const html = `
+ Headi\n\nng 1 | Head 2 |
+
+ Lorem | ipsum |
+  | sit amet |
+
+ `;
+ assert.equal(toMarkdown(html), "");
+});
+
QUnit.test("converts img tag", assert => {
const url = "https://example.com/image.png";
let html = `
`;
@@ -184,3 +195,22 @@ QUnit.test("converts blockquote tag", assert => {
output = "> Lorem ipsum\n> > dolor\n> > > sit\n> > amet";
assert.equal(toMarkdown(html), output);
});
+
+QUnit.test("converts ol list tag", assert => {
+ const html = `Testing
+
+ - Item 1
+ -
+ Item 2
+
+ - Sub Item 1
+ - Sub Item 2
+ - Sub Sub Item 1
- Sub Sub Item 2
+
+
+ - Item 3
+
+ `;
+ const markdown = `Testing\n\n1. Item 1\n2. Item 2\n\n 100. Sub Item 1\n 101. Sub Item 2\n\n * Sub _Sub_ Item 1\n * Sub **Sub** Item 2\n\n3. Item 3`;
+ assert.equal(toMarkdown(html), markdown);
+});