Skip to content

Commit 95f62f3

Browse files
Merge pull request #20580 from calixteman/reorg_link_outline
Fix links and outline after reorganizing a pdf
2 parents 23c7b1a + 43bd7fa commit 95f62f3

File tree

4 files changed

+89
-10
lines changed

4 files changed

+89
-10
lines changed

test/integration/reorganize_pages_spec.mjs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ import {
1919
closePages,
2020
createPromise,
2121
dragAndDrop,
22+
getAnnotationSelector,
2223
getRect,
2324
getThumbnailSelector,
2425
loadAndWait,
26+
scrollIntoView,
2527
waitForDOMMutation,
2628
} from "./test_utils.mjs";
2729

@@ -415,4 +417,73 @@ describe("Reorganize Pages View", () => {
415417
);
416418
});
417419
});
420+
421+
describe("Links and outlines", () => {
422+
let pages;
423+
424+
beforeEach(async () => {
425+
pages = await loadAndWait(
426+
"page_with_number_and_link.pdf",
427+
"#viewsManagerToggleButton",
428+
"page-fit",
429+
null,
430+
{ enableSplitMerge: true }
431+
);
432+
});
433+
434+
afterEach(async () => {
435+
await closePages(pages);
436+
});
437+
438+
it("should check that link is updated after moving pages", async () => {
439+
await Promise.all(
440+
pages.map(async ([browserName, page]) => {
441+
await waitForThumbnailVisible(page, 1);
442+
await movePages(page, [2], 10);
443+
await scrollIntoView(page, getAnnotationSelector("107R"));
444+
await page.click(getAnnotationSelector("107R"));
445+
await page.waitForSelector(
446+
".page[data-page-number='10'] + .page[data-page-number='2']",
447+
{
448+
visible: true,
449+
}
450+
);
451+
452+
const currentPage = await page.$eval(
453+
"#pageNumber",
454+
el => el.valueAsNumber
455+
);
456+
expect(currentPage).withContext(`In ${browserName}`).toBe(10);
457+
})
458+
);
459+
});
460+
461+
it("should check that outlines are updated after moving pages", async () => {
462+
await Promise.all(
463+
pages.map(async ([browserName, page]) => {
464+
await waitForThumbnailVisible(page, 1);
465+
await movePages(page, [2, 4], 10);
466+
467+
await page.click("#viewsManagerSelectorButton");
468+
await page.click("#outlinesViewMenu");
469+
await page.waitForSelector("#outlinesView", { visible: true });
470+
471+
await page.click("#outlinesView .treeItem:nth-child(2)");
472+
await page.waitForSelector(
473+
".page[data-page-number='10'] + .page[data-page-number='2']",
474+
{
475+
visible: true,
476+
}
477+
);
478+
479+
const currentPage = await page.$eval(
480+
"#pageNumber",
481+
el => el.valueAsNumber
482+
);
483+
// 9 because 2 and 4 were moved after page 10.
484+
expect(currentPage).withContext(`In ${browserName}`).toBe(9);
485+
})
486+
);
487+
});
488+
});
418489
});

test/pdfs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,3 +869,4 @@
869869
!bomb_giant.pdf
870870
!bug2009627.pdf
871871
!page_with_number.pdf
872+
!page_with_number_and_link.pdf
70.1 KB
Binary file not shown.

web/pdf_link_service.js

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
/** @typedef {import("./event_utils").EventBus} EventBus */
1717
/** @typedef {import("./interfaces").IPDFLinkService} IPDFLinkService */
1818

19+
import { PagesMapper, parseQueryString } from "./ui_utils.js";
1920
import { isValidExplicitDest } from "pdfjs-lib";
20-
import { parseQueryString } from "./ui_utils.js";
2121

2222
const DEFAULT_LINK_REL = "noopener noreferrer nofollow";
2323

@@ -50,6 +50,8 @@ const LinkTarget = {
5050
class PDFLinkService {
5151
externalLinkEnabled = true;
5252

53+
#pagesMapper = PagesMapper.instance;
54+
5355
/**
5456
* @param {PDFLinkServiceOptions} options
5557
*/
@@ -138,7 +140,7 @@ class PDFLinkService {
138140
if (!this.pdfDocument) {
139141
return;
140142
}
141-
let namedDest, explicitDest, pageNumber;
143+
let namedDest, explicitDest, pageId;
142144
if (typeof dest === "string") {
143145
namedDest = dest;
144146
explicitDest = await this.pdfDocument.getDestination(dest);
@@ -156,13 +158,13 @@ class PDFLinkService {
156158
const [destRef] = explicitDest;
157159

158160
if (destRef && typeof destRef === "object") {
159-
pageNumber = this.pdfDocument.cachedPageNumber(destRef);
161+
pageId = this.pdfDocument.cachedPageNumber(destRef);
160162

161-
if (!pageNumber) {
163+
if (!pageId) {
162164
// Fetch the page reference if it's not yet available. This could
163165
// only occur during loading, before all pages have been resolved.
164166
try {
165-
pageNumber = (await this.pdfDocument.getPageIndex(destRef)) + 1;
167+
pageId = (await this.pdfDocument.getPageIndex(destRef)) + 1;
166168
} catch {
167169
console.error(
168170
`goToDestination: "${destRef}" is not a valid page reference, for dest="${dest}".`
@@ -171,20 +173,25 @@ class PDFLinkService {
171173
}
172174
}
173175
} else if (Number.isInteger(destRef)) {
174-
pageNumber = destRef + 1;
176+
pageId = destRef + 1;
175177
}
176-
if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {
178+
if (!pageId || pageId < 1 || pageId > this.pagesCount) {
177179
console.error(
178-
`goToDestination: "${pageNumber}" is not a valid page number, for dest="${dest}".`
180+
`goToDestination: "${pageId}" is not a valid page number, for dest="${dest}".`
179181
);
180182
return;
181183
}
182184

185+
const pageNumber = this.#pagesMapper.getPageNumber(pageId);
186+
if (pageNumber === null) {
187+
return;
188+
}
189+
183190
if (this.pdfHistory) {
184191
// Update the browser history before scrolling the new destination into
185192
// view, to be able to accurately capture the current document position.
186193
this.pdfHistory.pushCurrentPosition();
187-
this.pdfHistory.push({ namedDest, explicitDest, pageNumber });
194+
this.pdfHistory.push({ namedDest, explicitDest, pageNumber: pageId });
188195
}
189196

190197
this.pdfViewer.scrollPageIntoView({
@@ -197,7 +204,7 @@ class PDFLinkService {
197204
this.eventBus._on(
198205
"textlayerrendered",
199206
evt => {
200-
if (evt.pageNumber === pageNumber) {
207+
if (evt.pageNumber === pageId) {
201208
evt.source.textLayer.div.focus();
202209
ac.abort();
203210
}

0 commit comments

Comments
 (0)