[api-minor] Add more general OpenAction support (PR 10334 follow-up, issue 11642)
This patch deprecates the existing `getOpenActionDestination` API method, in favor of a better and more general `getOpenAction` method instead. (For now JavaScript actions, related to printing, are still handled as before.) By clearly separating "regular" Print actions from the JavaScript handling, it's thus possible to get rid of the somewhat annoying and strictly incorrect warning when the viewer loads.
This commit is contained in:
parent
25693c6b6d
commit
01fb309a2a
@ -592,9 +592,12 @@ class Catalog {
|
||||
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");
|
||||
let openActionDest = null;
|
||||
let openAction = null;
|
||||
|
||||
if (isDict(obj)) {
|
||||
// Convert the OpenAction dictionary into a format that works with
|
||||
@ -602,16 +605,27 @@ class Catalog {
|
||||
const destDict = new Dict(this.xref);
|
||||
destDict.set("A", obj);
|
||||
|
||||
const resultObj = { url: null, dest: null };
|
||||
const resultObj = { url: null, dest: null, action: null };
|
||||
Catalog.parseDestDictionary({ destDict, resultObj });
|
||||
|
||||
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)) {
|
||||
openActionDest = obj;
|
||||
if (!openAction) {
|
||||
openAction = Object.create(null);
|
||||
}
|
||||
return shadow(this, "openActionDestination", openActionDest);
|
||||
openAction.dest = obj;
|
||||
}
|
||||
return shadow(this, "openAction", openAction);
|
||||
}
|
||||
|
||||
get attachments() {
|
||||
@ -668,27 +682,10 @@ class Catalog {
|
||||
}
|
||||
}
|
||||
|
||||
// Append OpenAction actions to the JavaScript array.
|
||||
const openActionDict = this.catDict.get("OpenAction");
|
||||
if (
|
||||
isDict(openActionDict) &&
|
||||
(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);
|
||||
}
|
||||
// Append OpenAction "JavaScript" actions to the JavaScript array.
|
||||
const openAction = this.catDict.get("OpenAction");
|
||||
if (isDict(openAction) && isName(openAction.get("S"), "JavaScript")) {
|
||||
appendIfJavaScriptDict(openAction);
|
||||
}
|
||||
|
||||
return shadow(this, "javaScript", javaScript);
|
||||
|
@ -458,8 +458,8 @@ var WorkerMessageHandler = {
|
||||
return pdfManager.ensureCatalog("viewerPreferences");
|
||||
});
|
||||
|
||||
handler.on("GetOpenActionDestination", function(data) {
|
||||
return pdfManager.ensureCatalog("openActionDestination");
|
||||
handler.on("GetOpenAction", function(data) {
|
||||
return pdfManager.ensureCatalog("openAction");
|
||||
});
|
||||
|
||||
handler.on("GetAttachments", function wphSetupGetAttachments(data) {
|
||||
|
@ -668,11 +668,18 @@ class PDFDocumentProxy {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise} A promise that is resolved with an {Array} containing
|
||||
* the destination, or `null` when no open action is present in the PDF.
|
||||
* @returns {Promise} A promise that is resolved with an {Object} containing
|
||||
* the currently supported actions, or `null` when no OpenAction exists.
|
||||
*/
|
||||
getOpenAction() {
|
||||
return this._transport.getOpenAction();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
getOpenActionDestination() {
|
||||
return this.messageHandler.sendWithPromise(
|
||||
"GetOpenActionDestination",
|
||||
null
|
||||
);
|
||||
getOpenAction() {
|
||||
return this.messageHandler.sendWithPromise("GetOpenAction", null);
|
||||
}
|
||||
|
||||
getAttachments() {
|
||||
|
@ -863,29 +863,69 @@ describe("api", function() {
|
||||
.catch(done.fail);
|
||||
});
|
||||
|
||||
it("gets default open action destination", function(done) {
|
||||
it("gets default open action", function(done) {
|
||||
var loadingTask = getDocument(buildGetDocumentParams("tracemonkey.pdf"));
|
||||
|
||||
loadingTask.promise
|
||||
.then(function(pdfDocument) {
|
||||
return pdfDocument.getOpenActionDestination();
|
||||
return pdfDocument.getOpenAction();
|
||||
})
|
||||
.then(function(dest) {
|
||||
expect(dest).toEqual(null);
|
||||
.then(function(openAction) {
|
||||
expect(openAction).toEqual(null);
|
||||
|
||||
loadingTask.destroy().then(done);
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
it("gets non-default open action destination", function(done) {
|
||||
it("gets non-default open action (with destination)", function(done) {
|
||||
doc
|
||||
.getOpenActionDestination()
|
||||
.then(function(dest) {
|
||||
expect(dest).toEqual([{ num: 15, gen: 0 }, { name: "FitH" }, null]);
|
||||
.getOpenAction()
|
||||
.then(function(openAction) {
|
||||
expect(openAction.dest).toEqual([
|
||||
{ num: 15, gen: 0 },
|
||||
{ name: "FitH" },
|
||||
null,
|
||||
]);
|
||||
expect(openAction.action).toBeUndefined();
|
||||
|
||||
done();
|
||||
})
|
||||
.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) {
|
||||
var promise = doc.getAttachments();
|
||||
@ -923,37 +963,6 @@ describe("api", function() {
|
||||
})
|
||||
.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) {
|
||||
// PDF document with "JavaScript" action in the OpenAction dictionary.
|
||||
var loadingTask = getDocument(buildGetDocumentParams("issue6106.pdf"));
|
||||
|
36
web/app.js
36
web/app.js
@ -1033,9 +1033,7 @@ const PDFViewerApplication = {
|
||||
const pageModePromise = pdfDocument.getPageMode().catch(function() {
|
||||
/* Avoid breaking initial rendering; ignoring errors. */
|
||||
});
|
||||
const openActionDestPromise = pdfDocument
|
||||
.getOpenActionDestination()
|
||||
.catch(function() {
|
||||
const openActionPromise = pdfDocument.getOpenAction().catch(function() {
|
||||
/* Avoid breaking initial rendering; ignoring errors. */
|
||||
});
|
||||
|
||||
@ -1087,7 +1085,7 @@ const PDFViewerApplication = {
|
||||
storePromise,
|
||||
pageLayoutPromise,
|
||||
pageModePromise,
|
||||
openActionDestPromise,
|
||||
openActionPromise,
|
||||
])
|
||||
.then(
|
||||
async ([
|
||||
@ -1095,14 +1093,14 @@ const PDFViewerApplication = {
|
||||
values = {},
|
||||
pageLayout,
|
||||
pageMode,
|
||||
openActionDest,
|
||||
openAction,
|
||||
]) => {
|
||||
const viewOnLoad = AppOptions.get("viewOnLoad");
|
||||
|
||||
this._initializePdfHistory({
|
||||
fingerprint: pdfDocument.fingerprint,
|
||||
viewOnLoad,
|
||||
initialDest: openActionDest,
|
||||
initialDest: openAction && openAction.dest,
|
||||
});
|
||||
const initialBookmark = this.initialBookmark;
|
||||
|
||||
@ -1228,14 +1226,20 @@ const PDFViewerApplication = {
|
||||
);
|
||||
});
|
||||
|
||||
pagesPromise.then(() => {
|
||||
pagesPromise.then(async () => {
|
||||
if (!this.supportsPrinting) {
|
||||
return;
|
||||
}
|
||||
pdfDocument.getJavaScript().then(javaScript => {
|
||||
if (!javaScript) {
|
||||
return;
|
||||
const [openAction, javaScript] = await Promise.all([
|
||||
openActionPromise,
|
||||
pdfDocument.getJavaScript(),
|
||||
]);
|
||||
let triggerAutoPrint = false;
|
||||
|
||||
if (openAction && openAction.action === "Print") {
|
||||
triggerAutoPrint = true;
|
||||
}
|
||||
if (javaScript) {
|
||||
javaScript.some(js => {
|
||||
if (!js) {
|
||||
// Don't warn/fallback for empty JavaScript actions.
|
||||
@ -1246,16 +1250,22 @@ const PDFViewerApplication = {
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!triggerAutoPrint) {
|
||||
// Hack to support auto printing.
|
||||
for (const js of javaScript) {
|
||||
if (js && AutoPrintRegExp.test(js)) {
|
||||
triggerAutoPrint = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (triggerAutoPrint) {
|
||||
setTimeout(function() {
|
||||
window.print();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onePageRendered.then(() => {
|
||||
|
Loading…
Reference in New Issue
Block a user