@plone/volto 15.0.0-alpha.4 → 15.0.0-alpha.8

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 (238) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +7 -6
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
  3. package/.github/workflows/docs.yml +15 -55
  4. package/CHANGELOG.md +57 -2
  5. package/CODE_OF_CONDUCT.md +0 -1
  6. package/COMMITLINT.md +19 -21
  7. package/README.md +1 -1
  8. package/SECURITY.md +0 -1
  9. package/addon-registry.js +6 -3
  10. package/dist/assets.json +1 -0
  11. package/dist/chunks.json +572 -0
  12. package/dist/loadable-stats.json +2099 -0
  13. package/dist/public/android-chrome-192x192.png +0 -0
  14. package/dist/public/android-chrome-512x512.png +0 -0
  15. package/dist/public/apple-touch-icon.png +0 -0
  16. package/dist/public/favicon-16x16.png +0 -0
  17. package/dist/public/favicon-32x32.png +0 -0
  18. package/dist/public/favicon.ico +0 -0
  19. package/dist/public/icon.svg +13 -0
  20. package/dist/public/index.html.spa +34 -0
  21. package/dist/public/robots.txt +2 -0
  22. package/dist/public/site.webmanifest +19 -0
  23. package/dist/public/static/css/15.2cdd5437.chunk.css +409 -0
  24. package/dist/public/static/css/15.2cdd5437.chunk.css.map +1 -0
  25. package/dist/public/static/css/8.37cef611.chunk.css +2 -0
  26. package/dist/public/static/css/8.37cef611.chunk.css.map +1 -0
  27. package/dist/public/static/css/client.4cb92c57.chunk.css +8 -0
  28. package/dist/public/static/css/client.4cb92c57.chunk.css.map +1 -0
  29. package/dist/public/static/css/plone-volto-components-manage-Widgets-DatetimeWidget.c847a331.chunk.css +2 -0
  30. package/dist/public/static/css/plone-volto-components-manage-Widgets-DatetimeWidget.c847a331.chunk.css.map +1 -0
  31. package/dist/public/static/js/0.3e794c57.chunk.js +2 -0
  32. package/dist/public/static/js/0.3e794c57.chunk.js.map +1 -0
  33. package/dist/public/static/js/1.fece2b93.chunk.js +3 -0
  34. package/dist/public/static/js/1.fece2b93.chunk.js.LICENSE.txt +8 -0
  35. package/dist/public/static/js/1.fece2b93.chunk.js.map +1 -0
  36. package/dist/public/static/js/15.2cdd5437.chunk.js +3 -0
  37. package/dist/public/static/js/15.2cdd5437.chunk.js.LICENSE.txt +120 -0
  38. package/dist/public/static/js/15.2cdd5437.chunk.js.map +1 -0
  39. package/dist/public/static/js/16.a3a0662d.chunk.js +3 -0
  40. package/dist/public/static/js/16.a3a0662d.chunk.js.LICENSE.txt +8 -0
  41. package/dist/public/static/js/16.a3a0662d.chunk.js.map +1 -0
  42. package/dist/public/static/js/17.9478c50d.chunk.js +2 -0
  43. package/dist/public/static/js/17.9478c50d.chunk.js.map +1 -0
  44. package/dist/public/static/js/18.388e65d0.chunk.js +2 -0
  45. package/dist/public/static/js/18.388e65d0.chunk.js.map +1 -0
  46. package/dist/public/static/js/19.7c6b4a80.chunk.js +2 -0
  47. package/dist/public/static/js/19.7c6b4a80.chunk.js.map +1 -0
  48. package/dist/public/static/js/2.e6b0d690.chunk.js +2 -0
  49. package/dist/public/static/js/2.e6b0d690.chunk.js.map +1 -0
  50. package/dist/public/static/js/20.ada67f0e.chunk.js +3 -0
  51. package/dist/public/static/js/20.ada67f0e.chunk.js.LICENSE.txt +8 -0
  52. package/dist/public/static/js/20.ada67f0e.chunk.js.map +1 -0
  53. package/dist/public/static/js/21.3de49ac8.chunk.js +2 -0
  54. package/dist/public/static/js/21.3de49ac8.chunk.js.map +1 -0
  55. package/dist/public/static/js/22.ecefb8f2.chunk.js +2 -0
  56. package/dist/public/static/js/22.ecefb8f2.chunk.js.map +1 -0
  57. package/dist/public/static/js/23.3027bc00.chunk.js +2 -0
  58. package/dist/public/static/js/23.3027bc00.chunk.js.map +1 -0
  59. package/dist/public/static/js/24.aaaf4abf.chunk.js +2 -0
  60. package/dist/public/static/js/24.aaaf4abf.chunk.js.map +1 -0
  61. package/dist/public/static/js/25.c4d7d5e0.chunk.js +2 -0
  62. package/dist/public/static/js/25.c4d7d5e0.chunk.js.map +1 -0
  63. package/dist/public/static/js/26.d59ac3c1.chunk.js +2 -0
  64. package/dist/public/static/js/26.d59ac3c1.chunk.js.map +1 -0
  65. package/dist/public/static/js/27.266d95dd.chunk.js +2 -0
  66. package/dist/public/static/js/27.266d95dd.chunk.js.map +1 -0
  67. package/dist/public/static/js/28.d965d304.chunk.js +2 -0
  68. package/dist/public/static/js/28.d965d304.chunk.js.map +1 -0
  69. package/dist/public/static/js/29.7d8d1992.chunk.js +2 -0
  70. package/dist/public/static/js/29.7d8d1992.chunk.js.map +1 -0
  71. package/dist/public/static/js/3.025ba843.chunk.js +2 -0
  72. package/dist/public/static/js/3.025ba843.chunk.js.map +1 -0
  73. package/dist/public/static/js/30.a3d54e31.chunk.js +2 -0
  74. package/dist/public/static/js/30.a3d54e31.chunk.js.map +1 -0
  75. package/dist/public/static/js/31.9edf64ee.chunk.js +2 -0
  76. package/dist/public/static/js/31.9edf64ee.chunk.js.map +1 -0
  77. package/dist/public/static/js/32.649dbfc2.chunk.js +2 -0
  78. package/dist/public/static/js/32.649dbfc2.chunk.js.map +1 -0
  79. package/dist/public/static/js/33.45949ca4.chunk.js +2 -0
  80. package/dist/public/static/js/33.45949ca4.chunk.js.map +1 -0
  81. package/dist/public/static/js/34.084257cf.chunk.js +2 -0
  82. package/dist/public/static/js/34.084257cf.chunk.js.map +1 -0
  83. package/dist/public/static/js/35.00679602.chunk.js +3 -0
  84. package/dist/public/static/js/35.00679602.chunk.js.LICENSE.txt +37 -0
  85. package/dist/public/static/js/35.00679602.chunk.js.map +1 -0
  86. package/dist/public/static/js/36.4a29fdbd.chunk.js +3 -0
  87. package/dist/public/static/js/36.4a29fdbd.chunk.js.LICENSE.txt +7 -0
  88. package/dist/public/static/js/36.4a29fdbd.chunk.js.map +1 -0
  89. package/dist/public/static/js/37.fbbe07b3.chunk.js +3 -0
  90. package/dist/public/static/js/37.fbbe07b3.chunk.js.LICENSE.txt +14 -0
  91. package/dist/public/static/js/37.fbbe07b3.chunk.js.map +1 -0
  92. package/dist/public/static/js/38.b31c59ad.chunk.js +3 -0
  93. package/dist/public/static/js/38.b31c59ad.chunk.js.LICENSE.txt +8 -0
  94. package/dist/public/static/js/38.b31c59ad.chunk.js.map +1 -0
  95. package/dist/public/static/js/39.69d6a789.chunk.js +2 -0
  96. package/dist/public/static/js/39.69d6a789.chunk.js.map +1 -0
  97. package/dist/public/static/js/4.bdc4a5c5.chunk.js +2 -0
  98. package/dist/public/static/js/4.bdc4a5c5.chunk.js.map +1 -0
  99. package/dist/public/static/js/40.90de6e4a.chunk.js +2 -0
  100. package/dist/public/static/js/40.90de6e4a.chunk.js.map +1 -0
  101. package/dist/public/static/js/7.7acc66bc.chunk.js +2 -0
  102. package/dist/public/static/js/7.7acc66bc.chunk.js.map +1 -0
  103. package/dist/public/static/js/8.37cef611.chunk.js +3 -0
  104. package/dist/public/static/js/8.37cef611.chunk.js.LICENSE.txt +25 -0
  105. package/dist/public/static/js/8.37cef611.chunk.js.map +1 -0
  106. package/dist/public/static/js/client.4cb92c57.chunk.js +2 -0
  107. package/dist/public/static/js/client.4cb92c57.chunk.js.map +1 -0
  108. package/dist/public/static/js/draft-js-lib-isSoftNewlineEvent.6cd05e34.chunk.js +2 -0
  109. package/dist/public/static/js/draft-js-lib-isSoftNewlineEvent.6cd05e34.chunk.js.map +1 -0
  110. package/dist/public/static/js/moment.2caa76d1.chunk.js +2 -0
  111. package/dist/public/static/js/moment.2caa76d1.chunk.js.map +1 -0
  112. package/dist/public/static/js/plone-volto-components-manage-Widgets-DatetimeWidget.c847a331.chunk.js +2 -0
  113. package/dist/public/static/js/plone-volto-components-manage-Widgets-DatetimeWidget.c847a331.chunk.js.map +1 -0
  114. package/dist/public/static/js/plone-volto-components-theme-View-EventView.433dd14b.chunk.js +2 -0
  115. package/dist/public/static/js/plone-volto-components-theme-View-EventView.433dd14b.chunk.js.map +1 -0
  116. package/dist/public/static/js/react-dates.f71abb7c.chunk.js +2 -0
  117. package/dist/public/static/js/react-dates.f71abb7c.chunk.js.map +1 -0
  118. package/dist/public/static/js/react-simple-code-editor.33478dc3.chunk.js +2 -0
  119. package/dist/public/static/js/react-simple-code-editor.33478dc3.chunk.js.map +1 -0
  120. package/dist/public/static/js/runtime~client.d372df0e.js +2 -0
  121. package/dist/public/static/js/runtime~client.d372df0e.js.map +1 -0
  122. package/dist/public/static/media/Logo.16e25cdf.svg +21 -0
  123. package/dist/public/static/media/block-image.8a4a14d5.svg +8 -0
  124. package/dist/public/static/media/block-maps.731e84f6.svg +7 -0
  125. package/dist/public/static/media/block-video.832fa3ff.svg +7 -0
  126. package/dist/public/static/media/default-image.9451b251.svg +13 -0
  127. package/dist/public/static/media/flags.9c74e172.png +0 -0
  128. package/dist/public/static/media/icons.022583c4.svg +320 -0
  129. package/dist/public/static/media/icons.06400145.ttf +0 -0
  130. package/dist/public/static/media/icons.dbc1ef8b.eot +0 -0
  131. package/dist/public/static/media/icons.df45b7de.woff +0 -0
  132. package/dist/server.js +2 -0
  133. package/locales/ca/LC_MESSAGES/volto.po +14 -0
  134. package/locales/ca.json +1 -1
  135. package/locales/de/LC_MESSAGES/volto.po +14 -0
  136. package/locales/de.json +1 -1
  137. package/locales/en/LC_MESSAGES/volto.po +14 -0
  138. package/locales/en.json +1 -1
  139. package/locales/es/LC_MESSAGES/volto.po +14 -0
  140. package/locales/es.json +1 -1
  141. package/locales/eu/LC_MESSAGES/volto.po +14 -0
  142. package/locales/eu.json +1 -1
  143. package/locales/fr/LC_MESSAGES/volto.po +14 -0
  144. package/locales/fr.json +1 -1
  145. package/locales/it/LC_MESSAGES/volto.po +14 -0
  146. package/locales/it.json +1 -1
  147. package/locales/ja/LC_MESSAGES/volto.po +14 -0
  148. package/locales/ja.json +1 -1
  149. package/locales/nl/LC_MESSAGES/volto.po +14 -0
  150. package/locales/nl.json +1 -1
  151. package/locales/pt/LC_MESSAGES/volto.po +14 -0
  152. package/locales/pt.json +1 -1
  153. package/locales/pt_BR/LC_MESSAGES/volto.po +14 -0
  154. package/locales/pt_BR.json +1 -1
  155. package/locales/ro/LC_MESSAGES/volto.po +14 -0
  156. package/locales/ro.json +1 -1
  157. package/locales/volto.pot +15 -1
  158. package/logos/Logo.png +0 -0
  159. package/logos/volto-colorful.png +0 -0
  160. package/logos/volto-colorful.svg +35 -0
  161. package/logos/volto-guide.png +0 -0
  162. package/logos/volto-h-transparent.svg +6 -0
  163. package/logos/volto-transparent.png +0 -0
  164. package/logos/volto-transparent.svg +19 -0
  165. package/logos/volto-transparent2.svg +5 -0
  166. package/logos/volto-yellow.svg +29 -0
  167. package/logos/volto.sketch +0 -0
  168. package/netlify.toml +2 -0
  169. package/package.json +6 -2
  170. package/razzle.config.js +2 -2
  171. package/src/actions/language/language.js +7 -2
  172. package/src/components/manage/AnchorPlugin/components/LinkButton/AddLinkForm.jsx +1 -2
  173. package/src/components/manage/AnchorPlugin/components/LinkButton/index.jsx +15 -6
  174. package/src/components/manage/AnchorPlugin/index.jsx +12 -5
  175. package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +8 -7
  176. package/src/components/manage/Blocks/Description/Edit.jsx +33 -19
  177. package/src/components/manage/Blocks/Description/Edit.test.jsx +6 -0
  178. package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +37 -26
  179. package/src/components/manage/Blocks/HeroImageLeft/Edit.test.jsx +6 -0
  180. package/src/components/manage/Blocks/Search/README.md +20 -0
  181. package/src/components/manage/Blocks/Search/components/CheckboxFacet.jsx +16 -3
  182. package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +120 -0
  183. package/src/components/manage/Blocks/Search/components/DateRangeFacet.test.jsx +34 -0
  184. package/src/components/manage/Blocks/Search/components/DateRangeFacetFilterListEntry.jsx +39 -0
  185. package/src/components/manage/Blocks/Search/components/Facets.jsx +24 -25
  186. package/src/components/manage/Blocks/Search/components/FilterList.jsx +37 -67
  187. package/src/components/manage/Blocks/Search/components/FilterList.test.jsx +49 -1
  188. package/src/components/manage/Blocks/Search/components/SelectFacet.jsx +9 -0
  189. package/src/components/manage/Blocks/Search/components/SelectFacetFilterListEntry.jsx +42 -0
  190. package/src/components/manage/Blocks/Search/components/SelectStyling.jsx +1 -1
  191. package/src/components/manage/Blocks/Search/components/ToggleFacet.jsx +38 -0
  192. package/src/components/manage/Blocks/Search/components/ToggleFacetFilterListEntry.jsx +39 -0
  193. package/src/components/manage/Blocks/Search/components/base.js +52 -0
  194. package/src/components/manage/Blocks/Search/components/index.js +5 -0
  195. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +68 -27
  196. package/src/components/manage/Blocks/Search/schema.js +7 -4
  197. package/src/components/manage/Blocks/Search/utils.js +16 -0
  198. package/src/components/manage/Blocks/Table/Cell.jsx +40 -14
  199. package/src/components/manage/Blocks/Table/Cell.test.jsx +7 -1
  200. package/src/components/manage/Blocks/Table/Edit.jsx +7 -3
  201. package/src/components/manage/Blocks/Table/Edit.test.jsx +6 -0
  202. package/src/components/manage/Blocks/Table/View.jsx +2 -2
  203. package/src/components/manage/Blocks/Text/Edit.jsx +56 -14
  204. package/src/components/manage/Blocks/Text/Edit.test.jsx +7 -1
  205. package/src/components/manage/Blocks/Text/View.jsx +2 -2
  206. package/src/components/manage/Blocks/Title/Edit.jsx +25 -13
  207. package/src/components/manage/Blocks/Title/Edit.test.jsx +6 -0
  208. package/src/components/manage/Sidebar/Sidebar.jsx +5 -1
  209. package/src/components/manage/Toolbar/Toolbar.jsx +3 -1
  210. package/src/components/manage/UniversalLink/UniversalLink.jsx +5 -2
  211. package/src/components/manage/Widgets/DatetimeWidget.jsx +3 -1
  212. package/src/components/manage/Widgets/UrlWidget.jsx +1 -1
  213. package/src/components/manage/Widgets/WysiwygWidget.jsx +45 -19
  214. package/src/components/manage/Widgets/WysiwygWidget.test.jsx +7 -1
  215. package/src/components/theme/View/LinkView.jsx +1 -1
  216. package/src/components/theme/View/View.jsx +5 -1
  217. package/src/config/Blocks.jsx +31 -0
  218. package/src/config/Loadables.jsx +22 -0
  219. package/src/config/RichTextEditor/Blocks.jsx +25 -20
  220. package/src/config/RichTextEditor/Plugins.jsx +38 -31
  221. package/src/config/RichTextEditor/Styles.jsx +48 -44
  222. package/src/config/RichTextEditor/index.js +25 -0
  223. package/src/config/index.js +14 -18
  224. package/src/helpers/Api/Api.js +18 -4
  225. package/src/helpers/Extensions/index.js +1 -1
  226. package/src/helpers/Extensions/withBlockExtensions.js +4 -0
  227. package/src/helpers/Extensions/withBlockExtensions.test.js +26 -1
  228. package/src/helpers/Url/Url.js +32 -1
  229. package/src/helpers/Url/urlRegex.js +7 -1
  230. package/src/helpers/index.js +2 -0
  231. package/src/middleware/api.js +21 -2
  232. package/src/server.jsx +9 -2
  233. package/test-setup-config.js +22 -7
  234. package/theme/themes/pastanaga/extras/blocks.less +29 -0
  235. package/src/components/manage/AnchorPlugin/utils/URLUtils.js +0 -36
  236. package/src/components/manage/AnchorPlugin/utils/mailRegex.js +0 -2
  237. package/src/components/manage/AnchorPlugin/utils/telRegex.js +0 -1
  238. package/src/components/manage/AnchorPlugin/utils/urlRegex.js +0 -54
@@ -5,6 +5,11 @@ import {
5
5
  DropdownIndicator,
6
6
  } from '@plone/volto/components/manage/Widgets/SelectStyling';
7
7
  import { selectTheme, customSelectStyles } from './SelectStyling';
8
+ import {
9
+ selectFacetSchemaEnhancer,
10
+ selectFacetStateToValue,
11
+ selectFacetValueToQuery,
12
+ } from './base';
8
13
 
9
14
  const SelectFacet = (props) => {
10
15
  const {
@@ -47,4 +52,8 @@ const SelectFacet = (props) => {
47
52
  );
48
53
  };
49
54
 
55
+ SelectFacet.schemaEnhancer = selectFacetSchemaEnhancer;
56
+ SelectFacet.stateToValue = selectFacetStateToValue;
57
+ SelectFacet.valueToQuery = selectFacetValueToQuery;
58
+
50
59
  export default injectLazyLibs('reactSelect')(SelectFacet);
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { Label, Icon } from 'semantic-ui-react';
3
+
4
+ function SelectFacetFilterListEntry(props) {
5
+ const { facet, isEditMode, setFacets, facets } = props;
6
+ return typeof facets[facet] === 'string' ? (
7
+ <Label size="small">
8
+ {facets[facet]}
9
+ <Icon
10
+ name="delete"
11
+ onClick={() => {
12
+ !isEditMode &&
13
+ setFacets({
14
+ ...facets,
15
+ [facet]: '',
16
+ });
17
+ }}
18
+ />
19
+ </Label>
20
+ ) : (
21
+ <>
22
+ {facets[facet].map((entry, i) => (
23
+ <Label size="small" key={i}>
24
+ {entry}
25
+ <Icon
26
+ name="delete"
27
+ onClick={() => {
28
+ const entries = facets[facet].filter((item) => item !== entry);
29
+ !isEditMode &&
30
+ setFacets({
31
+ ...facets,
32
+ [facet]: entries,
33
+ });
34
+ }}
35
+ />
36
+ </Label>
37
+ ))}
38
+ </>
39
+ );
40
+ }
41
+
42
+ export default SelectFacetFilterListEntry;
@@ -15,7 +15,7 @@ export const customSelectStyles = {
15
15
  borderBottom: '1px solid #c7d5d8',
16
16
  boxShadow: 'none',
17
17
  borderBottomStyle: state.menuIsOpen ? 'dotted' : 'solid',
18
- minHeight: '40px',
18
+ minHeight: '37px',
19
19
  }),
20
20
  menu: (styles, state) => ({
21
21
  ...styles,
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { Radio, Header } from 'semantic-ui-react';
3
+
4
+ const ToggleFacet = (props) => {
5
+ const { facet, isEditMode, onChange, value } = props; // value, choices, isMulti, onChange,
6
+
7
+ return (
8
+ <div className="checkbox-facet">
9
+ <Header as="h4">{facet?.title ?? facet?.field?.label}</Header>
10
+ <div className="radio">
11
+ <Radio
12
+ toggle
13
+ checked={value || typeof value === 'string'}
14
+ disabled={isEditMode}
15
+ onChange={(e, { checked }) => {
16
+ onChange(facet.field.value, checked);
17
+ }}
18
+ />
19
+ </div>
20
+ </div>
21
+ );
22
+ };
23
+
24
+ ToggleFacet.stateToValue = ({ facetSettings, index, selectedValue }) => {
25
+ return selectedValue || typeof selectedValue === 'string';
26
+ };
27
+
28
+ ToggleFacet.valueToQuery = ({ value, facet }) => {
29
+ return value || typeof value === 'string'
30
+ ? {
31
+ i: facet.field.value,
32
+ o: 'plone.app.querystring.operation.boolean.isTrue',
33
+ v: '',
34
+ }
35
+ : null;
36
+ };
37
+
38
+ export default ToggleFacet;
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { Label, Icon } from 'semantic-ui-react';
3
+ import { defineMessages, useIntl } from 'react-intl';
4
+
5
+ const messages = defineMessages({
6
+ yes: {
7
+ id: 'yes',
8
+ defaultMessage: 'Yes',
9
+ },
10
+ no: {
11
+ id: 'no',
12
+ defaultMessage: 'No',
13
+ },
14
+ });
15
+
16
+ function ToggleFacetFilterListEntry(props) {
17
+ const { facet, isEditMode, setFacets, facets } = props;
18
+ const intl = useIntl();
19
+
20
+ return (
21
+ <Label size="small">
22
+ {intl.formatMessage(facets[facet] ? messages.yes : messages.no)}
23
+ <Icon
24
+ name="delete"
25
+ onClick={() => {
26
+ const filteredFacets = Object.assign(
27
+ {},
28
+ ...Object.keys(facets)
29
+ .filter((f) => f !== facet)
30
+ .map((f) => ({ [f]: facets[f] })),
31
+ );
32
+ !isEditMode && setFacets(filteredFacets);
33
+ }}
34
+ />
35
+ </Label>
36
+ );
37
+ }
38
+
39
+ export default ToggleFacetFilterListEntry;
@@ -0,0 +1,52 @@
1
+ import { isEmpty } from 'lodash';
2
+
3
+ /**
4
+ * Converts the state (extracted from URL) to options for the facet control
5
+ *
6
+ * Shared by the SelectFacet and CheckboxFacet
7
+ */
8
+ export const selectFacetStateToValue = ({
9
+ facetSettings,
10
+ index,
11
+ selectedValue,
12
+ }) => {
13
+ const isMulti = facetSettings.multiple;
14
+ return selectedValue
15
+ ? isMulti
16
+ ? Array.isArray(selectedValue)
17
+ ? selectedValue.map((v) => ({
18
+ value: v,
19
+ label: index.values?.[v]?.title,
20
+ }))
21
+ : []
22
+ : {
23
+ value: selectedValue,
24
+ label: index.values?.[selectedValue]?.title,
25
+ }
26
+ : [];
27
+ };
28
+
29
+ export const selectFacetSchemaEnhancer = ({ schema, formData }) => {
30
+ // adds (enables) the 'multiple' field after the 'type' dropdown
31
+ let { fields } = schema.fieldsets[0];
32
+ const pos = fields.indexOf('type') + 1;
33
+ fields = [
34
+ ...fields.slice(0, pos),
35
+ 'multiple',
36
+ ...fields.slice(pos, fields.length),
37
+ ];
38
+ schema.fieldsets[0].fields = fields;
39
+ return schema;
40
+ };
41
+
42
+ export const selectFacetValueToQuery = ({ value, facet }) => {
43
+ return !isEmpty(value)
44
+ ? {
45
+ i: facet.field.value,
46
+ o: Array.isArray(value)
47
+ ? 'plone.app.querystring.operation.list.contains'
48
+ : 'plone.app.querystring.operation.selection.is',
49
+ v: value,
50
+ }
51
+ : undefined;
52
+ };
@@ -2,6 +2,11 @@ export SearchDetails from './SearchDetails';
2
2
  export Facets from './Facets';
3
3
  export SelectFacet from './SelectFacet';
4
4
  export CheckboxFacet from './CheckboxFacet';
5
+ export DateRangeFacet from './DateRangeFacet';
5
6
  export SearchInput from './SearchInput';
6
7
  export FilterList from './FilterList';
7
8
  export SortOn from './SortOn';
9
+ export ToggleFacet from './ToggleFacet';
10
+ export SelectFacetFilterListEntry from './SelectFacetFilterListEntry';
11
+ export ToggleFacetFilterListEntry from './ToggleFacetFilterListEntry';
12
+ export DateRangeFacetFilterListEntry from './DateRangeFacetFilterListEntry';
@@ -1,9 +1,11 @@
1
1
  import React from 'react';
2
2
  import { useSelector } from 'react-redux';
3
- import { isEmpty } from 'lodash';
4
3
  import qs from 'query-string';
5
4
  import { useLocation, useHistory } from 'react-router-dom';
6
5
 
6
+ import { resolveExtension } from '@plone/volto/helpers/Extensions/withBlockExtensions';
7
+ import config from '@plone/volto/registry';
8
+
7
9
  function getDisplayName(WrappedComponent) {
8
10
  return WrappedComponent.displayName || WrappedComponent.name || 'Component';
9
11
  }
@@ -25,16 +27,30 @@ const PAQO = 'plone.app.querystring.operation';
25
27
  *
26
28
  */
27
29
  function getInitialState(data, facets, urlSearchText, id) {
30
+ const {
31
+ types: facetWidgetTypes,
32
+ } = config.blocks.blocksConfig.search.extensions.facetWidgets;
33
+ const facetSettings = data?.facets || [];
34
+
28
35
  return {
29
36
  query: [
30
37
  ...(data.query?.query || []),
31
- ...Object.keys(facets).map((name) => ({
32
- i: name,
33
- v: facets[name],
34
-
35
- // TODO: make the facet operator pluggable
36
- o: 'plone.app.querystring.operation.selection.is',
37
- })),
38
+ ...(facetSettings || [])
39
+ .map((facet) => {
40
+ if (!facet?.field) return null;
41
+
42
+ const { valueToQuery } = resolveExtension(
43
+ 'type',
44
+ facetWidgetTypes,
45
+ facet,
46
+ );
47
+
48
+ const name = facet.field.value;
49
+ const value = facets[name];
50
+
51
+ return valueToQuery({ value, facet });
52
+ })
53
+ .filter((f) => !!f),
38
54
  ...(urlSearchText
39
55
  ? [
40
56
  {
@@ -54,27 +70,42 @@ function getInitialState(data, facets, urlSearchText, id) {
54
70
  }
55
71
 
56
72
  /**
57
- * "Normalizes" the search state to something that's serializable and usable
58
- * as initial state
73
+ * "Normalizes" the search state to something that's serializable
74
+ * (for querying) and used to compute data for the ListingBody
59
75
  *
60
76
  * @function normalizeState
61
77
  *
62
78
  */
63
- function normalizeState({ query, facets, id, searchText, sortOn, sortOrder }) {
79
+ function normalizeState({
80
+ query, // base query
81
+ facets, // facet values
82
+ id, // block id
83
+ searchText, // SearchableText
84
+ sortOn,
85
+ sortOrder,
86
+ facetSettings, // data.facets extracted from block data
87
+ }) {
88
+ const {
89
+ types: facetWidgetTypes,
90
+ } = config.blocks.blocksConfig.search.extensions.facetWidgets;
91
+
64
92
  const params = {
65
93
  query: [
66
94
  ...(query.query || []),
67
- ...Object.keys(facets).map((name) =>
68
- !isEmpty(facets[name])
69
- ? {
70
- i: name,
71
- o: Array.isArray(facets[name])
72
- ? 'plone.app.querystring.operation.list.contains'
73
- : 'plone.app.querystring.operation.selection.is',
74
- v: facets[name],
75
- }
76
- : undefined,
77
- ),
95
+ ...(facetSettings || []).map((facet) => {
96
+ if (!facet?.field) return null;
97
+
98
+ const { valueToQuery } = resolveExtension(
99
+ 'type',
100
+ facetWidgetTypes,
101
+ facet,
102
+ );
103
+
104
+ const name = facet.field.value;
105
+ const value = facets[name];
106
+
107
+ return valueToQuery({ value, facet });
108
+ }),
78
109
  ].filter((o) => !!o),
79
110
  sort_on: sortOn || query.sort_on,
80
111
  sort_order: sortOrder || query.sort_order,
@@ -217,7 +248,7 @@ const withSearch = (options) => (WrappedComponent) => {
217
248
  const [facets, setFacets] = React.useState(
218
249
  Object.assign(
219
250
  {},
220
- ...urlQuery.map(({ i, v }) => ({ [i]: v })),
251
+ ...urlQuery.map(({ i, v }) => ({ [i]: v })), // TODO: the 'o' should be kept. This would be a major refactoring of the facets
221
252
 
222
253
  // support for simple filters like ?Subject=something
223
254
  // TODO: since the move to hash params this is no longer working.
@@ -245,19 +276,21 @@ const withSearch = (options) => (WrappedComponent) => {
245
276
  );
246
277
 
247
278
  const timeoutRef = React.useRef();
279
+ const facetSettings = data?.facets;
248
280
 
249
281
  const onTriggerSearch = React.useCallback(
250
- (toSearch, toSearchFacets, toSortOn, toSortOrder) => {
282
+ (toSearchText, toSearchFacets, toSortOn, toSortOrder) => {
251
283
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
252
284
  timeoutRef.current = setTimeout(
253
285
  () => {
254
286
  const searchData = normalizeState({
287
+ id,
255
288
  query: data.query || {},
256
289
  facets: toSearchFacets || facets,
257
- id,
258
- searchText: toSearch,
290
+ searchText: toSearchText,
259
291
  sortOn: toSortOn || sortOn,
260
292
  sortOrder: toSortOrder || sortOrder,
293
+ facetSettings,
261
294
  });
262
295
  if (toSearchFacets) setFacets(toSearchFacets);
263
296
  if (toSortOn) setSortOn(toSortOn);
@@ -268,7 +301,15 @@ const withSearch = (options) => (WrappedComponent) => {
268
301
  toSearchFacets ? inputDelay / 3 : inputDelay,
269
302
  );
270
303
  },
271
- [data.query, facets, id, setLocationSearchData, sortOn, sortOrder],
304
+ [
305
+ data.query,
306
+ facets,
307
+ id,
308
+ setLocationSearchData,
309
+ sortOn,
310
+ sortOrder,
311
+ facetSettings,
312
+ ],
272
313
  );
273
314
 
274
315
  const querystringResults = useSelector(
@@ -1,6 +1,7 @@
1
1
  import config from '@plone/volto/registry';
2
2
  import { defineMessages } from 'react-intl';
3
3
  import { cloneDeep } from 'lodash';
4
+ import { hasNonValueOperation, hasDateOperation } from './utils';
4
5
 
5
6
  const messages = defineMessages({
6
7
  searchBlock: {
@@ -99,9 +100,9 @@ const messages = defineMessages({
99
100
 
100
101
  const enhanceSchema = (originalSchema, formData) => {
101
102
  const extensionName = 'facetWidgets';
102
- const extensionType = 'type';
103
+ const extensionType = 'type'; // property name in stored block data
103
104
  const variations =
104
- config.blocks.blocksConfig.search.extensions[extensionName][extensionType];
105
+ config.blocks.blocksConfig.search.extensions[extensionName].types;
105
106
 
106
107
  const activeItemName = formData?.[extensionType];
107
108
  let activeItem = variations?.find((item) => item.id === activeItemName);
@@ -122,7 +123,7 @@ const FacetSchema = ({ intl }) => ({
122
123
  {
123
124
  id: 'default',
124
125
  title: 'Default',
125
- fields: ['title', 'field', 'type', 'multiple', 'hidden'],
126
+ fields: ['title', 'field', 'type', 'hidden'],
126
127
  },
127
128
  ],
128
129
  properties: {
@@ -141,7 +142,9 @@ const FacetSchema = ({ intl }) => ({
141
142
  return Object.assign(
142
143
  {},
143
144
  ...Object.keys(options).map((k) =>
144
- Object.keys(options[k].values || {}).length
145
+ Object.keys(options[k].values || {}).length ||
146
+ hasNonValueOperation(options[k].operations) ||
147
+ hasDateOperation(options[k].operations)
145
148
  ? { [k]: options[k] }
146
149
  : {},
147
150
  ),
@@ -0,0 +1,16 @@
1
+ export const NONVALUE_OPERATIONS = new Set([
2
+ 'plone.app.querystring.operation.boolean.isFalse',
3
+ 'plone.app.querystring.operation.boolean.isTrue',
4
+ ]);
5
+
6
+ export const DATE_OPERATIONS = new Set([
7
+ 'plone.app.querystring.operation.date.between',
8
+ ]);
9
+
10
+ export const hasNonValueOperation = (ops) => {
11
+ return ops.filter((x) => NONVALUE_OPERATIONS.has(x)).length > 0;
12
+ };
13
+
14
+ export const hasDateOperation = (ops) => {
15
+ return ops.filter((x) => DATE_OPERATIONS.has(x)).length > 0;
16
+ };
@@ -5,19 +5,20 @@
5
5
 
6
6
  import React, { Component } from 'react';
7
7
  import PropTypes from 'prop-types';
8
- import Editor from 'draft-js-plugins-editor';
9
- import { convertFromRaw, EditorState, RichUtils } from 'draft-js';
10
- import createInlineToolbarPlugin from 'draft-js-inline-toolbar-plugin';
11
- import isSoftNewlineEvent from 'draft-js/lib/isSoftNewlineEvent';
12
8
  import { includes } from 'lodash';
13
9
  import config from '@plone/volto/registry';
14
10
 
11
+ import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
12
+ import loadable from '@loadable/component';
13
+
14
+ const Editor = loadable(() => import('draft-js-plugins-editor'));
15
+
15
16
  /**
16
17
  * Edit text cell class.
17
18
  * @class Cell
18
19
  * @extends Component
19
20
  */
20
- class Cell extends Component {
21
+ class CellComponent extends Component {
21
22
  /**
22
23
  * Property types.
23
24
  * @property {Object} propTypes Property types.
@@ -54,12 +55,16 @@ class Cell extends Component {
54
55
  constructor(props) {
55
56
  super(props);
56
57
 
58
+ const { EditorState, convertFromRaw } = props.draftJs;
59
+ const createInlineToolbarPlugin = props.draftJsInlineToolbarPlugin.default;
60
+
57
61
  if (!__SERVER__) {
62
+ this.draftConfig = config.settings.richtextEditorSettings(props);
58
63
  let editorState;
59
64
  editorState = EditorState.createWithContent(convertFromRaw(props.value));
60
65
 
61
66
  const inlineToolbarPlugin = createInlineToolbarPlugin({
62
- structure: config.settings.richTextEditorInlineToolbarButtons,
67
+ structure: this.draftConfig.richTextEditorInlineToolbarButtons,
63
68
  });
64
69
 
65
70
  this.state = {
@@ -125,7 +130,8 @@ class Cell extends Component {
125
130
  }
126
131
 
127
132
  const { InlineToolbar } = this.state.inlineToolbarPlugin;
128
- const { settings } = config;
133
+ const isSoftNewlineEvent = this.props.draftJsLibIsSoftNewlineEvent.default;
134
+ const { RichUtils } = this.props.draftJs;
129
135
 
130
136
  return (
131
137
  <div>
@@ -135,11 +141,11 @@ class Cell extends Component {
135
141
  editorState={this.state.editorState}
136
142
  plugins={[
137
143
  this.state.inlineToolbarPlugin,
138
- ...settings.richTextEditorPlugins,
144
+ ...this.draftConfig.richTextEditorPlugins,
139
145
  ]}
140
- blockRenderMap={settings.extendedBlockRenderMap}
141
- blockStyleFn={settings.blockStyleFn}
142
- customStyleMap={settings.customStyleMap}
146
+ blockRenderMap={this.draftConfig.extendedBlockRenderMap}
147
+ blockStyleFn={this.draftConfig.blockStyleFn}
148
+ customStyleMap={this.draftConfig.customStyleMap}
143
149
  handleReturn={(e) => {
144
150
  if (isSoftNewlineEvent(e)) {
145
151
  this.onChange(
@@ -155,10 +161,10 @@ class Cell extends Component {
155
161
  anchorKey,
156
162
  );
157
163
  const blockType = currentContentBlock.getType();
158
- if (!includes(settings.listBlockTypes, blockType)) {
164
+ if (!includes(this.draftConfig.listBlockTypes, blockType)) {
159
165
  this.props.onSelectBlock(
160
166
  this.props.onAddBlock(
161
- settings.defaultBlockType,
167
+ this.draftConfig.defaultBlockType,
162
168
  this.props.index + 1,
163
169
  ),
164
170
  );
@@ -178,4 +184,24 @@ class Cell extends Component {
178
184
  }
179
185
  }
180
186
 
181
- export default Cell;
187
+ export const Cell = injectLazyLibs([
188
+ 'draftJs',
189
+ 'draftJsBlockBreakoutPlugin',
190
+ 'draftJsCreateBlockStyleButton',
191
+ 'draftJsCreateInlineStyleButton',
192
+ 'draftJsFilters',
193
+ 'draftJsImportHtml',
194
+ 'draftJsInlineToolbarPlugin',
195
+ 'draftJsLibIsSoftNewlineEvent',
196
+ 'immutableLib',
197
+ ])(CellComponent);
198
+
199
+ const Preloader = (props) => {
200
+ const [loaded, setLoaded] = React.useState(false);
201
+ React.useEffect(() => {
202
+ Editor.load().then(() => setLoaded(true));
203
+ }, []);
204
+ return loaded ? <Cell {...props} /> : null;
205
+ };
206
+
207
+ export default Preloader;
@@ -1,9 +1,15 @@
1
1
  import React from 'react';
2
2
  import renderer from 'react-test-renderer';
3
- import Cell from './Cell';
3
+ import { Cell } from './Cell';
4
4
 
5
5
  global.__SERVER__ = true; // eslint-disable-line no-underscore-dangle
6
6
 
7
+ jest.mock('@plone/volto/helpers/Loadable/Loadable');
8
+ beforeAll(
9
+ async () =>
10
+ await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
11
+ );
12
+
7
13
  test('renders a cell component', () => {
8
14
  const component = renderer.create(
9
15
  <Cell onChange={() => {}} onSelectCell={() => {}} />,
@@ -5,15 +5,16 @@
5
5
 
6
6
  import React, { Component } from 'react';
7
7
  import PropTypes from 'prop-types';
8
+ import { compose } from 'redux';
8
9
  import { map, remove } from 'lodash';
9
10
  import { Button, Segment, Table, Form } from 'semantic-ui-react';
10
- import { convertToRaw } from 'draft-js';
11
11
  import { Portal } from 'react-portal';
12
12
  import cx from 'classnames';
13
13
  import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
14
14
 
15
15
  import Cell from '@plone/volto/components/manage/Blocks/Table/Cell';
16
16
  import { Field, Icon } from '@plone/volto/components';
17
+ import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
17
18
 
18
19
  import rowBeforeSVG from '@plone/volto/icons/row-before.svg';
19
20
  import rowAfterSVG from '@plone/volto/icons/row-after.svg';
@@ -208,6 +209,9 @@ class Edit extends Component {
208
209
  this.toggleBasic = this.toggleBasic.bind(this);
209
210
  this.toggleCelled = this.toggleCelled.bind(this);
210
211
  this.toggleStriped = this.toggleStriped.bind(this);
212
+
213
+ const { convertToRaw } = props.draftJs;
214
+ this.convertToRaw = convertToRaw;
211
215
  }
212
216
 
213
217
  /**
@@ -261,7 +265,7 @@ class Edit extends Component {
261
265
  */
262
266
  onChangeCell(row, cell, editorState) {
263
267
  const table = { ...this.props.data.table };
264
- table.rows[row].cells[cell].value = convertToRaw(
268
+ table.rows[row].cells[cell].value = this.convertToRaw(
265
269
  editorState.getCurrentContent(),
266
270
  );
267
271
  this.props.onChangeBlock(this.props.block, {
@@ -740,4 +744,4 @@ class Edit extends Component {
740
744
  }
741
745
  }
742
746
 
743
- export default injectIntl(Edit);
747
+ export default compose(injectLazyLibs(['draftJs']), injectIntl)(Edit);
@@ -5,6 +5,12 @@ import { Provider } from 'react-intl-redux';
5
5
 
6
6
  import Edit from './Edit';
7
7
 
8
+ jest.mock('@plone/volto/helpers/Loadable/Loadable');
9
+ beforeAll(
10
+ async () =>
11
+ await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
12
+ );
13
+
8
14
  const mockStore = configureStore();
9
15
 
10
16
  test('renders an edit table block component', () => {
@@ -37,8 +37,8 @@ const View = ({ data }) =>
37
37
  {cell.value && cell.value.blocks && cell.value.blocks[0].text
38
38
  ? redraft(
39
39
  cell.value,
40
- config.settings.ToHTMLRenderers,
41
- config.settings.ToHTMLOptions,
40
+ config.settings.richtextViewSettings.ToHTMLRenderers,
41
+ config.settings.richtextViewSettings.ToHTMLOptions,
42
42
  )
43
43
  : '\u00A0'}
44
44
  </Table.Cell>