|
@ -23,16 +23,14 @@ default_rules.code_block = function (tokens, idx /*, options, env */) { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default_rules.fence = function (tokens, idx, options /*, env, self*/) { |
|
|
default_rules.fence = function (tokens, idx, options, env, self) { |
|
|
var token = tokens[idx]; |
|
|
var token = tokens[idx], |
|
|
var langClass = ''; |
|
|
langName = '', |
|
|
var langPrefix = options.langPrefix; |
|
|
highlighted; |
|
|
var langName = ''; |
|
|
|
|
|
var highlighted; |
|
|
|
|
|
|
|
|
|
|
|
if (token.info) { |
|
|
if (token.info) { |
|
|
langName = escapeHtml(unescapeAll(token.info.trim().split(/\s+/g)[0])); |
|
|
langName = unescapeAll(token.info.trim().split(/\s+/g)[0]); |
|
|
langClass = ' class="' + langPrefix + langName + '"'; |
|
|
token.attrPush([ 'class', options.langPrefix + langName ]); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (options.highlight) { |
|
|
if (options.highlight) { |
|
@ -41,28 +39,24 @@ default_rules.fence = function (tokens, idx, options /*, env, self*/) { |
|
|
highlighted = escapeHtml(token.content); |
|
|
highlighted = escapeHtml(token.content); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return '<pre><code' + self.renderAttrs(token.attrs) + '>' |
|
|
return '<pre><code' + langClass + '>' |
|
|
|
|
|
+ highlighted |
|
|
+ highlighted |
|
|
+ '</code></pre>\n'; |
|
|
+ '</code></pre>\n'; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default_rules.image = function (tokens, idx, options, env, self) { |
|
|
default_rules.image = function (tokens, idx, options, env, self) { |
|
|
var i, token = tokens[idx], |
|
|
var token = tokens[idx]; |
|
|
alt = self.renderInlineAsText(tokens[idx].children, options, env); |
|
|
|
|
|
|
|
|
|
|
|
if (!token.attrs) { token.attrs = []; } |
|
|
|
|
|
|
|
|
|
|
|
// Replace "alt" tag with children tags rendered as text
|
|
|
// "alt" attr MUST be set, even if empty. Because it's mandatory and
|
|
|
|
|
|
// should be placed on proper position for tests.
|
|
|
//
|
|
|
//
|
|
|
for (i = 0; i < token.attrs.length; i++) { |
|
|
// Replace content with actual value
|
|
|
if (token.attrs[i][0] === 'alt') { |
|
|
|
|
|
token.attrs[i][1] = alt; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return self.rules.default_token(tokens, idx, options, env, self); |
|
|
token.attrs[token.attrIndex('alt')][1] = |
|
|
|
|
|
self.renderInlineAsText(token.children, options, env); |
|
|
|
|
|
|
|
|
|
|
|
return self.renderToken(tokens, idx, options, env, self); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -87,12 +81,86 @@ default_rules.html_inline = function (tokens, idx /*, options, env */) { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default_rules.default_token = function (tokens, idx, options /*, env, self */) { |
|
|
/** |
|
|
var i, l, nextToken, |
|
|
* new Renderer() |
|
|
|
|
|
* |
|
|
|
|
|
* Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults. |
|
|
|
|
|
**/ |
|
|
|
|
|
function Renderer() { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Renderer#rules -> Object |
|
|
|
|
|
* |
|
|
|
|
|
* Contains render rules for tokens. Can be updated and extended. |
|
|
|
|
|
* |
|
|
|
|
|
* ##### Example |
|
|
|
|
|
* |
|
|
|
|
|
* ```javascript
|
|
|
|
|
|
* var md = require('markdown-it')(); |
|
|
|
|
|
* |
|
|
|
|
|
* md.renderer.rules.strong_open = function () { return '<b>'; }; |
|
|
|
|
|
* md.renderer.rules.strong_close = function () { return '</b>'; }; |
|
|
|
|
|
* |
|
|
|
|
|
* var result = md.renderInline(...); |
|
|
|
|
|
* ``` |
|
|
|
|
|
* |
|
|
|
|
|
* Each rule is called as independed static function with fixed signature: |
|
|
|
|
|
* |
|
|
|
|
|
* ```javascript
|
|
|
|
|
|
* function my_token_render(tokens, idx, options, env, renderer) { |
|
|
|
|
|
* // ...
|
|
|
|
|
|
* return renderedHTML; |
|
|
|
|
|
* } |
|
|
|
|
|
* ``` |
|
|
|
|
|
* |
|
|
|
|
|
* See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js)
|
|
|
|
|
|
* for more details and examples. |
|
|
|
|
|
**/ |
|
|
|
|
|
this.rules = assign({}, default_rules); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Renderer.renderAttrs(attrs) -> String |
|
|
|
|
|
* - attrs (Array): array of token attributes |
|
|
|
|
|
* |
|
|
|
|
|
* Render token attributes to string. |
|
|
|
|
|
**/ |
|
|
|
|
|
Renderer.prototype.renderAttrs = function renderAttrs(attrs) { |
|
|
|
|
|
var i, l, result; |
|
|
|
|
|
|
|
|
|
|
|
if (!attrs) { return ''; } |
|
|
|
|
|
|
|
|
|
|
|
result = ''; |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0, l = attrs.length; i < l; i++) { |
|
|
|
|
|
result += ' ' + escapeHtml(attrs[i][0]) + '="' + escapeHtml(attrs[i][1]) + '"'; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Renderer.renderToken(tokens, idx, options) -> String |
|
|
|
|
|
* - tokens (Array): list of tokens |
|
|
|
|
|
* - idx (Numbed): token index to render |
|
|
|
|
|
* - options (Object): params of parser instance |
|
|
|
|
|
* |
|
|
|
|
|
* Default token renderer. Can be overriden by custom function |
|
|
|
|
|
* in [[Renderer#rules]]. |
|
|
|
|
|
**/ |
|
|
|
|
|
Renderer.prototype.renderToken = function renderToken(tokens, idx, options) { |
|
|
|
|
|
var nextToken, |
|
|
result = '', |
|
|
result = '', |
|
|
needLf = false, |
|
|
needLf = false, |
|
|
token = tokens[idx]; |
|
|
token = tokens[idx]; |
|
|
|
|
|
|
|
|
|
|
|
// Tight list paragraphs
|
|
|
|
|
|
if (token.hidden) { |
|
|
|
|
|
return ''; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Insert a newline between hidden paragraph and subsequent opening
|
|
|
// Insert a newline between hidden paragraph and subsequent opening
|
|
|
// block-level tag.
|
|
|
// block-level tag.
|
|
|
//
|
|
|
//
|
|
@ -100,39 +168,22 @@ default_rules.default_token = function (tokens, idx, options /*, env, self */) { |
|
|
// - a
|
|
|
// - a
|
|
|
// >
|
|
|
// >
|
|
|
//
|
|
|
//
|
|
|
if (token.block && idx && tokens[idx - 1].hidden && token.nesting !== -1) { |
|
|
if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) { |
|
|
result += '\n'; |
|
|
result += '\n'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Self-contained token with no tag name, e.g. `inline` or hidden paragraph.
|
|
|
|
|
|
//
|
|
|
|
|
|
// We should return content if it exists and an empty string otherwise.
|
|
|
|
|
|
//
|
|
|
|
|
|
if (!token.tag) { |
|
|
|
|
|
result += (token.content ? escapeHtml(token.content) : ''); |
|
|
|
|
|
return result; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Add token name, e.g. `<img`
|
|
|
// Add token name, e.g. `<img`
|
|
|
//
|
|
|
|
|
|
result += (token.nesting === -1 ? '</' : '<') + token.tag; |
|
|
result += (token.nesting === -1 ? '</' : '<') + token.tag; |
|
|
|
|
|
|
|
|
// Encode attributes, e.g. `<img src="foo"`
|
|
|
// Encode attributes, e.g. `<img src="foo"`
|
|
|
// ^^^^^^^^^^
|
|
|
result += this.renderAttrs(token.attrs); |
|
|
if (token.attrs) { |
|
|
|
|
|
for (i = 0, l = token.attrs.length; i < l; i++) { |
|
|
|
|
|
result += ' ' + escapeHtml(token.attrs[i][0]) + '="' + escapeHtml(token.attrs[i][1]) + '"'; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Add a slash for self-closing tags, e.g. `<img src="foo" /`
|
|
|
// Add a slash for self-closing tags, e.g. `<img src="foo" /`
|
|
|
// ^^
|
|
|
|
|
|
if (token.nesting === 0 && options.xhtmlOut && token.content === null) { |
|
|
if (token.nesting === 0 && options.xhtmlOut && token.content === null) { |
|
|
result += ' /'; |
|
|
result += ' /'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Check if we need to add a newline after this tag
|
|
|
// Check if we need to add a newline after this tag
|
|
|
//
|
|
|
|
|
|
if (token.block) { |
|
|
if (token.block) { |
|
|
needLf = true; |
|
|
needLf = true; |
|
|
|
|
|
|
|
@ -155,55 +206,16 @@ default_rules.default_token = function (tokens, idx, options /*, env, self */) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// If it's self-contained token, add its contents + closing tag
|
|
|
// If it's self-contained token, add its contents + closing tag
|
|
|
//
|
|
|
|
|
|
if (token.nesting === 0 && token.content !== null) { |
|
|
if (token.nesting === 0 && token.content !== null) { |
|
|
result += '>' + escapeHtml(token.content) + '</' + token.tag; |
|
|
result += '>' + escapeHtml(token.content) + '</' + token.tag; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
result += needLf ? '>\n' : '>'; |
|
|
result += needLf ? '>\n' : '>'; |
|
|
|
|
|
|
|
|
return result; |
|
|
return result; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* new Renderer() |
|
|
|
|
|
* |
|
|
|
|
|
* Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults. |
|
|
|
|
|
**/ |
|
|
|
|
|
function Renderer() { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Renderer#rules -> Object |
|
|
|
|
|
* |
|
|
|
|
|
* Contains render rules for tokens. Can be updated and extended. |
|
|
|
|
|
* |
|
|
|
|
|
* ##### Example |
|
|
|
|
|
* |
|
|
|
|
|
* ```javascript
|
|
|
|
|
|
* var md = require('markdown-it')(); |
|
|
|
|
|
* |
|
|
|
|
|
* md.renderer.rules.strong_open = function () { return '<b>'; }; |
|
|
|
|
|
* md.renderer.rules.strong_close = function () { return '</b>'; }; |
|
|
|
|
|
* |
|
|
|
|
|
* var result = md.renderInline(...); |
|
|
|
|
|
* ``` |
|
|
|
|
|
* |
|
|
|
|
|
* Each rule is called as independed static function with fixed signature: |
|
|
|
|
|
* |
|
|
|
|
|
* ```javascript
|
|
|
|
|
|
* function my_token_render(tokens, idx, options, env, renderer) { |
|
|
|
|
|
* // ...
|
|
|
|
|
|
* return renderedHTML; |
|
|
|
|
|
* } |
|
|
|
|
|
* ``` |
|
|
|
|
|
* |
|
|
|
|
|
* See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js)
|
|
|
|
|
|
* for more details and examples. |
|
|
|
|
|
**/ |
|
|
|
|
|
this.rules = assign({}, default_rules); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Renderer.renderInline(tokens, options, env) -> String |
|
|
* Renderer.renderInline(tokens, options, env) -> String |
|
|
* - tokens (Array): list on block tokens to renter |
|
|
* - tokens (Array): list on block tokens to renter |
|
@ -223,7 +235,7 @@ Renderer.prototype.renderInline = function (tokens, options, env) { |
|
|
if (typeof rules[type] !== 'undefined') { |
|
|
if (typeof rules[type] !== 'undefined') { |
|
|
result += rules[type](tokens, i, options, env, this); |
|
|
result += rules[type](tokens, i, options, env, this); |
|
|
} else { |
|
|
} else { |
|
|
result += rules.default_token(tokens, i, options, env); |
|
|
result += this.renderToken(tokens, i, options, env); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -279,7 +291,7 @@ Renderer.prototype.render = function (tokens, options, env) { |
|
|
} else if (typeof rules[type] !== 'undefined') { |
|
|
} else if (typeof rules[type] !== 'undefined') { |
|
|
result += rules[tokens[i].type](tokens, i, options, env, this); |
|
|
result += rules[tokens[i].type](tokens, i, options, env, this); |
|
|
} else { |
|
|
} else { |
|
|
result += rules.default_token(tokens, i, options, env); |
|
|
result += this.renderToken(tokens, i, options, env); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|