diff --git a/app/assets/javascripts/discourse/dialects/code_dialect.js b/app/assets/javascripts/discourse/dialects/code_dialect.js
index 8f0ff739a2..5bb5d6b8b0 100644
--- a/app/assets/javascripts/discourse/dialects/code_dialect.js
+++ b/app/assets/javascripts/discourse/dialects/code_dialect.js
@@ -10,6 +10,15 @@ var acceptableCodeClasses =
"profile", "python", "r", "rib", "rsl", "ruby", "rust", "scala", "smalltalk", "sql", "tex", "text",
"vala", "vbscript", "vhdl"];
+function flattenBlocks(blocks) {
+ var result = "";
+ blocks.forEach(function(b) {
+ result += b;
+ if (b.trailing) { result += b.trailing; }
+ });
+ return result;
+}
+
Discourse.Dialect.replaceBlock({
start: /^`{3}([^\n\[\]]+)?\n?([\s\S]*)?/gm,
stop: '```',
@@ -19,7 +28,7 @@ Discourse.Dialect.replaceBlock({
if (matches[1] && acceptableCodeClasses.indexOf(matches[1]) !== -1) {
klass = matches[1];
}
- return ['p', ['pre', ['code', {'class': klass}, blockContents.join("\n") ]]];
+ return ['p', ['pre', ['code', {'class': klass}, flattenBlocks(blockContents) ]]];
}
});
@@ -50,6 +59,6 @@ Discourse.Dialect.replaceBlock({
skipIfTradtionalLinebreaks: true,
emitter: function(blockContents) {
- return ['p', ['pre', blockContents.join("\n")]];
+ return ['p', ['pre', flattenBlocks(blockContents)]];
}
});
diff --git a/app/assets/javascripts/discourse/dialects/dialect.js b/app/assets/javascripts/discourse/dialects/dialect.js
index 67f7cb8cc9..94d81d1d0e 100644
--- a/app/assets/javascripts/discourse/dialects/dialect.js
+++ b/app/assets/javascripts/discourse/dialects/dialect.js
@@ -133,6 +133,19 @@ function invalidBoundary(args, prev) {
if (args.spaceOrTagBoundary && (!last.match(/(\s|\>)$/))) { return true; }
}
+/**
+ Returns the number of (terminated) lines in a string.
+
+ @method countLines
+ @param {string} str the string.
+ @returns {Integer} number of terminated lines in str
+**/
+function countLines(str) {
+ var index = -1, count = 0;
+ while ((index = str.indexOf("\n", index + 1)) !== -1) { count++; }
+ return count;
+}
+
/**
An object used for rendering our dialects.
@@ -359,102 +372,71 @@ Discourse.Dialect = {
var linebreaks = dialect.options.traditional_markdown_linebreaks ||
Discourse.SiteSettings.traditional_markdown_linebreaks;
-
- // Some replacers should not be run with traditional linebreaks
if (linebreaks && args.skipIfTradtionalLinebreaks) { return; }
args.start.lastIndex = 0;
- var m = (args.start).exec(block);
+ var result = [], match = (args.start).exec(block);
+ if (!match) { return; }
- if (!m) { return; }
+ var lastChance = function() {
+ return !next.some(function(e) { return e.indexOf(args.stop) !== -1; });
+ };
- var startPos = args.start.lastIndex - m[0].length,
- leading,
- blockContents = [],
- result = [],
- lineNumber = block.lineNumber;
-
- if (startPos > 0) {
- leading = block.slice(0, startPos);
- lineNumber += (leading.split("\n").length - 1);
-
- var para = ['p'];
- this.processInline(leading).forEach(function (l) {
- para.push(l);
- });
-
- result.push(para);
+ // shave off start tag and leading text, if any.
+ var pos = args.start.lastIndex - match[0].length,
+ leading = block.slice(0, pos),
+ trailing = match[2] ? match[2].replace(/^\n*/, "") : "";
+ if (block.indexOf(args.stop, pos + args.stop.length) === -1 && lastChance()) { return; }
+ if (leading.length > 0) { result.push(['p'].concat(this.processInline(leading))); }
+ if (trailing.length > 0) {
+ next.unshift(MD.mk_block(trailing, block.trailing,
+ block.lineNumber + countLines(leading) + (match[2] ? match[2].length : 0) - trailing.length));
}
- if (m[2]) {
- next.unshift(MD.mk_block(m[2], null, lineNumber + 1));
- }
+ // find matching stop tag in blocks.
+ var contentBlocks = [], nesting = 0, endPos, ep, offset, startPos, sp, m, b;
+ blockloop:
+ while (b = next.shift()) {
+ args.start.lastIndex = 0;
+ startPos = []; sp = 0;
+ while (m = (args.start).exec(b)) {
+ startPos.push(args.start.lastIndex - m[0].length);
+ args.start.lastIndex = args.start.lastIndex - (m[2] ? m[2].length : 0);
+ }
+ endPos = []; ep = 0; offset = 0;
+ while ((pos = b.indexOf(args.stop, offset)) !== -1) {
+ endPos.push(pos);
+ offset += (pos + args.stop.length);
+ }
- lineNumber++;
+ while (ep < endPos.length) {
+ if (sp < startPos.length && startPos[sp] < endPos[ep]) {
+ sp++; nesting++;
+ } else if (nesting > 0) {
+ ep++; nesting--;
+ } else {
+ break blockloop;
+ }
+ }
- var blockClosed = false;
- for (var i=0; i abc hello [quote=\"Bob, post:2, topic:1\"]
\n\n\nhello\n
\n",
- "\nhello
hello", "pre blocks don't include extra lines"); cooked("```\na\nb\nc\n\nd\n```",