From 689b296204e782a6d2365063671a448ff444da85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 27 Jun 2013 00:41:48 +0200 Subject: [PATCH] FIX: urls in BBCode tags weren't working --- .../discourse/components/bbcode.js | 47 +++++++++++++++++-- .../discourse/components/markdown.js | 18 ++++--- test/javascripts/components/markdown_test.js | 23 ++++++--- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/app/assets/javascripts/discourse/components/bbcode.js b/app/assets/javascripts/discourse/components/bbcode.js index ac39819c74b..4dbc9506d5a 100644 --- a/app/assets/javascripts/discourse/components/bbcode.js +++ b/app/assets/javascripts/discourse/components/bbcode.js @@ -10,6 +10,9 @@ Discourse.BBCode = { QUOTE_REGEXP: /\[quote=([^\]]*)\]((?:[\s\S](?!\[quote=[^\]]*\]))*?)\[\/quote\]/im, + IMG_REGEXP: /\[img\]([\s\S]*?)\[\/img\]/i, + URL_REGEXP: /\[url\]([\s\S]*?)\[\/url\]/i, + URL_WITH_TITLE_REGEXP: /\[url=(.+?)\]([\s\S]*?)\[\/url\]/i, // Define our replacers replacers: { @@ -145,6 +148,41 @@ Discourse.BBCode = { return result; }, + /** + We want to remove urls in BBCode tags from a string before applying markdown + to prevent them from being modified by markdown. + This will return an object that contains: + - a new version of the text with the urls replaced with unique ids + - a `template()` function for reapplying them later. + + @method extractUrls + @param {String} text The text inside which we want to replace urls + @returns {Object} object containing the new string and template function + **/ + extractUrls: function(text) { + var result = { text: "" + text, replacements: [] }; + var replacements = []; + var matches, key; + + _.each([Discourse.BBCode.IMG_REGEXP, Discourse.BBCode.URL_REGEXP, Discourse.BBCode.URL_WITH_TITLE_REGEXP], function(r) { + while (matches = r.exec(result.text)) { + key = md5(matches[0]); + replacements.push({ key: key, value: matches[0] }); + result.text = result.text.replace(matches[0], key); + } + }); + + result.template = function(input) { + _.each(replacements, function(r) { + input = input.replace(r.key, r.value); + }); + return input; + }; + + return (result); + }, + + /** We want to remove quotes from a string before applying markdown to avoid weird stuff with newlines and such. This will return an object that @@ -156,13 +194,12 @@ Discourse.BBCode = { @returns {Object} object containing the new string and template function **/ extractQuotes: function(text) { - var result = {text: "" + text, replacements: []}; - + var result = { text: "" + text, replacements: [] }; var replacements = []; + var matches, key; - var matches; while (matches = Discourse.BBCode.QUOTE_REGEXP.exec(result.text)) { - var key = md5(matches[0]); + key = md5(matches[0]); replacements.push({ key: key, value: matches[0], @@ -180,7 +217,7 @@ Discourse.BBCode = { return input; }; - return(result); + return (result); }, /** diff --git a/app/assets/javascripts/discourse/components/markdown.js b/app/assets/javascripts/discourse/components/markdown.js index 8f67853f53f..373df516ca4 100644 --- a/app/assets/javascripts/discourse/components/markdown.js +++ b/app/assets/javascripts/discourse/components/markdown.js @@ -99,7 +99,7 @@ Discourse.Markdown = { var converter = new Markdown.Converter(); var mentionLookup = opts.mentionLookup || Discourse.Mention.lookupCache; - var quoteTemplate = null; + var quoteTemplate = null, urlsTemplate = null; // Before cooking callbacks converter.hooks.chain("preConversion", function(text) { @@ -114,6 +114,13 @@ Discourse.Markdown = { return extracted.text; }); + // Extract urls in BBCode tags so they are not passed through markdown. + converter.hooks.chain("preConversion", function(text) { + var extracted = Discourse.BBCode.extractUrls(text); + urlsTemplate = extracted.template; + return extracted.text; + }); + // Support autolinking of www.something.com converter.hooks.chain("preConversion", function(text) { return text.replace(/(^|[\s\n])(www\.[a-z\.\-\_\(\)\/\?\=\%0-9]+)/gim, function(full, _, rest) { @@ -178,12 +185,11 @@ Discourse.Markdown = { }); converter.hooks.chain("postConversion", function(text) { - // reapply quotes - if (quoteTemplate) { - text = quoteTemplate(text); - } - + if (quoteTemplate) { text = quoteTemplate(text); } + // reapply urls + if (urlsTemplate) { text = urlsTemplate(text); } + // format with BBCode return Discourse.BBCode.format(text, opts); }); diff --git a/test/javascripts/components/markdown_test.js b/test/javascripts/components/markdown_test.js index 6ee020e73eb..2b6d7c9f832 100644 --- a/test/javascripts/components/markdown_test.js +++ b/test/javascripts/components/markdown_test.js @@ -77,7 +77,7 @@ test("Quotes", function() { "

1

\n


\n2

", "includes no avatar if none is found"); -}); +}); test("Mentions", function() { cookedOptions("Hello @sam", { mentionLookup: (function() { return true; }) }, @@ -120,9 +120,18 @@ test("SanitizeHTML", function() { }); -// TODO -// test("with BBCode", function() { -// cooked("[img]http://eviltrout.com/eviltrout.png[/img]", -// "

", -// "BBCode is parsed first"); -// }); +test("URLs in BBCode tags", function() { + + cooked("[img]http://eviltrout.com/eviltrout.png[/img][img]http://samsaffron.com/samsaffron.png[/img]", + "

", + "images are properly parsed"); + + cooked("[url]http://discourse.org[/url]", + "

http://discourse.org

", + "links are properly parsed"); + + cooked("[url=http://discourse.org]discourse[/url]", + "

discourse

", + "named links are properly parsed"); + +});