From 63eab8a0f9067d3e4c0a7ad2c0781f2b98752f90 Mon Sep 17 00:00:00 2001 From: Marco Di Pillo Tomic Date: Tue, 16 Jul 2024 10:17:07 -0300 Subject: [PATCH] separate fieldset from form --- src/ctrl/inputs/index.js | 8 +- src/ctrl/inputs/object.js | 160 ++++++++++++++++++++++++++++++++++ src/form.js | 178 ++++++-------------------------------- 3 files changed, 191 insertions(+), 155 deletions(-) create mode 100644 src/ctrl/inputs/object.js diff --git a/src/ctrl/inputs/index.js b/src/ctrl/inputs/index.js index 76b0d0c..c68242a 100644 --- a/src/ctrl/inputs/index.js +++ b/src/ctrl/inputs/index.js @@ -10,6 +10,7 @@ import select from './select.js' import radio from './radio.js' import checkbox from './checkbox.js' import file from './file.js' +import object from './object.js' import textarea from './textarea.js' import icon from './icon.js' import date from './date.js' @@ -105,7 +106,7 @@ export default ({ var delayValue = null var wrapper = null - s.update = (value, label) => { + s.update = s.properties || s.items ? update : (value, label) => { if (delay && delayValue !== value) { delayValue = value setTimeout(() => { @@ -126,6 +127,7 @@ export default ({ } wrapper = ( + s.ui != 'file' && (s.type == 'object' || s.properties) ? object : s.ui == 'pending' ? pending : s.ui == 'pagination' ? pagination : s.ui == 'link' ? link : @@ -144,7 +146,9 @@ export default ({ text )(s) - s.update(s.value, s.label) + if (typeof s.update == 'function' && !s.properties && !s.items) { + s.update(s.value, s.label) + } return wrapper } diff --git a/src/ctrl/inputs/object.js b/src/ctrl/inputs/object.js new file mode 100644 index 0000000..bc926dd --- /dev/null +++ b/src/ctrl/inputs/object.js @@ -0,0 +1,160 @@ +import e from '../../e.js' +import ctrl from '../index.js' +import tag from '../../tag.js' + +export default ({ + update, + properties, + title, + description, + ui, + icon, + close, + delay, + noValid, + size, + col, + readOnly, + writeOnly, + ...schema +}) => { + const P = properties || {} + const K = Object.keys(P) + const hasAlert = ui && description + const hasLegend = close || title || icon + const Data = {...schema.default} || {} + const Label = {} + var Err = K.reduce((E, k) => ({...E, [k]: true}), {}) + var hasErr = false + const ref = {} + + const target = e(({ + div, + fieldset, + legend, + button, + hr, + text + }) => !hasLegend && !K.length && !hasAlert ? text('') : fieldset({}, [ + !hasLegend ? null : legend({ + class: 'fw-bold clearfix '+ + (size == 'lg' ? 'fs-4' : size == 'sm' ? 'fs-6' : 'fs-5') + }, [ + tag({ + icon, + title, + description + }), + !close ? null : button({ + type: 'button', + class: 'btn-close float-end', + onclick: typeof close != 'function' ? null : close, + dataBsDismiss: typeof close != 'string' ? null : close + }) + ]), + !hasLegend ? null : hr({ + class: 'my-2' + }), + !hasAlert ? null : div({ + class: 'alert alert-'+ui+' my-0 '+ + (size == 'lg' ? ' fs-5' : size == 'sm' ? ' small' : ''), + role: 'alert' + }, [ + ctrl({ + type: 'string', + ui: 'text', + default: description, + readOnly: true + }) + ]), + !K.length ? null : div({ + class: 'row' + }) + ])) + + if (K.length) { + target.setProp = P => { + var done = false + const K = Object.keys(P) + K.forEach((k, index) => { + done = K.length - 1 == index + if (P[k] == null) { + ref[k]?.parentNode.removeChild(ref[k]) + delete Data[k] + delete Label[k] + delete Err[k] + return + } + + /*if (P[k].default !== undefined && Data[k] !== undefined) { + delete Data[k] + }*/ + + col = P[k].col || col + const {title, description, ...schema} = { + delay, + noValid, + size, + readOnly, + writeOnly, + ...P[k], + title: typeof P[k].title != 'string' ? k : P[k].title, + default: Data[k] == null ? P[k].default : Data[k], + data: Data + } + const el = e(({ + div, + label, + text, + button, + }) => + div({ + class: `col-${col || 12} `+ + (size == 'lg' ? 'my-3' : size == 'sm' ? 'my-1' : 'my-2')+ + (title ? ' row' : '')+ + (size == 'lg' ? ' fs-5' : size == 'sm' ? ' small' : '') + }, [ + !title ? null : div({ + class: 'col-md-3' + }, [ + label({ + class: 'form-label fw-bold', + title: description + }, [ + text(title+':') + ]) + ]), + ctrl({ + ...schema, + title: k, + description: !title ? description : null, + css: !title ? null : 'col-md-9', + update: (err, v, label) => { + label = typeof label != 'string' ? String(v) : label + Data[k] = v + Label[k] = label + Err[k] = !!err + hasErr = Object.keys(Err).reduce( + (err, k) => err || Err[k] + , false) + if (typeof update == 'function' && done) { + update(hasErr, Data, Label, target) + } + } + }) + ]) + ) + + if (ref[k] != null) { + ref[k].replaceWith(el) + } else { + target.querySelector('.row').appendChild(el) + } + ref[k] = el + }) + } + target.setProp(P) + } + + return target +} diff --git a/src/form.js b/src/form.js index 458aad2..0d185f9 100644 --- a/src/form.js +++ b/src/form.js @@ -9,38 +9,20 @@ export default ({ submit, links, block, - properties, - title, - description, - ui, - icon, - close, - delay, - noValid, - size, - col, - readOnly, - writeOnly, ...schema }) => { - const P = properties || {} - const K = Object.keys(P) - const hasAlert = ui && description - const hasLegend = close || title || icon - const Data = {...schema.default} || {} - const Label = {} - var Err = K.reduce((E, k) => ({...E, [k]: true}), {}) + var Data = null + var Label = null var hasErr = false var submitter = null const run = () => typeof submit != 'function' || hasErr ? null : submit(Data, Label) - const ref = {} links = links instanceof Array ? links : typeof submit != 'function' ? [] : [{href: 'submit'}] links = links.map(l => { l.data = Data - l.size = size + l.size = schema.size if (l.href === 'submit') { l.title = l.title == null ? T('submit') : l.title l.link = l.link == null ? 'primary' : l.link @@ -53,12 +35,26 @@ export default ({ } }) - const target = e(({ + const fields = ctrl({ + type: 'object', + ...schema, + update: (err, ...args) => { + hasErr = !!err + if (submitter) { + submitter.disabled = hasErr + } + Data = args[0] + Label = args[1] + if (typeof update == 'function') { + update(err, ...args) + } + } + }) + const hasFields = fields.nodeType == 1 + + return e(({ div, form, - fieldset, - legend, - button, hr }) => form({ class: css, @@ -69,51 +65,16 @@ export default ({ submitter ? submitter.click() : run() } }, [ - !hasLegend && !K.length && !hasAlert ? null : fieldset({}, [ - !hasLegend ? null : legend({ - class: 'fw-bold clearfix '+ - (size == 'lg' ? 'fs-4' : size == 'sm' ? 'fs-6' : 'fs-5') - }, [ - tag({ - icon, - title, - description - }), - !close ? null : button({ - type: 'button', - class: 'btn-close float-end', - onclick: typeof close != 'function' ? null : close, - dataBsDismiss: typeof close != 'string' ? null : close - }) - ]), - !hasLegend ? null : hr({ - class: 'my-2' - }), - !hasAlert ? null : div({ - class: 'alert alert-'+ui+' my-0 '+ - (size == 'lg' ? ' fs-5' : size == 'sm' ? ' small' : ''), - role: 'alert' - }, [ - ctrl({ - type: 'string', - ui: 'text', - default: description, - readOnly: true - }) - ]), - !K.length ? null : div({ - class: 'row' - }) - ]), - !links.length || (!K.length && !hasAlert) ? null : hr({ + fields, + !links.length || !hasFields ? null : hr({ class: 'my-2' }), !links.length ? null : block ? div({ class: 'btn-group w-100' }, links) : div({ class: 'row g-1 align-items-center justify-content-'+( - close == 'modal' ? 'end' : - (!K.length && !hasAlert) ? 'center' : 'start' + schema.close == 'modal' ? 'end' : + !hasFields ? 'center' : 'start' ) }, links.map(L => div({ @@ -121,93 +82,4 @@ export default ({ }, [L]) )) ])) - - if (K.length) { - target.setProp = P => { - var done = false - const K = Object.keys(P) - K.forEach((k, index) => { - done = K.length - 1 == index - if (P[k] == null) { - ref[k]?.parentNode.removeChild(ref[k]) - delete Data[k] - delete Label[k] - delete Err[k] - return - } - - /*if (P[k].default !== undefined && Data[k] !== undefined) { - delete Data[k] - }*/ - - col = P[k].col || col - const {title, description, ...schema} = { - delay, - noValid, - size, - readOnly, - writeOnly, - ...P[k], - title: typeof P[k].title != 'string' ? k : P[k].title, - default: Data[k] == null ? P[k].default : Data[k], - data: Data - } - const el = e(({ - div, - label, - text, - button, - }) => - div({ - class: `col-${col || 12} `+ - (size == 'lg' ? 'my-3' : size == 'sm' ? 'my-1' : 'my-2')+ - (title ? ' row' : '')+ - (size == 'lg' ? ' fs-5' : size == 'sm' ? ' small' : '') - }, [ - !title ? null : div({ - class: 'col-md-3' - }, [ - label({ - class: 'form-label fw-bold', - title: description - }, [ - text(title+':') - ]) - ]), - ctrl({ - ...schema, - title: k, - description: !title ? description : null, - css: !title ? null : 'col-md-9', - update: (err, v, label) => { - label = typeof label != 'string' ? String(v) : label - Data[k] = v - Label[k] = label - Err[k] = !!err - hasErr = Object.keys(Err).reduce( - (err, k) => err || Err[k] - , false) - if (submitter) { - submitter.disabled = !!hasErr - } - if (typeof update == 'function' && done) { - update(hasErr, Data, Label, target) - } - } - }) - ]) - ) - - if (ref[k] != null) { - ref[k].replaceWith(el) - } else { - target.querySelector('fieldset').querySelector('.row').appendChild(el) - } - ref[k] = el - }) - } - target.setProp(P) - } - - return target }