@bpmn-io/form-js-viewer 1.8.4 → 1.8.6
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/index.cjs +254 -135
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +253 -136
- package/dist/index.es.js.map +1 -1
- package/dist/types/Form.d.ts +2 -3
- package/dist/types/core/Validator.d.ts +16 -1
- package/dist/types/features/viewerCommands/ViewerCommands.d.ts +6 -0
- package/dist/types/features/viewerCommands/cmd/UpdateFieldInstanceValidationHandler.d.ts +10 -0
- package/dist/types/features/viewerCommands/cmd/UpdateFieldValidationHandler.d.ts +3 -0
- package/dist/types/util/expressions.d.ts +17 -0
- package/dist/types/util/index.d.ts +1 -0
- package/dist/types/util/simple.d.ts +1 -7
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -741,6 +741,20 @@ function generateIdForType(type) {
|
|
|
741
741
|
function clone(data, replacer) {
|
|
742
742
|
return JSON.parse(JSON.stringify(data, replacer));
|
|
743
743
|
}
|
|
744
|
+
function runRecursively(formField, fn) {
|
|
745
|
+
const components = formField.components || [];
|
|
746
|
+
components.forEach((component, _) => {
|
|
747
|
+
runRecursively(component, fn);
|
|
748
|
+
});
|
|
749
|
+
fn(formField);
|
|
750
|
+
}
|
|
751
|
+
function wrapObjectKeysWithUnderscores(obj) {
|
|
752
|
+
const newObj = {};
|
|
753
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
754
|
+
newObj[`_${key}_`] = value;
|
|
755
|
+
}
|
|
756
|
+
return newObj;
|
|
757
|
+
}
|
|
744
758
|
|
|
745
759
|
/**
|
|
746
760
|
* Transform a LocalExpressionContext object into a usable FEEL context.
|
|
@@ -757,25 +771,24 @@ function buildExpressionContext(context) {
|
|
|
757
771
|
return {
|
|
758
772
|
...specialContextKeys,
|
|
759
773
|
...data,
|
|
760
|
-
...
|
|
774
|
+
...wrapObjectKeysWithUnderscores(specialContextKeys)
|
|
761
775
|
};
|
|
762
776
|
}
|
|
763
|
-
function runRecursively(formField, fn) {
|
|
764
|
-
const components = formField.components || [];
|
|
765
|
-
components.forEach((component, index) => {
|
|
766
|
-
runRecursively(component, fn);
|
|
767
|
-
});
|
|
768
|
-
fn(formField);
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
// helpers //////////////////////
|
|
772
777
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
778
|
+
/**
|
|
779
|
+
* Evaluate a string based on the expressionLanguage and context information.
|
|
780
|
+
* If the string is not an expression, it is returned as is.
|
|
781
|
+
*
|
|
782
|
+
* @param {any} expressionLanguage - The expression language to use.
|
|
783
|
+
* @param {string} value - The string to evaluate.
|
|
784
|
+
* @param {Object} expressionContextInfo - The context information to use.
|
|
785
|
+
* @returns {any} - Evaluated value or the original value if not an expression.
|
|
786
|
+
*/
|
|
787
|
+
function runExpressionEvaluation(expressionLanguage, value, expressionContextInfo) {
|
|
788
|
+
if (expressionLanguage && expressionLanguage.isExpression(value)) {
|
|
789
|
+
return expressionLanguage.evaluate(value, buildExpressionContext(expressionContextInfo));
|
|
777
790
|
}
|
|
778
|
-
return
|
|
791
|
+
return value;
|
|
779
792
|
}
|
|
780
793
|
|
|
781
794
|
/**
|
|
@@ -908,12 +921,7 @@ function _isAllowedValue(value) {
|
|
|
908
921
|
function useExpressionEvaluation(value) {
|
|
909
922
|
const expressionLanguage = useService('expressionLanguage');
|
|
910
923
|
const expressionContextInfo = hooks.useContext(LocalExpressionContext);
|
|
911
|
-
return hooks.useMemo(() =>
|
|
912
|
-
if (expressionLanguage && expressionLanguage.isExpression(value)) {
|
|
913
|
-
return expressionLanguage.evaluate(value, buildExpressionContext(expressionContextInfo));
|
|
914
|
-
}
|
|
915
|
-
return value;
|
|
916
|
-
}, [expressionLanguage, expressionContextInfo, value]);
|
|
924
|
+
return hooks.useMemo(() => runExpressionEvaluation(expressionLanguage, value, expressionContextInfo), [expressionLanguage, expressionContextInfo, value]);
|
|
917
925
|
}
|
|
918
926
|
|
|
919
927
|
/**
|
|
@@ -1790,7 +1798,6 @@ function Checkbox(props) {
|
|
|
1790
1798
|
target
|
|
1791
1799
|
}) => {
|
|
1792
1800
|
props.onChange({
|
|
1793
|
-
field,
|
|
1794
1801
|
value: target.checked
|
|
1795
1802
|
});
|
|
1796
1803
|
};
|
|
@@ -1869,7 +1876,6 @@ function Checklist(props) {
|
|
|
1869
1876
|
const toggleCheckbox = toggledValue => {
|
|
1870
1877
|
const newValues = hasEqualValue(toggledValue, values) ? values.filter(value => !isEqual(value, toggledValue)) : [...values, toggledValue];
|
|
1871
1878
|
props.onChange({
|
|
1872
|
-
field,
|
|
1873
1879
|
value: newValues
|
|
1874
1880
|
});
|
|
1875
1881
|
};
|
|
@@ -1957,7 +1963,7 @@ function FormField(props) {
|
|
|
1957
1963
|
const {
|
|
1958
1964
|
field,
|
|
1959
1965
|
indexes,
|
|
1960
|
-
onChange
|
|
1966
|
+
onChange: _onChange
|
|
1961
1967
|
} = props;
|
|
1962
1968
|
const formFields = useService('formFields'),
|
|
1963
1969
|
viewerCommands = useService('viewerCommands', false),
|
|
@@ -1999,21 +2005,22 @@ function FormField(props) {
|
|
|
1999
2005
|
// add precedence: global readonly > form field disabled
|
|
2000
2006
|
const disabled = !properties.readOnly && (properties.disabled || field.disabled || false);
|
|
2001
2007
|
const hidden = useCondition(field.conditional && field.conditional.hide || null);
|
|
2008
|
+
const fieldInstance = hooks.useMemo(() => ({
|
|
2009
|
+
id: field.id,
|
|
2010
|
+
expressionContextInfo: localExpressionContext,
|
|
2011
|
+
valuePath,
|
|
2012
|
+
indexes
|
|
2013
|
+
}), [field.id, valuePath, localExpressionContext, indexes]);
|
|
2002
2014
|
|
|
2003
2015
|
// register form field instance
|
|
2004
2016
|
hooks.useEffect(() => {
|
|
2005
2017
|
if (formFieldInstanceRegistry && !hidden) {
|
|
2006
|
-
const instanceId = formFieldInstanceRegistry.add(
|
|
2007
|
-
id: field.id,
|
|
2008
|
-
expressionContextInfo: localExpressionContext,
|
|
2009
|
-
valuePath,
|
|
2010
|
-
indexes
|
|
2011
|
-
});
|
|
2018
|
+
const instanceId = formFieldInstanceRegistry.add(fieldInstance);
|
|
2012
2019
|
return () => {
|
|
2013
2020
|
formFieldInstanceRegistry.remove(instanceId);
|
|
2014
2021
|
};
|
|
2015
2022
|
}
|
|
2016
|
-
}, [
|
|
2023
|
+
}, [fieldInstance, formFieldInstanceRegistry, hidden]);
|
|
2017
2024
|
|
|
2018
2025
|
// ensures the initial validation behavior can be re-triggered upon form reset
|
|
2019
2026
|
hooks.useEffect(() => {
|
|
@@ -2034,34 +2041,33 @@ function FormField(props) {
|
|
|
2034
2041
|
const hasInitialValue = initialValue && !isEqual(initialValue, []);
|
|
2035
2042
|
if (initialValidationTrigger && hasInitialValue) {
|
|
2036
2043
|
setInitialValidationTrigger(false);
|
|
2037
|
-
viewerCommands.
|
|
2044
|
+
viewerCommands.updateFieldInstanceValidation(fieldInstance, initialValue);
|
|
2038
2045
|
}
|
|
2039
|
-
}, [
|
|
2046
|
+
}, [fieldInstance, initialValidationTrigger, initialValue, viewerCommands]);
|
|
2040
2047
|
const onBlur = hooks.useCallback(() => {
|
|
2041
2048
|
const value = minDash.get(data, valuePath);
|
|
2042
2049
|
if (initialValidationTrigger) {
|
|
2043
2050
|
setInitialValidationTrigger(false);
|
|
2044
|
-
viewerCommands.
|
|
2051
|
+
viewerCommands.updateFieldInstanceValidation(fieldInstance, value);
|
|
2045
2052
|
}
|
|
2046
2053
|
eventBus.fire('formField.blur', {
|
|
2047
2054
|
formField: field
|
|
2048
2055
|
});
|
|
2049
|
-
}, [eventBus, field,
|
|
2056
|
+
}, [data, eventBus, field, fieldInstance, initialValidationTrigger, valuePath, viewerCommands]);
|
|
2050
2057
|
const onFocus = hooks.useCallback(() => {
|
|
2051
2058
|
eventBus.fire('formField.focus', {
|
|
2052
2059
|
formField: field
|
|
2053
2060
|
});
|
|
2054
2061
|
}, [eventBus, field]);
|
|
2055
|
-
const
|
|
2056
|
-
// any data change will trigger validation
|
|
2062
|
+
const onChange = hooks.useCallback(update => {
|
|
2057
2063
|
setInitialValidationTrigger(false);
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
}
|
|
2064
|
-
}, [
|
|
2064
|
+
_onChange({
|
|
2065
|
+
field,
|
|
2066
|
+
indexes,
|
|
2067
|
+
fieldInstance,
|
|
2068
|
+
...update
|
|
2069
|
+
});
|
|
2070
|
+
}, [_onChange, field, fieldInstance, indexes]);
|
|
2065
2071
|
if (hidden) {
|
|
2066
2072
|
return jsxRuntime.jsx(Hidden, {
|
|
2067
2073
|
field: field
|
|
@@ -2074,11 +2080,12 @@ function FormField(props) {
|
|
|
2074
2080
|
disabled: disabled,
|
|
2075
2081
|
errors: fieldErrors,
|
|
2076
2082
|
domId: domId,
|
|
2077
|
-
onChange: disabled || readonly ? noop$1 :
|
|
2083
|
+
onChange: disabled || readonly ? noop$1 : onChange,
|
|
2078
2084
|
onBlur: disabled || readonly ? noop$1 : onBlur,
|
|
2079
2085
|
onFocus: disabled || readonly ? noop$1 : onFocus,
|
|
2080
2086
|
readonly: readonly,
|
|
2081
|
-
value: value
|
|
2087
|
+
value: value,
|
|
2088
|
+
fieldInstance: fieldInstance
|
|
2082
2089
|
});
|
|
2083
2090
|
if (fieldConfig.escapeGridRender) {
|
|
2084
2091
|
return formFieldElement;
|
|
@@ -3914,7 +3921,6 @@ function Radio(props) {
|
|
|
3914
3921
|
} = validate;
|
|
3915
3922
|
const onChange = v => {
|
|
3916
3923
|
props.onChange({
|
|
3917
|
-
field,
|
|
3918
3924
|
value: v
|
|
3919
3925
|
});
|
|
3920
3926
|
};
|
|
@@ -4062,10 +4068,9 @@ function SearchableSelect(props) {
|
|
|
4062
4068
|
const setValue = hooks.useCallback(option => {
|
|
4063
4069
|
setFilter(option && option.label || '');
|
|
4064
4070
|
props.onChange({
|
|
4065
|
-
value: option && option.value || null
|
|
4066
|
-
field
|
|
4071
|
+
value: option && option.value || null
|
|
4067
4072
|
});
|
|
4068
|
-
}, [
|
|
4073
|
+
}, [props]);
|
|
4069
4074
|
const displayState = hooks.useMemo(() => {
|
|
4070
4075
|
const ds = {};
|
|
4071
4076
|
ds.componentReady = !disabled && !readonly && loadState === LOAD_STATES.LOADED;
|
|
@@ -4211,10 +4216,9 @@ function SimpleSelect(props) {
|
|
|
4211
4216
|
const valueLabel = hooks.useMemo(() => value && getLabelCorrelation(value), [value, getLabelCorrelation]);
|
|
4212
4217
|
const setValue = hooks.useCallback(option => {
|
|
4213
4218
|
props.onChange({
|
|
4214
|
-
value: option && option.value || null
|
|
4215
|
-
field
|
|
4219
|
+
value: option && option.value || null
|
|
4216
4220
|
});
|
|
4217
|
-
}, [
|
|
4221
|
+
}, [props]);
|
|
4218
4222
|
const displayState = hooks.useMemo(() => {
|
|
4219
4223
|
const ds = {};
|
|
4220
4224
|
ds.componentReady = !disabled && !readonly && loadState === LOAD_STATES.LOADED;
|
|
@@ -4552,15 +4556,13 @@ function Taglist(props) {
|
|
|
4552
4556
|
return;
|
|
4553
4557
|
}
|
|
4554
4558
|
props.onChange({
|
|
4555
|
-
value: [...values, value]
|
|
4556
|
-
field
|
|
4559
|
+
value: [...values, value]
|
|
4557
4560
|
});
|
|
4558
4561
|
};
|
|
4559
4562
|
const deselectValue = value => {
|
|
4560
4563
|
const newValues = values.filter(v => !isEqual(v, value));
|
|
4561
4564
|
props.onChange({
|
|
4562
|
-
value: newValues
|
|
4563
|
-
field
|
|
4565
|
+
value: newValues
|
|
4564
4566
|
});
|
|
4565
4567
|
};
|
|
4566
4568
|
const onInputChange = ({
|
|
@@ -5049,7 +5051,6 @@ function Textfield(props) {
|
|
|
5049
5051
|
target
|
|
5050
5052
|
}) => {
|
|
5051
5053
|
props.onChange({
|
|
5052
|
-
field,
|
|
5053
5054
|
value: target.value
|
|
5054
5055
|
});
|
|
5055
5056
|
});
|
|
@@ -5149,7 +5150,6 @@ function Textarea(props) {
|
|
|
5149
5150
|
target
|
|
5150
5151
|
}) => {
|
|
5151
5152
|
props.onChange({
|
|
5152
|
-
field,
|
|
5153
5153
|
value: target.value
|
|
5154
5154
|
});
|
|
5155
5155
|
});
|
|
@@ -6618,6 +6618,9 @@ var commandModule = {
|
|
|
6618
6618
|
commandStack: ['type', CommandStack]
|
|
6619
6619
|
};
|
|
6620
6620
|
|
|
6621
|
+
/**
|
|
6622
|
+
* @deprecated
|
|
6623
|
+
*/
|
|
6621
6624
|
class UpdateFieldValidationHandler {
|
|
6622
6625
|
constructor(form, validator) {
|
|
6623
6626
|
this._form = form;
|
|
@@ -6647,6 +6650,38 @@ class UpdateFieldValidationHandler {
|
|
|
6647
6650
|
}
|
|
6648
6651
|
UpdateFieldValidationHandler.$inject = ['form', 'validator'];
|
|
6649
6652
|
|
|
6653
|
+
class UpdateFieldInstanceValidationHandler {
|
|
6654
|
+
constructor(form, validator) {
|
|
6655
|
+
this._form = form;
|
|
6656
|
+
this._validator = validator;
|
|
6657
|
+
}
|
|
6658
|
+
execute(context) {
|
|
6659
|
+
const {
|
|
6660
|
+
fieldInstance,
|
|
6661
|
+
value
|
|
6662
|
+
} = context;
|
|
6663
|
+
const {
|
|
6664
|
+
id,
|
|
6665
|
+
indexes
|
|
6666
|
+
} = fieldInstance;
|
|
6667
|
+
const {
|
|
6668
|
+
errors
|
|
6669
|
+
} = this._form._getState();
|
|
6670
|
+
context.oldErrors = clone(errors);
|
|
6671
|
+
const fieldErrors = this._validator.validateFieldInstance(fieldInstance, value);
|
|
6672
|
+
const updatedErrors = minDash.set(errors, [id, ...Object.values(indexes || {})], fieldErrors.length ? fieldErrors : undefined);
|
|
6673
|
+
this._form._setState({
|
|
6674
|
+
errors: updatedErrors
|
|
6675
|
+
});
|
|
6676
|
+
}
|
|
6677
|
+
revert(context) {
|
|
6678
|
+
this._form._setState({
|
|
6679
|
+
errors: context.oldErrors
|
|
6680
|
+
});
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6683
|
+
UpdateFieldInstanceValidationHandler.$inject = ['form', 'validator'];
|
|
6684
|
+
|
|
6650
6685
|
class ViewerCommands {
|
|
6651
6686
|
constructor(commandStack, eventBus) {
|
|
6652
6687
|
this._commandStack = commandStack;
|
|
@@ -6661,9 +6696,14 @@ class ViewerCommands {
|
|
|
6661
6696
|
}
|
|
6662
6697
|
getHandlers() {
|
|
6663
6698
|
return {
|
|
6664
|
-
'formField.validation.update': UpdateFieldValidationHandler
|
|
6699
|
+
'formField.validation.update': UpdateFieldValidationHandler,
|
|
6700
|
+
'formFieldInstance.validation.update': UpdateFieldInstanceValidationHandler
|
|
6665
6701
|
};
|
|
6666
6702
|
}
|
|
6703
|
+
|
|
6704
|
+
/**
|
|
6705
|
+
* @deprecated
|
|
6706
|
+
*/
|
|
6667
6707
|
updateFieldValidation(field, value, indexes) {
|
|
6668
6708
|
const context = {
|
|
6669
6709
|
field,
|
|
@@ -6672,6 +6712,13 @@ class ViewerCommands {
|
|
|
6672
6712
|
};
|
|
6673
6713
|
this._commandStack.execute('formField.validation.update', context);
|
|
6674
6714
|
}
|
|
6715
|
+
updateFieldInstanceValidation(fieldInstance, value) {
|
|
6716
|
+
const context = {
|
|
6717
|
+
fieldInstance,
|
|
6718
|
+
value
|
|
6719
|
+
};
|
|
6720
|
+
this._commandStack.execute('formFieldInstance.validation.update', context);
|
|
6721
|
+
}
|
|
6675
6722
|
}
|
|
6676
6723
|
ViewerCommands.$inject = ['commandStack', 'eventBus'];
|
|
6677
6724
|
|
|
@@ -6856,9 +6903,7 @@ class RepeatRenderManager {
|
|
|
6856
6903
|
updatedValues.push(newItem);
|
|
6857
6904
|
shouldScroll.current = true;
|
|
6858
6905
|
props.onChange({
|
|
6859
|
-
|
|
6860
|
-
value: updatedValues,
|
|
6861
|
-
indexes
|
|
6906
|
+
value: updatedValues
|
|
6862
6907
|
});
|
|
6863
6908
|
setSharedRepeatState(state => ({
|
|
6864
6909
|
...state,
|
|
@@ -7517,11 +7562,18 @@ const EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-
|
|
|
7517
7562
|
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}$/;
|
|
7518
7563
|
const VALIDATE_FEEL_PROPERTIES = ['min', 'max', 'minLength', 'maxLength'];
|
|
7519
7564
|
class Validator {
|
|
7520
|
-
constructor(expressionLanguage, conditionChecker, form) {
|
|
7565
|
+
constructor(expressionLanguage, conditionChecker, form, formFieldRegistry) {
|
|
7521
7566
|
this._expressionLanguage = expressionLanguage;
|
|
7522
7567
|
this._conditionChecker = conditionChecker;
|
|
7523
7568
|
this._form = form;
|
|
7569
|
+
this._formFieldRegistry = formFieldRegistry;
|
|
7524
7570
|
}
|
|
7571
|
+
|
|
7572
|
+
/**
|
|
7573
|
+
* Validate against a field definition, does not support proper expression evaluation.
|
|
7574
|
+
*
|
|
7575
|
+
* @deprecated use validateFieldInstance instead
|
|
7576
|
+
*/
|
|
7525
7577
|
validateField(field, value) {
|
|
7526
7578
|
const {
|
|
7527
7579
|
type,
|
|
@@ -7529,72 +7581,124 @@ class Validator {
|
|
|
7529
7581
|
} = field;
|
|
7530
7582
|
let errors = [];
|
|
7531
7583
|
if (type === 'number') {
|
|
7532
|
-
|
|
7533
|
-
decimalDigits,
|
|
7534
|
-
increment
|
|
7535
|
-
} = field;
|
|
7536
|
-
if (value === 'NaN') {
|
|
7537
|
-
errors = [...errors, 'Value is not a number.'];
|
|
7538
|
-
} else if (value) {
|
|
7539
|
-
if (decimalDigits >= 0 && countDecimals(value) > decimalDigits) {
|
|
7540
|
-
errors = [...errors, 'Value is expected to ' + (decimalDigits === 0 ? 'be an integer' : `have at most ${decimalDigits} decimal digit${decimalDigits > 1 ? 's' : ''}`) + '.'];
|
|
7541
|
-
}
|
|
7542
|
-
if (increment) {
|
|
7543
|
-
const bigValue = Big(value);
|
|
7544
|
-
const bigIncrement = Big(increment);
|
|
7545
|
-
const offset = bigValue.mod(bigIncrement);
|
|
7546
|
-
if (offset.cmp(0) !== 0) {
|
|
7547
|
-
const previousValue = bigValue.minus(offset);
|
|
7548
|
-
const nextValue = previousValue.plus(bigIncrement);
|
|
7549
|
-
errors = [...errors, `Please select a valid value, the two nearest valid values are ${previousValue} and ${nextValue}.`];
|
|
7550
|
-
}
|
|
7551
|
-
}
|
|
7552
|
-
}
|
|
7584
|
+
errors = [...errors, ...runNumberValidation(field, value)];
|
|
7553
7585
|
}
|
|
7554
7586
|
if (!validate) {
|
|
7555
7587
|
return errors;
|
|
7556
7588
|
}
|
|
7557
|
-
const evaluatedValidation =
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
}
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
if ('maxLength' in evaluatedValidation && value && value.trim().length > evaluatedValidation.maxLength) {
|
|
7579
|
-
errors = [...errors, `Field must have maximum length of ${evaluatedValidation.maxLength}.`];
|
|
7589
|
+
const evaluatedValidation = oldEvaluateFEELValues(validate, this._expressionLanguage, this._conditionChecker, this._form);
|
|
7590
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
7591
|
+
return errors;
|
|
7592
|
+
}
|
|
7593
|
+
|
|
7594
|
+
/**
|
|
7595
|
+
* Validate a field instance.
|
|
7596
|
+
*
|
|
7597
|
+
* @param {Object} fieldInstance
|
|
7598
|
+
* @param {string} value
|
|
7599
|
+
*
|
|
7600
|
+
* @returns {Array<string>}
|
|
7601
|
+
*/
|
|
7602
|
+
validateFieldInstance(fieldInstance, value) {
|
|
7603
|
+
const {
|
|
7604
|
+
id,
|
|
7605
|
+
expressionContextInfo
|
|
7606
|
+
} = fieldInstance;
|
|
7607
|
+
const field = this._formFieldRegistry.get(id);
|
|
7608
|
+
if (!field) {
|
|
7609
|
+
return [];
|
|
7580
7610
|
}
|
|
7581
|
-
|
|
7582
|
-
|
|
7611
|
+
const {
|
|
7612
|
+
type,
|
|
7613
|
+
validate
|
|
7614
|
+
} = field;
|
|
7615
|
+
let errors = [];
|
|
7616
|
+
if (type === 'number') {
|
|
7617
|
+
errors = [...errors, ...runNumberValidation(field, value)];
|
|
7583
7618
|
}
|
|
7584
|
-
if (
|
|
7585
|
-
|
|
7619
|
+
if (!validate) {
|
|
7620
|
+
return errors;
|
|
7586
7621
|
}
|
|
7622
|
+
const evaluatedValidation = evaluateFEELValues(validate, this._expressionLanguage, expressionContextInfo);
|
|
7623
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
7587
7624
|
return errors;
|
|
7588
7625
|
}
|
|
7589
7626
|
}
|
|
7590
|
-
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form'];
|
|
7627
|
+
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry'];
|
|
7591
7628
|
|
|
7592
7629
|
// helpers //////////
|
|
7593
7630
|
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7631
|
+
function runNumberValidation(field, value) {
|
|
7632
|
+
const {
|
|
7633
|
+
decimalDigits,
|
|
7634
|
+
increment
|
|
7635
|
+
} = field;
|
|
7636
|
+
const errors = [];
|
|
7637
|
+
if (value === 'NaN') {
|
|
7638
|
+
errors.push('Value is not a number.');
|
|
7639
|
+
} else if (value) {
|
|
7640
|
+
if (decimalDigits >= 0 && countDecimals(value) > decimalDigits) {
|
|
7641
|
+
errors.push('Value is expected to ' + (decimalDigits === 0 ? 'be an integer' : `have at most ${decimalDigits} decimal digit${decimalDigits > 1 ? 's' : ''}`) + '.');
|
|
7642
|
+
}
|
|
7643
|
+
if (increment) {
|
|
7644
|
+
const bigValue = Big(value);
|
|
7645
|
+
const bigIncrement = Big(increment);
|
|
7646
|
+
const offset = bigValue.mod(bigIncrement);
|
|
7647
|
+
if (offset.cmp(0) !== 0) {
|
|
7648
|
+
const previousValue = bigValue.minus(offset);
|
|
7649
|
+
const nextValue = previousValue.plus(bigIncrement);
|
|
7650
|
+
errors.push(`Please select a valid value, the two nearest valid values are ${previousValue} and ${nextValue}.`);
|
|
7651
|
+
}
|
|
7652
|
+
}
|
|
7653
|
+
}
|
|
7654
|
+
return errors;
|
|
7655
|
+
}
|
|
7656
|
+
function runPresetValidation(field, validation, value) {
|
|
7657
|
+
const errors = [];
|
|
7658
|
+
if (validation.pattern && value && !new RegExp(validation.pattern).test(value)) {
|
|
7659
|
+
errors.push(`Field must match pattern ${validation.pattern}.`);
|
|
7660
|
+
}
|
|
7661
|
+
if (validation.required) {
|
|
7662
|
+
const isUncheckedCheckbox = field.type === 'checkbox' && value === false;
|
|
7663
|
+
const isUnsetValue = minDash.isNil(value) || value === '';
|
|
7664
|
+
const isEmptyMultiselect = Array.isArray(value) && value.length === 0;
|
|
7665
|
+
if (isUncheckedCheckbox || isUnsetValue || isEmptyMultiselect) {
|
|
7666
|
+
errors.push('Field is required.');
|
|
7667
|
+
}
|
|
7668
|
+
}
|
|
7669
|
+
if ('min' in validation && (value || value === 0) && value < validation.min) {
|
|
7670
|
+
errors.push(`Field must have minimum value of ${validation.min}.`);
|
|
7671
|
+
}
|
|
7672
|
+
if ('max' in validation && (value || value === 0) && value > validation.max) {
|
|
7673
|
+
errors.push(`Field must have maximum value of ${validation.max}.`);
|
|
7674
|
+
}
|
|
7675
|
+
if ('minLength' in validation && value && value.trim().length < validation.minLength) {
|
|
7676
|
+
errors.push(`Field must have minimum length of ${validation.minLength}.`);
|
|
7677
|
+
}
|
|
7678
|
+
if ('maxLength' in validation && value && value.trim().length > validation.maxLength) {
|
|
7679
|
+
errors.push(`Field must have maximum length of ${validation.maxLength}.`);
|
|
7680
|
+
}
|
|
7681
|
+
if ('validationType' in validation && value && validation.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
|
|
7682
|
+
errors.push('Field must be a valid international phone number. (e.g. +4930664040900)');
|
|
7683
|
+
}
|
|
7684
|
+
if ('validationType' in validation && value && validation.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
|
|
7685
|
+
errors.push('Field must be a valid email.');
|
|
7686
|
+
}
|
|
7687
|
+
return errors;
|
|
7688
|
+
}
|
|
7689
|
+
function evaluateFEELValues(validate, expressionLanguage, expressionContextInfo) {
|
|
7690
|
+
const evaluatedValidate = {
|
|
7691
|
+
...validate
|
|
7692
|
+
};
|
|
7693
|
+
VALIDATE_FEEL_PROPERTIES.forEach(property => {
|
|
7694
|
+
const path = property.split('.');
|
|
7695
|
+
const value = minDash.get(evaluatedValidate, path);
|
|
7696
|
+
const evaluatedValue = runExpressionEvaluation(expressionLanguage, value, expressionContextInfo);
|
|
7697
|
+
minDash.set(evaluatedValidate, path, evaluatedValue === null ? undefined : evaluatedValue);
|
|
7698
|
+
});
|
|
7699
|
+
return evaluatedValidate;
|
|
7700
|
+
}
|
|
7701
|
+
function oldEvaluateFEELValues(validate, expressionLanguage, conditionChecker, form) {
|
|
7598
7702
|
const evaluatedValidate = {
|
|
7599
7703
|
...validate
|
|
7600
7704
|
};
|
|
@@ -8324,6 +8428,10 @@ class FormFieldInstanceRegistry {
|
|
|
8324
8428
|
valuePath,
|
|
8325
8429
|
indexes
|
|
8326
8430
|
};
|
|
8431
|
+
this._eventBus.fire('formFieldInstanceRegistry.changed', {
|
|
8432
|
+
instanceId,
|
|
8433
|
+
action: 'added'
|
|
8434
|
+
});
|
|
8327
8435
|
return instanceId;
|
|
8328
8436
|
}
|
|
8329
8437
|
remove(instanceId) {
|
|
@@ -8331,6 +8439,10 @@ class FormFieldInstanceRegistry {
|
|
|
8331
8439
|
return;
|
|
8332
8440
|
}
|
|
8333
8441
|
delete this._formFieldInstances[instanceId];
|
|
8442
|
+
this._eventBus.fire('formFieldInstanceRegistry.changed', {
|
|
8443
|
+
instanceId,
|
|
8444
|
+
action: 'removed'
|
|
8445
|
+
});
|
|
8334
8446
|
}
|
|
8335
8447
|
getAll() {
|
|
8336
8448
|
return Object.values(this._formFieldInstances);
|
|
@@ -8339,9 +8451,13 @@ class FormFieldInstanceRegistry {
|
|
|
8339
8451
|
return this.getAll().filter(({
|
|
8340
8452
|
id
|
|
8341
8453
|
}) => {
|
|
8454
|
+
const formFieldDefinition = this._formFieldRegistry.get(id);
|
|
8455
|
+
if (!formFieldDefinition) {
|
|
8456
|
+
return false;
|
|
8457
|
+
}
|
|
8342
8458
|
const {
|
|
8343
8459
|
type
|
|
8344
|
-
} =
|
|
8460
|
+
} = formFieldDefinition;
|
|
8345
8461
|
const {
|
|
8346
8462
|
config
|
|
8347
8463
|
} = this._formFields.get(type);
|
|
@@ -8601,11 +8717,12 @@ class Form {
|
|
|
8601
8717
|
} = this._getState();
|
|
8602
8718
|
const errors = {};
|
|
8603
8719
|
const getErrorPath = (id, indexes) => [id, ...Object.values(indexes || {})];
|
|
8604
|
-
formFieldInstanceRegistry.getAllKeyed().forEach(
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8720
|
+
formFieldInstanceRegistry.getAllKeyed().forEach(fieldInstance => {
|
|
8721
|
+
const {
|
|
8722
|
+
id,
|
|
8723
|
+
valuePath,
|
|
8724
|
+
indexes
|
|
8725
|
+
} = fieldInstance;
|
|
8609
8726
|
const field = formFieldRegistry.get(id);
|
|
8610
8727
|
|
|
8611
8728
|
// (1) Skip disabled fields
|
|
@@ -8613,9 +8730,9 @@ class Form {
|
|
|
8613
8730
|
return;
|
|
8614
8731
|
}
|
|
8615
8732
|
|
|
8616
|
-
// (2) Validate the field
|
|
8733
|
+
// (2) Validate the field instance
|
|
8617
8734
|
const value = minDash.get(data, valuePath);
|
|
8618
|
-
const fieldErrors = validator.
|
|
8735
|
+
const fieldErrors = validator.validateFieldInstance(fieldInstance, value);
|
|
8619
8736
|
if (fieldErrors.length) {
|
|
8620
8737
|
minDash.set(errors, getErrorPath(field.id, indexes), fieldErrors);
|
|
8621
8738
|
}
|
|
@@ -8720,26 +8837,26 @@ class Form {
|
|
|
8720
8837
|
/**
|
|
8721
8838
|
* @internal
|
|
8722
8839
|
*
|
|
8723
|
-
* @param { {
|
|
8840
|
+
* @param { { fieldInstance: any, value: any } } update
|
|
8724
8841
|
*/
|
|
8725
8842
|
_update(update) {
|
|
8726
8843
|
const {
|
|
8727
|
-
|
|
8728
|
-
indexes,
|
|
8844
|
+
fieldInstance,
|
|
8729
8845
|
value
|
|
8730
8846
|
} = update;
|
|
8847
|
+
const {
|
|
8848
|
+
id,
|
|
8849
|
+
valuePath,
|
|
8850
|
+
indexes
|
|
8851
|
+
} = fieldInstance;
|
|
8731
8852
|
const {
|
|
8732
8853
|
data,
|
|
8733
8854
|
errors
|
|
8734
8855
|
} = this._getState();
|
|
8735
|
-
const validator = this.get('validator')
|
|
8736
|
-
|
|
8737
|
-
const fieldErrors = validator.validateField(field, value);
|
|
8738
|
-
const valuePath = pathRegistry.getValuePath(field, {
|
|
8739
|
-
indexes
|
|
8740
|
-
});
|
|
8856
|
+
const validator = this.get('validator');
|
|
8857
|
+
const fieldErrors = validator.validateFieldInstance(fieldInstance, value);
|
|
8741
8858
|
minDash.set(data, valuePath, value);
|
|
8742
|
-
minDash.set(errors, [
|
|
8859
|
+
minDash.set(errors, [id, ...Object.values(indexes || {})], fieldErrors.length ? fieldErrors : undefined);
|
|
8743
8860
|
this._emit('field.updated', update);
|
|
8744
8861
|
this._setState({
|
|
8745
8862
|
data: clone(data),
|
|
@@ -9006,6 +9123,7 @@ exports.iconsByType = iconsByType;
|
|
|
9006
9123
|
exports.isRequired = isRequired;
|
|
9007
9124
|
exports.pathParse = pathParse;
|
|
9008
9125
|
exports.pathsEqual = pathsEqual;
|
|
9126
|
+
exports.runExpressionEvaluation = runExpressionEvaluation;
|
|
9009
9127
|
exports.runRecursively = runRecursively;
|
|
9010
9128
|
exports.sanitizeDateTimePickerValue = sanitizeDateTimePickerValue;
|
|
9011
9129
|
exports.sanitizeHTML = sanitizeHTML;
|
|
@@ -9018,4 +9136,5 @@ exports.useExpressionEvaluation = useExpressionEvaluation;
|
|
|
9018
9136
|
exports.useSingleLineTemplateEvaluation = useSingleLineTemplateEvaluation;
|
|
9019
9137
|
exports.useTemplateEvaluation = useTemplateEvaluation;
|
|
9020
9138
|
exports.wrapCSSStyles = wrapCSSStyles;
|
|
9139
|
+
exports.wrapObjectKeysWithUnderscores = wrapObjectKeysWithUnderscores;
|
|
9021
9140
|
//# sourceMappingURL=index.cjs.map
|