diff --git a/news/changelog-1.11.md b/news/changelog-1.11.md index c265820e2a0..4944dc36ba8 100644 --- a/news/changelog-1.11.md +++ b/news/changelog-1.11.md @@ -23,6 +23,7 @@ All changes included in 1.11: - ([#14795](https://github.com/quarto-dev/quarto-cli/issues/14795)): Fix keyboard focus in `revealjs` presentations reaching links and controls on nearby slides that are not shown. Tab now stays on the current slide, except in overview, scroll and print views where all slides are shown. - ([#14952](https://github.com/quarto-dev/quarto-cli/issues/14952)): Fix `revealjs` presentations disabling pinch-zoom on touch devices. The viewport `` tag no longer sets `maximum-scale=1.0` and `user-scalable=no`, which axe-core flagged (`meta-viewport`). - ([#15011](https://github.com/quarto-dev/quarto-cli/issues/15011)): Fix the slide menu of `revealjs` presentations being read by screen readers while it is closed and off screen, and Tab moving keyboard focus to it once it lists more slides than fit. (author: @jooyoungseo) +- ([#15015](https://github.com/quarto-dev/quarto-cli/issues/15015)): Fix the "Back to Article" link of notebook previews in website projects not being reachable or usable with the keyboard. ## Formats diff --git a/src/resources/formats/html/embed/template.html b/src/resources/formats/html/embed/template.html index 81cbc8d6fac..79079db8931 100644 --- a/src/resources/formats/html/embed/template.html +++ b/src/resources/formats/html/embed/template.html @@ -118,7 +118,7 @@
- $nbMeta.backLabel$ + $nbMeta.backLabel$
$nbMeta.title$
$if(nbMeta.downloadHref)$ diff --git a/tests/docs/playwright/html/notebook-preview-back-link/.gitignore b/tests/docs/playwright/html/notebook-preview-back-link/.gitignore new file mode 100644 index 00000000000..88834c4d263 --- /dev/null +++ b/tests/docs/playwright/html/notebook-preview-back-link/.gitignore @@ -0,0 +1 @@ +/notebook.out.ipynb diff --git a/tests/docs/playwright/html/notebook-preview-back-link/index.qmd b/tests/docs/playwright/html/notebook-preview-back-link/index.qmd new file mode 100644 index 00000000000..ff868c9c4ce --- /dev/null +++ b/tests/docs/playwright/html/notebook-preview-back-link/index.qmd @@ -0,0 +1,5 @@ +--- +title: "Home" +--- + +{{< embed notebook.ipynb#answer >}} diff --git a/tests/docs/playwright/html/notebook-preview-back-link/notebook.ipynb b/tests/docs/playwright/html/notebook-preview-back-link/notebook.ipynb new file mode 100644 index 00000000000..4a8eaaca779 --- /dev/null +++ b/tests/docs/playwright/html/notebook-preview-back-link/notebook.ipynb @@ -0,0 +1,38 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "answer", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| label: answer\n", + "1 + 1" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/docs/playwright/website/notebook-preview-back-link/.gitignore b/tests/docs/playwright/website/notebook-preview-back-link/.gitignore new file mode 100644 index 00000000000..91e4dc52c80 --- /dev/null +++ b/tests/docs/playwright/website/notebook-preview-back-link/.gitignore @@ -0,0 +1,3 @@ +/.quarto/ +/_site/ +**/*.quarto_ipynb diff --git a/tests/docs/playwright/website/notebook-preview-back-link/_quarto.yml b/tests/docs/playwright/website/notebook-preview-back-link/_quarto.yml new file mode 100644 index 00000000000..ee2b7147d78 --- /dev/null +++ b/tests/docs/playwright/website/notebook-preview-back-link/_quarto.yml @@ -0,0 +1,10 @@ +project: + type: website + +website: + title: "notebook-preview-back-link" + navbar: + left: + - index.qmd + +format: html diff --git a/tests/docs/playwright/website/notebook-preview-back-link/index.qmd b/tests/docs/playwright/website/notebook-preview-back-link/index.qmd new file mode 100644 index 00000000000..ff868c9c4ce --- /dev/null +++ b/tests/docs/playwright/website/notebook-preview-back-link/index.qmd @@ -0,0 +1,5 @@ +--- +title: "Home" +--- + +{{< embed notebook.ipynb#answer >}} diff --git a/tests/docs/playwright/website/notebook-preview-back-link/notebook.ipynb b/tests/docs/playwright/website/notebook-preview-back-link/notebook.ipynb new file mode 100644 index 00000000000..4a8eaaca779 --- /dev/null +++ b/tests/docs/playwright/website/notebook-preview-back-link/notebook.ipynb @@ -0,0 +1,38 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "answer", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| label: answer\n", + "1 + 1" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/integration/playwright/tests/notebook-preview-back-link.spec.ts b/tests/integration/playwright/tests/notebook-preview-back-link.spec.ts new file mode 100644 index 00000000000..916f5784765 --- /dev/null +++ b/tests/integration/playwright/tests/notebook-preview-back-link.spec.ts @@ -0,0 +1,51 @@ +import { expect, Locator, Page, test } from "@playwright/test"; + +// WebKit follows Safari's default of skipping links on Tab; Option+Tab +// visits every focusable element. +async function tabUntilFocused( + page: Page, + browserName: string, + target: Locator, + maxTabs = 25, +): Promise { + const tabKey = browserName === "webkit" ? "Alt+Tab" : "Tab"; + for (let i = 0; i < maxTabs; i++) { + await page.keyboard.press(tabKey); + if (await target.evaluate((el) => el === document.activeElement)) { + return true; + } + } + return false; +} + +// The notebook preview "Back to Article" control must be a keyboard-operable +// link in both website and standalone renders (#15015). +const testCases = [ + { + name: "website", + dir: "./website/notebook-preview-back-link/_site", + }, + { + name: "standalone document", + dir: "./html/notebook-preview-back-link", + }, +]; + +test.describe("Notebook preview back link", () => { + for (const { name, dir } of testCases) { + test(`${name} — Tab and Enter go back to the article`, async ({ page, browserName }) => { + // Open the preview from the article so there is history to go back to. + // The preview is opened without a cell hash so Tab starts at the top + // of the page, where the back link is. + await page.goto(`${dir}/index.html`); + await page.goto(`${dir}/notebook-preview.html`); + + const backLink = page.getByRole("link", { name: "Back to Article" }); + await expect(backLink).toBeVisible(); + expect(await tabUntilFocused(page, browserName, backLink)).toBe(true); + + await page.keyboard.press("Enter"); + await expect(page).toHaveURL(/\/index\.html$/); + }); + } +});