vendor/assets/javascripts/marked.js in marked-rails-0.2.10.1 vs vendor/assets/javascripts/marked.js in marked-rails-0.3.2.0
- old
+ new
@@ -1,8 +1,8 @@
/**
* marked - a markdown parser
- * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
+ * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
* https://github.com/chjj/marked
*/
;(function() {
@@ -16,12 +16,12 @@
fences: noop,
hr: /^( *[-*_]){3,} *(?:\n+|$)/,
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
nptable: noop,
lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
- blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
- list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
+ blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
+ list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
table: noop,
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
text: /^[^\n]+/
@@ -33,17 +33,22 @@
(/bull/g, block.bullet)
();
block.list = replace(block.list)
(/bull/g, block.bullet)
- ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
+ ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
+ ('def', '\\n+(?=' + block.def.source + ')')
();
+block.blockquote = replace(block.blockquote)
+ ('def', block.def)
+ ();
+
block._tag = '(?!(?:'
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
- + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
+ + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
block.html = replace(block.html)
('comment', /<!--[\s\S]*?-->/)
('closed', /<(tag)[\s\S]+?<\/\1>/)
('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
@@ -139,11 +144,11 @@
/**
* Lexing
*/
-Lexer.prototype.token = function(src, top) {
+Lexer.prototype.token = function(src, top, bq) {
var src = src.replace(/^ +$/gm, '')
, next
, loose
, cap
, bull
@@ -262,11 +267,11 @@
cap = cap[0].replace(/^ *> ?/gm, '');
// Pass `top` to keep the current
// "toplevel" state. This is exactly
// how markdown.pl works.
- this.token(cap, top);
+ this.token(cap, top, true);
this.tokens.push({
type: 'blockquote_end'
});
@@ -331,11 +336,11 @@
? 'loose_item_start'
: 'list_item_start'
});
// Recurse.
- this.token(item, false);
+ this.token(item, false, bq);
this.tokens.push({
type: 'list_item_end'
});
}
@@ -359,11 +364,11 @@
});
continue;
}
// def
- if (top && (cap = this.rules.def.exec(src))) {
+ if ((!bq && top) && (cap = this.rules.def.exec(src))) {
src = src.substring(cap[0].length);
this.tokens.links[cap[1].toLowerCase()] = {
href: cap[2],
title: cap[3]
};
@@ -512,10 +517,12 @@
function InlineLexer(links, options) {
this.options = options || marked.defaults;
this.links = links;
this.rules = inline.normal;
+ this.renderer = this.options.renderer || new Renderer;
+ this.renderer.options = this.options;
if (!this.links) {
throw new
Error('Tokens array requires a `links` property.');
}
@@ -575,47 +582,46 @@
href = this.mangle('mailto:') + text;
} else {
text = escape(cap[1]);
href = text;
}
- out += '<a href="'
- + href
- + '">'
- + text
- + '</a>';
+ out += this.renderer.link(href, null, text);
continue;
}
// url (gfm)
- if (cap = this.rules.url.exec(src)) {
+ if (!this.inLink && (cap = this.rules.url.exec(src))) {
src = src.substring(cap[0].length);
text = escape(cap[1]);
href = text;
- out += '<a href="'
- + href
- + '">'
- + text
- + '</a>';
+ out += this.renderer.link(href, null, text);
continue;
}
// tag
if (cap = this.rules.tag.exec(src)) {
+ if (!this.inLink && /^<a /i.test(cap[0])) {
+ this.inLink = true;
+ } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
+ this.inLink = false;
+ }
src = src.substring(cap[0].length);
out += this.options.sanitize
? escape(cap[0])
: cap[0];
continue;
}
// link
if (cap = this.rules.link.exec(src)) {
src = src.substring(cap[0].length);
+ this.inLink = true;
out += this.outputLink(cap, {
href: cap[2],
title: cap[3]
});
+ this.inLink = false;
continue;
}
// reflink, nolink
if ((cap = this.rules.reflink.exec(src))
@@ -626,54 +632,48 @@
if (!link || !link.href) {
out += cap[0].charAt(0);
src = cap[0].substring(1) + src;
continue;
}
+ this.inLink = true;
out += this.outputLink(cap, link);
+ this.inLink = false;
continue;
}
// strong
if (cap = this.rules.strong.exec(src)) {
src = src.substring(cap[0].length);
- out += '<strong>'
- + this.output(cap[2] || cap[1])
- + '</strong>';
+ out += this.renderer.strong(this.output(cap[2] || cap[1]));
continue;
}
// em
if (cap = this.rules.em.exec(src)) {
src = src.substring(cap[0].length);
- out += '<em>'
- + this.output(cap[2] || cap[1])
- + '</em>';
+ out += this.renderer.em(this.output(cap[2] || cap[1]));
continue;
}
// code
if (cap = this.rules.code.exec(src)) {
src = src.substring(cap[0].length);
- out += '<code>'
- + escape(cap[2], true)
- + '</code>';
+ out += this.renderer.codespan(escape(cap[2], true));
continue;
}
// br
if (cap = this.rules.br.exec(src)) {
src = src.substring(cap[0].length);
- out += '<br>';
+ out += this.renderer.br();
continue;
}
// del (gfm)
if (cap = this.rules.del.exec(src)) {
src = src.substring(cap[0].length);
- out += '<del>'
- + this.output(cap[1])
- + '</del>';
+ out += this.renderer.del(this.output(cap[1]));
continue;
}
// text
if (cap = this.rules.text.exec(src)) {
@@ -694,35 +694,16 @@
/**
* Compile Link
*/
InlineLexer.prototype.outputLink = function(cap, link) {
- if (cap[0].charAt(0) !== '!') {
- return '<a href="'
- + escape(link.href)
- + '"'
- + (link.title
- ? ' title="'
- + escape(link.title)
- + '"'
- : '')
- + '>'
- + this.output(cap[1])
- + '</a>';
- } else {
- return '<img src="'
- + escape(link.href)
- + '" alt="'
- + escape(cap[1])
- + '"'
- + (link.title
- ? ' title="'
- + escape(link.title)
- + '"'
- : '')
- + '>';
- }
+ var href = escape(link.href)
+ , title = link.title ? escape(link.title) : null;
+
+ return cap[0].charAt(0) !== '!'
+ ? this.renderer.link(href, title, this.output(cap[1]))
+ : this.renderer.image(href, title, escape(cap[1]));
};
/**
* Smartypants Transformations
*/
@@ -764,34 +745,180 @@
return out;
};
/**
+ * Renderer
+ */
+
+function Renderer(options) {
+ this.options = options || {};
+}
+
+Renderer.prototype.code = function(code, lang, escaped) {
+ if (this.options.highlight) {
+ var out = this.options.highlight(code, lang);
+ if (out != null && out !== code) {
+ escaped = true;
+ code = out;
+ }
+ }
+
+ if (!lang) {
+ return '<pre><code>'
+ + (escaped ? code : escape(code, true))
+ + '\n</code></pre>';
+ }
+
+ return '<pre><code class="'
+ + this.options.langPrefix
+ + escape(lang, true)
+ + '">'
+ + (escaped ? code : escape(code, true))
+ + '\n</code></pre>\n';
+};
+
+Renderer.prototype.blockquote = function(quote) {
+ return '<blockquote>\n' + quote + '</blockquote>\n';
+};
+
+Renderer.prototype.html = function(html) {
+ return html;
+};
+
+Renderer.prototype.heading = function(text, level, raw) {
+ return '<h'
+ + level
+ + ' id="'
+ + this.options.headerPrefix
+ + raw.toLowerCase().replace(/[^\w]+/g, '-')
+ + '">'
+ + text
+ + '</h'
+ + level
+ + '>\n';
+};
+
+Renderer.prototype.hr = function() {
+ return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
+};
+
+Renderer.prototype.list = function(body, ordered) {
+ var type = ordered ? 'ol' : 'ul';
+ return '<' + type + '>\n' + body + '</' + type + '>\n';
+};
+
+Renderer.prototype.listitem = function(text) {
+ return '<li>' + text + '</li>\n';
+};
+
+Renderer.prototype.paragraph = function(text) {
+ return '<p>' + text + '</p>\n';
+};
+
+Renderer.prototype.table = function(header, body) {
+ return '<table>\n'
+ + '<thead>\n'
+ + header
+ + '</thead>\n'
+ + '<tbody>\n'
+ + body
+ + '</tbody>\n'
+ + '</table>\n';
+};
+
+Renderer.prototype.tablerow = function(content) {
+ return '<tr>\n' + content + '</tr>\n';
+};
+
+Renderer.prototype.tablecell = function(content, flags) {
+ var type = flags.header ? 'th' : 'td';
+ var tag = flags.align
+ ? '<' + type + ' style="text-align:' + flags.align + '">'
+ : '<' + type + '>';
+ return tag + content + '</' + type + '>\n';
+};
+
+// span level renderer
+Renderer.prototype.strong = function(text) {
+ return '<strong>' + text + '</strong>';
+};
+
+Renderer.prototype.em = function(text) {
+ return '<em>' + text + '</em>';
+};
+
+Renderer.prototype.codespan = function(text) {
+ return '<code>' + text + '</code>';
+};
+
+Renderer.prototype.br = function() {
+ return this.options.xhtml ? '<br/>' : '<br>';
+};
+
+Renderer.prototype.del = function(text) {
+ return '<del>' + text + '</del>';
+};
+
+Renderer.prototype.link = function(href, title, text) {
+ if (this.options.sanitize) {
+ try {
+ var prot = decodeURIComponent(unescape(href))
+ .replace(/[^\w:]/g, '')
+ .toLowerCase();
+ } catch (e) {
+ return '';
+ }
+ if (prot.indexOf('javascript:') === 0) {
+ return '';
+ }
+ }
+ var out = '<a href="' + href + '"';
+ if (title) {
+ out += ' title="' + title + '"';
+ }
+ out += '>' + text + '</a>';
+ return out;
+};
+
+Renderer.prototype.image = function(href, title, text) {
+ var out = '<img src="' + href + '" alt="' + text + '"';
+ if (title) {
+ out += ' title="' + title + '"';
+ }
+ out += this.options.xhtml ? '/>' : '>';
+ return out;
+};
+
+/**
* Parsing & Compiling
*/
function Parser(options) {
this.tokens = [];
this.token = null;
this.options = options || marked.defaults;
+ this.options.renderer = this.options.renderer || new Renderer;
+ this.renderer = this.options.renderer;
+ this.renderer.options = this.options;
}
/**
* Static Parse Method
*/
-Parser.parse = function(src, options) {
- var parser = new Parser(options);
+Parser.parse = function(src, options, renderer) {
+ var parser = new Parser(options, renderer);
return parser.parse(src);
};
/**
* Parse Loop
*/
Parser.prototype.parse = function(src) {
- this.inline = new InlineLexer(src.links, this.options);
+ this.inline = new InlineLexer(src.links, this.options, this.renderer);
this.tokens = src.reverse();
var out = '';
while (this.next()) {
out += this.tok();
@@ -838,153 +965,108 @@
switch (this.token.type) {
case 'space': {
return '';
}
case 'hr': {
- return '<hr>\n';
+ return this.renderer.hr();
}
case 'heading': {
- return '<h'
- + this.token.depth
- + ' id="'
- + this.token.text.toLowerCase().replace(/[^\w]+/g, '-')
- + '">'
- + this.inline.output(this.token.text)
- + '</h'
- + this.token.depth
- + '>\n';
+ return this.renderer.heading(
+ this.inline.output(this.token.text),
+ this.token.depth,
+ this.token.text);
}
case 'code': {
- if (this.options.highlight) {
- var code = this.options.highlight(this.token.text, this.token.lang);
- if (code != null && code !== this.token.text) {
- this.token.escaped = true;
- this.token.text = code;
- }
- }
-
- if (!this.token.escaped) {
- this.token.text = escape(this.token.text, true);
- }
-
- return '<pre><code'
- + (this.token.lang
- ? ' class="'
- + this.options.langPrefix
- + this.token.lang
- + '"'
- : '')
- + '>'
- + this.token.text
- + '</code></pre>\n';
+ return this.renderer.code(this.token.text,
+ this.token.lang,
+ this.token.escaped);
}
case 'table': {
- var body = ''
- , heading
+ var header = ''
+ , body = ''
, i
, row
, cell
+ , flags
, j;
// header
- body += '<thead>\n<tr>\n';
+ cell = '';
for (i = 0; i < this.token.header.length; i++) {
- heading = this.inline.output(this.token.header[i]);
- body += '<th';
- if (this.token.align[i]) {
- body += ' style="text-align:' + this.token.align[i] + '"';
- }
- body += '>' + heading + '</th>\n';
+ flags = { header: true, align: this.token.align[i] };
+ cell += this.renderer.tablecell(
+ this.inline.output(this.token.header[i]),
+ { header: true, align: this.token.align[i] }
+ );
}
- body += '</tr>\n</thead>\n';
+ header += this.renderer.tablerow(cell);
- // body
- body += '<tbody>\n'
for (i = 0; i < this.token.cells.length; i++) {
row = this.token.cells[i];
- body += '<tr>\n';
+
+ cell = '';
for (j = 0; j < row.length; j++) {
- cell = this.inline.output(row[j]);
- body += '<td';
- if (this.token.align[j]) {
- body += ' style="text-align:' + this.token.align[j] + '"';
- }
- body += '>' + cell + '</td>\n';
+ cell += this.renderer.tablecell(
+ this.inline.output(row[j]),
+ { header: false, align: this.token.align[j] }
+ );
}
- body += '</tr>\n';
- }
- body += '</tbody>\n';
- return '<table>\n'
- + body
- + '</table>\n';
+ body += this.renderer.tablerow(cell);
+ }
+ return this.renderer.table(header, body);
}
case 'blockquote_start': {
var body = '';
while (this.next().type !== 'blockquote_end') {
body += this.tok();
}
- return '<blockquote>\n'
- + body
- + '</blockquote>\n';
+ return this.renderer.blockquote(body);
}
case 'list_start': {
- var type = this.token.ordered ? 'ol' : 'ul'
- , body = '';
+ var body = ''
+ , ordered = this.token.ordered;
while (this.next().type !== 'list_end') {
body += this.tok();
}
- return '<'
- + type
- + '>\n'
- + body
- + '</'
- + type
- + '>\n';
+ return this.renderer.list(body, ordered);
}
case 'list_item_start': {
var body = '';
while (this.next().type !== 'list_item_end') {
body += this.token.type === 'text'
? this.parseText()
: this.tok();
}
- return '<li>'
- + body
- + '</li>\n';
+ return this.renderer.listitem(body);
}
case 'loose_item_start': {
var body = '';
while (this.next().type !== 'list_item_end') {
body += this.tok();
}
- return '<li>'
- + body
- + '</li>\n';
+ return this.renderer.listitem(body);
}
case 'html': {
- return !this.token.pre && !this.options.pedantic
+ var html = !this.token.pre && !this.options.pedantic
? this.inline.output(this.token.text)
: this.token.text;
+ return this.renderer.html(html);
}
case 'paragraph': {
- return '<p>'
- + this.inline.output(this.token.text)
- + '</p>\n';
+ return this.renderer.paragraph(this.inline.output(this.token.text));
}
case 'text': {
- return '<p>'
- + this.parseText()
- + '</p>\n';
+ return this.renderer.paragraph(this.parseText());
}
}
};
/**
@@ -998,10 +1080,23 @@
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
+function unescape(html) {
+ return html.replace(/&([#\w]+);/g, function(_, n) {
+ n = n.toLowerCase();
+ if (n === 'colon') return ':';
+ if (n.charAt(0) === '#') {
+ return n.charAt(1) === 'x'
+ ? String.fromCharCode(parseInt(n.substring(2), 16))
+ : String.fromCharCode(+n.substring(1));
+ }
+ return '';
+ });
+}
+
function replace(regex, opt) {
regex = regex.source;
opt = opt || '';
return function self(name, val) {
if (!name) return new RegExp(regex, opt);
@@ -1030,10 +1125,11 @@
}
return obj;
}
+
/**
* Marked
*/
function marked(src, opt, callback) {
@@ -1132,18 +1228,23 @@
sanitize: false,
smartLists: false,
silent: false,
highlight: null,
langPrefix: 'lang-',
- smartypants: false
+ smartypants: false,
+ headerPrefix: '',
+ renderer: new Renderer,
+ xhtml: false
};
/**
* Expose
*/
marked.Parser = Parser;
marked.parser = Parser.parse;
+
+marked.Renderer = Renderer;
marked.Lexer = Lexer;
marked.lexer = Lexer.lex;
marked.InlineLexer = InlineLexer;