@eeacms/volto-clms-theme 1.1.68 → 1.1.70
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 +19 -0
- package/package.json +1 -1
- package/src/components/Blocks/CustomTemplates/VoltoTabsBlock/CclTabsView.jsx +27 -20
- package/src/components/Blocks/CustomTemplates/VoltoTabsBlock/CclVerticalTabsView.jsx +21 -19
- package/src/components/Blocks/CustomTemplates/VoltoTabsBlock/RoutingHOC.jsx +3 -4
- package/src/customizations/volto/components/manage/Blocks/Listing/withQuerystringResults.jsx +156 -0
- package/src/customizations/volto/components/manage/Blocks/Search/SearchBlockView.jsx +115 -0
- package/src/customizations/volto/components/theme/Footer/Footer.jsx +2 -4
- package/src/customizations/volto/components/theme/Header/Header.jsx +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ 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
|
+
### [1.1.70](https://github.com/eea/volto-clms-theme/compare/1.1.69...1.1.70) - 26 October 2023
|
|
8
|
+
|
|
9
|
+
#### :hammer_and_wrench: Others
|
|
10
|
+
|
|
11
|
+
- Jenkins alert [Ion Lizarazu - [`52b0d70`](https://github.com/eea/volto-clms-theme/commit/52b0d7061c6e33ba15dddc821dd398bb1aea04e0)]
|
|
12
|
+
- deep compare adaptedQuery to avoid multimple querystring-search requests on listing and search blocks [Ion Lizarazu - [`ad10528`](https://github.com/eea/volto-clms-theme/commit/ad10528ef526979fa2f3c9e8377051912e6e5c53)]
|
|
13
|
+
- rename correctly withQuerystringResults.jsx [Ion Lizarazu - [`3c5304a`](https://github.com/eea/volto-clms-theme/commit/3c5304afc48baedee570e48b37e2bc5ad53f2b8e)]
|
|
14
|
+
- add original withQueryStringResults.jsx file to override [Ion Lizarazu - [`dab1086`](https://github.com/eea/volto-clms-theme/commit/dab1086ea5e6f09e82c030a75a4180a8c68dafc0)]
|
|
15
|
+
### [1.1.69](https://github.com/eea/volto-clms-theme/compare/1.1.68...1.1.69) - 25 October 2023
|
|
16
|
+
|
|
17
|
+
#### :rocket: New Features
|
|
18
|
+
|
|
19
|
+
- feat: optimization for search block. sort_on and sort_order default values [Ion Lizarazu - [`96d0b66`](https://github.com/eea/volto-clms-theme/commit/96d0b6624238ffc114633f7ae21a25515cba9167)]
|
|
20
|
+
- feat: add titles to be accessible [Mikel Larreategi - [`82e2b97`](https://github.com/eea/volto-clms-theme/commit/82e2b97a0c0655c2322302e6b167f64430dff52c)]
|
|
21
|
+
|
|
22
|
+
#### :hammer_and_wrench: Others
|
|
23
|
+
|
|
24
|
+
- add original file to override SearchBlockView.jsx [Ion Lizarazu - [`7334fdc`](https://github.com/eea/volto-clms-theme/commit/7334fdc1c6c9023329490bfc086daf09934bce1b)]
|
|
25
|
+
- do not use duplicate names for tab controlling [Mikel Larreategi - [`ad6a648`](https://github.com/eea/volto-clms-theme/commit/ad6a648c91c5011fce2499b5c1bb72a8aa388d1c)]
|
|
7
26
|
### [1.1.68](https://github.com/eea/volto-clms-theme/compare/1.1.67...1.1.68) - 24 October 2023
|
|
8
27
|
|
|
9
28
|
#### :rocket: New Features
|
package/package.json
CHANGED
|
@@ -9,29 +9,36 @@ import cx from 'classnames';
|
|
|
9
9
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
10
10
|
|
|
11
11
|
const CclTabsView = (props) => {
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
metadata = {},
|
|
14
|
+
tabsList = [],
|
|
15
|
+
setActiveTab,
|
|
16
|
+
activeTab = null,
|
|
17
|
+
tabs = {},
|
|
18
|
+
} = props;
|
|
13
19
|
|
|
14
20
|
const PanelsComponent = () => {
|
|
15
21
|
return (
|
|
16
22
|
<div className="panels">
|
|
17
|
-
{tabsList
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
{tabsList
|
|
24
|
+
.filter((tab) => tab === activeTab)
|
|
25
|
+
.map((tab, index) => {
|
|
26
|
+
return (
|
|
27
|
+
<div
|
|
28
|
+
key={index}
|
|
29
|
+
className={cx('panel', tab === activeTab && 'panel-selected')}
|
|
30
|
+
id={`tab-${index}`}
|
|
31
|
+
role="tabpanel"
|
|
32
|
+
aria-hidden="false"
|
|
33
|
+
>
|
|
34
|
+
<RenderBlocks
|
|
35
|
+
{...props}
|
|
36
|
+
metadata={metadata}
|
|
37
|
+
content={tabs[tab]}
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
})}
|
|
35
42
|
</div>
|
|
36
43
|
);
|
|
37
44
|
};
|
|
@@ -56,7 +63,7 @@ const CclTabsView = (props) => {
|
|
|
56
63
|
key={index}
|
|
57
64
|
id={tabIndex}
|
|
58
65
|
role="tab"
|
|
59
|
-
aria-controls={
|
|
66
|
+
aria-controls={`tab-${index}`}
|
|
60
67
|
aria-selected={tab === activeTab}
|
|
61
68
|
active={(tab === activeTab).toString()}
|
|
62
69
|
/* classname hontan estiloa aldatu behar bada "===" "!==" gatik aldatuz nahikoa da */
|
|
@@ -98,25 +98,27 @@ const PanelsComponent = (props) => {
|
|
|
98
98
|
const { metadata = {}, tabsList = [], activeTab = null, tabs = {} } = props;
|
|
99
99
|
return (
|
|
100
100
|
<div className="right-content cont-w-75">
|
|
101
|
-
{tabsList
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
101
|
+
{tabsList
|
|
102
|
+
.filter((tab) => tab === activeTab)
|
|
103
|
+
.map((tab, index) => {
|
|
104
|
+
const title = tabs[tab].title;
|
|
105
|
+
const tabHash = `tab=${slugify(title)}`;
|
|
106
|
+
return (
|
|
107
|
+
<Route key={index} to={'#' + tabHash}>
|
|
108
|
+
<div
|
|
109
|
+
className={cx('panel', tab === activeTab && 'panel-selected')}
|
|
110
|
+
role="tabpanel"
|
|
111
|
+
aria-hidden="false"
|
|
112
|
+
>
|
|
113
|
+
<RenderBlocks
|
|
114
|
+
{...props}
|
|
115
|
+
metadata={metadata}
|
|
116
|
+
content={tabs[tab]}
|
|
117
|
+
/>
|
|
118
|
+
</div>
|
|
119
|
+
</Route>
|
|
120
|
+
);
|
|
121
|
+
})}
|
|
120
122
|
</div>
|
|
121
123
|
);
|
|
122
124
|
};
|
|
@@ -30,9 +30,9 @@ const RoutingHOC = (TabView) =>
|
|
|
30
30
|
const hashMatch = window.location.search
|
|
31
31
|
.match(/.*([&|?|#]tab=.*)/)[1]
|
|
32
32
|
.replace(/[&|?|#]tab=/, '');
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
return
|
|
33
|
+
const tab = tabsDict.find((t) => slugify(t.title) === hashMatch);
|
|
34
|
+
if (tab) {
|
|
35
|
+
return tab.id;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
return decideTabSubtab(rTabs, rTabsList[0], rTabsList[1]);
|
|
@@ -50,7 +50,6 @@ const RoutingHOC = (TabView) =>
|
|
|
50
50
|
}
|
|
51
51
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
52
52
|
}, [activeTabIndex, location]);
|
|
53
|
-
|
|
54
53
|
return <TabView {...props} />;
|
|
55
54
|
};
|
|
56
55
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
3
|
+
import hoistNonReactStatics from 'hoist-non-react-statics';
|
|
4
|
+
import useDeepCompareEffect from 'use-deep-compare-effect';
|
|
5
|
+
|
|
6
|
+
import { getContent, getQueryStringResults } from '@plone/volto/actions';
|
|
7
|
+
import { usePagination, getBaseUrl } from '@plone/volto/helpers';
|
|
8
|
+
|
|
9
|
+
import config from '@plone/volto/registry';
|
|
10
|
+
|
|
11
|
+
function getDisplayName(WrappedComponent) {
|
|
12
|
+
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default function withQuerystringResults(WrappedComponent) {
|
|
16
|
+
function WithQuerystringResults(props) {
|
|
17
|
+
const {
|
|
18
|
+
data = {},
|
|
19
|
+
id = data.block,
|
|
20
|
+
properties: content,
|
|
21
|
+
path,
|
|
22
|
+
variation,
|
|
23
|
+
} = props;
|
|
24
|
+
const { settings } = config;
|
|
25
|
+
const querystring = data.querystring || data; // For backwards compat with data saved before Blocks schema. Note, this is also how the Search block passes data to ListingBody
|
|
26
|
+
const subrequestID = content?.UID ? `${content?.UID}-${id}` : id;
|
|
27
|
+
const { b_size = settings.defaultPageSize } = querystring; // batchsize
|
|
28
|
+
|
|
29
|
+
// save the path so it won't trigger dispatch on eager router location change
|
|
30
|
+
const [initialPath] = React.useState(getBaseUrl(path));
|
|
31
|
+
|
|
32
|
+
const copyFields = ['limit', 'query', 'sort_on', 'sort_order', 'depth'];
|
|
33
|
+
const { currentPage, setCurrentPage } = usePagination(id, 1);
|
|
34
|
+
const adaptedQuery = Object.assign(
|
|
35
|
+
variation?.fullobjects ? { fullobjects: 1 } : { metadata_fields: '_all' },
|
|
36
|
+
{
|
|
37
|
+
b_size: b_size,
|
|
38
|
+
},
|
|
39
|
+
...copyFields.map((name) =>
|
|
40
|
+
Object.keys(querystring).includes(name)
|
|
41
|
+
? { [name]: querystring[name] }
|
|
42
|
+
: {},
|
|
43
|
+
),
|
|
44
|
+
);
|
|
45
|
+
const adaptedQueryRef = useRef(adaptedQuery);
|
|
46
|
+
const currentPageRef = useRef(currentPage);
|
|
47
|
+
|
|
48
|
+
const querystringResults = useSelector(
|
|
49
|
+
(state) => state.querystringsearch.subrequests,
|
|
50
|
+
);
|
|
51
|
+
const dispatch = useDispatch();
|
|
52
|
+
|
|
53
|
+
const folderItems = content?.is_folderish ? content.items : [];
|
|
54
|
+
const hasQuery = querystring?.query?.length > 0;
|
|
55
|
+
const hasLoaded = hasQuery
|
|
56
|
+
? querystringResults?.[subrequestID]?.loaded
|
|
57
|
+
: true;
|
|
58
|
+
|
|
59
|
+
const listingItems = hasQuery
|
|
60
|
+
? querystringResults?.[subrequestID]?.items || []
|
|
61
|
+
: folderItems;
|
|
62
|
+
|
|
63
|
+
const showAsFolderListing = !hasQuery && content?.items_total > b_size;
|
|
64
|
+
const showAsQueryListing =
|
|
65
|
+
hasQuery && querystringResults?.[subrequestID]?.total > b_size;
|
|
66
|
+
|
|
67
|
+
const totalPages = showAsFolderListing
|
|
68
|
+
? Math.ceil(content.items_total / b_size)
|
|
69
|
+
: showAsQueryListing
|
|
70
|
+
? Math.ceil(querystringResults[subrequestID].total / b_size)
|
|
71
|
+
: 0;
|
|
72
|
+
|
|
73
|
+
const prevBatch = showAsFolderListing
|
|
74
|
+
? content.batching?.prev
|
|
75
|
+
: showAsQueryListing
|
|
76
|
+
? querystringResults[subrequestID].batching?.prev
|
|
77
|
+
: null;
|
|
78
|
+
const nextBatch = showAsFolderListing
|
|
79
|
+
? content.batching?.next
|
|
80
|
+
: showAsQueryListing
|
|
81
|
+
? querystringResults[subrequestID].batching?.next
|
|
82
|
+
: null;
|
|
83
|
+
|
|
84
|
+
const isImageGallery =
|
|
85
|
+
(!data.variation && data.template === 'imageGallery') ||
|
|
86
|
+
data.variation === 'imageGallery';
|
|
87
|
+
|
|
88
|
+
const deepAdaptedQuery = JSON.stringify(adaptedQuery);
|
|
89
|
+
useDeepCompareEffect(() => {
|
|
90
|
+
if (hasQuery) {
|
|
91
|
+
dispatch(
|
|
92
|
+
getQueryStringResults(
|
|
93
|
+
initialPath,
|
|
94
|
+
adaptedQuery,
|
|
95
|
+
subrequestID,
|
|
96
|
+
currentPage,
|
|
97
|
+
),
|
|
98
|
+
);
|
|
99
|
+
} else if (isImageGallery && !hasQuery) {
|
|
100
|
+
// when used as image gallery, it doesn't need a query to list children
|
|
101
|
+
dispatch(
|
|
102
|
+
getQueryStringResults(
|
|
103
|
+
initialPath,
|
|
104
|
+
{
|
|
105
|
+
...adaptedQuery,
|
|
106
|
+
b_size: 10000000000,
|
|
107
|
+
query: [
|
|
108
|
+
{
|
|
109
|
+
i: 'path',
|
|
110
|
+
o: 'plone.app.querystring.operation.string.relativePath',
|
|
111
|
+
v: '',
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
subrequestID,
|
|
116
|
+
),
|
|
117
|
+
);
|
|
118
|
+
} else {
|
|
119
|
+
dispatch(getContent(initialPath, null, null, currentPage));
|
|
120
|
+
}
|
|
121
|
+
adaptedQueryRef.current = adaptedQuery;
|
|
122
|
+
currentPageRef.current = currentPage;
|
|
123
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
124
|
+
}, [
|
|
125
|
+
subrequestID,
|
|
126
|
+
isImageGallery,
|
|
127
|
+
deepAdaptedQuery,
|
|
128
|
+
hasQuery,
|
|
129
|
+
initialPath,
|
|
130
|
+
dispatch,
|
|
131
|
+
currentPage,
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<WrappedComponent
|
|
136
|
+
{...props}
|
|
137
|
+
onPaginationChange={(e, { activePage }) => setCurrentPage(activePage)}
|
|
138
|
+
total={querystringResults?.[subrequestID]?.total}
|
|
139
|
+
batch_size={b_size}
|
|
140
|
+
currentPage={currentPage}
|
|
141
|
+
totalPages={totalPages}
|
|
142
|
+
prevBatch={prevBatch}
|
|
143
|
+
nextBatch={nextBatch}
|
|
144
|
+
listingItems={listingItems}
|
|
145
|
+
hasLoaded={hasLoaded}
|
|
146
|
+
isFolderContentsListing={showAsFolderListing}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
WithQuerystringResults.displayName = `WithQuerystringResults(${getDisplayName(
|
|
152
|
+
WrappedComponent,
|
|
153
|
+
)})`;
|
|
154
|
+
|
|
155
|
+
return hoistNonReactStatics(WithQuerystringResults, WrappedComponent);
|
|
156
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import ListingBody from '@plone/volto/components/manage/Blocks/Listing/ListingBody';
|
|
4
|
+
import { withBlockExtensions } from '@plone/volto/helpers';
|
|
5
|
+
|
|
6
|
+
import config from '@plone/volto/registry';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
withSearch,
|
|
10
|
+
withQueryString,
|
|
11
|
+
} from '@plone/volto/components/manage/Blocks/Search/hocs';
|
|
12
|
+
import { compose } from 'redux';
|
|
13
|
+
import { useSelector } from 'react-redux';
|
|
14
|
+
import { isEqual, isFunction } from 'lodash';
|
|
15
|
+
|
|
16
|
+
const getListingBodyVariation = (data) => {
|
|
17
|
+
const { variations } = config.blocks.blocksConfig.listing;
|
|
18
|
+
|
|
19
|
+
let variation = data.listingBodyTemplate
|
|
20
|
+
? variations.find(({ id }) => id === data.listingBodyTemplate)
|
|
21
|
+
: variations.find(({ isDefault }) => isDefault);
|
|
22
|
+
|
|
23
|
+
if (!variation) variation = variations[0];
|
|
24
|
+
|
|
25
|
+
return variation;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const isfunc = (obj) => isFunction(obj) || typeof obj === 'function';
|
|
29
|
+
|
|
30
|
+
const _filtered = (obj) =>
|
|
31
|
+
Object.assign(
|
|
32
|
+
{},
|
|
33
|
+
...Object.keys(obj).map((k) => {
|
|
34
|
+
const reject = k !== 'properties' && !isfunc(obj[k]);
|
|
35
|
+
return reject ? { [k]: obj[k] } : {};
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const blockPropsAreChanged = (prevProps, nextProps) => {
|
|
40
|
+
const prev = _filtered(prevProps);
|
|
41
|
+
const next = _filtered(nextProps);
|
|
42
|
+
|
|
43
|
+
return isEqual(prev, next);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const applyDefaults = (data, root) => {
|
|
47
|
+
const defaultQuery = [
|
|
48
|
+
{
|
|
49
|
+
i: 'path',
|
|
50
|
+
o: 'plone.app.querystring.operation.string.absolutePath',
|
|
51
|
+
v: root || '/',
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
const sort_on = data?.sort_on ? { sort_on: data?.sort_on } : {};
|
|
55
|
+
const sort_order = data?.sort_order ? { sort_order: data?.sort_order } : {};
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
...data,
|
|
59
|
+
...sort_on,
|
|
60
|
+
...sort_order,
|
|
61
|
+
query: data?.query?.length ? data.query : defaultQuery,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const SearchBlockView = (props) => {
|
|
66
|
+
const { data, searchData, mode = 'view', variation } = props;
|
|
67
|
+
|
|
68
|
+
const Layout = variation.view;
|
|
69
|
+
|
|
70
|
+
const dataListingBodyVariation = getListingBodyVariation(data).id;
|
|
71
|
+
const [selectedView, setSelectedView] = React.useState(
|
|
72
|
+
dataListingBodyVariation,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// in the block edit you can change the used listing block variation,
|
|
76
|
+
// but it's cached here in the state. So we reset it.
|
|
77
|
+
React.useEffect(() => {
|
|
78
|
+
if (mode !== 'view') {
|
|
79
|
+
setSelectedView(dataListingBodyVariation);
|
|
80
|
+
}
|
|
81
|
+
}, [dataListingBodyVariation, mode]);
|
|
82
|
+
|
|
83
|
+
const root = useSelector((state) => state.breadcrumbs.root);
|
|
84
|
+
const listingBodyData = applyDefaults(searchData, root);
|
|
85
|
+
|
|
86
|
+
const { variations } = config.blocks.blocksConfig.listing;
|
|
87
|
+
const listingBodyVariation = variations.find(({ id }) => id === selectedView);
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<div className="block search">
|
|
91
|
+
<Layout
|
|
92
|
+
{...props}
|
|
93
|
+
isEditMode={mode === 'edit'}
|
|
94
|
+
selectedView={selectedView}
|
|
95
|
+
setSelectedView={setSelectedView}
|
|
96
|
+
>
|
|
97
|
+
<ListingBody
|
|
98
|
+
variation={{ ...data, ...listingBodyVariation }}
|
|
99
|
+
data={listingBodyData}
|
|
100
|
+
path={props.path}
|
|
101
|
+
isEditMode={mode === 'edit'}
|
|
102
|
+
/>
|
|
103
|
+
</Layout>
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const SearchBlockViewComponent = compose(
|
|
109
|
+
withBlockExtensions,
|
|
110
|
+
(Component) => React.memo(Component, blockPropsAreChanged),
|
|
111
|
+
)(SearchBlockView);
|
|
112
|
+
|
|
113
|
+
export default compose(withSearch())(
|
|
114
|
+
compose(withQueryString)(SearchBlockViewComponent),
|
|
115
|
+
);
|
|
@@ -478,6 +478,7 @@ class Footer extends Component {
|
|
|
478
478
|
href="https://www.eea.europa.eu/"
|
|
479
479
|
target="_blank"
|
|
480
480
|
rel="noreferrer"
|
|
481
|
+
title="European Environment Agency"
|
|
481
482
|
>
|
|
482
483
|
<ReactSVG
|
|
483
484
|
src={ECImage}
|
|
@@ -495,6 +496,7 @@ class Footer extends Component {
|
|
|
495
496
|
<a
|
|
496
497
|
href="https://joint-research-centre.ec.europa.eu/index_en"
|
|
497
498
|
target="_blank"
|
|
499
|
+
title="Joint Research Centre"
|
|
498
500
|
rel="noreferrer"
|
|
499
501
|
>
|
|
500
502
|
<ReactSVG
|
|
@@ -515,10 +517,6 @@ class Footer extends Component {
|
|
|
515
517
|
</span>
|
|
516
518
|
</a>
|
|
517
519
|
</div>
|
|
518
|
-
{/* <div className="ccl-footer-col-title">
|
|
519
|
-
{intl.formatMessage(messages.expertSupportProvidedBy)}
|
|
520
|
-
</div>
|
|
521
|
-
<p>{intl.formatMessage(messages.EIONETActionGroup)}</p> */}
|
|
522
520
|
</CclFooterColumn>
|
|
523
521
|
</div>
|
|
524
522
|
</div>
|
|
@@ -165,6 +165,7 @@ class Header extends Component {
|
|
|
165
165
|
<div className="ccl-container">
|
|
166
166
|
<div
|
|
167
167
|
className="ccl-main-menu-collapse-button"
|
|
168
|
+
aria-label="Toggle main menu"
|
|
168
169
|
onClick={() =>
|
|
169
170
|
this.setState({
|
|
170
171
|
mobileMenuOpen: !this.state.mobileMenuOpen,
|
|
@@ -188,6 +189,7 @@ class Header extends Component {
|
|
|
188
189
|
</div>
|
|
189
190
|
<div
|
|
190
191
|
className="ccl-search-collapse-button"
|
|
192
|
+
aria-label="Toggle search menu"
|
|
191
193
|
onClick={() =>
|
|
192
194
|
this.setState({
|
|
193
195
|
mobileSearchBoxOpen: !this.state.mobileSearchBoxOpen,
|