diff options
| author | Michael Williamson <mike@zwobble.org> | 2015-10-13 23:29:41 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2015-10-13 23:49:31 +0100 |
| commit | 7b7ce0d563ddc07172b0f241a5c3baf344f256e8 (patch) | |
| tree | 43f5fddf920d47e281a30139bde99da5a689d667 /lib/document-to-html.js | |
| parent | e04d054a1b414e843fa6d6f5ee1ae75c0df533b1 (diff) | |
Collapse similar HTML elements
Diffstat (limited to 'lib/document-to-html.js')
| -rw-r--r-- | lib/document-to-html.js | 283 |
1 files changed, 115 insertions, 168 deletions
diff --git a/lib/document-to-html.js b/lib/document-to-html.js index 8a7cec0..eef0f8e 100644 --- a/lib/document-to-html.js +++ b/lib/document-to-html.js @@ -4,9 +4,10 @@ var _ = require("underscore"); var promises = require("./promises"); var documents = require("./documents"); var htmlPaths = require("./html-paths"); -var HtmlGenerator = require("./html-generator").HtmlGenerator; var results = require("./results"); var images = require("./images"); +var Html = require("./html"); +var writers = require("./writers"); exports.DocumentConverter = DocumentConverter; @@ -42,48 +43,44 @@ function DocumentConversion(options) { var styleMap = options.styleMap || []; - function createHtmlGenerator() { - return new HtmlGenerator({ - prettyPrint: options.prettyPrint, - outputFormat: options.outputFormat - }); - } - function convertToHtml(document) { var messages = []; - var html = createHtmlGenerator(); - return promises.nfcall(elementToHtml, document, html, messages).then(function() { - html.closeAll(); - - return new results.Result(html.asString(), messages); + return promises.nfcall(elementToHtml, document, messages).then(function(html) { + var writer = writers.writer({ + prettyPrint: options.prettyPrint, + outputFormat: options.outputFormat + }); + Html.write(writer, Html.simplify(html)); + return new results.Result(writer.asString(), messages); }); } - function convertElements(elements, html, messages, callback) { - async.eachSeries(elements, function(element, callback) { - return elementToHtml(element, html, messages, callback); + function convertElements(elements, messages, callback) { + async.mapSeries(elements, function(element, callback) { + return elementToHtml(element, messages, callback); }, callback); } - function elementToHtml(element, html, messages, callback) { + function elementToHtml(element, messages, callback) { var handler = elementConverters[element.type]; if (handler) { - handler(element, html, messages, callback); + handler(element, messages, callback); } else { callback(); } } - function convertParagraph(element, html, messages, callback) { - html.satisfyPath(styleForParagraph(element, messages)); - - if (!options.ignoreEmptyParagraphs) { - html.writeAll(); - } + function convertParagraph(element, messages, callback) { + var style = styleForParagraph(element, messages); setImmediate(function() { - convertElements(element.children, html, messages, callback); + convertElements(element.children, messages, function(error, children) { + if (!options.ignoreEmptyParagraphs) { + children = [Html.forceWrite, Html.fragment(children)]; + } + callback(null, Html.pathToNode(style, children)); + }); }); } @@ -100,62 +97,63 @@ function DocumentConversion(options) { } } - function convertRun(run, html, messages, callback) { - var runHtml = createHtmlGenerator(); + function convertRun(run, messages, callback) { if (run.styleId) { var style = findStyle(run); - if (style) { - runHtml.satisfyPath(style.to); - } else { + if (!style) { messages.push(unrecognisedStyleWarning("run", run)); } } - if (run.isBold) { - runHtml.open(htmlPaths.element("strong")); - } - if (run.isItalic) { - runHtml.open(htmlPaths.element("em")); - } - if (run.verticalAlignment === documents.verticalAlignment.superscript) { - runHtml.open(htmlPaths.element("sup")); - } - if (run.verticalAlignment === documents.verticalAlignment.subscript) { - runHtml.open(htmlPaths.element("sub")); - } - if (run.isUnderline) { - convertUnderline(runHtml); - } - if (run.isStrikethrough) { - convertStrikethrough(runHtml); - } - convertElements(run.children, runHtml, messages, function(err) { - if (err) { - callback(err); - } else { - runHtml.closeAll(); - html.append(runHtml); - callback(); + convertElements(run.children, messages, function(error, children) { + var result = Html.fragment(children); + if (run.isStrikethrough) { + result = convertStrikethrough(result); + } + if (run.isUnderline) { + result = convertUnderline(result); + } + if (run.verticalAlignment === documents.verticalAlignment.subscript) { + result = wrap(result, "sub"); + } + if (run.verticalAlignment === documents.verticalAlignment.superscript) { + result = wrap(result, "sup"); + } + if (run.isItalic) { + result = wrap(result, "em"); } + if (run.isBold) { + result = wrap(result, "strong"); + } + if (style) { + result = Html.pathToNode(style.to, [result]); + } + callback(null, result); }); } + function wrap(node, tagName) { + return Html.elementWithTag(htmlPaths.element(tagName, {}, {fresh: false}), [node]); + } + function convertUnderline(runHtml) { - (options.convertUnderline || defaultConvertUnderline)(runHtml); + return (options.convertUnderline || defaultConvertUnderline)(runHtml); } - function convertStrikethrough(runHtml) { + function convertStrikethrough(result) { var style = findStyle({type: "strikethrough"}); if (style) { - runHtml.appendPath(style.to); + return Html.pathToNode(style.to, [result]); } else { - runHtml.open(htmlPaths.element("s")); + return wrap(result, "s"); } } function defaultConvertUnderline(runHtml) { var style = findStyle({type: "underline"}); if (style) { - runHtml.appendPath(style.to); + return Html.pathToNode(style.to, [runHtml]); + } else { + return runHtml; } } @@ -176,12 +174,14 @@ function DocumentConversion(options) { }); function recoveringConvertImage(convertImage) { - return function(image, html, messages, callback) { - convertImage(image, html, messages, function(error) { + return function(image, messages, callback) { + convertImage(image, messages, function(error, result) { if (error) { messages.push(results.warning(error.message)); + callback(null, Html.fragment()); + } else { + callback(null, result); } - callback(); }); }; } @@ -198,141 +198,88 @@ function DocumentConversion(options) { return idPrefix + "-" + suffix; } - function convertTable(element, html, messages, callback) { - html.closeAll(); - wrapChildren(element, "table", html, messages, callback); + function convertTable(element, messages, callback) { + wrapChildren(element, "table", messages, callback); } - function convertTableRow(element, html, messages, callback) { - wrapChildren(element, "tr", html, messages, callback); + function convertTableRow(element, messages, callback) { + wrapChildren(element, "tr", messages, callback); } - function convertTableCell(element, html, messages, callback) { - html.open(htmlPaths.element("td"), {alwaysWrite: true}); - - async.map(element.children, function(child, callback) { - var cellHtml = createHtmlGenerator(); - elementToHtml(child, cellHtml, messages, function(error) { - if (error) { - callback(error); - } else { - cellHtml.closeAll(); - callback(null, cellHtml); - } - }); - }, function(error, childrenHtml) { - if (error) { - callback(error); - } else { - childrenHtml.forEach(function(childHtml) { - html.append(childHtml); - }); - html.close(); - callback(); - } - }); + function convertTableCell(element, messages, callback) { + wrapChildren(element, "td", messages, callback); } - function wrapChildren(element, wrapElementName, html, messages, callback) { - html.open(htmlPaths.element(wrapElementName)); - convertElements(element.children, html, messages, function(err) { - if (err) { - callback(err); - } else { - html.close(); - callback(); - } + function wrapChildren(element, wrapElementName, messages, callback) { + convertElements(element.children, messages, function(error, children) { + callback(null, Html.element(wrapElementName, {}, [ + Html.forceWrite, + Html.fragment(children)])); }); } var elementConverters = { - "document": function(document, html, messages, callback) { - convertElements(document.children, html, messages, function(error) { - if (error) { - callback(error); - } else { - html.closeAll(); - html.open(htmlPaths.element("ol")); - var notes = noteReferences.map(function(noteReference) { - return document.notes.resolve(noteReference); - }); - convertElements(notes, html, messages, function(error) { - if (error) { - callback(error); - } else { - html.close(); - callback(); - } - }); - } + "document": function(document, messages, callback) { + convertElements(document.children, messages, function(error, children) { + var notes = noteReferences.map(function(noteReference) { + return document.notes.resolve(noteReference); + }); + convertElements(notes, messages, function(error, notesNodes) { + callback(null, Html.fragment([ + Html.fragment(children), + Html.element("ol", {}, notesNodes)])); + }); }); }, "paragraph": convertParagraph, "run": convertRun, - "text": function(element, html, messages, callback) { - html.text(element.value); - callback(); + "text": function(element, messages, callback) { + callback(null, Html.text(element.value)); }, - "tab": function(element, html, messages, callback) { - html.text("\t"); - callback(); + "tab": function(element, messages, callback) { + callback(null, Html.text("\t")); }, - "hyperlink": function(element, html, messages, callback) { + "hyperlink": function(element, messages, callback) { var href = element.anchor ? "#" + htmlId(element.anchor) : element.href; - html.open(htmlPaths.element("a", {href: href})); - convertElements(element.children, html, messages, function(err) { - if (err) { - callback(err); - } else { - html.close(); - callback(); - } + convertElements(element.children, messages, function(error, children) { + callback(null, Html.element("a", {href: href}, children)); }); }, - "bookmarkStart": function(element, html, messages, callback) { - html.open(htmlPaths.element("a", { + "bookmarkStart": function(element, messages, callback) { + callback(null, Html.element("a", { id: htmlId(element.name) - }), {alwaysWrite: true}); - html.close(); - callback(); + }, [Html.forceWrite])); }, - "noteReference": function(element, html, messages, callback) { - html.open(htmlPaths.element("sup")); - html.open(htmlPaths.element("a", { - href: "#" + noteHtmlId(element), - id: noteRefHtmlId(element) - })); + "noteReference": function(element, messages, callback) { noteReferences.push(element); - html.text("[" + (noteNumber++) + "]"); - html.close(); - html.close(); - callback(); + + callback(null, Html.element("sup", {}, [ + Html.element("a", { + href: "#" + noteHtmlId(element), + id: noteRefHtmlId(element) + }, [Html.text("[" + (noteNumber++) + "]")]) + ])); }, - "note": function(element, html, messages, callback) { - html.open(htmlPaths.element("li", {id: noteHtmlId(element)})); - var footnoteHtml = createHtmlGenerator(); - convertElements(element.body, footnoteHtml, messages, function(err) { - if (err) { - callback(err); - } else { - footnoteHtml.text(" "); - footnoteHtml.open(htmlPaths.element("a", {href: "#" + noteRefHtmlId(element)})); - footnoteHtml.text("↑"); - footnoteHtml.closeAll(); - html.append(footnoteHtml); - html.close(); - callback(); - } + "note": function(element, messages, callback) { + convertElements(element.body, messages, function(error, children) { + callback(null, Html.element("li", {id: noteHtmlId(element)}, [ + Html.fragment(children), + + Html.elementWithTag(htmlPaths.element("p", {}, {fresh: false}), [ + Html.text(" "), + Html.element("a", {href: "#" + noteRefHtmlId(element)}, [Html.text("↑")]), + + ]) + ])); }); }, "image": recoveringConvertImage(options.convertImage || defaultConvertImage), "table": convertTable, "tableRow": convertTableRow, "tableCell": convertTableCell, - "lineBreak": function(element, html, messages, callback) { - html.selfClosing(htmlPaths.element("br")); - callback(); + "lineBreak": function(element, messages, callback) { + callback(null, Html.selfClosingElement("br")); } }; return { |
