@bpmn-io/form-js-viewer 1.1.0 → 1.3.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/dist/assets/form-js-base.css +54 -1
- package/dist/assets/form-js.css +54 -1
- package/dist/index.cjs +1074 -636
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +1070 -636
- package/dist/index.es.js.map +1 -1
- package/dist/types/Form.d.ts +4 -0
- package/dist/types/core/FieldFactory.d.ts +19 -0
- package/dist/types/core/FormFieldRegistry.d.ts +0 -1
- package/dist/types/core/Importer.d.ts +56 -0
- package/dist/types/core/PathRegistry.d.ts +71 -0
- package/dist/types/core/index.d.ts +9 -5
- package/dist/types/features/expression-language/ConditionChecker.d.ts +3 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/render/components/form-fields/Checklist.d.ts +2 -6
- package/dist/types/render/components/form-fields/Default.d.ts +3 -3
- package/dist/types/render/components/form-fields/Group.d.ts +14 -0
- package/dist/types/render/components/form-fields/Radio.d.ts +2 -6
- package/dist/types/render/components/form-fields/Select.d.ts +2 -6
- package/dist/types/render/components/form-fields/Taglist.d.ts +2 -6
- package/dist/types/render/components/form-fields/parts/Grid.d.ts +1 -0
- package/dist/types/render/components/index.d.ts +4 -2
- package/dist/types/render/components/util/localisationUtil.d.ts +24 -0
- package/dist/types/render/components/util/valuesUtil.d.ts +6 -0
- package/dist/types/render/context/FormRenderContext.d.ts +3 -0
- package/dist/types/render/hooks/index.d.ts +2 -0
- package/dist/types/render/hooks/useDeepCompareState.d.ts +8 -0
- package/dist/types/render/hooks/usePrevious.d.ts +1 -0
- package/dist/types/util/index.d.ts +1 -2
- package/package.json +3 -2
- package/dist/types/import/Importer.d.ts +0 -45
- package/dist/types/import/index.d.ts +0 -5
package/dist/index.cjs
CHANGED
|
@@ -407,14 +407,230 @@ class FeelersTemplating {
|
|
|
407
407
|
}
|
|
408
408
|
FeelersTemplating.$inject = [];
|
|
409
409
|
|
|
410
|
+
// config ///////////////////
|
|
411
|
+
|
|
412
|
+
const MINUTES_IN_DAY = 60 * 24;
|
|
413
|
+
const DATETIME_SUBTYPES = {
|
|
414
|
+
DATE: 'date',
|
|
415
|
+
TIME: 'time',
|
|
416
|
+
DATETIME: 'datetime'
|
|
417
|
+
};
|
|
418
|
+
const TIME_SERIALISING_FORMATS = {
|
|
419
|
+
UTC_OFFSET: 'utc_offset',
|
|
420
|
+
UTC_NORMALIZED: 'utc_normalized',
|
|
421
|
+
NO_TIMEZONE: 'no_timezone'
|
|
422
|
+
};
|
|
423
|
+
const DATETIME_SUBTYPES_LABELS = {
|
|
424
|
+
[DATETIME_SUBTYPES.DATE]: 'Date',
|
|
425
|
+
[DATETIME_SUBTYPES.TIME]: 'Time',
|
|
426
|
+
[DATETIME_SUBTYPES.DATETIME]: 'Date & Time'
|
|
427
|
+
};
|
|
428
|
+
const TIME_SERIALISINGFORMAT_LABELS = {
|
|
429
|
+
[TIME_SERIALISING_FORMATS.UTC_OFFSET]: 'UTC offset',
|
|
430
|
+
[TIME_SERIALISING_FORMATS.UTC_NORMALIZED]: 'UTC normalized',
|
|
431
|
+
[TIME_SERIALISING_FORMATS.NO_TIMEZONE]: 'No timezone'
|
|
432
|
+
};
|
|
433
|
+
const DATETIME_SUBTYPE_PATH = ['subtype'];
|
|
434
|
+
const DATE_LABEL_PATH = ['dateLabel'];
|
|
435
|
+
const DATE_DISALLOW_PAST_PATH = ['disallowPassedDates'];
|
|
436
|
+
const TIME_LABEL_PATH = ['timeLabel'];
|
|
437
|
+
const TIME_USE24H_PATH = ['use24h'];
|
|
438
|
+
const TIME_INTERVAL_PATH = ['timeInterval'];
|
|
439
|
+
const TIME_SERIALISING_FORMAT_PATH = ['timeSerializingFormat'];
|
|
440
|
+
|
|
441
|
+
// config ///////////////////
|
|
442
|
+
|
|
443
|
+
const VALUES_SOURCES = {
|
|
444
|
+
STATIC: 'static',
|
|
445
|
+
INPUT: 'input',
|
|
446
|
+
EXPRESSION: 'expression'
|
|
447
|
+
};
|
|
448
|
+
const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
|
|
449
|
+
const VALUES_SOURCES_LABELS = {
|
|
450
|
+
[VALUES_SOURCES.STATIC]: 'Static',
|
|
451
|
+
[VALUES_SOURCES.INPUT]: 'Input data',
|
|
452
|
+
[VALUES_SOURCES.EXPRESSION]: 'Expression'
|
|
453
|
+
};
|
|
454
|
+
const VALUES_SOURCES_PATHS = {
|
|
455
|
+
[VALUES_SOURCES.STATIC]: ['values'],
|
|
456
|
+
[VALUES_SOURCES.INPUT]: ['valuesKey'],
|
|
457
|
+
[VALUES_SOURCES.EXPRESSION]: ['valuesExpression']
|
|
458
|
+
};
|
|
459
|
+
const VALUES_SOURCES_DEFAULTS = {
|
|
460
|
+
[VALUES_SOURCES.STATIC]: [{
|
|
461
|
+
label: 'Value',
|
|
462
|
+
value: 'value'
|
|
463
|
+
}],
|
|
464
|
+
[VALUES_SOURCES.INPUT]: '',
|
|
465
|
+
[VALUES_SOURCES.EXPRESSION]: '='
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
// helpers ///////////////////
|
|
469
|
+
|
|
470
|
+
function getValuesSource(field) {
|
|
471
|
+
for (const source of Object.values(VALUES_SOURCES)) {
|
|
472
|
+
if (minDash.get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
|
|
473
|
+
return source;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return VALUES_SOURCE_DEFAULT;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function createInjector(bootstrapModules) {
|
|
480
|
+
const injector = new didi.Injector(bootstrapModules);
|
|
481
|
+
injector.init();
|
|
482
|
+
return injector;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* @param {string?} prefix
|
|
487
|
+
*
|
|
488
|
+
* @returns Element
|
|
489
|
+
*/
|
|
490
|
+
function createFormContainer(prefix = 'fjs') {
|
|
491
|
+
const container = document.createElement('div');
|
|
492
|
+
container.classList.add(`${prefix}-container`);
|
|
493
|
+
return container;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression'];
|
|
497
|
+
const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text'];
|
|
498
|
+
function isRequired(field) {
|
|
499
|
+
return field.required;
|
|
500
|
+
}
|
|
501
|
+
function pathParse(path) {
|
|
502
|
+
if (!path) {
|
|
503
|
+
return [];
|
|
504
|
+
}
|
|
505
|
+
return path.split('.').map(key => {
|
|
506
|
+
return isNaN(parseInt(key)) ? key : parseInt(key);
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
function pathsEqual(a, b) {
|
|
510
|
+
return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
|
|
511
|
+
}
|
|
512
|
+
const indices = {};
|
|
513
|
+
function generateIndexForType(type) {
|
|
514
|
+
if (type in indices) {
|
|
515
|
+
indices[type]++;
|
|
516
|
+
} else {
|
|
517
|
+
indices[type] = 1;
|
|
518
|
+
}
|
|
519
|
+
return indices[type];
|
|
520
|
+
}
|
|
521
|
+
function generateIdForType(type) {
|
|
522
|
+
return `${type}${generateIndexForType(type)}`;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* @template T
|
|
527
|
+
* @param {T} data
|
|
528
|
+
* @param {(this: any, key: string, value: any) => any} [replacer]
|
|
529
|
+
* @return {T}
|
|
530
|
+
*/
|
|
531
|
+
function clone(data, replacer) {
|
|
532
|
+
return JSON.parse(JSON.stringify(data, replacer));
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Parse the schema for input variables a form might make use of
|
|
537
|
+
*
|
|
538
|
+
* @param {any} schema
|
|
539
|
+
*
|
|
540
|
+
* @return {string[]}
|
|
541
|
+
*/
|
|
542
|
+
function getSchemaVariables(schema, options = {}) {
|
|
543
|
+
const {
|
|
544
|
+
expressionLanguage = new FeelExpressionLanguage(null),
|
|
545
|
+
templating = new FeelersTemplating(),
|
|
546
|
+
inputs = true,
|
|
547
|
+
outputs = true
|
|
548
|
+
} = options;
|
|
549
|
+
if (!schema.components) {
|
|
550
|
+
return [];
|
|
551
|
+
}
|
|
552
|
+
const getAllComponents = node => {
|
|
553
|
+
const components = [];
|
|
554
|
+
if (node.components) {
|
|
555
|
+
node.components.forEach(component => {
|
|
556
|
+
components.push(component);
|
|
557
|
+
components.push(...getAllComponents(component));
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
return components;
|
|
561
|
+
};
|
|
562
|
+
const variables = getAllComponents(schema).reduce((variables, component) => {
|
|
563
|
+
const {
|
|
564
|
+
valuesKey
|
|
565
|
+
} = component;
|
|
566
|
+
|
|
567
|
+
// collect input-only variables
|
|
568
|
+
if (inputs) {
|
|
569
|
+
if (valuesKey) {
|
|
570
|
+
variables = [...variables, valuesKey];
|
|
571
|
+
}
|
|
572
|
+
EXPRESSION_PROPERTIES.forEach(prop => {
|
|
573
|
+
const property = minDash.get(component, prop.split('.'));
|
|
574
|
+
if (property && expressionLanguage.isExpression(property)) {
|
|
575
|
+
const expressionVariables = expressionLanguage.getVariableNames(property, {
|
|
576
|
+
type: 'expression'
|
|
577
|
+
});
|
|
578
|
+
variables = [...variables, ...expressionVariables];
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
TEMPLATE_PROPERTIES.forEach(prop => {
|
|
582
|
+
const property = minDash.get(component, prop.split('.'));
|
|
583
|
+
if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) {
|
|
584
|
+
const templateVariables = templating.getVariableNames(property);
|
|
585
|
+
variables = [...variables, ...templateVariables];
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
return variables.filter(variable => variable !== undefined || variable !== null);
|
|
590
|
+
}, []);
|
|
591
|
+
const getBindingVariables = node => {
|
|
592
|
+
const bindingVariable = [];
|
|
593
|
+
|
|
594
|
+
// c.f. https://github.com/bpmn-io/form-js/issues/778 @Skaiir to remove?
|
|
595
|
+
if (node.type === 'button') {
|
|
596
|
+
return [];
|
|
597
|
+
} else if (node.key) {
|
|
598
|
+
return [node.key.split('.')[0]];
|
|
599
|
+
} else if (node.path) {
|
|
600
|
+
return [node.path.split('.')[0]];
|
|
601
|
+
} else if (node.components) {
|
|
602
|
+
node.components.forEach(component => {
|
|
603
|
+
bindingVariable.push(...getBindingVariables(component));
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
return bindingVariable;
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
// collect binding variables
|
|
610
|
+
if (inputs || outputs) {
|
|
611
|
+
variables.push(...getBindingVariables(schema));
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// remove duplicates
|
|
615
|
+
return Array.from(new Set(variables));
|
|
616
|
+
}
|
|
617
|
+
function runRecursively(formField, fn) {
|
|
618
|
+
const components = formField.components || [];
|
|
619
|
+
components.forEach((component, index) => {
|
|
620
|
+
runRecursively(component, fn);
|
|
621
|
+
});
|
|
622
|
+
fn(formField);
|
|
623
|
+
}
|
|
624
|
+
|
|
410
625
|
/**
|
|
411
626
|
* @typedef {object} Condition
|
|
412
627
|
* @property {string} [hide]
|
|
413
628
|
*/
|
|
414
629
|
|
|
415
630
|
class ConditionChecker {
|
|
416
|
-
constructor(formFieldRegistry, eventBus) {
|
|
631
|
+
constructor(formFieldRegistry, pathRegistry, eventBus) {
|
|
417
632
|
this._formFieldRegistry = formFieldRegistry;
|
|
633
|
+
this._pathRegistry = pathRegistry;
|
|
418
634
|
this._eventBus = eventBus;
|
|
419
635
|
}
|
|
420
636
|
|
|
@@ -425,19 +641,27 @@ class ConditionChecker {
|
|
|
425
641
|
* @param {Object<string, any>} data
|
|
426
642
|
*/
|
|
427
643
|
applyConditions(properties, data = {}) {
|
|
428
|
-
const
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
for (const {
|
|
433
|
-
key,
|
|
434
|
-
condition
|
|
435
|
-
} of conditions) {
|
|
436
|
-
const shouldRemove = this._checkHideCondition(condition, data);
|
|
437
|
-
if (shouldRemove) {
|
|
438
|
-
delete newProperties[key];
|
|
439
|
-
}
|
|
644
|
+
const newProperties = clone(properties);
|
|
645
|
+
const form = this._formFieldRegistry.getAll().find(field => field.type === 'default');
|
|
646
|
+
if (!form) {
|
|
647
|
+
throw new Error('form field registry has no form');
|
|
440
648
|
}
|
|
649
|
+
this._pathRegistry.executeRecursivelyOnFields(form, ({
|
|
650
|
+
field,
|
|
651
|
+
isClosed,
|
|
652
|
+
context
|
|
653
|
+
}) => {
|
|
654
|
+
const {
|
|
655
|
+
conditional: condition
|
|
656
|
+
} = field;
|
|
657
|
+
context.isHidden = context.isHidden || condition && this._checkHideCondition(condition, data);
|
|
658
|
+
|
|
659
|
+
// only clear the leaf nodes, as groups may both point to the same path
|
|
660
|
+
if (context.isHidden && isClosed) {
|
|
661
|
+
const valuePath = this._pathRegistry.getValuePath(field);
|
|
662
|
+
this._clearObjectValueRecursively(valuePath, newProperties);
|
|
663
|
+
}
|
|
664
|
+
});
|
|
441
665
|
return newProperties;
|
|
442
666
|
}
|
|
443
667
|
|
|
@@ -482,24 +706,18 @@ class ConditionChecker {
|
|
|
482
706
|
const result = this.check(condition.hide, data);
|
|
483
707
|
return result === true;
|
|
484
708
|
}
|
|
485
|
-
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
key,
|
|
495
|
-
condition
|
|
496
|
-
}];
|
|
497
|
-
}
|
|
498
|
-
return conditions;
|
|
499
|
-
}, []);
|
|
709
|
+
_clearObjectValueRecursively(valuePath, obj) {
|
|
710
|
+
const workingValuePath = [...valuePath];
|
|
711
|
+
let recurse = false;
|
|
712
|
+
do {
|
|
713
|
+
minDash.set(obj, workingValuePath, undefined);
|
|
714
|
+
workingValuePath.pop();
|
|
715
|
+
const parentObject = minDash.get(obj, workingValuePath);
|
|
716
|
+
recurse = minDash.isObject(parentObject) && !minDash.values(parentObject).length && !!workingValuePath.length;
|
|
717
|
+
} while (recurse);
|
|
500
718
|
}
|
|
501
719
|
}
|
|
502
|
-
ConditionChecker.$inject = ['formFieldRegistry', 'eventBus'];
|
|
720
|
+
ConditionChecker.$inject = ['formFieldRegistry', 'pathRegistry', 'eventBus'];
|
|
503
721
|
|
|
504
722
|
var ExpressionLanguageModule = {
|
|
505
723
|
__init__: ['expressionLanguage', 'templating', 'conditionChecker'],
|
|
@@ -967,239 +1185,42 @@ CommandStack.prototype._popAction = function () {
|
|
|
967
1185
|
execution.trigger = null;
|
|
968
1186
|
}
|
|
969
1187
|
};
|
|
970
|
-
CommandStack.prototype._markDirty = function (elements) {
|
|
971
|
-
const execution = this._currentExecution;
|
|
972
|
-
if (!elements) {
|
|
973
|
-
return;
|
|
974
|
-
}
|
|
975
|
-
elements = minDash.isArray(elements) ? elements : [elements];
|
|
976
|
-
execution.dirty = execution.dirty.concat(elements);
|
|
977
|
-
};
|
|
978
|
-
CommandStack.prototype._executedAction = function (action, redo) {
|
|
979
|
-
const stackIdx = ++this._stackIdx;
|
|
980
|
-
if (!redo) {
|
|
981
|
-
this._stack.splice(stackIdx, this._stack.length, action);
|
|
982
|
-
}
|
|
983
|
-
};
|
|
984
|
-
CommandStack.prototype._revertedAction = function (action) {
|
|
985
|
-
this._stackIdx--;
|
|
986
|
-
};
|
|
987
|
-
CommandStack.prototype._getHandler = function (command) {
|
|
988
|
-
return this._handlerMap[command];
|
|
989
|
-
};
|
|
990
|
-
CommandStack.prototype._setHandler = function (command, handler) {
|
|
991
|
-
if (!command || !handler) {
|
|
992
|
-
throw new Error('command and handler required');
|
|
993
|
-
}
|
|
994
|
-
if (this._handlerMap[command]) {
|
|
995
|
-
throw new Error('overriding handler for command <' + command + '>');
|
|
996
|
-
}
|
|
997
|
-
this._handlerMap[command] = handler;
|
|
998
|
-
};
|
|
999
|
-
|
|
1000
|
-
/**
|
|
1001
|
-
* @type { import('didi').ModuleDeclaration }
|
|
1002
|
-
*/
|
|
1003
|
-
var commandModule = {
|
|
1004
|
-
commandStack: ['type', CommandStack]
|
|
1005
|
-
};
|
|
1006
|
-
|
|
1007
|
-
// config ///////////////////
|
|
1008
|
-
|
|
1009
|
-
const MINUTES_IN_DAY = 60 * 24;
|
|
1010
|
-
const DATETIME_SUBTYPES = {
|
|
1011
|
-
DATE: 'date',
|
|
1012
|
-
TIME: 'time',
|
|
1013
|
-
DATETIME: 'datetime'
|
|
1014
|
-
};
|
|
1015
|
-
const TIME_SERIALISING_FORMATS = {
|
|
1016
|
-
UTC_OFFSET: 'utc_offset',
|
|
1017
|
-
UTC_NORMALIZED: 'utc_normalized',
|
|
1018
|
-
NO_TIMEZONE: 'no_timezone'
|
|
1019
|
-
};
|
|
1020
|
-
const DATETIME_SUBTYPES_LABELS = {
|
|
1021
|
-
[DATETIME_SUBTYPES.DATE]: 'Date',
|
|
1022
|
-
[DATETIME_SUBTYPES.TIME]: 'Time',
|
|
1023
|
-
[DATETIME_SUBTYPES.DATETIME]: 'Date & Time'
|
|
1024
|
-
};
|
|
1025
|
-
const TIME_SERIALISINGFORMAT_LABELS = {
|
|
1026
|
-
[TIME_SERIALISING_FORMATS.UTC_OFFSET]: 'UTC offset',
|
|
1027
|
-
[TIME_SERIALISING_FORMATS.UTC_NORMALIZED]: 'UTC normalized',
|
|
1028
|
-
[TIME_SERIALISING_FORMATS.NO_TIMEZONE]: 'No timezone'
|
|
1029
|
-
};
|
|
1030
|
-
const DATETIME_SUBTYPE_PATH = ['subtype'];
|
|
1031
|
-
const DATE_LABEL_PATH = ['dateLabel'];
|
|
1032
|
-
const DATE_DISALLOW_PAST_PATH = ['disallowPassedDates'];
|
|
1033
|
-
const TIME_LABEL_PATH = ['timeLabel'];
|
|
1034
|
-
const TIME_USE24H_PATH = ['use24h'];
|
|
1035
|
-
const TIME_INTERVAL_PATH = ['timeInterval'];
|
|
1036
|
-
const TIME_SERIALISING_FORMAT_PATH = ['timeSerializingFormat'];
|
|
1037
|
-
|
|
1038
|
-
// config ///////////////////
|
|
1039
|
-
|
|
1040
|
-
const VALUES_SOURCES = {
|
|
1041
|
-
STATIC: 'static',
|
|
1042
|
-
INPUT: 'input',
|
|
1043
|
-
EXPRESSION: 'expression'
|
|
1044
|
-
};
|
|
1045
|
-
const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
|
|
1046
|
-
const VALUES_SOURCES_LABELS = {
|
|
1047
|
-
[VALUES_SOURCES.STATIC]: 'Static',
|
|
1048
|
-
[VALUES_SOURCES.INPUT]: 'Input data',
|
|
1049
|
-
[VALUES_SOURCES.EXPRESSION]: 'Expression'
|
|
1050
|
-
};
|
|
1051
|
-
const VALUES_SOURCES_PATHS = {
|
|
1052
|
-
[VALUES_SOURCES.STATIC]: ['values'],
|
|
1053
|
-
[VALUES_SOURCES.INPUT]: ['valuesKey'],
|
|
1054
|
-
[VALUES_SOURCES.EXPRESSION]: ['valuesExpression']
|
|
1055
|
-
};
|
|
1056
|
-
const VALUES_SOURCES_DEFAULTS = {
|
|
1057
|
-
[VALUES_SOURCES.STATIC]: [{
|
|
1058
|
-
label: 'Value',
|
|
1059
|
-
value: 'value'
|
|
1060
|
-
}],
|
|
1061
|
-
[VALUES_SOURCES.INPUT]: '',
|
|
1062
|
-
[VALUES_SOURCES.EXPRESSION]: '='
|
|
1063
|
-
};
|
|
1064
|
-
|
|
1065
|
-
// helpers ///////////////////
|
|
1066
|
-
|
|
1067
|
-
function getValuesSource(field) {
|
|
1068
|
-
for (const source of Object.values(VALUES_SOURCES)) {
|
|
1069
|
-
if (minDash.get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
|
|
1070
|
-
return source;
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
return VALUES_SOURCE_DEFAULT;
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
function createInjector(bootstrapModules) {
|
|
1077
|
-
const injector = new didi.Injector(bootstrapModules);
|
|
1078
|
-
injector.init();
|
|
1079
|
-
return injector;
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
/**
|
|
1083
|
-
* @param {string?} prefix
|
|
1084
|
-
*
|
|
1085
|
-
* @returns Element
|
|
1086
|
-
*/
|
|
1087
|
-
function createFormContainer(prefix = 'fjs') {
|
|
1088
|
-
const container = document.createElement('div');
|
|
1089
|
-
container.classList.add(`${prefix}-container`);
|
|
1090
|
-
return container;
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression'];
|
|
1094
|
-
const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text'];
|
|
1095
|
-
function findErrors(errors, path) {
|
|
1096
|
-
return errors[pathStringify(path)];
|
|
1097
|
-
}
|
|
1098
|
-
function isRequired(field) {
|
|
1099
|
-
return field.required;
|
|
1100
|
-
}
|
|
1101
|
-
function pathParse(path) {
|
|
1102
|
-
if (!path) {
|
|
1103
|
-
return [];
|
|
1104
|
-
}
|
|
1105
|
-
return path.split('.').map(key => {
|
|
1106
|
-
return isNaN(parseInt(key)) ? key : parseInt(key);
|
|
1107
|
-
});
|
|
1108
|
-
}
|
|
1109
|
-
function pathsEqual(a, b) {
|
|
1110
|
-
return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
|
|
1111
|
-
}
|
|
1112
|
-
function pathStringify(path) {
|
|
1113
|
-
if (!path) {
|
|
1114
|
-
return '';
|
|
1115
|
-
}
|
|
1116
|
-
return path.join('.');
|
|
1117
|
-
}
|
|
1118
|
-
const indices = {};
|
|
1119
|
-
function generateIndexForType(type) {
|
|
1120
|
-
if (type in indices) {
|
|
1121
|
-
indices[type]++;
|
|
1122
|
-
} else {
|
|
1123
|
-
indices[type] = 1;
|
|
1124
|
-
}
|
|
1125
|
-
return indices[type];
|
|
1126
|
-
}
|
|
1127
|
-
function generateIdForType(type) {
|
|
1128
|
-
return `${type}${generateIndexForType(type)}`;
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
/**
|
|
1132
|
-
* @template T
|
|
1133
|
-
* @param {T} data
|
|
1134
|
-
* @param {(this: any, key: string, value: any) => any} [replacer]
|
|
1135
|
-
* @return {T}
|
|
1136
|
-
*/
|
|
1137
|
-
function clone(data, replacer) {
|
|
1138
|
-
return JSON.parse(JSON.stringify(data, replacer));
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
/**
|
|
1142
|
-
* Parse the schema for input variables a form might make use of
|
|
1143
|
-
*
|
|
1144
|
-
* @param {any} schema
|
|
1145
|
-
*
|
|
1146
|
-
* @return {string[]}
|
|
1147
|
-
*/
|
|
1148
|
-
function getSchemaVariables(schema, options = {}) {
|
|
1149
|
-
const {
|
|
1150
|
-
expressionLanguage = new FeelExpressionLanguage(null),
|
|
1151
|
-
templating = new FeelersTemplating(),
|
|
1152
|
-
inputs = true,
|
|
1153
|
-
outputs = true
|
|
1154
|
-
} = options;
|
|
1155
|
-
if (!schema.components) {
|
|
1156
|
-
return [];
|
|
1157
|
-
}
|
|
1158
|
-
const variables = schema.components.reduce((variables, component) => {
|
|
1159
|
-
const {
|
|
1160
|
-
key,
|
|
1161
|
-
valuesKey,
|
|
1162
|
-
type
|
|
1163
|
-
} = component;
|
|
1164
|
-
if (['button'].includes(type)) {
|
|
1165
|
-
return variables;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
// collect bi-directional variables
|
|
1169
|
-
if (inputs || outputs) {
|
|
1170
|
-
if (key) {
|
|
1171
|
-
variables = [...variables, key];
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
// collect input-only variables
|
|
1176
|
-
if (inputs) {
|
|
1177
|
-
if (valuesKey) {
|
|
1178
|
-
variables = [...variables, valuesKey];
|
|
1179
|
-
}
|
|
1180
|
-
EXPRESSION_PROPERTIES.forEach(prop => {
|
|
1181
|
-
const property = minDash.get(component, prop.split('.'));
|
|
1182
|
-
if (property && expressionLanguage.isExpression(property)) {
|
|
1183
|
-
const expressionVariables = expressionLanguage.getVariableNames(property, {
|
|
1184
|
-
type: 'expression'
|
|
1185
|
-
});
|
|
1186
|
-
variables = [...variables, ...expressionVariables];
|
|
1187
|
-
}
|
|
1188
|
-
});
|
|
1189
|
-
TEMPLATE_PROPERTIES.forEach(prop => {
|
|
1190
|
-
const property = minDash.get(component, prop.split('.'));
|
|
1191
|
-
if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) {
|
|
1192
|
-
const templateVariables = templating.getVariableNames(property);
|
|
1193
|
-
variables = [...variables, ...templateVariables];
|
|
1194
|
-
}
|
|
1195
|
-
});
|
|
1196
|
-
}
|
|
1197
|
-
return variables.filter(variable => variable !== undefined || variable !== null);
|
|
1198
|
-
}, []);
|
|
1188
|
+
CommandStack.prototype._markDirty = function (elements) {
|
|
1189
|
+
const execution = this._currentExecution;
|
|
1190
|
+
if (!elements) {
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
elements = minDash.isArray(elements) ? elements : [elements];
|
|
1194
|
+
execution.dirty = execution.dirty.concat(elements);
|
|
1195
|
+
};
|
|
1196
|
+
CommandStack.prototype._executedAction = function (action, redo) {
|
|
1197
|
+
const stackIdx = ++this._stackIdx;
|
|
1198
|
+
if (!redo) {
|
|
1199
|
+
this._stack.splice(stackIdx, this._stack.length, action);
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1202
|
+
CommandStack.prototype._revertedAction = function (action) {
|
|
1203
|
+
this._stackIdx--;
|
|
1204
|
+
};
|
|
1205
|
+
CommandStack.prototype._getHandler = function (command) {
|
|
1206
|
+
return this._handlerMap[command];
|
|
1207
|
+
};
|
|
1208
|
+
CommandStack.prototype._setHandler = function (command, handler) {
|
|
1209
|
+
if (!command || !handler) {
|
|
1210
|
+
throw new Error('command and handler required');
|
|
1211
|
+
}
|
|
1212
|
+
if (this._handlerMap[command]) {
|
|
1213
|
+
throw new Error('overriding handler for command <' + command + '>');
|
|
1214
|
+
}
|
|
1215
|
+
this._handlerMap[command] = handler;
|
|
1216
|
+
};
|
|
1199
1217
|
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1218
|
+
/**
|
|
1219
|
+
* @type { import('didi').ModuleDeclaration }
|
|
1220
|
+
*/
|
|
1221
|
+
var commandModule = {
|
|
1222
|
+
commandStack: ['type', CommandStack]
|
|
1223
|
+
};
|
|
1203
1224
|
|
|
1204
1225
|
class UpdateFieldValidationHandler {
|
|
1205
1226
|
constructor(form, validator) {
|
|
@@ -1211,15 +1232,12 @@ class UpdateFieldValidationHandler {
|
|
|
1211
1232
|
field,
|
|
1212
1233
|
value
|
|
1213
1234
|
} = context;
|
|
1214
|
-
const {
|
|
1215
|
-
_path
|
|
1216
|
-
} = field;
|
|
1217
1235
|
const {
|
|
1218
1236
|
errors
|
|
1219
1237
|
} = this._form._getState();
|
|
1220
1238
|
context.oldErrors = clone(errors);
|
|
1221
1239
|
const fieldErrors = this._validator.validateField(field, value);
|
|
1222
|
-
const updatedErrors = minDash.set(errors, [
|
|
1240
|
+
const updatedErrors = minDash.set(errors, [field.id], fieldErrors.length ? fieldErrors : undefined);
|
|
1223
1241
|
this._form._setState({
|
|
1224
1242
|
errors: updatedErrors
|
|
1225
1243
|
});
|
|
@@ -1902,54 +1920,397 @@ function evaluateFEELValues(validate, expressionLanguage, conditionChecker, form
|
|
|
1902
1920
|
return evaluatedValidate;
|
|
1903
1921
|
}
|
|
1904
1922
|
|
|
1905
|
-
class
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1923
|
+
class Importer {
|
|
1924
|
+
/**
|
|
1925
|
+
* @constructor
|
|
1926
|
+
* @param { import('./FormFieldRegistry').default } formFieldRegistry
|
|
1927
|
+
* @param { import('./PathRegistry').default } pathRegistry
|
|
1928
|
+
* @param { import('./FieldFactory').default } fieldFactory
|
|
1929
|
+
* @param { import('./FormLayouter').default } formLayouter
|
|
1930
|
+
*/
|
|
1931
|
+
constructor(formFieldRegistry, pathRegistry, fieldFactory, formLayouter) {
|
|
1932
|
+
this._formFieldRegistry = formFieldRegistry;
|
|
1933
|
+
this._pathRegistry = pathRegistry;
|
|
1934
|
+
this._fieldFactory = fieldFactory;
|
|
1935
|
+
this._formLayouter = formLayouter;
|
|
1912
1936
|
}
|
|
1913
|
-
|
|
1937
|
+
|
|
1938
|
+
/**
|
|
1939
|
+
* Import schema creating rows, fields, attaching additional
|
|
1940
|
+
* information to each field and adding fields to the
|
|
1941
|
+
* field registry.
|
|
1942
|
+
*
|
|
1943
|
+
* Additional information attached:
|
|
1944
|
+
*
|
|
1945
|
+
* * `id` (unless present)
|
|
1946
|
+
* * `_parent`
|
|
1947
|
+
* * `_path`
|
|
1948
|
+
*
|
|
1949
|
+
* @param {any} schema
|
|
1950
|
+
*
|
|
1951
|
+
* @typedef {{ warnings: Error[], schema: any }} ImportResult
|
|
1952
|
+
* @returns {ImportResult}
|
|
1953
|
+
*/
|
|
1954
|
+
importSchema(schema) {
|
|
1955
|
+
// TODO: Add warnings
|
|
1956
|
+
const warnings = [];
|
|
1957
|
+
try {
|
|
1958
|
+
this._cleanup();
|
|
1959
|
+
const importedSchema = this.importFormField(clone(schema));
|
|
1960
|
+
this._formLayouter.calculateLayout(clone(importedSchema));
|
|
1961
|
+
return {
|
|
1962
|
+
schema: importedSchema,
|
|
1963
|
+
warnings
|
|
1964
|
+
};
|
|
1965
|
+
} catch (err) {
|
|
1966
|
+
this._cleanup();
|
|
1967
|
+
err.warnings = warnings;
|
|
1968
|
+
throw err;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
_cleanup() {
|
|
1972
|
+
this._formLayouter.clear();
|
|
1973
|
+
this._formFieldRegistry.clear();
|
|
1974
|
+
this._pathRegistry.clear();
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
/**
|
|
1978
|
+
* @param {{[x: string]: any}} fieldAttrs
|
|
1979
|
+
* @param {String} [parentId]
|
|
1980
|
+
* @param {number} [index]
|
|
1981
|
+
*
|
|
1982
|
+
* @return {any} field
|
|
1983
|
+
*/
|
|
1984
|
+
importFormField(fieldAttrs, parentId, index) {
|
|
1914
1985
|
const {
|
|
1915
|
-
|
|
1916
|
-
} =
|
|
1917
|
-
|
|
1918
|
-
|
|
1986
|
+
components
|
|
1987
|
+
} = fieldAttrs;
|
|
1988
|
+
let parent, path;
|
|
1989
|
+
if (parentId) {
|
|
1990
|
+
parent = this._formFieldRegistry.get(parentId);
|
|
1919
1991
|
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1992
|
+
|
|
1993
|
+
// set form field path
|
|
1994
|
+
path = parent ? [...parent._path, 'components', index] : [];
|
|
1995
|
+
const field = this._fieldFactory.create({
|
|
1996
|
+
...fieldAttrs,
|
|
1997
|
+
_path: path,
|
|
1998
|
+
_parent: parentId
|
|
1999
|
+
}, false);
|
|
2000
|
+
this._formFieldRegistry.add(field);
|
|
2001
|
+
if (components) {
|
|
2002
|
+
field.components = this.importFormFields(components, field.id);
|
|
2003
|
+
}
|
|
2004
|
+
return field;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
/**
|
|
2008
|
+
* @param {Array<any>} components
|
|
2009
|
+
* @param {string} parentId
|
|
2010
|
+
*
|
|
2011
|
+
* @return {Array<any>} imported components
|
|
2012
|
+
*/
|
|
2013
|
+
importFormFields(components, parentId) {
|
|
2014
|
+
return components.map((component, index) => {
|
|
2015
|
+
return this.importFormField(component, parentId, index);
|
|
1922
2016
|
});
|
|
1923
|
-
this._formFields[id] = formField;
|
|
1924
2017
|
}
|
|
1925
|
-
|
|
2018
|
+
}
|
|
2019
|
+
Importer.$inject = ['formFieldRegistry', 'pathRegistry', 'fieldFactory', 'formLayouter'];
|
|
2020
|
+
|
|
2021
|
+
class FieldFactory {
|
|
2022
|
+
/**
|
|
2023
|
+
* @constructor
|
|
2024
|
+
*
|
|
2025
|
+
* @param formFieldRegistry
|
|
2026
|
+
* @param formFields
|
|
2027
|
+
*/
|
|
2028
|
+
constructor(formFieldRegistry, pathRegistry, formFields) {
|
|
2029
|
+
this._formFieldRegistry = formFieldRegistry;
|
|
2030
|
+
this._pathRegistry = pathRegistry;
|
|
2031
|
+
this._formFields = formFields;
|
|
2032
|
+
}
|
|
2033
|
+
create(attrs, applyDefaults = true) {
|
|
1926
2034
|
const {
|
|
1927
|
-
id
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
2035
|
+
id,
|
|
2036
|
+
type,
|
|
2037
|
+
key,
|
|
2038
|
+
path,
|
|
2039
|
+
_parent
|
|
2040
|
+
} = attrs;
|
|
2041
|
+
const fieldDefinition = this._formFields.get(type);
|
|
2042
|
+
if (!fieldDefinition) {
|
|
2043
|
+
throw new Error(`form field of type <${type}> not supported`);
|
|
1931
2044
|
}
|
|
1932
|
-
|
|
1933
|
-
|
|
2045
|
+
const {
|
|
2046
|
+
config
|
|
2047
|
+
} = fieldDefinition;
|
|
2048
|
+
if (!config) {
|
|
2049
|
+
throw new Error(`form field of type <${type}> has no config`);
|
|
2050
|
+
}
|
|
2051
|
+
if (id && this._formFieldRegistry._ids.assigned(id)) {
|
|
2052
|
+
throw new Error(`form field with id <${id}> already exists`);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
// ensure that we can claim the path
|
|
2056
|
+
|
|
2057
|
+
const parent = _parent && this._formFieldRegistry.get(_parent);
|
|
2058
|
+
const parentPath = parent && this._pathRegistry.getValuePath(parent) || [];
|
|
2059
|
+
if (config.keyed && key && !this._pathRegistry.canClaimPath([...parentPath, ...key.split('.')], true)) {
|
|
2060
|
+
throw new Error(`binding path '${[...parentPath, key].join('.')}' is already claimed`);
|
|
2061
|
+
}
|
|
2062
|
+
if (config.pathed && path && !this._pathRegistry.canClaimPath([...parentPath, ...path.split('.')], false)) {
|
|
2063
|
+
throw new Error(`binding path '${[...parentPath, ...path.split('.')].join('.')}' is already claimed`);
|
|
2064
|
+
}
|
|
2065
|
+
const labelAttrs = applyDefaults && config.label ? {
|
|
2066
|
+
label: config.label
|
|
2067
|
+
} : {};
|
|
2068
|
+
const field = config.create({
|
|
2069
|
+
...labelAttrs,
|
|
2070
|
+
...attrs
|
|
1934
2071
|
});
|
|
1935
|
-
|
|
2072
|
+
this._ensureId(field);
|
|
2073
|
+
if (config.keyed) {
|
|
2074
|
+
this._ensureKey(field);
|
|
2075
|
+
}
|
|
2076
|
+
if (config.pathed && path) {
|
|
2077
|
+
this._pathRegistry.claimPath(this._pathRegistry.getValuePath(field), false);
|
|
2078
|
+
}
|
|
2079
|
+
return field;
|
|
1936
2080
|
}
|
|
1937
|
-
|
|
1938
|
-
|
|
2081
|
+
_ensureId(field) {
|
|
2082
|
+
if (field.id) {
|
|
2083
|
+
this._formFieldRegistry._ids.claim(field.id, field);
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
let prefix = 'Field';
|
|
2087
|
+
if (field.type === 'default') {
|
|
2088
|
+
prefix = 'Form';
|
|
2089
|
+
}
|
|
2090
|
+
field.id = this._formFieldRegistry._ids.nextPrefixed(`${prefix}_`, field);
|
|
1939
2091
|
}
|
|
1940
|
-
|
|
1941
|
-
|
|
2092
|
+
_ensureKey(field) {
|
|
2093
|
+
if (!field.key) {
|
|
2094
|
+
let random;
|
|
2095
|
+
const parent = this._formFieldRegistry.get(field._parent);
|
|
2096
|
+
|
|
2097
|
+
// ensure key uniqueness at level
|
|
2098
|
+
do {
|
|
2099
|
+
random = Math.random().toString(36).substring(7);
|
|
2100
|
+
} while (parent && parent.components.some(child => child.key === random));
|
|
2101
|
+
field.key = `${field.type}_${random}`;
|
|
2102
|
+
}
|
|
2103
|
+
this._pathRegistry.claimPath(this._pathRegistry.getValuePath(field), true);
|
|
1942
2104
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
2105
|
+
}
|
|
2106
|
+
FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields'];
|
|
2107
|
+
|
|
2108
|
+
/**
|
|
2109
|
+
* The PathRegistry class manages a hierarchical structure of paths associated with form fields.
|
|
2110
|
+
* It enables claiming, unclaiming, and validating paths within this structure.
|
|
2111
|
+
*
|
|
2112
|
+
* Example Tree Structure:
|
|
2113
|
+
*
|
|
2114
|
+
* [
|
|
2115
|
+
* {
|
|
2116
|
+
* segment: 'root',
|
|
2117
|
+
* claimCount: 1,
|
|
2118
|
+
* children: [
|
|
2119
|
+
* {
|
|
2120
|
+
* segment: 'child1',
|
|
2121
|
+
* claimCount: 2,
|
|
2122
|
+
* children: null // A leaf node (closed path)
|
|
2123
|
+
* },
|
|
2124
|
+
* {
|
|
2125
|
+
* segment: 'child2',
|
|
2126
|
+
* claimCount: 1,
|
|
2127
|
+
* children: [
|
|
2128
|
+
* {
|
|
2129
|
+
* segment: 'subChild1',
|
|
2130
|
+
* claimCount: 1,
|
|
2131
|
+
* children: [] // An open node (open path)
|
|
2132
|
+
* }
|
|
2133
|
+
* ]
|
|
2134
|
+
* }
|
|
2135
|
+
* ]
|
|
2136
|
+
* }
|
|
2137
|
+
* ]
|
|
2138
|
+
*/
|
|
2139
|
+
class PathRegistry {
|
|
2140
|
+
constructor(formFieldRegistry, formFields) {
|
|
2141
|
+
this._formFieldRegistry = formFieldRegistry;
|
|
2142
|
+
this._formFields = formFields;
|
|
2143
|
+
this._dataPaths = [];
|
|
2144
|
+
}
|
|
2145
|
+
canClaimPath(path, closed = false) {
|
|
2146
|
+
let node = {
|
|
2147
|
+
children: this._dataPaths
|
|
2148
|
+
};
|
|
2149
|
+
for (const segment of path) {
|
|
2150
|
+
node = _getNextSegment(node, segment);
|
|
2151
|
+
|
|
2152
|
+
// if no node at that path, we can claim it no matter what
|
|
2153
|
+
if (!node) {
|
|
2154
|
+
return true;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
// if we reach a leaf node, definitely not claimable
|
|
2158
|
+
if (node.children === null) {
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
// if after all segments we reach a node with children, we can claim it only openly
|
|
2164
|
+
return !closed;
|
|
2165
|
+
}
|
|
2166
|
+
claimPath(path, closed = false) {
|
|
2167
|
+
if (!this.canClaimPath(path, closed)) {
|
|
2168
|
+
throw new Error(`cannot claim path '${path.join('.')}'`);
|
|
2169
|
+
}
|
|
2170
|
+
let node = {
|
|
2171
|
+
children: this._dataPaths
|
|
2172
|
+
};
|
|
2173
|
+
for (const segment of path) {
|
|
2174
|
+
let child = _getNextSegment(node, segment);
|
|
2175
|
+
if (!child) {
|
|
2176
|
+
child = {
|
|
2177
|
+
segment,
|
|
2178
|
+
claimCount: 1,
|
|
2179
|
+
children: []
|
|
2180
|
+
};
|
|
2181
|
+
node.children.push(child);
|
|
2182
|
+
} else {
|
|
2183
|
+
child.claimCount++;
|
|
2184
|
+
}
|
|
2185
|
+
node = child;
|
|
2186
|
+
}
|
|
2187
|
+
if (closed) {
|
|
2188
|
+
node.children = null;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
unclaimPath(path) {
|
|
2192
|
+
// verification Pass
|
|
2193
|
+
let node = {
|
|
2194
|
+
children: this._dataPaths
|
|
2195
|
+
};
|
|
2196
|
+
for (const segment of path) {
|
|
2197
|
+
const child = _getNextSegment(node, segment);
|
|
2198
|
+
if (!child) {
|
|
2199
|
+
throw new Error(`no open path found for '${path.join('.')}'`);
|
|
2200
|
+
}
|
|
2201
|
+
node = child;
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
// mutation Pass
|
|
2205
|
+
node = {
|
|
2206
|
+
children: this._dataPaths
|
|
2207
|
+
};
|
|
2208
|
+
for (const segment of path) {
|
|
2209
|
+
const child = _getNextSegment(node, segment);
|
|
2210
|
+
child.claimCount--;
|
|
2211
|
+
if (child.claimCount === 0) {
|
|
2212
|
+
node.children.splice(node.children.indexOf(child), 1);
|
|
2213
|
+
break; // Abort early if claimCount reaches zero
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
node = child;
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
/**
|
|
2221
|
+
* Applies a function (fn) recursively on a given field and its children.
|
|
2222
|
+
*
|
|
2223
|
+
* - `field`: Starting field object.
|
|
2224
|
+
* - `fn`: Function to apply.
|
|
2225
|
+
* - `context`: Optional object for passing data between calls.
|
|
2226
|
+
*
|
|
2227
|
+
* Stops early if `fn` returns `false`. Useful for traversing the form field tree.
|
|
2228
|
+
*
|
|
2229
|
+
* @returns {boolean} Success status based on function execution.
|
|
2230
|
+
*/
|
|
2231
|
+
executeRecursivelyOnFields(field, fn, context = {}) {
|
|
2232
|
+
let result = true;
|
|
2233
|
+
const formFieldConfig = this._formFields.get(field.type).config;
|
|
2234
|
+
if (formFieldConfig.keyed) {
|
|
2235
|
+
const callResult = fn({
|
|
2236
|
+
field,
|
|
2237
|
+
isClosed: true,
|
|
2238
|
+
context
|
|
2239
|
+
});
|
|
2240
|
+
return result && callResult;
|
|
2241
|
+
} else if (formFieldConfig.pathed) {
|
|
2242
|
+
const callResult = fn({
|
|
2243
|
+
field,
|
|
2244
|
+
isClosed: false,
|
|
2245
|
+
context
|
|
2246
|
+
});
|
|
2247
|
+
result = result && callResult;
|
|
2248
|
+
}
|
|
2249
|
+
if (field.components) {
|
|
2250
|
+
for (const child of field.components) {
|
|
2251
|
+
const callResult = this.executeRecursivelyOnFields(child, fn, clone(context));
|
|
2252
|
+
result = result && callResult;
|
|
2253
|
+
|
|
2254
|
+
// only stop executing if false is specifically returned, not if undefined
|
|
2255
|
+
if (result === false) {
|
|
2256
|
+
return result;
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
return result;
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
/**
|
|
2264
|
+
* Generates an array representing the binding path to an underlying data object for a form field.
|
|
2265
|
+
*
|
|
2266
|
+
* @param {Object} field - The field object with properties: `key`, `path`, `id`, and optionally `_parent`.
|
|
2267
|
+
* @param {Object} [options={}] - Configuration options.
|
|
2268
|
+
* @param {Object} [options.replacements={}] - A map of field IDs to alternative path arrays.
|
|
2269
|
+
* @param {Object} [options.cutoffNode] - The ID of the parent field at which to stop generating the path.
|
|
2270
|
+
*
|
|
2271
|
+
* @returns {(Array<string>|undefined)} An array of strings representing the binding path, or undefined if not determinable.
|
|
2272
|
+
*/
|
|
2273
|
+
getValuePath(field, options = {}) {
|
|
2274
|
+
const {
|
|
2275
|
+
replacements = {},
|
|
2276
|
+
cutoffNode = null
|
|
2277
|
+
} = options;
|
|
2278
|
+
let localValuePath = [];
|
|
2279
|
+
const hasReplacement = Object.prototype.hasOwnProperty.call(replacements, field.id);
|
|
2280
|
+
const formFieldConfig = this._formFields.get(field.type).config;
|
|
2281
|
+
if (hasReplacement) {
|
|
2282
|
+
const replacement = replacements[field.id];
|
|
2283
|
+
if (replacement === null || replacement === undefined || replacement === '') {
|
|
2284
|
+
localValuePath = [];
|
|
2285
|
+
} else if (typeof replacement === 'string') {
|
|
2286
|
+
localValuePath = replacement.split('.');
|
|
2287
|
+
} else if (Array.isArray(replacement)) {
|
|
2288
|
+
localValuePath = replacement;
|
|
2289
|
+
} else {
|
|
2290
|
+
throw new Error(`replacements for field ${field.id} must be a string, array or null/undefined`);
|
|
2291
|
+
}
|
|
2292
|
+
} else if (formFieldConfig.keyed) {
|
|
2293
|
+
localValuePath = field.key.split('.');
|
|
2294
|
+
} else if (formFieldConfig.pathed && field.path) {
|
|
2295
|
+
localValuePath = field.path.split('.');
|
|
2296
|
+
}
|
|
2297
|
+
if (field._parent && field._parent !== cutoffNode) {
|
|
2298
|
+
const parent = this._formFieldRegistry.get(field._parent);
|
|
2299
|
+
return [...(this.getValuePath(parent, options) || []), ...localValuePath];
|
|
2300
|
+
}
|
|
2301
|
+
return localValuePath;
|
|
1945
2302
|
}
|
|
1946
2303
|
clear() {
|
|
1947
|
-
this.
|
|
1948
|
-
this._ids.clear();
|
|
1949
|
-
this._keys.clear();
|
|
2304
|
+
this._dataPaths = [];
|
|
1950
2305
|
}
|
|
1951
2306
|
}
|
|
1952
|
-
|
|
2307
|
+
const _getNextSegment = (node, segment) => {
|
|
2308
|
+
if (minDash.isArray(node.children)) {
|
|
2309
|
+
return node.children.find(node => node.segment === segment) || null;
|
|
2310
|
+
}
|
|
2311
|
+
return null;
|
|
2312
|
+
};
|
|
2313
|
+
PathRegistry.$inject = ['formFieldRegistry', 'formFields'];
|
|
1953
2314
|
|
|
1954
2315
|
/**
|
|
1955
2316
|
* @typedef { { id: String, components: Array<String> } } FormRow
|
|
@@ -2041,7 +2402,7 @@ class FormLayouter {
|
|
|
2041
2402
|
type,
|
|
2042
2403
|
components
|
|
2043
2404
|
} = formField;
|
|
2044
|
-
if (type !== 'default' || !components) {
|
|
2405
|
+
if (type !== 'default' && type !== 'group' || !components) {
|
|
2045
2406
|
return;
|
|
2046
2407
|
}
|
|
2047
2408
|
|
|
@@ -2096,147 +2457,52 @@ function allRows(formRows) {
|
|
|
2096
2457
|
return minDash.flatten(formRows.map(c => c.rows));
|
|
2097
2458
|
}
|
|
2098
2459
|
|
|
2099
|
-
class
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
*/
|
|
2106
|
-
constructor(formFieldRegistry, formFields, formLayouter) {
|
|
2107
|
-
this._formFieldRegistry = formFieldRegistry;
|
|
2108
|
-
this._formFields = formFields;
|
|
2109
|
-
this._formLayouter = formLayouter;
|
|
2110
|
-
}
|
|
2111
|
-
|
|
2112
|
-
/**
|
|
2113
|
-
* Import schema adding `id`, `_parent` and `_path`
|
|
2114
|
-
* information to each field and adding it to the
|
|
2115
|
-
* form field registry.
|
|
2116
|
-
*
|
|
2117
|
-
* @param {any} schema
|
|
2118
|
-
* @param {any} [data]
|
|
2119
|
-
*
|
|
2120
|
-
* @return { { warnings: Array<any>, schema: any, data: any } }
|
|
2121
|
-
*/
|
|
2122
|
-
importSchema(schema, data = {}) {
|
|
2123
|
-
// TODO: Add warnings - https://github.com/bpmn-io/form-js/issues/289
|
|
2124
|
-
const warnings = [];
|
|
2125
|
-
try {
|
|
2126
|
-
this._formLayouter.clear();
|
|
2127
|
-
const importedSchema = this.importFormField(clone(schema)),
|
|
2128
|
-
initializedData = this.initializeFieldValues(clone(data));
|
|
2129
|
-
this._formLayouter.calculateLayout(clone(importedSchema));
|
|
2130
|
-
return {
|
|
2131
|
-
warnings,
|
|
2132
|
-
schema: importedSchema,
|
|
2133
|
-
data: initializedData
|
|
2134
|
-
};
|
|
2135
|
-
} catch (err) {
|
|
2136
|
-
err.warnings = warnings;
|
|
2137
|
-
throw err;
|
|
2138
|
-
}
|
|
2460
|
+
class FormFieldRegistry {
|
|
2461
|
+
constructor(eventBus) {
|
|
2462
|
+
this._eventBus = eventBus;
|
|
2463
|
+
this._formFields = {};
|
|
2464
|
+
eventBus.on('form.clear', () => this.clear());
|
|
2465
|
+
this._ids = new Ids([32, 36, 1]);
|
|
2139
2466
|
}
|
|
2140
|
-
|
|
2141
|
-
/**
|
|
2142
|
-
* @param {any} formField
|
|
2143
|
-
* @param {string} [parentId]
|
|
2144
|
-
*
|
|
2145
|
-
* @return {any} importedField
|
|
2146
|
-
*/
|
|
2147
|
-
importFormField(formField, parentId) {
|
|
2467
|
+
add(formField) {
|
|
2148
2468
|
const {
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
id
|
|
2153
|
-
} = formField;
|
|
2154
|
-
if (parentId) {
|
|
2155
|
-
// set form field parent
|
|
2156
|
-
formField._parent = parentId;
|
|
2157
|
-
}
|
|
2158
|
-
if (!this._formFields.get(type)) {
|
|
2159
|
-
throw new Error(`form field of type <${type}> not supported`);
|
|
2160
|
-
}
|
|
2161
|
-
if (key) {
|
|
2162
|
-
// validate <key> uniqueness
|
|
2163
|
-
if (this._formFieldRegistry._keys.assigned(key)) {
|
|
2164
|
-
throw new Error(`form field with key <${key}> already exists`);
|
|
2165
|
-
}
|
|
2166
|
-
this._formFieldRegistry._keys.claim(key, formField);
|
|
2167
|
-
|
|
2168
|
-
// TODO: buttons should not have key
|
|
2169
|
-
if (type !== 'button') {
|
|
2170
|
-
// set form field path
|
|
2171
|
-
formField._path = [key];
|
|
2172
|
-
}
|
|
2173
|
-
}
|
|
2174
|
-
if (id) {
|
|
2175
|
-
// validate <id> uniqueness
|
|
2176
|
-
if (this._formFieldRegistry._ids.assigned(id)) {
|
|
2177
|
-
throw new Error(`form field with id <${id}> already exists`);
|
|
2178
|
-
}
|
|
2179
|
-
this._formFieldRegistry._ids.claim(id, formField);
|
|
2180
|
-
}
|
|
2181
|
-
|
|
2182
|
-
// set form field ID
|
|
2183
|
-
formField.id = id;
|
|
2184
|
-
this._formFieldRegistry.add(formField);
|
|
2185
|
-
if (components) {
|
|
2186
|
-
this.importFormFields(components, id);
|
|
2469
|
+
id
|
|
2470
|
+
} = formField;
|
|
2471
|
+
if (this._formFields[id]) {
|
|
2472
|
+
throw new Error(`form field with ID ${id} already exists`);
|
|
2187
2473
|
}
|
|
2188
|
-
|
|
2474
|
+
this._eventBus.fire('formField.add', {
|
|
2475
|
+
formField
|
|
2476
|
+
});
|
|
2477
|
+
this._formFields[id] = formField;
|
|
2189
2478
|
}
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2479
|
+
remove(formField) {
|
|
2480
|
+
const {
|
|
2481
|
+
id
|
|
2482
|
+
} = formField;
|
|
2483
|
+
if (!this._formFields[id]) {
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2486
|
+
this._eventBus.fire('formField.remove', {
|
|
2487
|
+
formField
|
|
2193
2488
|
});
|
|
2489
|
+
delete this._formFields[id];
|
|
2194
2490
|
}
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
} = formField;
|
|
2208
|
-
|
|
2209
|
-
// try to get value from data
|
|
2210
|
-
// if unavailable - try to get default value from form field
|
|
2211
|
-
// if unavailable - get empty value from form field
|
|
2212
|
-
|
|
2213
|
-
if (_path) {
|
|
2214
|
-
const {
|
|
2215
|
-
config: fieldConfig
|
|
2216
|
-
} = this._formFields.get(type);
|
|
2217
|
-
let valueData = minDash.get(data, _path);
|
|
2218
|
-
if (!minDash.isUndefined(valueData) && fieldConfig.sanitizeValue) {
|
|
2219
|
-
valueData = fieldConfig.sanitizeValue({
|
|
2220
|
-
formField,
|
|
2221
|
-
data,
|
|
2222
|
-
value: valueData
|
|
2223
|
-
});
|
|
2224
|
-
}
|
|
2225
|
-
const initializedFieldValue = !minDash.isUndefined(valueData) ? valueData : !minDash.isUndefined(defaultValue) ? defaultValue : fieldConfig.emptyValue;
|
|
2226
|
-
initializedData = {
|
|
2227
|
-
...initializedData,
|
|
2228
|
-
[_path[0]]: initializedFieldValue
|
|
2229
|
-
};
|
|
2230
|
-
}
|
|
2231
|
-
return initializedData;
|
|
2232
|
-
}, data);
|
|
2491
|
+
get(id) {
|
|
2492
|
+
return this._formFields[id];
|
|
2493
|
+
}
|
|
2494
|
+
getAll() {
|
|
2495
|
+
return Object.values(this._formFields);
|
|
2496
|
+
}
|
|
2497
|
+
forEach(callback) {
|
|
2498
|
+
this.getAll().forEach(formField => callback(formField));
|
|
2499
|
+
}
|
|
2500
|
+
clear() {
|
|
2501
|
+
this._formFields = {};
|
|
2502
|
+
this._ids.clear();
|
|
2233
2503
|
}
|
|
2234
2504
|
}
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
var importModule = {
|
|
2238
|
-
importer: ['type', Importer]
|
|
2239
|
-
};
|
|
2505
|
+
FormFieldRegistry.$inject = ['eventBus'];
|
|
2240
2506
|
|
|
2241
2507
|
function formFieldClasses(type, {
|
|
2242
2508
|
errors = [],
|
|
@@ -2291,7 +2557,7 @@ function Button(props) {
|
|
|
2291
2557
|
}
|
|
2292
2558
|
Button.config = {
|
|
2293
2559
|
type: type$c,
|
|
2294
|
-
keyed:
|
|
2560
|
+
keyed: false,
|
|
2295
2561
|
label: 'Button',
|
|
2296
2562
|
group: 'action',
|
|
2297
2563
|
create: (options = {}) => ({
|
|
@@ -2301,6 +2567,9 @@ Button.config = {
|
|
|
2301
2567
|
};
|
|
2302
2568
|
|
|
2303
2569
|
const FormRenderContext = preact.createContext({
|
|
2570
|
+
EmptyRoot: props => {
|
|
2571
|
+
return null;
|
|
2572
|
+
},
|
|
2304
2573
|
Empty: props => {
|
|
2305
2574
|
return null;
|
|
2306
2575
|
},
|
|
@@ -2330,6 +2599,10 @@ const FormRenderContext = preact.createContext({
|
|
|
2330
2599
|
class: props.class,
|
|
2331
2600
|
children: props.children
|
|
2332
2601
|
});
|
|
2602
|
+
},
|
|
2603
|
+
hoveredId: [],
|
|
2604
|
+
setHoveredId: newValue => {
|
|
2605
|
+
console.log(`setHoveredId not defined, called with '${newValue}'`);
|
|
2333
2606
|
}
|
|
2334
2607
|
});
|
|
2335
2608
|
var FormRenderContext$1 = FormRenderContext;
|
|
@@ -2451,6 +2724,37 @@ function useReadonly(formField, properties = {}) {
|
|
|
2451
2724
|
return readonly || false;
|
|
2452
2725
|
}
|
|
2453
2726
|
|
|
2727
|
+
function usePrevious(value, defaultValue, dependencies) {
|
|
2728
|
+
const ref = hooks.useRef(defaultValue);
|
|
2729
|
+
hooks.useEffect(() => ref.current = value, dependencies);
|
|
2730
|
+
return ref.current;
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
/**
|
|
2734
|
+
* A custom hook to manage state changes with deep comparison.
|
|
2735
|
+
*
|
|
2736
|
+
* @param {any} value - The current value to manage.
|
|
2737
|
+
* @param {any} defaultValue - The initial default value for the state.
|
|
2738
|
+
* @returns {any} - Returns the current state.
|
|
2739
|
+
*/
|
|
2740
|
+
function useDeepCompareState(value, defaultValue) {
|
|
2741
|
+
const [state, setState] = hooks.useState(defaultValue);
|
|
2742
|
+
const previous = usePrevious(value, defaultValue, [value]);
|
|
2743
|
+
const changed = !compare(previous, value);
|
|
2744
|
+
hooks.useEffect(() => {
|
|
2745
|
+
if (changed) {
|
|
2746
|
+
setState(value);
|
|
2747
|
+
}
|
|
2748
|
+
}, [changed, value]);
|
|
2749
|
+
return state;
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
// helpers //////////////////////////
|
|
2753
|
+
|
|
2754
|
+
function compare(a, b) {
|
|
2755
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
2756
|
+
}
|
|
2757
|
+
|
|
2454
2758
|
/**
|
|
2455
2759
|
* Template a string reactively based on form data. If the string is not a template, it is returned as is.
|
|
2456
2760
|
* Memoised to minimize re-renders
|
|
@@ -2671,6 +2975,21 @@ function _isReadableType(value) {
|
|
|
2671
2975
|
function _isValueSomething(value) {
|
|
2672
2976
|
return value || value === 0 || value === false;
|
|
2673
2977
|
}
|
|
2978
|
+
function createEmptyOptions(options = {}) {
|
|
2979
|
+
const defaults = {};
|
|
2980
|
+
|
|
2981
|
+
// provide default values if valuesKey and valuesExpression are not set
|
|
2982
|
+
if (!options.valuesKey && !options.valuesExpression) {
|
|
2983
|
+
defaults.values = [{
|
|
2984
|
+
label: 'Value',
|
|
2985
|
+
value: 'value'
|
|
2986
|
+
}];
|
|
2987
|
+
}
|
|
2988
|
+
return {
|
|
2989
|
+
...defaults,
|
|
2990
|
+
...options
|
|
2991
|
+
};
|
|
2992
|
+
}
|
|
2674
2993
|
|
|
2675
2994
|
/**
|
|
2676
2995
|
* @enum { String }
|
|
@@ -2705,11 +3024,8 @@ function useValuesAsync (field) {
|
|
|
2705
3024
|
state: LOAD_STATES.LOADING
|
|
2706
3025
|
});
|
|
2707
3026
|
const initialData = useService('form')._getState().initialData;
|
|
2708
|
-
const
|
|
2709
|
-
|
|
2710
|
-
return useExpressionEvaluation(valuesExpression);
|
|
2711
|
-
}
|
|
2712
|
-
}, [valuesExpression]);
|
|
3027
|
+
const expressionEvaluation = useExpressionEvaluation(valuesExpression);
|
|
3028
|
+
const evaluatedValues = useDeepCompareState(expressionEvaluation || [], []);
|
|
2713
3029
|
hooks.useEffect(() => {
|
|
2714
3030
|
let values = [];
|
|
2715
3031
|
|
|
@@ -2725,8 +3041,10 @@ function useValuesAsync (field) {
|
|
|
2725
3041
|
values = Array.isArray(staticValues) ? staticValues : [];
|
|
2726
3042
|
|
|
2727
3043
|
// expression
|
|
2728
|
-
} else if (
|
|
2729
|
-
|
|
3044
|
+
} else if (valuesExpression) {
|
|
3045
|
+
if (evaluatedValues && Array.isArray(evaluatedValues)) {
|
|
3046
|
+
values = evaluatedValues;
|
|
3047
|
+
}
|
|
2730
3048
|
} else {
|
|
2731
3049
|
setValuesGetter(buildErrorState('No values source defined in the form definition'));
|
|
2732
3050
|
return;
|
|
@@ -2735,7 +3053,7 @@ function useValuesAsync (field) {
|
|
|
2735
3053
|
// normalize data to support primitives and partially defined objects
|
|
2736
3054
|
values = normalizeValuesData(values);
|
|
2737
3055
|
setValuesGetter(buildLoadedState(values));
|
|
2738
|
-
}, [valuesKey, staticValues, initialData]);
|
|
3056
|
+
}, [valuesKey, staticValues, initialData, valuesExpression, evaluatedValues]);
|
|
2739
3057
|
return valuesGetter;
|
|
2740
3058
|
}
|
|
2741
3059
|
const buildErrorState = error => ({
|
|
@@ -3047,21 +3365,7 @@ Checklist.config = {
|
|
|
3047
3365
|
group: 'selection',
|
|
3048
3366
|
emptyValue: [],
|
|
3049
3367
|
sanitizeValue: sanitizeMultiSelectValue,
|
|
3050
|
-
create:
|
|
3051
|
-
const defaults = {};
|
|
3052
|
-
|
|
3053
|
-
// provide default values if valuesKey isn't set
|
|
3054
|
-
if (!options.valuesKey) {
|
|
3055
|
-
defaults.values = [{
|
|
3056
|
-
label: 'Value',
|
|
3057
|
-
value: 'value'
|
|
3058
|
-
}];
|
|
3059
|
-
}
|
|
3060
|
-
return {
|
|
3061
|
-
...defaults,
|
|
3062
|
-
...options
|
|
3063
|
-
};
|
|
3064
|
-
}
|
|
3368
|
+
create: createEmptyOptions
|
|
3065
3369
|
};
|
|
3066
3370
|
|
|
3067
3371
|
const noop$1 = () => false;
|
|
@@ -3072,6 +3376,7 @@ function FormField(props) {
|
|
|
3072
3376
|
} = props;
|
|
3073
3377
|
const formFields = useService('formFields'),
|
|
3074
3378
|
viewerCommands = useService('viewerCommands', false),
|
|
3379
|
+
pathRegistry = useService('pathRegistry'),
|
|
3075
3380
|
form = useService('form');
|
|
3076
3381
|
const {
|
|
3077
3382
|
initialData,
|
|
@@ -3088,10 +3393,10 @@ function FormField(props) {
|
|
|
3088
3393
|
if (!FormFieldComponent) {
|
|
3089
3394
|
throw new Error(`cannot render field <${field.type}>`);
|
|
3090
3395
|
}
|
|
3091
|
-
const
|
|
3092
|
-
const
|
|
3093
|
-
const fieldErrors = findErrors(errors, field._path);
|
|
3396
|
+
const valuePath = hooks.useMemo(() => pathRegistry.getValuePath(field), [field, pathRegistry]);
|
|
3397
|
+
const initialValue = hooks.useMemo(() => minDash.get(initialData, valuePath), [initialData, valuePath]);
|
|
3094
3398
|
const readonly = useReadonly(field, properties);
|
|
3399
|
+
const value = minDash.get(data, valuePath);
|
|
3095
3400
|
|
|
3096
3401
|
// add precedence: global readonly > form field disabled
|
|
3097
3402
|
const disabled = !properties.readOnly && (properties.disabled || field.disabled || false);
|
|
@@ -3118,7 +3423,7 @@ function FormField(props) {
|
|
|
3118
3423
|
children: jsxRuntime.jsx(FormFieldComponent, {
|
|
3119
3424
|
...props,
|
|
3120
3425
|
disabled: disabled,
|
|
3121
|
-
errors:
|
|
3426
|
+
errors: errors[field.id],
|
|
3122
3427
|
onChange: disabled || readonly ? noop$1 : onChange,
|
|
3123
3428
|
onBlur: disabled || readonly ? noop$1 : onBlur,
|
|
3124
3429
|
readonly: readonly,
|
|
@@ -3128,14 +3433,14 @@ function FormField(props) {
|
|
|
3128
3433
|
});
|
|
3129
3434
|
}
|
|
3130
3435
|
|
|
3131
|
-
function
|
|
3436
|
+
function Grid(props) {
|
|
3132
3437
|
const {
|
|
3133
3438
|
Children,
|
|
3134
|
-
Empty,
|
|
3135
3439
|
Row
|
|
3136
3440
|
} = hooks.useContext(FormRenderContext$1);
|
|
3137
3441
|
const {
|
|
3138
|
-
field
|
|
3442
|
+
field,
|
|
3443
|
+
Empty
|
|
3139
3444
|
} = props;
|
|
3140
3445
|
const {
|
|
3141
3446
|
id,
|
|
@@ -3172,7 +3477,20 @@ function Default(props) {
|
|
|
3172
3477
|
}), components.length ? null : jsxRuntime.jsx(Empty, {})]
|
|
3173
3478
|
});
|
|
3174
3479
|
}
|
|
3175
|
-
|
|
3480
|
+
|
|
3481
|
+
function FormComponent$1(props) {
|
|
3482
|
+
const {
|
|
3483
|
+
EmptyRoot
|
|
3484
|
+
} = hooks.useContext(FormRenderContext$1);
|
|
3485
|
+
const fullProps = {
|
|
3486
|
+
...props,
|
|
3487
|
+
Empty: EmptyRoot
|
|
3488
|
+
};
|
|
3489
|
+
return jsxRuntime.jsx(Grid, {
|
|
3490
|
+
...fullProps
|
|
3491
|
+
});
|
|
3492
|
+
}
|
|
3493
|
+
FormComponent$1.config = {
|
|
3176
3494
|
type: 'default',
|
|
3177
3495
|
keyed: false,
|
|
3178
3496
|
label: null,
|
|
@@ -3201,6 +3519,74 @@ var SvgCalendar = function SvgCalendar(props) {
|
|
|
3201
3519
|
};
|
|
3202
3520
|
var CalendarIcon = SvgCalendar;
|
|
3203
3521
|
|
|
3522
|
+
/**
|
|
3523
|
+
* Returns date format for the provided locale.
|
|
3524
|
+
* If the locale is not provided, uses the browser's locale.
|
|
3525
|
+
*
|
|
3526
|
+
* @param {string} [locale] - The locale to get date format for.
|
|
3527
|
+
* @returns {string} The date format for the locale.
|
|
3528
|
+
*/
|
|
3529
|
+
function getLocaleDateFormat(locale = 'default') {
|
|
3530
|
+
const parts = new Intl.DateTimeFormat(locale).formatToParts(new Date(Date.UTC(2020, 5, 5)));
|
|
3531
|
+
return parts.map(part => {
|
|
3532
|
+
const len = part.value.length;
|
|
3533
|
+
switch (part.type) {
|
|
3534
|
+
case 'day':
|
|
3535
|
+
return 'd'.repeat(len);
|
|
3536
|
+
case 'month':
|
|
3537
|
+
return 'M'.repeat(len);
|
|
3538
|
+
case 'year':
|
|
3539
|
+
return 'y'.repeat(len);
|
|
3540
|
+
default:
|
|
3541
|
+
return part.value;
|
|
3542
|
+
}
|
|
3543
|
+
}).join('');
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3546
|
+
/**
|
|
3547
|
+
* Returns readable date format for the provided locale.
|
|
3548
|
+
* If the locale is not provided, uses the browser's locale.
|
|
3549
|
+
*
|
|
3550
|
+
* @param {string} [locale] - The locale to get readable date format for.
|
|
3551
|
+
* @returns {string} The readable date format for the locale.
|
|
3552
|
+
*/
|
|
3553
|
+
function getLocaleReadableDateFormat(locale) {
|
|
3554
|
+
let format = getLocaleDateFormat(locale).toLowerCase();
|
|
3555
|
+
|
|
3556
|
+
// Ensure month is in 'mm' format
|
|
3557
|
+
if (!format.includes('mm')) {
|
|
3558
|
+
format = format.replace('m', 'mm');
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3561
|
+
// Ensure day is in 'dd' format
|
|
3562
|
+
if (!format.includes('dd')) {
|
|
3563
|
+
format = format.replace('d', 'dd');
|
|
3564
|
+
}
|
|
3565
|
+
return format;
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
/**
|
|
3569
|
+
* Returns flatpickr config for the provided locale.
|
|
3570
|
+
* If the locale is not provided, uses the browser's locale.
|
|
3571
|
+
*
|
|
3572
|
+
* @param {string} [locale] - The locale to get flatpickr config for.
|
|
3573
|
+
* @returns {object} The flatpickr config for the locale.
|
|
3574
|
+
*/
|
|
3575
|
+
function getLocaleDateFlatpickrConfig(locale) {
|
|
3576
|
+
return flatpickerizeDateFormat(getLocaleDateFormat(locale));
|
|
3577
|
+
}
|
|
3578
|
+
function flatpickerizeDateFormat(dateFormat) {
|
|
3579
|
+
const useLeadingZero = {
|
|
3580
|
+
day: dateFormat.includes('dd'),
|
|
3581
|
+
month: dateFormat.includes('MM'),
|
|
3582
|
+
year: dateFormat.includes('yyyy')
|
|
3583
|
+
};
|
|
3584
|
+
dateFormat = useLeadingZero.day ? dateFormat.replace('dd', 'd') : dateFormat.replace('d', 'j');
|
|
3585
|
+
dateFormat = useLeadingZero.month ? dateFormat.replace('MM', 'm') : dateFormat.replace('M', 'n');
|
|
3586
|
+
dateFormat = useLeadingZero.year ? dateFormat.replace('yyyy', 'Y') : dateFormat.replace('yy', 'y');
|
|
3587
|
+
return dateFormat;
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3204
3590
|
function InputAdorner(props) {
|
|
3205
3591
|
const {
|
|
3206
3592
|
pre,
|
|
@@ -3275,7 +3661,7 @@ function Datepicker(props) {
|
|
|
3275
3661
|
hooks.useEffect(() => {
|
|
3276
3662
|
let config = {
|
|
3277
3663
|
allowInput: true,
|
|
3278
|
-
dateFormat:
|
|
3664
|
+
dateFormat: getLocaleDateFlatpickrConfig(),
|
|
3279
3665
|
static: true,
|
|
3280
3666
|
clickOpens: false,
|
|
3281
3667
|
// TODO: support dates prior to 1900 (https://github.com/bpmn-io/form-js/issues/533)
|
|
@@ -3367,7 +3753,7 @@ function Datepicker(props) {
|
|
|
3367
3753
|
class: "fjs-input",
|
|
3368
3754
|
disabled: disabled,
|
|
3369
3755
|
readOnly: readonly,
|
|
3370
|
-
placeholder:
|
|
3756
|
+
placeholder: getLocaleReadableDateFormat(),
|
|
3371
3757
|
autoComplete: "off",
|
|
3372
3758
|
onFocus: onInputFocus,
|
|
3373
3759
|
onKeyDown: onInputKeyDown,
|
|
@@ -3452,7 +3838,8 @@ function DropdownList(props) {
|
|
|
3452
3838
|
hooks.useEffect(() => {
|
|
3453
3839
|
const individualEntries = dropdownContainer.current.children;
|
|
3454
3840
|
if (individualEntries.length && !mouseControl) {
|
|
3455
|
-
individualEntries[focusedValueIndex]
|
|
3841
|
+
const focusedEntry = individualEntries[focusedValueIndex];
|
|
3842
|
+
focusedEntry && focusedEntry.scrollIntoView({
|
|
3456
3843
|
block: 'nearest',
|
|
3457
3844
|
inline: 'nearest'
|
|
3458
3845
|
});
|
|
@@ -3988,6 +4375,52 @@ function FormComponent(props) {
|
|
|
3988
4375
|
});
|
|
3989
4376
|
}
|
|
3990
4377
|
|
|
4378
|
+
function Group(props) {
|
|
4379
|
+
const {
|
|
4380
|
+
field
|
|
4381
|
+
} = props;
|
|
4382
|
+
const {
|
|
4383
|
+
label,
|
|
4384
|
+
id,
|
|
4385
|
+
type,
|
|
4386
|
+
showOutline
|
|
4387
|
+
} = field;
|
|
4388
|
+
const {
|
|
4389
|
+
formId
|
|
4390
|
+
} = hooks.useContext(FormContext$1);
|
|
4391
|
+
const {
|
|
4392
|
+
Empty
|
|
4393
|
+
} = hooks.useContext(FormRenderContext$1);
|
|
4394
|
+
const fullProps = {
|
|
4395
|
+
...props,
|
|
4396
|
+
Empty
|
|
4397
|
+
};
|
|
4398
|
+
return jsxRuntime.jsxs("div", {
|
|
4399
|
+
className: classNames(formFieldClasses(type), {
|
|
4400
|
+
'fjs-outlined': showOutline
|
|
4401
|
+
}),
|
|
4402
|
+
role: "group",
|
|
4403
|
+
"aria-labelledby": prefixId(id, formId),
|
|
4404
|
+
children: [jsxRuntime.jsx(Label, {
|
|
4405
|
+
id: prefixId(id, formId),
|
|
4406
|
+
label: label
|
|
4407
|
+
}), jsxRuntime.jsx(Grid, {
|
|
4408
|
+
...fullProps
|
|
4409
|
+
})]
|
|
4410
|
+
});
|
|
4411
|
+
}
|
|
4412
|
+
Group.config = {
|
|
4413
|
+
type: 'group',
|
|
4414
|
+
pathed: true,
|
|
4415
|
+
label: 'Group',
|
|
4416
|
+
group: 'presentation',
|
|
4417
|
+
create: (options = {}) => ({
|
|
4418
|
+
components: [],
|
|
4419
|
+
showOutline: true,
|
|
4420
|
+
...options
|
|
4421
|
+
})
|
|
4422
|
+
};
|
|
4423
|
+
|
|
3991
4424
|
const NODE_TYPE_TEXT = 3,
|
|
3992
4425
|
NODE_TYPE_ELEMENT = 1;
|
|
3993
4426
|
const ALLOWED_NODES = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span', 'em', 'a', 'p', 'div', 'ul', 'ol', 'li', 'hr', 'blockquote', 'img', 'pre', 'code', 'br', 'strong', 'table', 'thead', 'tbody', 'tr', 'th', 'td'];
|
|
@@ -4576,21 +5009,7 @@ Radio.config = {
|
|
|
4576
5009
|
group: 'selection',
|
|
4577
5010
|
emptyValue: null,
|
|
4578
5011
|
sanitizeValue: sanitizeSingleSelectValue,
|
|
4579
|
-
create:
|
|
4580
|
-
const defaults = {};
|
|
4581
|
-
|
|
4582
|
-
// provide default values if valuesKey isn't set
|
|
4583
|
-
if (!options.valuesKey) {
|
|
4584
|
-
defaults.values = [{
|
|
4585
|
-
label: 'Value',
|
|
4586
|
-
value: 'value'
|
|
4587
|
-
}];
|
|
4588
|
-
}
|
|
4589
|
-
return {
|
|
4590
|
-
...defaults,
|
|
4591
|
-
...options
|
|
4592
|
-
};
|
|
4593
|
-
}
|
|
5012
|
+
create: createEmptyOptions
|
|
4594
5013
|
};
|
|
4595
5014
|
|
|
4596
5015
|
var _path$d;
|
|
@@ -4942,21 +5361,7 @@ Select.config = {
|
|
|
4942
5361
|
group: 'selection',
|
|
4943
5362
|
emptyValue: null,
|
|
4944
5363
|
sanitizeValue: sanitizeSingleSelectValue,
|
|
4945
|
-
create:
|
|
4946
|
-
const defaults = {};
|
|
4947
|
-
|
|
4948
|
-
// provide default values if valuesKey isn't set
|
|
4949
|
-
if (!options.valuesKey) {
|
|
4950
|
-
defaults.values = [{
|
|
4951
|
-
label: 'Value',
|
|
4952
|
-
value: 'value'
|
|
4953
|
-
}];
|
|
4954
|
-
}
|
|
4955
|
-
return {
|
|
4956
|
-
...defaults,
|
|
4957
|
-
...options
|
|
4958
|
-
};
|
|
4959
|
-
}
|
|
5364
|
+
create: createEmptyOptions
|
|
4960
5365
|
};
|
|
4961
5366
|
|
|
4962
5367
|
const type$4 = 'spacer';
|
|
@@ -5184,21 +5589,7 @@ Taglist.config = {
|
|
|
5184
5589
|
group: 'selection',
|
|
5185
5590
|
emptyValue: [],
|
|
5186
5591
|
sanitizeValue: sanitizeMultiSelectValue,
|
|
5187
|
-
create:
|
|
5188
|
-
const defaults = {};
|
|
5189
|
-
|
|
5190
|
-
// provide default values if valuesKey isn't set
|
|
5191
|
-
if (!options.valuesKey) {
|
|
5192
|
-
defaults.values = [{
|
|
5193
|
-
label: 'Value',
|
|
5194
|
-
value: 'value'
|
|
5195
|
-
}];
|
|
5196
|
-
}
|
|
5197
|
-
return {
|
|
5198
|
-
...defaults,
|
|
5199
|
-
...options
|
|
5200
|
-
};
|
|
5201
|
-
}
|
|
5592
|
+
create: createEmptyOptions
|
|
5202
5593
|
};
|
|
5203
5594
|
|
|
5204
5595
|
const type$2 = 'text';
|
|
@@ -5615,13 +6006,14 @@ var SvgGroup = function SvgGroup(props) {
|
|
|
5615
6006
|
return /*#__PURE__*/React__namespace.createElement("svg", _extends$8({
|
|
5616
6007
|
xmlns: "http://www.w3.org/2000/svg",
|
|
5617
6008
|
width: 54,
|
|
5618
|
-
height: 54
|
|
6009
|
+
height: 54,
|
|
6010
|
+
fill: "currentcolor"
|
|
5619
6011
|
}, props), _path$8 || (_path$8 = /*#__PURE__*/React__namespace.createElement("path", {
|
|
5620
6012
|
fillRule: "evenodd",
|
|
5621
6013
|
d: "M8 33v5a1 1 0 0 0 1 1h4v2H9a3 3 0 0 1-3-3v-5h2Zm18 6v2H15v-2h11Zm13 0v2H28v-2h11Zm9-6v5a3 3 0 0 1-3 3h-4v-2h4a1 1 0 0 0 .993-.883L46 38v-5h2ZM8 22v9H6v-9h2Zm40 0v9h-2v-9h2Zm-35-9v2H9a1 1 0 0 0-.993.883L8 16v4H6v-4a3 3 0 0 1 3-3h4Zm32 0a3 3 0 0 1 3 3v4h-2v-4a1 1 0 0 0-.883-.993L45 15h-4v-2h4Zm-6 0v2H28v-2h11Zm-13 0v2H15v-2h11Z"
|
|
5622
6014
|
})));
|
|
5623
6015
|
};
|
|
5624
|
-
var
|
|
6016
|
+
var GroupIcon = SvgGroup;
|
|
5625
6017
|
|
|
5626
6018
|
var _path$7;
|
|
5627
6019
|
function _extends$7() { _extends$7 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$7.apply(this, arguments); }
|
|
@@ -5674,14 +6066,14 @@ var SvgSpacer = function SvgSpacer(props) {
|
|
|
5674
6066
|
xmlns: "http://www.w3.org/2000/svg",
|
|
5675
6067
|
width: 54,
|
|
5676
6068
|
height: 54,
|
|
5677
|
-
fill: "
|
|
6069
|
+
fill: "currentcolor"
|
|
5678
6070
|
}, props), _path$4 || (_path$4 = /*#__PURE__*/React__namespace.createElement("path", {
|
|
5679
|
-
stroke: "
|
|
6071
|
+
stroke: "currentcolor",
|
|
5680
6072
|
strokeLinecap: "square",
|
|
5681
6073
|
strokeWidth: 2,
|
|
5682
6074
|
d: "M9 23h36M9 31h36"
|
|
5683
6075
|
})), _path2$1 || (_path2$1 = /*#__PURE__*/React__namespace.createElement("path", {
|
|
5684
|
-
stroke: "
|
|
6076
|
+
stroke: "currentcolor",
|
|
5685
6077
|
strokeLinecap: "round",
|
|
5686
6078
|
strokeLinejoin: "round",
|
|
5687
6079
|
strokeWidth: 2,
|
|
@@ -5759,8 +6151,9 @@ const iconsByType = type => {
|
|
|
5759
6151
|
button: ButtonIcon,
|
|
5760
6152
|
checkbox: CheckboxIcon,
|
|
5761
6153
|
checklist: ChecklistIcon,
|
|
5762
|
-
columns:
|
|
6154
|
+
columns: GroupIcon,
|
|
5763
6155
|
datetime: DatetimeIcon,
|
|
6156
|
+
group: GroupIcon,
|
|
5764
6157
|
image: ImageIcon,
|
|
5765
6158
|
number: NumberIcon,
|
|
5766
6159
|
radio: RadioIcon,
|
|
@@ -5774,7 +6167,7 @@ const iconsByType = type => {
|
|
|
5774
6167
|
}[type];
|
|
5775
6168
|
};
|
|
5776
6169
|
|
|
5777
|
-
const formFields = [Button, Checkbox, Checklist,
|
|
6170
|
+
const formFields = [Button, Checkbox, Checklist, FormComponent$1, Group, Image, Numberfield, Datetime, Radio, Select, Spacer, Taglist, Text, Textfield, Textarea];
|
|
5778
6171
|
|
|
5779
6172
|
class FormFields {
|
|
5780
6173
|
constructor() {
|
|
@@ -5850,62 +6243,65 @@ var renderModule = {
|
|
|
5850
6243
|
};
|
|
5851
6244
|
|
|
5852
6245
|
var core = {
|
|
5853
|
-
__depends__: [
|
|
6246
|
+
__depends__: [renderModule],
|
|
5854
6247
|
eventBus: ['type', EventBus],
|
|
6248
|
+
importer: ['type', Importer],
|
|
6249
|
+
fieldFactory: ['type', FieldFactory],
|
|
5855
6250
|
formFieldRegistry: ['type', FormFieldRegistry],
|
|
6251
|
+
pathRegistry: ['type', PathRegistry],
|
|
5856
6252
|
formLayouter: ['type', FormLayouter],
|
|
5857
6253
|
validator: ['type', Validator]
|
|
5858
6254
|
};
|
|
5859
6255
|
|
|
5860
|
-
/**
|
|
5861
|
-
* @typedef { import('./types').Injector } Injector
|
|
5862
|
-
* @typedef { import('./types').Data } Data
|
|
5863
|
-
* @typedef { import('./types').Errors } Errors
|
|
5864
|
-
* @typedef { import('./types').Schema } Schema
|
|
5865
|
-
* @typedef { import('./types').FormProperties } FormProperties
|
|
5866
|
-
* @typedef { import('./types').FormProperty } FormProperty
|
|
5867
|
-
* @typedef { import('./types').FormEvent } FormEvent
|
|
5868
|
-
* @typedef { import('./types').FormOptions } FormOptions
|
|
5869
|
-
*
|
|
5870
|
-
* @typedef { {
|
|
5871
|
-
* data: Data,
|
|
5872
|
-
* initialData: Data,
|
|
5873
|
-
* errors: Errors,
|
|
5874
|
-
* properties: FormProperties,
|
|
5875
|
-
* schema: Schema
|
|
5876
|
-
* } } State
|
|
5877
|
-
*
|
|
5878
|
-
* @typedef { (type:FormEvent, priority:number, handler:Function) => void } OnEventWithPriority
|
|
5879
|
-
* @typedef { (type:FormEvent, handler:Function) => void } OnEventWithOutPriority
|
|
5880
|
-
* @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
|
|
6256
|
+
/**
|
|
6257
|
+
* @typedef { import('./types').Injector } Injector
|
|
6258
|
+
* @typedef { import('./types').Data } Data
|
|
6259
|
+
* @typedef { import('./types').Errors } Errors
|
|
6260
|
+
* @typedef { import('./types').Schema } Schema
|
|
6261
|
+
* @typedef { import('./types').FormProperties } FormProperties
|
|
6262
|
+
* @typedef { import('./types').FormProperty } FormProperty
|
|
6263
|
+
* @typedef { import('./types').FormEvent } FormEvent
|
|
6264
|
+
* @typedef { import('./types').FormOptions } FormOptions
|
|
6265
|
+
*
|
|
6266
|
+
* @typedef { {
|
|
6267
|
+
* data: Data,
|
|
6268
|
+
* initialData: Data,
|
|
6269
|
+
* errors: Errors,
|
|
6270
|
+
* properties: FormProperties,
|
|
6271
|
+
* schema: Schema
|
|
6272
|
+
* } } State
|
|
6273
|
+
*
|
|
6274
|
+
* @typedef { (type:FormEvent, priority:number, handler:Function) => void } OnEventWithPriority
|
|
6275
|
+
* @typedef { (type:FormEvent, handler:Function) => void } OnEventWithOutPriority
|
|
6276
|
+
* @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
|
|
5881
6277
|
*/
|
|
5882
6278
|
|
|
5883
6279
|
const ids = new Ids([32, 36, 1]);
|
|
5884
6280
|
|
|
5885
|
-
/**
|
|
5886
|
-
* The form.
|
|
6281
|
+
/**
|
|
6282
|
+
* The form.
|
|
5887
6283
|
*/
|
|
5888
6284
|
class Form {
|
|
5889
|
-
/**
|
|
5890
|
-
* @constructor
|
|
5891
|
-
* @param {FormOptions} options
|
|
6285
|
+
/**
|
|
6286
|
+
* @constructor
|
|
6287
|
+
* @param {FormOptions} options
|
|
5892
6288
|
*/
|
|
5893
6289
|
constructor(options = {}) {
|
|
5894
|
-
/**
|
|
5895
|
-
* @public
|
|
5896
|
-
* @type {OnEventType}
|
|
6290
|
+
/**
|
|
6291
|
+
* @public
|
|
6292
|
+
* @type {OnEventType}
|
|
5897
6293
|
*/
|
|
5898
6294
|
this.on = this._onEvent;
|
|
5899
6295
|
|
|
5900
|
-
/**
|
|
5901
|
-
* @public
|
|
5902
|
-
* @type {String}
|
|
6296
|
+
/**
|
|
6297
|
+
* @public
|
|
6298
|
+
* @type {String}
|
|
5903
6299
|
*/
|
|
5904
6300
|
this._id = ids.next();
|
|
5905
6301
|
|
|
5906
|
-
/**
|
|
5907
|
-
* @private
|
|
5908
|
-
* @type {Element}
|
|
6302
|
+
/**
|
|
6303
|
+
* @private
|
|
6304
|
+
* @type {Element}
|
|
5909
6305
|
*/
|
|
5910
6306
|
this._container = createFormContainer();
|
|
5911
6307
|
const {
|
|
@@ -5914,9 +6310,9 @@ class Form {
|
|
|
5914
6310
|
properties = {}
|
|
5915
6311
|
} = options;
|
|
5916
6312
|
|
|
5917
|
-
/**
|
|
5918
|
-
* @private
|
|
5919
|
-
* @type {State}
|
|
6313
|
+
/**
|
|
6314
|
+
* @private
|
|
6315
|
+
* @type {State}
|
|
5920
6316
|
*/
|
|
5921
6317
|
this._state = {
|
|
5922
6318
|
initialData: null,
|
|
@@ -5940,9 +6336,9 @@ class Form {
|
|
|
5940
6336
|
this._emit('form.clear');
|
|
5941
6337
|
}
|
|
5942
6338
|
|
|
5943
|
-
/**
|
|
5944
|
-
* Destroy the form, removing it from DOM,
|
|
5945
|
-
* if attached.
|
|
6339
|
+
/**
|
|
6340
|
+
* Destroy the form, removing it from DOM,
|
|
6341
|
+
* if attached.
|
|
5946
6342
|
*/
|
|
5947
6343
|
destroy() {
|
|
5948
6344
|
// destroy form services
|
|
@@ -5953,13 +6349,13 @@ class Form {
|
|
|
5953
6349
|
this._detach(false);
|
|
5954
6350
|
}
|
|
5955
6351
|
|
|
5956
|
-
/**
|
|
5957
|
-
* Open a form schema with the given initial data.
|
|
5958
|
-
*
|
|
5959
|
-
* @param {Schema} schema
|
|
5960
|
-
* @param {Data} [data]
|
|
5961
|
-
*
|
|
5962
|
-
* @return Promise<{ warnings: Array<any> }>
|
|
6352
|
+
/**
|
|
6353
|
+
* Open a form schema with the given initial data.
|
|
6354
|
+
*
|
|
6355
|
+
* @param {Schema} schema
|
|
6356
|
+
* @param {Data} [data]
|
|
6357
|
+
*
|
|
6358
|
+
* @return Promise<{ warnings: Array<any> }>
|
|
5963
6359
|
*/
|
|
5964
6360
|
importSchema(schema, data = {}) {
|
|
5965
6361
|
return new Promise((resolve, reject) => {
|
|
@@ -5967,9 +6363,9 @@ class Form {
|
|
|
5967
6363
|
this.clear();
|
|
5968
6364
|
const {
|
|
5969
6365
|
schema: importedSchema,
|
|
5970
|
-
data: initializedData,
|
|
5971
6366
|
warnings
|
|
5972
|
-
} = this.get('importer').importSchema(schema
|
|
6367
|
+
} = this.get('importer').importSchema(schema);
|
|
6368
|
+
const initializedData = this._initializeFieldData(clone(data));
|
|
5973
6369
|
this._setState({
|
|
5974
6370
|
data: initializedData,
|
|
5975
6371
|
errors: {},
|
|
@@ -5992,10 +6388,10 @@ class Form {
|
|
|
5992
6388
|
});
|
|
5993
6389
|
}
|
|
5994
6390
|
|
|
5995
|
-
/**
|
|
5996
|
-
* Submit the form, triggering all field validations.
|
|
5997
|
-
*
|
|
5998
|
-
* @returns { { data: Data, errors: Errors } }
|
|
6391
|
+
/**
|
|
6392
|
+
* Submit the form, triggering all field validations.
|
|
6393
|
+
*
|
|
6394
|
+
* @returns { { data: Data, errors: Errors } }
|
|
5999
6395
|
*/
|
|
6000
6396
|
submit() {
|
|
6001
6397
|
const {
|
|
@@ -6022,26 +6418,26 @@ class Form {
|
|
|
6022
6418
|
});
|
|
6023
6419
|
}
|
|
6024
6420
|
|
|
6025
|
-
/**
|
|
6026
|
-
* @returns {Errors}
|
|
6421
|
+
/**
|
|
6422
|
+
* @returns {Errors}
|
|
6027
6423
|
*/
|
|
6028
6424
|
validate() {
|
|
6029
6425
|
const formFieldRegistry = this.get('formFieldRegistry'),
|
|
6426
|
+
pathRegistry = this.get('pathRegistry'),
|
|
6030
6427
|
validator = this.get('validator');
|
|
6031
6428
|
const {
|
|
6032
6429
|
data
|
|
6033
6430
|
} = this._getState();
|
|
6034
6431
|
const errors = formFieldRegistry.getAll().reduce((errors, field) => {
|
|
6035
6432
|
const {
|
|
6036
|
-
disabled
|
|
6037
|
-
_path
|
|
6433
|
+
disabled
|
|
6038
6434
|
} = field;
|
|
6039
6435
|
if (disabled) {
|
|
6040
6436
|
return errors;
|
|
6041
6437
|
}
|
|
6042
|
-
const value = minDash.get(data,
|
|
6438
|
+
const value = minDash.get(data, pathRegistry.getValuePath(field));
|
|
6043
6439
|
const fieldErrors = validator.validateField(field, value);
|
|
6044
|
-
return minDash.set(errors, [
|
|
6440
|
+
return minDash.set(errors, [field.id], fieldErrors.length ? fieldErrors : undefined);
|
|
6045
6441
|
}, /** @type {Errors} */{});
|
|
6046
6442
|
this._setState({
|
|
6047
6443
|
errors
|
|
@@ -6049,8 +6445,8 @@ class Form {
|
|
|
6049
6445
|
return errors;
|
|
6050
6446
|
}
|
|
6051
6447
|
|
|
6052
|
-
/**
|
|
6053
|
-
* @param {Element|string} parentNode
|
|
6448
|
+
/**
|
|
6449
|
+
* @param {Element|string} parentNode
|
|
6054
6450
|
*/
|
|
6055
6451
|
attachTo(parentNode) {
|
|
6056
6452
|
if (!parentNode) {
|
|
@@ -6068,10 +6464,10 @@ class Form {
|
|
|
6068
6464
|
this._detach();
|
|
6069
6465
|
}
|
|
6070
6466
|
|
|
6071
|
-
/**
|
|
6072
|
-
* @private
|
|
6073
|
-
*
|
|
6074
|
-
* @param {boolean} [emit]
|
|
6467
|
+
/**
|
|
6468
|
+
* @private
|
|
6469
|
+
*
|
|
6470
|
+
* @param {boolean} [emit]
|
|
6075
6471
|
*/
|
|
6076
6472
|
_detach(emit = true) {
|
|
6077
6473
|
const container = this._container,
|
|
@@ -6085,9 +6481,9 @@ class Form {
|
|
|
6085
6481
|
parentNode.removeChild(container);
|
|
6086
6482
|
}
|
|
6087
6483
|
|
|
6088
|
-
/**
|
|
6089
|
-
* @param {FormProperty} property
|
|
6090
|
-
* @param {any} value
|
|
6484
|
+
/**
|
|
6485
|
+
* @param {FormProperty} property
|
|
6486
|
+
* @param {any} value
|
|
6091
6487
|
*/
|
|
6092
6488
|
setProperty(property, value) {
|
|
6093
6489
|
const properties = minDash.set(this._getState().properties, [property], value);
|
|
@@ -6096,21 +6492,21 @@ class Form {
|
|
|
6096
6492
|
});
|
|
6097
6493
|
}
|
|
6098
6494
|
|
|
6099
|
-
/**
|
|
6100
|
-
* @param {FormEvent} type
|
|
6101
|
-
* @param {Function} handler
|
|
6495
|
+
/**
|
|
6496
|
+
* @param {FormEvent} type
|
|
6497
|
+
* @param {Function} handler
|
|
6102
6498
|
*/
|
|
6103
6499
|
off(type, handler) {
|
|
6104
6500
|
this.get('eventBus').off(type, handler);
|
|
6105
6501
|
}
|
|
6106
6502
|
|
|
6107
|
-
/**
|
|
6108
|
-
* @private
|
|
6109
|
-
*
|
|
6110
|
-
* @param {FormOptions} options
|
|
6111
|
-
* @param {Element} container
|
|
6112
|
-
*
|
|
6113
|
-
* @returns {Injector}
|
|
6503
|
+
/**
|
|
6504
|
+
* @private
|
|
6505
|
+
*
|
|
6506
|
+
* @param {FormOptions} options
|
|
6507
|
+
* @param {Element} container
|
|
6508
|
+
*
|
|
6509
|
+
* @returns {Injector}
|
|
6114
6510
|
*/
|
|
6115
6511
|
_createInjector(options, container) {
|
|
6116
6512
|
const {
|
|
@@ -6129,17 +6525,17 @@ class Form {
|
|
|
6129
6525
|
}, core, ...modules, ...additionalModules]);
|
|
6130
6526
|
}
|
|
6131
6527
|
|
|
6132
|
-
/**
|
|
6133
|
-
* @private
|
|
6528
|
+
/**
|
|
6529
|
+
* @private
|
|
6134
6530
|
*/
|
|
6135
6531
|
_emit(type, data) {
|
|
6136
6532
|
this.get('eventBus').fire(type, data);
|
|
6137
6533
|
}
|
|
6138
6534
|
|
|
6139
|
-
/**
|
|
6140
|
-
* @internal
|
|
6141
|
-
*
|
|
6142
|
-
* @param { { add?: boolean, field: any, remove?: number, value?: any } } update
|
|
6535
|
+
/**
|
|
6536
|
+
* @internal
|
|
6537
|
+
*
|
|
6538
|
+
* @param { { add?: boolean, field: any, remove?: number, value?: any } } update
|
|
6143
6539
|
*/
|
|
6144
6540
|
_update(update) {
|
|
6145
6541
|
const {
|
|
@@ -6147,31 +6543,29 @@ class Form {
|
|
|
6147
6543
|
value
|
|
6148
6544
|
} = update;
|
|
6149
6545
|
const {
|
|
6150
|
-
_path
|
|
6151
|
-
} = field;
|
|
6152
|
-
let {
|
|
6153
6546
|
data,
|
|
6154
6547
|
errors
|
|
6155
6548
|
} = this._getState();
|
|
6156
|
-
const validator = this.get('validator')
|
|
6549
|
+
const validator = this.get('validator'),
|
|
6550
|
+
pathRegistry = this.get('pathRegistry');
|
|
6157
6551
|
const fieldErrors = validator.validateField(field, value);
|
|
6158
|
-
minDash.set(data,
|
|
6159
|
-
minDash.set(errors, [
|
|
6552
|
+
minDash.set(data, pathRegistry.getValuePath(field), value);
|
|
6553
|
+
minDash.set(errors, [field.id], fieldErrors.length ? fieldErrors : undefined);
|
|
6160
6554
|
this._setState({
|
|
6161
6555
|
data: clone(data),
|
|
6162
6556
|
errors: clone(errors)
|
|
6163
6557
|
});
|
|
6164
6558
|
}
|
|
6165
6559
|
|
|
6166
|
-
/**
|
|
6167
|
-
* @internal
|
|
6560
|
+
/**
|
|
6561
|
+
* @internal
|
|
6168
6562
|
*/
|
|
6169
6563
|
_getState() {
|
|
6170
6564
|
return this._state;
|
|
6171
6565
|
}
|
|
6172
6566
|
|
|
6173
|
-
/**
|
|
6174
|
-
* @internal
|
|
6567
|
+
/**
|
|
6568
|
+
* @internal
|
|
6175
6569
|
*/
|
|
6176
6570
|
_setState(state) {
|
|
6177
6571
|
this._state = {
|
|
@@ -6181,56 +6575,96 @@ class Form {
|
|
|
6181
6575
|
this._emit('changed', this._getState());
|
|
6182
6576
|
}
|
|
6183
6577
|
|
|
6184
|
-
/**
|
|
6185
|
-
* @internal
|
|
6578
|
+
/**
|
|
6579
|
+
* @internal
|
|
6186
6580
|
*/
|
|
6187
6581
|
_getModules() {
|
|
6188
6582
|
return [ExpressionLanguageModule, MarkdownModule, ViewerCommandsModule];
|
|
6189
6583
|
}
|
|
6190
6584
|
|
|
6191
|
-
/**
|
|
6192
|
-
* @internal
|
|
6585
|
+
/**
|
|
6586
|
+
* @internal
|
|
6193
6587
|
*/
|
|
6194
6588
|
_onEvent(type, priority, handler) {
|
|
6195
6589
|
this.get('eventBus').on(type, priority, handler);
|
|
6196
6590
|
}
|
|
6197
6591
|
|
|
6198
|
-
/**
|
|
6199
|
-
* @internal
|
|
6592
|
+
/**
|
|
6593
|
+
* @internal
|
|
6200
6594
|
*/
|
|
6201
6595
|
_getSubmitData() {
|
|
6202
|
-
const formFieldRegistry = this.get('formFieldRegistry')
|
|
6596
|
+
const formFieldRegistry = this.get('formFieldRegistry'),
|
|
6597
|
+
pathRegistry = this.get('pathRegistry'),
|
|
6598
|
+
formFields = this.get('formFields');
|
|
6203
6599
|
const formData = this._getState().data;
|
|
6204
6600
|
const submitData = formFieldRegistry.getAll().reduce((previous, field) => {
|
|
6205
6601
|
const {
|
|
6206
6602
|
disabled,
|
|
6207
|
-
|
|
6603
|
+
type
|
|
6208
6604
|
} = field;
|
|
6605
|
+
const {
|
|
6606
|
+
config: fieldConfig
|
|
6607
|
+
} = formFields.get(type);
|
|
6209
6608
|
|
|
6210
|
-
// do not submit disabled form fields
|
|
6211
|
-
if (disabled || !
|
|
6609
|
+
// do not submit disabled form fields or routing fields
|
|
6610
|
+
if (disabled || !fieldConfig.keyed) {
|
|
6212
6611
|
return previous;
|
|
6213
6612
|
}
|
|
6214
|
-
const
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
[_path[0]]: value
|
|
6218
|
-
};
|
|
6613
|
+
const valuePath = pathRegistry.getValuePath(field);
|
|
6614
|
+
const value = minDash.get(formData, valuePath);
|
|
6615
|
+
return minDash.set(previous, valuePath, value);
|
|
6219
6616
|
}, {});
|
|
6220
6617
|
const filteredSubmitData = this._applyConditions(submitData, formData);
|
|
6221
6618
|
return filteredSubmitData;
|
|
6222
6619
|
}
|
|
6223
6620
|
|
|
6224
|
-
/**
|
|
6225
|
-
* @internal
|
|
6621
|
+
/**
|
|
6622
|
+
* @internal
|
|
6226
6623
|
*/
|
|
6227
6624
|
_applyConditions(toFilter, data) {
|
|
6228
6625
|
const conditionChecker = this.get('conditionChecker');
|
|
6229
6626
|
return conditionChecker.applyConditions(toFilter, data);
|
|
6230
6627
|
}
|
|
6628
|
+
|
|
6629
|
+
/**
|
|
6630
|
+
* @internal
|
|
6631
|
+
*/
|
|
6632
|
+
_initializeFieldData(data) {
|
|
6633
|
+
const formFieldRegistry = this.get('formFieldRegistry'),
|
|
6634
|
+
formFields = this.get('formFields'),
|
|
6635
|
+
pathRegistry = this.get('pathRegistry');
|
|
6636
|
+
return formFieldRegistry.getAll().reduce((initializedData, formField) => {
|
|
6637
|
+
const {
|
|
6638
|
+
defaultValue,
|
|
6639
|
+
type
|
|
6640
|
+
} = formField;
|
|
6641
|
+
|
|
6642
|
+
// try to get value from data
|
|
6643
|
+
// if unavailable - try to get default value from form field
|
|
6644
|
+
// if unavailable - get empty value from form field
|
|
6645
|
+
|
|
6646
|
+
const valuePath = pathRegistry.getValuePath(formField);
|
|
6647
|
+
if (valuePath) {
|
|
6648
|
+
const {
|
|
6649
|
+
config: fieldConfig
|
|
6650
|
+
} = formFields.get(type);
|
|
6651
|
+
let valueData = minDash.get(data, valuePath);
|
|
6652
|
+
if (!minDash.isUndefined(valueData) && fieldConfig.sanitizeValue) {
|
|
6653
|
+
valueData = fieldConfig.sanitizeValue({
|
|
6654
|
+
formField,
|
|
6655
|
+
data,
|
|
6656
|
+
value: valueData
|
|
6657
|
+
});
|
|
6658
|
+
}
|
|
6659
|
+
const initializedFieldValue = !minDash.isUndefined(valueData) ? valueData : !minDash.isUndefined(defaultValue) ? defaultValue : fieldConfig.emptyValue;
|
|
6660
|
+
return minDash.set(initializedData, valuePath, initializedFieldValue);
|
|
6661
|
+
}
|
|
6662
|
+
return initializedData;
|
|
6663
|
+
}, data);
|
|
6664
|
+
}
|
|
6231
6665
|
}
|
|
6232
6666
|
|
|
6233
|
-
const schemaVersion =
|
|
6667
|
+
const schemaVersion = 11;
|
|
6234
6668
|
|
|
6235
6669
|
/**
|
|
6236
6670
|
* @typedef { import('./types').CreateFormOptions } CreateFormOptions
|
|
@@ -6265,22 +6699,27 @@ exports.DATETIME_SUBTYPE_PATH = DATETIME_SUBTYPE_PATH;
|
|
|
6265
6699
|
exports.DATE_DISALLOW_PAST_PATH = DATE_DISALLOW_PAST_PATH;
|
|
6266
6700
|
exports.DATE_LABEL_PATH = DATE_LABEL_PATH;
|
|
6267
6701
|
exports.Datetime = Datetime;
|
|
6268
|
-
exports.Default =
|
|
6702
|
+
exports.Default = FormComponent$1;
|
|
6269
6703
|
exports.ExpressionLanguageModule = ExpressionLanguageModule;
|
|
6270
6704
|
exports.FeelExpressionLanguage = FeelExpressionLanguage;
|
|
6271
6705
|
exports.FeelersTemplating = FeelersTemplating;
|
|
6706
|
+
exports.FieldFactory = FieldFactory;
|
|
6272
6707
|
exports.Form = Form;
|
|
6273
6708
|
exports.FormComponent = FormComponent;
|
|
6274
6709
|
exports.FormContext = FormContext$1;
|
|
6710
|
+
exports.FormField = FormField;
|
|
6275
6711
|
exports.FormFieldRegistry = FormFieldRegistry;
|
|
6276
6712
|
exports.FormFields = FormFields;
|
|
6277
6713
|
exports.FormLayouter = FormLayouter;
|
|
6278
6714
|
exports.FormRenderContext = FormRenderContext$1;
|
|
6715
|
+
exports.Group = Group;
|
|
6279
6716
|
exports.Image = Image;
|
|
6717
|
+
exports.Importer = Importer;
|
|
6280
6718
|
exports.MINUTES_IN_DAY = MINUTES_IN_DAY;
|
|
6281
6719
|
exports.MarkdownModule = MarkdownModule;
|
|
6282
6720
|
exports.MarkdownRenderer = MarkdownRenderer;
|
|
6283
6721
|
exports.Numberfield = Numberfield;
|
|
6722
|
+
exports.PathRegistry = PathRegistry;
|
|
6284
6723
|
exports.Radio = Radio;
|
|
6285
6724
|
exports.Select = Select;
|
|
6286
6725
|
exports.Spacer = Spacer;
|
|
@@ -6305,7 +6744,6 @@ exports.clone = clone;
|
|
|
6305
6744
|
exports.createForm = createForm;
|
|
6306
6745
|
exports.createFormContainer = createFormContainer;
|
|
6307
6746
|
exports.createInjector = createInjector;
|
|
6308
|
-
exports.findErrors = findErrors;
|
|
6309
6747
|
exports.formFields = formFields;
|
|
6310
6748
|
exports.generateIdForType = generateIdForType;
|
|
6311
6749
|
exports.generateIndexForType = generateIndexForType;
|
|
@@ -6314,7 +6752,7 @@ exports.getValuesSource = getValuesSource;
|
|
|
6314
6752
|
exports.iconsByType = iconsByType;
|
|
6315
6753
|
exports.isRequired = isRequired;
|
|
6316
6754
|
exports.pathParse = pathParse;
|
|
6317
|
-
exports.pathStringify = pathStringify;
|
|
6318
6755
|
exports.pathsEqual = pathsEqual;
|
|
6756
|
+
exports.runRecursively = runRecursively;
|
|
6319
6757
|
exports.schemaVersion = schemaVersion;
|
|
6320
6758
|
//# sourceMappingURL=index.cjs.map
|