From 3cec95a2c35acb2f460dcb37dc2ffb7a9f042c07 Mon Sep 17 00:00:00 2001
From: Robin Ward
Date: Thu, 29 Aug 2013 11:38:51 -0400
Subject: [PATCH] Better API for parsing out blocks in the parser.
---
.../discourse/dialects/bbcode_dialect.js | 145 +++++-------------
.../javascripts/discourse/dialects/dialect.js | 58 +++++++
.../discourse/dialects/github_code_dialect.js | 77 +---------
spec/components/pretty_text_spec.rb | 2 +-
test/javascripts/components/bbcode_test.js | 4 +-
test/javascripts/components/markdown_test.js | 2 +-
6 files changed, 107 insertions(+), 181 deletions(-)
diff --git a/app/assets/javascripts/discourse/dialects/bbcode_dialect.js b/app/assets/javascripts/discourse/dialects/bbcode_dialect.js
index 8ea9825b4..90c528bf8 100644
--- a/app/assets/javascripts/discourse/dialects/bbcode_dialect.js
+++ b/app/assets/javascripts/discourse/dialects/bbcode_dialect.js
@@ -102,128 +102,61 @@ replaceBBCodeParams("color", function(param, contents) {
}
});
-Discourse.Dialect.on("register", function(event) {
+// Handles `[code] ... [/code]` blocks
+Discourse.Dialect.replaceBlock({
+ start: /(\[code\])([\s\S]*)/igm,
+ stop: '[/code]',
- var dialect = event.dialect,
- MD = event.MD;
+ emitter: function(blockContents) {
+ return ['p', ['pre'].concat(blockContents)];
+ }
+});
- /**
- Support BBCode [code] blocks
+// Support BBCode [quote] blocks
+Discourse.Dialect.replaceBlock({
+ start: new RegExp("\\[quote=?([^\\[\\]]+)?\\]([\\s\\S]*)", "igm"),
+ stop: '[/quote]',
+ emitter: function(blockContents, matches, options) {
- @method bbcodeCode
- @param {Markdown.Block} block the block to examine
- @param {Array} next the next blocks in the sequence
- @return {Array} the JsonML containing the markup or undefined if nothing changed.
- @namespace Discourse.Dialect
- **/
- dialect.inline["[code]"] = function bbcodeCode(text, orig_match) {
- var bbcodePattern = new RegExp("\\[code\\]([\\s\\S]*?)\\[\\/code\\]", "igm"),
- m = bbcodePattern.exec(text);
+ var paramsString = matches[1].replace(/\"/g, ''),
+ params = {'class': 'quote'},
+ paramsSplit = paramsString.split(/\, */),
+ username = paramsSplit[0];
- if (m) {
- var contents = m[1].trim().split("\n");
+ paramsSplit.forEach(function(p,i) {
+ if (i > 0) {
+ var assignment = p.split(':');
+ if (assignment[0] && assignment[1]) {
+ params['data-' + assignment[0]] = assignment[1].trim();
+ }
+ }
+ });
- var html = ['pre', "\n"];
- contents.forEach(function (n) {
- html.push(n.trim());
- html.push(["br"]);
- html.push("\n");
- });
-
- return [m[0].length, html];
+ var avatarImg;
+ if (options.lookupAvatarByPostNumber) {
+ // client-side, we can retrieve the avatar from the post
+ var postNumber = parseInt(params['data-post'], 10);
+ avatarImg = options.lookupAvatarByPostNumber(postNumber);
+ } else if (options.lookupAvatar) {
+ // server-side, we need to lookup the avatar from the username
+ avatarImg = options.lookupAvatar(username);
}
- };
- /**
- Support BBCode [quote] blocks
+ var contents = this.processInline(blockContents.join(" \n \n"));
+ contents.unshift('blockquote');
- @method bbcodeQuote
- @param {Markdown.Block} block the block to examine
- @param {Array} next the next blocks in the sequence
- @return {Array} the JsonML containing the markup or undefined if nothing changed.
- @namespace Discourse.Dialect
- **/
- dialect.block['quote'] = function bbcodeQuote(block, next) {
- var m = new RegExp("\\[quote=?([^\\[\\]]+)?\\]([\\s\\S]*)", "igm").exec(block);
- if (m) {
- var paramsString = m[1].replace(/\"/g, ''),
- params = {'class': 'quote'},
- paramsSplit = paramsString.split(/\, */),
- username = paramsSplit[0],
- opts = dialect.options,
- startPos = block.indexOf(m[0]),
- leading,
- quoteContents = [],
- result = [];
-
- if (startPos > 0) {
- leading = block.slice(0, startPos);
-
- var para = ['p'];
- this.processInline(leading).forEach(function (l) {
- para.push(l);
- });
-
- result.push(para);
- }
-
- paramsSplit.forEach(function(p,i) {
- if (i > 0) {
- var assignment = p.split(':');
- if (assignment[0] && assignment[1]) {
- params['data-' + assignment[0]] = assignment[1].trim();
- }
- }
- });
-
- var avatarImg;
- if (opts.lookupAvatarByPostNumber) {
- // client-side, we can retrieve the avatar from the post
- var postNumber = parseInt(params['data-post'], 10);
- avatarImg = opts.lookupAvatarByPostNumber(postNumber);
- } else if (opts.lookupAvatar) {
- // server-side, we need to lookup the avatar from the username
- avatarImg = opts.lookupAvatar(username);
- }
-
- if (m[2]) { next.unshift(MD.mk_block(m[2])); }
-
- while (next.length > 0) {
- var b = next.shift(),
- n = b.match(/([\s\S]*)\[\/quote\]([\s\S]*)/m);
-
- if (n) {
- if (n[2]) {
- next.unshift(MD.mk_block(n[2]));
- }
- quoteContents.push(n[1]);
- break;
- } else {
- quoteContents.push(b);
- }
- }
-
- var contents = this.processInline(quoteContents.join(" \n \n"));
- contents.unshift('blockquote');
-
-
- result.push(['p', ['aside', params,
+ return ['p', ['aside', params,
['div', {'class': 'title'},
['div', {'class': 'quote-controls'}],
avatarImg ? avatarImg : "",
- I18n.t('user.said',{username: username})
+ I18n.t('user.said', {username: username})
],
contents
- ]]);
- return result;
- }
- };
-
+ ]];
+ }
});
-
Discourse.Dialect.on("parseNode", function(event) {
-
var node = event.node,
path = event.path;
diff --git a/app/assets/javascripts/discourse/dialects/dialect.js b/app/assets/javascripts/discourse/dialects/dialect.js
index 9ee2d24a4..ba208fac9 100644
--- a/app/assets/javascripts/discourse/dialects/dialect.js
+++ b/app/assets/javascripts/discourse/dialects/dialect.js
@@ -204,6 +204,64 @@ Discourse.Dialect = {
};
},
+ replaceBlock: function(args) {
+ dialect.block[args.start.toString()] = function(block, next) {
+ args.start.lastIndex = 0;
+ var m = (args.start).exec(block);
+ if (!m) { return; }
+
+ var startPos = block.indexOf(m[0]),
+ 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);
+ }
+ if (m[2]) { next.unshift(MD.mk_block(m[2], null, lineNumber + 1)); }
+
+ lineNumber++;
+ while (next.length > 0) {
+ var b = next.shift(),
+ blockLine = b.lineNumber,
+ diff = ((typeof blockLine === "undefined") ? lineNumber : blockLine) - lineNumber;
+
+ var endFound = b.indexOf(args.stop),
+ leadingContents = b.slice(0, endFound),
+ trailingContents = b.slice(endFound+args.stop.length);
+
+ for (var i=1; i 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);
- }
-
- if (m[2]) { next.unshift(MD.mk_block(m[2], null, lineNumber + 1)); }
-
- lineNumber++;
- while (next.length > 0) {
- var b = next.shift(),
- blockLine = b.lineNumber,
- diff = ((typeof blockLine === "undefined") ? lineNumber : blockLine) - lineNumber;
-
- var endFound = b.indexOf('```'),
- leadingCode = b.slice(0, endFound),
- trailingCode = b.slice(endFound+3);
-
- for (var i=1; i
"
+ PrettyText.cook("[quote=\"EvilTrout, post:123, topic:456, full:true\"]ddd\n[/quote]").should match_html ""
end
it "should produce a quote" do
diff --git a/test/javascripts/components/bbcode_test.js b/test/javascripts/components/bbcode_test.js
index 71416e267..a72e86559 100644
--- a/test/javascripts/components/bbcode_test.js
+++ b/test/javascripts/components/bbcode_test.js
@@ -11,8 +11,8 @@ test('basic bbcode', function() {
format("[i]emphasis[/i]", "emphasis", "italics text");
format("[u]underlined[/u]", "underlined", "underlines text");
format("[s]strikethrough[/s]", "strikethrough", "strikes-through text");
- format("[code]\nx++\n[/code]", "\nx++
\n
", "makes code into pre");
- format("[code]\nx++\ny++\nz++\n[/code]", "\nx++
\ny++
\nz++
\n
", "makes code into pre");
+ format("[code]\nx++\n[/code]", "\nx++
", "makes code into pre");
+ format("[code]\nx++\ny++\nz++\n[/code]", "\nx++\ny++\nz++
", "makes code into pre");
format("[spoiler]it's a sled[/spoiler]", "it's a sled", "supports spoiler tags");
format("[img]http://eviltrout.com/eviltrout.png[/img]", "
", "links images");
format("[url]http://bettercallsaul.com[/url]", "http://bettercallsaul.com", "supports [url] without a title");
diff --git a/test/javascripts/components/markdown_test.js b/test/javascripts/components/markdown_test.js
index b4a22bf1b..118164da5 100644
--- a/test/javascripts/components/markdown_test.js
+++ b/test/javascripts/components/markdown_test.js
@@ -114,7 +114,7 @@ test("Quotes", function() {
cookedOptions("[quote=\"eviltrout, post: 1\"]\na quote\n\nsecond line\n[/quote]",
{ topicId: 2 },
"",
+ "a quote
second line",
"works with multiple lines");
cookedOptions("1[quote=\"bob, post:1\"]my quote[/quote]2",