@eeacms/volto-cca-policy 0.2.7 → 0.2.9
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.md +27 -0
- package/package.json +1 -1
- package/src/components/manage/Blocks/CaseStudyExplorer/CaseStudyFilters.jsx +12 -3
- package/src/components/manage/Blocks/TabsBlock/Spotlight.jsx +2 -3
- package/src/components/manage/Blocks/TabsBlock/spotlight.less +24 -3
- package/src/customizations/@eeacms/volto-eea-design-system/ui/Header/HeaderMenuPopUp.js +18 -19
- package/src/customizations/volto/components/manage/Widgets/ArrayWidget.jsx +428 -0
- package/src/customizations/volto/components/manage/Widgets/Readme.md +5 -0
- package/src/index.js +0 -54
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,33 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [0.2.9](https://github.com/eea/volto-cca-policy/compare/0.2.8...0.2.9) - 25 April 2024
|
|
8
|
+
|
|
9
|
+
#### :bug: Bug Fixes
|
|
10
|
+
|
|
11
|
+
- fix(menu): remove menu layout configuration and show hidden children in the menu [kreafox - [`7b8001b`](https://github.com/eea/volto-cca-policy/commit/7b8001b4d4860d0469d9deded380735843763aad)]
|
|
12
|
+
- fix: Add ArrayWidget customization [kreafox - [`60bad7e`](https://github.com/eea/volto-cca-policy/commit/60bad7e3acd59b03322b56d33e6856f356d82e9b)]
|
|
13
|
+
|
|
14
|
+
#### :house: Internal changes
|
|
15
|
+
|
|
16
|
+
- style: Automated code fix [eea-jenkins - [`64b254f`](https://github.com/eea/volto-cca-policy/commit/64b254f14959c73a7154e1a4ad921f8b2f075ae4)]
|
|
17
|
+
|
|
18
|
+
### [0.2.8](https://github.com/eea/volto-cca-policy/compare/0.2.7...0.2.8) - 23 April 2024
|
|
19
|
+
|
|
20
|
+
#### :bug: Bug Fixes
|
|
21
|
+
|
|
22
|
+
- fix(tabs): disable hover on Spotlight view [kreafox - [`4ec2545`](https://github.com/eea/volto-cca-policy/commit/4ec25452bcf4702e779d6af7165b99054b4dd012)]
|
|
23
|
+
- fix(block): change icon type and fix icon size in Case Study Explorer block [kreafox - [`a65e4bc`](https://github.com/eea/volto-cca-policy/commit/a65e4bc6d3dee7dc39a05e008e7ee4fc5db53939)]
|
|
24
|
+
|
|
25
|
+
#### :nail_care: Enhancements
|
|
26
|
+
|
|
27
|
+
- change: improve Spotlight tab variation [kreafox - [`a7d2eb9`](https://github.com/eea/volto-cca-policy/commit/a7d2eb9e6c49eef986f53f2daa08114f27de3313)]
|
|
28
|
+
- change(block): improve accordion icon [kreafox - [`79d4a7e`](https://github.com/eea/volto-cca-policy/commit/79d4a7e2cad1cbf50cc77e550a4c9494670dd9e8)]
|
|
29
|
+
|
|
30
|
+
#### :house: Internal changes
|
|
31
|
+
|
|
32
|
+
- style: Automated code fix [eea-jenkins - [`74ecf1e`](https://github.com/eea/volto-cca-policy/commit/74ecf1eb58c613913f0deb6d218ff4c156477e27)]
|
|
33
|
+
|
|
7
34
|
### [0.2.7](https://github.com/eea/volto-cca-policy/compare/0.2.6...0.2.7) - 19 April 2024
|
|
8
35
|
|
|
9
36
|
#### :rocket: New Features
|
package/package.json
CHANGED
|
@@ -2,6 +2,15 @@ import React from 'react';
|
|
|
2
2
|
import { useIntl, FormattedMessage } from 'react-intl';
|
|
3
3
|
import { Accordion, Icon, Checkbox } from 'semantic-ui-react';
|
|
4
4
|
|
|
5
|
+
const AccordionIcon = ({ active }) => {
|
|
6
|
+
return (
|
|
7
|
+
<Icon
|
|
8
|
+
size="small"
|
|
9
|
+
className={active ? 'ri-arrow-up-s-line' : 'ri-arrow-down-s-line'}
|
|
10
|
+
/>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
5
14
|
export default function CaseStudyFilters(props) {
|
|
6
15
|
const { filters, activeFilters, setActiveFilters } = props;
|
|
7
16
|
|
|
@@ -55,7 +64,7 @@ export default function CaseStudyFilters(props) {
|
|
|
55
64
|
index={0}
|
|
56
65
|
onClick={handleClick}
|
|
57
66
|
>
|
|
58
|
-
<
|
|
67
|
+
<AccordionIcon active={activeIndex.includes(0)} />
|
|
59
68
|
<FormattedMessage
|
|
60
69
|
id="Adaptation sectors"
|
|
61
70
|
defaultMessage="Adaptation sectors"
|
|
@@ -80,7 +89,7 @@ export default function CaseStudyFilters(props) {
|
|
|
80
89
|
index={1}
|
|
81
90
|
onClick={handleClick}
|
|
82
91
|
>
|
|
83
|
-
<
|
|
92
|
+
<AccordionIcon active={activeIndex.includes(1)} />
|
|
84
93
|
<FormattedMessage
|
|
85
94
|
id="Climate impacts"
|
|
86
95
|
defaultMessage="Climate impacts"
|
|
@@ -105,7 +114,7 @@ export default function CaseStudyFilters(props) {
|
|
|
105
114
|
index={2}
|
|
106
115
|
onClick={handleClick}
|
|
107
116
|
>
|
|
108
|
-
<
|
|
117
|
+
<AccordionIcon active={activeIndex.includes(2)} />
|
|
109
118
|
<FormattedMessage
|
|
110
119
|
id="Key type measures"
|
|
111
120
|
defaultMessage="Key type measures"
|
|
@@ -52,8 +52,7 @@ export const AssetTab = ({ props, tabIndex, tabTitle }) => {
|
|
|
52
52
|
src={
|
|
53
53
|
isInternalURL(imageObject['@id'])
|
|
54
54
|
? `${flattenToAppURL(imageObject['@id'])}/${
|
|
55
|
-
imageObject?.image_scales?.image?.[0].
|
|
56
|
-
?.download || imageObject?.image_scales?.image?.[0].download
|
|
55
|
+
imageObject?.image_scales?.image?.[0].download
|
|
57
56
|
}`
|
|
58
57
|
: imageObject['@id']
|
|
59
58
|
}
|
|
@@ -123,7 +122,7 @@ const MenuItem = (props) => {
|
|
|
123
122
|
aria-selected={tab === activeTab}
|
|
124
123
|
tabIndex={0}
|
|
125
124
|
role={'tab'}
|
|
126
|
-
onMouseOver={focusTab}
|
|
125
|
+
// onMouseOver={focusTab}
|
|
127
126
|
onFocus={focusTab}
|
|
128
127
|
onClick={focusTab}
|
|
129
128
|
onKeyDown={(e) => {
|
|
@@ -6,14 +6,35 @@
|
|
|
6
6
|
// this is the menu
|
|
7
7
|
flex-wrap: wrap;
|
|
8
8
|
border: none;
|
|
9
|
+
margin: 1em 0 !important;
|
|
9
10
|
box-shadow: none;
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
.ui.image.thumb {
|
|
13
|
+
width: 190px;
|
|
14
|
+
height: auto;
|
|
15
|
+
}
|
|
11
16
|
|
|
12
17
|
.item {
|
|
13
|
-
|
|
18
|
+
padding: 0.5em;
|
|
19
|
+
border: 1px solid transparent !important;
|
|
20
|
+
margin: 10px 0;
|
|
21
|
+
|
|
22
|
+
&:not(:last-child) {
|
|
23
|
+
margin-right: 15px !important;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&:hover {
|
|
27
|
+
border: 1px solid #ddd !important;
|
|
28
|
+
border-radius: 4px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&.active,
|
|
32
|
+
&.active:hover {
|
|
33
|
+
border: 1px solid #ddd !important;
|
|
34
|
+
border-radius: 5px;
|
|
35
|
+
}
|
|
14
36
|
|
|
15
37
|
&:before {
|
|
16
|
-
// border: 0px !important;
|
|
17
38
|
background: none;
|
|
18
39
|
}
|
|
19
40
|
}
|
|
@@ -28,13 +28,13 @@ const ItemGrid = ({
|
|
|
28
28
|
item,
|
|
29
29
|
columns,
|
|
30
30
|
renderMenuItem,
|
|
31
|
-
hideChildrenFromNavigation,
|
|
31
|
+
// hideChildrenFromNavigation,
|
|
32
32
|
}) => {
|
|
33
33
|
const item_id = item.title.toLowerCase().replaceAll(' ', '-') + '-sub-title';
|
|
34
34
|
return (
|
|
35
35
|
<>
|
|
36
36
|
{renderMenuItem(item, { className: 'sub-title', id: item_id })}
|
|
37
|
-
{item.items.length
|
|
37
|
+
{item.items.length ? (
|
|
38
38
|
<List
|
|
39
39
|
aria-labelledby={item_id}
|
|
40
40
|
className={columns && columns > 1 ? `has--${columns}--columns` : ''}
|
|
@@ -51,7 +51,7 @@ const Item = ({
|
|
|
51
51
|
icon = false,
|
|
52
52
|
iconName,
|
|
53
53
|
renderMenuItem,
|
|
54
|
-
hideChildrenFromNavigation,
|
|
54
|
+
// hideChildrenFromNavigation,
|
|
55
55
|
}) => {
|
|
56
56
|
const item_id = item.title.toLowerCase().replaceAll(' ', '-') + '-sub-title';
|
|
57
57
|
return (
|
|
@@ -60,22 +60,21 @@ const Item = ({
|
|
|
60
60
|
className: 'sub-title',
|
|
61
61
|
id: item_id,
|
|
62
62
|
})}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)}
|
|
63
|
+
|
|
64
|
+
<List className="menu-list" aria-labelledby={item_id}>
|
|
65
|
+
{item.items.map((listItem, index) => (
|
|
66
|
+
<React.Fragment key={index}>
|
|
67
|
+
{renderMenuItem(
|
|
68
|
+
listItem,
|
|
69
|
+
{
|
|
70
|
+
className: 'item',
|
|
71
|
+
key: index,
|
|
72
|
+
},
|
|
73
|
+
{ children: icon && <Icon className={iconName} /> },
|
|
74
|
+
)}
|
|
75
|
+
</React.Fragment>
|
|
76
|
+
))}
|
|
77
|
+
</List>
|
|
79
78
|
</>
|
|
80
79
|
);
|
|
81
80
|
};
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ArrayWidget component.
|
|
3
|
+
* @module components/manage/Widgets/ArrayWidget
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { Component } from 'react';
|
|
7
|
+
import { defineMessages, injectIntl } from 'react-intl';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { compose } from 'redux';
|
|
10
|
+
import { connect } from 'react-redux';
|
|
11
|
+
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
12
|
+
import { find, isObject } from 'lodash';
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
getVocabFromHint,
|
|
16
|
+
getVocabFromField,
|
|
17
|
+
getVocabFromItems,
|
|
18
|
+
} from '@plone/volto/helpers';
|
|
19
|
+
import { getVocabulary } from '@plone/volto/actions';
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
Option,
|
|
23
|
+
DropdownIndicator,
|
|
24
|
+
ClearIndicator,
|
|
25
|
+
selectTheme,
|
|
26
|
+
customSelectStyles,
|
|
27
|
+
MenuList,
|
|
28
|
+
SortableMultiValue,
|
|
29
|
+
SortableMultiValueLabel,
|
|
30
|
+
MultiValueContainer,
|
|
31
|
+
} from '@plone/volto/components/manage/Widgets/SelectStyling';
|
|
32
|
+
|
|
33
|
+
import { FormFieldWrapper } from '@plone/volto/components';
|
|
34
|
+
|
|
35
|
+
const messages = defineMessages({
|
|
36
|
+
select: {
|
|
37
|
+
id: 'Select…',
|
|
38
|
+
defaultMessage: 'Select…',
|
|
39
|
+
},
|
|
40
|
+
no_value: {
|
|
41
|
+
id: 'No value',
|
|
42
|
+
defaultMessage: 'No value',
|
|
43
|
+
},
|
|
44
|
+
no_options: {
|
|
45
|
+
id: 'No options',
|
|
46
|
+
defaultMessage: 'No options',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
function arrayMove(array, from, to) {
|
|
51
|
+
const slicedArray = array.slice();
|
|
52
|
+
slicedArray.splice(
|
|
53
|
+
to < 0 ? array.length + to : to,
|
|
54
|
+
0,
|
|
55
|
+
slicedArray.splice(from, 1)[0],
|
|
56
|
+
);
|
|
57
|
+
return slicedArray;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function normalizeArrayValue(choices, value) {
|
|
61
|
+
if (!value || !Array.isArray(value)) return [];
|
|
62
|
+
if (value.length === 0) return value;
|
|
63
|
+
|
|
64
|
+
if (typeof value[0] === 'string') {
|
|
65
|
+
// raw value like ['foo', 'bar']
|
|
66
|
+
return value.map((v) => {
|
|
67
|
+
return {
|
|
68
|
+
label: find(choices, (c) => c.value === v)?.label || v,
|
|
69
|
+
value: v,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
isObject(value[0]) &&
|
|
76
|
+
Object.keys(value[0]).includes('token') // Array of objects, w/ label+value
|
|
77
|
+
) {
|
|
78
|
+
return value
|
|
79
|
+
.map((v) => {
|
|
80
|
+
const item = find(choices, (c) => c.value === v.token);
|
|
81
|
+
return item
|
|
82
|
+
? {
|
|
83
|
+
label: item.label || item.title || item.token,
|
|
84
|
+
value: v.token,
|
|
85
|
+
}
|
|
86
|
+
: {
|
|
87
|
+
// avoid a crash if choices doesn't include this item
|
|
88
|
+
label: v.label,
|
|
89
|
+
value: v.token,
|
|
90
|
+
};
|
|
91
|
+
})
|
|
92
|
+
.filter((f) => !!f);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function normalizeChoices(choices) {
|
|
99
|
+
if (Array.isArray(choices) && choices.length && Array.isArray(choices[0])) {
|
|
100
|
+
return choices.map((option) => ({
|
|
101
|
+
value: option[0],
|
|
102
|
+
label:
|
|
103
|
+
// Fix "None" on the serializer, to remove when fixed in p.restapi
|
|
104
|
+
option[1] !== 'None' && option[1] ? option[1] : option[0],
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return choices;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Compare values and return true if equal.
|
|
113
|
+
* Consider upper and lower case.
|
|
114
|
+
* @method compareOption
|
|
115
|
+
* @param {*} inputValue
|
|
116
|
+
* @param {*} option
|
|
117
|
+
* @param {*} accessors
|
|
118
|
+
* @returns {boolean}
|
|
119
|
+
*/
|
|
120
|
+
const compareOption = (inputValue = '', option, accessors) => {
|
|
121
|
+
const candidate = String(inputValue);
|
|
122
|
+
const optionValue = String(accessors.getOptionValue(option));
|
|
123
|
+
const optionLabel = String(accessors.getOptionLabel(option));
|
|
124
|
+
return optionValue === candidate || optionLabel === candidate;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* ArrayWidget component class.
|
|
129
|
+
* @class ArrayWidget
|
|
130
|
+
* @extends Component
|
|
131
|
+
*
|
|
132
|
+
* A createable select array widget will be rendered if the named vocabulary is
|
|
133
|
+
* in the widget definition (hint) like:
|
|
134
|
+
*
|
|
135
|
+
* ```
|
|
136
|
+
* list_field_voc_unconstrained = schema.List(
|
|
137
|
+
* title=u"List field with values from vocabulary but not constrained to them.",
|
|
138
|
+
* description=u"zope.schema.List",
|
|
139
|
+
* value_type=schema.TextLine(),
|
|
140
|
+
* required=False,
|
|
141
|
+
* missing_value=[],
|
|
142
|
+
* )
|
|
143
|
+
* directives.widget(
|
|
144
|
+
* "list_field_voc_unconstrained",
|
|
145
|
+
* AjaxSelectFieldWidget,
|
|
146
|
+
* vocabulary="plone.app.vocabularies.PortalTypes",
|
|
147
|
+
* )
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
class ArrayWidget extends Component {
|
|
151
|
+
/**
|
|
152
|
+
* Property types.
|
|
153
|
+
* @property {Object} propTypes Property types.
|
|
154
|
+
* @static
|
|
155
|
+
*/
|
|
156
|
+
static propTypes = {
|
|
157
|
+
id: PropTypes.string.isRequired,
|
|
158
|
+
title: PropTypes.string.isRequired,
|
|
159
|
+
description: PropTypes.string,
|
|
160
|
+
required: PropTypes.bool,
|
|
161
|
+
error: PropTypes.arrayOf(PropTypes.string),
|
|
162
|
+
getVocabulary: PropTypes.func.isRequired,
|
|
163
|
+
choices: PropTypes.arrayOf(
|
|
164
|
+
PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
|
165
|
+
),
|
|
166
|
+
vocabLoading: PropTypes.bool,
|
|
167
|
+
vocabLoaded: PropTypes.bool,
|
|
168
|
+
items: PropTypes.shape({
|
|
169
|
+
vocabulary: PropTypes.object,
|
|
170
|
+
}),
|
|
171
|
+
widgetOptions: PropTypes.shape({
|
|
172
|
+
vocabulary: PropTypes.object,
|
|
173
|
+
}),
|
|
174
|
+
value: PropTypes.arrayOf(
|
|
175
|
+
PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
|
|
176
|
+
),
|
|
177
|
+
placeholder: PropTypes.string,
|
|
178
|
+
onChange: PropTypes.func.isRequired,
|
|
179
|
+
wrapped: PropTypes.bool,
|
|
180
|
+
creatable: PropTypes.bool, //if widget has no vocab and you want to be creatable
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Default properties
|
|
185
|
+
* @property {Object} defaultProps Default properties.
|
|
186
|
+
* @static
|
|
187
|
+
*/
|
|
188
|
+
static defaultProps = {
|
|
189
|
+
description: null,
|
|
190
|
+
required: false,
|
|
191
|
+
items: {
|
|
192
|
+
vocabulary: null,
|
|
193
|
+
},
|
|
194
|
+
widgetOptions: {
|
|
195
|
+
vocabulary: null,
|
|
196
|
+
},
|
|
197
|
+
error: [],
|
|
198
|
+
choices: [],
|
|
199
|
+
value: null,
|
|
200
|
+
creatable: false,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Constructor
|
|
205
|
+
* @method constructor
|
|
206
|
+
* @param {Object} props Component properties
|
|
207
|
+
* @constructs Actions
|
|
208
|
+
*/
|
|
209
|
+
constructor(props) {
|
|
210
|
+
super(props);
|
|
211
|
+
|
|
212
|
+
this.handleChange = this.handleChange.bind(this);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Component did mount
|
|
217
|
+
* @method componentDidMount
|
|
218
|
+
* @returns {undefined}
|
|
219
|
+
*/
|
|
220
|
+
componentDidMount() {
|
|
221
|
+
if (
|
|
222
|
+
!this.props.items?.choices?.length &&
|
|
223
|
+
!this.props.choices?.length &&
|
|
224
|
+
this.props.vocabBaseUrl
|
|
225
|
+
) {
|
|
226
|
+
this.props.getVocabulary({
|
|
227
|
+
vocabNameOrURL: this.props.vocabBaseUrl,
|
|
228
|
+
size: -1,
|
|
229
|
+
subrequest: this.props.lang,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
componentDidUpdate() {
|
|
235
|
+
if (
|
|
236
|
+
!this.props.items?.choices?.length &&
|
|
237
|
+
!this.props.choices?.length &&
|
|
238
|
+
this.props.vocabLoading === undefined &&
|
|
239
|
+
!this.props.vocabLoaded &&
|
|
240
|
+
this.props.vocabBaseUrl
|
|
241
|
+
) {
|
|
242
|
+
this.props.getVocabulary({
|
|
243
|
+
vocabNameOrURL: this.props.vocabBaseUrl,
|
|
244
|
+
size: -1,
|
|
245
|
+
subrequest: this.props.lang,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Handle the field change, store it in the local state and back to simple
|
|
252
|
+
* array of tokens for correct serialization
|
|
253
|
+
* @method handleChange
|
|
254
|
+
* @param {array} selectedOption The selected options (already aggregated).
|
|
255
|
+
* @returns {undefined}
|
|
256
|
+
*/
|
|
257
|
+
handleChange(selectedOption) {
|
|
258
|
+
this.props.onChange(
|
|
259
|
+
this.props.id,
|
|
260
|
+
selectedOption ? selectedOption.map((item) => item.value) : null,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
onSortEnd = (selectedOption, { oldIndex, newIndex }) => {
|
|
265
|
+
const newValue = arrayMove(selectedOption, oldIndex, newIndex);
|
|
266
|
+
|
|
267
|
+
this.handleChange(newValue);
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Render method.
|
|
272
|
+
* @method render
|
|
273
|
+
* @returns {string} Markup for the component.
|
|
274
|
+
*/
|
|
275
|
+
render() {
|
|
276
|
+
const choices = normalizeChoices(this.props?.choices || []);
|
|
277
|
+
const selectedOption = normalizeArrayValue(choices, this.props.value);
|
|
278
|
+
|
|
279
|
+
const CreatableSelect = this.props.reactSelectCreateable.default;
|
|
280
|
+
const { SortableContainer } = this.props.reactSortableHOC;
|
|
281
|
+
const Select = this.props.reactSelect.default;
|
|
282
|
+
const SortableSelect =
|
|
283
|
+
// It will be only createable if the named vocabulary is in the widget definition
|
|
284
|
+
// (hint) like:
|
|
285
|
+
// list_field_voc_unconstrained = schema.List(
|
|
286
|
+
// title=u"List field with values from vocabulary but not constrained to them.",
|
|
287
|
+
// description=u"zope.schema.List",
|
|
288
|
+
// value_type=schema.TextLine(),
|
|
289
|
+
// required=False,
|
|
290
|
+
// missing_value=[],
|
|
291
|
+
// )
|
|
292
|
+
// directives.widget(
|
|
293
|
+
// "list_field_voc_unconstrained",
|
|
294
|
+
// AjaxSelectFieldWidget,
|
|
295
|
+
// vocabulary="plone.app.vocabularies.PortalTypes",
|
|
296
|
+
// )
|
|
297
|
+
this.props?.choices &&
|
|
298
|
+
!getVocabFromHint(this.props) &&
|
|
299
|
+
!this.props.creatable
|
|
300
|
+
? SortableContainer(Select)
|
|
301
|
+
: SortableContainer(CreatableSelect);
|
|
302
|
+
|
|
303
|
+
return (
|
|
304
|
+
<FormFieldWrapper {...this.props}>
|
|
305
|
+
<SortableSelect
|
|
306
|
+
useDragHandle
|
|
307
|
+
// react-sortable-hoc props:
|
|
308
|
+
axis="xy"
|
|
309
|
+
onSortEnd={this.onSortEnd}
|
|
310
|
+
menuShouldScrollIntoView={false}
|
|
311
|
+
distance={4}
|
|
312
|
+
// small fix for https://github.com/clauderic/react-sortable-hoc/pull/352:
|
|
313
|
+
getHelperDimensions={({ node }) => node.getBoundingClientRect()}
|
|
314
|
+
id={`field-${this.props.id}`}
|
|
315
|
+
key={this.props.id}
|
|
316
|
+
isDisabled={this.props.disabled || this.props.isDisabled}
|
|
317
|
+
className="react-select-container"
|
|
318
|
+
classNamePrefix="react-select"
|
|
319
|
+
/* eslint-disable jsx-a11y/no-autofocus */
|
|
320
|
+
// start customization
|
|
321
|
+
// autoFocus={this.props.focus}
|
|
322
|
+
// end customization
|
|
323
|
+
/* eslint-enable jsx-a11y/no-autofocus */
|
|
324
|
+
options={
|
|
325
|
+
this.props.vocabBaseUrl
|
|
326
|
+
? choices
|
|
327
|
+
: this.props.choices
|
|
328
|
+
? [
|
|
329
|
+
...choices,
|
|
330
|
+
...(this.props.noValueOption &&
|
|
331
|
+
(this.props.default === undefined ||
|
|
332
|
+
this.props.default === null)
|
|
333
|
+
? [
|
|
334
|
+
{
|
|
335
|
+
label: this.props.intl.formatMessage(
|
|
336
|
+
messages.no_value,
|
|
337
|
+
),
|
|
338
|
+
value: 'no-value',
|
|
339
|
+
},
|
|
340
|
+
]
|
|
341
|
+
: []),
|
|
342
|
+
]
|
|
343
|
+
: [
|
|
344
|
+
{
|
|
345
|
+
label: this.props.intl.formatMessage(messages.no_value),
|
|
346
|
+
value: 'no-value',
|
|
347
|
+
},
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
styles={customSelectStyles}
|
|
351
|
+
theme={selectTheme}
|
|
352
|
+
components={{
|
|
353
|
+
...(this.props.choices?.length > 25 && {
|
|
354
|
+
MenuList,
|
|
355
|
+
}),
|
|
356
|
+
MultiValueContainer,
|
|
357
|
+
MultiValue: SortableMultiValue,
|
|
358
|
+
MultiValueLabel: SortableMultiValueLabel,
|
|
359
|
+
DropdownIndicator,
|
|
360
|
+
ClearIndicator,
|
|
361
|
+
Option,
|
|
362
|
+
}}
|
|
363
|
+
value={selectedOption || []}
|
|
364
|
+
placeholder={
|
|
365
|
+
this.props.placeholder ??
|
|
366
|
+
this.props.intl.formatMessage(messages.select)
|
|
367
|
+
}
|
|
368
|
+
onChange={this.handleChange}
|
|
369
|
+
isValidNewOption={(
|
|
370
|
+
inputValue,
|
|
371
|
+
selectValue,
|
|
372
|
+
selectOptions,
|
|
373
|
+
accessors,
|
|
374
|
+
) =>
|
|
375
|
+
!(
|
|
376
|
+
!inputValue ||
|
|
377
|
+
selectValue.some((option) =>
|
|
378
|
+
compareOption(inputValue, option, accessors),
|
|
379
|
+
) ||
|
|
380
|
+
selectOptions.some((option) =>
|
|
381
|
+
compareOption(inputValue, option, accessors),
|
|
382
|
+
)
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
isClearable
|
|
386
|
+
isMulti
|
|
387
|
+
/>
|
|
388
|
+
</FormFieldWrapper>
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export const ArrayWidgetComponent = injectIntl(ArrayWidget);
|
|
394
|
+
|
|
395
|
+
export default compose(
|
|
396
|
+
injectIntl,
|
|
397
|
+
injectLazyLibs(['reactSelect', 'reactSelectCreateable', 'reactSortableHOC']),
|
|
398
|
+
connect(
|
|
399
|
+
(state, props) => {
|
|
400
|
+
const vocabBaseUrl =
|
|
401
|
+
getVocabFromHint(props) ||
|
|
402
|
+
getVocabFromField(props) ||
|
|
403
|
+
getVocabFromItems(props);
|
|
404
|
+
|
|
405
|
+
const vocabState =
|
|
406
|
+
state.vocabularies?.[vocabBaseUrl]?.subrequests?.[state.intl.locale];
|
|
407
|
+
|
|
408
|
+
// If the schema already has the choices in it, then do not try to get the vocab,
|
|
409
|
+
// even if there is one
|
|
410
|
+
if (props.items?.choices) {
|
|
411
|
+
return {
|
|
412
|
+
choices: props.items.choices,
|
|
413
|
+
lang: state.intl.locale,
|
|
414
|
+
};
|
|
415
|
+
} else if (vocabState) {
|
|
416
|
+
return {
|
|
417
|
+
choices: vocabState.items,
|
|
418
|
+
vocabBaseUrl,
|
|
419
|
+
vocabLoading: vocabState.loading,
|
|
420
|
+
vocabLoaded: vocabState.loaded,
|
|
421
|
+
lang: state.intl.locale,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
return { vocabBaseUrl, lang: state.intl.locale };
|
|
425
|
+
},
|
|
426
|
+
{ getVocabulary },
|
|
427
|
+
),
|
|
428
|
+
)(ArrayWidget);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Original: https://github.com/plone/volto/blob/16.x.x/src/components/manage/Widgets/ArrayWidget.jsx
|
|
2
|
+
|
|
3
|
+
The issue can be reproduce in the metadata section block. The Select widget from the edit sidebar steals the focus when you try to edit a slate text after you edit the Select widget in the metadata section block.
|
|
4
|
+
The quick solution was to comment the "autoFocus" prop in the Select component (see the customization part in ArrayWidget.jsx, line 321).
|
|
5
|
+
This is a temporary fix until it is properly tested and fixed the issue in this ticket: https://taskman.eionet.europa.eu/issues/268852
|
package/src/index.js
CHANGED
|
@@ -323,60 +323,6 @@ const applyConfig = (config) => {
|
|
|
323
323
|
},
|
|
324
324
|
];
|
|
325
325
|
|
|
326
|
-
const hideChildren = {
|
|
327
|
-
hideChildrenFromNavigation: false,
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
// mega menu layout settings
|
|
331
|
-
config.settings.menuItemsLayouts = {
|
|
332
|
-
// '*': {
|
|
333
|
-
// hideChildrenFromNavigation: false,
|
|
334
|
-
// },
|
|
335
|
-
'/en/eu-policy': hideChildren,
|
|
336
|
-
'/de/eu-policy': hideChildren,
|
|
337
|
-
'/fr/eu-policy': hideChildren,
|
|
338
|
-
'/es/eu-policy': hideChildren,
|
|
339
|
-
'/it/eu-policy': hideChildren,
|
|
340
|
-
'/pl/eu-policy': hideChildren,
|
|
341
|
-
'/en/knowledge-1': hideChildren,
|
|
342
|
-
'/de/knowledge-1': hideChildren,
|
|
343
|
-
'/fr/knowledge-1': hideChildren,
|
|
344
|
-
'/es/knowledge-1': hideChildren,
|
|
345
|
-
'/it/knowledge-1': hideChildren,
|
|
346
|
-
'/pl/knowledge-1': hideChildren,
|
|
347
|
-
// observatory
|
|
348
|
-
'/en/observatory/about': hideChildren,
|
|
349
|
-
'/de/observatory/about': hideChildren,
|
|
350
|
-
'/fr/observatory/about': hideChildren,
|
|
351
|
-
'/es/observatory/about': hideChildren,
|
|
352
|
-
'/it/observatory/about': hideChildren,
|
|
353
|
-
'/pl/observatory/about': hideChildren,
|
|
354
|
-
'/en/observatory/policy-context-1': hideChildren,
|
|
355
|
-
'/de/observatory/policy-context-1': hideChildren,
|
|
356
|
-
'/fr/observatory/policy-context-1': hideChildren,
|
|
357
|
-
'/es/observatory/policy-context-1': hideChildren,
|
|
358
|
-
'/it/observatory/policy-context-1': hideChildren,
|
|
359
|
-
'/pl/observatory/policy-context-1': hideChildren,
|
|
360
|
-
'/en/observatory/evidence-on-climate-and-health': hideChildren,
|
|
361
|
-
'/de/observatory/evidence-on-climate-and-health': hideChildren,
|
|
362
|
-
'/fr/observatory/evidence-on-climate-and-health': hideChildren,
|
|
363
|
-
'/es/observatory/evidence-on-climate-and-health': hideChildren,
|
|
364
|
-
'/it/observatory/evidence-on-climate-and-health': hideChildren,
|
|
365
|
-
'/pl/observatory/evidence-on-climate-and-health': hideChildren,
|
|
366
|
-
'/en/observatory/resource-catalogue-1': hideChildren,
|
|
367
|
-
'/de/observatory/resource-catalogue-1': hideChildren,
|
|
368
|
-
'/fr/observatory/resource-catalogue-1': hideChildren,
|
|
369
|
-
'/es/observatory/resource-catalogue-1': hideChildren,
|
|
370
|
-
'/it/observatory/resource-catalogue-1': hideChildren,
|
|
371
|
-
'/pl/observatory/resource-catalogue-1': hideChildren,
|
|
372
|
-
'/en/observatory/publications-and-outreach': hideChildren,
|
|
373
|
-
'/de/observatory/publications-and-outreach': hideChildren,
|
|
374
|
-
'/fr/observatory/publications-and-outreach': hideChildren,
|
|
375
|
-
'/es/observatory/publications-and-outreach': hideChildren,
|
|
376
|
-
'/it/observatory/publications-and-outreach': hideChildren,
|
|
377
|
-
'/pl/observatory/publications-and-outreach': hideChildren,
|
|
378
|
-
};
|
|
379
|
-
|
|
380
326
|
// Custom results
|
|
381
327
|
config.settings.searchlib.resolve.HealthHorizontalCardItem = {
|
|
382
328
|
component: HealthHorizontalCardItem,
|