Merge pull request #20746 from calixteman/bug2019714

Fix tooltips on thumbnails and checkbox (bug 2019714)
This commit is contained in:
calixteman 2026-02-27 18:20:37 +01:00 committed by GitHub
commit bd260b2d15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
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"