@plone/volto 15.0.0-alpha.0 → 15.0.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.
Files changed (236) hide show
  1. package/.eslintrc +1 -1
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +7 -6
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
  4. package/.github/workflows/{core-sandbox.yml → coresandbox.yml} +1 -1
  5. package/.github/workflows/docs.yml +15 -55
  6. package/.storybook/main.js +3 -9
  7. package/CHANGELOG.md +140 -2
  8. package/CODE_OF_CONDUCT.md +0 -1
  9. package/COMMITLINT.md +19 -21
  10. package/README.md +2 -1
  11. package/SECURITY.md +0 -1
  12. package/addon-registry.js +20 -12
  13. package/create-addons-loader.js +1 -1
  14. package/cypress/support/commands.js +3 -1
  15. package/dist/assets.json +1 -0
  16. package/dist/chunks.json +571 -0
  17. package/dist/loadable-stats.json +2070 -0
  18. package/dist/public/android-chrome-192x192.png +0 -0
  19. package/dist/public/android-chrome-512x512.png +0 -0
  20. package/dist/public/apple-touch-icon.png +0 -0
  21. package/dist/public/favicon-16x16.png +0 -0
  22. package/dist/public/favicon-32x32.png +0 -0
  23. package/dist/public/favicon.ico +0 -0
  24. package/dist/public/icon.svg +13 -0
  25. package/dist/public/index.html.spa +34 -0
  26. package/dist/public/robots.txt +2 -0
  27. package/dist/public/site.webmanifest +19 -0
  28. package/dist/public/static/css/14.803b450c.chunk.css +409 -0
  29. package/dist/public/static/css/3.a3490306.chunk.css +2 -0
  30. package/dist/public/static/css/client.0ead607b.chunk.css +8 -0
  31. package/dist/public/static/css/plone-volto-components-manage-Widgets-DatetimeWidget.77a7ad0d.chunk.css +2 -0
  32. package/dist/public/static/js/0.3e794c57.chunk.js +2 -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/14.803b450c.chunk.js +3 -0
  36. package/dist/public/static/js/14.803b450c.chunk.js.LICENSE.txt +146 -0
  37. package/dist/public/static/js/15.c1eb25b4.chunk.js +3 -0
  38. package/dist/public/static/js/15.c1eb25b4.chunk.js.LICENSE.txt +8 -0
  39. package/dist/public/static/js/16.70e24cba.chunk.js +2 -0
  40. package/dist/public/static/js/17.f03d2a82.chunk.js +2 -0
  41. package/dist/public/static/js/18.0f0b1dfa.chunk.js +2 -0
  42. package/dist/public/static/js/19.61ef8815.chunk.js +3 -0
  43. package/dist/public/static/js/19.61ef8815.chunk.js.LICENSE.txt +8 -0
  44. package/dist/public/static/js/20.6b37f925.chunk.js +2 -0
  45. package/dist/public/static/js/21.8704b265.chunk.js +2 -0
  46. package/dist/public/static/js/22.5a2b56ff.chunk.js +2 -0
  47. package/dist/public/static/js/23.a53c8d7b.chunk.js +2 -0
  48. package/dist/public/static/js/24.d44c620a.chunk.js +2 -0
  49. package/dist/public/static/js/25.3129d6c8.chunk.js +2 -0
  50. package/dist/public/static/js/26.9dfad319.chunk.js +2 -0
  51. package/dist/public/static/js/27.efbb318a.chunk.js +2 -0
  52. package/dist/public/static/js/28.b4840d60.chunk.js +2 -0
  53. package/dist/public/static/js/29.690d4b54.chunk.js +2 -0
  54. package/dist/public/static/js/3.a3490306.chunk.js +2 -0
  55. package/dist/public/static/js/30.5f174f94.chunk.js +2 -0
  56. package/dist/public/static/js/31.4a7cf109.chunk.js +2 -0
  57. package/dist/public/static/js/32.2247dcf7.chunk.js +2 -0
  58. package/dist/public/static/js/33.87874f33.chunk.js +2 -0
  59. package/dist/public/static/js/34.aec37d56.chunk.js +3 -0
  60. package/dist/public/static/js/34.aec37d56.chunk.js.LICENSE.txt +37 -0
  61. package/dist/public/static/js/35.73887e02.chunk.js +3 -0
  62. package/dist/public/static/js/35.73887e02.chunk.js.LICENSE.txt +7 -0
  63. package/dist/public/static/js/36.19d2e05a.chunk.js +3 -0
  64. package/dist/public/static/js/36.19d2e05a.chunk.js.LICENSE.txt +14 -0
  65. package/dist/public/static/js/37.96925a5f.chunk.js +3 -0
  66. package/dist/public/static/js/37.96925a5f.chunk.js.LICENSE.txt +8 -0
  67. package/dist/public/static/js/38.701a2e85.chunk.js +2 -0
  68. package/dist/public/static/js/39.4cbf0549.chunk.js +2 -0
  69. package/dist/public/static/js/4.bdc4a5c5.chunk.js +2 -0
  70. package/dist/public/static/js/6.69ba4792.chunk.js +2 -0
  71. package/dist/public/static/js/client.0ead607b.chunk.js +2 -0
  72. package/dist/public/static/js/draft-js-lib-isSoftNewlineEvent.ad4b1307.chunk.js +2 -0
  73. package/dist/public/static/js/moment.dfd83abb.chunk.js +2 -0
  74. package/dist/public/static/js/plone-volto-components-manage-Widgets-DatetimeWidget.77a7ad0d.chunk.js +2 -0
  75. package/dist/public/static/js/plone-volto-components-theme-View-EventView.c500936a.chunk.js +2 -0
  76. package/dist/public/static/js/react-dates.d94a34ee.chunk.js +2 -0
  77. package/dist/public/static/js/react-select.43f17559.chunk.js +2 -0
  78. package/dist/public/static/js/react-simple-code-editor.484ec69f.chunk.js +2 -0
  79. package/dist/public/static/js/runtime~client.c0921d19.js +2 -0
  80. package/dist/public/static/media/Logo.16e25cdf.svg +21 -0
  81. package/dist/public/static/media/block-image.8a4a14d5.svg +8 -0
  82. package/dist/public/static/media/block-maps.731e84f6.svg +7 -0
  83. package/dist/public/static/media/block-video.832fa3ff.svg +7 -0
  84. package/dist/public/static/media/default-image.9451b251.svg +13 -0
  85. package/dist/public/static/media/flags.9c74e172.png +0 -0
  86. package/dist/public/static/media/icons.022583c4.svg +320 -0
  87. package/dist/public/static/media/icons.06400145.ttf +0 -0
  88. package/dist/public/static/media/icons.dbc1ef8b.eot +0 -0
  89. package/dist/public/static/media/icons.df45b7de.woff +0 -0
  90. package/dist/server.js +2 -0
  91. package/docker-compose.yml +15 -10
  92. package/locales/ca/LC_MESSAGES/volto.po +33 -9
  93. package/locales/ca.json +1 -1
  94. package/locales/de/LC_MESSAGES/volto.po +33 -9
  95. package/locales/de.json +1 -1
  96. package/locales/en/LC_MESSAGES/volto.po +33 -9
  97. package/locales/en.json +1 -1
  98. package/locales/es/LC_MESSAGES/volto.po +33 -9
  99. package/locales/es.json +1 -1
  100. package/locales/eu/LC_MESSAGES/volto.po +33 -9
  101. package/locales/eu.json +1 -1
  102. package/locales/fr/LC_MESSAGES/volto.po +33 -9
  103. package/locales/fr.json +1 -1
  104. package/locales/it/LC_MESSAGES/volto.po +33 -9
  105. package/locales/it.json +1 -1
  106. package/locales/ja/LC_MESSAGES/volto.po +33 -9
  107. package/locales/ja.json +1 -1
  108. package/locales/nl/LC_MESSAGES/volto.po +33 -9
  109. package/locales/nl.json +1 -1
  110. package/locales/pt/LC_MESSAGES/volto.po +33 -9
  111. package/locales/pt.json +1 -1
  112. package/locales/pt_BR/LC_MESSAGES/volto.po +33 -9
  113. package/locales/pt_BR.json +1 -1
  114. package/locales/ro/LC_MESSAGES/volto.po +33 -9
  115. package/locales/ro.json +1 -1
  116. package/locales/volto.pot +34 -10
  117. package/logos/Logo.png +0 -0
  118. package/logos/volto-colorful.png +0 -0
  119. package/logos/volto-colorful.svg +35 -0
  120. package/logos/volto-guide.png +0 -0
  121. package/logos/volto-h-transparent.svg +6 -0
  122. package/logos/volto-transparent.png +0 -0
  123. package/logos/volto-transparent.svg +19 -0
  124. package/logos/volto-transparent2.svg +5 -0
  125. package/logos/volto-yellow.svg +29 -0
  126. package/logos/volto.sketch +0 -0
  127. package/netlify.toml +2 -0
  128. package/package.json +22 -12
  129. package/pyvenv.cfg +3 -0
  130. package/razzle.config.js +17 -13
  131. package/src/actions/language/language.js +23 -11
  132. package/src/actions/lazyLibraries/lazyLibraries.js +8 -4
  133. package/src/components/index.js +2 -0
  134. package/src/components/manage/Add/Add.jsx +1 -1
  135. package/src/components/manage/AnchorPlugin/components/LinkButton/AddLinkForm.jsx +1 -2
  136. package/src/components/manage/AnchorPlugin/components/LinkButton/index.jsx +15 -6
  137. package/src/components/manage/AnchorPlugin/index.jsx +12 -5
  138. package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +8 -7
  139. package/src/components/manage/Blocks/Description/Edit.jsx +33 -19
  140. package/src/components/manage/Blocks/Description/Edit.test.jsx +6 -0
  141. package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +37 -26
  142. package/src/components/manage/Blocks/HeroImageLeft/Edit.test.jsx +6 -0
  143. package/src/components/manage/Blocks/Listing/View.jsx +1 -1
  144. package/src/components/manage/Blocks/Search/README.md +20 -0
  145. package/src/components/manage/Blocks/Search/components/CheckboxFacet.jsx +16 -3
  146. package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +120 -0
  147. package/src/components/manage/Blocks/Search/components/DateRangeFacet.test.jsx +34 -0
  148. package/src/components/manage/Blocks/Search/components/DateRangeFacetFilterListEntry.jsx +39 -0
  149. package/src/components/manage/Blocks/Search/components/Facets.jsx +24 -25
  150. package/src/components/manage/Blocks/Search/components/FilterList.jsx +37 -67
  151. package/src/components/manage/Blocks/Search/components/FilterList.test.jsx +49 -1
  152. package/src/components/manage/Blocks/Search/components/SelectFacet.jsx +9 -0
  153. package/src/components/manage/Blocks/Search/components/SelectFacetFilterListEntry.jsx +42 -0
  154. package/src/components/manage/Blocks/Search/components/SelectStyling.jsx +1 -1
  155. package/src/components/manage/Blocks/Search/components/ToggleFacet.jsx +38 -0
  156. package/src/components/manage/Blocks/Search/components/ToggleFacetFilterListEntry.jsx +39 -0
  157. package/src/components/manage/Blocks/Search/components/base.js +52 -0
  158. package/src/components/manage/Blocks/Search/components/index.js +5 -0
  159. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +68 -27
  160. package/src/components/manage/Blocks/Search/schema.js +7 -4
  161. package/src/components/manage/Blocks/Search/utils.js +16 -0
  162. package/src/components/manage/Blocks/Table/Cell.jsx +40 -14
  163. package/src/components/manage/Blocks/Table/Cell.test.jsx +7 -1
  164. package/src/components/manage/Blocks/Table/Edit.jsx +7 -3
  165. package/src/components/manage/Blocks/Table/Edit.test.jsx +6 -0
  166. package/src/components/manage/Blocks/Table/View.jsx +2 -2
  167. package/src/components/manage/Blocks/Text/Edit.jsx +56 -14
  168. package/src/components/manage/Blocks/Text/Edit.test.jsx +7 -1
  169. package/src/components/manage/Blocks/Text/View.jsx +2 -2
  170. package/src/components/manage/Blocks/Title/Edit.jsx +25 -13
  171. package/src/components/manage/Blocks/Title/Edit.test.jsx +6 -0
  172. package/src/components/manage/Contents/ContentsIndexHeader.test.jsx +2 -1
  173. package/src/components/manage/Contents/ContentsUploadModal.jsx +3 -1
  174. package/src/components/manage/Multilingual/CreateTranslation.jsx +1 -1
  175. package/src/components/manage/Multilingual/TranslationObject.jsx +1 -1
  176. package/src/components/manage/Pluggable/index.js +1 -1
  177. package/src/components/manage/Preferences/PersonalPreferences.jsx +1 -1
  178. package/src/components/manage/Sidebar/Sidebar.jsx +5 -1
  179. package/src/components/manage/Toolbar/Toolbar.jsx +3 -1
  180. package/src/components/manage/UniversalLink/UniversalLink.jsx +5 -2
  181. package/src/components/manage/Widgets/DatetimeWidget.jsx +3 -1
  182. package/src/components/manage/Widgets/IdWidget.jsx +234 -0
  183. package/src/components/manage/Widgets/IdWidget.stories.jsx +21 -0
  184. package/src/components/manage/Widgets/IdWidget.test.jsx +135 -0
  185. package/src/components/manage/Widgets/SelectAutoComplete.jsx +2 -2
  186. package/src/components/manage/Widgets/UrlWidget.jsx +1 -1
  187. package/src/components/manage/Widgets/WysiwygWidget.jsx +45 -19
  188. package/src/components/manage/Widgets/WysiwygWidget.test.jsx +7 -1
  189. package/src/components/theme/ContactForm/ContactForm.jsx +1 -1
  190. package/src/components/theme/EventDetails/EventDetails.jsx +140 -0
  191. package/src/components/theme/EventDetails/EventDetails.test.jsx +87 -0
  192. package/src/components/theme/LanguageSelector/LanguageSelector.js +2 -18
  193. package/src/components/theme/Login/Login.jsx +3 -1
  194. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +10 -31
  195. package/src/components/theme/View/EventView.jsx +62 -140
  196. package/src/components/theme/View/LinkView.jsx +3 -3
  197. package/src/components/theme/View/NewsItemView.jsx +44 -35
  198. package/src/components/theme/View/View.jsx +5 -1
  199. package/src/config/Blocks.jsx +31 -0
  200. package/src/config/Loadables.jsx +22 -0
  201. package/src/config/RichTextEditor/Blocks.jsx +25 -20
  202. package/src/config/RichTextEditor/Plugins.jsx +38 -31
  203. package/src/config/RichTextEditor/Styles.jsx +48 -44
  204. package/src/config/RichTextEditor/index.js +25 -0
  205. package/src/config/Widgets.jsx +2 -0
  206. package/src/config/index.js +15 -18
  207. package/src/helpers/Api/Api.js +20 -4
  208. package/src/helpers/Extensions/index.js +1 -1
  209. package/src/helpers/Extensions/withBlockExtensions.js +4 -0
  210. package/src/helpers/Extensions/withBlockExtensions.test.js +26 -1
  211. package/src/helpers/Url/Url.js +41 -1
  212. package/src/helpers/Url/Url.test.js +7 -0
  213. package/src/helpers/Url/urlRegex.js +7 -1
  214. package/src/helpers/index.js +3 -0
  215. package/src/middleware/api.js +35 -3
  216. package/src/server.jsx +20 -6
  217. package/src/start-client.jsx +2 -2
  218. package/src/store.js +1 -1
  219. package/test-setup-config.js +22 -7
  220. package/theme/themes/pastanaga/extras/blocks.less +29 -0
  221. package/theme/themes/pastanaga/extras/contents.less +6 -0
  222. package/{webpack-bundle-analyze-plugin.js → webpack-plugins/webpack-bundle-analyze-plugin.js} +0 -0
  223. package/{webpack-less-plugin.js → webpack-plugins/webpack-less-plugin.js} +0 -0
  224. package/{webpack-relative-resolver.js → webpack-plugins/webpack-relative-resolver.js} +0 -0
  225. package/{webpack-root-resolver.js → webpack-plugins/webpack-root-resolver.js} +0 -0
  226. package/{webpack-sentry-plugin.js → webpack-plugins/webpack-sentry-plugin.js} +0 -0
  227. package/{webpack-svg-plugin.js → webpack-plugins/webpack-svg-plugin.js} +0 -0
  228. package/.surgeignore +0 -2
  229. package/Dockerfile.slim +0 -27
  230. package/patches/fixprettier.patch +0 -11
  231. package/patches/fixstylelint.patch +0 -11
  232. package/src/components/manage/AnchorPlugin/utils/URLUtils.js +0 -36
  233. package/src/components/manage/AnchorPlugin/utils/mailRegex.js +0 -2
  234. package/src/components/manage/AnchorPlugin/utils/telRegex.js +0 -1
  235. package/src/components/manage/AnchorPlugin/utils/urlRegex.js +0 -54
  236. package/styleguide.config.js +0 -42
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import createInlineStyleButton from 'draft-js-buttons/lib/utils/createInlineStyleButton';
3
- import createBlockStyleButton from 'draft-js-buttons/lib/utils/createBlockStyleButton';
2
+ // import createInlineStyleButton from 'draft-js-buttons/lib/utils/createInlineStyleButton';
3
+ // import createBlockStyleButton from 'draft-js-buttons/lib/utils/createBlockStyleButton';
4
4
 
5
5
  import Icon from '@plone/volto/components/theme/Icon/Icon';
6
6
 
@@ -13,53 +13,57 @@ import orderedListSVG from '@plone/volto/icons/list-numbered.svg';
13
13
  import blockquoteSVG from '@plone/volto/icons/quote.svg';
14
14
  import calloutSVG from '@plone/volto/icons/megaphone.svg';
15
15
 
16
- const BoldButton = createInlineStyleButton({
17
- style: 'BOLD',
18
- children: <Icon name={boldSVG} size="24px" />,
19
- });
16
+ export default function (props) {
17
+ const createInlineStyleButton = props.draftJsCreateInlineStyleButton.default;
18
+ const createBlockStyleButton = props.draftJsCreateBlockStyleButton.default;
20
19
 
21
- const ItalicButton = createInlineStyleButton({
22
- style: 'ITALIC',
23
- children: <Icon name={italicSVG} size="24px" />,
24
- });
20
+ const BoldButton = createInlineStyleButton({
21
+ style: 'BOLD',
22
+ children: <Icon name={boldSVG} size="24px" />,
23
+ });
25
24
 
26
- const HeadlineTwoButton = createBlockStyleButton({
27
- blockType: 'header-two',
28
- children: <Icon name={textSVG} size="24px" />,
29
- });
25
+ const ItalicButton = createInlineStyleButton({
26
+ style: 'ITALIC',
27
+ children: <Icon name={italicSVG} size="24px" />,
28
+ });
30
29
 
31
- const HeadlineThreeButton = createBlockStyleButton({
32
- blockType: 'header-three',
33
- children: <Icon name={subtextSVG} size="24px" />,
34
- });
30
+ const HeadlineTwoButton = createBlockStyleButton({
31
+ blockType: 'header-two',
32
+ children: <Icon name={textSVG} size="24px" />,
33
+ });
35
34
 
36
- const UnorderedListButton = createBlockStyleButton({
37
- blockType: 'unordered-list-item',
38
- children: <Icon name={unorderedListSVG} size="24px" />,
39
- });
35
+ const HeadlineThreeButton = createBlockStyleButton({
36
+ blockType: 'header-three',
37
+ children: <Icon name={subtextSVG} size="24px" />,
38
+ });
40
39
 
41
- const OrderedListButton = createBlockStyleButton({
42
- blockType: 'ordered-list-item',
43
- children: <Icon name={orderedListSVG} size="24px" />,
44
- });
40
+ const UnorderedListButton = createBlockStyleButton({
41
+ blockType: 'unordered-list-item',
42
+ children: <Icon name={unorderedListSVG} size="24px" />,
43
+ });
45
44
 
46
- const BlockquoteButton = createBlockStyleButton({
47
- blockType: 'blockquote',
48
- children: <Icon name={blockquoteSVG} size="24px" />,
49
- });
45
+ const OrderedListButton = createBlockStyleButton({
46
+ blockType: 'ordered-list-item',
47
+ children: <Icon name={orderedListSVG} size="24px" />,
48
+ });
50
49
 
51
- const CalloutButton = createBlockStyleButton({
52
- blockType: 'callout',
53
- children: <Icon name={calloutSVG} size="24px" />,
54
- });
50
+ const BlockquoteButton = createBlockStyleButton({
51
+ blockType: 'blockquote',
52
+ children: <Icon name={blockquoteSVG} size="24px" />,
53
+ });
55
54
 
56
- export {
57
- BlockquoteButton,
58
- BoldButton,
59
- CalloutButton,
60
- ItalicButton,
61
- HeadlineTwoButton,
62
- HeadlineThreeButton,
63
- OrderedListButton,
64
- UnorderedListButton,
65
- };
55
+ const CalloutButton = createBlockStyleButton({
56
+ blockType: 'callout',
57
+ children: <Icon name={calloutSVG} size="24px" />,
58
+ });
59
+ return {
60
+ BlockquoteButton,
61
+ BoldButton,
62
+ CalloutButton,
63
+ ItalicButton,
64
+ HeadlineTwoButton,
65
+ HeadlineThreeButton,
66
+ OrderedListButton,
67
+ UnorderedListButton,
68
+ };
69
+ }
@@ -0,0 +1,25 @@
1
+ import ToHTMLRenderers, { options as ToHTMLOptions } from './ToHTML';
2
+ import Blocks from './Blocks';
3
+ import Plugins from './Plugins';
4
+ import FromHTMLCustomBlockFn from './FromHTML';
5
+
6
+ export const richtextEditorSettings = (props) => {
7
+ const { plugins, inlineToolbarButtons } = Plugins(props);
8
+ const { extendedBlockRenderMap, blockStyleFn, listBlockTypes } = Blocks(
9
+ props,
10
+ );
11
+
12
+ return {
13
+ extendedBlockRenderMap,
14
+ blockStyleFn: blockStyleFn,
15
+ listBlockTypes: listBlockTypes,
16
+ richTextEditorPlugins: plugins,
17
+ richTextEditorInlineToolbarButtons: inlineToolbarButtons,
18
+ FromHTMLCustomBlockFn,
19
+ };
20
+ };
21
+
22
+ export const richtextViewSettings = {
23
+ ToHTMLRenderers,
24
+ ToHTMLOptions,
25
+ };
@@ -7,6 +7,7 @@ import AlignWidget from '@plone/volto/components/manage/Widgets/AlignWidget';
7
7
  import ArrayWidget from '@plone/volto/components/manage/Widgets/ArrayWidget';
8
8
  import CheckboxWidget from '@plone/volto/components/manage/Widgets/CheckboxWidget';
9
9
  import FileWidget from '@plone/volto/components/manage/Widgets/FileWidget';
10
+ import IdWidget from '@plone/volto/components/manage/Widgets/IdWidget';
10
11
  import PasswordWidget from '@plone/volto/components/manage/Widgets/PasswordWidget';
11
12
  import QueryWidget from '@plone/volto/components/manage/Widgets/QueryWidget';
12
13
  import QuerySortOnWidget from '@plone/volto/components/manage/Widgets/QuerySortOnWidget';
@@ -47,6 +48,7 @@ export const widgetMapping = {
47
48
  query: QuerystringWidget,
48
49
  recurrence: RecurrenceWidget,
49
50
  remoteUrl: UrlWidget,
51
+ id: IdWidget,
50
52
  },
51
53
  widget: {
52
54
  richtext: WysiwygWidget,
@@ -11,16 +11,6 @@ import {
11
11
  errorViews,
12
12
  } from './Views';
13
13
  import { nonContentRoutes } from './NonContentRoutes';
14
- import ToHTMLRenderers, {
15
- options as ToHTMLOptions,
16
- } from './RichTextEditor/ToHTML';
17
- import {
18
- extendedBlockRenderMap,
19
- blockStyleFn,
20
- listBlockTypes,
21
- } from './RichTextEditor/Blocks';
22
- import plugins, { inlineToolbarButtons } from './RichTextEditor/Plugins';
23
- import FromHTMLCustomBlockFn from './RichTextEditor/FromHTML';
24
14
  import {
25
15
  groupBlocksOrder,
26
16
  requiredBlocks,
@@ -34,6 +24,8 @@ import { sentryOptions } from './Sentry';
34
24
  import { contentIcons } from './ContentIcons';
35
25
  import { controlPanelsIcons } from './ControlPanels';
36
26
 
27
+ import { richtextEditorSettings, richtextViewSettings } from './RichTextEditor';
28
+
37
29
  import applyAddonConfiguration from 'load-volto-addons';
38
30
 
39
31
  import ConfigRegistry from '@plone/volto/registry';
@@ -96,16 +88,12 @@ let config = {
96
88
  websockets: process.env.RAZZLE_WEBSOCKETS || false,
97
89
  // TODO: legacyTraverse to be removed when the use of the legacy traverse is deprecated.
98
90
  legacyTraverse: process.env.RAZZLE_LEGACY_TRAVERSE || false,
91
+ cookieExpires: 15552000, //in seconds. Default is 6 month (15552000)
99
92
  nonContentRoutes,
100
- extendedBlockRenderMap,
101
- blockStyleFn,
102
- listBlockTypes,
103
- FromHTMLCustomBlockFn,
104
- richTextEditorInlineToolbarButtons: inlineToolbarButtons,
105
- richTextEditorPlugins: plugins,
106
- ToHTMLRenderers,
107
- ToHTMLOptions,
93
+ richtextEditorSettings,
94
+ richtextViewSettings,
108
95
  imageObjects: ['Image'],
96
+ reservedIds: ['login', 'layout', 'plone', 'zip', 'properties'],
109
97
  downloadableObjects: ['File'], //list of content-types for which the direct download of the file will be carried out if the user is not authenticated
110
98
  listingPreviewImageField: 'image', // deprecated from Volto 14 onwards
111
99
  customStyleMap: null,
@@ -136,6 +124,15 @@ let config = {
136
124
  'reactBeautifulDnd',
137
125
  // 'diffLib',
138
126
  ],
127
+ draftEditor: [
128
+ 'immutableLib',
129
+ 'draftJs',
130
+ 'draftJsLibIsSoftNewlineEvent',
131
+ 'draftJsFilters',
132
+ 'draftJsInlineToolbarPlugin',
133
+ 'draftJsImportHtml',
134
+ 'draftJsBlockBreakoutPlugin',
135
+ ],
139
136
  },
140
137
  appExtras: [],
141
138
  maxResponseSize: 2000000000, // This is superagent default (200 mb)
@@ -6,6 +6,7 @@
6
6
  import superagent from 'superagent';
7
7
  import Cookies from 'universal-cookie';
8
8
  import config from '@plone/volto/registry';
9
+ import { stripQuerystring } from '@plone/volto/helpers';
9
10
 
10
11
  const methods = ['get', 'post', 'put', 'patch', 'del'];
11
12
 
@@ -46,7 +47,10 @@ class Api {
46
47
  const cookies = new Cookies();
47
48
 
48
49
  methods.forEach((method) => {
49
- this[method] = (path, { params, data, type, headers = {} } = {}) => {
50
+ this[method] = (
51
+ path,
52
+ { params, data, type, headers = {}, checkUrl = false } = {},
53
+ ) => {
50
54
  let request;
51
55
  let promise = new Promise((resolve, reject) => {
52
56
  request = superagent[method](formatUrl(path));
@@ -78,9 +82,21 @@ class Api {
78
82
  request.send(data);
79
83
  }
80
84
 
81
- request.end((err, response) =>
82
- err ? reject(err) : resolve(response.body || response.text),
83
- );
85
+ request.end((err, response) => {
86
+ if (
87
+ checkUrl &&
88
+ request.url &&
89
+ request.xhr &&
90
+ stripQuerystring(request.url) !==
91
+ stripQuerystring(request.xhr.responseURL)
92
+ ) {
93
+ return reject({
94
+ code: 301,
95
+ url: request.xhr.responseURL,
96
+ });
97
+ }
98
+ return err ? reject(err) : resolve(response.body || response.text);
99
+ });
84
100
  });
85
101
  promise.request = request;
86
102
  return promise;
@@ -1,2 +1,2 @@
1
1
  export * from './withBlockSchemaEnhancer';
2
- export withBlockExtensions from './withBlockExtensions';
2
+ export withBlockExtensions, { resolveExtension } from './withBlockExtensions';
@@ -5,6 +5,10 @@
5
5
  import React from 'react';
6
6
  import config from '@plone/volto/registry';
7
7
 
8
+ /**
9
+ * Retrieves the extension (variation) settings from the provided
10
+ * configuration, based on incoming data.
11
+ */
8
12
  export function resolveExtension(name, extensions, data) {
9
13
  const selectedExtension = data[name];
10
14
 
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import withBlockExtensions from './withBlockExtensions';
2
+ import withBlockExtensions, { resolveExtension } from './withBlockExtensions';
3
3
  import config from '@plone/volto/registry';
4
4
  import { render } from '@testing-library/react';
5
5
 
@@ -56,3 +56,28 @@ describe('withBlockExtensions', () => {
56
56
  expect(container).toMatchSnapshot();
57
57
  });
58
58
  });
59
+
60
+ describe('resolveExtensions', () => {
61
+ it('resolves the extensions from provided configuration', () => {
62
+ const data = { variation: 'extB' };
63
+ const extensions = {
64
+ variations: [
65
+ {
66
+ id: 'extA',
67
+ payload: 'extA specific',
68
+ },
69
+ {
70
+ id: 'extB',
71
+ payload: 'extB specific',
72
+ },
73
+ ],
74
+ };
75
+
76
+ const resolved = resolveExtension(
77
+ 'variation',
78
+ extensions['variations'],
79
+ data,
80
+ );
81
+ expect(resolved.payload).toEqual('extB specific');
82
+ });
83
+ });
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { last, memoize } from 'lodash';
7
- import urlRegex from './urlRegex';
7
+ import { urlRegex, telRegex, mailRegex } from './urlRegex';
8
8
  import prependHttp from 'prepend-http';
9
9
  import config from '@plone/volto/registry';
10
10
 
@@ -102,6 +102,15 @@ export function flattenToAppURL(url) {
102
102
  .replace(settings.publicURL, '')
103
103
  );
104
104
  }
105
+ /**
106
+ * Given a URL it remove the querystring from the URL.
107
+ * @method stripQuerystring
108
+ * @param {string} url URL of the object
109
+ * @returns {string} URL without querystring
110
+ */
111
+ export function stripQuerystring(url) {
112
+ return url.replace(/\?.*$/, '');
113
+ }
105
114
 
106
115
  /**
107
116
  * Given a URL if it starts with the API server URL
@@ -214,3 +223,34 @@ export function normalizeUrl(url) {
214
223
  export function removeProtocol(url) {
215
224
  return url.replace('https://', '').replace('http://', '');
216
225
  }
226
+
227
+ export function isMail(text) {
228
+ return mailRegex().test(text);
229
+ }
230
+
231
+ export function isTelephone(text) {
232
+ return telRegex().test(text);
233
+ }
234
+
235
+ export function normaliseMail(email) {
236
+ if (email.toLowerCase().startsWith('mailto:')) {
237
+ return email;
238
+ }
239
+ return `mailto:${email}`;
240
+ }
241
+
242
+ export function normalizeTelephone(tel) {
243
+ if (tel.toLowerCase().startsWith('tel:')) {
244
+ return tel;
245
+ }
246
+ return `tel:${tel}`;
247
+ }
248
+
249
+ export const URLUtils = {
250
+ normalizeTelephone,
251
+ normaliseMail,
252
+ normalizeUrl,
253
+ isTelephone,
254
+ isMail,
255
+ isUrl,
256
+ };
@@ -3,6 +3,7 @@ import config from '@plone/volto/registry';
3
3
  import {
4
4
  flattenToAppURL,
5
5
  flattenHTMLToAppURL,
6
+ stripQuerystring,
6
7
  toPublicURL,
7
8
  getBaseUrl,
8
9
  getView,
@@ -84,6 +85,12 @@ describe('Url', () => {
84
85
  });
85
86
  });
86
87
 
88
+ describe('stripQuerystring', () => {
89
+ it('returns stripped URL given a URL with a querystring', () => {
90
+ expect(stripQuerystring('/content?search=test')).toBe('/content');
91
+ });
92
+ });
93
+
87
94
  describe('toPublicURL', () => {
88
95
  it('returns public URL given the app URL', () => {
89
96
  const savedPublicURL = settings.publicURL;
@@ -2,6 +2,12 @@
2
2
  /* eslint-disable no-confusing-arrow */
3
3
  import tlds from 'tlds';
4
4
 
5
+ export const mailRegex = () =>
6
+ /^((mailto:[^<>()/[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
7
+
8
+ export const telRegex = () =>
9
+ /^[tel:]*[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s./0-9]*$/g;
10
+
5
11
  const v4 =
6
12
  '(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){3}';
7
13
  const v6seg = '[0-9a-fA-F]{1,4}';
@@ -31,7 +37,7 @@ ipRegex.v4 = (opts) =>
31
37
  ipRegex.v6 = (opts) =>
32
38
  opts && opts.exact ? new RegExp(`^${v6}$`) : new RegExp(v6, 'g');
33
39
 
34
- export default (_opts) => {
40
+ export const urlRegex = (_opts) => {
35
41
  const opts = Object.assign({ strict: true }, _opts);
36
42
  const protocol = `(?:(?:[a-z]+:)?//)${opts.strict ? '' : '?'}`;
37
43
  const auth = '(?:\\S+(?::\\S*)?@)?';
@@ -16,6 +16,7 @@ export {
16
16
  addAppURL,
17
17
  flattenHTMLToAppURL,
18
18
  flattenToAppURL,
19
+ stripQuerystring,
19
20
  toPublicURL,
20
21
  isInternalURL,
21
22
  getParentUrl,
@@ -26,6 +27,7 @@ export {
26
27
  isUrl,
27
28
  normalizeUrl,
28
29
  removeProtocol,
30
+ URLUtils,
29
31
  } from '@plone/volto/helpers/Url/Url';
30
32
  export { generateSitemap } from '@plone/volto/helpers/Sitemap/Sitemap';
31
33
  export { generateRobots } from '@plone/volto/helpers/Robots/Robots';
@@ -83,6 +85,7 @@ export {
83
85
  withVariationSchemaEnhancer,
84
86
  withBlockExtensions,
85
87
  applySchemaEnhancer,
88
+ resolveExtension,
86
89
  } from './Extensions';
87
90
  export { asyncConnect } from './AsyncConnect';
88
91
  export { userHasRoles } from './User/User';
@@ -12,11 +12,13 @@ import qs from 'query-string';
12
12
  import config from '@plone/volto/registry';
13
13
 
14
14
  import {
15
+ GET_CONTENT,
15
16
  LOGIN,
16
17
  RESET_APIERROR,
17
18
  SET_APIERROR,
18
19
  } from '@plone/volto/constants/ActionTypes';
19
-
20
+ import { changeLanguage } from '@plone/volto/actions';
21
+ import { normalizeLanguageName } from '@plone/volto/helpers';
20
22
  let socket = null;
21
23
 
22
24
  /**
@@ -104,11 +106,15 @@ function sendOnSocket(request) {
104
106
  * @returns {Promise} Action promise.
105
107
  */
106
108
  export default (api) => ({ dispatch, getState }) => (next) => (action) => {
109
+ const { settings } = config;
110
+
107
111
  if (typeof action === 'function') {
108
112
  return action(dispatch, getState);
109
113
  }
110
114
 
111
- const { request, type, mode = 'paralel', ...rest } = action;
115
+ const { request, type, mode = 'parallel', ...rest } = action;
116
+ const { subrequest } = action; // We want subrequest remains in `...rest` above
117
+
112
118
  let actionPromise;
113
119
 
114
120
  if (!request) {
@@ -143,6 +149,9 @@ export default (api) => ({ dispatch, getState }) => (next) => (action) => {
143
149
  type: item.type,
144
150
  headers: item.headers,
145
151
  params: request.params,
152
+ checkUrl: settings.actions_raising_api_errors.includes(
153
+ action.type,
154
+ ),
146
155
  }).then((reqres) => {
147
156
  return [...acc, reqres];
148
157
  });
@@ -155,6 +164,9 @@ export default (api) => ({ dispatch, getState }) => (next) => (action) => {
155
164
  type: item.type,
156
165
  headers: item.headers,
157
166
  params: request.params,
167
+ checkUrl: settings.actions_raising_api_errors.includes(
168
+ action.type,
169
+ ),
158
170
  }),
159
171
  ),
160
172
  )
@@ -163,6 +175,7 @@ export default (api) => ({ dispatch, getState }) => (next) => (action) => {
163
175
  type: request.type,
164
176
  headers: request.headers,
165
177
  params: request.params,
178
+ checkUrl: settings.actions_raising_api_errors.includes(action.type),
166
179
  });
167
180
  actionPromise.then(
168
181
  (result) => {
@@ -173,6 +186,15 @@ export default (api) => ({ dispatch, getState }) => (next) => (action) => {
173
186
  type: RESET_APIERROR,
174
187
  });
175
188
  }
189
+ if (type === GET_CONTENT) {
190
+ const lang = result?.language?.token;
191
+ if (lang && getState().intl.language !== lang && !subrequest) {
192
+ const langFileName = normalizeLanguageName(lang);
193
+ import('~/../locales/' + langFileName + '.json').then((locale) => {
194
+ dispatch(changeLanguage(lang, locale.default));
195
+ });
196
+ }
197
+ }
176
198
  if (type === LOGIN && settings.websockets) {
177
199
  const cookies = new Cookies();
178
200
  cookies.set('auth_token', result.token, {
@@ -204,7 +226,6 @@ export default (api) => ({ dispatch, getState }) => (next) => (action) => {
204
226
  return next({ ...rest, result, type: `${type}_SUCCESS` });
205
227
  },
206
228
  (error) => {
207
- const { settings } = config;
208
229
  // Only SRR can set ECONNREFUSED
209
230
  if (error.code === 'ECONNREFUSED') {
210
231
  next({
@@ -238,6 +259,17 @@ export default (api) => ({ dispatch, getState }) => (next) => (action) => {
238
259
  });
239
260
  }
240
261
 
262
+ // Redirect
263
+ else if (error?.code === 301) {
264
+ next({
265
+ ...rest,
266
+ error,
267
+ statusCode: error.code,
268
+ connectionRefused: false,
269
+ type: SET_APIERROR,
270
+ });
271
+ }
272
+
241
273
  // The rest
242
274
  else if (settings.actions_raising_api_errors.includes(action.type)) {
243
275
  if (error?.response?.statusCode === 401) {
package/src/server.jsx CHANGED
@@ -18,7 +18,7 @@ import { CookiesProvider } from 'react-cookie';
18
18
  import cookiesMiddleware from 'universal-cookie-express';
19
19
  import debug from 'debug';
20
20
 
21
- import routes from '~/routes';
21
+ import routes from '@root/routes';
22
22
  import config from '@plone/volto/registry';
23
23
 
24
24
  import {
@@ -44,7 +44,7 @@ let locales = {};
44
44
  if (config.settings) {
45
45
  config.settings.supportedLanguages.forEach((lang) => {
46
46
  const langFileName = normalizeLanguageName(lang);
47
- import('~/../locales/' + langFileName + '.json').then((locale) => {
47
+ import('@root/../locales/' + langFileName + '.json').then((locale) => {
48
48
  locales = { ...locales, [lang]: locale.default };
49
49
  });
50
50
  });
@@ -58,7 +58,13 @@ const supported = new locale.Locales(keys(languages), 'en');
58
58
 
59
59
  const server = express()
60
60
  .disable('x-powered-by')
61
- .use(express.static(process.env.RAZZLE_PUBLIC_DIR))
61
+ .use(
62
+ express.static(
63
+ process.env.BUILD_DIR
64
+ ? path.join(process.env.BUILD_DIR, 'public')
65
+ : process.env.RAZZLE_PUBLIC_DIR,
66
+ ),
67
+ )
62
68
  .head('/*', function (req, res) {
63
69
  // Support for HEAD requests. Required by start-test utility in CI.
64
70
  res.send('');
@@ -179,8 +185,9 @@ server.get('/*', (req, res) => {
179
185
  const { store, api, errorHandler } = req.app.locals;
180
186
 
181
187
  // @loadable/server extractor
188
+ const buildDir = process.env.BUILD_DIR || 'build';
182
189
  const extractor = new ChunkExtractor({
183
- statsFile: path.resolve('build/loadable-stats.json'),
190
+ statsFile: path.resolve(path.join(buildDir, 'loadable-stats.json')),
184
191
  entrypoints: ['client'],
185
192
  });
186
193
 
@@ -192,11 +199,18 @@ server.get('/*', (req, res) => {
192
199
  // The content info is in the store at this point thanks to the asynconnect
193
200
  // features, then we can force the current language info into the store when
194
201
  // coming from an SSR request
195
- const updatedLang =
202
+ const contentLang =
196
203
  store.getState().content.data?.language?.token ||
197
204
  config.settings.defaultLanguage;
198
205
 
199
- store.dispatch(changeLanguage(updatedLang, locales[updatedLang]));
206
+ const cookie_lang =
207
+ req.universalCookies.get('I18N_LANGUAGE') ||
208
+ config.settings.defaultLanguage ||
209
+ req.headers['accept-language'];
210
+
211
+ if (cookie_lang !== contentLang) {
212
+ store.dispatch(changeLanguage(contentLang, locales[contentLang], req));
213
+ }
200
214
 
201
215
  const context = {};
202
216
  resetServerContext();
@@ -1,5 +1,5 @@
1
1
  import '@plone/volto/config'; // This is the bootstrap for the global config - client side
2
- import '~/theme';
2
+ import '@root/theme';
3
3
  import React from 'react';
4
4
  import { hydrate } from 'react-dom';
5
5
  import { Provider } from 'react-redux';
@@ -10,7 +10,7 @@ import { ReduxAsyncConnect } from '@plone/volto/helpers/AsyncConnect';
10
10
  import { loadableReady } from '@loadable/component';
11
11
  import { CookiesProvider } from 'react-cookie';
12
12
  import debug from 'debug';
13
- import routes from '~/routes';
13
+ import routes from '@root/routes';
14
14
  import config from '@plone/volto/registry';
15
15
 
16
16
  import configureStore from '@plone/volto/store';
package/src/store.js CHANGED
@@ -5,7 +5,7 @@ import { connectRouter, routerMiddleware } from 'connected-react-router';
5
5
  import { save, load } from 'redux-localstorage-simple';
6
6
 
7
7
  import config from '@plone/volto/registry';
8
- import reducers from '~/reducers';
8
+ import reducers from '@root/reducers';
9
9
 
10
10
  import { api, crashReporter, blacklistRoutes } from '@plone/volto/middleware';
11
11