Merge pull request #15618 from calixteman/15614
[JS] Some functions (print, alert,...) must be called only after a user activation
This commit is contained in:
commit
8f80efa4ab
@ -81,6 +81,13 @@ class SandboxSupportBase {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callbackId === 0) {
|
||||
// This callbackId corresponds to the one used for userActivation.
|
||||
// So here, we cancel the last userActivation.
|
||||
this.win.clearTimeout(this.timeoutIds.get(callbackId));
|
||||
}
|
||||
|
||||
const id = this.win.setTimeout(() => {
|
||||
this.timeoutIds.delete(callbackId);
|
||||
this.callSandboxFunction("timeoutCb", {
|
||||
|
@ -23,6 +23,7 @@ const VIEWER_TYPE = "PDF.js";
|
||||
const VIEWER_VARIATION = "Full";
|
||||
const VIEWER_VERSION = 21.00720099;
|
||||
const FORMS_VERSION = 21.00720099;
|
||||
const USERACTIVATION_CALLBACKID = 0;
|
||||
|
||||
class App extends PDFObject {
|
||||
constructor(data) {
|
||||
@ -45,7 +46,8 @@ class App extends PDFObject {
|
||||
this._eventDispatcher = new EventDispatcher(
|
||||
this._document,
|
||||
data.calculationOrder,
|
||||
this._objects
|
||||
this._objects,
|
||||
data.externalCall
|
||||
);
|
||||
|
||||
this._timeoutIds = new WeakMap();
|
||||
@ -63,7 +65,7 @@ class App extends PDFObject {
|
||||
}
|
||||
|
||||
this._timeoutCallbackIds = new Map();
|
||||
this._timeoutCallbackId = 0;
|
||||
this._timeoutCallbackId = USERACTIVATION_CALLBACKID + 1;
|
||||
this._globalEval = data.globalEval;
|
||||
this._externalCall = data.externalCall;
|
||||
}
|
||||
@ -85,6 +87,11 @@ class App extends PDFObject {
|
||||
}
|
||||
|
||||
_evalCallback({ callbackId, interval }) {
|
||||
if (callbackId === USERACTIVATION_CALLBACKID) {
|
||||
// Special callback id for userActivation stuff.
|
||||
this._document.obj._userActivation = false;
|
||||
return;
|
||||
}
|
||||
const expr = this._timeoutCallbackIds.get(callbackId);
|
||||
if (!interval) {
|
||||
this._unregisterTimeoutCallback(callbackId);
|
||||
@ -429,6 +436,11 @@ class App extends PDFObject {
|
||||
oDoc = null,
|
||||
oCheckbox = null
|
||||
) {
|
||||
if (!this._document.obj._userActivation) {
|
||||
return 0;
|
||||
}
|
||||
this._document.obj._userActivation = false;
|
||||
|
||||
if (cMsg && typeof cMsg === "object") {
|
||||
nType = cMsg.nType;
|
||||
cMsg = cMsg.cMsg;
|
||||
@ -475,8 +487,18 @@ class App extends PDFObject {
|
||||
}
|
||||
|
||||
execMenuItem(item) {
|
||||
if (!this._document.obj._userActivation) {
|
||||
return;
|
||||
}
|
||||
this._document.obj._userActivation = false;
|
||||
|
||||
switch (item) {
|
||||
case "SaveAs":
|
||||
if (this._document.obj._disableSaving) {
|
||||
return;
|
||||
}
|
||||
this._send({ command: item });
|
||||
break;
|
||||
case "FirstPage":
|
||||
case "LastPage":
|
||||
case "NextPage":
|
||||
@ -489,6 +511,9 @@ class App extends PDFObject {
|
||||
this._send({ command: "zoom", value: "page-fit" });
|
||||
break;
|
||||
case "Print":
|
||||
if (this._document.obj._disablePrinting) {
|
||||
return;
|
||||
}
|
||||
this._send({ command: "print" });
|
||||
break;
|
||||
}
|
||||
@ -629,4 +654,4 @@ class App extends PDFObject {
|
||||
}
|
||||
}
|
||||
|
||||
export { App };
|
||||
export { App, USERACTIVATION_CALLBACKID };
|
||||
|
@ -96,6 +96,9 @@ class Doc extends PDFObject {
|
||||
this._actions = createActionsMap(data.actions);
|
||||
this._globalEval = data.globalEval;
|
||||
this._pageActions = new Map();
|
||||
this._userActivation = false;
|
||||
this._disablePrinting = false;
|
||||
this._disableSaving = false;
|
||||
}
|
||||
|
||||
_dispatchDocEvent(name) {
|
||||
@ -108,12 +111,27 @@ class Doc extends PDFObject {
|
||||
"DidPrint",
|
||||
"OpenAction",
|
||||
]);
|
||||
// When a pdf has just been opened it doesn't really make sense
|
||||
// to save it: it's up to the user to decide if they want to do that.
|
||||
// A pdf can contain an action /FooBar which will trigger a save
|
||||
// even if there are no WillSave/DidSave (which are themselves triggered
|
||||
// after a save).
|
||||
this._disableSaving = true;
|
||||
for (const actionName of this._actions.keys()) {
|
||||
if (!dontRun.has(actionName)) {
|
||||
this._runActions(actionName);
|
||||
}
|
||||
}
|
||||
this._runActions("OpenAction");
|
||||
this._disableSaving = false;
|
||||
} else if (name === "WillPrint") {
|
||||
this._disablePrinting = true;
|
||||
this._runActions(name);
|
||||
this._disablePrinting = false;
|
||||
} else if (name === "WillSave") {
|
||||
this._disableSaving = true;
|
||||
this._runActions(name);
|
||||
this._disableSaving = false;
|
||||
} else {
|
||||
this._runActions(name);
|
||||
}
|
||||
@ -361,6 +379,11 @@ class Doc extends PDFObject {
|
||||
}
|
||||
|
||||
set layout(value) {
|
||||
if (!this._userActivation) {
|
||||
return;
|
||||
}
|
||||
this._userActivation = false;
|
||||
|
||||
if (typeof value !== "string") {
|
||||
return;
|
||||
}
|
||||
@ -480,6 +503,11 @@ class Doc extends PDFObject {
|
||||
}
|
||||
|
||||
set pageNum(value) {
|
||||
if (!this._userActivation) {
|
||||
return;
|
||||
}
|
||||
this._userActivation = false;
|
||||
|
||||
if (typeof value !== "number" || value < 0 || value >= this._numPages) {
|
||||
return;
|
||||
}
|
||||
@ -628,6 +656,11 @@ class Doc extends PDFObject {
|
||||
}
|
||||
|
||||
set zoomType(type) {
|
||||
if (!this._userActivation) {
|
||||
return;
|
||||
}
|
||||
this._userActivation = false;
|
||||
|
||||
if (typeof type !== "string") {
|
||||
return;
|
||||
}
|
||||
@ -662,6 +695,11 @@ class Doc extends PDFObject {
|
||||
}
|
||||
|
||||
set zoom(value) {
|
||||
if (!this._userActivation) {
|
||||
return;
|
||||
}
|
||||
this._userActivation = false;
|
||||
|
||||
if (typeof value !== "number" || value < 8.33 || value > 6400) {
|
||||
return;
|
||||
}
|
||||
@ -1057,6 +1095,11 @@ class Doc extends PDFObject {
|
||||
bAnnotations = true,
|
||||
printParams = null
|
||||
) {
|
||||
if (this._disablePrinting || !this._userActivation) {
|
||||
return;
|
||||
}
|
||||
this._userActivation = false;
|
||||
|
||||
if (bUI && typeof bUI === "object") {
|
||||
nStart = bUI.nStart;
|
||||
nEnd = bUI.nEnd;
|
||||
|
@ -13,6 +13,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { USERACTIVATION_CALLBACKID } from "./doc.js";
|
||||
|
||||
const USERACTIVATION_MAXTIME_VALIDITY = 5000;
|
||||
|
||||
class Event {
|
||||
constructor(data) {
|
||||
this.change = data.change || "";
|
||||
@ -39,10 +43,11 @@ class Event {
|
||||
}
|
||||
|
||||
class EventDispatcher {
|
||||
constructor(document, calculationOrder, objects) {
|
||||
constructor(document, calculationOrder, objects, externalCall) {
|
||||
this._document = document;
|
||||
this._calculationOrder = calculationOrder;
|
||||
this._objects = objects;
|
||||
this._externalCall = externalCall;
|
||||
|
||||
this._document.obj._eventDispatcher = this;
|
||||
this._isCalculating = false;
|
||||
@ -66,6 +71,14 @@ class EventDispatcher {
|
||||
return `${prefix}${event.change}${postfix}`;
|
||||
}
|
||||
|
||||
userActivation() {
|
||||
this._document.obj._userActivation = true;
|
||||
this._externalCall("setTimeout", [
|
||||
USERACTIVATION_CALLBACKID,
|
||||
USERACTIVATION_MAXTIME_VALIDITY,
|
||||
]);
|
||||
}
|
||||
|
||||
dispatch(baseEvent) {
|
||||
const id = baseEvent.id;
|
||||
if (!(id in this._objects)) {
|
||||
@ -76,19 +89,27 @@ class EventDispatcher {
|
||||
event.name = baseEvent.name;
|
||||
}
|
||||
if (id === "doc") {
|
||||
if (event.name === "Open") {
|
||||
const eventName = event.name;
|
||||
if (eventName === "Open") {
|
||||
// Before running the Open event, we format all the fields
|
||||
// (see bug 1766987).
|
||||
this.formatAll();
|
||||
}
|
||||
if (
|
||||
!["DidPrint", "DidSave", "WillPrint", "WillSave"].includes(eventName)
|
||||
) {
|
||||
this.userActivation();
|
||||
}
|
||||
this._document.obj._dispatchDocEvent(event.name);
|
||||
} else if (id === "page") {
|
||||
this.userActivation();
|
||||
this._document.obj._dispatchPageEvent(
|
||||
event.name,
|
||||
baseEvent.actions,
|
||||
baseEvent.pageNumber
|
||||
);
|
||||
} else if (id === "app" && baseEvent.name === "ResetForm") {
|
||||
this.userActivation();
|
||||
for (const fieldId of baseEvent.ids) {
|
||||
const obj = this._objects[fieldId];
|
||||
obj?.obj._reset();
|
||||
@ -102,6 +123,8 @@ class EventDispatcher {
|
||||
const event = (globalThis.event = new Event(baseEvent));
|
||||
let savedChange;
|
||||
|
||||
this.userActivation();
|
||||
|
||||
if (source.obj._isButton()) {
|
||||
source.obj._id = id;
|
||||
event.value = source.obj._getExportValue(event.value);
|
||||
|
Loading…
x
Reference in New Issue
Block a user