Skip to content

fix: link-external-newwindow: true not respected by default listing - #9469

Draft
mcanouil wants to merge 22 commits into
quarto-dev:mainfrom
mcanouil:fix/issue9468
Draft

mcanouil wants to merge 22 commits into
quarto-dev:mainfrom
mcanouil:fix/issue9468

Conversation

@mcanouil

@mcanouil mcanouil commented Apr 24, 2024 •

Copy link
Copy Markdown
Collaborator

Description

With link-external-newwindow: true, external listing items now open in a new tab.
Fixes #9468.

The external-link script skipped listing items because they carried no-external, which turns off both the new tab and the icon.
A new class, no-external-icon, turns off only the icon, and default and grid items use it.
no-external keeps its meaning, and an external link inside an item description keeps its icon.
The listing reruns the script when pagination, filtering or sorting shows new items.

Quarto never tells screen reader users that a link opens a new tab, which fails WCAG technique G201 (success criterion 3.2.5), and this change opens more links that way.
Each link the script opens in a new tab now ends with a visually hidden "(opens in a new tab)", from a new language key link-external-newwindow-label (English only for now).
An external item without an image also left an empty thumbnail link in the tab order, which #15099 fixed only for items with a file; it is now hidden the same way.

Playwright tests cover default, grid and table listings, pagination, minimal: true, axe-core, and a page without the option.
Table rows still open in the same tab when clicked outside the link, which I'll address separately.

Checklist

I have (if applicable):

  • referenced the GitHub issue this PR closes
  • updated the appropriate changelog in the PR
  • ensured the present test suite passes
  • added new tests
  • created a separate documentation PR in Quarto's website repo and linked it to this PR
AI-assisted PR
  • AI tool used: Claude Code.
  • Codebase grounding: local clone.
  • Human review: I have reviewed, tested, and verified the AI-generated content before submitting.

Note: autonomous AI agents submitting PRs without human oversight are not permitted — see the Code of Conduct.

@mcanouil
mcanouil requested a review from cscheid April 24, 2024 15:11
@mcanouil mcanouil self-assigned this Apr 24, 2024
@cscheid

cscheid commented Apr 24, 2024

Copy link
Copy Markdown
Member

I'm a bit confused about the fix here; I would have expected there to be a condition that needs to be checked depending on link-external-newwindow. How does removing that solve the problem without causing a problem with (eg) link-external-newwindow: false?

@mcanouil

mcanouil commented Apr 24, 2024 •

Copy link
Copy Markdown
Collaborator Author

That's the thing I did not figure out yet.
The other listing templates are very similar in this aspect.

The option seems to be applied at another level as I did not find anything in src/resources/projects/website/listing. The only thing I found was the fact that it was explicitly hardcoded that links should never be opened in a new window and only within the default type listing.

Edit: this is why removing this class makes the external new window option works. The option is used as part of a JavaScript script which is added to HTML when the option is true.

@cderv

cderv commented Apr 24, 2024

Copy link
Copy Markdown
Member

Just a note that this PR is exactly a revert of commit 8c61f7e

So I don't know exactly why it was added this way with no-external, but it seems it was done on purpose. I'll ask Charles as he is around.

@mcanouil

mcanouil commented Apr 24, 2024 •

Copy link
Copy Markdown
Collaborator Author

Yes, I was looking into it to find what was the reason for this to be done only in the default.
I did not find any issues or smoke tests related to this. I also did quite few tests and did not find any downside of not having this class.

@dragonstyle in case you recall why you did add the .no-external class for all links in the default listing item template.

@mcanouil
mcanouil marked this pull request as draft April 27, 2024 15:28
@mcanouil

Copy link
Copy Markdown
Collaborator Author

Do not merge.
I want to investigate a bit more.

@mcanouil
mcanouil marked this pull request as ready for review April 28, 2024 12:05
@mcanouil

Copy link
Copy Markdown
Collaborator Author

I've tested on various website listings (6) and did not see any issues.

@cderv

cderv commented Apr 29, 2024

Copy link
Copy Markdown
Member

I believe what needs to be tested if all the feature that removing no-external would trigger
https://github.com/cderv/quarto-cli/blob/adef941f451f3ce8443ebf68e2f310e57b07b4be/src/resources/formats/html/templates/quarto-html.ejs#L365-L395

From the code it seems to mean

  • External new window adding noopener
  • External icon adding an icon on the link

Currently, both of this won't happen to links with .no-external

After discussing with @dragonstyle last week, he does not remember why exactly but was warning us that it could have been made following some slack discussion for some of our doc website, and that it could trigger other stuff.

Now, things may have changed since then, and maybe removing the class won't trigger anything bad 🤔

@cderv

cderv commented Apr 29, 2024

Copy link
Copy Markdown
Member

For example, this is how it looks if I add link-external-icon: true
image

We got an icon everywhere - and I don't think we want this really

@mcanouil

Copy link
Copy Markdown
Collaborator Author

Indeed, that might be the issue Charles tried to fix.

I think the "noexternal" fix is wrong. Wrong in the sense that other listing will have the same issues.
I believe, the right fix is to not add the external icon for links in listings (except if they are in the "description").

What do you think?
If this sounds good I'll tinker around that idea.
Meanwhile, putting this PR back in draft.

@mcanouil
mcanouil marked this pull request as draft April 29, 2024 08:35
@cscheid cscheid added this to the v1.7 milestone Nov 18, 2024
@mcanouil

mcanouil commented Feb 1, 2025

Copy link
Copy Markdown
Collaborator Author

Updating this PR with the addition of a CSS rule to get the same display behaviour (no external icon in default listing).
This means the default listing would respect link-external-newwindow but wouldn't link-external-icon.

Code

---
title: "Test"
link-external-newwindow: true
link-external-icon: true
listing:
  contents:
    - path: https://www.nature.com/articles/d41586-024-00692-7
      title: "China–US climate collaboration concerns as Xie and Kerry step down"
      author: Smriti Mallapaty
      description: "Gang's quote on the importance to continue the research exchange and colloboration 'If the river freezes over, water will still flow underneath.'"
      date: "2024-03-12"
      categories: [Nature]
    - path: https://www.scientificamerican.com/article/what-the-u-s-china-agreement-means-for-greenhouse-gas-emissions/
      title: "What the U.S.-China Agreement Means for Greenhouse Gas Emissions"
      author: 
        - Benjamin Storrow
        - Sara Schonhardt
      description: "The two nations announced limited steps to address climate change. But even a modest agreement could have far-reaching effects."
      date: "2023-11-16"
      categories: [Scientific American, E&E News]
  sort: "date desc"
  categories: true
  sort-ui: false
  filter-ui: false
page-layout: full
title-block-banner: true
---

@mcanouil
mcanouil marked this pull request as ready for review February 1, 2025 15:06
@cscheid

cscheid commented Mar 14, 2025

Copy link
Copy Markdown
Member

Thanks for working on this PR again. This is all quite a bit messy and, because it's close to reverting a previous commit, I don't think I'm comfortable merging it before adding tests that exercise the expected behavior for these different options.

@mcanouil

Copy link
Copy Markdown
Collaborator Author

I'll try to figure suitable tests for behaviour and icons.

Switching this to draft for now.

@mcanouil
mcanouil marked this pull request as draft March 14, 2025 14:08
@cscheid cscheid modified the milestones: v1.7, v1.8 Apr 7, 2025
@mcanouil mcanouil closed this Jul 15, 2025
@mcanouil
mcanouil deleted the fix/issue9468 branch July 15, 2025 08:59
@mcanouil
mcanouil restored the fix/issue9468 branch July 15, 2025 09:00
@mcanouil mcanouil reopened this Jul 15, 2025
@posit-snyk-bot

posit-snyk-bot commented Jul 15, 2025 •

Copy link
Copy Markdown
Collaborator

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues
✅ Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@cscheid cscheid modified the milestones: v1.8, v1.9 Aug 20, 2025
@mcanouil

Copy link
Copy Markdown
Collaborator Author

If link-external-icon: true is set, grid listing items could show external icons (this is pre-existing behaviour).
As the original issue was about "default", I left as-is.

@mcanouil
mcanouil marked this pull request as draft October 19, 2026 11:53
@mcanouil

mcanouil commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator Author

@cscheid, I've reworked this so it no longer reverts the earlier fix.
The CSS rule is gone, and the listing items now use a separate no-external-icon class, so no-external behaves as before.
Playwright tests now cover the icons and the new-tab behaviour in default, grid and table listings, plus pagination.
The description above has the details, including the screen reader announcement for links that open in a new tab.

@cderv If you want to follow up on this.

@mcanouil
mcanouil marked this pull request as ready for review October 26, 2026 09:48
@mcanouil

mcanouil commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator Author

(fixing the issue with the tests)

@mcanouil
mcanouil marked this pull request as draft October 26, 2026 11:15
The data-quarto-external attribute ended up in the selectors axe builds,
which changed finding signatures and broke matching against an axe
baseline.
@mcanouil

mcanouil commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator Author

The smoke test smoke/axe/axe-findings.test.ts fails because of a change I made in this PR.
To decorate links shown after pagination, I made quartoDecorateExternalLinks run again on each list.js updated event.
So that it skips links it has already handled, I had it set data-quarto-external="" on every link it processes.
axe uses that attribute when it builds selectors, so the planted finding link-name :: p > a becomes link-name :: p > a[data-quarto-external=""].
The same change would shift the signatures in any user's _axe-baseline.json.

Removing the marker fixes the test, and almost every decoration step is safe to repeat.
The one exception is the custom icon branch, used when link-external-icon is a string: it inserts a new <i class="bi-… quarto-ext-icon"> on every run.
Search and sort fire updated as well as pagination.
Each hashchange also calls quarto-listing-loaded again, which adds another updated listener, so the icons would multiply.
The schema only accepts true or false for link-external-icon, so a string reaches this branch only with validate-yaml: false.

Options I looked at:

  • Remove the marker and leave the custom icon branch as it is, accepting duplicate icons for a value the schema rejects. (current)
  • Remove the marker and check for an existing .quarto-ext-icon sibling before inserting one.
  • Keep a re-run guard that doesn't touch the DOM, such as a WeakSet of processed links.

For now, the PR follows the first option.
Is the string form of link-external-icon still meant to be supported?
If not, removing that branch in a follow-up would make the first option clean.
Which approach would you prefer for this PR?

# Conflicts:
#	src/resources/editor/tools/yaml/all-schema-definitions.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

link-external-newwindow: true not respected by default listing

4 participants