aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-07-07 21:27:53 +0100
committerMichael Williamson <mike@zwobble.org>2016-07-07 21:27:53 +0100
commitc0a14c171f5bdfda6cb76b1589a43ada3b5768ce (patch)
tree7055a83898f6af08a0a7239812ef1d5c52732716
parent1c439031d328a09bfb178b1182c09bb62d03782c (diff)
Add conversion of comments
-rw-r--r--lib/document-matchers.js2
-rw-r--r--lib/document-to-html.js88
-rw-r--r--lib/documents.js3
-rw-r--r--test/document-to-html.tests.js32
4 files changed, 112 insertions, 13 deletions
diff --git a/lib/document-matchers.js b/lib/document-matchers.js
index 60bc65f..bdc213c 100644
--- a/lib/document-matchers.js
+++ b/lib/document-matchers.js
@@ -4,7 +4,7 @@ exports.bold = new Matcher("bold");
exports.italic = new Matcher("italic");
exports.underline = new Matcher("underline");
exports.strikethrough = new Matcher("strikethrough");
-exports.commentReference = new Matcher("comment-reference");
+exports.commentReference = new Matcher("commentReference");
function paragraph(options) {
diff --git a/lib/document-to-html.js b/lib/document-to-html.js
index 2b7815a..1b3a3df 100644
--- a/lib/document-to-html.js
+++ b/lib/document-to-html.js
@@ -13,18 +13,25 @@ exports.DocumentConverter = DocumentConverter;
function DocumentConverter(options) {
return {
- convertToHtml: function() {
- var conversion = new DocumentConversion(options);
- return conversion.convertToHtml.apply(this, arguments);
+ convertToHtml: function(element) {
+ var comments = _.indexBy(
+ element.type === documents.types.document ? element.comments : [],
+ "commentId"
+ );
+ var conversion = new DocumentConversion(options, comments);
+ return conversion.convertToHtml(element);
}
};
}
-function DocumentConversion(options) {
+function DocumentConversion(options, comments) {
var noteNumber = 1;
var noteReferences = [];
+ var referencedComments = [];
+ var commentCountByInitials = {};
+
options = _.extend({ignoreEmptyParagraphs: true}, options);
var idPrefix = options.idPrefix === undefined ? "" : options.idPrefix;
@@ -154,9 +161,9 @@ function DocumentConversion(options) {
}
function findHtmlPathForRunProperty(elementType, defaultTagName) {
- var style = findStyle({type: elementType});
- if (style) {
- return style.to;
+ var path = findHtmlPath({type: elementType});
+ if (path) {
+ return path;
} else if (defaultTagName) {
return htmlPaths.element(defaultTagName, {}, {fresh: false});
} else {
@@ -164,6 +171,11 @@ function DocumentConversion(options) {
}
}
+ function findHtmlPath(element, defaultPath) {
+ var style = findStyle(element);
+ return style ? style.to : defaultPath;
+ }
+
function findStyle(element) {
for (var i = 0; i < styleMap.length; i++) {
if (styleMap[i].from.matches(element)) {
@@ -190,11 +202,19 @@ function DocumentConversion(options) {
}
function noteHtmlId(note) {
- return htmlId(note.noteType + "-" + note.noteId);
+ return referentHtmlId(note.noteType, note.noteId);
}
function noteRefHtmlId(note) {
- return htmlId(note.noteType + "-ref-" + note.noteId);
+ return referenceHtmlId(note.noteType, note.noteId);
+ }
+
+ function referentHtmlId(referenceType, referenceId) {
+ return htmlId(referenceType + "-" + referenceId);
+ }
+
+ function referenceHtmlId(referenceType, referenceId) {
+ return htmlId(referenceType + "-ref-" + referenceId);
}
function htmlId(suffix) {
@@ -224,6 +244,49 @@ function DocumentConversion(options) {
];
}
+ function convertCommentReference(reference, messages) {
+ return findHtmlPath(reference, htmlPaths.ignore).wrap(function() {
+ var comment = comments[reference.commentId];
+ if (commentCountByInitials[comment.authorInitials] === undefined) {
+ commentCountByInitials[comment.authorInitials] = 0;
+ }
+ var count = ++commentCountByInitials[comment.authorInitials];
+ var label = "[" + comment.authorInitials + count + "]";
+ referencedComments.push({label: label, comment: comment});
+ // TODO: remove duplication with note references
+ return [
+ Html.freshElement("a", {
+ href: "#" + referentHtmlId("comment", reference.commentId),
+ id: referenceHtmlId("comment", reference.commentId)
+ }, [Html.text(label)])
+ ];
+ });
+ }
+
+ function convertComment(referencedComment, messages) {
+ // TODO: remove duplication with note references
+
+ var label = referencedComment.label;
+ var comment = referencedComment.comment;
+ var body = convertElements(comment.body).concat([
+ Html.nonFreshElement("p", {}, [
+ Html.text(" "),
+ Html.freshElement("a", {"href": "#" + referenceHtmlId("comment", comment.commentId)}, [
+ Html.text("↑")
+ ])
+ ])
+ ]);
+
+ return [
+ Html.freshElement(
+ "dt",
+ {"id": referentHtmlId("comment", comment.commentId)},
+ [Html.text("Comment " + label)]
+ ),
+ Html.freshElement("dd", {}, body)
+ ];
+ }
+
function wrapChildrenInFreshElement(element, wrapElementName, messages) {
var children = convertElements(element.children, messages);
return [
@@ -239,7 +302,10 @@ function DocumentConversion(options) {
});
var notesNodes = convertElements(notes, messages);
return children.concat([
- Html.freshElement("ol", {}, notesNodes)
+ Html.freshElement("ol", {}, notesNodes),
+ Html.freshElement("dl", {}, flatMap(referencedComments, function(referencedComment) {
+ return convertComment(referencedComment, messages);
+ }))
]);
},
"paragraph": convertParagraph,
@@ -281,6 +347,8 @@ function DocumentConversion(options) {
return Html.freshElement("li", {id: noteHtmlId(element)}, body);
},
+ "commentReference": convertCommentReference,
+ "comment": convertComment,
"image": deferredConversion(recoveringConvertImage(options.convertImage || defaultConvertImage)),
"table": convertTable,
"tableRow": convertTableRow,
diff --git a/lib/documents.js b/lib/documents.js
index 9f01d88..428dc09 100644
--- a/lib/documents.js
+++ b/lib/documents.js
@@ -24,7 +24,8 @@ function Document(children, options) {
return {
type: types.document,
children: children,
- notes: options.notes || new Notes({})
+ notes: options.notes || new Notes({}),
+ comments: options.comments || []
};
}
diff --git a/test/document-to-html.tests.js b/test/document-to-html.tests.js
index 436014f..af08050 100644
--- a/test/document-to-html.tests.js
+++ b/test/document-to-html.tests.js
@@ -486,7 +486,7 @@ test('footnotes are included after the main body', function() {
});
test('comments are ignored by default', function() {
- var reference = documents.commentReference("4");
+ var reference = documents.commentReference({commentId: "4"});
var comment = documents.comment({
commentId: "4",
body: [paragraphOfText("Who's there?")]
@@ -503,7 +503,37 @@ test('comments are ignored by default', function() {
assert.equal(result.value, '<p>Knock knock</p>');
assert.deepEqual(result.messages, []);
});
+});
+test('comment references are linked to comment after main body', function() {
+ var reference = documents.commentReference({commentId: "4"});
+ var comment = documents.comment({
+ commentId: "4",
+ body: [paragraphOfText("Who's there?")],
+ authorName: "The Piemaker",
+ authorInitials: "TP"
+ });
+ var document = documents.document([
+ documents.paragraph([
+ runOfText("Knock knock"),
+ documents.run([reference])
+ ])
+ ], {comments: [comment]});
+
+ var converter = new DocumentConverter({
+ idPrefix: "doc-42-",
+ styleMap: [
+ {from: documentMatchers.commentReference, to: htmlPaths.element("sup")}
+ ]
+ });
+ return converter.convertToHtml(document).then(function(result) {
+ var expectedHtml = (
+ '<p>Knock knock<sup><a href="#doc-42-comment-4" id="doc-42-comment-ref-4">[TP1]</a></sup></p>' +
+ '<dl><dt id="doc-42-comment-4">Comment [TP1]</dt><dd><p>Who\'s there? <a href="#doc-42-comment-ref-4">↑</a></p></dd></dl>'
+ );
+ assert.equal(result.value, expectedHtml);
+ assert.deepEqual(result.messages, []);
+ });
});
test('images are written with data URIs', function() {