Fixes to JsonForm and json

* Update model when JsonForm.editable set false
* Bugfixes in jsonPatch
This commit is contained in:
2025-09-21 00:00:50 +02:00
parent 123231833d
commit 6e1351d9ab
5 changed files with 65 additions and 6 deletions

View File

@@ -30,14 +30,14 @@
--jsl-dialog-bgcolor: #ffd; --jsl-dialog-bgcolor: #ffd;
--jsl-dialog-bordercolor: #835f10; --jsl-dialog-bordercolor: #835f10;
.-title::before { .-title::before {
content: ' '; content: '⁉️ ';
} }
} }
&.-style-error { &.-style-error {
--jsl-dialog-bgcolor: #fcc; --jsl-dialog-bgcolor: #fcc;
--jsl-dialog-bordercolor: #bb3434; --jsl-dialog-bordercolor: #bb3434;
.-title::before { .-title::before {
content: '⚠️ '; content: ' ';
} }
} }
&.-style-warning { &.-style-warning {

View File

@@ -10,7 +10,7 @@
<script type="module"> <script type="module">
import { el } from './dom.js'; import { el } from './dom.js';
import { dialog } from './dialog.js'; import { dialog } from './dialog.js';
import { JsonForm, TextField, SelectField } from './jsonform.js'; import { JsonForm, TextField, NumericField } from './jsonform.js';
import { jsonQuery, jsonPatch, tokenizePath } from './json.js'; import { jsonQuery, jsonPatch, tokenizePath } from './json.js';
import { date } from './date.js'; import { date } from './date.js';
@@ -45,7 +45,7 @@ document.body.appendChild(root);
const userForm = new JsonForm(); const userForm = new JsonForm();
userForm.layout.addRow() userForm.layout.addRow()
.append(new TextField({ label:"Username", width:70, path:".username" })) .append(new TextField({ label:"Username", width:70, path:".username" }))
.append(new TextField({ label:"ID", path:".id", locked:true })); .append(new NumericField({ label:"ID", path:".id", locked:true }));
userForm.layout.addRow() userForm.layout.addRow()
.append(new TextField({ label:"Created", width:50, path:".meta.created", locked:true })) .append(new TextField({ label:"Created", width:50, path:".meta.created", locked:true }))
.append(new TextField({ label:"Updated", width:50, path:".meta.updated", locked:true })); .append(new TextField({ label:"Updated", width:50, path:".meta.updated", locked:true }));
@@ -62,6 +62,9 @@ userForm.model = {
btn3.addEventListener('click', () => { btn3.addEventListener('click', () => {
userForm.editable = !userForm.editable; userForm.editable = !userForm.editable;
if (!userForm.editable) {
console.log(userForm.model);
}
}); });
// console.log(tokenizePath(".foo.bar[1].title")); // console.log(tokenizePath(".foo.bar[1].title"));

View File

@@ -90,7 +90,7 @@ function jsonPatch(json, path, value) {
if (search === 'key') { if (search === 'key') {
// find key tok in ptr // find key tok in ptr
if (typeof ptr[tok] === 'undefined') { if (typeof ptr[tok] === 'undefined') {
return defaultValue; return json;
} else { } else {
if (toks.length === 0) { if (toks.length === 0) {
ptr[tok] = value; ptr[tok] = value;

View File

@@ -56,6 +56,9 @@
border: solid 1px var(--jsl-form-focused-outline); border: solid 1px var(--jsl-form-focused-outline);
} }
} }
&.-number-field {
text-align: right;
}
} }
} }
} }

View File

@@ -1,6 +1,6 @@
import { dom, el } from './dom.js'; import { dom, el } from './dom.js';
import { jsonQuery } from './json.js'; import { jsonQuery, jsonPatch } from './json.js';
/** /**
* This form encapsulates a form with a model and a layout. * This form encapsulates a form with a model and a layout.
@@ -50,6 +50,7 @@ class JsonForm {
refreshModel() { refreshModel() {
// TODO go over the fields and update the model with any modified data // TODO go over the fields and update the model with any modified data
this.#model = this.#layout.updateModel(this.#model);
} }
} }
@@ -77,6 +78,11 @@ class FormLayout {
this.#rows.forEach(row => row.modelUpdated(model)); this.#rows.forEach(row => row.modelUpdated(model));
} }
updateModel(model) {
this.#rows.forEach(row => model = row.updateModel(model));
return model;
}
setEditable(state) { setEditable(state) {
this.#rows.forEach(row => row.setEditable(state)); this.#rows.forEach(row => row.setEditable(state));
} }
@@ -110,6 +116,14 @@ class FormRow {
}); });
} }
updateModel(model) {
this.#fields.forEach(field => {
if (!field.options.path) return;
model = jsonPatch(model, field.options.path, field.value);
});
return model;
}
setEditable(state) { setEditable(state) {
this.#fields.forEach(field => { this.#fields.forEach(field => {
if (field.options.locked === true) return; if (field.options.locked === true) return;
@@ -163,6 +177,15 @@ class FormField {
return this.#el; return this.#el;
} }
/**
* Update the value without triggering any effects
*
* @param {*} value The new value
*/
updateValue(value) {
this.#value = value;
}
buildField() { buildField() {
} }
@@ -192,6 +215,35 @@ class TextField extends FormField {
if (state) { if (state) {
dom.apply(this.#input, { 'contenteditable':'plaintext-only' }); dom.apply(this.#input, { 'contenteditable':'plaintext-only' });
} else { } else {
this.updateValue(this.#input.innerText);
dom.apply(this.#input, { 'contenteditable':null });
}
}
}
class NumericField extends FormField {
#input = null;
buildField() {
if (!this.#input) {
this.#input = el.div({ class: '-field -number-field' })
this.el.appendChild(this.#input);
}
this.#input.innerText = this.value;
}
valueUpdated() {
this.#input.innerText = this.value;
}
getValue() {
if (this.options.float) {
return parseFloat(this.#input.innerText);
}
return parseInt(this.#input.innerText);
}
setEditable(state) {
if (state) {
dom.apply(this.#input, { 'contenteditable':'plaintext-only' });
} else {
this.updateValue(this.#input.innerText);
dom.apply(this.#input, { 'contenteditable':null }); dom.apply(this.#input, { 'contenteditable':null });
} }
} }
@@ -222,6 +274,7 @@ export {
FormRow, FormRow,
FormField, FormField,
TextField, TextField,
NumericField,
DateField, DateField,
SelectField, SelectField,
CheckField, CheckField,