From a3757016d9e30dc998062b34203cca40fa78573f Mon Sep 17 00:00:00 2001
From: Robin Ward
Date: Wed, 21 Aug 2013 22:36:02 -0400
Subject: [PATCH] FIX: Quotes with new lines were broken
---
.../discourse/dialects/bbcode_dialect.js | 102 ++++++++++++------
.../discourse/views/composer_view.js | 9 +-
test/javascripts/components/bbcode_test.js | 8 +-
test/javascripts/components/markdown_test.js | 14 ++-
4 files changed, 86 insertions(+), 47 deletions(-)
diff --git a/app/assets/javascripts/discourse/dialects/bbcode_dialect.js b/app/assets/javascripts/discourse/dialects/bbcode_dialect.js
index 1c4c38ea6b1..9ac4475af1a 100644
--- a/app/assets/javascripts/discourse/dialects/bbcode_dialect.js
+++ b/app/assets/javascripts/discourse/dialects/bbcode_dialect.js
@@ -107,46 +107,80 @@ Discourse.Dialect.on("register", function(event) {
@return {Array} the JsonML containing the markup or undefined if nothing changed.
@namespace Discourse.Dialect
**/
- dialect.inline["[quote="] = function bbcodeQuote(text, orig_match) {
- var bbcodePattern = new RegExp("\\[quote=?([^\\[\\]]+)?\\]([\\s\\S]*?)\\[\\/quote\\]", "igm"),
- m = bbcodePattern.exec(text);
+ 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 (!m) { return; }
- var paramsString = m[1].replace(/\"/g, ''),
- params = {'class': 'quote'},
- paramsSplit = paramsString.split(/\, */),
- username = paramsSplit[0],
- opts = dialect.options;
+ if (startPos > 0) {
+ leading = block.slice(0, startPos);
- 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 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 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);
+ var contents = this.processInline(quoteContents.join(" \n \n"));
+ contents.unshift('blockquote');
+
+
+ result.push(['p', ['aside', params,
+ ['div', {'class': 'title'},
+ ['div', {'class': 'quote-controls'}],
+ avatarImg ? avatarImg + "\n" : "",
+ I18n.t('user.said',{username: username})
+ ],
+ contents
+ ]]);
+ return result;
}
-
- var quote = ['aside', params,
- ['div', {'class': 'title'},
- ['div', {'class': 'quote-controls'}],
- avatarImg ? avatarImg + "\n" : "",
- I18n.t('user.said',{username: username})
- ],
- ['blockquote'].concat(this.processInline(m[2]))
- ];
-
- return [m[0].length, quote];
};
});
diff --git a/app/assets/javascripts/discourse/views/composer_view.js b/app/assets/javascripts/discourse/views/composer_view.js
index 57fada42edb..707c5df7892 100644
--- a/app/assets/javascripts/discourse/views/composer_view.js
+++ b/app/assets/javascripts/discourse/views/composer_view.js
@@ -192,9 +192,12 @@ Discourse.ComposerView = Discourse.View.extend({
this.editor = editor = Discourse.Markdown.createEditor({
lookupAvatarByPostNumber: function(postNumber) {
- var quotedPost = composerView.get('controller.controllers.topic.postStream.posts').findProperty("post_number", postNumber);
- if (quotedPost) {
- return Discourse.Utilities.tinyAvatar(quotedPost.get("avatar_template"));
+ var posts = composerView.get('controller.controllers.topic.postStream.posts');
+ if (posts) {
+ var quotedPost = posts.findProperty("post_number", postNumber);
+ if (quotedPost) {
+ return Discourse.Utilities.tinyAvatar(quotedPost.get("avatar_template"));
+ }
}
}
});
diff --git a/test/javascripts/components/bbcode_test.js b/test/javascripts/components/bbcode_test.js
index dc04b8e56d2..d198ffd92e2 100644
--- a/test/javascripts/components/bbcode_test.js
+++ b/test/javascripts/components/bbcode_test.js
@@ -88,15 +88,9 @@ test("quote formatting", function() {
format("[quote=\"eviltrout, post:1, topic:1\"]abc[/quote]\nhello",
"
\nhello",
+ "abc
\n\n\nhello",
"handles new lines properly");
- format("before[quote=\"eviltrout, post:1, topic:1\"]first[/quote]middle[quote=\"eviltrout, post:2, topic:2\"]second[/quote]after",
- "before
middle
after",
- "can handle more than one quote");
-
});
diff --git a/test/javascripts/components/markdown_test.js b/test/javascripts/components/markdown_test.js
index ff7fb0d586e..cce57a4412a 100644
--- a/test/javascripts/components/markdown_test.js
+++ b/test/javascripts/components/markdown_test.js
@@ -85,15 +85,23 @@ test("Links", function() {
});
test("Quotes", function() {
+
+ cookedOptions("[quote=\"eviltrout, post: 1\"]\na quote\n\nsecond line\n[/quote]",
+ { topicId: 2 },
+ "
",
+ "works with multiple lines");
+
cookedOptions("1[quote=\"bob, post:1\"]my quote[/quote]2",
{ topicId: 2, lookupAvatar: function(name) { return "" + name; } },
- "1
2
",
+ "1
\n\n\n\n2
",
"handles quotes properly");
cookedOptions("1[quote=\"bob, post:1\"]my quote[/quote]2",
{ topicId: 2, lookupAvatar: function(name) { } },
- "1
2
",
+ "1
\n\n\n\n2
",
"includes no avatar if none is found");
});