@bpmn-io/form-js-viewer 0.9.9 → 0.10.0-alpha.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 +6 -0
- package/dist/assets/form-js.css +13 -5
- package/dist/index.cjs +300 -418
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +299 -418
- package/dist/index.es.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/render/components/Util.d.ts +4 -1
- package/dist/types/render/components/form-fields/Textarea.d.ts +13 -0
- package/dist/types/render/components/index.d.ts +2 -1
- package/package.json +2 -2
package/dist/index.es.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import Ids from 'ids';
|
|
2
2
|
import { isArray, isFunction, isNumber, bind, assign, isNil, get, isUndefined, isObject, set, isString } from 'min-dash';
|
|
3
3
|
import snarkdown from '@bpmn-io/snarkdown';
|
|
4
|
+
import classNames from 'classnames';
|
|
4
5
|
import { jsx, jsxs } from 'preact/jsx-runtime';
|
|
5
6
|
import { useContext, useState, useEffect, useRef, useMemo, useCallback } from 'preact/hooks';
|
|
6
7
|
import { createContext, createElement, Fragment, render } from 'preact';
|
|
7
8
|
import React, { createPortal } from 'preact/compat';
|
|
8
|
-
import classNames from 'classnames';
|
|
9
9
|
import Markup from 'preact-markup';
|
|
10
10
|
import { Injector } from 'didi';
|
|
11
11
|
|
|
12
12
|
var FN_REF = '__fn';
|
|
13
13
|
var DEFAULT_PRIORITY = 1000;
|
|
14
14
|
var slice = Array.prototype.slice;
|
|
15
|
+
|
|
15
16
|
/**
|
|
16
17
|
* A general purpose event bus.
|
|
17
18
|
*
|
|
@@ -95,13 +96,14 @@ var slice = Array.prototype.slice;
|
|
|
95
96
|
* console.log(sum); // 3
|
|
96
97
|
* ```
|
|
97
98
|
*/
|
|
98
|
-
|
|
99
99
|
function EventBus() {
|
|
100
|
-
this._listeners = {};
|
|
101
|
-
// message passing until the bitter end
|
|
100
|
+
this._listeners = {};
|
|
102
101
|
|
|
102
|
+
// cleanup on destroy on lowest priority to allow
|
|
103
|
+
// message passing until the bitter end
|
|
103
104
|
this.on('diagram.destroy', 1, this._destroy, this);
|
|
104
105
|
}
|
|
106
|
+
|
|
105
107
|
/**
|
|
106
108
|
* Register an event listener for events with the given name.
|
|
107
109
|
*
|
|
@@ -119,30 +121,25 @@ function EventBus() {
|
|
|
119
121
|
* @param {Function} callback
|
|
120
122
|
* @param {Object} [that] Pass context (`this`) to the callback
|
|
121
123
|
*/
|
|
122
|
-
|
|
123
124
|
EventBus.prototype.on = function (events, priority, callback, that) {
|
|
124
125
|
events = isArray(events) ? events : [events];
|
|
125
|
-
|
|
126
126
|
if (isFunction(priority)) {
|
|
127
127
|
that = callback;
|
|
128
128
|
callback = priority;
|
|
129
129
|
priority = DEFAULT_PRIORITY;
|
|
130
130
|
}
|
|
131
|
-
|
|
132
131
|
if (!isNumber(priority)) {
|
|
133
132
|
throw new Error('priority must be a number');
|
|
134
133
|
}
|
|
135
|
-
|
|
136
134
|
var actualCallback = callback;
|
|
137
|
-
|
|
138
135
|
if (that) {
|
|
139
|
-
actualCallback = bind(callback, that);
|
|
136
|
+
actualCallback = bind(callback, that);
|
|
137
|
+
|
|
138
|
+
// make sure we remember and are able to remove
|
|
140
139
|
// bound callbacks via {@link #off} using the original
|
|
141
140
|
// callback
|
|
142
|
-
|
|
143
141
|
actualCallback[FN_REF] = callback[FN_REF] || callback;
|
|
144
142
|
}
|
|
145
|
-
|
|
146
143
|
var self = this;
|
|
147
144
|
events.forEach(function (e) {
|
|
148
145
|
self._addListener(e, {
|
|
@@ -152,6 +149,7 @@ EventBus.prototype.on = function (events, priority, callback, that) {
|
|
|
152
149
|
});
|
|
153
150
|
});
|
|
154
151
|
};
|
|
152
|
+
|
|
155
153
|
/**
|
|
156
154
|
* Register an event listener that is executed only once.
|
|
157
155
|
*
|
|
@@ -160,34 +158,30 @@ EventBus.prototype.on = function (events, priority, callback, that) {
|
|
|
160
158
|
* @param {Function} callback the callback to execute
|
|
161
159
|
* @param {Object} [that] Pass context (`this`) to the callback
|
|
162
160
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
165
161
|
EventBus.prototype.once = function (event, priority, callback, that) {
|
|
166
162
|
var self = this;
|
|
167
|
-
|
|
168
163
|
if (isFunction(priority)) {
|
|
169
164
|
that = callback;
|
|
170
165
|
callback = priority;
|
|
171
166
|
priority = DEFAULT_PRIORITY;
|
|
172
167
|
}
|
|
173
|
-
|
|
174
168
|
if (!isNumber(priority)) {
|
|
175
169
|
throw new Error('priority must be a number');
|
|
176
170
|
}
|
|
177
|
-
|
|
178
171
|
function wrappedCallback() {
|
|
179
172
|
wrappedCallback.__isTomb = true;
|
|
180
173
|
var result = callback.apply(that, arguments);
|
|
181
174
|
self.off(event, wrappedCallback);
|
|
182
175
|
return result;
|
|
183
|
-
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// make sure we remember and are able to remove
|
|
184
179
|
// bound callbacks via {@link #off} using the original
|
|
185
180
|
// callback
|
|
186
|
-
|
|
187
|
-
|
|
188
181
|
wrappedCallback[FN_REF] = callback;
|
|
189
182
|
this.on(event, priority, wrappedCallback);
|
|
190
183
|
};
|
|
184
|
+
|
|
191
185
|
/**
|
|
192
186
|
* Removes event listeners by event and callback.
|
|
193
187
|
*
|
|
@@ -196,8 +190,6 @@ EventBus.prototype.once = function (event, priority, callback, that) {
|
|
|
196
190
|
* @param {string|Array<string>} events
|
|
197
191
|
* @param {Function} [callback]
|
|
198
192
|
*/
|
|
199
|
-
|
|
200
|
-
|
|
201
193
|
EventBus.prototype.off = function (events, callback) {
|
|
202
194
|
events = isArray(events) ? events : [events];
|
|
203
195
|
var self = this;
|
|
@@ -205,6 +197,7 @@ EventBus.prototype.off = function (events, callback) {
|
|
|
205
197
|
self._removeListener(event, callback);
|
|
206
198
|
});
|
|
207
199
|
};
|
|
200
|
+
|
|
208
201
|
/**
|
|
209
202
|
* Create an EventBus event.
|
|
210
203
|
*
|
|
@@ -212,13 +205,12 @@ EventBus.prototype.off = function (events, callback) {
|
|
|
212
205
|
*
|
|
213
206
|
* @return {Object} event, recognized by the eventBus
|
|
214
207
|
*/
|
|
215
|
-
|
|
216
|
-
|
|
217
208
|
EventBus.prototype.createEvent = function (data) {
|
|
218
209
|
var event = new InternalEvent();
|
|
219
210
|
event.init(data);
|
|
220
211
|
return event;
|
|
221
212
|
};
|
|
213
|
+
|
|
222
214
|
/**
|
|
223
215
|
* Fires a named event.
|
|
224
216
|
*
|
|
@@ -249,45 +241,40 @@ EventBus.prototype.createEvent = function (data) {
|
|
|
249
241
|
* @return {boolean} the events return value, if specified or false if the
|
|
250
242
|
* default action was prevented by listeners
|
|
251
243
|
*/
|
|
252
|
-
|
|
253
|
-
|
|
254
244
|
EventBus.prototype.fire = function (type, data) {
|
|
255
245
|
var event, firstListener, returnValue, args;
|
|
256
246
|
args = slice.call(arguments);
|
|
257
|
-
|
|
258
247
|
if (typeof type === 'object') {
|
|
259
248
|
data = type;
|
|
260
249
|
type = data.type;
|
|
261
250
|
}
|
|
262
|
-
|
|
263
251
|
if (!type) {
|
|
264
252
|
throw new Error('no event type specified');
|
|
265
253
|
}
|
|
266
|
-
|
|
267
254
|
firstListener = this._listeners[type];
|
|
268
|
-
|
|
269
255
|
if (!firstListener) {
|
|
270
256
|
return;
|
|
271
|
-
}
|
|
272
|
-
// events here. We wrap them only once, though
|
|
273
|
-
|
|
257
|
+
}
|
|
274
258
|
|
|
259
|
+
// we make sure we fire instances of our home made
|
|
260
|
+
// events here. We wrap them only once, though
|
|
275
261
|
if (data instanceof InternalEvent) {
|
|
276
262
|
// we are fine, we alread have an event
|
|
277
263
|
event = data;
|
|
278
264
|
} else {
|
|
279
265
|
event = this.createEvent(data);
|
|
280
|
-
}
|
|
281
|
-
|
|
266
|
+
}
|
|
282
267
|
|
|
283
|
-
|
|
268
|
+
// ensure we pass the event as the first parameter
|
|
269
|
+
args[0] = event;
|
|
284
270
|
|
|
285
|
-
|
|
271
|
+
// original event type (in case we delegate)
|
|
272
|
+
var originalType = event.type;
|
|
286
273
|
|
|
274
|
+
// update event type before delegation
|
|
287
275
|
if (type !== originalType) {
|
|
288
276
|
event.type = type;
|
|
289
277
|
}
|
|
290
|
-
|
|
291
278
|
try {
|
|
292
279
|
returnValue = this._invokeListeners(event, args, firstListener);
|
|
293
280
|
} finally {
|
|
@@ -295,60 +282,51 @@ EventBus.prototype.fire = function (type, data) {
|
|
|
295
282
|
if (type !== originalType) {
|
|
296
283
|
event.type = originalType;
|
|
297
284
|
}
|
|
298
|
-
}
|
|
299
|
-
// got prevented and no other return value exists
|
|
300
|
-
|
|
285
|
+
}
|
|
301
286
|
|
|
287
|
+
// set the return value to false if the event default
|
|
288
|
+
// got prevented and no other return value exists
|
|
302
289
|
if (returnValue === undefined && event.defaultPrevented) {
|
|
303
290
|
returnValue = false;
|
|
304
291
|
}
|
|
305
|
-
|
|
306
292
|
return returnValue;
|
|
307
293
|
};
|
|
308
|
-
|
|
309
294
|
EventBus.prototype.handleError = function (error) {
|
|
310
295
|
return this.fire('error', {
|
|
311
296
|
error: error
|
|
312
297
|
}) === false;
|
|
313
298
|
};
|
|
314
|
-
|
|
315
299
|
EventBus.prototype._destroy = function () {
|
|
316
300
|
this._listeners = {};
|
|
317
301
|
};
|
|
318
|
-
|
|
319
302
|
EventBus.prototype._invokeListeners = function (event, args, listener) {
|
|
320
303
|
var returnValue;
|
|
321
|
-
|
|
322
304
|
while (listener) {
|
|
323
305
|
// handle stopped propagation
|
|
324
306
|
if (event.cancelBubble) {
|
|
325
307
|
break;
|
|
326
308
|
}
|
|
327
|
-
|
|
328
309
|
returnValue = this._invokeListener(event, args, listener);
|
|
329
310
|
listener = listener.next;
|
|
330
311
|
}
|
|
331
|
-
|
|
332
312
|
return returnValue;
|
|
333
313
|
};
|
|
334
|
-
|
|
335
314
|
EventBus.prototype._invokeListener = function (event, args, listener) {
|
|
336
315
|
var returnValue;
|
|
337
|
-
|
|
338
316
|
if (listener.callback.__isTomb) {
|
|
339
317
|
return returnValue;
|
|
340
318
|
}
|
|
341
|
-
|
|
342
319
|
try {
|
|
343
320
|
// returning false prevents the default action
|
|
344
|
-
returnValue = invokeFunction(listener.callback, args);
|
|
321
|
+
returnValue = invokeFunction(listener.callback, args);
|
|
345
322
|
|
|
323
|
+
// stop propagation on return value
|
|
346
324
|
if (returnValue !== undefined) {
|
|
347
325
|
event.returnValue = returnValue;
|
|
348
326
|
event.stopPropagation();
|
|
349
|
-
}
|
|
350
|
-
|
|
327
|
+
}
|
|
351
328
|
|
|
329
|
+
// prevent default on return false
|
|
352
330
|
if (returnValue === false) {
|
|
353
331
|
event.preventDefault();
|
|
354
332
|
}
|
|
@@ -358,9 +336,9 @@ EventBus.prototype._invokeListener = function (event, args, listener) {
|
|
|
358
336
|
throw error;
|
|
359
337
|
}
|
|
360
338
|
}
|
|
361
|
-
|
|
362
339
|
return returnValue;
|
|
363
340
|
};
|
|
341
|
+
|
|
364
342
|
/*
|
|
365
343
|
* Add new listener with a certain priority to the list
|
|
366
344
|
* of listeners (for the given event).
|
|
@@ -377,67 +355,54 @@ EventBus.prototype._invokeListener = function (event, args, listener) {
|
|
|
377
355
|
* @param {string} event
|
|
378
356
|
* @param {Object} listener { priority, callback }
|
|
379
357
|
*/
|
|
380
|
-
|
|
381
|
-
|
|
382
358
|
EventBus.prototype._addListener = function (event, newListener) {
|
|
383
359
|
var listener = this._getListeners(event),
|
|
384
|
-
|
|
385
|
-
|
|
360
|
+
previousListener;
|
|
386
361
|
|
|
362
|
+
// no prior listeners
|
|
387
363
|
if (!listener) {
|
|
388
364
|
this._setListeners(event, newListener);
|
|
389
|
-
|
|
390
365
|
return;
|
|
391
|
-
}
|
|
392
|
-
// 0 (high) to n > 0 (low)
|
|
393
|
-
|
|
366
|
+
}
|
|
394
367
|
|
|
368
|
+
// ensure we order listeners by priority from
|
|
369
|
+
// 0 (high) to n > 0 (low)
|
|
395
370
|
while (listener) {
|
|
396
371
|
if (listener.priority < newListener.priority) {
|
|
397
372
|
newListener.next = listener;
|
|
398
|
-
|
|
399
373
|
if (previousListener) {
|
|
400
374
|
previousListener.next = newListener;
|
|
401
375
|
} else {
|
|
402
376
|
this._setListeners(event, newListener);
|
|
403
377
|
}
|
|
404
|
-
|
|
405
378
|
return;
|
|
406
379
|
}
|
|
407
|
-
|
|
408
380
|
previousListener = listener;
|
|
409
381
|
listener = listener.next;
|
|
410
|
-
}
|
|
411
|
-
|
|
382
|
+
}
|
|
412
383
|
|
|
384
|
+
// add new listener to back
|
|
413
385
|
previousListener.next = newListener;
|
|
414
386
|
};
|
|
415
|
-
|
|
416
387
|
EventBus.prototype._getListeners = function (name) {
|
|
417
388
|
return this._listeners[name];
|
|
418
389
|
};
|
|
419
|
-
|
|
420
390
|
EventBus.prototype._setListeners = function (name, listener) {
|
|
421
391
|
this._listeners[name] = listener;
|
|
422
392
|
};
|
|
423
|
-
|
|
424
393
|
EventBus.prototype._removeListener = function (event, callback) {
|
|
425
394
|
var listener = this._getListeners(event),
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
395
|
+
nextListener,
|
|
396
|
+
previousListener,
|
|
397
|
+
listenerCallback;
|
|
430
398
|
if (!callback) {
|
|
431
399
|
// clear listeners
|
|
432
400
|
this._setListeners(event, null);
|
|
433
|
-
|
|
434
401
|
return;
|
|
435
402
|
}
|
|
436
|
-
|
|
437
403
|
while (listener) {
|
|
438
404
|
nextListener = listener.next;
|
|
439
405
|
listenerCallback = listener.callback;
|
|
440
|
-
|
|
441
406
|
if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
|
|
442
407
|
if (previousListener) {
|
|
443
408
|
previousListener.next = nextListener;
|
|
@@ -446,29 +411,25 @@ EventBus.prototype._removeListener = function (event, callback) {
|
|
|
446
411
|
this._setListeners(event, nextListener);
|
|
447
412
|
}
|
|
448
413
|
}
|
|
449
|
-
|
|
450
414
|
previousListener = listener;
|
|
451
415
|
listener = nextListener;
|
|
452
416
|
}
|
|
453
417
|
};
|
|
418
|
+
|
|
454
419
|
/**
|
|
455
420
|
* A event that is emitted via the event bus.
|
|
456
421
|
*/
|
|
457
|
-
|
|
458
|
-
|
|
459
422
|
function InternalEvent() {}
|
|
460
|
-
|
|
461
423
|
InternalEvent.prototype.stopPropagation = function () {
|
|
462
424
|
this.cancelBubble = true;
|
|
463
425
|
};
|
|
464
|
-
|
|
465
426
|
InternalEvent.prototype.preventDefault = function () {
|
|
466
427
|
this.defaultPrevented = true;
|
|
467
428
|
};
|
|
468
|
-
|
|
469
429
|
InternalEvent.prototype.init = function (data) {
|
|
470
430
|
assign(this, data || {});
|
|
471
431
|
};
|
|
432
|
+
|
|
472
433
|
/**
|
|
473
434
|
* Invoke function. Be fast...
|
|
474
435
|
*
|
|
@@ -477,50 +438,47 @@ InternalEvent.prototype.init = function (data) {
|
|
|
477
438
|
*
|
|
478
439
|
* @return {Any}
|
|
479
440
|
*/
|
|
480
|
-
|
|
481
|
-
|
|
482
441
|
function invokeFunction(fn, args) {
|
|
483
442
|
return fn.apply(null, args);
|
|
484
443
|
}
|
|
485
444
|
|
|
445
|
+
const EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
446
|
+
const PHONE_PATTERN = /(\+|00)(297|93|244|1264|358|355|376|971|54|374|1684|1268|61|43|994|257|32|229|226|880|359|973|1242|387|590|375|501|1441|591|55|1246|673|975|267|236|1|61|41|56|86|225|237|243|242|682|57|269|238|506|53|5999|61|1345|357|420|49|253|1767|45|1809|1829|1849|213|593|20|291|212|34|372|251|358|679|500|33|298|691|241|44|995|44|233|350|224|590|220|245|240|30|1473|299|502|594|1671|592|852|504|385|509|36|62|44|91|246|353|98|964|354|972|39|1876|44|962|81|76|77|254|996|855|686|1869|82|383|965|856|961|231|218|1758|423|94|266|370|352|371|853|590|212|377|373|261|960|52|692|389|223|356|95|382|976|1670|258|222|1664|596|230|265|60|262|264|687|227|672|234|505|683|31|47|977|674|64|968|92|507|64|51|63|680|675|48|1787|1939|850|351|595|970|689|974|262|40|7|250|966|249|221|65|500|4779|677|232|503|378|252|508|381|211|239|597|421|386|46|268|1721|248|963|1649|235|228|66|992|690|993|670|676|1868|216|90|688|886|255|256|380|598|1|998|3906698|379|1784|58|1284|1340|84|678|681|685|967|27|260|263)(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\d{4,20}$/;
|
|
486
447
|
class Validator {
|
|
487
448
|
validateField(field, value) {
|
|
488
449
|
const {
|
|
489
450
|
validate
|
|
490
451
|
} = field;
|
|
491
452
|
let errors = [];
|
|
492
|
-
|
|
493
453
|
if (!validate) {
|
|
494
454
|
return errors;
|
|
495
455
|
}
|
|
496
|
-
|
|
497
456
|
if (validate.pattern && value && !new RegExp(validate.pattern).test(value)) {
|
|
498
457
|
errors = [...errors, `Field must match pattern ${validate.pattern}.`];
|
|
499
458
|
}
|
|
500
|
-
|
|
501
459
|
if (validate.required && (isNil(value) || value === '')) {
|
|
502
460
|
errors = [...errors, 'Field is required.'];
|
|
503
461
|
}
|
|
504
|
-
|
|
505
462
|
if ('min' in validate && value && value < validate.min) {
|
|
506
463
|
errors = [...errors, `Field must have minimum value of ${validate.min}.`];
|
|
507
464
|
}
|
|
508
|
-
|
|
509
465
|
if ('max' in validate && value && value > validate.max) {
|
|
510
466
|
errors = [...errors, `Field must have maximum value of ${validate.max}.`];
|
|
511
467
|
}
|
|
512
|
-
|
|
513
468
|
if ('minLength' in validate && value && value.trim().length < validate.minLength) {
|
|
514
469
|
errors = [...errors, `Field must have minimum length of ${validate.minLength}.`];
|
|
515
470
|
}
|
|
516
|
-
|
|
517
471
|
if ('maxLength' in validate && value && value.trim().length > validate.maxLength) {
|
|
518
472
|
errors = [...errors, `Field must have maximum length of ${validate.maxLength}.`];
|
|
519
473
|
}
|
|
520
|
-
|
|
474
|
+
if ('validationType' in validate && value && validate.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
|
|
475
|
+
errors = [...errors, 'Field must be a valid international phone number. (e.g. +4930664040900)'];
|
|
476
|
+
}
|
|
477
|
+
if ('validationType' in validate && value && validate.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
|
|
478
|
+
errors = [...errors, 'Field must be a valid email.'];
|
|
479
|
+
}
|
|
521
480
|
return errors;
|
|
522
481
|
}
|
|
523
|
-
|
|
524
482
|
}
|
|
525
483
|
Validator.$inject = [];
|
|
526
484
|
|
|
@@ -532,59 +490,44 @@ class FormFieldRegistry {
|
|
|
532
490
|
this._ids = new Ids([32, 36, 1]);
|
|
533
491
|
this._keys = new Ids([32, 36, 1]);
|
|
534
492
|
}
|
|
535
|
-
|
|
536
493
|
add(formField) {
|
|
537
494
|
const {
|
|
538
495
|
id
|
|
539
496
|
} = formField;
|
|
540
|
-
|
|
541
497
|
if (this._formFields[id]) {
|
|
542
498
|
throw new Error(`form field with ID ${id} already exists`);
|
|
543
499
|
}
|
|
544
|
-
|
|
545
500
|
this._eventBus.fire('formField.add', {
|
|
546
501
|
formField
|
|
547
502
|
});
|
|
548
|
-
|
|
549
503
|
this._formFields[id] = formField;
|
|
550
504
|
}
|
|
551
|
-
|
|
552
505
|
remove(formField) {
|
|
553
506
|
const {
|
|
554
507
|
id
|
|
555
508
|
} = formField;
|
|
556
|
-
|
|
557
509
|
if (!this._formFields[id]) {
|
|
558
510
|
return;
|
|
559
511
|
}
|
|
560
|
-
|
|
561
512
|
this._eventBus.fire('formField.remove', {
|
|
562
513
|
formField
|
|
563
514
|
});
|
|
564
|
-
|
|
565
515
|
delete this._formFields[id];
|
|
566
516
|
}
|
|
567
|
-
|
|
568
517
|
get(id) {
|
|
569
518
|
return this._formFields[id];
|
|
570
519
|
}
|
|
571
|
-
|
|
572
520
|
getAll() {
|
|
573
521
|
return Object.values(this._formFields);
|
|
574
522
|
}
|
|
575
|
-
|
|
576
523
|
forEach(callback) {
|
|
577
524
|
this.getAll().forEach(formField => callback(formField));
|
|
578
525
|
}
|
|
579
|
-
|
|
580
526
|
clear() {
|
|
581
527
|
this._formFields = {};
|
|
582
|
-
|
|
583
528
|
this._ids.clear();
|
|
584
|
-
|
|
585
529
|
this._keys.clear();
|
|
586
530
|
}
|
|
587
|
-
|
|
588
531
|
}
|
|
589
532
|
FormFieldRegistry.$inject = ['eventBus'];
|
|
590
533
|
|
|
@@ -615,7 +558,6 @@ function pathParse(path) {
|
|
|
615
558
|
if (!path) {
|
|
616
559
|
return [];
|
|
617
560
|
}
|
|
618
|
-
|
|
619
561
|
return path.split('.').map(key => {
|
|
620
562
|
return isNaN(parseInt(key)) ? key : parseInt(key);
|
|
621
563
|
});
|
|
@@ -627,7 +569,6 @@ function pathStringify(path) {
|
|
|
627
569
|
if (!path) {
|
|
628
570
|
return '';
|
|
629
571
|
}
|
|
630
|
-
|
|
631
572
|
return path.join('.');
|
|
632
573
|
}
|
|
633
574
|
const indices = {};
|
|
@@ -637,22 +578,22 @@ function generateIndexForType(type) {
|
|
|
637
578
|
} else {
|
|
638
579
|
indices[type] = 1;
|
|
639
580
|
}
|
|
640
|
-
|
|
641
581
|
return indices[type];
|
|
642
582
|
}
|
|
643
583
|
function generateIdForType(type) {
|
|
644
584
|
return `${type}${generateIndexForType(type)}`;
|
|
645
585
|
}
|
|
586
|
+
|
|
646
587
|
/**
|
|
647
588
|
* @template T
|
|
648
589
|
* @param {T} data
|
|
649
590
|
* @param {(this: any, key: string, value: any) => any} [replacer]
|
|
650
591
|
* @return {T}
|
|
651
592
|
*/
|
|
652
|
-
|
|
653
593
|
function clone(data, replacer) {
|
|
654
594
|
return JSON.parse(JSON.stringify(data, replacer));
|
|
655
595
|
}
|
|
596
|
+
|
|
656
597
|
/**
|
|
657
598
|
* Parse the schema for input variables a form might make use of
|
|
658
599
|
*
|
|
@@ -665,26 +606,21 @@ function getSchemaVariables(schema) {
|
|
|
665
606
|
if (!schema.components) {
|
|
666
607
|
return [];
|
|
667
608
|
}
|
|
668
|
-
|
|
669
609
|
return schema.components.reduce((variables, component) => {
|
|
670
610
|
const {
|
|
671
611
|
key,
|
|
672
612
|
valuesKey,
|
|
673
613
|
type
|
|
674
614
|
} = component;
|
|
675
|
-
|
|
676
615
|
if (['text', 'button'].includes(type)) {
|
|
677
616
|
return variables;
|
|
678
617
|
}
|
|
679
|
-
|
|
680
618
|
if (key) {
|
|
681
619
|
variables = [...variables, key];
|
|
682
620
|
}
|
|
683
|
-
|
|
684
621
|
if (valuesKey && !variables.includes(valuesKey)) {
|
|
685
622
|
variables = [...variables, valuesKey];
|
|
686
623
|
}
|
|
687
|
-
|
|
688
624
|
return variables;
|
|
689
625
|
}, []);
|
|
690
626
|
}
|
|
@@ -699,6 +635,7 @@ class Importer {
|
|
|
699
635
|
this._formFieldRegistry = formFieldRegistry;
|
|
700
636
|
this._formFields = formFields;
|
|
701
637
|
}
|
|
638
|
+
|
|
702
639
|
/**
|
|
703
640
|
* Import schema adding `id`, `_parent` and `_path`
|
|
704
641
|
* information to each field and adding it to the
|
|
@@ -709,15 +646,12 @@ class Importer {
|
|
|
709
646
|
*
|
|
710
647
|
* @return { { warnings: Array<any>, schema: any, data: any } }
|
|
711
648
|
*/
|
|
712
|
-
|
|
713
|
-
|
|
714
649
|
importSchema(schema, data = {}) {
|
|
715
650
|
// TODO: Add warnings - https://github.com/bpmn-io/form-js/issues/289
|
|
716
651
|
const warnings = [];
|
|
717
|
-
|
|
718
652
|
try {
|
|
719
653
|
const importedSchema = this.importFormField(clone(schema)),
|
|
720
|
-
|
|
654
|
+
importedData = this.importData(clone(data));
|
|
721
655
|
return {
|
|
722
656
|
warnings,
|
|
723
657
|
schema: importedSchema,
|
|
@@ -728,14 +662,13 @@ class Importer {
|
|
|
728
662
|
throw err;
|
|
729
663
|
}
|
|
730
664
|
}
|
|
665
|
+
|
|
731
666
|
/**
|
|
732
667
|
* @param {any} formField
|
|
733
668
|
* @param {string} [parentId]
|
|
734
669
|
*
|
|
735
670
|
* @return {any} importedField
|
|
736
671
|
*/
|
|
737
|
-
|
|
738
|
-
|
|
739
672
|
importFormField(formField, parentId) {
|
|
740
673
|
const {
|
|
741
674
|
components,
|
|
@@ -743,64 +676,53 @@ class Importer {
|
|
|
743
676
|
type,
|
|
744
677
|
id = generateIdForType(type)
|
|
745
678
|
} = formField;
|
|
746
|
-
|
|
747
679
|
if (parentId) {
|
|
748
680
|
// set form field parent
|
|
749
681
|
formField._parent = parentId;
|
|
750
682
|
}
|
|
751
|
-
|
|
752
683
|
if (!this._formFields.get(type)) {
|
|
753
684
|
throw new Error(`form field of type <${type}> not supported`);
|
|
754
685
|
}
|
|
755
|
-
|
|
756
686
|
if (key) {
|
|
757
687
|
// validate <key> uniqueness
|
|
758
688
|
if (this._formFieldRegistry._keys.assigned(key)) {
|
|
759
689
|
throw new Error(`form field with key <${key}> already exists`);
|
|
760
690
|
}
|
|
691
|
+
this._formFieldRegistry._keys.claim(key, formField);
|
|
761
692
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
693
|
+
// TODO: buttons should not have key
|
|
765
694
|
if (type !== 'button') {
|
|
766
695
|
// set form field path
|
|
767
696
|
formField._path = [key];
|
|
768
697
|
}
|
|
769
698
|
}
|
|
770
|
-
|
|
771
699
|
if (id) {
|
|
772
700
|
// validate <id> uniqueness
|
|
773
701
|
if (this._formFieldRegistry._ids.assigned(id)) {
|
|
774
702
|
throw new Error(`form field with id <${id}> already exists`);
|
|
775
703
|
}
|
|
776
|
-
|
|
777
704
|
this._formFieldRegistry._ids.claim(id, formField);
|
|
778
|
-
}
|
|
779
|
-
|
|
705
|
+
}
|
|
780
706
|
|
|
707
|
+
// set form field ID
|
|
781
708
|
formField.id = id;
|
|
782
|
-
|
|
783
709
|
this._formFieldRegistry.add(formField);
|
|
784
|
-
|
|
785
710
|
if (components) {
|
|
786
711
|
this.importFormFields(components, id);
|
|
787
712
|
}
|
|
788
|
-
|
|
789
713
|
return formField;
|
|
790
714
|
}
|
|
791
|
-
|
|
792
715
|
importFormFields(components, parentId) {
|
|
793
716
|
components.forEach(component => {
|
|
794
717
|
this.importFormField(component, parentId);
|
|
795
718
|
});
|
|
796
719
|
}
|
|
720
|
+
|
|
797
721
|
/**
|
|
798
722
|
* @param {Object} data
|
|
799
723
|
*
|
|
800
724
|
* @return {Object} importedData
|
|
801
725
|
*/
|
|
802
|
-
|
|
803
|
-
|
|
804
726
|
importData(data) {
|
|
805
727
|
return this._formFieldRegistry.getAll().reduce((importedData, formField) => {
|
|
806
728
|
const {
|
|
@@ -808,22 +730,24 @@ class Importer {
|
|
|
808
730
|
_path,
|
|
809
731
|
type,
|
|
810
732
|
valuesKey
|
|
811
|
-
} = formField;
|
|
733
|
+
} = formField;
|
|
734
|
+
|
|
735
|
+
// get values defined via valuesKey
|
|
812
736
|
|
|
813
737
|
if (valuesKey) {
|
|
814
|
-
importedData = {
|
|
738
|
+
importedData = {
|
|
739
|
+
...importedData,
|
|
815
740
|
[valuesKey]: get(data, [valuesKey])
|
|
816
741
|
};
|
|
817
|
-
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// try to get value from data
|
|
818
745
|
// if unavailable - try to get default value from form field
|
|
819
746
|
// if unavailable - get empty value from form field
|
|
820
747
|
|
|
821
|
-
|
|
822
748
|
if (_path) {
|
|
823
749
|
const fieldImplementation = this._formFields.get(type);
|
|
824
|
-
|
|
825
750
|
let valueData = get(data, _path);
|
|
826
|
-
|
|
827
751
|
if (!isUndefined(valueData) && fieldImplementation.sanitizeValue) {
|
|
828
752
|
valueData = fieldImplementation.sanitizeValue({
|
|
829
753
|
formField,
|
|
@@ -831,17 +755,15 @@ class Importer {
|
|
|
831
755
|
value: valueData
|
|
832
756
|
});
|
|
833
757
|
}
|
|
834
|
-
|
|
835
758
|
const initialFieldValue = !isUndefined(valueData) ? valueData : !isUndefined(defaultValue) ? defaultValue : fieldImplementation.emptyValue;
|
|
836
|
-
importedData = {
|
|
759
|
+
importedData = {
|
|
760
|
+
...importedData,
|
|
837
761
|
[_path[0]]: initialFieldValue
|
|
838
762
|
};
|
|
839
763
|
}
|
|
840
|
-
|
|
841
764
|
return importedData;
|
|
842
765
|
}, {});
|
|
843
766
|
}
|
|
844
|
-
|
|
845
767
|
}
|
|
846
768
|
Importer.$inject = ['formFieldRegistry', 'formFields'];
|
|
847
769
|
|
|
@@ -850,30 +772,26 @@ var importModule = {
|
|
|
850
772
|
};
|
|
851
773
|
|
|
852
774
|
const NODE_TYPE_TEXT = 3,
|
|
853
|
-
|
|
775
|
+
NODE_TYPE_ELEMENT = 1;
|
|
854
776
|
const ALLOWED_NODES = ['h1', 'h2', 'h3', 'h4', 'h5', 'span', 'em', 'a', 'p', 'div', 'ul', 'ol', 'li', 'hr', 'blockquote', 'img', 'pre', 'code', 'br', 'strong'];
|
|
855
777
|
const ALLOWED_ATTRIBUTES = ['align', 'alt', 'class', 'href', 'id', 'name', 'rel', 'target', 'src'];
|
|
856
778
|
const ALLOWED_URI_PATTERN = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i; // eslint-disable-line no-useless-escape
|
|
857
|
-
|
|
858
779
|
const ATTR_WHITESPACE_PATTERN = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g; // eslint-disable-line no-control-regex
|
|
859
780
|
|
|
860
781
|
const FORM_ELEMENT = document.createElement('form');
|
|
782
|
+
|
|
861
783
|
/**
|
|
862
784
|
* Sanitize a HTML string and return the cleaned, safe version.
|
|
863
785
|
*
|
|
864
786
|
* @param {string} html
|
|
865
787
|
* @return {string}
|
|
866
788
|
*/
|
|
867
|
-
|
|
868
789
|
function sanitizeHTML(html) {
|
|
869
790
|
const doc = new DOMParser().parseFromString(`<!DOCTYPE html>\n<html><body><div>${html}`, 'text/html');
|
|
870
791
|
doc.normalize();
|
|
871
792
|
const element = doc.body.firstChild;
|
|
872
|
-
|
|
873
793
|
if (element) {
|
|
874
|
-
sanitizeNode(
|
|
875
|
-
/** @type Element */
|
|
876
|
-
element);
|
|
794
|
+
sanitizeNode( /** @type Element */element);
|
|
877
795
|
return new XMLSerializer().serializeToString(element);
|
|
878
796
|
} else {
|
|
879
797
|
// handle the case that document parsing
|
|
@@ -881,6 +799,7 @@ function sanitizeHTML(html) {
|
|
|
881
799
|
return '';
|
|
882
800
|
}
|
|
883
801
|
}
|
|
802
|
+
|
|
884
803
|
/**
|
|
885
804
|
* Recursively sanitize a HTML node, potentially
|
|
886
805
|
* removing it, its children or attributes.
|
|
@@ -891,51 +810,48 @@ function sanitizeHTML(html) {
|
|
|
891
810
|
*
|
|
892
811
|
* @param {Element} node
|
|
893
812
|
*/
|
|
894
|
-
|
|
895
813
|
function sanitizeNode(node) {
|
|
896
814
|
// allow text nodes
|
|
897
815
|
if (node.nodeType === NODE_TYPE_TEXT) {
|
|
898
816
|
return;
|
|
899
|
-
}
|
|
900
|
-
|
|
817
|
+
}
|
|
901
818
|
|
|
819
|
+
// disallow all other nodes but Element
|
|
902
820
|
if (node.nodeType !== NODE_TYPE_ELEMENT) {
|
|
903
821
|
return node.remove();
|
|
904
822
|
}
|
|
823
|
+
const lcTag = node.tagName.toLowerCase();
|
|
905
824
|
|
|
906
|
-
|
|
907
|
-
|
|
825
|
+
// disallow non-whitelisted tags
|
|
908
826
|
if (!ALLOWED_NODES.includes(lcTag)) {
|
|
909
827
|
return node.remove();
|
|
910
828
|
}
|
|
829
|
+
const attributes = node.attributes;
|
|
911
830
|
|
|
912
|
-
|
|
913
|
-
|
|
831
|
+
// clean attributes
|
|
914
832
|
for (let i = attributes.length; i--;) {
|
|
915
833
|
const attribute = attributes[i];
|
|
916
834
|
const name = attribute.name;
|
|
917
|
-
const lcName = name.toLowerCase();
|
|
835
|
+
const lcName = name.toLowerCase();
|
|
918
836
|
|
|
837
|
+
// normalize node value
|
|
919
838
|
const value = attribute.value.trim();
|
|
920
839
|
node.removeAttribute(name);
|
|
921
840
|
const valid = isValidAttribute(lcTag, lcName, value);
|
|
922
|
-
|
|
923
841
|
if (valid) {
|
|
924
842
|
node.setAttribute(name, value);
|
|
925
843
|
}
|
|
926
|
-
}
|
|
927
|
-
|
|
844
|
+
}
|
|
928
845
|
|
|
846
|
+
// force noopener on target="_blank" links
|
|
929
847
|
if (lcTag === 'a' && node.getAttribute('target') === '_blank' && node.getAttribute('rel') !== 'noopener') {
|
|
930
848
|
node.setAttribute('rel', 'noopener');
|
|
931
849
|
}
|
|
932
|
-
|
|
933
850
|
for (let i = node.childNodes.length; i--;) {
|
|
934
|
-
sanitizeNode(
|
|
935
|
-
/** @type Element */
|
|
936
|
-
node.childNodes[i]);
|
|
851
|
+
sanitizeNode( /** @type Element */node.childNodes[i]);
|
|
937
852
|
}
|
|
938
853
|
}
|
|
854
|
+
|
|
939
855
|
/**
|
|
940
856
|
* Validates attributes for validity.
|
|
941
857
|
*
|
|
@@ -944,56 +860,51 @@ function sanitizeNode(node) {
|
|
|
944
860
|
* @param {string} value
|
|
945
861
|
* @return {boolean}
|
|
946
862
|
*/
|
|
947
|
-
|
|
948
|
-
|
|
949
863
|
function isValidAttribute(lcTag, lcName, value) {
|
|
950
864
|
// disallow most attributes based on whitelist
|
|
951
865
|
if (!ALLOWED_ATTRIBUTES.includes(lcName)) {
|
|
952
866
|
return false;
|
|
953
|
-
}
|
|
954
|
-
|
|
867
|
+
}
|
|
955
868
|
|
|
869
|
+
// disallow "DOM clobbering" / polution of document and wrapping form elements
|
|
956
870
|
if ((lcName === 'id' || lcName === 'name') && (value in document || value in FORM_ELEMENT)) {
|
|
957
871
|
return false;
|
|
958
872
|
}
|
|
959
|
-
|
|
960
873
|
if (lcName === 'target' && value !== '_blank') {
|
|
961
874
|
return false;
|
|
962
|
-
}
|
|
963
|
-
|
|
875
|
+
}
|
|
964
876
|
|
|
877
|
+
// allow valid url links only
|
|
965
878
|
if (lcName === 'href' && !ALLOWED_URI_PATTERN.test(value.replace(ATTR_WHITESPACE_PATTERN, ''))) {
|
|
966
879
|
return false;
|
|
967
880
|
}
|
|
968
|
-
|
|
969
881
|
return true;
|
|
970
882
|
}
|
|
971
883
|
|
|
972
|
-
function formFieldClasses(type,
|
|
884
|
+
function formFieldClasses(type, {
|
|
885
|
+
errors = [],
|
|
886
|
+
disabled = false
|
|
887
|
+
} = {}) {
|
|
973
888
|
if (!type) {
|
|
974
889
|
throw new Error('type required');
|
|
975
890
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
classes.push('fjs-has-errors');
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
return classes.join(' ');
|
|
891
|
+
return classNames('fjs-form-field', `fjs-form-field-${type}`, {
|
|
892
|
+
'fjs-has-errors': errors.length > 0,
|
|
893
|
+
'fjs-disabled': disabled
|
|
894
|
+
});
|
|
984
895
|
}
|
|
985
896
|
function prefixId(id, formId) {
|
|
986
897
|
if (formId) {
|
|
987
898
|
return `fjs-form-${formId}-${id}`;
|
|
988
899
|
}
|
|
989
|
-
|
|
990
900
|
return `fjs-form-${id}`;
|
|
991
901
|
}
|
|
992
902
|
function markdownToHTML(markdown) {
|
|
993
903
|
const htmls = markdown.split(/(?:\r?\n){2,}/).map(line => /^((\d+.)|[><\s#-*])/.test(line) ? snarkdown(line) : `<p>${snarkdown(line)}</p>`);
|
|
994
904
|
return htmls.join('\n\n');
|
|
995
|
-
}
|
|
905
|
+
}
|
|
996
906
|
|
|
907
|
+
// see https://github.com/developit/snarkdown/issues/70
|
|
997
908
|
function safeMarkdown(markdown) {
|
|
998
909
|
const html = markdownToHTML(markdown);
|
|
999
910
|
return sanitizeHTML(html);
|
|
@@ -1008,7 +919,6 @@ function sanitizeSingleSelectValue(options) {
|
|
|
1008
919
|
valuesKey,
|
|
1009
920
|
values
|
|
1010
921
|
} = formField;
|
|
1011
|
-
|
|
1012
922
|
try {
|
|
1013
923
|
const validValues = (valuesKey ? get(data, [valuesKey]) : values).map(v => v.value) || [];
|
|
1014
924
|
return validValues.includes(value) ? value : null;
|
|
@@ -1028,7 +938,6 @@ function sanitizeMultiSelectValue(options) {
|
|
|
1028
938
|
valuesKey,
|
|
1029
939
|
values
|
|
1030
940
|
} = formField;
|
|
1031
|
-
|
|
1032
941
|
try {
|
|
1033
942
|
const validValues = (valuesKey ? get(data, [valuesKey]) : values).map(v => v.value) || [];
|
|
1034
943
|
return value.filter(v => validValues.includes(v));
|
|
@@ -1039,7 +948,7 @@ function sanitizeMultiSelectValue(options) {
|
|
|
1039
948
|
}
|
|
1040
949
|
}
|
|
1041
950
|
|
|
1042
|
-
const type$
|
|
951
|
+
const type$9 = 'button';
|
|
1043
952
|
function Button(props) {
|
|
1044
953
|
const {
|
|
1045
954
|
disabled,
|
|
@@ -1049,7 +958,7 @@ function Button(props) {
|
|
|
1049
958
|
action = 'submit'
|
|
1050
959
|
} = field;
|
|
1051
960
|
return jsx("div", {
|
|
1052
|
-
class: formFieldClasses(type$
|
|
961
|
+
class: formFieldClasses(type$9),
|
|
1053
962
|
children: jsx("button", {
|
|
1054
963
|
class: "fjs-button",
|
|
1055
964
|
type: action,
|
|
@@ -1058,15 +967,13 @@ function Button(props) {
|
|
|
1058
967
|
})
|
|
1059
968
|
});
|
|
1060
969
|
}
|
|
1061
|
-
|
|
1062
970
|
Button.create = function (options = {}) {
|
|
1063
971
|
return {
|
|
1064
972
|
action: 'submit',
|
|
1065
973
|
...options
|
|
1066
974
|
};
|
|
1067
975
|
};
|
|
1068
|
-
|
|
1069
|
-
Button.type = type$8;
|
|
976
|
+
Button.type = type$9;
|
|
1070
977
|
Button.label = 'Button';
|
|
1071
978
|
Button.keyed = true;
|
|
1072
979
|
|
|
@@ -1088,9 +995,7 @@ const FormRenderContext = createContext({
|
|
|
1088
995
|
*
|
|
1089
996
|
* @returns {any}
|
|
1090
997
|
*/
|
|
1091
|
-
|
|
1092
998
|
function getService(type, strict) {}
|
|
1093
|
-
|
|
1094
999
|
const FormContext = createContext({
|
|
1095
1000
|
getService,
|
|
1096
1001
|
formId: null
|
|
@@ -1100,11 +1005,9 @@ function Description(props) {
|
|
|
1100
1005
|
const {
|
|
1101
1006
|
description
|
|
1102
1007
|
} = props;
|
|
1103
|
-
|
|
1104
1008
|
if (!description) {
|
|
1105
1009
|
return null;
|
|
1106
1010
|
}
|
|
1107
|
-
|
|
1108
1011
|
return jsx("div", {
|
|
1109
1012
|
class: "fjs-form-field-description",
|
|
1110
1013
|
children: description
|
|
@@ -1115,11 +1018,9 @@ function Errors(props) {
|
|
|
1115
1018
|
const {
|
|
1116
1019
|
errors
|
|
1117
1020
|
} = props;
|
|
1118
|
-
|
|
1119
1021
|
if (!errors.length) {
|
|
1120
1022
|
return null;
|
|
1121
1023
|
}
|
|
1122
|
-
|
|
1123
1024
|
return jsx("div", {
|
|
1124
1025
|
class: "fjs-form-field-error",
|
|
1125
1026
|
children: jsx("ul", {
|
|
@@ -1140,7 +1041,7 @@ function Label(props) {
|
|
|
1140
1041
|
} = props;
|
|
1141
1042
|
return jsxs("label", {
|
|
1142
1043
|
for: id,
|
|
1143
|
-
class:
|
|
1044
|
+
class: classNames('fjs-form-field-label', props['class']),
|
|
1144
1045
|
children: [props.children, label || '', required && jsx("span", {
|
|
1145
1046
|
class: "fjs-asterix",
|
|
1146
1047
|
children: "*"
|
|
@@ -1148,7 +1049,7 @@ function Label(props) {
|
|
|
1148
1049
|
});
|
|
1149
1050
|
}
|
|
1150
1051
|
|
|
1151
|
-
const type$
|
|
1052
|
+
const type$8 = 'checkbox';
|
|
1152
1053
|
function Checkbox(props) {
|
|
1153
1054
|
const {
|
|
1154
1055
|
disabled,
|
|
@@ -1161,7 +1062,6 @@ function Checkbox(props) {
|
|
|
1161
1062
|
id,
|
|
1162
1063
|
label
|
|
1163
1064
|
} = field;
|
|
1164
|
-
|
|
1165
1065
|
const onChange = ({
|
|
1166
1066
|
target
|
|
1167
1067
|
}) => {
|
|
@@ -1170,12 +1070,16 @@ function Checkbox(props) {
|
|
|
1170
1070
|
value: target.checked
|
|
1171
1071
|
});
|
|
1172
1072
|
};
|
|
1173
|
-
|
|
1174
1073
|
const {
|
|
1175
1074
|
formId
|
|
1176
1075
|
} = useContext(FormContext);
|
|
1177
1076
|
return jsxs("div", {
|
|
1178
|
-
class: formFieldClasses(type$
|
|
1077
|
+
class: classNames(formFieldClasses(type$8, {
|
|
1078
|
+
errors,
|
|
1079
|
+
disabled
|
|
1080
|
+
}), {
|
|
1081
|
+
'fjs-checked': value
|
|
1082
|
+
}),
|
|
1179
1083
|
children: [jsx(Label, {
|
|
1180
1084
|
id: prefixId(id, formId),
|
|
1181
1085
|
label: label,
|
|
@@ -1195,17 +1099,15 @@ function Checkbox(props) {
|
|
|
1195
1099
|
})]
|
|
1196
1100
|
});
|
|
1197
1101
|
}
|
|
1198
|
-
|
|
1199
1102
|
Checkbox.create = function (options = {}) {
|
|
1200
|
-
return {
|
|
1103
|
+
return {
|
|
1104
|
+
...options
|
|
1201
1105
|
};
|
|
1202
1106
|
};
|
|
1203
|
-
|
|
1204
|
-
Checkbox.type = type$7;
|
|
1107
|
+
Checkbox.type = type$8;
|
|
1205
1108
|
Checkbox.label = 'Checkbox';
|
|
1206
1109
|
Checkbox.keyed = true;
|
|
1207
1110
|
Checkbox.emptyValue = false;
|
|
1208
|
-
|
|
1209
1111
|
Checkbox.sanitizeValue = ({
|
|
1210
1112
|
value
|
|
1211
1113
|
}) => value === true;
|
|
@@ -1220,12 +1122,12 @@ function useService (type, strict) {
|
|
|
1220
1122
|
/**
|
|
1221
1123
|
* @enum { String }
|
|
1222
1124
|
*/
|
|
1223
|
-
|
|
1224
1125
|
const LOAD_STATES = {
|
|
1225
1126
|
LOADING: 'loading',
|
|
1226
1127
|
LOADED: 'loaded',
|
|
1227
1128
|
ERROR: 'error'
|
|
1228
1129
|
};
|
|
1130
|
+
|
|
1229
1131
|
/**
|
|
1230
1132
|
* @typedef {Object} ValuesGetter
|
|
1231
1133
|
* @property {Object[]} values - The values data
|
|
@@ -1238,7 +1140,6 @@ const LOAD_STATES = {
|
|
|
1238
1140
|
* @param {Object} field - The form field to handle values for
|
|
1239
1141
|
* @return {ValuesGetter} valuesGetter - A values getter object providing loading state and values
|
|
1240
1142
|
*/
|
|
1241
|
-
|
|
1242
1143
|
function useValuesAsync (field) {
|
|
1243
1144
|
const {
|
|
1244
1145
|
valuesKey,
|
|
@@ -1249,15 +1150,11 @@ function useValuesAsync (field) {
|
|
|
1249
1150
|
error: undefined,
|
|
1250
1151
|
state: LOAD_STATES.LOADING
|
|
1251
1152
|
});
|
|
1252
|
-
|
|
1253
1153
|
const initialData = useService('form')._getState().initialData;
|
|
1254
|
-
|
|
1255
1154
|
useEffect(() => {
|
|
1256
1155
|
let values = [];
|
|
1257
|
-
|
|
1258
1156
|
if (valuesKey !== undefined) {
|
|
1259
1157
|
const keyedValues = (initialData || {})[valuesKey];
|
|
1260
|
-
|
|
1261
1158
|
if (keyedValues && Array.isArray(keyedValues)) {
|
|
1262
1159
|
values = keyedValues;
|
|
1263
1160
|
}
|
|
@@ -1267,25 +1164,22 @@ function useValuesAsync (field) {
|
|
|
1267
1164
|
setValuesGetter(getErrorState('No values source defined in the form definition'));
|
|
1268
1165
|
return;
|
|
1269
1166
|
}
|
|
1270
|
-
|
|
1271
1167
|
setValuesGetter(buildLoadedState(values));
|
|
1272
1168
|
}, [valuesKey, staticValues, initialData]);
|
|
1273
1169
|
return valuesGetter;
|
|
1274
1170
|
}
|
|
1275
|
-
|
|
1276
1171
|
const getErrorState = error => ({
|
|
1277
1172
|
values: [],
|
|
1278
1173
|
error,
|
|
1279
1174
|
state: LOAD_STATES.ERROR
|
|
1280
1175
|
});
|
|
1281
|
-
|
|
1282
1176
|
const buildLoadedState = values => ({
|
|
1283
1177
|
values,
|
|
1284
1178
|
error: undefined,
|
|
1285
1179
|
state: LOAD_STATES.LOADED
|
|
1286
1180
|
});
|
|
1287
1181
|
|
|
1288
|
-
const type$
|
|
1182
|
+
const type$7 = 'checklist';
|
|
1289
1183
|
function Checklist(props) {
|
|
1290
1184
|
const {
|
|
1291
1185
|
disabled,
|
|
@@ -1298,22 +1192,18 @@ function Checklist(props) {
|
|
|
1298
1192
|
id,
|
|
1299
1193
|
label
|
|
1300
1194
|
} = field;
|
|
1301
|
-
|
|
1302
1195
|
const toggleCheckbox = v => {
|
|
1303
1196
|
let newValue = [...value];
|
|
1304
|
-
|
|
1305
1197
|
if (!newValue.includes(v)) {
|
|
1306
1198
|
newValue.push(v);
|
|
1307
1199
|
} else {
|
|
1308
1200
|
newValue = newValue.filter(x => x != v);
|
|
1309
1201
|
}
|
|
1310
|
-
|
|
1311
1202
|
props.onChange({
|
|
1312
1203
|
field,
|
|
1313
1204
|
value: newValue
|
|
1314
1205
|
});
|
|
1315
1206
|
};
|
|
1316
|
-
|
|
1317
1207
|
const {
|
|
1318
1208
|
state: loadState,
|
|
1319
1209
|
values: options
|
|
@@ -1322,13 +1212,19 @@ function Checklist(props) {
|
|
|
1322
1212
|
formId
|
|
1323
1213
|
} = useContext(FormContext);
|
|
1324
1214
|
return jsxs("div", {
|
|
1325
|
-
class: formFieldClasses(type$
|
|
1215
|
+
class: classNames(formFieldClasses(type$7, {
|
|
1216
|
+
errors,
|
|
1217
|
+
disabled
|
|
1218
|
+
})),
|
|
1326
1219
|
children: [jsx(Label, {
|
|
1327
1220
|
label: label
|
|
1328
1221
|
}), loadState == LOAD_STATES.LOADED && options.map((v, index) => {
|
|
1329
1222
|
return jsx(Label, {
|
|
1330
1223
|
id: prefixId(`${id}-${index}`, formId),
|
|
1331
1224
|
label: v.label,
|
|
1225
|
+
class: classNames({
|
|
1226
|
+
'fjs-checked': value.includes(v.value)
|
|
1227
|
+
}),
|
|
1332
1228
|
required: false,
|
|
1333
1229
|
children: jsx("input", {
|
|
1334
1230
|
checked: value.includes(v.value),
|
|
@@ -1346,7 +1242,6 @@ function Checklist(props) {
|
|
|
1346
1242
|
})]
|
|
1347
1243
|
});
|
|
1348
1244
|
}
|
|
1349
|
-
|
|
1350
1245
|
Checklist.create = function (options = {}) {
|
|
1351
1246
|
if (options.valuesKey) return options;
|
|
1352
1247
|
return {
|
|
@@ -1357,15 +1252,13 @@ Checklist.create = function (options = {}) {
|
|
|
1357
1252
|
...options
|
|
1358
1253
|
};
|
|
1359
1254
|
};
|
|
1360
|
-
|
|
1361
|
-
Checklist.type = type$6;
|
|
1255
|
+
Checklist.type = type$7;
|
|
1362
1256
|
Checklist.label = 'Checklist';
|
|
1363
1257
|
Checklist.keyed = true;
|
|
1364
1258
|
Checklist.emptyValue = [];
|
|
1365
1259
|
Checklist.sanitizeValue = sanitizeMultiSelectValue;
|
|
1366
1260
|
|
|
1367
1261
|
const noop$1 = () => false;
|
|
1368
|
-
|
|
1369
1262
|
function FormField(props) {
|
|
1370
1263
|
const {
|
|
1371
1264
|
field,
|
|
@@ -1375,29 +1268,26 @@ function FormField(props) {
|
|
|
1375
1268
|
_path
|
|
1376
1269
|
} = field;
|
|
1377
1270
|
const formFields = useService('formFields'),
|
|
1378
|
-
|
|
1379
|
-
|
|
1271
|
+
form = useService('form');
|
|
1380
1272
|
const {
|
|
1381
1273
|
data,
|
|
1382
1274
|
errors,
|
|
1383
1275
|
properties
|
|
1384
1276
|
} = form._getState();
|
|
1385
|
-
|
|
1386
1277
|
const {
|
|
1387
1278
|
Element
|
|
1388
1279
|
} = useContext(FormRenderContext);
|
|
1389
1280
|
const FormFieldComponent = formFields.get(field.type);
|
|
1390
|
-
|
|
1391
1281
|
if (!FormFieldComponent) {
|
|
1392
1282
|
throw new Error(`cannot render field <${field.type}>`);
|
|
1393
1283
|
}
|
|
1394
|
-
|
|
1395
1284
|
const value = get(data, _path);
|
|
1396
1285
|
const fieldErrors = findErrors(errors, _path);
|
|
1397
1286
|
const disabled = properties.readOnly || field.disabled || false;
|
|
1398
1287
|
return jsx(Element, {
|
|
1399
1288
|
field: field,
|
|
1400
|
-
children: jsx(FormFieldComponent, {
|
|
1289
|
+
children: jsx(FormFieldComponent, {
|
|
1290
|
+
...props,
|
|
1401
1291
|
disabled: disabled,
|
|
1402
1292
|
errors: fieldErrors,
|
|
1403
1293
|
onChange: disabled ? noop$1 : onChange,
|
|
@@ -1421,21 +1311,20 @@ function Default(props) {
|
|
|
1421
1311
|
class: "fjs-vertical-layout",
|
|
1422
1312
|
field: field,
|
|
1423
1313
|
children: [components.map(childField => {
|
|
1424
|
-
return createElement(FormField, {
|
|
1314
|
+
return createElement(FormField, {
|
|
1315
|
+
...props,
|
|
1425
1316
|
key: childField.id,
|
|
1426
1317
|
field: childField
|
|
1427
1318
|
});
|
|
1428
1319
|
}), components.length ? null : jsx(Empty, {})]
|
|
1429
1320
|
});
|
|
1430
1321
|
}
|
|
1431
|
-
|
|
1432
1322
|
Default.create = function (options = {}) {
|
|
1433
1323
|
return {
|
|
1434
1324
|
components: [],
|
|
1435
1325
|
...options
|
|
1436
1326
|
};
|
|
1437
1327
|
};
|
|
1438
|
-
|
|
1439
1328
|
Default.type = 'default';
|
|
1440
1329
|
Default.keyed = false;
|
|
1441
1330
|
|
|
@@ -1444,7 +1333,6 @@ Default.keyed = false;
|
|
|
1444
1333
|
*
|
|
1445
1334
|
* @see http://bpmn.io/license for more information.
|
|
1446
1335
|
*/
|
|
1447
|
-
|
|
1448
1336
|
function Logo() {
|
|
1449
1337
|
return jsxs("svg", {
|
|
1450
1338
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -1461,16 +1349,13 @@ function Logo() {
|
|
|
1461
1349
|
})]
|
|
1462
1350
|
});
|
|
1463
1351
|
}
|
|
1464
|
-
|
|
1465
1352
|
function Lightbox(props) {
|
|
1466
1353
|
const {
|
|
1467
1354
|
open
|
|
1468
1355
|
} = props;
|
|
1469
|
-
|
|
1470
1356
|
if (!open) {
|
|
1471
1357
|
return null;
|
|
1472
1358
|
}
|
|
1473
|
-
|
|
1474
1359
|
return jsxs("div", {
|
|
1475
1360
|
class: "fjs-powered-by-lightbox",
|
|
1476
1361
|
style: "z-index: 100; position: fixed; top: 0; left: 0;right: 0; bottom: 0",
|
|
@@ -1498,7 +1383,6 @@ function Lightbox(props) {
|
|
|
1498
1383
|
})]
|
|
1499
1384
|
});
|
|
1500
1385
|
}
|
|
1501
|
-
|
|
1502
1386
|
function Link(props) {
|
|
1503
1387
|
return jsx("div", {
|
|
1504
1388
|
class: "fjs-powered-by fjs-form-field",
|
|
@@ -1515,17 +1399,14 @@ function Link(props) {
|
|
|
1515
1399
|
})
|
|
1516
1400
|
});
|
|
1517
1401
|
}
|
|
1518
|
-
|
|
1519
1402
|
function PoweredBy(props) {
|
|
1520
1403
|
const [open, setOpen] = useState(false);
|
|
1521
|
-
|
|
1522
1404
|
function toggleOpen(open) {
|
|
1523
1405
|
return event => {
|
|
1524
1406
|
event.preventDefault();
|
|
1525
1407
|
setOpen(open);
|
|
1526
1408
|
};
|
|
1527
1409
|
}
|
|
1528
|
-
|
|
1529
1410
|
return jsxs(Fragment, {
|
|
1530
1411
|
children: [createPortal(jsx(Lightbox, {
|
|
1531
1412
|
open: open,
|
|
@@ -1537,30 +1418,24 @@ function PoweredBy(props) {
|
|
|
1537
1418
|
}
|
|
1538
1419
|
|
|
1539
1420
|
const noop = () => {};
|
|
1540
|
-
|
|
1541
1421
|
function FormComponent(props) {
|
|
1542
1422
|
const form = useService('form');
|
|
1543
|
-
|
|
1544
1423
|
const {
|
|
1545
1424
|
schema
|
|
1546
1425
|
} = form._getState();
|
|
1547
|
-
|
|
1548
1426
|
const {
|
|
1549
1427
|
onSubmit = noop,
|
|
1550
1428
|
onReset = noop,
|
|
1551
1429
|
onChange = noop
|
|
1552
1430
|
} = props;
|
|
1553
|
-
|
|
1554
1431
|
const handleSubmit = event => {
|
|
1555
1432
|
event.preventDefault();
|
|
1556
1433
|
onSubmit();
|
|
1557
1434
|
};
|
|
1558
|
-
|
|
1559
1435
|
const handleReset = event => {
|
|
1560
1436
|
event.preventDefault();
|
|
1561
1437
|
onReset();
|
|
1562
1438
|
};
|
|
1563
|
-
|
|
1564
1439
|
return jsxs("form", {
|
|
1565
1440
|
class: "fjs-form",
|
|
1566
1441
|
onSubmit: handleSubmit,
|
|
@@ -1572,7 +1447,7 @@ function FormComponent(props) {
|
|
|
1572
1447
|
});
|
|
1573
1448
|
}
|
|
1574
1449
|
|
|
1575
|
-
const type$
|
|
1450
|
+
const type$6 = 'number';
|
|
1576
1451
|
function Number(props) {
|
|
1577
1452
|
const {
|
|
1578
1453
|
disabled,
|
|
@@ -1589,7 +1464,6 @@ function Number(props) {
|
|
|
1589
1464
|
const {
|
|
1590
1465
|
required
|
|
1591
1466
|
} = validate;
|
|
1592
|
-
|
|
1593
1467
|
const onChange = ({
|
|
1594
1468
|
target
|
|
1595
1469
|
}) => {
|
|
@@ -1600,12 +1474,14 @@ function Number(props) {
|
|
|
1600
1474
|
})
|
|
1601
1475
|
});
|
|
1602
1476
|
};
|
|
1603
|
-
|
|
1604
1477
|
const {
|
|
1605
1478
|
formId
|
|
1606
1479
|
} = useContext(FormContext);
|
|
1607
1480
|
return jsxs("div", {
|
|
1608
|
-
class: formFieldClasses(type$
|
|
1481
|
+
class: formFieldClasses(type$6, {
|
|
1482
|
+
errors,
|
|
1483
|
+
disabled
|
|
1484
|
+
}),
|
|
1609
1485
|
children: [jsx(Label, {
|
|
1610
1486
|
id: prefixId(id, formId),
|
|
1611
1487
|
label: label,
|
|
@@ -1624,25 +1500,23 @@ function Number(props) {
|
|
|
1624
1500
|
})]
|
|
1625
1501
|
});
|
|
1626
1502
|
}
|
|
1627
|
-
|
|
1628
1503
|
Number.create = function (options = {}) {
|
|
1629
|
-
return {
|
|
1504
|
+
return {
|
|
1505
|
+
...options
|
|
1630
1506
|
};
|
|
1631
1507
|
};
|
|
1632
|
-
|
|
1633
1508
|
Number.sanitizeValue = ({
|
|
1634
1509
|
value
|
|
1635
1510
|
}) => {
|
|
1636
1511
|
const parsedValue = parseInt(value, 10);
|
|
1637
1512
|
return isNaN(parsedValue) ? null : parsedValue;
|
|
1638
1513
|
};
|
|
1639
|
-
|
|
1640
|
-
Number.type = type$5;
|
|
1514
|
+
Number.type = type$6;
|
|
1641
1515
|
Number.keyed = true;
|
|
1642
1516
|
Number.label = 'Number';
|
|
1643
1517
|
Number.emptyValue = null;
|
|
1644
1518
|
|
|
1645
|
-
const type$
|
|
1519
|
+
const type$5 = 'radio';
|
|
1646
1520
|
function Radio(props) {
|
|
1647
1521
|
const {
|
|
1648
1522
|
disabled,
|
|
@@ -1659,14 +1533,12 @@ function Radio(props) {
|
|
|
1659
1533
|
const {
|
|
1660
1534
|
required
|
|
1661
1535
|
} = validate;
|
|
1662
|
-
|
|
1663
1536
|
const onChange = v => {
|
|
1664
1537
|
props.onChange({
|
|
1665
1538
|
field,
|
|
1666
1539
|
value: v
|
|
1667
1540
|
});
|
|
1668
1541
|
};
|
|
1669
|
-
|
|
1670
1542
|
const {
|
|
1671
1543
|
state: loadState,
|
|
1672
1544
|
values: options
|
|
@@ -1675,7 +1547,10 @@ function Radio(props) {
|
|
|
1675
1547
|
formId
|
|
1676
1548
|
} = useContext(FormContext);
|
|
1677
1549
|
return jsxs("div", {
|
|
1678
|
-
class: formFieldClasses(type$
|
|
1550
|
+
class: formFieldClasses(type$5, {
|
|
1551
|
+
errors,
|
|
1552
|
+
disabled
|
|
1553
|
+
}),
|
|
1679
1554
|
children: [jsx(Label, {
|
|
1680
1555
|
label: label,
|
|
1681
1556
|
required: required
|
|
@@ -1683,6 +1558,9 @@ function Radio(props) {
|
|
|
1683
1558
|
return jsx(Label, {
|
|
1684
1559
|
id: prefixId(`${id}-${index}`, formId),
|
|
1685
1560
|
label: option.label,
|
|
1561
|
+
class: classNames({
|
|
1562
|
+
'fjs-checked': option.value === value
|
|
1563
|
+
}),
|
|
1686
1564
|
required: false,
|
|
1687
1565
|
children: jsx("input", {
|
|
1688
1566
|
checked: option.value === value,
|
|
@@ -1700,7 +1578,6 @@ function Radio(props) {
|
|
|
1700
1578
|
})]
|
|
1701
1579
|
});
|
|
1702
1580
|
}
|
|
1703
|
-
|
|
1704
1581
|
Radio.create = function (options = {}) {
|
|
1705
1582
|
if (options.valuesKey) return options;
|
|
1706
1583
|
return {
|
|
@@ -1711,14 +1588,13 @@ Radio.create = function (options = {}) {
|
|
|
1711
1588
|
...options
|
|
1712
1589
|
};
|
|
1713
1590
|
};
|
|
1714
|
-
|
|
1715
|
-
Radio.type = type$4;
|
|
1591
|
+
Radio.type = type$5;
|
|
1716
1592
|
Radio.label = 'Radio';
|
|
1717
1593
|
Radio.keyed = true;
|
|
1718
1594
|
Radio.emptyValue = null;
|
|
1719
1595
|
Radio.sanitizeValue = sanitizeSingleSelectValue;
|
|
1720
1596
|
|
|
1721
|
-
const type$
|
|
1597
|
+
const type$4 = 'select';
|
|
1722
1598
|
function Select(props) {
|
|
1723
1599
|
const {
|
|
1724
1600
|
disabled,
|
|
@@ -1735,7 +1611,6 @@ function Select(props) {
|
|
|
1735
1611
|
const {
|
|
1736
1612
|
required
|
|
1737
1613
|
} = validate;
|
|
1738
|
-
|
|
1739
1614
|
const onChange = ({
|
|
1740
1615
|
target
|
|
1741
1616
|
}) => {
|
|
@@ -1744,7 +1619,6 @@ function Select(props) {
|
|
|
1744
1619
|
value: target.value === '' ? null : target.value
|
|
1745
1620
|
});
|
|
1746
1621
|
};
|
|
1747
|
-
|
|
1748
1622
|
const {
|
|
1749
1623
|
state: loadState,
|
|
1750
1624
|
values: options
|
|
@@ -1753,7 +1627,10 @@ function Select(props) {
|
|
|
1753
1627
|
formId
|
|
1754
1628
|
} = useContext(FormContext);
|
|
1755
1629
|
return jsxs("div", {
|
|
1756
|
-
class: formFieldClasses(type$
|
|
1630
|
+
class: formFieldClasses(type$4, {
|
|
1631
|
+
errors,
|
|
1632
|
+
disabled
|
|
1633
|
+
}),
|
|
1757
1634
|
children: [jsx(Label, {
|
|
1758
1635
|
id: prefixId(id, formId),
|
|
1759
1636
|
label: label,
|
|
@@ -1779,7 +1656,6 @@ function Select(props) {
|
|
|
1779
1656
|
})]
|
|
1780
1657
|
});
|
|
1781
1658
|
}
|
|
1782
|
-
|
|
1783
1659
|
Select.create = function (options = {}) {
|
|
1784
1660
|
if (options.valuesKey) return options;
|
|
1785
1661
|
return {
|
|
@@ -1790,8 +1666,7 @@ Select.create = function (options = {}) {
|
|
|
1790
1666
|
...options
|
|
1791
1667
|
};
|
|
1792
1668
|
};
|
|
1793
|
-
|
|
1794
|
-
Select.type = type$3;
|
|
1669
|
+
Select.type = type$4;
|
|
1795
1670
|
Select.label = 'Select';
|
|
1796
1671
|
Select.keyed = true;
|
|
1797
1672
|
Select.emptyValue = null;
|
|
@@ -1810,7 +1685,7 @@ var CloseIcon = (({
|
|
|
1810
1685
|
fillRule: "evenodd",
|
|
1811
1686
|
clipRule: "evenodd",
|
|
1812
1687
|
d: "M12 4.7l-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7z",
|
|
1813
|
-
fill: "
|
|
1688
|
+
fill: "currentColor"
|
|
1814
1689
|
})));
|
|
1815
1690
|
|
|
1816
1691
|
function useKeyDownAction(targetKey, action, listenerElement = window) {
|
|
@@ -1821,7 +1696,6 @@ function useKeyDownAction(targetKey, action, listenerElement = window) {
|
|
|
1821
1696
|
action();
|
|
1822
1697
|
}
|
|
1823
1698
|
}
|
|
1824
|
-
|
|
1825
1699
|
useEffect(() => {
|
|
1826
1700
|
listenerElement.addEventListener('keydown', downHandler);
|
|
1827
1701
|
return () => {
|
|
@@ -1831,9 +1705,7 @@ function useKeyDownAction(targetKey, action, listenerElement = window) {
|
|
|
1831
1705
|
}
|
|
1832
1706
|
|
|
1833
1707
|
const DEFAULT_LABEL_GETTER = value => value;
|
|
1834
|
-
|
|
1835
1708
|
const NOOP = () => {};
|
|
1836
|
-
|
|
1837
1709
|
function DropdownList(props) {
|
|
1838
1710
|
const {
|
|
1839
1711
|
keyEventsListener = window,
|
|
@@ -1853,7 +1725,6 @@ function DropdownList(props) {
|
|
|
1853
1725
|
}, [values.length]);
|
|
1854
1726
|
useEffect(() => {
|
|
1855
1727
|
if (focusedValueIndex === 0) return;
|
|
1856
|
-
|
|
1857
1728
|
if (!focusedValueIndex || !values.length) {
|
|
1858
1729
|
setFocusedValueIndex(0);
|
|
1859
1730
|
} else if (focusedValueIndex >= values.length) {
|
|
@@ -1879,7 +1750,6 @@ function DropdownList(props) {
|
|
|
1879
1750
|
}, keyEventsListener);
|
|
1880
1751
|
useEffect(() => {
|
|
1881
1752
|
const individualEntries = dropdownContainer.current.children;
|
|
1882
|
-
|
|
1883
1753
|
if (individualEntries.length && !mouseControl) {
|
|
1884
1754
|
individualEntries[focusedValueIndex].scrollIntoView({
|
|
1885
1755
|
block: 'nearest',
|
|
@@ -1887,23 +1757,19 @@ function DropdownList(props) {
|
|
|
1887
1757
|
});
|
|
1888
1758
|
}
|
|
1889
1759
|
}, [focusedValueIndex, mouseControl]);
|
|
1890
|
-
|
|
1891
1760
|
const mouseMove = (e, i) => {
|
|
1892
1761
|
const userMoved = !mouseScreenPos.current || mouseScreenPos.current.x !== e.screenX && mouseScreenPos.current.y !== e.screenY;
|
|
1893
|
-
|
|
1894
1762
|
if (userMoved) {
|
|
1895
1763
|
mouseScreenPos.current = {
|
|
1896
1764
|
x: e.screenX,
|
|
1897
1765
|
y: e.screenY
|
|
1898
1766
|
};
|
|
1899
|
-
|
|
1900
1767
|
if (!mouseControl) {
|
|
1901
1768
|
setMouseControl(true);
|
|
1902
1769
|
setFocusedValueIndex(i);
|
|
1903
1770
|
}
|
|
1904
1771
|
}
|
|
1905
1772
|
};
|
|
1906
|
-
|
|
1907
1773
|
return jsxs("div", {
|
|
1908
1774
|
ref: dropdownContainer,
|
|
1909
1775
|
tabIndex: -1,
|
|
@@ -1929,7 +1795,7 @@ function DropdownList(props) {
|
|
|
1929
1795
|
});
|
|
1930
1796
|
}
|
|
1931
1797
|
|
|
1932
|
-
const type$
|
|
1798
|
+
const type$3 = 'taglist';
|
|
1933
1799
|
function Taglist(props) {
|
|
1934
1800
|
const {
|
|
1935
1801
|
disabled,
|
|
@@ -1954,12 +1820,14 @@ function Taglist(props) {
|
|
|
1954
1820
|
const {
|
|
1955
1821
|
state: loadState,
|
|
1956
1822
|
values: options
|
|
1957
|
-
} = useValuesAsync(field);
|
|
1823
|
+
} = useValuesAsync(field);
|
|
1958
1824
|
|
|
1825
|
+
// We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
|
|
1959
1826
|
const valueToOptionMap = useMemo(() => Object.assign({}, ...options.map((o, x) => ({
|
|
1960
1827
|
[o.value]: options[x]
|
|
1961
|
-
}))), [options]);
|
|
1828
|
+
}))), [options]);
|
|
1962
1829
|
|
|
1830
|
+
// Usage of stringify is necessary here because we want this effect to only trigger when there is a value change to the array
|
|
1963
1831
|
useEffect(() => {
|
|
1964
1832
|
if (loadState === LOAD_STATES.LOADED) {
|
|
1965
1833
|
setFilteredOptions(options.filter(o => o.label && o.value && o.label.toLowerCase().includes(filter.toLowerCase()) && !values.includes(o.value)));
|
|
@@ -1970,37 +1838,32 @@ function Taglist(props) {
|
|
|
1970
1838
|
useEffect(() => {
|
|
1971
1839
|
setHasOptionsLeft(options.length > values.length);
|
|
1972
1840
|
}, [options.length, values.length]);
|
|
1973
|
-
|
|
1974
1841
|
const onFilterChange = ({
|
|
1975
1842
|
target
|
|
1976
1843
|
}) => {
|
|
1977
1844
|
setIsEscapeClose(false);
|
|
1978
1845
|
setFilter(target.value);
|
|
1979
1846
|
};
|
|
1980
|
-
|
|
1981
1847
|
const selectValue = value => {
|
|
1982
1848
|
if (filter) {
|
|
1983
1849
|
setFilter('');
|
|
1984
|
-
}
|
|
1985
|
-
|
|
1850
|
+
}
|
|
1986
1851
|
|
|
1852
|
+
// Ensure values cannot be double selected due to latency
|
|
1987
1853
|
if (values.at(-1) === value) {
|
|
1988
1854
|
return;
|
|
1989
1855
|
}
|
|
1990
|
-
|
|
1991
1856
|
props.onChange({
|
|
1992
1857
|
value: [...values, value],
|
|
1993
1858
|
field
|
|
1994
1859
|
});
|
|
1995
1860
|
};
|
|
1996
|
-
|
|
1997
1861
|
const deselectValue = value => {
|
|
1998
1862
|
props.onChange({
|
|
1999
1863
|
value: values.filter(v => v != value),
|
|
2000
1864
|
field
|
|
2001
1865
|
});
|
|
2002
1866
|
};
|
|
2003
|
-
|
|
2004
1867
|
const onInputKeyDown = e => {
|
|
2005
1868
|
switch (e.key) {
|
|
2006
1869
|
case 'ArrowUp':
|
|
@@ -2008,32 +1871,29 @@ function Taglist(props) {
|
|
|
2008
1871
|
// We do not want the cursor to seek in the search field when we press up and down
|
|
2009
1872
|
e.preventDefault();
|
|
2010
1873
|
break;
|
|
2011
|
-
|
|
2012
1874
|
case 'Backspace':
|
|
2013
1875
|
if (!filter && values.length) {
|
|
2014
1876
|
deselectValue(values[values.length - 1]);
|
|
2015
1877
|
}
|
|
2016
|
-
|
|
2017
1878
|
break;
|
|
2018
|
-
|
|
2019
1879
|
case 'Escape':
|
|
2020
1880
|
setIsEscapeClose(true);
|
|
2021
1881
|
break;
|
|
2022
|
-
|
|
2023
1882
|
case 'Enter':
|
|
2024
1883
|
if (isEscapeClosed) {
|
|
2025
1884
|
setIsEscapeClose(false);
|
|
2026
1885
|
}
|
|
2027
|
-
|
|
2028
1886
|
break;
|
|
2029
1887
|
}
|
|
2030
1888
|
};
|
|
2031
|
-
|
|
2032
1889
|
return jsxs("div", {
|
|
2033
|
-
class: formFieldClasses(type$
|
|
1890
|
+
class: formFieldClasses(type$3, {
|
|
1891
|
+
errors,
|
|
1892
|
+
disabled
|
|
1893
|
+
}),
|
|
2034
1894
|
children: [jsx(Label, {
|
|
2035
1895
|
label: label,
|
|
2036
|
-
id: prefixId(id
|
|
1896
|
+
id: prefixId(`${id}-search`, formId)
|
|
2037
1897
|
}), jsxs("div", {
|
|
2038
1898
|
class: classNames('fjs-taglist', {
|
|
2039
1899
|
'disabled': disabled
|
|
@@ -2085,7 +1945,6 @@ function Taglist(props) {
|
|
|
2085
1945
|
})]
|
|
2086
1946
|
});
|
|
2087
1947
|
}
|
|
2088
|
-
|
|
2089
1948
|
Taglist.create = function (options = {}) {
|
|
2090
1949
|
if (options.valuesKey) return options;
|
|
2091
1950
|
return {
|
|
@@ -2096,14 +1955,13 @@ Taglist.create = function (options = {}) {
|
|
|
2096
1955
|
...options
|
|
2097
1956
|
};
|
|
2098
1957
|
};
|
|
2099
|
-
|
|
2100
|
-
Taglist.type = type$2;
|
|
1958
|
+
Taglist.type = type$3;
|
|
2101
1959
|
Taglist.label = 'Taglist';
|
|
2102
1960
|
Taglist.keyed = true;
|
|
2103
1961
|
Taglist.emptyValue = [];
|
|
2104
1962
|
Taglist.sanitizeValue = sanitizeMultiSelectValue;
|
|
2105
1963
|
|
|
2106
|
-
const type$
|
|
1964
|
+
const type$2 = 'text';
|
|
2107
1965
|
function Text(props) {
|
|
2108
1966
|
const {
|
|
2109
1967
|
field
|
|
@@ -2112,25 +1970,23 @@ function Text(props) {
|
|
|
2112
1970
|
text = ''
|
|
2113
1971
|
} = field;
|
|
2114
1972
|
return jsx("div", {
|
|
2115
|
-
class: formFieldClasses(type$
|
|
1973
|
+
class: formFieldClasses(type$2),
|
|
2116
1974
|
children: jsx(Markup, {
|
|
2117
1975
|
markup: safeMarkdown(text),
|
|
2118
1976
|
trim: false
|
|
2119
1977
|
})
|
|
2120
1978
|
});
|
|
2121
1979
|
}
|
|
2122
|
-
|
|
2123
1980
|
Text.create = function (options = {}) {
|
|
2124
1981
|
return {
|
|
2125
1982
|
text: '# Text',
|
|
2126
1983
|
...options
|
|
2127
1984
|
};
|
|
2128
1985
|
};
|
|
2129
|
-
|
|
2130
|
-
Text.type = type$1;
|
|
1986
|
+
Text.type = type$2;
|
|
2131
1987
|
Text.keyed = false;
|
|
2132
1988
|
|
|
2133
|
-
const type = 'textfield';
|
|
1989
|
+
const type$1 = 'textfield';
|
|
2134
1990
|
function Textfield(props) {
|
|
2135
1991
|
const {
|
|
2136
1992
|
disabled,
|
|
@@ -2147,7 +2003,6 @@ function Textfield(props) {
|
|
|
2147
2003
|
const {
|
|
2148
2004
|
required
|
|
2149
2005
|
} = validate;
|
|
2150
|
-
|
|
2151
2006
|
const onChange = ({
|
|
2152
2007
|
target
|
|
2153
2008
|
}) => {
|
|
@@ -2156,12 +2011,14 @@ function Textfield(props) {
|
|
|
2156
2011
|
value: target.value
|
|
2157
2012
|
});
|
|
2158
2013
|
};
|
|
2159
|
-
|
|
2160
2014
|
const {
|
|
2161
2015
|
formId
|
|
2162
2016
|
} = useContext(FormContext);
|
|
2163
2017
|
return jsxs("div", {
|
|
2164
|
-
class: formFieldClasses(type,
|
|
2018
|
+
class: formFieldClasses(type$1, {
|
|
2019
|
+
errors,
|
|
2020
|
+
disabled
|
|
2021
|
+
}),
|
|
2165
2022
|
children: [jsx(Label, {
|
|
2166
2023
|
id: prefixId(id, formId),
|
|
2167
2024
|
label: label,
|
|
@@ -2180,22 +2037,101 @@ function Textfield(props) {
|
|
|
2180
2037
|
})]
|
|
2181
2038
|
});
|
|
2182
2039
|
}
|
|
2183
|
-
|
|
2184
2040
|
Textfield.create = function (options = {}) {
|
|
2185
|
-
return {
|
|
2041
|
+
return {
|
|
2042
|
+
...options
|
|
2186
2043
|
};
|
|
2187
2044
|
};
|
|
2188
|
-
|
|
2189
|
-
Textfield.
|
|
2190
|
-
Textfield.label = 'Text Field';
|
|
2045
|
+
Textfield.type = type$1;
|
|
2046
|
+
Textfield.label = 'Text field';
|
|
2191
2047
|
Textfield.keyed = true;
|
|
2192
2048
|
Textfield.emptyValue = '';
|
|
2193
|
-
|
|
2194
2049
|
Textfield.sanitizeValue = ({
|
|
2195
2050
|
value
|
|
2196
|
-
}) => isArray(value) || isObject(value) ?
|
|
2051
|
+
}) => isArray(value) || isObject(value) ? '' : String(value);
|
|
2197
2052
|
|
|
2198
|
-
const
|
|
2053
|
+
const type = 'textarea';
|
|
2054
|
+
function Textarea(props) {
|
|
2055
|
+
const {
|
|
2056
|
+
disabled,
|
|
2057
|
+
errors = [],
|
|
2058
|
+
field,
|
|
2059
|
+
value = ''
|
|
2060
|
+
} = props;
|
|
2061
|
+
const {
|
|
2062
|
+
description,
|
|
2063
|
+
id,
|
|
2064
|
+
label,
|
|
2065
|
+
validate = {}
|
|
2066
|
+
} = field;
|
|
2067
|
+
const {
|
|
2068
|
+
required
|
|
2069
|
+
} = validate;
|
|
2070
|
+
const textareaRef = useRef();
|
|
2071
|
+
const onInput = ({
|
|
2072
|
+
target
|
|
2073
|
+
}) => {
|
|
2074
|
+
props.onChange({
|
|
2075
|
+
field,
|
|
2076
|
+
value: target.value
|
|
2077
|
+
});
|
|
2078
|
+
};
|
|
2079
|
+
const autoSizeTextarea = useCallback(textarea => {
|
|
2080
|
+
// Ensures the textarea shrinks back, and improves resizing behavior consistency
|
|
2081
|
+
textarea.style.height = '0px';
|
|
2082
|
+
const computed = window.getComputedStyle(textarea);
|
|
2083
|
+
const calculatedHeight = parseInt(computed.getPropertyValue('border-top-width')) + parseInt(computed.getPropertyValue('padding-top')) + textarea.scrollHeight + parseInt(computed.getPropertyValue('padding-bottom')) + parseInt(computed.getPropertyValue('border-bottom-width'));
|
|
2084
|
+
const minHeight = 75;
|
|
2085
|
+
const maxHeight = 350;
|
|
2086
|
+
const displayHeight = Math.max(Math.min(calculatedHeight, maxHeight), minHeight);
|
|
2087
|
+
textarea.style.height = `${displayHeight}px`;
|
|
2088
|
+
|
|
2089
|
+
// Overflow is hidden by default to hide scrollbar flickering
|
|
2090
|
+
textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
|
|
2091
|
+
}, []);
|
|
2092
|
+
useEffect(() => {
|
|
2093
|
+
autoSizeTextarea(textareaRef.current);
|
|
2094
|
+
}, [autoSizeTextarea, value]);
|
|
2095
|
+
const {
|
|
2096
|
+
formId
|
|
2097
|
+
} = useContext(FormContext);
|
|
2098
|
+
return jsxs("div", {
|
|
2099
|
+
class: formFieldClasses(type, {
|
|
2100
|
+
errors,
|
|
2101
|
+
disabled
|
|
2102
|
+
}),
|
|
2103
|
+
children: [jsx(Label, {
|
|
2104
|
+
id: prefixId(id, formId),
|
|
2105
|
+
label: label,
|
|
2106
|
+
required: required
|
|
2107
|
+
}), jsx("textarea", {
|
|
2108
|
+
class: "fjs-textarea",
|
|
2109
|
+
disabled: disabled,
|
|
2110
|
+
id: prefixId(id, formId),
|
|
2111
|
+
onInput: onInput,
|
|
2112
|
+
value: value,
|
|
2113
|
+
ref: textareaRef
|
|
2114
|
+
}), jsx(Description, {
|
|
2115
|
+
description: description
|
|
2116
|
+
}), jsx(Errors, {
|
|
2117
|
+
errors: errors
|
|
2118
|
+
})]
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
Textarea.create = function (options = {}) {
|
|
2122
|
+
return {
|
|
2123
|
+
...options
|
|
2124
|
+
};
|
|
2125
|
+
};
|
|
2126
|
+
Textarea.type = type;
|
|
2127
|
+
Textarea.label = 'Text area';
|
|
2128
|
+
Textarea.keyed = true;
|
|
2129
|
+
Textarea.emptyValue = '';
|
|
2130
|
+
Textarea.sanitizeValue = ({
|
|
2131
|
+
value
|
|
2132
|
+
}) => isArray(value) || isObject(value) ? '' : String(value);
|
|
2133
|
+
|
|
2134
|
+
const formFields = [Button, Checkbox, Checklist, Default, Number, Radio, Select, Taglist, Text, Textfield, Textarea];
|
|
2199
2135
|
|
|
2200
2136
|
class FormFields {
|
|
2201
2137
|
constructor() {
|
|
@@ -2207,15 +2143,12 @@ class FormFields {
|
|
|
2207
2143
|
this.register(type, formField);
|
|
2208
2144
|
});
|
|
2209
2145
|
}
|
|
2210
|
-
|
|
2211
2146
|
register(type, formField) {
|
|
2212
2147
|
this._formFields[type] = formField;
|
|
2213
2148
|
}
|
|
2214
|
-
|
|
2215
2149
|
get(type) {
|
|
2216
2150
|
return this._formFields[type];
|
|
2217
2151
|
}
|
|
2218
|
-
|
|
2219
2152
|
}
|
|
2220
2153
|
|
|
2221
2154
|
function Renderer(config, eventBus, form, injector) {
|
|
@@ -2225,7 +2158,6 @@ function Renderer(config, eventBus, form, injector) {
|
|
|
2225
2158
|
getService(type, strict = true) {
|
|
2226
2159
|
return injector.get(type, strict);
|
|
2227
2160
|
},
|
|
2228
|
-
|
|
2229
2161
|
formId: form._id
|
|
2230
2162
|
};
|
|
2231
2163
|
eventBus.on('changed', newState => {
|
|
@@ -2247,11 +2179,9 @@ function Renderer(config, eventBus, form, injector) {
|
|
|
2247
2179
|
const {
|
|
2248
2180
|
schema
|
|
2249
2181
|
} = state;
|
|
2250
|
-
|
|
2251
2182
|
if (!schema) {
|
|
2252
2183
|
return null;
|
|
2253
2184
|
}
|
|
2254
|
-
|
|
2255
2185
|
return jsx(FormContext.Provider, {
|
|
2256
2186
|
value: formContext,
|
|
2257
2187
|
children: jsx(FormComponent, {
|
|
@@ -2261,7 +2191,6 @@ function Renderer(config, eventBus, form, injector) {
|
|
|
2261
2191
|
})
|
|
2262
2192
|
});
|
|
2263
2193
|
};
|
|
2264
|
-
|
|
2265
2194
|
const {
|
|
2266
2195
|
container
|
|
2267
2196
|
} = config;
|
|
@@ -2311,10 +2240,10 @@ var core = {
|
|
|
2311
2240
|
*/
|
|
2312
2241
|
|
|
2313
2242
|
const ids = new Ids([32, 36, 1]);
|
|
2243
|
+
|
|
2314
2244
|
/**
|
|
2315
2245
|
* The form.
|
|
2316
2246
|
*/
|
|
2317
|
-
|
|
2318
2247
|
class Form {
|
|
2319
2248
|
/**
|
|
2320
2249
|
* @constructor
|
|
@@ -2326,28 +2255,28 @@ class Form {
|
|
|
2326
2255
|
* @type {OnEventType}
|
|
2327
2256
|
*/
|
|
2328
2257
|
this.on = this._onEvent;
|
|
2258
|
+
|
|
2329
2259
|
/**
|
|
2330
2260
|
* @public
|
|
2331
2261
|
* @type {String}
|
|
2332
2262
|
*/
|
|
2333
|
-
|
|
2334
2263
|
this._id = ids.next();
|
|
2264
|
+
|
|
2335
2265
|
/**
|
|
2336
2266
|
* @private
|
|
2337
2267
|
* @type {Element}
|
|
2338
2268
|
*/
|
|
2339
|
-
|
|
2340
2269
|
this._container = createFormContainer();
|
|
2341
2270
|
const {
|
|
2342
2271
|
container,
|
|
2343
2272
|
injector = this._createInjector(options, this._container),
|
|
2344
2273
|
properties = {}
|
|
2345
2274
|
} = options;
|
|
2275
|
+
|
|
2346
2276
|
/**
|
|
2347
2277
|
* @private
|
|
2348
2278
|
* @type {State}
|
|
2349
2279
|
*/
|
|
2350
|
-
|
|
2351
2280
|
this._state = {
|
|
2352
2281
|
initialData: null,
|
|
2353
2282
|
data: null,
|
|
@@ -2358,33 +2287,31 @@ class Form {
|
|
|
2358
2287
|
this.get = injector.get;
|
|
2359
2288
|
this.invoke = injector.invoke;
|
|
2360
2289
|
this.get('eventBus').fire('form.init');
|
|
2361
|
-
|
|
2362
2290
|
if (container) {
|
|
2363
2291
|
this.attachTo(container);
|
|
2364
2292
|
}
|
|
2365
2293
|
}
|
|
2366
|
-
|
|
2367
2294
|
clear() {
|
|
2368
2295
|
// clear form services
|
|
2369
|
-
this._emit('diagram.clear');
|
|
2370
|
-
|
|
2296
|
+
this._emit('diagram.clear');
|
|
2371
2297
|
|
|
2298
|
+
// clear diagram services (e.g. EventBus)
|
|
2372
2299
|
this._emit('form.clear');
|
|
2373
2300
|
}
|
|
2301
|
+
|
|
2374
2302
|
/**
|
|
2375
2303
|
* Destroy the form, removing it from DOM,
|
|
2376
2304
|
* if attached.
|
|
2377
2305
|
*/
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
2306
|
destroy() {
|
|
2381
2307
|
// destroy form services
|
|
2382
|
-
this.get('eventBus').fire('form.destroy');
|
|
2308
|
+
this.get('eventBus').fire('form.destroy');
|
|
2383
2309
|
|
|
2310
|
+
// destroy diagram services (e.g. EventBus)
|
|
2384
2311
|
this.get('eventBus').fire('diagram.destroy');
|
|
2385
|
-
|
|
2386
2312
|
this._detach(false);
|
|
2387
2313
|
}
|
|
2314
|
+
|
|
2388
2315
|
/**
|
|
2389
2316
|
* Open a form schema with the given initial data.
|
|
2390
2317
|
*
|
|
@@ -2393,8 +2320,6 @@ class Form {
|
|
|
2393
2320
|
*
|
|
2394
2321
|
* @return Promise<{ warnings: Array<any> }>
|
|
2395
2322
|
*/
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
2323
|
importSchema(schema, data = {}) {
|
|
2399
2324
|
return new Promise((resolve, reject) => {
|
|
2400
2325
|
try {
|
|
@@ -2404,18 +2329,15 @@ class Form {
|
|
|
2404
2329
|
data: importedData,
|
|
2405
2330
|
warnings
|
|
2406
2331
|
} = this.get('importer').importSchema(schema, data);
|
|
2407
|
-
|
|
2408
2332
|
this._setState({
|
|
2409
2333
|
data: importedData,
|
|
2410
2334
|
errors: {},
|
|
2411
2335
|
schema: importedSchema,
|
|
2412
2336
|
initialData: clone(importedData)
|
|
2413
2337
|
});
|
|
2414
|
-
|
|
2415
2338
|
this._emit('import.done', {
|
|
2416
2339
|
warnings
|
|
2417
2340
|
});
|
|
2418
|
-
|
|
2419
2341
|
return resolve({
|
|
2420
2342
|
warnings
|
|
2421
2343
|
});
|
|
@@ -2424,154 +2346,124 @@ class Form {
|
|
|
2424
2346
|
error,
|
|
2425
2347
|
warnings: error.warnings || []
|
|
2426
2348
|
});
|
|
2427
|
-
|
|
2428
2349
|
return reject(error);
|
|
2429
2350
|
}
|
|
2430
2351
|
});
|
|
2431
2352
|
}
|
|
2353
|
+
|
|
2432
2354
|
/**
|
|
2433
2355
|
* Submit the form, triggering all field validations.
|
|
2434
2356
|
*
|
|
2435
2357
|
* @returns { { data: Data, errors: Errors } }
|
|
2436
2358
|
*/
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
2359
|
submit() {
|
|
2440
2360
|
const {
|
|
2441
2361
|
properties
|
|
2442
2362
|
} = this._getState();
|
|
2443
|
-
|
|
2444
2363
|
if (properties.readOnly) {
|
|
2445
2364
|
throw new Error('form is read-only');
|
|
2446
2365
|
}
|
|
2447
|
-
|
|
2448
2366
|
const data = this._getSubmitData();
|
|
2449
|
-
|
|
2450
2367
|
const errors = this.validate();
|
|
2451
|
-
|
|
2452
2368
|
this._emit('submit', {
|
|
2453
2369
|
data,
|
|
2454
2370
|
errors
|
|
2455
2371
|
});
|
|
2456
|
-
|
|
2457
2372
|
return {
|
|
2458
2373
|
data,
|
|
2459
2374
|
errors
|
|
2460
2375
|
};
|
|
2461
2376
|
}
|
|
2462
|
-
|
|
2463
2377
|
reset() {
|
|
2464
2378
|
this._emit('reset');
|
|
2465
|
-
|
|
2466
2379
|
this._setState({
|
|
2467
2380
|
data: clone(this._state.initialData),
|
|
2468
2381
|
errors: {}
|
|
2469
2382
|
});
|
|
2470
2383
|
}
|
|
2384
|
+
|
|
2471
2385
|
/**
|
|
2472
2386
|
* @returns {Errors}
|
|
2473
2387
|
*/
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
2388
|
validate() {
|
|
2477
2389
|
const formFieldRegistry = this.get('formFieldRegistry'),
|
|
2478
|
-
|
|
2479
|
-
|
|
2390
|
+
validator = this.get('validator');
|
|
2480
2391
|
const {
|
|
2481
2392
|
data
|
|
2482
2393
|
} = this._getState();
|
|
2483
|
-
|
|
2484
2394
|
const errors = formFieldRegistry.getAll().reduce((errors, field) => {
|
|
2485
2395
|
const {
|
|
2486
2396
|
disabled,
|
|
2487
2397
|
_path
|
|
2488
2398
|
} = field;
|
|
2489
|
-
|
|
2490
2399
|
if (disabled) {
|
|
2491
2400
|
return errors;
|
|
2492
2401
|
}
|
|
2493
|
-
|
|
2494
2402
|
const value = get(data, _path);
|
|
2495
2403
|
const fieldErrors = validator.validateField(field, value);
|
|
2496
2404
|
return set(errors, [pathStringify(_path)], fieldErrors.length ? fieldErrors : undefined);
|
|
2497
|
-
},
|
|
2498
|
-
/** @type {Errors} */
|
|
2499
|
-
{});
|
|
2500
|
-
|
|
2405
|
+
}, /** @type {Errors} */{});
|
|
2501
2406
|
this._setState({
|
|
2502
2407
|
errors
|
|
2503
2408
|
});
|
|
2504
|
-
|
|
2505
2409
|
return errors;
|
|
2506
2410
|
}
|
|
2411
|
+
|
|
2507
2412
|
/**
|
|
2508
2413
|
* @param {Element|string} parentNode
|
|
2509
2414
|
*/
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
2415
|
attachTo(parentNode) {
|
|
2513
2416
|
if (!parentNode) {
|
|
2514
2417
|
throw new Error('parentNode required');
|
|
2515
2418
|
}
|
|
2516
|
-
|
|
2517
2419
|
this.detach();
|
|
2518
|
-
|
|
2519
2420
|
if (isString(parentNode)) {
|
|
2520
2421
|
parentNode = document.querySelector(parentNode);
|
|
2521
2422
|
}
|
|
2522
|
-
|
|
2523
2423
|
const container = this._container;
|
|
2524
2424
|
parentNode.appendChild(container);
|
|
2525
|
-
|
|
2526
2425
|
this._emit('attach');
|
|
2527
2426
|
}
|
|
2528
|
-
|
|
2529
2427
|
detach() {
|
|
2530
2428
|
this._detach();
|
|
2531
2429
|
}
|
|
2430
|
+
|
|
2532
2431
|
/**
|
|
2533
2432
|
* @private
|
|
2534
2433
|
*
|
|
2535
2434
|
* @param {boolean} [emit]
|
|
2536
2435
|
*/
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
2436
|
_detach(emit = true) {
|
|
2540
2437
|
const container = this._container,
|
|
2541
|
-
|
|
2542
|
-
|
|
2438
|
+
parentNode = container.parentNode;
|
|
2543
2439
|
if (!parentNode) {
|
|
2544
2440
|
return;
|
|
2545
2441
|
}
|
|
2546
|
-
|
|
2547
2442
|
if (emit) {
|
|
2548
2443
|
this._emit('detach');
|
|
2549
2444
|
}
|
|
2550
|
-
|
|
2551
2445
|
parentNode.removeChild(container);
|
|
2552
2446
|
}
|
|
2447
|
+
|
|
2553
2448
|
/**
|
|
2554
2449
|
* @param {FormProperty} property
|
|
2555
2450
|
* @param {any} value
|
|
2556
2451
|
*/
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
2452
|
setProperty(property, value) {
|
|
2560
2453
|
const properties = set(this._getState().properties, [property], value);
|
|
2561
|
-
|
|
2562
2454
|
this._setState({
|
|
2563
2455
|
properties
|
|
2564
2456
|
});
|
|
2565
2457
|
}
|
|
2458
|
+
|
|
2566
2459
|
/**
|
|
2567
2460
|
* @param {FormEvent} type
|
|
2568
2461
|
* @param {Function} handler
|
|
2569
2462
|
*/
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
2463
|
off(type, handler) {
|
|
2573
2464
|
this.get('eventBus').off(type, handler);
|
|
2574
2465
|
}
|
|
2466
|
+
|
|
2575
2467
|
/**
|
|
2576
2468
|
* @private
|
|
2577
2469
|
*
|
|
@@ -2580,8 +2472,6 @@ class Form {
|
|
|
2580
2472
|
*
|
|
2581
2473
|
* @returns {Injector}
|
|
2582
2474
|
*/
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
2475
|
_createInjector(options, container) {
|
|
2586
2476
|
const {
|
|
2587
2477
|
additionalModules = [],
|
|
@@ -2598,21 +2488,19 @@ class Form {
|
|
|
2598
2488
|
form: ['value', this]
|
|
2599
2489
|
}, core, ...modules, ...additionalModules]);
|
|
2600
2490
|
}
|
|
2491
|
+
|
|
2601
2492
|
/**
|
|
2602
2493
|
* @private
|
|
2603
2494
|
*/
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
2495
|
_emit(type, data) {
|
|
2607
2496
|
this.get('eventBus').fire(type, data);
|
|
2608
2497
|
}
|
|
2498
|
+
|
|
2609
2499
|
/**
|
|
2610
2500
|
* @internal
|
|
2611
2501
|
*
|
|
2612
2502
|
* @param { { add?: boolean, field: any, remove?: number, value?: any } } update
|
|
2613
2503
|
*/
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
2504
|
_update(update) {
|
|
2617
2505
|
const {
|
|
2618
2506
|
field,
|
|
@@ -2621,77 +2509,71 @@ class Form {
|
|
|
2621
2509
|
const {
|
|
2622
2510
|
_path
|
|
2623
2511
|
} = field;
|
|
2624
|
-
|
|
2625
2512
|
let {
|
|
2626
2513
|
data,
|
|
2627
2514
|
errors
|
|
2628
2515
|
} = this._getState();
|
|
2629
|
-
|
|
2630
2516
|
const validator = this.get('validator');
|
|
2631
2517
|
const fieldErrors = validator.validateField(field, value);
|
|
2632
2518
|
set(data, _path, value);
|
|
2633
2519
|
set(errors, [pathStringify(_path)], fieldErrors.length ? fieldErrors : undefined);
|
|
2634
|
-
|
|
2635
2520
|
this._setState({
|
|
2636
2521
|
data: clone(data),
|
|
2637
2522
|
errors: clone(errors)
|
|
2638
2523
|
});
|
|
2639
2524
|
}
|
|
2525
|
+
|
|
2640
2526
|
/**
|
|
2641
2527
|
* @internal
|
|
2642
2528
|
*/
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
2529
|
_getState() {
|
|
2646
2530
|
return this._state;
|
|
2647
2531
|
}
|
|
2532
|
+
|
|
2648
2533
|
/**
|
|
2649
2534
|
* @internal
|
|
2650
2535
|
*/
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
2536
|
_setState(state) {
|
|
2654
|
-
this._state = {
|
|
2537
|
+
this._state = {
|
|
2538
|
+
...this._state,
|
|
2655
2539
|
...state
|
|
2656
2540
|
};
|
|
2657
|
-
|
|
2658
2541
|
this._emit('changed', this._getState());
|
|
2659
2542
|
}
|
|
2543
|
+
|
|
2660
2544
|
/**
|
|
2661
2545
|
* @internal
|
|
2662
2546
|
*/
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
2547
|
_onEvent(type, priority, handler) {
|
|
2666
2548
|
this.get('eventBus').on(type, priority, handler);
|
|
2667
2549
|
}
|
|
2550
|
+
|
|
2668
2551
|
/**
|
|
2669
2552
|
* @internal
|
|
2670
2553
|
*/
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
2554
|
_getSubmitData() {
|
|
2674
2555
|
const formFieldRegistry = this.get('formFieldRegistry');
|
|
2675
2556
|
return formFieldRegistry.getAll().reduce((data, field) => {
|
|
2676
2557
|
const {
|
|
2677
2558
|
disabled,
|
|
2678
2559
|
_path
|
|
2679
|
-
} = field;
|
|
2560
|
+
} = field;
|
|
2680
2561
|
|
|
2562
|
+
// do not submit disabled form fields
|
|
2681
2563
|
if (disabled || !_path) {
|
|
2682
2564
|
return data;
|
|
2683
2565
|
}
|
|
2684
|
-
|
|
2685
2566
|
const value = get(this._getState().data, _path);
|
|
2686
|
-
return {
|
|
2567
|
+
return {
|
|
2568
|
+
...data,
|
|
2687
2569
|
[_path[0]]: value
|
|
2688
2570
|
};
|
|
2689
2571
|
}, {});
|
|
2690
2572
|
}
|
|
2691
|
-
|
|
2692
2573
|
}
|
|
2693
2574
|
|
|
2694
|
-
const schemaVersion =
|
|
2575
|
+
const schemaVersion = 6;
|
|
2576
|
+
|
|
2695
2577
|
/**
|
|
2696
2578
|
* @typedef { import('./types').CreateFormOptions } CreateFormOptions
|
|
2697
2579
|
*/
|
|
@@ -2703,7 +2585,6 @@ const schemaVersion = 5;
|
|
|
2703
2585
|
*
|
|
2704
2586
|
* @return {Promise<Form>}
|
|
2705
2587
|
*/
|
|
2706
|
-
|
|
2707
2588
|
function createForm(options) {
|
|
2708
2589
|
const {
|
|
2709
2590
|
data,
|
|
@@ -2716,5 +2597,5 @@ function createForm(options) {
|
|
|
2716
2597
|
});
|
|
2717
2598
|
}
|
|
2718
2599
|
|
|
2719
|
-
export { Button, Checkbox, Checklist, Default, Form, FormComponent, FormContext, FormFieldRegistry, FormFields, FormRenderContext, Number, Radio, Select, Taglist, Text, Textfield, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, getSchemaVariables, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion };
|
|
2600
|
+
export { Button, Checkbox, Checklist, Default, Form, FormComponent, FormContext, FormFieldRegistry, FormFields, FormRenderContext, Number, Radio, Select, Taglist, Text, Textarea, Textfield, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, getSchemaVariables, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion };
|
|
2720
2601
|
//# sourceMappingURL=index.es.js.map
|