From 416fbb68f20da612f53713605489a9cba5d02a6e Mon Sep 17 00:00:00 2001 From: benweet Date: Tue, 25 Jun 2013 22:43:00 +0100 Subject: [PATCH] Moved footnotes into Markdown Extra extension --- js/extensionMgr.js | 1 - js/extensions/markdownFootnotes.js | 100 ----------------------------- js/extensions/mathJax.js | 2 +- js/libs/Markdown.Extra.js | 95 ++++++++++++++++++++++++++- 4 files changed, 93 insertions(+), 105 deletions(-) delete mode 100644 js/extensions/markdownFootnotes.js diff --git a/js/extensionMgr.js b/js/extensionMgr.js index 1dfad50e..c789c9e9 100644 --- a/js/extensionMgr.js +++ b/js/extensionMgr.js @@ -15,7 +15,6 @@ define([ "extensions/workingIndicator", "extensions/notifications", "extensions/markdownExtra", - "extensions/markdownFootnotes", "extensions/toc", "extensions/mathJax", "extensions/emailConverter", diff --git a/js/extensions/markdownFootnotes.js b/js/extensions/markdownFootnotes.js deleted file mode 100644 index c8777094..00000000 --- a/js/extensions/markdownFootnotes.js +++ /dev/null @@ -1,100 +0,0 @@ -define([ - "underscore", - "utils", - "classes/Extension", -], function(_, utils, Extension) { - - var markdownFootnotes = new Extension("markdownFootnotes", "Markdown Footnotes", true); - markdownFootnotes.settingsBlock = '

Adds support for Markdown footnotes.

'; - - var inlineTags = new RegExp([ - '^(<\\/?(a|abbr|acronym|applet|area|b|basefont|', - 'bdo|big|button|cite|code|del|dfn|em|figcaption|', - 'font|i|iframe|img|input|ins|kbd|label|map|', - 'mark|meter|object|param|progress|q|ruby|rp|rt|s|', - 'samp|script|select|small|span|strike|strong|', - 'sub|sup|textarea|time|tt|u|var|wbr)[^>]*>|', - '<(br)\\s?\\/?>)$' - ].join(''), 'i'); - - var previousPostConversion = undefined; - markdownFootnotes.onEditorConfigure = function(editor) { - var converter = editor.getConverter(); - previousPostConversion = converter.hooks.postConversion; - converter.hooks.chain("postNormalization", _StripFootnoteDefinitions); - converter.hooks.chain("postBlockGamut", _DoFootnotes); - converter.hooks.chain("postConversion", _PrintFootnotes); - }; - - var footnotes = undefined; - var usedFootnotes = undefined; - function _StripFootnoteDefinitions(text) { - footnotes = {}; - usedFootnotes = []; - - text = text.replace(/\n[ ]{0,3}\[\^(.+?)\]\:[ \t]*\n?([\s\S]*?)\n{1,2}((?=\n[ ]{0,3}\S)|\Z)/g, function(wholeMatch, m1, m2) { - m1 = utils.slugify(m1); - m2 += "\n"; - m2 = m2.replace(/^[ ]{0,3}/g, ""); - footnotes[m1] = m2; - return "\n"; - }); - - return text; - } - - var blockGamutHookCallback = undefined; - function _DoFootnotes(text, blockGamutHookCallbackParam) { - blockGamutHookCallback = blockGamutHookCallbackParam; - var footnoteCounter = 0; - text = text.replace(/\[\^(.+?)\]/g, function(wholeMatch, m1) { - var id = utils.slugify(m1); - var footnote = footnotes[id]; - if(footnote === undefined) { - return ""; - } - footnoteCounter++; - usedFootnotes.push(id); - return '' + footnoteCounter + ''; - }); - - return text; - } - - function _PrintFootnotes(text) { - if(usedFootnotes.length === 0) { - return text; - } - - _.each(footnotes, function(footnote, id) { - var formattedfootnote = blockGamutHookCallback(footnote); - formattedfootnote = unescapeSpecialChars(formattedfootnote); - formattedfootnote = formattedfootnote.replace(/~D/g, "$$").replace(/~T/g, "~"); - formattedfootnote = previousPostConversion(formattedfootnote); - formattedfootnote = formattedfootnote.replace(/<[^>]*>?/gi, function(tag) { - return tag.match(inlineTags) ? tag : ''; - }); - footnotes[id] = formattedfootnote; - }); - - text += '\n\n
\n
\n
    \n\n'; - _.each(usedFootnotes, function(id) { - var footnote = footnotes[id]; - text += '
  1. ' + footnote + '
  2. \n\n'; - }); - text += '
\n
'; - return text; - } - - // Duplicated from PageDown converter - function unescapeSpecialChars(text) { - // Swap back in all the special characters we've hidden. - text = text.replace(/~E(\d+)E/g, function(wholeMatch, m1) { - var charCodeToReplace = parseInt(m1); - return String.fromCharCode(charCodeToReplace); - }); - return text; - } - - return markdownFootnotes; -}); \ No newline at end of file diff --git a/js/extensions/mathJax.js b/js/extensions/mathJax.js index 337771b4..7f8a3534 100644 --- a/js/extensions/mathJax.js +++ b/js/extensions/mathJax.js @@ -9,7 +9,7 @@ define([ mathJax.settingsBlock = mathJaxSettingsBlockHTML; mathJax.defaultConfig = { tex: "{}", - tex2jax: '{ inlineMath: [["$","$"],["\\\\(","\\\\)"]], displayMath: [["$$","$$"],["\\[","\\]"]], processEscapes: true }' + tex2jax: '{ inlineMath: [["$","$"],["\\\\\\\\(","\\\\\\\\)"]], displayMath: [["$$","$$"],["\\\\[","\\\\]"]], processEscapes: true }' }; mathJax.onLoadSettings = function() { diff --git a/js/libs/Markdown.Extra.js b/js/libs/Markdown.Extra.js index 990dc158..c85683e3 100644 --- a/js/libs/Markdown.Extra.js +++ b/js/libs/Markdown.Extra.js @@ -120,6 +120,15 @@ }); return text; } + + function slugify(text) { + return text.toLowerCase() + .replace(/\s+/g, '-') // Replace spaces with - + .replace(/[^\w\-]+/g, '') // Remove all non-word chars + .replace(/\-\-+/g, '-') // Replace multiple - with single - + .replace(/^-+/, '') // Trim - from start of text + .replace(/-+$/, ''); // Trim - from end of text + } /***************************************************************************** * Markdown.Extra * @@ -135,6 +144,10 @@ // Stores html blocks we generate in hooks so that // they're not destroyed if the user is using a sanitizing converter this.hashBlocks = []; + + // Stores footnotes + this.footnotes = {}; + this.usedFootnotes = []; // Special attribute blocks for fenced code blocks and headers enabled. this.attributeBlocks = false; @@ -160,7 +173,7 @@ options = options || {}; options.extensions = options.extensions || ["all"]; if (contains(options.extensions, "all")) { - options.extensions = ["tables", "fenced_code_gfm", "def_list", "attr_list"]; + options.extensions = ["tables", "fenced_code_gfm", "def_list", "attr_list", "footnotes"]; } if (contains(options.extensions, "attr_list")) { postNormalizationTransformations.push("hashFcbAttributeBlocks"); @@ -177,6 +190,11 @@ if (contains(options.extensions, "def_list")) { preBlockGamutTransformations.push("definitionLists"); } + if (contains(options.extensions, "footnotes")) { + postNormalizationTransformations.push("stripFootnoteDefinitions"); + preBlockGamutTransformations.push("doFootnotes"); + postConversionTransformations.push("printFootnotes"); + } converter.hooks.chain("postNormalization", function(text) { return extra.doTransform(postNormalizationTransformations, text) + '\n'; @@ -194,7 +212,9 @@ converter.hooks.chain("postConversion", function(text) { text = extra.doTransform(postConversionTransformations, text); // Clear state vars that may use unnecessary memory - this.hashBlocks = []; + extra.hashBlocks = []; + extra.footnotes = {}; + extra.usedFootnotes = []; return text; }); @@ -276,7 +296,7 @@ // TODO: use sentinels. Should we just add/remove them in doConversion? // TODO: better matches for id / class attributes var attrBlock = "\\{\\s*[.|#][^}]+\\}"; - var fcbAttributes = new RegExp("^(```[^{]*)\\s+(" + attrBlock + ")[ \\t]*\\n" + + var fcbAttributes = new RegExp("^(```[^{\\n]*)\\s+(" + attrBlock + ")[ \\t]*\\n" + "(?=([\\s\\S]*?)\\n```\\s*(\\n|0x03))", "gm"); var self = this; @@ -437,6 +457,75 @@ }; + /****************************************************************** + * Footnotes * + *****************************************************************/ + + // Strip footnote, store in hashes. + Markdown.Extra.prototype.stripFootnoteDefinitions = function(text) { + var self = this; + + text = text.replace( + /\n[ ]{0,3}\[\^(.+?)\]\:[ \t]*\n?([\s\S]*?)\n{1,2}((?=\n[ ]{0,3}\S)|$)/g, + function(wholeMatch, m1, m2) { + m1 = slugify(m1); + m2 += "\n"; + m2 = m2.replace(/^[ ]{0,3}/g, ""); + self.footnotes[m1] = m2; + return "\n"; + }); + + return text; + }; + + + // Find and convert footnotes references. + Markdown.Extra.prototype.doFootnotes = function(text) { + var self = this; + + var footnoteCounter = 0; + text = text.replace(/\[\^(.+?)\]/g, function(wholeMatch, m1) { + var id = slugify(m1); + var footnote = self.footnotes[id]; + if (footnote === undefined) { + return ""; + } + footnoteCounter++; + self.usedFootnotes.push(id); + return '' + footnoteCounter + + ''; + }); + + return text; + }; + + // Print footnotes at the end of the document + Markdown.Extra.prototype.printFootnotes = function(text) { + var self = this; + + if (self.usedFootnotes.length === 0) { + return text; + } + + text += '\n\n
\n
\n
    \n\n'; + for(var i=0; i' + + formattedfootnote + + ' \n\n'; + } + text += '
\n
'; + return text; + }; + + /****************************************************************** * Fenced Code Blocks (gfm) * ******************************************************************/