formeo 5.2.0 → 5.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/demo/assets/css/demo.min.css +1 -1
- package/dist/demo/assets/css/demo.min.css.gz +0 -0
- package/dist/demo/assets/css/formeo.min.css +1 -1
- package/dist/demo/assets/js/demo.min.js +56 -56
- package/dist/demo/assets/js/demo.min.js.gz +0 -0
- package/dist/demo/assets/js/form.min.js +1 -1
- package/dist/demo/assets/js/formeo.cjs.js +179 -45
- package/dist/demo/assets/js/formeo.es.js +179 -45
- package/dist/demo/assets/js/formeo.min.cjs.js +2 -2
- package/dist/demo/assets/js/formeo.min.es.js +2 -2
- package/dist/demo/assets/js/formeo.min.js +179 -45
- package/dist/demo/assets/js/formeo.min.umd.js +2 -2
- package/dist/demo/assets/js/formeo.umd.js +179 -45
- package/dist/demo/assets/js/html.min.js +1 -1
- package/dist/demo/assets/js/layout.min.js +1 -1
- package/dist/demo/assets/js/mode-json.min.js +1 -1
- package/dist/demo/assets/js/mode-json.min.js.gz +0 -0
- package/dist/demo/assets/js/theme-github_light_default.min.js +1 -1
- package/dist/demo/index.html +1 -1
- package/dist/formData_schema.json +730 -1
- package/dist/formeo.cjs.js +179 -45
- package/dist/formeo.css +1 -1
- package/dist/formeo.es.js +179 -45
- package/dist/formeo.min.cjs.js +2 -2
- package/dist/formeo.min.css +1 -1
- package/dist/formeo.min.es.js +2 -2
- package/dist/formeo.min.js +179 -45
- package/dist/formeo.min.umd.js +2 -2
- package/dist/formeo.umd.js +179 -45
- package/package.json +3 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/**
|
|
3
3
|
formeo - https://formeo.io
|
|
4
|
-
Version: 5.1
|
|
4
|
+
Version: 5.2.1
|
|
5
5
|
Author: Draggable https://draggable.io
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -6064,7 +6064,7 @@ Author: Draggable https://draggable.io
|
|
|
6064
6064
|
var name$1, version$2, type, main, module$1, unpkg, exports$1, files, homepage, repository, author, contributors, bugs, description, keywords, ignore, config, scripts, devDependencies, dependencies, release, commitlint, package_default;
|
|
6065
6065
|
var init_package = __esmMin((() => {
|
|
6066
6066
|
name$1 = "formeo";
|
|
6067
|
-
version$2 = "5.1
|
|
6067
|
+
version$2 = "5.2.1";
|
|
6068
6068
|
type = "module";
|
|
6069
6069
|
main = "dist/formeo.cjs.js";
|
|
6070
6070
|
module$1 = "dist/formeo.es.js";
|
|
@@ -6126,7 +6126,7 @@ Author: Draggable https://draggable.io
|
|
|
6126
6126
|
"postbuild:demo": "node --no-warnings tools/copy-assets.mjs",
|
|
6127
6127
|
"build:demo:watch": "vite build --mode demo --watch",
|
|
6128
6128
|
"build:icons": "node ./tools/generate-sprite",
|
|
6129
|
-
"lint": "biome check ./src && node tools/check-color-literals.mjs",
|
|
6129
|
+
"lint": "biome check ./src && node tools/check-color-literals.mjs && node tools/check-doc-links.mjs",
|
|
6130
6130
|
"lint:fix": "biome check --write ./src",
|
|
6131
6131
|
"format": "biome format --write .",
|
|
6132
6132
|
"test": "node --loader=./tools/svg-loader.mjs --import=./tools/__mocks__/sprite-init.mjs --experimental-test-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.{js,mjs}",
|
|
@@ -6168,8 +6168,7 @@ Author: Draggable https://draggable.io
|
|
|
6168
6168
|
"vite-plugin-banner": "^0.8.0",
|
|
6169
6169
|
"vite-plugin-compression": "^0.5.1",
|
|
6170
6170
|
"vite-plugin-html": "^3.2.2",
|
|
6171
|
-
"zod": "^4.4.3"
|
|
6172
|
-
"zod-to-json-schema": "^3.23.5"
|
|
6171
|
+
"zod": "^4.4.3"
|
|
6173
6172
|
};
|
|
6174
6173
|
dependencies = {
|
|
6175
6174
|
"@draggable/formeo-languages": "^3.4.1",
|
|
@@ -12090,7 +12089,7 @@ Author: Draggable https://draggable.io
|
|
|
12090
12089
|
}));
|
|
12091
12090
|
//#endregion
|
|
12092
12091
|
//#region src/lib/js/common/dom.js
|
|
12093
|
-
var iconFontTemplates, inputTags, stripOn, useCaptureEvts, defaultActionHandler, getName, DOM, dom;
|
|
12092
|
+
var iconFontTemplates, inputTags, REQUIRED_GROUP_ATTR, OPTION_INPUT_ATTRS, GROUP_CONSUMED_ATTRS, groupWrapperAttrs, stripOn, useCaptureEvts, defaultActionHandler, getName, DOM, dom;
|
|
12094
12093
|
var init_dom = __esmMin((() => {
|
|
12095
12094
|
init_components();
|
|
12096
12095
|
init_constants();
|
|
@@ -12112,6 +12111,18 @@ Author: Draggable https://draggable.io
|
|
|
12112
12111
|
"textarea",
|
|
12113
12112
|
"select"
|
|
12114
12113
|
]);
|
|
12114
|
+
REQUIRED_GROUP_ATTR = "formeo-required-group";
|
|
12115
|
+
OPTION_INPUT_ATTRS = ["disabled", "form"];
|
|
12116
|
+
GROUP_CONSUMED_ATTRS = new Set([
|
|
12117
|
+
"type",
|
|
12118
|
+
"id",
|
|
12119
|
+
"name",
|
|
12120
|
+
"className",
|
|
12121
|
+
"value",
|
|
12122
|
+
"required",
|
|
12123
|
+
...OPTION_INPUT_ATTRS
|
|
12124
|
+
]);
|
|
12125
|
+
groupWrapperAttrs = (attrs = {}) => Object.fromEntries(Object.entries(attrs).filter(([key]) => !GROUP_CONSUMED_ATTRS.has(key)));
|
|
12115
12126
|
stripOn = (str) => str.replace(/^on([A-Z])/, (_, l) => l.toLowerCase());
|
|
12116
12127
|
useCaptureEvts = new Set(["focus", "blur"]);
|
|
12117
12128
|
defaultActionHandler = (event) => {
|
|
@@ -12235,9 +12246,18 @@ Author: Draggable https://draggable.io
|
|
|
12235
12246
|
helpers.forEach(processedOptions, (option) => {
|
|
12236
12247
|
wrap.children.push(_this.create(option, isPreview));
|
|
12237
12248
|
});
|
|
12238
|
-
|
|
12249
|
+
const groupAttrs = elem.attrs || {};
|
|
12250
|
+
if (groupAttrs.className) wrap.className = groupAttrs.className;
|
|
12239
12251
|
wrap.id = elem.id;
|
|
12240
|
-
wrap.
|
|
12252
|
+
wrap.attrs = groupWrapperAttrs(groupAttrs);
|
|
12253
|
+
wrap.config = {
|
|
12254
|
+
...elem.config,
|
|
12255
|
+
required: Boolean(groupAttrs.required)
|
|
12256
|
+
};
|
|
12257
|
+
if (!isPreview && groupAttrs.type === "checkbox" && groupAttrs.required) {
|
|
12258
|
+
wrap.attrs[`data-${REQUIRED_GROUP_ATTR}`] = "true";
|
|
12259
|
+
wrap.action = { change: ({ currentTarget }) => this.syncCheckboxGroupRequired(currentTarget) };
|
|
12260
|
+
}
|
|
12241
12261
|
return this.create(wrap, isPreview);
|
|
12242
12262
|
}
|
|
12243
12263
|
processed.push("options");
|
|
@@ -12440,16 +12460,20 @@ Author: Draggable https://draggable.io
|
|
|
12440
12460
|
const { action, attrs = {} } = elem;
|
|
12441
12461
|
const fieldType = attrs.type || elem.tag;
|
|
12442
12462
|
const id = attrs.id || elem.id;
|
|
12463
|
+
const name = !isPreview && attrs.name || id;
|
|
12464
|
+
const sharedInputAttrs = Object.fromEntries(OPTION_INPUT_ATTRS.filter((key) => key in attrs).map((key) => [key, attrs[key]]));
|
|
12465
|
+
if (attrs.required) sharedInputAttrs.required = fieldType !== "checkbox" || !options.some(({ selected, checked }) => selected || checked);
|
|
12443
12466
|
const optionMap = (option, i) => {
|
|
12444
12467
|
const { label, value, ...rest } = option;
|
|
12445
12468
|
const defaultInput = () => {
|
|
12446
12469
|
const input = {
|
|
12447
12470
|
tag: "input",
|
|
12448
12471
|
attrs: {
|
|
12449
|
-
name
|
|
12472
|
+
name,
|
|
12450
12473
|
type: fieldType,
|
|
12451
12474
|
value: value || "",
|
|
12452
12475
|
id: `${id}-${i}`,
|
|
12476
|
+
...sharedInputAttrs,
|
|
12453
12477
|
...rest
|
|
12454
12478
|
},
|
|
12455
12479
|
action
|
|
@@ -12551,6 +12575,18 @@ Author: Draggable https://draggable.io
|
|
|
12551
12575
|
const labelAfter = helpers.get(elem, "config.labelAfter");
|
|
12552
12576
|
return labelAfter === void 0 ? type === "checkbox" || type === "radio" : labelAfter;
|
|
12553
12577
|
}
|
|
12578
|
+
/**
|
|
12579
|
+
* A required checkbox group needs at least one checked box, not every box.
|
|
12580
|
+
* Every box stays `required` while none is checked; once one is checked none is.
|
|
12581
|
+
* Boxes inside a hidden container are never required.
|
|
12582
|
+
* @param {Element} groupElem wrapper holding the group's checkboxes
|
|
12583
|
+
*/
|
|
12584
|
+
syncCheckboxGroupRequired(groupElem) {
|
|
12585
|
+
const boxes = Array.from(groupElem.querySelectorAll("input[type=\"checkbox\"]"));
|
|
12586
|
+
const isHidden = Boolean(groupElem.closest("[hidden]"));
|
|
12587
|
+
const noneChecked = !boxes.some((box) => box.checked);
|
|
12588
|
+
for (const box of boxes) box.required = !isHidden && noneChecked;
|
|
12589
|
+
}
|
|
12554
12590
|
requiredMark = () => ({
|
|
12555
12591
|
tag: "span",
|
|
12556
12592
|
className: "text-error",
|
|
@@ -12574,7 +12610,7 @@ Author: Draggable https://draggable.io
|
|
|
12574
12610
|
* @return {Object} config object
|
|
12575
12611
|
*/
|
|
12576
12612
|
label(elem, fMap) {
|
|
12577
|
-
const required = helpers.get(elem, "attrs.required");
|
|
12613
|
+
const required = helpers.get(elem, "attrs.required") || helpers.get(elem, "config.required");
|
|
12578
12614
|
let { config: { label: labelText = "", helpText = "", tooltip = null } } = elem;
|
|
12579
12615
|
const { id: elemId, attrs } = elem;
|
|
12580
12616
|
if (typeof labelText === "function") labelText = labelText();
|
|
@@ -18169,12 +18205,23 @@ Author: Draggable https://draggable.io
|
|
|
18169
18205
|
acc[key] = assignmentHandlers[key];
|
|
18170
18206
|
return acc;
|
|
18171
18207
|
}, {});
|
|
18208
|
+
/**
|
|
18209
|
+
* Setting `checked` fires no `change`, so a required checkbox group the box belongs to is
|
|
18210
|
+
* re-synced directly. A synthetic `change` could re-trigger conditions.
|
|
18211
|
+
* @param {Element} elem checkbox or radio input
|
|
18212
|
+
*/
|
|
18213
|
+
var syncRequiredGroupOf = (elem) => {
|
|
18214
|
+
const group = elem.closest?.(REQUIRED_GROUP_SELECTOR);
|
|
18215
|
+
if (group) dom.syncCheckboxGroupRequired(group);
|
|
18216
|
+
};
|
|
18172
18217
|
var targetPropertyMap = {
|
|
18173
18218
|
isChecked: (elem) => {
|
|
18174
18219
|
elem.checked = true;
|
|
18220
|
+
syncRequiredGroupOf(elem);
|
|
18175
18221
|
},
|
|
18176
18222
|
isNotChecked: (elem) => {
|
|
18177
18223
|
elem.checked = false;
|
|
18224
|
+
syncRequiredGroupOf(elem);
|
|
18178
18225
|
},
|
|
18179
18226
|
value: (elem, { assignment, ...rest }) => {
|
|
18180
18227
|
const assignmentAction = assignmentMap[assignment]?.(elem, rest);
|
|
@@ -18183,15 +18230,60 @@ Author: Draggable https://draggable.io
|
|
|
18183
18230
|
return assignmentAction;
|
|
18184
18231
|
},
|
|
18185
18232
|
isNotVisible: (elem) => {
|
|
18186
|
-
if (elem?._required === void 0) elem._required = elem.required;
|
|
18187
18233
|
elem.parentElement.setAttribute("hidden", true);
|
|
18188
|
-
elem
|
|
18234
|
+
suspendRequired(elem);
|
|
18189
18235
|
},
|
|
18190
18236
|
isVisible: (elem) => {
|
|
18191
18237
|
elem.parentElement.removeAttribute("hidden");
|
|
18192
|
-
elem
|
|
18238
|
+
restoreRequired(elem);
|
|
18239
|
+
}
|
|
18240
|
+
};
|
|
18241
|
+
var FORM_CONTROL_SELECTOR = "input, select, textarea";
|
|
18242
|
+
var REQUIRED_GROUP_SELECTOR = `[data-${REQUIRED_GROUP_ATTR}]`;
|
|
18243
|
+
/**
|
|
18244
|
+
* The element itself when it matches, plus every descendant that does
|
|
18245
|
+
* @param {Element} elem
|
|
18246
|
+
* @param {String} selector
|
|
18247
|
+
* @return {Array<Element>}
|
|
18248
|
+
*/
|
|
18249
|
+
var selfAndDescendants = (elem, selector) => [...elem.matches(selector) ? [elem] : [], ...elem.querySelectorAll(selector)];
|
|
18250
|
+
/**
|
|
18251
|
+
* A hidden control can't be filled in, so it must not be required. Remembers each control's
|
|
18252
|
+
* `required` so that restoreRequired can put it back. Works for a field, a group or a whole row.
|
|
18253
|
+
* @param {Element} elem condition target
|
|
18254
|
+
*/
|
|
18255
|
+
var suspendRequired = (elem) => {
|
|
18256
|
+
for (const control of selfAndDescendants(elem, FORM_CONTROL_SELECTOR)) {
|
|
18257
|
+
if (control._required === void 0) control._required = control.required;
|
|
18258
|
+
control.required = false;
|
|
18259
|
+
}
|
|
18260
|
+
};
|
|
18261
|
+
/**
|
|
18262
|
+
* Undoes suspendRequired. Controls that were never suspended are left alone, and so are controls
|
|
18263
|
+
* still inside a hidden container: they keep their saved `required` until that container is shown.
|
|
18264
|
+
* @param {Element} elem condition target
|
|
18265
|
+
*/
|
|
18266
|
+
var restoreRequired = (elem) => {
|
|
18267
|
+
for (const control of selfAndDescendants(elem, FORM_CONTROL_SELECTOR)) if (control._required !== void 0 && !control.closest("[hidden]")) {
|
|
18268
|
+
control.required = control._required;
|
|
18269
|
+
delete control._required;
|
|
18193
18270
|
}
|
|
18271
|
+
for (const group of selfAndDescendants(elem, REQUIRED_GROUP_SELECTOR)) dom.syncCheckboxGroupRequired(group);
|
|
18194
18272
|
};
|
|
18273
|
+
var LOGICAL_AND = new Set(["&&", "and"]);
|
|
18274
|
+
/**
|
|
18275
|
+
* Splits a condition's if-clauses into OR-groups of AND-ed clauses. A clause's `logical`
|
|
18276
|
+
* ('&&' / '||', or 'and' / 'or') joins it to the clause before it, and '&&' binds tighter
|
|
18277
|
+
* than '||' as in JavaScript. The first clause's `logical` is ignored, and a missing
|
|
18278
|
+
* `logical` means OR, which is how every clause behaved before AND was supported.
|
|
18279
|
+
* @param {Array<Object>} ifConditions
|
|
18280
|
+
* @return {Array<Array<Object>>} e.g. A || B && C -> [[A], [B, C]]
|
|
18281
|
+
*/
|
|
18282
|
+
var groupIfConditions = (ifConditions = []) => ifConditions.reduce((groups, clause, index) => {
|
|
18283
|
+
if (index > 0 && LOGICAL_AND.has(clause.logical)) groups[groups.length - 1].push(clause);
|
|
18284
|
+
else groups.push([clause]);
|
|
18285
|
+
return groups;
|
|
18286
|
+
}, []);
|
|
18195
18287
|
//#endregion
|
|
18196
18288
|
//#region src/lib/js/renderer/index.js
|
|
18197
18289
|
init_dom();
|
|
@@ -18256,20 +18348,31 @@ Author: Draggable https://draggable.io
|
|
|
18256
18348
|
const fieldData = {
|
|
18257
18349
|
key,
|
|
18258
18350
|
value,
|
|
18259
|
-
label: this.
|
|
18351
|
+
label: this.componentByName(key)?.config?.label || ""
|
|
18260
18352
|
};
|
|
18261
18353
|
userFormData.push(fieldData);
|
|
18262
18354
|
}
|
|
18263
18355
|
return userFormData;
|
|
18264
18356
|
}
|
|
18357
|
+
/**
|
|
18358
|
+
* Finds the component data behind a submitted field name
|
|
18359
|
+
* @param {String} name
|
|
18360
|
+
* @return {Object|undefined}
|
|
18361
|
+
*/
|
|
18362
|
+
componentByName(name) {
|
|
18363
|
+
return this.components[baseId(name)] || Object.values(this.components).find((component) => component.attrs?.name === name);
|
|
18364
|
+
}
|
|
18265
18365
|
set userData(data = {}) {
|
|
18266
18366
|
const form = this.container.querySelector("form");
|
|
18267
18367
|
for (const key of Object.keys(data)) {
|
|
18268
18368
|
const fields = form.elements[key];
|
|
18269
|
-
|
|
18369
|
+
const checkables = checkableInputs(fields);
|
|
18370
|
+
if (checkables?.[0].type === "checkbox") {
|
|
18270
18371
|
const values = Array.isArray(data[key]) ? data[key] : [data[key]];
|
|
18271
|
-
for (const field of
|
|
18272
|
-
|
|
18372
|
+
for (const field of checkables) field.checked = values.includes(field.value);
|
|
18373
|
+
const group = checkables[0].closest(`[data-${REQUIRED_GROUP_ATTR}]`);
|
|
18374
|
+
if (group) dom.syncCheckboxGroupRequired(group);
|
|
18375
|
+
} else if (checkables?.[0].type === "radio") for (const field of checkables) field.checked = field.value === data[key];
|
|
18273
18376
|
else if (fields.type) fields.value = data[key];
|
|
18274
18377
|
}
|
|
18275
18378
|
}
|
|
@@ -18295,9 +18398,20 @@ Author: Draggable https://draggable.io
|
|
|
18295
18398
|
children: this.processedData
|
|
18296
18399
|
};
|
|
18297
18400
|
this.renderedForm = dom.render(config);
|
|
18401
|
+
this.renderedForm.addEventListener("reset", this.syncRequiredGroupsAfterReset);
|
|
18298
18402
|
this.applyConditions();
|
|
18299
18403
|
return this.renderedForm;
|
|
18300
18404
|
}
|
|
18405
|
+
/**
|
|
18406
|
+
* A reset changes checkedness without firing `change`, so required checkbox groups are re-synced.
|
|
18407
|
+
* The `reset` event fires before the controls revert, hence the deferral.
|
|
18408
|
+
* @param {Event} evt the form's reset event
|
|
18409
|
+
*/
|
|
18410
|
+
syncRequiredGroupsAfterReset = ({ currentTarget: form }) => {
|
|
18411
|
+
setTimeout(() => {
|
|
18412
|
+
for (const group of form.querySelectorAll(`[data-${REQUIRED_GROUP_ATTR}]`)) dom.syncCheckboxGroupRequired(group);
|
|
18413
|
+
}, 0);
|
|
18414
|
+
};
|
|
18301
18415
|
get html() {
|
|
18302
18416
|
return (this.renderedForm || this.getRenderedForm()).outerHTML;
|
|
18303
18417
|
}
|
|
@@ -18372,7 +18486,8 @@ Author: Draggable https://draggable.io
|
|
|
18372
18486
|
...attrs,
|
|
18373
18487
|
"data-clone-of": id
|
|
18374
18488
|
};
|
|
18375
|
-
if (rest.
|
|
18489
|
+
if (rest.options && ["checkbox", "radio"].includes(attrs.type)) delete updatedAttrs.name;
|
|
18490
|
+
else if (rest.tag === "input") updatedAttrs.name = getName(this.components[componentId]);
|
|
18376
18491
|
return {
|
|
18377
18492
|
...rest,
|
|
18378
18493
|
id: "f-" + uuid(id),
|
|
@@ -18417,46 +18532,57 @@ Author: Draggable https://draggable.io
|
|
|
18417
18532
|
});
|
|
18418
18533
|
}
|
|
18419
18534
|
/**
|
|
18420
|
-
*
|
|
18421
|
-
*
|
|
18535
|
+
* Wires every condition of every rendered component: evaluates it once on render and again
|
|
18536
|
+
* whenever a component one of its if-clauses reads from changes.
|
|
18422
18537
|
*/
|
|
18423
|
-
handleComponentCondition = (component, ifRest, thenConditions) => {
|
|
18424
|
-
if (!component) return;
|
|
18425
|
-
if (isNodeCollection(component)) {
|
|
18426
|
-
for (const elem of component) this.handleComponentCondition(elem, ifRest, thenConditions);
|
|
18427
|
-
return;
|
|
18428
|
-
}
|
|
18429
|
-
const listenerEvent = LISTEN_TYPE_MAP(component);
|
|
18430
|
-
if (listenerEvent) component.addEventListener(listenerEvent, (evt) => {
|
|
18431
|
-
if (this.evaluateCondition(ifRest, evt)) for (const thenCondition of thenConditions) this.execResult(thenCondition, evt);
|
|
18432
|
-
}, false);
|
|
18433
|
-
const fakeEvt = { target: component };
|
|
18434
|
-
if (this.evaluateCondition(ifRest, fakeEvt)) for (const thenCondition of thenConditions) this.execResult(thenCondition, fakeEvt);
|
|
18435
|
-
};
|
|
18436
18538
|
applyConditions = () => {
|
|
18437
18539
|
for (const { conditions } of Object.values(this.components)) {
|
|
18438
18540
|
if (!conditions) continue;
|
|
18439
|
-
for (const condition of conditions) {
|
|
18440
|
-
|
|
18441
|
-
|
|
18442
|
-
|
|
18443
|
-
} catch (err) {
|
|
18444
|
-
console.error("formeo: condition skipped", ifCondition, err);
|
|
18445
|
-
}
|
|
18541
|
+
for (const condition of conditions) try {
|
|
18542
|
+
this.applyCondition(condition);
|
|
18543
|
+
} catch (err) {
|
|
18544
|
+
console.error("formeo: condition skipped", condition, err);
|
|
18446
18545
|
}
|
|
18447
18546
|
}
|
|
18448
18547
|
};
|
|
18449
|
-
applyCondition = (
|
|
18450
|
-
|
|
18451
|
-
|
|
18548
|
+
applyCondition = ({ if: ifConditions = [], then: thenConditions = [] }) => {
|
|
18549
|
+
const clauseGroups = groupIfConditions(ifConditions);
|
|
18550
|
+
let running = false;
|
|
18551
|
+
const run = (evt) => {
|
|
18552
|
+
if (running) return;
|
|
18553
|
+
running = true;
|
|
18554
|
+
try {
|
|
18555
|
+
if (this.evaluateClauseGroups(clauseGroups)) for (const thenCondition of thenConditions) this.execResult(thenCondition, evt);
|
|
18556
|
+
} finally {
|
|
18557
|
+
running = false;
|
|
18558
|
+
}
|
|
18559
|
+
};
|
|
18560
|
+
const watchedAddresses = new Set(ifConditions.flatMap(({ source, target }) => [source, target]).filter(isAddress));
|
|
18561
|
+
for (const address of watchedAddresses) {
|
|
18452
18562
|
const { component, options } = this.getComponent(address);
|
|
18453
|
-
this.
|
|
18563
|
+
this.listenForChanges(options || component, run);
|
|
18564
|
+
}
|
|
18565
|
+
run({ target: null });
|
|
18566
|
+
};
|
|
18567
|
+
/**
|
|
18568
|
+
* @param {Array<Array<Object>>} clauseGroups output of groupIfConditions
|
|
18569
|
+
* @return {Boolean} true when every clause of at least one group matches
|
|
18570
|
+
*/
|
|
18571
|
+
evaluateClauseGroups = (clauseGroups) => clauseGroups.some((group) => group.length && group.every((clause) => this.evaluateCondition(clause)));
|
|
18572
|
+
listenForChanges = (component, handler) => {
|
|
18573
|
+
if (!component) return;
|
|
18574
|
+
if (isNodeCollection(component)) {
|
|
18575
|
+
for (const elem of component) this.listenForChanges(elem, handler);
|
|
18576
|
+
return;
|
|
18454
18577
|
}
|
|
18578
|
+
const listenerEvent = LISTEN_TYPE_MAP(component);
|
|
18579
|
+
if (listenerEvent) component.addEventListener(listenerEvent, handler, false);
|
|
18455
18580
|
};
|
|
18456
18581
|
/**
|
|
18457
18582
|
* Evaulate conditions
|
|
18458
18583
|
*/
|
|
18459
18584
|
evaluateCondition = ({ source, sourceProperty, targetProperty, comparison, target }) => {
|
|
18585
|
+
if (!isAddress(source) || !this.getComponent(source)?.component) return false;
|
|
18460
18586
|
const sourceValue = this.getComponentProperty(source, sourceProperty);
|
|
18461
18587
|
if (typeof sourceValue === "boolean") return sourceValue;
|
|
18462
18588
|
const targetValue = String(isAddress(target) ? this.getComponentProperty(target, targetProperty) : target);
|
|
@@ -18483,7 +18609,10 @@ Author: Draggable https://draggable.io
|
|
|
18483
18609
|
const result = { component: null };
|
|
18484
18610
|
if (!isAddress(address)) return null;
|
|
18485
18611
|
const [, componentId, optionsKey, optionIndex] = splitAddress(address);
|
|
18486
|
-
|
|
18612
|
+
let component = null;
|
|
18613
|
+
try {
|
|
18614
|
+
component = this.renderedForm.querySelector(`#f-${componentId}`);
|
|
18615
|
+
} catch {}
|
|
18487
18616
|
if (!component) return result;
|
|
18488
18617
|
result.component = component;
|
|
18489
18618
|
if (optionsKey) {
|
|
@@ -18502,6 +18631,11 @@ Author: Draggable https://draggable.io
|
|
|
18502
18631
|
return components;
|
|
18503
18632
|
};
|
|
18504
18633
|
};
|
|
18634
|
+
var isCheckable = (elem) => ["checkbox", "radio"].includes(elem?.type);
|
|
18635
|
+
var checkableInputs = (fields) => {
|
|
18636
|
+
if (isCheckable(fields)) return [fields];
|
|
18637
|
+
return fields?.length && isCheckable(fields[0]) ? Array.from(fields) : null;
|
|
18638
|
+
};
|
|
18505
18639
|
var isDomNode = (value) => Boolean(value) && typeof value.nodeType === "number";
|
|
18506
18640
|
var isNodeCollection = (value) => Boolean(value) && !isDomNode(value) && typeof value.length === "number";
|
|
18507
18641
|
var tagName = (component) => component.tagName?.toLowerCase();
|
|
Binary file
|
package/dist/demo/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en" xml:lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="chrome=1"><meta name="viewport" content="user-scalable=no,width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1"><meta name="description" content="Vanilla Javascript form building module"><meta name="theme-color" content="#232323"><title>Formeo | Drag & Drop Form Creation</title><script type="module" crossorigin src="/formeo/assets/js/demo.min.js"></script><link rel="stylesheet" crossorigin href="/formeo/assets/css/demo.min.css"></head><body><div class="site-wrap"><header id="demo-header"><div class="header-inner"><img id="formeo-logo" src="/formeo/assets/img/formeo-logo.svg" alt="Formeo Logo" width="100"><nav aria-label="Framework navigation"><ul><li><label for="framework-select">Framework:</label> <select name="framework-select" id="framework-select" class="form-control"><option value="vanilla">Vanilla JavaScript</option><option value="angular">Angular</option><option value="react">React</option></select></li><li><label for="locale">Language</label> <select name="locale" id="locale" class="form-control"><option value="af-ZA" dir="ltr">Afrikaans (Suid-Afrika)</option><option value="ar-TN" dir="rtl">العربية (تونس)</option><option value="cs-CZ" dir="ltr">čeština (Česko)</option><option value="de-DE" dir="ltr">Deutsch (Deutschland)</option><option value="en-US" dir="ltr">English</option><option value="es-ES" dir="ltr">español de España</option><option value="fa-IR" dir="rtl">فارسی (ایران)</option><option value="fi-FI" dir="ltr">suomi (Suomi)</option><option value="fr-FR" dir="ltr">français (France)</option><option value="he-IL" dir="rtl">עברית (ישראל)</option><option value="hi-IN" dir="ltr">हिन्दी (भारत)</option><option value="hu-HU" dir="ltr">magyar (Magyarország)</option><option value="it-IT" dir="ltr">italiano (Italia)</option><option value="ja-JP" dir="ltr">日本語 (日本)</option><option value="nb-NO" dir="ltr">norsk bokmål (Norge)</option><option value="pl-PL" dir="ltr">polski (Polska)</option><option value="pt-BR" dir="ltr">português (Brasil)</option><option value="pt-PT" dir="ltr">português europeu</option><option value="ro-RO" dir="ltr">română (România)</option><option value="ru-RU" dir="ltr">русский (Россия)</option><option value="th-TH" dir="ltr">ไทย (ไทย)</option><option value="tr-TR" dir="ltr">Türkçe (Türkiye)</option><option value="zh-CN" dir="ltr">中文(中国)</option><option value="zh-HK" dir="ltr">中文(中國香港特別行政區)</option></select></li><li><label for="control-filter">Control Filter:</label> <input id="control-filter" placeholder="ex. text" class="form-control"></li><li style="float:right">v5.1
|
|
1
|
+
<!doctype html><html lang="en" xml:lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="chrome=1"><meta name="viewport" content="user-scalable=no,width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1"><meta name="description" content="Vanilla Javascript form building module"><meta name="theme-color" content="#232323"><title>Formeo | Drag & Drop Form Creation</title><script type="module" crossorigin src="/formeo/assets/js/demo.min.js"></script><link rel="stylesheet" crossorigin href="/formeo/assets/css/demo.min.css"></head><body><div class="site-wrap"><header id="demo-header"><div class="header-inner"><img id="formeo-logo" src="/formeo/assets/img/formeo-logo.svg" alt="Formeo Logo" width="100"><nav aria-label="Framework navigation"><ul><li><label for="framework-select">Framework:</label> <select name="framework-select" id="framework-select" class="form-control"><option value="vanilla">Vanilla JavaScript</option><option value="angular">Angular</option><option value="react">React</option></select></li><li><label for="locale">Language</label> <select name="locale" id="locale" class="form-control"><option value="af-ZA" dir="ltr">Afrikaans (Suid-Afrika)</option><option value="ar-TN" dir="rtl">العربية (تونس)</option><option value="cs-CZ" dir="ltr">čeština (Česko)</option><option value="de-DE" dir="ltr">Deutsch (Deutschland)</option><option value="en-US" dir="ltr">English</option><option value="es-ES" dir="ltr">español de España</option><option value="fa-IR" dir="rtl">فارسی (ایران)</option><option value="fi-FI" dir="ltr">suomi (Suomi)</option><option value="fr-FR" dir="ltr">français (France)</option><option value="he-IL" dir="rtl">עברית (ישראל)</option><option value="hi-IN" dir="ltr">हिन्दी (भारत)</option><option value="hu-HU" dir="ltr">magyar (Magyarország)</option><option value="it-IT" dir="ltr">italiano (Italia)</option><option value="ja-JP" dir="ltr">日本語 (日本)</option><option value="nb-NO" dir="ltr">norsk bokmål (Norge)</option><option value="pl-PL" dir="ltr">polski (Polska)</option><option value="pt-BR" dir="ltr">português (Brasil)</option><option value="pt-PT" dir="ltr">português europeu</option><option value="ro-RO" dir="ltr">română (România)</option><option value="ru-RU" dir="ltr">русский (Россия)</option><option value="th-TH" dir="ltr">ไทย (ไทย)</option><option value="tr-TR" dir="ltr">Türkçe (Türkiye)</option><option value="zh-CN" dir="ltr">中文(中国)</option><option value="zh-HK" dir="ltr">中文(中國香港特別行政區)</option></select></li><li><label for="control-filter">Control Filter:</label> <input id="control-filter" placeholder="ex. text" class="form-control"></li><li style="float:right">v5.2.1</li></ul></nav></div></header><section id="main_content" class="inner"><div id="framework-container"></div></section><div class="container render-btn-wrap" id="editor-action-buttons"></div><div id="formData-popover" popover><div class="popover-header"><h3>Test formData</h3><div><button type="button" id="format-json">Format</button> <button type="button" id="collapse-json">Collapse</button> <button type="button" id="copy-json">Copy to Clipboard</button></div></div><pre id="formData-editor"></pre><div class="formData-actions"><button popovertarget="formData-popover" popovertargetaction="hide" type="button">Cancel</button> <button id="submit-formData" type="button">Submit</button></div></div><footer id="demo-footer"><nav aria-label="Footer navigation"><ul><li><a href="https://github.com/Draggable/formeo" target="_blank" title="View project on GitHub"><img src="/formeo/assets/img/github.png" width="77" alt="GitHub"></a></li></ul></nav></footer></div></body></html>
|