@dmitryvim/form-builder 0.1.35 → 0.1.38
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 +10 -5
- package/dist/demo.js +182 -54
- package/dist/elements.html +588 -160
- package/dist/elements.js +270 -232
- package/dist/form-builder.js +426 -134
- package/dist/index.html +70 -20
- package/package.json +1 -1
- package/docs/13_form_builder.html +0 -1337
- package/docs/REQUIREMENTS.md +0 -313
- package/docs/integration.md +0 -480
- package/docs/schema.md +0 -433
package/dist/elements.js
CHANGED
|
@@ -12,12 +12,12 @@ function initializeFormBuilder() {
|
|
|
12
12
|
const fileUrl = URL.createObjectURL(file);
|
|
13
13
|
|
|
14
14
|
fileStorage.set(resourceId, {
|
|
15
|
-
file
|
|
15
|
+
file,
|
|
16
16
|
url: fileUrl,
|
|
17
17
|
name: file.name,
|
|
18
18
|
type: file.type,
|
|
19
19
|
size: file.size,
|
|
20
|
-
uploadDate: new Date().toISOString()
|
|
20
|
+
uploadDate: new Date().toISOString(),
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
return resourceId;
|
|
@@ -27,7 +27,7 @@ function initializeFormBuilder() {
|
|
|
27
27
|
FormBuilder.setDownloadHandler((resourceId, fileName) => {
|
|
28
28
|
const fileData = fileStorage.get(resourceId);
|
|
29
29
|
if (fileData && fileData.url) {
|
|
30
|
-
const a = document.createElement(
|
|
30
|
+
const a = document.createElement("a");
|
|
31
31
|
a.href = fileData.url;
|
|
32
32
|
a.download = fileName || fileData.name;
|
|
33
33
|
document.body.appendChild(a);
|
|
@@ -53,266 +53,297 @@ const elementSchemas = {
|
|
|
53
53
|
text: {
|
|
54
54
|
schema: {
|
|
55
55
|
version: "0.3",
|
|
56
|
-
elements: [
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
56
|
+
elements: [
|
|
57
|
+
{
|
|
58
|
+
type: "text",
|
|
59
|
+
key: "username",
|
|
60
|
+
label: "Username",
|
|
61
|
+
placeholder: "Enter your username",
|
|
62
|
+
required: true,
|
|
63
|
+
minLength: 3,
|
|
64
|
+
maxLength: 20,
|
|
65
|
+
pattern: "^[a-zA-Z0-9_]+$",
|
|
66
|
+
description:
|
|
67
|
+
"Username must be 3-20 characters, alphanumeric and underscore only",
|
|
68
|
+
default: "",
|
|
69
|
+
actions: [
|
|
70
|
+
{
|
|
71
|
+
value: "check_availability",
|
|
72
|
+
label: "Check Availability",
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
],
|
|
72
77
|
},
|
|
73
|
-
prefill: { username: "john_doe" }
|
|
78
|
+
prefill: { username: "john_doe" },
|
|
74
79
|
},
|
|
75
80
|
|
|
76
|
-
|
|
81
|
+
"text-multiple": {
|
|
77
82
|
schema: {
|
|
78
83
|
version: "0.3",
|
|
79
|
-
elements: [
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
84
|
+
elements: [
|
|
85
|
+
{
|
|
86
|
+
type: "text",
|
|
87
|
+
key: "keywords",
|
|
88
|
+
label: "Keywords",
|
|
89
|
+
placeholder: "Enter keyword",
|
|
90
|
+
required: true,
|
|
91
|
+
multiple: true,
|
|
92
|
+
minCount: 2,
|
|
93
|
+
maxCount: 5,
|
|
94
|
+
minLength: 2,
|
|
95
|
+
maxLength: 30,
|
|
96
|
+
description:
|
|
97
|
+
"Add multiple keywords, minimum 2 required, maximum 5 allowed",
|
|
98
|
+
default: "example",
|
|
99
|
+
},
|
|
100
|
+
],
|
|
93
101
|
},
|
|
94
|
-
prefill: { keywords: ["javascript", "react", "nodejs"] }
|
|
102
|
+
prefill: { keywords: ["javascript", "react", "nodejs"] },
|
|
95
103
|
},
|
|
96
104
|
|
|
97
105
|
textarea: {
|
|
98
106
|
schema: {
|
|
99
107
|
version: "0.3",
|
|
100
|
-
elements: [
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
elements: [
|
|
109
|
+
{
|
|
110
|
+
type: "textarea",
|
|
111
|
+
key: "description",
|
|
112
|
+
label: "Description",
|
|
113
|
+
placeholder: "Enter detailed description...",
|
|
114
|
+
rows: 6,
|
|
115
|
+
required: false,
|
|
116
|
+
minLength: 10,
|
|
117
|
+
maxLength: 500,
|
|
118
|
+
description: "Provide a detailed description of your project",
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
prefill: {
|
|
123
|
+
description:
|
|
124
|
+
"This is a sample project description that demonstrates the textarea field with multiple lines of text.",
|
|
111
125
|
},
|
|
112
|
-
prefill: { description: "This is a sample project description that demonstrates the textarea field with multiple lines of text." }
|
|
113
126
|
},
|
|
114
127
|
|
|
115
|
-
|
|
128
|
+
"textarea-multiple": {
|
|
116
129
|
schema: {
|
|
117
130
|
version: "0.3",
|
|
118
|
-
elements: [
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
elements: [
|
|
132
|
+
{
|
|
133
|
+
type: "textarea",
|
|
134
|
+
key: "features",
|
|
135
|
+
label: "Product Features",
|
|
136
|
+
placeholder: "Describe a feature...",
|
|
137
|
+
rows: 4,
|
|
138
|
+
required: true,
|
|
139
|
+
multiple: true,
|
|
140
|
+
minCount: 2,
|
|
141
|
+
maxCount: 4,
|
|
142
|
+
minLength: 20,
|
|
143
|
+
maxLength: 200,
|
|
144
|
+
description: "List key product features, minimum 2 required",
|
|
145
|
+
},
|
|
146
|
+
],
|
|
132
147
|
},
|
|
133
148
|
prefill: {
|
|
134
149
|
features: [
|
|
135
150
|
"High-quality materials ensure durability and long-lasting performance",
|
|
136
|
-
"User-friendly interface makes it easy to operate for all skill levels"
|
|
137
|
-
]
|
|
138
|
-
}
|
|
151
|
+
"User-friendly interface makes it easy to operate for all skill levels",
|
|
152
|
+
],
|
|
153
|
+
},
|
|
139
154
|
},
|
|
140
155
|
|
|
141
156
|
number: {
|
|
142
157
|
schema: {
|
|
143
158
|
version: "0.3",
|
|
144
|
-
elements: [
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
elements: [
|
|
160
|
+
{
|
|
161
|
+
type: "number",
|
|
162
|
+
key: "price",
|
|
163
|
+
label: "Price (USD)",
|
|
164
|
+
placeholder: "0.00",
|
|
165
|
+
required: true,
|
|
166
|
+
min: 0,
|
|
167
|
+
max: 10000,
|
|
168
|
+
step: 0.01,
|
|
169
|
+
default: 99.99,
|
|
170
|
+
description: "Product price in US dollars",
|
|
171
|
+
},
|
|
172
|
+
],
|
|
156
173
|
},
|
|
157
|
-
prefill: { price: 149.99 }
|
|
174
|
+
prefill: { price: 149.99 },
|
|
158
175
|
},
|
|
159
176
|
|
|
160
|
-
|
|
177
|
+
"number-multiple": {
|
|
161
178
|
schema: {
|
|
162
179
|
version: "0.3",
|
|
163
|
-
elements: [
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
180
|
+
elements: [
|
|
181
|
+
{
|
|
182
|
+
type: "number",
|
|
183
|
+
key: "dimensions",
|
|
184
|
+
label: "Dimensions (cm)",
|
|
185
|
+
placeholder: "0.0",
|
|
186
|
+
required: true,
|
|
187
|
+
multiple: true,
|
|
188
|
+
minCount: 2,
|
|
189
|
+
maxCount: 3,
|
|
190
|
+
min: 0.1,
|
|
191
|
+
max: 500,
|
|
192
|
+
step: 0.1,
|
|
193
|
+
decimals: 1,
|
|
194
|
+
default: 10.0,
|
|
195
|
+
description:
|
|
196
|
+
"Enter product dimensions: width, height, and optionally depth",
|
|
197
|
+
},
|
|
198
|
+
],
|
|
179
199
|
},
|
|
180
|
-
prefill: { dimensions: [25.5, 30.0, 15.2] }
|
|
200
|
+
prefill: { dimensions: [25.5, 30.0, 15.2] },
|
|
181
201
|
},
|
|
182
202
|
|
|
183
203
|
select: {
|
|
184
204
|
schema: {
|
|
185
205
|
version: "0.3",
|
|
186
|
-
elements: [
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
206
|
+
elements: [
|
|
207
|
+
{
|
|
208
|
+
type: "select",
|
|
209
|
+
key: "category",
|
|
210
|
+
label: "Product Category",
|
|
211
|
+
required: true,
|
|
212
|
+
options: [
|
|
213
|
+
{ value: "electronics", label: "Electronics" },
|
|
214
|
+
{ value: "clothing", label: "Clothing & Apparel" },
|
|
215
|
+
{ value: "books", label: "Books & Media" },
|
|
216
|
+
{ value: "home", label: "Home & Garden" },
|
|
217
|
+
{ value: "sports", label: "Sports & Recreation" },
|
|
218
|
+
],
|
|
219
|
+
default: "electronics",
|
|
220
|
+
description: "Select the primary category for your product",
|
|
221
|
+
},
|
|
222
|
+
],
|
|
201
223
|
},
|
|
202
|
-
prefill: { category: "books" }
|
|
224
|
+
prefill: { category: "books" },
|
|
203
225
|
},
|
|
204
226
|
|
|
205
|
-
|
|
227
|
+
"select-multiple": {
|
|
206
228
|
schema: {
|
|
207
229
|
version: "0.3",
|
|
208
|
-
elements: [
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
230
|
+
elements: [
|
|
231
|
+
{
|
|
232
|
+
type: "select",
|
|
233
|
+
key: "tags",
|
|
234
|
+
label: "Product Tags",
|
|
235
|
+
required: true,
|
|
236
|
+
multiple: true,
|
|
237
|
+
minCount: 1,
|
|
238
|
+
maxCount: 3,
|
|
239
|
+
options: [
|
|
240
|
+
{ value: "new", label: "New" },
|
|
241
|
+
{ value: "popular", label: "Popular" },
|
|
242
|
+
{ value: "sale", label: "On Sale" },
|
|
243
|
+
{ value: "featured", label: "Featured" },
|
|
244
|
+
{ value: "limited", label: "Limited Edition" },
|
|
245
|
+
{ value: "bestseller", label: "Bestseller" },
|
|
246
|
+
],
|
|
247
|
+
default: "new",
|
|
248
|
+
description:
|
|
249
|
+
"Select relevant tags for the product, maximum 3 allowed",
|
|
250
|
+
},
|
|
251
|
+
],
|
|
227
252
|
},
|
|
228
|
-
prefill: { tags: ["popular", "featured"] }
|
|
253
|
+
prefill: { tags: ["popular", "featured"] },
|
|
229
254
|
},
|
|
230
255
|
|
|
231
256
|
file: {
|
|
232
257
|
schema: {
|
|
233
258
|
version: "0.3",
|
|
234
|
-
elements: [
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
259
|
+
elements: [
|
|
260
|
+
{
|
|
261
|
+
type: "file",
|
|
262
|
+
key: "avatar",
|
|
263
|
+
label: "Profile Picture",
|
|
264
|
+
required: false,
|
|
265
|
+
accept: {
|
|
266
|
+
extensions: ["jpg", "jpeg", "png", "gif", "webp"],
|
|
267
|
+
maxSize: 5242880,
|
|
268
|
+
},
|
|
269
|
+
description: "Upload your profile picture (max 5MB, images only)",
|
|
242
270
|
},
|
|
243
|
-
|
|
244
|
-
}]
|
|
271
|
+
],
|
|
245
272
|
},
|
|
246
|
-
prefill: { avatar: null }
|
|
273
|
+
prefill: { avatar: null },
|
|
247
274
|
},
|
|
248
275
|
|
|
249
276
|
files: {
|
|
250
277
|
schema: {
|
|
251
278
|
version: "0.3",
|
|
252
|
-
elements: [
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
279
|
+
elements: [
|
|
280
|
+
{
|
|
281
|
+
type: "files",
|
|
282
|
+
key: "attachments",
|
|
283
|
+
label: "Project Attachments",
|
|
284
|
+
required: false,
|
|
285
|
+
min: 1,
|
|
286
|
+
max: 10,
|
|
287
|
+
accept: {
|
|
288
|
+
extensions: ["jpg", "png", "pdf", "doc", "docx", "mp4"],
|
|
289
|
+
maxSize: 10485760,
|
|
290
|
+
},
|
|
291
|
+
description: "Upload project files (max 10MB each, 1-10 files)",
|
|
262
292
|
},
|
|
263
|
-
|
|
264
|
-
}]
|
|
293
|
+
],
|
|
265
294
|
},
|
|
266
|
-
prefill: { attachments: [] }
|
|
295
|
+
prefill: { attachments: [] },
|
|
267
296
|
},
|
|
268
297
|
|
|
269
298
|
group: {
|
|
270
299
|
schema: {
|
|
271
300
|
version: "0.3",
|
|
272
|
-
elements: [
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
elements: [
|
|
281
|
-
{
|
|
282
|
-
type: "text",
|
|
283
|
-
key: "name",
|
|
284
|
-
label: "Contact Name",
|
|
285
|
-
required: true
|
|
301
|
+
elements: [
|
|
302
|
+
{
|
|
303
|
+
type: "group",
|
|
304
|
+
key: "contacts",
|
|
305
|
+
label: "Contact Information",
|
|
306
|
+
repeat: {
|
|
307
|
+
min: 1,
|
|
308
|
+
max: 5,
|
|
286
309
|
},
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
310
|
+
elements: [
|
|
311
|
+
{
|
|
312
|
+
type: "text",
|
|
313
|
+
key: "name",
|
|
314
|
+
label: "Contact Name",
|
|
315
|
+
required: true,
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
type: "text",
|
|
319
|
+
key: "email",
|
|
320
|
+
label: "Email Address",
|
|
321
|
+
required: true,
|
|
322
|
+
pattern: "^[^@]+@[^@]+\\.[^@]+$",
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
type: "select",
|
|
326
|
+
key: "role",
|
|
327
|
+
label: "Role",
|
|
328
|
+
options: [
|
|
329
|
+
{ value: "primary", label: "Primary Contact" },
|
|
330
|
+
{ value: "secondary", label: "Secondary Contact" },
|
|
331
|
+
{ value: "technical", label: "Technical Contact" },
|
|
332
|
+
],
|
|
333
|
+
default: "primary",
|
|
334
|
+
},
|
|
335
|
+
],
|
|
336
|
+
description: "Add contact information for your project",
|
|
337
|
+
},
|
|
338
|
+
],
|
|
308
339
|
},
|
|
309
340
|
prefill: {
|
|
310
341
|
contacts: [
|
|
311
342
|
{ name: "John Smith", email: "john@company.com", role: "primary" },
|
|
312
|
-
{ name: "Jane Doe", email: "jane@company.com", role: "technical" }
|
|
313
|
-
]
|
|
314
|
-
}
|
|
315
|
-
}
|
|
343
|
+
{ name: "Jane Doe", email: "jane@company.com", role: "technical" },
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
},
|
|
316
347
|
};
|
|
317
348
|
|
|
318
349
|
// Update preview for an element
|
|
@@ -321,13 +352,15 @@ function updatePreview(elementType) {
|
|
|
321
352
|
if (!elementData) return;
|
|
322
353
|
|
|
323
354
|
const previewContainer = document.getElementById(`${elementType}-preview`);
|
|
324
|
-
const readonlyToggle = document.querySelector(
|
|
355
|
+
const readonlyToggle = document.querySelector(
|
|
356
|
+
`input[data-element="${elementType}"]`,
|
|
357
|
+
);
|
|
325
358
|
|
|
326
359
|
if (!previewContainer) return;
|
|
327
360
|
|
|
328
361
|
// Set form root and mode
|
|
329
362
|
FormBuilder.setFormRoot(previewContainer);
|
|
330
|
-
FormBuilder.setMode(readonlyToggle?.checked ?
|
|
363
|
+
FormBuilder.setMode(readonlyToggle?.checked ? "readonly" : "edit");
|
|
331
364
|
|
|
332
365
|
// Render the form
|
|
333
366
|
FormBuilder.renderForm(elementData.schema, elementData.prefill);
|
|
@@ -353,7 +386,7 @@ function applySchemaChanges(elementType) {
|
|
|
353
386
|
elementSchemas[elementType].schema.elements[0] = elementSchema;
|
|
354
387
|
updatePreview(elementType);
|
|
355
388
|
} catch (error) {
|
|
356
|
-
console.error(
|
|
389
|
+
console.error("Invalid JSON in schema:", error);
|
|
357
390
|
// Reset to original if invalid
|
|
358
391
|
updateSchemaTextarea(elementType);
|
|
359
392
|
}
|
|
@@ -361,59 +394,62 @@ function applySchemaChanges(elementType) {
|
|
|
361
394
|
|
|
362
395
|
// Initialize navigation
|
|
363
396
|
function initializeNavigation() {
|
|
364
|
-
const navItems = document.querySelectorAll(
|
|
397
|
+
const navItems = document.querySelectorAll(".nav-item");
|
|
365
398
|
|
|
366
399
|
// Set initial active state
|
|
367
400
|
if (navItems.length > 0) {
|
|
368
|
-
navItems[0].classList.add(
|
|
401
|
+
navItems[0].classList.add("active");
|
|
369
402
|
}
|
|
370
403
|
|
|
371
|
-
navItems.forEach(item => {
|
|
372
|
-
item.addEventListener(
|
|
404
|
+
navItems.forEach((item) => {
|
|
405
|
+
item.addEventListener("click", (e) => {
|
|
373
406
|
e.preventDefault();
|
|
374
407
|
|
|
375
408
|
// Remove active class from all items
|
|
376
|
-
navItems.forEach(nav => nav.classList.remove(
|
|
409
|
+
navItems.forEach((nav) => nav.classList.remove("active"));
|
|
377
410
|
|
|
378
411
|
// Add active class to clicked item
|
|
379
|
-
item.classList.add(
|
|
412
|
+
item.classList.add("active");
|
|
380
413
|
|
|
381
414
|
// Scroll to element
|
|
382
|
-
const elementId = item.getAttribute(
|
|
415
|
+
const elementId = item.getAttribute("href").substring(1);
|
|
383
416
|
const element = document.getElementById(elementId);
|
|
384
417
|
if (element) {
|
|
385
|
-
element.scrollIntoView({ behavior:
|
|
418
|
+
element.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
386
419
|
}
|
|
387
420
|
});
|
|
388
421
|
});
|
|
389
422
|
|
|
390
423
|
// Handle scroll-based active states
|
|
391
|
-
const sections = document.querySelectorAll(
|
|
392
|
-
const observer = new IntersectionObserver(
|
|
393
|
-
entries
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
nav.
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
424
|
+
const sections = document.querySelectorAll(".element-section");
|
|
425
|
+
const observer = new IntersectionObserver(
|
|
426
|
+
(entries) => {
|
|
427
|
+
entries.forEach((entry) => {
|
|
428
|
+
if (entry.isIntersecting) {
|
|
429
|
+
const id = entry.target.id;
|
|
430
|
+
navItems.forEach((nav) => {
|
|
431
|
+
nav.classList.remove("active");
|
|
432
|
+
if (nav.getAttribute("href") === `#${id}`) {
|
|
433
|
+
nav.classList.add("active");
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
rootMargin: "-20% 0% -20% 0%",
|
|
441
|
+
threshold: 0.1,
|
|
442
|
+
},
|
|
443
|
+
);
|
|
408
444
|
|
|
409
|
-
sections.forEach(section => {
|
|
445
|
+
sections.forEach((section) => {
|
|
410
446
|
observer.observe(section);
|
|
411
447
|
});
|
|
412
448
|
}
|
|
413
449
|
|
|
414
450
|
// Initialize all elements
|
|
415
451
|
function initializeElements() {
|
|
416
|
-
Object.keys(elementSchemas).forEach(elementType => {
|
|
452
|
+
Object.keys(elementSchemas).forEach((elementType) => {
|
|
417
453
|
// Update textarea with schema
|
|
418
454
|
updateSchemaTextarea(elementType);
|
|
419
455
|
|
|
@@ -421,7 +457,7 @@ function initializeElements() {
|
|
|
421
457
|
const textarea = document.getElementById(`${elementType}-schema`);
|
|
422
458
|
if (textarea) {
|
|
423
459
|
let debounceTimer;
|
|
424
|
-
textarea.addEventListener(
|
|
460
|
+
textarea.addEventListener("input", () => {
|
|
425
461
|
clearTimeout(debounceTimer);
|
|
426
462
|
debounceTimer = setTimeout(() => {
|
|
427
463
|
applySchemaChanges(elementType);
|
|
@@ -430,9 +466,11 @@ function initializeElements() {
|
|
|
430
466
|
}
|
|
431
467
|
|
|
432
468
|
// Setup readonly toggle
|
|
433
|
-
const readonlyToggle = document.querySelector(
|
|
469
|
+
const readonlyToggle = document.querySelector(
|
|
470
|
+
`input[data-element="${elementType}"]`,
|
|
471
|
+
);
|
|
434
472
|
if (readonlyToggle) {
|
|
435
|
-
readonlyToggle.addEventListener(
|
|
473
|
+
readonlyToggle.addEventListener("change", () => {
|
|
436
474
|
updatePreview(elementType);
|
|
437
475
|
});
|
|
438
476
|
}
|
|
@@ -443,8 +481,8 @@ function initializeElements() {
|
|
|
443
481
|
}
|
|
444
482
|
|
|
445
483
|
// Initialize everything when DOM is loaded
|
|
446
|
-
document.addEventListener(
|
|
484
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
447
485
|
initializeFormBuilder();
|
|
448
486
|
initializeNavigation();
|
|
449
487
|
initializeElements();
|
|
450
|
-
});
|
|
488
|
+
});
|