@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.
- package/.gitignore~ +71 -0
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +49 -0
- package/cypress/support/commands.js +2 -1
- package/cypress/support/e2e.js +1 -2
- package/locales/ca/LC_MESSAGES/volto.po +24 -5
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +37 -18
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +25 -6
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +25 -6
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +24 -5
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +24 -5
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +24 -5
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +250 -231
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +24 -5
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +24 -5
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +24 -5
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +25 -6
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +24 -5
- package/locales/ro.json +1 -1
- package/locales/volto.pot +25 -6
- package/locales/zh_CN/LC_MESSAGES/volto.po +24 -5
- package/locales/zh_CN.json +1 -1
- package/news/4547.breaking~ +1 -0
- package/package.json +6 -6
- package/packages/volto-slate/package.json +1 -1
- package/src/actions/relations/rebuild.js +7 -7
- package/src/components/index.js +1 -0
- package/src/components/manage/Actions/Actions.jsx +133 -243
- package/src/components/manage/Blocks/Container/Edit.jsx +4 -1
- package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +1 -0
- package/src/components/manage/Blocks/Grid/Edit.jsx +13 -1
- package/src/components/manage/Blocks/Image/Edit.jsx +40 -5
- package/src/components/manage/Blocks/Image/Edit.test.jsx +2 -0
- package/src/components/manage/Blocks/Image/ImageSidebar.jsx +64 -15
- package/src/components/manage/Blocks/Image/View.jsx +26 -5
- package/src/components/manage/Blocks/Image/View.test.jsx +20 -0
- package/src/components/manage/Blocks/Image/schema.js +1 -9
- package/src/components/manage/Blocks/Image/utils.js +14 -0
- package/src/components/manage/Blocks/LeadImage/Edit.jsx +32 -10
- package/src/components/manage/Blocks/LeadImage/Edit.test.jsx +11 -1
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +28 -9
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +8 -2
- package/src/components/manage/Blocks/LeadImage/View.jsx +50 -38
- package/src/components/manage/Blocks/LeadImage/View.test.jsx +11 -1
- package/src/components/manage/Blocks/Listing/SummaryTemplate.jsx +1 -1
- package/src/components/manage/Blocks/Maps/Edit.jsx +135 -209
- package/src/components/manage/Blocks/Search/SearchBlockView.jsx +3 -2
- package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +13 -23
- package/src/components/manage/Contents/Contents.jsx +8 -6
- package/src/components/manage/Contents/ContentsPropertiesModal.jsx +1 -13
- package/src/components/manage/Controlpanels/Groups/RenderGroups.jsx +2 -2
- package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +30 -7
- package/src/components/manage/Controlpanels/Relations/Relations.jsx +2 -2
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +53 -59
- package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +2 -2
- package/src/components/manage/Delete/Delete.jsx +96 -171
- package/src/components/manage/Sidebar/AlignBlock.jsx +1 -1
- package/src/components/manage/Widgets/SelectUtils.js +1 -1
- package/src/components/manage/Workflow/Workflow.jsx +75 -184
- package/src/components/theme/Image/Image.jsx +96 -0
- package/src/components/theme/Image/Image.test.jsx +125 -0
- package/src/components/theme/Logo/Logo.jsx +2 -0
- package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +95 -170
- package/src/components/theme/PreviewImage/PreviewImage.jsx +25 -14
- package/src/components/theme/PreviewImage/PreviewImage.test.js +39 -16
- package/src/components/theme/View/AlbumView.jsx +11 -15
- package/src/components/theme/View/EventView.jsx +30 -23
- package/src/components/theme/View/ImageView.jsx +5 -2
- package/src/components/theme/View/ImageView.test.jsx +4 -0
- package/src/components/theme/View/ListingView.jsx +5 -3
- package/src/components/theme/View/NewsItemView.jsx +7 -13
- package/src/components/theme/View/SummaryView.jsx +4 -3
- package/src/config/Blocks.jsx +2 -0
- package/src/config/Components.jsx +3 -1
- package/src/config/index.js~ +223 -0
- package/src/express-middleware/files.js +8 -6
- package/src/express-middleware/images.js +7 -1
- package/src/helpers/MessageLabels/MessageLabels.js +6 -0
- package/src/helpers/Url/Url.js +22 -1
- package/src/helpers/Url/Url.test.js +41 -0
- package/src/reducers/relations/relations.js +1 -1
- package/test-setup-config.js +9 -1
- package/theme/themes/pastanaga/extras/blocks.less +3 -1
- package/theme/themes/pastanaga/extras/main.less +5 -0
- package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +0 -90
- package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +0 -6
- package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +0 -6
- package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +0 -6
- package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +0 -10
- package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +0 -10
- package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +0 -30
- package/packages/volto-slate/build/messages/src/elementEditor/messages.json +0 -10
- package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +0 -6
- package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +0 -6
- package/src/components/manage/Blocks/Teaser/utils.js +0 -44
- package/src/components/manage/Blocks/Teaser/utils.test.jsx +0 -229
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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,
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
122
|
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
147
|
-
|
|
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
|
-
|
|
165
|
-
|
|
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
|
-
<
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
</
|
|
217
|
-
</
|
|
120
|
+
</p>
|
|
121
|
+
</Container>
|
|
218
122
|
);
|
|
219
123
|
}
|
|
220
|
-
}
|
|
221
124
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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(
|
|
14
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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}
|
|
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
|
|
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}
|
|
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(
|
|
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
|
|
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
|
|
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 {
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
<
|
|
36
|
+
<Image
|
|
37
|
+
item={content}
|
|
38
|
+
imageField="image"
|
|
36
39
|
alt={content.title}
|
|
37
|
-
|
|
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
|
|
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
|
-
|
|
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>
|