-
-
-
-
-
-
-
{props.content}
+export default ({ content, id, ariaLabel }: TooltipProps) => {
+ const [isActive, setIsActive] = useState(false);
+ const tooltipButtonRef = useRef
(null);
+
+ const handleKeyDown = (event: React.KeyboardEvent) => {
+ if (event.key === 'Escape' && isActive) {
+ event.preventDefault();
+ event.stopPropagation();
+ if (tooltipButtonRef.current) {
+ tooltipButtonRef.current.click();
+ } else {
+ setIsActive(false);
+ }
+ }
+ };
+
+ const handleClick = (event: React.MouseEvent) => {
+ event.preventDefault();
+ event.stopPropagation();
+ setIsActive(!isActive);
+ };
+
+ // Focus and press Enter or Space to toggle tooltip
+ // Mouse click to toggle tooltip
+ // Hover to open tooltip
+ // Unfocus, Unhover or Escape to close tooltip
+ return (
+ setIsActive(false)}
+ onMouseEnter={() => setIsActive(true)}
+ onMouseLeave={() => setIsActive(false)}>
+
+
+
+
-
-)
+ );
+}
diff --git a/src/components/Topbar.tsx b/src/components/Topbar.tsx
index 79143392..59bb649a 100644
--- a/src/components/Topbar.tsx
+++ b/src/components/Topbar.tsx
@@ -13,7 +13,6 @@
import React from 'react';
import { ActionBar, ActionBarRow } from 'searchkit';
-import Translate from 'react-translate-component';
import counterpart from 'counterpart';
import SortingSelector from './SortingSelector';
import PageSizeSelector from './PageSizeSelector';
@@ -23,55 +22,53 @@ export default () => (
-
-
-
+
-
-
-
+
diff --git a/src/containers/SearchPage.tsx b/src/containers/SearchPage.tsx
index 3097e668..eb18f593 100644
--- a/src/containers/SearchPage.tsx
+++ b/src/containers/SearchPage.tsx
@@ -24,6 +24,7 @@ import {
import Translate from 'react-translate-component';
import Header from '../components/Header';
import {connect} from 'react-redux';
+import Tooltip from '../components/Tooltip';
import Panel from '../components/Panel';
import searchkit from '../utilities/searchkit';
import _ from 'lodash';
@@ -95,11 +96,14 @@ export class SearchPage extends Component
{
orderDirection="desc"
operator="OR"
containerComponent={}
- tooltip={}
+ tooltip={}
+ ariaLabel={counterpart.translate("filters.topic.tooltip.ariaLabel")}/>}
className="classifications"
collapsable={true}
defaultCollapsed={true}/>}
- listComponent={}/>}
+ listComponent={}
+ ariaLabel={counterpart.translate('filters.topic.label')}/>}
size={100}/>
{/* {
size={2700}/> */}
}
- className="Keywords"
- collapsable={true}
- defaultCollapsed={true}/>}
+ placeholder={counterpart.translate('filters.keywords.placeholder')}
+ containerComponent={}
+ tooltip={}
+ ariaLabel={counterpart.translate("filters.keywords.tooltip.ariaLabel")}/>}
+ className="keywords"
+ collapsable={true}
+ defaultCollapsed={true}/>}
queryFields={["keywordsSearchField"]}/>
{
title={counterpart.translate('filters.collectionDates.label')}
rangeComponent={RangeSliderInput}
containerComponent={}
- tooltip={}
+ tooltip={}
className="dataCollectionYear"
collapsable={true}
defaultCollapsed={true}/>}/>
@@ -150,11 +158,14 @@ export class SearchPage extends Component {
orderDirection="asc"
operator="OR"
containerComponent={}
- tooltip={}
+ tooltip={}
className="studyAreaCountries"
collapsable={true}
defaultCollapsed={true}/>}
- listComponent={}/>}
+ listComponent={}
+ ariaLabel={counterpart.translate('filters.country.label')}/>}
size={500}/>
{
orderDirection="asc"
operator="OR"
containerComponent={}
- tooltip={}
+ tooltip={}
className="publisher"
collapsable={true}
defaultCollapsed={true}/>}
- listComponent={}/>}
+ listComponent={}
+ ariaLabel={counterpart.translate('filters.publisher.label')}/>}
size={500}/>
@@ -182,7 +196,7 @@ export class SearchPage extends Component
{
+ listComponent={}/>
{
+ listComponent={}/>
diff --git a/src/styles/modules/_tooltip.scss b/src/styles/modules/_tooltip.scss
index bd6912b7..2fab78d1 100644
--- a/src/styles/modules/_tooltip.scss
+++ b/src/styles/modules/_tooltip.scss
@@ -21,3 +21,7 @@
}
}
}
+
+.tooltip-icon {
+ pointer-events: none;
+}
\ No newline at end of file
diff --git a/tests/src/components/Tooltip.tsx b/tests/src/components/Tooltip.tsx
index 4e2c8939..3ab067a4 100644
--- a/tests/src/components/Tooltip.tsx
+++ b/tests/src/components/Tooltip.tsx
@@ -18,7 +18,9 @@ import Tooltip from '../../../src/components/Tooltip';
// Mock props and shallow render component for test.
function setup() {
const props = {
- content: 'Content'
+ content: 'Content',
+ id: 'test-tooltip',
+ ariaLabel: 'Label'
};
const enzymeWrapper = shallow(
);
return {
@@ -39,4 +41,55 @@ describe('Tooltip component', () => {
const tooltip = enzymeWrapper.find('.dropdown');
expect(tooltip.find('p').text()).toBe(props.content);
});
+
+ it('should be closed by default', () => {
+ const { enzymeWrapper } = setup();
+ const tooltip = enzymeWrapper.find('.dropdown');
+ expect(tooltip.hasClass('is-active')).toBe(false);
+ expect(tooltip.find('.dropdown-item').prop('aria-hidden')).toBe('true');
+ });
+
+ it('should be open after clicking and closed after clicking again', () => {
+ const { enzymeWrapper } = setup();
+ enzymeWrapper.find('.button').simulate('click', { preventDefault(){}, stopPropagation(){}});
+ expect(enzymeWrapper.find('.dropdown').hasClass('is-active')).toBe(true);
+ enzymeWrapper.find('.button').simulate('click', { preventDefault(){}, stopPropagation(){}});
+ expect(enzymeWrapper.find('.dropdown').hasClass('is-active')).toBe(false);
+ });
+
+ it('should click tooltip button after pressing escape', () => {
+ const { enzymeWrapper } = setup();
+ const useRefSpy = jest.spyOn(React, 'useRef').mockReturnValueOnce({ current: { click(){} } });
+ enzymeWrapper.find('.button').simulate('click', { preventDefault(){}, stopPropagation(){}});
+ expect(enzymeWrapper.find('.dropdown').hasClass('is-active')).toBe(true);
+ enzymeWrapper.find('.button').simulate('keydown', { preventDefault(){}, stopPropagation(){},
+ key: 'Escape', keyCode: 27, which: 27 })
+ expect(useRefSpy).toBeCalledTimes(1);
+ });
+
+ it('should be closed after pressing escape', () => {
+ const { enzymeWrapper } = setup();
+ enzymeWrapper.find('.button').simulate('click', { preventDefault(){}, stopPropagation(){}});
+ expect(enzymeWrapper.find('.dropdown').hasClass('is-active')).toBe(true);
+ enzymeWrapper.find('.button').simulate('keydown', { preventDefault(){}, stopPropagation(){},
+ key: 'Escape', keyCode: 27, which: 27 })
+ expect(enzymeWrapper.find('.dropdown').hasClass('is-active')).toBe(false);
+ });
+
+
+ it('should be closed after blur', () => {
+ const { enzymeWrapper } = setup();
+ enzymeWrapper.find('.button').simulate('click', { preventDefault(){}, stopPropagation(){}});
+ expect(enzymeWrapper.find('.dropdown').hasClass('is-active')).toBe(true);
+ enzymeWrapper.find('.dropdown').simulate('blur')
+ expect(enzymeWrapper.find('.dropdown').hasClass('is-active')).toBe(false);
+ });
+
+ it('should be open after mouseenter and closed after mouseleave', () => {
+ const { enzymeWrapper } = setup();
+ enzymeWrapper.find('.dropdown').simulate('mouseenter')
+ expect(enzymeWrapper.find('.dropdown').hasClass('is-active')).toBe(true);
+ enzymeWrapper.find('.dropdown').simulate('mouseleave')
+ expect(enzymeWrapper.find('.dropdown').hasClass('is-active')).toBe(false);
+ });
});
diff --git a/translations/en.json b/translations/en.json
index 9e449d89..1fc97f7c 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -10,8 +10,14 @@
"alternateLanguage": "The study description is available in the following languages"
}
},
- "search": "Enter search term in the selected language",
- "searchInfotip": "The catalogue contains study descriptions in various languages. The system searches with your search terms from study descriptions available in the language you have selected. The catalogue does not have ‘All languages’ option as due to linguistic differences this would give incomplete results. See the User Guide for more detailed information.",
+ "search": {
+ "placeholder": "Enter search term in the selected language",
+ "tooltip": {
+ "content": "The catalogue contains study descriptions in various languages. The system searches with your search terms from study descriptions available in the language you have selected. The catalogue does not have ‘All languages’ option as due to linguistic differences this would give incomplete results. See the User Guide for more detailed information.",
+ "ariaLabel":"Tooltip button for search and search language"
+ },
+ "languageSelect": "Select search language"
+ },
"noHits": {
"noResultsFound": "No results found for \"%(query)s\" in the selected language.",
"searchWithoutFilters": "Search for \"%(query)s\" without filters",
@@ -22,32 +28,58 @@
"topic": {
"label": "Topic",
"placeholder": "Search topics",
- "tooltip": "
CESSDA Topic Classification serves to identify the general topics, subjects or themes of a study. Note: Some studies use other topic classifications and are not included in the filter."
+ "tooltip": {
+ "content": "
CESSDA Topic Classification serves to identify the general topics, subjects or themes of a study. Note: Some studies use other topic classifications and are not included in the filter.",
+ "ariaLabel": "Tooltip button for Topic filter"
+ }
+ },
+ "keywords": {
+ "label": "Keywords",
+ "placeholder": "Search keywords",
+ "tooltip": {
+ "content": "Keywords which describe the content of the data. Many but not all metadata providers use
ELSST Thesaurus for their keywords. Search term can be truncated by using the asterisk (*) after the search term, e.g. discrim*.",
+ "ariaLabel": "Tooltip button for Keywords filter"
+ }
},
"collectionDates": {
"label": "Collection years",
"placeholder": "Search years",
- "tooltip": "The year(s) in which the data for the study were collected."
+ "tooltip": {
+ "content": "The year(s) in which the data for the study were collected.",
+ "ariaLabel": "Tooltip button for Collection years filter"
+ }
},
"languageOfDataFiles": {
"label": "Language of data files",
- "placeholder": "Search languages",
- "tooltip": "Language of the research dataset, i.e. the language of the variable names/labels or interview transcriptions etc."
+ "placeholder": "Search language of data files",
+ "tooltip": {
+ "content": "Language of the research dataset, i.e. the language of the variable names/labels or interview transcriptions etc.",
+ "ariaLabel": "Tooltip button for language of data files"
+ }
},
"country": {
"label": "Country",
"placeholder": "Search countries",
- "tooltip": "The country which the data cover. Note: the filter only includes those studies where the metadata provide an ISO 3166-1 country code. Use an additional free-text search with country name for more results."
+ "tooltip": {
+ "content": "The country which the data cover. Note: the filter only includes those studies where the metadata provide an ISO 3166-1 country code. Use an additional free-text search with country name for more results.",
+ "ariaLabel":"Tooltip button for Country filter"
+ }
},
"langAvailableIn": {
"label": "Search language(s)",
"placeholder": "Search language(s)",
- "tooltip": "Language of study titles and abstract / description."
+ "tooltip": {
+ "content": "Language of study titles and abstract / description.",
+ "ariaLabel": "Tooltip button for search language"
+ }
},
"publisher": {
"label": "Publisher",
"placeholder": "Search publishers",
- "tooltip": "Name of the institution providing the information on the study."
+ "tooltip": {
+ "content": "Name of the institution providing the information on the study.",
+ "ariaLabel": "Tooltip button for Publisher filter"
+ }
},
"summary": {
"label": "Filter summary",
@@ -76,6 +108,13 @@
"publicationDateAscending": "Date of publication (oldest)",
"publicationDateDescending": "Date of publication (newest)"
},
+ "pagination": {
+ "page": "Page ",
+ "navTop": "Top pagination, current page ",
+ "navBottom": "Bottom pagination, current page ",
+ "previous": "Previous page, page ",
+ "next": "Next page, page "
+ },
"advancedSearch": {
"label": "Search help",
"introduction": "The following special characters can be used to perform advanced search queries:",
@@ -122,7 +161,10 @@
"abstract": "Abstract",
"methodology": {
"label": "Methodology",
- "tooltip": "Terminology used is generally based on DDI controlled vocabularies: Time Method, Analysis Unit, Sampling Procedure and Mode of Collection, available at
CESSDA Vocabulary Service."
+ "tooltip": {
+ "content": "Terminology used is generally based on DDI controlled vocabularies: Time Method, Analysis Unit, Sampling Procedure and Mode of Collection, available at
CESSDA Vocabulary Service.",
+ "ariaLabel": "Tooltip button for Methodology"
+ }
},
"country": "Country",
"timeDimension": "Time dimension",
@@ -139,15 +181,25 @@
"studyNumber": "Study number",
"topics": {
"label": "Topics",
- "tooltip": "Many but not all metadata providers use
CESSDA Topic Classification for their topic terms."
+ "tooltip": {
+ "content": "Many but not all metadata providers use
CESSDA Topic Classification for their topic terms.",
+ "ariaLabel": "Tooltip button for Topics"
+ }
},
"keywords": {
"label": "Keywords",
- "tooltip": "Many but not all metadata providers use
ELSST Thesaurus for their keywords."
+ "tooltip": {
+ "content": "Many but not all metadata providers use
ELSST Thesaurus for their keywords.",
+ "ariaLabel": "Tooltip button for Keywords"
+ }
},
"relatedPublications": "Related publications"
},
+ "header": {
+ "frontPage": "Front/search page"
+ },
"footer": {
+ "mainWebsite": "Main website of CESSDA",
"followUsOn": "Follow us on",
"documentation": "Documentation",
"privacy": "Privacy Policy",