/*! Flatdoc (http://ricostacruz.com/flatdoc) (c) 2013 Rico Sta. Cruz. MIT licensed. Also includes: marked a markdown parser (c) 2011-2013, Christopher Jeffrey. (MIT Licensed) https://github.com/chjj/marked base64.js http://github.com/dankogai/js-base64 */ (function($) { var exports = this; var marked; /** * Basic Flatdoc module. * * The main entry point is `Flatdoc.run()`, which invokes the [Runner]. * * Flatdoc.run({ * fetcher: Flatdoc.github('rstacruz/backbone-patterns'); * }); */ var Flatdoc = exports.Flatdoc = {}; /** * Creates a runner. * See [Flatdoc]. */ Flatdoc.run = function(options) { $(function() { (new Flatdoc.runner(options)).run(); }); }; /** * File fetcher function. * * Fetches a given `url` via AJAX. * See [Runner#run()] for a description of fetcher functions. */ Flatdoc.file = function(url) { return function(callback) { $.get(url) .fail(function(e) { callback(e, null); }) .done(function(data) { callback(null, data); }); }; }; /** * Github fetcher. * Fetches from repo `repo` (in format 'user/repo'). * * If the parameter `filepath` is supplied, it fetches the contents of that * given file in the repo. * * See [Runner#run()] for a description of fetcher functions. * * See: http://developer.github.com/v3/repos/contents/ */ Flatdoc.github = function(repo, filepath) { var url; if (filepath) { url = 'https://api.github.com/repos/'+repo+'/contents/'+filepath; } else { url = 'https://api.github.com/repos/'+repo+'/readme'; } return function(callback) { $.get(url) .fail(function(e) { callback(e, null); }) .done(function(data) { var markdown = exports.Base64.decode(data.content); callback(null, markdown); }); }; }; /** * Parser module. * Parses a given Markdown document and returns a JSON object with data * on the Markdown document. * * var data = Flatdoc.parser.parse('markdown source here'); * console.log(data); * * data == { * title: 'My Project', * content: '
This project is a...', * menu: {...} * } */ var Parser = Flatdoc.parser = {}; /** * Parses a given Markdown document. * See `Parser` for more info. */ Parser.parse = function(source) { marked = exports.marked; Parser.setMarkedOptions(); var html = $("
Hello there, this is a docu...");
* Flatdoc.transformer.mangle($content);
*
* If you would like to change any of the transformations, decorate any of
* the functions in `Flatdoc.transformer`.
*/
var Transformer = Flatdoc.transformer = {};
/**
* Takes a given HTML `$content` and improves the markup of it by executing
* the transformations.
*
* > See: [Transformer](#transformer)
*/
Transformer.mangle = function($content) {
this.addIDs($content);
this.buttonize($content);
this.smartquotes($content);
};
/**
* Adds IDs to headings.
*/
Transformer.addIDs = function($content) {
$content.find('h1, h2, h3').each(function() {
var $el = $(this);
var text = $el.text();
var id = slugify(text);
$el.attr('id', id);
});
};
/**
* Returns menu data for a given HTML.
*
* menu = Flatdoc.transformer.getMenu($content);
* menu == {
* level: 0,
* items: [{
* section: "Getting started",
* level: 1,
* items: [...]}, ...]}
*/
Transformer.getMenu = function($content) {
var root = {items: [], id: '', level: 0};
var cache = [root];
function mkdir_p(level) {
var parent = (level > 1) ? mkdir_p(level-1) : root;
if (!cache[level]) {
var obj = { items: [], level: level };
cache[level] = obj;
parent.items.push(obj);
return obj;
}
return cache[level];
}
$content.find('h1, h2, h3').each(function() {
var $el = $(this);
var level = +(this.nodeName.substr(1));
var parent = mkdir_p(level-1);
var obj = { section: $el.text(), items: [], level: level, id: $el.attr('id') };
parent.items.push(obj);
cache[level] = obj;
});
return root;
};
/**
* Changes "button >" text to buttons.
*/
Transformer.buttonize = function($content) {
$content.find('a').each(function() {
var $a = $(this);
var m = $a.text().match(/^(.*) >$/);
if (m) $a.text(m[1]).addClass('button');
});
};
/**
* Applies smart quotes to a given element.
* It leaves `code` and `pre` blocks alone.
*/
Transformer.smartquotes = function ($content) {
var nodes = getTextNodesIn($content), len = nodes.length;
for (var i=0; i
'
+ escape(cap[2], true)
+ '
';
continue;
}
// br
if (cap = this.rules.br.exec(src)) {
src = src.substring(cap[0].length);
out += ''
+ this.token.text
+ '
\n';
}
case 'table': {
var body = ''
, heading
, i
, row
, cell
, j;
// header
body += '\n\n' + body + '\n'; } case 'list_start': { var type = this.token.ordered ? 'ol' : 'ul' , body = ''; while (this.next().type !== 'list_end') { body += this.tok(); } return '<' + type + '>\n' + body + '' + type + '>\n'; } case 'list_item_start': { var body = ''; while (this.next().type !== 'list_item_end') { body += this.token.type === 'text' ? this.parseText() : this.tok(); } return '
' + this.inline.output(this.token.text) + '
\n'; } case 'text': { return '' + this.parseText() + '
\n'; } } }; /** * Helpers */ function escape(html, encode) { return html .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } 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; function merge(obj) { var i = 1 , target , key; for (; i < arguments.length; i++) { target = arguments[i]; for (key in target) { if (Object.prototype.hasOwnProperty.call(target, key)) { obj[key] = target[key]; } } } return obj; } /** * Marked */ function marked(src, opt, callback) { if (callback || typeof opt === 'function') { if (!callback) { callback = opt; opt = null; } if (opt) opt = merge({}, marked.defaults, opt); var tokens = Lexer.lex(tokens, opt) , highlight = opt.highlight , pending = 0 , l = tokens.length , i = 0; if (!highlight || highlight.length < 3) { return callback(null, Parser.parse(tokens, opt)); } var done = function() { delete opt.highlight; var out = Parser.parse(tokens, opt); opt.highlight = highlight; return callback(null, out); }; for (; i < l; i++) { (function(token) { if (token.type !== 'code') return; pending++; return highlight(token.text, token.lang, function(err, code) { if (code == null || code === token.text) { return --pending || done(); } token.text = code; token.escaped = true; --pending || done(); }); })(tokens[i]); } return; } try { if (opt) opt = merge({}, marked.defaults, opt); return Parser.parse(Lexer.lex(src, opt), opt); } catch (e) { e.message += '\nPlease report this to https://github.com/chjj/marked.'; if ((opt || marked.defaults).silent) { return 'An error occured:
' + escape(e.message + '', true) + ''; } throw e; } } /** * Options */ marked.options = marked.setOptions = function(opt) { merge(marked.defaults, opt); return marked; }; marked.defaults = { gfm: true, tables: true, breaks: false, pedantic: false, sanitize: false, smartLists: false, silent: false, highlight: null, langPrefix: 'lang-' }; /** * Expose */ marked.Parser = Parser; marked.parser = Parser.parse; marked.Lexer = Lexer; marked.lexer = Lexer.lex; marked.InlineLexer = InlineLexer; marked.inlineLexer = InlineLexer.output; marked.parse = marked; if (typeof exports === 'object') { module.exports = marked; } else if (typeof define === 'function' && define.amd) { define(function() { return marked; }); } else { this.marked = marked; } }).call(function() { return this || (typeof window !== 'undefined' ? window : global); }()); /*! * $Id: base64.js,v 2.12 2013/05/06 07:54:20 dankogai Exp dankogai $ * * Licensed under the MIT license. * http://opensource.org/licenses/mit-license * * References: * http://en.wikipedia.org/wiki/Base64 */ (function(global) { 'use strict'; if (global.Base64) return; var version = "2.1.2"; // if node.js, we use Buffer var buffer; if (typeof module !== 'undefined' && module.exports) { buffer = require('buffer').Buffer; } // constants var b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var b64tab = function(bin) { var t = {}; for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; return t; }(b64chars); var fromCharCode = String.fromCharCode; // encoder stuff var cb_utob = function(c) { if (c.length < 2) { var cc = c.charCodeAt(0); return cc < 0x80 ? c : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) + fromCharCode(0x80 | (cc & 0x3f))) : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + fromCharCode(0x80 | ( cc & 0x3f))); } else { var cc = 0x10000 + (c.charCodeAt(0) - 0xD800) * 0x400 + (c.charCodeAt(1) - 0xDC00); return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + fromCharCode(0x80 | ( cc & 0x3f))); } }; var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; var utob = function(u) { return u.replace(re_utob, cb_utob); }; var cb_encode = function(ccc) { var padlen = [0, 2, 1][ccc.length % 3], ord = ccc.charCodeAt(0) << 16 | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), chars = [ b64chars.charAt( ord >>> 18), b64chars.charAt((ord >>> 12) & 63), padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), padlen >= 1 ? '=' : b64chars.charAt(ord & 63) ]; return chars.join(''); }; var btoa = global.btoa || function(b) { return b.replace(/[\s\S]{1,3}/g, cb_encode); }; var _encode = buffer ? function (u) { return (new buffer(u)).toString('base64') } : function (u) { return btoa(utob(u)) } ; var encode = function(u, urisafe) { return !urisafe ? _encode(u) : _encode(u).replace(/[+\/]/g, function(m0) { return m0 == '+' ? '-' : '_'; }).replace(/=/g, ''); }; var encodeURI = function(u) { return encode(u, true) }; // decoder stuff var re_btou = new RegExp([ '[\xC0-\xDF][\x80-\xBF]', '[\xE0-\xEF][\x80-\xBF]{2}', '[\xF0-\xF7][\x80-\xBF]{3}' ].join('|'), 'g'); var cb_btou = function(cccc) { switch(cccc.length) { case 4: var cp = ((0x07 & cccc.charCodeAt(0)) << 18) | ((0x3f & cccc.charCodeAt(1)) << 12) | ((0x3f & cccc.charCodeAt(2)) << 6) | (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000; return (fromCharCode((offset >>> 10) + 0xD800) + fromCharCode((offset & 0x3FF) + 0xDC00)); case 3: return fromCharCode( ((0x0f & cccc.charCodeAt(0)) << 12) | ((0x3f & cccc.charCodeAt(1)) << 6) | (0x3f & cccc.charCodeAt(2)) ); default: return fromCharCode( ((0x1f & cccc.charCodeAt(0)) << 6) | (0x3f & cccc.charCodeAt(1)) ); } }; var btou = function(b) { return b.replace(re_btou, cb_btou); }; var cb_decode = function(cccc) { var len = cccc.length, padlen = len % 4, n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) | (len > 3 ? b64tab[cccc.charAt(3)] : 0), chars = [ fromCharCode( n >>> 16), fromCharCode((n >>> 8) & 0xff), fromCharCode( n & 0xff) ]; chars.length -= [0, 0, 2, 1][padlen]; return chars.join(''); }; var atob = global.atob || function(a){ return a.replace(/[\s\S]{1,4}/g, cb_decode); }; var _decode = buffer ? function(a) { return (new buffer(a, 'base64')).toString() } : function(a) { return btou(atob(a)) }; var decode = function(a){ return _decode( a.replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' }) .replace(/[^A-Za-z0-9\+\/]/g, '') ); }; // export Base64 global.Base64 = { VERSION: version, atob: atob, btoa: btoa, fromBase64: decode, toBase64: encode, utob: utob, encode: encode, encodeURI: encodeURI, btou: btou, decode: decode }; // if ES5 is available, make Base64.extendString() available if (typeof Object.defineProperty === 'function') { var noEnum = function(v){ return {value:v,enumerable:false,writable:true,configurable:true}; }; global.Base64.extendString = function () { Object.defineProperty( String.prototype, 'fromBase64', noEnum(function () { return decode(this) })); Object.defineProperty( String.prototype, 'toBase64', noEnum(function (urisafe) { return encode(this, urisafe) })); Object.defineProperty( String.prototype, 'toBase64URI', noEnum(function () { return encode(this, true) })); }; } // that's it! })(this);