-
- if (options.simplifiedAutoLink) {
- text = text.replace(simpleURLRegex, '$1');
- text = text.replace(simpleMailRegex, replaceMail);
- }
-
- function replaceMail(wholeMatch, m1) {
- var unescapedStr = showdown.subParser('unescapeSpecialChars')(m1);
- return showdown.subParser('encodeEmailAddress')(unescapedStr);
- }
-
- return text;
-});
-
-/**
- * These are all the transformations that form block-level
- * tags like paragraphs, headers, and list items.
- */
-showdown.subParser('blockGamut', function (text, options, globals) {
- 'use strict';
-
- // we parse blockquotes first so that we can have headings and hrs
- // inside blockquotes
- text = showdown.subParser('blockQuotes')(text, options, globals);
- text = showdown.subParser('headers')(text, options, globals);
-
- // Do Horizontal Rules:
- var key = showdown.subParser('hashBlock')('
', options, globals);
- text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key);
- text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key);
- text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, key);
-
- text = showdown.subParser('lists')(text, options, globals);
- text = showdown.subParser('codeBlocks')(text, options, globals);
- text = showdown.subParser('tables')(text, options, globals);
-
- // 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
- // tags around block-level tags.
- text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
- text = showdown.subParser('paragraphs')(text, options, globals);
-
- return text;
-
-});
-
-showdown.subParser('blockQuotes', function (text, options, globals) {
- 'use strict';
-
- /*
- text = text.replace(/
- ( // Wrap whole match in $1
- (
- ^[ \t]*>[ \t]? // '>' at the start of a line
- .+\n // rest of the first line
- (.+\n)* // subsequent consecutive lines
- \n* // blanks
- )+
- )
- /gm, function(){...});
- */
-
- text = text.replace(/((^[ \t]{0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {
- var bq = m1;
-
- // attacklab: hack around Konqueror 3.5.4 bug:
- // "----------bug".replace(/^-/g,"") == "bug"
- bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting
-
- // attacklab: clean up hack
- bq = bq.replace(/~0/g, '');
-
- bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines
- bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);
- bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse
-
- bq = bq.replace(/(^|\n)/g, '$1 ');
- // These leading spaces screw with
content, so we need to fix that:
- bq = bq.replace(/(\s*[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
- var pre = m1;
- // attacklab: hack around Konqueror 3.5.4 bug:
- pre = pre.replace(/^ /mg, '~0');
- pre = pre.replace(/~0/g, '');
- return pre;
- });
-
- return showdown.subParser('hashBlock')('\n' + bq + '\n
', options, globals);
- });
- return text;
-});
-
-/**
- * Process Markdown `` blocks.
- */
-showdown.subParser('codeBlocks', function (text, options, globals) {
- 'use strict';
-
- /*
- text = text.replace(text,
- /(?:\n\n|^)
- ( // $1 = the code block -- one or more lines, starting with a space/tab
- (?:
- (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
- .*\n+
- )+
- )
- (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
- /g,function(){...});
- */
-
- // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
- text += '~0';
-
- var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;
- text = text.replace(pattern, function (wholeMatch, m1, m2) {
- var codeblock = m1,
- nextChar = m2,
- end = '\n';
-
- codeblock = showdown.subParser('outdent')(codeblock);
- codeblock = showdown.subParser('encodeCode')(codeblock);
- codeblock = showdown.subParser('detab')(codeblock);
- codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
- codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
-
- if (options.omitExtraWLInCodeBlocks) {
- end = '';
- }
-
- codeblock = '' + codeblock + end + '
';
-
- return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;
- });
-
- // attacklab: strip sentinel
- text = text.replace(/~0/, '');
-
- return text;
-});
-
-/**
- *
- * * Backtick quotes are used for spans.
- *
- * * You can use multiple backticks as the delimiters if you want to
- * include literal backticks in the code span. So, this input:
- *
- * Just type ``foo `bar` baz`` at the prompt.
- *
- * Will translate to:
- *
- * Just type foo `bar` baz at the prompt.
- *
- * There's no arbitrary limit to the number of backticks you
- * can use as delimters. If you need three consecutive backticks
- * in your code, use four for delimiters, etc.
- *
- * * You can use spaces to get literal backticks at the edges:
- *
- * ... type `` `bar` `` ...
- *
- * Turns to:
- *
- * ... type `bar` ...
- */
-showdown.subParser('codeSpans', function (text) {
- 'use strict';
-
- //special case -> literal html code tag
- text = text.replace(/(<]*?>)([^]*?)<\/code>/g, function (wholeMatch, tag, c) {
- c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
- c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
- c = showdown.subParser('encodeCode')(c);
- return tag + c + '';
- });
-
- /*
- text = text.replace(/
- (^|[^\\]) // Character before opening ` can't be a backslash
- (`+) // $2 = Opening run of `
- ( // $3 = The code block
- [^\r]*?
- [^`] // attacklab: work around lack of lookbehind
- )
- \2 // Matching closer
- (?!`)
- /gm, function(){...});
- */
- text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
- function (wholeMatch, m1, m2, m3) {
- var c = m3;
- c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
- c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
- c = showdown.subParser('encodeCode')(c);
- return m1 + '' + c + '';
- }
- );
-
- return text;
-});
-
-/**
- * Convert all tabs to spaces
- */
-showdown.subParser('detab', function (text) {
- 'use strict';
-
- // expand first n-1 tabs
- text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width
-
- // replace the nth with two sentinels
- text = text.replace(/\t/g, '~A~B');
-
- // use the sentinel to anchor our regex so it doesn't explode
- text = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1) {
- var leadingText = m1,
- numSpaces = 4 - leadingText.length % 4; // g_tab_width
-
- // there *must* be a better way to do this:
- for (var i = 0; i < numSpaces; i++) {
- leadingText += ' ';
- }
-
- return leadingText;
- });
-
- // clean up sentinels
- text = text.replace(/~A/g, ' '); // g_tab_width
- text = text.replace(/~B/g, '');
-
- return text;
-
-});
-
-/**
- * Smart processing for ampersands and angle brackets that need to be encoded.
- */
-showdown.subParser('encodeAmpsAndAngles', function (text) {
- 'use strict';
- // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
- // http://bumppo.net/projects/amputator/
- text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&');
-
- // Encode naked <'s
- text = text.replace(/<(?![a-z\/?\$!])/gi, '<');
-
- return text;
-});
-
-/**
- * Returns the string, with after processing the following backslash escape sequences.
- *
- * attacklab: The polite way to do this is with the new escapeCharacters() function:
- *
- * text = escapeCharacters(text,"\\",true);
- * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
- *
- * ...but we're sidestepping its use of the (slow) RegExp constructor
- * as an optimization for Firefox. This function gets called a LOT.
- */
-showdown.subParser('encodeBackslashEscapes', function (text) {
- 'use strict';
- text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);
- text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback);
- return text;
-});
-
-/**
- * Encode/escape certain characters inside Markdown code runs.
- * The point is that in code, these characters are literals,
- * and lose their special Markdown meanings.
- */
-showdown.subParser('encodeCode', function (text) {
- 'use strict';
-
- // Encode all ampersands; HTML entities are not
- // entities within a Markdown code span.
- text = text.replace(/&/g, '&');
-
- // Do the angle bracket song and dance:
- text = text.replace(//g, '>');
-
- // Now, escape characters that are magic in Markdown:
- text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false);
-
- // jj the line above breaks this:
- //---
- //* Item
- // 1. Subitem
- // special char: *
- // ---
-
- return text;
-});
-
-/**
- * Input: an email address, e.g. "foo@example.com"
- *
- * Output: the email address as a mailto link, with each character
- * of the address encoded as either a decimal or hex entity, in
- * the hopes of foiling most address harvesting spam bots. E.g.:
- *
- * foo
- * @example.com
- *
- * Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
- * mailing list:
- *
- */
-showdown.subParser('encodeEmailAddress', function (addr) {
- 'use strict';
-
- var encode = [
- function (ch) {
- return '' + ch.charCodeAt(0) + ';';
- },
- function (ch) {
- return '' + ch.charCodeAt(0).toString(16) + ';';
- },
- function (ch) {
- return ch;
- }
- ];
-
- addr = 'mailto:' + addr;
-
- addr = addr.replace(/./g, function (ch) {
- if (ch === '@') {
- // this *must* be encoded. I insist.
- ch = encode[Math.floor(Math.random() * 2)](ch);
- } else if (ch !== ':') {
- // leave ':' alone (to spot mailto: later)
- var r = Math.random();
- // roughly 10% raw, 45% hex, 45% dec
- ch = (
- r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)
- );
- }
- return ch;
- });
-
- addr = '' + addr + '';
- addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible part
-
- return addr;
-});
-
-/**
- * Within tags -- meaning between < and > -- encode [\ ` * _] so they
- * don't conflict with their use in Markdown for code, italics and strong.
- */
-showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text) {
- 'use strict';
-
- // Build a regex to find HTML tags and comments. See Friedl's
- // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
- var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi;
-
- text = text.replace(regex, function (wholeMatch) {
- var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`');
- tag = showdown.helper.escapeCharacters(tag, '\\`*_', false);
- return tag;
- });
-
- return text;
-});
-
-/**
- * Handle github codeblocks prior to running HashHTML so that
- * HTML contained within the codeblock gets escaped properly
- * Example:
- * ```ruby
- * def hello_world(x)
- * puts "Hello, #{x}"
- * end
- * ```
- */
-showdown.subParser('githubCodeBlocks', function (text, options, globals) {
- 'use strict';
-
- // early exit if option is not enabled
- if (!options.ghCodeBlocks) {
- return text;
- }
-
- text += '~0';
-
- text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
- var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
-
- codeblock = showdown.subParser('encodeCode')(codeblock);
- codeblock = showdown.subParser('detab')(codeblock);
- codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
- codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
-
- codeblock = '' + codeblock + end + '
';
-
- return showdown.subParser('hashBlock')(codeblock, options, globals);
- });
-
- // attacklab: strip sentinel
- text = text.replace(/~0/, '');
-
- return text;
-
-});
-
-showdown.subParser('hashBlock', function (text, options, globals) {
- 'use strict';
- text = text.replace(/(^\n+|\n+$)/g, '');
- return '\n\n~K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';
-});
-
-showdown.subParser('hashElement', function (text, options, globals) {
- 'use strict';
-
- return function (wholeMatch, m1) {
- var blockText = m1;
-
- // Undo double lines
- blockText = blockText.replace(/\n\n/g, '\n');
- 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' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';
-
- return blockText;
- };
-});
-
-showdown.subParser('hashHTMLBlocks', function (text, options, globals) {
- 'use strict';
-
- // attacklab: Double up blank lines to reduce lookaround
- text = text.replace(/\n/g, '\n\n');
-
- // Hashify HTML blocks:
- // We only want to do this for block-level HTML tags, such as headers,
- // lists, and tables. That's because we still want to wrap s around
- // "paragraphs" that are wrapped in non-block-level tags, such as anchors,
- // phrase emphasis, and spans. The list of tags we're looking for is
- // hard-coded:
- //var block_tags_a =
- // 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del|style|section|header|footer|nav|article|aside';
- // var block_tags_b =
- // 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside';
-
- // First, look for nested blocks, e.g.:
- //
- //
- // tags for inner block must be indented.
- //
- //
- //
- // The outermost tags must start at the left margin for this to match, and
- // the inner nested divs must be indented.
- // We need to do this before the next, more liberal match, because the next
- // match will start at the first `` and stop at the first `
`.
-
- // attacklab: This regex can be expensive when it fails.
- /*
- var text = text.replace(/
- ( // save in $1
- ^ // start of line (with /m)
- <($block_tags_a) // start tag = $2
- \b // word break
- // attacklab: hack around khtml/pcre bug...
- [^\r]*?\n // any number of lines, minimally matching
- \2> // the matching end tag
- [ \t]* // trailing spaces/tabs
- (?=\n+) // followed by a newline
- ) // attacklab: there are sentinel newlines at end of document
- /gm,function(){...}};
- */
- text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,
- showdown.subParser('hashElement')(text, options, globals));
-
- //
- // Now match more liberally, simply from `\n` to `\n`
- //
-
- /*
- var text = text.replace(/
- ( // save in $1
- ^ // start of line (with /m)
- <($block_tags_b) // start tag = $2
- \b // word break
- // attacklab: hack around khtml/pcre bug...
- [^\r]*? // any number of lines, minimally matching
- \2> // the matching end tag
- [ \t]* // trailing spaces/tabs
- (?=\n+) // followed by a newline
- ) // attacklab: there are sentinel newlines at end of document
- /gm,function(){...}};
- */
- text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside|address|audio|canvas|figure|hgroup|output|video)\b[^\r]*?<\/\2>[ \t]*(?=\n+)\n)/gm,
- showdown.subParser('hashElement')(text, options, globals));
-
- // Special case just for
. It was easier to make a special case than
- // to make the other regex more complicated.
-
- /*
- text = text.replace(/
- ( // save in $1
- \n\n // Starting after a blank line
- [ ]{0,3}
- (<(hr) // start tag = $2
- \b // word break
- ([^<>])*? //
- \/?>) // the matching end tag
- [ \t]*
- (?=\n{2,}) // followed by a blank line
- )
- /g,showdown.subParser('hashElement')(text, options, globals));
- */
- text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,
- showdown.subParser('hashElement')(text, options, globals));
-
- // Special case for standalone HTML comments:
-
- /*
- text = text.replace(/
- ( // save in $1
- \n\n // Starting after a blank line
- [ ]{0,3} // attacklab: g_tab_width - 1
-
- [ \t]*
- (?=\n{2,}) // followed by a blank line
- )
- /g,showdown.subParser('hashElement')(text, options, globals));
- */
- text = text.replace(/(\n\n[ ]{0,3}[ \t]*(?=\n{2,}))/g,
- showdown.subParser('hashElement')(text, options, globals));
-
- // PHP and ASP-style processor instructions (...?> and <%...%>)
-
- /*
- 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,showdown.subParser('hashElement')(text, options, globals));
- */
- text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,
- showdown.subParser('hashElement')(text, options, globals));
-
- // attacklab: Undo double lines (see comment at top of this function)
- text = text.replace(/\n\n/g, '\n');
- return text;
-
-});
-
-showdown.subParser('headers', function (text, options, globals) {
- 'use strict';
-
- var prefixHeader = options.prefixHeaderId,
- headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
-
- // Set text-style headers:
- // Header 1
- // ========
- //
- // Header 2
- // --------
- //
- setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
- setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;
-
- text = text.replace(setextRegexH1, function (wholeMatch, m1) {
-
- var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
- hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
- hLevel = headerLevelStart,
- hashBlock = '' + spanGamut + '';
- return showdown.subParser('hashBlock')(hashBlock, options, globals);
- });
-
- text = text.replace(setextRegexH2, function (matchFound, m1) {
- var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
- hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
- hLevel = headerLevelStart + 1,
- hashBlock = '' + spanGamut + '';
- return showdown.subParser('hashBlock')(hashBlock, options, globals);
- });
-
- // atx-style headers:
- // # Header 1
- // ## Header 2
- // ## Header 2 with closing hashes ##
- // ...
- // ###### Header 6
- //
- text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, function (wholeMatch, m1, m2) {
- var span = showdown.subParser('spanGamut')(m2, options, globals),
- hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',
- hLevel = headerLevelStart - 1 + m1.length,
- header = '' + span + '';
-
- return showdown.subParser('hashBlock')(header, options, globals);
- });
-
- function headerId(m) {
- var title, escapedId = m.replace(/[^\w]/g, '').toLowerCase();
-
- if (globals.hashLinkCounts[escapedId]) {
- title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++);
- } else {
- title = escapedId;
- globals.hashLinkCounts[escapedId] = 1;
- }
-
- // Prefix id to prevent causing inadvertent pre-existing style matches.
- if (prefixHeader === true) {
- prefixHeader = 'section';
- }
-
- if (showdown.helper.isString(prefixHeader)) {
- return prefixHeader + title;
- }
- return title;
- }
-
- return text;
-});
-
-/**
- * Turn Markdown image shortcuts into
,