From 5c0054d58dc0ea3b8869a7c62311fe19a7a18656 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Fri, 16 Jun 2023 18:45:09 +0200 Subject: [PATCH] Guess that a checkbox belongs to a group in using its T value (bug 1838855) --- src/core/annotation.js | 11 ++++++++ src/core/document.js | 5 ++++ src/display/annotation_layer.js | 8 +++--- test/integration/annotation_spec.js | 40 +++++++++++++++++++++++++++++ test/unit/api_spec.js | 16 ++++++++++++ 5 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/core/annotation.js b/src/core/annotation.js index 0f15834a0..18fc96589 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -1530,6 +1530,17 @@ class WidgetAnnotation extends Annotation { if (data.fieldName === undefined) { data.fieldName = this._constructFieldName(dict); } + if ( + data.fieldName && + /\[\d+\]$/.test(data.fieldName) && + !dict.has("Kids") + ) { + data.baseFieldName = data.fieldName.substring( + 0, + data.fieldName.lastIndexOf("[") + ); + } + if (data.actions === undefined) { data.actions = collectActions(xref, dict, AnnotationActionEventType); } diff --git a/src/core/document.js b/src/core/document.js index f18334597..6b0b1e8c1 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -1674,6 +1674,11 @@ class PDFDocument { } } + if (!field.has("Kids") && /\[\d+\]$/.test(name)) { + // We've a terminal node: strip the index. + name = name.substring(0, name.lastIndexOf("[")); + } + if (!promises.has(name)) { promises.set(name, []); } diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index 167310c48..725451a92 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -1106,7 +1106,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement { element.setAttribute("data-element-id", id); element.disabled = this.data.readOnly; - element.name = this.data.fieldName; + element.name = this.data.baseFieldName || this.data.fieldName; element.tabIndex = DEFAULT_TAB_INDEX; this._setRequired(element, this.data.required); @@ -1408,7 +1408,7 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement { element.disabled = data.readOnly; this._setRequired(element, this.data.required); element.type = "checkbox"; - element.name = data.fieldName; + element.name = data.baseFieldName || data.fieldName; if (value) { element.setAttribute("checked", true); } @@ -1493,7 +1493,7 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement { element.disabled = data.readOnly; this._setRequired(element, this.data.required); element.type = "radio"; - element.name = data.fieldName; + element.name = data.baseFieldName || data.fieldName; if (value) { element.setAttribute("checked", true); } @@ -1606,7 +1606,7 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { selectElement.disabled = this.data.readOnly; this._setRequired(selectElement, this.data.required); - selectElement.name = this.data.fieldName; + selectElement.name = this.data.baseFieldName || this.data.fieldName; selectElement.tabIndex = DEFAULT_TAB_INDEX; let addAnEmptyEntry = this.data.combo && this.data.options.length > 0; diff --git a/test/integration/annotation_spec.js b/test/integration/annotation_spec.js index 97cea0a52..68152e1cf 100644 --- a/test/integration/annotation_spec.js +++ b/test/integration/annotation_spec.js @@ -120,6 +120,46 @@ describe("Checkbox annotation", () => { ); }); }); + + describe("f1040_2022.pdf", () => { + let pages; + + beforeAll(async () => { + pages = await loadAndWait( + "f1040_2022.pdf", + "[data-annotation-id='1566R']" + ); + }); + + afterAll(async () => { + await closePages(pages); + }); + + it("must check the checkbox", async () => { + await Promise.all( + pages.map(async ([_browserName, page]) => { + const selectors = [1566, 1568, 1569, 1570, 1571].map( + id => `[data-annotation-id='${id}R']` + ); + for (const selector of selectors) { + await page.click(selector); + for (const otherSelector of selectors) { + if (otherSelector === selector) { + await page.waitForFunction( + `document.querySelector("${selector} > :first-child").checked` + ); + } else { + await page.waitForFunction( + `!document.querySelector("${otherSelector} > :first-child").checked` + ); + } + } + page.waitForTimeout(10); + } + }) + ); + }); + }); }); describe("Text widget", () => { diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index d323a8d3a..8da40a71d 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -1491,6 +1491,22 @@ describe("api", function () { await loadingTask.destroy(); }); + it("check field object for group of buttons", async function () { + if (isNodeJS) { + pending("Linked test-cases are not supported in Node.js."); + } + + const loadingTask = getDocument(buildGetDocumentParams("f1040_2022.pdf")); + const pdfDoc = await loadingTask.promise; + const fieldObjects = await pdfDoc.getFieldObjects(); + + expect( + fieldObjects["topmostSubform[0].Page1[0].c1_01"].map(o => o.id) + ).toEqual(["1566R", "1568R", "1569R", "1570R", "1571R"]); + + await loadingTask.destroy(); + }); + it("gets non-existent calculationOrder", async function () { const calculationOrder = await pdfDocument.getCalculationOrderIds(); expect(calculationOrder).toEqual(null);