Mercurial > zeropaste
view lib/assets/javascripts/marked.js @ 208:953d284ec195
Revamp the routing
author | Edho Arief <edho@myconan.net> |
---|---|
date | Sat, 11 May 2013 22:39:06 +0900 |
parents | 90b59418828a |
children |
line wrap: on
line source
/** * marked - A markdown parser (https://github.com/chjj/marked) * Copyright (c) 2011-2012, Christopher Jeffrey. (MIT Licensed) */ ;(function() { /** * Block-Level Grammar */ var block = { newline: /^\n+/, code: /^( {4}[^\n]+\n*)+/, fences: noop, hr: /^( *[-*_]){3,} *(?:\n+|$)/, heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, lheading: /^([^\n]+)\n *(=|-){3,} *\n*/, blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, list: /^( *)(bull) [^\0]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, def: /^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, paragraph: /^([^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+\n*/, text: /^[^\n]+/ }; block.bullet = /(?:[*+-]|\d+\.)/; block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; block.item = replace(block.item, 'gm') (/bull/g, block.bullet) (); block.list = replace(block.list) (/bull/g, block.bullet) ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/) (); block.html = replace(block.html) ('comment', /<!--[^\0]*?-->/) ('closed', /<(tag)[^\0]+?<\/\1>/) ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/) (/tag/g, tag()) (); block.paragraph = replace(block.paragraph) ('hr', block.hr) ('heading', block.heading) ('lheading', block.lheading) ('blockquote', block.blockquote) ('tag', '<' + tag()) ('def', block.def) (); block.normal = { fences: block.fences, paragraph: block.paragraph }; block.gfm = { fences: /^ *(```|~~~) *(\w+)? *\n([^\0]+?)\s*\1 *(?:\n+|$)/, paragraph: /^/ }; block.gfm.paragraph = replace(block.paragraph) ('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|') (); /** * Block Lexer */ block.lexer = function(src) { var tokens = []; tokens.links = {}; src = src .replace(/\r\n|\r/g, '\n') .replace(/\t/g, ' '); return block.token(src, tokens, true); }; block.token = function(src, tokens, top) { var src = src.replace(/^ +$/gm, '') , next , loose , cap , item , space , i , l; while (src) { // newline if (cap = block.newline.exec(src)) { src = src.substring(cap[0].length); if (cap[0].length > 1) { tokens.push({ type: 'space' }); } } // code if (cap = block.code.exec(src)) { src = src.substring(cap[0].length); cap = cap[0].replace(/^ {4}/gm, ''); tokens.push({ type: 'code', text: !options.pedantic ? cap.replace(/\n+$/, '') : cap }); continue; } // fences (gfm) if (cap = block.fences.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'code', lang: cap[2], text: cap[3] }); continue; } // heading if (cap = block.heading.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'heading', depth: cap[1].length, text: cap[2] }); continue; } // lheading if (cap = block.lheading.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'heading', depth: cap[2] === '=' ? 1 : 2, text: cap[1] }); continue; } // hr if (cap = block.hr.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'hr' }); continue; } // blockquote if (cap = block.blockquote.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'blockquote_start' }); cap = cap[0].replace(/^ *> ?/gm, ''); // Pass `top` to keep the current // "toplevel" state. This is exactly // how markdown.pl works. block.token(cap, tokens, top); tokens.push({ type: 'blockquote_end' }); continue; } // list if (cap = block.list.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: 'list_start', ordered: isFinite(cap[2]) }); // Get each top-level item. cap = cap[0].match(block.item); next = false; l = cap.length; i = 0; for (; i < l; i++) { item = cap[i]; // Remove the list item's bullet // so it is seen as the next token. space = item.length; item = item.replace(/^ *([*+-]|\d+\.) +/, ''); // Outdent whatever the // list item contains. Hacky. if (~item.indexOf('\n ')) { space -= item.length; item = !options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, ''); } // Determine whether item is loose or not. // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ // for discount behavior. loose = next || /\n\n(?!\s*$)/.test(item); if (i !== l - 1) { next = item[item.length-1] === '\n'; if (!loose) loose = next; } tokens.push({ type: loose ? 'loose_item_start' : 'list_item_start' }); // Recurse. block.token(item, tokens); tokens.push({ type: 'list_item_end' }); } tokens.push({ type: 'list_end' }); continue; } // html if (cap = block.html.exec(src)) { src = src.substring(cap[0].length); tokens.push({ type: options.sanitize ? 'paragraph' : 'html', pre: cap[1] === 'pre', text: cap[0] }); continue; } // def if (top && (cap = block.def.exec(src))) { src = src.substring(cap[0].length); tokens.links[cap[1].toLowerCase()] = { href: cap[2], title: cap[3] }; continue; } // top-level paragraph if (top && (cap = block.paragraph.exec(src))) { src = src.substring(cap[0].length); tokens.push({ type: 'paragraph', text: cap[0] }); continue; } // text if (cap = block.text.exec(src)) { // Top-level should never reach here. src = src.substring(cap[0].length); tokens.push({ type: 'text', text: cap[0] }); continue; } } return tokens; }; /** * Inline Processing */ var inline = { escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, url: noop, tag: /^<!--[^\0]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, link: /^!?\[(inside)\]\(href\)/, reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, strong: /^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/, em: /^\b_((?:__|[^\0])+?)_\b|^\*((?:\*\*|[^\0])+?)\*(?!\*)/, code: /^(`+)([^\0]*?[^`])\1(?!`)/, br: /^ {2,}\n(?!\s*$)/, text: /^[^\0]+?(?=[\\<!\[_*`]| {2,}\n|$)/ }; inline._linkInside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/; inline._linkHref = /\s*<?([^\s]*?)>?(?:\s+['"]([^\0]*?)['"])?\s*/; inline.link = replace(inline.link) ('inside', inline._linkInside) ('href', inline._linkHref) (); inline.reflink = replace(inline.reflink) ('inside', inline._linkInside) (); inline.normal = { url: inline.url, strong: inline.strong, em: inline.em, text: inline.text }; inline.pedantic = { strong: /^__(?=\S)([^\0]*?\S)__(?!_)|^\*\*(?=\S)([^\0]*?\S)\*\*(?!\*)/, em: /^_(?=\S)([^\0]*?\S)_(?!_)|^\*(?=\S)([^\0]*?\S)\*(?!\*)/ }; inline.gfm = { url: /^(https?:\/\/[^\s]+[^.,:;"')\]\s])/, text: /^[^\0]+?(?=[\\<!\[_*`]|https?:\/\/| {2,}\n|$)/ }; /** * Inline Lexer */ inline.lexer = function(src) { var out = '' , links = tokens.links , link , text , href , cap; while (src) { // escape if (cap = inline.escape.exec(src)) { src = src.substring(cap[0].length); out += cap[1]; continue; } // autolink if (cap = inline.autolink.exec(src)) { src = src.substring(cap[0].length); if (cap[2] === '@') { text = cap[1][6] === ':' ? mangle(cap[1].substring(7)) : mangle(cap[1]); href = mangle('mailto:') + text; } else { text = escape(cap[1]); href = text; } out += '<a href="' + href + '">' + text + '</a>'; continue; } // url (gfm) if (cap = inline.url.exec(src)) { src = src.substring(cap[0].length); text = escape(cap[1]); href = text; out += '<a href="' + href + '">' + text + '</a>'; continue; } // tag if (cap = inline.tag.exec(src)) { src = src.substring(cap[0].length); out += options.sanitize ? escape(cap[0]) : cap[0]; continue; } // link if (cap = inline.link.exec(src)) { src = src.substring(cap[0].length); out += outputLink(cap, { href: cap[2], title: cap[3] }); continue; } // reflink, nolink if ((cap = inline.reflink.exec(src)) || (cap = inline.nolink.exec(src))) { src = src.substring(cap[0].length); link = (cap[2] || cap[1]).replace(/\s+/g, ' '); link = links[link.toLowerCase()]; if (!link || !link.href) { out += cap[0][0]; src = cap[0].substring(1) + src; continue; } out += outputLink(cap, link); continue; } // strong if (cap = inline.strong.exec(src)) { src = src.substring(cap[0].length); out += '<strong>' + inline.lexer(cap[2] || cap[1]) + '</strong>'; continue; } // em if (cap = inline.em.exec(src)) { src = src.substring(cap[0].length); out += '<em>' + inline.lexer(cap[2] || cap[1]) + '</em>'; continue; } // code if (cap = inline.code.exec(src)) { src = src.substring(cap[0].length); out += '<code>' + escape(cap[2], true) + '</code>'; continue; } // br if (cap = inline.br.exec(src)) { src = src.substring(cap[0].length); out += '<br>'; continue; } // text if (cap = inline.text.exec(src)) { src = src.substring(cap[0].length); out += escape(cap[0]); continue; } } return out; }; function outputLink(cap, link) { if (cap[0][0] !== '!') { return '<a href="' + escape(link.href) + '"' + (link.title ? ' title="' + escape(link.title) + '"' : '') + '>' + inline.lexer(cap[1]) + '</a>'; } else { return '<img src="' + escape(link.href) + '" alt="' + escape(cap[1]) + '"' + (link.title ? ' title="' + escape(link.title) + '"' : '') + '>'; } } /** * Parsing */ var tokens , token; function next() { return token = tokens.pop(); } function tok() { switch (token.type) { case 'space': { return ''; } case 'hr': { return '<hr>\n'; } case 'heading': { return '<h' + token.depth + '>' + inline.lexer(token.text) + '</h' + token.depth + '>\n'; } case 'code': { if (options.highlight) { token.code = options.highlight(token.text, token.lang); if (token.code != null && token.code !== token.text) { token.escaped = true; token.text = token.code; } } if (!token.escaped) { token.text = escape(token.text, true); } return '<pre><code' + (token.lang ? ' class="lang-' + token.lang + '"' : '') + '>' + token.text + '</code></pre>\n'; } case 'blockquote_start': { var body = ''; while (next().type !== 'blockquote_end') { body += tok(); } return '<blockquote>\n' + body + '</blockquote>\n'; } case 'list_start': { var type = token.ordered ? 'ol' : 'ul' , body = ''; while (next().type !== 'list_end') { body += tok(); } return '<' + type + '>\n' + body + '</' + type + '>\n'; } case 'list_item_start': { var body = ''; while (next().type !== 'list_item_end') { body += token.type === 'text' ? parseText() : tok(); } return '<li>' + body + '</li>\n'; } case 'loose_item_start': { var body = ''; while (next().type !== 'list_item_end') { body += tok(); } return '<li>' + body + '</li>\n'; } case 'html': { return !token.pre && !options.pedantic ? inline.lexer(token.text) : token.text; } case 'paragraph': { return '<p>' + inline.lexer(token.text) + '</p>\n'; } case 'text': { return '<p>' + parseText() + '</p>\n'; } } } function parseText() { var body = token.text , top; while ((top = tokens[tokens.length-1]) && top.type === 'text') { body += '\n' + next().text; } return inline.lexer(body); } function parse(src) { tokens = src.reverse(); var out = ''; while (next()) { out += tok(); } tokens = null; token = null; return out; } /** * Helpers */ function escape(html, encode) { return html .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function mangle(text) { var out = '' , l = text.length , i = 0 , ch; for (; i < l; i++) { ch = text.charCodeAt(i); if (Math.random() > 0.5) { ch = 'x' + ch.toString(16); } out += '&#' + ch + ';'; } return out; } function tag() { var 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'; return tag; } function replace(regex, opt) { regex = regex.source; opt = opt || ''; return function self(name, val) { if (!name) return new RegExp(regex, opt); val = val.source || val; val = val.replace(/(^|[^\[])\^/g, '$1'); regex = regex.replace(name, val); return self; }; } function noop() {} noop.exec = noop; /** * Marked */ function marked(src, opt) { setOptions(opt); return parse(block.lexer(src)); } /** * Options */ var options , defaults; function setOptions(opt) { if (!opt) opt = defaults; if (options === opt) return; options = opt; if (options.gfm) { block.fences = block.gfm.fences; block.paragraph = block.gfm.paragraph; inline.text = inline.gfm.text; inline.url = inline.gfm.url; } else { block.fences = block.normal.fences; block.paragraph = block.normal.paragraph; inline.text = inline.normal.text; inline.url = inline.normal.url; } if (options.pedantic) { inline.em = inline.pedantic.em; inline.strong = inline.pedantic.strong; } else { inline.em = inline.normal.em; inline.strong = inline.normal.strong; } } marked.options = marked.setOptions = function(opt) { defaults = opt; setOptions(opt); return marked; }; marked.setOptions({ gfm: true, pedantic: false, sanitize: false, highlight: null }); /** * Expose */ marked.parser = function(src, opt) { setOptions(opt); return parse(src); }; marked.lexer = function(src, opt) { setOptions(opt); return block.lexer(src); }; marked.parse = marked; if (typeof module !== 'undefined') { module.exports = marked; } else { this.marked = marked; } }).call(function() { return this || (typeof window !== 'undefined' ? window : global); }());