Class FootnoteHtmlNodeRenderer
- java.lang.Object
-
- org.commonmark.ext.footnotes.internal.FootnoteHtmlNodeRenderer
-
- All Implemented Interfaces:
NodeRenderer
public class FootnoteHtmlNodeRenderer extends java.lang.Object implements NodeRenderer
HTML rendering for footnotes.Aims to match the rendering of cmark-gfm (which is slightly different from GitHub's when it comes to class attributes, not sure why).
Some notes on how rendering works:
- Footnotes are numbered according to the order of references, starting at 1
- Definitions are rendered at the end of the document, regardless of where the definition was in the source
- Definitions are ordered by number
- Definitions have links back to their references (one or more)
Nested footnotes
Text in footnote definitions can reference other footnotes, even ones that aren't referenced in the main text. This makes them tricky because it's not enough to just go through the main text for references. And before we can render a definition, we need to know all references (because we add links back to references).In other words, footnotes form a directed graph. Footnotes can reference each other so cycles are possible too.
One way to implement it, which is what cmark-gfm does, is to go through the whole document (including definitions) and find all references in order. That guarantees that all definitions are found, but it has strange results for ordering or when the reference is in an unreferenced definition, see tests. In graph terms, it renders all definitions that have an incoming edge, no matter whether they are connected to the main text or not.
The way we implement it:
- Start with the references in the main text; we can render them as we go
- After the main text is rendered, we have the referenced definitions, but there might be more from definition text
- To find the remaining definitions, we visit the definitions from before to look at references
- Repeat (breadth-first search) until we've found all definitions (note that we can't render before that's done because of backrefs)
- Now render the definitions (and any references inside)
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static class
FootnoteHtmlNodeRenderer.DefinitionVisitor
private static class
FootnoteHtmlNodeRenderer.ReferencedDefinition
private static class
FootnoteHtmlNodeRenderer.ReferenceInfo
private static class
FootnoteHtmlNodeRenderer.ShallowReferenceVisitor
Visit footnote references/inline footnotes inside the parent (but not the parent itself).
-
Field Summary
Fields Modifier and Type Field Description private HtmlNodeRendererContext
context
private DefinitionMap<FootnoteDefinition>
definitionMap
All definitions (even potentially unused ones), for looking up referencesprivate HtmlWriter
html
private java.util.Map<Node,FootnoteHtmlNodeRenderer.ReferencedDefinition>
referencedDefinitions
Definitions that were referenced, in order in which they should be rendered.private java.util.Map<Node,FootnoteHtmlNodeRenderer.ReferenceInfo>
references
Information about references that should be rendered as footnotes.
-
Constructor Summary
Constructors Constructor Description FootnoteHtmlNodeRenderer(HtmlNodeRendererContext context)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description void
afterRoot(Node rootNode)
Called after the root node is rendered, to do any final processing at the end.void
beforeRoot(Node rootNode)
Called before the root node is rendered, to do any initial processing at the start.private java.lang.String
definitionId(java.lang.String definitionKey)
private java.lang.String
definitionKey(java.lang.String label, int number)
java.util.Set<java.lang.Class<? extends Node>>
getNodeTypes()
private java.lang.String
referenceId(java.lang.String definitionKey, int number)
private FootnoteHtmlNodeRenderer.ReferenceInfo
registerReference(Node node, java.lang.String label)
void
render(Node node)
Render the specified node.private void
renderBackrefs(Node def, FootnoteHtmlNodeRenderer.ReferencedDefinition referencedDefinition)
private void
renderChildren(Node parent)
private void
renderDefinition(Node def, FootnoteHtmlNodeRenderer.ReferencedDefinition referencedDefinition)
private void
renderReference(Node node, FootnoteHtmlNodeRenderer.ReferenceInfo referenceInfo)
private FootnoteHtmlNodeRenderer.ReferenceInfo
tryRegisterReference(FootnoteReference ref)
-
-
-
Field Detail
-
html
private final HtmlWriter html
-
context
private final HtmlNodeRendererContext context
-
definitionMap
private DefinitionMap<FootnoteDefinition> definitionMap
All definitions (even potentially unused ones), for looking up references
-
referencedDefinitions
private final java.util.Map<Node,FootnoteHtmlNodeRenderer.ReferencedDefinition> referencedDefinitions
Definitions that were referenced, in order in which they should be rendered.
-
references
private final java.util.Map<Node,FootnoteHtmlNodeRenderer.ReferenceInfo> references
Information about references that should be rendered as footnotes. This doesn't contain all references, just the ones from inside definitions.
-
-
Constructor Detail
-
FootnoteHtmlNodeRenderer
public FootnoteHtmlNodeRenderer(HtmlNodeRendererContext context)
-
-
Method Detail
-
getNodeTypes
public java.util.Set<java.lang.Class<? extends Node>> getNodeTypes()
- Specified by:
getNodeTypes
in interfaceNodeRenderer
- Returns:
- the types of nodes that this renderer handles
-
beforeRoot
public void beforeRoot(Node rootNode)
Description copied from interface:NodeRenderer
Called before the root node is rendered, to do any initial processing at the start.- Specified by:
beforeRoot
in interfaceNodeRenderer
- Parameters:
rootNode
- the root (top-level) node
-
render
public void render(Node node)
Description copied from interface:NodeRenderer
Render the specified node.- Specified by:
render
in interfaceNodeRenderer
- Parameters:
node
- the node to render, will be an instance of one ofNodeRenderer.getNodeTypes()
-
afterRoot
public void afterRoot(Node rootNode)
Description copied from interface:NodeRenderer
Called after the root node is rendered, to do any final processing at the end.- Specified by:
afterRoot
in interfaceNodeRenderer
- Parameters:
rootNode
- the root (top-level) node
-
tryRegisterReference
private FootnoteHtmlNodeRenderer.ReferenceInfo tryRegisterReference(FootnoteReference ref)
-
registerReference
private FootnoteHtmlNodeRenderer.ReferenceInfo registerReference(Node node, java.lang.String label)
-
renderReference
private void renderReference(Node node, FootnoteHtmlNodeRenderer.ReferenceInfo referenceInfo)
-
renderDefinition
private void renderDefinition(Node def, FootnoteHtmlNodeRenderer.ReferencedDefinition referencedDefinition)
-
renderBackrefs
private void renderBackrefs(Node def, FootnoteHtmlNodeRenderer.ReferencedDefinition referencedDefinition)
-
referenceId
private java.lang.String referenceId(java.lang.String definitionKey, int number)
-
definitionKey
private java.lang.String definitionKey(java.lang.String label, int number)
-
definitionId
private java.lang.String definitionId(java.lang.String definitionKey)
-
renderChildren
private void renderChildren(Node parent)
-
-