From 6369eb20be5f11335b48a7c92fbe31743cee069f Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Fri, 27 Sep 2013 09:18:02 +0100 Subject: [PATCH 1/4] Remove broken image from fixture issue #866 - this fixes the problem inside the fixture --- core/server/data/fixtures/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/server/data/fixtures/index.js b/core/server/data/fixtures/index.js index d96ec4a4f0..a0754c742a 100644 --- a/core/server/data/fixtures/index.js +++ b/core/server/data/fixtures/index.js @@ -12,7 +12,7 @@ var fixtures = { "title": "Welcome to Ghost", "slug": "welcome-to-ghost", "markdown": "You're in! Nice. We've put together a little post to introduce you to the Ghost editor and get you started. Go ahead and edit this post to get going and learn how it all works!\n\n## Getting Started\n\nWriting in markdown is really easy. In the left hand panel of Ghost, you simply write as you normally would. Where appropriate, you can use *formatting* shortcuts to style your content. For example, a list:\n\n* Item number one\n* Item number two\n * A nested item\n* A final item\n\nor with numbers!\n\n1. Remember to buy some milk\n2. Drink the milk\n3. Tweet that I remembered to buy the milk, and drank it\n\n### Links\n\nWant to link to a source? No problem. If you paste in url, like http://ghost.org - it'll automatically be linked up. But if you want to customise your anchor text, you can do that too! Here's a link to [the Ghost website](http://ghost.org). Neat.\n\n### What about Images?\n\nImages work too! Already know the URL of the image you want to include in your article? Simply paste it in like this to make it show up:\n\n![The Ghost Logo](http://tryghost.org/ghost.png)\n\nNot sure which image you want to use yet? That's ok too. Leave yourself a descriptive placeholder and keep writing. Come back later and drag and drop the image in to upload:\n\n![A bowl of bananas]\n\n\n### Quoting\n\nSometimes a link isn't enough, you want to quote someone on what they've said. It was probably very wisdomous. Is wisdomous a word? Find out in a future release when we introduce spellcheck! For now - it's definitely a word.\n\n> Wisdomous - it's definitely a word.\n\n### Working with Code\n\nGot a streak of geek? We've got you covered there, too. You can write inline `` blocks really easily with back ticks. Want to show off something more comprehensive? 4 spaces of indentation gets you there.\n\n .awesome-thing {\n display: block;\n width: 100%;\n }\n\n### Ready for a Break? \n\nThrow 3 or more dashes down on any new line and you've got yourself a fancy new divider. Aw yeah.\n\n---\n\n### Advanced Usage\n\nThere's one fantastic secret about Markdown. If you want, you can write plain old HTML and it'll still work! Very flexible.\n\n\n\nThat should be enough to get you started. Have fun - and let us know what you think :)", - "html": "

You're in! Nice. We've put together a little post to introduce you to the Ghost editor and get you started. Go ahead and edit this post to get going and learn how it all works!

\n\n

Getting Started

\n\n

Writing in markdown is really easy. In the left hand panel of Ghost, you simply write as you normally would. Where appropriate, you can use formatting shortcuts to style your content. For example, a list:

\n\n\n\n

or with numbers!

\n\n
    \n
  1. Remember to buy some milk
  2. \n
  3. Drink the milk
  4. \n
  5. Tweet that I remembered to buy the milk, and drank it
  6. \n
\n\n

Links

\n\n

Want to link to a source? No problem. If you paste in url, like http://ghost.org - it'll automatically be linked up. But if you want to customise your anchor text, you can do that too! Here's a link to the Ghost website. Neat.

\n\n

What about Images?

\n\n

Images work too! Already know the URL of the image you want to include in your article? Simply paste it in like this to make it show up:

\n\n

\"The

\n\n

Not sure which image you want to use yet? That's ok too. Leave yourself a descriptive placeholder and keep writing. Come back later and drag and drop the image in to upload:

\n\n

\"A

\n\n

Quoting

\n\n

Sometimes a link isn't enough, you want to quote someone on what they've said. It was probably very wisdomous. Is wisdomous a word? Find out in a future release when we introduce spellcheck! For now - it's definitely a word.

\n\n
\n

Wisdomous - it's definitely a word.

\n
\n\n

Working with Code

\n\n

Got a streak of geek? We've got you covered there, too. You can write inline <code> blocks really easily with back ticks. Want to show off something more comprehensive? 4 spaces of indentation gets you there.

\n\n
.awesome-thing {\n    display: block;\n    width: 100%;\n}\n
\n\n

Ready for a Break?

\n\n

Throw 3 or more dashes down on any new line and you've got yourself a fancy new divider. Aw yeah.

\n\n
\n\n

Advanced Usage

\n\n

There's one fantastic secret about Markdown. If you want, you can write plain old HTML and it'll still work! Very flexible.

\n\n

\n\n

That should be enough to get you started. Have fun - and let us know what you think :)

", + "html": "

You're in! Nice. We've put together a little post to introduce you to the Ghost editor and get you started. Go ahead and edit this post to get going and learn how it all works!

\n\n

Getting Started

\n\n

Writing in markdown is really easy. In the left hand panel of Ghost, you simply write as you normally would. Where appropriate, you can use formatting shortcuts to style your content. For example, a list:

\n\n\n\n

or with numbers!

\n\n
    \n
  1. Remember to buy some milk
  2. \n
  3. Drink the milk
  4. \n
  5. Tweet that I remembered to buy the milk, and drank it
  6. \n
\n\n

Links

\n\n

Want to link to a source? No problem. If you paste in url, like http://ghost.org - it'll automatically be linked up. But if you want to customise your anchor text, you can do that too! Here's a link to the Ghost website. Neat.

\n\n

What about Images?

\n\n

Images work too! Already know the URL of the image you want to include in your article? Simply paste it in like this to make it show up:

\n\n

\"The

\n\n

Not sure which image you want to use yet? That's ok too. Leave yourself a descriptive placeholder and keep writing. Come back later and drag and drop the image in to upload:

\n\n

Quoting

\n\n

Sometimes a link isn't enough, you want to quote someone on what they've said. It was probably very wisdomous. Is wisdomous a word? Find out in a future release when we introduce spellcheck! For now - it's definitely a word.

\n\n
\n

Wisdomous - it's definitely a word.

\n
\n\n

Working with Code

\n\n

Got a streak of geek? We've got you covered there, too. You can write inline <code> blocks really easily with back ticks. Want to show off something more comprehensive? 4 spaces of indentation gets you there.

\n\n
.awesome-thing {\n    display: block;\n    width: 100%;\n}\n
\n\n

Ready for a Break?

\n\n

Throw 3 or more dashes down on any new line and you've got yourself a fancy new divider. Aw yeah.

\n\n
\n\n

Advanced Usage

\n\n

There's one fantastic secret about Markdown. If you want, you can write plain old HTML and it'll still work! Very flexible.

\n\n

\n\n

That should be enough to get you started. Have fun - and let us know what you think :)

", "image": null, "featured": false, "page": false, From 8c6519fde7cc47a5ffd50d7941a4a3dfc9c14a29 Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Fri, 27 Sep 2013 11:30:41 +0100 Subject: [PATCH 2/4] Don't output image tag for empty source closes #866 - ensures we don't end up creating any more empty image tags. --- core/shared/vendor/showdown/extensions/github.js | 6 +++++- core/test/unit/shared_gfm_spec.js | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/core/shared/vendor/showdown/extensions/github.js b/core/shared/vendor/showdown/extensions/github.js index 07db047f10..367d6eee20 100644 --- a/core/shared/vendor/showdown/extensions/github.js +++ b/core/shared/vendor/showdown/extensions/github.js @@ -36,7 +36,11 @@ // better URL support, but no title support text = text.replace(imageMarkdownRegex, function (match, key, alt, src) { - return '' + alt + ''; + if (src) { + return '' + alt + ''; + } + + return ''; }); //prevent foo_bar and foo_bar_baz from ending up with an italic word in the middle diff --git a/core/test/unit/shared_gfm_spec.js b/core/test/unit/shared_gfm_spec.js index f657f2abf3..1f7699f790 100644 --- a/core/test/unit/shared_gfm_spec.js +++ b/core/test/unit/shared_gfm_spec.js @@ -252,4 +252,19 @@ describe("Github showdown extensions", function () { }); }); + it("should not output image if there is no src", function () { + var testPhrases = [ + { + input: "![anything here]()", + output: /^$/ + } + ], + processedMarkup; + + testPhrases.forEach(function (testPhrase) { + processedMarkup = _ConvertPhrase(testPhrase.input); + processedMarkup.should.match(testPhrase.output); + }); + }); + }); \ No newline at end of file From e411ed68899e3d1f357ca899b7f66b0cb7876071 Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Fri, 27 Sep 2013 11:35:44 +0100 Subject: [PATCH 3/4] No autolinking inside of code blocks closes #865 - rejigged markdown to have some functionality before showdown runs, and other functionality before. - autolinking now happens last, so it can be smarter --- .../vendor/showdown/extensions/github.js | 54 ++++++++++++------- core/test/unit/client_showdown_int_spec.js | 26 ++++++++- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/core/shared/vendor/showdown/extensions/github.js b/core/shared/vendor/showdown/extensions/github.js index 367d6eee20..48259bdff3 100644 --- a/core/shared/vendor/showdown/extensions/github.js +++ b/core/shared/vendor/showdown/extensions/github.js @@ -16,11 +16,10 @@ } }, { - // GFM newline and underscore modifications + // GFM newline and underscore modifications, happen BEFORE showdown type : 'lang', filter : function (text) { - var extractions = {}, - imageMarkdownRegex = /^(?:\{(.*?)\})?!(?:\[([^\n\]]*)\])(?:\(([^\n\]]*)\))?$/gim, + var preExtractions = {}, hashID = 0; function hashId() { @@ -30,19 +29,10 @@ // Extract pre blocks text = text.replace(/
[\s\S]*?<\/pre>/gim, function (x) {
                         var hash = hashId();
-                        extractions[hash] = x;
+                        preExtractions[hash] = x;
                         return "{gfm-js-extract-pre-" + hash + "}";
                     }, 'm');
 
-                    // better URL support, but no title support
-                    text = text.replace(imageMarkdownRegex, function (match, key, alt, src) {
-                        if (src) {
-                            return '' + alt + '';
-                        }
-
-                        return '';
-                    });
-
                     //prevent foo_bar and foo_bar_baz from ending up with an italic word in the middle
                     text = text.replace(/(^(?! {4}|\t)\w+_\w+_\w[\w_]*)/gm, function (x) {
                         return x.replace(/_/gm, '\\_');
@@ -53,8 +43,9 @@
                         return x.match(/\n{2}/) ? x : x.trim() + "  \n";
                     });
 
+
                     text = text.replace(/\{gfm-js-extract-pre-([0-9]+)\}/gm, function (x, y) {
-                        return "\n\n" + extractions[y];
+                        return "\n\n" + preExtractions[y];
                     });
 
 
@@ -62,25 +53,43 @@
                 }
             },
             {
-                // Auto-link URLs and emails
-                type    : 'lang',
+                // GFM autolinking & custom image handling, happens AFTER showdown
+                type    : 'html',
                 filter  : function (text) {
-                    var extractions = {},
+                    var refExtractions = {},
+                        preExtractions = {},
+                        imageMarkdownRegex = /^(?:\{(.*?)\})?!(?:\[([^\n\]]*)\])(?:\(([^\n\]]*)\))?$/gim,
                         hashID = 0;
 
                     function hashId() {
                         return hashID++;
                     }
 
+                    // Extract pre blocks
+                    text = text.replace(/<(pre|code)>[\s\S]*?<\/(\1)>/gim, function (x) {
+                        var hash = hashId();
+                        preExtractions[hash] = x;
+                        return "{gfm-js-extract-pre-" + hash + "}";
+                    }, 'm');
+
                     // filter out def urls
                     // from Marked https://github.com/chjj/marked/blob/master/lib/marked.js#L24
                     text = text.replace(/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/gmi,
                         function (x) {
                             var hash = hashId();
-                            extractions[hash] = x;
+                            refExtractions[hash] = x;
                             return "{gfm-js-extract-ref-url-" + hash + "}";
                         });
 
+                    // better URL support, but no title support
+                    text = text.replace(imageMarkdownRegex, function (match, key, alt, src) {
+                        if (src) {
+                            return '' + alt + '';
+                        }
+
+                        return '';
+                    });
+
                     // match a URL
                     // adapted from https://gist.github.com/jorilallo/1283095#L158
                     // and http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript
@@ -95,13 +104,18 @@
                             return lookBehind ? wholeMatch : "" + wholeMatch + "";
                         });
 
-                    // match emil
+                    // match email
                     text = text.replace(/[a-z0-9_\-+=.]+@[a-z0-9\-]+(\.[a-z0-9-]+)+/gmi, function (wholeMatch) {
                         return "" + wholeMatch + "";
                     });
 
+                    // replace extractions
+                    text = text.replace(/\{gfm-js-extract-pre-([0-9]+)\}/gm, function (x, y) {
+                        return preExtractions[y];
+                    });
+
                     text = text.replace(/\{gfm-js-extract-ref-url-([0-9]+)\}/gi, function (x, y) {
-                        return "\n\n" + extractions[y];
+                        return "\n\n" + refExtractions[y];
                     });
 
                     return text;
diff --git a/core/test/unit/client_showdown_int_spec.js b/core/test/unit/client_showdown_int_spec.js
index 1b427c2f2b..ff95c524b5 100644
--- a/core/test/unit/client_showdown_int_spec.js
+++ b/core/test/unit/client_showdown_int_spec.js
@@ -178,7 +178,7 @@ describe("Showdown client side converter", function () {
                 },
                 {
                     input: "# http://google.co.uk",
-                    output: /^

http:\/\/google.co.uk<\/a><\/h1>$/ + output: /^

http:\/\/google.co.uk<\/a><\/h1>$/ }, { input: "* http://google.co.uk", @@ -279,6 +279,30 @@ describe("Showdown client side converter", function () { }); }); + it("should NOT auto-link URLS inside of code/pre blocks", function () { + var testPhrases = [ + { + input: "```\nurl: http://google.co.uk\n```", + output: /^
url: http:\/\/google.co.uk  \n<\/code><\/pre>$/
+                },
+                {
+                    input: "`url: http://google.co.uk`",
+                    output: /^

url: http:\/\/google.co.uk<\/code><\/p>$/ + }, + { + input: "Hello type some `url: http://google.co.uk` stuff", + output: /^

Hello type some url: http:\/\/google.co.uk<\/code> stuff<\/p>$/ + } + + ], + processedMarkup; + + testPhrases.forEach(function (testPhrase) { + processedMarkup = converter.makeHtml(testPhrase.input); + processedMarkup.should.match(testPhrase.output); + }); + }); + it("should not display anything for reference URL", function () { var testPhrases = [ { From 50a16ceb76f1faac3c6d6a93343aacfa018cc57f Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Fri, 27 Sep 2013 11:36:12 +0100 Subject: [PATCH 4/4] Test Cleanup --- core/test/unit/api_settings_spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/core/test/unit/api_settings_spec.js b/core/test/unit/api_settings_spec.js index adbe1aca8b..fa7b25f598 100644 --- a/core/test/unit/api_settings_spec.js +++ b/core/test/unit/api_settings_spec.js @@ -205,7 +205,6 @@ describe('Settings Model', function () { it('populates any unset settings from the JSON defaults', function (done) { SettingsModel.findAll().then(function (allSettings) { - console.log(allSettings.models) allSettings.length.should.equal(0); return SettingsModel.populateDefaults(); }).then(function () {