Skip to content

Commit

Permalink
Support "Captioned titles" in asciidoctor-parser-doxia-module (#938)
Browse files Browse the repository at this point in the history
* Add support for Example (inline and blocks)
* Add support for captioned titles in appendixes, tables, listing, figure, and examples.
* Fix empty table generating <table> element
* Refactor Section tests for readability 

Fixes #749
  • Loading branch information
abelsromero authored Oct 20, 2024
1 parent 912de34 commit e870c8c
Show file tree
Hide file tree
Showing 26 changed files with 685 additions and 214 deletions.
10 changes: 7 additions & 3 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ Bug Fixes::

* Fix open IMG tags in parser-doxia-module (#930)
* Fix naming in Asciidoctor Converter Doxia Module pom (#934)
* Fix empty table generating <table> element (asciidoctor-parser-doxia-module) (#938)

Improvements::

* Added support for AsciidoctorJ v3.0.0 (#651)
* Add compatibility with maven-site-plugin v3.20.0 and Doxia v2.0.0 (#933)
* Add support for code blocks titles in asciidoctor-parser-doxia-module (#935)
* Refactor AST traversal method in asciidoctor-parser-doxia-module (#944)
* Add support for code blocks titles (asciidoctor-parser-doxia-module) (#935)
* Refactor AST traversal method (asciidoctor-parser-doxia-module) (#944)
* Empty titles in document or empty literals no longer generate <h1> or <pre> in asciidoctor-parser-doxia-module (#944)
* Sections are now wrapped in <div> in asciidoctor-parser-doxia-module (#944)
* Sections are now wrapped in <div> in (asciidoctor-parser-doxia-module) (#944)
* Add support for inline and Example blocks (asciidoctor-parser-doxia-module) (#938)
* Add support for captioned titles in appendixes, tables, listing, figure, and examples (asciidoctor-parser-doxia-module) (#938)


Build / Infrastructure::

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,16 @@ Linux:::
BSD:::
. FreeBSD
. NetBSD

=== Examples

.Optional title (1)
====
This is an example of an example block (1).
====

.Optional title (2)
[example]
This is an example of an example block (2).
*dadsas* https://dasd.com

Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ new HtmlAsserter(htmlContent).with { asserter ->
asserter.containsUnorderedList("Desktop", "Server")
asserter.descriptionListTerm("BSD")
asserter.containsOrderedList("FreeBSD", "NetBSD")

asserter.containsSectionTitle("Examples", 3)
asserter.containsExampleDiv()
asserter.containsExampleDiv()
}

String strong(String text) {
Expand Down Expand Up @@ -224,8 +228,15 @@ class HtmlAsserter {
}
}

void containsExampleDiv() {
final def key = "<div style=\"background: #fffef7;"
def found = find(key)
assertFound("Example <div>", key, found)
}

void assertTableCaption(String htmlBlock, String caption) {
def start = htmlBlock.indexOf("<caption>") + "<caption>".length()
def start = htmlBlock.indexOf("<caption") + "<caption".length()
start = htmlBlock.indexOf(">", start) + 1
def end = htmlBlock.indexOf("</caption>")
if (start < 0 || end < 0)
fail("Caption not found ($start, $end)")
Expand All @@ -239,11 +250,11 @@ class HtmlAsserter {

void assertTableHeaders(String htmlBlock, List<String> headers) {
def actualHeaders = Arrays.stream(htmlBlock.split("<"))
.filter(line -> line.startsWith("th>"))
.map(line -> {
return line.substring("th>".length())
})
.collect(Collectors.toList())
.filter(line -> line.startsWith("th>"))
.map(line -> {
return line.substring("th>".length())
})
.collect(Collectors.toList())

if (actualHeaders != headers)
fail("Table headers not valid. Found: $actualHeaders, expected: $headers")
Expand All @@ -266,8 +277,8 @@ class HtmlAsserter {
// Removes linebreaks to validate to avoid OS dependant issues.
private String clean(String value) {
return value.replaceAll("\r\n", "")
.replaceAll("\n", "")
.trim();
.replaceAll("\n", "")
.trim();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.asciidoctor.ast.StructuralNode;
import org.asciidoctor.maven.site.parser.processors.DescriptionListNodeProcessor;
import org.asciidoctor.maven.site.parser.processors.DocumentNodeProcessor;
import org.asciidoctor.maven.site.parser.processors.ExampleNodeProcessor;
import org.asciidoctor.maven.site.parser.processors.ImageNodeProcessor;
import org.asciidoctor.maven.site.parser.processors.ListItemNodeProcessor;
import org.asciidoctor.maven.site.parser.processors.ListingNodeProcessor;
Expand Down Expand Up @@ -35,6 +36,7 @@ public NodeSinker(Sink sink) {
nodeProcessors = Arrays.asList(
new DescriptionListNodeProcessor(sink, this),
new DocumentNodeProcessor(sink, this),
new ExampleNodeProcessor(sink, this),
new ImageNodeProcessor(sink, this),
new ListItemNodeProcessor(sink, this),
new ListingNodeProcessor(sink, this),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public class DocumentNodeProcessor extends AbstractSinkNodeProcessor implements
/**
* Constructor.
*
* @param sink Doxia {@link Sink}
* @param sink Doxia {@link Sink}
* @param nodeSinker
*/
public DocumentNodeProcessor(Sink sink, NodeSinker nodeSinker) {
super(sink, nodeSinker);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.asciidoctor.maven.site.parser.processors;

import java.util.List;

import org.apache.maven.doxia.sink.Sink;
import org.asciidoctor.ast.StructuralNode;
import org.asciidoctor.maven.site.parser.NodeProcessor;
import org.asciidoctor.maven.site.parser.NodeSinker;

import static javax.swing.text.html.HTML.Attribute.STYLE;
import static org.asciidoctor.maven.commons.StringUtils.isNotBlank;

/**
* Inline images are processed as paragraphs.
*
* @author abelsromero
* @since 3.1.0
*/
public class ExampleNodeProcessor extends AbstractSinkNodeProcessor implements NodeProcessor {

/**
* Constructor.
*
* @param sink Doxia {@link Sink}
* @param nodeSinker
*/
public ExampleNodeProcessor(Sink sink, NodeSinker nodeSinker) {
super(sink, nodeSinker);
}

@Override
public boolean applies(StructuralNode node) {
return "example".equals(node.getNodeName());
}

@Override
public void process(StructuralNode node) {
// Add caption as a div (same as Asciidoctor):
// - For consistency
// - Using `figureCaption` requires wrapping the image in <figure> which adds indentation
final Sink sink = getSink();

sink.division();
final String title = TitleCaptionExtractor.getText(node);
if (isNotBlank(title)) {
sink.division(SinkAttributes.of(STYLE, Styles.CAPTION));
sink.text(title);
sink.division_();
}

final List<StructuralNode> blocks = node.getBlocks();
if (!blocks.isEmpty()) {
divWrap(sink, node, () -> blocks.forEach(this::sink));
} else {
// For :content_model: simple (inline)
// https://docs.asciidoctor.org/asciidoc/latest/blocks/example-blocks/#example-style-syntax
final String content = (String) node.getContent();
if (isNotBlank(content)) {
divWrap(sink, node, () -> sink.rawText(content));
}
}

sink.division_();
}

void divWrap(Sink sink, StructuralNode node, Runnable consumer) {
sink.division(SinkAttributes.of(STYLE, Styles.EXAMPLE));
consumer.run();
sink.division_();
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package org.asciidoctor.maven.site.parser.processors;

import javax.swing.text.html.HTML.Attribute;
import java.nio.file.FileSystems;

import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.asciidoctor.ast.StructuralNode;
import org.asciidoctor.maven.site.parser.NodeProcessor;
import org.asciidoctor.maven.site.parser.NodeSinker;

import static javax.swing.text.html.HTML.Attribute.ALT;
import static javax.swing.text.html.HTML.Attribute.STYLE;
import static org.asciidoctor.maven.commons.StringUtils.isBlank;
import static org.asciidoctor.maven.commons.StringUtils.isNotBlank;

/**
* Inline images are processed as paragraphs.
Expand Down Expand Up @@ -40,12 +41,21 @@ public void process(StructuralNode node) {
final String alt = (String) node.getAttribute("alt");

final String imagesdir = (String) node.getAttribute("imagesdir");
String imagePath = isBlank(imagesdir) ? target : formatPath(imagesdir, target);
final SinkEventAttributeSet attributes = new SinkEventAttributeSet();
if (!isBlank(alt))
attributes.addAttribute(Attribute.ALT, alt);
final String imagePath = isBlank(imagesdir) ? target : formatPath(imagesdir, target);

getSink().figureGraphics(imagePath, attributes);
// Add caption as a div (same as Asciidoctor):
// - For consistency
// - Using `figureCaption` requires wrapping the image in <figure> which adds indentation
final Sink sink = getSink();
sink.division();
sink.figureGraphics(imagePath, !isBlank(alt) ? SinkAttributes.of(ALT, alt) : null);
final String title = TitleCaptionExtractor.getText(node);
if (isNotBlank(title)) {
sink.division(SinkAttributes.of(STYLE, Styles.CAPTION));
sink.text(title);
sink.division_();
}
sink.division_();
}

private String formatPath(String imagesdir, String target) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import org.apache.maven.doxia.sink.Sink;
import org.asciidoctor.ast.StructuralNode;
import org.asciidoctor.maven.commons.StringUtils;
import org.asciidoctor.maven.site.parser.NodeProcessor;
import org.asciidoctor.maven.site.parser.NodeSinker;

Expand Down Expand Up @@ -39,20 +38,15 @@ public boolean applies(StructuralNode node) {
@Override
public void process(StructuralNode node) {
final StringBuilder contentBuilder = new StringBuilder();
String language = (String) node.getAttribute("language");
String style = node.getStyle();
final String language = (String) node.getAttribute("language");
final String style = node.getStyle();

boolean isSourceBlock = isSourceBlock(language, style);

if (isSourceBlock) {
// source class triggers prettify auto-detection
contentBuilder.append("<div class=\"source\">");

final String title = node.getTitle();
if (StringUtils.isNotBlank(title)) {
contentBuilder.append("<div style=\"color: #7a2518; margin-bottom: .25em;\" >" + title + "</div>");
}

processTitle(node, contentBuilder);
contentBuilder.append("<pre class=\"")
.append(FLUIDO_SKIN_SOURCE_HIGHLIGHTER);
if (isLinenumsEnabled(node))
Expand All @@ -77,6 +71,13 @@ public void process(StructuralNode node) {
getSink().rawText(contentBuilder.toString());
}

private static void processTitle(StructuralNode node, StringBuilder contentBuilder) {
final String title = TitleCaptionExtractor.getText(node);
if (isNotBlank(title)) {
contentBuilder.append("<div style=\"" + Styles.CAPTION + "\" >" + title + "</div>");
}
}

private boolean isLinenumsEnabled(StructuralNode node) {
// linenums attribute can be set with empty string value
return LINENUMS_ATTRIBUTE.equals(node.getAttribute("linenums"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import org.apache.maven.doxia.sink.Sink;
import org.asciidoctor.ast.Section;
import org.asciidoctor.ast.StructuralNode;
import org.asciidoctor.jruby.ast.impl.SectionImpl;
import org.asciidoctor.maven.commons.StringUtils;
import org.asciidoctor.maven.site.parser.NodeProcessor;
import org.asciidoctor.maven.site.parser.NodeSinker;
import org.slf4j.Logger;
Expand Down Expand Up @@ -77,7 +79,14 @@ private String formatTitle(String title, Section node) {
final Long sectnumlevels = getSectnumlevels(node);
final int level = node.getLevel();
if (numbered && level <= sectnumlevels) {
return String.format("%s %s", node.getSectnum(), title);
// Use 'getString' instead of method to support pre-3.0.0 AsciidoctorJ
final String caption = node.getCaption();
final String sectnum = ((SectionImpl) node).getString("sectnum");
if (StringUtils.isBlank(caption)) {
return String.format("%s %s", sectnum, title);
} else {
return String.format("%s %s", caption.trim(), title);
}
}
return title;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.asciidoctor.maven.site.parser.processors;

import javax.swing.text.html.HTML.Attribute;

import org.apache.maven.doxia.sink.SinkEventAttributes;
import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;

class SinkAttributes {

static SinkEventAttributes of(Attribute name, String value) {
final var attributes = new SinkEventAttributeSet();
attributes.addAttribute(name, value);
return attributes;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.asciidoctor.maven.site.parser.processors;

import java.util.stream.Collectors;
import java.util.stream.Stream;

class Styles {

public static final String CAPTION = Stream.of(
"color: #7a2518",
"margin-bottom: .25em"
).collect(Collectors.joining("; "));


public static final String EXAMPLE = Stream.of(
"background: #fffef7",
"border-color: #e0e0dc",
"border: 1px solid #e6e6e6",
"box-shadow: 0 1px 4px #e0e0dc",
"margin-bottom: 1.25em",
"padding: 1.25em"
).collect(Collectors.joining("; "));
}
Loading

0 comments on commit e870c8c

Please sign in to comment.