@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.
Files changed (102) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/locales/ca/LC_MESSAGES/volto.po +31 -1
  3. package/locales/ca.json +1 -1
  4. package/locales/de/LC_MESSAGES/volto.po +31 -1
  5. package/locales/de.json +1 -1
  6. package/locales/en/LC_MESSAGES/volto.po +31 -1
  7. package/locales/en.json +1 -1
  8. package/locales/es/LC_MESSAGES/volto.po +31 -1
  9. package/locales/es.json +1 -1
  10. package/locales/eu/LC_MESSAGES/volto.po +31 -1
  11. package/locales/eu.json +1 -1
  12. package/locales/fi/LC_MESSAGES/volto.po +31 -1
  13. package/locales/fi.json +1 -1
  14. package/locales/fr/LC_MESSAGES/volto.po +31 -1
  15. package/locales/fr.json +1 -1
  16. package/locales/hi/LC_MESSAGES/volto.po +31 -1
  17. package/locales/hi.json +1 -1
  18. package/locales/it/LC_MESSAGES/volto.po +31 -1
  19. package/locales/it.json +1 -1
  20. package/locales/ja/LC_MESSAGES/volto.po +31 -1
  21. package/locales/ja.json +1 -1
  22. package/locales/nl/LC_MESSAGES/volto.po +31 -1
  23. package/locales/nl.json +1 -1
  24. package/locales/pt/LC_MESSAGES/volto.po +31 -1
  25. package/locales/pt.json +1 -1
  26. package/locales/pt_BR/LC_MESSAGES/volto.po +31 -1
  27. package/locales/pt_BR.json +1 -1
  28. package/locales/ro/LC_MESSAGES/volto.po +31 -1
  29. package/locales/ro.json +1 -1
  30. package/locales/volto.pot +32 -2
  31. package/locales/zh_CN/LC_MESSAGES/volto.po +31 -1
  32. package/locales/zh_CN.json +1 -1
  33. package/package.json +4 -5
  34. package/razzle.config.js +2 -2
  35. package/src/components/index.js +0 -1
  36. package/src/components/manage/AnchorPlugin/components/LinkButton/AddLinkForm.jsx +1 -1
  37. package/src/components/manage/AnchorPlugin/useLinkEditor.jsx +21 -21
  38. package/src/components/manage/Blocks/Block/BlocksForm.jsx +5 -0
  39. package/src/components/manage/Blocks/Block/Order/Item.jsx +6 -2
  40. package/src/components/manage/Blocks/Block/Order/Order.jsx +2 -0
  41. package/src/components/manage/Blocks/Container/Data.jsx +10 -2
  42. package/src/components/manage/Blocks/Image/ImageSidebar.jsx +10 -2
  43. package/src/components/manage/Blocks/Listing/ListingData.jsx +10 -2
  44. package/src/components/manage/Blocks/Maps/MapsSidebar.jsx +3 -1
  45. package/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +2 -0
  46. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +18 -2
  47. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +1 -1
  48. package/src/components/manage/Blocks/Teaser/Data.jsx +10 -2
  49. package/src/components/manage/Blocks/ToC/Edit.jsx +1 -0
  50. package/src/components/manage/Blocks/Video/Edit.jsx +1 -1
  51. package/src/components/manage/Blocks/Video/VideoSidebar.jsx +3 -1
  52. package/src/components/manage/Contents/Contents.jsx +1 -1
  53. package/src/components/manage/Controlpanels/ContentTypeSchema.jsx +1 -0
  54. package/src/components/manage/Controlpanels/UndoControlpanel.jsx +3 -3
  55. package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +28 -12
  56. package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +12 -4
  57. package/src/components/manage/Form/Form.jsx +85 -20
  58. package/src/components/manage/Form/InlineForm.jsx +4 -6
  59. package/src/components/manage/Form/ModalForm.jsx +1 -1
  60. package/src/components/manage/History/History.jsx +1 -1
  61. package/src/components/manage/Pluggable/Pluggable.test.js +1 -1
  62. package/src/components/manage/Toolbar/Toolbar.jsx +1 -1
  63. package/src/components/manage/Widgets/ArrayWidget.jsx +2 -2
  64. package/src/components/manage/Widgets/ImageWidget.jsx +34 -10
  65. package/src/components/manage/Widgets/RecurrenceWidget/EndField.jsx +7 -1
  66. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +80 -31
  67. package/src/components/theme/Login/Login.jsx +25 -4
  68. package/src/components/theme/Logout/Logout.jsx +2 -2
  69. package/src/components/theme/Search/Search.jsx +13 -5
  70. package/src/components/theme/View/View.jsx +0 -7
  71. package/src/components/theme/View/View.test.jsx +0 -3
  72. package/src/config/Widgets.jsx +1 -1
  73. package/src/config/index.js +7 -2
  74. package/src/config/validation.ts +155 -0
  75. package/src/helpers/Extensions/withBlockExtensions.jsx +1 -1
  76. package/src/helpers/FormValidation/FormValidation.jsx +109 -170
  77. package/src/helpers/FormValidation/FormValidation.test.js +836 -8
  78. package/src/helpers/FormValidation/validators.ts +203 -0
  79. package/src/helpers/MessageLabels/MessageLabels.js +28 -0
  80. package/src/helpers/Url/Url.test.js +4 -4
  81. package/src/helpers/User/User.js +1 -1
  82. package/src/hooks/client/useClient.js +1 -1
  83. package/test-setup-config.jsx +7 -0
  84. package/theme/themes/default/modules/embed.variables +1 -1
  85. package/theme/themes/pastanaga/collections/form.overrides +36 -2
  86. package/theme/themes/pastanaga/extras/blocks.less +14 -5
  87. package/theme/themes/pastanaga/extras/sidebar.less +4 -0
  88. package/theme/themes/pastanaga/extras/toolbar.less +10 -3
  89. package/tsconfig.declarations.json +3 -2
  90. package/types/components/index.d.ts +0 -1
  91. package/types/components/manage/Blocks/Block/Order/Order.d.ts +2 -1
  92. package/types/components/theme/Logout/Logout.d.ts +1 -1
  93. package/types/config/RichTextEditor/ToHTML.d.ts +1 -1
  94. package/types/config/Widgets.d.ts +2 -2
  95. package/types/config/validation.d.ts +3 -0
  96. package/types/helpers/Extensions/withBlockExtensions.d.ts +1 -1
  97. package/types/helpers/FormValidation/FormValidation.d.ts +1 -0
  98. package/types/helpers/FormValidation/validators.d.ts +29 -0
  99. package/types/helpers/MessageLabels/MessageLabels.d.ts +36 -0
  100. package/types/helpers/User/User.d.ts +1 -1
  101. package/src/components/theme/SocialSharing/SocialSharing.jsx +0 -48
  102. package/src/components/theme/SocialSharing/SocialSharing.test.jsx +0 -14
@@ -37,7 +37,6 @@ import {
37
37
  FREQUENCES,
38
38
  WEEKLY_DAYS,
39
39
  MONDAYFRIDAY_DAYS,
40
- toISOString,
41
40
  rrulei18n,
42
41
  } from './Utils';
43
42
 
@@ -219,26 +218,40 @@ class RecurrenceWidget extends Component {
219
218
 
220
219
  componentDidUpdate(prevProps) {
221
220
  if (this.props.value) {
222
- if (prevProps.formData?.start !== this.props.formData?.start) {
223
- let start = this.getUTCDate(this.props.formData?.start)
224
- .startOf('day')
225
- .toDate();
226
-
227
- this.setState((prevState) => {
228
- let rruleSet = prevState.rruleSet;
229
-
230
- rruleSet = this.updateRruleSet(
231
- rruleSet,
232
- prevState.formValues,
233
- 'dtstart',
234
- start,
235
- );
236
-
237
- return {
238
- ...prevState,
239
- rruleSet,
240
- };
241
- });
221
+ const changedStart =
222
+ prevProps.formData?.start !== this.props.formData?.start;
223
+ const changedEnd = prevProps.formData?.end !== this.props.formData?.end;
224
+
225
+ if (changedStart || changedEnd) {
226
+ let start = this.getUTCDate(this.props.formData?.start).toDate();
227
+
228
+ let changeFormValues = {};
229
+ if (changedEnd) {
230
+ changeFormValues.until = this.getUTCDate(
231
+ this.props.formData?.end,
232
+ ).toDate();
233
+ }
234
+ this.setState(
235
+ (prevState) => {
236
+ let rruleSet = prevState.rruleSet;
237
+
238
+ rruleSet = this.updateRruleSet(
239
+ rruleSet,
240
+ { ...prevState.formValues, ...changeFormValues },
241
+ 'dtstart',
242
+ start,
243
+ );
244
+
245
+ return {
246
+ ...prevState,
247
+ rruleSet,
248
+ };
249
+ },
250
+ () => {
251
+ //then, after set state, set recurrence rrule value
252
+ this.saveRrule();
253
+ },
254
+ );
242
255
  }
243
256
  }
244
257
  }
@@ -250,7 +263,8 @@ class RecurrenceWidget extends Component {
250
263
  setRecurrenceStartEnd = () => {
251
264
  const start = this.props.formData?.start;
252
265
 
253
- let _start = this.getUTCDate(start).startOf('day').toDate();
266
+ // The `start` date from Plone is in UTC
267
+ const _start = new Date(start);
254
268
 
255
269
  this.setState((prevState) => {
256
270
  let rruleSet = prevState.rruleSet;
@@ -339,7 +353,7 @@ class RecurrenceWidget extends Component {
339
353
  case 'until':
340
354
  if (value != null) {
341
355
  formValues['recurrenceEnds'] = option;
342
- formValues[option] = toISOString(value);
356
+ formValues[option] = value;
343
357
  }
344
358
  break;
345
359
  case 'byweekday':
@@ -422,7 +436,24 @@ class RecurrenceWidget extends Component {
422
436
  }
423
437
  break;
424
438
  case 'until':
425
- value = value ? this.moment(new Date(value)).utc().toDate() : null;
439
+ let mDate = null;
440
+ if (value) {
441
+ mDate = this.moment(new Date(value));
442
+ if (typeof value === 'string') {
443
+ mDate = this.moment(new Date(value));
444
+ } else {
445
+ //object-->Date()
446
+ mDate = this.moment(value);
447
+ }
448
+
449
+ if (this.props.formData.end) {
450
+ //set time from formData.end
451
+ const mEnd = this.moment(new Date(this.props.formData.end));
452
+ mDate.set('hour', mEnd.get('hour'));
453
+ mDate.set('minute', mEnd.get('minute'));
454
+ }
455
+ }
456
+ value = value ? mDate.toDate() : null;
426
457
  break;
427
458
  default:
428
459
  break;
@@ -447,7 +478,7 @@ class RecurrenceWidget extends Component {
447
478
  ? value
448
479
  : rruleSet.dtstart()
449
480
  ? rruleSet.dtstart()
450
- : this.moment().utc().toDate();
481
+ : new Date();
451
482
  var exdates =
452
483
  field === 'exdates' ? value : Object.assign([], rruleSet.exdates());
453
484
 
@@ -470,13 +501,14 @@ class RecurrenceWidget extends Component {
470
501
 
471
502
  getDefaultUntil = (freq) => {
472
503
  const moment = this.moment;
504
+
473
505
  var end = this.props.formData?.end
474
- ? toISOString(this.getUTCDate(this.props.formData.end).toDate())
506
+ ? moment(new Date(this.props.formData.end))
475
507
  : null;
476
- var tomorrow = toISOString(moment().add(1, 'days').utc().toDate());
477
- var nextWeek = toISOString(moment().add(7, 'days').utc().toDate());
478
- var nextMonth = toISOString(moment().add(1, 'months').utc().toDate());
479
- var nextYear = toISOString(moment().add(1, 'years').utc().toDate());
508
+ var tomorrow = moment().add(1, 'days');
509
+ var nextWeek = moment().add(7, 'days');
510
+ var nextMonth = moment().add(1, 'months');
511
+ var nextYear = moment().add(1, 'years');
480
512
 
481
513
  var until = end;
482
514
  switch (freq) {
@@ -502,6 +534,19 @@ class RecurrenceWidget extends Component {
502
534
  break;
503
535
  }
504
536
 
537
+ if (this.props.formData.end) {
538
+ //set default end time
539
+ until.set('hour', end.get('hour'));
540
+ until.set('minute', end.get('minute'));
541
+ }
542
+ until = new Date(
543
+ until.get('year'),
544
+ until.get('month'),
545
+ until.get('date'),
546
+ until.get('hour'),
547
+ until.get('minute'),
548
+ );
549
+
505
550
  return until;
506
551
  };
507
552
 
@@ -716,9 +761,13 @@ class RecurrenceWidget extends Component {
716
761
  }
717
762
  };
718
763
 
719
- save = () => {
764
+ saveRrule = () => {
720
765
  var value = this.state.rruleSet.toString();
721
766
  this.props.onChange(this.props.id, value);
767
+ };
768
+
769
+ save = () => {
770
+ this.saveRrule();
722
771
  this.close();
723
772
  };
724
773
 
@@ -12,10 +12,15 @@ import {
12
12
  import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
13
13
  import qs from 'query-string';
14
14
 
15
- import { Helmet } from '@plone/volto/helpers';
15
+ import { Helmet, usePrevious } from '@plone/volto/helpers';
16
16
  import config from '@plone/volto/registry';
17
17
  import { Icon } from '@plone/volto/components';
18
- import { login, resetLoginRequest } from '@plone/volto/actions';
18
+ import {
19
+ login,
20
+ logout,
21
+ resetLoginRequest,
22
+ purgeMessages,
23
+ } from '@plone/volto/actions';
19
24
  import { toast } from 'react-toastify';
20
25
  import { Toast } from '@plone/volto/components';
21
26
  import aheadSVG from '@plone/volto/icons/ahead.svg';
@@ -78,8 +83,22 @@ const Login = (props) => {
78
83
  location.pathname.replace(/\/login\/?$/, '').replace(/\/logout\/?$/, '') ||
79
84
  '/';
80
85
 
86
+ const previousToken = usePrevious(token);
87
+
81
88
  useEffect(() => {
82
- if (token && !(props.isLogout || location?.state?.isLogout)) {
89
+ if (location?.state?.isLogout) {
90
+ // Execute a true Logout action
91
+ // This is needed to cover the use case of being logged in in
92
+ // another backend (eg. in development), having a token for
93
+ // localhost and try to use it, the login route has to know that
94
+ // it's the same as it comes from a logout
95
+ // See also Unauthorized.jsx
96
+ dispatch(logout());
97
+ dispatch(purgeMessages());
98
+ // Reset the location state
99
+ history.push(`${location.pathname}${location.search}`);
100
+ } else if (token && token !== previousToken) {
101
+ // We just did a true login action
83
102
  history.push(returnUrl || '/');
84
103
  if (toast.isActive('loggedOut')) {
85
104
  toast.dismiss('loggedOut');
@@ -116,8 +135,10 @@ const Login = (props) => {
116
135
  intl,
117
136
  history,
118
137
  returnUrl,
119
- props.isLogout,
138
+ location.search,
139
+ location.pathname,
120
140
  location?.state?.isLogout,
141
+ previousToken,
121
142
  ]);
122
143
 
123
144
  const onLogin = (event) => {
@@ -3,7 +3,7 @@ import { useDispatch, useSelector, shallowEqual } from 'react-redux';
3
3
  import { useHistory } from 'react-router-dom';
4
4
  import { defineMessages, useIntl } from 'react-intl';
5
5
  import qs from 'query-string';
6
- import { Login, Toast } from '@plone/volto/components';
6
+ import { Toast } from '@plone/volto/components';
7
7
  import { logout, purgeMessages } from '@plone/volto/actions';
8
8
  import { toast } from 'react-toastify';
9
9
 
@@ -55,7 +55,7 @@ const Logout = ({ location }) => {
55
55
  }
56
56
  }, [history, returnUrl, intl, token]);
57
57
 
58
- return <Login location={{ query: location.query }} isLogout={true} />;
58
+ return '';
59
59
  };
60
60
 
61
61
  export default Logout;
@@ -71,6 +71,7 @@ class Search extends Component {
71
71
 
72
72
  constructor(props) {
73
73
  super(props);
74
+ this.defaultPageSize = config.settings.defaultPageSize;
74
75
  this.state = { currentPage: 1, isClient: false, active: 'relevance' };
75
76
  }
76
77
 
@@ -109,19 +110,24 @@ class Search extends Component {
109
110
  const options = qs.parse(this.props.history.location.search);
110
111
  this.setState({ currentPage: 1 });
111
112
  options['use_site_search_settings'] = 1;
112
- this.props.searchContent('', options);
113
+ this.props.searchContent('', {
114
+ b_size: this.defaultPageSize,
115
+ ...options,
116
+ });
113
117
  };
114
118
 
115
119
  handleQueryPaginationChange = (e, { activePage }) => {
116
- const { settings } = config;
117
120
  window.scrollTo(0, 0);
118
121
  let options = qs.parse(this.props.history.location.search);
119
122
  options['use_site_search_settings'] = 1;
120
123
 
121
124
  this.setState({ currentPage: activePage }, () => {
122
125
  this.props.searchContent('', {
126
+ b_size: this.defaultPageSize,
123
127
  ...options,
124
- b_start: (this.state.currentPage - 1) * settings.defaultPageSize,
128
+ b_start:
129
+ (this.state.currentPage - 1) *
130
+ (options.b_size || this.defaultPageSize),
125
131
  });
126
132
  });
127
133
  };
@@ -149,7 +155,8 @@ class Search extends Component {
149
155
  * @returns {string} Markup for the component.
150
156
  */
151
157
  render() {
152
- const { settings } = config;
158
+ const options = qs.parse(this.props.history.location.search);
159
+
153
160
  return (
154
161
  <Container id="page-search">
155
162
  <Helmet title={this.props.intl.formatMessage(messages.Search)} />
@@ -282,7 +289,8 @@ class Search extends Component {
282
289
  <Pagination
283
290
  activePage={this.state.currentPage}
284
291
  totalPages={Math.ceil(
285
- this.props.search.items_total / settings.defaultPageSize,
292
+ this.props.search.items_total /
293
+ (options.b_size || this.defaultPageSize),
286
294
  )}
287
295
  onPageChange={this.handleQueryPaginationChange}
288
296
  firstItem={null}
@@ -261,13 +261,6 @@ class View extends Component {
261
261
  this.props.content.subjects.length > 0 && (
262
262
  <Tags tags={this.props.content.subjects} />
263
263
  )}
264
- {/* Add opt-in social sharing if required, disabled by default */}
265
- {/* In the future this might be parameterized from the app config */}
266
- {/* <SocialSharing
267
- url={typeof window === 'undefined' ? '' : window.location.href}
268
- title={this.props.content.title}
269
- description={this.props.content.description || ''}
270
- /> */}
271
264
  {this.props.content.allow_discussion && (
272
265
  <Comments pathname={this.props.pathname} />
273
266
  )}
@@ -30,9 +30,6 @@ jest.mock('../../manage/Toolbar/Toolbar', () =>
30
30
  jest.fn(() => <div id="Portal" />),
31
31
  );
32
32
 
33
- jest.mock('../SocialSharing/SocialSharing', () =>
34
- jest.fn(() => <div id="SocialSharing" />),
35
- );
36
33
  jest.mock('../Comments/Comments', () => jest.fn(() => <div id="Comments" />));
37
34
  jest.mock('../Tags/Tags', () => jest.fn(() => <div id="Tags" />));
38
35
  jest.mock('../SlotRenderer/SlotRenderer', () =>
@@ -55,7 +55,6 @@ import ImageWidget from '@plone/volto/components/manage/Widgets/ImageWidget';
55
55
  // Widgets mapping
56
56
  export const widgetMapping = {
57
57
  id: {
58
- schema: SchemaWidget,
59
58
  subjects: TokenWidget,
60
59
  query: QuerystringWidget,
61
60
  recurrence: RecurrenceWidget,
@@ -89,6 +88,7 @@ export const widgetMapping = {
89
88
  autocomplete: SelectAutoComplete,
90
89
  color_picker: ColorPickerWidget,
91
90
  select: SelectWidget,
91
+ schema: SchemaWidget,
92
92
  },
93
93
  vocabulary: {
94
94
  'plone.app.vocabularies.Catalog': ObjectBrowserWidget,
@@ -32,6 +32,7 @@ import applyAddonConfiguration, { addonsInfo } from 'load-volto-addons';
32
32
  import ConfigRegistry from '@plone/volto/registry';
33
33
 
34
34
  import { getSiteAsyncPropExtender } from '@plone/volto/helpers';
35
+ import { registerValidators } from './validation';
35
36
 
36
37
  const host = process.env.HOST || 'localhost';
37
38
  const port = process.env.PORT || '3000';
@@ -97,7 +98,7 @@ let config = {
97
98
  process.env.RAZZLE_INTERNAL_API_PATH ||
98
99
  process.env.RAZZLE_API_PATH ||
99
100
  'http://localhost:8080/Plone', // Set it to '' for disabling the proxy
100
- // proxyRewriteTarget Set it for set a custom target for the proxy or overide the internal VHM rewrite
101
+ // proxyRewriteTarget Set it for set a custom target for the proxy or override the internal VHM rewrite
101
102
  // proxyRewriteTarget: '/VirtualHostBase/http/localhost:8080/Plone/VirtualHostRoot/_vh_api'
102
103
  // proxyRewriteTarget: 'https://myvoltositeinproduction.com'
103
104
  proxyRewriteTarget: process.env.RAZZLE_PROXY_REWRITE_TARGET || undefined,
@@ -209,8 +210,9 @@ let config = {
209
210
  },
210
211
  addonRoutes: [],
211
212
  addonReducers: {},
212
- slots: {},
213
213
  components,
214
+ slots: {},
215
+ utilities: {},
214
216
  };
215
217
 
216
218
  // The apiExpanders depends on a config of the object, so it's done here
@@ -238,5 +240,8 @@ ConfigRegistry.addonRoutes = config.addonRoutes;
238
240
  ConfigRegistry.addonReducers = config.addonReducers;
239
241
  ConfigRegistry.components = config.components;
240
242
  ConfigRegistry.slots = config.slots;
243
+ ConfigRegistry.utilities = config.utilities;
244
+
245
+ registerValidators(ConfigRegistry);
241
246
 
242
247
  applyAddonConfiguration(ConfigRegistry);
@@ -0,0 +1,155 @@
1
+ import { ConfigType } from '@plone/registry';
2
+
3
+ import {
4
+ minLengthValidator,
5
+ maxLengthValidator,
6
+ urlValidator,
7
+ emailValidator,
8
+ isNumberValidator,
9
+ maximumValidator,
10
+ minimumValidator,
11
+ isIntegerValidator,
12
+ maxItemsValidator,
13
+ minItemsValidator,
14
+ hasUniqueItemsValidator,
15
+ startEventDateRangeValidator,
16
+ endEventDateRangeValidator,
17
+ patternValidator,
18
+ } from '@plone/volto/helpers/FormValidation/validators';
19
+
20
+ const registerValidators = (config: ConfigType) => {
21
+ config.registerUtility({
22
+ name: 'minLength',
23
+ type: 'validator',
24
+ dependencies: { fieldType: 'string' },
25
+ method: minLengthValidator,
26
+ });
27
+
28
+ config.registerUtility({
29
+ name: 'maxLength',
30
+ type: 'validator',
31
+ dependencies: { fieldType: 'string' },
32
+ method: maxLengthValidator,
33
+ });
34
+
35
+ config.registerUtility({
36
+ name: 'pattern',
37
+ type: 'validator',
38
+ dependencies: { fieldType: 'string' },
39
+ method: patternValidator,
40
+ });
41
+
42
+ config.registerUtility({
43
+ name: 'minLength',
44
+ type: 'validator',
45
+ dependencies: { fieldType: 'password' },
46
+ method: minLengthValidator,
47
+ });
48
+
49
+ config.registerUtility({
50
+ name: 'maxLength',
51
+ type: 'validator',
52
+ dependencies: { fieldType: 'password' },
53
+ method: maxLengthValidator,
54
+ });
55
+
56
+ config.registerUtility({
57
+ name: 'pattern',
58
+ type: 'validator',
59
+ dependencies: { fieldType: 'password' },
60
+ method: patternValidator,
61
+ });
62
+
63
+ config.registerUtility({
64
+ name: 'email',
65
+ type: 'validator',
66
+ dependencies: { widget: 'email' },
67
+ method: emailValidator,
68
+ });
69
+
70
+ config.registerUtility({
71
+ name: 'url',
72
+ type: 'validator',
73
+ dependencies: { widget: 'url' },
74
+ method: urlValidator,
75
+ });
76
+
77
+ config.registerUtility({
78
+ name: 'number',
79
+ type: 'validator',
80
+ dependencies: { fieldType: 'number' },
81
+ method: isNumberValidator,
82
+ });
83
+
84
+ config.registerUtility({
85
+ name: 'minimum',
86
+ type: 'validator',
87
+ dependencies: { fieldType: 'number' },
88
+ method: minimumValidator,
89
+ });
90
+
91
+ config.registerUtility({
92
+ name: 'maximum',
93
+ type: 'validator',
94
+ dependencies: { fieldType: 'number' },
95
+ method: maximumValidator,
96
+ });
97
+
98
+ config.registerUtility({
99
+ name: 'integer',
100
+ type: 'validator',
101
+ dependencies: { fieldType: 'integer' },
102
+ method: isIntegerValidator,
103
+ });
104
+
105
+ config.registerUtility({
106
+ name: 'minimum',
107
+ type: 'validator',
108
+ dependencies: { fieldType: 'integer' },
109
+ method: minimumValidator,
110
+ });
111
+
112
+ config.registerUtility({
113
+ name: 'maximum',
114
+ type: 'validator',
115
+ dependencies: { fieldType: 'integer' },
116
+ method: maximumValidator,
117
+ });
118
+
119
+ config.registerUtility({
120
+ name: 'maxItems',
121
+ type: 'validator',
122
+ dependencies: { fieldType: 'array' },
123
+ method: maxItemsValidator,
124
+ });
125
+
126
+ config.registerUtility({
127
+ name: 'minItems',
128
+ type: 'validator',
129
+ dependencies: { fieldType: 'array' },
130
+ method: minItemsValidator,
131
+ });
132
+
133
+ config.registerUtility({
134
+ name: 'uniqueItems',
135
+ type: 'validator',
136
+ dependencies: { fieldType: 'array' },
137
+ method: hasUniqueItemsValidator,
138
+ });
139
+
140
+ config.registerUtility({
141
+ name: 'dateRangeValidator',
142
+ type: 'validator',
143
+ dependencies: { behaviorName: 'plone.eventbasic', fieldName: 'start' },
144
+ method: startEventDateRangeValidator,
145
+ });
146
+
147
+ config.registerUtility({
148
+ name: 'dateRangeValidator',
149
+ type: 'validator',
150
+ dependencies: { behaviorName: 'plone.eventbasic', fieldName: 'end' },
151
+ method: endEventDateRangeValidator,
152
+ });
153
+ };
154
+
155
+ export { registerValidators };
@@ -51,7 +51,7 @@ export function resolveExtension(name, extensions, data) {
51
51
  * - extensions is the blocksConfig extensions object for that block
52
52
  * - resolvedExtensions is an object with
53
53
  * `{ variation, <someExtensionA>, <someExtensionB> }` and each of these
54
- * fields hold the coresponding definition object from the block's
54
+ * fields hold the corresponding definition object from the block's
55
55
  * configuration.
56
56
  */
57
57
  export function resolveBlockExtensions(data, blocksConfig) {