@plone/volto 18.0.0-alpha.40 → 18.0.0-alpha.42
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/CHANGELOG.md +61 -0
- package/locales/ca/LC_MESSAGES/volto.po +31 -1
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +31 -1
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +31 -1
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +31 -1
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +31 -1
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +31 -1
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +31 -1
- package/locales/fr.json +1 -1
- package/locales/hi/LC_MESSAGES/volto.po +31 -1
- package/locales/hi.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +31 -1
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +31 -1
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +31 -1
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +31 -1
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +31 -1
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +31 -1
- package/locales/ro.json +1 -1
- package/locales/volto.pot +32 -2
- package/locales/zh_CN/LC_MESSAGES/volto.po +31 -1
- package/locales/zh_CN.json +1 -1
- package/package.json +4 -5
- package/razzle.config.js +2 -2
- package/src/components/index.js +0 -1
- package/src/components/manage/AnchorPlugin/components/LinkButton/AddLinkForm.jsx +1 -1
- package/src/components/manage/AnchorPlugin/useLinkEditor.jsx +21 -21
- package/src/components/manage/Blocks/Block/BlocksForm.jsx +5 -0
- package/src/components/manage/Blocks/Block/Order/Item.jsx +6 -2
- package/src/components/manage/Blocks/Block/Order/Order.jsx +2 -0
- package/src/components/manage/Blocks/Container/Data.jsx +10 -2
- package/src/components/manage/Blocks/Image/ImageSidebar.jsx +10 -2
- package/src/components/manage/Blocks/Listing/ListingData.jsx +10 -2
- package/src/components/manage/Blocks/Maps/MapsSidebar.jsx +3 -1
- package/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +2 -0
- package/src/components/manage/Blocks/Search/SearchBlockView.jsx +18 -2
- package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +1 -1
- package/src/components/manage/Blocks/Teaser/Data.jsx +10 -2
- package/src/components/manage/Blocks/ToC/Edit.jsx +1 -0
- package/src/components/manage/Blocks/Video/Edit.jsx +1 -1
- package/src/components/manage/Blocks/Video/VideoSidebar.jsx +3 -1
- package/src/components/manage/Contents/Contents.jsx +1 -1
- package/src/components/manage/Controlpanels/ContentTypeSchema.jsx +1 -0
- package/src/components/manage/Controlpanels/UndoControlpanel.jsx +3 -3
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +28 -12
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +12 -4
- package/src/components/manage/Form/Form.jsx +85 -20
- package/src/components/manage/Form/InlineForm.jsx +4 -6
- package/src/components/manage/Form/ModalForm.jsx +1 -1
- package/src/components/manage/History/History.jsx +1 -1
- package/src/components/manage/Pluggable/Pluggable.test.js +1 -1
- package/src/components/manage/Toolbar/Toolbar.jsx +1 -1
- package/src/components/manage/Widgets/ArrayWidget.jsx +2 -2
- package/src/components/manage/Widgets/ImageWidget.jsx +34 -10
- package/src/components/manage/Widgets/RecurrenceWidget/EndField.jsx +7 -1
- package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +80 -31
- package/src/components/theme/Login/Login.jsx +25 -4
- package/src/components/theme/Logout/Logout.jsx +2 -2
- package/src/components/theme/Search/Search.jsx +13 -5
- package/src/components/theme/View/View.jsx +0 -7
- package/src/components/theme/View/View.test.jsx +0 -3
- package/src/config/Widgets.jsx +1 -1
- package/src/config/index.js +7 -2
- package/src/config/validation.ts +155 -0
- package/src/helpers/Extensions/withBlockExtensions.jsx +1 -1
- package/src/helpers/FormValidation/FormValidation.jsx +109 -170
- package/src/helpers/FormValidation/FormValidation.test.js +836 -8
- package/src/helpers/FormValidation/validators.ts +203 -0
- package/src/helpers/MessageLabels/MessageLabels.js +28 -0
- package/src/helpers/Url/Url.test.js +4 -4
- package/src/helpers/User/User.js +1 -1
- package/src/hooks/client/useClient.js +1 -1
- package/test-setup-config.jsx +7 -0
- package/theme/themes/default/modules/embed.variables +1 -1
- package/theme/themes/pastanaga/collections/form.overrides +36 -2
- package/theme/themes/pastanaga/extras/blocks.less +14 -5
- package/theme/themes/pastanaga/extras/sidebar.less +4 -0
- package/theme/themes/pastanaga/extras/toolbar.less +10 -3
- package/tsconfig.declarations.json +3 -2
- package/types/components/index.d.ts +0 -1
- package/types/components/manage/Blocks/Block/Order/Order.d.ts +2 -1
- package/types/components/theme/Logout/Logout.d.ts +1 -1
- package/types/config/RichTextEditor/ToHTML.d.ts +1 -1
- package/types/config/Widgets.d.ts +2 -2
- package/types/config/validation.d.ts +3 -0
- package/types/helpers/Extensions/withBlockExtensions.d.ts +1 -1
- package/types/helpers/FormValidation/FormValidation.d.ts +1 -0
- package/types/helpers/FormValidation/validators.d.ts +29 -0
- package/types/helpers/MessageLabels/MessageLabels.d.ts +36 -0
- package/types/helpers/User/User.d.ts +1 -1
- package/src/components/theme/SocialSharing/SocialSharing.jsx +0 -48
- package/src/components/theme/SocialSharing/SocialSharing.test.jsx +0 -14
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { map,
|
|
1
|
+
import { map, keys, intersection, isEmpty } from 'lodash';
|
|
2
2
|
import { messages } from '../MessageLabels/MessageLabels';
|
|
3
3
|
import config from '@plone/volto/registry';
|
|
4
4
|
import { toast } from 'react-toastify';
|
|
@@ -11,7 +11,12 @@ import Toast from '@plone/volto/components/manage/Toast/Toast';
|
|
|
11
11
|
* @param {string | number} valueToCompare can compare '47' < 50
|
|
12
12
|
* @param {Function} intlFunc
|
|
13
13
|
*/
|
|
14
|
-
const validationMessage = (
|
|
14
|
+
export const validationMessage = (
|
|
15
|
+
isValid,
|
|
16
|
+
criterion,
|
|
17
|
+
valueToCompare,
|
|
18
|
+
intlFunc,
|
|
19
|
+
) =>
|
|
15
20
|
!isValid
|
|
16
21
|
? intlFunc(messages[criterion], {
|
|
17
22
|
len: valueToCompare,
|
|
@@ -19,142 +24,7 @@ const validationMessage = (isValid, criterion, valueToCompare, intlFunc) =>
|
|
|
19
24
|
: null;
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
|
-
*
|
|
23
|
-
* @param {string | number} value can compare '47' < 50
|
|
24
|
-
* @param {string | number} valueToCompare can compare '47' < 50
|
|
25
|
-
* @param {string} maxCriterion
|
|
26
|
-
* @param {Function} intlFunc
|
|
27
|
-
*/
|
|
28
|
-
const isMaxPropertyValid = (value, valueToCompare, maxCriterion, intlFunc) => {
|
|
29
|
-
const isValid = valueToCompare !== undefined ? value <= valueToCompare : true;
|
|
30
|
-
return validationMessage(isValid, maxCriterion, valueToCompare, intlFunc);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Returns if based on the criterion the value is higher or equal
|
|
35
|
-
* @param {string | number} value can compare '47' < 50
|
|
36
|
-
* @param {string | number} valueToCompare can compare '47' < 50
|
|
37
|
-
* @param {string} minCriterion
|
|
38
|
-
* @param {Function} intlFunc
|
|
39
|
-
*/
|
|
40
|
-
const isMinPropertyValid = (value, valueToCompare, minCriterion, intlFunc) => {
|
|
41
|
-
const isValid = valueToCompare !== undefined ? value >= valueToCompare : true;
|
|
42
|
-
return validationMessage(isValid, minCriterion, valueToCompare, intlFunc);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const widgetValidation = {
|
|
46
|
-
email: {
|
|
47
|
-
isValidEmail: (emailValue, emailObj, intlFunc) => {
|
|
48
|
-
// Email Regex taken from from WHATWG living standard:
|
|
49
|
-
// https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type=email)
|
|
50
|
-
const emailRegex =
|
|
51
|
-
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
52
|
-
const isValid = emailRegex.test(emailValue);
|
|
53
|
-
return !isValid ? intlFunc(messages.isValidEmail) : null;
|
|
54
|
-
},
|
|
55
|
-
minLength: (emailValue, emailObj, intlFunc) =>
|
|
56
|
-
isMinPropertyValid(
|
|
57
|
-
emailValue.length,
|
|
58
|
-
emailObj.minLength,
|
|
59
|
-
'minLength',
|
|
60
|
-
intlFunc,
|
|
61
|
-
),
|
|
62
|
-
maxLength: (emailValue, emailObj, intlFunc) =>
|
|
63
|
-
isMaxPropertyValid(
|
|
64
|
-
emailValue.length,
|
|
65
|
-
emailObj.maxLength,
|
|
66
|
-
'maxLength',
|
|
67
|
-
intlFunc,
|
|
68
|
-
),
|
|
69
|
-
},
|
|
70
|
-
url: {
|
|
71
|
-
isValidURL: (urlValue, urlObj, intlFunc) => {
|
|
72
|
-
var urlRegex = new RegExp(
|
|
73
|
-
'^(https?:\\/\\/)?' + // validate protocol
|
|
74
|
-
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // validate domain name
|
|
75
|
-
'((\\d{1,3}\\.){3}\\d{1,3}))|' + // validate OR ip (v4) address
|
|
76
|
-
'(localhost)' + // validate OR localhost address
|
|
77
|
-
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // validate port and path
|
|
78
|
-
'(\\?[;&a-z\\d%_.~+=-]*)?' + // validate query string
|
|
79
|
-
'(\\#[-a-z\\d_]*)?$', // validate fragment locator
|
|
80
|
-
'i',
|
|
81
|
-
);
|
|
82
|
-
const isValid = urlRegex.test(urlValue);
|
|
83
|
-
return !isValid ? intlFunc(messages.isValidURL) : null;
|
|
84
|
-
},
|
|
85
|
-
minLength: (urlValue, urlObj, intlFunc) =>
|
|
86
|
-
isMinPropertyValid(
|
|
87
|
-
urlValue.length,
|
|
88
|
-
urlObj.minLength,
|
|
89
|
-
'minLength',
|
|
90
|
-
intlFunc,
|
|
91
|
-
),
|
|
92
|
-
maxLength: (urlValue, urlObj, intlFunc) =>
|
|
93
|
-
isMaxPropertyValid(
|
|
94
|
-
urlValue.length,
|
|
95
|
-
urlObj.maxLength,
|
|
96
|
-
'maxLength',
|
|
97
|
-
intlFunc,
|
|
98
|
-
),
|
|
99
|
-
},
|
|
100
|
-
password: {
|
|
101
|
-
minLength: (passwordValue, passwordObj, intlFunc) =>
|
|
102
|
-
isMinPropertyValid(
|
|
103
|
-
passwordValue.length,
|
|
104
|
-
passwordObj.minLength,
|
|
105
|
-
'minLength',
|
|
106
|
-
intlFunc,
|
|
107
|
-
),
|
|
108
|
-
maxLength: (passwordValue, passwordObj, intlFunc) =>
|
|
109
|
-
isMaxPropertyValid(
|
|
110
|
-
passwordValue.length,
|
|
111
|
-
passwordObj.maxLength,
|
|
112
|
-
'maxLength',
|
|
113
|
-
intlFunc,
|
|
114
|
-
),
|
|
115
|
-
},
|
|
116
|
-
string: {
|
|
117
|
-
minLength: (value, itemObj, intlFunc) =>
|
|
118
|
-
isMinPropertyValid(
|
|
119
|
-
value.length,
|
|
120
|
-
itemObj.minLength,
|
|
121
|
-
'minLength',
|
|
122
|
-
intlFunc,
|
|
123
|
-
),
|
|
124
|
-
maxLength: (value, itemObj, intlFunc) =>
|
|
125
|
-
isMaxPropertyValid(
|
|
126
|
-
value.length,
|
|
127
|
-
itemObj.maxLength,
|
|
128
|
-
'maxLength',
|
|
129
|
-
intlFunc,
|
|
130
|
-
),
|
|
131
|
-
},
|
|
132
|
-
number: {
|
|
133
|
-
isNumber: (value, itemObj, intlFunc) => {
|
|
134
|
-
const floatRegex = /^[+-]?\d+(\.\d+)?$/;
|
|
135
|
-
const isValid = !isNaN(value) && floatRegex.test(value);
|
|
136
|
-
return !isValid ? intlFunc(messages.isNumber) : null;
|
|
137
|
-
},
|
|
138
|
-
minimum: (value, itemObj, intlFunc) =>
|
|
139
|
-
isMinPropertyValid(value, itemObj.minimum, 'minimum', intlFunc),
|
|
140
|
-
maximum: (value, itemObj, intlFunc) =>
|
|
141
|
-
isMaxPropertyValid(value, itemObj.maximum, 'maximum', intlFunc),
|
|
142
|
-
},
|
|
143
|
-
integer: {
|
|
144
|
-
isInteger: (value, itemObj, intlFunc) => {
|
|
145
|
-
const intRegex = /^-?[0-9]+$/;
|
|
146
|
-
const isValid = !isNaN(value) && intRegex.test(value);
|
|
147
|
-
return !isValid ? intlFunc(messages.isInteger) : null;
|
|
148
|
-
},
|
|
149
|
-
minimum: (value, itemObj, intlFunc) =>
|
|
150
|
-
isMinPropertyValid(value, itemObj.minimum, 'minimum', intlFunc),
|
|
151
|
-
maximum: (value, itemObj, intlFunc) =>
|
|
152
|
-
isMaxPropertyValid(value, itemObj.maximum, 'maximum', intlFunc),
|
|
153
|
-
},
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* The string that comes my not be a valid JSON
|
|
27
|
+
* The string that comes might not be a valid JSON
|
|
158
28
|
* @param {string} requestItem
|
|
159
29
|
*/
|
|
160
30
|
export const tryParseJSON = (requestItem) => {
|
|
@@ -171,24 +41,6 @@ export const tryParseJSON = (requestItem) => {
|
|
|
171
41
|
return resultObj;
|
|
172
42
|
};
|
|
173
43
|
|
|
174
|
-
/**
|
|
175
|
-
* Returns errors if obj has unique Items
|
|
176
|
-
* @param {Object} field
|
|
177
|
-
* @param {*} fieldData
|
|
178
|
-
* @returns {Object[string]} - list of errors
|
|
179
|
-
*/
|
|
180
|
-
const hasUniqueItems = (field, fieldData, formatMessage) => {
|
|
181
|
-
const errors = [];
|
|
182
|
-
if (
|
|
183
|
-
field.uniqueItems &&
|
|
184
|
-
fieldData &&
|
|
185
|
-
uniq(fieldData).length !== fieldData.length
|
|
186
|
-
) {
|
|
187
|
-
errors.push(formatMessage(messages.uniqueItems));
|
|
188
|
-
}
|
|
189
|
-
return errors;
|
|
190
|
-
};
|
|
191
|
-
|
|
192
44
|
/**
|
|
193
45
|
* If required fields are undefined, return list of errors
|
|
194
46
|
* @returns {Object[string]} - list of errors
|
|
@@ -252,35 +104,122 @@ const validateFieldsPerFieldset = (
|
|
|
252
104
|
touchedField,
|
|
253
105
|
);
|
|
254
106
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const widgetValidationCriteria = widgetValidation[fieldWidgetType]
|
|
258
|
-
? Object.keys(widgetValidation[fieldWidgetType])
|
|
259
|
-
: [];
|
|
260
|
-
let fieldData = formData[fieldId];
|
|
261
|
-
// test each criterion ex maximum, isEmail, isUrl, maxLength etc
|
|
262
|
-
const fieldErrors = widgetValidationCriteria
|
|
107
|
+
function checkFieldErrors(fieldValidationCriteria, field, fieldData) {
|
|
108
|
+
return fieldValidationCriteria
|
|
263
109
|
.map((widgetCriterion) => {
|
|
264
110
|
const errorMessage =
|
|
265
111
|
fieldData === undefined || fieldData === null
|
|
266
112
|
? null
|
|
267
|
-
:
|
|
268
|
-
fieldData,
|
|
113
|
+
: widgetCriterion.method({
|
|
114
|
+
value: fieldData,
|
|
269
115
|
field,
|
|
116
|
+
formData,
|
|
270
117
|
formatMessage,
|
|
271
|
-
);
|
|
118
|
+
});
|
|
272
119
|
return errorMessage;
|
|
273
120
|
})
|
|
274
121
|
.filter((item) => !!item);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
Object.entries(schema.properties).forEach(([fieldId, field]) => {
|
|
125
|
+
let fieldData = formData[fieldId];
|
|
126
|
+
|
|
127
|
+
// Validation per specific validator set (format property)
|
|
128
|
+
const hasSpecificValidator =
|
|
129
|
+
field.widgetOptions?.frontendOptions?.format || field.format;
|
|
130
|
+
let specificFieldErrors = [];
|
|
131
|
+
if (hasSpecificValidator) {
|
|
132
|
+
const specificValidationCriteria = config.getUtilities({
|
|
133
|
+
type: 'validator',
|
|
134
|
+
dependencies: { format: hasSpecificValidator },
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
specificFieldErrors = checkFieldErrors(
|
|
138
|
+
specificValidationCriteria,
|
|
139
|
+
field,
|
|
140
|
+
fieldData,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Validation per field type
|
|
145
|
+
const fieldType = field.type || 'string'; // defaults to string
|
|
146
|
+
const fieldTypeValidationCriteria = config.getUtilities({
|
|
147
|
+
type: 'validator',
|
|
148
|
+
dependencies: { fieldType },
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const fieldErrors = checkFieldErrors(
|
|
152
|
+
fieldTypeValidationCriteria,
|
|
153
|
+
field,
|
|
154
|
+
fieldData,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Validation per field widget
|
|
158
|
+
const widgetName =
|
|
159
|
+
field.widgetOptions?.frontendOptions?.widget || field.widget || '';
|
|
160
|
+
|
|
161
|
+
let widgetErrors = [];
|
|
162
|
+
if (widgetName) {
|
|
163
|
+
const widgetNameValidationCriteria = config.getUtilities({
|
|
164
|
+
type: 'validator',
|
|
165
|
+
dependencies: { widget: widgetName },
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
widgetErrors = checkFieldErrors(
|
|
169
|
+
widgetNameValidationCriteria,
|
|
170
|
+
field,
|
|
171
|
+
fieldData,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Validation per specific behavior and field name (for content types)
|
|
176
|
+
const behaviorName = field.behavior;
|
|
177
|
+
let perBehaviorFieldErrors = [];
|
|
178
|
+
if (behaviorName) {
|
|
179
|
+
const specificPerBehaviorFieldValidationCriteria = config.getUtilities({
|
|
180
|
+
type: 'validator',
|
|
181
|
+
dependencies: { behaviorName, fieldName: fieldId },
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
perBehaviorFieldErrors = checkFieldErrors(
|
|
185
|
+
specificPerBehaviorFieldValidationCriteria,
|
|
186
|
+
field,
|
|
187
|
+
fieldData,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Validation per block type validator (for blocks)
|
|
192
|
+
const blockType = formData['@type'];
|
|
193
|
+
let blockTypeFieldErrors = [];
|
|
194
|
+
if (blockType) {
|
|
195
|
+
const blockTypeFieldValidationCriteria = config.getUtilities({
|
|
196
|
+
type: 'validator',
|
|
197
|
+
dependencies: { blockType, fieldName: fieldId },
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
blockTypeFieldErrors = checkFieldErrors(
|
|
201
|
+
blockTypeFieldValidationCriteria,
|
|
202
|
+
field,
|
|
203
|
+
fieldData,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
275
206
|
|
|
276
|
-
const
|
|
277
|
-
|
|
207
|
+
const mergedErrors = [
|
|
208
|
+
...specificFieldErrors,
|
|
209
|
+
...fieldErrors,
|
|
210
|
+
...widgetErrors,
|
|
211
|
+
...perBehaviorFieldErrors,
|
|
212
|
+
...blockTypeFieldErrors,
|
|
213
|
+
];
|
|
278
214
|
|
|
279
215
|
if (mergedErrors.length > 0) {
|
|
280
216
|
errors[fieldId] = [
|
|
281
217
|
...(errors[fieldId] || []),
|
|
218
|
+
...specificFieldErrors,
|
|
282
219
|
...fieldErrors,
|
|
283
|
-
...
|
|
220
|
+
...widgetErrors,
|
|
221
|
+
...perBehaviorFieldErrors,
|
|
222
|
+
...blockTypeFieldErrors,
|
|
284
223
|
];
|
|
285
224
|
}
|
|
286
225
|
});
|