(function (app) { 'use strict'; const u = app.modules.util; function makeArray(schema, ui, path, value, options) { const wrap = u.h('div', { className: 'form-field form-array' }); const label = (ui && ui['ui:title']) || schema.title || options.fieldName || ''; if (label) { const lbl = u.h('label', { className: 'form-field__label' }); lbl.appendChild(document.createTextNode(label)); if (options.required) { lbl.appendChild(u.h('span', { className: 'required-mark' }, '*')); } wrap.appendChild(lbl); } if (schema.description) { wrap.appendChild(u.h('div', { className: 'form-field__description' }, schema.description)); } const errEl = u.h('div', { className: 'form-field__error', hidden: true }); wrap.appendChild(errEl); const rowsEl = u.h('div', { className: 'form-array__rows' }); wrap.appendChild(rowsEl); const itemSchema = schema.items || { type: 'string' }; const itemUi = (ui && ui.items) || {}; const uiOpts = (ui && ui['ui:options']) || {}; const addable = uiOpts.addable !== false; const removable = uiOpts.removable !== false; const rows = []; function repath() { for (let i = 0; i < rows.length; i++) { rows[i].widget.path = u.ptrPush(path, String(i)); } } function addRow(rowValue) { const idx = rows.length; const rowPath = u.ptrPush(path, String(idx)); const childWidget = app.modules.render.create(itemSchema, itemUi, rowPath, rowValue, { fieldName: '', required: false }); const rowEl = u.h('div', { className: 'form-array__row' }); const body = u.h('div', { className: 'form-array__row-body' }); body.appendChild(childWidget.el); rowEl.appendChild(body); if (removable) { const actions = u.h('div', { className: 'form-array__row-actions' }); const removeBtn = u.h('button', { type: 'button', className: 'btn btn-sm btn-secondary', title: 'Remove this row', onClick: function () { removeRow(rowEl); } }, '×'); actions.appendChild(removeBtn); rowEl.appendChild(actions); } rows.push({ widget: childWidget, rowEl: rowEl }); rowsEl.appendChild(rowEl); } function removeRow(targetEl) { for (let i = 0; i < rows.length; i++) { if (rows[i].rowEl === targetEl) { rows.splice(i, 1); targetEl.remove(); repath(); return; } } } const initial = Array.isArray(value) ? value : []; for (let i = 0; i < initial.length; i++) { addRow(initial[i]); } if (addable) { const addBtn = u.h('button', { type: 'button', className: 'btn btn-sm btn-secondary form-array__add', onClick: function () { addRow(undefined); } }, '+ Add'); wrap.appendChild(addBtn); } return { el: wrap, path: path, type: 'array', read: function () { const out = []; for (let i = 0; i < rows.length; i++) { const v = rows[i].widget.read(); if (v !== undefined) { out.push(v); } } return out; }, setError: function (msg) { errEl.textContent = msg; errEl.hidden = false; }, clearErrors: function () { errEl.textContent = ''; errEl.hidden = true; for (let i = 0; i < rows.length; i++) { rows[i].widget.clearErrors(); } }, child: function (idxStr) { const i = parseInt(idxStr, 10); return (rows[i] && rows[i].widget) || null; } }; } app.modules.array = { makeArray: makeArray }; })(window.formApp);