Skip to content

Commit 5597077

Browse files
committed
JS - Add the basic architecture to be able to execute embedded js
1 parent a373137 commit 5597077

18 files changed

+821
-0
lines changed

extensions/chromium/preferences_schema.json

+4
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@
151151
"type": "boolean",
152152
"default": true
153153
},
154+
"enableScripting": {
155+
"type": "boolean",
156+
"default": false
157+
},
154158
"enablePermissions": {
155159
"type": "boolean",
156160
"default": false

gulpfile.js

+20
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,23 @@ function createMainBundle(defines) {
316316
.pipe(replaceJSRootName(mainAMDName, "pdfjsLib"));
317317
}
318318

319+
function createScriptingBundle(defines) {
320+
var mainAMDName = "pdfjs-dist/build/pdf.scripting";
321+
var mainOutputName = "pdf.scripting.js";
322+
323+
var mainFileConfig = createWebpackConfig(defines, {
324+
filename: mainOutputName,
325+
library: mainAMDName,
326+
libraryTarget: "umd",
327+
umdNamedDefine: true,
328+
});
329+
return gulp
330+
.src("./src/scripting_api/initialization.js")
331+
.pipe(webpack2Stream(mainFileConfig))
332+
.pipe(replaceWebpackRequire())
333+
.pipe(replaceJSRootName(mainAMDName, "pdfjsScripting"));
334+
}
335+
319336
function createWorkerBundle(defines) {
320337
var workerAMDName = "pdfjs-dist/build/pdf.worker";
321338
var workerOutputName = "pdf.worker.js";
@@ -1036,6 +1053,9 @@ gulp.task(
10361053
createMainBundle(defines).pipe(
10371054
gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")
10381055
),
1056+
createScriptingBundle(defines).pipe(
1057+
gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")
1058+
),
10391059
createWorkerBundle(defines).pipe(
10401060
gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")
10411061
),

src/display/annotation_layer.js

+31
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
468468
element.setAttribute("value", textContent);
469469
}
470470

471+
element.setAttribute("id", id);
472+
471473
element.addEventListener("input", function (event) {
472474
storage.setValue(id, event.target.value);
473475
});
@@ -476,6 +478,35 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
476478
event.target.setSelectionRange(0, 0);
477479
});
478480

481+
if (this.data.actions) {
482+
element.addEventListener("updateFromSandbox", function (event) {
483+
const data = event.detail;
484+
if ("value" in data) {
485+
event.target.value = event.detail.value;
486+
} else if ("focus" in data) {
487+
event.target.focus({ preventScroll: false });
488+
}
489+
});
490+
491+
for (const eventType of Object.keys(this.data.actions)) {
492+
switch (eventType) {
493+
case "Format":
494+
element.addEventListener("blur", function (event) {
495+
window.dispatchEvent(
496+
new CustomEvent("dispatchEventInSandbox", {
497+
detail: {
498+
id,
499+
name: "Format",
500+
value: event.target.value,
501+
},
502+
})
503+
);
504+
});
505+
break;
506+
}
507+
}
508+
}
509+
479510
element.disabled = this.data.readOnly;
480511
element.name = this.data.fieldName;
481512

src/scripting_api/aform.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* Copyright 2020 Mozilla Foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
class AForm {
17+
constructor(document, app, util) {
18+
this._document = document;
19+
this._app = app;
20+
this._util = util;
21+
}
22+
23+
AFNumber_Format(
24+
nDec,
25+
sepStyle,
26+
negStyle,
27+
currStyle,
28+
strCurrency,
29+
bCurrencyPrepend
30+
) {
31+
const event = this._document._event;
32+
if (!event.value) {
33+
return;
34+
}
35+
36+
nDec = Math.abs(nDec);
37+
const value = event.value.trim().replace(",", ".");
38+
let number = Number.parseFloat(value);
39+
if (isNaN(number) || !isFinite(number)) {
40+
number = 0;
41+
}
42+
event.value = number.toFixed(nDec);
43+
}
44+
}
45+
46+
export { AForm };

src/scripting_api/app.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* Copyright 2020 Mozilla Foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
import { EventDispatcher } from "./event.js";
17+
import { NotSupportedError } from "./error.js";
18+
import { PDFObject } from "./pdf_object.js";
19+
20+
class App extends PDFObject {
21+
constructor(data) {
22+
super(data);
23+
this._document = data._document;
24+
this._objects = Object.create(null);
25+
this._eventDispatcher = new EventDispatcher(
26+
this._document,
27+
data.calculationOrder,
28+
this._objects
29+
);
30+
31+
// used in proxy.js to check that this the object with the backdoor
32+
this._isApp = true;
33+
}
34+
35+
// This function is called thanks to the proxy
36+
// when we call app['random_string'] to dispatch the event.
37+
_dispatchEvent(pdfEvent) {
38+
this._eventDispatcher.dispatch(pdfEvent);
39+
}
40+
41+
get activeDocs() {
42+
return [this._document.wrapped];
43+
}
44+
45+
set activeDocs(_) {
46+
throw new NotSupportedError("app.activeDocs");
47+
}
48+
49+
alert(
50+
cMsg,
51+
nIcon = 0,
52+
nType = 0,
53+
cTitle = "PDF.js",
54+
oDoc = null,
55+
oCheckbox = null
56+
) {
57+
this._send({ command: "alert", value: cMsg });
58+
}
59+
}
60+
61+
export { App };

src/scripting_api/console.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* Copyright 2020 Mozilla Foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
import { PDFObject } from "./pdf_object.js";
17+
18+
class Console extends PDFObject {
19+
clear() {
20+
this._send({ id: "clear" });
21+
}
22+
23+
hide() {
24+
/* Not implemented */
25+
}
26+
27+
println(msg) {
28+
if (typeof msg === "string") {
29+
this._send({ command: "println", value: "PDF.js Console:: " + msg });
30+
}
31+
}
32+
33+
show() {
34+
/* Not implemented */
35+
}
36+
}
37+
38+
export { Console };

src/scripting_api/doc.js

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/* Copyright 2020 Mozilla Foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
import { PDFObject } from "./pdf_object.js";
17+
18+
class Doc extends PDFObject {
19+
constructor(data) {
20+
super(data);
21+
22+
this._printParams = null;
23+
this._fields = Object.create(null);
24+
this._event = null;
25+
}
26+
27+
calculateNow() {
28+
this._eventDispatcher.calculateNow();
29+
}
30+
31+
getField(cName) {
32+
if (typeof cName !== "string") {
33+
throw new TypeError("Invalid field name: must be a string");
34+
}
35+
if (cName in this._fields) {
36+
return this._fields[cName];
37+
}
38+
for (const [name, field] of Object.entries(this._fields)) {
39+
if (name.includes(cName)) {
40+
return field;
41+
}
42+
}
43+
44+
return undefined;
45+
}
46+
}
47+
48+
export { Doc };

src/scripting_api/error.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* Copyright 2020 Mozilla Foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
class NotSupportedError extends Error {
17+
constructor(name) {
18+
super(`${name} isn't supported in PDF.js`);
19+
this.name = "NotSupportedError";
20+
}
21+
}
22+
23+
export { NotSupportedError };

src/scripting_api/event.js

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* Copyright 2020 Mozilla Foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
class Event {
17+
constructor(data) {
18+
this.change = data.change || "";
19+
this.changeEx = data.changeEx || null;
20+
this.commitKey = data.commitKey || 0;
21+
this.fieldFull = data.fieldFull || false;
22+
this.keyDown = data.keyDown || false;
23+
this.modifier = data.modifier || false;
24+
this.name = data.name;
25+
this.rc = true;
26+
this.richChange = data.richChange || [];
27+
this.richChangeEx = data.richChangeEx || [];
28+
this.richValue = data.richValue || [];
29+
this.selEnd = data.selEnd || 0;
30+
this.selStart = data.selStart || 0;
31+
this.shift = data.shift || false;
32+
this.source = data.source || null;
33+
this.target = data.target || null;
34+
this.targetName = data.targetName || "";
35+
this.type = "Field";
36+
this.value = data.value || null;
37+
this.willCommit = data.willCommit || false;
38+
}
39+
}
40+
41+
class EventDispatcher {
42+
constructor(document, calculationOrder, objects) {
43+
this._document = document;
44+
this._calculationOrder = calculationOrder;
45+
this._objects = objects;
46+
47+
this._document.obj._eventDispatcher = this;
48+
}
49+
50+
dispatch(baseEvent) {
51+
const id = baseEvent.id;
52+
if (!(id in this._objects)) {
53+
return;
54+
}
55+
56+
const name = baseEvent.name.replace(" ", "");
57+
const source = this._objects[id];
58+
const event = (this._document.obj._event = new Event(baseEvent));
59+
const oldValue = source.obj.value;
60+
61+
this.runActions(source, source, event, name);
62+
if (event.rc && oldValue !== event.value) {
63+
source.wrapped.value = event.value;
64+
}
65+
}
66+
67+
runActions(source, target, event, eventName) {
68+
event.source = source.wrapped;
69+
event.target = target.wrapped;
70+
event.name = eventName;
71+
event.rc = true;
72+
if (!target.obj._runActions(event)) {
73+
return true;
74+
}
75+
return event.rc;
76+
}
77+
}
78+
79+
export { Event, EventDispatcher };

0 commit comments

Comments
 (0)