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