XFA - Use native radio and checkbox buttons
- Remove current stuff which relies on some system fonts to avoid bad rendering.
This commit is contained in:
parent
f2ade671ec
commit
f61f80a5a3
@ -890,71 +890,45 @@ class CheckButton extends XFAObject {
|
||||
}
|
||||
|
||||
[$toHTML](availableSpace) {
|
||||
// TODO: shape and mark == default.
|
||||
const style = toStyle(this, "border", "margin");
|
||||
// TODO: border, shape and mark.
|
||||
|
||||
const style = toStyle("margin");
|
||||
const size = measureToString(this.size);
|
||||
|
||||
style.width = style.height = size;
|
||||
|
||||
let mark, radius;
|
||||
if (this.shape === "square") {
|
||||
mark = "▪";
|
||||
radius = "10%";
|
||||
} else {
|
||||
mark = "●";
|
||||
radius = "50%";
|
||||
}
|
||||
|
||||
if (!style.borderRadius) {
|
||||
style.borderRadius = radius;
|
||||
}
|
||||
|
||||
if (this.mark !== "default") {
|
||||
// TODO: To avoid some rendering issues we should use svg
|
||||
// to draw marks.
|
||||
switch (this.mark) {
|
||||
case "check":
|
||||
mark = "✓";
|
||||
break;
|
||||
case "circle":
|
||||
mark = "●";
|
||||
break;
|
||||
case "cross":
|
||||
mark = "✕";
|
||||
break;
|
||||
case "diamond":
|
||||
mark = "♦";
|
||||
break;
|
||||
case "square":
|
||||
mark = "▪";
|
||||
break;
|
||||
case "star":
|
||||
mark = "★";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (size !== "10px") {
|
||||
style.fontSize = size;
|
||||
style.lineHeight = size;
|
||||
style.width = size;
|
||||
style.height = size;
|
||||
}
|
||||
|
||||
let type;
|
||||
let className;
|
||||
let groupId;
|
||||
let id;
|
||||
const fieldId = this[$getParent]()[$getParent]()[$uid];
|
||||
const container = this[$getParent]()[$getParent]()[$getParent]();
|
||||
if (container instanceof ExclGroup) {
|
||||
groupId = container[$uid];
|
||||
type = "radio";
|
||||
className = "xfaRadio";
|
||||
id = `${fieldId}-radio`;
|
||||
} else {
|
||||
type = "checkbox";
|
||||
className = "xfaCheckbox";
|
||||
}
|
||||
|
||||
const input = {
|
||||
name: "input",
|
||||
attributes: {
|
||||
class: "xfaCheckbox",
|
||||
class: className,
|
||||
style,
|
||||
fieldId,
|
||||
type: "radio",
|
||||
id: `${fieldId}-radio`,
|
||||
type,
|
||||
},
|
||||
};
|
||||
|
||||
const container = this[$getParent]()[$getParent]()[$getParent]();
|
||||
if (container instanceof ExclGroup) {
|
||||
input.attributes.name = container[$uid];
|
||||
if (id) {
|
||||
input.attributes.id = id;
|
||||
}
|
||||
|
||||
if (groupId) {
|
||||
input.attributes.name = groupId;
|
||||
}
|
||||
|
||||
return HTMLResult.success({
|
||||
@ -962,17 +936,7 @@ class CheckButton extends XFAObject {
|
||||
attributes: {
|
||||
class: "xfaLabel",
|
||||
},
|
||||
children: [
|
||||
input,
|
||||
{
|
||||
name: "span",
|
||||
attributes: {
|
||||
class: "xfaCheckboxMark",
|
||||
mark,
|
||||
style,
|
||||
},
|
||||
},
|
||||
],
|
||||
children: [input],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -16,20 +16,26 @@
|
||||
import { PageViewport } from "./display_utils.js";
|
||||
|
||||
class XfaLayer {
|
||||
static setupStorage(html, fieldId, element, storage) {
|
||||
static setupStorage(html, fieldId, element, storage, intent) {
|
||||
const storedData = storage.getValue(fieldId, { value: null });
|
||||
switch (element.name) {
|
||||
case "textarea":
|
||||
html.textContent = storedData.value !== null ? storedData.value : "";
|
||||
if (intent === "print") {
|
||||
break;
|
||||
}
|
||||
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") {
|
||||
if (storedData.value) {
|
||||
html.setAttribute("checked", true);
|
||||
}
|
||||
if (intent === "print") {
|
||||
break;
|
||||
}
|
||||
html.addEventListener("change", event => {
|
||||
const { target } = event;
|
||||
for (const radio of document.getElementsByName(target.name)) {
|
||||
@ -40,7 +46,23 @@ class XfaLayer {
|
||||
}
|
||||
storage.setValue(fieldId, { value: target.checked });
|
||||
});
|
||||
} else if (element.attributes.type === "checkbox") {
|
||||
if (storedData.value) {
|
||||
html.setAttribute("checked", true);
|
||||
}
|
||||
if (intent === "print") {
|
||||
break;
|
||||
}
|
||||
html.addEventListener("input", event => {
|
||||
storage.setValue(fieldId, { value: event.target.checked });
|
||||
});
|
||||
} else {
|
||||
if (storedData.value !== null) {
|
||||
html.setAttribute("value", storedData.value);
|
||||
}
|
||||
if (intent === "print") {
|
||||
break;
|
||||
}
|
||||
html.addEventListener("input", event => {
|
||||
storage.setValue(fieldId, { value: event.target.value });
|
||||
});
|
||||
@ -66,8 +88,13 @@ class XfaLayer {
|
||||
}
|
||||
}
|
||||
|
||||
static setAttributes(html, element, storage) {
|
||||
static setAttributes(html, element, storage, intent) {
|
||||
const { attributes } = element;
|
||||
if (attributes.type === "radio") {
|
||||
// Avoid to have a radio group when printing with the same as one
|
||||
// already displayed.
|
||||
attributes.name = `${attributes.name}-${intent}`;
|
||||
}
|
||||
for (const [key, value] of Object.entries(attributes)) {
|
||||
if (value === null || value === undefined || key === "fieldId") {
|
||||
continue;
|
||||
@ -94,6 +121,7 @@ class XfaLayer {
|
||||
static render(parameters) {
|
||||
const storage = parameters.annotationStorage;
|
||||
const root = parameters.xfa;
|
||||
const intent = parameters.intent;
|
||||
const rootHtml = document.createElement(root.name);
|
||||
if (root.attributes) {
|
||||
this.setAttributes(rootHtml, root);
|
||||
@ -134,7 +162,7 @@ class XfaLayer {
|
||||
const childHtml = document.createElement(name);
|
||||
html.appendChild(childHtml);
|
||||
if (child.attributes) {
|
||||
this.setAttributes(childHtml, child, storage);
|
||||
this.setAttributes(childHtml, child, storage, intent);
|
||||
}
|
||||
|
||||
if (child.children && child.children.length > 0) {
|
||||
|
@ -125,38 +125,6 @@
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xfaLabel > input[type="radio"] {
|
||||
/* Use this trick to make the checkbox invisible but
|
||||
but still focusable. */
|
||||
position: absolute;
|
||||
left: -99999px;
|
||||
}
|
||||
|
||||
.xfaLabel > input[type="radio"]:focus + .xfaCheckboxMark {
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.xfaCheckboxMark {
|
||||
cursor: pointer;
|
||||
flex: 0 0 auto;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
border-color: #8f8f9d;
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.xfaCheckbox:checked + .xfaCheckboxMark::after {
|
||||
content: attr(mark);
|
||||
}
|
||||
|
||||
.xfaButton {
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
@ -169,6 +137,13 @@
|
||||
background: Highlight;
|
||||
}
|
||||
|
||||
.xfaCheckbox,
|
||||
.xfaRadio {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.xfaRich {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ class XfaLayerBuilder {
|
||||
xfa: this.xfaHtml,
|
||||
page: null,
|
||||
annotationStorage: this.annotationStorage,
|
||||
intent,
|
||||
};
|
||||
|
||||
// Create an xfa layer div and render the form
|
||||
|
Loading…
Reference in New Issue
Block a user