-
Notifications
You must be signed in to change notification settings - Fork 297
Description
Describe the Bug
When using the Attributes extension, attributes cannot be applied to an img tag, instead they are always applied to the parent tag.
Reproducing
Note: code here is in kotlin as that's what my project is in and it's easier to write. It is decently trivial to translate it back to java.
val options = MutableDataSet()
options[Parser.EXTENSIONS] = listOf(
AttributesExtension.create(),
)
val parser = Parser.builder(flexmarkOptions).build()
val htmlRenderer = HtmlRenderer.builder(flexmarkOptions).build()
@Language("Markdown")
val document = parser.parse(
"""
{class="my-class"}
""".trimIndent()
)
val renderedResult = renderer.render(document)
println(renderedResult)Expected Result
<p>
<img src="/my-image.png" alt="image" class="my-class">
</p>
<p>
<a href="/my-link" class="my-class">link</a>
</p>Actual Result
<p class="my-class">
<img src="/my-image.png" alt="image">
</p>
<p>
<a href="/my-link" class="my-class">link</a>
</p>Notice how it still adds the class to the <a> tag as expected, however it is not added to the <img> tag as expected.
Additional Context
I have determined exactly what is causing the bug, it is particular piece of code right here in AttributesNodePostProcessor.java:
Lines 90 to 92 in cc3a2f5
| } else { | |
| if ((!myOptions.assignTextAttributes && (previous instanceof Text || previous instanceof TextBase)) || previous.getEndOffset() < attributesNode.getStartOffset()) { | |
| // either previous is text and no text attributes or not attached to the previous node |
The issue has to do with the comparison between previous.getEndOffset() and attributesNode.getStartOffset(). In image tags, attributesNode.getStartOffset() is always greater than previous.getEndOffset(), which then causes it to always be true.
Here is a fix that I've implemented in my own project in the meantime:
val endOffset = previous.endOffset
val startOffset = attributesNode.startOffset - if (previous is Image || previous is ResizableImage) 1 else 0
if ((!options.assignTextAttributes && (previous is Text || previous is TextBase)) || endOffset < startOffset) {
// ...in java, you would do
int endOffset = previous.getEndOffset();
int startOffset = attributesNode.getStartOffset() - (previous instanceof Image || previous instanceof ResizableImage ? 1 : 0);
if ((!myOptions.assignTextAttributes && (previous instanceof Text || previous instanceof TextBase)) || endOffset < startOffset) {
// ...I'm checking if it's an instance of either Image or ResizableImage (to support the Resizable Image extension)
This is also likely an issue with the Media Tags extension, however I have not tested it. If it is, you would fix this by also checking if it's an instance of AbstractMediaLink.