Fix tooltips on thumbnails and checkbox (bug 2019714)

And fix an issue with some integration tests where the manage button was disabled (hence not in the tab cycle).
This commit is contained in:
Calixte Denizet 2026-02-26 19:13:45 +01:00
parent 45b0f8b05e
commit aa928105b4
No known key found for this signature in database
GPG Key ID: 0C5442631EE0691F
5 changed files with 58 additions and 40 deletions

View File

@ -192,8 +192,9 @@ pdfjs-additional-layers = Additional Layers
# Variables: # Variables:
# $page (Number) - the page number # $page (Number) - the page number
pdfjs-thumb-page-title = # $total (Number) - the number of pages
.title = Page { $page } pdfjs-thumb-page-title1 =
.title = Page { $page } of { $total }
# Variables: # Variables:
# $page (Number) - the page number # $page (Number) - the page number
@ -202,8 +203,8 @@ pdfjs-thumb-page-canvas =
# Variables: # Variables:
# $page (Number) - the page number # $page (Number) - the page number
pdfjs-thumb-page-checkbox = pdfjs-thumb-page-checkbox1 =
.aria-label = Select page { $page } .title = Select page { $page }
## Find panel button title and messages ## Find panel button title and messages
@ -690,11 +691,11 @@ pdfjs-editor-add-comment-button =
## - layers. ## - layers.
## The thumbnails view is used to edit the pdf: remove/insert pages, ... ## The thumbnails view is used to edit the pdf: remove/insert pages, ...
pdfjs-toggle-views-manager-button = pdfjs-toggle-views-manager-button1 =
.title = Toggle Sidebar .title = Manage pages
pdfjs-toggle-views-manager-notification-button = pdfjs-toggle-views-manager-notification-button =
.title = Toggle Sidebar (document contains thumbnails/outline/attachments/layers) .title = Toggle Sidebar (document contains thumbnails/outline/attachments/layers)
pdfjs-toggle-views-manager-button-label = Toggle Sidebar pdfjs-toggle-views-manager-button1-label = Manage pages
pdfjs-views-manager-sidebar = pdfjs-views-manager-sidebar =
.aria-label = Sidebar .aria-label = Sidebar

View File

@ -262,7 +262,7 @@ function getAnnotationSelector(id) {
} }
function getThumbnailSelector(pageNumber) { function getThumbnailSelector(pageNumber) {
return `.thumbnailImageContainer[data-l10n-args='{"page":${pageNumber}}']`; return `.thumbnailImageContainer[data-l10n-args^='{"page":${pageNumber}']`;
} }
async function getSpanRectFromText(page, pageNumber, text) { async function getSpanRectFromText(page, pageNumber, text) {
@ -645,6 +645,7 @@ function waitForEditorMovedInDOM(page) {
} }
async function scrollIntoView(page, selector) { async function scrollIntoView(page, selector) {
await page.waitForSelector(selector, { visible: true });
const handle = await page.evaluateHandle( const handle = await page.evaluateHandle(
sel => [ sel => [
new Promise(resolve => { new Promise(resolve => {
@ -982,6 +983,9 @@ async function showViewsManager(page) {
"#outerContainer:not(.viewsManagerMoving).viewsManagerOpen", "#outerContainer:not(.viewsManagerMoving).viewsManagerOpen",
{ visible: true } { visible: true }
); );
await page.waitForSelector("#viewsManagerStatusActionButton:not(:disabled)", {
visible: true,
});
} }
// Unicode bidi isolation characters, Fluent adds these markers to the text. // Unicode bidi isolation characters, Fluent adds these markers to the text.

View File

@ -2,6 +2,7 @@ import {
awaitPromise, awaitPromise,
closePages, closePages,
FSI, FSI,
getThumbnailSelector,
kbFocusNext, kbFocusNext,
loadAndWait, loadAndWait,
PDI, PDI,
@ -9,10 +10,7 @@ import {
} from "./test_utils.mjs"; } from "./test_utils.mjs";
function waitForThumbnailVisible(page, pageNum) { function waitForThumbnailVisible(page, pageNum) {
return page.waitForSelector( return page.waitForSelector(getThumbnailSelector(pageNum), { visible: true });
`.thumbnailImageContainer[data-l10n-args='{"page":${pageNum}}']`,
{ visible: true }
);
} }
async function waitForMenu(page, buttonSelector, visible = true) { async function waitForMenu(page, buttonSelector, visible = true) {
@ -56,6 +54,14 @@ describe("PDF Thumbnail View", () => {
await page.waitForSelector(`${thumbSelector}[src^="blob:http:"]`, { await page.waitForSelector(`${thumbSelector}[src^="blob:http:"]`, {
visible: true, visible: true,
}); });
const title = await page.$eval(
getThumbnailSelector(1),
el => el.title
);
expect(title)
.withContext(`In ${browserName}`)
.toBe(`Page ${FSI}1${PDI} of ${FSI}14${PDI}`);
}) })
); );
}); });
@ -110,7 +116,7 @@ describe("PDF Thumbnail View", () => {
for (const pageNum of [14, 1, 13, 2]) { for (const pageNum of [14, 1, 13, 2]) {
await goToPage(page, pageNum); await goToPage(page, pageNum);
const thumbSelector = `.thumbnailImageContainer[data-l10n-args='{"page":${pageNum}}']`; const thumbSelector = getThumbnailSelector(pageNum);
await page.waitForSelector( await page.waitForSelector(
`.thumbnail ${thumbSelector}[aria-current="page"]`, `.thumbnail ${thumbSelector}[aria-current="page"]`,
{ visible: true } { visible: true }
@ -158,26 +164,25 @@ describe("PDF Thumbnail View", () => {
await kbFocusNext(page); await kbFocusNext(page);
await page.waitForSelector( await page.waitForSelector(
`#thumbnailsView .thumbnailImageContainer[data-l10n-args='{"page":1}']:focus`, `#thumbnailsView ${getThumbnailSelector(1)}:focus`,
{ visible: true } { visible: true }
); );
await page.keyboard.press("ArrowDown"); await page.keyboard.press("ArrowDown");
await page.waitForSelector( await page.waitForSelector(
`#thumbnailsView .thumbnailImageContainer[data-l10n-args='{"page":2}']:focus`, `#thumbnailsView ${getThumbnailSelector(2)}:focus`,
{ visible: true } { visible: true }
); );
await page.keyboard.press("ArrowUp"); await page.keyboard.press("ArrowUp");
await page.waitForSelector( await page.waitForSelector(`${getThumbnailSelector(1)}:focus`, {
`#thumbnailsView .thumbnailImageContainer[data-l10n-args='{"page":1}']:focus`, visible: true,
{ visible: true } });
);
await page.keyboard.press("ArrowDown"); await page.keyboard.press("ArrowDown");
await page.keyboard.press("ArrowDown"); await page.keyboard.press("ArrowDown");
await page.waitForSelector( await page.waitForSelector(
`#thumbnailsView .thumbnailImageContainer[data-l10n-args='{"page":3}']:focus`, `#thumbnailsView ${getThumbnailSelector(3)}:focus`,
{ visible: true } { visible: true }
); );
@ -190,13 +195,13 @@ describe("PDF Thumbnail View", () => {
await page.keyboard.press("End"); await page.keyboard.press("End");
await page.waitForSelector( await page.waitForSelector(
`#thumbnailsView .thumbnailImageContainer[data-l10n-args='{"page":14}']:focus`, `#thumbnailsView ${getThumbnailSelector(14)}:focus`,
{ visible: true } { visible: true }
); );
await page.keyboard.press("Home"); await page.keyboard.press("Home");
await page.waitForSelector( await page.waitForSelector(
`#thumbnailsView .thumbnailImageContainer[data-l10n-args='{"page":1}']:focus`, `#thumbnailsView ${getThumbnailSelector(1)}:focus`,
{ visible: true } { visible: true }
); );
}) })
@ -322,17 +327,17 @@ describe("PDF Thumbnail View", () => {
await closePages(pages); await closePages(pages);
}); });
it("should have accessible label on checkbox", async () => { it("should have a title on the checkbox", async () => {
await Promise.all( await Promise.all(
pages.map(async ([browserName, page]) => { pages.map(async ([browserName, page]) => {
await showViewsManager(page); await showViewsManager(page);
await waitForThumbnailVisible(page, 1); await waitForThumbnailVisible(page, 1);
const ariaLabel = await page.$eval( const title = await page.$eval(
`.thumbnail[page-number="1"] input[type="checkbox"]`, `.thumbnail[page-number="1"] input[type="checkbox"]`,
el => el.getAttribute("aria-label") el => el.title
); );
expect(ariaLabel) expect(title)
.withContext(`In ${browserName}`) .withContext(`In ${browserName}`)
.toBe(`Select page ${FSI}1${PDI}`); .toBe(`Select page ${FSI}1${PDI}`);
}) })
@ -478,10 +483,9 @@ describe("PDF Thumbnail View", () => {
await kbFocusNext(page); await kbFocusNext(page);
// Verify we're on the first thumbnail // Verify we're on the first thumbnail
await page.waitForSelector( await page.waitForSelector(`${getThumbnailSelector(1)}:focus`, {
`#thumbnailsView .thumbnailImageContainer[data-l10n-args='{"page":1}']:focus`, visible: true,
{ visible: true } });
);
// Tab to checkbox // Tab to checkbox
await kbFocusNext(page); await kbFocusNext(page);

View File

@ -131,6 +131,8 @@ class PDFThumbnailView extends RenderableView {
imageContainer.tabIndex = -1; imageContainer.tabIndex = -1;
imageContainer.draggable = false; imageContainer.draggable = false;
imageContainer.setAttribute("page-number", id); imageContainer.setAttribute("page-number", id);
imageContainer.setAttribute("data-l10n-id", "pdfjs-thumb-page-title1");
imageContainer.setAttribute("data-l10n-args", this.#getPageL10nArgs(true));
const image = (this.image = document.createElement("img")); const image = (this.image = document.createElement("img"));
imageContainer.append(image); imageContainer.append(image);
@ -139,8 +141,8 @@ class PDFThumbnailView extends RenderableView {
const checkbox = (this.checkbox = document.createElement("input")); const checkbox = (this.checkbox = document.createElement("input"));
checkbox.type = "checkbox"; checkbox.type = "checkbox";
checkbox.tabIndex = -1; checkbox.tabIndex = -1;
checkbox.setAttribute("data-l10n-id", "pdfjs-thumb-page-checkbox"); checkbox.setAttribute("data-l10n-id", "pdfjs-thumb-page-checkbox1");
checkbox.setAttribute("data-l10n-args", this.#pageL10nArgs); checkbox.setAttribute("data-l10n-args", this.#getPageL10nArgs());
thumbnailContainer.append(checkbox); thumbnailContainer.append(checkbox);
this.pasteButton = null; this.pasteButton = null;
} }
@ -331,8 +333,8 @@ class PDFThumbnailView extends RenderableView {
reducedCanvas.toBlob(resolve); reducedCanvas.toBlob(resolve);
const blob = await promise; const blob = await promise;
image.src = URL.createObjectURL(blob); image.src = URL.createObjectURL(blob);
imageContainer.setAttribute("data-l10n-id", "pdfjs-thumb-page-canvas"); image.setAttribute("data-l10n-id", "pdfjs-thumb-page-canvas");
imageContainer.setAttribute("data-l10n-args", this.#pageL10nArgs); image.setAttribute("data-l10n-args", this.#getPageL10nArgs());
imageContainer.classList.remove("missingThumbnailImage"); imageContainer.classList.remove("missingThumbnailImage");
if (!FeatureTest.isOffscreenCanvasSupported) { if (!FeatureTest.isOffscreenCanvasSupported) {
// Clean up the canvas element since it is no longer needed. // Clean up the canvas element since it is no longer needed.
@ -525,8 +527,11 @@ class PDFThumbnailView extends RenderableView {
return canvas; return canvas;
} }
get #pageL10nArgs() { #getPageL10nArgs(hasTotal = false) {
return JSON.stringify({ page: this.pageLabel ?? this.id }); return JSON.stringify({
page: this.pageLabel ?? this.id,
total: hasTotal ? this.linkService.pagesCount : undefined,
});
} }
/** /**
@ -534,8 +539,12 @@ class PDFThumbnailView extends RenderableView {
*/ */
setPageLabel(label) { setPageLabel(label) {
this.pageLabel = typeof label === "string" ? label : null; this.pageLabel = typeof label === "string" ? label : null;
this.imageContainer.setAttribute("data-l10n-args", this.#pageL10nArgs); this.imageContainer.setAttribute(
this.checkbox?.setAttribute("data-l10n-args", this.#pageL10nArgs); "data-l10n-args",
this.#getPageL10nArgs(true)
);
this.image.setAttribute("data-l10n-args", this.#getPageL10nArgs());
this.checkbox?.setAttribute("data-l10n-args", this.#getPageL10nArgs());
} }
} }

View File

@ -111,12 +111,12 @@ See https://github.com/adobe-type-tools/cmap-resources
class="toolbarButton" class="toolbarButton"
type="button" type="button"
tabindex="0" tabindex="0"
data-l10n-id="pdfjs-toggle-views-manager-button" data-l10n-id="pdfjs-toggle-views-manager-button1"
aria-expanded="false" aria-expanded="false"
aria-haspopup="true" aria-haspopup="true"
aria-controls="viewsManager" aria-controls="viewsManager"
> >
<span data-l10n-id="pdfjs-toggle-views-manager-button-label"></span> <span data-l10n-id="pdfjs-toggle-views-manager-button1-label"></span>
</button> </button>
<div <div
id="viewsManager" id="viewsManager"