diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-08-29 11:25:59 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-08-29 11:25:59 +0100 |
| commit | 28c8b89afea499191b13849140354b21819937f4 (patch) | |
| tree | 69439b8fbe969ee8778c9c7d371187e6e53b7276 /src | |
| parent | 8c392ff2f11c84bbeff3536c1ab4d0e9442c8f20 (diff) | |
Add conversion for comments
Diffstat (limited to 'src')
5 files changed, 135 insertions, 22 deletions
diff --git a/src/main/java/org/zwobble/mammoth/internal/conversion/DocumentToHtml.java b/src/main/java/org/zwobble/mammoth/internal/conversion/DocumentToHtml.java index 1254747..b22742c 100644 --- a/src/main/java/org/zwobble/mammoth/internal/conversion/DocumentToHtml.java +++ b/src/main/java/org/zwobble/mammoth/internal/conversion/DocumentToHtml.java @@ -8,17 +8,19 @@ import org.zwobble.mammoth.internal.styles.HtmlPath; import org.zwobble.mammoth.internal.styles.StyleMap; import org.zwobble.mammoth.internal.util.Base64Encoding; import org.zwobble.mammoth.internal.util.Lists; +import org.zwobble.mammoth.internal.util.Maps; import java.io.IOException; import java.util.*; import java.util.function.Supplier; import static org.zwobble.mammoth.internal.util.Lists.*; +import static org.zwobble.mammoth.internal.util.Maps.lookup; import static org.zwobble.mammoth.internal.util.Maps.map; public class DocumentToHtml { public static InternalResult<List<HtmlNode>> convertToHtml(Document document, DocumentToHtmlOptions options) { - DocumentToHtml documentConverter = new DocumentToHtml(options); + DocumentToHtml documentConverter = new DocumentToHtml(options, document.getComments()); return new InternalResult<>( documentConverter.convertToHtml(document), documentConverter.warnings); @@ -32,36 +34,51 @@ public class DocumentToHtml { } public static InternalResult<List<HtmlNode>> convertToHtml(DocumentElement element, DocumentToHtmlOptions options) { - DocumentToHtml documentConverter = new DocumentToHtml(options); + DocumentToHtml documentConverter = new DocumentToHtml(options, list()); return new InternalResult<>( documentConverter.convertToHtml(element), documentConverter.warnings); } + private static class ReferencedComment { + private final String label; + private final Comment comment; + + private ReferencedComment(String label, Comment comment) { + this.label = label; + this.comment = comment; + } + } + private final String idPrefix; private final boolean preserveEmptyParagraphs; private final StyleMap styleMap; + private final Map<String, Comment> comments; private final List<NoteReference> noteReferences = new ArrayList<>(); + private final List<ReferencedComment> referencedComments = new ArrayList<>(); private final Set<String> warnings = new HashSet<>(); - private DocumentToHtml(DocumentToHtmlOptions options) { + private DocumentToHtml(DocumentToHtmlOptions options, List<Comment> comments) { this.idPrefix = options.idPrefix(); this.preserveEmptyParagraphs = options.shouldPreserveEmptyParagraphs(); this.styleMap = options.styleMap(); + this.comments = Maps.toMapWithKey(comments, Comment::getCommentId); } private List<HtmlNode> convertToHtml(Document document) { List<HtmlNode> mainBody = convertChildrenToHtml(document); // TODO: can you have note references inside a note? List<Note> notes = findNotes(document, noteReferences); - if (notes.isEmpty()) { - return mainBody; - } else { - HtmlNode noteNode = Html.element("ol", - eagerMap(notes, this::convertToHtml)); - return eagerConcat(mainBody, list(noteNode)); - } + List<HtmlNode> noteNodes = notes.isEmpty() + ? list() + : list(Html.element("ol", eagerMap(notes, this::convertToHtml))); + + List<HtmlNode> commentNodes = referencedComments.isEmpty() + ? list() + : list(Html.element("dl", eagerFlatMap(referencedComments, this::convertToHtml))); + + return eagerConcat(mainBody, noteNodes, commentNodes); } private HtmlNode convertToHtml(Note note) { @@ -76,6 +93,25 @@ public class DocumentToHtml { return Html.element("li", map("id", id), eagerConcat(noteBody, list(backLink))); } + private List<HtmlNode> convertToHtml(ReferencedComment referencedComment) { + // TODO: remove duplication with notes + String commentId = referencedComment.comment.getCommentId(); + List<HtmlNode> body = convertToHtml(referencedComment.comment.getBody()); + // TODO: we probably want this to collapse more eagerly than other collapsible elements + // -- for instance, any paragraph will probably do, regardless of attributes. (Possible other elements will do too.) + HtmlNode backLink = Html.collapsibleElement("p", list( + Html.text(" "), + Html.element("a", map("href", "#" + generateReferenceHtmlId("comment", commentId)), list(Html.text("↑"))))); + + return list( + Html.element( + "dt", + map("id", generateReferentHtmlId("comment", commentId)), + list(Html.text("Comment " + referencedComment.label))), + Html.element("dd", + eagerConcat(body, list(backLink)))); + } + private List<HtmlNode> convertToHtml(List<DocumentElement> elements) { return eagerFlatMap( elements, @@ -210,7 +246,21 @@ public class DocumentToHtml { @Override public List<HtmlNode> visit(CommentReference commentReference) { - return list(); + return styleMap.getCommentReference().orElse(HtmlPath.IGNORE).wrap(() -> { + String commentId = commentReference.getCommentId(); + Comment comment = lookup(comments, commentId) + .orElseThrow(() -> new RuntimeException("Referenced comment could not be found, id: " + commentId)); + String label = "[" + comment.getAuthorInitials().orElse("") + (referencedComments.size() + 1) + "]"; + referencedComments.add(new ReferencedComment(label, comment)); + + // TODO: Remove duplication with note references + return list(Html.element( + "a", + map( + "href", "#" + generateReferentHtmlId("comment", commentId), + "id", generateReferenceHtmlId("comment", commentId)), + list(Html.text(label)))); + }).get(); } @Override @@ -240,11 +290,19 @@ public class DocumentToHtml { } private String generateNoteHtmlId(NoteType noteType, String noteId) { - return generateId(noteTypeToIdFragment(noteType) + "-" + noteId); + return generateReferentHtmlId(noteTypeToIdFragment(noteType), noteId); } private String generateNoteRefHtmlId(NoteType noteType, String noteId) { - return generateId(noteTypeToIdFragment(noteType) + "-ref-" + noteId); + return generateReferenceHtmlId(noteTypeToIdFragment(noteType), noteId); + } + + private String generateReferentHtmlId(String referenceType, String referenceId) { + return generateId(referenceType + "-" + referenceId); + } + + private String generateReferenceHtmlId(String referenceType, String referenceId) { + return generateId(referenceType + "-ref-" + referenceId); } private String noteTypeToIdFragment(NoteType noteType) { diff --git a/src/main/java/org/zwobble/mammoth/internal/documents/Document.java b/src/main/java/org/zwobble/mammoth/internal/documents/Document.java index 77d5580..5adc50d 100644 --- a/src/main/java/org/zwobble/mammoth/internal/documents/Document.java +++ b/src/main/java/org/zwobble/mammoth/internal/documents/Document.java @@ -20,4 +20,8 @@ public class Document implements HasChildren { public Notes getNotes() { return notes; } + + public List<Comment> getComments() { + return comments; + } } diff --git a/src/main/java/org/zwobble/mammoth/internal/styles/StyleMap.java b/src/main/java/org/zwobble/mammoth/internal/styles/StyleMap.java index eb810aa..c587483 100644 --- a/src/main/java/org/zwobble/mammoth/internal/styles/StyleMap.java +++ b/src/main/java/org/zwobble/mammoth/internal/styles/StyleMap.java @@ -71,6 +71,10 @@ public class StyleMap { return strikethrough; } + public Optional<HtmlPath> getCommentReference() { + return commentReference; + } + public Optional<HtmlPath> getParagraphHtmlPath(Paragraph paragraph) { return tryFind(paragraphStyles, styleMapping -> styleMapping.matches(paragraph)) .map(StyleMapping::getHtmlPath); diff --git a/src/main/java/org/zwobble/mammoth/internal/util/Lists.java b/src/main/java/org/zwobble/mammoth/internal/util/Lists.java index 0fb53c1..3fbb5dd 100644 --- a/src/main/java/org/zwobble/mammoth/internal/util/Lists.java +++ b/src/main/java/org/zwobble/mammoth/internal/util/Lists.java @@ -40,6 +40,14 @@ public class Lists { return Stream.concat(stream(first), stream(second)).collect(Collectors.toList()); } + public static <T> List<T> eagerConcat(Collection<T> first, Collection<T> second, Collection<T> third) { + List<T> result = new ArrayList<>(first.size() + second.size() + third.size()); + result.addAll(first); + result.addAll(second); + result.addAll(third); + return result; + } + public static <T> List<T> eagerFilter(Iterable<T> iterable, Predicate<T> predicate) { return stream(iterable).filter(predicate).collect(Collectors.toList()); } diff --git a/src/test/java/org/zwobble/mammoth/tests/conversion/DocumentToHtmlTests.java b/src/test/java/org/zwobble/mammoth/tests/conversion/DocumentToHtmlTests.java index c5cb073..b144b78 100644 --- a/src/test/java/org/zwobble/mammoth/tests/conversion/DocumentToHtmlTests.java +++ b/src/test/java/org/zwobble/mammoth/tests/conversion/DocumentToHtmlTests.java @@ -8,10 +8,7 @@ import org.zwobble.mammoth.internal.documents.*; import org.zwobble.mammoth.internal.html.Html; import org.zwobble.mammoth.internal.html.HtmlNode; import org.zwobble.mammoth.internal.results.InternalResult; -import org.zwobble.mammoth.internal.styles.HtmlPath; -import org.zwobble.mammoth.internal.styles.ParagraphMatcher; -import org.zwobble.mammoth.internal.styles.RunMatcher; -import org.zwobble.mammoth.internal.styles.StyleMap; +import org.zwobble.mammoth.internal.styles.*; import java.io.ByteArrayInputStream; import java.util.List; @@ -322,10 +319,11 @@ public class DocumentToHtmlTests { @Test public void commentsAreIgnoredByDefault() { - Document document = document(withChildren( - paragraph(withChildren( - runWithText("Knock knock"), - run(withChildren(new CommentReference("4")))))), + Document document = document( + withChildren( + paragraph(withChildren( + runWithText("Knock knock"), + run(withChildren(new CommentReference("4")))))), withComments(comment("4", list(paragraphWithText("Who's there?"))))); assertThat( @@ -336,6 +334,42 @@ public class DocumentToHtmlTests { } @Test + public void commentReferencesAreLinkedToCommentAfterMainBody() { + CommentReference reference = new CommentReference("4"); + Comment comment = new Comment( + "4", + list(paragraphWithText("Who's there?")), + Optional.of("The Piemaker"), + Optional.of("TP") + ); + Document document = document( + withChildren( + paragraph(withChildren( + runWithText("Knock knock"), + run(withChildren(reference))))), + withComments(comment) + ); + + StyleMap styleMap = StyleMap.builder().commentReference(HtmlPath.element("sup")).build(); + assertThat( + convertToHtml(document, styleMap), + deepEquals(list( + Html.element("p", list( + Html.text("Knock knock"), + Html.element("sup", list( + Html.element("a", map("href", "#doc-42-comment-4", "id", "doc-42-comment-ref-4"), list(Html.text("[TP1]"))))))), + Html.element("dl", list( + Html.element("dt", map("id", "doc-42-comment-4"), list( + Html.text("Comment [TP1]"))), + Html.element("dd", list( + Html.element("p", list( + Html.text("Who's there?"))), + Html.collapsibleElement("p", list( + Html.text(" "), + Html.element("a", map("href", "#doc-42-comment-ref-4"), list(Html.text("↑")))))))))))); + } + + @Test public void imagesAreConvertedToImageTagsWithDataUriByDefault() { Image image = new Image( Optional.empty(), @@ -358,8 +392,13 @@ public class DocumentToHtmlTests { } private List<HtmlNode> convertToHtml(Document document) { + return convertToHtml(document, StyleMap.EMPTY); + } + + private List<HtmlNode> convertToHtml(Document document, StyleMap styleMap) { DocumentToHtmlOptions options = DocumentToHtmlOptions.DEFAULT - .idPrefix("doc-42-"); + .idPrefix("doc-42-") + .addStyleMap(styleMap); InternalResult<List<HtmlNode>> result = DocumentToHtml.convertToHtml(document, options); assertThat(result.getWarnings(), emptyIterable()); return result.getValue(); |
