Skip to content

Attributes Not Properly Applied to Images #642

Open
@solonovamax

Description

@solonovamax

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(
    """
        ![image](/my-image.png){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:

} 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions