@plone/volto 17.0.0-alpha.0 → 17.0.0-alpha.2
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/.changelog.draft +21 -12
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +118 -5
- package/README.md +4 -4
- package/cypress/support/commands.js +25 -0
- package/locales/ca/LC_MESSAGES/volto.po +5 -0
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +5 -0
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +5 -0
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +5 -0
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +5 -0
- package/locales/eu.json +1 -1
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +5 -0
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +5 -0
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +5 -0
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +5 -0
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +5 -0
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +5 -0
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +5 -0
- package/locales/ro.json +1 -1
- package/locales/volto.pot +5 -0
- package/locales/zh_CN/LC_MESSAGES/volto.po +5 -0
- package/locales/zh_CN.json +1 -1
- package/package-why.json +0 -1
- package/package.json +7 -7
- package/packages/volto-slate/package.json +1 -1
- package/packages/volto-slate/src/blocks/Table/TableBlockView.jsx +4 -4
- package/packages/volto-slate/src/blocks/Table/index.js +2 -0
- package/src/components/manage/BlockChooser/BlockChooserButton.jsx +63 -29
- package/src/components/manage/BlockChooser/BlockChooserSearch.jsx +0 -1
- package/src/components/manage/Blocks/Listing/Edit.jsx +0 -5
- package/src/components/manage/Blocks/Listing/ListingBody.jsx +77 -61
- package/src/components/manage/Blocks/Listing/View.jsx +0 -4
- package/src/components/manage/Blocks/ToC/Edit.jsx +1 -0
- package/src/components/manage/Contents/Contents.jsx +35 -8
- package/src/components/manage/Controlpanels/Controlpanels.jsx +1 -1
- package/src/components/manage/DragDropList/DragDropList.jsx +63 -42
- package/src/components/manage/Form/BlocksToolbar.jsx +5 -1
- package/src/components/manage/Form/Form.jsx +6 -2
- package/src/components/manage/History/History.jsx +35 -18
- package/src/components/theme/View/EventView.jsx +1 -1
- package/src/components/theme/View/NewsItemView.jsx +1 -1
- package/src/config/index.js +1 -0
- package/src/config/server.js +19 -0
- package/src/express-middleware/devproxy.js +4 -2
- package/src/express-middleware/static.js +32 -0
- package/src/server.jsx +1 -7
- package/src/start-server.js +4 -2
- package/theme/themes/pastanaga/extras/blocks.less +0 -9
- package/theme/themes/pastanaga/extras/contents.less +1 -0
- package/theme/themes/pastanaga/extras/main.less +80 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { createRef } from 'react';
|
|
2
2
|
import { FormattedMessage, injectIntl } from 'react-intl';
|
|
3
|
+
import cx from 'classnames';
|
|
3
4
|
import { Pagination, Dimmer, Loader } from 'semantic-ui-react';
|
|
4
5
|
import { Icon } from '@plone/volto/components';
|
|
5
6
|
import config from '@plone/volto/registry';
|
|
@@ -44,70 +45,85 @@ const ListingBody = withQuerystringResults((props) => {
|
|
|
44
45
|
? variation.noResultsComponent
|
|
45
46
|
: config.blocks?.blocksConfig['listing'].noResultsComponent;
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
prevItem={{
|
|
68
|
-
content: <Icon name={paginationLeftSVG} size="18px" />,
|
|
69
|
-
icon: true,
|
|
70
|
-
'aria-disabled': !prevBatch,
|
|
71
|
-
className: !prevBatch ? 'disabled' : null,
|
|
72
|
-
}}
|
|
73
|
-
nextItem={{
|
|
74
|
-
content: <Icon name={paginationRightSVG} size="18px" />,
|
|
75
|
-
icon: true,
|
|
76
|
-
'aria-disabled': !nextBatch,
|
|
77
|
-
className: !nextBatch ? 'disabled' : null,
|
|
78
|
-
}}
|
|
48
|
+
const HeadlineTag = data.headlineTag || 'h2';
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
{data.headline && (
|
|
53
|
+
<HeadlineTag
|
|
54
|
+
className={cx('headline', {
|
|
55
|
+
emptyListing: !listingItems?.length > 0,
|
|
56
|
+
})}
|
|
57
|
+
>
|
|
58
|
+
{data.headline}
|
|
59
|
+
</HeadlineTag>
|
|
60
|
+
)}
|
|
61
|
+
{listingItems?.length > 0 ? (
|
|
62
|
+
<div ref={listingRef}>
|
|
63
|
+
<ListingBodyTemplate
|
|
64
|
+
items={listingItems}
|
|
65
|
+
isEditMode={isEditMode}
|
|
66
|
+
{...data}
|
|
67
|
+
{...variation}
|
|
79
68
|
/>
|
|
69
|
+
{totalPages > 1 && (
|
|
70
|
+
<div className="pagination-wrapper">
|
|
71
|
+
<Pagination
|
|
72
|
+
activePage={currentPage}
|
|
73
|
+
totalPages={totalPages}
|
|
74
|
+
onPageChange={(e, { activePage }) => {
|
|
75
|
+
!isEditMode &&
|
|
76
|
+
listingRef.current.scrollIntoView({ behavior: 'smooth' });
|
|
77
|
+
onPaginationChange(e, { activePage });
|
|
78
|
+
}}
|
|
79
|
+
firstItem={null}
|
|
80
|
+
lastItem={null}
|
|
81
|
+
prevItem={{
|
|
82
|
+
content: <Icon name={paginationLeftSVG} size="18px" />,
|
|
83
|
+
icon: true,
|
|
84
|
+
'aria-disabled': !prevBatch,
|
|
85
|
+
className: !prevBatch ? 'disabled' : null,
|
|
86
|
+
}}
|
|
87
|
+
nextItem={{
|
|
88
|
+
content: <Icon name={paginationRightSVG} size="18px" />,
|
|
89
|
+
icon: true,
|
|
90
|
+
'aria-disabled': !nextBatch,
|
|
91
|
+
className: !nextBatch ? 'disabled' : null,
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
97
|
+
) : isEditMode ? (
|
|
98
|
+
<div className="listing message" ref={listingRef}>
|
|
99
|
+
{isFolderContentsListing && (
|
|
100
|
+
<FormattedMessage
|
|
101
|
+
id="No items found in this container."
|
|
102
|
+
defaultMessage="No items found in this container."
|
|
103
|
+
/>
|
|
104
|
+
)}
|
|
105
|
+
{hasLoaded && NoResults && (
|
|
106
|
+
<NoResults isEditMode={isEditMode} {...data} />
|
|
107
|
+
)}
|
|
108
|
+
<Dimmer active={!hasLoaded} inverted>
|
|
109
|
+
<Loader indeterminate size="small">
|
|
110
|
+
<FormattedMessage id="loading" defaultMessage="Loading" />
|
|
111
|
+
</Loader>
|
|
112
|
+
</Dimmer>
|
|
113
|
+
</div>
|
|
114
|
+
) : (
|
|
115
|
+
<div className="emptyListing">
|
|
116
|
+
{hasLoaded && NoResults && (
|
|
117
|
+
<NoResults isEditMode={isEditMode} {...data} />
|
|
118
|
+
)}
|
|
119
|
+
<Dimmer active={!hasLoaded} inverted>
|
|
120
|
+
<Loader indeterminate size="small">
|
|
121
|
+
<FormattedMessage id="loading" defaultMessage="Loading" />
|
|
122
|
+
</Loader>
|
|
123
|
+
</Dimmer>
|
|
80
124
|
</div>
|
|
81
125
|
)}
|
|
82
|
-
|
|
83
|
-
) : isEditMode ? (
|
|
84
|
-
<div className="listing message" ref={listingRef}>
|
|
85
|
-
{isFolderContentsListing && (
|
|
86
|
-
<FormattedMessage
|
|
87
|
-
id="No items found in this container."
|
|
88
|
-
defaultMessage="No items found in this container."
|
|
89
|
-
/>
|
|
90
|
-
)}
|
|
91
|
-
{hasLoaded && NoResults && (
|
|
92
|
-
<NoResults isEditMode={isEditMode} {...data} />
|
|
93
|
-
)}
|
|
94
|
-
<Dimmer active={!hasLoaded} inverted>
|
|
95
|
-
<Loader indeterminate size="small">
|
|
96
|
-
<FormattedMessage id="loading" defaultMessage="Loading" />
|
|
97
|
-
</Loader>
|
|
98
|
-
</Dimmer>
|
|
99
|
-
</div>
|
|
100
|
-
) : (
|
|
101
|
-
<div>
|
|
102
|
-
{hasLoaded && NoResults && (
|
|
103
|
-
<NoResults isEditMode={isEditMode} {...data} />
|
|
104
|
-
)}
|
|
105
|
-
<Dimmer active={!hasLoaded} inverted>
|
|
106
|
-
<Loader indeterminate size="small">
|
|
107
|
-
<FormattedMessage id="loading" defaultMessage="Loading" />
|
|
108
|
-
</Loader>
|
|
109
|
-
</Dimmer>
|
|
110
|
-
</div>
|
|
126
|
+
</>
|
|
111
127
|
);
|
|
112
128
|
});
|
|
113
129
|
|
|
@@ -7,15 +7,11 @@ import { ListingBlockBody as ListingBody } from '@plone/volto/components';
|
|
|
7
7
|
|
|
8
8
|
const View = (props) => {
|
|
9
9
|
const { data, path, pathname, className } = props;
|
|
10
|
-
const HeadlineTag = data.headlineTag || 'h2';
|
|
11
10
|
|
|
12
11
|
return (
|
|
13
12
|
<div
|
|
14
13
|
className={cx('block listing', data.variation || 'default', className)}
|
|
15
14
|
>
|
|
16
|
-
{data.headline && (
|
|
17
|
-
<HeadlineTag className="headline">{data.headline}</HeadlineTag>
|
|
18
|
-
)}
|
|
19
15
|
<ListingBody {...props} path={path ?? pathname} />
|
|
20
16
|
</div>
|
|
21
17
|
);
|
|
@@ -290,6 +290,10 @@ const messages = defineMessages({
|
|
|
290
290
|
id: 'This Page is referenced by the following items:',
|
|
291
291
|
defaultMessage: 'This Page is referenced by the following items:',
|
|
292
292
|
},
|
|
293
|
+
deleteItemCountMessage: {
|
|
294
|
+
id: 'Total items to be deleted:',
|
|
295
|
+
defaultMessage: 'Total items to be deleted:',
|
|
296
|
+
},
|
|
293
297
|
deleteItemMessage: {
|
|
294
298
|
id: 'Items to be deleted:',
|
|
295
299
|
defaultMessage: 'Items to be deleted:',
|
|
@@ -418,6 +422,8 @@ class Contents extends Component {
|
|
|
418
422
|
this.paste = this.paste.bind(this);
|
|
419
423
|
this.fetchContents = this.fetchContents.bind(this);
|
|
420
424
|
this.orderTimeout = null;
|
|
425
|
+
this.deleteItemsToShowThreshold = 10;
|
|
426
|
+
|
|
421
427
|
this.state = {
|
|
422
428
|
selected: [],
|
|
423
429
|
showDelete: false,
|
|
@@ -427,6 +433,7 @@ class Contents extends Component {
|
|
|
427
433
|
showProperties: false,
|
|
428
434
|
showWorkflow: false,
|
|
429
435
|
itemsToDelete: [],
|
|
436
|
+
showAllItemsToDelete: true,
|
|
430
437
|
items: this.props.items,
|
|
431
438
|
filter: '',
|
|
432
439
|
currentPage: 0,
|
|
@@ -456,7 +463,6 @@ class Contents extends Component {
|
|
|
456
463
|
this.fetchContents();
|
|
457
464
|
this.setState({ isClient: true });
|
|
458
465
|
}
|
|
459
|
-
|
|
460
466
|
async componentDidUpdate(_, prevState) {
|
|
461
467
|
if (
|
|
462
468
|
this.state.itemsToDelete !== prevState.itemsToDelete &&
|
|
@@ -468,6 +474,8 @@ class Contents extends Component {
|
|
|
468
474
|
this.getFieldById(item, 'UID'),
|
|
469
475
|
),
|
|
470
476
|
),
|
|
477
|
+
showAllItemsToDelete:
|
|
478
|
+
this.state.itemsToDelete.length < this.deleteItemsToShowThreshold,
|
|
471
479
|
});
|
|
472
480
|
}
|
|
473
481
|
}
|
|
@@ -1188,16 +1196,35 @@ class Contents extends Component {
|
|
|
1188
1196
|
<div className="content">
|
|
1189
1197
|
<h3>
|
|
1190
1198
|
{this.props.intl.formatMessage(
|
|
1191
|
-
messages.
|
|
1192
|
-
)}
|
|
1199
|
+
messages.deleteItemCountMessage,
|
|
1200
|
+
) + ` ${this.state.itemsToDelete.length}`}
|
|
1193
1201
|
</h3>
|
|
1194
1202
|
<ul className="content">
|
|
1195
|
-
{map(
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1203
|
+
{map(
|
|
1204
|
+
this.state.showAllItemsToDelete
|
|
1205
|
+
? this.state.itemsToDelete
|
|
1206
|
+
: this.state.itemsToDelete.slice(
|
|
1207
|
+
0,
|
|
1208
|
+
this.deleteItemsToShowThreshold,
|
|
1209
|
+
),
|
|
1210
|
+
(item) => (
|
|
1211
|
+
<li key={item}>
|
|
1212
|
+
{this.getFieldById(item, 'title')}
|
|
1213
|
+
</li>
|
|
1214
|
+
),
|
|
1215
|
+
)}
|
|
1200
1216
|
</ul>
|
|
1217
|
+
{!this.state.showAllItemsToDelete && (
|
|
1218
|
+
<Button
|
|
1219
|
+
onClick={() =>
|
|
1220
|
+
this.setState({
|
|
1221
|
+
showAllItemsToDelete: true,
|
|
1222
|
+
})
|
|
1223
|
+
}
|
|
1224
|
+
>
|
|
1225
|
+
Show all items
|
|
1226
|
+
</Button>
|
|
1227
|
+
)}
|
|
1201
1228
|
{this.state.linkIntegrityBreakages.length > 0 ? (
|
|
1202
1229
|
<div>
|
|
1203
1230
|
<h3>
|
|
@@ -270,7 +270,7 @@ class Controlpanels extends Component {
|
|
|
270
270
|
{group}
|
|
271
271
|
</Segment>,
|
|
272
272
|
<Segment key={`body-${group}`} attached>
|
|
273
|
-
<Grid columns={6}>
|
|
273
|
+
<Grid doubling columns={6}>
|
|
274
274
|
<Grid.Row>
|
|
275
275
|
{map(filter(controlpanels, { group }), (controlpanel) => (
|
|
276
276
|
<Grid.Column key={controlpanel.id}>
|
|
@@ -3,7 +3,7 @@ import { isEmpty } from 'lodash';
|
|
|
3
3
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
4
4
|
import { v4 as uuid } from 'uuid';
|
|
5
5
|
|
|
6
|
-
const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex) => {
|
|
6
|
+
const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex, uid) => {
|
|
7
7
|
// Because of the margin rendering rules, there is no easy
|
|
8
8
|
// way to calculate the offset of the placeholder.
|
|
9
9
|
//
|
|
@@ -13,12 +13,16 @@ const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex) => {
|
|
|
13
13
|
//
|
|
14
14
|
// To get a placeholder that looks good in all cases, we
|
|
15
15
|
// fill up the space between the previous and the next element.
|
|
16
|
-
const
|
|
16
|
+
const queryAttr = 'data-rbd-droppable-id';
|
|
17
|
+
const domQuery = `[${queryAttr}='${uid}']`;
|
|
18
|
+
const parentDOM = document.querySelector(domQuery);
|
|
19
|
+
|
|
20
|
+
const childrenArray = [...parentDOM.children];
|
|
17
21
|
// Remove the source element
|
|
18
22
|
childrenArray.splice(sourceIndex, 1);
|
|
19
23
|
// Also remove the placeholder that the library always inserts at the end
|
|
20
24
|
childrenArray.splice(-1, 1);
|
|
21
|
-
const parentRect =
|
|
25
|
+
const parentRect = parentDOM.getBoundingClientRect();
|
|
22
26
|
const prevNode = childrenArray[destinationIndex - 1];
|
|
23
27
|
const nextNode = childrenArray[destinationIndex];
|
|
24
28
|
let top, bottom;
|
|
@@ -40,9 +44,7 @@ const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex) => {
|
|
|
40
44
|
return {
|
|
41
45
|
clientY: top,
|
|
42
46
|
clientHeight: bottom - top,
|
|
43
|
-
clientX: parseFloat(
|
|
44
|
-
window.getComputedStyle(draggedDOM.parentNode).paddingLeft,
|
|
45
|
-
),
|
|
47
|
+
clientX: parseFloat(window.getComputedStyle(parentDOM).paddingLeft),
|
|
46
48
|
clientWidth: draggedDOM.clientWidth,
|
|
47
49
|
};
|
|
48
50
|
};
|
|
@@ -63,17 +65,22 @@ const DragDropList = (props) => {
|
|
|
63
65
|
// queueing timed action
|
|
64
66
|
const timer = useRef(null);
|
|
65
67
|
|
|
66
|
-
const onDragStart = React.useCallback(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
const onDragStart = React.useCallback(
|
|
69
|
+
(event) => {
|
|
70
|
+
clearTimeout(timer.current);
|
|
71
|
+
const queryAttr = 'data-rbd-draggable-id';
|
|
72
|
+
const domQuery = `[${queryAttr}='${event.draggableId}']`;
|
|
73
|
+
const draggedDOM = document.querySelector(domQuery);
|
|
74
|
+
if (!draggedDOM) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const sourceIndex = event.source.index;
|
|
78
|
+
setPlaceholderProps(
|
|
79
|
+
getPlaceholder(draggedDOM, sourceIndex, sourceIndex, uid),
|
|
80
|
+
);
|
|
81
|
+
},
|
|
82
|
+
[uid],
|
|
83
|
+
);
|
|
77
84
|
|
|
78
85
|
const onDragEnd = React.useCallback(
|
|
79
86
|
(result) => {
|
|
@@ -84,30 +91,33 @@ const DragDropList = (props) => {
|
|
|
84
91
|
[onMoveItem],
|
|
85
92
|
);
|
|
86
93
|
|
|
87
|
-
const onDragUpdate = React.useCallback(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
94
|
+
const onDragUpdate = React.useCallback(
|
|
95
|
+
(update) => {
|
|
96
|
+
clearTimeout(timer.current);
|
|
97
|
+
setPlaceholderProps({});
|
|
98
|
+
if (!update.destination) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const draggableId = update.draggableId;
|
|
102
|
+
const queryAttr = 'data-rbd-draggable-id';
|
|
103
|
+
const domQuery = `[${queryAttr}='${draggableId}']`;
|
|
104
|
+
const draggedDOM = document.querySelector(domQuery);
|
|
105
|
+
if (!draggedDOM) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const sourceIndex = update.source.index;
|
|
109
|
+
const destinationIndex = update.destination.index;
|
|
110
|
+
// Wait until the animations have finished, to make it look good.
|
|
111
|
+
timer.current = setTimeout(
|
|
112
|
+
() =>
|
|
113
|
+
setPlaceholderProps(
|
|
114
|
+
getPlaceholder(draggedDOM, sourceIndex, destinationIndex, uid),
|
|
115
|
+
),
|
|
116
|
+
250,
|
|
117
|
+
);
|
|
118
|
+
},
|
|
119
|
+
[uid],
|
|
120
|
+
);
|
|
111
121
|
|
|
112
122
|
const AsDomComponent = as;
|
|
113
123
|
return (
|
|
@@ -116,7 +126,18 @@ const DragDropList = (props) => {
|
|
|
116
126
|
onDragUpdate={onDragUpdate}
|
|
117
127
|
onDragEnd={onDragEnd}
|
|
118
128
|
>
|
|
119
|
-
<Droppable
|
|
129
|
+
<Droppable
|
|
130
|
+
droppableId={uid}
|
|
131
|
+
renderClone={(provided, snapshot, rubric) => {
|
|
132
|
+
const index = rubric.source.index;
|
|
133
|
+
return children({
|
|
134
|
+
child: childList[index][1],
|
|
135
|
+
childId: childList[index][0],
|
|
136
|
+
index,
|
|
137
|
+
draginfo: provided,
|
|
138
|
+
});
|
|
139
|
+
}}
|
|
140
|
+
>
|
|
120
141
|
{(provided, snapshot) => (
|
|
121
142
|
<AsDomComponent
|
|
122
143
|
ref={provided.innerRef}
|
|
@@ -177,7 +177,11 @@ export class BlocksToolbarComponent extends React.Component {
|
|
|
177
177
|
''
|
|
178
178
|
)}
|
|
179
179
|
{selectedBlock && (blocksClipboard?.cut || blocksClipboard?.copy) && (
|
|
180
|
-
<Plug
|
|
180
|
+
<Plug
|
|
181
|
+
pluggable="main.toolbar.bottom"
|
|
182
|
+
id="block-paste-btn"
|
|
183
|
+
dependencies={[selectedBlock]}
|
|
184
|
+
>
|
|
181
185
|
<button
|
|
182
186
|
aria-label={intl.formatMessage(messages.pasteBlocks)}
|
|
183
187
|
onClick={this.pasteBlocks}
|
|
@@ -258,7 +258,11 @@ class Form extends Component {
|
|
|
258
258
|
* Tab selection is done only by setting activeIndex in state
|
|
259
259
|
*/
|
|
260
260
|
onTabChange(e, { activeIndex }) {
|
|
261
|
-
this.
|
|
261
|
+
const defaultFocus = this.props.schema.fieldsets[activeIndex].fields[0];
|
|
262
|
+
this.setState({
|
|
263
|
+
activeIndex,
|
|
264
|
+
...(defaultFocus ? { inFocus: { [defaultFocus]: true } } : {}),
|
|
265
|
+
});
|
|
262
266
|
}
|
|
263
267
|
|
|
264
268
|
/**
|
|
@@ -686,7 +690,7 @@ class Form extends Component {
|
|
|
686
690
|
id={field}
|
|
687
691
|
formData={this.state.formData}
|
|
688
692
|
fieldSet={item.title.toLowerCase()}
|
|
689
|
-
focus={
|
|
693
|
+
focus={this.state.inFocus[field]}
|
|
690
694
|
value={this.state.formData?.[field]}
|
|
691
695
|
required={schema.required.indexOf(field) !== -1}
|
|
692
696
|
onChange={this.onChangeField}
|
|
@@ -116,22 +116,37 @@ class History extends Component {
|
|
|
116
116
|
this.props.revertHistory(getBaseUrl(this.props.pathname), value);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
* @returns {string} Markup for the component.
|
|
123
|
-
*/
|
|
124
|
-
render() {
|
|
119
|
+
processHistoryEntries = () => {
|
|
120
|
+
// Getting the history entries from the props
|
|
121
|
+
// No clue why the reverse(concat()) is necessary
|
|
125
122
|
const entries = reverse(concat(this.props.entries));
|
|
126
123
|
let title = entries.length > 0 ? entries[0].state_title : '';
|
|
127
124
|
for (let x = 1; x < entries.length; x += 1) {
|
|
128
125
|
entries[x].prev_state_title = title;
|
|
129
126
|
title = entries[x].state_title || title;
|
|
130
127
|
}
|
|
128
|
+
// We reverse them again
|
|
131
129
|
reverse(entries);
|
|
130
|
+
|
|
131
|
+
// We identify the latest 'versioning' entry and mark it
|
|
132
|
+
const current_version = find(entries, (item) => item.type === 'versioning');
|
|
133
|
+
if (current_version) {
|
|
134
|
+
current_version.is_current = true;
|
|
135
|
+
}
|
|
136
|
+
return entries;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Render method.
|
|
141
|
+
* @method render
|
|
142
|
+
* @returns {string} Markup for the component.
|
|
143
|
+
*/
|
|
144
|
+
render() {
|
|
132
145
|
const historyAction = find(this.props.objectActions, {
|
|
133
146
|
id: 'history',
|
|
134
147
|
});
|
|
148
|
+
const entries = this.processHistoryEntries();
|
|
149
|
+
|
|
135
150
|
return !historyAction ? (
|
|
136
151
|
<>
|
|
137
152
|
{this.props.token ? (
|
|
@@ -266,18 +281,20 @@ class History extends Component {
|
|
|
266
281
|
/>
|
|
267
282
|
</Link>
|
|
268
283
|
)}
|
|
269
|
-
{'version' in entry &&
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
284
|
+
{'version' in entry &&
|
|
285
|
+
entry.may_revert &&
|
|
286
|
+
!entry.is_current && (
|
|
287
|
+
<Dropdown.Item
|
|
288
|
+
value={entry.version}
|
|
289
|
+
onClick={this.onRevert}
|
|
290
|
+
>
|
|
291
|
+
<Icon name="undo" />{' '}
|
|
292
|
+
<FormattedMessage
|
|
293
|
+
id="Revert to this revision"
|
|
294
|
+
defaultMessage="Revert to this revision"
|
|
295
|
+
/>
|
|
296
|
+
</Dropdown.Item>
|
|
297
|
+
)}
|
|
281
298
|
</Dropdown.Menu>
|
|
282
299
|
</Dropdown>
|
|
283
300
|
)}
|
|
@@ -43,7 +43,7 @@ const EventView = (props) => {
|
|
|
43
43
|
const { content } = props;
|
|
44
44
|
|
|
45
45
|
return (
|
|
46
|
-
<div id="page-document" className="ui container
|
|
46
|
+
<div id="page-document" className="ui container view-wrapper event-view">
|
|
47
47
|
<Grid>
|
|
48
48
|
<Grid.Column width={7} className="mobile hidden">
|
|
49
49
|
{hasBlocksData(content) ? (
|
|
@@ -21,7 +21,7 @@ import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
|
|
|
21
21
|
*/
|
|
22
22
|
const NewsItemView = ({ content }) =>
|
|
23
23
|
hasBlocksData(content) ? (
|
|
24
|
-
<div id="page-document" className="ui container
|
|
24
|
+
<div id="page-document" className="ui container view-wrapper newsitem-view">
|
|
25
25
|
<RenderBlocks content={content} />
|
|
26
26
|
</div>
|
|
27
27
|
) : (
|
package/src/config/index.js
CHANGED
|
@@ -89,6 +89,7 @@ let config = {
|
|
|
89
89
|
// https://6.docs.plone.org/volto/deploying/seamless-mode.html
|
|
90
90
|
devProxyToApiPath:
|
|
91
91
|
process.env.RAZZLE_DEV_PROXY_API_PATH ||
|
|
92
|
+
process.env.RAZZLE_INTERNAL_API_PATH ||
|
|
92
93
|
process.env.RAZZLE_API_PATH ||
|
|
93
94
|
'http://localhost:8080/Plone', // Set it to '' for disabling the proxy
|
|
94
95
|
// proxyRewriteTarget Set it for set a custom target for the proxy or overide the internal VHM rewrite
|
package/src/config/server.js
CHANGED
|
@@ -2,6 +2,7 @@ import imagesMiddleware from '@plone/volto/express-middleware/images';
|
|
|
2
2
|
import filesMiddleware from '@plone/volto/express-middleware/files';
|
|
3
3
|
import robotstxtMiddleware from '@plone/volto/express-middleware/robotstxt';
|
|
4
4
|
import sitemapMiddleware from '@plone/volto/express-middleware/sitemap';
|
|
5
|
+
import staticsMiddleware from '@plone/volto/express-middleware/static';
|
|
5
6
|
import devProxyMiddleware from '@plone/volto/express-middleware/devproxy';
|
|
6
7
|
|
|
7
8
|
const settings = {
|
|
@@ -11,10 +12,28 @@ const settings = {
|
|
|
11
12
|
imagesMiddleware(),
|
|
12
13
|
robotstxtMiddleware(),
|
|
13
14
|
sitemapMiddleware(),
|
|
15
|
+
staticsMiddleware(),
|
|
14
16
|
],
|
|
15
17
|
criticalCssPath: 'public/critical.css',
|
|
16
18
|
readCriticalCss: null, // so it will be defaultReadCriticalCss
|
|
17
19
|
extractScripts: { errorPages: false },
|
|
20
|
+
staticFiles: [
|
|
21
|
+
{
|
|
22
|
+
id: 'root_static',
|
|
23
|
+
match: /^\/static\/.*/,
|
|
24
|
+
headers: {
|
|
25
|
+
// stable resources never change. 31536000 seconds == 365 days
|
|
26
|
+
'Cache-Control': 'public, max-age=31536000',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'all',
|
|
31
|
+
match: /.*/,
|
|
32
|
+
headers: {
|
|
33
|
+
'Cache-Control': 'public, max-age=60',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
18
37
|
};
|
|
19
38
|
|
|
20
39
|
export default settings;
|
|
@@ -75,12 +75,14 @@ export default function () {
|
|
|
75
75
|
const { apiPathURL, instancePath } = getEnv();
|
|
76
76
|
const target =
|
|
77
77
|
config.settings.proxyRewriteTarget ||
|
|
78
|
-
`/VirtualHostBase
|
|
78
|
+
`/VirtualHostBase/${apiPathURL.protocol.slice(0, -1)}/${
|
|
79
|
+
apiPathURL.hostname
|
|
80
|
+
}:${apiPathURL.port}${instancePath}/++api++/VirtualHostRoot`;
|
|
79
81
|
|
|
80
82
|
return `${target}${path.replace('/++api++', '')}`;
|
|
81
83
|
},
|
|
82
84
|
logLevel: process.env.DEBUG_HPM ? 'debug' : 'silent',
|
|
83
|
-
...(
|
|
85
|
+
...(process.env.RAZZLE_DEV_PROXY_INSECURE && {
|
|
84
86
|
changeOrigin: true,
|
|
85
87
|
secure: false,
|
|
86
88
|
}),
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import config from '@plone/volto/registry';
|
|
4
|
+
|
|
5
|
+
const staticMiddleware = express.static(
|
|
6
|
+
process.env.BUILD_DIR
|
|
7
|
+
? path.join(process.env.BUILD_DIR, 'public')
|
|
8
|
+
: process.env.RAZZLE_PUBLIC_DIR,
|
|
9
|
+
{
|
|
10
|
+
setHeaders: function (res, path) {
|
|
11
|
+
const pathLib = require('path');
|
|
12
|
+
const base = pathLib.resolve(process.env.RAZZLE_PUBLIC_DIR);
|
|
13
|
+
const relpath = path.substr(base.length);
|
|
14
|
+
config.settings.serverConfig.staticFiles.some((elem) => {
|
|
15
|
+
if (relpath.match(elem.match)) {
|
|
16
|
+
for (const name in elem.headers) {
|
|
17
|
+
res.setHeader(name, elem.headers[name] || 'undefined');
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
export default function () {
|
|
28
|
+
const middleware = express.Router();
|
|
29
|
+
middleware.all('*', staticMiddleware);
|
|
30
|
+
middleware.id = 'staticResourcesProcessor';
|
|
31
|
+
return middleware;
|
|
32
|
+
}
|