From 085caa9370951ac84bddd3e549d0cb3c3dfc6967 Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Mon, 16 Mar 2015 19:30:50 +0000 Subject: [PATCH] Move showdown extensions to ghost-showdown no issue - We already maintain our own fork of showdown, this moves our custom extensions to our fork - Code duplication is removed - Tests are also moved to the other repo --- ghost/admin/Brocfile.js | 9 +- ghost/admin/bower.json | 2 +- .../showdown/extensions/ghostfootnotes.js | 110 ----------- .../vendor/showdown/extensions/ghostgfm.js | 171 ------------------ .../showdown/extensions/ghosthighlight.js | 71 -------- .../showdown/extensions/ghostimagepreview.js | 51 ------ 6 files changed, 5 insertions(+), 409 deletions(-) delete mode 100644 ghost/admin/vendor/showdown/extensions/ghostfootnotes.js delete mode 100644 ghost/admin/vendor/showdown/extensions/ghostgfm.js delete mode 100644 ghost/admin/vendor/showdown/extensions/ghosthighlight.js delete mode 100644 ghost/admin/vendor/showdown/extensions/ghostimagepreview.js diff --git a/ghost/admin/Brocfile.js b/ghost/admin/Brocfile.js index 1b71645cb2..410dbed13e 100644 --- a/ghost/admin/Brocfile.js +++ b/ghost/admin/Brocfile.js @@ -36,6 +36,10 @@ app.import('bower_components/ember-load-initializers/ember-load-initializers.js' app.import('bower_components/validator-js/validator.js'); app.import('bower_components/rangyinputs/rangyinputs-jquery-src.js'); app.import('bower_components/showdown-ghost/src/showdown.js'); +app.import('bower_components/showdown-ghost/src/extensions/ghostgfm.js'); +app.import('bower_components/showdown-ghost/src/extensions/ghostimagepreview.js'); +app.import('bower_components/showdown-ghost/src/extensions/footnotes.js'); +app.import('bower_components/showdown-ghost/src/extensions/highlight.js'); app.import('bower_components/moment/moment.js'); app.import('bower_components/keymaster/keymaster.js'); app.import('bower_components/device/lib/device.js'); @@ -49,9 +53,4 @@ app.import('bower_components/google-caja/html-css-sanitizer-bundle.js'); app.import('bower_components/nanoscroller/bin/javascripts/jquery.nanoscroller.js'); app.import('bower_components/jqueryui-touch-punch/jquery.ui.touch-punch.js'); -app.import('vendor/showdown/extensions/ghostgfm.js'); -app.import('vendor/showdown/extensions/ghostimagepreview.js'); -app.import('vendor/showdown/extensions/ghostfootnotes.js'); -app.import('vendor/showdown/extensions/ghosthighlight.js'); - module.exports = app.toTree(); diff --git a/ghost/admin/bower.json b/ghost/admin/bower.json index 05eafa2360..15e86d4226 100644 --- a/ghost/admin/bower.json +++ b/ghost/admin/bower.json @@ -23,7 +23,7 @@ "normalize-scss": "~3.0.1", "nprogress": "0.1.2", "rangyinputs": "1.2.0", - "showdown-ghost": "0.3.4", + "showdown-ghost": "0.3.6", "validator-js": "3.28.0" }, "devDependencies": { diff --git a/ghost/admin/vendor/showdown/extensions/ghostfootnotes.js b/ghost/admin/vendor/showdown/extensions/ghostfootnotes.js deleted file mode 100644 index b491504451..0000000000 --- a/ghost/admin/vendor/showdown/extensions/ghostfootnotes.js +++ /dev/null @@ -1,110 +0,0 @@ -/* jshint node:true, browser:true */ - -// Adds footnote syntax as per Markdown Extra: -// -// https://michelf.ca/projects/php-markdown/extra/#footnotes -// -// That's some text with a footnote.[^1] -// -// [^1]: And that's the footnote. -// -// That's the second paragraph. -// -// Also supports [^n] if you don't want to worry about preserving -// the footnote order yourself. - -function replaceInlineFootnotes(text) { - // Inline footnotes e.g. "foo[^1]" - var inlineRegex = /(?!^)\[\^(\d+|n)\]/gim, - i = 0; - - return text.replace(inlineRegex, function (match, n) { - // We allow both automatic and manual footnote numbering - if (n === 'n') { - n = i + 1; - } - - var s = '' + - '' + n + '' + - ''; - i += 1; - return s; - }); -} - -function replaceEndFootnotes(text, converter) { - // Expanded footnotes at the end e.g. "[^1]: cool stuff" - var endRegex = /\[\^(\d+|n)\]: ([\s\S]*?)$(?! )/gim, - m = text.match(endRegex), - total = m ? m.length : 0, - i = 0; - - return text.replace(endRegex, function (match, n, content) { - if (n === 'n') { - n = i + 1; - } - - content = content.replace(/\n /g, '
'); - content = converter.makeHtml(content); - content = content.replace(/<\/p>$/, ''); - var s = '
  • ' + - content + ' ' + - '

  • '; - - if (i === 0) { - s = '
      ' + s; - } - - if (i === total - 1) { - s = s + '
    '; - } - - i += 1; - return s; - }); -} - -(function () { - var footnotes = function (converter) { - return [ - { - type: 'lang', - filter: function (text) { - var preExtractions = {}, - hashID = 0; - - function hashId() { - return hashID += 1; - } - - // Extract pre blocks - text = text.replace(/```[\s\S]*?\n```/gim, function (x) { - var hash = hashId(); - preExtractions[hash] = x; - return '{gfm-js-extract-pre-' + hash + '}'; - }, 'm'); - - text = replaceInlineFootnotes(text); - text = replaceEndFootnotes(text, converter); - - // replace extractions - text = text.replace(/\{gfm-js-extract-pre-([0-9]+)\}/gm, function (x, y) { - return preExtractions[y]; - }); - - return text; - } - } - ]; - }; - - // Client-side export - if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { - window.Showdown.extensions.footnotes = footnotes; - } - // Server-side export - if (typeof module !== 'undefined') { - module.exports = footnotes; - } -}()); diff --git a/ghost/admin/vendor/showdown/extensions/ghostgfm.js b/ghost/admin/vendor/showdown/extensions/ghostgfm.js deleted file mode 100644 index bcc9626d96..0000000000 --- a/ghost/admin/vendor/showdown/extensions/ghostgfm.js +++ /dev/null @@ -1,171 +0,0 @@ -/* jshint node:true, browser:true */ - -// Ghost GFM -// Taken and extended from the Showdown Github Extension (WIP) -// Makes a number of pre and post-processing changes to the way markdown is handled -// -// ~~strike-through~~ -> strike-through (Pre) -// GFM newlines & underscores (Pre) -// 4 or more underscores (Pre) -// autolinking / custom image handling (Post) - -(function () { - var ghostgfm = function () { - return [ - { - // strike-through - // NOTE: showdown already replaced "~" with "~T", so we need to adjust accordingly. - type: 'lang', - regex: '(~T){2}([^~]+)(~T){2}', - replace: function (match, prefix, content) { - return '' + content + ''; - } - }, - { - // Escaped tildes - // NOTE: showdown already replaced "~" with "~T", and this char doesn't get escaped properly. - type: 'lang', - regex: '\\\\(~T)', - replace: function (match, content) { - return content; - } - }, - { - // GFM newline and underscore modifications, happen BEFORE showdown - type: 'lang', - filter: function (text) { - var extractions = {}, - imageMarkdownRegex = /^(?:\{(.*?)\})?!(?:\[([^\n\]]*)\])(?:\(([^\n\]]*)\))?$/gim, - hashID = 0; - - function hashId() { - /*jshint plusplus:false*/ - return hashID++; - } - - // Extract pre blocks - text = text.replace(/
    [\s\S]*?<\/pre>/gim, function (x) {
    -                        var hash = hashId();
    -                        extractions[hash] = x;
    -                        return '{gfm-js-extract-pre-' + hash + '}';
    -                    }, 'm');
    -
    -                    // Extract code blocks
    -                    text = text.replace(/```[\s\S]*```/gim, function (x) {
    -                        var hash = hashId();
    -                        extractions[hash] = x;
    -                        return '{gfm-js-extract-code-' + hash + '}';
    -                    }, 'm');
    -
    -                    // 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, '\\_');
    -                    });
    -
    -                    text = text.replace(/\{gfm-js-extract-code-([0-9]+)\}/gm, function (x, y) {
    -                        return extractions[y];
    -                    });
    -
    -                    // in very clear cases, let newlines become 
    tags - /*jshint -W049 */ - text = text.replace(/^[\w\<\'\'][^\n]*\n+/gm, function (x) { - return x.match(/\n{2}/) ? x : x.trim() + ' \n'; - }); - /*jshint +W049 */ - - // better URL support, but no title support - text = text.replace(imageMarkdownRegex, function (match, key, alt, src) { - if (src) { - return '' + alt + ''; - } - - return ''; - }); - - text = text.replace(/\{gfm-js-extract-pre-([0-9]+)\}/gm, function (x, y) { - return '\n\n' + extractions[y]; - }); - - return text; - } - }, - - // 4 or more inline underscores e.g. Ghost rocks my _____! - { - type: 'lang', - filter: function (text) { - return text.replace(/([^_\n\r])(_{4,})/g, function (match, prefix, underscores) { - return prefix + underscores.replace(/_/g, '_'); - }); - } - }, - - { - // GFM autolinking & custom image handling, happens AFTER showdown - type: 'html', - filter: function (text) { - var refExtractions = {}, - preExtractions = {}, - hashID = 0; - - function hashId() { - /*jshint plusplus:false*/ - 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(); - refExtractions[hash] = x; - return '{gfm-js-extract-ref-url-' + hash + '}'; - }); - - // match a URL - // adapted from https://gist.github.com/jorilallo/1283095#L158 - // and http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript - /*jshint -W049 */ - text = text.replace(/(\]\(|\]|\[|]*?\>)?https?\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!]/gmi, - function (wholeMatch, lookBehind, matchIndex) { - // Check we are not inside an HTML tag - var left = text.slice(0, matchIndex), right = text.slice(matchIndex); - if ((left.match(/<[^>]+$/) && right.match(/^[^>]*>/)) || lookBehind) { - return wholeMatch; - } - // If we have a matching lookBehind, this is a failure, else wrap the match in tag - return lookBehind ? wholeMatch : '' + wholeMatch + ''; - }); - /*jshint +W049 */ - - // 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' + refExtractions[y]; - }); - - return text; - } - } - ]; - }; - - // Client-side export - if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { - window.Showdown.extensions.ghostgfm = ghostgfm; - } - // Server-side export - if (typeof module !== 'undefined') { - module.exports = ghostgfm; - } -}()); diff --git a/ghost/admin/vendor/showdown/extensions/ghosthighlight.js b/ghost/admin/vendor/showdown/extensions/ghosthighlight.js deleted file mode 100644 index b867b0183b..0000000000 --- a/ghost/admin/vendor/showdown/extensions/ghosthighlight.js +++ /dev/null @@ -1,71 +0,0 @@ -/* jshint node:true, browser:true, -W044 */ - -// Adds highlight syntax as per RedCarpet: -// -// https://github.com/vmg/redcarpet -// -// This is ==highlighted==. It looks like this: highlighted - -(function () { - var highlight = function () { - return [ - { - type: 'html', - filter: function (text) { - var highlightRegex = /(=){2}([\s\S]+?)(=){2}/gim, - preExtractions = {}, - codeExtractions = {}, - hashID = 0; - - function hashId() { - return hashID += 1; - } - - // Extract pre blocks - text = text.replace(/
    [\s\S]*?<\/pre>/gim, function (x) {
    -                        var hash = hashId();
    -                        preExtractions[hash] = x;
    -                        return '{gfm-js-extract-pre-' + hash + '}';
    -                    }, 'm');
    -
    -                    // Extract code blocks
    -                    text = text.replace(/[\s\S]*?<\/code>/gim, function (x) {
    -                        var hash = hashId();
    -                        codeExtractions[hash] = x;
    -                        return '{gfm-js-extract-code-' + hash + '}';
    -                    }, 'm');
    -
    -                    text = text.replace(highlightRegex, function (match, n, content) {
    -                        // Check the content isn't just an `=`
    -                        if (!/^=+$/.test(content)) {
    -                            return '' + content + '';
    -                        }
    -
    -                        return match;
    -                    });
    -
    -                    // replace pre extractions
    -                    text = text.replace(/\{gfm-js-extract-pre-([0-9]+)\}/gm, function (x, y) {
    -                        return preExtractions[y];
    -                    });
    -
    -                     // replace code extractions
    -                    text = text.replace(/\{gfm-js-extract-code-([0-9]+)\}/gm, function (x, y) {
    -                        return codeExtractions[y];
    -                    });
    -
    -                    return text;
    -                }
    -            }
    -        ];
    -    };
    -
    -    // Client-side export
    -    if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) {
    -        window.Showdown.extensions.highlight = highlight;
    -    }
    -    // Server-side export
    -    if (typeof module !== 'undefined') {
    -        module.exports = highlight;
    -    }
    -}());
    diff --git a/ghost/admin/vendor/showdown/extensions/ghostimagepreview.js b/ghost/admin/vendor/showdown/extensions/ghostimagepreview.js
    deleted file mode 100644
    index 5974c4e5b7..0000000000
    --- a/ghost/admin/vendor/showdown/extensions/ghostimagepreview.js
    +++ /dev/null
    @@ -1,51 +0,0 @@
    -/* jshint node:true, browser:true */
    -
    -// Ghost Image Preview
    -//
    -// Manages the conversion of image markdown `![]()` from markdown into the HTML image preview
    -// This provides a dropzone and other interface elements for adding images
    -// Is only used in the admin client.
    -
    -var Ghost = Ghost || {};
    -(function () {
    -    var ghostimagepreview = function () {
    -        return [
    -            // ![] image syntax
    -            {
    -                type: 'lang',
    -                filter: function (text) {
    -                    var imageMarkdownRegex = /^!(?:\[([^\n\]]*)\])(?:\(([^\n\]]*)\))?$/gim,
    -                    /* regex from isURL in node-validator. Yum! */
    -                        uriRegex = /^(?!mailto:)(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))|localhost)(?::\d{2,5})?(?:\/[^\s]*)?$/i,
    -                        pathRegex = /^(\/)?([^\/\0]+(\/)?)+$/i;
    -
    -                    return text.replace(imageMarkdownRegex, function (match, alt, src) {
    -                        var result = '',
    -                            output;
    -
    -                        if (src && (src.match(uriRegex) || src.match(pathRegex))) {
    -                            result = '';
    -                        }
    -
    -                        output = '
    ' + - result + - '
    Add image of ' + alt + '
    ' + - '' + - '
    '; - - return output; - }); - } - } - ]; - }; - - // Client-side export - if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { - window.Showdown.extensions.ghostimagepreview = ghostimagepreview; - } - // Server-side export - if (typeof module !== 'undefined') { - module.exports = ghostimagepreview; - } -}());