@eeacms/volto-eea-website-theme 1.22.1 → 1.24.0

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 (25) hide show
  1. package/CHANGELOG.md +42 -10
  2. package/RELEASE.md +14 -14
  3. package/cypress.config.js +3 -3
  4. package/jest-addon.config.js +3 -0
  5. package/package.json +4 -3
  6. package/src/components/manage/Blocks/Title/schema.js +40 -1
  7. package/src/components/theme/Banner/View.jsx +2 -1
  8. package/src/config.js +27 -15
  9. package/src/customizations/@plone/volto-slate/editor/extensions/normalizeExternalData.js +9 -0
  10. package/src/customizations/volto/components/manage/Blocks/Image/Edit.jsx +9 -6
  11. package/src/customizations/volto/components/manage/Blocks/Image/Edit.test.jsx +312 -0
  12. package/src/customizations/volto/components/manage/Blocks/Image/View.jsx +9 -6
  13. package/src/customizations/volto/components/manage/Blocks/LeadImage/Edit.jsx +8 -4
  14. package/src/customizations/volto/components/manage/Blocks/LeadImage/View.jsx +8 -5
  15. package/src/customizations/volto/components/manage/Blocks/LeadImage/schema.js +0 -1
  16. package/src/customizations/volto/components/manage/Form/Form.test.jsx +1124 -0
  17. package/src/customizations/volto/components/manage/Widgets/ObjectBrowserWidget.test.jsx +193 -0
  18. package/src/customizations/volto/components/theme/Comments/Comments.test.jsx +407 -0
  19. package/src/customizations/volto/components/theme/Header/Header.jsx +53 -50
  20. package/src/customizations/volto/components/theme/Header/Header.test.jsx +326 -0
  21. package/src/helpers/schema-utils.js +40 -34
  22. package/src/index.js +122 -15
  23. package/src/index.test.js +343 -0
  24. package/src/customizations/@eeacms/volto-tabs-block/components/templates/default/schema.js +0 -109
  25. package/src/customizations/@eeacms/volto-tabs-block/components/templates/horizontal-responsive/schema.js +0 -109
@@ -0,0 +1,312 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import { Provider } from 'react-intl-redux';
4
+ import configureMockStore from 'redux-mock-store';
5
+ import Edit from './Edit';
6
+ import config from '@plone/volto/registry';
7
+ import '@testing-library/jest-dom/extend-expect';
8
+
9
+ const mockStore = configureMockStore();
10
+ const { settings } = config;
11
+
12
+ let store;
13
+
14
+ config.blocks.blocksConfig = {
15
+ image: {
16
+ id: 'image',
17
+ title: 'Image',
18
+ group: 'media',
19
+ extensions: {},
20
+ variations: [],
21
+ restricted: false,
22
+ mostUsed: true,
23
+ sidebarTab: 1,
24
+ security: {
25
+ addPermission: [],
26
+ view: [],
27
+ },
28
+ },
29
+ };
30
+ const blockId = '1234';
31
+
32
+ describe('Edit', () => {
33
+ beforeEach(() => {
34
+ store = mockStore({
35
+ content: {
36
+ create: {},
37
+ data: {},
38
+ subrequests: {
39
+ [blockId]: {},
40
+ },
41
+ },
42
+ intl: {
43
+ locale: 'en',
44
+ messages: {},
45
+ },
46
+ });
47
+ });
48
+
49
+ it('should render without errors', () => {
50
+ const { container } = render(
51
+ <Provider store={store}>
52
+ <Edit
53
+ data={{
54
+ url: 'http://localhost:8080/Plone/image',
55
+ '@type': 'image',
56
+ align: 'full',
57
+ }}
58
+ selected={false}
59
+ block={blockId}
60
+ content={{}}
61
+ request={{
62
+ loading: false,
63
+ loaded: false,
64
+ }}
65
+ pathname="/news"
66
+ onChangeBlock={() => {}}
67
+ onSelectBlock={() => {}}
68
+ onDeleteBlock={() => {}}
69
+ createContent={() => {}}
70
+ onFocusPreviousBlock={() => {}}
71
+ onFocusNextBlock={() => {}}
72
+ handleKeyDown={() => {}}
73
+ index={1}
74
+ openObjectBrowser={() => {}}
75
+ />
76
+ </Provider>,
77
+ );
78
+
79
+ settings.internalApiPath = 'http://localhost:8080/Plone';
80
+
81
+ expect(container.querySelector('.block.image.align')).toBeInTheDocument();
82
+ expect(
83
+ container.querySelector('.image-block-container'),
84
+ ).toBeInTheDocument();
85
+ expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
86
+ });
87
+
88
+ it('should render without errors', () => {
89
+ const { container } = render(
90
+ <Provider store={store}>
91
+ <Edit
92
+ data={{
93
+ url: 'http://localhost:8080/Plone/image',
94
+ '@type': 'image',
95
+ size: 'l',
96
+ copyright: 'Copyright',
97
+ }}
98
+ selected={false}
99
+ block={blockId}
100
+ content={{}}
101
+ request={{
102
+ loading: false,
103
+ loaded: false,
104
+ }}
105
+ pathname="/news"
106
+ onChangeBlock={() => {}}
107
+ onSelectBlock={() => {}}
108
+ onDeleteBlock={() => {}}
109
+ createContent={() => {}}
110
+ onFocusPreviousBlock={() => {}}
111
+ onFocusNextBlock={() => {}}
112
+ handleKeyDown={() => {}}
113
+ index={1}
114
+ openObjectBrowser={() => {}}
115
+ />
116
+ </Provider>,
117
+ );
118
+
119
+ settings.internalApiPath = 'http://localhost:8080/Plone';
120
+
121
+ expect(container.querySelector('.block.image.align')).toBeInTheDocument();
122
+ expect(
123
+ container.querySelector('.image-block-container'),
124
+ ).toBeInTheDocument();
125
+ expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
126
+ });
127
+
128
+ it('should render without errors', () => {
129
+ const { container } = render(
130
+ <Provider store={store}>
131
+ <Edit
132
+ data={{
133
+ url: 'http://localhost:8080/Plone/image',
134
+ '@type': 'image',
135
+ size: 'm',
136
+ }}
137
+ selected={false}
138
+ block={blockId}
139
+ content={{}}
140
+ request={{
141
+ loading: false,
142
+ loaded: false,
143
+ }}
144
+ pathname="/news"
145
+ onChangeBlock={() => {}}
146
+ onSelectBlock={() => {}}
147
+ onDeleteBlock={() => {}}
148
+ createContent={() => {}}
149
+ onFocusPreviousBlock={() => {}}
150
+ onFocusNextBlock={() => {}}
151
+ handleKeyDown={() => {}}
152
+ index={1}
153
+ openObjectBrowser={() => {}}
154
+ />
155
+ </Provider>,
156
+ );
157
+
158
+ settings.internalApiPath = 'http://localhost:8080/Plone';
159
+
160
+ expect(container.querySelector('.block.image.align')).toBeInTheDocument();
161
+ expect(
162
+ container.querySelector('.image-block-container'),
163
+ ).toBeInTheDocument();
164
+ expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
165
+ });
166
+
167
+ it('should render without errors', () => {
168
+ const { container } = render(
169
+ <Provider store={store}>
170
+ <Edit
171
+ data={{
172
+ url: 'http://localhost:8080/Plone/image',
173
+ '@type': 'image',
174
+ size: 's',
175
+ }}
176
+ selected={false}
177
+ block={blockId}
178
+ content={{}}
179
+ request={{
180
+ loading: false,
181
+ loaded: false,
182
+ }}
183
+ pathname="/news"
184
+ onChangeBlock={() => {}}
185
+ onSelectBlock={() => {}}
186
+ onDeleteBlock={() => {}}
187
+ createContent={() => {}}
188
+ onFocusPreviousBlock={() => {}}
189
+ onFocusNextBlock={() => {}}
190
+ handleKeyDown={() => {}}
191
+ index={1}
192
+ openObjectBrowser={() => {}}
193
+ />
194
+ </Provider>,
195
+ );
196
+
197
+ settings.internalApiPath = 'http://localhost:8080/Plone';
198
+
199
+ expect(container.querySelector('.block.image.align')).toBeInTheDocument();
200
+ expect(
201
+ container.querySelector('.image-block-container'),
202
+ ).toBeInTheDocument();
203
+ expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
204
+ });
205
+
206
+ it('should render without errors', () => {
207
+ const { container } = render(
208
+ <Provider store={store}>
209
+ <Edit
210
+ data={{
211
+ url: 'http://localhost:8080/Plone/image',
212
+ '@type': 'image',
213
+ }}
214
+ selected={false}
215
+ block={blockId}
216
+ content={{}}
217
+ request={{
218
+ loading: false,
219
+ loaded: false,
220
+ }}
221
+ pathname="/news"
222
+ onChangeBlock={() => {}}
223
+ onSelectBlock={() => {}}
224
+ onDeleteBlock={() => {}}
225
+ createContent={() => {}}
226
+ onFocusPreviousBlock={() => {}}
227
+ onFocusNextBlock={() => {}}
228
+ handleKeyDown={() => {}}
229
+ index={1}
230
+ openObjectBrowser={() => {}}
231
+ />
232
+ </Provider>,
233
+ );
234
+
235
+ settings.internalApiPath = 'http://localhost:8080/Plone';
236
+
237
+ expect(container.querySelector('.block.image.align')).toBeInTheDocument();
238
+ expect(
239
+ container.querySelector('.image-block-container'),
240
+ ).toBeInTheDocument();
241
+ expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
242
+ });
243
+
244
+ it('should render without errors', () => {
245
+ const { container } = render(
246
+ <Provider store={store}>
247
+ <Edit
248
+ data={{
249
+ url: 'http://localhost:80801/Plone/image',
250
+ '@type': 'image',
251
+ }}
252
+ selected={false}
253
+ block={blockId}
254
+ content={{}}
255
+ request={{
256
+ loading: false,
257
+ loaded: false,
258
+ }}
259
+ pathname="/news"
260
+ onChangeBlock={() => {}}
261
+ onSelectBlock={() => {}}
262
+ onDeleteBlock={() => {}}
263
+ createContent={() => {}}
264
+ onFocusPreviousBlock={() => {}}
265
+ onFocusNextBlock={() => {}}
266
+ handleKeyDown={() => {}}
267
+ index={1}
268
+ openObjectBrowser={() => {}}
269
+ />
270
+ </Provider>,
271
+ );
272
+
273
+ settings.internalApiPath = 'http://localhost:8080/Plone';
274
+
275
+ expect(container.querySelector('.block.image.align')).toBeInTheDocument();
276
+ expect(
277
+ container.querySelector('.image-block-container'),
278
+ ).toBeInTheDocument();
279
+ expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
280
+ });
281
+
282
+ it('should render without errors', () => {
283
+ render(
284
+ <Provider store={store}>
285
+ <Edit
286
+ data={{
287
+ url: undefined,
288
+ '@type': 'image',
289
+ }}
290
+ selected={false}
291
+ block={blockId}
292
+ content={{}}
293
+ request={{
294
+ loading: false,
295
+ loaded: false,
296
+ }}
297
+ editable={true}
298
+ pathname="/news"
299
+ onChangeBlock={() => {}}
300
+ onSelectBlock={() => {}}
301
+ onDeleteBlock={() => {}}
302
+ createContent={() => {}}
303
+ onFocusPreviousBlock={() => {}}
304
+ onFocusNextBlock={() => {}}
305
+ handleKeyDown={() => {}}
306
+ index={1}
307
+ openObjectBrowser={() => {}}
308
+ />
309
+ </Provider>,
310
+ );
311
+ });
312
+ });
@@ -61,12 +61,15 @@ export const View = (props) => {
61
61
  const image = (
62
62
  <>
63
63
  <img
64
- className={cx({
65
- 'full-width': data.align === 'full',
66
- large: data.size === 'l',
67
- medium: data.size === 'm',
68
- small: data.size === 's',
69
- })}
64
+ className={cx(
65
+ {
66
+ 'full-width': data.align === 'full',
67
+ large: data.size === 'l',
68
+ medium: data.size === 'm',
69
+ small: data.size === 's',
70
+ },
71
+ data?.styles?.objectPosition,
72
+ )}
70
73
  src={
71
74
  isInternalURL(data.url)
72
75
  ? // Backwards compat in the case that the block is storing the full server URL
@@ -84,8 +84,7 @@ class Edit extends Component {
84
84
  const placeholder =
85
85
  this.props.data.placeholder ||
86
86
  this.props.intl.formatMessage(messages.ImageBlockInputPlaceholder);
87
- const { copyright, copyrightIcon, copyrightPosition } = data;
88
-
87
+ const { copyright, copyrightIcon, copyrightPosition, styles } = data;
89
88
  return (
90
89
  <div
91
90
  className={cx(
@@ -97,7 +96,9 @@ class Edit extends Component {
97
96
  )}
98
97
  >
99
98
  <div
100
- className={`image-block-container ${data?.align ? data?.align : ''}`}
99
+ className={cx(
100
+ `image-block-container ${data?.align ? data?.align : ''}`,
101
+ )}
101
102
  >
102
103
  {!properties.image && (
103
104
  <Message>
@@ -110,7 +111,10 @@ class Edit extends Component {
110
111
  {properties.image && (
111
112
  <div className="image-block">
112
113
  <img
113
- className={cx({ 'full-width': data.align === 'full' })}
114
+ className={cx(
115
+ { 'full-width': data.align === 'full' },
116
+ styles?.objectPosition,
117
+ )}
114
118
  src={
115
119
  properties.image.data
116
120
  ? `data:${properties.image['content-type']};base64,${properties.image.data}`
@@ -18,7 +18,7 @@ import { flattenToAppURL } from '@plone/volto/helpers';
18
18
  */
19
19
  const View = (props) => {
20
20
  const { data, properties } = props;
21
- const { copyright, copyrightIcon, copyrightPosition } = data;
21
+ const { copyright, copyrightIcon, copyrightPosition, styles } = data;
22
22
 
23
23
  // const [hovering, setHovering] = React.useState(false);
24
24
  const [viewLoaded, setViewLoaded] = React.useState(false);
@@ -40,9 +40,9 @@ const View = (props) => {
40
40
  )}
41
41
  >
42
42
  <div
43
- className={`image-block-container ${
44
- data?.align ? data?.align : ''
45
- }`}
43
+ className={cx(
44
+ `image-block-container ${data?.align ? data?.align : ''}`,
45
+ )}
46
46
  >
47
47
  {properties.image && (
48
48
  <>
@@ -50,7 +50,10 @@ const View = (props) => {
50
50
  const image = (
51
51
  <div className="image-block">
52
52
  <img
53
- className={cx({ 'full-width': data.align === 'full' })}
53
+ className={cx(
54
+ { 'full-width': data.align === 'full' },
55
+ styles?.objectPosition,
56
+ )}
54
57
  src={flattenToAppURL(properties.image.download)}
55
58
  alt={properties.image_caption || ''}
56
59
  />
@@ -42,7 +42,6 @@ const messages = defineMessages({
42
42
  defaultMessage: 'External URL',
43
43
  },
44
44
  });
45
-
46
45
  export function LeadImageSchema({ formData, intl }) {
47
46
  return {
48
47
  fieldsets: [