@eeacms/volto-eea-website-policy 0.3.0 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -65
- package/package.json +1 -1
- package/src/components/Blocks/ContextNavigation/ContextNavigationEdit.jsx +31 -0
- package/src/components/Blocks/ContextNavigation/ContextNavigationView.jsx +17 -0
- package/src/components/Blocks/ContextNavigation/index.js +26 -0
- package/src/components/Blocks/ContextNavigation/schema.js +81 -0
- package/src/customizations/volto/components/manage/Controlpanels/ContentTypeLayout.jsx +520 -0
- package/src/customizations/volto/helpers/Blocks/Blocks.js +440 -0
- package/src/index.js +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,92 +4,89 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### [0.3.3](https://github.com/eea/volto-eea-website-policy/compare/0.3.2...0.3.3) - 5 September 2022
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- change(item): enable theming for icon and text color and added tertiary option [`58c2d28`](https://github.com/eea/volto-eea-website-policy/commit/58c2d2864fe94c9e7808064b61d3b6c4e6fccbb1)
|
|
11
|
-
- change(item): commented sizes too small for item icons and enabled tertiary theme [`0f02d7d`](https://github.com/eea/volto-eea-website-policy/commit/0f02d7d6204b068b78c3f977a561782a19b6f79e)
|
|
9
|
+
#### :hammer_and_wrench: Others
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
- override(ContentTypeLayout): Enable volto.blocks.editable.layout - refs #153858 [Alin Voinea - [`a07d3f5`](https://github.com/eea/volto-eea-website-policy/commit/a07d3f5f175925fdcd600e3c99620b4c0f42cb69)]
|
|
12
|
+
- override(ContentTypeLayout) - from @plone/volto 16 alpha 12 [Alin Voinea - [`777068d`](https://github.com/eea/volto-eea-website-policy/commit/777068d4b41d4c94863e2c34ea274f150ead7875)]
|
|
13
|
+
### [0.3.2](https://github.com/eea/volto-eea-website-policy/compare/0.3.1...0.3.2) - 10 August 2022
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
#### :hammer_and_wrench: Others
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
- Customize
|
|
17
|
+
- Safely get data - refs #153018 [Alin Voinea - [`aefc689`](https://github.com/eea/volto-eea-website-policy/commit/aefc68979f6aad86ea02952f82e639dfe8c566f2)]
|
|
18
|
+
- Customize Blocks helper - copy unchanged from @plone/volto 16.alpha.12 [Alin Voinea - [`368ffa8`](https://github.com/eea/volto-eea-website-policy/commit/368ffa8c9ebfc54d364d7bf13b60f4016f1c90e8)]
|
|
19
|
+
### [0.3.1](https://github.com/eea/volto-eea-website-policy/compare/0.3.0...0.3.1) - 1 August 2022
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
### [0.3.0](https://github.com/eea/volto-eea-website-policy/compare/0.2.6...0.3.0) - 6 July 2022
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
#### :nail_care: Enhancements
|
|
23
24
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
- Disable Image Cards block [`3ed8dc3`](https://github.com/eea/volto-eea-website-policy/commit/3ed8dc311cad8e30a8c918ecec7b21cc99260c50)
|
|
28
|
-
- Rounded Card variation - refs #148723 [`4b46731`](https://github.com/eea/volto-eea-website-policy/commit/4b46731e25962bbb6e7159d0db8a9a642a95eb53)
|
|
25
|
+
- change(package): bump release version [David Ichim - [`1b00439`](https://github.com/eea/volto-eea-website-policy/commit/1b0043933442bb73c1042dce644a2c09e5f210f4)]
|
|
26
|
+
- change(item): enable theming for icon and text color and added tertiary option [David Ichim - [`58c2d28`](https://github.com/eea/volto-eea-website-policy/commit/58c2d2864fe94c9e7808064b61d3b6c4e6fccbb1)]
|
|
27
|
+
- change(item): commented sizes too small for item icons and enabled tertiary theme [David Ichim - [`0f02d7d`](https://github.com/eea/volto-eea-website-policy/commit/0f02d7d6204b068b78c3f977a561782a19b6f79e)]
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
### [0.2.6](https://github.com/eea/volto-eea-website-policy/compare/0.2.5...0.2.6) - 1 July 2022
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
#### :hammer_and_wrench: Others
|
|
33
32
|
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
- Fix className vs class warning [`fea1603`](https://github.com/eea/volto-eea-website-policy/commit/fea1603eefd628d57640a6b94ddbbb7edfb0d841)
|
|
38
|
-
- Custom card view for teaser [`c8eded0`](https://github.com/eea/volto-eea-website-policy/commit/c8eded011b8317cce9f842526f5d86771f54797b)
|
|
33
|
+
- Fix Cannot read properties of undefined (reading 'translations') [Alin Voinea - [`8e7b8b8`](https://github.com/eea/volto-eea-website-policy/commit/8e7b8b8533b14f173d77783fe2d0b517c29c5937)]
|
|
34
|
+
- Customize Toolbar.jsx - copied unchanged from @plone/volto 16.0.0.alpha.11 [Alin Voinea - [`b7add4f`](https://github.com/eea/volto-eea-website-policy/commit/b7add4faa8ef2dde7d77489fc8bc431cbb023314)]
|
|
35
|
+
### [0.2.5](https://github.com/eea/volto-eea-website-policy/compare/0.2.4...0.2.5) - 23 June 2022
|
|
39
36
|
|
|
40
|
-
####
|
|
37
|
+
#### :hammer_and_wrench: Others
|
|
41
38
|
|
|
42
|
-
|
|
39
|
+
- Rounded card via style wrapper [Alin Voinea - [`6728684`](https://github.com/eea/volto-eea-website-policy/commit/67286844b00902aa4c6b316b50be35db95c531f0)]
|
|
40
|
+
- Revert "Rounded Card variation - refs #148723" [Alin Voinea - [`0168a86`](https://github.com/eea/volto-eea-website-policy/commit/0168a86fa644a9b848e37c7f5054eb4308c36784)]
|
|
41
|
+
- Disable Image Cards block [Alin Voinea - [`3ed8dc3`](https://github.com/eea/volto-eea-website-policy/commit/3ed8dc311cad8e30a8c918ecec7b21cc99260c50)]
|
|
42
|
+
- Rounded Card variation - refs #148723 [Alin Voinea - [`4b46731`](https://github.com/eea/volto-eea-website-policy/commit/4b46731e25962bbb6e7159d0db8a9a642a95eb53)]
|
|
43
|
+
### [0.2.4](https://github.com/eea/volto-eea-website-policy/compare/0.2.3...0.2.4) - 13 June 2022
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
- prettier fix [`c2a6d2d`](https://github.com/eea/volto-eea-website-policy/commit/c2a6d2d3b12ce771b9b4413c5a6db157ccd9d1fc)
|
|
46
|
-
- Update index.js [`fb73895`](https://github.com/eea/volto-eea-website-policy/commit/fb7389509bc7e207942762c5e02a93d0168a6fba)
|
|
47
|
-
- removed change from commit 719e3778 [`29e636b`](https://github.com/eea/volto-eea-website-policy/commit/29e636b34ab02992c67cc5960f4dc6b21b1b4e71)
|
|
48
|
-
- added navDepth to level 4 in order to fill mega menu [`719e377`](https://github.com/eea/volto-eea-website-policy/commit/719e37785cfa2ed37568c82a34dc470b52483d04)
|
|
49
|
-
- Rearrange Block Chooser [`9a5c118`](https://github.com/eea/volto-eea-website-policy/commit/9a5c1187ba21fa1898394a4b6cf6dd68bd68f258)
|
|
50
|
-
- Move Item block un components folder [`9fb6ab2`](https://github.com/eea/volto-eea-website-policy/commit/9fb6ab2fb02cc5c1a7e25367de5ebe7109bd3dc4)
|
|
51
|
-
- Set default sizes for image & icon in Item block [`af22ec7`](https://github.com/eea/volto-eea-website-policy/commit/af22ec78b2c6fd1d033dc1acfec5e64f8926cd77)
|
|
52
|
-
- Add helpers functions [`353581c`](https://github.com/eea/volto-eea-website-policy/commit/353581cc6602b5e573eee93c74a67656203c0968)
|
|
53
|
-
- Add Teaser block folder's structure [`9457dd4`](https://github.com/eea/volto-eea-website-policy/commit/9457dd4ffaa2631eceb46bfd1ec2d201e8b3d7a8)
|
|
45
|
+
#### :hammer_and_wrench: Others
|
|
54
46
|
|
|
55
|
-
|
|
47
|
+
- Fix listing block title: Listing (Content) [Alin Voinea - [`cec2760`](https://github.com/eea/volto-eea-website-policy/commit/cec276082c3fc1b5486c996c3746a6958fb3a1a9)]
|
|
48
|
+
- Add theme to teaser stylewrapper [Alin Voinea - [`60eeb28`](https://github.com/eea/volto-eea-website-policy/commit/60eeb28b7793708c59d0af73ffb09895e8f2c87d)]
|
|
49
|
+
- Fix className vs class warning [Alin Voinea - [`fea1603`](https://github.com/eea/volto-eea-website-policy/commit/fea1603eefd628d57640a6b94ddbbb7edfb0d841)]
|
|
50
|
+
- Custom card view for teaser [Alin Voinea - [`c8eded0`](https://github.com/eea/volto-eea-website-policy/commit/c8eded011b8317cce9f842526f5d86771f54797b)]
|
|
51
|
+
### [0.2.3](https://github.com/eea/volto-eea-website-policy/compare/0.2.2...0.2.3) - 10 June 2022
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
#### :hammer_and_wrench: Others
|
|
58
54
|
|
|
59
|
-
-
|
|
55
|
+
- prettier fix [David Ichim - [`c2a6d2d`](https://github.com/eea/volto-eea-website-policy/commit/c2a6d2d3b12ce771b9b4413c5a6db157ccd9d1fc)]
|
|
56
|
+
- Update index.js [ichim-david - [`fb73895`](https://github.com/eea/volto-eea-website-policy/commit/fb7389509bc7e207942762c5e02a93d0168a6fba)]
|
|
57
|
+
- removed change from commit 719e3778 [ichim-david - [`29e636b`](https://github.com/eea/volto-eea-website-policy/commit/29e636b34ab02992c67cc5960f4dc6b21b1b4e71)]
|
|
58
|
+
- added navDepth to level 4 in order to fill mega menu [ichim-david - [`719e377`](https://github.com/eea/volto-eea-website-policy/commit/719e37785cfa2ed37568c82a34dc470b52483d04)]
|
|
59
|
+
- Rearrange Block Chooser [Alin Voinea - [`9a5c118`](https://github.com/eea/volto-eea-website-policy/commit/9a5c1187ba21fa1898394a4b6cf6dd68bd68f258)]
|
|
60
|
+
- Move Item block un components folder [Miu Razvan - [`9fb6ab2`](https://github.com/eea/volto-eea-website-policy/commit/9fb6ab2fb02cc5c1a7e25367de5ebe7109bd3dc4)]
|
|
61
|
+
- Set default sizes for image & icon in Item block [Miu Razvan - [`af22ec7`](https://github.com/eea/volto-eea-website-policy/commit/af22ec78b2c6fd1d033dc1acfec5e64f8926cd77)]
|
|
62
|
+
- Add helpers functions [Miu Razvan - [`353581c`](https://github.com/eea/volto-eea-website-policy/commit/353581cc6602b5e573eee93c74a67656203c0968)]
|
|
63
|
+
- Add Teaser block folder's structure [Alin Voinea - [`9457dd4`](https://github.com/eea/volto-eea-website-policy/commit/9457dd4ffaa2631eceb46bfd1ec2d201e8b3d7a8)]
|
|
64
|
+
### [0.2.2](https://github.com/eea/volto-eea-website-policy/compare/0.2.1...0.2.2) - 24 May 2022
|
|
60
65
|
|
|
61
|
-
|
|
66
|
+
### [0.2.1](https://github.com/eea/volto-eea-website-policy/compare/0.2.0...0.2.1) - 25 March 2022
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
### [0.2.0](https://github.com/eea/volto-eea-website-policy/compare/0.1.1...0.2.0) - 18 March 2022
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
- 137187 keycloak integration for plone6 [`#3`](https://github.com/eea/volto-eea-website-policy/pull/3)
|
|
70
|
+
#### :hammer_and_wrench: Others
|
|
67
71
|
|
|
68
|
-
|
|
72
|
+
- Release 0.2.0 [Alin Voinea - [`4b72206`](https://github.com/eea/volto-eea-website-policy/commit/4b72206675ab13ed81567df590849613581d7f10)]
|
|
73
|
+
- Update index.js [Alexandru Ghica - [`0f5be15`](https://github.com/eea/volto-eea-website-policy/commit/0f5be1553b608f49c9a61bbc69a0f90219260a83)]
|
|
74
|
+
- Update index.js [Alexandru Ghica - [`03dd3b1`](https://github.com/eea/volto-eea-website-policy/commit/03dd3b162d3175df00048339bed4f9a7d097a896)]
|
|
75
|
+
- format index.js [Andrei Grigore - [`db4481a`](https://github.com/eea/volto-eea-website-policy/commit/db4481aeeba59a769272659f33278c902fc69bec)]
|
|
76
|
+
- Update index.js [Alexandru Ghica - [`dc09886`](https://github.com/eea/volto-eea-website-policy/commit/dc0988640a76a9914381b120f58bb61a9ab1eb39)]
|
|
77
|
+
- Added externalRoutes [Alexandru Ghica - [`b68135b`](https://github.com/eea/volto-eea-website-policy/commit/b68135b013fafa93a41ea602ea2fad30879abe0f)]
|
|
78
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`575cca6`](https://github.com/eea/volto-eea-website-policy/commit/575cca674602ca2e1c2a41300c47ba594ff49aa0)]
|
|
79
|
+
### [0.1.1](https://github.com/eea/volto-eea-website-policy/compare/0.1.0...0.1.1) - 4 March 2022
|
|
69
80
|
|
|
70
|
-
|
|
81
|
+
#### :hammer_and_wrench: Others
|
|
71
82
|
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
- format index.js [`db4481a`](https://github.com/eea/volto-eea-website-policy/commit/db4481aeeba59a769272659f33278c902fc69bec)
|
|
78
|
-
- Update index.js [`dc09886`](https://github.com/eea/volto-eea-website-policy/commit/dc0988640a76a9914381b120f58bb61a9ab1eb39)
|
|
79
|
-
- Added externalRoutes [`b68135b`](https://github.com/eea/volto-eea-website-policy/commit/b68135b013fafa93a41ea602ea2fad30879abe0f)
|
|
83
|
+
- Enable description block by default [Alin Voinea - [`b3d6534`](https://github.com/eea/volto-eea-website-policy/commit/b3d6534a57f7288899c4f59b5cec553370363d8b)]
|
|
84
|
+
- Prepare for first release [Alin Voinea - [`69e36b1`](https://github.com/eea/volto-eea-website-policy/commit/69e36b1c82b75b0917ef3d433581c50cdcf6c341)]
|
|
85
|
+
- Enable working copy support [Alin Voinea - [`7c6269d`](https://github.com/eea/volto-eea-website-policy/commit/7c6269d75df915f39c15e8ed0893cc062601e7a7)]
|
|
86
|
+
- Enable multilingual [Alin Voinea - [`73210b9`](https://github.com/eea/volto-eea-website-policy/commit/73210b90ad968909da0c15583992f8f58e99e632)]
|
|
87
|
+
### 0.1.0 - 4 March 2022
|
|
80
88
|
|
|
81
|
-
####
|
|
89
|
+
#### :hammer_and_wrench: Others
|
|
82
90
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
- Release [`#1`](https://github.com/eea/volto-eea-website-policy/pull/1)
|
|
86
|
-
- Enable description block by default [`b3d6534`](https://github.com/eea/volto-eea-website-policy/commit/b3d6534a57f7288899c4f59b5cec553370363d8b)
|
|
87
|
-
- Prepare for first release [`69e36b1`](https://github.com/eea/volto-eea-website-policy/commit/69e36b1c82b75b0917ef3d433581c50cdcf6c341)
|
|
88
|
-
- Enable working copy support [`7c6269d`](https://github.com/eea/volto-eea-website-policy/commit/7c6269d75df915f39c15e8ed0893cc062601e7a7)
|
|
89
|
-
- Enable multilingual [`73210b9`](https://github.com/eea/volto-eea-website-policy/commit/73210b90ad968909da0c15583992f8f58e99e632)
|
|
90
|
-
|
|
91
|
-
#### 0.1.0
|
|
92
|
-
|
|
93
|
-
> 4 March 2022
|
|
94
|
-
|
|
95
|
-
- Initial commit [`3800692`](https://github.com/eea/volto-eea-website-policy/commit/3800692f7a4de6460815bd6061facacb986cbef0)
|
|
91
|
+
- yarn bootstrap [Alin Voinea - [`9b4d197`](https://github.com/eea/volto-eea-website-policy/commit/9b4d197cbc7992566cb36524d190078d5ad21a44)]
|
|
92
|
+
- Initial commit [Alin Voinea - [`3800692`](https://github.com/eea/volto-eea-website-policy/commit/3800692f7a4de6460815bd6061facacb986cbef0)]
|
package/package.json
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { EditSchema } from './schema';
|
|
3
|
+
import { InlineForm, SidebarPortal } from '@plone/volto/components';
|
|
4
|
+
import ContextNavigationView from './ContextNavigationView';
|
|
5
|
+
|
|
6
|
+
const ContextNavigationFillView = (props) => {
|
|
7
|
+
const schema = EditSchema();
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<h3>Context navigation</h3>
|
|
11
|
+
<ContextNavigationView {...props} />{' '}
|
|
12
|
+
<SidebarPortal selected={props.selected}>
|
|
13
|
+
{props.selected && (
|
|
14
|
+
<InlineForm
|
|
15
|
+
title={schema.title}
|
|
16
|
+
schema={schema}
|
|
17
|
+
formData={props.data}
|
|
18
|
+
onChangeField={(id, value) => {
|
|
19
|
+
props.onChangeBlock(props.block, {
|
|
20
|
+
...props.data,
|
|
21
|
+
[id]: value,
|
|
22
|
+
});
|
|
23
|
+
}}
|
|
24
|
+
/>
|
|
25
|
+
)}
|
|
26
|
+
</SidebarPortal>
|
|
27
|
+
</>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default ContextNavigationFillView;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ConnectedContextNavigation from '@plone/volto/components/theme/Navigation/ContextNavigation';
|
|
3
|
+
import { flattenToAppURL } from '@plone/volto/helpers';
|
|
4
|
+
|
|
5
|
+
const ContextNavigationView = ({ data = {} }) => {
|
|
6
|
+
const navProps = { ...data };
|
|
7
|
+
const root_path = data?.root_node?.[0]?.['@id'];
|
|
8
|
+
if (root_path) navProps['root_path'] = flattenToAppURL(root_path);
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
<ConnectedContextNavigation params={navProps} />
|
|
13
|
+
</>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default ContextNavigationView;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import codeSVG from '@plone/volto/icons/code.svg';
|
|
2
|
+
import ContextNavigationEdit from './ContextNavigationEdit';
|
|
3
|
+
import ContextNavigationView from './ContextNavigationView';
|
|
4
|
+
import BlockSettingsSchema from '@plone/volto/components/manage/Blocks/Block/Schema';
|
|
5
|
+
|
|
6
|
+
export default (config) => {
|
|
7
|
+
config.blocks.blocksConfig.contextNavigation = {
|
|
8
|
+
id: 'contextNavigation',
|
|
9
|
+
title: 'Navigation',
|
|
10
|
+
icon: codeSVG,
|
|
11
|
+
group: 'site',
|
|
12
|
+
view: ContextNavigationView,
|
|
13
|
+
edit: ContextNavigationEdit,
|
|
14
|
+
schema: BlockSettingsSchema,
|
|
15
|
+
restricted: false,
|
|
16
|
+
mostUsed: true,
|
|
17
|
+
blockHasOwnFocusManagement: true,
|
|
18
|
+
sidebarTab: 1,
|
|
19
|
+
security: {
|
|
20
|
+
addPermission: [],
|
|
21
|
+
view: [],
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return config;
|
|
26
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export const EditSchema = () => {
|
|
2
|
+
return {
|
|
3
|
+
title: 'Navigation',
|
|
4
|
+
fieldsets: [
|
|
5
|
+
{
|
|
6
|
+
id: 'default',
|
|
7
|
+
title: 'Default',
|
|
8
|
+
fields: [
|
|
9
|
+
'name',
|
|
10
|
+
'root_node',
|
|
11
|
+
'includeTop',
|
|
12
|
+
'currentFolderOnly',
|
|
13
|
+
'topLevel',
|
|
14
|
+
'bottomLevel',
|
|
15
|
+
'no_icons',
|
|
16
|
+
'thumb_scale',
|
|
17
|
+
'no_thumbs',
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
required: [],
|
|
22
|
+
properties: {
|
|
23
|
+
name: {
|
|
24
|
+
title: 'Title',
|
|
25
|
+
description: 'The title of the navigation tree',
|
|
26
|
+
},
|
|
27
|
+
root_node: {
|
|
28
|
+
title: 'Root node',
|
|
29
|
+
description:
|
|
30
|
+
'You may search for and choose a folder to act as the root of the navigation tree. Leave blank to use the Plone site root.',
|
|
31
|
+
widget: 'object_browser',
|
|
32
|
+
// TODO: these don't work. Why?
|
|
33
|
+
mode: 'link',
|
|
34
|
+
selectedItemAttrs: ['Title', 'Description'],
|
|
35
|
+
},
|
|
36
|
+
includeTop: {
|
|
37
|
+
title: 'Include top node',
|
|
38
|
+
description:
|
|
39
|
+
"Whether or not to show the top, or 'root', node in the navigation tree. This is affected by the 'Start level' setting.",
|
|
40
|
+
type: 'boolean',
|
|
41
|
+
},
|
|
42
|
+
currentFolderOnly: {
|
|
43
|
+
title: 'Only show the contents of the current folder',
|
|
44
|
+
description:
|
|
45
|
+
'If selected, the navigation tree will only show the current folder and its children at all times.',
|
|
46
|
+
type: 'boolean',
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
topLevel: {
|
|
50
|
+
title: 'Start level',
|
|
51
|
+
description:
|
|
52
|
+
'An integer value that specifies the number of folder levels below the site root that must be exceeded before the navigation tree will display. 0 means that the navigation tree should be displayed everywhere including pages in the root of the site. 1 means the tree only shows up inside folders located in the root and downwards, never showing at the top level.',
|
|
53
|
+
type: 'number',
|
|
54
|
+
default: 1,
|
|
55
|
+
},
|
|
56
|
+
bottomLevel: {
|
|
57
|
+
title: 'Navigation tree depth',
|
|
58
|
+
description:
|
|
59
|
+
'How many folders should be included before the navigation tree stops. 0 means no limit. 1 only includes the root folder.',
|
|
60
|
+
type: 'number',
|
|
61
|
+
default: 0,
|
|
62
|
+
},
|
|
63
|
+
no_icons: {
|
|
64
|
+
title: 'Supress icons',
|
|
65
|
+
description:
|
|
66
|
+
'If enabled, the portlet will not show document type icons.',
|
|
67
|
+
type: 'boolean',
|
|
68
|
+
},
|
|
69
|
+
thumb_scale: {
|
|
70
|
+
title: 'Override thumb scale',
|
|
71
|
+
description:
|
|
72
|
+
"Enter a valid scale name (see 'Image Handling' control panel) to override (e.g. icon, tile, thumb, mini, preview, ... ). Leave empty to use default (see 'Site' control panel).",
|
|
73
|
+
},
|
|
74
|
+
no_thumbs: {
|
|
75
|
+
title: 'Supress thumbs',
|
|
76
|
+
type: 'boolean',
|
|
77
|
+
description: 'If enabled, the portlet will not show thumbs.',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
};
|
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Type component.
|
|
3
|
+
* @module components/manage/Controlpanels/ContentTypeLayout
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { Component } from 'react';
|
|
7
|
+
import PropTypes from 'prop-types';
|
|
8
|
+
import { connect } from 'react-redux';
|
|
9
|
+
import { compose } from 'redux';
|
|
10
|
+
import { Link } from 'react-router-dom';
|
|
11
|
+
import {
|
|
12
|
+
getParentUrl,
|
|
13
|
+
hasBlocksData,
|
|
14
|
+
getBlocksFieldname,
|
|
15
|
+
getBlocksLayoutFieldname,
|
|
16
|
+
} from '@plone/volto/helpers';
|
|
17
|
+
import { Portal } from 'react-portal';
|
|
18
|
+
import { Button, Segment } from 'semantic-ui-react';
|
|
19
|
+
import { toast } from 'react-toastify';
|
|
20
|
+
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
21
|
+
import { nth, join } from 'lodash';
|
|
22
|
+
import {
|
|
23
|
+
Error,
|
|
24
|
+
Form,
|
|
25
|
+
Icon,
|
|
26
|
+
Toolbar,
|
|
27
|
+
Sidebar,
|
|
28
|
+
Toast,
|
|
29
|
+
} from '@plone/volto/components';
|
|
30
|
+
import {
|
|
31
|
+
getSchema,
|
|
32
|
+
updateSchema,
|
|
33
|
+
getControlpanel,
|
|
34
|
+
updateControlpanel,
|
|
35
|
+
} from '@plone/volto/actions';
|
|
36
|
+
|
|
37
|
+
import saveSVG from '@plone/volto/icons/save.svg';
|
|
38
|
+
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
39
|
+
import backSVG from '@plone/volto/icons/back.svg';
|
|
40
|
+
|
|
41
|
+
const messages = defineMessages({
|
|
42
|
+
changesSaved: {
|
|
43
|
+
id: 'Changes saved.',
|
|
44
|
+
defaultMessage: 'Changes saved.',
|
|
45
|
+
},
|
|
46
|
+
back: {
|
|
47
|
+
id: 'Back',
|
|
48
|
+
defaultMessage: 'Back',
|
|
49
|
+
},
|
|
50
|
+
save: {
|
|
51
|
+
id: 'Save',
|
|
52
|
+
defaultMessage: 'Save',
|
|
53
|
+
},
|
|
54
|
+
cancel: {
|
|
55
|
+
id: 'Cancel',
|
|
56
|
+
defaultMessage: 'Cancel',
|
|
57
|
+
},
|
|
58
|
+
info: {
|
|
59
|
+
id: 'Info',
|
|
60
|
+
defaultMessage: 'Info',
|
|
61
|
+
},
|
|
62
|
+
enable: {
|
|
63
|
+
id: 'Enable editable Blocks',
|
|
64
|
+
defaultMessage: 'Enable editable Blocks',
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* ContentTypeLayout class.
|
|
70
|
+
* @class ContentTypeLayout
|
|
71
|
+
* @extends Component
|
|
72
|
+
*/
|
|
73
|
+
class ContentTypeLayout extends Component {
|
|
74
|
+
/**
|
|
75
|
+
* Property types.
|
|
76
|
+
* @property {Object} propTypes Property types.
|
|
77
|
+
* @static
|
|
78
|
+
*/
|
|
79
|
+
static propTypes = {
|
|
80
|
+
updateControlpanel: PropTypes.func.isRequired,
|
|
81
|
+
getControlpanel: PropTypes.func.isRequired,
|
|
82
|
+
getSchema: PropTypes.func.isRequired,
|
|
83
|
+
updateSchema: PropTypes.func.isRequired,
|
|
84
|
+
id: PropTypes.string.isRequired,
|
|
85
|
+
parent: PropTypes.string.isRequired,
|
|
86
|
+
pathname: PropTypes.string.isRequired,
|
|
87
|
+
schemaRequest: PropTypes.objectOf(PropTypes.any).isRequired,
|
|
88
|
+
cpanelRequest: PropTypes.objectOf(PropTypes.any).isRequired,
|
|
89
|
+
schema: PropTypes.objectOf(PropTypes.any),
|
|
90
|
+
controlpanel: PropTypes.shape({
|
|
91
|
+
'@id': PropTypes.string,
|
|
92
|
+
data: PropTypes.object,
|
|
93
|
+
schema: PropTypes.object,
|
|
94
|
+
title: PropTypes.string,
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Default properties.
|
|
100
|
+
* @property {Object} defaultProps Default properties.
|
|
101
|
+
* @static
|
|
102
|
+
*/
|
|
103
|
+
static defaultProps = {
|
|
104
|
+
schema: {},
|
|
105
|
+
controlpanel: null,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Constructor
|
|
110
|
+
* @method constructor
|
|
111
|
+
* @param {Object} props Component properties
|
|
112
|
+
* @constructs ContentTypeLayout
|
|
113
|
+
*/
|
|
114
|
+
constructor(props) {
|
|
115
|
+
super(props);
|
|
116
|
+
|
|
117
|
+
this.state = {
|
|
118
|
+
visual: false,
|
|
119
|
+
content: null,
|
|
120
|
+
readOnlyBehavior: null,
|
|
121
|
+
error: null,
|
|
122
|
+
isClient: false,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
this.onCancel = this.onCancel.bind(this);
|
|
126
|
+
this.onSubmit = this.onSubmit.bind(this);
|
|
127
|
+
this.onEnableBlocks = this.onEnableBlocks.bind(this);
|
|
128
|
+
this.onEnableBlocksBehavior = this.onEnableBlocksBehavior.bind(this);
|
|
129
|
+
this.onDisableBlocksBehavior = this.onDisableBlocksBehavior.bind(this);
|
|
130
|
+
this.form = React.createRef();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Component did mount
|
|
135
|
+
* @method componentDidMount
|
|
136
|
+
* @returns {undefined}
|
|
137
|
+
*/
|
|
138
|
+
componentDidMount() {
|
|
139
|
+
this.props.getControlpanel(join([this.props.parent, this.props.id], '/'));
|
|
140
|
+
this.props.getSchema(this.props.id);
|
|
141
|
+
this.setState({ isClient: true });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Component will receive props
|
|
146
|
+
* @method componentWillReceiveProps
|
|
147
|
+
* @param {Object} nextProps Next properties
|
|
148
|
+
* @returns {undefined}
|
|
149
|
+
*/
|
|
150
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
151
|
+
// Control Panel GET
|
|
152
|
+
if (
|
|
153
|
+
this.props.cpanelRequest.get.loading &&
|
|
154
|
+
nextProps.cpanelRequest.get.error
|
|
155
|
+
) {
|
|
156
|
+
this.setState({
|
|
157
|
+
error: nextProps.cpanelRequest.get.error,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Schema GET
|
|
162
|
+
if (this.props.schemaRequest.loading && nextProps.schemaRequest.loaded) {
|
|
163
|
+
const properties = nextProps.schema?.properties || {};
|
|
164
|
+
const content = {};
|
|
165
|
+
for (const key in properties) {
|
|
166
|
+
const value = properties[key].default;
|
|
167
|
+
if (value) {
|
|
168
|
+
content[key] = value;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (hasBlocksData(properties)) {
|
|
173
|
+
this.setState({
|
|
174
|
+
visual: true,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const blocksFieldName = getBlocksFieldname(properties);
|
|
178
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(properties);
|
|
179
|
+
content[blocksFieldName] = properties[blocksFieldName]?.default || {};
|
|
180
|
+
content[blocksLayoutFieldname] = properties[blocksLayoutFieldname]
|
|
181
|
+
?.default || { items: [] };
|
|
182
|
+
|
|
183
|
+
const blocksBehavior = properties[blocksFieldName]?.behavior || '';
|
|
184
|
+
this.setState({
|
|
185
|
+
readOnlyBehavior: !blocksBehavior.includes('generated')
|
|
186
|
+
? blocksBehavior
|
|
187
|
+
: '',
|
|
188
|
+
});
|
|
189
|
+
} else {
|
|
190
|
+
this.setState({
|
|
191
|
+
visual: false,
|
|
192
|
+
readOnlyBehavior: '',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
this.setState({
|
|
197
|
+
content: content,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Schema updated
|
|
202
|
+
if (
|
|
203
|
+
this.props.schemaRequest.update.loading &&
|
|
204
|
+
nextProps.schemaRequest.update.loaded
|
|
205
|
+
) {
|
|
206
|
+
this.props.getSchema(this.props.id);
|
|
207
|
+
toast.info(
|
|
208
|
+
<Toast
|
|
209
|
+
info
|
|
210
|
+
title={this.props.intl.formatMessage(messages.info)}
|
|
211
|
+
content={this.props.intl.formatMessage(messages.changesSaved)}
|
|
212
|
+
/>,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Blocks behavior disabled
|
|
217
|
+
if (
|
|
218
|
+
this.props.cpanelRequest.update.loading &&
|
|
219
|
+
nextProps.cpanelRequest.update.loaded
|
|
220
|
+
) {
|
|
221
|
+
this.onEnableBlocks();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Submit handler
|
|
227
|
+
* @method onSubmit
|
|
228
|
+
* @param {object} data Form data.
|
|
229
|
+
* @returns {undefined}
|
|
230
|
+
*/
|
|
231
|
+
onSubmit(data) {
|
|
232
|
+
const schema = { properties: {} };
|
|
233
|
+
Object.keys(data)
|
|
234
|
+
.filter((k) => data[k])
|
|
235
|
+
.forEach((k) => (schema.properties[k] = { default: data[k] }));
|
|
236
|
+
this.props.updateSchema(this.props.id, schema);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Cancel handler
|
|
241
|
+
* @method onCancel
|
|
242
|
+
* @returns {undefined}
|
|
243
|
+
*/
|
|
244
|
+
onCancel() {
|
|
245
|
+
const url = getParentUrl(this.props.pathname);
|
|
246
|
+
this.props.history.push(getParentUrl(url));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Enable blocks handler
|
|
251
|
+
* @method onEnableBlocks
|
|
252
|
+
* @returns {undefined}
|
|
253
|
+
*/
|
|
254
|
+
onEnableBlocks() {
|
|
255
|
+
const { properties = {} } = this.props.schema;
|
|
256
|
+
const blocksFieldName = getBlocksFieldname(properties);
|
|
257
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(properties);
|
|
258
|
+
const schema = {
|
|
259
|
+
fieldsets: [
|
|
260
|
+
{
|
|
261
|
+
id: 'layout',
|
|
262
|
+
title: 'Layout',
|
|
263
|
+
fields: ['blocks', 'blocks_layout'],
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
properties: {
|
|
267
|
+
blocks: {
|
|
268
|
+
title: 'Blocks',
|
|
269
|
+
type: 'dict',
|
|
270
|
+
widget: 'json',
|
|
271
|
+
factory: 'JSONField',
|
|
272
|
+
default: properties[blocksFieldName]?.default || {},
|
|
273
|
+
},
|
|
274
|
+
blocks_layout: {
|
|
275
|
+
title: 'Blocks Layout',
|
|
276
|
+
type: 'dict',
|
|
277
|
+
widget: 'json',
|
|
278
|
+
factory: 'JSONField',
|
|
279
|
+
default: properties[blocksLayoutFieldname]?.default || { items: [] },
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
this.props.updateSchema(this.props.id, schema);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Disable Blocks behavior handler
|
|
288
|
+
* @method onDisableBlocksBehavior
|
|
289
|
+
* @returns {undefined}
|
|
290
|
+
*/
|
|
291
|
+
onDisableBlocksBehavior() {
|
|
292
|
+
this.props.updateControlpanel(this.props.controlpanel['@id'], {
|
|
293
|
+
[this.state.readOnlyBehavior]: false,
|
|
294
|
+
'volto.blocks.editable.layout': true,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Enable Blocks behavior handler
|
|
300
|
+
* @method onEnableBlocksBehavior
|
|
301
|
+
* @returns {undefined}
|
|
302
|
+
*/
|
|
303
|
+
onEnableBlocksBehavior() {
|
|
304
|
+
this.props.updateControlpanel(this.props.controlpanel['@id'], {
|
|
305
|
+
'volto.blocks.editable.layout': true,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Render method.
|
|
311
|
+
* @method render
|
|
312
|
+
* @returns {string} Markup for the component.
|
|
313
|
+
*/
|
|
314
|
+
render() {
|
|
315
|
+
// Error
|
|
316
|
+
if (this.state.error) {
|
|
317
|
+
return <Error error={this.state.error} />;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (!this.state.visual) {
|
|
321
|
+
// Still loading
|
|
322
|
+
if (!this.state.content) {
|
|
323
|
+
return <div />;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Blocks are not enabled
|
|
327
|
+
return (
|
|
328
|
+
<>
|
|
329
|
+
<Segment
|
|
330
|
+
placeholder
|
|
331
|
+
id="page-controlpanel-layout"
|
|
332
|
+
className="ui container center aligned"
|
|
333
|
+
>
|
|
334
|
+
<div>
|
|
335
|
+
<FormattedMessage
|
|
336
|
+
id="Can not edit Layout for <strong>{type}</strong> content-type as it doesn't have support for <strong>Volto Blocks</strong> enabled"
|
|
337
|
+
defaultMessage="Can not edit Layout for <strong>{type}</strong> content-type as it doesn't have support for <strong>Volto Blocks</strong> enabled"
|
|
338
|
+
values={{
|
|
339
|
+
strong: (...chunks) => <strong>{chunks}</strong>,
|
|
340
|
+
type: this.props?.controlpanel?.title || this.props.id,
|
|
341
|
+
}}
|
|
342
|
+
/>
|
|
343
|
+
</div>
|
|
344
|
+
<div className="ui divider"></div>
|
|
345
|
+
<Button
|
|
346
|
+
primary
|
|
347
|
+
onClick={this.onEnableBlocksBehavior}
|
|
348
|
+
content={this.props.intl.formatMessage(messages.enable)}
|
|
349
|
+
/>
|
|
350
|
+
</Segment>
|
|
351
|
+
<Portal
|
|
352
|
+
node={this.state.isClient && document.getElementById('toolbar')}
|
|
353
|
+
>
|
|
354
|
+
<Toolbar
|
|
355
|
+
pathname={this.props.pathname}
|
|
356
|
+
hideDefaultViewButtons
|
|
357
|
+
inner={
|
|
358
|
+
<>
|
|
359
|
+
<Link className="item" to="#" onClick={() => this.onCancel()}>
|
|
360
|
+
<Icon
|
|
361
|
+
name={backSVG}
|
|
362
|
+
size="30px"
|
|
363
|
+
className="contents circled"
|
|
364
|
+
title={this.props.intl.formatMessage(messages.back)}
|
|
365
|
+
/>
|
|
366
|
+
</Link>
|
|
367
|
+
</>
|
|
368
|
+
}
|
|
369
|
+
/>
|
|
370
|
+
</Portal>
|
|
371
|
+
</>
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (this.state.readOnlyBehavior) {
|
|
376
|
+
return (
|
|
377
|
+
<>
|
|
378
|
+
<Segment
|
|
379
|
+
placeholder
|
|
380
|
+
id="page-controlpanel-layout"
|
|
381
|
+
className="ui container center aligned"
|
|
382
|
+
>
|
|
383
|
+
<div>
|
|
384
|
+
<FormattedMessage
|
|
385
|
+
id="Can not edit Layout for <strong>{type}</strong> content-type as the <strong>Blocks behavior</strong> is enabled and <strong>read-only</strong>"
|
|
386
|
+
defaultMessage="Can not edit Layout for <strong>{type}</strong> content-type as the <strong>Blocks behavior</strong> is enabled and <strong>read-only</strong>"
|
|
387
|
+
values={{
|
|
388
|
+
strong: (...chunks) => <strong>{chunks}</strong>,
|
|
389
|
+
type: this.props?.controlpanel?.title || this.props.id,
|
|
390
|
+
}}
|
|
391
|
+
/>
|
|
392
|
+
</div>
|
|
393
|
+
<div className="ui divider"></div>
|
|
394
|
+
<Button
|
|
395
|
+
primary
|
|
396
|
+
onClick={this.onDisableBlocksBehavior}
|
|
397
|
+
content={this.props.intl.formatMessage(messages.enable)}
|
|
398
|
+
/>
|
|
399
|
+
</Segment>
|
|
400
|
+
<Portal
|
|
401
|
+
node={this.state.isClient && document.getElementById('toolbar')}
|
|
402
|
+
>
|
|
403
|
+
<Toolbar
|
|
404
|
+
pathname={this.props.pathname}
|
|
405
|
+
hideDefaultViewButtons
|
|
406
|
+
inner={
|
|
407
|
+
<>
|
|
408
|
+
<Link className="item" to="#" onClick={() => this.onCancel()}>
|
|
409
|
+
<Icon
|
|
410
|
+
name={backSVG}
|
|
411
|
+
size="30px"
|
|
412
|
+
className="contents circled"
|
|
413
|
+
title={this.props.intl.formatMessage(messages.back)}
|
|
414
|
+
/>
|
|
415
|
+
</Link>
|
|
416
|
+
</>
|
|
417
|
+
}
|
|
418
|
+
/>
|
|
419
|
+
</Portal>
|
|
420
|
+
</>
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Render layout editor
|
|
425
|
+
const blocksFieldName = getBlocksFieldname(
|
|
426
|
+
this.props.schema?.properties || {},
|
|
427
|
+
);
|
|
428
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(
|
|
429
|
+
this.props.schema?.properties || {},
|
|
430
|
+
);
|
|
431
|
+
return (
|
|
432
|
+
<div id="page-controlpanel-layout">
|
|
433
|
+
<Form
|
|
434
|
+
isAdminForm
|
|
435
|
+
ref={this.form}
|
|
436
|
+
schema={{
|
|
437
|
+
fieldsets: [
|
|
438
|
+
{
|
|
439
|
+
id: 'layout',
|
|
440
|
+
title: 'Layout',
|
|
441
|
+
fields: [blocksFieldName, blocksLayoutFieldname],
|
|
442
|
+
},
|
|
443
|
+
],
|
|
444
|
+
properties: {
|
|
445
|
+
...this.props.schema.properties[blocksFieldName],
|
|
446
|
+
...this.props.schema.properties[blocksLayoutFieldname],
|
|
447
|
+
},
|
|
448
|
+
required: [],
|
|
449
|
+
}}
|
|
450
|
+
formData={this.state.content}
|
|
451
|
+
onSubmit={this.onSubmit}
|
|
452
|
+
onCancel={this.onCancel}
|
|
453
|
+
pathname={this.props.pathname}
|
|
454
|
+
visual={this.state.visual}
|
|
455
|
+
hideActions
|
|
456
|
+
/>
|
|
457
|
+
<Portal
|
|
458
|
+
node={this.state.isClient && document.getElementById('sidebar')}
|
|
459
|
+
>
|
|
460
|
+
<Sidebar settingsTab={true} documentTab={false} />
|
|
461
|
+
</Portal>
|
|
462
|
+
<Portal
|
|
463
|
+
node={this.state.isClient && document.getElementById('toolbar')}
|
|
464
|
+
>
|
|
465
|
+
<Toolbar
|
|
466
|
+
pathname={this.props.pathname}
|
|
467
|
+
hideDefaultViewButtons
|
|
468
|
+
inner={
|
|
469
|
+
<>
|
|
470
|
+
<Button
|
|
471
|
+
id="toolbar-save"
|
|
472
|
+
className="save"
|
|
473
|
+
aria-label={this.props.intl.formatMessage(messages.save)}
|
|
474
|
+
onClick={() => this.form.current.onSubmit()}
|
|
475
|
+
disabled={this.props.schemaRequest.update.loading}
|
|
476
|
+
loading={this.props.schemaRequest.update.loading}
|
|
477
|
+
>
|
|
478
|
+
<Icon
|
|
479
|
+
name={saveSVG}
|
|
480
|
+
className="circled"
|
|
481
|
+
size="30px"
|
|
482
|
+
title={this.props.intl.formatMessage(messages.save)}
|
|
483
|
+
/>
|
|
484
|
+
</Button>
|
|
485
|
+
<Button
|
|
486
|
+
className="cancel"
|
|
487
|
+
aria-label={this.props.intl.formatMessage(messages.cancel)}
|
|
488
|
+
onClick={() => this.onCancel()}
|
|
489
|
+
>
|
|
490
|
+
<Icon
|
|
491
|
+
name={clearSVG}
|
|
492
|
+
className="circled"
|
|
493
|
+
size="30px"
|
|
494
|
+
title={this.props.intl.formatMessage(messages.cancel)}
|
|
495
|
+
/>
|
|
496
|
+
</Button>
|
|
497
|
+
</>
|
|
498
|
+
}
|
|
499
|
+
/>
|
|
500
|
+
</Portal>
|
|
501
|
+
</div>
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
export default compose(
|
|
507
|
+
injectIntl,
|
|
508
|
+
connect(
|
|
509
|
+
(state, props) => ({
|
|
510
|
+
schema: state.schema.schema,
|
|
511
|
+
schemaRequest: state.schema,
|
|
512
|
+
cpanelRequest: state.controlpanels,
|
|
513
|
+
controlpanel: state.controlpanels.controlpanel,
|
|
514
|
+
pathname: props.location.pathname,
|
|
515
|
+
id: nth(props.location.pathname.split('/'), -2),
|
|
516
|
+
parent: nth(props.location.pathname.split('/'), -3),
|
|
517
|
+
}),
|
|
518
|
+
{ getSchema, updateSchema, getControlpanel, updateControlpanel },
|
|
519
|
+
),
|
|
520
|
+
)(ContentTypeLayout);
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blocks helper.
|
|
3
|
+
* @module helpers/Blocks
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { omit, without, endsWith, find, isObject, keys, toPairs } from 'lodash';
|
|
7
|
+
import move from 'lodash-move';
|
|
8
|
+
import { v4 as uuid } from 'uuid';
|
|
9
|
+
import config from '@plone/volto/registry';
|
|
10
|
+
import { applySchemaEnhancer } from '@plone/volto/helpers';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get blocks field.
|
|
14
|
+
* @function getBlocksFieldname
|
|
15
|
+
* @param {Object} props Properties.
|
|
16
|
+
* @return {string} Field name of the blocks
|
|
17
|
+
*/
|
|
18
|
+
export function getBlocksFieldname(props) {
|
|
19
|
+
return (
|
|
20
|
+
find(
|
|
21
|
+
keys(props),
|
|
22
|
+
(key) => key !== 'volto.blocks' && endsWith(key, 'blocks'),
|
|
23
|
+
) || null
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get blocks layout field.
|
|
29
|
+
* @function getBlocksLayoutFieldname
|
|
30
|
+
* @param {Object} props Properties.
|
|
31
|
+
* @return {string} Field name of the blocks layout
|
|
32
|
+
*/
|
|
33
|
+
export function getBlocksLayoutFieldname(props) {
|
|
34
|
+
return (
|
|
35
|
+
find(
|
|
36
|
+
keys(props),
|
|
37
|
+
(key) => key !== 'volto.blocks' && endsWith(key, 'blocks_layout'),
|
|
38
|
+
) || null
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Has blocks data.
|
|
44
|
+
* @function hasBlocksData
|
|
45
|
+
* @param {Object} props Properties.
|
|
46
|
+
* @return {boolean} True if it has blocks data.
|
|
47
|
+
*/
|
|
48
|
+
export function hasBlocksData(props) {
|
|
49
|
+
return (
|
|
50
|
+
find(
|
|
51
|
+
keys(props),
|
|
52
|
+
(key) => key !== 'volto.blocks' && endsWith(key, 'blocks'),
|
|
53
|
+
) !== undefined
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Pluggable method to test if a block has a set value (any non-empty value)
|
|
59
|
+
* @function blockHasValue
|
|
60
|
+
* @param {Object} data Block data
|
|
61
|
+
* @return {boolean} True if block has a non-empty value
|
|
62
|
+
*/
|
|
63
|
+
export function blockHasValue(data) {
|
|
64
|
+
const { blocks } = config;
|
|
65
|
+
const blockType = data['@type'];
|
|
66
|
+
const check = blocks.blocksConfig[blockType]?.blockHasValue;
|
|
67
|
+
if (!check) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
return check(data);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get block pairs of [id, block] from content properties
|
|
75
|
+
* @function getBlocks
|
|
76
|
+
* @param {Object} properties
|
|
77
|
+
* @return {Array} a list of block [id, value] pairs, in order from layout
|
|
78
|
+
*/
|
|
79
|
+
export const getBlocks = (properties) => {
|
|
80
|
+
const blocksFieldName = getBlocksFieldname(properties);
|
|
81
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(properties);
|
|
82
|
+
return (
|
|
83
|
+
properties[blocksLayoutFieldname]?.items?.map((n) => [
|
|
84
|
+
n,
|
|
85
|
+
properties[blocksFieldName][n],
|
|
86
|
+
]) || []
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Move block to different location index within blocks_layout
|
|
92
|
+
* @function moveBlock
|
|
93
|
+
* @param {Object} formData Form data
|
|
94
|
+
* @param {number} source index within form blocks_layout items
|
|
95
|
+
* @param {number} destination index within form blocks_layout items
|
|
96
|
+
* @return {Object} New form data
|
|
97
|
+
*/
|
|
98
|
+
export function moveBlock(formData, source, destination) {
|
|
99
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
|
|
100
|
+
return {
|
|
101
|
+
...formData,
|
|
102
|
+
[blocksLayoutFieldname]: {
|
|
103
|
+
items: move(formData[blocksLayoutFieldname].items, source, destination),
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Delete block by id
|
|
110
|
+
* @function deleteBlock
|
|
111
|
+
* @param {Object} formData Form data
|
|
112
|
+
* @param {string} blockId Block uid
|
|
113
|
+
* @return {Object} New form data
|
|
114
|
+
*/
|
|
115
|
+
export function deleteBlock(formData, blockId) {
|
|
116
|
+
const blocksFieldname = getBlocksFieldname(formData);
|
|
117
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
|
|
118
|
+
|
|
119
|
+
let newFormData = {
|
|
120
|
+
...formData,
|
|
121
|
+
[blocksLayoutFieldname]: {
|
|
122
|
+
items: without(formData[blocksLayoutFieldname].items, blockId),
|
|
123
|
+
},
|
|
124
|
+
[blocksFieldname]: omit(formData[blocksFieldname], [blockId]),
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
if (newFormData[blocksLayoutFieldname].items.length === 0) {
|
|
128
|
+
newFormData = addBlock(newFormData, config.settings.defaultBlockType, 0);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return newFormData;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Add block
|
|
136
|
+
* @function addBlock
|
|
137
|
+
* @param {Object} formData Form data
|
|
138
|
+
* @param {string} type Block type
|
|
139
|
+
* @param {number} index Destination index
|
|
140
|
+
* @return {Array} New block id, New form data
|
|
141
|
+
*/
|
|
142
|
+
export function addBlock(formData, type, index) {
|
|
143
|
+
const { settings } = config;
|
|
144
|
+
const id = uuid();
|
|
145
|
+
const idTrailingBlock = uuid();
|
|
146
|
+
const blocksFieldname = getBlocksFieldname(formData);
|
|
147
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
|
|
148
|
+
const totalItems = formData[blocksLayoutFieldname].items.length;
|
|
149
|
+
const insert = index === -1 ? totalItems : index;
|
|
150
|
+
|
|
151
|
+
return [
|
|
152
|
+
id,
|
|
153
|
+
{
|
|
154
|
+
...formData,
|
|
155
|
+
[blocksLayoutFieldname]: {
|
|
156
|
+
items: [
|
|
157
|
+
...formData[blocksLayoutFieldname].items.slice(0, insert),
|
|
158
|
+
id,
|
|
159
|
+
...(type !== settings.defaultBlockType ? [idTrailingBlock] : []),
|
|
160
|
+
...formData[blocksLayoutFieldname].items.slice(insert),
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
[blocksFieldname]: {
|
|
164
|
+
...formData[blocksFieldname],
|
|
165
|
+
[id]: {
|
|
166
|
+
'@type': type,
|
|
167
|
+
},
|
|
168
|
+
...(type !== settings.defaultBlockType && {
|
|
169
|
+
[idTrailingBlock]: {
|
|
170
|
+
'@type': settings.defaultBlockType,
|
|
171
|
+
},
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
selected: id,
|
|
175
|
+
},
|
|
176
|
+
];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Mutate block
|
|
181
|
+
* @function mutateBlock
|
|
182
|
+
* @param {Object} formData Form data
|
|
183
|
+
* @param {string} id Block uid to mutate
|
|
184
|
+
* @param {number} value Block's new value
|
|
185
|
+
* @return {Object} New form data
|
|
186
|
+
*/
|
|
187
|
+
export function mutateBlock(formData, id, value) {
|
|
188
|
+
const { settings } = config;
|
|
189
|
+
const blocksFieldname = getBlocksFieldname(formData);
|
|
190
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
|
|
191
|
+
const index = formData[blocksLayoutFieldname].items.indexOf(id) + 1;
|
|
192
|
+
|
|
193
|
+
// Test if block at index is already a placeholder (trailing) block
|
|
194
|
+
const trailId = formData[blocksLayoutFieldname].items[index];
|
|
195
|
+
if (trailId) {
|
|
196
|
+
const block = formData[blocksFieldname][trailId];
|
|
197
|
+
if (!blockHasValue(block)) {
|
|
198
|
+
return {
|
|
199
|
+
...formData,
|
|
200
|
+
[blocksFieldname]: {
|
|
201
|
+
...formData[blocksFieldname],
|
|
202
|
+
[id]: value || null,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const idTrailingBlock = uuid();
|
|
209
|
+
return {
|
|
210
|
+
...formData,
|
|
211
|
+
[blocksFieldname]: {
|
|
212
|
+
...formData[blocksFieldname],
|
|
213
|
+
[id]: value || null,
|
|
214
|
+
[idTrailingBlock]: {
|
|
215
|
+
'@type': settings.defaultBlockType,
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
[blocksLayoutFieldname]: {
|
|
219
|
+
items: [
|
|
220
|
+
...formData[blocksLayoutFieldname].items.slice(0, index),
|
|
221
|
+
idTrailingBlock,
|
|
222
|
+
...formData[blocksLayoutFieldname].items.slice(index),
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Insert new block before another block
|
|
230
|
+
* @function insertBlock
|
|
231
|
+
* @param {Object} formData Form data
|
|
232
|
+
* @param {string} id Insert new block before the block with this id
|
|
233
|
+
* @param {number} value New block's value
|
|
234
|
+
* @return {Array} New block id, New form data
|
|
235
|
+
*/
|
|
236
|
+
export function insertBlock(formData, id, value, current = {}) {
|
|
237
|
+
const blocksFieldname = getBlocksFieldname(formData);
|
|
238
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
|
|
239
|
+
const index = formData[blocksLayoutFieldname].items.indexOf(id);
|
|
240
|
+
|
|
241
|
+
const newBlockId = uuid();
|
|
242
|
+
return [
|
|
243
|
+
newBlockId,
|
|
244
|
+
{
|
|
245
|
+
...formData,
|
|
246
|
+
[blocksFieldname]: {
|
|
247
|
+
...formData[blocksFieldname],
|
|
248
|
+
[newBlockId]: value || null,
|
|
249
|
+
[id]: {
|
|
250
|
+
...formData[blocksFieldname][id],
|
|
251
|
+
...current,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
[blocksLayoutFieldname]: {
|
|
255
|
+
items: [
|
|
256
|
+
...formData[blocksLayoutFieldname].items.slice(0, index),
|
|
257
|
+
newBlockId,
|
|
258
|
+
...formData[blocksLayoutFieldname].items.slice(index),
|
|
259
|
+
],
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Change block
|
|
267
|
+
* @function changeBlock
|
|
268
|
+
* @param {Object} formData Form data
|
|
269
|
+
* @param {string} id Block uid to change
|
|
270
|
+
* @param {number} value Block's new value
|
|
271
|
+
* @return {Object} New form data
|
|
272
|
+
*/
|
|
273
|
+
export function changeBlock(formData, id, value) {
|
|
274
|
+
const blocksFieldname = getBlocksFieldname(formData);
|
|
275
|
+
return {
|
|
276
|
+
...formData,
|
|
277
|
+
[blocksFieldname]: {
|
|
278
|
+
...formData[blocksFieldname],
|
|
279
|
+
[id]: value || null,
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Get the next block UID within form
|
|
286
|
+
* @function nextBlockId
|
|
287
|
+
* @param {Object} formData Form data
|
|
288
|
+
* @param {string} currentBlock Block uid
|
|
289
|
+
* @return {string} Next block uid
|
|
290
|
+
*/
|
|
291
|
+
export function nextBlockId(formData, currentBlock) {
|
|
292
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
|
|
293
|
+
const currentIndex = formData[blocksLayoutFieldname].items.indexOf(
|
|
294
|
+
currentBlock,
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
if (currentIndex === formData[blocksLayoutFieldname].items.length - 1) {
|
|
298
|
+
// We are already at the bottom block don't do anything
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const newIndex = currentIndex + 1;
|
|
303
|
+
return formData[blocksLayoutFieldname].items[newIndex];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Get the previous block UID within form
|
|
308
|
+
* @function previousBlockId
|
|
309
|
+
* @param {Object} formData Form data
|
|
310
|
+
* @param {string} currentBlock Block uid
|
|
311
|
+
* @return {string} Previous block uid
|
|
312
|
+
*/
|
|
313
|
+
export function previousBlockId(formData, currentBlock) {
|
|
314
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
|
|
315
|
+
const currentIndex = formData[blocksLayoutFieldname].items.indexOf(
|
|
316
|
+
currentBlock,
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
if (currentIndex === 0) {
|
|
320
|
+
// We are already at the top block don't do anything
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
const newindex = currentIndex - 1;
|
|
324
|
+
return formData[blocksLayoutFieldname].items[newindex];
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Generate empty block form
|
|
329
|
+
* @function emptyBlocksForm
|
|
330
|
+
* @param {Object} formData Form data
|
|
331
|
+
* @return {Object} Empty blocks form with one defaultBlockType block
|
|
332
|
+
*/
|
|
333
|
+
export function emptyBlocksForm() {
|
|
334
|
+
const { settings } = config;
|
|
335
|
+
const id = uuid();
|
|
336
|
+
return {
|
|
337
|
+
blocks: {
|
|
338
|
+
[id]: {
|
|
339
|
+
'@type': settings.defaultBlockType,
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
blocks_layout: { items: [id] },
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Recursively discover blocks in data and call the provided callback
|
|
348
|
+
* @function visitBlocks
|
|
349
|
+
* @param {Object} content A content data structure (an object with blocks and blocks_layout)
|
|
350
|
+
* @param {Function} callback A function to call on each discovered block
|
|
351
|
+
*/
|
|
352
|
+
export function visitBlocks(content, callback) {
|
|
353
|
+
const queue = getBlocks(content);
|
|
354
|
+
while (queue.length > 0) {
|
|
355
|
+
const [id, blockdata] = queue.shift();
|
|
356
|
+
callback([id, blockdata]);
|
|
357
|
+
|
|
358
|
+
// assumes that a block value is like: {blocks, blocks_layout} or
|
|
359
|
+
// { data: {blocks, blocks_layout}}
|
|
360
|
+
if (Object.keys(blockdata || {}).indexOf('blocks') > -1) {
|
|
361
|
+
queue.push(...getBlocks(blockdata));
|
|
362
|
+
}
|
|
363
|
+
if (Object.keys(blockdata?.data || {}).indexOf('blocks') > -1) {
|
|
364
|
+
queue.push(...getBlocks(blockdata.data));
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Initializes data with the default values coming from schema
|
|
371
|
+
*/
|
|
372
|
+
export function applySchemaDefaults({ data = {}, schema }) {
|
|
373
|
+
const derivedData = {
|
|
374
|
+
...Object.keys(schema.properties).reduce((accumulator, currentField) => {
|
|
375
|
+
return schema.properties[currentField].default
|
|
376
|
+
? {
|
|
377
|
+
...accumulator,
|
|
378
|
+
[currentField]: schema.properties[currentField].default,
|
|
379
|
+
}
|
|
380
|
+
: accumulator;
|
|
381
|
+
}, {}),
|
|
382
|
+
...data,
|
|
383
|
+
};
|
|
384
|
+
return derivedData;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Apply the block's default (as defined in schema) to the block data.
|
|
389
|
+
*
|
|
390
|
+
* @function applyBlockDefaults
|
|
391
|
+
* @param {Object} params An object with data, intl and anything else
|
|
392
|
+
* @return {Object} Derived data, with the defaults extracted from the schema
|
|
393
|
+
*/
|
|
394
|
+
export function applyBlockDefaults({ data = {}, intl, ...rest }, blocksConfig) {
|
|
395
|
+
const block_type = data['@type'];
|
|
396
|
+
const { blockSchema } =
|
|
397
|
+
(blocksConfig || config.blocks.blocksConfig)[block_type] || {};
|
|
398
|
+
if (!blockSchema) return data;
|
|
399
|
+
|
|
400
|
+
let schema =
|
|
401
|
+
typeof blockSchema === 'function'
|
|
402
|
+
? blockSchema({ data, intl, ...rest })
|
|
403
|
+
: blockSchema;
|
|
404
|
+
schema = applySchemaEnhancer({ schema, formData: data, intl });
|
|
405
|
+
|
|
406
|
+
return applySchemaDefaults({ data, schema });
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export const buildStyleClassNamesFromData = (styles) => {
|
|
410
|
+
// styles has the form
|
|
411
|
+
// const styles = {
|
|
412
|
+
// color: 'red',
|
|
413
|
+
// backgroundColor: '#AABBCC',
|
|
414
|
+
// }
|
|
415
|
+
// Returns: ['has--color--red', 'has--backgroundColor--AABBCC']
|
|
416
|
+
let styleArray = [];
|
|
417
|
+
const pairedStyles = toPairs(styles);
|
|
418
|
+
pairedStyles.forEach((item) => {
|
|
419
|
+
if (isObject(item[1])) {
|
|
420
|
+
const flattenedNestedStyles = toPairs(item[1]).map((nested) => [
|
|
421
|
+
item[0],
|
|
422
|
+
...nested,
|
|
423
|
+
]);
|
|
424
|
+
flattenedNestedStyles.forEach((sub) => styleArray.push(sub));
|
|
425
|
+
} else {
|
|
426
|
+
styleArray.push(item);
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
return styleArray.map((item) => {
|
|
430
|
+
const classname = item.map((item) => {
|
|
431
|
+
const str_item = item ? item.toString() : '';
|
|
432
|
+
return str_item && str_item.startsWith('#')
|
|
433
|
+
? str_item.replace('#', '')
|
|
434
|
+
: str_item;
|
|
435
|
+
});
|
|
436
|
+
return `has--${classname[0]}--${classname[1]}${
|
|
437
|
+
classname[2] ? `--${classname[2]}` : ''
|
|
438
|
+
}`;
|
|
439
|
+
});
|
|
440
|
+
};
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { runtimeConfig } from '@plone/volto/runtime_config';
|
|
|
2
2
|
import installCallout from 'volto-slate/editor/plugins/Callout';
|
|
3
3
|
import installItemBlock from '@eeacms/volto-eea-website-policy/components/Blocks/Item';
|
|
4
4
|
import customizeTeaserBlock from '@eeacms/volto-eea-website-policy/components/Blocks/Teaser';
|
|
5
|
+
import installContextNavigationBlock from '@eeacms/volto-eea-website-policy/components/Blocks/ContextNavigation';
|
|
5
6
|
|
|
6
7
|
const applyConfig = (config) => {
|
|
7
8
|
// if (process.env.NODE_ENV === 'production') {
|
|
@@ -99,10 +100,11 @@ const applyConfig = (config) => {
|
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
// Custom blocks
|
|
102
|
-
config = [
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
config = [
|
|
104
|
+
installItemBlock,
|
|
105
|
+
installContextNavigationBlock,
|
|
106
|
+
customizeTeaserBlock,
|
|
107
|
+
].reduce((acc, apply) => apply(acc), config);
|
|
106
108
|
config.blocks.blocksConfig.item.mostUsed = true;
|
|
107
109
|
|
|
108
110
|
// Disable some blocks
|