@bpmn-io/form-js-viewer 1.8.4 → 1.8.5
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 +244 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +243 -137
- 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,121 @@ 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
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
if (
|
|
7582
|
-
errors = [...errors,
|
|
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
|
+
const {
|
|
7609
|
+
type,
|
|
7610
|
+
validate
|
|
7611
|
+
} = field;
|
|
7612
|
+
let errors = [];
|
|
7613
|
+
if (type === 'number') {
|
|
7614
|
+
errors = [...errors, ...runNumberValidation(field, value)];
|
|
7583
7615
|
}
|
|
7584
|
-
if (
|
|
7585
|
-
|
|
7616
|
+
if (!validate) {
|
|
7617
|
+
return errors;
|
|
7586
7618
|
}
|
|
7619
|
+
const evaluatedValidation = evaluateFEELValues(validate, this._expressionLanguage, expressionContextInfo);
|
|
7620
|
+
errors = [...errors, ...runPresetValidation(field, evaluatedValidation, value)];
|
|
7587
7621
|
return errors;
|
|
7588
7622
|
}
|
|
7589
7623
|
}
|
|
7590
|
-
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form'];
|
|
7624
|
+
Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form', 'formFieldRegistry'];
|
|
7591
7625
|
|
|
7592
7626
|
// helpers //////////
|
|
7593
7627
|
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7628
|
+
function runNumberValidation(field, value) {
|
|
7629
|
+
const {
|
|
7630
|
+
decimalDigits,
|
|
7631
|
+
increment
|
|
7632
|
+
} = field;
|
|
7633
|
+
const errors = [];
|
|
7634
|
+
if (value === 'NaN') {
|
|
7635
|
+
errors.push('Value is not a number.');
|
|
7636
|
+
} else if (value) {
|
|
7637
|
+
if (decimalDigits >= 0 && countDecimals(value) > decimalDigits) {
|
|
7638
|
+
errors.push('Value is expected to ' + (decimalDigits === 0 ? 'be an integer' : `have at most ${decimalDigits} decimal digit${decimalDigits > 1 ? 's' : ''}`) + '.');
|
|
7639
|
+
}
|
|
7640
|
+
if (increment) {
|
|
7641
|
+
const bigValue = Big(value);
|
|
7642
|
+
const bigIncrement = Big(increment);
|
|
7643
|
+
const offset = bigValue.mod(bigIncrement);
|
|
7644
|
+
if (offset.cmp(0) !== 0) {
|
|
7645
|
+
const previousValue = bigValue.minus(offset);
|
|
7646
|
+
const nextValue = previousValue.plus(bigIncrement);
|
|
7647
|
+
errors.push(`Please select a valid value, the two nearest valid values are ${previousValue} and ${nextValue}.`);
|
|
7648
|
+
}
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7651
|
+
return errors;
|
|
7652
|
+
}
|
|
7653
|
+
function runPresetValidation(field, validation, value) {
|
|
7654
|
+
const errors = [];
|
|
7655
|
+
if (validation.pattern && value && !new RegExp(validation.pattern).test(value)) {
|
|
7656
|
+
errors.push(`Field must match pattern ${validation.pattern}.`);
|
|
7657
|
+
}
|
|
7658
|
+
if (validation.required) {
|
|
7659
|
+
const isUncheckedCheckbox = field.type === 'checkbox' && value === false;
|
|
7660
|
+
const isUnsetValue = minDash.isNil(value) || value === '';
|
|
7661
|
+
const isEmptyMultiselect = Array.isArray(value) && value.length === 0;
|
|
7662
|
+
if (isUncheckedCheckbox || isUnsetValue || isEmptyMultiselect) {
|
|
7663
|
+
errors.push('Field is required.');
|
|
7664
|
+
}
|
|
7665
|
+
}
|
|
7666
|
+
if ('min' in validation && (value || value === 0) && value < validation.min) {
|
|
7667
|
+
errors.push(`Field must have minimum value of ${validation.min}.`);
|
|
7668
|
+
}
|
|
7669
|
+
if ('max' in validation && (value || value === 0) && value > validation.max) {
|
|
7670
|
+
errors.push(`Field must have maximum value of ${validation.max}.`);
|
|
7671
|
+
}
|
|
7672
|
+
if ('minLength' in validation && value && value.trim().length < validation.minLength) {
|
|
7673
|
+
errors.push(`Field must have minimum length of ${validation.minLength}.`);
|
|
7674
|
+
}
|
|
7675
|
+
if ('maxLength' in validation && value && value.trim().length > validation.maxLength) {
|
|
7676
|
+
errors.push(`Field must have maximum length of ${validation.maxLength}.`);
|
|
7677
|
+
}
|
|
7678
|
+
if ('validationType' in validation && value && validation.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
|
|
7679
|
+
errors.push('Field must be a valid international phone number. (e.g. +4930664040900)');
|
|
7680
|
+
}
|
|
7681
|
+
if ('validationType' in validation && value && validation.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
|
|
7682
|
+
errors.push('Field must be a valid email.');
|
|
7683
|
+
}
|
|
7684
|
+
return errors;
|
|
7685
|
+
}
|
|
7686
|
+
function evaluateFEELValues(validate, expressionLanguage, expressionContextInfo) {
|
|
7687
|
+
const evaluatedValidate = {
|
|
7688
|
+
...validate
|
|
7689
|
+
};
|
|
7690
|
+
VALIDATE_FEEL_PROPERTIES.forEach(property => {
|
|
7691
|
+
const path = property.split('.');
|
|
7692
|
+
const value = minDash.get(evaluatedValidate, path);
|
|
7693
|
+
const evaluatedValue = runExpressionEvaluation(expressionLanguage, value, expressionContextInfo);
|
|
7694
|
+
minDash.set(evaluatedValidate, path, evaluatedValue === null ? undefined : evaluatedValue);
|
|
7695
|
+
});
|
|
7696
|
+
return evaluatedValidate;
|
|
7697
|
+
}
|
|
7698
|
+
function oldEvaluateFEELValues(validate, expressionLanguage, conditionChecker, form) {
|
|
7598
7699
|
const evaluatedValidate = {
|
|
7599
7700
|
...validate
|
|
7600
7701
|
};
|
|
@@ -8339,9 +8440,13 @@ class FormFieldInstanceRegistry {
|
|
|
8339
8440
|
return this.getAll().filter(({
|
|
8340
8441
|
id
|
|
8341
8442
|
}) => {
|
|
8443
|
+
const formFieldDefinition = this._formFieldRegistry.get(id);
|
|
8444
|
+
if (!formFieldDefinition) {
|
|
8445
|
+
return false;
|
|
8446
|
+
}
|
|
8342
8447
|
const {
|
|
8343
8448
|
type
|
|
8344
|
-
} =
|
|
8449
|
+
} = formFieldDefinition;
|
|
8345
8450
|
const {
|
|
8346
8451
|
config
|
|
8347
8452
|
} = this._formFields.get(type);
|
|
@@ -8601,11 +8706,12 @@ class Form {
|
|
|
8601
8706
|
} = this._getState();
|
|
8602
8707
|
const errors = {};
|
|
8603
8708
|
const getErrorPath = (id, indexes) => [id, ...Object.values(indexes || {})];
|
|
8604
|
-
formFieldInstanceRegistry.getAllKeyed().forEach(
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8709
|
+
formFieldInstanceRegistry.getAllKeyed().forEach(fieldInstance => {
|
|
8710
|
+
const {
|
|
8711
|
+
id,
|
|
8712
|
+
valuePath,
|
|
8713
|
+
indexes
|
|
8714
|
+
} = fieldInstance;
|
|
8609
8715
|
const field = formFieldRegistry.get(id);
|
|
8610
8716
|
|
|
8611
8717
|
// (1) Skip disabled fields
|
|
@@ -8613,9 +8719,9 @@ class Form {
|
|
|
8613
8719
|
return;
|
|
8614
8720
|
}
|
|
8615
8721
|
|
|
8616
|
-
// (2) Validate the field
|
|
8722
|
+
// (2) Validate the field instance
|
|
8617
8723
|
const value = minDash.get(data, valuePath);
|
|
8618
|
-
const fieldErrors = validator.
|
|
8724
|
+
const fieldErrors = validator.validateFieldInstance(fieldInstance, value);
|
|
8619
8725
|
if (fieldErrors.length) {
|
|
8620
8726
|
minDash.set(errors, getErrorPath(field.id, indexes), fieldErrors);
|
|
8621
8727
|
}
|
|
@@ -8720,26 +8826,26 @@ class Form {
|
|
|
8720
8826
|
/**
|
|
8721
8827
|
* @internal
|
|
8722
8828
|
*
|
|
8723
|
-
* @param { {
|
|
8829
|
+
* @param { { fieldInstance: any, value: any } } update
|
|
8724
8830
|
*/
|
|
8725
8831
|
_update(update) {
|
|
8726
8832
|
const {
|
|
8727
|
-
|
|
8728
|
-
indexes,
|
|
8833
|
+
fieldInstance,
|
|
8729
8834
|
value
|
|
8730
8835
|
} = update;
|
|
8836
|
+
const {
|
|
8837
|
+
id,
|
|
8838
|
+
valuePath,
|
|
8839
|
+
indexes
|
|
8840
|
+
} = fieldInstance;
|
|
8731
8841
|
const {
|
|
8732
8842
|
data,
|
|
8733
8843
|
errors
|
|
8734
8844
|
} = 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
|
-
});
|
|
8845
|
+
const validator = this.get('validator');
|
|
8846
|
+
const fieldErrors = validator.validateFieldInstance(fieldInstance, value);
|
|
8741
8847
|
minDash.set(data, valuePath, value);
|
|
8742
|
-
minDash.set(errors, [
|
|
8848
|
+
minDash.set(errors, [id, ...Object.values(indexes || {})], fieldErrors.length ? fieldErrors : undefined);
|
|
8743
8849
|
this._emit('field.updated', update);
|
|
8744
8850
|
this._setState({
|
|
8745
8851
|
data: clone(data),
|
|
@@ -9006,6 +9112,7 @@ exports.iconsByType = iconsByType;
|
|
|
9006
9112
|
exports.isRequired = isRequired;
|
|
9007
9113
|
exports.pathParse = pathParse;
|
|
9008
9114
|
exports.pathsEqual = pathsEqual;
|
|
9115
|
+
exports.runExpressionEvaluation = runExpressionEvaluation;
|
|
9009
9116
|
exports.runRecursively = runRecursively;
|
|
9010
9117
|
exports.sanitizeDateTimePickerValue = sanitizeDateTimePickerValue;
|
|
9011
9118
|
exports.sanitizeHTML = sanitizeHTML;
|
|
@@ -9018,4 +9125,5 @@ exports.useExpressionEvaluation = useExpressionEvaluation;
|
|
|
9018
9125
|
exports.useSingleLineTemplateEvaluation = useSingleLineTemplateEvaluation;
|
|
9019
9126
|
exports.useTemplateEvaluation = useTemplateEvaluation;
|
|
9020
9127
|
exports.wrapCSSStyles = wrapCSSStyles;
|
|
9128
|
+
exports.wrapObjectKeysWithUnderscores = wrapObjectKeysWithUnderscores;
|
|
9021
9129
|
//# sourceMappingURL=index.cjs.map
|