[JS] Some functions (print, alert,...) must be called only after a user activation
- Some events, which require a user interaction, will allow those functions to be called. But after few seconds, if there are no more user interaction, it won't be possible anymore. The idea is to give an opportunity to the user to leave the pdf. - Disable print function when we're printing, the same with saving and disallow to save on open events.
This commit is contained in:
parent
27b251ac99
commit
0de804a256
@ -81,6 +81,13 @@ class SandboxSupportBase {
|
|||||||
) {
|
) {
|
||||||
return;
|
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(() => {
|
const id = this.win.setTimeout(() => {
|
||||||
this.timeoutIds.delete(callbackId);
|
this.timeoutIds.delete(callbackId);
|
||||||
this.callSandboxFunction("timeoutCb", {
|
this.callSandboxFunction("timeoutCb", {
|
||||||
|
@ -23,6 +23,7 @@ const VIEWER_TYPE = "PDF.js";
|
|||||||
const VIEWER_VARIATION = "Full";
|
const VIEWER_VARIATION = "Full";
|
||||||
const VIEWER_VERSION = 21.00720099;
|
const VIEWER_VERSION = 21.00720099;
|
||||||
const FORMS_VERSION = 21.00720099;
|
const FORMS_VERSION = 21.00720099;
|
||||||
|
const USERACTIVATION_CALLBACKID = 0;
|
||||||
|
|
||||||
class App extends PDFObject {
|
class App extends PDFObject {
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
@ -45,7 +46,8 @@ class App extends PDFObject {
|
|||||||
this._eventDispatcher = new EventDispatcher(
|
this._eventDispatcher = new EventDispatcher(
|
||||||
this._document,
|
this._document,
|
||||||
data.calculationOrder,
|
data.calculationOrder,
|
||||||
this._objects
|
this._objects,
|
||||||
|
data.externalCall
|
||||||
);
|
);
|
||||||
|
|
||||||
this._timeoutIds = new WeakMap();
|
this._timeoutIds = new WeakMap();
|
||||||
@ -63,7 +65,7 @@ class App extends PDFObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._timeoutCallbackIds = new Map();
|
this._timeoutCallbackIds = new Map();
|
||||||
this._timeoutCallbackId = 0;
|
this._timeoutCallbackId = USERACTIVATION_CALLBACKID + 1;
|
||||||
this._globalEval = data.globalEval;
|
this._globalEval = data.globalEval;
|
||||||
this._externalCall = data.externalCall;
|
this._externalCall = data.externalCall;
|
||||||
}
|
}
|
||||||
@ -85,6 +87,11 @@ class App extends PDFObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_evalCallback({ callbackId, interval }) {
|
_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);
|
const expr = this._timeoutCallbackIds.get(callbackId);
|
||||||
if (!interval) {
|
if (!interval) {
|
||||||
this._unregisterTimeoutCallback(callbackId);
|
this._unregisterTimeoutCallback(callbackId);
|
||||||
@ -429,6 +436,11 @@ class App extends PDFObject {
|
|||||||
oDoc = null,
|
oDoc = null,
|
||||||
oCheckbox = null
|
oCheckbox = null
|
||||||
) {
|
) {
|
||||||
|
if (!this._document.obj._userActivation) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
this._document.obj._userActivation = false;
|
||||||
|
|
||||||
if (cMsg && typeof cMsg === "object") {
|
if (cMsg && typeof cMsg === "object") {
|
||||||
nType = cMsg.nType;
|
nType = cMsg.nType;
|
||||||
cMsg = cMsg.cMsg;
|
cMsg = cMsg.cMsg;
|
||||||
@ -475,8 +487,18 @@ class App extends PDFObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
execMenuItem(item) {
|
execMenuItem(item) {
|
||||||
|
if (!this._document.obj._userActivation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._document.obj._userActivation = false;
|
||||||
|
|
||||||
switch (item) {
|
switch (item) {
|
||||||
case "SaveAs":
|
case "SaveAs":
|
||||||
|
if (this._document.obj._disableSaving) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._send({ command: item });
|
||||||
|
break;
|
||||||
case "FirstPage":
|
case "FirstPage":
|
||||||
case "LastPage":
|
case "LastPage":
|
||||||
case "NextPage":
|
case "NextPage":
|
||||||
@ -489,6 +511,9 @@ class App extends PDFObject {
|
|||||||
this._send({ command: "zoom", value: "page-fit" });
|
this._send({ command: "zoom", value: "page-fit" });
|
||||||
break;
|
break;
|
||||||
case "Print":
|
case "Print":
|
||||||
|
if (this._document.obj._disablePrinting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this._send({ command: "print" });
|
this._send({ command: "print" });
|
||||||
break;
|
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._actions = createActionsMap(data.actions);
|
||||||
this._globalEval = data.globalEval;
|
this._globalEval = data.globalEval;
|
||||||
this._pageActions = new Map();
|
this._pageActions = new Map();
|
||||||
|
this._userActivation = false;
|
||||||
|
this._disablePrinting = false;
|
||||||
|
this._disableSaving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_dispatchDocEvent(name) {
|
_dispatchDocEvent(name) {
|
||||||
@ -108,12 +111,27 @@ class Doc extends PDFObject {
|
|||||||
"DidPrint",
|
"DidPrint",
|
||||||
"OpenAction",
|
"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()) {
|
for (const actionName of this._actions.keys()) {
|
||||||
if (!dontRun.has(actionName)) {
|
if (!dontRun.has(actionName)) {
|
||||||
this._runActions(actionName);
|
this._runActions(actionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._runActions("OpenAction");
|
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 {
|
} else {
|
||||||
this._runActions(name);
|
this._runActions(name);
|
||||||
}
|
}
|
||||||
@ -361,6 +379,11 @@ class Doc extends PDFObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set layout(value) {
|
set layout(value) {
|
||||||
|
if (!this._userActivation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._userActivation = false;
|
||||||
|
|
||||||
if (typeof value !== "string") {
|
if (typeof value !== "string") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -480,6 +503,11 @@ class Doc extends PDFObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set pageNum(value) {
|
set pageNum(value) {
|
||||||
|
if (!this._userActivation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._userActivation = false;
|
||||||
|
|
||||||
if (typeof value !== "number" || value < 0 || value >= this._numPages) {
|
if (typeof value !== "number" || value < 0 || value >= this._numPages) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -628,6 +656,11 @@ class Doc extends PDFObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set zoomType(type) {
|
set zoomType(type) {
|
||||||
|
if (!this._userActivation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._userActivation = false;
|
||||||
|
|
||||||
if (typeof type !== "string") {
|
if (typeof type !== "string") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -662,6 +695,11 @@ class Doc extends PDFObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set zoom(value) {
|
set zoom(value) {
|
||||||
|
if (!this._userActivation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._userActivation = false;
|
||||||
|
|
||||||
if (typeof value !== "number" || value < 8.33 || value > 6400) {
|
if (typeof value !== "number" || value < 8.33 || value > 6400) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1057,6 +1095,11 @@ class Doc extends PDFObject {
|
|||||||
bAnnotations = true,
|
bAnnotations = true,
|
||||||
printParams = null
|
printParams = null
|
||||||
) {
|
) {
|
||||||
|
if (this._disablePrinting || !this._userActivation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._userActivation = false;
|
||||||
|
|
||||||
if (bUI && typeof bUI === "object") {
|
if (bUI && typeof bUI === "object") {
|
||||||
nStart = bUI.nStart;
|
nStart = bUI.nStart;
|
||||||
nEnd = bUI.nEnd;
|
nEnd = bUI.nEnd;
|
||||||
|
@ -13,6 +13,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { USERACTIVATION_CALLBACKID } from "./doc.js";
|
||||||
|
|
||||||
|
const USERACTIVATION_MAXTIME_VALIDITY = 5000;
|
||||||
|
|
||||||
class Event {
|
class Event {
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
this.change = data.change || "";
|
this.change = data.change || "";
|
||||||
@ -39,10 +43,11 @@ class Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EventDispatcher {
|
class EventDispatcher {
|
||||||
constructor(document, calculationOrder, objects) {
|
constructor(document, calculationOrder, objects, externalCall) {
|
||||||
this._document = document;
|
this._document = document;
|
||||||
this._calculationOrder = calculationOrder;
|
this._calculationOrder = calculationOrder;
|
||||||
this._objects = objects;
|
this._objects = objects;
|
||||||
|
this._externalCall = externalCall;
|
||||||
|
|
||||||
this._document.obj._eventDispatcher = this;
|
this._document.obj._eventDispatcher = this;
|
||||||
this._isCalculating = false;
|
this._isCalculating = false;
|
||||||
@ -66,6 +71,14 @@ class EventDispatcher {
|
|||||||
return `${prefix}${event.change}${postfix}`;
|
return `${prefix}${event.change}${postfix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userActivation() {
|
||||||
|
this._document.obj._userActivation = true;
|
||||||
|
this._externalCall("setTimeout", [
|
||||||
|
USERACTIVATION_CALLBACKID,
|
||||||
|
USERACTIVATION_MAXTIME_VALIDITY,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(baseEvent) {
|
dispatch(baseEvent) {
|
||||||
const id = baseEvent.id;
|
const id = baseEvent.id;
|
||||||
if (!(id in this._objects)) {
|
if (!(id in this._objects)) {
|
||||||
@ -76,19 +89,27 @@ class EventDispatcher {
|
|||||||
event.name = baseEvent.name;
|
event.name = baseEvent.name;
|
||||||
}
|
}
|
||||||
if (id === "doc") {
|
if (id === "doc") {
|
||||||
if (event.name === "Open") {
|
const eventName = event.name;
|
||||||
|
if (eventName === "Open") {
|
||||||
// Before running the Open event, we format all the fields
|
// Before running the Open event, we format all the fields
|
||||||
// (see bug 1766987).
|
// (see bug 1766987).
|
||||||
this.formatAll();
|
this.formatAll();
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
!["DidPrint", "DidSave", "WillPrint", "WillSave"].includes(eventName)
|
||||||
|
) {
|
||||||
|
this.userActivation();
|
||||||
|
}
|
||||||
this._document.obj._dispatchDocEvent(event.name);
|
this._document.obj._dispatchDocEvent(event.name);
|
||||||
} else if (id === "page") {
|
} else if (id === "page") {
|
||||||
|
this.userActivation();
|
||||||
this._document.obj._dispatchPageEvent(
|
this._document.obj._dispatchPageEvent(
|
||||||
event.name,
|
event.name,
|
||||||
baseEvent.actions,
|
baseEvent.actions,
|
||||||
baseEvent.pageNumber
|
baseEvent.pageNumber
|
||||||
);
|
);
|
||||||
} else if (id === "app" && baseEvent.name === "ResetForm") {
|
} else if (id === "app" && baseEvent.name === "ResetForm") {
|
||||||
|
this.userActivation();
|
||||||
for (const fieldId of baseEvent.ids) {
|
for (const fieldId of baseEvent.ids) {
|
||||||
const obj = this._objects[fieldId];
|
const obj = this._objects[fieldId];
|
||||||
obj?.obj._reset();
|
obj?.obj._reset();
|
||||||
@ -102,6 +123,8 @@ class EventDispatcher {
|
|||||||
const event = (globalThis.event = new Event(baseEvent));
|
const event = (globalThis.event = new Event(baseEvent));
|
||||||
let savedChange;
|
let savedChange;
|
||||||
|
|
||||||
|
this.userActivation();
|
||||||
|
|
||||||
if (source.obj._isButton()) {
|
if (source.obj._isButton()) {
|
||||||
source.obj._id = id;
|
source.obj._id = id;
|
||||||
event.value = source.obj._getExportValue(event.value);
|
event.value = source.obj._getExportValue(event.value);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user