Ado
view release on metacpan or search on metacpan
public/vendor/pagedown/Markdown.Converter.js view on Meta::CPAN
function HookCollection() { }
HookCollection.prototype = {
chain: function (hookname, func) {
var original = this[hookname];
if (!original)
throw new Error("unknown hook " + hookname);
if (original === identity)
this[hookname] = func;
else
this[hookname] = function (text) {
var args = Array.prototype.slice.call(arguments, 0);
args[0] = original.apply(null, args);
return func.apply(null, args);
};
},
set: function (hookname, func) {
if (!this[hookname])
throw new Error("unknown hook " + hookname);
this[hookname] = func;
},
addNoop: function (hookname) {
this[hookname] = identity;
},
addFalse: function (hookname) {
this[hookname] = returnFalse;
}
};
Markdown.HookCollection = HookCollection;
// g_urls and g_titles allow arbitrary user-entered strings as keys. This
// caused an exception (and hence stopped the rendering) when the user entered
// e.g. [push] or [__proto__]. Adding a prefix to the actual key prevents this
// (since no builtin property starts with "s_"). See
// http://meta.stackoverflow.com/questions/64655/strange-wmd-bug
// (granted, switching from Array() to Object() alone would have left only __proto__
// to be a problem)
function SaveHash() { }
SaveHash.prototype = {
set: function (key, value) {
this["s_" + key] = value;
},
get: function (key) {
return this["s_" + key];
}
};
Markdown.Converter = function () {
var pluginHooks = this.hooks = new HookCollection();
// given a URL that was encountered by itself (without markup), should return the link text that's to be given to this link
pluginHooks.addNoop("plainLinkText");
// called with the orignal text as given to makeHtml. The result of this plugin hook is the actual markdown source that will be cooked
pluginHooks.addNoop("preConversion");
// called with the text once all normalizations have been completed (tabs to spaces, line endings, etc.), but before any conversions have
pluginHooks.addNoop("postNormalization");
// Called with the text before / after creating block elements like code blocks and lists. Note that this is called recursively
// with inner content, e.g. it's called with the full text, and then only with the content of a blockquote. The inner
// call will receive outdented text.
pluginHooks.addNoop("preBlockGamut");
pluginHooks.addNoop("postBlockGamut");
// called with the text of a single block element before / after the span-level conversions (bold, code spans, etc.) have been made
pluginHooks.addNoop("preSpanGamut");
pluginHooks.addNoop("postSpanGamut");
// called with the final cooked HTML code. The result of this plugin hook is the actual output of makeHtml
pluginHooks.addNoop("postConversion");
//
// Private state of the converter instance:
//
// Global hashes, used by various utility routines
var g_urls;
var g_titles;
var g_html_blocks;
// Used to track when we're inside an ordered or unordered list
// (see _ProcessListItems() for details):
var g_list_level;
this.makeHtml = function (text) {
//
// Main function. The order in which other subs are called here is
// essential. Link and image substitutions need to happen before
// _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the <a>
// and <img> tags get encoded.
//
// This will only happen if makeHtml on the same converter instance is called from a plugin hook.
// Don't do that.
if (g_urls)
throw new Error("Recursive call to converter.makeHtml");
// Create the private state objects.
g_urls = new SaveHash();
g_titles = new SaveHash();
g_html_blocks = [];
g_list_level = 0;
text = pluginHooks.preConversion(text);
// attacklab: Replace ~ with ~T
// This lets us use tilde as an escape char to avoid md5 hashes
// The choice of character is arbitray; anything that isn't
// magic in Markdown will work.
text = text.replace(/~/g, "~T");
// attacklab: Replace $ with ~D
// RegExp interprets $ as a special character
// when it's in a replacement string
text = text.replace(/\$/g, "~D");
// Standardize line endings
text = text.replace(/\r\n/g, "\n"); // DOS to Unix
text = text.replace(/\r/g, "\n"); // Mac to Unix
// Make sure text begins and ends with a couple of newlines:
text = "\n\n" + text + "\n\n";
// Convert all tabs to spaces.
text = _Detab(text);
// Strip any lines consisting only of spaces and tabs.
// This makes subsequent regexen easier to write, because we can
// match consecutive blank lines with /\n+/ instead of something
// contorted like /[ \t]*\n+/ .
text = text.replace(/^[ \t]+$/mg, "");
text = pluginHooks.postNormalization(text);
// Turn block-level HTML blocks into hash entries
text = _HashHTMLBlocks(text);
// Strip link definitions, store in hashes.
text = _StripLinkDefinitions(text);
text = _RunBlockGamut(text);
text = _UnescapeSpecialChars(text);
// attacklab: Restore dollar signs
text = text.replace(/~D/g, "$$");
// attacklab: Restore tildes
text = text.replace(/~T/g, "~");
text = pluginHooks.postConversion(text);
g_html_blocks = g_titles = g_urls = null;
return text;
};
function _StripLinkDefinitions(text) {
//
// Strips link definitions from text, stores the URLs and titles in
// hash references.
//
// Link defs are in the form: ^[id]: url "optional title"
/*
text = text.replace(/
^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
[ \t]*
\n? // maybe *one* newline
[ \t]*
<?(\S+?)>? // url = $2
(?=\s|$) // lookahead for whitespace instead of the lookbehind removed below
[ \t]*
\n? // maybe one newline
[ \t]*
( // (potential) title = $3
(\n*) // any lines skipped = $4 attacklab: lookbehind removed
[ \t]+
["(]
(.+?) // title = $5
[")]
[ \t]*
)? // title is optional
(?:\n+|$)
/gm, function(){...});
*/
text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?(?=\s|$)[ \t]*\n?[ \t]*((\n*)["(](.+?)[")][ \t]*)?(?:\n+)/gm,
function (wholeMatch, m1, m2, m3, m4, m5) {
m1 = m1.toLowerCase();
g_urls.set(m1, _EncodeAmpsAndAngles(m2)); // Link IDs are case-insensitive
if (m4) {
// Oops, found blank lines, so it's not a title.
// Put back the parenthetical statement we stole.
return m3;
} else if (m5) {
g_titles.set(m1, m5.replace(/"/g, """));
}
// Completely remove the definition from the text
return "";
}
);
return text;
}
function _HashHTMLBlocks(text) {
// Hashify HTML blocks:
public/vendor/pagedown/Markdown.Converter.js view on Meta::CPAN
/*
text = text.replace(/
(?:
\n\n // Starting after a blank line
)
( // save in $1
[ ]{0,3} // attacklab: g_tab_width - 1
(?:
<([?%]) // $2
[^\r]*?
\2>
)
[ \t]*
(?=\n{2,}) // followed by a blank line
)
/g,hashElement);
*/
text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, hashElement);
return text;
}
function hashElement(wholeMatch, m1) {
var blockText = m1;
// Undo double lines
blockText = blockText.replace(/^\n+/, "");
// strip trailing blank lines
blockText = blockText.replace(/\n+$/g, "");
// Replace the element text with a marker ("~KxK" where x is its key)
blockText = "\n\n~K" + (g_html_blocks.push(blockText) - 1) + "K\n\n";
return blockText;
}
var blockGamutHookCallback = function (t) { return _RunBlockGamut(t); }
function _RunBlockGamut(text, doNotUnhash) {
//
// These are all the transformations that form block-level
// tags like paragraphs, headers, and list items.
//
text = pluginHooks.preBlockGamut(text, blockGamutHookCallback);
text = _DoHeaders(text);
// Do Horizontal Rules:
var replacement = "<hr />\n";
text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, replacement);
text = text.replace(/^[ ]{0,2}([ ]?-[ ]?){3,}[ \t]*$/gm, replacement);
text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, replacement);
text = _DoLists(text);
text = _DoCodeBlocks(text);
text = _DoBlockQuotes(text);
text = pluginHooks.postBlockGamut(text, blockGamutHookCallback);
// We already ran _HashHTMLBlocks() before, in Markdown(), but that
// was to escape raw HTML in the original Markdown source. This time,
// we're escaping the markup we've just created, so that we don't wrap
// <p> tags around block-level tags.
text = _HashHTMLBlocks(text);
text = _FormParagraphs(text, doNotUnhash);
return text;
}
function _RunSpanGamut(text) {
//
// These are all the transformations that occur *within* block-level
// tags like paragraphs, headers, and list items.
//
text = pluginHooks.preSpanGamut(text);
text = _DoCodeSpans(text);
text = _EscapeSpecialCharsWithinTagAttributes(text);
text = _EncodeBackslashEscapes(text);
// Process anchor and image tags. Images must come first,
// because ![foo][f] looks like an anchor.
text = _DoImages(text);
text = _DoAnchors(text);
// Make links out of things like `<http://example.com/>`
// Must come after _DoAnchors(), because you can use < and >
// delimiters in inline links like [this](<url>).
text = _DoAutoLinks(text);
text = text.replace(/~P/g, "://"); // put in place to prevent autolinking; reset now
text = _EncodeAmpsAndAngles(text);
text = _DoItalicsAndBold(text);
// Do hard breaks:
text = text.replace(/ +\n/g, " <br>\n");
text = pluginHooks.postSpanGamut(text);
return text;
}
function _EscapeSpecialCharsWithinTagAttributes(text) {
//
// Within tags -- meaning between < and > -- encode [\ ` * _] so they
// don't conflict with their use in Markdown for code, italics and strong.
//
// Build a regex to find HTML tags and comments. See Friedl's
// "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
// SE: changed the comment part of the regex
var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--(?:|(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>)/gi;
text = text.replace(regex, function (wholeMatch) {
var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, "$1`");
tag = escapeCharacters(tag, wholeMatch.charAt(1) == "!" ? "\\`*_/" : "\\`*_"); // also escape slashes in comments to prevent autolinking there -- http://meta.stackoverflow.com/questions/95987
return tag;
});
return text;
}
function _DoAnchors(text) {
//
// Turn Markdown link shortcuts into XHTML <a> tags.
//
//
// First, handle reference-style links: [link text] [id]
//
/*
text = text.replace(/
( // wrap whole match in $1
\[
(
(?:
\[[^\]]*\] // allow brackets nested one level
|
[^\[] // or anything else
)*
)
\]
[ ]? // one optional space
(?:\n[ ]*)? // one optional newline followed by spaces
\[
(.*?) // id = $3
\]
)
()()()() // pad remaining backreferences
/g, writeAnchorTag);
*/
text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeAnchorTag);
//
( run in 3.714 seconds using v1.01-cache-2.11-cpan-ad19def0cd9 )