@dmitryvim/form-builder 0.2.25 → 0.2.26
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 +65 -11
- package/dist/browser/formbuilder.min.js +122 -122
- package/dist/browser/formbuilder.v0.2.26.min.js +606 -0
- package/dist/cjs/index.cjs +258 -151
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +255 -151
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +122 -122
- package/dist/types/types/schema.d.ts +2 -0
- package/dist/types/utils/helpers.d.ts +6 -0
- package/package.json +1 -1
- package/dist/browser/formbuilder.v0.2.25.min.js +0 -606
package/dist/esm/index.js
CHANGED
|
@@ -6,7 +6,10 @@ function t(key, state, params) {
|
|
|
6
6
|
let text = localeTranslations?.[key] || fallbackTranslations?.[key] || key;
|
|
7
7
|
if (params) {
|
|
8
8
|
for (const [paramKey, paramValue] of Object.entries(params)) {
|
|
9
|
-
text = text.replace(
|
|
9
|
+
text = text.replace(
|
|
10
|
+
new RegExp(`\\{${paramKey}\\}`, "g"),
|
|
11
|
+
String(paramValue)
|
|
12
|
+
);
|
|
10
13
|
}
|
|
11
14
|
}
|
|
12
15
|
return text;
|
|
@@ -249,6 +252,9 @@ function validateSchema(schema) {
|
|
|
249
252
|
}
|
|
250
253
|
|
|
251
254
|
// src/utils/helpers.ts
|
|
255
|
+
function isElementReadonly(element, state, ctx) {
|
|
256
|
+
return element.readonly === true || state.config.readonly === true || ctx?.inheritedReadonly === true;
|
|
257
|
+
}
|
|
252
258
|
function isPlainObject(obj) {
|
|
253
259
|
return obj && typeof obj === "object" && obj.constructor === Object;
|
|
254
260
|
}
|
|
@@ -407,6 +413,7 @@ function createCharCounter(element, input, isTextarea = false) {
|
|
|
407
413
|
}
|
|
408
414
|
function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
409
415
|
const state = ctx.state;
|
|
416
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
410
417
|
const inputWrapper = document.createElement("div");
|
|
411
418
|
inputWrapper.style.cssText = "position: relative;";
|
|
412
419
|
const textInput = document.createElement("input");
|
|
@@ -417,7 +424,7 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
417
424
|
padding-right: 60px;
|
|
418
425
|
border: var(--fb-border-width) solid var(--fb-border-color);
|
|
419
426
|
border-radius: var(--fb-border-radius);
|
|
420
|
-
background-color: ${
|
|
427
|
+
background-color: ${readonly ? "var(--fb-background-readonly-color)" : "var(--fb-background-color)"};
|
|
421
428
|
color: var(--fb-text-color);
|
|
422
429
|
font-size: var(--fb-font-size);
|
|
423
430
|
font-family: var(--fb-font-family);
|
|
@@ -428,8 +435,8 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
428
435
|
textInput.name = pathKey;
|
|
429
436
|
textInput.placeholder = element.placeholder || "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442";
|
|
430
437
|
textInput.value = ctx.prefill[element.key] || element.default || "";
|
|
431
|
-
textInput.readOnly =
|
|
432
|
-
if (!
|
|
438
|
+
textInput.readOnly = readonly;
|
|
439
|
+
if (!readonly) {
|
|
433
440
|
textInput.addEventListener("focus", () => {
|
|
434
441
|
textInput.style.borderColor = "var(--fb-border-focus-color)";
|
|
435
442
|
textInput.style.outline = `var(--fb-focus-ring-width) solid var(--fb-focus-ring-color)`;
|
|
@@ -450,7 +457,7 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
450
457
|
}
|
|
451
458
|
});
|
|
452
459
|
}
|
|
453
|
-
if (!
|
|
460
|
+
if (!readonly && ctx.instance) {
|
|
454
461
|
const handleChange = () => {
|
|
455
462
|
const value = textInput.value === "" ? null : textInput.value;
|
|
456
463
|
ctx.instance.triggerOnChange(pathKey, value);
|
|
@@ -459,7 +466,7 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
459
466
|
textInput.addEventListener("input", handleChange);
|
|
460
467
|
}
|
|
461
468
|
inputWrapper.appendChild(textInput);
|
|
462
|
-
if (!
|
|
469
|
+
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
463
470
|
const counter = createCharCounter(element, textInput, false);
|
|
464
471
|
inputWrapper.appendChild(counter);
|
|
465
472
|
}
|
|
@@ -467,6 +474,7 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
467
474
|
}
|
|
468
475
|
function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
469
476
|
const state = ctx.state;
|
|
477
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
470
478
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
471
479
|
const values = Array.isArray(prefillValues) ? [...prefillValues] : [];
|
|
472
480
|
const minCount = element.minCount ?? 1;
|
|
@@ -498,7 +506,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
498
506
|
padding-right: 60px;
|
|
499
507
|
border: var(--fb-border-width) solid var(--fb-border-color);
|
|
500
508
|
border-radius: var(--fb-border-radius);
|
|
501
|
-
background-color: ${
|
|
509
|
+
background-color: ${readonly ? "var(--fb-background-readonly-color)" : "var(--fb-background-color)"};
|
|
502
510
|
color: var(--fb-text-color);
|
|
503
511
|
font-size: var(--fb-font-size);
|
|
504
512
|
font-family: var(--fb-font-family);
|
|
@@ -508,8 +516,8 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
508
516
|
`;
|
|
509
517
|
textInput.placeholder = element.placeholder || t("placeholderText", state);
|
|
510
518
|
textInput.value = value;
|
|
511
|
-
textInput.readOnly =
|
|
512
|
-
if (!
|
|
519
|
+
textInput.readOnly = readonly;
|
|
520
|
+
if (!readonly) {
|
|
513
521
|
textInput.addEventListener("focus", () => {
|
|
514
522
|
textInput.style.borderColor = "var(--fb-border-focus-color)";
|
|
515
523
|
textInput.style.outline = `var(--fb-focus-ring-width) solid var(--fb-focus-ring-color)`;
|
|
@@ -530,7 +538,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
530
538
|
}
|
|
531
539
|
});
|
|
532
540
|
}
|
|
533
|
-
if (!
|
|
541
|
+
if (!readonly && ctx.instance) {
|
|
534
542
|
const handleChange = () => {
|
|
535
543
|
const value2 = textInput.value === "" ? null : textInput.value;
|
|
536
544
|
ctx.instance.triggerOnChange(textInput.name, value2);
|
|
@@ -539,7 +547,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
539
547
|
textInput.addEventListener("input", handleChange);
|
|
540
548
|
}
|
|
541
549
|
inputContainer.appendChild(textInput);
|
|
542
|
-
if (!
|
|
550
|
+
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
543
551
|
const counter = createCharCounter(element, textInput, false);
|
|
544
552
|
inputContainer.appendChild(counter);
|
|
545
553
|
}
|
|
@@ -553,7 +561,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
553
561
|
return itemWrapper;
|
|
554
562
|
}
|
|
555
563
|
function updateRemoveButtons() {
|
|
556
|
-
if (
|
|
564
|
+
if (readonly) return;
|
|
557
565
|
const items = container.querySelectorAll(".multiple-text-item");
|
|
558
566
|
const currentCount = items.length;
|
|
559
567
|
items.forEach((item) => {
|
|
@@ -598,7 +606,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
598
606
|
}
|
|
599
607
|
let addRow = null;
|
|
600
608
|
let countDisplay = null;
|
|
601
|
-
if (!
|
|
609
|
+
if (!readonly) {
|
|
602
610
|
addRow = document.createElement("div");
|
|
603
611
|
addRow.className = "flex items-center gap-3 mt-2";
|
|
604
612
|
const addBtn = document.createElement("button");
|
|
@@ -806,6 +814,7 @@ function applyAutoExpand(textarea) {
|
|
|
806
814
|
}
|
|
807
815
|
function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
808
816
|
const state = ctx.state;
|
|
817
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
809
818
|
const textareaWrapper = document.createElement("div");
|
|
810
819
|
textareaWrapper.style.cssText = "position: relative;";
|
|
811
820
|
const textareaInput = document.createElement("textarea");
|
|
@@ -815,8 +824,8 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
815
824
|
textareaInput.placeholder = element.placeholder || "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442";
|
|
816
825
|
textareaInput.rows = element.rows || 4;
|
|
817
826
|
textareaInput.value = ctx.prefill[element.key] || element.default || "";
|
|
818
|
-
textareaInput.readOnly =
|
|
819
|
-
if (!
|
|
827
|
+
textareaInput.readOnly = readonly;
|
|
828
|
+
if (!readonly && ctx.instance) {
|
|
820
829
|
const handleChange = () => {
|
|
821
830
|
const value = textareaInput.value === "" ? null : textareaInput.value;
|
|
822
831
|
ctx.instance.triggerOnChange(pathKey, value);
|
|
@@ -824,11 +833,11 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
824
833
|
textareaInput.addEventListener("blur", handleChange);
|
|
825
834
|
textareaInput.addEventListener("input", handleChange);
|
|
826
835
|
}
|
|
827
|
-
if (element.autoExpand ||
|
|
836
|
+
if (element.autoExpand || readonly) {
|
|
828
837
|
applyAutoExpand(textareaInput);
|
|
829
838
|
}
|
|
830
839
|
textareaWrapper.appendChild(textareaInput);
|
|
831
|
-
if (!
|
|
840
|
+
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
832
841
|
const counter = createCharCounter(element, textareaInput, true);
|
|
833
842
|
textareaWrapper.appendChild(counter);
|
|
834
843
|
}
|
|
@@ -836,6 +845,7 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
836
845
|
}
|
|
837
846
|
function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
838
847
|
const state = ctx.state;
|
|
848
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
839
849
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
840
850
|
const values = Array.isArray(prefillValues) ? [...prefillValues] : [];
|
|
841
851
|
const minCount = element.minCount ?? 1;
|
|
@@ -866,8 +876,8 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
866
876
|
textareaInput.placeholder = element.placeholder || t("placeholderText", state);
|
|
867
877
|
textareaInput.rows = element.rows || 4;
|
|
868
878
|
textareaInput.value = value;
|
|
869
|
-
textareaInput.readOnly =
|
|
870
|
-
if (!
|
|
879
|
+
textareaInput.readOnly = readonly;
|
|
880
|
+
if (!readonly && ctx.instance) {
|
|
871
881
|
const handleChange = () => {
|
|
872
882
|
const value2 = textareaInput.value === "" ? null : textareaInput.value;
|
|
873
883
|
ctx.instance.triggerOnChange(textareaInput.name, value2);
|
|
@@ -875,11 +885,11 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
875
885
|
textareaInput.addEventListener("blur", handleChange);
|
|
876
886
|
textareaInput.addEventListener("input", handleChange);
|
|
877
887
|
}
|
|
878
|
-
if (element.autoExpand ||
|
|
888
|
+
if (element.autoExpand || readonly) {
|
|
879
889
|
applyAutoExpand(textareaInput);
|
|
880
890
|
}
|
|
881
891
|
textareaContainer.appendChild(textareaInput);
|
|
882
|
-
if (!
|
|
892
|
+
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
883
893
|
const counter = createCharCounter(element, textareaInput, true);
|
|
884
894
|
textareaContainer.appendChild(counter);
|
|
885
895
|
}
|
|
@@ -893,7 +903,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
893
903
|
return itemWrapper;
|
|
894
904
|
}
|
|
895
905
|
function updateRemoveButtons() {
|
|
896
|
-
if (
|
|
906
|
+
if (readonly) return;
|
|
897
907
|
const items = container.querySelectorAll(".multiple-textarea-item");
|
|
898
908
|
const currentCount = items.length;
|
|
899
909
|
items.forEach((item) => {
|
|
@@ -927,7 +937,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
927
937
|
}
|
|
928
938
|
let addRow = null;
|
|
929
939
|
let countDisplay = null;
|
|
930
|
-
if (!
|
|
940
|
+
if (!readonly) {
|
|
931
941
|
addRow = document.createElement("div");
|
|
932
942
|
addRow.className = "flex items-center gap-3 mt-2";
|
|
933
943
|
const addBtn = document.createElement("button");
|
|
@@ -961,7 +971,9 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
961
971
|
}
|
|
962
972
|
function updateAddButton() {
|
|
963
973
|
if (!addRow || !countDisplay) return;
|
|
964
|
-
const addBtn = addRow.querySelector(
|
|
974
|
+
const addBtn = addRow.querySelector(
|
|
975
|
+
".add-textarea-btn"
|
|
976
|
+
);
|
|
965
977
|
if (addBtn) {
|
|
966
978
|
const disabled = values.length >= maxCount;
|
|
967
979
|
addBtn.disabled = disabled;
|
|
@@ -980,7 +992,7 @@ function validateTextareaElement(element, key, context) {
|
|
|
980
992
|
function updateTextareaField(element, fieldPath, value, context) {
|
|
981
993
|
updateTextField(element, fieldPath, value, context);
|
|
982
994
|
const { scopeRoot, state } = context;
|
|
983
|
-
const shouldAutoExpand = element.autoExpand || state
|
|
995
|
+
const shouldAutoExpand = element.autoExpand || isElementReadonly(element, state);
|
|
984
996
|
if (!shouldAutoExpand) return;
|
|
985
997
|
if (element.multiple) {
|
|
986
998
|
const textareas = scopeRoot.querySelectorAll(
|
|
@@ -1041,6 +1053,7 @@ function createNumberRangeHint(element, input) {
|
|
|
1041
1053
|
}
|
|
1042
1054
|
function renderNumberElement(element, ctx, wrapper, pathKey) {
|
|
1043
1055
|
const state = ctx.state;
|
|
1056
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
1044
1057
|
const inputWrapper = document.createElement("div");
|
|
1045
1058
|
inputWrapper.style.cssText = "position: relative;";
|
|
1046
1059
|
const numberInput = document.createElement("input");
|
|
@@ -1053,8 +1066,8 @@ function renderNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1053
1066
|
if (element.max !== void 0) numberInput.max = element.max.toString();
|
|
1054
1067
|
if (element.step !== void 0) numberInput.step = element.step.toString();
|
|
1055
1068
|
numberInput.value = ctx.prefill[element.key] || element.default || "";
|
|
1056
|
-
numberInput.readOnly =
|
|
1057
|
-
if (!
|
|
1069
|
+
numberInput.readOnly = readonly;
|
|
1070
|
+
if (!readonly && ctx.instance) {
|
|
1058
1071
|
const handleChange = () => {
|
|
1059
1072
|
const value = numberInput.value ? parseFloat(numberInput.value) : null;
|
|
1060
1073
|
ctx.instance.triggerOnChange(pathKey, value);
|
|
@@ -1063,7 +1076,7 @@ function renderNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1063
1076
|
numberInput.addEventListener("input", handleChange);
|
|
1064
1077
|
}
|
|
1065
1078
|
inputWrapper.appendChild(numberInput);
|
|
1066
|
-
if (!
|
|
1079
|
+
if (!readonly && (element.min != null || element.max != null)) {
|
|
1067
1080
|
const counter = createNumberRangeHint(element, numberInput);
|
|
1068
1081
|
inputWrapper.appendChild(counter);
|
|
1069
1082
|
}
|
|
@@ -1071,6 +1084,7 @@ function renderNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1071
1084
|
}
|
|
1072
1085
|
function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
1073
1086
|
const state = ctx.state;
|
|
1087
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
1074
1088
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
1075
1089
|
const values = Array.isArray(prefillValues) ? [...prefillValues] : [];
|
|
1076
1090
|
const minCount = element.minCount ?? 1;
|
|
@@ -1104,8 +1118,8 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1104
1118
|
if (element.max !== void 0) numberInput.max = element.max.toString();
|
|
1105
1119
|
if (element.step !== void 0) numberInput.step = element.step.toString();
|
|
1106
1120
|
numberInput.value = value.toString();
|
|
1107
|
-
numberInput.readOnly =
|
|
1108
|
-
if (!
|
|
1121
|
+
numberInput.readOnly = readonly;
|
|
1122
|
+
if (!readonly && ctx.instance) {
|
|
1109
1123
|
const handleChange = () => {
|
|
1110
1124
|
const val = numberInput.value ? parseFloat(numberInput.value) : null;
|
|
1111
1125
|
ctx.instance.triggerOnChange(numberInput.name, val);
|
|
@@ -1114,7 +1128,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1114
1128
|
numberInput.addEventListener("input", handleChange);
|
|
1115
1129
|
}
|
|
1116
1130
|
inputContainer.appendChild(numberInput);
|
|
1117
|
-
if (!
|
|
1131
|
+
if (!readonly && (element.min != null || element.max != null)) {
|
|
1118
1132
|
const counter = createNumberRangeHint(element, numberInput);
|
|
1119
1133
|
inputContainer.appendChild(counter);
|
|
1120
1134
|
}
|
|
@@ -1128,7 +1142,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1128
1142
|
return itemWrapper;
|
|
1129
1143
|
}
|
|
1130
1144
|
function updateRemoveButtons() {
|
|
1131
|
-
if (
|
|
1145
|
+
if (readonly) return;
|
|
1132
1146
|
const items = container.querySelectorAll(".multiple-number-item");
|
|
1133
1147
|
const currentCount = items.length;
|
|
1134
1148
|
items.forEach((item) => {
|
|
@@ -1162,7 +1176,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1162
1176
|
}
|
|
1163
1177
|
let addRow = null;
|
|
1164
1178
|
let countDisplay = null;
|
|
1165
|
-
if (!
|
|
1179
|
+
if (!readonly) {
|
|
1166
1180
|
addRow = document.createElement("div");
|
|
1167
1181
|
addRow.className = "flex items-center gap-3 mt-2";
|
|
1168
1182
|
const addBtn = document.createElement("button");
|
|
@@ -1367,10 +1381,11 @@ function updateNumberField(element, fieldPath, value, context) {
|
|
|
1367
1381
|
// src/components/select.ts
|
|
1368
1382
|
function renderSelectElement(element, ctx, wrapper, pathKey) {
|
|
1369
1383
|
const state = ctx.state;
|
|
1384
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
1370
1385
|
const selectInput = document.createElement("select");
|
|
1371
1386
|
selectInput.className = "w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500";
|
|
1372
1387
|
selectInput.name = pathKey;
|
|
1373
|
-
selectInput.disabled =
|
|
1388
|
+
selectInput.disabled = readonly;
|
|
1374
1389
|
(element.options || []).forEach((option) => {
|
|
1375
1390
|
const optionEl = document.createElement("option");
|
|
1376
1391
|
optionEl.value = option.value;
|
|
@@ -1380,14 +1395,14 @@ function renderSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1380
1395
|
}
|
|
1381
1396
|
selectInput.appendChild(optionEl);
|
|
1382
1397
|
});
|
|
1383
|
-
if (!
|
|
1398
|
+
if (!readonly && ctx.instance) {
|
|
1384
1399
|
const handleChange = () => {
|
|
1385
1400
|
ctx.instance.triggerOnChange(pathKey, selectInput.value);
|
|
1386
1401
|
};
|
|
1387
1402
|
selectInput.addEventListener("change", handleChange);
|
|
1388
1403
|
}
|
|
1389
1404
|
wrapper.appendChild(selectInput);
|
|
1390
|
-
if (!
|
|
1405
|
+
if (!readonly) {
|
|
1391
1406
|
const selectHint = document.createElement("p");
|
|
1392
1407
|
selectHint.className = "text-xs text-gray-500 mt-1";
|
|
1393
1408
|
selectHint.textContent = makeFieldHint(element, state);
|
|
@@ -1396,6 +1411,7 @@ function renderSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1396
1411
|
}
|
|
1397
1412
|
function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
1398
1413
|
const state = ctx.state;
|
|
1414
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
1399
1415
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
1400
1416
|
const values = Array.isArray(prefillValues) ? [...prefillValues] : [];
|
|
1401
1417
|
const minCount = element.minCount ?? 1;
|
|
@@ -1420,7 +1436,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1420
1436
|
itemWrapper.className = "multiple-select-item flex items-center gap-2";
|
|
1421
1437
|
const selectInput = document.createElement("select");
|
|
1422
1438
|
selectInput.className = "flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500";
|
|
1423
|
-
selectInput.disabled =
|
|
1439
|
+
selectInput.disabled = readonly;
|
|
1424
1440
|
(element.options || []).forEach((option) => {
|
|
1425
1441
|
const optionElement = document.createElement("option");
|
|
1426
1442
|
optionElement.value = option.value;
|
|
@@ -1430,7 +1446,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1430
1446
|
}
|
|
1431
1447
|
selectInput.appendChild(optionElement);
|
|
1432
1448
|
});
|
|
1433
|
-
if (!
|
|
1449
|
+
if (!readonly && ctx.instance) {
|
|
1434
1450
|
const handleChange = () => {
|
|
1435
1451
|
ctx.instance.triggerOnChange(selectInput.name, selectInput.value);
|
|
1436
1452
|
};
|
|
@@ -1446,7 +1462,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1446
1462
|
return itemWrapper;
|
|
1447
1463
|
}
|
|
1448
1464
|
function updateRemoveButtons() {
|
|
1449
|
-
if (
|
|
1465
|
+
if (readonly) return;
|
|
1450
1466
|
const items = container.querySelectorAll(".multiple-select-item");
|
|
1451
1467
|
const currentCount = items.length;
|
|
1452
1468
|
items.forEach((item) => {
|
|
@@ -1478,7 +1494,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1478
1494
|
}
|
|
1479
1495
|
let addRow = null;
|
|
1480
1496
|
let countDisplay = null;
|
|
1481
|
-
if (!
|
|
1497
|
+
if (!readonly) {
|
|
1482
1498
|
addRow = document.createElement("div");
|
|
1483
1499
|
addRow.className = "flex items-center gap-3 mt-2";
|
|
1484
1500
|
const addBtn = document.createElement("button");
|
|
@@ -1525,7 +1541,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1525
1541
|
values.forEach((value) => addSelectItem(value));
|
|
1526
1542
|
updateAddButton();
|
|
1527
1543
|
updateRemoveButtons();
|
|
1528
|
-
if (!
|
|
1544
|
+
if (!readonly) {
|
|
1529
1545
|
const hint = document.createElement("p");
|
|
1530
1546
|
hint.className = "text-xs text-gray-500 mt-1";
|
|
1531
1547
|
hint.textContent = makeFieldHint(element, state);
|
|
@@ -1741,12 +1757,14 @@ function buildSegmentedGroup(element, currentValue, hiddenInput, readonly, onCha
|
|
|
1741
1757
|
}
|
|
1742
1758
|
function renderSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
1743
1759
|
const state = ctx.state;
|
|
1744
|
-
const initialValue = String(
|
|
1760
|
+
const initialValue = String(
|
|
1761
|
+
ctx.prefill[element.key] ?? element.default ?? ""
|
|
1762
|
+
);
|
|
1745
1763
|
const hiddenInput = document.createElement("input");
|
|
1746
1764
|
hiddenInput.type = "hidden";
|
|
1747
1765
|
hiddenInput.name = pathKey;
|
|
1748
1766
|
hiddenInput.value = initialValue;
|
|
1749
|
-
const readonly = state
|
|
1767
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
1750
1768
|
const onChange = !readonly && ctx.instance ? (value) => {
|
|
1751
1769
|
ctx.instance.triggerOnChange(pathKey, value);
|
|
1752
1770
|
} : null;
|
|
@@ -1775,7 +1793,7 @@ function renderMultipleSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
|
1775
1793
|
while (values.length < minCount) {
|
|
1776
1794
|
values.push(element.default || element.options?.[0]?.value || "");
|
|
1777
1795
|
}
|
|
1778
|
-
const readonly = state
|
|
1796
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
1779
1797
|
const container = document.createElement("div");
|
|
1780
1798
|
container.className = "space-y-2";
|
|
1781
1799
|
wrapper.appendChild(container);
|
|
@@ -2178,9 +2196,7 @@ function renderUploadedVideoPreview(container, thumbnailUrl, _videoType, state)
|
|
|
2178
2196
|
video.preload = "metadata";
|
|
2179
2197
|
video.muted = true;
|
|
2180
2198
|
video.src = thumbnailUrl;
|
|
2181
|
-
video.appendChild(
|
|
2182
|
-
document.createTextNode(t("videoNotSupported", state))
|
|
2183
|
-
);
|
|
2199
|
+
video.appendChild(document.createTextNode(t("videoNotSupported", state)));
|
|
2184
2200
|
container.appendChild(video);
|
|
2185
2201
|
}
|
|
2186
2202
|
function renderDeleteButton(container, resourceId, state) {
|
|
@@ -2992,9 +3008,15 @@ function setupFilesPickerHandler(filesPicker, initialFiles, state, updateCallbac
|
|
|
2992
3008
|
}
|
|
2993
3009
|
function renderFileElement(element, ctx, wrapper, pathKey) {
|
|
2994
3010
|
const state = ctx.state;
|
|
2995
|
-
if (state
|
|
2996
|
-
const
|
|
3011
|
+
if (isElementReadonly(element, state, ctx)) {
|
|
3012
|
+
const rawInitial = ctx.prefill[element.key];
|
|
3013
|
+
const initial = typeof rawInitial === "string" ? rawInitial : "";
|
|
2997
3014
|
if (initial) {
|
|
3015
|
+
const hiddenInput = document.createElement("input");
|
|
3016
|
+
hiddenInput.type = "hidden";
|
|
3017
|
+
hiddenInput.name = pathKey;
|
|
3018
|
+
hiddenInput.value = initial;
|
|
3019
|
+
wrapper.appendChild(hiddenInput);
|
|
2998
3020
|
renderFilePreviewReadonly(initial, state).then((filePreview) => {
|
|
2999
3021
|
wrapper.appendChild(filePreview);
|
|
3000
3022
|
}).catch((err) => {
|
|
@@ -3082,10 +3104,24 @@ function renderFileElement(element, ctx, wrapper, pathKey) {
|
|
|
3082
3104
|
}
|
|
3083
3105
|
function renderFilesElement(element, ctx, wrapper, pathKey) {
|
|
3084
3106
|
const state = ctx.state;
|
|
3085
|
-
if (state
|
|
3107
|
+
if (isElementReadonly(element, state, ctx)) {
|
|
3108
|
+
const rawPrefill = ctx.prefill[element.key];
|
|
3109
|
+
const initialFiles = Array.isArray(rawPrefill) ? rawPrefill : [];
|
|
3110
|
+
const filesWrapper = document.createElement("div");
|
|
3111
|
+
filesWrapper.className = "space-y-2";
|
|
3112
|
+
filesWrapper.dataset.filesWrapper = pathKey;
|
|
3113
|
+
const filesList = document.createElement("div");
|
|
3114
|
+
filesList.className = "files-list";
|
|
3115
|
+
initialFiles.forEach((resourceId) => {
|
|
3116
|
+
const pill = document.createElement("div");
|
|
3117
|
+
pill.className = "resource-pill";
|
|
3118
|
+
pill.dataset.resourceId = resourceId;
|
|
3119
|
+
filesList.appendChild(pill);
|
|
3120
|
+
});
|
|
3121
|
+
filesWrapper.appendChild(filesList);
|
|
3122
|
+
wrapper.appendChild(filesWrapper);
|
|
3086
3123
|
const resultsWrapper = document.createElement("div");
|
|
3087
3124
|
resultsWrapper.className = "space-y-4";
|
|
3088
|
-
const initialFiles = ctx.prefill[element.key] || [];
|
|
3089
3125
|
if (initialFiles.length > 0) {
|
|
3090
3126
|
initialFiles.forEach((resourceId) => {
|
|
3091
3127
|
renderFilePreviewReadonly(resourceId, state).then((filePreview) => {
|
|
@@ -3116,6 +3152,7 @@ function renderFilesElement(element, ctx, wrapper, pathKey) {
|
|
|
3116
3152
|
};
|
|
3117
3153
|
const filesWrapper = document.createElement("div");
|
|
3118
3154
|
filesWrapper.className = "space-y-2";
|
|
3155
|
+
filesWrapper.dataset.filesWrapper = pathKey;
|
|
3119
3156
|
const filesPicker = document.createElement("input");
|
|
3120
3157
|
filesPicker.type = "file";
|
|
3121
3158
|
filesPicker.name = pathKey;
|
|
@@ -3165,10 +3202,24 @@ function renderMultipleFileElement(element, ctx, wrapper, pathKey) {
|
|
|
3165
3202
|
const state = ctx.state;
|
|
3166
3203
|
const minFiles = element.minCount ?? 0;
|
|
3167
3204
|
const maxFiles = element.maxCount ?? Infinity;
|
|
3168
|
-
if (state
|
|
3205
|
+
if (isElementReadonly(element, state, ctx)) {
|
|
3206
|
+
const rawPrefill = ctx.prefill[element.key];
|
|
3207
|
+
const initialFiles = Array.isArray(rawPrefill) ? rawPrefill : [];
|
|
3208
|
+
const filesWrapper = document.createElement("div");
|
|
3209
|
+
filesWrapper.className = "space-y-2";
|
|
3210
|
+
filesWrapper.dataset.filesWrapper = pathKey;
|
|
3211
|
+
const filesList = document.createElement("div");
|
|
3212
|
+
filesList.className = "files-list";
|
|
3213
|
+
initialFiles.forEach((resourceId) => {
|
|
3214
|
+
const pill = document.createElement("div");
|
|
3215
|
+
pill.className = "resource-pill";
|
|
3216
|
+
pill.dataset.resourceId = resourceId;
|
|
3217
|
+
filesList.appendChild(pill);
|
|
3218
|
+
});
|
|
3219
|
+
filesWrapper.appendChild(filesList);
|
|
3220
|
+
wrapper.appendChild(filesWrapper);
|
|
3169
3221
|
const resultsWrapper = document.createElement("div");
|
|
3170
3222
|
resultsWrapper.className = "space-y-4";
|
|
3171
|
-
const initialFiles = ctx.prefill[element.key] || [];
|
|
3172
3223
|
if (initialFiles.length > 0) {
|
|
3173
3224
|
initialFiles.forEach((resourceId) => {
|
|
3174
3225
|
renderFilePreviewReadonly(resourceId, state).then((filePreview) => {
|
|
@@ -3184,6 +3235,7 @@ function renderMultipleFileElement(element, ctx, wrapper, pathKey) {
|
|
|
3184
3235
|
} else {
|
|
3185
3236
|
const filesWrapper = document.createElement("div");
|
|
3186
3237
|
filesWrapper.className = "space-y-2";
|
|
3238
|
+
filesWrapper.dataset.filesWrapper = pathKey;
|
|
3187
3239
|
const filesPicker = document.createElement("input");
|
|
3188
3240
|
filesPicker.type = "file";
|
|
3189
3241
|
filesPicker.name = pathKey;
|
|
@@ -3297,10 +3349,9 @@ function validateFileElement(element, key, context) {
|
|
|
3297
3349
|
};
|
|
3298
3350
|
if (isMultipleField) {
|
|
3299
3351
|
const fullKey = pathJoin(path, key);
|
|
3300
|
-
const
|
|
3301
|
-
`
|
|
3352
|
+
const filesWrapper = scopeRoot.querySelector(
|
|
3353
|
+
`[data-files-wrapper="${fullKey}"]`
|
|
3302
3354
|
);
|
|
3303
|
-
const filesWrapper = pickerInput?.closest(".space-y-2");
|
|
3304
3355
|
const container = filesWrapper?.querySelector(".files-list") || null;
|
|
3305
3356
|
const resourceIds = [];
|
|
3306
3357
|
if (container) {
|
|
@@ -3559,15 +3610,16 @@ function createEditColourUI(value, pathKey, ctx) {
|
|
|
3559
3610
|
}
|
|
3560
3611
|
function renderColourElement(element, ctx, wrapper, pathKey) {
|
|
3561
3612
|
const state = ctx.state;
|
|
3613
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
3562
3614
|
const initialValue = ctx.prefill[element.key] || element.default || "#000000";
|
|
3563
|
-
if (
|
|
3615
|
+
if (readonly) {
|
|
3564
3616
|
const readonlyUI = createReadonlyColourUI(initialValue);
|
|
3565
3617
|
wrapper.appendChild(readonlyUI);
|
|
3566
3618
|
} else {
|
|
3567
3619
|
const editUI = createEditColourUI(initialValue, pathKey, ctx);
|
|
3568
3620
|
wrapper.appendChild(editUI);
|
|
3569
3621
|
}
|
|
3570
|
-
if (!
|
|
3622
|
+
if (!readonly) {
|
|
3571
3623
|
const colourHint = document.createElement("p");
|
|
3572
3624
|
colourHint.className = "mt-1";
|
|
3573
3625
|
colourHint.style.cssText = `
|
|
@@ -3580,6 +3632,7 @@ function renderColourElement(element, ctx, wrapper, pathKey) {
|
|
|
3580
3632
|
}
|
|
3581
3633
|
function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
3582
3634
|
const state = ctx.state;
|
|
3635
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
3583
3636
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
3584
3637
|
const values = Array.isArray(prefillValues) ? [...prefillValues] : [];
|
|
3585
3638
|
const minCount = element.minCount ?? 1;
|
|
@@ -3602,7 +3655,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
3602
3655
|
function addColourItem(value = "#000000", index = -1) {
|
|
3603
3656
|
const itemWrapper = document.createElement("div");
|
|
3604
3657
|
itemWrapper.className = "multiple-colour-item flex items-center gap-2";
|
|
3605
|
-
if (
|
|
3658
|
+
if (readonly) {
|
|
3606
3659
|
const readonlyUI = createReadonlyColourUI(value);
|
|
3607
3660
|
while (readonlyUI.firstChild) {
|
|
3608
3661
|
itemWrapper.appendChild(readonlyUI.firstChild);
|
|
@@ -3622,7 +3675,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
3622
3675
|
return itemWrapper;
|
|
3623
3676
|
}
|
|
3624
3677
|
function updateRemoveButtons() {
|
|
3625
|
-
if (
|
|
3678
|
+
if (readonly) return;
|
|
3626
3679
|
const items = container.querySelectorAll(".multiple-colour-item");
|
|
3627
3680
|
const currentCount = items.length;
|
|
3628
3681
|
items.forEach((item) => {
|
|
@@ -3667,7 +3720,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
3667
3720
|
}
|
|
3668
3721
|
let addRow = null;
|
|
3669
3722
|
let countDisplay = null;
|
|
3670
|
-
if (!
|
|
3723
|
+
if (!readonly) {
|
|
3671
3724
|
addRow = document.createElement("div");
|
|
3672
3725
|
addRow.className = "flex items-center gap-3 mt-2";
|
|
3673
3726
|
const addBtn = document.createElement("button");
|
|
@@ -3714,7 +3767,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
3714
3767
|
values.forEach((value) => addColourItem(value));
|
|
3715
3768
|
updateAddButton();
|
|
3716
3769
|
updateRemoveButtons();
|
|
3717
|
-
if (!
|
|
3770
|
+
if (!readonly) {
|
|
3718
3771
|
const hint = document.createElement("p");
|
|
3719
3772
|
hint.className = "mt-1";
|
|
3720
3773
|
hint.style.cssText = `
|
|
@@ -3783,7 +3836,9 @@ function validateColourElement(element, key, context) {
|
|
|
3783
3836
|
return normalized;
|
|
3784
3837
|
};
|
|
3785
3838
|
if (element.multiple) {
|
|
3786
|
-
const hexInputs = scopeRoot.querySelectorAll(
|
|
3839
|
+
const hexInputs = scopeRoot.querySelectorAll(
|
|
3840
|
+
`[name^="${key}["].colour-hex-input`
|
|
3841
|
+
);
|
|
3787
3842
|
const values = [];
|
|
3788
3843
|
hexInputs.forEach((input, index) => {
|
|
3789
3844
|
const val = input?.value ?? "";
|
|
@@ -3830,7 +3885,9 @@ function updateColourField(element, fieldPath, value, context) {
|
|
|
3830
3885
|
);
|
|
3831
3886
|
return;
|
|
3832
3887
|
}
|
|
3833
|
-
const hexInputs = scopeRoot.querySelectorAll(
|
|
3888
|
+
const hexInputs = scopeRoot.querySelectorAll(
|
|
3889
|
+
`[name^="${fieldPath}["].colour-hex-input`
|
|
3890
|
+
);
|
|
3834
3891
|
hexInputs.forEach((hexInput, index) => {
|
|
3835
3892
|
if (index < value.length) {
|
|
3836
3893
|
const normalized = normalizeColourValue(value[index]);
|
|
@@ -4025,6 +4082,7 @@ function renderSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
4025
4082
|
);
|
|
4026
4083
|
}
|
|
4027
4084
|
const state = ctx.state;
|
|
4085
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
4028
4086
|
const defaultValue = element.default !== void 0 ? element.default : (element.min + element.max) / 2;
|
|
4029
4087
|
const initialValue = ctx.prefill[element.key] ?? defaultValue;
|
|
4030
4088
|
const sliderUI = createSliderUI(
|
|
@@ -4032,10 +4090,10 @@ function renderSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
4032
4090
|
pathKey,
|
|
4033
4091
|
element,
|
|
4034
4092
|
ctx,
|
|
4035
|
-
|
|
4093
|
+
readonly
|
|
4036
4094
|
);
|
|
4037
4095
|
wrapper.appendChild(sliderUI);
|
|
4038
|
-
if (!
|
|
4096
|
+
if (!readonly) {
|
|
4039
4097
|
const hint = document.createElement("p");
|
|
4040
4098
|
hint.className = "mt-1";
|
|
4041
4099
|
hint.style.cssText = `
|
|
@@ -4059,6 +4117,7 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
4059
4117
|
);
|
|
4060
4118
|
}
|
|
4061
4119
|
const state = ctx.state;
|
|
4120
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
4062
4121
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
4063
4122
|
const values = Array.isArray(prefillValues) ? [...prefillValues] : [];
|
|
4064
4123
|
const minCount = element.minCount ?? 1;
|
|
@@ -4083,13 +4142,7 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
4083
4142
|
const itemWrapper = document.createElement("div");
|
|
4084
4143
|
itemWrapper.className = "multiple-slider-item flex items-start gap-2";
|
|
4085
4144
|
const tempPathKey = `${pathKey}[${container.children.length}]`;
|
|
4086
|
-
const sliderUI = createSliderUI(
|
|
4087
|
-
value,
|
|
4088
|
-
tempPathKey,
|
|
4089
|
-
element,
|
|
4090
|
-
ctx,
|
|
4091
|
-
state.config.readonly
|
|
4092
|
-
);
|
|
4145
|
+
const sliderUI = createSliderUI(value, tempPathKey, element, ctx, readonly);
|
|
4093
4146
|
sliderUI.style.flex = "1";
|
|
4094
4147
|
itemWrapper.appendChild(sliderUI);
|
|
4095
4148
|
if (index === -1) {
|
|
@@ -4101,7 +4154,7 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
4101
4154
|
return itemWrapper;
|
|
4102
4155
|
}
|
|
4103
4156
|
function updateRemoveButtons() {
|
|
4104
|
-
if (
|
|
4157
|
+
if (readonly) return;
|
|
4105
4158
|
const items = container.querySelectorAll(".multiple-slider-item");
|
|
4106
4159
|
const currentCount = items.length;
|
|
4107
4160
|
items.forEach((item) => {
|
|
@@ -4147,7 +4200,7 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
4147
4200
|
}
|
|
4148
4201
|
let addRow = null;
|
|
4149
4202
|
let countDisplay = null;
|
|
4150
|
-
if (!
|
|
4203
|
+
if (!readonly) {
|
|
4151
4204
|
addRow = document.createElement("div");
|
|
4152
4205
|
addRow.className = "flex items-center gap-3 mt-2";
|
|
4153
4206
|
const addBtn = document.createElement("button");
|
|
@@ -4193,7 +4246,7 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
4193
4246
|
values.forEach((value) => addSliderItem(value));
|
|
4194
4247
|
updateAddButton();
|
|
4195
4248
|
updateRemoveButtons();
|
|
4196
|
-
if (!
|
|
4249
|
+
if (!readonly) {
|
|
4197
4250
|
const hint = document.createElement("p");
|
|
4198
4251
|
hint.className = "mt-1";
|
|
4199
4252
|
hint.style.cssText = `
|
|
@@ -4432,9 +4485,7 @@ function mergeWithDefaults(prefill, defaults) {
|
|
|
4432
4485
|
}
|
|
4433
4486
|
function extractRootFormData(formRoot) {
|
|
4434
4487
|
const data = {};
|
|
4435
|
-
const inputs = formRoot.querySelectorAll(
|
|
4436
|
-
"input, select, textarea"
|
|
4437
|
-
);
|
|
4488
|
+
const inputs = formRoot.querySelectorAll("input, select, textarea");
|
|
4438
4489
|
inputs.forEach((input) => {
|
|
4439
4490
|
const fieldName = input.getAttribute("name");
|
|
4440
4491
|
if (fieldName && !fieldName.includes("[") && !fieldName.includes(".")) {
|
|
@@ -4498,7 +4549,8 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
4498
4549
|
} else {
|
|
4499
4550
|
itemsWrap.className = `grid grid-cols-${columns} gap-4`;
|
|
4500
4551
|
}
|
|
4501
|
-
|
|
4552
|
+
const containerIsReadonly = isElementReadonly(element, ctx.state, ctx);
|
|
4553
|
+
if (!containerIsReadonly) {
|
|
4502
4554
|
const hintsElement = createPrefillHints(element, pathKey);
|
|
4503
4555
|
if (hintsElement) {
|
|
4504
4556
|
containerWrap.appendChild(hintsElement);
|
|
@@ -4513,12 +4565,15 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
4513
4565
|
// Merged prefill with defaults for enableIf evaluation
|
|
4514
4566
|
formData: ctx.formData ?? ctx.prefill,
|
|
4515
4567
|
// Complete root data for enableIf evaluation
|
|
4516
|
-
state: ctx.state
|
|
4568
|
+
state: ctx.state,
|
|
4569
|
+
inheritedReadonly: containerIsReadonly || ctx.inheritedReadonly
|
|
4517
4570
|
};
|
|
4518
4571
|
element.elements.forEach((child) => {
|
|
4519
4572
|
if (child.hidden || child.type === "hidden") {
|
|
4520
4573
|
const prefillVal = containerPrefill[child.key] ?? child.default ?? null;
|
|
4521
|
-
itemsWrap.appendChild(
|
|
4574
|
+
itemsWrap.appendChild(
|
|
4575
|
+
createHiddenInput(pathJoin(subCtx.path, child.key), prefillVal)
|
|
4576
|
+
);
|
|
4522
4577
|
} else {
|
|
4523
4578
|
itemsWrap.appendChild(renderElement(child, subCtx));
|
|
4524
4579
|
}
|
|
@@ -4528,13 +4583,15 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
4528
4583
|
}
|
|
4529
4584
|
function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
4530
4585
|
const state = ctx.state;
|
|
4586
|
+
const containerIsReadonly = isElementReadonly(element, state, ctx);
|
|
4587
|
+
const childInheritedReadonly = containerIsReadonly || ctx.inheritedReadonly;
|
|
4531
4588
|
const containerWrap = document.createElement("div");
|
|
4532
4589
|
containerWrap.className = "border border-gray-200 rounded-lg p-4 bg-gray-50";
|
|
4533
4590
|
const countDisplay = document.createElement("span");
|
|
4534
4591
|
countDisplay.className = "text-sm text-gray-500";
|
|
4535
4592
|
const itemsWrap = document.createElement("div");
|
|
4536
4593
|
itemsWrap.className = "space-y-4";
|
|
4537
|
-
if (!
|
|
4594
|
+
if (!containerIsReadonly) {
|
|
4538
4595
|
const hintsElement = createPrefillHints(element, element.key);
|
|
4539
4596
|
if (hintsElement) {
|
|
4540
4597
|
containerWrap.appendChild(hintsElement);
|
|
@@ -4572,8 +4629,9 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4572
4629
|
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
4573
4630
|
prefill: childDefaults,
|
|
4574
4631
|
// Defaults for enableIf evaluation
|
|
4575
|
-
formData: currentFormData
|
|
4632
|
+
formData: currentFormData,
|
|
4576
4633
|
// Current root data from DOM for enableIf
|
|
4634
|
+
inheritedReadonly: childInheritedReadonly
|
|
4577
4635
|
};
|
|
4578
4636
|
const item = document.createElement("div");
|
|
4579
4637
|
item.className = "containerItem border border-gray-300 rounded-lg p-4 bg-white";
|
|
@@ -4587,13 +4645,18 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4587
4645
|
}
|
|
4588
4646
|
element.elements.forEach((child) => {
|
|
4589
4647
|
if (child.hidden || child.type === "hidden") {
|
|
4590
|
-
childWrapper.appendChild(
|
|
4648
|
+
childWrapper.appendChild(
|
|
4649
|
+
createHiddenInput(
|
|
4650
|
+
pathJoin(subCtx.path, child.key),
|
|
4651
|
+
child.default ?? null
|
|
4652
|
+
)
|
|
4653
|
+
);
|
|
4591
4654
|
} else {
|
|
4592
4655
|
childWrapper.appendChild(renderElement(child, subCtx));
|
|
4593
4656
|
}
|
|
4594
4657
|
});
|
|
4595
4658
|
item.appendChild(childWrapper);
|
|
4596
|
-
if (!
|
|
4659
|
+
if (!containerIsReadonly) {
|
|
4597
4660
|
const rem = document.createElement("button");
|
|
4598
4661
|
rem.type = "button";
|
|
4599
4662
|
rem.className = "absolute top-2 right-2 px-2 py-1 rounded";
|
|
@@ -4643,8 +4706,9 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4643
4706
|
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
4644
4707
|
prefill: mergedPrefill,
|
|
4645
4708
|
// Merged prefill with defaults for enableIf
|
|
4646
|
-
formData: ctx.formData ?? ctx.prefill
|
|
4709
|
+
formData: ctx.formData ?? ctx.prefill,
|
|
4647
4710
|
// Complete root data for enableIf
|
|
4711
|
+
inheritedReadonly: childInheritedReadonly
|
|
4648
4712
|
};
|
|
4649
4713
|
const item = document.createElement("div");
|
|
4650
4714
|
item.className = "containerItem border border-gray-300 rounded-lg p-4 bg-white";
|
|
@@ -4659,13 +4723,15 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4659
4723
|
element.elements.forEach((child) => {
|
|
4660
4724
|
if (child.hidden || child.type === "hidden") {
|
|
4661
4725
|
const prefillVal = prefillObj?.[child.key] ?? child.default ?? null;
|
|
4662
|
-
childWrapper.appendChild(
|
|
4726
|
+
childWrapper.appendChild(
|
|
4727
|
+
createHiddenInput(pathJoin(subCtx.path, child.key), prefillVal)
|
|
4728
|
+
);
|
|
4663
4729
|
} else {
|
|
4664
4730
|
childWrapper.appendChild(renderElement(child, subCtx));
|
|
4665
4731
|
}
|
|
4666
4732
|
});
|
|
4667
4733
|
item.appendChild(childWrapper);
|
|
4668
|
-
if (!
|
|
4734
|
+
if (!containerIsReadonly) {
|
|
4669
4735
|
const rem = document.createElement("button");
|
|
4670
4736
|
rem.type = "button";
|
|
4671
4737
|
rem.className = "absolute top-2 right-2 px-2 py-1 rounded";
|
|
@@ -4688,7 +4754,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4688
4754
|
itemsWrap.appendChild(item);
|
|
4689
4755
|
});
|
|
4690
4756
|
}
|
|
4691
|
-
if (!
|
|
4757
|
+
if (!containerIsReadonly) {
|
|
4692
4758
|
while (countItems() < min) {
|
|
4693
4759
|
const idx = countItems();
|
|
4694
4760
|
const subCtx = {
|
|
@@ -4696,8 +4762,9 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4696
4762
|
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
4697
4763
|
prefill: childDefaults,
|
|
4698
4764
|
// Defaults for enableIf evaluation
|
|
4699
|
-
formData: ctx.formData ?? ctx.prefill
|
|
4765
|
+
formData: ctx.formData ?? ctx.prefill,
|
|
4700
4766
|
// Complete root data for enableIf
|
|
4767
|
+
inheritedReadonly: childInheritedReadonly
|
|
4701
4768
|
};
|
|
4702
4769
|
const item = document.createElement("div");
|
|
4703
4770
|
item.className = "containerItem border border-gray-300 rounded-lg p-4 bg-white";
|
|
@@ -4711,7 +4778,12 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4711
4778
|
}
|
|
4712
4779
|
element.elements.forEach((child) => {
|
|
4713
4780
|
if (child.hidden || child.type === "hidden") {
|
|
4714
|
-
childWrapper.appendChild(
|
|
4781
|
+
childWrapper.appendChild(
|
|
4782
|
+
createHiddenInput(
|
|
4783
|
+
pathJoin(subCtx.path, child.key),
|
|
4784
|
+
child.default ?? null
|
|
4785
|
+
)
|
|
4786
|
+
);
|
|
4715
4787
|
} else {
|
|
4716
4788
|
childWrapper.appendChild(renderElement(child, subCtx));
|
|
4717
4789
|
}
|
|
@@ -4743,7 +4815,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4743
4815
|
}
|
|
4744
4816
|
}
|
|
4745
4817
|
containerWrap.appendChild(itemsWrap);
|
|
4746
|
-
if (!
|
|
4818
|
+
if (!containerIsReadonly) {
|
|
4747
4819
|
const addRow = document.createElement("div");
|
|
4748
4820
|
addRow.className = "flex items-center gap-3 mt-2";
|
|
4749
4821
|
addRow.appendChild(createAddButton());
|
|
@@ -4902,8 +4974,10 @@ function updateContainerField(element, fieldPath, value, context) {
|
|
|
4902
4974
|
const filesKey = richChild.filesKey ?? "files";
|
|
4903
4975
|
const containerValue = itemValue;
|
|
4904
4976
|
const compositeValue = {};
|
|
4905
|
-
if (textKey in containerValue)
|
|
4906
|
-
|
|
4977
|
+
if (textKey in containerValue)
|
|
4978
|
+
compositeValue[textKey] = containerValue[textKey];
|
|
4979
|
+
if (filesKey in containerValue)
|
|
4980
|
+
compositeValue[filesKey] = containerValue[filesKey];
|
|
4907
4981
|
if (Object.keys(compositeValue).length > 0) {
|
|
4908
4982
|
instance.updateField(childPath, compositeValue);
|
|
4909
4983
|
}
|
|
@@ -4939,8 +5013,10 @@ function updateContainerField(element, fieldPath, value, context) {
|
|
|
4939
5013
|
const filesKey = richChild.filesKey ?? "files";
|
|
4940
5014
|
const containerValue = value;
|
|
4941
5015
|
const compositeValue = {};
|
|
4942
|
-
if (textKey in containerValue)
|
|
4943
|
-
|
|
5016
|
+
if (textKey in containerValue)
|
|
5017
|
+
compositeValue[textKey] = containerValue[textKey];
|
|
5018
|
+
if (filesKey in containerValue)
|
|
5019
|
+
compositeValue[filesKey] = containerValue[filesKey];
|
|
4944
5020
|
if (Object.keys(compositeValue).length > 0) {
|
|
4945
5021
|
instance.updateField(childPath, compositeValue);
|
|
4946
5022
|
}
|
|
@@ -5278,12 +5354,21 @@ function renderEditTable(element, initialData, pathKey, ctx, wrapper) {
|
|
|
5278
5354
|
const hiddenInput = document.createElement("input");
|
|
5279
5355
|
hiddenInput.type = "hidden";
|
|
5280
5356
|
hiddenInput.name = pathKey;
|
|
5281
|
-
hiddenInput.value = JSON.stringify({
|
|
5357
|
+
hiddenInput.value = JSON.stringify({
|
|
5358
|
+
[cellsKey]: cells,
|
|
5359
|
+
[mergesKey]: merges
|
|
5360
|
+
});
|
|
5282
5361
|
wrapper.appendChild(hiddenInput);
|
|
5283
5362
|
function persistValue() {
|
|
5284
|
-
hiddenInput.value = JSON.stringify({
|
|
5363
|
+
hiddenInput.value = JSON.stringify({
|
|
5364
|
+
[cellsKey]: cells,
|
|
5365
|
+
[mergesKey]: merges
|
|
5366
|
+
});
|
|
5285
5367
|
if (instance) {
|
|
5286
|
-
instance.triggerOnChange(pathKey, {
|
|
5368
|
+
instance.triggerOnChange(pathKey, {
|
|
5369
|
+
[cellsKey]: cells,
|
|
5370
|
+
[mergesKey]: merges
|
|
5371
|
+
});
|
|
5287
5372
|
}
|
|
5288
5373
|
}
|
|
5289
5374
|
hiddenInput._applyExternalUpdate = (data) => {
|
|
@@ -5342,9 +5427,7 @@ function renderEditTable(element, initialData, pathKey, ctx, wrapper) {
|
|
|
5342
5427
|
rebuild();
|
|
5343
5428
|
} catch (e) {
|
|
5344
5429
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
5345
|
-
console.error(
|
|
5346
|
-
t("tableImportError", state).replace("{error}", errMsg)
|
|
5347
|
-
);
|
|
5430
|
+
console.error(t("tableImportError", state).replace("{error}", errMsg));
|
|
5348
5431
|
} finally {
|
|
5349
5432
|
overlay.remove();
|
|
5350
5433
|
}
|
|
@@ -5492,15 +5575,19 @@ function renderEditTable(element, initialData, pathKey, ctx, wrapper) {
|
|
|
5492
5575
|
contextMenu.style.display = "none";
|
|
5493
5576
|
}
|
|
5494
5577
|
const menuDismissCtrl = new AbortController();
|
|
5495
|
-
document.addEventListener(
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5578
|
+
document.addEventListener(
|
|
5579
|
+
"mousedown",
|
|
5580
|
+
(e) => {
|
|
5581
|
+
if (!wrapper.isConnected) {
|
|
5582
|
+
menuDismissCtrl.abort();
|
|
5583
|
+
return;
|
|
5584
|
+
}
|
|
5585
|
+
if (!contextMenu.contains(e.target)) {
|
|
5586
|
+
hideContextMenu();
|
|
5587
|
+
}
|
|
5588
|
+
},
|
|
5589
|
+
{ signal: menuDismissCtrl.signal }
|
|
5590
|
+
);
|
|
5504
5591
|
function applySelectionStyles() {
|
|
5505
5592
|
const range = selectionRange(sel);
|
|
5506
5593
|
const allTds = tableEl.querySelectorAll("td[data-row]");
|
|
@@ -5846,7 +5933,9 @@ function renderEditTable(element, initialData, pathKey, ctx, wrapper) {
|
|
|
5846
5933
|
if (!anchor) return;
|
|
5847
5934
|
const text = e.clipboardData?.getData("text/plain") ?? "";
|
|
5848
5935
|
const isMultiCell = text.includes(" ") || text.split(/\r?\n/).filter((l) => l).length > 1;
|
|
5849
|
-
const editing = tableEl.querySelector(
|
|
5936
|
+
const editing = tableEl.querySelector(
|
|
5937
|
+
"[contenteditable='true']"
|
|
5938
|
+
);
|
|
5850
5939
|
if (editing && !isMultiCell) return;
|
|
5851
5940
|
e.preventDefault();
|
|
5852
5941
|
if (editing) {
|
|
@@ -6002,7 +6091,11 @@ function renderEditTable(element, initialData, pathKey, ctx, wrapper) {
|
|
|
6002
6091
|
}
|
|
6003
6092
|
}
|
|
6004
6093
|
function updateTopZoneOverlays(mx, wr, tblR, scrollL, active) {
|
|
6005
|
-
const headerCells = active ? Array.from(
|
|
6094
|
+
const headerCells = active ? Array.from(
|
|
6095
|
+
tableEl.querySelectorAll(
|
|
6096
|
+
"thead td[data-col]"
|
|
6097
|
+
)
|
|
6098
|
+
) : [];
|
|
6006
6099
|
let closestColIdx = -1;
|
|
6007
6100
|
let closestColDist = Infinity;
|
|
6008
6101
|
let closestBorderX = -1;
|
|
@@ -6020,7 +6113,10 @@ function renderEditTable(element, initialData, pathKey, ctx, wrapper) {
|
|
|
6020
6113
|
if (borderDist < closestBorderDist && borderDist < 20) {
|
|
6021
6114
|
closestBorderDist = borderDist;
|
|
6022
6115
|
closestBorderX = cellRect.right - wr.left + scrollL;
|
|
6023
|
-
closestAfterCol = parseInt(
|
|
6116
|
+
closestAfterCol = parseInt(
|
|
6117
|
+
headerCells[i].getAttribute("data-col") ?? "0",
|
|
6118
|
+
10
|
|
6119
|
+
);
|
|
6024
6120
|
}
|
|
6025
6121
|
}
|
|
6026
6122
|
colRemoveBtns.forEach((btn, idx) => {
|
|
@@ -6075,7 +6171,10 @@ function renderEditTable(element, initialData, pathKey, ctx, wrapper) {
|
|
|
6075
6171
|
closestRowBorderDist = borderDist;
|
|
6076
6172
|
closestBorderY = trRect.bottom - wr.top;
|
|
6077
6173
|
const firstTd = allRowEls[i].querySelector("td[data-row]");
|
|
6078
|
-
closestAfterRow = parseInt(
|
|
6174
|
+
closestAfterRow = parseInt(
|
|
6175
|
+
firstTd?.getAttribute("data-row") ?? "0",
|
|
6176
|
+
10
|
|
6177
|
+
);
|
|
6079
6178
|
}
|
|
6080
6179
|
}
|
|
6081
6180
|
rowRemoveBtns.forEach((btn, idx) => {
|
|
@@ -6101,7 +6200,8 @@ function renderEditTable(element, initialData, pathKey, ctx, wrapper) {
|
|
|
6101
6200
|
let rafPending = false;
|
|
6102
6201
|
tableWrapper.onmousemove = (e) => {
|
|
6103
6202
|
const target = e.target;
|
|
6104
|
-
if (target.tagName === "BUTTON" && target.parentElement === tableWrapper)
|
|
6203
|
+
if (target.tagName === "BUTTON" && target.parentElement === tableWrapper)
|
|
6204
|
+
return;
|
|
6105
6205
|
if (rafPending) return;
|
|
6106
6206
|
rafPending = true;
|
|
6107
6207
|
const mx = e.clientX;
|
|
@@ -6160,6 +6260,7 @@ function isTableDataWithFieldNames(v, cellsKey) {
|
|
|
6160
6260
|
}
|
|
6161
6261
|
function renderTableElement(element, ctx, wrapper, pathKey) {
|
|
6162
6262
|
const state = ctx.state;
|
|
6263
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
6163
6264
|
const rawPrefill = ctx.prefill[element.key];
|
|
6164
6265
|
const cellsKey = element.fieldNames?.cells ?? "cells";
|
|
6165
6266
|
const mergesKey = element.fieldNames?.merges ?? "merges";
|
|
@@ -6194,11 +6295,13 @@ function renderTableElement(element, ctx, wrapper, pathKey) {
|
|
|
6194
6295
|
const cols = rows > 0 ? initialData.cells[0].length : 0;
|
|
6195
6296
|
const err = validateMerges(initialData.merges, rows, cols);
|
|
6196
6297
|
if (err) {
|
|
6197
|
-
console.warn(
|
|
6298
|
+
console.warn(
|
|
6299
|
+
`Table "${element.key}": invalid prefill merges stripped (${err})`
|
|
6300
|
+
);
|
|
6198
6301
|
initialData = { ...initialData, merges: [] };
|
|
6199
6302
|
}
|
|
6200
6303
|
}
|
|
6201
|
-
if (
|
|
6304
|
+
if (readonly) {
|
|
6202
6305
|
renderReadonlyTable(initialData, wrapper);
|
|
6203
6306
|
} else {
|
|
6204
6307
|
renderEditTable(element, initialData, pathKey, ctx, wrapper);
|
|
@@ -6875,20 +6978,26 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
6875
6978
|
});
|
|
6876
6979
|
let mentionTooltip = null;
|
|
6877
6980
|
backdrop.addEventListener("mouseover", (e) => {
|
|
6878
|
-
const mark = e.target.closest?.(
|
|
6981
|
+
const mark = e.target.closest?.(
|
|
6982
|
+
"mark"
|
|
6983
|
+
);
|
|
6879
6984
|
if (!mark?.dataset.rid) return;
|
|
6880
6985
|
mentionTooltip = removePortalTooltip(mentionTooltip);
|
|
6881
6986
|
mentionTooltip = showMentionTooltip(mark, mark.dataset.rid, state);
|
|
6882
6987
|
});
|
|
6883
6988
|
backdrop.addEventListener("mouseout", (e) => {
|
|
6884
|
-
const mark = e.target.closest?.(
|
|
6989
|
+
const mark = e.target.closest?.(
|
|
6990
|
+
"mark"
|
|
6991
|
+
);
|
|
6885
6992
|
if (!mark) return;
|
|
6886
6993
|
const related = e.relatedTarget;
|
|
6887
6994
|
if (related?.closest?.("mark")) return;
|
|
6888
6995
|
mentionTooltip = removePortalTooltip(mentionTooltip);
|
|
6889
6996
|
});
|
|
6890
6997
|
backdrop.addEventListener("mousedown", (e) => {
|
|
6891
|
-
const mark = e.target.closest?.(
|
|
6998
|
+
const mark = e.target.closest?.(
|
|
6999
|
+
"mark"
|
|
7000
|
+
);
|
|
6892
7001
|
if (!mark) return;
|
|
6893
7002
|
mentionTooltip = removePortalTooltip(mentionTooltip);
|
|
6894
7003
|
const marks = backdrop.querySelectorAll("mark");
|
|
@@ -7132,11 +7241,7 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
7132
7241
|
textarea.addEventListener("keydown", (e) => {
|
|
7133
7242
|
if (!dropdownState.open) return;
|
|
7134
7243
|
const labels = buildFileLabelsFromClosure();
|
|
7135
|
-
const filtered = filterFilesForDropdown(
|
|
7136
|
-
dropdownState.query,
|
|
7137
|
-
files,
|
|
7138
|
-
labels
|
|
7139
|
-
);
|
|
7244
|
+
const filtered = filterFilesForDropdown(dropdownState.query, files, labels);
|
|
7140
7245
|
if (e.key === "ArrowDown") {
|
|
7141
7246
|
e.preventDefault();
|
|
7142
7247
|
dropdownState.selectedIndex = Math.min(
|
|
@@ -7463,6 +7568,7 @@ function renderReadonlyMode(_element, ctx, wrapper, _pathKey, value) {
|
|
|
7463
7568
|
}
|
|
7464
7569
|
function renderRichInputElement(element, ctx, wrapper, pathKey) {
|
|
7465
7570
|
const state = ctx.state;
|
|
7571
|
+
const readonly = isElementReadonly(element, state, ctx);
|
|
7466
7572
|
const textKey = element.textKey ?? "text";
|
|
7467
7573
|
const filesKey = element.filesKey ?? "files";
|
|
7468
7574
|
let initialValue;
|
|
@@ -7500,7 +7606,7 @@ function renderRichInputElement(element, ctx, wrapper, pathKey) {
|
|
|
7500
7606
|
});
|
|
7501
7607
|
}
|
|
7502
7608
|
}
|
|
7503
|
-
if (
|
|
7609
|
+
if (readonly) {
|
|
7504
7610
|
renderReadonlyMode(element, ctx, wrapper, pathKey, initialValue);
|
|
7505
7611
|
} else {
|
|
7506
7612
|
if (!state.config.uploadFile) {
|
|
@@ -7562,9 +7668,7 @@ function validateRichInputElement(element, key, context) {
|
|
|
7562
7668
|
}
|
|
7563
7669
|
}
|
|
7564
7670
|
if (element.maxFiles != null && files.length > element.maxFiles) {
|
|
7565
|
-
errors.push(
|
|
7566
|
-
`${key}: ${t("maxFiles", state, { max: element.maxFiles })}`
|
|
7567
|
-
);
|
|
7671
|
+
errors.push(`${key}: ${t("maxFiles", state, { max: element.maxFiles })}`);
|
|
7568
7672
|
}
|
|
7569
7673
|
}
|
|
7570
7674
|
return { value, errors, spread: !!element.flatOutput };
|
|
@@ -7680,9 +7784,7 @@ function shouldDisableElement(element, ctx) {
|
|
|
7680
7784
|
return false;
|
|
7681
7785
|
}
|
|
7682
7786
|
function extractDOMValue(fieldPath, formRoot) {
|
|
7683
|
-
const input = formRoot.querySelector(
|
|
7684
|
-
`[name="${fieldPath}"]`
|
|
7685
|
-
);
|
|
7787
|
+
const input = formRoot.querySelector(`[name="${fieldPath}"]`);
|
|
7686
7788
|
if (!input) {
|
|
7687
7789
|
return void 0;
|
|
7688
7790
|
}
|
|
@@ -7727,9 +7829,7 @@ function reevaluateEnableIf(wrapper, element, ctx) {
|
|
|
7727
7829
|
`[data-container-item="${containerKey}[${containerIndex}]"]`
|
|
7728
7830
|
);
|
|
7729
7831
|
if (containerItemElement) {
|
|
7730
|
-
const inputs = containerItemElement.querySelectorAll(
|
|
7731
|
-
"input, select, textarea"
|
|
7732
|
-
);
|
|
7832
|
+
const inputs = containerItemElement.querySelectorAll("input, select, textarea");
|
|
7733
7833
|
inputs.forEach((input) => {
|
|
7734
7834
|
const fieldName = input.getAttribute("name");
|
|
7735
7835
|
if (fieldName) {
|
|
@@ -7781,7 +7881,10 @@ function reevaluateEnableIf(wrapper, element, ctx) {
|
|
|
7781
7881
|
wrapper.setAttribute("data-conditionally-disabled", "true");
|
|
7782
7882
|
}
|
|
7783
7883
|
} catch (error) {
|
|
7784
|
-
console.error(
|
|
7884
|
+
console.error(
|
|
7885
|
+
`Error re-evaluating enableIf for field "${element.key}":`,
|
|
7886
|
+
error
|
|
7887
|
+
);
|
|
7785
7888
|
}
|
|
7786
7889
|
}
|
|
7787
7890
|
function setupEnableIfListeners(wrapper, element, ctx) {
|
|
@@ -7802,14 +7905,10 @@ function setupEnableIfListeners(wrapper, element, ctx) {
|
|
|
7802
7905
|
} else {
|
|
7803
7906
|
dependencyFieldPath = dependencyKey;
|
|
7804
7907
|
}
|
|
7805
|
-
const dependencyInput = formRoot.querySelector(
|
|
7806
|
-
`[name="${dependencyFieldPath}"]`
|
|
7807
|
-
);
|
|
7908
|
+
const dependencyInput = formRoot.querySelector(`[name="${dependencyFieldPath}"]`);
|
|
7808
7909
|
if (!dependencyInput) {
|
|
7809
7910
|
const observer = new MutationObserver(() => {
|
|
7810
|
-
const input = formRoot.querySelector(
|
|
7811
|
-
`[name="${dependencyFieldPath}"]`
|
|
7812
|
-
);
|
|
7911
|
+
const input = formRoot.querySelector(`[name="${dependencyFieldPath}"]`);
|
|
7813
7912
|
if (input) {
|
|
7814
7913
|
input.addEventListener("change", () => {
|
|
7815
7914
|
reevaluateEnableIf(wrapper, element, ctx);
|
|
@@ -7956,7 +8055,9 @@ function dispatchToRenderer(element, ctx, wrapper, pathKey) {
|
|
|
7956
8055
|
default: {
|
|
7957
8056
|
const unsupported = document.createElement("div");
|
|
7958
8057
|
unsupported.className = "text-red-500 text-sm";
|
|
7959
|
-
unsupported.textContent = t("unsupportedFieldType", ctx.state, {
|
|
8058
|
+
unsupported.textContent = t("unsupportedFieldType", ctx.state, {
|
|
8059
|
+
type: element.type
|
|
8060
|
+
});
|
|
7960
8061
|
wrapper.appendChild(unsupported);
|
|
7961
8062
|
}
|
|
7962
8063
|
}
|
|
@@ -8908,7 +9009,10 @@ var FormBuilderInstance = class {
|
|
|
8908
9009
|
);
|
|
8909
9010
|
if (componentResult !== null) {
|
|
8910
9011
|
errors.push(...componentResult.errors);
|
|
8911
|
-
return {
|
|
9012
|
+
return {
|
|
9013
|
+
value: componentResult.value,
|
|
9014
|
+
spread: !!componentResult.spread
|
|
9015
|
+
};
|
|
8912
9016
|
}
|
|
8913
9017
|
console.warn(`Unknown field type "${element.type}" for key "${key}"`);
|
|
8914
9018
|
return { value: null, spread: false };
|
|
@@ -8917,10 +9021,7 @@ var FormBuilderInstance = class {
|
|
|
8917
9021
|
this.state.schema.elements.forEach((element) => {
|
|
8918
9022
|
if (element.enableIf) {
|
|
8919
9023
|
try {
|
|
8920
|
-
const shouldEnable = evaluateEnableCondition(
|
|
8921
|
-
element.enableIf,
|
|
8922
|
-
data
|
|
8923
|
-
);
|
|
9024
|
+
const shouldEnable = evaluateEnableCondition(element.enableIf, data);
|
|
8924
9025
|
if (!shouldEnable) {
|
|
8925
9026
|
return;
|
|
8926
9027
|
}
|
|
@@ -9215,7 +9316,10 @@ var FormBuilderInstance = class {
|
|
|
9215
9316
|
disabledWrapper.className = "fb-field-wrapper-disabled";
|
|
9216
9317
|
disabledWrapper.style.display = "none";
|
|
9217
9318
|
disabledWrapper.setAttribute("data-field-key", element.key);
|
|
9218
|
-
disabledWrapper.setAttribute(
|
|
9319
|
+
disabledWrapper.setAttribute(
|
|
9320
|
+
"data-conditionally-disabled",
|
|
9321
|
+
"true"
|
|
9322
|
+
);
|
|
9219
9323
|
wrapper.parentNode?.replaceChild(disabledWrapper, wrapper);
|
|
9220
9324
|
}
|
|
9221
9325
|
} catch (error) {
|