|
|
@ -8,31 +8,6 @@ var replaceEntities = require('./common/utils').replaceEntities; |
|
|
|
var escapeHtml = require('./common/utils').escapeHtml; |
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Helpers
|
|
|
|
|
|
|
|
function nextToken(tokens, idx) { |
|
|
|
if (++idx >= tokens.length - 2) { return idx; } |
|
|
|
if ((tokens[idx].type === 'paragraph_open' && tokens[idx].tight) && |
|
|
|
(tokens[idx + 1].type === 'inline' && tokens[idx + 1].content.length === 0) && |
|
|
|
(tokens[idx + 2].type === 'paragraph_close' && tokens[idx + 2].tight)) { |
|
|
|
return nextToken(tokens, idx + 2); |
|
|
|
} |
|
|
|
return idx; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// check if we need to hide '\n' before next token
|
|
|
|
function getBreak(tokens, idx) { |
|
|
|
idx = nextToken(tokens, idx); |
|
|
|
if (idx < tokens.length && |
|
|
|
tokens[idx].type === 'list_item_close') { |
|
|
|
return ''; |
|
|
|
} |
|
|
|
|
|
|
|
return '\n'; |
|
|
|
} |
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
var rules = {}; |
|
|
@ -42,14 +17,14 @@ var rules = {}; |
|
|
|
rules.blockquote_open = function (/* tokens, idx, options, env */) { |
|
|
|
return '<blockquote>\n'; |
|
|
|
}; |
|
|
|
rules.blockquote_close = function (tokens, idx /*, options, env */) { |
|
|
|
return '</blockquote>' + getBreak(tokens, idx); |
|
|
|
rules.blockquote_close = function (/* tokens, idx, options, env */) { |
|
|
|
return '</blockquote>\n'; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
rules.code = function (tokens, idx /*, options, env */) { |
|
|
|
if (tokens[idx].block) { |
|
|
|
return '<pre><code>' + escapeHtml(tokens[idx].content) + '</code></pre>' + getBreak(tokens, idx); |
|
|
|
return '<pre><code>' + escapeHtml(tokens[idx].content) + '</code></pre>\n'; |
|
|
|
} |
|
|
|
|
|
|
|
return '<code>' + escapeHtml(tokens[idx].content) + '</code>'; |
|
|
@ -91,7 +66,7 @@ rules.fence = function (tokens, idx, options, env, self) { |
|
|
|
|
|
|
|
return '<pre><code' + langClass + '>' |
|
|
|
+ highlighted |
|
|
|
+ '</code></pre>' + getBreak(tokens, idx); |
|
|
|
+ '</code></pre>\n'; |
|
|
|
}; |
|
|
|
|
|
|
|
rules.fence_custom = {}; |
|
|
@ -105,30 +80,35 @@ rules.heading_close = function (tokens, idx /*, options, env */) { |
|
|
|
|
|
|
|
|
|
|
|
rules.hr = function (tokens, idx, options /*, env */) { |
|
|
|
return (options.xhtmlOut ? '<hr />' : '<hr>') + getBreak(tokens, idx); |
|
|
|
return (options.xhtmlOut ? '<hr />\n' : '<hr>\n'); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
rules.bullet_list_open = function (/* tokens, idx, options, env */) { |
|
|
|
return '<ul>\n'; |
|
|
|
}; |
|
|
|
rules.bullet_list_close = function (tokens, idx /*, options, env */) { |
|
|
|
return '</ul>' + getBreak(tokens, idx); |
|
|
|
rules.bullet_list_close = function (/* tokens, idx, options, env */) { |
|
|
|
return '</ul>\n'; |
|
|
|
}; |
|
|
|
rules.list_item_open = function (/* tokens, idx, options, env */) { |
|
|
|
return '<li>'; |
|
|
|
rules.list_item_open = function (tokens, idx /*, options, env */) { |
|
|
|
var next = tokens[idx + 1]; |
|
|
|
if ((next.type === 'list_item_close') || |
|
|
|
(next.type === 'paragraph_open' && next.tight)) { |
|
|
|
return '<li>'; |
|
|
|
} |
|
|
|
return '<li>\n'; |
|
|
|
}; |
|
|
|
rules.list_item_close = function (/* tokens, idx, options, env */) { |
|
|
|
return '</li>\n'; |
|
|
|
}; |
|
|
|
rules.ordered_list_open = function (tokens, idx /*, options, env */) { |
|
|
|
var token = tokens[idx]; |
|
|
|
return '<ol' |
|
|
|
+ (token.order > 1 ? ' start="' + token.order + '"' : '') |
|
|
|
+ '>\n'; |
|
|
|
if (tokens[idx].order > 1) { |
|
|
|
return '<ol start="' + tokens[idx].order + '">\n'; |
|
|
|
} |
|
|
|
return '<ol>\n'; |
|
|
|
}; |
|
|
|
rules.ordered_list_close = function (tokens, idx /*, options, env */) { |
|
|
|
return '</ol>' + getBreak(tokens, idx); |
|
|
|
rules.ordered_list_close = function (/* tokens, idx, options, env */) { |
|
|
|
return '</ol>\n'; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -136,8 +116,21 @@ rules.paragraph_open = function (tokens, idx /*, options, env */) { |
|
|
|
return tokens[idx].tight ? '' : '<p>'; |
|
|
|
}; |
|
|
|
rules.paragraph_close = function (tokens, idx /*, options, env */) { |
|
|
|
var addBreak = !(tokens[idx].tight && idx && tokens[idx - 1].type === 'inline' && !tokens[idx - 1].content); |
|
|
|
return (tokens[idx].tight ? '' : '</p>') + (addBreak ? getBreak(tokens, idx) : ''); |
|
|
|
// We have 2 cases of "hidden" paragraphs
|
|
|
|
//
|
|
|
|
// 1. In tight lists
|
|
|
|
// 2. When content was stripped (reference definition, for example)
|
|
|
|
//
|
|
|
|
if (tokens[idx].tight === true) { |
|
|
|
if (!tokens[idx - 1].content) { |
|
|
|
return ''; |
|
|
|
} |
|
|
|
if (tokens[idx + 1].type === 'list_item_close') { |
|
|
|
return ''; |
|
|
|
} |
|
|
|
return '\n'; |
|
|
|
} |
|
|
|
return '</p>\n'; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -184,19 +177,19 @@ rules.tr_close = function (/* tokens, idx, options, env */) { |
|
|
|
return '</tr>\n'; |
|
|
|
}; |
|
|
|
rules.th_open = function (tokens, idx /*, options, env */) { |
|
|
|
var token = tokens[idx]; |
|
|
|
return '<th' |
|
|
|
+ (token.align ? ' style="text-align:' + token.align + '"' : '') |
|
|
|
+ '>'; |
|
|
|
if (tokens[idx].align) { |
|
|
|
return '<th style="text-align:' + tokens[idx].align + '">'; |
|
|
|
} |
|
|
|
return '<th>'; |
|
|
|
}; |
|
|
|
rules.th_close = function (/* tokens, idx, options, env */) { |
|
|
|
return '</th>'; |
|
|
|
}; |
|
|
|
rules.td_open = function (tokens, idx /*, options, env */) { |
|
|
|
var token = tokens[idx]; |
|
|
|
return '<td' |
|
|
|
+ (token.align ? ' style="text-align:' + token.align + '"' : '') |
|
|
|
+ '>'; |
|
|
|
if (tokens[idx].align) { |
|
|
|
return '<td style="text-align:' + tokens[idx].align + '">'; |
|
|
|
} |
|
|
|
return '<td>'; |
|
|
|
}; |
|
|
|
rules.td_close = function (/* tokens, idx, options, env */) { |
|
|
|
return '</td>'; |
|
|
@ -335,8 +328,6 @@ rules.dd_close = function() { |
|
|
|
function Renderer() { |
|
|
|
// Clone rules object to allow local modifications
|
|
|
|
this.rules = assign({}, rules); |
|
|
|
// exported helper, for custom rules only
|
|
|
|
this.getBreak = getBreak; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|