Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Markdown support in listings templates #11760

Merged
merged 14 commits into from
Jan 6, 2025

Conversation

mcanouil
Copy link
Collaborator

@mcanouil mcanouil commented Dec 30, 2024

The changes restore Markdown support in the default listings templates after the introduction of {=html} in version 1.7.5. This update ensures that Markdown formatting is correctly rendered in listings.

Fixes #11758.

This PR also adds a check for subtitle field in the default listing. Previously it was adding subtitle even when not provided as long as title was.

Tested on: https://m.canouil.dev/quarto-issues-experiments/issue11758/
Source: https://github.com/mcanouil/quarto-issues-experiments/tree/main/quarto-cli-11758

To do:

@mcanouil mcanouil self-assigned this Dec 30, 2024
@mcanouil mcanouil changed the title fix:Markdown support in listings templates fix: Markdown support in listings templates Dec 30, 2024
Copy link
Collaborator

@cderv cderv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot !

Using raw inlines for each raw HTML seems the right call if we need to avoid markdown in HTML parsing.

Only impact I can think of is that <div> in markdown leads to Div in AST, while using raw inline leads to RawInline. It has impact on Lua filter processing.

❯ pandoc -t native
<div class="thumbnail">**STRONG**</div>
^Z
[ Div
    ( "" , [ "thumbnail" ] , [] )
    [ Plain [ Strong [ Str "STRONG" ] ] ]
]

~ took 12s
❯ pandoc -t native
`<div class="thumbnail">`{=html}**STRONG**`</div>`{=html}
^Z
[ Para
    [ RawInline (Format "html") "<div class=\"thumbnail\">"
    , Strong [ Str "STRONG" ]
    , RawInline (Format "html") "</div>"
    ]
]

So we probably need to make sure we have no Lua processing applying on any Div we create in Listing. I check our Lua code using search.

See more in comment about some example of potential issue - I think we are safe as they seems to apply in Dashboard format only.

Regarding test, it seems something needs to be adapted as a test seems to be broken. Didn't look carefully yet.

Thanks again for the PR !

@mcanouil
Copy link
Collaborator Author

mcanouil commented Jan 2, 2025

I'm a bit stuck for the remaining raw HTML code.

Using the following without raw code block works as expected for having the item being read/evaluated as markdown.

<h5 class="no-anchor card-title listing-title"><%= item.title %></h5>

Using raw block will lead to the item being placed in a <p> tag leading to extra styling which is really unwanted inside h5.

```{=html}
<h5 class="no-anchor card-title listing-title">
```
<%= item.title %>
```{=html}
</h5>
```
```

This happens for other parts with `<div>` (grid and default listings) and `<td>` (table listing and grid listing for metadata).

Margins added by `<p>` could be dealt with (S)CSS but it's a bit messy.

Any ideas?

Comment on lines 87 to 89
```
<%= outputValue(itemNumber, field) %>
```{=html}
Copy link
Collaborator Author

@mcanouil mcanouil Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This leads to extra <p> being added as the line is read as Markdown.

image

Copy link
Collaborator Author

@mcanouil mcanouil Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactor a bit by making <td> outside the raw block.

9c43d63

Comment on lines 138 to 149
```{=html}
<table class="card-other-values">
<% for (const field of otherFields) {
let value = readField(item, field);
<% for (const field of otherFields) {
let value = readField(item, field);
%>
<tr>
<td><%= listing.utilities.fieldName(field) %></td>
<td class="<%-field%>"><%= listing.utilities.outputLink(item, field, value) %></td>
<td class="<%- field %>"><%= listing.utilities.outputLink(item, field, value) %></td>
</tr>
<% } %>
</table>
```
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No markdown supports in metadata with this.
Splitting this to allow markdown for listing.utilities.fieldName(field) and listing.utilities.outputLink(item, field, value) will lead to <p> being added.

Copy link
Collaborator Author

@mcanouil mcanouil Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency until there is a decision, I switched to using raw blocks except for the lines with the variables to allow markdown.

9c43d63

This means, there is still inline HTML.

@mcanouil
Copy link
Collaborator Author

mcanouil commented Jan 2, 2025

In the current state, I have a constant normal memory consumption when rendering the project from #11701

Still need to check the failing test: https://github.com/quarto-dev/quarto-cli/actions/runs/12582608380/job/35068595360?pr=11760
Edit: I don't understand what's the issue or what's being tested as the listing (tests/docs/listings) renders and works properly from what I have seen.
This listing test could be updated to include markdown in title/subtitle/description.
Edit2: seems to be good now

@mcanouil mcanouil added the needs-discussion Issues that require a team-wide discussion before proceeding further label Jan 2, 2025
@mcanouil mcanouil marked this pull request as ready for review January 2, 2025 16:26
Copy link
Collaborator

@cscheid cscheid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great!

I wanted to leave one comment for future reference because of a subtle change in behavior, but I think it's ready to merge.

tests/docs/listings/_quarto.yml Show resolved Hide resolved
@cscheid cscheid merged commit 7417a5e into quarto-dev:main Jan 6, 2025
47 checks passed
@mcanouil mcanouil deleted the fix/issue11758 branch January 6, 2025 16:26
Copy link
Collaborator

@cderv cderv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to improve my knowledge and remove some concerns due to interrogation I have. I prefer to be sure we avoid possible regression.

Those EJS template where using <%- and not <%= in some case to be sure that content is encoded, when used in attributes for example.

Maybe there was issue to fix and we wrongly encoded some of them, though I am not sure all replacement of <%- are justified below, specifically those with localizedString().

I may be missing something though, so asking for precision again to fully understand those EJS template.

Thanks for your patience :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

localizedString() usage here will insert a user provided value. I think it is safer to keep using <%- here, especially when used in HTML attribute, as we can't know which character would be used.

Maybe there won't be any < used for listing-page-order-by but if so, then I think it could break HTML.

That is my thinking. If there is a specific reason, I am missing it, so I would really like to understand and learn something new. Why replacing ?

My first though is that using %<- for escaping is safer.

Thank you

Copy link
Collaborator Author

@mcanouil mcanouil Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value is used inside text attribute or inside div which means the content is directly displayed to the users.
Escaping what's supposed to be a string would lead to weird placeholder, aria-label, and option text display.

image

Why would the text need escaping? I might have missed something but to me, there are no reasons to escape those values.

Both "work" and both can lead to unexpected outputs when non ASCII string provided.
I don't think there is a perfect solution. The rational being the use of = was the same as the overall PR, i.e., allow Markdown/HTML (of course no markdown evaluation is possible anyway when inside raw block).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding of this <%- vs <%= in template is that

  • Templating here is used to create HTML content
  • Some characters in HTML have meaning for the structure and so if they need to be shown as text, they should be HTML escape so that in browser they are shown as text, and not considered HTML

Maybe this won't ever happen but I was thinking it is safer to always HTML escape <%- when we know the content provided shouldn't be interpreted as HTML structure.

Example in lodash doc #11787 is quite explicite about escaping

// Use the HTML "escape" delimiter to escape data property values.
var compiled = _.template('<b><%- value %></b>');
compiled({ 'value': '<script>' });
// => '<b>&lt;script&gt;</b>'

If you want to write <script> as such in strong case, then you need the template to HTML escape the value.

So for language customizable value, I am thinking it is better to protect if a user wants to use something like quotes (") in the value.

Maybe I am wrong about this but I think my thinking sum up

  • <%- would be safer as this is why it was used before. Maybe it is not useful but it does not harm to use it
  • I don't see the gain of switching to <%=, especially if it could potentially be opened to regression.

🤷

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As all the occurrences are in an HTML raw block, I think we can go (back) with <%- as no markdown will ever work there.

Should I do the PR?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep on the purpose of learning, as this is still unclear, can you explain to me

no markdown will ever work there.

Or rather you'll confirm if I understand correctly

  • This ejs template is in fact a markdown file
  • So we should be carefull when not in a raw block because Markdown in HTML will be interpreted (which is the initial problem)
  • And in this case, escaping could be harmful because it could break the markdown syntax.
  • And so what I shared above is really valid only inside raw block, or inside a template file that is not interpreted as .md file.

I think this is what I was missing, right ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's it.

Copy link
Collaborator Author

@mcanouil mcanouil Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably update the documentation about all this story:

  • using raw block (Pandoc memory issue and possible parsing issue that could happen, as without, Pandoc has to guess it's HTML)
  • EJS templates in Quarto are read as Mardown files

https://quarto.org/docs/websites/website-listings-custom.html

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-discussion Issues that require a team-wide discussion before proceeding further
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Markdown is no longer supported in listings (>= 1.7.5)
3 participants