summaryrefslogtreecommitdiff
path: root/js/lib/html.js
diff options
context:
space:
mode:
authorJohn MacFarlane <jgm@berkeley.edu>2015-01-09 11:02:10 -0800
committerJohn MacFarlane <jgm@berkeley.edu>2015-01-09 11:02:10 -0800
commit1777d308f050cc4fddd1f835e483eaf17071241f (patch)
treee487767c41bc68605e948b2bfc308a7518eb3465 /js/lib/html.js
parentd2eb8460e8409f8c419f816312c3362e45367913 (diff)
Rename js/lib/html-renderer.js -> js/lib/html.js.
Diffstat (limited to 'js/lib/html.js')
-rw-r--r--js/lib/html.js239
1 files changed, 239 insertions, 0 deletions
diff --git a/js/lib/html.js b/js/lib/html.js
new file mode 100644
index 0000000..e7953cf
--- /dev/null
+++ b/js/lib/html.js
@@ -0,0 +1,239 @@
+// 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('<img src="' + esc(node.destination, true) +
+ '" alt="');
+ }
+ disableTags += 1;
+ } else {
+ disableTags -= 1;
+ if (disableTags == 0) {
+ if (node.title) {
+ out('" title="' + esc(node.title, true));
+ }
+ 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 "<br />" 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, '&amp;')
+ .replace(/[<]/g, '&lt;')
+ .replace(/[>]/g, '&gt;')
+ .replace(/["]/g, '&quot;');
+ } else {
+ return s.replace(/[&]/g,'&amp;')
+ .replace(/[<]/g, '&lt;')
+ .replace(/[>]/g, '&gt;')
+ .replace(/["]/g, '&quot;');
+ }
+ },
+ render: renderNodes
+ };
+}
+
+module.exports = HtmlRenderer;