AsciidoctorJ的API暴露了一系列的扩展点。一个扩展点可以操作Asciidoc文档的生成结果。例如,一个扩展点的实现 Postprocessor插入自定义的页脚文本。
一个标签式代码块需要插入动态行为和自定义样式。为此,我们需要在生成的HTML文档的标签中加入CSS和JavaScript。该 DocinfoProcessor扩展点可以直接操作文档的页眉和页脚,很适合我们的用例。
清单1显示了一个实现了抽象类DocinfoProcessor 的类。这个代码例子省略了详细的实现细节,例如,如何从classpath中读取文件。关于更多的细节,请看该类的完整源代码。
TabbedCodeBlockDocinfoProcessor.java
import org.asciidoctor.ast.Document;
import org.asciidoctor.extension.DocinfoProcessor;
import java.util.Map;
public class TabbedCodeBlockDocinfoProcessor extends DocinfoProcessor {
public static final String TABBED_CODE_CSS_FILE_PATH_ATTRIBUTE = "tabbed-code-css-path";
public static final String TABBED_CODE_JS_FILE_PATH_ATTRIBUTE = "tabbed-code-js-path";
public static final String DEFAULT_CSS_FILE_PATH = "/codeBlockSwitch.css";
public static final String DEFAULT_JS_FILE_PATH = "/codeBlockSwitch.js";
@Override
public String process(Document document) {
if (document.isBasebackend("html")) {
Map attributes = document.getAttributes();
String cssPath = getCssPath(attributes, TABBED_CODE_CSS_FILE_PATH_ATTRIBUTE, DEFAULT_CSS_FILE_PATH);
String jsPath = getCssPath(attributes, TABBED_CODE_JS_FILE_PATH_ATTRIBUTE, DEFAULT_JS_FILE_PATH);
String css = readFileContentsFromClasspath(cssPath);
String js = readFileContentsFromClasspath(jsPath);
return modifyHeadHtml(css, js);
}
return null;
}
...
}
清单1.DocinfoProcessor的一个实现
我想指出这个代码例子中两个值得注意的部分。你可能已经注意到,process 方法只处理HTML处理。我们这样做的原因很简单。将一个标签式的代码块添加到其他后端,如PDF文件,将需要不同的处理方式。默认情况下,该类使用一个预定义的CSS和JavaScript文件,该文件随扩展的分发而来。另外,终端用户也可以设置一个属性,用于提供自定义的样式或JavaScript行为。
每个你想提供给Asciidoctor处理器的扩展都需要注册。你可以通过实现一个类型为ExtensionRegistry 的类来做到这一点。清单2演示了一个将TabbedCodeBlockDocinfoProcessor 添加到扩展注册表的实现。
TabbedCodeBlockExtension.java
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.extension.JavaExtensionRegistry;
import org.asciidoctor.extension.spi.ExtensionRegistry;
public class TabbedCodeBlockExtension implements ExtensionRegistry {
@Override
public void register(Asciidoctor asciidoctor) {
JavaExtensionRegistry javaExtensionRegistry = asciidoctor.javaExtensionRegistry();
javaExtensionRegistry.docinfoProcessor(TabbedCodeBlockDocinfoProcessor.class);
}
}
清单2.在扩展注册表中注册DocinfoProcessor
我们还没有完成。你还需要创建一个名为org.asciidoctor.extension.spi.ExtensionRegistry 的文件,并将其指向扩展实现,以便Asciidoctor能够发现它。
META-INF/services/org.asciidoctor.extension.spi.ExtensionRegistry
com.bmuschko.asciidoctorj.tabbedcode.TabbedCodeBlockExtension
清单3.让扩展可以被发现
就这样,你写了第一个AsciidoctorJ扩展。接下来,我们将专注于测试、发布和使用扩展的重要方面。