diff --git a/src/main/java/io/github/moacirrf/netbeans/markdown/html/CheckboxAdjuster.java b/src/main/java/io/github/moacirrf/netbeans/markdown/html/CheckboxAdjuster.java new file mode 100644 index 0000000..99d4be9 --- /dev/null +++ b/src/main/java/io/github/moacirrf/netbeans/markdown/html/CheckboxAdjuster.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 moacirrf + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package io.github.moacirrf.netbeans.markdown.html; + +import java.util.function.Predicate; +import static javax.swing.text.html.HTML.Tag.LI; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; + +/** + * + * @author moacirrf + */ +public class CheckboxAdjuster implements HtmlAdjuster, Predicate { + + private static final String STYLE = "list-style-type:none"; + + @Override + public Document adjust(Document inputDocument) { + inputDocument.getElementsByTag("input") + .stream() + .filter(this::test) + .map(input -> { + if (!isLI(input.parent())) { + return input.parent().parent(); + } + return input.parent(); + }) + .forEach(li + -> li.attr("style", STYLE)); + return inputDocument; + } + + @Override + public boolean test(Element inputElement) { + return isLI(inputElement.parent()) || isLI(inputElement.parent().parent()); + } + + public boolean isLI(Element inputElement) { + return LI.toString().equalsIgnoreCase(inputElement.tag().getName()); + } + +} diff --git a/src/main/java/io/github/moacirrf/netbeans/markdown/html/HtmlBuilder.java b/src/main/java/io/github/moacirrf/netbeans/markdown/html/HtmlBuilder.java index 1341357..e1032dc 100644 --- a/src/main/java/io/github/moacirrf/netbeans/markdown/html/HtmlBuilder.java +++ b/src/main/java/io/github/moacirrf/netbeans/markdown/html/HtmlBuilder.java @@ -62,6 +62,7 @@ private HtmlBuilder(MutableDataSet options) { htmlAdjusters.add(new LinksAdjuster()); htmlAdjusters.add(new FirstElementAdjuster()); htmlAdjusters.add(new ListAdjuster()); + htmlAdjusters.add(new CheckboxAdjuster()); } public String build(String markdownText) { diff --git a/src/main/java/io/github/moacirrf/netbeans/markdown/html/flexmark/MyCoreNodeDocxRenderer.java b/src/main/java/io/github/moacirrf/netbeans/markdown/html/flexmark/MyCoreNodeDocxRenderer.java index b179cae..5e9af65 100644 --- a/src/main/java/io/github/moacirrf/netbeans/markdown/html/flexmark/MyCoreNodeDocxRenderer.java +++ b/src/main/java/io/github/moacirrf/netbeans/markdown/html/flexmark/MyCoreNodeDocxRenderer.java @@ -857,13 +857,23 @@ private void renderListItem(ListItem node, DocxRendererContext docx) { idNum = bulletLists[listLevel]; } } - - docx.setBlockFormatProvider(new ListItemBlockFormatProvider<>(docx, listParagraphStyleId, listSpacingStyle, idNum, listLevel, ListItem.class, ListBlock.class)); - addBlockAttributeFormatting(node, AttributablePart.NODE, docx, false); + boolean hasChildCheckbox = false; + if (node.hasChildren()) { + var childChar = node.getChildChars(); + if (childChar != null && childChar.isNotBlank() && childChar.length() > 3) { + hasChildCheckbox = childChar.firstChar() == '[' + && childChar.charAt(2) == ']'; + } + } + if (!hasChildCheckbox) { + docx.setBlockFormatProvider(new ListItemBlockFormatProvider<>(docx, listParagraphStyleId, listSpacingStyle, idNum, listLevel, ListItem.class, ListBlock.class)); + addBlockAttributeFormatting(node, AttributablePart.NODE, docx, false); + } docx.renderChildren(node); } - private void render(SoftLineBreak node, DocxRendererContext docx) { + +private void render(SoftLineBreak node, DocxRendererContext docx) { docx.addTextCreateR(" "); } @@ -2049,9 +2059,13 @@ private void rendeHtmlNode(Node node, DocxRendererContext docx) { private Tbl myTbl; private Tr myTr; - private void render(TableBlock node, DocxRendererContext docx) { + private + +void render(TableBlock node, DocxRendererContext docx) { // if we have a caption and it goes before the table, we add it here - Node caption = node.getFirstChildAny(TableCaption.class); + Node caption = node.getFirstChildAny(TableCaption.class + +); if (caption != null && tableCaptionBeforeTable) { renderTableCaption((TableCaption) caption, docx); } @@ -2349,8 +2363,11 @@ private void render(EnumeratedReferenceText node, DocxRendererContext docx) { } } else { String type = EnumeratedReferenceRepository.getType(text.toString()); - if (type.isEmpty() || text.equals(type + ":")) { - Node parent = node.getAncestorOfType(Heading.class); + +if (type.isEmpty() || text.equals(type + ":")) { + Node parent = node.getAncestorOfType(Heading.class + +); if (parent instanceof Heading) { text = (type.isEmpty() ? text : type) + ":" + headerIdGenerator.getId(parent); @@ -2381,66 +2398,67 @@ private void render(EnumeratedReferenceLink node, DocxRendererContext docx) { attributes = docx.extendRenderingNodeAttributes(AttributablePart.NODE, attributes); renderURL(node.getText(), docx, "#" + text, attributes, () -> EnumeratedReferences.renderReferenceOrdinals(renderings, new OrdinalRenderer(MyCoreNodeDocxRenderer.this, docx))); - } + +} } private static class OrdinalRenderer implements EnumeratedOrdinalRenderer { - final MyCoreNodeDocxRenderer renderer; - final DocxRendererContext docx; - - public OrdinalRenderer(MyCoreNodeDocxRenderer renderer, DocxRendererContext docx) { - this.renderer = renderer; - this.docx = docx; - } + final MyCoreNodeDocxRenderer renderer; + final DocxRendererContext docx; - @Override - public void startRendering(EnumeratedReferenceRendering[] renderings) { + public OrdinalRenderer(MyCoreNodeDocxRenderer renderer, DocxRendererContext docx) { + this.renderer = renderer; + this.docx = docx; + } - } + @Override + public void startRendering(EnumeratedReferenceRendering[] renderings) { - @Override - public void setEnumOrdinalRunnable(Runnable runnable) { - renderer.ordinalRunnable = runnable; - } + } - @Override - public Runnable getEnumOrdinalRunnable() { - return renderer.ordinalRunnable; - } + @Override + public void setEnumOrdinalRunnable(Runnable runnable) { + renderer.ordinalRunnable = runnable; + } - @Override - public void render(int referenceOrdinal, EnumeratedReferenceBlock referenceFormat, String defaultText, boolean needSeparator) { - Runnable compoundRunnable = renderer.ordinalRunnable; - String text = referenceOrdinal + (needSeparator ? "." : ""); + @Override + public Runnable getEnumOrdinalRunnable() { + return renderer.ordinalRunnable; + } - if (referenceFormat != null) { - renderer.ordinalRunnable = () -> { - if (compoundRunnable != null) { - compoundRunnable.run(); - } - docx.addTextCreateR(text); - }; + @Override + public void render(int referenceOrdinal, EnumeratedReferenceBlock referenceFormat, String defaultText, boolean needSeparator) { + Runnable compoundRunnable = renderer.ordinalRunnable; + String text = referenceOrdinal + (needSeparator ? "." : ""); - docx.renderChildren(referenceFormat); - } else { + if (referenceFormat != null) { + renderer.ordinalRunnable = () -> { if (compoundRunnable != null) { - docx.addTextCreateR(defaultText + " "); compoundRunnable.run(); - docx.addTextCreateR(text); - } else { - docx.addTextCreateR(defaultText + " " + text); } + docx.addTextCreateR(text); + }; + + docx.renderChildren(referenceFormat); + } else { + if (compoundRunnable != null) { + docx.addTextCreateR(defaultText + " "); + compoundRunnable.run(); + docx.addTextCreateR(text); + } else { + docx.addTextCreateR(defaultText + " " + text); } } + } - @Override - public void endRendering() { + @Override + public void endRendering() { - } } +} - private void render(EnumeratedReferenceBlock node, DocxRendererContext docx) { +private void render(EnumeratedReferenceBlock node, DocxRendererContext docx) { } @@ -2492,245 +2510,247 @@ private void render(JekyllTagBlock node, DocxRendererContext docx) { // docx.render(inclChild); // } // } - } + + +} private static class UrlRenderer implements Runnable { - final private DocxRendererContext myDocx; - final private String myLinkText; - final private String myLinkUrl; + final private DocxRendererContext myDocx; + final private String myLinkText; + final private String myLinkUrl; - public UrlRenderer(DocxRendererContext docx, String linkText, String linkUrl) { - myDocx = docx; - myLinkText = linkText; - myLinkUrl = linkUrl; - } + public UrlRenderer(DocxRendererContext docx, String linkText, String linkUrl) { + myDocx = docx; + myLinkText = linkText; + myLinkUrl = linkUrl; + } - @Override - public void run() { - // Create object for r - myDocx.addTextCreateR(myLinkText == null ? myLinkUrl : myLinkText); - } + @Override + public void run() { + // Create object for r + myDocx.addTextCreateR(myLinkText == null ? myLinkUrl : myLinkText); } +} - private static class UrlRunContainer implements RunContainer { +private static class UrlRunContainer implements RunContainer { - final private P.Hyperlink myHyperlink; + final private P.Hyperlink myHyperlink; - public UrlRunContainer(P.Hyperlink hyperlink) { - myHyperlink = hyperlink; - } + public UrlRunContainer(P.Hyperlink hyperlink) { + myHyperlink = hyperlink; + } - @Override - public void addR(R r) { - myHyperlink.getContent().add(r); - } + @Override + public void addR(R r) { + myHyperlink.getContent().add(r); + } - @Override - public R getLastR() { - List content = myHyperlink.getContent(); - if (content == null || content.size() == 0) { - return null; - } - Object o = content.get(content.size() - 1); - return o instanceof R ? (R) o : null; + @Override + public R getLastR() { + List content = myHyperlink.getContent(); + if (content == null || content.size() == 0) { + return null; } + Object o = content.get(content.size() - 1); + return o instanceof R ? (R) o : null; } +} - private static class ChildRenderer implements Runnable { +private static class ChildRenderer implements Runnable { - final private DocxRendererContext myDocx; - final private Node myNode; + final private DocxRendererContext myDocx; + final private Node myNode; - public ChildRenderer(DocxRendererContext docx, Node node) { - myDocx = docx; - myNode = node; - } + public ChildRenderer(DocxRendererContext docx, Node node) { + myDocx = docx; + myNode = node; + } - @Override - public void run() { - myDocx.renderChildren(myNode); - } + @Override + public void run() { + myDocx.renderChildren(myNode); } +} - private static class FootnoteFrame implements Runnable { +private static class FootnoteFrame implements Runnable { - final DocxRendererContext myDocx; - final CTFtnEdn myFtnEdn; - final private FootnoteBlock myFootnoteBlock; + final DocxRendererContext myDocx; + final CTFtnEdn myFtnEdn; + final private FootnoteBlock myFootnoteBlock; - public FootnoteFrame(DocxRendererContext docx, CTFtnEdn ftnEdn, FootnoteBlock footnoteBlock) { - myDocx = docx; - myFtnEdn = ftnEdn; - myFootnoteBlock = footnoteBlock; - } + public FootnoteFrame(DocxRendererContext docx, CTFtnEdn ftnEdn, FootnoteBlock footnoteBlock) { + myDocx = docx; + myFtnEdn = ftnEdn; + myFootnoteBlock = footnoteBlock; + } - @Override - public void run() { - myDocx.setBlockFormatProvider(new FootnoteBlockFormatProvider<>(myDocx)); - myDocx.setRunFormatProvider(new FootnoteRunFormatProvider<>(myDocx)); - myDocx.setParaContainer(new ParaContainer() { - @Override - public void addP(P p) { - myFtnEdn.getContent().add(p); - } + @Override + public void run() { + myDocx.setBlockFormatProvider(new FootnoteBlockFormatProvider<>(myDocx)); + myDocx.setRunFormatProvider(new FootnoteRunFormatProvider<>(myDocx)); + myDocx.setParaContainer(new ParaContainer() { + @Override + public void addP(P p) { + myFtnEdn.getContent().add(p); + } - @Override - public P getLastP() { - List content = myFtnEdn.getContent(); - if (content == null || content.size() == 0) { - return null; - } - Object o = content.get(content.size() - 1); - return o instanceof P ? (P) o : null; + @Override + public P getLastP() { + List content = myFtnEdn.getContent(); + if (content == null || content.size() == 0) { + return null; } - }); + Object o = content.get(content.size() - 1); + return o instanceof P ? (P) o : null; + } + }); - myDocx.setContentContainer(new ContentContainer() { - @Override - public RelationshipsPart getRelationshipsPart() { - try { - return myDocx.getFootnotesPart().getRelationshipsPart(); - } catch (Docx4JException e) { - e.printStackTrace(); - return myDocx.getDocxDocument().getRelationshipsPart(); - } + myDocx.setContentContainer(new ContentContainer() { + @Override + public RelationshipsPart getRelationshipsPart() { + try { + return myDocx.getFootnotesPart().getRelationshipsPart(); + } catch (Docx4JException e) { + e.printStackTrace(); + return myDocx.getDocxDocument().getRelationshipsPart(); } + } - @Override - public Part getContainerPart() { - try { - return myDocx.getFootnotesPart(); - } catch (Docx4JException e) { - e.printStackTrace(); - return myDocx.getDocxDocument(); - } + @Override + public Part getContainerPart() { + try { + return myDocx.getFootnotesPart(); + } catch (Docx4JException e) { + e.printStackTrace(); + return myDocx.getDocxDocument(); } + } - @Override - public List getContent() { - return myFtnEdn.getContent(); - } + @Override + public List getContent() { + return myFtnEdn.getContent(); + } - @Override - public Object getLastContentElement() { - List content = getContent(); - return content != null && content.size() > 0 ? content.get(content.size() - 1) : null; - } + @Override + public Object getLastContentElement() { + List content = getContent(); + return content != null && content.size() > 0 ? content.get(content.size() - 1) : null; + } - @Override - public void addContentElement(Object element) { - getContent().add(element); - } - }); - myDocx.renderChildren(myFootnoteBlock); - } + @Override + public void addContentElement(Object element) { + getContent().add(element); + } + }); + myDocx.renderChildren(myFootnoteBlock); } +} - private static class TableCaptionRenderer implements Runnable { +private static class TableCaptionRenderer implements Runnable { - final private DocxRendererContext myDocx; - final private TableCaption myNode; + final private DocxRendererContext myDocx; + final private TableCaption myNode; - public TableCaptionRenderer(DocxRendererContext docx, TableCaption node) { - myDocx = docx; - myNode = node; - } + public TableCaptionRenderer(DocxRendererContext docx, TableCaption node) { + myDocx = docx; + myNode = node; + } - @Override - public void run() { - myDocx.setBlockFormatProvider(new BlockFormatProviderBase<>(myDocx, myDocx.getDocxRendererOptions().TABLE_CAPTION)); - myDocx.createP(); - myDocx.renderChildren(myNode); - } + @Override + public void run() { + myDocx.setBlockFormatProvider(new BlockFormatProviderBase<>(myDocx, myDocx.getDocxRendererOptions().TABLE_CAPTION)); + myDocx.createP(); + myDocx.renderChildren(myNode); } +} - private static class TableCellContentContainer implements ContentContainer { +private static class TableCellContentContainer implements ContentContainer { - final private Tc myTc; - final private DocxRendererContext myDocx; - final private Part myContainerPart; - final private boolean[] myFirstP; + final private Tc myTc; + final private DocxRendererContext myDocx; + final private Part myContainerPart; + final private boolean[] myFirstP; - public TableCellContentContainer(Tc tc, DocxRendererContext docx, boolean[] firstP) { - myTc = tc; - myDocx = docx; - myFirstP = firstP; - myContainerPart = myDocx.getContainerPart(); - } + public TableCellContentContainer(Tc tc, DocxRendererContext docx, boolean[] firstP) { + myTc = tc; + myDocx = docx; + myFirstP = firstP; + myContainerPart = myDocx.getContainerPart(); + } - @Override - public List getContent() { - return myTc.getContent(); - } + @Override + public List getContent() { + return myTc.getContent(); + } - @Override - public RelationshipsPart getRelationshipsPart() { - return myContainerPart.relationships; - } + @Override + public RelationshipsPart getRelationshipsPart() { + return myContainerPart.relationships; + } - @Override - public Part getContainerPart() { - return myContainerPart; - } + @Override + public Part getContainerPart() { + return myContainerPart; + } - @Override - public Object getLastContentElement() { - List content = myTc.getContent(); - return content != null && content.size() > 0 ? content.get(content.size() - 1) : null; - } + @Override + public Object getLastContentElement() { + List content = myTc.getContent(); + return content != null && content.size() > 0 ? content.get(content.size() - 1) : null; + } - @Override - public void addContentElement(Object element) { - myTc.getContent().add(element); - myFirstP[0] = false; - } + @Override + public void addContentElement(Object element) { + myTc.getContent().add(element); + myFirstP[0] = false; } +} - private static class TableCellParaContainer implements ParaContainer { +private static class TableCellParaContainer implements ParaContainer { - final private TableCell myNode; - final private Tc myTc; - final private DocxRendererContext myDocx; - final private boolean[] myFirstP; + final private TableCell myNode; + final private Tc myTc; + final private DocxRendererContext myDocx; + final private boolean[] myFirstP; - public TableCellParaContainer(TableCell node, Tc tc, DocxRendererContext docx, boolean[] firstP) { - myNode = node; - myTc = tc; - myDocx = docx; - myFirstP = firstP; - } + public TableCellParaContainer(TableCell node, Tc tc, DocxRendererContext docx, boolean[] firstP) { + myNode = node; + myTc = tc; + myDocx = docx; + myFirstP = firstP; + } - @Override - public void addP(P p) { - myFirstP[0] = false; - myTc.getContent().add(p); - } - - @Override - public P getLastP() { - List content = myTc.getContent(); - if (myFirstP[0] && (content == null || content.size() == 0)) { - // Create object for p - P p = myDocx.createP(); - PPr ppr = p.getPPr(); - - // Create object for jc - if (myNode.getAlignment() != null) { - JcEnumeration alignValue = getAlignValue(myNode.getAlignment()); - Jc jc3 = myDocx.getFactory().createJc(); - ppr.setJc(jc3); - jc3.setVal(alignValue); - } + @Override + public void addP(P p) { + myFirstP[0] = false; + myTc.getContent().add(p); + } - myFirstP[0] = false; + @Override + public P getLastP() { + List content = myTc.getContent(); + if (myFirstP[0] && (content == null || content.size() == 0)) { + // Create object for p + P p = myDocx.createP(); + PPr ppr = p.getPPr(); + + // Create object for jc + if (myNode.getAlignment() != null) { + JcEnumeration alignValue = getAlignValue(myNode.getAlignment()); + Jc jc3 = myDocx.getFactory().createJc(); + ppr.setJc(jc3); + jc3.setVal(alignValue); } - if (content == null || content.size() == 0) { - return null; - } - Object o = content.get(content.size() - 1); - return o instanceof P ? (P) o : null; + myFirstP[0] = false; } + + if (content == null || content.size() == 0) { + return null; + } + Object o = content.get(content.size() - 1); + return o instanceof P ? (P) o : null; } } +} diff --git a/src/test/java/io/github/moacirrf/netbeans/markdown/html/CheckboxAdjusterTest.java b/src/test/java/io/github/moacirrf/netbeans/markdown/html/CheckboxAdjusterTest.java new file mode 100644 index 0000000..b34024e --- /dev/null +++ b/src/test/java/io/github/moacirrf/netbeans/markdown/html/CheckboxAdjusterTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 moacirrf + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package io.github.moacirrf.netbeans.markdown.html; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.junit.Assert; +import org.junit.Test; + +/** + * + * @author moacirrf + */ +public class CheckboxAdjusterTest { + + private HtmlBuilder htmlBuilder = HtmlBuilder.getInstance(); + + public static final String HTML_GIVEN = "\n" + + " \n" + + "
\n" + + "
    \n" + + "
  •  Design
  • \n" + + "
  •  Production
  • \n" + + "
\n" + + "
\n" + + " \n" + + ""; + + + @Test + public void testAdjust() { + var adjuster = new CheckboxAdjuster(); + + Document given = Jsoup.parse(HTML_GIVEN); + + Document document = adjuster.adjust(given); + + boolean expected = hasStyle(document, "list-style-type:none"); + + Assert.assertTrue(expected); + } + + public boolean hasStyle(Document doc, String style) { + return doc.getElementsByTag("li").attr("style").contains(style); + } + +}