Skip to content

Commit

Permalink
JS -- Fix doc.getField and add missing field methods
Browse files Browse the repository at this point in the history
 - getField("foo") was wrongly returning a field named "foobar";
 - field object had few missing unimplemented methods
  • Loading branch information
calixteman committed Feb 1, 2021
1 parent c92011e commit 5fad6b2
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 3 deletions.
37 changes: 36 additions & 1 deletion src/scripting_api/doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -828,15 +828,50 @@ class Doc extends PDFObject {
return searchedField;
}

const parts = cName.split("#");
let childIndex = NaN;
if (parts.length === 2) {
childIndex = Math.floor(parseFloat(parts[1]));
cName = parts[0];
}

for (const [name, field] of this._fields.entries()) {
if (name.includes(cName)) {
if (name.endsWith(cName)) {
if (!isNaN(childIndex)) {
const children = this._getChildren(name);
if (childIndex < 0 || childIndex >= children.length) {
childIndex = 0;
}
if (childIndex < children.length) {
this._fields.set(cName, children[childIndex]);
return children[childIndex];
}
}
this._fields.set(cName, field);
return field;
}
}

return undefined;
}

_getChildren(fieldName) {
// Children of foo.bar are foo.bar.oof, foo.bar.rab
// but not foo.bar.oof.FOO.
const len = fieldName.length;
const children = [];
const pattern = /^\.[^.]+$/;
for (const [name, field] of this._fields.entries()) {
if (name.startsWith(fieldName)) {
const finalPart = name.slice(len);
if (finalPart.match(pattern)) {
children.push(field);
}
}
}
return children;
}

getIcon() {
/* Not implemented */
}
Expand Down
74 changes: 73 additions & 1 deletion src/scripting_api/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Field extends PDFObject {
this.doNotSpellCheck = data.doNotSpellCheck;
this.delay = data.delay;
this.display = data.display;
this.doc = data.doc;
this.doc = data.doc.wrapped;
this.editable = data.editable;
this.exportValues = data.exportValues;
this.fileSelect = data.fileSelect;
Expand Down Expand Up @@ -68,8 +68,13 @@ class Field extends PDFObject {

// Private
this._actions = createActionsMap(data.actions);
this._browseForFileToSubmit = data.browseForFileToSubmit || null;
this._buttonCaption = null;
this._buttonIcon = null;
this._children = null;
this._currentValueIndices = data.currentValueIndices || 0;
this._document = data.doc;
this._fieldPath = data.fieldPath;
this._fillColor = data.fillColor || ["T"];
this._isChoice = Array.isArray(data.items);
this._items = data.items || [];
Expand Down Expand Up @@ -197,6 +202,48 @@ class Field extends PDFObject {
this._valueAsString = val ? val.toString() : "";
}

browseForFileToSubmit() {
if (this._browseForFileToSubmit) {
// TODO: implement this function on Firefox side
// we can use nsIFilePicker but open method is async.
// Maybe it's possible to use a html input (type=file) too.
this._browseForFileToSubmit();
}
}

buttonGetCaption(nFace = 0) {
if (this._buttonCaption) {
return this._buttonCaption[nFace];
}
return "";
}

buttonGetIcon(nFace = 0) {
if (this._buttonIcon) {
return this._buttonIcon[nFace];
}
return null;
}

buttonImportIcon(cPath = null, nPave = 0) {
/* Not implemented */
}

buttonSetCaption(cCaption, nFace = 0) {
if (!this._buttonCaption) {
this._buttonCaption = ["", "", ""];
}
this._buttonCaption[nFace] = cCaption;
// TODO: send to the annotation layer
}

buttonSetIcon(oIcon, nFace = 0) {
if (!this._buttonIcon) {
this._buttonIcon = [null, null, null];
}
this._buttonIcon[nFace] = oIcon;
}

checkThisBox(nWidget, bCheckIt = true) {}

clearItems() {
Expand Down Expand Up @@ -260,6 +307,17 @@ class Field extends PDFObject {
return bExportValue ? item.exportValue : item.displayValue;
}

getArray() {
if (this._children === null) {
this._children = this._document.obj._getChildren(this._fieldPath);
}
return this._children;
}

getLock() {
return undefined;
}

isBoxChecked(nWidget) {
return false;
}
Expand Down Expand Up @@ -337,6 +395,20 @@ class Field extends PDFObject {
this._send({ id: this._id, items: this._items });
}

setLock() {}

signatureGetModifications() {}

signatureGetSeedValue() {}

signatureInfo() {}

signatureSetSeedValue() {}

signatureSign() {}

signatureValidate() {}

_isButton() {
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion src/scripting_api/initialization.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ function initSandbox(params) {
const obj = objs[0];
obj.send = send;
obj.globalEval = globalEval;
obj.doc = _document.wrapped;
obj.doc = _document;
obj.fieldPath = name;
let field;
if (obj.type === "radiobutton") {
const otherButtons = objs.slice(1);
Expand Down
58 changes: 58 additions & 0 deletions test/unit/scripting_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,64 @@ describe("Scripting", function () {
done.fail(ex);
}
});

it("should get field using a path", async function (done) {
const base = value => {
return {
id: getId(),
value,
actions: {},
type: "text",
};
};
const data = {
objects: {
A: [base(1)],
"A.B": [base(2)],
"A.B.C": [base(3)],
"A.B.C.D": [base(4)],
"A.B.C.D.E": [base(5)],
"A.B.C.D.E.F": [base(6)],
"A.B.C.D.G": [base(7)],
C: [base(8)],
},
appInfo: { language: "en-US", platform: "Linux x86_64" },
calculationOrder: [],
dispatchEventName: "_dispatchMe",
};
sandbox.createSandbox(data);

try {
await myeval(`this.getField("A").value`).then(value => {
expect(value).toEqual(1);
});
await myeval(`this.getField("B.C").value`).then(value => {
expect(value).toEqual(3);
});
// path has been cached so try again
await myeval(`this.getField("B.C").value`).then(value => {
expect(value).toEqual(3);
});
await myeval(`this.getField("B.C.D#0").value`).then(value => {
expect(value).toEqual(5);
});
await myeval(`this.getField("B.C.D#1").value`).then(value => {
expect(value).toEqual(7);
});
await myeval(`this.getField("C").value`).then(value => {
expect(value).toEqual(8);
});

await myeval(
`this.getField("A.B.C.D").getArray().map((x) => x.value)`
).then(value => {
expect(value).toEqual([5, 7]);
});
done();
} catch (ex) {
done.fail(ex);
}
});
});

describe("Util", function () {
Expand Down

0 comments on commit 5fad6b2

Please sign in to comment.