|
@@ -72,13 +72,10 @@ function initform(form,map,ro = false) {
|
|
|
const val = map.get(e.name);
|
|
|
if (val == null)
|
|
|
continue;
|
|
|
- if (e.type == 'checkbox') {
|
|
|
- e.checked = cfgbool(val) == cfgbool(e.value);
|
|
|
- } else if (e.type == 'radio') {
|
|
|
+ if (e.type == 'radio')
|
|
|
e.checked = (val == e.value);
|
|
|
- } else {
|
|
|
+ else
|
|
|
e.value = val;
|
|
|
- }
|
|
|
} else if (e instanceof HTMLButtonElement) {
|
|
|
e.disabled = ro;
|
|
|
}
|
|
@@ -174,9 +171,7 @@ function textformdata(form) {
|
|
|
if (val == undefined || !e.name || e instanceof HTMLButtonElement) {
|
|
|
continue;
|
|
|
} else if (e instanceof HTMLInputElement) {
|
|
|
- if (e.type == 'checkbox')
|
|
|
- val = e.checked == cfgbool(val) ? '1' : '0';
|
|
|
- else if (e.type == 'radio' && !e.checked)
|
|
|
+ if (e.type == 'radio' && !e.checked)
|
|
|
continue;
|
|
|
}
|
|
|
data += e.name + '=' + val + "\r\n";
|
|
@@ -250,3 +245,90 @@ class IncHTML extends HTMLElement {
|
|
|
}
|
|
|
}
|
|
|
customElements.define('x-inc', IncHTML);
|
|
|
+
|
|
|
+// Smart checkbox INPUT element
|
|
|
+class XBox extends HTMLInputElement {
|
|
|
+ set negative(x) { return this.toggleAttribute('negative', x); }
|
|
|
+ get negative() { return this.hasAttribute('negative'); }
|
|
|
+ #truth;
|
|
|
+ get truth() { return this.#truth; }
|
|
|
+ update_truth() {
|
|
|
+ const old_truth = this.#truth;
|
|
|
+ this.#truth = this.checked != this.negative;
|
|
|
+ if (this.#truth !== old_truth)
|
|
|
+ this.resolve_conflicts();
|
|
|
+ }
|
|
|
+ set truth(x) {
|
|
|
+ const new_truth = !!x;
|
|
|
+ if (new_truth !== this.#truth) {
|
|
|
+ this.checked = new_truth != this.negative;
|
|
|
+ this.update_truth();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ set_list(n,x) { this.setAttribute(n, x ? x.join(',') : ''); }
|
|
|
+ get_list(n) { var a = this.getAttribute(n); return a ? a.split(/\s*;\s*/) : []; }
|
|
|
+ get needs() { return this.get_list('needs'); }
|
|
|
+ set conflicts(x) { this.set_list('conflicts',x); }
|
|
|
+ get conflicts() { return this.get_list('conflicts'); }
|
|
|
+ set value(x) { this.truth = cfgbool(x); }
|
|
|
+ get value() { return this.truth ? '1' : '0'; }
|
|
|
+
|
|
|
+ constructor() {
|
|
|
+ super();
|
|
|
+ this.setAttribute('type', 'checkbox');
|
|
|
+ this.checked = cfgbool(this.getAttribute('value')) != this.negative;
|
|
|
+ this.addEventListener('change', this.update_truth);
|
|
|
+ this.update_truth();
|
|
|
+ }
|
|
|
+
|
|
|
+ connectedCallback() { this.update_truth(); }
|
|
|
+ adoptedCallback() { this.update_truth(); }
|
|
|
+
|
|
|
+ static get observedAttributes() {
|
|
|
+ return ['value', 'negative', 'conflicts', 'needs'];
|
|
|
+ }
|
|
|
+ attributeChangedCallback(name, oldval, newval) {
|
|
|
+ if (oldval === newval)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (name == 'value') {
|
|
|
+ this.truth = cfgbool(newval);
|
|
|
+ } else if (name == 'negative') {
|
|
|
+ this.checked = this.#truth != this.negative;
|
|
|
+ } else if (name == 'conflicts' || name == 'needs') {
|
|
|
+ this.resolve_conflicts();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ form_objects(list) {
|
|
|
+ if (!this.form)
|
|
|
+ return [];
|
|
|
+ return list.map((n) => this.form.elements[n]);
|
|
|
+ }
|
|
|
+ do_resolve(which, sense) {
|
|
|
+ for (const e of this.form_objects(which)) {
|
|
|
+ if (e instanceof XBox)
|
|
|
+ e.truth = sense;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #resolving;
|
|
|
+ resolve_conflicts() {
|
|
|
+ const t = this.#truth;
|
|
|
+ if (this.#resolving || !this.form)
|
|
|
+ return;
|
|
|
+ this.#resolving = true;
|
|
|
+ if (t) {
|
|
|
+ this.do_resolve(this.needs, true);
|
|
|
+ this.do_resolve(this.conflicts, false);
|
|
|
+ } else {
|
|
|
+ for (const e of this.form.elements) {
|
|
|
+ if (e instanceof XBox && e.truth) {
|
|
|
+ if (e.form_objects(e.needs).some((x) => x === this))
|
|
|
+ e.truth = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.#resolving = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+customElements.define('x-box', XBox, { extends: 'input' });
|