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" var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math" // First, look for nested blocks, e.g.: //
tags around block-level tags.
text = _HashHTMLBlocks(text);
text = _FormParagraphs(text);
return text;
}
var _RunSpanGamut = function(text) {
//
// These are all the transformations that occur *within* block-level
// tags like paragraphs, headers, and list items.
//
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 ` Just type tags
//
// Strip leading and trailing lines:
text = text.replace(/^\n+/g,"");
text = text.replace(/\n+$/g,"");
var grafs = text.split(/\n{2,}/g);
var grafsOut = new Array();
//
// Wrap tags.
//
var end = grafs.length;
for (var i=0; i ");
str += "
\n");
return text;
}
var _EscapeSpecialCharsWithinTagAttributes = function(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.
var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi;
text = text.replace(regex, function(wholeMatch) {
var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`");
tag = escapeCharacters(tag,"\\`*_");
return tag;
});
return text;
}
var _DoAnchors = function(text) {
//
// Turn Markdown link shortcuts into XHTML 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,_DoAnchors_callback);
*/
text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag);
//
// Next, inline-style links: [link text](url "optional title")
//
/*
text = text.replace(/
( // wrap whole match in $1
\[
(
(?:
\[[^\]]*\] // allow brackets nested one level
|
[^\[\]] // or anything else
)
)
\]
\( // literal paren
[ \t]*
() // no id, so leave $3 empty
(?:[^\(]*?\([^\)]*?\).*?)
( // href = $4
(?:[^\(]*?\([^\)]*?\)\S*?) // Match one depth of parentheses
|
(?:.*?) // Match no parentheses
)
>?
[ \t]*
( // $5
(['"]) // quote char = $6
(.*?) // Title = $7
\6 // matching quote
[ \t]* // ignore any spaces/tabs between closing quote and )
)? // title is optional
\)
)
/g,writeAnchorTag);
*/
text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()((?:[^\(]*?\([^\)]*?\)\S*?)|(?:.*?))>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);
//
// Last, handle reference-style shortcuts: [link text]
// These must come last in case you've also got [link test][1]
// or [link test](/foo)
//
/*
text = text.replace(/
( // wrap whole match in $1
\[
([^\[\]]+) // link text = $2; can't contain '[' or ']'
\]
)()()()()() // pad rest of backreferences
/g, writeAnchorTag);
*/
text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
return text;
}
var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
if (m7 == undefined) m7 = "";
var whole_match = m1;
var link_text = m2;
var link_id = m3.toLowerCase();
var url = m4;
var title = m7;
if (url == "") {
if (link_id == "") {
// lower-case and turn embedded newlines into spaces
link_id = link_text.toLowerCase().replace(/ ?\n/g," ");
}
url = "#"+link_id;
if (g_urls[link_id] != undefined) {
url = g_urls[link_id];
if (g_titles[link_id] != undefined) {
title = g_titles[link_id];
}
}
else {
if (whole_match.search(/\(\s*\)$/m)>-1) {
// Special case for explicit empty url
url = "";
} else {
return whole_match;
}
}
}
url = escapeCharacters(url,"*_");
var result = "" + link_text + "";
if (config.refprint) {
if (!g_print_refs[url]) {
g_print_refs[url] = ++g_print_refs_count;
}
result += '~E91E' + g_print_refs[url] + '~E93E';
}
return result;
}
var _DoImages = function(text) {
//
// Turn Markdown image shortcuts into tags.
//
//
// First, handle reference-style labeled images: ![alt text][id]
//
/*
text = text.replace(/
( // wrap whole match in $1
!\[
(.*?) // alt text = $2
\]
[ ]? // one optional space
(?:\n[ ]*)? // one optional newline followed by spaces
\[
(.*?) // id = $3
\]
)()()()() // pad rest of backreferences
/g,writeImageTag);
*/
text = text.replace(/(![<>]?\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);
//
// Next, handle inline images: ![alt text](url "optional title")
// Don't forget: encode * and _
/*
text = text.replace(/
( // wrap whole match in $1
!\[
(.*?) // alt text = $2
\]
\s? // One optional whitespace character
\( // literal paren
[ \t]*
() // no id, so leave $3 empty
( // src url = $4
(?:[^\(]*?\([^\)]*?\)\S*?) // Match one depth of parentheses
|
(?:\S+?) // Match 0 depth of parentheses
)
>?
[ \t]*
( // $5
(['"]) // quote char = $6
(.*?) // title = $7
\6 // matching quote
[ \t]*
)? // title is optional
\)
)
/g,writeImageTag);
*/
text = text.replace(/(![<>]?\[(.*?)\]\s?\([ \t]*()((?:[^\(]*?\([^\)]*?\)\S*?)|(?:\S*?))>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);
return text;
}
var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
var whole_match = m1;
var alt_text = m2;
var link_id = m3.toLowerCase();
var url = m4;
var title = m7;
if (!title) title = "";
if (url == "" && link_id !== "") {
// lower-case and turn embedded newlines into spaces
if (g_urls[link_id] != undefined) {
url = g_urls[link_id];
if (g_titles[link_id] != undefined) {
title = g_titles[link_id];
} else {
title = undefined;
}
}
}
var figure = false, match;
if (match = whole_match.match(/^!([<>])/)) {
if (match[1] === ">") {
figure = "right";
} else if (match[1] === "<") {
figure = "left";
}
}
alt_text = alt_text.replace(/"/g,""");
url = escapeCharacters(url,"*_");
var result = "";
if (config.figures && figure !== false) {
if (title === undefined || title === "") {
result = '
\n ' + title + '\n' + _RunSpanGamut(m1) + "
");
} else {
return hashBlock('' + _RunSpanGamut(m1) + "
");
}
}
);
text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
function(matchFound,m1) {
if (config.headerautoid) {
return hashBlock('' + _RunSpanGamut(m1) + "
");
} else {
return hashBlock('' + _RunSpanGamut(m1) + "
");
}
}
);
// atx-style headers:
// # Header 1
// ## Header 2
// ## Header 2 with closing hashes ##
// ...
// ###### Header 6
//
/*
text = text.replace(/
^(\#{1,6}) // $1 = string of #'s
[ \t]*
(.+?) // $2 = Header text
[ \t]*
\#* // optional closing #'s (not counted)
\n+
/gm, function() {...});
*/
text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
function(wholeMatch,m1,m2) {
var h_level = m1.length;
if (config.headerautoid) {
return hashBlock("` blocks.
//
/*
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";
if (config.github_flavouring) {
text = text.replace(/\n```([a-zA-Z]+)?\s*\n((?:.*\n+)+?)(\n*```|(?=~0))/g,
function (wholeMatch, m1, m2) {
var codeblock = _EncodeCode(m2);
codeblock = _Detab(codeblock);
codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
if (m1) {
codeblock = "
";
} else {
codeblock = "" + codeblock + "\n
";
}
return hashBlock(codeblock);
});
}
text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
function(wholeMatch,m1,m2) {
var codeblock = m1;
var nextChar = m2;
codeblock = _EncodeCode( _Outdent(codeblock));
codeblock = _Detab(codeblock);
codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
codeblock = "" + codeblock + "\n
";
return hashBlock(codeblock) + nextChar;
}
);
// attacklab: strip sentinel
text = text.replace(/~0/,"");
return text;
}
var hashBlock = function(text) {
text = text.replace(/(^\n+|\n+$)/g,"");
return "\n\n~K" + (g_html_blocks.push(text)-1) + "K\n\n";
}
var _DoCodeSpans = function(text) {
//
// * Backtick quotes are used for " + codeblock + "\n
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:
//
//
foo `bar` baz
at the prompt.`bar`
...
//
/*
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,m4) {
var c = m3;
c = c.replace(/^([ \t]*)/g,""); // leading whitespace
c = c.replace(/[ \t]*$/g,""); // trailing whitespace
c = _EncodeCode(c);
return m1+""+c+"
";
});
if (config.math) {
text = text.replace(/(^|[^\\])(%%)([^\r]*?[^%])\2(?!%)/gm,
function(wholeMatch,m1,m2,m3,m4) {
var c = m3;
c = c.replace(/^([ \t]*)/g,""); // leading whitespace
c = c.replace(/[ \t]*$/g,""); // trailing whitespace
c = _EncodeCode(c);
return m1+'%%'+c+"%%";
});
text = text.replace(/(^|[^\\])(~D~D)([^\r]*?[^~])\2(?!~D)/gm,
function(wholeMatch,m1,m2,m3,m4) {
var c = m3;
c = c.replace(/^([ \t]*)/g,""); // leading whitespace
c = c.replace(/[ \t]*$/g,""); // trailing whitespace
c = _EncodeCode(c);
return m1+'~D~D'+c+"~D~D";
});
}
return text;
}
var _EncodeCode = function(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.
//
// 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,">");
// Pipes are escaped early, unescape them into escaped pipes.
// Need to find better solution.
text = text.replace(/~E124E/g, "\\|");
// Now, escape characters that are magic in Markdown:
text = escapeCharacters(text,"\*_{}[]\\",false);
// jj the line above breaks this:
//---
//* Item
// 1. Subitem
// special char: *
//---
return text;
}
var _DoTextStyle = function(text) {
// must go first:
text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,
"$2");
if (config.github_flavouring) {
text = text.replace(/(\w)_(\w)/g, "$1~E95E$2") // ** GFM ** "~E95E" == escaped "_"
}
text = text.replace(/(~T~T)(?=\S)([^\r]*?\S[*_]*)\1/g, "$2");
text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,
"$2");
return text;
}
var _DoBlockQuotes = function(text) {
/*
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]*>[ \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 = _RunBlockGamut(bq); // 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 hashBlock("
\n" + bq + "\n
");
});
return text;
}
var _FormParagraphs = function(text) {
//
// Params:
// $text - string to process with html
"); // ** GFM **
}
str = str.replace(/^([ \t]*)/g,"\n";
text += "\n";
text += "
";
return text;
}
} // end of Showdown.converter
// Sourced from https://github.com/andris9/node-markdown
var stripUnwantedHTML = function (html /*, allowedTags, allowedAttributes, forceProtocol */){
var allowedTags = arguments[1] ||
'a|b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|h4|h5|h6|'+
'i|img|li|ol|p|pre|sup|sub|strong|strike|ul|br|hr|span|'+
'table|th|tr|td|tbody|thead|tfoot|div',
allowedAttributes = arguments[2] || {
'img': 'src|width|height|alt',
'a': 'href',
'*': 'title',
'span': 'class',
'tr': 'rowspan',
'td': 'colspan|align',
'th': 'rowspan|align',
'div': 'class',
'code': 'class'
}, forceProtocol = arguments[3] || true;
testAllowed = new RegExp('^('+allowedTags.toLowerCase()+')$'),
findTags = /<(\/?)\s*([\w:\-]+)([^>]*)>/g,
findAttribs = /(\s*)([\w:-]+)\s*=\s*(?:(?:(["'])([^\3]+?)(?:\3))|([^\s]+))/g;
// convert all strings patterns into regexp objects (if not already converted)
for(var i in allowedAttributes){
if(allowedAttributes.hasOwnProperty(i) && typeof allowedAttributes[i] === 'string'){
allowedAttributes[i] = new RegExp('^('+
allowedAttributes[i].toLowerCase()+')$');
}
}
// find and match html tags
return html.replace(findTags, function(original, lslash, tag, params){
var tagAttr, wildcardAttr,
rslash = params.substr(-1)=="/" && "/" || "";
tag = tag.toLowerCase();
// tag is not allowed, return empty string
if(!tag.match(testAllowed))
return "";
// tag is allowed
else{
// regexp objects for a particular tag
tagAttr = tag in allowedAttributes && allowedAttributes[tag];
wildcardAttr = "*" in allowedAttributes && allowedAttributes["*"];
// if no attribs are allowed
if(!tagAttr && !wildcardAttr)
return "<"+lslash+tag+rslash+">";
// remove trailing slash if any
params = params.trim();
if(rslash){
params = params.substr(0, params.length-1);
}
// find and remove unwanted attributes
params = params.replace(findAttribs, function(original, space,
name, quot, value){
name = name.toLowerCase();
if (!value && !quot) {
value = "";
quot = '"';
} else if (!value) {
value = quot;
quot = '"';
}
// force data: and javascript: links and images to #
if((name=="href" || name=="src") &&
(value.trim().substr(0, "javascript:".length)=="javascript:"
|| (name == "href" && value.trim().substr(0, "data:".length)=="data:"))) {
value = "#";
}
// scope links and sources to http protocol
if (forceProtocol &&
(name=="href" || name=="src") &&
!/^[a-zA-Z]{3,5}:\/\//.test(value) &&
(value.length < 8 && value.trim().substr(0, "mailto:".length)=="mailto:")) {
value = "http://" + value;
}
if((wildcardAttr && name.match(wildcardAttr)) ||
(tagAttr && name.match(tagAttr))){
return space+name+"="+quot+value+quot;
}else
return "";
});
return "<"+lslash+tag+(params?" "+params:"")+rslash+">";
}
});
}
// export
if (typeof exports != 'undefined') exports.Showdown = Showdown;\n";
for (var i = 0; i < col_count; ++i) {
text += " \n";
text += "\n";
// Split content by row.
var rows = content.split(/\n/);
text += "\n";
for (var i = 0, len = rows.length; i < len; ++i) {
// Parsing span elements, including code spans, character escapes,
// and inline HTML tags, so that pipes inside those gets ignored.
// $row = $this->parseSpan($row); // TODO
// Split row by cell.
var row_cells = rows[i].split(/[ ]*[|][ ]*/);
// row_cells = array_pad($row_cells, $col_count, ''); // TODO
text += "" + _RunSpanGamut(doTrim(headers[i])) + " \n";
}
text += "\n";
for (var j = 0, len2 = row_cells.length; j < len2; ++j) {
text += " \n";
}
text += "\n";
text += "" + _RunSpanGamut(doTrim(row_cells[j])) + " \n";
}
text += "