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",