@eeacms/volto-bise-policy 1.0.0 → 1.0.1

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 (105) hide show
  1. package/CHANGELOG.md +15 -2
  2. package/package.json +3 -1
  3. package/src/components/manage/Blocks/NewsletterSignup/Edit.jsx +30 -0
  4. package/src/components/manage/Blocks/NewsletterSignup/View.jsx +13 -0
  5. package/src/components/manage/Blocks/NewsletterSignup/index.js +49 -0
  6. package/src/components/manage/Blocks/NewsletterSignup/schema.js +25 -0
  7. package/src/components/manage/Blocks/index.js +2 -0
  8. package/src/customizations/@eeacms/volto-eea-design-system/ui/Header/HeaderMenuPopUp.js +354 -0
  9. package/src/customizations/@eeacms/volto-eea-website-theme/components/theme/SubsiteClass.jsx +70 -0
  10. package/src/customizations/volto/components/manage/Edit/Edit.jsx +519 -0
  11. package/src/customizations/volto/components/manage/Form/BlockDataForm.jsx +28 -0
  12. package/src/customizations/volto/components/manage/Form/BlocksToolbar.jsx +214 -0
  13. package/src/customizations/volto/components/manage/Form/Field.jsx +269 -0
  14. package/src/customizations/volto/components/manage/Form/Form.jsx +804 -0
  15. package/src/customizations/volto/components/theme/Header/Header.jsx +151 -131
  16. package/src/index.js +31 -5
  17. package/theme/collections/message.overrides +10 -0
  18. package/theme/elements/container.overrides +156 -0
  19. package/theme/elements/segment.variables +1 -0
  20. package/theme/extras/header.overrides +107 -13
  21. package/theme/extras/header.variables +12 -0
  22. package/theme/extras/keyfacts.less +3 -3
  23. package/theme/extras/pluggables.less +17 -16
  24. package/theme/fonts/OpenSans-Bold.ttf +0 -0
  25. package/theme/fonts/OpenSans-Regular.ttf +0 -0
  26. package/theme/fonts/OpenSans-Semibold.ttf +0 -0
  27. package/theme/fonts/Rajdhani-Bold.ttf +0 -0
  28. package/theme/fonts/Rajdhani-Regular.ttf +0 -0
  29. package/theme/globals/helpers.less +75 -0
  30. package/theme/globals/natura2000.less +53 -0
  31. package/theme/globals/site.overrides +204 -4
  32. package/theme/globals/site.variables +5 -0
  33. package/theme/modules/accordion.overrides +3 -0
  34. package/theme/modules/accordion.variables +7 -0
  35. package/theme/modules/tab.overrides +176 -0
  36. package/theme/theme.config +1 -0
  37. package/theme/views/card.variables +2 -0
  38. package/locales/bg/LC_MESSAGES/volto.po +0 -14
  39. package/locales/bg.json +0 -1
  40. package/locales/bs/LC_MESSAGES/volto.po +0 -14
  41. package/locales/bs.json +0 -1
  42. package/locales/cs/LC_MESSAGES/volto.po +0 -14
  43. package/locales/cs.json +0 -1
  44. package/locales/da/LC_MESSAGES/volto.po +0 -14
  45. package/locales/da.json +0 -1
  46. package/locales/de/LC_MESSAGES/volto.po +0 -29
  47. package/locales/de.json +0 -1
  48. package/locales/el/LC_MESSAGES/volto.po +0 -14
  49. package/locales/el.json +0 -1
  50. package/locales/en/LC_MESSAGES/volto.po +0 -14
  51. package/locales/en.json +0 -1
  52. package/locales/es/LC_MESSAGES/volto.po +0 -24
  53. package/locales/es.json +0 -1
  54. package/locales/et/LC_MESSAGES/volto.po +0 -14
  55. package/locales/et.json +0 -1
  56. package/locales/eu/LC_MESSAGES/volto.po +0 -19
  57. package/locales/eu.json +0 -1
  58. package/locales/fi/LC_MESSAGES/volto.po +0 -14
  59. package/locales/fi.json +0 -1
  60. package/locales/fr/LC_MESSAGES/volto.po +0 -29
  61. package/locales/fr.json +0 -1
  62. package/locales/ga/LC_MESSAGES/volto.po +0 -14
  63. package/locales/ga.json +0 -1
  64. package/locales/hr/LC_MESSAGES/volto.po +0 -14
  65. package/locales/hr.json +0 -1
  66. package/locales/hu/LC_MESSAGES/volto.po +0 -14
  67. package/locales/hu.json +0 -1
  68. package/locales/is/LC_MESSAGES/volto.po +0 -14
  69. package/locales/is.json +0 -1
  70. package/locales/it/LC_MESSAGES/volto.po +0 -14
  71. package/locales/it.json +0 -1
  72. package/locales/ja/LC_MESSAGES/volto.po +0 -21
  73. package/locales/ja.json +0 -1
  74. package/locales/lt/LC_MESSAGES/volto.po +0 -14
  75. package/locales/lt.json +0 -1
  76. package/locales/lv/LC_MESSAGES/volto.po +0 -14
  77. package/locales/lv.json +0 -1
  78. package/locales/mk/LC_MESSAGES/volto.po +0 -14
  79. package/locales/mk.json +0 -1
  80. package/locales/mt/LC_MESSAGES/volto.po +0 -14
  81. package/locales/mt.json +0 -1
  82. package/locales/nl/LC_MESSAGES/volto.po +0 -33
  83. package/locales/nl.json +0 -1
  84. package/locales/no/LC_MESSAGES/volto.po +0 -14
  85. package/locales/no.json +0 -1
  86. package/locales/pl/LC_MESSAGES/volto.po +0 -14
  87. package/locales/pl.json +0 -1
  88. package/locales/pt/LC_MESSAGES/volto.po +0 -22
  89. package/locales/pt.json +0 -1
  90. package/locales/pt_BR/LC_MESSAGES/volto.po +0 -20
  91. package/locales/pt_BR.json +0 -1
  92. package/locales/ro/LC_MESSAGES/volto.po +0 -20
  93. package/locales/ro.json +0 -1
  94. package/locales/sh/LC_MESSAGES/volto.po +0 -14
  95. package/locales/sh.json +0 -1
  96. package/locales/sk/LC_MESSAGES/volto.po +0 -14
  97. package/locales/sk.json +0 -1
  98. package/locales/sl/LC_MESSAGES/volto.po +0 -14
  99. package/locales/sl.json +0 -1
  100. package/locales/sq/LC_MESSAGES/volto.po +0 -14
  101. package/locales/sq.json +0 -1
  102. package/locales/sv/LC_MESSAGES/volto.po +0 -14
  103. package/locales/sv.json +0 -1
  104. package/locales/tr/LC_MESSAGES/volto.po +0 -14
  105. package/locales/tr.json +0 -1
@@ -0,0 +1,214 @@
1
+ import React from 'react';
2
+ import { compose } from 'redux';
3
+ import { connect } from 'react-redux';
4
+ import { injectIntl } from 'react-intl';
5
+ import {
6
+ messages,
7
+ getBlocksFieldname,
8
+ getBlocksLayoutFieldname,
9
+ } from '@plone/volto/helpers';
10
+ import { Icon } from '@plone/volto/components';
11
+ import { Plug } from '@plone/volto/components/manage/Pluggable';
12
+ import { v4 as uuid } from 'uuid';
13
+ import { load } from 'redux-localstorage-simple';
14
+ import { isEqual, omit, without } from 'lodash';
15
+
16
+ import { setBlocksClipboard, resetBlocksClipboard } from '@plone/volto/actions';
17
+ import config from '@plone/volto/registry';
18
+
19
+ import copySVG from '@plone/volto/icons/copy.svg';
20
+ import cutSVG from '@plone/volto/icons/cut.svg';
21
+ import pasteSVG from '@plone/volto/icons/paste.svg';
22
+ import trashSVG from '@plone/volto/icons/delete.svg';
23
+
24
+ export class BlocksToolbarComponent extends React.Component {
25
+ constructor(props) {
26
+ super(props);
27
+
28
+ this.copyBlocksToClipboard = this.copyBlocksToClipboard.bind(this);
29
+ this.cutBlocksToClipboard = this.cutBlocksToClipboard.bind(this);
30
+ this.deleteBlocks = this.deleteBlocks.bind(this);
31
+ this.loadFromStorage = this.loadFromStorage.bind(this);
32
+ this.pasteBlocks = this.pasteBlocks.bind(this);
33
+ this.setBlocksClipboard = this.setBlocksClipboard.bind(this);
34
+ }
35
+
36
+ loadFromStorage() {
37
+ const clipboard = load({ states: ['blocksClipboard'] })?.blocksClipboard;
38
+ if (!isEqual(clipboard, this.props.blocksClipboard))
39
+ this.props.setBlocksClipboard(clipboard || {});
40
+ }
41
+
42
+ componentDidMount() {
43
+ window.addEventListener('storage', this.loadFromStorage, true);
44
+ }
45
+
46
+ componentWillUnmount() {
47
+ window.removeEventListener('storage', this.loadFromStorage);
48
+ }
49
+
50
+ deleteBlocks() {
51
+ const blockIds = this.props.selectedBlocks;
52
+
53
+ const { formData } = this.props;
54
+ const blocksFieldname = getBlocksFieldname(formData);
55
+ const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
56
+
57
+ // Might need ReactDOM.unstable_batchedUpdates()
58
+ this.props.onSelectBlock(null);
59
+ const newBlockData = {
60
+ [blocksFieldname]: omit(formData[blocksFieldname], blockIds),
61
+ [blocksLayoutFieldname]: {
62
+ ...formData[blocksLayoutFieldname],
63
+ items: without(formData[blocksLayoutFieldname].items, ...blockIds),
64
+ },
65
+ };
66
+ this.props.onChangeBlocks(newBlockData);
67
+ }
68
+
69
+ copyBlocksToClipboard() {
70
+ this.setBlocksClipboard('copy');
71
+ }
72
+
73
+ cutBlocksToClipboard() {
74
+ this.setBlocksClipboard('cut');
75
+ this.deleteBlocks();
76
+ }
77
+
78
+ setBlocksClipboard(actionType) {
79
+ const { formData } = this.props;
80
+ const blocksFieldname = getBlocksFieldname(formData);
81
+ const blocks = formData[blocksFieldname];
82
+ const blocksData = this.props.selectedBlocks.map(
83
+ (blockId) => blocks[blockId],
84
+ );
85
+ this.props.setBlocksClipboard({ [actionType]: blocksData });
86
+ this.props.onSetSelectedBlocks([]);
87
+ }
88
+
89
+ pasteBlocks(e) {
90
+ const { formData, blocksClipboard = {}, selectedBlock } = this.props;
91
+ const mode = Object.keys(blocksClipboard).includes('cut') ? 'cut' : 'copy';
92
+ const blocksData = blocksClipboard[mode] || [];
93
+ const cloneWithIds = blocksData
94
+ .filter((blockData) => !!blockData['@type'])
95
+ .map((blockData) => {
96
+ const blockConfig = config.blocks.blocksConfig[blockData['@type']];
97
+ return mode === 'copy'
98
+ ? blockConfig.cloneData
99
+ ? blockConfig.cloneData(blockData)
100
+ : [uuid(), blockData]
101
+ : [uuid(), blockData]; // if cut/pasting blocks, we don't clone
102
+ })
103
+ .filter((info) => !!info); // some blocks may refuse to be copied
104
+ const blocksFieldname = getBlocksFieldname(formData);
105
+ const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
106
+ const selectedIndex =
107
+ formData[blocksLayoutFieldname].items.indexOf(selectedBlock) + 1;
108
+
109
+ const newBlockData = {
110
+ [blocksFieldname]: {
111
+ ...formData[blocksFieldname],
112
+ ...Object.assign(
113
+ {},
114
+ ...cloneWithIds.map(([id, data]) => ({ [id]: data })),
115
+ ),
116
+ },
117
+ [blocksLayoutFieldname]: {
118
+ ...formData[blocksLayoutFieldname],
119
+ items: [
120
+ ...formData[blocksLayoutFieldname].items.slice(0, selectedIndex),
121
+ ...cloneWithIds.map(([id]) => id),
122
+ ...formData[blocksLayoutFieldname].items.slice(selectedIndex),
123
+ ],
124
+ },
125
+ };
126
+
127
+ if (!(e.ctrlKey || e.metaKey)) this.props.resetBlocksClipboard();
128
+ this.props.onChangeBlocks(newBlockData);
129
+ }
130
+
131
+ render() {
132
+ const {
133
+ blocksClipboard = {},
134
+ selectedBlock,
135
+ selectedBlocks,
136
+ intl,
137
+ } = this.props;
138
+ return (
139
+ <>
140
+ {selectedBlocks.length > 0 ? (
141
+ <>
142
+ <Plug pluggable="main.toolbar.bottom" id="blocks-delete-btn">
143
+ <button
144
+ aria-label={intl.formatMessage(messages.deleteBlocks)}
145
+ onClick={this.deleteBlocks}
146
+ tabIndex={0}
147
+ className="deleteBlocks"
148
+ id="toolbar-delete-blocks"
149
+ >
150
+ <Icon name={trashSVG} size="30px" />
151
+ </button>
152
+ </Plug>
153
+ <Plug pluggable="main.toolbar.bottom" id="blocks-cut-btn">
154
+ <button
155
+ aria-label={intl.formatMessage(messages.cutBlocks)}
156
+ onClick={this.cutBlocksToClipboard}
157
+ tabIndex={0}
158
+ className="cutBlocks"
159
+ id="toolbar-cut-blocks"
160
+ >
161
+ <Icon name={cutSVG} size="30px" />
162
+ </button>
163
+ </Plug>
164
+ <Plug pluggable="main.toolbar.bottom" id="blocks-copy-btn">
165
+ <button
166
+ aria-label={intl.formatMessage(messages.copyBlocks)}
167
+ onClick={this.copyBlocksToClipboard}
168
+ tabIndex={0}
169
+ className="copyBlocks"
170
+ id="toolbar-copy-blocks"
171
+ >
172
+ <Icon name={copySVG} size="30px" />
173
+ </button>
174
+ </Plug>
175
+ </>
176
+ ) : (
177
+ ''
178
+ )}
179
+ {selectedBlock && (blocksClipboard?.cut || blocksClipboard?.copy) && (
180
+ <Plug
181
+ pluggable="main.toolbar.bottom"
182
+ id="block-paste-btn"
183
+ dependencies={[selectedBlock]}
184
+ >
185
+ <button
186
+ aria-label={intl.formatMessage(messages.pasteBlocks)}
187
+ onClick={this.pasteBlocks}
188
+ tabIndex={0}
189
+ className="pasteBlocks"
190
+ id="toolbar-paste-blocks"
191
+ >
192
+ <span className="blockCount">
193
+ {(blocksClipboard.cut || blocksClipboard.copy).length}
194
+ </span>
195
+ <Icon name={pasteSVG} size="30px" />
196
+ </button>
197
+ </Plug>
198
+ )}
199
+ </>
200
+ );
201
+ }
202
+ }
203
+
204
+ export default compose(
205
+ injectIntl,
206
+ connect(
207
+ (state) => {
208
+ return {
209
+ blocksClipboard: state?.blocksClipboard || {},
210
+ };
211
+ },
212
+ { setBlocksClipboard, resetBlocksClipboard },
213
+ ),
214
+ )(BlocksToolbarComponent);
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Field component.
3
+ * @module components/manage/Form/Field
4
+ */
5
+
6
+ import React from 'react';
7
+ import PropTypes from 'prop-types';
8
+ import { injectIntl } from 'react-intl';
9
+ import config from '@plone/volto/registry';
10
+ import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
11
+
12
+ const MODE_HIDDEN = 'hidden'; //hidden mode. If mode is hidden, field is not rendered
13
+ /**
14
+ * Get default widget
15
+ * @method getViewDefault
16
+ * @returns {string} Widget component.
17
+ */
18
+ const getWidgetDefault = () => config.widgets.default;
19
+
20
+ /**
21
+ * Get widget by field's `id` attribute
22
+ * @method getWidgetById
23
+ * @param {string} id Id
24
+ * @returns {string} Widget component.
25
+ */
26
+ const getWidgetByFieldId = (id) => config.widgets.id[id] || null;
27
+
28
+ /**
29
+ * Get widget by factory attribute
30
+ * @method getWidgetByFactory
31
+ * @param {string} id Id
32
+ * @returns {string} Widget component.
33
+ */
34
+ const getWidgetByFactory = (factory) =>
35
+ config.widgets.factory?.[factory] || null;
36
+
37
+ /**
38
+ * Get widget by field's `widget` attribute
39
+ * @method getWidgetByName
40
+ * @param {string} widget Widget
41
+ * @returns {string} Widget component.
42
+ */
43
+ const getWidgetByName = (widget) =>
44
+ typeof widget === 'string'
45
+ ? config.widgets.widget[widget] || getWidgetDefault()
46
+ : null;
47
+
48
+ /**
49
+ * Get widget by tagged values
50
+ * @param {object} widgetOptions
51
+ * @returns {string} Widget component.
52
+ *
53
+
54
+ directives.widget(
55
+ 'fieldname',
56
+ frontendOptions={
57
+ "widget": 'specialwidget',
58
+ "version": 'extra'
59
+ })
60
+
61
+ */
62
+ const getWidgetFromTaggedValues = (widgetOptions) =>
63
+ typeof widgetOptions?.frontendOptions?.widget === 'string'
64
+ ? config.widgets.widget[widgetOptions.frontendOptions.widget]
65
+ : null;
66
+
67
+ /**
68
+ * Get widget props from tagged values
69
+ * @param {object} widgetOptions
70
+ * @returns {string} Widget component.
71
+ *
72
+
73
+ directives.widget(
74
+ "fieldname",
75
+ frontendOptions={
76
+ "widget": "specialwidget",
77
+ "widgetProps": {"prop1": "specialprop"}
78
+ })
79
+
80
+ */
81
+ const getWidgetPropsFromTaggedValues = (widgetOptions) =>
82
+ typeof widgetOptions?.frontendOptions?.widgetProps === 'object'
83
+ ? widgetOptions.frontendOptions.widgetProps
84
+ : null;
85
+
86
+ /**
87
+ * Get widget by field's `vocabulary` attribute
88
+ * @method getWidgetByVocabulary
89
+ * @param {string} vocabulary Widget
90
+ * @returns {string} Widget component.
91
+ */
92
+ const getWidgetByVocabulary = (vocabulary) =>
93
+ vocabulary && vocabulary['@id']
94
+ ? config.widgets.vocabulary[
95
+ vocabulary['@id'].replace(/^.*\/@vocabularies\//, '')
96
+ ]
97
+ : null;
98
+
99
+ /**
100
+ * Get widget by field's hints `vocabulary` attribute in widgetOptions
101
+ * @method getWidgetByVocabularyFromHint
102
+ * @param {string} props Widget props
103
+ * @returns {string} Widget component.
104
+ */
105
+ const getWidgetByVocabularyFromHint = (props) =>
106
+ props.widgetOptions && props.widgetOptions.vocabulary
107
+ ? config.widgets.vocabulary[
108
+ props.widgetOptions.vocabulary['@id'].replace(
109
+ /^.*\/@vocabularies\//,
110
+ '',
111
+ )
112
+ ]
113
+ : null;
114
+
115
+ /**
116
+ * Get widget by field's `choices` attribute
117
+ * @method getWidgetByChoices
118
+ * @param {string} choices Widget
119
+ * @returns {string} Widget component.
120
+ */
121
+ const getWidgetByChoices = (props) => {
122
+ if (props.choices) {
123
+ return config.widgets.choices;
124
+ }
125
+
126
+ if (props.vocabulary) {
127
+ // If vocabulary exists, then it means it's a choice field in disguise with
128
+ // no widget specified that probably contains a string then we force it
129
+ // to be a select widget instead
130
+ return config.widgets.choices;
131
+ }
132
+
133
+ return null;
134
+ };
135
+
136
+ /**
137
+ * Get widget by field's `type` attribute
138
+ * @method getWidgetByType
139
+ * @param {string} type Type
140
+ * @returns {string} Widget component.
141
+ */
142
+ const getWidgetByType = (type) => config.widgets.type[type] || null;
143
+
144
+ /**
145
+ * Field component class.
146
+ * @function Field
147
+ * @param {Object} props Properties.
148
+ * @returns {string} Markup of the component.
149
+ */
150
+ const UnconnectedField = (props, { intl }) => {
151
+ const Widget =
152
+ getWidgetByFieldId(props.id) ||
153
+ getWidgetFromTaggedValues(props.widgetOptions) ||
154
+ getWidgetByName(props.widget) ||
155
+ getWidgetByChoices(props) ||
156
+ getWidgetByVocabulary(props.vocabulary) ||
157
+ getWidgetByVocabularyFromHint(props) ||
158
+ getWidgetByFactory(props.factory) ||
159
+ getWidgetByType(props.type) ||
160
+ getWidgetDefault();
161
+
162
+ if (props.mode === MODE_HIDDEN) {
163
+ return null;
164
+ }
165
+
166
+ // Adding the widget props from tagged values (if any)
167
+ const widgetProps = {
168
+ ...props,
169
+ ...getWidgetPropsFromTaggedValues(props.widgetOptions),
170
+ };
171
+
172
+ if (props.onOrder) {
173
+ const { DropTarget, DragSource } = props.reactDnd;
174
+ const WrappedWidget = DropTarget(
175
+ 'field',
176
+ {
177
+ hover(properties, monitor) {
178
+ const dragOrder = monitor.getItem().order;
179
+ const hoverOrder = properties.order;
180
+
181
+ if (dragOrder === hoverOrder) {
182
+ return;
183
+ }
184
+ properties.onOrder(dragOrder, hoverOrder - dragOrder);
185
+
186
+ monitor.getItem().order = hoverOrder;
187
+ },
188
+ },
189
+ (connect) => ({
190
+ connectDropTarget: connect.dropTarget(),
191
+ }),
192
+ )(
193
+ DragSource(
194
+ 'field',
195
+ {
196
+ beginDrag(properties) {
197
+ return {
198
+ id: properties.label,
199
+ order: properties.order,
200
+ };
201
+ },
202
+ },
203
+ (connect, monitor) => ({
204
+ connectDragSource: connect.dragSource(),
205
+ connectDragPreview: connect.dragPreview(),
206
+ isDragging: monitor.isDragging(),
207
+ }),
208
+ )(
209
+ ({
210
+ connectDropTarget,
211
+ connectDragSource,
212
+ connectDragPreview,
213
+ ...rest
214
+ }) =>
215
+ connectDropTarget(
216
+ connectDragSource(
217
+ connectDragPreview(
218
+ <div>
219
+ <Widget {...rest} />
220
+ </div>,
221
+ ),
222
+ ),
223
+ ),
224
+ ),
225
+ );
226
+ return <WrappedWidget {...widgetProps} />;
227
+ }
228
+ return <Widget {...widgetProps} />;
229
+ };
230
+
231
+ const DndConnectedField = injectLazyLibs(['reactDnd'])(UnconnectedField);
232
+
233
+ const Field = (props) =>
234
+ props.onOrder ? (
235
+ <DndConnectedField {...props} />
236
+ ) : (
237
+ <UnconnectedField {...props} />
238
+ );
239
+
240
+ /**
241
+ * Property types.
242
+ * @property {Object} propTypes Property types.
243
+ * @static
244
+ */
245
+ Field.propTypes = {
246
+ widget: PropTypes.string,
247
+ vocabulary: PropTypes.shape({ '@id': PropTypes.string }),
248
+ choices: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)),
249
+ type: PropTypes.string,
250
+ id: PropTypes.string.isRequired,
251
+ focus: PropTypes.bool,
252
+ onOrder: PropTypes.func,
253
+ };
254
+
255
+ /**
256
+ * Default properties.
257
+ * @property {Object} defaultProps Default properties.
258
+ * @static
259
+ */
260
+ Field.defaultProps = {
261
+ widget: null,
262
+ vocabulary: null,
263
+ choices: null,
264
+ type: 'string',
265
+ focus: false,
266
+ onOrder: null,
267
+ };
268
+
269
+ export default injectIntl(Field);