json-object-editor 0.10.657 โ†’ 0.10.662

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.
@@ -0,0 +1,608 @@
1
+ /**
2
+ * JOE React Form Renderer
3
+ * Vanilla JS form renderer using React from CDN (no build step)
4
+ *
5
+ * Usage:
6
+ * 1. Include React from CDN in your page
7
+ * 2. Load this script
8
+ * 3. Call: joeReactForm.init({ rootId: 'react-form-root', formDefinitionUrl: '/_include/{json_include_id}', formId: '{joe_form_id}' })
9
+ */
10
+
11
+ (function(window) {
12
+ 'use strict';
13
+
14
+ // Wait for React/ReactDOM to load if not immediately available
15
+ function waitForReact(callback, maxAttempts) {
16
+ maxAttempts = maxAttempts || 50; // 50 attempts = ~2.5 seconds if 50ms intervals
17
+ var attempts = 0;
18
+
19
+ function check() {
20
+ if (typeof window.React !== 'undefined' && typeof window.ReactDOM !== 'undefined') {
21
+ callback();
22
+ } else {
23
+ attempts++;
24
+ if (attempts < maxAttempts) {
25
+ setTimeout(check, 50);
26
+ } else {
27
+ console.error('JOE React Form: React and ReactDOM failed to load after ' + (maxAttempts * 50) + 'ms. Make sure React CDN scripts are included before this script.');
28
+ }
29
+ }
30
+ }
31
+
32
+ check();
33
+ }
34
+
35
+ // Test data generators for auto-fill
36
+ function generateTestValue(field, allFields) {
37
+ switch (field.type) {
38
+ case 'text':
39
+ if (field.id.toLowerCase().includes('name')) {
40
+ return field.id.toLowerCase().includes('first') ? 'John' : 'Doe';
41
+ }
42
+ if (field.id.toLowerCase().includes('email')) {
43
+ return 'test@example.com';
44
+ }
45
+ if (field.id.toLowerCase().includes('phone')) {
46
+ return '(555) 555-5555';
47
+ }
48
+ return 'Test ' + field.label;
49
+ case 'email':
50
+ return 'test@example.com';
51
+ case 'phone':
52
+ return '(555) 555-5555';
53
+ case 'number':
54
+ return field.min !== undefined ? field.min : 0;
55
+ case 'textarea':
56
+ return 'Test content for ' + field.label + '. This is sample text to fill the field.';
57
+ case 'select':
58
+ if (field.options && field.options.length > 0) {
59
+ // Prefer first non-blank option, or first option if all have values
60
+ var firstOption = field.options[0];
61
+ return firstOption.value || (field.options.length > 1 ? field.options[1].value : '');
62
+ }
63
+ return '';
64
+ case 'boolean':
65
+ return false; // Default to false for booleans
66
+ case 'scale':
67
+ var min = field.min !== undefined ? field.min : 0;
68
+ var max = field.max !== undefined ? field.max : 5;
69
+ return Math.floor((min + max) / 2); // Middle value
70
+ default:
71
+ return 'test';
72
+ }
73
+ }
74
+
75
+ // Create the public API immediately - this ensures joeReactForm exists even if React isn't loaded yet
76
+ window.joeReactForm = {
77
+ init: function(options) {
78
+ var rootId = options.rootId || 'react-form-root';
79
+ var formDefinitionUrl = options.formDefinitionUrl;
80
+ var formId = options.formId;
81
+
82
+ if (!formDefinitionUrl) {
83
+ console.error('JOE React Form: formDefinitionUrl is required');
84
+ return;
85
+ }
86
+
87
+ if (!formId) {
88
+ console.error('JOE React Form: formId is required');
89
+ return;
90
+ }
91
+
92
+ // Wait for React if needed, then initialize
93
+ function doInit() {
94
+ if (typeof window.React === 'undefined' || typeof window.ReactDOM === 'undefined') {
95
+ waitForReact(doInit);
96
+ return;
97
+ }
98
+
99
+ // React is loaded - proceed with initialization
100
+ var React = window.React;
101
+ var ReactDOM = window.ReactDOM;
102
+ var createElement = React.createElement;
103
+ var useState = React.useState;
104
+ var useMemo = React.useMemo;
105
+
106
+ // Helper function for className
107
+ function clsx() {
108
+ var classes = [];
109
+ for (var i = 0; i < arguments.length; i++) {
110
+ if (arguments[i]) classes.push(arguments[i]);
111
+ }
112
+ return classes.join(' ');
113
+ }
114
+
115
+ // Condition evaluation
116
+ function evalCondition(cond, values) {
117
+ var v = values && values[cond.field];
118
+ switch (cond.op) {
119
+ case 'eq':
120
+ return v === cond.value;
121
+ case 'neq':
122
+ return v !== cond.value;
123
+ case 'contains':
124
+ return typeof v === 'string' ? v.toLowerCase().indexOf(String(cond.value).toLowerCase()) !== -1 : false;
125
+ case 'gt':
126
+ return Number(v) > Number(cond.value);
127
+ case 'gte':
128
+ return Number(v) >= Number(cond.value);
129
+ case 'lt':
130
+ return Number(v) < Number(cond.value);
131
+ case 'lte':
132
+ return Number(v) <= Number(cond.value);
133
+ case 'truthy':
134
+ return Boolean(v);
135
+ default:
136
+ return false;
137
+ }
138
+ }
139
+
140
+ // Visibility check
141
+ function isVisible(field, values) {
142
+ var vis = field.visibility;
143
+ if (!vis) return true;
144
+ if (vis.whenAll) {
145
+ return vis.whenAll.every(function(c) { return evalCondition(c, values); });
146
+ }
147
+ if (vis.whenAny) {
148
+ return vis.whenAny.some(function(c) { return evalCondition(c, values); });
149
+ }
150
+ return true;
151
+ }
152
+
153
+ // Field component
154
+ function Field(props) {
155
+ var field = props.field;
156
+ var value = props.value;
157
+ var onChange = props.onChange;
158
+ var error = props.error;
159
+
160
+ var commonProps = {
161
+ id: field.id,
162
+ name: field.id,
163
+ className: 'w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm shadow-sm focus:border-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-200',
164
+ value: value !== undefined && value !== null ? value : '',
165
+ onChange: function(e) { onChange(field.id, e.target.value); }
166
+ };
167
+
168
+ var label = createElement('label', {
169
+ htmlFor: field.id,
170
+ className: 'text-sm font-medium text-slate-900'
171
+ }, field.label, field.required ? createElement('span', { className: 'ml-1 text-rose-600' }, '*') : null);
172
+
173
+ var inputElement;
174
+
175
+ if (field.type === 'textarea') {
176
+ inputElement = createElement('textarea', Object.assign({}, commonProps, {
177
+ rows: 4,
178
+ placeholder: field.placeholder || ''
179
+ }));
180
+ } else if (field.type === 'select') {
181
+ var options = (field.options || []).map(function(o) {
182
+ return createElement('option', { key: o.value, value: o.value }, o.label);
183
+ });
184
+ inputElement = createElement('select', Object.assign({}, commonProps, {
185
+ value: value !== undefined && value !== null ? value : '',
186
+ onChange: function(e) { onChange(field.id, e.target.value); }
187
+ }), createElement('option', { value: '' }, 'Selectโ€ฆ'), options);
188
+ } else if (field.type === 'boolean') {
189
+ inputElement = createElement('div', { className: 'flex items-center gap-3' },
190
+ createElement('label', { className: 'inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm shadow-sm' },
191
+ createElement('input', {
192
+ type: 'radio',
193
+ name: field.id,
194
+ checked: value === true,
195
+ onChange: function() { onChange(field.id, true); }
196
+ }),
197
+ 'Yes'
198
+ ),
199
+ createElement('label', { className: 'inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm shadow-sm' },
200
+ createElement('input', {
201
+ type: 'radio',
202
+ name: field.id,
203
+ checked: value === false,
204
+ onChange: function() { onChange(field.id, false); }
205
+ }),
206
+ 'No'
207
+ )
208
+ );
209
+ } else if (field.type === 'scale') {
210
+ var min = field.min !== undefined ? field.min : 0;
211
+ var max = field.max !== undefined ? field.max : 5;
212
+ var currentValue = value !== undefined && value !== null ? value : 0;
213
+ inputElement = createElement('div', { className: 'space-y-2' },
214
+ createElement('input', {
215
+ type: 'range',
216
+ min: min,
217
+ max: max,
218
+ step: 1,
219
+ value: currentValue,
220
+ onChange: function(e) { onChange(field.id, Number(e.target.value)); },
221
+ className: 'w-full'
222
+ }),
223
+ createElement('div', { className: 'flex items-center justify-between text-xs text-slate-500' },
224
+ createElement('span', null, field.minLabel !== undefined ? field.minLabel : min),
225
+ createElement('span', { className: 'rounded-lg bg-slate-100 px-2 py-1 text-slate-700' }, String(currentValue)),
226
+ createElement('span', null, field.maxLabel !== undefined ? field.maxLabel : max)
227
+ )
228
+ );
229
+ } else {
230
+ var inputType = field.type === 'number' ? 'number' : (field.type === 'email' ? 'email' : 'text');
231
+ inputElement = createElement('input', Object.assign({}, commonProps, {
232
+ type: inputType,
233
+ min: field.min,
234
+ max: field.max,
235
+ step: field.step,
236
+ placeholder: field.placeholder || ''
237
+ }));
238
+ }
239
+
240
+ return createElement('div', { className: 'space-y-1' },
241
+ createElement('div', { className: 'flex items-start justify-between gap-3' }, label),
242
+ inputElement,
243
+ error ? createElement('p', { className: 'text-xs text-rose-600' }, error) : null
244
+ );
245
+ }
246
+
247
+ // Validation
248
+ function validateSection(section, values) {
249
+ var errors = {};
250
+ for (var i = 0; i < section.fields.length; i++) {
251
+ var f = section.fields[i];
252
+ if (!isVisible(f, values)) continue;
253
+ if (!f.required) continue;
254
+
255
+ var v = values[f.id];
256
+ var empty = v === undefined || v === null || v === '';
257
+
258
+ if (f.type === 'boolean') {
259
+ if (v !== true && v !== false) {
260
+ errors[f.id] = 'Please select Yes or No.';
261
+ }
262
+ } else if (f.type === 'scale') {
263
+ if (v === undefined || v === null) {
264
+ errors[f.id] = 'Please choose a value.';
265
+ }
266
+ } else if (empty) {
267
+ errors[f.id] = 'This field is required.';
268
+ }
269
+ }
270
+ return errors;
271
+ }
272
+
273
+ // Check for test mode from query string
274
+ var testMode = false;
275
+ var skipValidation = false;
276
+ if (typeof window !== 'undefined' && window.location) {
277
+ var params = new URLSearchParams(window.location.search);
278
+ testMode = params.get('test') === '1' || params.get('test') === 'true';
279
+ skipValidation = params.get('skipValidation') === '1' || params.get('skipValidation') === 'true';
280
+ }
281
+
282
+ // Main App component
283
+ function App(props) {
284
+ var formDefinition = props.formDefinition;
285
+ var formId = props.formId;
286
+
287
+ if (!formDefinition || !formDefinition.sections || formDefinition.sections.length === 0) {
288
+ return createElement('div', { style: { padding: '20px' } }, 'Loading form...');
289
+ }
290
+
291
+ var sections = formDefinition.sections;
292
+
293
+ var stepState = useState(0);
294
+ var step = stepState[0];
295
+ var setStep = stepState[1];
296
+
297
+ var valuesState = useState({});
298
+ var values = valuesState[0];
299
+ var setValues = valuesState[1];
300
+
301
+ var errorsState = useState({});
302
+ var errors = errorsState[0];
303
+ var setErrors = errorsState[1];
304
+
305
+ var showReviewState = useState(false);
306
+ var showReview = showReviewState[0];
307
+ var setShowReview = showReviewState[1];
308
+
309
+ var current = sections[step];
310
+
311
+ var visibleFields = useMemo(function() {
312
+ if (!current) return [];
313
+ return current.fields.filter(function(f) { return isVisible(f, values); });
314
+ }, [current, values]);
315
+
316
+ // Collect all fields from all sections for auto-fill
317
+ var allFields = useMemo(function() {
318
+ var fields = [];
319
+ sections.forEach(function(section) {
320
+ if (section.fields) {
321
+ section.fields.forEach(function(f) {
322
+ fields.push(f);
323
+ });
324
+ }
325
+ });
326
+ return fields;
327
+ }, [sections]);
328
+
329
+ // Auto-fill function for testing
330
+ function autoFillForm() {
331
+ var newValues = {};
332
+ allFields.forEach(function(field) {
333
+ if (isVisible(field, newValues)) {
334
+ var testValue = generateTestValue(field, allFields);
335
+ if (testValue !== null && testValue !== undefined) {
336
+ newValues[field.id] = testValue;
337
+ }
338
+ }
339
+ });
340
+ setValues(newValues);
341
+ setErrors({});
342
+ console.log('JOE React Form: Auto-filled form with test data', newValues);
343
+ }
344
+
345
+ // Force submission bypassing validation
346
+ function forceSubmit() {
347
+ submitForm();
348
+ }
349
+
350
+ // Expose testing functions to window in test mode
351
+ if (testMode && typeof window !== 'undefined') {
352
+ window.__joeReactFormTest = {
353
+ autoFill: autoFillForm,
354
+ forceSubmit: forceSubmit,
355
+ getValues: function() { return values; },
356
+ setValues: setValues,
357
+ submit: submitForm,
358
+ setStep: setStep,
359
+ goToReview: function() { setShowReview(true); },
360
+ formDefinition: formDefinition
361
+ };
362
+ console.log('JOE React Form: Test mode enabled. Use window.__joeReactFormTest for testing.');
363
+ console.log('Available functions:', Object.keys(window.__joeReactFormTest));
364
+ }
365
+
366
+ function setValue(id, v) {
367
+ setValues(function(prev) {
368
+ var next = Object.assign({}, prev);
369
+ next[id] = v;
370
+ return next;
371
+ });
372
+ setErrors(function(prev) {
373
+ if (!prev[id]) return prev;
374
+ var next = Object.assign({}, prev);
375
+ delete next[id];
376
+ return next;
377
+ });
378
+ }
379
+
380
+ function next() {
381
+ if (!current) return;
382
+ var e = validateSection(current, values);
383
+ setErrors(e);
384
+ // Skip validation check if in skipValidation mode
385
+ if (!skipValidation && Object.keys(e).length) return;
386
+
387
+ if (step < sections.length - 1) {
388
+ setStep(step + 1);
389
+ window.scrollTo({ top: 0, behavior: 'smooth' });
390
+ } else {
391
+ setShowReview(true);
392
+ window.scrollTo({ top: 0, behavior: 'smooth' });
393
+ }
394
+ }
395
+
396
+ function back() {
397
+ if (showReview) {
398
+ setShowReview(false);
399
+ return;
400
+ }
401
+ setStep(Math.max(0, step - 1));
402
+ window.scrollTo({ top: 0, behavior: 'smooth' });
403
+ }
404
+
405
+ function submitForm() {
406
+ // Submit to JOE
407
+ var submissionData = {
408
+ formid: formId,
409
+ submission: values
410
+ };
411
+
412
+ fetch('/API/plugin/formBuilder/submission', {
413
+ method: 'POST',
414
+ headers: { 'Content-Type': 'application/json' },
415
+ body: JSON.stringify(submissionData)
416
+ })
417
+ .then(function(response) { return response.json(); })
418
+ .then(function(data) {
419
+ if (data.errors) {
420
+ alert('Submission error: ' + (typeof data.errors === 'string' ? data.errors : JSON.stringify(data.errors)));
421
+ return;
422
+ }
423
+ alert('Form submitted successfully!');
424
+ // Could redirect or show success message
425
+ })
426
+ .catch(function(error) {
427
+ console.error('Submission error:', error);
428
+ alert('Error submitting form: ' + error.message);
429
+ });
430
+ }
431
+
432
+ // Already checked formDefinition above, just check current
433
+ if (!current) {
434
+ return createElement('div', { style: { padding: '20px' } }, 'Loading form...');
435
+ }
436
+
437
+ var progressPercent = showReview ? 100 : ((step + 1) / sections.length) * 100;
438
+
439
+ return createElement('div', { className: 'min-h-screen bg-gradient-to-b from-slate-50 to-white' },
440
+ createElement('div', { className: 'mx-auto max-w-3xl px-4 py-8' },
441
+ createElement('header', { className: 'mb-6' },
442
+ createElement('div', { className: 'flex flex-col gap-2' },
443
+ createElement('h1', { className: 'text-2xl font-semibold text-slate-900' }, formDefinition.formName || 'Form'),
444
+ createElement('p', { className: 'text-sm text-slate-600' },
445
+ 'Version ' + (formDefinition.version || '1.0') + ' โ€ข Interactive form'
446
+ )
447
+ ),
448
+ createElement('div', { className: 'mt-4 h-2 w-full overflow-hidden rounded-full bg-slate-100' },
449
+ createElement('div', {
450
+ className: 'h-full rounded-full bg-slate-900 transition-all',
451
+ style: { width: progressPercent + '%' }
452
+ })
453
+ ),
454
+ createElement('div', { className: 'mt-2 flex items-center justify-between text-xs text-slate-500' },
455
+ createElement('span', null, showReview ? 'Review' : 'Section ' + (step + 1) + ' of ' + sections.length),
456
+ createElement('span', null, showReview ? 'Ready' : current.title)
457
+ )
458
+ ),
459
+ createElement('main', { className: 'rounded-2xl border border-slate-200 bg-white p-5 shadow-sm' },
460
+ !showReview ? createElement('div', null,
461
+ createElement('div', { className: 'mb-4' },
462
+ createElement('h2', { className: 'text-lg font-semibold text-slate-900' }, current.title),
463
+ current.description ? createElement('p', { className: 'mt-1 text-sm text-slate-600' }, current.description) : null
464
+ ),
465
+ createElement('div', { className: 'grid gap-4' },
466
+ visibleFields.map(function(f) {
467
+ return createElement(Field, {
468
+ key: f.id,
469
+ field: f,
470
+ value: values[f.id],
471
+ onChange: setValue,
472
+ error: errors[f.id]
473
+ });
474
+ })
475
+ ),
476
+ createElement('div', { className: 'mt-6 flex items-center justify-between' },
477
+ createElement('div', { className: 'flex items-center gap-2' },
478
+ createElement('button', {
479
+ onClick: back,
480
+ disabled: step === 0,
481
+ className: clsx(
482
+ 'rounded-xl px-4 py-2 text-sm font-medium',
483
+ step === 0
484
+ ? 'cursor-not-allowed bg-slate-100 text-slate-400'
485
+ : 'bg-slate-100 text-slate-800 hover:bg-slate-200'
486
+ )
487
+ }, 'Back'),
488
+ testMode ? createElement('button', {
489
+ onClick: autoFillForm,
490
+ className: 'rounded-xl bg-amber-500 px-3 py-2 text-xs font-medium text-white hover:bg-amber-600',
491
+ title: 'Auto-fill all fields with test data'
492
+ }, '๐Ÿงช Auto-fill') : null
493
+ ),
494
+ createElement('button', {
495
+ onClick: next,
496
+ className: 'rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white hover:bg-slate-800'
497
+ }, step === sections.length - 1 ? 'Review' : 'Next')
498
+ )
499
+ ) : createElement('div', null,
500
+ createElement('div', { className: 'mb-4' },
501
+ createElement('h2', { className: 'text-lg font-semibold text-slate-900' }, 'Review & Submit'),
502
+ createElement('p', { className: 'mt-1 text-sm text-slate-600' },
503
+ 'Please review your answers before submitting.'
504
+ )
505
+ ),
506
+ createElement('div', { className: 'rounded-xl border border-slate-200 bg-slate-50 p-3' },
507
+ createElement('pre', { className: 'max-h-[55vh] overflow-auto text-xs text-slate-800' },
508
+ JSON.stringify(values, null, 2)
509
+ )
510
+ ),
511
+ createElement('div', { className: 'mt-6 flex items-center justify-between' },
512
+ createElement('div', { className: 'flex items-center gap-2' },
513
+ createElement('button', {
514
+ onClick: back,
515
+ className: 'rounded-xl bg-slate-100 px-4 py-2 text-sm font-medium text-slate-800 hover:bg-slate-200'
516
+ }, 'Back'),
517
+ testMode ? createElement('button', {
518
+ onClick: forceSubmit,
519
+ className: 'rounded-xl bg-red-500 px-3 py-2 text-xs font-medium text-white hover:bg-red-600',
520
+ title: 'Force submit (bypass validation)'
521
+ }, '๐Ÿš€ Force Submit') : null
522
+ ),
523
+ createElement('button', {
524
+ onClick: submitForm,
525
+ className: 'rounded-xl bg-slate-900 px-4 py-2 text-sm font-medium text-white hover:bg-slate-800'
526
+ }, 'Submit')
527
+ )
528
+ )
529
+ )
530
+ )
531
+ );
532
+ }
533
+
534
+ // Fetch form definition and render
535
+ console.log('JOE React Form: Fetching form definition from:', formDefinitionUrl);
536
+ fetch(formDefinitionUrl)
537
+ .then(function(response) {
538
+ if (!response.ok) {
539
+ throw new Error('HTTP error! status: ' + response.status);
540
+ }
541
+ return response.json();
542
+ })
543
+ .then(function(responseData) {
544
+ console.log('JOE React Form: Raw response received:', responseData);
545
+ console.log('JOE React Form: Response type:', typeof responseData);
546
+ console.log('JOE React Form: Has sections?', responseData && responseData.sections);
547
+
548
+ // Handle potential response wrapping (some APIs wrap in {data: {...}})
549
+ var formDefinition = responseData;
550
+ if (responseData && responseData.data && responseData.data.sections) {
551
+ formDefinition = responseData.data;
552
+ console.log('JOE React Form: Unwrapped response.data');
553
+ }
554
+
555
+ // If response has errors, show them
556
+ if (responseData && (responseData.errors || responseData.error)) {
557
+ console.error('JOE React Form: API returned error:', responseData.errors || responseData.error);
558
+ var root = document.getElementById(rootId);
559
+ if (root) {
560
+ var errorMsg = responseData.errors || responseData.error;
561
+ root.innerHTML = '<div style="padding: 20px; color: red;">Error loading form: ' +
562
+ (typeof errorMsg === 'string' ? errorMsg : JSON.stringify(errorMsg)) + '</div>';
563
+ }
564
+ return;
565
+ }
566
+
567
+ console.log('JOE React Form: Processing form definition:', formDefinition);
568
+ console.log('JOE React Form: Sections count:', formDefinition && formDefinition.sections ? formDefinition.sections.length : 'N/A');
569
+
570
+ if (!formDefinition || !formDefinition.sections || formDefinition.sections.length === 0) {
571
+ console.error('JOE React Form: Invalid form definition');
572
+ console.error('JOE React Form: formDefinition:', formDefinition);
573
+ console.error('JOE React Form: formDefinition.sections:', formDefinition && formDefinition.sections);
574
+ var root = document.getElementById(rootId);
575
+ if (root) {
576
+ root.innerHTML = '<div style="padding: 20px; color: red;">Error: Form definition is invalid or has no sections.<br><pre style="font-size:11px; overflow:auto; max-height:200px;">' +
577
+ JSON.stringify(formDefinition, null, 2) + '</pre></div>';
578
+ }
579
+ return;
580
+ }
581
+
582
+ var root = document.getElementById(rootId);
583
+ if (!root) {
584
+ console.error('JOE React Form: root element #' + rootId + ' not found');
585
+ return;
586
+ }
587
+
588
+ console.log('JOE React Form: Rendering form with', formDefinition.sections.length, 'sections');
589
+ ReactDOM.render(
590
+ createElement(App, { formDefinition: formDefinition, formId: formId }),
591
+ root
592
+ );
593
+ })
594
+ .catch(function(error) {
595
+ console.error('JOE React Form: Error loading form definition:', error);
596
+ var root = document.getElementById(rootId);
597
+ if (root) {
598
+ root.innerHTML = '<div style="padding: 20px; color: red;">Error loading form: ' + error.message + '</div>';
599
+ }
600
+ });
601
+ }
602
+
603
+ // Start initialization (will wait for React if needed)
604
+ doInit();
605
+ }
606
+ };
607
+
608
+ })(window);
package/js/joe.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /* --------------------------------------------------------
2
2
  *
3
- * json-object-editor - v0.10.657
3
+ * json-object-editor - v0.10.661
4
4
  * Created by: Corey Hadden
5
5
  *
6
6
  * -------------------------------------------------------- */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-object-editor",
3
- "version": "0.10.657",
3
+ "version": "0.10.662",
4
4
  "description": "JOE the Json Object Editor | Platform Edition",
5
5
  "main": "app.js",
6
6
  "scripts": {