Merge pull request #11644 from Snuffleupagus/openAction
[api-minor] Add more general OpenAction support (PR 10334 follow-up, issue 11642)
This commit is contained in:
commit
aa3e5a2b8f
@ -592,9 +592,12 @@ class Catalog {
|
|||||||
return shadow(this, "viewerPreferences", prefs);
|
return shadow(this, "viewerPreferences", prefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
get openActionDestination() {
|
/**
|
||||||
|
* NOTE: "JavaScript" actions are, for now, handled by `get javaScript` below.
|
||||||
|
*/
|
||||||
|
get openAction() {
|
||||||
const obj = this.catDict.get("OpenAction");
|
const obj = this.catDict.get("OpenAction");
|
||||||
let openActionDest = null;
|
let openAction = null;
|
||||||
|
|
||||||
if (isDict(obj)) {
|
if (isDict(obj)) {
|
||||||
// Convert the OpenAction dictionary into a format that works with
|
// Convert the OpenAction dictionary into a format that works with
|
||||||
@ -602,16 +605,27 @@ class Catalog {
|
|||||||
const destDict = new Dict(this.xref);
|
const destDict = new Dict(this.xref);
|
||||||
destDict.set("A", obj);
|
destDict.set("A", obj);
|
||||||
|
|
||||||
const resultObj = { url: null, dest: null };
|
const resultObj = { url: null, dest: null, action: null };
|
||||||
Catalog.parseDestDictionary({ destDict, resultObj });
|
Catalog.parseDestDictionary({ destDict, resultObj });
|
||||||
|
|
||||||
if (Array.isArray(resultObj.dest)) {
|
if (Array.isArray(resultObj.dest)) {
|
||||||
openActionDest = resultObj.dest;
|
if (!openAction) {
|
||||||
|
openAction = Object.create(null);
|
||||||
|
}
|
||||||
|
openAction.dest = resultObj.dest;
|
||||||
|
} else if (resultObj.action) {
|
||||||
|
if (!openAction) {
|
||||||
|
openAction = Object.create(null);
|
||||||
|
}
|
||||||
|
openAction.action = resultObj.action;
|
||||||
}
|
}
|
||||||
} else if (Array.isArray(obj)) {
|
} else if (Array.isArray(obj)) {
|
||||||
openActionDest = obj;
|
if (!openAction) {
|
||||||
|
openAction = Object.create(null);
|
||||||
|
}
|
||||||
|
openAction.dest = obj;
|
||||||
}
|
}
|
||||||
return shadow(this, "openActionDestination", openActionDest);
|
return shadow(this, "openAction", openAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
get attachments() {
|
get attachments() {
|
||||||
@ -668,27 +682,10 @@ class Catalog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append OpenAction actions to the JavaScript array.
|
// Append OpenAction "JavaScript" actions to the JavaScript array.
|
||||||
const openActionDict = this.catDict.get("OpenAction");
|
const openAction = this.catDict.get("OpenAction");
|
||||||
if (
|
if (isDict(openAction) && isName(openAction.get("S"), "JavaScript")) {
|
||||||
isDict(openActionDict) &&
|
appendIfJavaScriptDict(openAction);
|
||||||
(isName(openActionDict.get("Type"), "Action") ||
|
|
||||||
!openActionDict.has("Type"))
|
|
||||||
) {
|
|
||||||
const actionType = openActionDict.get("S");
|
|
||||||
if (isName(actionType, "Named")) {
|
|
||||||
// The named Print action is not a part of the PDF 1.7 specification,
|
|
||||||
// but is supported by many PDF readers/writers (including Adobe's).
|
|
||||||
const action = openActionDict.get("N");
|
|
||||||
if (isName(action, "Print")) {
|
|
||||||
if (!javaScript) {
|
|
||||||
javaScript = [];
|
|
||||||
}
|
|
||||||
javaScript.push("print({});");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
appendIfJavaScriptDict(openActionDict);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return shadow(this, "javaScript", javaScript);
|
return shadow(this, "javaScript", javaScript);
|
||||||
|
@ -458,8 +458,8 @@ var WorkerMessageHandler = {
|
|||||||
return pdfManager.ensureCatalog("viewerPreferences");
|
return pdfManager.ensureCatalog("viewerPreferences");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetOpenActionDestination", function(data) {
|
handler.on("GetOpenAction", function(data) {
|
||||||
return pdfManager.ensureCatalog("openActionDestination");
|
return pdfManager.ensureCatalog("openAction");
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetAttachments", function wphSetupGetAttachments(data) {
|
handler.on("GetAttachments", function wphSetupGetAttachments(data) {
|
||||||
|
@ -668,11 +668,18 @@ class PDFDocumentProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise} A promise that is resolved with an {Array} containing
|
* @returns {Promise} A promise that is resolved with an {Object} containing
|
||||||
* the destination, or `null` when no open action is present in the PDF.
|
* the currently supported actions, or `null` when no OpenAction exists.
|
||||||
*/
|
*/
|
||||||
|
getOpenAction() {
|
||||||
|
return this._transport.getOpenAction();
|
||||||
|
}
|
||||||
|
|
||||||
getOpenActionDestination() {
|
getOpenActionDestination() {
|
||||||
return this._transport.getOpenActionDestination();
|
deprecated("getOpenActionDestination, use getOpenAction instead.");
|
||||||
|
return this.getOpenAction().then(function(openAction) {
|
||||||
|
return openAction && openAction.dest ? openAction.dest : null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2518,11 +2525,8 @@ class WorkerTransport {
|
|||||||
return this.messageHandler.sendWithPromise("GetViewerPreferences", null);
|
return this.messageHandler.sendWithPromise("GetViewerPreferences", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOpenActionDestination() {
|
getOpenAction() {
|
||||||
return this.messageHandler.sendWithPromise(
|
return this.messageHandler.sendWithPromise("GetOpenAction", null);
|
||||||
"GetOpenActionDestination",
|
|
||||||
null
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAttachments() {
|
getAttachments() {
|
||||||
|
@ -863,29 +863,69 @@ describe("api", function() {
|
|||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("gets default open action destination", function(done) {
|
it("gets default open action", function(done) {
|
||||||
var loadingTask = getDocument(buildGetDocumentParams("tracemonkey.pdf"));
|
var loadingTask = getDocument(buildGetDocumentParams("tracemonkey.pdf"));
|
||||||
|
|
||||||
loadingTask.promise
|
loadingTask.promise
|
||||||
.then(function(pdfDocument) {
|
.then(function(pdfDocument) {
|
||||||
return pdfDocument.getOpenActionDestination();
|
return pdfDocument.getOpenAction();
|
||||||
})
|
})
|
||||||
.then(function(dest) {
|
.then(function(openAction) {
|
||||||
expect(dest).toEqual(null);
|
expect(openAction).toEqual(null);
|
||||||
|
|
||||||
loadingTask.destroy().then(done);
|
loadingTask.destroy().then(done);
|
||||||
})
|
})
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
it("gets non-default open action destination", function(done) {
|
it("gets non-default open action (with destination)", function(done) {
|
||||||
doc
|
doc
|
||||||
.getOpenActionDestination()
|
.getOpenAction()
|
||||||
.then(function(dest) {
|
.then(function(openAction) {
|
||||||
expect(dest).toEqual([{ num: 15, gen: 0 }, { name: "FitH" }, null]);
|
expect(openAction.dest).toEqual([
|
||||||
|
{ num: 15, gen: 0 },
|
||||||
|
{ name: "FitH" },
|
||||||
|
null,
|
||||||
|
]);
|
||||||
|
expect(openAction.action).toBeUndefined();
|
||||||
|
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
it("gets non-default open action (with Print action)", function(done) {
|
||||||
|
// PDF document with "Print" Named action in the OpenAction dictionary.
|
||||||
|
const loadingTask1 = getDocument(
|
||||||
|
buildGetDocumentParams("bug1001080.pdf")
|
||||||
|
);
|
||||||
|
// PDF document with "Print" Named action in the OpenAction dictionary,
|
||||||
|
// but the OpenAction dictionary is missing the `Type` entry.
|
||||||
|
const loadingTask2 = getDocument(
|
||||||
|
buildGetDocumentParams("issue11442_reduced.pdf")
|
||||||
|
);
|
||||||
|
|
||||||
|
const promise1 = loadingTask1.promise
|
||||||
|
.then(function(pdfDocument) {
|
||||||
|
return pdfDocument.getOpenAction();
|
||||||
|
})
|
||||||
|
.then(function(openAction) {
|
||||||
|
expect(openAction.dest).toBeUndefined();
|
||||||
|
expect(openAction.action).toEqual("Print");
|
||||||
|
|
||||||
|
return loadingTask1.destroy();
|
||||||
|
});
|
||||||
|
const promise2 = loadingTask2.promise
|
||||||
|
.then(function(pdfDocument) {
|
||||||
|
return pdfDocument.getOpenAction();
|
||||||
|
})
|
||||||
|
.then(function(openAction) {
|
||||||
|
expect(openAction.dest).toBeUndefined();
|
||||||
|
expect(openAction.action).toEqual("Print");
|
||||||
|
|
||||||
|
return loadingTask2.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
Promise.all([promise1, promise2]).then(done, done.fail);
|
||||||
|
});
|
||||||
|
|
||||||
it("gets non-existent attachments", function(done) {
|
it("gets non-existent attachments", function(done) {
|
||||||
var promise = doc.getAttachments();
|
var promise = doc.getAttachments();
|
||||||
@ -923,37 +963,6 @@ describe("api", function() {
|
|||||||
})
|
})
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
it("gets javascript with printing instructions (Print action)", function(done) {
|
|
||||||
// PDF document with "Print" Named action in the OpenAction dictionary.
|
|
||||||
var loadingTask = getDocument(buildGetDocumentParams("bug1001080.pdf"));
|
|
||||||
var promise = loadingTask.promise.then(function(doc) {
|
|
||||||
return doc.getJavaScript();
|
|
||||||
});
|
|
||||||
promise
|
|
||||||
.then(function(data) {
|
|
||||||
expect(data).toEqual(["print({});"]);
|
|
||||||
expect(data[0]).toMatch(AutoPrintRegExp);
|
|
||||||
loadingTask.destroy().then(done);
|
|
||||||
})
|
|
||||||
.catch(done.fail);
|
|
||||||
});
|
|
||||||
it("gets javascript with printing instructions (Print action without type)", function(done) {
|
|
||||||
// PDF document with "Print" Named action in the OpenAction dictionary,
|
|
||||||
// but the OpenAction dictionary is missing the `Type` entry.
|
|
||||||
var loadingTask = getDocument(
|
|
||||||
buildGetDocumentParams("issue11442_reduced.pdf")
|
|
||||||
);
|
|
||||||
var promise = loadingTask.promise.then(function(doc) {
|
|
||||||
return doc.getJavaScript();
|
|
||||||
});
|
|
||||||
promise
|
|
||||||
.then(function(data) {
|
|
||||||
expect(data).toEqual(["print({});"]);
|
|
||||||
expect(data[0]).toMatch(AutoPrintRegExp);
|
|
||||||
loadingTask.destroy().then(done);
|
|
||||||
})
|
|
||||||
.catch(done.fail);
|
|
||||||
});
|
|
||||||
it("gets javascript with printing instructions (JS action)", function(done) {
|
it("gets javascript with printing instructions (JS action)", function(done) {
|
||||||
// PDF document with "JavaScript" action in the OpenAction dictionary.
|
// PDF document with "JavaScript" action in the OpenAction dictionary.
|
||||||
var loadingTask = getDocument(buildGetDocumentParams("issue6106.pdf"));
|
var loadingTask = getDocument(buildGetDocumentParams("issue6106.pdf"));
|
||||||
|
52
web/app.js
52
web/app.js
@ -1033,11 +1033,9 @@ const PDFViewerApplication = {
|
|||||||
const pageModePromise = pdfDocument.getPageMode().catch(function() {
|
const pageModePromise = pdfDocument.getPageMode().catch(function() {
|
||||||
/* Avoid breaking initial rendering; ignoring errors. */
|
/* Avoid breaking initial rendering; ignoring errors. */
|
||||||
});
|
});
|
||||||
const openActionDestPromise = pdfDocument
|
const openActionPromise = pdfDocument.getOpenAction().catch(function() {
|
||||||
.getOpenActionDestination()
|
/* Avoid breaking initial rendering; ignoring errors. */
|
||||||
.catch(function() {
|
});
|
||||||
/* Avoid breaking initial rendering; ignoring errors. */
|
|
||||||
});
|
|
||||||
|
|
||||||
this.toolbar.setPagesCount(pdfDocument.numPages, false);
|
this.toolbar.setPagesCount(pdfDocument.numPages, false);
|
||||||
this.secondaryToolbar.setPagesCount(pdfDocument.numPages);
|
this.secondaryToolbar.setPagesCount(pdfDocument.numPages);
|
||||||
@ -1085,7 +1083,7 @@ const PDFViewerApplication = {
|
|||||||
storePromise,
|
storePromise,
|
||||||
pageLayoutPromise,
|
pageLayoutPromise,
|
||||||
pageModePromise,
|
pageModePromise,
|
||||||
openActionDestPromise,
|
openActionPromise,
|
||||||
])
|
])
|
||||||
.then(
|
.then(
|
||||||
async ([
|
async ([
|
||||||
@ -1093,14 +1091,14 @@ const PDFViewerApplication = {
|
|||||||
values = {},
|
values = {},
|
||||||
pageLayout,
|
pageLayout,
|
||||||
pageMode,
|
pageMode,
|
||||||
openActionDest,
|
openAction,
|
||||||
]) => {
|
]) => {
|
||||||
const viewOnLoad = AppOptions.get("viewOnLoad");
|
const viewOnLoad = AppOptions.get("viewOnLoad");
|
||||||
|
|
||||||
this._initializePdfHistory({
|
this._initializePdfHistory({
|
||||||
fingerprint: pdfDocument.fingerprint,
|
fingerprint: pdfDocument.fingerprint,
|
||||||
viewOnLoad,
|
viewOnLoad,
|
||||||
initialDest: openActionDest,
|
initialDest: openAction && openAction.dest,
|
||||||
});
|
});
|
||||||
const initialBookmark = this.initialBookmark;
|
const initialBookmark = this.initialBookmark;
|
||||||
|
|
||||||
@ -1226,14 +1224,20 @@ const PDFViewerApplication = {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
pagesPromise.then(() => {
|
pagesPromise.then(async () => {
|
||||||
if (!this.supportsPrinting) {
|
if (!this.supportsPrinting) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pdfDocument.getJavaScript().then(javaScript => {
|
const [openAction, javaScript] = await Promise.all([
|
||||||
if (!javaScript) {
|
openActionPromise,
|
||||||
return;
|
pdfDocument.getJavaScript(),
|
||||||
}
|
]);
|
||||||
|
let triggerAutoPrint = false;
|
||||||
|
|
||||||
|
if (openAction && openAction.action === "Print") {
|
||||||
|
triggerAutoPrint = true;
|
||||||
|
}
|
||||||
|
if (javaScript) {
|
||||||
javaScript.some(js => {
|
javaScript.some(js => {
|
||||||
if (!js) {
|
if (!js) {
|
||||||
// Don't warn/fallback for empty JavaScript actions.
|
// Don't warn/fallback for empty JavaScript actions.
|
||||||
@ -1244,16 +1248,22 @@ const PDFViewerApplication = {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hack to support auto printing.
|
if (!triggerAutoPrint) {
|
||||||
for (const js of javaScript) {
|
// Hack to support auto printing.
|
||||||
if (js && AutoPrintRegExp.test(js)) {
|
for (const js of javaScript) {
|
||||||
setTimeout(function() {
|
if (js && AutoPrintRegExp.test(js)) {
|
||||||
window.print();
|
triggerAutoPrint = true;
|
||||||
});
|
break;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
if (triggerAutoPrint) {
|
||||||
|
setTimeout(function() {
|
||||||
|
window.print();
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onePageRendered.then(() => {
|
onePageRendered.then(() => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user