mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-06-12 21:21:04 +02:00
Merge pull request #21407 from calixteman/fix_hidden_updated_field
Fix form fields with their own canvas updated on non-rendered pages
This commit is contained in:
commit
c541d24ac3
@ -1321,15 +1321,6 @@ class WidgetAnnotationElement extends AnnotationElement {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
showElementAndHideCanvas(element) {
|
||||
if (this.data.hasOwnCanvas) {
|
||||
if (element.previousSibling?.nodeName === "CANVAS") {
|
||||
element.previousSibling.hidden = true;
|
||||
}
|
||||
element.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
_getKeyModifier(event) {
|
||||
return FeatureTest.platform.isMac ? event.metaKey : event.ctrlKey;
|
||||
}
|
||||
@ -1547,7 +1538,14 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
}
|
||||
}
|
||||
if (this.data.hasOwnCanvas) {
|
||||
element.hidden = true;
|
||||
// The rendered appearance (a canvas) is shown instead of this element.
|
||||
this.container.classList.add("hasOwnCanvas");
|
||||
if (storage.has(id)) {
|
||||
// Once the field is modified, the `sandboxModified` class hides the
|
||||
// (now outdated) canvas and shows this element instead.
|
||||
// The field can already have been modified.
|
||||
this.container.classList.add("sandboxModified");
|
||||
}
|
||||
}
|
||||
GetElementsByNameSet.add(element);
|
||||
this.contentElement = element;
|
||||
@ -1637,7 +1635,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
});
|
||||
|
||||
element.addEventListener("updatefromsandbox", jsEvent => {
|
||||
this.showElementAndHideCanvas(jsEvent.target);
|
||||
this.container.classList.add("sandboxModified");
|
||||
const actions = {
|
||||
value(event) {
|
||||
elementData.userValue = event.detail.value ?? "";
|
||||
|
||||
@ -1886,23 +1886,30 @@ describe("Interaction", () => {
|
||||
const selector = getAnnotationSelector("9R");
|
||||
const hasVisibleCanvas = await page.$eval(
|
||||
`${selector} > canvas`,
|
||||
elem => elem && !elem.hasAttribute("hidden")
|
||||
elem => getComputedStyle(elem).display !== "none"
|
||||
);
|
||||
expect(hasVisibleCanvas)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual(true);
|
||||
|
||||
const hasHiddenInput = await page.$eval(`${selector} > input`, elem =>
|
||||
elem?.hasAttribute("hidden")
|
||||
const hasHiddenInput = await page.$eval(
|
||||
`${selector} > input`,
|
||||
elem => getComputedStyle(elem).display === "none"
|
||||
);
|
||||
expect(hasHiddenInput).withContext(`In ${browserName}`).toEqual(true);
|
||||
|
||||
await page.click(getSelector("12R"));
|
||||
await page.waitForSelector(`${selector} > canvas[hidden]`);
|
||||
await page.waitForFunction(
|
||||
sel =>
|
||||
getComputedStyle(document.querySelector(`${sel} > canvas`))
|
||||
.display === "none",
|
||||
{},
|
||||
selector
|
||||
);
|
||||
|
||||
const hasHiddenCanvas = await page.$eval(
|
||||
`${selector} > canvas`,
|
||||
elem => elem?.hasAttribute("hidden")
|
||||
elem => getComputedStyle(elem).display === "none"
|
||||
);
|
||||
expect(hasHiddenCanvas)
|
||||
.withContext(`In ${browserName}`)
|
||||
@ -1910,7 +1917,7 @@ describe("Interaction", () => {
|
||||
|
||||
const hasVisibleInput = await page.$eval(
|
||||
`${selector} > input`,
|
||||
elem => elem && !elem.hasAttribute("hidden")
|
||||
elem => getComputedStyle(elem).display !== "none"
|
||||
);
|
||||
expect(hasVisibleInput)
|
||||
.withContext(`In ${browserName}`)
|
||||
@ -2696,4 +2703,89 @@ describe("Interaction", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("in text_field_own_canvas_calc.pdf", () => {
|
||||
let pages;
|
||||
|
||||
beforeEach(async () => {
|
||||
pages = await loadAndWait(
|
||||
"text_field_own_canvas_calc.pdf",
|
||||
getSelector("7R"),
|
||||
"page-fit"
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await closePages(pages);
|
||||
});
|
||||
|
||||
it("must show the field instead of its canvas when it was calculated while its page wasn't rendered", async () => {
|
||||
await Promise.all(
|
||||
pages.map(async ([browserName, page]) => {
|
||||
// The read-only "Mirror" field (8R) is on page 3, which hasn't been
|
||||
// rendered yet.
|
||||
expect(await page.$(getSelector("8R")))
|
||||
.withContext(`In ${browserName}`)
|
||||
.toBeNull();
|
||||
|
||||
// Modifying the "Source" field (7R) on page 1 mirrors its value into
|
||||
// the read-only field on page 3 through a Calculate action.
|
||||
await page.type(getSelector("7R"), "Hello PDF.js");
|
||||
await page.keyboard.press("Enter");
|
||||
await waitForEntryInStorage(
|
||||
page,
|
||||
"8R",
|
||||
{ value: "Hello PDF.js" },
|
||||
(stored, expected) =>
|
||||
!!stored &&
|
||||
JSON.parse(stored).value === JSON.parse(expected).value
|
||||
);
|
||||
|
||||
// The value has been mirrored into the storage while page 3, and
|
||||
// hence its annotation layer, hasn't been rendered yet.
|
||||
const page3AnnotationCount = await page.evaluate(() => {
|
||||
const layer = document.querySelector(
|
||||
'.page[data-page-number="3"] .annotationLayer'
|
||||
);
|
||||
return layer ? layer.childElementCount : 0;
|
||||
});
|
||||
expect(page3AnnotationCount)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual(0);
|
||||
|
||||
// Render page 3.
|
||||
await scrollIntoView(page, '.page[data-page-number="3"]');
|
||||
const inputPage3Selector = getSelector("8R");
|
||||
await page.waitForSelector(
|
||||
`.sandboxModified:has(${inputPage3Selector})`,
|
||||
{ visible: true }
|
||||
);
|
||||
|
||||
// The field must show its (calculated) value and the now-outdated
|
||||
// canvas must be hidden.
|
||||
const { value, isFieldVisible, isCanvasHidden } = await page.evaluate(
|
||||
sel => {
|
||||
const input = document.querySelector(sel);
|
||||
const canvas = input
|
||||
.closest("section")
|
||||
.querySelector("canvas.annotationContent");
|
||||
return {
|
||||
value: input.value,
|
||||
isFieldVisible: getComputedStyle(input).display !== "none",
|
||||
isCanvasHidden:
|
||||
!!canvas && getComputedStyle(canvas).display === "none",
|
||||
};
|
||||
},
|
||||
inputPage3Selector
|
||||
);
|
||||
|
||||
expect(value)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual("Hello PDF.js");
|
||||
expect(isFieldVisible).withContext(`In ${browserName}`).toBe(true);
|
||||
expect(isCanvasHidden).withContext(`In ${browserName}`).toBe(true);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -931,3 +931,4 @@
|
||||
!issue21346.pdf
|
||||
!cidfont_cmap_overflow.pdf
|
||||
!jbig2_file_header.pdf
|
||||
!text_field_own_canvas_calc.pdf
|
||||
|
||||
64
test/pdfs/text_field_own_canvas_calc.pdf
Normal file
64
test/pdfs/text_field_own_canvas_calc.pdf
Normal file
@ -0,0 +1,64 @@
|
||||
%PDF-1.7
|
||||
%ÿÿÿÿ
|
||||
1 0 obj
|
||||
<< /Type /Catalog /Pages 2 0 R /AcroForm 3 0 R >>
|
||||
endobj
|
||||
2 0 obj
|
||||
<< /Type /Pages /Kids [4 0 R 5 0 R 6 0 R] /Count 3 >>
|
||||
endobj
|
||||
3 0 obj
|
||||
<< /Fields [7 0 R 8 0 R] /CO [8 0 R] /DR << /Font << /Helv 9 0 R >> >> /DA (/Helv 12 Tf 0 g) /NeedAppearances true >>
|
||||
endobj
|
||||
4 0 obj
|
||||
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << >> /Annots [7 0 R] >>
|
||||
endobj
|
||||
5 0 obj
|
||||
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << >> >>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << >> /Annots [8 0 R] >>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Type /Annot /Subtype /Widget /FT /Tx /T (Source) /Rect [100 650 300 670] /P 4 0 R /F 4 /DA (/Helv 12 Tf 0 g) /AP << /N 10 0 R >> >>
|
||||
endobj
|
||||
8 0 obj
|
||||
<< /Type /Annot /Subtype /Widget /FT /Tx /T (Mirror) /Ff 1 /Rect [100 650 300 670] /P 6 0 R /F 4 /DA (/Helv 12 Tf 0 g) /AA << /C 11 0 R >> /AP << /N 12 0 R >> >>
|
||||
endobj
|
||||
9 0 obj
|
||||
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Name /Helv >>
|
||||
endobj
|
||||
10 0 obj
|
||||
<< /Type /XObject /Subtype /Form /BBox [0 0 200 20] /Resources << /Font << /Helv 9 0 R >> >> /Length 50 >>
|
||||
stream
|
||||
/Tx BMC q BT /Helv 12 Tf 0 g 2 5 Td () Tj ET Q EMC
|
||||
endstream
|
||||
endobj
|
||||
11 0 obj
|
||||
<< /Type /Action /S /JavaScript /JS (event.value = this.getField("Source").value;) >>
|
||||
endobj
|
||||
12 0 obj
|
||||
<< /Type /XObject /Subtype /Form /BBox [0 0 200 20] /Resources << /Font << /Helv 9 0 R >> >> /Length 49 >>
|
||||
stream
|
||||
/Tx BMC q 0.85 0.85 0.85 rg 0 0 200 20 re f Q EMC
|
||||
endstream
|
||||
endobj
|
||||
xref
|
||||
0 13
|
||||
0000000000 65535 f
|
||||
0000000015 00000 n
|
||||
0000000080 00000 n
|
||||
0000000149 00000 n
|
||||
0000000282 00000 n
|
||||
0000000386 00000 n
|
||||
0000000474 00000 n
|
||||
0000000578 00000 n
|
||||
0000000729 00000 n
|
||||
0000000906 00000 n
|
||||
0000000988 00000 n
|
||||
0000001179 00000 n
|
||||
0000001281 00000 n
|
||||
trailer
|
||||
<< /Size 13 /Root 1 0 R >>
|
||||
startxref
|
||||
1471
|
||||
%%EOF
|
||||
@ -138,6 +138,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* A field rendered to its own canvas shows that canvas and keeps its editable
|
||||
element hidden. Once the field is modified the canvas is outdated, so it's
|
||||
hidden and the element is shown instead. */
|
||||
.hasOwnCanvas:not(.sandboxModified) :is(input, textarea) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hasOwnCanvas.sandboxModified canvas.annotationContent {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.textLayer.selecting ~ & section {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user