Merge pull request #16433 from calixteman/bug1825002

For text widgets, get the text from the AP stream instead of from the format callback (bug 1825002)
This commit is contained in:
calixteman 2023-05-17 16:48:59 +02:00 committed by GitHub
commit 839be801a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 93 additions and 35 deletions

View File

@ -2461,6 +2461,10 @@ class TextWidgetAnnotation extends WidgetAnnotation {
this.data.doNotScroll = this.hasFieldFlag(AnnotationFieldFlag.DONOTSCROLL); this.data.doNotScroll = this.hasFieldFlag(AnnotationFieldFlag.DONOTSCROLL);
} }
get hasTextContent() {
return !!this.appearance;
}
_getCombAppearance( _getCombAppearance(
defaultAppearance, defaultAppearance,
font, font,

View File

@ -1049,7 +1049,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
const storedData = storage.getValue(id, { const storedData = storage.getValue(id, {
value: this.data.fieldValue, value: this.data.fieldValue,
}); });
let textContent = storedData.formattedValue || storedData.value || ""; let textContent = storedData.value || "";
const maxLen = storage.getValue(id, { const maxLen = storage.getValue(id, {
charLimit: this.data.maxLen, charLimit: this.data.maxLen,
}).charLimit; }).charLimit;
@ -1057,23 +1057,29 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
textContent = textContent.slice(0, maxLen); textContent = textContent.slice(0, maxLen);
} }
let fieldFormattedValues =
storedData.formattedValue || this.data.textContent?.join("\n") || null;
if (fieldFormattedValues && this.data.comb) {
fieldFormattedValues = fieldFormattedValues.replaceAll(/\s+/g, "");
}
const elementData = { const elementData = {
userValue: textContent, userValue: textContent,
formattedValue: null, formattedValue: fieldFormattedValues,
lastCommittedValue: null, lastCommittedValue: null,
commitKey: 1, commitKey: 1,
}; };
if (this.data.multiLine) { if (this.data.multiLine) {
element = document.createElement("textarea"); element = document.createElement("textarea");
element.textContent = textContent; element.textContent = fieldFormattedValues ?? textContent;
if (this.data.doNotScroll) { if (this.data.doNotScroll) {
element.style.overflowY = "hidden"; element.style.overflowY = "hidden";
} }
} else { } else {
element = document.createElement("input"); element = document.createElement("input");
element.type = "text"; element.type = "text";
element.setAttribute("value", textContent); element.setAttribute("value", fieldFormattedValues ?? textContent);
if (this.data.doNotScroll) { if (this.data.doNotScroll) {
element.style.overflowX = "hidden"; element.style.overflowX = "hidden";
} }

View File

@ -98,8 +98,9 @@ class EventDispatcher {
// errors in the case where a formatter is using one of those named // errors in the case where a formatter is using one of those named
// actions (see #15818). // actions (see #15818).
this._document.obj._initActions(); this._document.obj._initActions();
// Before running the Open event, we format all the fields // Before running the Open event, we run the format callbacks but
// (see bug 1766987). // without changing the value of the fields.
// Acrobat does the same thing.
this.formatAll(); this.formatAll();
} }
if ( if (
@ -232,13 +233,7 @@ class EventDispatcher {
const event = (globalThis.event = new Event({})); const event = (globalThis.event = new Event({}));
for (const source of Object.values(this._objects)) { for (const source of Object.values(this._objects)) {
event.value = source.obj.value; event.value = source.obj.value;
if (this.runActions(source, source, event, "Format")) { this.runActions(source, source, event, "Format");
source.obj._send({
id: source.obj._id,
siblings: source.obj._siblings,
formattedValue: event.value?.toString?.(),
});
}
} }
} }

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { createActionsMap, FieldType, getFieldType } from "./common.js"; import { createActionsMap, getFieldType } from "./common.js";
import { Color } from "./color.js"; import { Color } from "./color.js";
import { PDFObject } from "./pdf_object.js"; import { PDFObject } from "./pdf_object.js";
@ -247,29 +247,15 @@ class Field extends PDFObject {
return; return;
} }
if (value === "") { if (value === "" || typeof value !== "string") {
this._value = ""; this._originalValue = undefined;
} else if (typeof value === "string") {
switch (this._fieldType) {
case FieldType.none: {
this._originalValue = value;
const _value = value.trim().replace(",", ".");
this._value = !isNaN(_value) ? parseFloat(_value) : value;
break;
}
case FieldType.number:
case FieldType.percent: {
const _value = value.trim().replace(",", ".");
const number = parseFloat(_value);
this._value = !isNaN(number) ? number : 0;
break;
}
default:
this._value = value;
}
} else {
this._value = value; this._value = value;
return;
} }
this._originalValue = value;
const _value = value.trim().replace(",", ".");
this._value = !isNaN(_value) ? parseFloat(_value) : value;
} }
_getValue() { _getValue() {

View File

@ -1897,4 +1897,70 @@ describe("Interaction", () => {
); );
}); });
}); });
describe("in bug1825002.pdf", () => {
let pages;
beforeAll(async () => {
pages = await loadAndWait("bug1825002.pdf", getSelector("23R"));
});
afterAll(async () => {
await closePages(pages);
});
it("must check that a field has the correct formatted value", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await page.waitForFunction(
"window.PDFViewerApplication.scriptingReady === true"
);
let text = await page.$eval(getSelector("23R"), el => el.value);
expect(text)
.withContext(`In ${browserName}`)
.toEqual("ABCDEFGHIJKLMN");
await page.click(getSelector("23R"));
await page.waitForFunction(
`${getQuerySelector("23R")}.value !== "ABCDEFGHIJKLMN"`
);
text = await page.$eval(getSelector("23R"), el => el.value);
expect(text).withContext(`In ${browserName}`).toEqual("123,45.7A");
})
);
});
it("must check that a field is empty", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await page.waitForFunction(
"window.PDFViewerApplication.scriptingReady === true"
);
let text = await page.$eval(getSelector("26R"), el => el.value);
expect(text).withContext(`In ${browserName}`).toEqual("");
await page.click(getSelector("26R"));
await page.type(getSelector("26R"), "abcde", { delay: 10 });
await page.click(getSelector("23R"));
await page.waitForTimeout(10);
await page.click(getSelector("26R"));
await page.keyboard.down("Control");
await page.keyboard.press("A");
await page.keyboard.up("Control");
await page.keyboard.press("Backspace");
await page.click(getSelector("23R"));
await page.waitForTimeout(10);
text = await page.$eval(getSelector("26R"), el => el.value);
expect(text).withContext(`In ${browserName}`).toEqual("");
})
);
});
});
}); });

View File

@ -591,3 +591,4 @@
!issue16316.pdf !issue16316.pdf
!issue14565.pdf !issue14565.pdf
!multiline.pdf !multiline.pdf
!bug1825002.pdf

BIN
test/pdfs/bug1825002.pdf Executable file

Binary file not shown.