@plone/volto 17.0.0-alpha.20 → 17.0.0-alpha.22

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 (108) hide show
  1. package/.gitignore~ +71 -0
  2. package/.yarn/install-state.gz +0 -0
  3. package/CHANGELOG.md +49 -0
  4. package/cypress/support/commands.js +2 -1
  5. package/cypress/support/e2e.js +1 -2
  6. package/locales/ca/LC_MESSAGES/volto.po +24 -5
  7. package/locales/ca.json +1 -1
  8. package/locales/de/LC_MESSAGES/volto.po +37 -18
  9. package/locales/de.json +1 -1
  10. package/locales/en/LC_MESSAGES/volto.po +25 -6
  11. package/locales/en.json +1 -1
  12. package/locales/es/LC_MESSAGES/volto.po +25 -6
  13. package/locales/es.json +1 -1
  14. package/locales/eu/LC_MESSAGES/volto.po +24 -5
  15. package/locales/eu.json +1 -1
  16. package/locales/fi/LC_MESSAGES/volto.po +24 -5
  17. package/locales/fi.json +1 -1
  18. package/locales/fr/LC_MESSAGES/volto.po +24 -5
  19. package/locales/fr.json +1 -1
  20. package/locales/it/LC_MESSAGES/volto.po +250 -231
  21. package/locales/it.json +1 -1
  22. package/locales/ja/LC_MESSAGES/volto.po +24 -5
  23. package/locales/ja.json +1 -1
  24. package/locales/nl/LC_MESSAGES/volto.po +24 -5
  25. package/locales/nl.json +1 -1
  26. package/locales/pt/LC_MESSAGES/volto.po +24 -5
  27. package/locales/pt.json +1 -1
  28. package/locales/pt_BR/LC_MESSAGES/volto.po +25 -6
  29. package/locales/pt_BR.json +1 -1
  30. package/locales/ro/LC_MESSAGES/volto.po +24 -5
  31. package/locales/ro.json +1 -1
  32. package/locales/volto.pot +25 -6
  33. package/locales/zh_CN/LC_MESSAGES/volto.po +24 -5
  34. package/locales/zh_CN.json +1 -1
  35. package/news/4547.breaking~ +1 -0
  36. package/package.json +6 -6
  37. package/packages/volto-slate/package.json +1 -1
  38. package/src/actions/relations/rebuild.js +7 -7
  39. package/src/components/index.js +1 -0
  40. package/src/components/manage/Actions/Actions.jsx +133 -243
  41. package/src/components/manage/Blocks/Container/Edit.jsx +4 -1
  42. package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +1 -0
  43. package/src/components/manage/Blocks/Grid/Edit.jsx +13 -1
  44. package/src/components/manage/Blocks/Image/Edit.jsx +40 -5
  45. package/src/components/manage/Blocks/Image/Edit.test.jsx +2 -0
  46. package/src/components/manage/Blocks/Image/ImageSidebar.jsx +64 -15
  47. package/src/components/manage/Blocks/Image/View.jsx +26 -5
  48. package/src/components/manage/Blocks/Image/View.test.jsx +20 -0
  49. package/src/components/manage/Blocks/Image/schema.js +1 -9
  50. package/src/components/manage/Blocks/Image/utils.js +14 -0
  51. package/src/components/manage/Blocks/LeadImage/Edit.jsx +32 -10
  52. package/src/components/manage/Blocks/LeadImage/Edit.test.jsx +11 -1
  53. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +28 -9
  54. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +8 -2
  55. package/src/components/manage/Blocks/LeadImage/View.jsx +50 -38
  56. package/src/components/manage/Blocks/LeadImage/View.test.jsx +11 -1
  57. package/src/components/manage/Blocks/Listing/SummaryTemplate.jsx +1 -1
  58. package/src/components/manage/Blocks/Maps/Edit.jsx +135 -209
  59. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +3 -2
  60. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +13 -23
  61. package/src/components/manage/Contents/Contents.jsx +8 -6
  62. package/src/components/manage/Contents/ContentsPropertiesModal.jsx +1 -13
  63. package/src/components/manage/Controlpanels/Groups/RenderGroups.jsx +2 -2
  64. package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +30 -7
  65. package/src/components/manage/Controlpanels/Relations/Relations.jsx +2 -2
  66. package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +53 -59
  67. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +2 -2
  68. package/src/components/manage/Delete/Delete.jsx +96 -171
  69. package/src/components/manage/Sidebar/AlignBlock.jsx +1 -1
  70. package/src/components/manage/Widgets/SelectUtils.js +1 -1
  71. package/src/components/manage/Workflow/Workflow.jsx +75 -184
  72. package/src/components/theme/Image/Image.jsx +96 -0
  73. package/src/components/theme/Image/Image.test.jsx +125 -0
  74. package/src/components/theme/Logo/Logo.jsx +2 -0
  75. package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +95 -170
  76. package/src/components/theme/PreviewImage/PreviewImage.jsx +25 -14
  77. package/src/components/theme/PreviewImage/PreviewImage.test.js +39 -16
  78. package/src/components/theme/View/AlbumView.jsx +11 -15
  79. package/src/components/theme/View/EventView.jsx +30 -23
  80. package/src/components/theme/View/ImageView.jsx +5 -2
  81. package/src/components/theme/View/ImageView.test.jsx +4 -0
  82. package/src/components/theme/View/ListingView.jsx +5 -3
  83. package/src/components/theme/View/NewsItemView.jsx +7 -13
  84. package/src/components/theme/View/SummaryView.jsx +4 -3
  85. package/src/config/Blocks.jsx +2 -0
  86. package/src/config/Components.jsx +3 -1
  87. package/src/config/index.js~ +223 -0
  88. package/src/express-middleware/files.js +8 -6
  89. package/src/express-middleware/images.js +7 -1
  90. package/src/helpers/MessageLabels/MessageLabels.js +6 -0
  91. package/src/helpers/Url/Url.js +22 -1
  92. package/src/helpers/Url/Url.test.js +41 -0
  93. package/src/reducers/relations/relations.js +1 -1
  94. package/test-setup-config.js +9 -1
  95. package/theme/themes/pastanaga/extras/blocks.less +3 -1
  96. package/theme/themes/pastanaga/extras/main.less +5 -0
  97. package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +0 -90
  98. package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +0 -6
  99. package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +0 -6
  100. package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +0 -6
  101. package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +0 -10
  102. package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +0 -10
  103. package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +0 -30
  104. package/packages/volto-slate/build/messages/src/elementEditor/messages.json +0 -10
  105. package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +0 -6
  106. package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +0 -6
  107. package/src/components/manage/Blocks/Teaser/utils.js +0 -44
  108. package/src/components/manage/Blocks/Teaser/utils.test.jsx +0 -229
@@ -1,17 +1,10 @@
1
- /**
2
- * RequestPasswordReset component.
3
- * @module components/theme/RequestPasswordReset/RequestPasswordReset
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 { withRouter } from 'react-router-dom';
11
- import { Helmet } from '@plone/volto/helpers';
1
+ import { useState, useEffect, useRef } from 'react';
2
+ import { useDispatch, useSelector } from 'react-redux';
3
+ import { useHistory } from 'react-router-dom';
12
4
  import { Container } from 'semantic-ui-react';
13
- import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
5
+ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
14
6
 
7
+ import { Helmet, usePrevious } from '@plone/volto/helpers';
15
8
  import { Form } from '@plone/volto/components';
16
9
  import { resetPassword } from '@plone/volto/actions';
17
10
  import config from '@plone/volto/registry';
@@ -56,178 +49,110 @@ const messages = defineMessages({
56
49
  },
57
50
  });
58
51
 
59
- /**
60
- * RequestPasswordReset class.
61
- * @class RequestPasswordReset
62
- * @extends Component
63
- */
64
- class RequestPasswordReset extends Component {
65
- /**
66
- * Property types.
67
- * @property {Object} propTypes Property types.
68
- * @static
69
- */
70
- static propTypes = {
71
- loading: PropTypes.bool.isRequired,
72
- loaded: PropTypes.bool.isRequired,
73
- error: PropTypes.string,
74
- resetPassword: PropTypes.func.isRequired,
75
- };
52
+ const useUsers = () => {
53
+ const loading = useSelector((state) => state.users.reset.loading);
54
+ const loaded = useSelector((state) => state.users.reset.loaded);
55
+ const error = useSelector((state) => state.users.reset.error);
76
56
 
77
- /**
78
- * Default properties.
79
- * @property {Object} defaultProps Default properties.
80
- * @static
81
- */
82
- static defaultProps = {
83
- error: null,
84
- };
57
+ return { loading, loaded, error };
58
+ };
85
59
 
86
- /**
87
- * Constructor
88
- * @method constructor
89
- * @param {Object} props Component properties
90
- * @constructs Controlpanel
91
- */
92
- constructor(props) {
93
- super(props);
94
- this.onCancel = this.onCancel.bind(this);
95
- this.onSubmit = this.onSubmit.bind(this);
96
- this.identifierField = config.settings.useEmailAsLogin
97
- ? 'email'
98
- : 'username';
60
+ const RequestPasswordReset = () => {
61
+ const intl = useIntl();
62
+ const dispatch = useDispatch();
63
+ const [error, setError] = useState(null);
64
+ const [isSuccessful, setisSuccessful] = useState(false);
65
+ const history = useHistory();
66
+ const identifierTitle = useRef();
67
+ const identifierRequiredMessage = useRef();
68
+ const { loaded, loading, error: props_error } = useUsers();
69
+ const prevloading = usePrevious(loading);
99
70
 
100
- if (this.identifierField === 'email') {
101
- this.identifierTitle = this.props.intl.formatMessage(messages.emailTitle);
102
- this.identifierRequiredMessage = this.props.intl.formatMessage(
103
- messages.emailRequired,
104
- );
105
- } else {
106
- this.identifierTitle = this.props.intl.formatMessage(
107
- messages.usernameTitle,
108
- );
109
- this.identifierRequiredMessage = this.props.intl.formatMessage(
110
- messages.usernameRequired,
111
- );
112
- }
71
+ const identifierField = config.settings.useEmailAsLogin
72
+ ? 'email'
73
+ : 'username';
113
74
 
114
- this.state = {
115
- error: null,
116
- isSuccessful: false,
117
- };
75
+ if (identifierField === 'email') {
76
+ identifierTitle.current = intl.formatMessage(messages.emailTitle);
77
+ identifierRequiredMessage.current = intl.formatMessage(
78
+ messages.emailRequired,
79
+ );
80
+ } else {
81
+ identifierTitle.current = intl.formatMessage(messages.usernameTitle);
82
+ identifierRequiredMessage.current = intl.formatMessage(
83
+ messages.usernameRequired,
84
+ );
118
85
  }
119
86
 
120
- /**
121
- * Component will receive props
122
- * @method componentWillReceiveProps
123
- * @param {Object} nextProps Next properties
124
- * @returns {undefined}
125
- */
126
- UNSAFE_componentWillReceiveProps(nextProps) {
127
- if (this.props.loading && nextProps.loaded) {
128
- this.setState({ isSuccessful: true });
129
- }
130
- }
87
+ useEffect(() => {
88
+ if (prevloading && loaded) setisSuccessful(true);
89
+ }, [prevloading, loaded]);
131
90
 
132
- /**
133
- * Submit handler
134
- * @method onSubmit
135
- * @param {object} data Form data.
136
- * @param {object} event Form data.
137
- * @returns {undefined}
138
- */
139
- onSubmit(data) {
140
- if (data[this.identifierField]) {
141
- this.props.resetPassword(data[this.identifierField]);
142
- this.setState({
143
- error: null,
144
- });
91
+ const onSubmit = (data) => {
92
+ if (data[identifierField]) {
93
+ dispatch(resetPassword(data[identifierField]));
94
+ setError(null);
145
95
  } else {
146
- this.setState({
147
- error: {
148
- message: this.identifierRequiredMessage,
149
- },
96
+ setError({
97
+ message: identifierRequiredMessage.current,
150
98
  });
151
99
  }
152
- }
153
-
154
- /**
155
- * Cancel handler
156
- * @method onCancel
157
- * @returns {undefined}
158
- */
159
- onCancel() {
160
- this.props.history.goBack();
161
- }
100
+ };
162
101
 
163
- /**
164
- * Render method.
165
- * @method render
166
- * @returns {string} Markup for the component.
167
- */
168
- render() {
169
- if (this.state.isSuccessful) {
170
- return (
171
- <Container>
172
- <h1 className="documentFirstHeading">
173
- <FormattedMessage
174
- id="heading_sent_password"
175
- defaultMessage="Password reset confirmation sent"
176
- />
177
- </h1>
178
- <p className="description">
179
- <FormattedMessage
180
- id="description_sent_password"
181
- defaultMessage="Your password reset request has been mailed. It should arrive in your mailbox shortly. When you receive the message, visit the address it contains to reset your password."
182
- />
183
- </p>
184
- </Container>
185
- );
186
- }
102
+ const onCancel = () => {
103
+ history.goBack();
104
+ };
187
105
 
106
+ if (isSuccessful) {
188
107
  return (
189
- <div id="page-password-reset">
190
- <Helmet title={this.props.intl.formatMessage(messages.passwordReset)} />
191
- <Container>
192
- <Form
193
- title={this.props.intl.formatMessage(messages.title)}
194
- description={this.props.intl.formatMessage(messages.description)}
195
- onSubmit={this.onSubmit}
196
- onCancel={this.onCancel}
197
- error={this.state.error || this.props.error}
198
- schema={{
199
- fieldsets: [
200
- {
201
- id: 'default',
202
- title: this.props.intl.formatMessage(messages.default),
203
- fields: [this.identifierField],
204
- },
205
- ],
206
- properties: {
207
- [this.identifierField]: {
208
- type: 'string',
209
- title: this.identifierTitle,
210
- },
211
- },
212
- submitLabel: this.props.intl.formatMessage(messages.sendEmail),
213
- required: [this.identifierField],
214
- }}
108
+ <Container>
109
+ <h1 className="documentFirstHeading">
110
+ <FormattedMessage
111
+ id="heading_sent_password"
112
+ defaultMessage="Password reset confirmation sent"
113
+ />
114
+ </h1>
115
+ <p className="description">
116
+ <FormattedMessage
117
+ id="description_sent_password"
118
+ defaultMessage="Your password reset request has been mailed. It should arrive in your mailbox shortly. When you receive the message, visit the address it contains to reset your password."
215
119
  />
216
- </Container>
217
- </div>
120
+ </p>
121
+ </Container>
218
122
  );
219
123
  }
220
- }
221
124
 
222
- export default compose(
223
- withRouter,
224
- injectIntl,
225
- connect(
226
- (state) => ({
227
- loading: state.users.reset.loading,
228
- loaded: state.users.reset.loaded,
229
- error: state.users.reset.error,
230
- }),
231
- { resetPassword },
232
- ),
233
- )(RequestPasswordReset);
125
+ return (
126
+ <div id="page-password-reset">
127
+ <Helmet title={intl.formatMessage(messages.passwordReset)} />
128
+ <Container>
129
+ <Form
130
+ title={intl.formatMessage(messages.title)}
131
+ description={intl.formatMessage(messages.description)}
132
+ onSubmit={onSubmit}
133
+ onCancel={onCancel}
134
+ error={error || props_error}
135
+ schema={{
136
+ fieldsets: [
137
+ {
138
+ id: 'default',
139
+ title: intl.formatMessage(messages.default),
140
+ fields: [identifierField],
141
+ },
142
+ ],
143
+ properties: {
144
+ [identifierField]: {
145
+ type: 'string',
146
+ title: identifierTitle.current,
147
+ },
148
+ },
149
+ submitLabel: intl.formatMessage(messages.sendEmail),
150
+ required: [identifierField],
151
+ }}
152
+ />
153
+ </Container>
154
+ </div>
155
+ );
156
+ };
157
+
158
+ export default RequestPasswordReset;
@@ -1,34 +1,45 @@
1
- import React from 'react';
2
1
  import PropTypes from 'prop-types';
3
2
 
4
- import { flattenToAppURL } from '@plone/volto/helpers';
5
3
  import config from '@plone/volto/registry';
6
4
 
7
5
  import DefaultImageSVG from '@plone/volto/components/manage/Blocks/Listing/default-image.svg';
8
6
 
9
7
  /**
10
8
  * Renders a preview image for a catalog brain result item.
11
- *
12
9
  */
13
- function PreviewImage(props) {
14
- const { item, size = 'preview', alt, ...rest } = props;
15
- const src = item.image_field
16
- ? flattenToAppURL(`${item['@id']}/@@images/${item.image_field}/${size}`)
17
- : config.getComponent({
18
- name: 'DefaultImage',
19
- dependencies: ['listing', 'summary'],
20
- }).component || DefaultImageSVG;
10
+ function PreviewImage({ item, alt, ...rest }) {
11
+ const Image = config.getComponent({ name: 'Image' }).component;
21
12
 
22
- return <img src={src} alt={alt ?? item.title} {...rest} />;
13
+ if (item.image_field && item.image_scales?.[item.image_field]?.[0]) {
14
+ return (
15
+ <Image item={item} imageField={item.image_field} alt={alt} {...rest} />
16
+ );
17
+ } else {
18
+ return (
19
+ <img
20
+ src={
21
+ config.getComponent({
22
+ name: 'DefaultImage',
23
+ dependencies: ['listing', 'summary'],
24
+ }).component || DefaultImageSVG
25
+ }
26
+ alt={alt}
27
+ {...rest}
28
+ width="400"
29
+ height="300"
30
+ />
31
+ );
32
+ }
23
33
  }
24
34
 
25
35
  PreviewImage.propTypes = {
26
- size: PropTypes.string,
27
36
  item: PropTypes.shape({
28
37
  '@id': PropTypes.string.isRequired,
29
- image_field: PropTypes.string,
30
38
  title: PropTypes.string.isRequired,
39
+ image_field: PropTypes.string,
40
+ image_scales: PropTypes.object,
31
41
  }),
42
+ alt: PropTypes.string.isRequired,
32
43
  };
33
44
 
34
45
  export default PreviewImage;
@@ -7,35 +7,56 @@ describe('PreviewImage', () => {
7
7
  it('renders a preview image', () => {
8
8
  const item = {
9
9
  image_field: 'image',
10
- title: 'Item title',
11
- '@id': 'http://localhost:3000/something',
12
- };
13
- const component = renderer.create(<PreviewImage item={item} />);
14
- const json = component.toJSON();
15
- expect(json).toMatchSnapshot();
16
- });
17
-
18
- it('renders a preview image with extra props', () => {
19
- const item = {
20
- image_field: 'image',
10
+ image_scales: {
11
+ image: [
12
+ {
13
+ download: '@@images/image',
14
+ width: 400,
15
+ height: 400,
16
+ scales: {
17
+ preview: {
18
+ download: '@@images/image-400.png',
19
+ width: 400,
20
+ height: 400,
21
+ },
22
+ },
23
+ },
24
+ ],
25
+ },
21
26
  title: 'Item title',
22
27
  '@id': 'http://localhost:3000/something',
23
28
  };
24
29
  const component = renderer.create(
25
- <PreviewImage item={item} className="extra" />,
30
+ <PreviewImage item={item} alt={item.title} />,
26
31
  );
27
32
  const json = component.toJSON();
28
33
  expect(json).toMatchSnapshot();
29
34
  });
30
35
 
31
- it('renders a preview image with custom size', () => {
36
+ it('renders a preview image with extra props', () => {
32
37
  const item = {
33
38
  image_field: 'image',
39
+ image_scales: {
40
+ image: [
41
+ {
42
+ download: '@@images/image',
43
+ width: 400,
44
+ height: 400,
45
+ scales: {
46
+ preview: {
47
+ download: '@@images/image-400.png',
48
+ width: 400,
49
+ height: 400,
50
+ },
51
+ },
52
+ },
53
+ ],
54
+ },
34
55
  title: 'Item title',
35
56
  '@id': 'http://localhost:3000/something',
36
57
  };
37
58
  const component = renderer.create(
38
- <PreviewImage item={item} size="large" />,
59
+ <PreviewImage item={item} alt={item.title} className="extra" />,
39
60
  );
40
61
  const json = component.toJSON();
41
62
  expect(json).toMatchSnapshot();
@@ -46,7 +67,9 @@ describe('PreviewImage', () => {
46
67
  title: 'Item title',
47
68
  '@id': 'http://localhost:3000/something',
48
69
  };
49
- const component = renderer.create(<PreviewImage item={item} />);
70
+ const component = renderer.create(
71
+ <PreviewImage item={item} alt={item.title} />,
72
+ );
50
73
  const json = component.toJSON();
51
74
  expect(json).toMatchSnapshot();
52
75
  });
@@ -57,7 +80,7 @@ describe('PreviewImage', () => {
57
80
  '@id': 'http://localhost:3000/something',
58
81
  };
59
82
  const component = renderer.create(
60
- <PreviewImage item={item} className="extra" />,
83
+ <PreviewImage item={item} alt={item.title} className="extra" />,
61
84
  );
62
85
  const json = component.toJSON();
63
86
  expect(json).toMatchSnapshot();
@@ -3,7 +3,7 @@
3
3
  * @module components/theme/View/AlbumView
4
4
  */
5
5
 
6
- import React, { Component } from 'react';
6
+ import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import {
9
9
  Container as SemanticContainer,
@@ -11,7 +11,7 @@ import {
11
11
  Segment,
12
12
  } from 'semantic-ui-react';
13
13
  import { Button, Modal, Grid } from 'semantic-ui-react';
14
- import { Icon, UniversalLink, PreviewImage } from '@plone/volto/components';
14
+ import { Icon, UniversalLink } from '@plone/volto/components';
15
15
  import config from '@plone/volto/registry';
16
16
 
17
17
  import openSVG from '@plone/volto/icons/open.svg';
@@ -24,7 +24,7 @@ import backSVG from '@plone/volto/icons/back.svg';
24
24
  * @param {Object} content Content object.
25
25
  * @returns {string} Markup of the component.
26
26
  */
27
- class AlbumView extends Component {
27
+ class AlbumView extends React.Component {
28
28
  constructor(props) {
29
29
  super(props);
30
30
 
@@ -63,6 +63,8 @@ class AlbumView extends Component {
63
63
  const { content } = this.props;
64
64
  const Container =
65
65
  config.getComponent({ name: 'Container' }).component || SemanticContainer;
66
+ const PreviewImage = config.getComponent({ name: 'PreviewImage' })
67
+ .component;
66
68
 
67
69
  return (
68
70
  <Container className="view-wrapper">
@@ -88,17 +90,16 @@ class AlbumView extends Component {
88
90
  <Segment className="imageborder">
89
91
  <PreviewImage
90
92
  item={item}
91
- alt={
92
- item.image_caption
93
- ? item.image_caption
94
- : item.title
95
- }
93
+ alt={item.image_caption || item.title}
96
94
  onClick={() => {
97
95
  this.setState({
98
96
  openIndex: index,
99
97
  });
100
98
  }}
101
99
  className="ui middle aligned image"
100
+ responsive={true}
101
+ loading="lazy"
102
+ title={item.title}
102
103
  />
103
104
  </Segment>
104
105
  </Grid.Column>
@@ -141,20 +142,15 @@ class AlbumView extends Component {
141
142
  <Modal.Content image>
142
143
  <PreviewImage
143
144
  item={item}
144
- alt={
145
- item.image_caption
146
- ? item.image_caption
147
- : item.title
148
- }
145
+ alt={item.image_caption}
149
146
  onClick={() => {
150
147
  this.setState({
151
148
  openIndex: index,
152
149
  });
153
150
  }}
154
- size="large"
155
151
  className="ui image"
152
+ responsive={true}
156
153
  />
157
-
158
154
  <Modal.Description>
159
155
  <p>{item.description}</p>
160
156
  </Modal.Description>
@@ -6,34 +6,41 @@
6
6
  import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import { hasBlocksData, flattenHTMLToAppURL } from '@plone/volto/helpers';
9
- import { Image, Grid } from 'semantic-ui-react';
9
+ import { Grid } from 'semantic-ui-react';
10
10
  import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
11
11
  import { EventDetails } from '@plone/volto/components';
12
12
  import { Container as SemanticContainer } from 'semantic-ui-react';
13
13
  import config from '@plone/volto/registry';
14
14
 
15
- const EventTextfieldView = ({ content }) => (
16
- <React.Fragment>
17
- {content.title && <h1 className="documentFirstHeading">{content.title}</h1>}
18
- {content.description && (
19
- <p className="documentDescription">{content.description}</p>
20
- )}
21
- {content.image && (
22
- <Image
23
- className="document-image"
24
- src={content.image.scales.thumb.download}
25
- floated="right"
26
- />
27
- )}
28
- {content.text && (
29
- <div
30
- dangerouslySetInnerHTML={{
31
- __html: flattenHTMLToAppURL(content.text.data),
32
- }}
33
- />
34
- )}
35
- </React.Fragment>
36
- );
15
+ const EventTextfieldView = ({ content }) => {
16
+ const Image = config.getComponent({ name: 'Image' }).component;
17
+
18
+ return (
19
+ <React.Fragment>
20
+ {content.title && (
21
+ <h1 className="documentFirstHeading">{content.title}</h1>
22
+ )}
23
+ {content.description && (
24
+ <p className="documentDescription">{content.description}</p>
25
+ )}
26
+ {content.image && (
27
+ <Image
28
+ className="document-image ui right floated image"
29
+ item={content}
30
+ imageField="image"
31
+ alt=""
32
+ />
33
+ )}
34
+ {content.text && (
35
+ <div
36
+ dangerouslySetInnerHTML={{
37
+ __html: flattenHTMLToAppURL(content.text.data),
38
+ }}
39
+ />
40
+ )}
41
+ </React.Fragment>
42
+ );
43
+ };
37
44
 
38
45
  /**
39
46
  * EventView view component class.
@@ -18,6 +18,7 @@ import config from '@plone/volto/registry';
18
18
  * @returns {string} Markup of the component.
19
19
  */
20
20
  const ImageView = ({ content }) => {
21
+ const Image = config.getComponent({ name: 'Image' }).component;
21
22
  const Container =
22
23
  config.getComponent({ name: 'Container' }).component || SemanticContainer;
23
24
 
@@ -32,9 +33,11 @@ const ImageView = ({ content }) => {
32
33
  )}
33
34
  {content?.image?.download && (
34
35
  <a href={flattenToAppURL(content.image.download)}>
35
- <img
36
+ <Image
37
+ item={content}
38
+ imageField="image"
36
39
  alt={content.title}
37
- src={flattenToAppURL(content.image.scales.preview.download)}
40
+ responsive={true}
38
41
  />
39
42
  <figcaption>
40
43
  <FormattedMessage
@@ -23,9 +23,13 @@ test('renders an image view component', () => {
23
23
  image: {
24
24
  size: 123123,
25
25
  download: 'file:///preview.jpg',
26
+ width: 400,
27
+ height: 400,
26
28
  scales: {
27
29
  preview: {
28
30
  download: 'file:///preview.jpg',
31
+ width: 400,
32
+ height: 400,
29
33
  },
30
34
  },
31
35
  },
@@ -6,7 +6,7 @@
6
6
  import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import { Segment, Container as SemanticContainer } from 'semantic-ui-react';
9
- import { UniversalLink, PreviewImage } from '@plone/volto/components';
9
+ import { UniversalLink } from '@plone/volto/components';
10
10
  import config from '@plone/volto/registry';
11
11
 
12
12
  /**
@@ -18,6 +18,7 @@ import config from '@plone/volto/registry';
18
18
  const ListingView = ({ content }) => {
19
19
  const Container =
20
20
  config.getComponent({ name: 'Container' }).component || SemanticContainer;
21
+ const PreviewImage = config.getComponent({ name: 'PreviewImage' }).component;
21
22
 
22
23
  return (
23
24
  <Container id="page-home">
@@ -35,9 +36,10 @@ const ListingView = ({ content }) => {
35
36
  {item.image_field && (
36
37
  <PreviewImage
37
38
  item={item}
38
- size="thumb"
39
- alt={item.image_caption ? item.image_caption : item.title}
39
+ alt={item.image_caption}
40
40
  className="ui image"
41
+ responsive={true}
42
+ loading="lazy"
41
43
  />
42
44
  )}
43
45
  </Segment>