// Helper function to produce an HTML tag.
var tag = function(name, attribs, selfclosing) {
var result = '<' + name;
if (attribs) {
var i = 0;
var attrib;
while ((attrib = attribs[i]) !== undefined) {
result = result.concat(' ', attrib[0], '="', attrib[1], '"');
i++;
}
}
if (selfclosing)
result += ' /';
result += '>';
return result;
};
var renderNodes = function(block) {
var attrs;
var info_words;
var tagname;
var walker = block.walker();
var event, node, entering;
var buffer = [];
var disableTags = 0;
var grandparent;
var out = function(s) {
if (disableTags > 0) {
buffer.push(s.replace(/\<[^>]*\>/g, ''));
} else {
buffer.push(s);
}
}
var esc = this.escape;
var cr = function() {
if (buffer.length > 0 && buffer[buffer.length - 1] !== '\n') {
out('\n');
}
}
while (event = walker.next()) {
entering = event.entering;
node = event.node;
switch (node.t) {
case 'Text':
out(esc(node.c));
break;
case 'Softbreak':
out(this.softbreak);
break;
case 'Hardbreak':
out(tag('br', [], true));
cr();
break;
case 'Emph':
out(tag(entering ? 'em' : '/em'));
break;
case 'Strong':
out(tag(entering ? 'strong' : '/strong'));
break;
case 'Emph':
out(tag(entering ? 'strong' : '/strong'));
break;
case 'Html':
out(node.c);
break;
case 'Link':
if (entering) {
attrs = [['href', esc(node.destination, true)]];
if (node.title) {
attrs.push(['title', esc(node.title, true)]);
}
out(tag('a', attrs));
} else {
out(tag('/a'));
}
break;
case 'Image':
if (entering) {
if (disableTags == 0) {
out('');
}
}
break;
case 'Code':
out(tag('code') + esc(node.c) + tag('/code'));
break;
case 'Document':
break;
case 'Paragraph':
grandparent = node.parent.parent;
if (grandparent !== null &&
grandparent.t === 'List') {
if (grandparent.tight)
break;
}
if (entering) {
cr();
out(tag('p'));
} else {
out(tag('/p'));
cr();
}
break;
case 'BlockQuote':
if (entering) {
cr();
out(tag('blockquote'));
cr();
} else {
cr();
out(tag('/blockquote'));
cr();
}
break;
case 'ListItem':
if (entering) {
out(tag('li'));
} else {
out(tag('/li'));
cr();
}
break;
case 'List':
tagname = node.list_data.type === 'Bullet' ? 'ul' : 'ol';
if (entering) {
attr = (!node.list_data.start || node.list_data.start === 1) ?
[] : [['start', node.list_data.start.toString()]];
cr();
out(tag(tagname, attr));
cr();
} else {
cr();
out(tag('/' + tagname));
cr();
}
break;
case 'Header':
tagname = 'h' + node.level;
if (entering) {
cr();
out(tag(tagname));
} else {
out(tag('/' + tagname));
cr();
}
break;
case 'CodeBlock':
info_words = node.info ? node.info.split(/ +/) : [];
attr = (info_words.length === 0 || info_words[0].length === 0)
? [] : [['class', 'language-' + esc(info_words[0], true)]];
cr();
out(tag('pre') + tag('code', attr));
out(this.escape(node.string_content));
out(tag('/code') + tag('/pre'));
cr();
break;
case 'HtmlBlock':
cr();
out(node.string_content);
cr();
break;
case 'HorizontalRule':
cr();
out(tag('hr', [], true));
cr();
break;
case 'ReferenceDef':
break;
default:
console.log("Unknown node type " + node.t);
}
}
return buffer.join('');
};
// The HtmlRenderer object.
function HtmlRenderer(){
return {
// default options:
blocksep: '\n', // space between blocks
innersep: '\n', // space between block container tag and contents
softbreak: '\n', // by default, soft breaks are rendered as newlines in HTML
// set to "
" to make them hard breaks
// set to " " if you want to ignore line wrapping in source
escape: function(s, preserve_entities) {
if (preserve_entities) {
return s.replace(/[&](?![#](x[a-f0-9]{1,8}|[0-9]{1,8});|[a-z][a-z0-9]{1,31};)/gi, '&')
.replace(/[<]/g, '<')
.replace(/[>]/g, '>')
.replace(/["]/g, '"');
} else {
return s.replace(/[&]/g,'&')
.replace(/[<]/g, '<')
.replace(/[>]/g, '>')
.replace(/["]/g, '"');
}
},
render: renderNodes
};
}
module.exports = HtmlRenderer;