[api-minor] Support Named-actions in the outline (issue 15367)

Apparently this is implemented in e.g. Adobe Reader, and the specification does support it, however it cannot be commonly used in real-world PDF documents since it took over ten years for this feature to be requested.
This commit is contained in:
Jonas Jenwald 2022-08-30 18:40:27 +02:00
parent 86370bd5c5
commit 216b86a082
5 changed files with 38 additions and 2 deletions

View File

@ -302,7 +302,7 @@ class Catalog {
throw new FormatError("Invalid outline item encountered."); throw new FormatError("Invalid outline item encountered.");
} }
const data = { url: null, dest: null }; const data = { url: null, dest: null, action: null };
Catalog.parseDestDictionary({ Catalog.parseDestDictionary({
destDict: outlineDict, destDict: outlineDict,
resultObj: data, resultObj: data,
@ -324,6 +324,7 @@ class Catalog {
} }
const outlineItem = { const outlineItem = {
action: data.action,
dest: data.dest, dest: data.dest,
url: data.url, url: data.url,
unsafeUrl: data.unsafeUrl, unsafeUrl: data.unsafeUrl,

View File

@ -50,6 +50,7 @@
!issue7439.pdf !issue7439.pdf
!issue7847_radial.pdf !issue7847_radial.pdf
!issue14953.pdf !issue14953.pdf
!issue15367.pdf
!issue7446.pdf !issue7446.pdf
!issue7492.pdf !issue7492.pdf
!issue7544.pdf !issue7544.pdf

BIN
test/pdfs/issue15367.pdf Normal file

Binary file not shown.

View File

@ -1535,6 +1535,7 @@ describe("api", function () {
expect(outline.length).toEqual(6); expect(outline.length).toEqual(6);
expect(outline[4]).toEqual({ expect(outline[4]).toEqual({
action: null,
dest: "Händel -- Halle🎆lujah", dest: "Händel -- Halle🎆lujah",
url: null, url: null,
unsafeUrl: undefined, unsafeUrl: undefined,
@ -1550,6 +1551,31 @@ describe("api", function () {
await loadingTask.destroy(); await loadingTask.destroy();
}); });
it("gets outline, with named-actions (issue 15367)", async function () {
const loadingTask = getDocument(buildGetDocumentParams("issue15367.pdf"));
const pdfDoc = await loadingTask.promise;
const outline = await pdfDoc.getOutline();
expect(Array.isArray(outline)).toEqual(true);
expect(outline.length).toEqual(4);
expect(outline[1]).toEqual({
action: "PrevPage",
dest: null,
url: null,
unsafeUrl: undefined,
newWindow: undefined,
title: "Previous Page",
color: new Uint8ClampedArray([0, 0, 0]),
count: undefined,
bold: false,
italic: false,
items: [],
});
await loadingTask.destroy();
});
it("gets outline with non-displayable chars", async function () { it("gets outline with non-displayable chars", async function () {
const loadingTask = getDocument(buildGetDocumentParams("issue14267.pdf")); const loadingTask = getDocument(buildGetDocumentParams("issue14267.pdf"));
const pdfDoc = await loadingTask.promise; const pdfDoc = await loadingTask.promise;

View File

@ -109,13 +109,21 @@ class PDFOutlineViewer extends BaseTreeViewer {
/** /**
* @private * @private
*/ */
_bindLink(element, { url, newWindow, dest }) { _bindLink(element, { url, newWindow, action, dest }) {
const { linkService } = this; const { linkService } = this;
if (url) { if (url) {
linkService.addLinkAttributes(element, url, newWindow); linkService.addLinkAttributes(element, url, newWindow);
return; return;
} }
if (action) {
element.href = linkService.getAnchorUrl("");
element.onclick = () => {
linkService.executeNamedAction(action);
return false;
};
return;
}
element.href = linkService.getDestinationHash(dest); element.href = linkService.getDestinationHash(dest);
element.onclick = evt => { element.onclick = evt => {