Bugfixes, dialog improvements
* It is now possible to pass an element as the dialog message to have it inserted as the body.
This commit is contained in:
19
README.md
19
README.md
@@ -67,6 +67,13 @@ dialog.msgbox("Ready!").then(
|
||||
dialog.select("Put in warehouse", "Select", { "none":"None", "1":"WH1", "2":"WH2" }).then(...)
|
||||
```
|
||||
|
||||
* `dialog.TYPE(body, ?title, ?actions, ?options)` → `Promise`
|
||||
|
||||
Options:
|
||||
|
||||
- `showClose` - true to show close button in top left corner
|
||||
- `width` - valid CSS width definition
|
||||
|
||||
### dom.js
|
||||
|
||||
This component offers `dom` and `el` that can be used to manipulate the DOM.
|
||||
@@ -143,4 +150,16 @@ productForm.editable = true;
|
||||
// when the user is done editing set editable = false and access the updated model
|
||||
productForm.editable = false;
|
||||
const newModel = productForm.model; // → { product:{ name:"Swedish Fish" }, price:"8.99" }
|
||||
|
||||
// You can even put a form inside a dialog!
|
||||
dialog.dialog(productForm.dom(), "Title", {"ok":"Update"}, { showClose:true, width:'400px' }).then(
|
||||
(result) => {
|
||||
productForm.editable = false;
|
||||
if (result == 'ok') {
|
||||
// productForm.model is updated
|
||||
}
|
||||
}
|
||||
)
|
||||
productForm.editable = true;
|
||||
|
||||
```
|
||||
|
||||
12
dialog.css
12
dialog.css
@@ -53,7 +53,7 @@
|
||||
border-top-right-radius: 0.5rem;
|
||||
/* background: rgba(0, 0, 0, 0.2); */
|
||||
display: flex;
|
||||
padding: 0.5rem;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.-title {
|
||||
@@ -68,18 +68,18 @@
|
||||
}
|
||||
|
||||
.-content {
|
||||
padding: 0.5rem;
|
||||
padding: 0px 0.75rem;
|
||||
}
|
||||
|
||||
.-buttons {
|
||||
padding: 0.5rem;
|
||||
padding-top: 0.2rem;
|
||||
text-align: center;
|
||||
padding: 0.75rem;
|
||||
text-align: right;
|
||||
|
||||
.action {
|
||||
font-size: 105%;
|
||||
border: solid 1px #666;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.35rem 0.6rem;
|
||||
padding: 0.45rem 0.8rem;
|
||||
margin: 0px 0.25rem;
|
||||
background: #eee;
|
||||
|
||||
|
||||
33
dialog.js
33
dialog.js
@@ -20,6 +20,7 @@ class UserDialog {
|
||||
#title = "MessageBox";
|
||||
#message;
|
||||
#actions = { "ok":"Ok" };
|
||||
#options = {};
|
||||
|
||||
/**
|
||||
* Dialog constructor
|
||||
@@ -29,11 +30,12 @@ class UserDialog {
|
||||
* @param {string} message The dialog message
|
||||
* @param {object} actions The dialog actions
|
||||
*/
|
||||
constructor(style, title, message, actions) {
|
||||
constructor(style, title, message, actions, options) {
|
||||
if (style) this.#style = style;
|
||||
if (title) this.#title = title;
|
||||
if (message) this.#message = message;
|
||||
if (actions && typeof actions == 'object') this.#actions = actions;
|
||||
if (options && typeof options == 'object') this.#options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,6 +58,9 @@ class UserDialog {
|
||||
throw new Error("#buildDialog should not be called with an active #dialog");
|
||||
|
||||
const dialog = el.dialog({ class: 'jsl-dialog' });
|
||||
if (this.#options.width) {
|
||||
dialog.style.width = this.#options.width;
|
||||
}
|
||||
dialog.addEventListener('close', event => {
|
||||
if (this.#resolver) {
|
||||
this.#resolver(false);
|
||||
@@ -68,10 +73,16 @@ class UserDialog {
|
||||
let cbtn;
|
||||
dom.append(dialog, el.div({ class: '-header' }, [
|
||||
el.div({ class: '-title' }, this.#title),
|
||||
// cbtn = el.button({ class: '-close-btn' }, '✕')
|
||||
cbtn = (this.#options.showClose ?? false) ? el.button({ class: '-close-btn' }, '✕') : null,
|
||||
]));
|
||||
if (this.#options.body ?? null) {
|
||||
dom.append(dialog, el.div({ class: '-content' }, this.#options.body));
|
||||
} else {
|
||||
dom.append(dialog, el.div({ class: '-content' }, this.#message));
|
||||
// cbtn.addEventListener('click', () => { this.#handleButton(false); });
|
||||
}
|
||||
if (this.#options.showClose ?? false) {
|
||||
cbtn.addEventListener('click', () => { this.#handleButton(false); });
|
||||
}
|
||||
|
||||
const buttons = el.div({ class: '-buttons' });
|
||||
let tabindex = 1;
|
||||
@@ -129,39 +140,39 @@ class UserDialogFactory {
|
||||
* @param {object} actions The buttons to present at the bottom of the dialog
|
||||
* @returns Promise
|
||||
*/
|
||||
showDialog(type, title, message, actions) {
|
||||
showDialog(type, title, message, actions, options) {
|
||||
let dialog;
|
||||
switch (type) {
|
||||
case 'msgbox':
|
||||
title = title ?? "MessageBox";
|
||||
actions = actions ?? { 'ok': 'Ok' };
|
||||
dialog = new UserDialog('msgbox', title, message, actions);
|
||||
dialog = new UserDialog('msgbox', title, message, actions, options);
|
||||
break;
|
||||
case 'information':
|
||||
case 'info':
|
||||
title = title ?? "Information";
|
||||
actions = actions ?? { 'ok': 'Ok' };
|
||||
dialog = new UserDialog('info', title, message, actions);
|
||||
dialog = new UserDialog('info', title, message, actions, options);
|
||||
break;
|
||||
case 'error':
|
||||
title = title ?? "Error";
|
||||
actions = actions ?? { 'ok': 'Ok' };
|
||||
dialog = new UserDialog('error', title, message, actions);
|
||||
dialog = new UserDialog('error', title, message, actions, options);
|
||||
break;
|
||||
case 'warning':
|
||||
title = title ?? "Warning";
|
||||
actions = actions ?? { 'ok': 'Ok' };
|
||||
dialog = new UserDialog('warning', title, message, actions);
|
||||
dialog = new UserDialog('warning', title, message, actions, options);
|
||||
break;
|
||||
case 'confirm':
|
||||
title = title ?? "Confirmation";
|
||||
actions = actions ?? { 'ok': 'Ok', 'cancel': 'Cancel' };
|
||||
dialog = new UserDialog('confirm', title, message, actions);
|
||||
dialog = new UserDialog('confirm', title, message, actions, options);
|
||||
break;
|
||||
default:
|
||||
title = title ?? "Dialog";
|
||||
actions = actions ?? { 'ok': 'Ok' };
|
||||
dialog = new UserDialog(type, title, message, actions);
|
||||
dialog = new UserDialog(type, title, message, actions, options);
|
||||
}
|
||||
|
||||
return dialog.show();
|
||||
@@ -176,7 +187,7 @@ const dialog = new Proxy(factory, {
|
||||
get(target, name) {
|
||||
return name in target
|
||||
? target[name]
|
||||
: (message, title = null, actions = null) => target.showDialog(name, title, message, actions);
|
||||
: (message, title = null, actions = null, options = {}) => target.showDialog(name, title, message, actions, options);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
2
dom.js
2
dom.js
@@ -56,6 +56,8 @@ class DomHelper {
|
||||
* @returns
|
||||
*/
|
||||
append(tag, children) {
|
||||
// Handle null, to make it easy to skip items with conditionals
|
||||
if (children === null) return;
|
||||
//console.debug(`append: ${tag.nodeName}`, children);
|
||||
if (typeof children == 'object' && children instanceof Element) {
|
||||
//console.debug(`-> appended element`);
|
||||
|
||||
25
index.html
25
index.html
@@ -15,7 +15,7 @@ import { jsonQuery, jsonPatch, tokenizePath } from './json.js';
|
||||
import { date } from './date.js';
|
||||
|
||||
// build our dom
|
||||
let btn, btn2, btn3;
|
||||
let btn, btn2, btn3, btn4;
|
||||
let root = el.div({}, [
|
||||
el.div({ style:'color:#444;' }, "This is dynamically generated!"),
|
||||
el.div({ style:'display:flex; gap:0.25rem; margin-top:0.25rem;' }, [
|
||||
@@ -23,6 +23,7 @@ let root = el.div({}, [
|
||||
btn = el.button({}, "Hello World"),
|
||||
btn2 = el.button({}, "Error mode"),
|
||||
btn3 = el.button({}, "Edit form"),
|
||||
btn4 = el.button({}, "Form modal"),
|
||||
])
|
||||
]);
|
||||
// click handler
|
||||
@@ -49,6 +50,8 @@ userForm.layout.addRow()
|
||||
userForm.layout.addRow()
|
||||
.append(new TextField({ label:"Created", width:50, path:".meta.created", locked:true }))
|
||||
.append(new TextField({ label:"Updated", width:50, path:".meta.updated", locked:true }));
|
||||
userForm.layout.addRow()
|
||||
.append(new NumericField({ label:"Salary", width:30, path:".meta.salary", fixed:2 }));
|
||||
document.body.appendChild(userForm.dom());
|
||||
|
||||
// Set the model
|
||||
@@ -67,6 +70,26 @@ btn3.addEventListener('click', () => {
|
||||
}
|
||||
});
|
||||
|
||||
const productForm = new JsonForm();
|
||||
productForm.layout.addRow()
|
||||
.append(new TextField({ label:"Product", width:60, path:".product.name" }))
|
||||
.append(new NumericField({ label:"Price", path:".product.price", fixed:2 }));
|
||||
|
||||
productForm.model = {};
|
||||
|
||||
btn4.addEventListener('click', () => {
|
||||
dialog.dialog(productForm.dom(), "Title", {"ok":"Update"}, { showClose:true, width:'400px' }).then(
|
||||
(result) => {
|
||||
productForm.editable = false;
|
||||
if (result == 'ok') {
|
||||
console.log(productForm.model);
|
||||
}
|
||||
}
|
||||
)
|
||||
productForm.editable = true;
|
||||
});
|
||||
|
||||
|
||||
// console.log(tokenizePath(".foo.bar[1].title"));
|
||||
// console.log(jsonQuery({ "foo":{ "bar":"42" }}, ".foo.bar" ));
|
||||
// console.log(jsonQuery([ { name:"cheese" }, { name:"bread" }, { name:"milk" } ], "[].name" ));
|
||||
|
||||
6
json.js
6
json.js
@@ -90,7 +90,13 @@ function jsonPatch(json, path, value) {
|
||||
if (search === 'key') {
|
||||
// find key tok in ptr
|
||||
if (typeof ptr[tok] === 'undefined') {
|
||||
if (toks.length === 0) {
|
||||
ptr[tok] = value;
|
||||
return json;
|
||||
} else {
|
||||
ptr[tok] = {};
|
||||
ptr = ptr[tok];
|
||||
}
|
||||
} else {
|
||||
if (toks.length === 0) {
|
||||
ptr[tok] = value;
|
||||
|
||||
14
jsonform.js
14
jsonform.js
@@ -119,6 +119,7 @@ class FormRow {
|
||||
updateModel(model) {
|
||||
this.#fields.forEach(field => {
|
||||
if (!field.options.path) return;
|
||||
field.value = field.getValue();
|
||||
model = jsonPatch(model, field.options.path, field.value);
|
||||
});
|
||||
return model;
|
||||
@@ -206,9 +207,14 @@ class TextField extends FormField {
|
||||
this.#input.innerText = this.value;
|
||||
}
|
||||
valueUpdated() {
|
||||
if (!this.#input) return;
|
||||
this.#input.innerText = this.value;
|
||||
}
|
||||
getValue() {
|
||||
if (this.#input.innerText === '') {
|
||||
if (this.options.nullable !== false)
|
||||
return null;
|
||||
}
|
||||
return this.#input.innerText;
|
||||
}
|
||||
setEditable(state) {
|
||||
@@ -231,9 +237,17 @@ class NumericField extends FormField {
|
||||
this.#input.innerText = this.value;
|
||||
}
|
||||
valueUpdated() {
|
||||
if (!this.#input) return;
|
||||
this.#input.innerText = this.value;
|
||||
}
|
||||
getValue() {
|
||||
if (this.#input.innerText === '') {
|
||||
if (this.options.nullable !== false)
|
||||
return null;
|
||||
}
|
||||
if (this.options.fixed && typeof this.options.fixed == 'number') {
|
||||
return parseFloat(this.#input.innerText).toFixed(this.options.fixed);
|
||||
}
|
||||
if (this.options.float) {
|
||||
return parseFloat(this.#input.innerText);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user