@gofranz/formshive-submit 1.0.0
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 +619 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/field-errors.d.ts +95 -0
- package/dist/field-errors.d.ts.map +1 -0
- package/dist/file-handler.d.ts +43 -0
- package/dist/file-handler.d.ts.map +1 -0
- package/dist/formshive-submit.cjs +1714 -0
- package/dist/formshive-submit.cjs.map +1 -0
- package/dist/formshive-submit.esm.js +1644 -0
- package/dist/formshive-submit.esm.js.map +1 -0
- package/dist/formshive-submit.js +1720 -0
- package/dist/formshive-submit.js.map +1 -0
- package/dist/formshive-submit.min.js +2 -0
- package/dist/formshive-submit.min.js.map +1 -0
- package/dist/main.d.ts +66 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/retry.d.ts +73 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/submit.d.ts +49 -0
- package/dist/submit.d.ts.map +1 -0
- package/dist/test.html +1074 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +115 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +52 -0
package/dist/test.html
ADDED
|
@@ -0,0 +1,1074 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Formshive Submit Library Test</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
10
|
+
max-width: 1200px;
|
|
11
|
+
margin: 0 auto;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
background-color: #f5f5f5;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.container {
|
|
17
|
+
background: white;
|
|
18
|
+
padding: 30px;
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
21
|
+
margin-bottom: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
h1, h2 {
|
|
25
|
+
color: #333;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.form-section {
|
|
29
|
+
margin-bottom: 40px;
|
|
30
|
+
padding: 20px;
|
|
31
|
+
border: 1px solid #e0e0e0;
|
|
32
|
+
border-radius: 5px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.form-group {
|
|
36
|
+
margin-bottom: 15px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
label {
|
|
40
|
+
display: block;
|
|
41
|
+
margin-bottom: 5px;
|
|
42
|
+
font-weight: 500;
|
|
43
|
+
color: #555;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
input, textarea, select {
|
|
47
|
+
width: 100%;
|
|
48
|
+
max-width: 400px;
|
|
49
|
+
padding: 10px;
|
|
50
|
+
border: 1px solid #ddd;
|
|
51
|
+
border-radius: 4px;
|
|
52
|
+
font-size: 14px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
button {
|
|
56
|
+
background-color: #007bff;
|
|
57
|
+
color: white;
|
|
58
|
+
padding: 10px 20px;
|
|
59
|
+
border: none;
|
|
60
|
+
border-radius: 4px;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
font-size: 14px;
|
|
63
|
+
margin-right: 10px;
|
|
64
|
+
margin-bottom: 10px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
button:hover {
|
|
68
|
+
background-color: #0056b3;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
button:disabled {
|
|
72
|
+
background-color: #ccc;
|
|
73
|
+
cursor: not-allowed;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.progress {
|
|
77
|
+
width: 100%;
|
|
78
|
+
max-width: 400px;
|
|
79
|
+
height: 20px;
|
|
80
|
+
background-color: #f0f0f0;
|
|
81
|
+
border-radius: 10px;
|
|
82
|
+
overflow: hidden;
|
|
83
|
+
margin: 10px 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.progress-bar {
|
|
87
|
+
height: 100%;
|
|
88
|
+
background-color: #007bff;
|
|
89
|
+
width: 0%;
|
|
90
|
+
transition: width 0.3s ease;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.log {
|
|
94
|
+
background-color: #f8f9fa;
|
|
95
|
+
border: 1px solid #e9ecef;
|
|
96
|
+
border-radius: 4px;
|
|
97
|
+
padding: 15px;
|
|
98
|
+
max-height: 300px;
|
|
99
|
+
overflow-y: auto;
|
|
100
|
+
font-family: 'Courier New', monospace;
|
|
101
|
+
font-size: 12px;
|
|
102
|
+
white-space: pre-wrap;
|
|
103
|
+
margin-top: 10px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.status {
|
|
107
|
+
padding: 10px 15px;
|
|
108
|
+
border-radius: 4px;
|
|
109
|
+
margin: 10px 0;
|
|
110
|
+
font-weight: 500;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.status.success {
|
|
114
|
+
background-color: #d4edda;
|
|
115
|
+
color: #155724;
|
|
116
|
+
border: 1px solid #c3e6cb;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.status.error {
|
|
120
|
+
background-color: #f8d7da;
|
|
121
|
+
color: #721c24;
|
|
122
|
+
border: 1px solid #f5c6cb;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.status.info {
|
|
126
|
+
background-color: #cce7ff;
|
|
127
|
+
color: #004085;
|
|
128
|
+
border: 1px solid #99d3ff;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.tabs {
|
|
132
|
+
display: flex;
|
|
133
|
+
border-bottom: 1px solid #ddd;
|
|
134
|
+
margin-bottom: 20px;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.tab {
|
|
138
|
+
padding: 10px 20px;
|
|
139
|
+
cursor: pointer;
|
|
140
|
+
border: none;
|
|
141
|
+
background: none;
|
|
142
|
+
border-bottom: 3px solid transparent;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.tab.active {
|
|
146
|
+
border-bottom-color: #007bff;
|
|
147
|
+
color: #007bff;
|
|
148
|
+
font-weight: 500;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.tab-content {
|
|
152
|
+
display: none;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.tab-content.active {
|
|
156
|
+
display: block;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.code-block {
|
|
160
|
+
background-color: #f1f3f4;
|
|
161
|
+
padding: 15px;
|
|
162
|
+
border-radius: 4px;
|
|
163
|
+
font-family: 'Courier New', monospace;
|
|
164
|
+
font-size: 13px;
|
|
165
|
+
overflow-x: auto;
|
|
166
|
+
margin: 10px 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.field-error {
|
|
170
|
+
color: #dc3545;
|
|
171
|
+
background-color: #f8d7da;
|
|
172
|
+
border: 1px solid #f5c6cb;
|
|
173
|
+
border-radius: 3px;
|
|
174
|
+
padding: 6px 10px;
|
|
175
|
+
margin-top: 5px;
|
|
176
|
+
font-size: 12px;
|
|
177
|
+
display: block;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.input-error {
|
|
181
|
+
border-color: #dc3545 !important;
|
|
182
|
+
background-color: #fff5f5;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.input-success {
|
|
186
|
+
border-color: #28a745;
|
|
187
|
+
background-color: #f8fff8;
|
|
188
|
+
}
|
|
189
|
+
</style>
|
|
190
|
+
</head>
|
|
191
|
+
<body>
|
|
192
|
+
<div class="container">
|
|
193
|
+
<h1>Formshive Submit Library Test Page</h1>
|
|
194
|
+
<p>This page demonstrates various features of the Formshive Submit library.</p>
|
|
195
|
+
|
|
196
|
+
<div class="tabs">
|
|
197
|
+
<button class="tab active" onclick="showTab('basic')">Basic Form</button>
|
|
198
|
+
<button class="tab" onclick="showTab('files')">File Upload</button>
|
|
199
|
+
<button class="tab" onclick="showTab('custom')">Custom Config</button>
|
|
200
|
+
<button class="tab" onclick="showTab('validation')">Field Validation</button>
|
|
201
|
+
<button class="tab" onclick="showTab('axios')">With Axios</button>
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
<!-- Basic Form Tab -->
|
|
205
|
+
<div id="basic" class="tab-content active">
|
|
206
|
+
<div class="form-section">
|
|
207
|
+
<h2>Basic Form Submission</h2>
|
|
208
|
+
<p>Simple form submission with default settings.</p>
|
|
209
|
+
|
|
210
|
+
<form id="basicForm">
|
|
211
|
+
<div class="form-group">
|
|
212
|
+
<label for="formId1">Form ID:</label>
|
|
213
|
+
<input type="text" id="formId1" value="test-form-id" required>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<div class="form-group">
|
|
217
|
+
<label for="name1">Name:</label>
|
|
218
|
+
<input type="text" id="name1" value="John Doe" required>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<div class="form-group">
|
|
222
|
+
<label for="email1">Email:</label>
|
|
223
|
+
<input type="email" id="email1" value="john@example.com" required>
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
<div class="form-group">
|
|
227
|
+
<label for="message1">Message:</label>
|
|
228
|
+
<textarea id="message1" rows="4">Hello from Formshive Submit library!</textarea>
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
<button type="submit">Submit Form</button>
|
|
232
|
+
<button type="button" onclick="clearLog('basicLog')">Clear Log</button>
|
|
233
|
+
</form>
|
|
234
|
+
|
|
235
|
+
<div id="basicStatus"></div>
|
|
236
|
+
<div id="basicLog" class="log"></div>
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
<!-- File Upload Tab -->
|
|
241
|
+
<div id="files" class="tab-content">
|
|
242
|
+
<div class="form-section">
|
|
243
|
+
<h2>Form with File Upload</h2>
|
|
244
|
+
<p>Form submission with file uploads and progress tracking.</p>
|
|
245
|
+
|
|
246
|
+
<form id="fileForm">
|
|
247
|
+
<div class="form-group">
|
|
248
|
+
<label for="formId2">Form ID:</label>
|
|
249
|
+
<input type="text" id="formId2" value="file-form-id" required>
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
<div class="form-group">
|
|
253
|
+
<label for="name2">Name:</label>
|
|
254
|
+
<input type="text" id="name2" value="Jane Smith" required>
|
|
255
|
+
</div>
|
|
256
|
+
|
|
257
|
+
<div class="form-group">
|
|
258
|
+
<label for="files2">Files:</label>
|
|
259
|
+
<input type="file" id="files2" multiple accept=".txt,.pdf,.jpg,.png">
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
<div class="form-group">
|
|
263
|
+
<label for="description2">Description:</label>
|
|
264
|
+
<textarea id="description2" rows="3">These are test files.</textarea>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<button type="submit">Submit with Files</button>
|
|
268
|
+
<button type="button" onclick="clearLog('fileLog')">Clear Log</button>
|
|
269
|
+
</form>
|
|
270
|
+
|
|
271
|
+
<div class="progress" style="display: none;" id="fileProgress">
|
|
272
|
+
<div class="progress-bar" id="fileProgressBar"></div>
|
|
273
|
+
</div>
|
|
274
|
+
<div id="fileProgressText"></div>
|
|
275
|
+
|
|
276
|
+
<div id="fileStatus"></div>
|
|
277
|
+
<div id="fileLog" class="log"></div>
|
|
278
|
+
</div>
|
|
279
|
+
|
|
280
|
+
<!-- Second File Upload Form -->
|
|
281
|
+
<div class="form-section">
|
|
282
|
+
<h2>Single File Upload Form</h2>
|
|
283
|
+
<p>Another form demonstrating single file upload with different validation rules.</p>
|
|
284
|
+
|
|
285
|
+
<form id="singleFileForm">
|
|
286
|
+
<div class="form-group">
|
|
287
|
+
<label for="formId2b">Form ID:</label>
|
|
288
|
+
<input type="text" id="formId2b" value="single-file-form-id" required>
|
|
289
|
+
</div>
|
|
290
|
+
|
|
291
|
+
<div class="form-group">
|
|
292
|
+
<label for="email2b">Email:</label>
|
|
293
|
+
<input type="email" id="email2b" value="user@example.com" required>
|
|
294
|
+
</div>
|
|
295
|
+
|
|
296
|
+
<div class="form-group">
|
|
297
|
+
<label for="category2b">Category:</label>
|
|
298
|
+
<select id="category2b" required>
|
|
299
|
+
<option value="">Select category...</option>
|
|
300
|
+
<option value="document">Document</option>
|
|
301
|
+
<option value="image">Image</option>
|
|
302
|
+
<option value="video">Video</option>
|
|
303
|
+
<option value="other">Other</option>
|
|
304
|
+
</select>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<div class="form-group">
|
|
308
|
+
<label for="singleFile">Upload File (max 5MB):</label>
|
|
309
|
+
<input type="file" id="singleFile" accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.mp4,.mov" required>
|
|
310
|
+
<small style="color: #666; font-size: 12px;">Allowed: PDF, Word docs, Images, Videos</small>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<div class="form-group">
|
|
314
|
+
<label for="comments2b">Comments (optional):</label>
|
|
315
|
+
<textarea id="comments2b" rows="3" placeholder="Add any additional comments..."></textarea>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<button type="submit">Upload Single File</button>
|
|
319
|
+
<button type="button" onclick="clearLog('singleFileLog')">Clear Log</button>
|
|
320
|
+
</form>
|
|
321
|
+
|
|
322
|
+
<div class="progress" style="display: none;" id="singleFileProgress">
|
|
323
|
+
<div class="progress-bar" id="singleFileProgressBar"></div>
|
|
324
|
+
</div>
|
|
325
|
+
<div id="singleFileProgressText"></div>
|
|
326
|
+
|
|
327
|
+
<div id="singleFileStatus"></div>
|
|
328
|
+
<div id="singleFileLog" class="log"></div>
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
|
|
332
|
+
<!-- Field Validation Tab -->
|
|
333
|
+
<div id="validation" class="tab-content">
|
|
334
|
+
<div class="form-section">
|
|
335
|
+
<h2>Field Validation Error Handling</h2>
|
|
336
|
+
<p>This form demonstrates how to handle structured field validation errors from Formshive.</p>
|
|
337
|
+
|
|
338
|
+
<form id="validationForm">
|
|
339
|
+
<div class="form-group">
|
|
340
|
+
<label for="formId4">Form ID:</label>
|
|
341
|
+
<input type="text" id="formId4" value="validation-test-form" required>
|
|
342
|
+
</div>
|
|
343
|
+
|
|
344
|
+
<div class="form-group">
|
|
345
|
+
<label for="email4">Email:</label>
|
|
346
|
+
<input type="email" id="email4" value="invalid-email" required>
|
|
347
|
+
<div id="email4-error" class="field-error" style="display: none;"></div>
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
<div class="form-group">
|
|
351
|
+
<label for="phone4">Phone:</label>
|
|
352
|
+
<input type="tel" id="phone4" value="123" required>
|
|
353
|
+
<div id="phone4-error" class="field-error" style="display: none;"></div>
|
|
354
|
+
</div>
|
|
355
|
+
|
|
356
|
+
<div class="form-group">
|
|
357
|
+
<label for="age4">Age:</label>
|
|
358
|
+
<input type="number" id="age4" value="999" min="18" max="100" required>
|
|
359
|
+
<div id="age4-error" class="field-error" style="display: none;"></div>
|
|
360
|
+
</div>
|
|
361
|
+
|
|
362
|
+
<div class="form-group">
|
|
363
|
+
<label for="website4">Website:</label>
|
|
364
|
+
<input type="url" id="website4" value="not-a-url" placeholder="https://example.com">
|
|
365
|
+
<div id="website4-error" class="field-error" style="display: none;"></div>
|
|
366
|
+
</div>
|
|
367
|
+
|
|
368
|
+
<div class="form-group">
|
|
369
|
+
<label for="message4">Message (min 10 characters):</label>
|
|
370
|
+
<textarea id="message4" rows="3" required>Hi</textarea>
|
|
371
|
+
<div id="message4-error" class="field-error" style="display: none;"></div>
|
|
372
|
+
</div>
|
|
373
|
+
|
|
374
|
+
<button type="submit">Submit (Expect Validation Errors)</button>
|
|
375
|
+
<button type="button" onclick="clearValidationErrors()">Clear Errors</button>
|
|
376
|
+
<button type="button" onclick="clearLog('validationLog')">Clear Log</button>
|
|
377
|
+
</form>
|
|
378
|
+
|
|
379
|
+
<div id="validationStatus"></div>
|
|
380
|
+
<div id="validationLog" class="log"></div>
|
|
381
|
+
|
|
382
|
+
<div style="margin-top: 20px;">
|
|
383
|
+
<h3>Field Error Helpers Demo</h3>
|
|
384
|
+
<div id="fieldErrorHelpers" style="background: #f5f5f5; padding: 15px; border-radius: 4px;">
|
|
385
|
+
<p><strong>Field Error Information:</strong></p>
|
|
386
|
+
<div id="errorSummary">Submit form to see field validation errors</div>
|
|
387
|
+
<div id="errorDetails" style="margin-top: 10px;"></div>
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
</div>
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
<!-- Custom Config Tab -->
|
|
394
|
+
<div id="custom" class="tab-content">
|
|
395
|
+
<div class="form-section">
|
|
396
|
+
<h2>Custom Configuration</h2>
|
|
397
|
+
<p>Form submission with custom retry settings and callbacks.</p>
|
|
398
|
+
|
|
399
|
+
<form id="customForm">
|
|
400
|
+
<div class="form-group">
|
|
401
|
+
<label for="formId3">Form ID:</label>
|
|
402
|
+
<input type="text" id="formId3" value="custom-form-id" required>
|
|
403
|
+
</div>
|
|
404
|
+
|
|
405
|
+
<div class="form-group">
|
|
406
|
+
<label for="endpoint3">Endpoint:</label>
|
|
407
|
+
<input type="url" id="endpoint3" value="https://api.formshive.com/v1" required>
|
|
408
|
+
</div>
|
|
409
|
+
|
|
410
|
+
<div class="form-group">
|
|
411
|
+
<label for="maxRetries3">Max Retries:</label>
|
|
412
|
+
<select id="maxRetries3">
|
|
413
|
+
<option value="1">1</option>
|
|
414
|
+
<option value="3" selected>3</option>
|
|
415
|
+
<option value="5">5</option>
|
|
416
|
+
</select>
|
|
417
|
+
</div>
|
|
418
|
+
|
|
419
|
+
<div class="form-group">
|
|
420
|
+
<label for="baseDelay3">Base Delay (ms):</label>
|
|
421
|
+
<input type="number" id="baseDelay3" value="1000" min="100" max="10000">
|
|
422
|
+
</div>
|
|
423
|
+
|
|
424
|
+
<div class="form-group">
|
|
425
|
+
<label for="subject3">Subject:</label>
|
|
426
|
+
<input type="text" id="subject3" value="Custom Configuration Test">
|
|
427
|
+
</div>
|
|
428
|
+
|
|
429
|
+
<div class="form-group">
|
|
430
|
+
<label for="content3">Content:</label>
|
|
431
|
+
<textarea id="content3" rows="4">Testing custom retry configuration and callbacks.</textarea>
|
|
432
|
+
</div>
|
|
433
|
+
|
|
434
|
+
<button type="submit">Submit with Custom Config</button>
|
|
435
|
+
<button type="button" onclick="clearLog('customLog')">Clear Log</button>
|
|
436
|
+
</form>
|
|
437
|
+
|
|
438
|
+
<div id="customStatus"></div>
|
|
439
|
+
<div id="customLog" class="log"></div>
|
|
440
|
+
</div>
|
|
441
|
+
</div>
|
|
442
|
+
|
|
443
|
+
<!-- Axios Tab -->
|
|
444
|
+
<div id="axios" class="tab-content">
|
|
445
|
+
<div class="form-section">
|
|
446
|
+
<h2>Using Axios HTTP Client</h2>
|
|
447
|
+
<p>Form submission using Axios instead of fetch (requires axios to be loaded).</p>
|
|
448
|
+
|
|
449
|
+
<form id="axiosForm">
|
|
450
|
+
<div class="form-group">
|
|
451
|
+
<label for="formId4">Form ID:</label>
|
|
452
|
+
<input type="text" id="formId4" value="axios-form-id" required>
|
|
453
|
+
</div>
|
|
454
|
+
|
|
455
|
+
<div class="form-group">
|
|
456
|
+
<label for="title4">Title:</label>
|
|
457
|
+
<input type="text" id="title4" value="Axios Test" required>
|
|
458
|
+
</div>
|
|
459
|
+
|
|
460
|
+
<div class="form-group">
|
|
461
|
+
<label for="body4">Body:</label>
|
|
462
|
+
<textarea id="body4" rows="4">This form was submitted using Axios HTTP client.</textarea>
|
|
463
|
+
</div>
|
|
464
|
+
|
|
465
|
+
<button type="submit">Submit with Axios</button>
|
|
466
|
+
<button type="button" onclick="clearLog('axiosLog')">Clear Log</button>
|
|
467
|
+
</form>
|
|
468
|
+
|
|
469
|
+
<div id="axiosStatus"></div>
|
|
470
|
+
<div id="axiosLog" class="log"></div>
|
|
471
|
+
</div>
|
|
472
|
+
</div>
|
|
473
|
+
|
|
474
|
+
<!-- Documentation -->
|
|
475
|
+
<div class="container">
|
|
476
|
+
<h2>Usage Examples</h2>
|
|
477
|
+
|
|
478
|
+
<h3>Basic Usage</h3>
|
|
479
|
+
<div class="code-block">
|
|
480
|
+
// Simple form submission
|
|
481
|
+
FormshiveSubmit.submitFormSimple('your-form-id', {
|
|
482
|
+
name: 'John Doe',
|
|
483
|
+
email: 'john@example.com',
|
|
484
|
+
message: 'Hello world!'
|
|
485
|
+
}).then(response => {
|
|
486
|
+
console.log('Success:', response);
|
|
487
|
+
}).catch(error => {
|
|
488
|
+
console.error('Error:', error);
|
|
489
|
+
});
|
|
490
|
+
</div>
|
|
491
|
+
|
|
492
|
+
<h3>With File Upload</h3>
|
|
493
|
+
<div class="code-block">
|
|
494
|
+
// Form data with files
|
|
495
|
+
const formData = new FormData();
|
|
496
|
+
formData.append('name', 'Jane Smith');
|
|
497
|
+
formData.append('file', fileInput.files[0]);
|
|
498
|
+
|
|
499
|
+
FormshiveSubmit.submitForm({
|
|
500
|
+
formId: 'file-form-id',
|
|
501
|
+
data: formData,
|
|
502
|
+
files: {
|
|
503
|
+
maxFileSize: 5 * 1024 * 1024, // 5MB
|
|
504
|
+
allowedTypes: ['image/jpeg', 'application/pdf'],
|
|
505
|
+
trackProgress: true
|
|
506
|
+
},
|
|
507
|
+
callbacks: {
|
|
508
|
+
onProgress: (percent, loaded, total) => {
|
|
509
|
+
console.log(`Upload progress: ${percent}%`);
|
|
510
|
+
updateProgressBar(percent);
|
|
511
|
+
},
|
|
512
|
+
onSuccess: (response) => {
|
|
513
|
+
console.log('File uploaded!', response);
|
|
514
|
+
},
|
|
515
|
+
onError: (error) => {
|
|
516
|
+
if (error.code === 'FILE_TOO_LARGE') {
|
|
517
|
+
alert('File is too large!');
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
</div>
|
|
523
|
+
|
|
524
|
+
<h3>Field Validation Error Handling</h3>
|
|
525
|
+
<div class="code-block">
|
|
526
|
+
try {
|
|
527
|
+
const response = await FormshiveSubmit.submitForm({
|
|
528
|
+
formId: 'your-form-id',
|
|
529
|
+
data: { email: 'invalid-email', phone: '123' }
|
|
530
|
+
});
|
|
531
|
+
} catch (error) {
|
|
532
|
+
// Check if this is a field validation error
|
|
533
|
+
if (FormshiveSubmit.isFieldValidationError(error)) {
|
|
534
|
+
// Get all field errors
|
|
535
|
+
const fieldErrors = FormshiveSubmit.getFieldErrors(error);
|
|
536
|
+
|
|
537
|
+
// Display errors next to form fields
|
|
538
|
+
fieldErrors.forEach(fieldError => {
|
|
539
|
+
const input = document.getElementById(fieldError.field);
|
|
540
|
+
const errorDiv = document.getElementById(fieldError.field + '-error');
|
|
541
|
+
|
|
542
|
+
if (input) input.classList.add('error');
|
|
543
|
+
if (errorDiv) {
|
|
544
|
+
errorDiv.textContent = fieldError.message;
|
|
545
|
+
errorDiv.style.display = 'block';
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// Or use field error helpers for easier UI integration
|
|
550
|
+
const helpers = FormshiveSubmit.createFieldErrorHelpers(error);
|
|
551
|
+
|
|
552
|
+
console.log('Email has error:', helpers.hasError('email'));
|
|
553
|
+
console.log('Email error message:', helpers.getMessage('email'));
|
|
554
|
+
console.log('Phone error CSS class:', helpers.getFieldClass('phone'));
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
</div>
|
|
558
|
+
|
|
559
|
+
<h3>Custom Retry Configuration</h3>
|
|
560
|
+
<div class="code-block">
|
|
561
|
+
FormshiveSubmit.submitForm({
|
|
562
|
+
formId: 'your-form-id',
|
|
563
|
+
data: { message: 'Hello' },
|
|
564
|
+
retry: {
|
|
565
|
+
maxAttempts: 5,
|
|
566
|
+
baseDelay: 2000,
|
|
567
|
+
maxDelay: 30000
|
|
568
|
+
},
|
|
569
|
+
callbacks: {
|
|
570
|
+
onRetry: (attempt, maxAttempts) => {
|
|
571
|
+
console.log(`Retry ${attempt}/${maxAttempts}`);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
</div>
|
|
576
|
+
</div>
|
|
577
|
+
</div>
|
|
578
|
+
|
|
579
|
+
<!-- Include the library (update path as needed) -->
|
|
580
|
+
<script src="formshive-submit.min.js"></script>
|
|
581
|
+
<!-- Optional: Include Axios for axios example -->
|
|
582
|
+
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js"></script>
|
|
583
|
+
|
|
584
|
+
<script>
|
|
585
|
+
// Tab switching functionality
|
|
586
|
+
function showTab(tabName) {
|
|
587
|
+
// Hide all tab contents
|
|
588
|
+
const tabContents = document.querySelectorAll('.tab-content');
|
|
589
|
+
tabContents.forEach(content => content.classList.remove('active'));
|
|
590
|
+
|
|
591
|
+
// Remove active class from all tabs
|
|
592
|
+
const tabs = document.querySelectorAll('.tab');
|
|
593
|
+
tabs.forEach(tab => tab.classList.remove('active'));
|
|
594
|
+
|
|
595
|
+
// Show selected tab content and mark tab as active
|
|
596
|
+
document.getElementById(tabName).classList.add('active');
|
|
597
|
+
event.target.classList.add('active');
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Utility functions
|
|
601
|
+
function log(elementId, message, type = 'info') {
|
|
602
|
+
const logElement = document.getElementById(elementId);
|
|
603
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
604
|
+
const logMessage = `[${timestamp}] ${message}\n`;
|
|
605
|
+
logElement.textContent += logMessage;
|
|
606
|
+
logElement.scrollTop = logElement.scrollHeight;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function clearLog(elementId) {
|
|
610
|
+
document.getElementById(elementId).textContent = '';
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function showStatus(elementId, message, type = 'info') {
|
|
614
|
+
const statusElement = document.getElementById(elementId);
|
|
615
|
+
statusElement.innerHTML = `<div class="status ${type}">${message}</div>`;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function updateProgress(percent, loaded, total, progressBarId = 'fileProgressBar', progressTextId = 'fileProgressText', progressContainerId = 'fileProgress') {
|
|
619
|
+
const progressBar = document.getElementById(progressBarId);
|
|
620
|
+
const progressText = document.getElementById(progressTextId);
|
|
621
|
+
const progressContainer = document.getElementById(progressContainerId);
|
|
622
|
+
|
|
623
|
+
progressContainer.style.display = 'block';
|
|
624
|
+
progressBar.style.width = percent + '%';
|
|
625
|
+
progressText.textContent = `Upload progress: ${percent}% (${formatBytes(loaded)} / ${formatBytes(total)})`;
|
|
626
|
+
|
|
627
|
+
if (percent === 100) {
|
|
628
|
+
setTimeout(() => {
|
|
629
|
+
progressContainer.style.display = 'none';
|
|
630
|
+
progressText.textContent = '';
|
|
631
|
+
}, 2000);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function formatBytes(bytes) {
|
|
636
|
+
if (bytes === 0) return '0 Bytes';
|
|
637
|
+
const k = 1024;
|
|
638
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
639
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
640
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Form submissions
|
|
644
|
+
document.getElementById('basicForm').addEventListener('submit', async (e) => {
|
|
645
|
+
e.preventDefault();
|
|
646
|
+
|
|
647
|
+
const formId = document.getElementById('formId1').value;
|
|
648
|
+
const data = {
|
|
649
|
+
name: document.getElementById('name1').value,
|
|
650
|
+
email: document.getElementById('email1').value,
|
|
651
|
+
message: document.getElementById('message1').value
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
log('basicLog', `Starting basic form submission...`);
|
|
655
|
+
log('basicLog', `Form ID: ${formId}`);
|
|
656
|
+
log('basicLog', `Data: ${JSON.stringify(data, null, 2)}`);
|
|
657
|
+
|
|
658
|
+
try {
|
|
659
|
+
const response = await FormshiveSubmit.submitFormSimple(formId, data, {
|
|
660
|
+
debug: true,
|
|
661
|
+
callbacks: {
|
|
662
|
+
onStart: () => log('basicLog', 'Submission started'),
|
|
663
|
+
onRetry: (attempt, maxAttempts, error) => {
|
|
664
|
+
log('basicLog', `Retry ${attempt}/${maxAttempts}: ${error.message}`);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
log('basicLog', 'SUCCESS: Form submitted successfully');
|
|
670
|
+
log('basicLog', `Response: ${JSON.stringify(response, null, 2)}`);
|
|
671
|
+
showStatus('basicStatus', 'Form submitted successfully!', 'success');
|
|
672
|
+
|
|
673
|
+
} catch (error) {
|
|
674
|
+
log('basicLog', `ERROR: ${error.message}`);
|
|
675
|
+
log('basicLog', `Error code: ${error.code}`);
|
|
676
|
+
log('basicLog', `Status code: ${error.statusCode}`);
|
|
677
|
+
showStatus('basicStatus', `Error: ${error.message}`, 'error');
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
document.getElementById('fileForm').addEventListener('submit', async (e) => {
|
|
682
|
+
e.preventDefault();
|
|
683
|
+
|
|
684
|
+
const formId = document.getElementById('formId2').value;
|
|
685
|
+
const name = document.getElementById('name2').value;
|
|
686
|
+
const description = document.getElementById('description2').value;
|
|
687
|
+
const files = document.getElementById('files2').files;
|
|
688
|
+
|
|
689
|
+
// Create FormData with files
|
|
690
|
+
const formData = new FormData();
|
|
691
|
+
formData.append('name', name);
|
|
692
|
+
formData.append('description', description);
|
|
693
|
+
|
|
694
|
+
for (let i = 0; i < files.length; i++) {
|
|
695
|
+
formData.append(`file_${i}`, files[i]);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
log('fileLog', `Starting file form submission...`);
|
|
699
|
+
log('fileLog', `Form ID: ${formId}`);
|
|
700
|
+
log('fileLog', `Files: ${files.length} files selected`);
|
|
701
|
+
|
|
702
|
+
try {
|
|
703
|
+
const response = await FormshiveSubmit.submitForm({
|
|
704
|
+
formId: formId,
|
|
705
|
+
data: formData,
|
|
706
|
+
debug: true,
|
|
707
|
+
files: {
|
|
708
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
709
|
+
trackProgress: true
|
|
710
|
+
},
|
|
711
|
+
callbacks: {
|
|
712
|
+
onStart: () => log('fileLog', 'File upload started'),
|
|
713
|
+
onProgress: (percent, loaded, total) => {
|
|
714
|
+
log('fileLog', `Upload progress: ${percent}%`);
|
|
715
|
+
updateProgress(percent, loaded, total, 'fileProgressBar', 'fileProgressText', 'fileProgress');
|
|
716
|
+
},
|
|
717
|
+
onRetry: (attempt, maxAttempts, error) => {
|
|
718
|
+
log('fileLog', `Retry ${attempt}/${maxAttempts}: ${error.message}`);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
log('fileLog', 'SUCCESS: Files uploaded successfully');
|
|
724
|
+
log('fileLog', `Response: ${JSON.stringify(response, null, 2)}`);
|
|
725
|
+
showStatus('fileStatus', 'Files uploaded successfully!', 'success');
|
|
726
|
+
|
|
727
|
+
} catch (error) {
|
|
728
|
+
log('fileLog', `ERROR: ${error.message}`);
|
|
729
|
+
log('fileLog', `Error code: ${error.code}`);
|
|
730
|
+
showStatus('fileStatus', `Error: ${error.message}`, 'error');
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
document.getElementById('singleFileForm').addEventListener('submit', async (e) => {
|
|
735
|
+
e.preventDefault();
|
|
736
|
+
|
|
737
|
+
const formId = document.getElementById('formId2b').value;
|
|
738
|
+
const email = document.getElementById('email2b').value;
|
|
739
|
+
const category = document.getElementById('category2b').value;
|
|
740
|
+
const comments = document.getElementById('comments2b').value;
|
|
741
|
+
const fileInput = document.getElementById('singleFile');
|
|
742
|
+
const file = fileInput.files[0];
|
|
743
|
+
|
|
744
|
+
if (!file) {
|
|
745
|
+
log('singleFileLog', 'ERROR: No file selected');
|
|
746
|
+
showStatus('singleFileStatus', 'Please select a file to upload', 'error');
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Create FormData with single file
|
|
751
|
+
const formData = new FormData();
|
|
752
|
+
formData.append('email', email);
|
|
753
|
+
formData.append('category', category);
|
|
754
|
+
formData.append('comments', comments);
|
|
755
|
+
formData.append('file', file);
|
|
756
|
+
|
|
757
|
+
log('singleFileLog', `Starting single file upload...`);
|
|
758
|
+
log('singleFileLog', `Form ID: ${formId}`);
|
|
759
|
+
log('singleFileLog', `File: ${file.name} (${formatBytes(file.size)})`);
|
|
760
|
+
log('singleFileLog', `File type: ${file.type}`);
|
|
761
|
+
log('singleFileLog', `Category: ${category}`);
|
|
762
|
+
|
|
763
|
+
try {
|
|
764
|
+
const response = await FormshiveSubmit.submitForm({
|
|
765
|
+
formId: formId,
|
|
766
|
+
data: formData,
|
|
767
|
+
debug: true,
|
|
768
|
+
files: {
|
|
769
|
+
maxFileSize: 5 * 1024 * 1024, // 5MB limit
|
|
770
|
+
allowedTypes: [
|
|
771
|
+
'application/pdf',
|
|
772
|
+
'application/msword',
|
|
773
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
774
|
+
'image/jpeg',
|
|
775
|
+
'image/jpg',
|
|
776
|
+
'image/png',
|
|
777
|
+
'video/mp4',
|
|
778
|
+
'video/quicktime'
|
|
779
|
+
],
|
|
780
|
+
trackProgress: true
|
|
781
|
+
},
|
|
782
|
+
callbacks: {
|
|
783
|
+
onStart: () => log('singleFileLog', 'Single file upload started'),
|
|
784
|
+
onProgress: (percent, loaded, total) => {
|
|
785
|
+
log('singleFileLog', `Upload progress: ${percent}%`);
|
|
786
|
+
updateProgress(percent, loaded, total, 'singleFileProgressBar', 'singleFileProgressText', 'singleFileProgress');
|
|
787
|
+
},
|
|
788
|
+
onRetry: (attempt, maxAttempts, error) => {
|
|
789
|
+
log('singleFileLog', `Retry ${attempt}/${maxAttempts}: ${error.message}`);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
log('singleFileLog', 'SUCCESS: File uploaded successfully');
|
|
795
|
+
log('singleFileLog', `Response: ${JSON.stringify(response, null, 2)}`);
|
|
796
|
+
showStatus('singleFileStatus', `File "${file.name}" uploaded successfully!`, 'success');
|
|
797
|
+
|
|
798
|
+
// Reset form
|
|
799
|
+
document.getElementById('singleFileForm').reset();
|
|
800
|
+
document.getElementById('category2b').value = '';
|
|
801
|
+
|
|
802
|
+
} catch (error) {
|
|
803
|
+
log('singleFileLog', `ERROR: ${error.message}`);
|
|
804
|
+
log('singleFileLog', `Error code: ${error.code}`);
|
|
805
|
+
|
|
806
|
+
// Show user-friendly error message based on error code
|
|
807
|
+
let userMessage = error.message;
|
|
808
|
+
if (error.code === 'FILE_TOO_LARGE') {
|
|
809
|
+
userMessage = `File "${file.name}" is too large. Maximum size is 5MB.`;
|
|
810
|
+
} else if (error.code === 'INVALID_FILE_TYPE') {
|
|
811
|
+
userMessage = `File "${file.name}" has an unsupported format. Please use PDF, Word docs, images, or videos.`;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
showStatus('singleFileStatus', userMessage, 'error');
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
document.getElementById('customForm').addEventListener('submit', async (e) => {
|
|
819
|
+
e.preventDefault();
|
|
820
|
+
|
|
821
|
+
const formId = document.getElementById('formId3').value;
|
|
822
|
+
const endpoint = document.getElementById('endpoint3').value;
|
|
823
|
+
const maxRetries = parseInt(document.getElementById('maxRetries3').value);
|
|
824
|
+
const baseDelay = parseInt(document.getElementById('baseDelay3').value);
|
|
825
|
+
|
|
826
|
+
const data = {
|
|
827
|
+
subject: document.getElementById('subject3').value,
|
|
828
|
+
content: document.getElementById('content3').value
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
log('customLog', `Starting custom form submission...`);
|
|
832
|
+
log('customLog', `Form ID: ${formId}`);
|
|
833
|
+
log('customLog', `Endpoint: ${endpoint}`);
|
|
834
|
+
log('customLog', `Retry config: max=${maxRetries}, delay=${baseDelay}ms`);
|
|
835
|
+
|
|
836
|
+
try {
|
|
837
|
+
const response = await FormshiveSubmit.submitForm({
|
|
838
|
+
formId: formId,
|
|
839
|
+
data: data,
|
|
840
|
+
endpoint: endpoint,
|
|
841
|
+
debug: true,
|
|
842
|
+
retry: {
|
|
843
|
+
maxAttempts: maxRetries,
|
|
844
|
+
baseDelay: baseDelay,
|
|
845
|
+
enableJitter: true
|
|
846
|
+
},
|
|
847
|
+
callbacks: {
|
|
848
|
+
onStart: () => log('customLog', 'Custom submission started'),
|
|
849
|
+
onRetry: (attempt, maxAttempts, error) => {
|
|
850
|
+
log('customLog', `Retry ${attempt}/${maxAttempts}: ${error.message}`);
|
|
851
|
+
showStatus('customStatus', `Retrying... (${attempt}/${maxAttempts})`, 'info');
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
log('customLog', 'SUCCESS: Custom form submitted successfully');
|
|
857
|
+
log('customLog', `Response: ${JSON.stringify(response, null, 2)}`);
|
|
858
|
+
showStatus('customStatus', 'Form submitted successfully with custom config!', 'success');
|
|
859
|
+
|
|
860
|
+
} catch (error) {
|
|
861
|
+
log('customLog', `ERROR: ${error.message}`);
|
|
862
|
+
log('customLog', `Final attempt: ${error.attempt}`);
|
|
863
|
+
showStatus('customStatus', `Error: ${error.message}`, 'error');
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
document.getElementById('axiosForm').addEventListener('submit', async (e) => {
|
|
868
|
+
e.preventDefault();
|
|
869
|
+
|
|
870
|
+
// Check if axios is available
|
|
871
|
+
if (typeof axios === 'undefined') {
|
|
872
|
+
log('axiosLog', 'ERROR: Axios is not loaded');
|
|
873
|
+
showStatus('axiosStatus', 'Error: Axios library not found. Please include Axios.', 'error');
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const formId = document.getElementById('formId4').value;
|
|
878
|
+
const data = {
|
|
879
|
+
title: document.getElementById('title4').value,
|
|
880
|
+
body: document.getElementById('body4').value
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
log('axiosLog', `Starting Axios form submission...`);
|
|
884
|
+
log('axiosLog', `Form ID: ${formId}`);
|
|
885
|
+
log('axiosLog', `Using Axios HTTP client`);
|
|
886
|
+
|
|
887
|
+
try {
|
|
888
|
+
const response = await FormshiveSubmit.submitForm({
|
|
889
|
+
formId: formId,
|
|
890
|
+
data: data,
|
|
891
|
+
httpClient: 'axios', // Use axios instead of fetch
|
|
892
|
+
debug: true,
|
|
893
|
+
callbacks: {
|
|
894
|
+
onStart: () => log('axiosLog', 'Axios submission started'),
|
|
895
|
+
onRetry: (attempt, maxAttempts, error) => {
|
|
896
|
+
log('axiosLog', `Retry ${attempt}/${maxAttempts}: ${error.message}`);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
log('axiosLog', 'SUCCESS: Form submitted successfully with Axios');
|
|
902
|
+
log('axiosLog', `Response: ${JSON.stringify(response, null, 2)}`);
|
|
903
|
+
showStatus('axiosStatus', 'Form submitted successfully with Axios!', 'success');
|
|
904
|
+
|
|
905
|
+
} catch (error) {
|
|
906
|
+
log('axiosLog', `ERROR: ${error.message}`);
|
|
907
|
+
log('axiosLog', `Error code: ${error.code}`);
|
|
908
|
+
showStatus('axiosStatus', `Error: ${error.message}`, 'error');
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
document.getElementById('validationForm').addEventListener('submit', async (e) => {
|
|
913
|
+
e.preventDefault();
|
|
914
|
+
|
|
915
|
+
// Clear any existing errors first
|
|
916
|
+
clearValidationErrors();
|
|
917
|
+
|
|
918
|
+
const formId = document.getElementById('formId4').value;
|
|
919
|
+
const data = {
|
|
920
|
+
email: document.getElementById('email4').value,
|
|
921
|
+
phone: document.getElementById('phone4').value,
|
|
922
|
+
age: document.getElementById('age4').value,
|
|
923
|
+
website: document.getElementById('website4').value,
|
|
924
|
+
message: document.getElementById('message4').value
|
|
925
|
+
};
|
|
926
|
+
|
|
927
|
+
log('validationLog', `Starting validation test submission...`);
|
|
928
|
+
log('validationLog', `Form ID: ${formId}`);
|
|
929
|
+
log('validationLog', `Data: ${JSON.stringify(data, null, 2)}`);
|
|
930
|
+
|
|
931
|
+
try {
|
|
932
|
+
const response = await FormshiveSubmit.submitForm({
|
|
933
|
+
formId: formId,
|
|
934
|
+
data: data,
|
|
935
|
+
debug: true,
|
|
936
|
+
callbacks: {
|
|
937
|
+
onStart: () => log('validationLog', 'Validation test started'),
|
|
938
|
+
onError: (error) => {
|
|
939
|
+
// This callback will be called, but we also handle it in the catch block
|
|
940
|
+
log('validationLog', 'Error callback triggered');
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
log('validationLog', 'SUCCESS: Validation test submitted successfully');
|
|
946
|
+
log('validationLog', `Response: ${JSON.stringify(response, null, 2)}`);
|
|
947
|
+
showStatus('validationStatus', 'Form submitted successfully!', 'success');
|
|
948
|
+
|
|
949
|
+
// Clear field errors and update demo
|
|
950
|
+
clearValidationErrors();
|
|
951
|
+
updateFieldErrorDemo(null);
|
|
952
|
+
|
|
953
|
+
} catch (error) {
|
|
954
|
+
log('validationLog', `ERROR: ${error.message}`);
|
|
955
|
+
log('validationLog', `Error code: ${error.code}`);
|
|
956
|
+
log('validationLog', `Status code: ${error.statusCode}`);
|
|
957
|
+
|
|
958
|
+
// Check if this is a field validation error
|
|
959
|
+
if (FormshiveSubmit.isFieldValidationError(error)) {
|
|
960
|
+
log('validationLog', 'FIELD VALIDATION ERRORS DETECTED:');
|
|
961
|
+
|
|
962
|
+
const fieldErrors = FormshiveSubmit.getFieldErrors(error);
|
|
963
|
+
fieldErrors.forEach(fieldError => {
|
|
964
|
+
log('validationLog', ` - ${fieldError.field}: ${fieldError.message} (code: ${fieldError.code})`);
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
// Show field errors in the form
|
|
968
|
+
showFieldValidationErrors(error);
|
|
969
|
+
|
|
970
|
+
// Update field error demo
|
|
971
|
+
updateFieldErrorDemo(error);
|
|
972
|
+
|
|
973
|
+
const summary = FormshiveSubmit.getValidationErrorSummary ?
|
|
974
|
+
FormshiveSubmit.getValidationErrorSummary(error) :
|
|
975
|
+
`Validation failed for ${fieldErrors.length} fields`;
|
|
976
|
+
|
|
977
|
+
showStatus('validationStatus', summary, 'error');
|
|
978
|
+
} else {
|
|
979
|
+
showStatus('validationStatus', `Error: ${error.message}`, 'error');
|
|
980
|
+
updateFieldErrorDemo(null);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
// Validation error handling functions
|
|
986
|
+
function clearValidationErrors() {
|
|
987
|
+
const form = document.getElementById('validationForm');
|
|
988
|
+
const inputs = form.querySelectorAll('input, textarea');
|
|
989
|
+
|
|
990
|
+
// Remove error classes and hide error messages
|
|
991
|
+
inputs.forEach(input => {
|
|
992
|
+
input.classList.remove('input-error');
|
|
993
|
+
const errorDiv = document.getElementById(input.id + '-error');
|
|
994
|
+
if (errorDiv) {
|
|
995
|
+
errorDiv.style.display = 'none';
|
|
996
|
+
errorDiv.textContent = '';
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
function showFieldValidationErrors(error) {
|
|
1002
|
+
const fieldErrors = FormshiveSubmit.getFieldErrors(error);
|
|
1003
|
+
|
|
1004
|
+
fieldErrors.forEach(fieldError => {
|
|
1005
|
+
const input = document.getElementById(fieldError.field + '4'); // Add '4' suffix for validation form
|
|
1006
|
+
const errorDiv = document.getElementById(fieldError.field + '4-error');
|
|
1007
|
+
|
|
1008
|
+
if (input) {
|
|
1009
|
+
input.classList.add('input-error');
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
if (errorDiv) {
|
|
1013
|
+
errorDiv.textContent = fieldError.message;
|
|
1014
|
+
errorDiv.style.display = 'block';
|
|
1015
|
+
}
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
function updateFieldErrorDemo(error) {
|
|
1020
|
+
const errorSummary = document.getElementById('errorSummary');
|
|
1021
|
+
const errorDetails = document.getElementById('errorDetails');
|
|
1022
|
+
|
|
1023
|
+
if (!error || !FormshiveSubmit.isFieldValidationError(error)) {
|
|
1024
|
+
errorSummary.innerHTML = 'Submit form to see field validation errors';
|
|
1025
|
+
errorDetails.innerHTML = '';
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// Get field error helpers
|
|
1030
|
+
const helpers = FormshiveSubmit.createFieldErrorHelpers(error, 'input-error');
|
|
1031
|
+
|
|
1032
|
+
// Show summary
|
|
1033
|
+
const summary = FormshiveSubmit.getValidationErrorSummary ?
|
|
1034
|
+
FormshiveSubmit.getValidationErrorSummary(error) :
|
|
1035
|
+
'Field validation errors occurred';
|
|
1036
|
+
errorSummary.innerHTML = `<strong>Error Summary:</strong> ${summary}`;
|
|
1037
|
+
|
|
1038
|
+
// Show detailed error information
|
|
1039
|
+
const fieldErrors = FormshiveSubmit.getFieldErrors(error);
|
|
1040
|
+
let detailsHtml = '<div style="margin-top: 10px;"><strong>Field Details:</strong></div>';
|
|
1041
|
+
|
|
1042
|
+
['email', 'phone', 'age', 'website', 'message'].forEach(fieldName => {
|
|
1043
|
+
const hasError = helpers.hasError(fieldName);
|
|
1044
|
+
const message = helpers.getMessage(fieldName);
|
|
1045
|
+
const statusIcon = hasError ? '❌' : '✅';
|
|
1046
|
+
const statusText = hasError ? `Error: ${message}` : 'Valid';
|
|
1047
|
+
|
|
1048
|
+
detailsHtml += `<div style="padding: 4px 0;">
|
|
1049
|
+
<strong>${fieldName}:</strong> ${statusIcon} ${statusText}
|
|
1050
|
+
</div>`;
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
detailsHtml += '<div style="margin-top: 10px;"><strong>Available Helper Methods:</strong></div>';
|
|
1054
|
+
detailsHtml += '<code style="font-size: 11px; background: #f8f9fa; padding: 8px; display: block; margin-top: 5px;">';
|
|
1055
|
+
detailsHtml += `helpers.hasError('email'): ${helpers.hasError('email')}<br>`;
|
|
1056
|
+
detailsHtml += `helpers.getMessage('phone'): "${helpers.getMessage('phone')}"<br>`;
|
|
1057
|
+
detailsHtml += `helpers.getFieldClass('age'): "${helpers.getFieldClass('age')}"`;
|
|
1058
|
+
detailsHtml += '</code>';
|
|
1059
|
+
|
|
1060
|
+
errorDetails.innerHTML = detailsHtml;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// Initialize
|
|
1064
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
1065
|
+
log('basicLog', 'Formshive Submit Test Page loaded');
|
|
1066
|
+
log('basicLog', `Library version: ${FormshiveSubmit ? 'Loaded' : 'Not found'}`);
|
|
1067
|
+
|
|
1068
|
+
if (typeof FormshiveSubmit !== 'undefined') {
|
|
1069
|
+
log('basicLog', 'Available methods: ' + Object.keys(FormshiveSubmit).join(', '));
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
</script>
|
|
1073
|
+
</body>
|
|
1074
|
+
</html>
|