JS - Collect and execute actions at doc and pages level

* the goal is to execute actions like Open or OpenAction
 * can be tested with issue6106.pdf (auto-print)
 * once #12701 is merged, we can add page actions
This commit is contained in:
Calixte Denizet 2020-12-07 19:22:14 +01:00
parent 142f131ee1
commit 1e2173f038
18 changed files with 829 additions and 125 deletions

View file

@ -0,0 +1,26 @@
/* Copyright 2020 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function createActionsMap(actions) {
const actionsMap = new Map();
if (actions) {
for (const [eventType, actionsForEvent] of Object.entries(actions)) {
actionsMap.set(eventType, actionsForEvent);
}
}
return actionsMap;
}
export { createActionsMap };

View file

@ -13,6 +13,7 @@
* limitations under the License.
*/
import { createActionsMap } from "./common.js";
import { PDFObject } from "./pdf_object.js";
import { PrintParams } from "./print_params.js";
import { ZoomType } from "./constants.js";
@ -88,6 +89,48 @@ class Doc extends PDFObject {
this._zoomType = ZoomType.none;
this._zoom = data.zoom || 100;
this._actions = createActionsMap(data.actions);
this._globalEval = data.globalEval;
}
_dispatchDocEvent(name) {
if (name === "Open") {
const dontRun = new Set([
"WillClose",
"WillSave",
"DidSave",
"WillPrint",
"DidPrint",
"OpenAction",
]);
for (const actionName of this._actions.keys()) {
if (!dontRun.has(actionName)) {
this._runActions(actionName);
}
}
this._runActions("OpenAction");
} else {
this._runActions(name);
}
}
_dispatchPageEvent(name, action, pageNumber) {
if (name === "PageOpen") {
this._pageNum = pageNumber - 1;
}
this._globalEval(action);
}
_runActions(name) {
if (!this._actions.has(name)) {
return;
}
const actions = this._actions.get(name);
for (const action of actions) {
this._globalEval(action);
}
}
_addField(name, field) {
@ -954,7 +997,7 @@ class Doc extends PDFObject {
nEnd = -1;
}
this._send({ id: "print", start: nStart, end: nEnd });
this._send({ command: "print", start: nStart, end: nEnd });
}
removeDataObject() {

View file

@ -65,12 +65,28 @@ class EventDispatcher {
dispatch(baseEvent) {
const id = baseEvent.id;
if (!(id in this._objects)) {
let event;
if (id === "doc" || id === "page") {
event = globalThis.event = new Event(baseEvent);
event.source = event.target = this._document.wrapped;
event.name = baseEvent.name;
}
if (id === "doc") {
this._document.obj._dispatchDocEvent(event.name);
}
if (id === "page") {
this._document.obj._dispatchPageEvent(
event.name,
baseEvent.action,
baseEvent.pageNumber
);
}
return;
}
const name = baseEvent.name.replace(" ", "");
const source = this._objects[id];
globalThis.event = new Event(baseEvent);
const event = (globalThis.event = new Event(baseEvent));
let savedChange;
if (source.obj._isButton()) {
@ -156,7 +172,7 @@ class EventDispatcher {
const first = this._calculationOrder[0];
const source = this._objects[first];
globalThis.event = new Event({});
this.runCalculate(source, event);
this.runCalculate(source, globalThis.event);
}
runCalculate(source, event) {

View file

@ -14,6 +14,7 @@
*/
import { Color } from "./color.js";
import { createActionsMap } from "./common.js";
import { PDFObject } from "./pdf_object.js";
class Field extends PDFObject {
@ -72,7 +73,7 @@ class Field extends PDFObject {
// Private
this._document = data.doc;
this._actions = this._createActionsMap(data.actions);
this._actions = createActionsMap(data.actions);
this._fillColor = data.fillColor || ["T"];
this._strokeColor = data.strokeColor || ["G", 0];
@ -133,16 +134,6 @@ class Field extends PDFObject {
this._send({ id: this._id, focus: true });
}
_createActionsMap(actions) {
const actionsMap = new Map();
if (actions) {
for (const [eventType, actionsForEvent] of Object.entries(actions)) {
actionsMap.set(eventType, actionsForEvent);
}
}
return actionsMap;
}
_isButton() {
return false;
}

View file

@ -51,6 +51,7 @@ function initSandbox(params) {
const { data } = params;
const doc = new Doc({
send,
globalEval,
...data.docInfo,
});
const _document = { obj: doc, wrapped: new Proxy(doc, proxyHandler) };
@ -67,16 +68,17 @@ function initSandbox(params) {
const util = new Util({ externalCall });
const aform = new AForm(doc, app, util);
for (const [name, objs] of Object.entries(data.objects)) {
const obj = objs[0];
obj.send = send;
obj.globalEval = globalEval;
obj.doc = _document.wrapped;
obj.globalEval = globalEval;
const field = new Field(obj);
const wrapped = new Proxy(field, proxyHandler);
doc._addField(name, wrapped);
app._objects[obj.id] = { obj: field, wrapped };
if (data.objects) {
for (const [name, objs] of Object.entries(data.objects)) {
const obj = objs[0];
obj.send = send;
obj.globalEval = globalEval;
obj.doc = _document.wrapped;
const field = new Field(obj);
const wrapped = new Proxy(field, proxyHandler);
doc._addField(name, wrapped);
app._objects[obj.id] = { obj: field, wrapped };
}
}
globalThis.event = null;