diff --git a/README.md b/README.md index bb8feff7ba..0007fa9f61 100644 --- a/README.md +++ b/README.md @@ -75,10 +75,11 @@ marked has a few different switches which change behavior. - __smartLists__: Use smarter list behavior than the original markdown. Disabled by default. May eventually be default with the old behavior moved into `pedantic`. -- __langPrefix__: Set the prefix for code block classes. Defaults to `lang-`. ## Usage +A simple overview of the usage: + ``` js // Set default options marked.setOptions({ @@ -87,18 +88,53 @@ marked.setOptions({ breaks: false, pedantic: false, sanitize: true, - smartLists: true, - langPrefix: 'language-', - highlight: function(code, lang) { - if (lang === 'js') { - return highlighter.javascript(code); - } - return code; - } + smartLists: true }); console.log(marked('i am using __markdown__.')); ``` +### High level + +You can customize the result with a customized renderer. + +``` js +var renderer = new marked.Renderer() + +renderer.header = function(text, level) { + return '
' + text + '
' +} + +var parse = function(src, options) { + options = options || {}; + return marked.parser(marked.lexer(src, options), options, renderer); +} + +console.log(parse('# h1')) +``` + +The renderer API: + +``` +blockcode: function(code, lang) +blockquote: function(text) +blockhtml: function(html) + +header: function(text, level) +paragraph: function(text) + +hrule: function() + +list: function(contents, isOrdered) +listitem: function(text) + +table: function(header, body) +tablerow: function(content) +tablecell: function(text, flags) +// flags: {header: false, align: 'center'} +``` + +### Pro level + You also have direct access to the lexer and parser if you so desire. ``` js diff --git a/lib/marked.js b/lib/marked.js index e71e19dbd4..ec3c90169a 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -742,13 +742,77 @@ InlineLexer.prototype.mangle = function(text) { return out; }; +/** + * Renderer + */ + +function Renderer(options) { + this.options = options || {}; +} +Renderer.prototype.blockcode = function(code, lang) { + if (!lang) { + return '
' + escape(code, true) + '\n
'; + } + return '
'
+    + escape(code)
+    + '\n
\n'; +}; +Renderer.prototype.blockquote = function(quote) { + return '
\n' + quote + '
\n'; +}; +Renderer.prototype.blockhtml = function(html) { + return html; +}; +Renderer.prototype.header = function(text, level) { + return '' + text + '\n'; +}; +Renderer.prototype.hrule = function() { + return '
\n'; +}; +Renderer.prototype.list = function(body, ordered) { + var type = ordered ? 'ol' : 'ul'; + return '<' + type + '>\n' + body + '\n'; +}; +Renderer.prototype.listitem = function(text) { + return '
  • ' + text + '
  • \n'; +}; +Renderer.prototype.paragraph = function(text) { + return '

    ' + text + '

    \n'; +}; +Renderer.prototype.table = function(header, body) { + return '\n' + + '\n' + + header + + '\n' + + '\n' + + body + + '\n' + + '
    \n'; +}; +Renderer.prototype.tablerow = function(content) { + return '\n' + content + '\n'; +}; +Renderer.prototype.tablecell = function(content, flags) { + var type = flags.header ? 'th' : 'td'; + var tag = flags.align + ? '<' + type + ' align="' + flags.align + '">' : '<' + type + '>'; + return tag + content + '\n'; +}; + /** * Parsing & Compiling */ -function Parser(options) { +function Parser(options, renderer) { this.tokens = []; this.token = null; + if (options instanceof Renderer) { + options = null; + renderer = options; + } + this.renderer = renderer || new Renderer(); this.options = options || marked.defaults; } @@ -756,8 +820,8 @@ function Parser(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); }; @@ -812,82 +876,60 @@ Parser.prototype.parseText = function() { */ Parser.prototype.tok = function() { + var renderer = this.renderer; + switch (this.token.type) { case 'space': { return ''; } case 'hr': { - return '
    \n'; + return renderer.hrule(); } case 'heading': { - return '' - + this.inline.output(this.token.text) - + '\n'; + return renderer.header( + this.inline.output(this.token.text), + this.token.depth + ); } 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 '
    '
    -        + this.token.text
    -        + '
    \n'; + return renderer.blockcode(this.token.text, this.token.lang); } case 'table': { - var body = '' - , heading + var header = '' + , body = '' , i , row , cell + , flags , j; // header - body += '\n\n'; + cell = ''; for (i = 0; i < this.token.header.length; i++) { - heading = this.inline.output(this.token.header[i]); - body += this.token.align[i] - ? '' + heading + '\n' - : '' + heading + '\n'; + // render cell + flags = {header: true, align: this.token.align[i]}; + cell += renderer.tablecell( + this.inline.output(this.token.header[i]), + {header: true, align: this.token.align[i]} + ); + // render row } - body += '\n\n'; + header += renderer.tablerow(cell); - // body - body += '\n' for (i = 0; i < this.token.cells.length; i++) { row = this.token.cells[i]; - body += '\n'; + + cell = ''; for (j = 0; j < row.length; j++) { - cell = this.inline.output(row[j]); - body += this.token.align[j] - ? '' + cell + '\n' - : '' + cell + '\n'; + cell += renderer.tablecell( + this.inline.output(row[j]), + {header: false, align: this.token.align[j]} + ); } - body += '\n'; - } - body += '\n'; - return '\n' - + body - + '
    \n'; + body += renderer.tablerow(cell); + } + return renderer.table(header, body); } case 'blockquote_start': { var body = ''; @@ -896,25 +938,16 @@ Parser.prototype.tok = function() { body += this.tok(); } - return '
    \n' - + body - + '
    \n'; + return 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 - + '\n'; + return renderer.list(body, ordered); } case 'list_item_start': { var body = ''; @@ -925,9 +958,7 @@ Parser.prototype.tok = function() { : this.tok(); } - return '
  • ' - + body - + '
  • \n'; + return renderer.listitem(body); } case 'loose_item_start': { var body = ''; @@ -936,19 +967,16 @@ Parser.prototype.tok = function() { body += this.tok(); } - return '
  • ' - + body - + '
  • \n'; + return 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 renderer.blockhtml(html); } case 'paragraph': { - return '

    ' - + this.inline.output(this.token.text) - + '

    \n'; + return renderer.paragraph(this.inline.output(this.token.text)); } case 'text': { return '

    ' @@ -1003,6 +1031,7 @@ function merge(obj) { return obj; } + /** * Marked */ @@ -1039,9 +1068,7 @@ marked.defaults = { pedantic: false, sanitize: false, smartLists: false, - silent: false, - highlight: null, - langPrefix: 'lang-' + silent: false }; /** @@ -1051,6 +1078,8 @@ marked.defaults = { marked.Parser = Parser; marked.parser = Parser.parse; +marked.Renderer = Renderer; + marked.Lexer = Lexer; marked.lexer = Lexer.lex; diff --git a/package.json b/package.json index 5a71165d4f..a94f03ab7a 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,10 @@ "name": "marked", "description": "A markdown parser built for speed", "author": "Christopher Jeffrey", - "version": "0.2.8", + "version": "0.3.0a1", "main": "./lib/marked.js", "bin": "./bin/marked", "man": "./man/marked.1", - "preferGlobal": true, "repository": "git://github.com/chjj/marked.git", "homepage": "https://github.com/chjj/marked", "bugs": { "url": "http://github.com/chjj/marked/issues" },