@eeacms/volto-eea-website-theme 3.19.1 → 4.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.
- package/.eslintrc.js +7 -6
- package/CHANGELOG.md +26 -0
- package/DEVELOP.md +19 -17
- package/README.md +19 -7
- package/docker-compose.yml +1 -1
- package/jest-addon.config.js +8 -4
- package/package.json +1 -1
- package/src/actions/navigation.js +1 -1
- package/src/components/manage/Blocks/ContextNavigation/ContextNavigationEdit.jsx +4 -2
- package/src/components/manage/Blocks/ContextNavigation/ContextNavigationEdit.test.jsx +25 -19
- package/src/components/manage/Blocks/ContextNavigation/ContextNavigationView.jsx +2 -1
- package/src/components/manage/Blocks/ContextNavigation/ContextNavigationView.test.jsx +6 -4
- package/src/components/manage/Blocks/ContextNavigation/variations/Accordion.jsx +2 -2
- package/src/components/manage/Blocks/ContextNavigation/variations/ReportNavigation.jsx +4 -2
- package/src/components/manage/Blocks/ContextNavigation/variations/ReportNavigation.test.jsx +1 -1
- package/src/components/manage/Blocks/GroupBlockTemplate/FlexGroup/FlexGroup.jsx +12 -44
- package/src/components/manage/Blocks/GroupBlockTemplate/FlexGroup/RenderBlocks.jsx +5 -4
- package/src/components/manage/Blocks/GroupBlockTemplate/FlexGroup/editor-flex.less +45 -4
- package/src/components/manage/Blocks/LayoutSettings/LayoutSettingsEdit.jsx +2 -1
- package/src/components/manage/Blocks/LayoutSettings/LayoutSettingsEdit.test.jsx +12 -4
- package/src/components/manage/Blocks/LayoutSettings/LayoutSettingsView.jsx +1 -1
- package/src/components/manage/Blocks/Title/Edit.jsx +3 -3
- package/src/components/manage/Blocks/Title/View.jsx +2 -1
- package/src/components/manage/Blocks/Title/variations/WebReport.jsx +2 -2
- package/src/components/manage/Blocks/Title/variations/WebReport.test.jsx +6 -4
- package/src/components/manage/Blocks/Title/variations/WebReportPage.jsx +2 -2
- package/src/components/manage/Blocks/Title/variations/WebReportPage.test.jsx +6 -4
- package/src/components/theme/Banner/View.jsx +1 -1
- package/src/components/theme/BaseTag.jsx +2 -1
- package/src/components/theme/BaseTag.test.jsx +7 -2
- package/src/components/theme/DraftBackground/DraftBackground.jsx +2 -1
- package/src/components/theme/Homepage/HomePageInverseView.jsx +3 -3
- package/src/components/theme/Homepage/HomePageInverseView.test.jsx +1 -1
- package/src/components/theme/Homepage/HomePageView.jsx +3 -3
- package/src/components/theme/Homepage/HomePageView.test.jsx +1 -1
- package/src/components/theme/Logo.jsx +3 -3
- package/src/components/theme/NotFound/GoneView.jsx +3 -2
- package/src/components/theme/NotFound/GoneView.test.jsx +5 -4
- package/src/components/theme/NotFound/NotFound.jsx +1 -1
- package/src/components/theme/NotFound/NotFound.test.jsx +3 -2
- package/src/components/theme/PrintLoader/PrintLoader.test.jsx +1 -1
- package/src/components/theme/SubsiteClass.jsx +6 -4
- package/src/components/theme/SubsiteClass.test.jsx +3 -2
- package/src/components/theme/WebReport/WebReportSectionView.jsx +2 -2
- package/src/components/theme/WebReport/WebReportSectionView.test.jsx +10 -5
- package/src/components/theme/Widgets/ADUserGroupSelectWidget.jsx +2 -2
- package/src/components/theme/Widgets/ContributorsViewWidget.jsx +1 -1
- package/src/components/theme/Widgets/CreatableSelectWidget.jsx +7 -4
- package/src/components/theme/Widgets/CreatorsViewWidget.jsx +1 -1
- package/src/components/theme/Widgets/DateWidget.jsx +1 -1
- package/src/components/theme/Widgets/DateWidget.test.js +1 -1
- package/src/components/theme/Widgets/DatetimeWidget.jsx +1 -1
- package/src/components/theme/Widgets/DatetimeWidget.test.js +1 -1
- package/src/components/theme/Widgets/ImageViewWidget.jsx +1 -0
- package/src/components/theme/Widgets/NavigationBehaviorWidget.jsx +7 -3
- package/src/components/theme/Widgets/NavigationBehaviorWidget.test.jsx +51 -46
- package/src/components/theme/Widgets/UserSelectWidget.jsx +13 -10
- package/src/customizations/@plone/volto-slate/blocks/Table/TableBlockView.jsx +3 -3
- package/src/customizations/@plone/volto-slate/blocks/Text/TextBlockView.jsx +2 -2
- package/src/customizations/@plone/volto-slate/editor/SlateEditor.jsx +23 -10
- package/src/customizations/@plone/volto-slate/editor/render.jsx +7 -3
- package/src/customizations/@plone/volto-slate/utils/blocks.js +11 -8
- package/src/customizations/volto/components/manage/Blocks/Grid/View.jsx +2 -2
- package/src/customizations/volto/components/manage/Blocks/Image/Edit.jsx +30 -27
- package/src/customizations/volto/components/manage/Blocks/Image/Edit.test.jsx +244 -246
- package/src/customizations/volto/components/manage/Blocks/Image/View.jsx +23 -25
- package/src/customizations/volto/components/manage/Blocks/LeadImage/Edit.jsx +6 -4
- package/src/customizations/volto/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +4 -2
- package/src/customizations/volto/components/manage/Blocks/LeadImage/View.jsx +2 -2
- package/src/customizations/volto/components/manage/Controlpanels/Groups/RenderGroups.jsx +1 -1
- package/src/customizations/volto/components/manage/Controlpanels/Groups/RenderGroups.test.jsx +108 -42
- package/src/customizations/volto/components/manage/Diff/DiffField.jsx +4 -3
- package/src/customizations/volto/components/manage/Display/Display.jsx +8 -7
- package/src/customizations/volto/components/manage/Sidebar/ObjectBrowserBody.jsx +42 -21
- package/src/customizations/volto/components/manage/Sidebar/ObjectBrowserNav.jsx +2 -1
- package/src/customizations/volto/components/manage/Sidebar/SidebarPopup.jsx +46 -24
- package/src/customizations/volto/components/manage/Sidebar/objectBrowserSelection.js +58 -0
- package/src/customizations/volto/components/manage/Toolbar/More.jsx +8 -10
- package/src/customizations/volto/components/manage/Widgets/NumberWidget.jsx +1 -1
- package/src/customizations/volto/components/manage/Widgets/NumberWidget.test.jsx +6 -1
- package/src/customizations/volto/components/manage/Widgets/ObjectBrowserWidget.jsx +66 -12
- package/src/customizations/volto/components/manage/Workflow/Workflow.jsx +10 -9
- package/src/customizations/volto/components/theme/Breadcrumbs/Breadcrumbs.jsx +3 -2
- package/src/customizations/volto/components/theme/Comments/Comments.jsx +9 -8
- package/src/customizations/volto/components/theme/Comments/Comments.test.jsx +29 -7
- package/src/customizations/volto/components/theme/ContactForm/ContactForm.jsx +1 -1
- package/src/customizations/volto/components/theme/ContactForm/ContactForm.test.js +5 -0
- package/src/customizations/volto/components/theme/ContentMetadataTags/ContentMetadataTags.jsx +5 -7
- package/src/customizations/volto/components/theme/EventDetails/EventDetails.jsx +2 -2
- package/src/customizations/volto/components/theme/Footer/Footer.jsx +1 -1
- package/src/customizations/volto/components/theme/Header/Header.jsx +10 -8
- package/src/customizations/volto/components/theme/Header/Header.test.jsx +1 -1
- package/src/customizations/volto/components/theme/Header/LanguageSwitcher.jsx +3 -3
- package/src/customizations/volto/components/theme/Image/Image.jsx +4 -3
- package/src/customizations/volto/components/theme/Unauthorized/Unauthorized.jsx +1 -1
- package/src/customizations/volto/components/theme/View/DefaultView.jsx +4 -3
- package/src/customizations/volto/components/theme/View/EventView.jsx +3 -2
- package/src/customizations/volto/helpers/Html/Html.jsx +16 -6
- package/src/customizations/volto/helpers/Html/Readme.md +7 -1
- package/src/customizations/volto/reducers/breadcrumbs/breadcrumbs.js +3 -6
- package/src/customizations/volto/server.jsx +13 -15
- package/src/helpers/schema-utils.js +1 -1
- package/src/helpers/schema-utils.test.js +1 -1
- package/src/hocs/withErrorBoundary.jsx +1 -1
- package/src/hocs/withErrorBoundary.test.jsx +4 -11
- package/src/hocs/withRootNavigation.jsx +3 -2
- package/src/hocs/withRootNavigation.test.jsx +18 -14
- package/src/index.js +3 -3
- package/src/slate.js +1 -1
- package/src/customizations/volto/components/manage/Blocks/LeadImage/AlignChooser.jsx +0 -76
- package/src/customizations/volto/components/manage/Blocks/LeadImage/AlignChooser.test.js +0 -50
- package/src/customizations/volto/components/manage/Sidebar/SidebarPopup copy.jsx +0 -82
|
@@ -1,22 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image block Edit — unit tests
|
|
3
|
+
*
|
|
4
|
+
* Volto 17 / 18 dual-support notes
|
|
5
|
+
* ---------------------------------
|
|
6
|
+
* Importing `@plone/volto/components` (the full barrel) triggers the chain:
|
|
7
|
+
* TranslationObject.jsx → store.js → `@root/reducers`
|
|
8
|
+
* which Jest cannot resolve in this project's test environment.
|
|
9
|
+
* We therefore stub the entire barrel and provide minimal fakes for the
|
|
10
|
+
* components that Edit.jsx actually uses. `@eeacms/volto-eea-design-system/ui`
|
|
11
|
+
* is mocked for the same reason (external design-system package not present in
|
|
12
|
+
* the test runner).
|
|
13
|
+
*
|
|
14
|
+
* Both mocks are version-agnostic — they expose the same API on V17 and V18.
|
|
15
|
+
*
|
|
16
|
+
* IMPORTANT: jest.mock() factories cannot reference out-of-scope variables
|
|
17
|
+
* (including React imported via ESM). Use require() inside the factory instead.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// jest.mock() calls are hoisted above all imports by babel-jest.
|
|
21
|
+
/* eslint-disable no-undef */
|
|
22
|
+
|
|
23
|
+
/* eslint-enable no-undef */
|
|
24
|
+
|
|
1
25
|
import config from '@plone/volto/registry';
|
|
2
|
-
import '@testing-library/jest-dom
|
|
26
|
+
import '@testing-library/jest-dom';
|
|
3
27
|
import { render } from '@testing-library/react';
|
|
4
28
|
import React from 'react';
|
|
5
29
|
import { Provider } from 'react-intl-redux';
|
|
6
30
|
import configureMockStore from 'redux-mock-store';
|
|
7
|
-
import Edit from './Edit';
|
|
8
|
-
|
|
9
|
-
|
|
31
|
+
import Edit, { getImageBlockSizes } from './Edit';
|
|
32
|
+
|
|
33
|
+
jest.mock('@plone/volto/components', () => {
|
|
34
|
+
const React = require('react');
|
|
35
|
+
|
|
36
|
+
const MockImage = (props) =>
|
|
37
|
+
React.createElement('img', {
|
|
38
|
+
src: props.src,
|
|
39
|
+
alt: props.alt,
|
|
40
|
+
className: props.className,
|
|
41
|
+
loading: props.loading,
|
|
42
|
+
'data-testid': 'volto-image',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
// Volto SVG icon wrapper — renders nothing in tests
|
|
47
|
+
Icon: () => null,
|
|
48
|
+
// Image sidebar form rendered inside SidebarPortal — not under test here
|
|
49
|
+
ImageSidebar: () => null,
|
|
50
|
+
// Portal that makes sidebar visible only when `selected` is true
|
|
51
|
+
SidebarPortal: (props) =>
|
|
52
|
+
props.selected
|
|
53
|
+
? React.createElement(
|
|
54
|
+
'div',
|
|
55
|
+
{ 'data-testid': 'sidebar-portal' },
|
|
56
|
+
props.children,
|
|
57
|
+
)
|
|
58
|
+
: null,
|
|
59
|
+
// Volto responsive image component
|
|
60
|
+
Image: MockImage,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
10
63
|
|
|
64
|
+
jest.mock('@eeacms/volto-eea-design-system/ui/Copyright/Copyright', () => {
|
|
65
|
+
const React = require('react');
|
|
66
|
+
|
|
67
|
+
const Copyright = (props) =>
|
|
68
|
+
React.createElement(
|
|
69
|
+
'div',
|
|
70
|
+
{ 'data-testid': 'eea-copyright' },
|
|
71
|
+
props.children,
|
|
72
|
+
);
|
|
73
|
+
Copyright.Icon = (props) =>
|
|
74
|
+
React.createElement(
|
|
75
|
+
'span',
|
|
76
|
+
{ 'data-testid': 'eea-copyright-icon' },
|
|
77
|
+
props.children,
|
|
78
|
+
);
|
|
79
|
+
Copyright.Text = (props) =>
|
|
80
|
+
React.createElement(
|
|
81
|
+
'span',
|
|
82
|
+
{ 'data-testid': 'eea-copyright-text' },
|
|
83
|
+
props.children,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
__esModule: true,
|
|
88
|
+
default: Copyright,
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Register our mock Image component so config.getComponent({ name: 'Image' })
|
|
93
|
+
// returns something renderable during tests.
|
|
94
|
+
const MockImage = jest.requireMock('@plone/volto/components').Image;
|
|
11
95
|
config.set('components', {
|
|
12
|
-
Image: { component:
|
|
96
|
+
Image: { component: MockImage },
|
|
13
97
|
});
|
|
14
98
|
|
|
15
99
|
const mockStore = configureMockStore();
|
|
16
100
|
const { settings } = config;
|
|
17
101
|
|
|
18
|
-
let store;
|
|
19
|
-
|
|
20
102
|
config.blocks.blocksConfig = {
|
|
21
103
|
image: {
|
|
22
104
|
id: 'image',
|
|
@@ -34,286 +116,202 @@ config.blocks.blocksConfig = {
|
|
|
34
116
|
getSizes: getImageBlockSizes,
|
|
35
117
|
},
|
|
36
118
|
};
|
|
119
|
+
|
|
37
120
|
const blockId = '1234';
|
|
38
121
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
messages: {},
|
|
52
|
-
},
|
|
53
|
-
});
|
|
122
|
+
/**
|
|
123
|
+
* Helper: render Edit wrapped in Redux + intl Provider.
|
|
124
|
+
*/
|
|
125
|
+
const renderEdit = (data, extraProps = {}) => {
|
|
126
|
+
settings.internalApiPath = 'http://localhost:8080/Plone';
|
|
127
|
+
const store = mockStore({
|
|
128
|
+
content: {
|
|
129
|
+
create: {},
|
|
130
|
+
data: {},
|
|
131
|
+
subrequests: { [blockId]: {} },
|
|
132
|
+
},
|
|
133
|
+
intl: { locale: 'en', messages: {} },
|
|
54
134
|
});
|
|
55
135
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
handleKeyDown={() => {}}
|
|
80
|
-
index={1}
|
|
81
|
-
openObjectBrowser={() => {}}
|
|
82
|
-
/>
|
|
83
|
-
</Provider>,
|
|
84
|
-
);
|
|
136
|
+
return render(
|
|
137
|
+
<Provider store={store}>
|
|
138
|
+
<Edit
|
|
139
|
+
data={{ '@type': 'image', ...data }}
|
|
140
|
+
selected={false}
|
|
141
|
+
block={blockId}
|
|
142
|
+
content={{}}
|
|
143
|
+
request={{ loading: false, loaded: false }}
|
|
144
|
+
pathname="/news"
|
|
145
|
+
onChangeBlock={() => {}}
|
|
146
|
+
onSelectBlock={() => {}}
|
|
147
|
+
onDeleteBlock={() => {}}
|
|
148
|
+
createContent={() => {}}
|
|
149
|
+
onFocusPreviousBlock={() => {}}
|
|
150
|
+
onFocusNextBlock={() => {}}
|
|
151
|
+
handleKeyDown={() => {}}
|
|
152
|
+
index={1}
|
|
153
|
+
openObjectBrowser={() => {}}
|
|
154
|
+
{...extraProps}
|
|
155
|
+
/>
|
|
156
|
+
</Provider>,
|
|
157
|
+
);
|
|
158
|
+
};
|
|
85
159
|
|
|
86
|
-
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
// getImageBlockSizes — pure-function export used by blocksConfig.getSizes
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
87
163
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
).toBeInTheDocument();
|
|
92
|
-
expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
|
|
164
|
+
describe('getImageBlockSizes', () => {
|
|
165
|
+
it('returns 100vw for full-width alignment', () => {
|
|
166
|
+
expect(getImageBlockSizes({ align: 'full' })).toBe('100vw');
|
|
93
167
|
});
|
|
94
168
|
|
|
95
|
-
it('
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
url: 'http://localhost:8080/Plone/image',
|
|
101
|
-
'@type': 'image',
|
|
102
|
-
size: 'l',
|
|
103
|
-
copyright: 'Copyright',
|
|
104
|
-
}}
|
|
105
|
-
selected={false}
|
|
106
|
-
block={blockId}
|
|
107
|
-
content={{}}
|
|
108
|
-
request={{
|
|
109
|
-
loading: false,
|
|
110
|
-
loaded: false,
|
|
111
|
-
}}
|
|
112
|
-
pathname="/news"
|
|
113
|
-
onChangeBlock={() => {}}
|
|
114
|
-
onSelectBlock={() => {}}
|
|
115
|
-
onDeleteBlock={() => {}}
|
|
116
|
-
createContent={() => {}}
|
|
117
|
-
onFocusPreviousBlock={() => {}}
|
|
118
|
-
onFocusNextBlock={() => {}}
|
|
119
|
-
handleKeyDown={() => {}}
|
|
120
|
-
index={1}
|
|
121
|
-
openObjectBrowser={() => {}}
|
|
122
|
-
/>
|
|
123
|
-
</Provider>,
|
|
124
|
-
);
|
|
169
|
+
it('returns correct sizes for centered alignment', () => {
|
|
170
|
+
expect(getImageBlockSizes({ align: 'center', size: 'l' })).toBe('100vw');
|
|
171
|
+
expect(getImageBlockSizes({ align: 'center', size: 'm' })).toBe('50vw');
|
|
172
|
+
expect(getImageBlockSizes({ align: 'center', size: 's' })).toBe('25vw');
|
|
173
|
+
});
|
|
125
174
|
|
|
126
|
-
|
|
175
|
+
it('returns correct sizes for left / right alignment', () => {
|
|
176
|
+
expect(getImageBlockSizes({ align: 'left', size: 'l' })).toBe('50vw');
|
|
177
|
+
expect(getImageBlockSizes({ align: 'left', size: 'm' })).toBe('25vw');
|
|
178
|
+
expect(getImageBlockSizes({ align: 'right', size: 's' })).toBe('15vw');
|
|
179
|
+
});
|
|
127
180
|
|
|
128
|
-
|
|
129
|
-
expect(
|
|
130
|
-
container.querySelector('.image-block-container'),
|
|
131
|
-
).toBeInTheDocument();
|
|
132
|
-
expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
|
|
181
|
+
it('returns undefined for unknown alignment', () => {
|
|
182
|
+
expect(getImageBlockSizes({})).toBeUndefined();
|
|
133
183
|
});
|
|
184
|
+
});
|
|
134
185
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
<Edit
|
|
139
|
-
data={{
|
|
140
|
-
url: 'http://localhost:8080/Plone/image',
|
|
141
|
-
'@type': 'image',
|
|
142
|
-
size: 'm',
|
|
143
|
-
}}
|
|
144
|
-
selected={false}
|
|
145
|
-
block={blockId}
|
|
146
|
-
content={{}}
|
|
147
|
-
request={{
|
|
148
|
-
loading: false,
|
|
149
|
-
loaded: false,
|
|
150
|
-
}}
|
|
151
|
-
pathname="/news"
|
|
152
|
-
onChangeBlock={() => {}}
|
|
153
|
-
onSelectBlock={() => {}}
|
|
154
|
-
onDeleteBlock={() => {}}
|
|
155
|
-
createContent={() => {}}
|
|
156
|
-
onFocusPreviousBlock={() => {}}
|
|
157
|
-
onFocusNextBlock={() => {}}
|
|
158
|
-
handleKeyDown={() => {}}
|
|
159
|
-
index={1}
|
|
160
|
-
openObjectBrowser={() => {}}
|
|
161
|
-
/>
|
|
162
|
-
</Provider>,
|
|
163
|
-
);
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// Edit rendering — EEA structural requirements (image-block-container, etc.)
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
164
189
|
|
|
165
|
-
|
|
190
|
+
describe('Edit', () => {
|
|
191
|
+
it('renders the EEA wrapper structure when a URL is provided (full align)', () => {
|
|
192
|
+
const { container } = renderEdit({
|
|
193
|
+
url: 'http://localhost:8080/Plone/image',
|
|
194
|
+
align: 'full',
|
|
195
|
+
});
|
|
166
196
|
|
|
167
197
|
expect(container.querySelector('.block.image.align')).toBeInTheDocument();
|
|
168
198
|
expect(
|
|
169
199
|
container.querySelector('.image-block-container'),
|
|
170
200
|
).toBeInTheDocument();
|
|
201
|
+
// copyright-wrapper is always rendered when there is a URL
|
|
171
202
|
expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
|
|
172
203
|
});
|
|
173
204
|
|
|
174
|
-
it('
|
|
175
|
-
const {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
request={{
|
|
187
|
-
loading: false,
|
|
188
|
-
loaded: false,
|
|
189
|
-
}}
|
|
190
|
-
pathname="/news"
|
|
191
|
-
onChangeBlock={() => {}}
|
|
192
|
-
onSelectBlock={() => {}}
|
|
193
|
-
onDeleteBlock={() => {}}
|
|
194
|
-
createContent={() => {}}
|
|
195
|
-
onFocusPreviousBlock={() => {}}
|
|
196
|
-
onFocusNextBlock={() => {}}
|
|
197
|
-
handleKeyDown={() => {}}
|
|
198
|
-
index={1}
|
|
199
|
-
openObjectBrowser={() => {}}
|
|
200
|
-
/>
|
|
201
|
-
</Provider>,
|
|
205
|
+
it('shows the copyright overlay when copyright text is set and size is l', () => {
|
|
206
|
+
const { getByTestId } = renderEdit({
|
|
207
|
+
url: 'http://localhost:8080/Plone/image',
|
|
208
|
+
size: 'l',
|
|
209
|
+
copyright: 'EEA Copyright',
|
|
210
|
+
copyrightIcon: 'ri-copyright-line',
|
|
211
|
+
copyrightPosition: 'left',
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
expect(getByTestId('eea-copyright')).toBeInTheDocument();
|
|
215
|
+
expect(getByTestId('eea-copyright-text')).toHaveTextContent(
|
|
216
|
+
'EEA Copyright',
|
|
202
217
|
);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('shows the copyright overlay when no size is specified (defaults to showing)', () => {
|
|
221
|
+
const { getByTestId } = renderEdit({
|
|
222
|
+
url: 'http://localhost:8080/Plone/image',
|
|
223
|
+
copyright: 'EEA Copyright',
|
|
224
|
+
});
|
|
225
|
+
// showCopyright is true when size is undefined
|
|
226
|
+
expect(getByTestId('eea-copyright')).toBeInTheDocument();
|
|
227
|
+
});
|
|
203
228
|
|
|
204
|
-
|
|
229
|
+
it('hides the copyright overlay when size is m', () => {
|
|
230
|
+
const { queryByTestId } = renderEdit({
|
|
231
|
+
url: 'http://localhost:8080/Plone/image',
|
|
232
|
+
size: 'm',
|
|
233
|
+
copyright: 'EEA Copyright',
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// showCopyright is false for size !== 'l' and size !== undefined
|
|
237
|
+
expect(queryByTestId('eea-copyright')).not.toBeInTheDocument();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('hides the copyright overlay when size is s', () => {
|
|
241
|
+
const { queryByTestId } = renderEdit({
|
|
242
|
+
url: 'http://localhost:8080/Plone/image',
|
|
243
|
+
size: 's',
|
|
244
|
+
copyright: 'EEA Copyright',
|
|
245
|
+
});
|
|
246
|
+
expect(queryByTestId('eea-copyright')).not.toBeInTheDocument();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('renders without copyright when no copyright text is provided', () => {
|
|
250
|
+
const { container, queryByTestId } = renderEdit({
|
|
251
|
+
url: 'http://localhost:8080/Plone/image',
|
|
252
|
+
size: 'l',
|
|
253
|
+
});
|
|
205
254
|
|
|
206
|
-
expect(container.querySelector('.block.image.align')).toBeInTheDocument();
|
|
207
255
|
expect(
|
|
208
256
|
container.querySelector('.image-block-container'),
|
|
209
257
|
).toBeInTheDocument();
|
|
210
|
-
expect(
|
|
258
|
+
expect(queryByTestId('eea-copyright')).not.toBeInTheDocument();
|
|
211
259
|
});
|
|
212
260
|
|
|
213
|
-
it('
|
|
214
|
-
const { container } =
|
|
215
|
-
<Provider store={store}>
|
|
216
|
-
<Edit
|
|
217
|
-
data={{
|
|
218
|
-
url: 'http://localhost:8080/Plone/image',
|
|
219
|
-
'@type': 'image',
|
|
220
|
-
}}
|
|
221
|
-
selected={false}
|
|
222
|
-
block={blockId}
|
|
223
|
-
content={{}}
|
|
224
|
-
request={{
|
|
225
|
-
loading: false,
|
|
226
|
-
loaded: false,
|
|
227
|
-
}}
|
|
228
|
-
pathname="/news"
|
|
229
|
-
onChangeBlock={() => {}}
|
|
230
|
-
onSelectBlock={() => {}}
|
|
231
|
-
onDeleteBlock={() => {}}
|
|
232
|
-
createContent={() => {}}
|
|
233
|
-
onFocusPreviousBlock={() => {}}
|
|
234
|
-
onFocusNextBlock={() => {}}
|
|
235
|
-
handleKeyDown={() => {}}
|
|
236
|
-
index={1}
|
|
237
|
-
openObjectBrowser={() => {}}
|
|
238
|
-
/>
|
|
239
|
-
</Provider>,
|
|
240
|
-
);
|
|
241
|
-
|
|
242
|
-
settings.internalApiPath = 'http://localhost:8080/Plone';
|
|
261
|
+
it('renders without a URL — shows the dropzone upload UI', () => {
|
|
262
|
+
const { container } = renderEdit({ url: undefined }, { editable: true });
|
|
243
263
|
|
|
244
264
|
expect(container.querySelector('.block.image.align')).toBeInTheDocument();
|
|
245
265
|
expect(
|
|
246
266
|
container.querySelector('.image-block-container'),
|
|
247
267
|
).toBeInTheDocument();
|
|
248
|
-
|
|
268
|
+
// No copyright-wrapper when there is no image URL
|
|
269
|
+
expect(
|
|
270
|
+
container.querySelector('.copyright-wrapper'),
|
|
271
|
+
).not.toBeInTheDocument();
|
|
249
272
|
});
|
|
250
273
|
|
|
251
|
-
it('
|
|
252
|
-
const { container } =
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
request={{
|
|
263
|
-
loading: false,
|
|
264
|
-
loaded: false,
|
|
265
|
-
}}
|
|
266
|
-
pathname="/news"
|
|
267
|
-
onChangeBlock={() => {}}
|
|
268
|
-
onSelectBlock={() => {}}
|
|
269
|
-
onDeleteBlock={() => {}}
|
|
270
|
-
createContent={() => {}}
|
|
271
|
-
onFocusPreviousBlock={() => {}}
|
|
272
|
-
onFocusNextBlock={() => {}}
|
|
273
|
-
handleKeyDown={() => {}}
|
|
274
|
-
index={1}
|
|
275
|
-
openObjectBrowser={() => {}}
|
|
276
|
-
/>
|
|
277
|
-
</Provider>,
|
|
278
|
-
);
|
|
274
|
+
it('applies align class to both the outer block and the EEA container', () => {
|
|
275
|
+
const { container } = renderEdit({
|
|
276
|
+
url: 'http://localhost:8080/Plone/image',
|
|
277
|
+
align: 'left',
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
const outer = container.querySelector('.block.image.align');
|
|
281
|
+
expect(outer).toHaveClass('left');
|
|
282
|
+
const inner = container.querySelector('.image-block-container');
|
|
283
|
+
expect(inner).toHaveClass('left');
|
|
284
|
+
});
|
|
279
285
|
|
|
280
|
-
|
|
286
|
+
it('applies center class when no align is provided', () => {
|
|
287
|
+
const { container } = renderEdit({
|
|
288
|
+
url: 'http://localhost:8080/Plone/image',
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
const outer = container.querySelector('.block.image.align');
|
|
292
|
+
expect(outer).toHaveClass('center');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('applies size class to the EEA container and the image', () => {
|
|
296
|
+
const { container } = renderEdit({
|
|
297
|
+
url: 'http://localhost:8080/Plone/image',
|
|
298
|
+
size: 'l',
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const inner = container.querySelector('.image-block-container');
|
|
302
|
+
expect(inner).toHaveClass('large');
|
|
303
|
+
const img = container.querySelector('[data-testid="volto-image"]');
|
|
304
|
+
expect(img).toHaveClass('large');
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('renders with an external URL', () => {
|
|
308
|
+
const { container } = renderEdit({
|
|
309
|
+
url: 'https://example.com/image.png',
|
|
310
|
+
});
|
|
281
311
|
|
|
282
312
|
expect(container.querySelector('.block.image.align')).toBeInTheDocument();
|
|
283
313
|
expect(
|
|
284
314
|
container.querySelector('.image-block-container'),
|
|
285
315
|
).toBeInTheDocument();
|
|
286
|
-
expect(container.querySelector('.copyright-wrapper')).toBeInTheDocument();
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it('should render without errors', () => {
|
|
290
|
-
render(
|
|
291
|
-
<Provider store={store}>
|
|
292
|
-
<Edit
|
|
293
|
-
data={{
|
|
294
|
-
url: undefined,
|
|
295
|
-
'@type': 'image',
|
|
296
|
-
}}
|
|
297
|
-
selected={false}
|
|
298
|
-
block={blockId}
|
|
299
|
-
content={{}}
|
|
300
|
-
request={{
|
|
301
|
-
loading: false,
|
|
302
|
-
loaded: false,
|
|
303
|
-
}}
|
|
304
|
-
editable={true}
|
|
305
|
-
pathname="/news"
|
|
306
|
-
onChangeBlock={() => {}}
|
|
307
|
-
onSelectBlock={() => {}}
|
|
308
|
-
onDeleteBlock={() => {}}
|
|
309
|
-
createContent={() => {}}
|
|
310
|
-
onFocusPreviousBlock={() => {}}
|
|
311
|
-
onFocusNextBlock={() => {}}
|
|
312
|
-
handleKeyDown={() => {}}
|
|
313
|
-
index={1}
|
|
314
|
-
openObjectBrowser={() => {}}
|
|
315
|
-
/>
|
|
316
|
-
</Provider>,
|
|
317
|
-
);
|
|
318
316
|
});
|
|
319
317
|
});
|
|
@@ -6,16 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import PropTypes from 'prop-types';
|
|
9
|
-
import
|
|
9
|
+
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
10
10
|
import { Icon } from 'semantic-ui-react';
|
|
11
11
|
import cx from 'classnames';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
isInternalURL,
|
|
15
|
-
withBlockExtensions,
|
|
16
|
-
} from '@plone/volto/helpers';
|
|
12
|
+
import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers/Url/Url';
|
|
13
|
+
import { withBlockExtensions } from '@plone/volto/helpers//Extensions';
|
|
17
14
|
import config from '@plone/volto/registry';
|
|
18
|
-
import
|
|
15
|
+
import Copyright from '@eeacms/volto-eea-design-system/ui/Copyright/Copyright';
|
|
19
16
|
|
|
20
17
|
/**
|
|
21
18
|
* View image block class.
|
|
@@ -25,7 +22,8 @@ import { Copyright } from '@eeacms/volto-eea-design-system/ui';
|
|
|
25
22
|
export const View = (props) => {
|
|
26
23
|
const { className, data, detached, style } = props;
|
|
27
24
|
const { copyright, copyrightIcon, copyrightPosition } = data;
|
|
28
|
-
const
|
|
25
|
+
const hrefItem = data?.href?.[0];
|
|
26
|
+
const href = hrefItem?.['@id'] || '';
|
|
29
27
|
const showCopyright = data?.size === 'l' || !data.size;
|
|
30
28
|
|
|
31
29
|
const Image = config.getComponent({ name: 'Image' }).component;
|
|
@@ -84,25 +82,25 @@ export const View = (props) => {
|
|
|
84
82
|
data.image_scales
|
|
85
83
|
? undefined
|
|
86
84
|
: isInternalURL(data.url)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
? // Backwards compat in the case that the block is storing the full server URL
|
|
86
|
+
(() => {
|
|
87
|
+
if (data.size === 'l')
|
|
88
|
+
return `${flattenToAppURL(
|
|
89
|
+
data.url,
|
|
90
|
+
)}/@@images/image/large`;
|
|
91
|
+
if (data.size === 'm')
|
|
92
|
+
return `${flattenToAppURL(
|
|
93
|
+
data.url,
|
|
94
|
+
)}/@@images/image/preview`;
|
|
95
|
+
if (data.size === 's')
|
|
96
|
+
return `${flattenToAppURL(
|
|
97
|
+
data.url,
|
|
98
|
+
)}/@@images/image/mini`;
|
|
90
99
|
return `${flattenToAppURL(
|
|
91
100
|
data.url,
|
|
92
101
|
)}/@@images/image/large`;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
data.url,
|
|
96
|
-
)}/@@images/image/preview`;
|
|
97
|
-
if (data.size === 's')
|
|
98
|
-
return `${flattenToAppURL(
|
|
99
|
-
data.url,
|
|
100
|
-
)}/@@images/image/mini`;
|
|
101
|
-
return `${flattenToAppURL(
|
|
102
|
-
data.url,
|
|
103
|
-
)}/@@images/image/large`;
|
|
104
|
-
})()
|
|
105
|
-
: data.url
|
|
102
|
+
})()
|
|
103
|
+
: data.url
|
|
106
104
|
}
|
|
107
105
|
sizes={config.blocks.blocksConfig.image.getSizes(data)}
|
|
108
106
|
alt={data.alt || ''}
|
|
@@ -130,7 +128,7 @@ export const View = (props) => {
|
|
|
130
128
|
if (href) {
|
|
131
129
|
return (
|
|
132
130
|
<UniversalLink
|
|
133
|
-
|
|
131
|
+
item={hrefItem}
|
|
134
132
|
openLinkInNewTab={data.openLinkInNewTab}
|
|
135
133
|
>
|
|
136
134
|
{image}
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
* Edit image block.
|
|
3
3
|
* @module components/manage/Blocks/Image/Edit
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
import React, { Component } from 'react';
|
|
7
6
|
import PropTypes from 'prop-types';
|
|
8
7
|
import { compose } from 'redux';
|
|
9
8
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
10
9
|
import cx from 'classnames';
|
|
11
10
|
import { Message } from 'semantic-ui-react';
|
|
12
|
-
import
|
|
11
|
+
import isEqual from 'lodash/isEqual';
|
|
13
12
|
|
|
14
|
-
import
|
|
13
|
+
import Copyright from '@eeacms/volto-eea-design-system/ui/Copyright/Copyright';
|
|
15
14
|
import { Icon } from 'semantic-ui-react';
|
|
16
|
-
import
|
|
15
|
+
import LeadImageSidebar from '@plone/volto/components/manage/Blocks/LeadImage/LeadImageSidebar';
|
|
16
|
+
import SidebarPortal from '@plone/volto/components/manage/Sidebar/SidebarPortal';
|
|
17
17
|
import config from '@plone/volto/registry';
|
|
18
18
|
|
|
19
19
|
import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg';
|
|
@@ -111,6 +111,7 @@ class Edit extends Component {
|
|
|
111
111
|
{!hasImage && (
|
|
112
112
|
<Message>
|
|
113
113
|
<center>
|
|
114
|
+
{/* eslint-disable-next-line no-restricted-syntax */}
|
|
114
115
|
<img src={imageBlockSVG} alt="" />
|
|
115
116
|
<div className="message-text">{placeholder}</div>
|
|
116
117
|
</center>
|
|
@@ -118,6 +119,7 @@ class Edit extends Component {
|
|
|
118
119
|
)}
|
|
119
120
|
{hasImage && hasImageData && (
|
|
120
121
|
<div className="image-block">
|
|
122
|
+
{/* eslint-disable-next-line no-restricted-syntax */}
|
|
121
123
|
<img
|
|
122
124
|
className={(className, data?.styles?.objectPosition)}
|
|
123
125
|
src={`data:${properties.image['content-type']};base64,${properties.image.data}`}
|