]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-18068 Buttons must have discernible text
authorguillaume-peoch-sonarsource <guillaume.peoch@sonarsource.com>
Tue, 31 Jan 2023 15:56:27 +0000 (16:56 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 2 Feb 2023 20:03:40 +0000 (20:03 +0000)
server/sonar-web/src/main/js/components/controls/DateInput.tsx
server/sonar-web/src/main/js/components/controls/__tests__/DateInput-test.tsx
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/DateInput-test.tsx.snap
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 96ce359c17c625d20d3cabf69766040b7d6394e1..80174673eff41cd7cb9917a1ddcd744f68d270c6 100644 (file)
@@ -33,6 +33,7 @@ import {
   getShortWeekDayName,
   getWeekDayName,
   translate,
+  translateWithParameters,
 } from '../../helpers/l10n';
 import './DayPicker.css';
 import EscKeydownHandler from './EscKeydownHandler';
@@ -64,6 +65,8 @@ interface State {
 
 type Week = [string, string, string, string, string, string, string];
 
+const LAST_MONTH_INDEX = 11;
+
 export default class DateInput extends React.PureComponent<Props, State> {
   input?: HTMLInputElement | null;
 
@@ -123,6 +126,36 @@ export default class DateInput extends React.PureComponent<Props, State> {
     this.setState((state) => ({ currentMonth: addMonths(state.currentMonth, 1) }));
   };
 
+  getPreviousMonthAriaLabel = () => {
+    const { currentMonth } = this.state;
+    return currentMonth.getMonth() === 0
+      ? translateWithParameters(
+          'show_month_x_of_year_y',
+          getShortMonthName(LAST_MONTH_INDEX),
+          currentMonth.getFullYear() - 1
+        )
+      : translateWithParameters(
+          'show_month_x_of_year_y',
+          getShortMonthName(currentMonth.getMonth() - 1),
+          currentMonth.getFullYear()
+        );
+  };
+
+  getNextMonthAriaLabel = () => {
+    const { currentMonth } = this.state;
+    return currentMonth.getMonth() === LAST_MONTH_INDEX
+      ? translateWithParameters(
+          'show_month_x_of_year_y',
+          getShortMonthName(0),
+          currentMonth.getFullYear() + 1
+        )
+      : translateWithParameters(
+          'show_month_x_of_year_y',
+          getShortMonthName(currentMonth.getMonth() + 1),
+          currentMonth.getFullYear()
+        );
+  };
+
   render() {
     const {
       alignRight,
@@ -195,7 +228,11 @@ export default class DateInput extends React.PureComponent<Props, State> {
               {open && (
                 <div className={classNames('date-input-calendar', { 'align-right': alignRight })}>
                   <nav className="date-input-calendar-nav">
-                    <ButtonIcon className="button-small" onClick={this.handlePreviousMonthClick}>
+                    <ButtonIcon
+                      className="button-small"
+                      aria-label={this.getPreviousMonthAriaLabel()}
+                      onClick={this.handlePreviousMonthClick}
+                    >
                       <ChevronLeftIcon />
                     </ButtonIcon>
                     <div className="date-input-calender-month">
@@ -218,7 +255,11 @@ export default class DateInput extends React.PureComponent<Props, State> {
                         )}
                       />
                     </div>
-                    <ButtonIcon className="button-small" onClick={this.handleNextMonthClick}>
+                    <ButtonIcon
+                      className="button-small"
+                      aria-label={this.getNextMonthAriaLabel()}
+                      onClick={this.handleNextMonthClick}
+                    >
                       <ChevronRightIcon />
                     </ButtonIcon>
                   </nav>
index 93500bcbe5ff9218a39ce396a481963b2cedebd9..30bd6262f1136e80dfe622f789d6a36dfd0cd346 100644 (file)
@@ -103,6 +103,17 @@ it('should hightlightTo range', () => {
   expect(dayPicker.prop('selectedDays')).toEqual([dateB]);
 });
 
+it('should announce the proper month and year for next/previous buttons aria label', () => {
+  const { wrapper, instance } = shallowRender();
+  expect(wrapper.state().currentMonth).toEqual(dateA);
+  expect(instance.getPreviousMonthAriaLabel()).toEqual('show_month_x_of_year_y.Dec.2017');
+  expect(instance.getNextMonthAriaLabel()).toEqual('show_month_x_of_year_y.Feb.2018');
+
+  instance.handleCurrentMonthChange({ value: 11 });
+  expect(instance.getPreviousMonthAriaLabel()).toEqual('show_month_x_of_year_y.Nov.2018');
+  expect(instance.getNextMonthAriaLabel()).toEqual('show_month_x_of_year_y.Jan.2019');
+});
+
 function shallowRender(props?: Partial<DateInput['props']>) {
   const wrapper = shallow<DateInput>(
     <DateInput
index bfe52a639ce40d748e7ef2ee42394be6f6bc2b5d..e6f37a0c6d7fefa2cdc6bad789dfd389236b27db 100644 (file)
@@ -116,6 +116,7 @@ exports[`should render 3`] = `
             className="date-input-calendar-nav"
           >
             <ButtonIcon
+              aria-label="show_month_x_of_year_y.Dec.2017"
               className="button-small"
               onClick={[Function]}
             >
@@ -248,6 +249,7 @@ exports[`should render 3`] = `
               />
             </div>
             <ButtonIcon
+              aria-label="show_month_x_of_year_y.Feb.2018"
               className="button-small"
               onClick={[Function]}
             >
index e6d4da7b6153de8cc5711b6389af88c1d38a8839..922a5e29dc1f265c03001624e2bc2c8bed851f1c 100644 (file)
@@ -369,6 +369,7 @@ Th=Th
 Fr=Fr
 Sa=Sa
 select_month=Select a month
+show_month_x_of_year_y=Show {0} of {1}
 select_year=Select a year
 
 #------------------------------------------------------------------------------