From f9b857463be40304c1745d7f2109c2cd499eb271 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Wed, 3 Dec 2025 15:51:34 +0100 Subject: [PATCH] Use HTMLElement.scrollIntoView when showing a thumbnail --- test/integration/thumbnail_view_spec.mjs | 50 +++++++++++++++++++++++- web/pdf_thumbnail_viewer.js | 9 +++-- web/viewer.css | 1 + 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/test/integration/thumbnail_view_spec.mjs b/test/integration/thumbnail_view_spec.mjs index 428813604..0dae8eecf 100644 --- a/test/integration/thumbnail_view_spec.mjs +++ b/test/integration/thumbnail_view_spec.mjs @@ -1,4 +1,4 @@ -import { closePages, loadAndWait } from "./test_utils.mjs"; +import { awaitPromise, closePages, loadAndWait } from "./test_utils.mjs"; describe("PDF Thumbnail View", () => { describe("Works without errors", () => { @@ -32,4 +32,52 @@ describe("PDF Thumbnail View", () => { ); }); }); + + describe("The view is scrolled correctly", () => { + let pages; + + beforeEach(async () => { + pages = await loadAndWait("tracemonkey.pdf", "#sidebarToggleButton"); + }); + + afterEach(async () => { + await closePages(pages); + }); + + async function goToPage(page, number) { + const handle = await page.evaluateHandle( + num => [ + new Promise(resolve => { + const container = document.getElementById("thumbnailView"); + container.addEventListener("scrollend", resolve, { once: true }); + // eslint-disable-next-line no-undef + PDFViewerApplication.pdfLinkService.goToPage(num); + }), + ], + number + ); + return awaitPromise(handle); + } + + it("should scroll the view", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await page.click("#sidebarToggleButton"); + + for (const pageNum of [14, 1, 13, 2]) { + await goToPage(page, pageNum); + const thumbSelector = `.thumbnailImage[data-l10n-args='{"page":${pageNum}}']`; + await page.waitForSelector( + `.thumbnail:has(${thumbSelector}).selected`, + { visible: true } + ); + const src = await page.$eval(thumbSelector, el => el.src); + expect(src) + .withContext(`In ${browserName}`) + .toMatch(/^blob:http:/); + } + }) + ); + }); + }); }); diff --git a/web/pdf_thumbnail_viewer.js b/web/pdf_thumbnail_viewer.js index 2079b641b..46b7192fc 100644 --- a/web/pdf_thumbnail_viewer.js +++ b/web/pdf_thumbnail_viewer.js @@ -24,13 +24,16 @@ import { getVisibleElements, isValidRotation, RenderingStates, - scrollIntoView, watchScroll, } from "./ui_utils.js"; import { PDFThumbnailView } from "./pdf_thumbnail_view.js"; -const THUMBNAIL_SCROLL_MARGIN = -19; const THUMBNAIL_SELECTED_CLASS = "selected"; +const SCROLL_OPTIONS = { + behavior: "instant", + container: "nearest", + block: "nearest", +}; /** * @typedef {Object} PDFThumbnailViewerOptions @@ -139,7 +142,7 @@ class PDFThumbnailViewer { } } if (shouldScroll) { - scrollIntoView(thumbnailView.div, { top: THUMBNAIL_SCROLL_MARGIN }); + thumbnailView.div.scrollIntoView(SCROLL_OPTIONS); } } diff --git a/web/viewer.css b/web/viewer.css index 896b91a5a..d2ef9366d 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -729,6 +729,7 @@ body { height: auto; > .thumbnail { + scroll-margin-block: 19px; width: var(--thumbnail-width); margin: 0 10px 5px; padding: 1px;