Skip to content

Commit

Permalink
[Annotations] charLimit === 0 means unlimited (bug 1782564)
Browse files Browse the repository at this point in the history
Changing the charLimit in JS had no impact, so this patch aims to fix
that and add an integration test for it.
  • Loading branch information
calixteman committed Aug 18, 2022
1 parent b05010c commit 2ab5b9a
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 10 deletions.
4 changes: 2 additions & 2 deletions src/core/annotation.js
Expand Up @@ -2254,7 +2254,7 @@ class TextWidgetAnnotation extends WidgetAnnotation {

// Determine the maximum length of text in the field.
let maximumLength = getInheritableProperty({ dict, key: "MaxLen" });
if (!Number.isInteger(maximumLength) || maximumLength < 0) {
if (!Number.isInteger(maximumLength) || maximumLength <= 0) {
maximumLength = null;
}
this.data.maxLen = maximumLength;
Expand Down Expand Up @@ -2417,7 +2417,7 @@ class TextWidgetAnnotation extends WidgetAnnotation {
defaultValue: this.data.defaultFieldValue || "",
multiline: this.data.multiLine,
password: this.hasFieldFlag(AnnotationFieldFlag.PASSWORD),
charLimit: this.data.maxLen,
charLimit: this.data.maxLen || 0,
comb: this.data.comb,
editable: !this.data.readOnly,
hidden: this.data.hidden,
Expand Down
50 changes: 44 additions & 6 deletions src/display/annotation_layer.js
Expand Up @@ -1000,7 +1000,14 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
const storedData = storage.getValue(id, {
value: this.data.fieldValue,
});
const textContent = storedData.formattedValue || storedData.value || "";
let textContent = storedData.formattedValue || storedData.value || "";
const maxLen = storage.getValue(id, {
charLimit: this.data.maxLen,
}).charLimit;
if (maxLen !== null && textContent.length > maxLen) {
textContent = textContent.slice(0, maxLen);
}

const elementData = {
userValue: textContent,
formattedValue: null,
Expand Down Expand Up @@ -1030,6 +1037,10 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {

this._setRequired(element, this.data.required);

if (maxLen !== null) {
element.maxLength = maxLen;
}

element.addEventListener("input", event => {
storage.setValue(id, { value: event.target.value });
this.setPropertyOnSiblings(
Expand Down Expand Up @@ -1064,6 +1075,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
});

element.addEventListener("updatefromsandbox", jsEvent => {
const self = this;
const actions = {
value(event) {
elementData.userValue = event.detail.value ?? "";
Expand All @@ -1088,6 +1100,36 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
selRange(event) {
event.target.setSelectionRange(...event.detail.selRange);
},
charLimit(event) {
const { charLimit } = event.detail;
const { target } = event;
if (charLimit === 0) {
target.removeAttribute("maxLength");
return;
}

target.setAttribute("maxLength", charLimit);
let value = elementData.userValue;
if (!value || value.length <= charLimit) {
return;
}
value = value.slice(0, charLimit);
event.target.value = elementData.userValue = value;
storage.setValue(id, { value });

self.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
source: self,
detail: {
id,
name: "Keystroke",
value,
willCommit: true,
commitKey: 1,
selStart: target.selectionStart,
selEnd: target.selectionEnd,
},
});
},
};
this._dispatchEventFromSandbox(actions, jsEvent);
});
Expand Down Expand Up @@ -1225,13 +1267,9 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
element.addEventListener("blur", blurListener);
}

if (this.data.maxLen !== null) {
element.maxLength = this.data.maxLen;
}

if (this.data.comb) {
const fieldWidth = this.data.rect[2] - this.data.rect[0];
const combWidth = fieldWidth / this.data.maxLen;
const combWidth = fieldWidth / maxLen;

element.classList.add("comb");
element.style.letterSpacing = `calc(${combWidth}px * var(--scale-factor) - 1ch)`;
Expand Down
13 changes: 12 additions & 1 deletion src/scripting_api/field.js
Expand Up @@ -29,7 +29,6 @@ class Field extends PDFObject {
this.buttonScaleHow = data.buttonScaleHow;
this.ButtonScaleWhen = data.buttonScaleWhen;
this.calcOrderIndex = data.calcOrderIndex;
this.charLimit = data.charLimit;
this.comb = data.comb;
this.commitOnSelChange = data.commitOnSelChange;
this.currentValueIndices = data.currentValueIndices;
Expand Down Expand Up @@ -69,6 +68,7 @@ class Field extends PDFObject {
this._browseForFileToSubmit = data.browseForFileToSubmit || null;
this._buttonCaption = null;
this._buttonIcon = null;
this._charLimit = data.charLimit;
this._children = null;
this._currentValueIndices = data.currentValueIndices || 0;
this._document = data.doc;
Expand Down Expand Up @@ -151,6 +151,17 @@ class Field extends PDFObject {
this.fillColor = color;
}

get charLimit() {
return this._charLimit;
}

set charLimit(limit) {
if (typeof limit !== "number") {
throw new Error("Invalid argument value");
}
this._charLimit = Math.max(0, Math.floor(limit));
}

get numItems() {
if (!this._isChoice) {
throw new Error("Not a choice widget");
Expand Down
61 changes: 61 additions & 0 deletions test/integration/scripting_spec.js
Expand Up @@ -1492,4 +1492,65 @@ describe("Interaction", () => {
);
});
});

describe("in bug1782564.pdf", () => {
let pages;

beforeAll(async () => {
pages = await loadAndWait("bug1782564.pdf", getSelector("7R"));
});

afterAll(async () => {
await closePages(pages);
});

it("must check that charLimit is correctly set", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await page.waitForFunction(
"window.PDFViewerApplication.scriptingReady === true"
);

await clearInput(page, getSelector("7R"));
// By default the charLimit is 0 which means that the input
// length is unlimited.
await page.type(getSelector("7R"), "abcdefghijklmnopq", {
delay: 10,
});

let value = await page.$eval(getSelector("7R"), el => el.value);
expect(value)
.withContext(`In ${browserName}`)
.toEqual("abcdefghijklmnopq");

// charLimit is set to 1
await page.click(getSelector("9R"));

await page.waitForFunction(
`document.querySelector('${getSelector(
"7R"
)}').value !== "abcdefgh"`
);

value = await page.$eval(getSelector("7R"), el => el.value);
expect(value).withContext(`In ${browserName}`).toEqual("a");

await clearInput(page, getSelector("7R"));
await page.type(getSelector("7R"), "xyz", { delay: 10 });

value = await page.$eval(getSelector("7R"), el => el.value);
expect(value).withContext(`In ${browserName}`).toEqual("x");

// charLimit is set to 2
await page.click(getSelector("9R"));

await clearInput(page, getSelector("7R"));
await page.type(getSelector("7R"), "xyz", { delay: 10 });

value = await page.$eval(getSelector("7R"), el => el.value);
expect(value).withContext(`In ${browserName}`).toEqual("xy");
})
);
});
});
});
1 change: 1 addition & 0 deletions test/pdfs/.gitignore
Expand Up @@ -535,3 +535,4 @@
!issue15092.pdf
!bug1782186.pdf
!tracemonkey_a11y.pdf
!bug1782564.pdf
Binary file added test/pdfs/bug1782564.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion test/unit/api_spec.js
Expand Up @@ -1390,7 +1390,7 @@ describe("api", function () {
defaultValue: "",
multiline: false,
password: false,
charLimit: null,
charLimit: 0,
comb: false,
editable: true,
hidden: false,
Expand Down

0 comments on commit 2ab5b9a

Please sign in to comment.