Merge pull request #13427 from calixteman/xfa_storage

XFA - Add a storage to save fields values
This commit is contained in:
Brendan Dahl 2021-05-28 12:10:08 -07:00 committed by GitHub
commit a6484c9861
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 30 deletions

View File

@ -941,11 +941,14 @@ class CheckButton extends XFAObject {
style.height = size; style.height = size;
} }
const fieldId = this[$getParent]()[$getParent]()[$uid];
const input = { const input = {
name: "input", name: "input",
attributes: { attributes: {
class: "xfaCheckbox", class: "xfaCheckbox",
fieldId,
type: "radio", type: "radio",
id: `${fieldId}-radio`,
}, },
}; };
@ -1023,6 +1026,7 @@ class ChoiceList extends XFAObject {
const selectAttributes = { const selectAttributes = {
class: "xfaSelect", class: "xfaSelect",
fieldId: this[$getParent]()[$getParent]()[$uid],
style, style,
}; };
@ -1249,6 +1253,7 @@ class DateTimeEdit extends XFAObject {
name: "input", name: "input",
attributes: { attributes: {
type: "text", type: "text",
fieldId: this[$getParent]()[$getParent]()[$uid],
class: "xfaTextfield", class: "xfaTextfield",
style, style,
}, },
@ -3012,6 +3017,7 @@ class NumericEdit extends XFAObject {
name: "input", name: "input",
attributes: { attributes: {
type: "text", type: "text",
fieldId: this[$getParent]()[$getParent]()[$uid],
class: "xfaTextfield", class: "xfaTextfield",
style, style,
}, },
@ -4550,6 +4556,7 @@ class TextEdit extends XFAObject {
html = { html = {
name: "textarea", name: "textarea",
attributes: { attributes: {
fieldId: this[$getParent]()[$getParent]()[$uid],
class: "xfaTextfield", class: "xfaTextfield",
style, style,
}, },
@ -4559,6 +4566,7 @@ class TextEdit extends XFAObject {
name: "input", name: "input",
attributes: { attributes: {
type: "text", type: "text",
fieldId: this[$getParent]()[$getParent]()[$uid],
class: "xfaTextfield", class: "xfaTextfield",
style, style,
}, },

View File

@ -14,9 +14,60 @@
*/ */
class XfaLayer { class XfaLayer {
static setAttributes(html, attrs) { static setupStorage(html, fieldId, element, storage) {
for (const [key, value] of Object.entries(attrs)) { const storedData = storage.getValue(fieldId, { value: null });
if (value === null || value === undefined) { switch (element.name) {
case "textarea":
html.textContent = storedData.value !== null ? storedData.value : "";
html.addEventListener("input", event => {
storage.setValue(fieldId, { value: event.target.value });
});
break;
case "input":
if (storedData.value !== null) {
html.setAttribute("value", storedData.value);
}
if (element.attributes.type === "radio") {
html.addEventListener("change", event => {
const { target } = event;
for (const radio of document.getElementsByName(target.name)) {
if (radio !== target) {
const id = radio.id;
storage.setValue(id.split("-")[0], { value: false });
}
}
storage.setValue(fieldId, { value: target.checked });
});
} else {
html.addEventListener("input", event => {
storage.setValue(fieldId, { value: event.target.value });
});
}
break;
case "select":
if (storedData.value !== null) {
for (const option of element.children) {
if (option.attributes.value === storedData.value) {
option.attributes.selected = true;
}
}
}
html.addEventListener("input", event => {
const options = event.target.options;
const value =
options.selectedIndex === -1
? null
: options[options.selectedIndex].value;
storage.setValue(fieldId, { value });
});
break;
}
}
static setAttributes(html, element, storage) {
const { attributes } = element;
for (const [key, value] of Object.entries(attributes)) {
if (value === null || value === undefined || key === "fieldId") {
continue; continue;
} }
@ -30,13 +81,20 @@ class XfaLayer {
Object.assign(html.style, value); Object.assign(html.style, value);
} }
} }
// Set the value after the others to be sure overwrite
// any other values.
if (storage && attributes.fieldId !== undefined) {
this.setupStorage(html, attributes.fieldId, element, storage);
}
} }
static render(parameters) { static render(parameters) {
const storage = parameters.annotationStorage;
const root = parameters.xfa; const root = parameters.xfa;
const rootHtml = document.createElement(root.name); const rootHtml = document.createElement(root.name);
if (root.attributes) { if (root.attributes) {
XfaLayer.setAttributes(rootHtml, root.attributes); this.setAttributes(rootHtml, root);
} }
const stack = [[root, -1, rootHtml]]; const stack = [[root, -1, rootHtml]];
@ -69,7 +127,7 @@ class XfaLayer {
const childHtml = document.createElement(name); const childHtml = document.createElement(name);
html.appendChild(childHtml); html.appendChild(childHtml);
if (child.attributes) { if (child.attributes) {
XfaLayer.setAttributes(childHtml, child.attributes); this.setAttributes(childHtml, child, storage);
} }
if (child.children && child.children.length > 0) { if (child.children && child.children.length > 0) {

View File

@ -1317,12 +1317,16 @@ class BaseViewer {
/** /**
* @param {HTMLDivElement} pageDiv * @param {HTMLDivElement} pageDiv
* @param {PDFPage} pdfPage * @param {PDFPage} pdfPage
* @param {AnnotationStorage} [annotationStorage] - Storage for annotation
* data in forms.
* @returns {XfaLayerBuilder} * @returns {XfaLayerBuilder}
*/ */
createXfaLayerBuilder(pageDiv, pdfPage) { createXfaLayerBuilder(pageDiv, pdfPage, annotationStorage = null) {
return new XfaLayerBuilder({ return new XfaLayerBuilder({
pageDiv, pageDiv,
pdfPage, pdfPage,
annotationStorage:
annotationStorage || this.pdfDocument?.annotationStorage,
}); });
} }

View File

@ -603,7 +603,8 @@ class PDFPageView {
if (!this.xfaLayer) { if (!this.xfaLayer) {
this.xfaLayer = this.xfaLayerFactory.createXfaLayerBuilder( this.xfaLayer = this.xfaLayerFactory.createXfaLayerBuilder(
div, div,
pdfPage pdfPage,
/* annotationStorage = */ null
); );
} }
this._renderXfaLayer(); this._renderXfaLayer();

View File

@ -19,15 +19,17 @@ import { XfaLayer } from "pdfjs-lib";
* @typedef {Object} XfaLayerBuilderOptions * @typedef {Object} XfaLayerBuilderOptions
* @property {HTMLDivElement} pageDiv * @property {HTMLDivElement} pageDiv
* @property {PDFPage} pdfPage * @property {PDFPage} pdfPage
* @property {AnnotationStorage} [annotationStorage]
*/ */
class XfaLayerBuilder { class XfaLayerBuilder {
/** /**
* @param {XfaLayerBuilderOptions} options * @param {XfaLayerBuilderOptions} options
*/ */
constructor({ pageDiv, pdfPage }) { constructor({ pageDiv, pdfPage, annotationStorage }) {
this.pageDiv = pageDiv; this.pageDiv = pageDiv;
this.pdfPage = pdfPage; this.pdfPage = pdfPage;
this.annotationStorage = annotationStorage;
this.div = null; this.div = null;
this._cancelled = false; this._cancelled = false;
@ -40,16 +42,18 @@ class XfaLayerBuilder {
* annotations is complete. * annotations is complete.
*/ */
render(viewport, intent = "display") { render(viewport, intent = "display") {
return this.pdfPage.getXfa().then(xfa => { return this.pdfPage
.getXfa()
.then(xfa => {
if (this._cancelled) { if (this._cancelled) {
return; return;
} }
const parameters = { const parameters = {
viewport: viewport.clone({ dontFlip: true }), viewport: viewport.clone({ dontFlip: true }),
div: this.div, div: this.div,
xfa, xfa,
page: this.pdfPage, page: this.pdfPage,
annotationStorage: this.annotationStorage,
}; };
if (this.div) { if (this.div) {
@ -62,6 +66,9 @@ class XfaLayerBuilder {
XfaLayer.render(parameters); XfaLayer.render(parameters);
} }
})
.catch(error => {
console.error(error);
}); });
} }
@ -84,11 +91,13 @@ class DefaultXfaLayerFactory {
/** /**
* @param {HTMLDivElement} pageDiv * @param {HTMLDivElement} pageDiv
* @param {PDFPage} pdfPage * @param {PDFPage} pdfPage
* @param {AnnotationStorage} [annotationStorage]
*/ */
createXfaLayerBuilder(pageDiv, pdfPage) { createXfaLayerBuilder(pageDiv, pdfPage, annotationStorage = null) {
return new XfaLayerBuilder({ return new XfaLayerBuilder({
pageDiv, pageDiv,
pdfPage, pdfPage,
annotationStorage,
}); });
} }
} }