@shopgate/pwa-ui-shared 7.30.0-alpha.10 → 7.30.0-alpha.11
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/AccordionContainer/index.js +17 -11
- package/AccordionContainer/spec.js +12 -3
- package/ActionButton/index.js +47 -33
- package/ActionButton/spec.js +5 -1
- package/AddToCartButton/index.js +44 -33
- package/AddToCartButton/mock.js +20 -8
- package/AddToCartButton/spec.js +4 -3
- package/Availability/index.js +5 -3
- package/Availability/spec.js +6 -5
- package/Button/index.js +73 -58
- package/Button/spec.js +16 -10
- package/ButtonLink/index.js +20 -12
- package/ButtonLink/spec.js +5 -3
- package/Card/index.js +5 -3
- package/CardList/components/Item/index.js +5 -3
- package/CardList/index.js +21 -12
- package/CartTotalLine/components/Amount/index.js +10 -8
- package/CartTotalLine/components/Hint/index.js +7 -5
- package/CartTotalLine/components/Label/index.js +12 -10
- package/CartTotalLine/components/Spacer/index.js +5 -3
- package/CartTotalLine/index.js +5 -3
- package/Checkbox/index.js +6 -5
- package/Chip/index.js +28 -22
- package/Chip/spec.js +9 -6
- package/ContextMenu/ContextMenuProvider.js +5 -3
- package/ContextMenu/components/Item/index.js +14 -11
- package/ContextMenu/components/Position/index.js +20 -12
- package/ContextMenu/index.js +54 -44
- package/ContextMenu/spec.js +31 -20
- package/Dialog/components/HtmlContentDialog/index.js +9 -7
- package/Dialog/components/HtmlContentDialog/spec.js +9 -6
- package/Dialog/components/PipelineErrorDialog/index.js +106 -47
- package/Dialog/components/PipelineErrorDialog/spec.js +5 -4
- package/Dialog/components/TextMessageDialog/index.js +9 -7
- package/Dialog/components/TextMessageDialog/spec.js +9 -6
- package/Dialog/components/VariantSelectModal/index.js +7 -5
- package/Dialog/components/VariantSelectModal/spec.js +6 -3
- package/Dialog/index.js +12 -8
- package/Dialog/spec.js +7 -6
- package/DiscountBadge/index.js +10 -8
- package/DiscountBadge/spec.js +3 -2
- package/FavoritesButton/index.js +40 -31
- package/FavoritesButton/spec.js +7 -3
- package/Form/Builder/classes/ActionListener/index.js +400 -401
- package/Form/Builder/components/CheckboxElement.js +13 -5
- package/Form/Builder/components/CountryElement.js +13 -5
- package/Form/Builder/components/ProvinceElement.js +13 -5
- package/Form/Builder/components/RadioElement.js +19 -11
- package/Form/Builder/components/SelectElement.js +26 -16
- package/Form/Builder/components/TextElement.js +13 -5
- package/Form/Builder/index.js +70 -60
- package/Form/Builder/spec.js +10 -9
- package/Form/Checkbox/index.js +31 -21
- package/Form/InfoField/index.js +19 -12
- package/Form/InfoField/spec.js +4 -1
- package/Form/Password/index.js +22 -15
- package/Form/Password/spec.js +10 -5
- package/Form/RadioGroup/components/Item/index.js +34 -25
- package/Form/RadioGroup/index.js +37 -28
- package/Form/RadioGroup/spec.js +45 -31
- package/Form/Select/index.js +52 -43
- package/Form/Select/spec.js +5 -2
- package/Form/SelectContextChoices/index.js +26 -22
- package/Form/SelectContextChoices/spec.js +4 -1
- package/Form/TextField/index.js +40 -27
- package/Form/TextField/spec.js +34 -21
- package/Form/index.js +23 -15
- package/FormElement/components/ErrorText/index.js +7 -5
- package/FormElement/components/Label/index.js +6 -4
- package/FormElement/components/Placeholder/index.js +7 -5
- package/FormElement/components/Underline/index.js +8 -6
- package/FormElement/index.js +62 -46
- package/FormElement/spec.js +10 -9
- package/Glow/index.js +30 -22
- package/Glow/spec.js +6 -1
- package/IndicatorCircle/index.js +10 -8
- package/IndicatorCircle/spec.js +3 -2
- package/LoadingIndicator/index.js +8 -6
- package/Manufacturer/index.js +9 -7
- package/MessageBar/index.js +20 -17
- package/MessageBar/spec.js +6 -5
- package/NoResults/components/Icon/index.js +134 -110
- package/NoResults/index.js +27 -21
- package/Placeholder/index.js +13 -5
- package/PlaceholderLabel/index.js +2 -1
- package/PlaceholderLabel/spec.js +13 -6
- package/PlaceholderParagraph/index.js +13 -12
- package/PlaceholderParagraph/spec.js +13 -6
- package/Price/index.js +46 -28
- package/PriceInfo/index.js +2 -1
- package/PriceStriked/index.js +41 -29
- package/ProductProperties/index.js +13 -10
- package/ProgressBar/index.js +28 -19
- package/ProgressBar/spec.js +2 -1
- package/RadioButton/index.js +6 -5
- package/RadioButton/spec.js +3 -2
- package/RatingNumber/index.js +2 -1
- package/RatingStars/index.js +50 -34
- package/RatingStars/spec.js +7 -6
- package/Ripple/components/RippleAnimation/index.js +12 -10
- package/Ripple/index.js +72 -62
- package/RippleButton/index.js +44 -27
- package/RippleButton/spec.js +20 -13
- package/ScannerOverlay/components/CameraOverlay/index.js +8 -5
- package/ScannerOverlay/components/ScannerBar/components/FlashlightButton/index.js +25 -21
- package/ScannerOverlay/components/ScannerBar/components/ScannerInstructions/index.js +7 -5
- package/ScannerOverlay/components/ScannerBar/index.js +17 -12
- package/ScannerOverlay/index.js +24 -15
- package/Sheet/components/Header/components/SearchBar/index.js +35 -28
- package/Sheet/components/Header/components/SearchBar/spec.js +2 -1
- package/Sheet/components/Header/index.js +47 -34
- package/Sheet/components/Header/spec.js +2 -1
- package/Sheet/index.js +80 -65
- package/Sheet/spec.js +27 -14
- package/TaxDisclaimer/index.js +13 -10
- package/TaxDisclaimer/spec.js +3 -2
- package/TextField/components/ErrorText/index.js +7 -5
- package/TextField/components/FormElement/index.js +4 -3
- package/TextField/components/Hint/index.js +7 -5
- package/TextField/components/Label/index.js +6 -4
- package/TextField/components/Underline/index.js +8 -6
- package/TextField/index.js +102 -85
- package/TextField/spec.js +37 -23
- package/ToggleIcon/index.js +23 -15
- package/ToggleIcon/spec.js +12 -8
- package/icons/AccountBoxIcon.js +5 -4
- package/icons/AddMoreIcon.js +5 -4
- package/icons/ArrowDropIcon.js +5 -4
- package/icons/ArrowIcon.js +5 -4
- package/icons/BarcodeScannerIcon.js +5 -4
- package/icons/BoxIcon.js +5 -4
- package/icons/BrowseIcon.js +5 -4
- package/icons/BurgerIcon.js +5 -4
- package/icons/CalendarIcon.js +5 -5
- package/icons/CartCouponIcon.js +5 -4
- package/icons/CartIcon.js +5 -4
- package/icons/CartPlusIcon.js +5 -4
- package/icons/CheckIcon.js +5 -4
- package/icons/CheckedIcon.js +5 -4
- package/icons/ChevronIcon.js +5 -4
- package/icons/CreditCardIcon.js +5 -4
- package/icons/CrossIcon.js +5 -4
- package/icons/DescriptionIcon.js +5 -4
- package/icons/FilterIcon.js +5 -4
- package/icons/FlashDisabledIcon.js +5 -4
- package/icons/FlashEnabledIcon.js +5 -4
- package/icons/GridIcon.js +5 -4
- package/icons/HeartIcon.js +5 -4
- package/icons/HeartOutlineIcon.js +5 -4
- package/icons/HeartPlusIcon.js +5 -4
- package/icons/HeartPlusOutlineIcon.js +5 -4
- package/icons/HomeIcon.js +5 -4
- package/icons/InfoIcon.js +5 -4
- package/icons/InfoOutlineIcon.js +5 -4
- package/icons/ListIcon.js +5 -4
- package/icons/LocalShippingIcon.js +5 -4
- package/icons/LocationIcon.js +5 -4
- package/icons/LocatorIcon.js +5 -4
- package/icons/LockIcon.js +5 -4
- package/icons/LogoutIcon.js +5 -4
- package/icons/MagnifierIcon.js +5 -4
- package/icons/MapMarkerIcon.js +5 -4
- package/icons/MoreIcon.js +5 -4
- package/icons/MoreVertIcon.js +5 -4
- package/icons/NotificationIcon.js +5 -4
- package/icons/PersonIcon.js +5 -4
- package/icons/PhoneIcon.js +5 -4
- package/icons/PlaceholderIcon.js +5 -4
- package/icons/RadioCheckedIcon.js +5 -4
- package/icons/RadioUncheckedIcon.js +5 -4
- package/icons/SecurityIcon.js +5 -4
- package/icons/ShippingMethodIcon.js +5 -4
- package/icons/ShoppingCartIcon.js +5 -4
- package/icons/SortIcon.js +5 -4
- package/icons/StarHalfIcon.js +5 -4
- package/icons/StarIcon.js +5 -4
- package/icons/StarOutlineIcon.js +5 -4
- package/icons/StopIcon.js +5 -4
- package/icons/TickIcon.js +5 -4
- package/icons/TimeIcon.js +5 -4
- package/icons/TrashIcon.js +5 -4
- package/icons/TrashOutlineIcon.js +5 -4
- package/icons/UncheckedIcon.js +5 -4
- package/icons/ViewListIcon.js +5 -4
- package/icons/VisibilityIcon.js +5 -4
- package/icons/VisibilityOffIcon.js +5 -4
- package/icons/WarningIcon.js +5 -4
- package/package.json +7 -8
|
@@ -5,441 +5,440 @@ import { ACTION_TYPE_UPDATE_PROVINCE_ELEMENT, ACTION_TYPE_SET_VISIBILITY, ACTION
|
|
|
5
5
|
/**
|
|
6
6
|
* ActionListener and handler for the FormBuilder component
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
let ActionListener =
|
|
9
|
+
/**
|
|
10
|
+
* Constructor
|
|
11
|
+
* @param {function(string)} getProvincesList Takes a country code and returns a list of provinces
|
|
12
|
+
* @param {Object} defaults Form defaults
|
|
13
|
+
*/
|
|
14
|
+
function ActionListener(getProvincesList, defaults) {
|
|
9
15
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param {
|
|
16
|
+
* Takes the elements to be rendered by the FormBuilder and attaches available action listeners
|
|
17
|
+
* to the component.
|
|
18
|
+
* @param {FormElement[]} elementList List of all elements
|
|
13
19
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.attachAll = elementList => {
|
|
21
|
-
// Attach action listeners for element (context) actions
|
|
22
|
-
elementList.forEach(element => {
|
|
23
|
-
let elementActions = element.actions;
|
|
24
|
-
if (element.type === ELEMENT_TYPE_PROVINCE) {
|
|
25
|
-
elementActions = elementActions || [];
|
|
26
|
-
|
|
27
|
-
// Requires a country element to create a "update provinces" action
|
|
28
|
-
const countryElement = elementList.find(el => el.type === ELEMENT_TYPE_COUNTRY);
|
|
29
|
-
if (countryElement) {
|
|
30
|
-
// Attach new action, which is always triggered, when the (only) country element changes
|
|
31
|
-
elementActions.push({
|
|
32
|
-
type: ACTION_TYPE_UPDATE_PROVINCE_ELEMENT,
|
|
33
|
-
rules: [{
|
|
34
|
-
context: countryElement.id
|
|
35
|
-
}]
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (elementActions === undefined) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Create listeners for all supported actions
|
|
44
|
-
elementActions.forEach(action => {
|
|
45
|
-
const actionRules = action.rules || [];
|
|
46
|
-
// Always apply action to itself if no rules given
|
|
47
|
-
if (actionRules.length === 0) {
|
|
48
|
-
// Define a basic rule if no rules given
|
|
49
|
-
actionRules.push({
|
|
50
|
-
context: element.id
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Actions do have a fixed structure which needs to be fulfilled
|
|
55
|
-
const normalizedAction = {
|
|
56
|
-
...action,
|
|
57
|
-
rules: actionRules
|
|
58
|
-
};
|
|
20
|
+
this.attachAll = elementList => {
|
|
21
|
+
// Attach action listeners for element (context) actions
|
|
22
|
+
elementList.forEach(element => {
|
|
23
|
+
let elementActions = element.actions;
|
|
24
|
+
if (element.type === ELEMENT_TYPE_PROVINCE) {
|
|
25
|
+
elementActions = elementActions || [];
|
|
59
26
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
27
|
+
// Requires a country element to create a "update provinces" action
|
|
28
|
+
const countryElement = elementList.find(el => el.type === ELEMENT_TYPE_COUNTRY);
|
|
29
|
+
if (countryElement) {
|
|
30
|
+
// Attach new action, which is always triggered, when the (only) country element changes
|
|
31
|
+
elementActions.push({
|
|
32
|
+
type: ACTION_TYPE_UPDATE_PROVINCE_ELEMENT,
|
|
33
|
+
rules: [{
|
|
34
|
+
context: countryElement.id
|
|
35
|
+
}]
|
|
63
36
|
});
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* Attaches one or possibly multiple action listeners for the given rule
|
|
69
|
-
* @param {FormElement} element The current element that is modified by the action
|
|
70
|
-
* @param {FormFieldAction} action The action and it's params
|
|
71
|
-
* @param {FormFieldActionRule} rule The rule to check in case the action listener is triggered
|
|
72
|
-
*/
|
|
73
|
-
this.attach = (element, action, rule) => {
|
|
74
|
-
let actionListener;
|
|
75
|
-
switch (action.type) {
|
|
76
|
-
case ACTION_TYPE_UPDATE_PROVINCE_ELEMENT:
|
|
77
|
-
{
|
|
78
|
-
actionListener = this.createUpdateProvinceElementHandler(element, action);
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
case ACTION_TYPE_SET_VISIBILITY:
|
|
82
|
-
{
|
|
83
|
-
// Visibility is special and uses the result of the evaluation itself
|
|
84
|
-
actionListener = this.createSetVisibilityHandler(element, action);
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
case ACTION_TYPE_SET_VALUE:
|
|
88
|
-
{
|
|
89
|
-
actionListener = this.createEvaluatedHandler(element, action, this.createSetValueHandler(element, action));
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
case ACTION_TYPE_TRANSFORM:
|
|
93
|
-
{
|
|
94
|
-
actionListener = this.createEvaluatedHandler(element, action, this.createTransformHandler(element, action));
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
default:
|
|
98
|
-
return;
|
|
37
|
+
}
|
|
99
38
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Action listener creator to check all related rules before calling any further action listeners
|
|
104
|
-
* @param {FormElement} element The element for which the listener should be created for
|
|
105
|
-
* @param {FormFieldAction} action The action to be create a listener for
|
|
106
|
-
* @param {Function} actionListener The action listener to call if the rule applies
|
|
107
|
-
* @returns {Function} Returns a function to modify and return the modified state.
|
|
108
|
-
*/
|
|
109
|
-
this.createEvaluatedHandler = (element, action, actionListener) => (prevState, nextState) => {
|
|
110
|
-
// Apply rules before accepting any changes
|
|
111
|
-
if (!this.evaluateRules(element, action, nextState)) {
|
|
112
|
-
return nextState;
|
|
39
|
+
if (elementActions === undefined) {
|
|
40
|
+
return;
|
|
113
41
|
}
|
|
114
|
-
return actionListener(prevState, nextState);
|
|
115
|
-
};
|
|
116
|
-
/**
|
|
117
|
-
* Action listener creator to handle "updateCountryChange" action
|
|
118
|
-
* @param {FormElement} provinceEl The element for which the listener should be created for
|
|
119
|
-
* @param {FormFieldAction} action The action to be create a listener for
|
|
120
|
-
* @returns {Function} Returns a function to modify and return the modified state.
|
|
121
|
-
*/
|
|
122
|
-
this.createUpdateProvinceElementHandler = (provinceEl, action) => (prevState, nextState) => {
|
|
123
|
-
const countryElementId = action.rules[0].context;
|
|
124
|
-
const countryValue = nextState.formData[countryElementId];
|
|
125
|
-
const countryDefault = this.defaults[countryElementId];
|
|
126
|
-
const newState = {
|
|
127
|
-
...nextState
|
|
128
|
-
};
|
|
129
42
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Action listener creator to handle "setVisibility" actions
|
|
141
|
-
* @param {FormElement} element The element for which the listener should be created for
|
|
142
|
-
* @param {FormFieldAction} action The action to be create a listener for
|
|
143
|
-
* @returns {Function} Returns a function to modify and return the modified state.
|
|
144
|
-
*/
|
|
145
|
-
this.createSetVisibilityHandler = (element, action) => (prevState, nextState) => {
|
|
146
|
-
let newState = {
|
|
147
|
-
...nextState,
|
|
148
|
-
elementVisibility: {
|
|
149
|
-
...nextState.elementVisibility,
|
|
150
|
-
[element.id]: this.evaluateRules(element, action, nextState)
|
|
151
|
-
},
|
|
152
|
-
// Copy form data to be able to check changes and all follow up actions
|
|
153
|
-
formData: {
|
|
154
|
-
...nextState.formData
|
|
43
|
+
// Create listeners for all supported actions
|
|
44
|
+
elementActions.forEach(action => {
|
|
45
|
+
const actionRules = action.rules || [];
|
|
46
|
+
// Always apply action to itself if no rules given
|
|
47
|
+
if (actionRules.length === 0) {
|
|
48
|
+
// Define a basic rule if no rules given
|
|
49
|
+
actionRules.push({
|
|
50
|
+
context: element.id
|
|
51
|
+
});
|
|
155
52
|
}
|
|
156
|
-
};
|
|
157
|
-
if (newState.formData[element.id] === undefined && newState.elementVisibility[element.id]) {
|
|
158
|
-
newState.formData[element.id] = this.defaults[element.id];
|
|
159
|
-
} else if (!newState.elementVisibility[element.id] && newState.formData[element.id] !== undefined) {
|
|
160
|
-
delete newState.formData[element.id];
|
|
161
|
-
}
|
|
162
53
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
};
|
|
169
|
-
/**
|
|
170
|
-
* Action listener creator to handle "setValue" actions
|
|
171
|
-
* @param {FormElement} element The element for which the listener should be created for
|
|
172
|
-
* @param {FormFieldAction} action The action to be create a listener for
|
|
173
|
-
* @returns {Function} Returns the modified state.
|
|
174
|
-
*/
|
|
175
|
-
this.createSetValueHandler = (element, action) => (prevState, nextState) => {
|
|
176
|
-
if (typeof action.params !== 'object' || Array.isArray(action.params)) {
|
|
177
|
-
logger.error(`Error: Invalid or missing form action in element '${element.id}'. ` + 'Params must be in the format: { "type": string, "value": string }');
|
|
178
|
-
return nextState;
|
|
179
|
-
}
|
|
180
|
-
let {
|
|
181
|
-
value
|
|
182
|
-
} = action.params;
|
|
54
|
+
// Actions do have a fixed structure which needs to be fulfilled
|
|
55
|
+
const normalizedAction = {
|
|
56
|
+
...action,
|
|
57
|
+
rules: actionRules
|
|
58
|
+
};
|
|
183
59
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
60
|
+
// Assign the action listeners to all contexts of the current element
|
|
61
|
+
actionRules.forEach(rule => {
|
|
62
|
+
this.attach(element, normalizedAction, rule);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Attaches one or possibly multiple action listeners for the given rule
|
|
69
|
+
* @param {FormElement} element The current element that is modified by the action
|
|
70
|
+
* @param {FormFieldAction} action The action and it's params
|
|
71
|
+
* @param {FormFieldActionRule} rule The rule to check in case the action listener is triggered
|
|
72
|
+
*/
|
|
73
|
+
this.attach = (element, action, rule) => {
|
|
74
|
+
let actionListener;
|
|
75
|
+
switch (action.type) {
|
|
76
|
+
case ACTION_TYPE_UPDATE_PROVINCE_ELEMENT:
|
|
77
|
+
{
|
|
78
|
+
actionListener = this.createUpdateProvinceElementHandler(element, action);
|
|
203
79
|
break;
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// Perform action based on "setValue" type, defined in params
|
|
210
|
-
switch (action.params.type) {
|
|
211
|
-
case ACTION_SET_VALUE_LENGTH_OF:
|
|
212
|
-
value = `${nextState.formData[action.params.value].length}`;
|
|
80
|
+
}
|
|
81
|
+
case ACTION_TYPE_SET_VISIBILITY:
|
|
82
|
+
{
|
|
83
|
+
// Visibility is special and uses the result of the evaluation itself
|
|
84
|
+
actionListener = this.createSetVisibilityHandler(element, action);
|
|
213
85
|
break;
|
|
214
|
-
|
|
215
|
-
|
|
86
|
+
}
|
|
87
|
+
case ACTION_TYPE_SET_VALUE:
|
|
88
|
+
{
|
|
89
|
+
actionListener = this.createEvaluatedHandler(element, action, this.createSetValueHandler(element, action));
|
|
216
90
|
break;
|
|
217
|
-
|
|
218
|
-
|
|
91
|
+
}
|
|
92
|
+
case ACTION_TYPE_TRANSFORM:
|
|
93
|
+
{
|
|
94
|
+
actionListener = this.createEvaluatedHandler(element, action, this.createTransformHandler(element, action));
|
|
219
95
|
break;
|
|
220
|
-
default:
|
|
221
|
-
logger.error(`Error: Invalid form action param 'type' in element '${element.id}'. ` + `Allowed param types are: '${ACTION_SET_VALUE_LENGTH_OF}', ` + `'${ACTION_SET_VALUE_COPY_FROM}', '${ACTION_SET_VALUE_FIXED}'`);
|
|
222
|
-
return nextState;
|
|
223
|
-
}
|
|
224
|
-
let newState = {
|
|
225
|
-
...nextState,
|
|
226
|
-
formData: {
|
|
227
|
-
...nextState.formData,
|
|
228
|
-
[element.id]: value
|
|
229
96
|
}
|
|
230
|
-
|
|
97
|
+
default:
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
this.register(rule.context, actionListener);
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Action listener creator to check all related rules before calling any further action listeners
|
|
104
|
+
* @param {FormElement} element The element for which the listener should be created for
|
|
105
|
+
* @param {FormFieldAction} action The action to be create a listener for
|
|
106
|
+
* @param {Function} actionListener The action listener to call if the rule applies
|
|
107
|
+
* @returns {Function} Returns a function to modify and return the modified state.
|
|
108
|
+
*/
|
|
109
|
+
this.createEvaluatedHandler = (element, action, actionListener) => (prevState, nextState) => {
|
|
110
|
+
// Apply rules before accepting any changes
|
|
111
|
+
if (!this.evaluateRules(element, action, nextState)) {
|
|
112
|
+
return nextState;
|
|
113
|
+
}
|
|
114
|
+
return actionListener(prevState, nextState);
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Action listener creator to handle "updateCountryChange" action
|
|
118
|
+
* @param {FormElement} provinceEl The element for which the listener should be created for
|
|
119
|
+
* @param {FormFieldAction} action The action to be create a listener for
|
|
120
|
+
* @returns {Function} Returns a function to modify and return the modified state.
|
|
121
|
+
*/
|
|
122
|
+
this.createUpdateProvinceElementHandler = (provinceEl, action) => (prevState, nextState) => {
|
|
123
|
+
const countryElementId = action.rules[0].context;
|
|
124
|
+
const countryValue = nextState.formData[countryElementId];
|
|
125
|
+
const countryDefault = this.defaults[countryElementId];
|
|
126
|
+
const newState = {
|
|
127
|
+
...nextState
|
|
128
|
+
};
|
|
231
129
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
130
|
+
// Overwrite province with the form's default, if country matches the default as well
|
|
131
|
+
if (countryValue === countryDefault) {
|
|
132
|
+
newState.formData[provinceEl.id] = this.defaults[provinceEl.id];
|
|
133
|
+
} else {
|
|
134
|
+
// Update province to first or no selection, based on "required" attribute
|
|
135
|
+
newState.formData[provinceEl.id] = !provinceEl.required ? '' : Object.keys(this.getProvincesList(countryValue))[0];
|
|
136
|
+
}
|
|
137
|
+
return newState;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Action listener creator to handle "setVisibility" actions
|
|
141
|
+
* @param {FormElement} element The element for which the listener should be created for
|
|
142
|
+
* @param {FormFieldAction} action The action to be create a listener for
|
|
143
|
+
* @returns {Function} Returns a function to modify and return the modified state.
|
|
144
|
+
*/
|
|
145
|
+
this.createSetVisibilityHandler = (element, action) => (prevState, nextState) => {
|
|
146
|
+
let newState = {
|
|
147
|
+
...nextState,
|
|
148
|
+
elementVisibility: {
|
|
149
|
+
...nextState.elementVisibility,
|
|
150
|
+
[element.id]: this.evaluateRules(element, action, nextState)
|
|
151
|
+
},
|
|
152
|
+
// Copy form data to be able to check changes and all follow up actions
|
|
153
|
+
formData: {
|
|
154
|
+
...nextState.formData
|
|
235
155
|
}
|
|
236
|
-
return newState;
|
|
237
156
|
};
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
157
|
+
if (newState.formData[element.id] === undefined && newState.elementVisibility[element.id]) {
|
|
158
|
+
newState.formData[element.id] = this.defaults[element.id];
|
|
159
|
+
} else if (!newState.elementVisibility[element.id] && newState.formData[element.id] !== undefined) {
|
|
160
|
+
delete newState.formData[element.id];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Notify follow up listeners about the current change
|
|
164
|
+
if (nextState.formData[element.id] !== newState.formData[element.id]) {
|
|
165
|
+
newState = this.notify(element.id, prevState, newState);
|
|
166
|
+
}
|
|
167
|
+
return newState;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Action listener creator to handle "setValue" actions
|
|
171
|
+
* @param {FormElement} element The element for which the listener should be created for
|
|
172
|
+
* @param {FormFieldAction} action The action to be create a listener for
|
|
173
|
+
* @returns {Function} Returns the modified state.
|
|
174
|
+
*/
|
|
175
|
+
this.createSetValueHandler = (element, action) => (prevState, nextState) => {
|
|
176
|
+
if (typeof action.params !== 'object' || Array.isArray(action.params)) {
|
|
177
|
+
logger.error(`Error: Invalid or missing form action in element '${element.id}'. ` + 'Params must be in the format: { "type": string, "value": string }');
|
|
178
|
+
return nextState;
|
|
179
|
+
}
|
|
180
|
+
let {
|
|
181
|
+
value
|
|
182
|
+
} = action.params;
|
|
183
|
+
|
|
184
|
+
// Check correctness of value data type
|
|
185
|
+
switch (typeof value) {
|
|
186
|
+
case 'boolean':
|
|
187
|
+
if (element.type !== ELEMENT_TYPE_CHECKBOX) {
|
|
188
|
+
logger.error(`Error: Invalid form action param in element '${element.id}'. ` + `Allowed '${ELEMENT_TYPE_CHECKBOX}' data type for 'params.value' is: 'boolean'`);
|
|
189
|
+
return nextState;
|
|
255
190
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
return subject;
|
|
262
|
-
}
|
|
263
|
-
if (typeof String.prototype[action.params.type] === 'function') {
|
|
264
|
-
return String.prototype[action.params.type].apply(subject, args);
|
|
265
|
-
}
|
|
266
|
-
return String[action.params.type](subject);
|
|
267
|
-
}
|
|
268
|
-
case 'boolean':
|
|
269
|
-
{
|
|
270
|
-
if (typeof Boolean.prototype[action.params.type] !== 'function' && typeof Boolean[action.params.type] !== 'function') {
|
|
271
|
-
logger.error("Error: Invalid transform function passed to actions 'params.type' " + `attribute in element '${element.id}'. Must be withing 'String.prototype'!`);
|
|
272
|
-
return subject;
|
|
273
|
-
}
|
|
274
|
-
if (typeof Boolean.prototype[action.params.type] === 'function') {
|
|
275
|
-
return Boolean.prototype[action.params.type].apply(subject, args);
|
|
276
|
-
}
|
|
277
|
-
return Boolean[action.params.type](subject);
|
|
278
|
-
}
|
|
279
|
-
case 'number':
|
|
280
|
-
{
|
|
281
|
-
if (typeof Number.prototype[action.params.type] !== 'function' && typeof Number[action.params.type] !== 'function') {
|
|
282
|
-
logger.error("Error: Invalid transform function passed to actions 'params.type' " + `attribute in element '${element.id}'. Must be withing 'String.prototype'!`);
|
|
283
|
-
return subject;
|
|
284
|
-
}
|
|
285
|
-
if (typeof Number.prototype[action.params.type] === 'function') {
|
|
286
|
-
return Number.prototype[action.params.type].apply(subject, args);
|
|
287
|
-
}
|
|
288
|
-
return Number[action.params.type](subject);
|
|
289
|
-
}
|
|
290
|
-
default:
|
|
291
|
-
logger.error("Error: The given data can not be transformed. Must be of type 'string', " + "'boolean' or 'number'");
|
|
292
|
-
return subject;
|
|
191
|
+
break;
|
|
192
|
+
case 'number':
|
|
193
|
+
if (element.type !== ELEMENT_TYPE_NUMBER) {
|
|
194
|
+
logger.error(`Error: Invalid form action param in element '${element.id}'. ` + `Allowed '${ELEMENT_TYPE_NUMBER}' data types for 'params.value' are: ` + "'number' and 'string'");
|
|
195
|
+
return nextState;
|
|
293
196
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
[element.id]: transform(nextState.formData[element.id])
|
|
197
|
+
break;
|
|
198
|
+
case 'string':
|
|
199
|
+
if (element.type === ELEMENT_TYPE_CHECKBOX) {
|
|
200
|
+
logger.error(`Error: Invalid form action param in element '${element.id}'. ` + `Allowed '${ELEMENT_TYPE_CHECKBOX}' data type for 'params.value' is: 'boolean'`);
|
|
201
|
+
return nextState;
|
|
300
202
|
}
|
|
301
|
-
|
|
203
|
+
break;
|
|
204
|
+
default:
|
|
205
|
+
logger.error(`Error: Invalid form action param in element '${element.id}'. ` + `Can not use '${typeof value}' data for elements of type '${element.type}'`);
|
|
206
|
+
return nextState;
|
|
207
|
+
}
|
|
302
208
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
209
|
+
// Perform action based on "setValue" type, defined in params
|
|
210
|
+
switch (action.params.type) {
|
|
211
|
+
case ACTION_SET_VALUE_LENGTH_OF:
|
|
212
|
+
value = `${nextState.formData[action.params.value].length}`;
|
|
213
|
+
break;
|
|
214
|
+
case ACTION_SET_VALUE_COPY_FROM:
|
|
215
|
+
value = nextState.formData[action.params.value];
|
|
216
|
+
break;
|
|
217
|
+
case undefined:
|
|
218
|
+
case ACTION_SET_VALUE_FIXED:
|
|
219
|
+
break;
|
|
220
|
+
default:
|
|
221
|
+
logger.error(`Error: Invalid form action param 'type' in element '${element.id}'. ` + `Allowed param types are: '${ACTION_SET_VALUE_LENGTH_OF}', ` + `'${ACTION_SET_VALUE_COPY_FROM}', '${ACTION_SET_VALUE_FIXED}'`);
|
|
222
|
+
return nextState;
|
|
223
|
+
}
|
|
224
|
+
let newState = {
|
|
225
|
+
...nextState,
|
|
226
|
+
formData: {
|
|
227
|
+
...nextState.formData,
|
|
228
|
+
[element.id]: value
|
|
306
229
|
}
|
|
307
|
-
return newState;
|
|
308
230
|
};
|
|
231
|
+
|
|
232
|
+
// Notify follow up listeners about the current change, if there are any changes
|
|
233
|
+
if (nextState.formData[element.id] !== value) {
|
|
234
|
+
newState = this.notify(element.id, prevState, newState);
|
|
235
|
+
}
|
|
236
|
+
return newState;
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Action listener creator to handle "transform" actions
|
|
240
|
+
* @param {FormElement} element The element for which the listener should be created for
|
|
241
|
+
* @param {FormFieldAction} action The action to be create a listener for
|
|
242
|
+
* @returns {Function} Returns a function to modify and return the modified state.
|
|
243
|
+
*/
|
|
244
|
+
this.createTransformHandler = (element, action) => (prevState, nextState) => {
|
|
309
245
|
/**
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* @
|
|
313
|
-
* @param {FormFieldAction} action The current action to be evaluate rules for
|
|
314
|
-
* @param {Object} nextState The state at the time before the "action" event finished
|
|
315
|
-
* @returns {boolean}
|
|
246
|
+
* Takes a string and applies a case function on it
|
|
247
|
+
* @param {string|boolean|number} subject The subject to be transformed
|
|
248
|
+
* @returns {string|boolean|number}
|
|
316
249
|
*/
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
ruleData = true;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Check rule validity
|
|
333
|
-
if (!ACTION_RULE_DATA_TYPES[ruleType]) {
|
|
334
|
-
logger.error(`Error: Unknown action rule type '${ruleType}'in element '${element.id}'`);
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
// Check type of ruleData
|
|
338
|
-
const ruleDataType = ACTION_RULE_DATA_TYPES[ruleType];
|
|
339
|
-
if (ruleDataType === 'array' && !Array.isArray(ruleData)) {
|
|
340
|
-
logger.error(`Error: Invalid FormBuilder action rule in element '${element.id}': ` + `data must be an 'array' for rule type '${ruleType}'`);
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
// eslint-disable-next-line valid-typeof
|
|
344
|
-
if (ruleDataType !== 'array' && typeof ruleData !== ruleDataType) {
|
|
345
|
-
logger.error(`Error: Invalid FormBuilder action rule in element '${element.id}': ` + `data must be '${ruleDataType}' for rule type '${ruleType}'`);
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
switch (ruleType) {
|
|
349
|
-
case ACTION_RULE_TYPE_ONE_OF:
|
|
350
|
-
{
|
|
351
|
-
tmpResult = ruleData.includes(nextState.formData[rule.context]);
|
|
352
|
-
break;
|
|
250
|
+
const transform = subject => {
|
|
251
|
+
// Get optional params to be applied in the transformation process
|
|
252
|
+
let args = action.params.value || [];
|
|
253
|
+
if (Array.isArray(action.params.value)) {
|
|
254
|
+
args = action.params.value;
|
|
255
|
+
}
|
|
256
|
+
switch (typeof subject) {
|
|
257
|
+
case 'string':
|
|
258
|
+
{
|
|
259
|
+
if (typeof String.prototype[action.params.type] !== 'function' && typeof String[action.params.type] !== 'function') {
|
|
260
|
+
logger.error("Error: Invalid transform function passed to actions 'params.type' " + `attribute in element '${element.id}'. Must be withing 'String.prototype'!`);
|
|
261
|
+
return subject;
|
|
353
262
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
tmpResult = !ruleData.includes(nextState.formData[rule.context]);
|
|
357
|
-
break;
|
|
263
|
+
if (typeof String.prototype[action.params.type] === 'function') {
|
|
264
|
+
return String.prototype[action.params.type].apply(subject, args);
|
|
358
265
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
266
|
+
return String[action.params.type](subject);
|
|
267
|
+
}
|
|
268
|
+
case 'boolean':
|
|
269
|
+
{
|
|
270
|
+
if (typeof Boolean.prototype[action.params.type] !== 'function' && typeof Boolean[action.params.type] !== 'function') {
|
|
271
|
+
logger.error("Error: Invalid transform function passed to actions 'params.type' " + `attribute in element '${element.id}'. Must be withing 'String.prototype'!`);
|
|
272
|
+
return subject;
|
|
363
273
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const regexParts = ruleData.split('/');
|
|
367
|
-
let regexPattern = '';
|
|
368
|
-
let regexParam = '';
|
|
369
|
-
if (regexParts.length === 1) {
|
|
370
|
-
[regexPattern] = regexParts;
|
|
371
|
-
} else if (regexParts.length === 3) {
|
|
372
|
-
regexParts.shift();
|
|
373
|
-
[regexPattern, regexParam = ''] = regexParts;
|
|
374
|
-
} else {
|
|
375
|
-
logger.error(`Error: Invalid regex string in action rule in element ${element.id}`);
|
|
376
|
-
break;
|
|
377
|
-
}
|
|
378
|
-
const regex = new RegExp(regexPattern, regexParam);
|
|
379
|
-
tmpResult = regex.test(nextState.formData[rule.context]);
|
|
380
|
-
break;
|
|
274
|
+
if (typeof Boolean.prototype[action.params.type] === 'function') {
|
|
275
|
+
return Boolean.prototype[action.params.type].apply(subject, args);
|
|
381
276
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
* @returns {Function}
|
|
396
|
-
*/
|
|
397
|
-
this.createConcatMethod = method => (prev, next) => {
|
|
398
|
-
switch (method) {
|
|
399
|
-
case ACTION_RULES_CONCAT_METHOD_NONE:
|
|
400
|
-
return prev && !next;
|
|
401
|
-
case ACTION_RULES_CONCAT_METHOD_ANY:
|
|
402
|
-
return prev || next;
|
|
403
|
-
case ACTION_RULES_CONCAT_METHOD_ALL:
|
|
277
|
+
return Boolean[action.params.type](subject);
|
|
278
|
+
}
|
|
279
|
+
case 'number':
|
|
280
|
+
{
|
|
281
|
+
if (typeof Number.prototype[action.params.type] !== 'function' && typeof Number[action.params.type] !== 'function') {
|
|
282
|
+
logger.error("Error: Invalid transform function passed to actions 'params.type' " + `attribute in element '${element.id}'. Must be withing 'String.prototype'!`);
|
|
283
|
+
return subject;
|
|
284
|
+
}
|
|
285
|
+
if (typeof Number.prototype[action.params.type] === 'function') {
|
|
286
|
+
return Number.prototype[action.params.type].apply(subject, args);
|
|
287
|
+
}
|
|
288
|
+
return Number[action.params.type](subject);
|
|
289
|
+
}
|
|
404
290
|
default:
|
|
405
|
-
|
|
291
|
+
logger.error("Error: The given data can not be transformed. Must be of type 'string', " + "'boolean' or 'number'");
|
|
292
|
+
return subject;
|
|
406
293
|
}
|
|
407
294
|
};
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
*/
|
|
414
|
-
this.register = (elementId, handler) => {
|
|
415
|
-
if (!this.actionListeners[elementId]) {
|
|
416
|
-
this.actionListeners[elementId] = [];
|
|
295
|
+
let newState = {
|
|
296
|
+
...nextState,
|
|
297
|
+
formData: {
|
|
298
|
+
...nextState.formData,
|
|
299
|
+
[element.id]: transform(nextState.formData[element.id])
|
|
417
300
|
}
|
|
418
|
-
this.actionListeners[elementId].push(handler);
|
|
419
301
|
};
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
302
|
+
|
|
303
|
+
// Notify follow up listeners about the current change
|
|
304
|
+
if (nextState.formData[element.id] !== newState.formData[element.id]) {
|
|
305
|
+
newState = this.notify(element.id, prevState, newState);
|
|
306
|
+
}
|
|
307
|
+
return newState;
|
|
308
|
+
};
|
|
309
|
+
/**
|
|
310
|
+
* Evaluates all action rules of a given element action
|
|
311
|
+
*
|
|
312
|
+
* @param {FormElement} element The element of which the action rules should be evaluated
|
|
313
|
+
* @param {FormFieldAction} action The current action to be evaluate rules for
|
|
314
|
+
* @param {Object} nextState The state at the time before the "action" event finished
|
|
315
|
+
* @returns {boolean}
|
|
316
|
+
*/
|
|
317
|
+
this.evaluateRules = (element, action, nextState) => {
|
|
318
|
+
const concatRules = this.createConcatMethod(action.ruleConcatMethod);
|
|
319
|
+
const resultInitValue = action.ruleConcatMethod !== ACTION_RULES_CONCAT_METHOD_ANY;
|
|
320
|
+
let result = resultInitValue;
|
|
321
|
+
action.rules.forEach(rule => {
|
|
322
|
+
let tmpResult = resultInitValue;
|
|
323
|
+
let ruleType = rule.type;
|
|
324
|
+
let ruleData = rule.data;
|
|
325
|
+
|
|
326
|
+
// Default to rule type "boolean" and data true when type not given
|
|
327
|
+
if (ruleType === undefined) {
|
|
328
|
+
ruleType = ACTION_RULE_TYPE_BOOLEAN;
|
|
329
|
+
ruleData = true;
|
|
437
330
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
331
|
+
|
|
332
|
+
// Check rule validity
|
|
333
|
+
if (!ACTION_RULE_DATA_TYPES[ruleType]) {
|
|
334
|
+
logger.error(`Error: Unknown action rule type '${ruleType}'in element '${element.id}'`);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
// Check type of ruleData
|
|
338
|
+
const ruleDataType = ACTION_RULE_DATA_TYPES[ruleType];
|
|
339
|
+
if (ruleDataType === 'array' && !Array.isArray(ruleData)) {
|
|
340
|
+
logger.error(`Error: Invalid FormBuilder action rule in element '${element.id}': ` + `data must be an 'array' for rule type '${ruleType}'`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
// eslint-disable-next-line valid-typeof
|
|
344
|
+
if (ruleDataType !== 'array' && typeof ruleData !== ruleDataType) {
|
|
345
|
+
logger.error(`Error: Invalid FormBuilder action rule in element '${element.id}': ` + `data must be '${ruleDataType}' for rule type '${ruleType}'`);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
switch (ruleType) {
|
|
349
|
+
case ACTION_RULE_TYPE_ONE_OF:
|
|
350
|
+
{
|
|
351
|
+
tmpResult = ruleData.includes(nextState.formData[rule.context]);
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
case ACTION_RULE_TYPE_NOT_IN:
|
|
355
|
+
{
|
|
356
|
+
tmpResult = !ruleData.includes(nextState.formData[rule.context]);
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
case ACTION_RULE_TYPE_BOOLEAN:
|
|
360
|
+
{
|
|
361
|
+
tmpResult = ruleData;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
case ACTION_RULE_TYPE_REGEX:
|
|
365
|
+
{
|
|
366
|
+
const regexParts = ruleData.split('/');
|
|
367
|
+
let regexPattern = '';
|
|
368
|
+
let regexParam = '';
|
|
369
|
+
if (regexParts.length === 1) {
|
|
370
|
+
[regexPattern] = regexParts;
|
|
371
|
+
} else if (regexParts.length === 3) {
|
|
372
|
+
regexParts.shift();
|
|
373
|
+
[regexPattern, regexParam = ''] = regexParts;
|
|
374
|
+
} else {
|
|
375
|
+
logger.error(`Error: Invalid regex string in action rule in element ${element.id}`);
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
const regex = new RegExp(regexPattern, regexParam);
|
|
379
|
+
tmpResult = regex.test(nextState.formData[rule.context]);
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
default:
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Concat rules based on the rule concat method of the action
|
|
387
|
+
result = concatRules(result, tmpResult);
|
|
388
|
+
});
|
|
389
|
+
return result;
|
|
390
|
+
};
|
|
391
|
+
/**
|
|
392
|
+
* Creates a concat function that defines how to concatenate action rule results
|
|
393
|
+
*
|
|
394
|
+
* @param {string} method The method defined by the action
|
|
395
|
+
* @returns {Function}
|
|
396
|
+
*/
|
|
397
|
+
this.createConcatMethod = method => (prev, next) => {
|
|
398
|
+
switch (method) {
|
|
399
|
+
case ACTION_RULES_CONCAT_METHOD_NONE:
|
|
400
|
+
return prev && !next;
|
|
401
|
+
case ACTION_RULES_CONCAT_METHOD_ANY:
|
|
402
|
+
return prev || next;
|
|
403
|
+
case ACTION_RULES_CONCAT_METHOD_ALL:
|
|
404
|
+
default:
|
|
405
|
+
return prev && next;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
/**
|
|
409
|
+
* Adds a "action" listener to a given context element
|
|
410
|
+
*
|
|
411
|
+
* @param {string} elementId the element to listen for
|
|
412
|
+
* @param {Function} handler The listener to call when something has changed
|
|
413
|
+
*/
|
|
414
|
+
this.register = (elementId, handler) => {
|
|
415
|
+
if (!this.actionListeners[elementId]) {
|
|
416
|
+
this.actionListeners[elementId] = [];
|
|
417
|
+
}
|
|
418
|
+
this.actionListeners[elementId].push(handler);
|
|
419
|
+
};
|
|
420
|
+
/**
|
|
421
|
+
* Takes an element id, the state to work with and optional data and notifies all "action"
|
|
422
|
+
* listeners about the change. Every listener can manipulate the state.
|
|
423
|
+
* Returns the new state.
|
|
424
|
+
*
|
|
425
|
+
* @param {string} elementId The id of the element that was changed
|
|
426
|
+
* @param {Object} prevState The state before any changes took place
|
|
427
|
+
* @param {Object} nextState The state containing all updates before the listeners are executed
|
|
428
|
+
* @returns {Object} The new state after all handlers have been executed.
|
|
429
|
+
*/
|
|
430
|
+
this.notify = (elementId, prevState, nextState) => {
|
|
431
|
+
let newState = nextState;
|
|
432
|
+
if (this.actionListeners[elementId]) {
|
|
433
|
+
this.actionListeners[elementId].forEach(notifyListener => {
|
|
434
|
+
// Note: The order of state changes is applied in the same order of listener registration
|
|
435
|
+
newState = notifyListener(prevState, newState);
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
return newState;
|
|
439
|
+
};
|
|
440
|
+
this.defaults = defaults;
|
|
441
|
+
this.getProvincesList = getProvincesList;
|
|
442
|
+
this.actionListeners = {};
|
|
443
|
+
};
|
|
445
444
|
export default ActionListener;
|