Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessible sort buttons #12217

Merged
merged 7 commits into from
Jun 20, 2017
Merged

Accessible sort buttons #12217

merged 7 commits into from
Jun 20, 2017

Conversation

aphelionz
Copy link
Contributor

Will Resolve #11853

Here's my rationale. I know that the directive code is likely inadequate, so I'm happy to get feedback there. Otherwise this should work as expected.

  1. Changing the i to a button to make it clickable without a javascript handler
  2. Adding the usual id and tabindex
  3. Making the screen reader say "Sort time ascending" when clicking the button will cause it to sort it ascending

To test, tab to the time field in the discover interface and hit the space bar to sort.

@aphelionz aphelionz requested a review from cjcenizal June 7, 2017 02:43
@aphelionz
Copy link
Contributor Author

@cjcenizal Also please feel free to add any other appropriate reviewers to this.

@aphelionz aphelionz changed the title First pass at creating accessible sort buttons Accessible sort buttons Jun 7, 2017
@cjcenizal cjcenizal requested a review from Bargs June 7, 2017 18:57
Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I think there are a couple things we need to account for before we can merge, but we're close!

ng-click="cycleSortOrder(indexPattern.timeFieldName)"
tooltip="Sort by time"
></button>
</span>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice solution! A few lines below, I think we also need to update this markup similarly:

    <span class="table-header-name">
      {{name | shortDots}} <i ng-class="headerClass(name)" ng-click="cycleSortOrder(name)" tooltip="{{tooltip(name)}}" tooltip-append-to-body="1"></i>
    </span>

I think this is what drives the appearance of the sort button for a non-time columns (e.g. geo.srcdest). To show this column in the table header, just expand open a row and click this icon:

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was addressed.


$scope.sortText = $scope.sortOrder[1] === 'asc'
? 'Button: Sort time descending'
: 'Button: Sort time ascending';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea! But I think we'll need to extract this out into its own scope method, and tweak it to use a dynamic column name. Something like this (haven't tested that this works):

<button aria-label="{{ getAriaLabelForColumn('time') }}">
$scope.getAriaLabelForColumn = function getAriaLabelForColumn(name) {
  const [currentColumnName, currentDirection = 'asc'] = $scope.sortOrder;
  if(name === currentColumnName && currentDirection === 'asc') {
    return `Button: Sort ${name} ascending`;
  }

  return `Button: Sort ${name} descending`;
}

@@ -213,6 +213,9 @@ kbn-table, .kbn-table {

.fa {
font-size: 1.1em;
border: none;
background: none;
padding: 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's create a new class called .docTableHeaderButton in doc_table/doc_table.less and move these styles there, just so they're a little more organized together and semantically specific.

@aphelionz
Copy link
Contributor Author

Jenkins, please test

@cjcenizal
Copy link
Contributor

@aphelionz you just need to have some variation of the words "jenkins test this", I think

@cjcenizal
Copy link
Contributor

Though I am impressed by how polite to jenkins you always are!

Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚡️ One super minor request then we're good to go.


if (!sortOrder || column !== sortOrder[0]) return defaultClass;
return ['fa', sortOrder[1] === 'asc' ? 'fa-sort-up' : 'fa-sort-down'];
return ['fa', 'docTableHeaderButton', sortOrder[1] === 'asc' ? 'fa-sort-up' : 'fa-sort-down'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because docTableHeaderButton is going to be applied in every case, we can actually remove it from this logic (and go back to what was here originally), and use it directly in the template instead by assigning it with the class attribute:

    <span>Time <button
      id="docTableHeaderFieldSort{{indexPattern.timeFieldName}}"
      tabindex="0"
      aria-label="{{ getAriaLabelForColumn(indexPattern.timeFieldName) }}"
      class="docTableHeaderButton"
      ng-class="headerClass(indexPattern.timeFieldName)"
      role="button"
      ng-click="cycleSortOrder(indexPattern.timeFieldName)"
      tooltip="Sort by time"
    ></button>
    </span>

      <button
        id="docTableHeaderFieldSort{{name}}"
        tabindex="0"
        aria-label="{{ getAriaLabelForColumn(name) }}"
        class="docTableHeaderButton"
        ng-class="headerClass(name)"
        ng-click="cycleSortOrder(name)"
        tooltip="{{tooltip(name)}}"
        tooltip-append-to-body="1"
      ></button>

@Bargs
Copy link
Contributor

Bargs commented Jun 12, 2017

Hmmm the columns that aren't currently being sorted on seem to only be tabbable if you are hovering over them with your mouse. I thought maybe display:none was being used but that doesn't seem to be the case. Not sure what's going on exactly.

tabbablesort

@aphelionz
Copy link
Contributor Author

@Bargs @cjcenizal Yeah, we might need to loop in design to see what they want to do here. I'll play with it a bit more. I think I can get them to be visually hidden but still tabbable.

@cjcenizal
Copy link
Contributor

@Bargs Good catch!

@aphelionz We'll just need to replace lines 203 to 229 of src/ui/public/styles/base.less with these styles:

kbn-table, .kbn-table {
  font-size: @font-size-small;

  th {
    white-space: nowrap;
    padding-right: 10px;

    .table-header-move, .table-header-sortchange {
      opacity: 0;

      &:focus {
        opacity: 1;
      }
    }

    .fa {
      font-size: 1.1em;
    }

  }

  th:hover {
    .table-header-move, .table-header-sortchange {
      opacity: 1;
    }
  }
}

Switching from visibility to opacity makes them tabbable and then we can reveal them when they have focus.

I think we also just need to change the <i> elements to <button> elements in src/ui/public/doc_table/components/table_header.html to make them tabbable, and then move some classes around to reveal them on focus too. That file would become:

<tr>
  <th width="1%"></th>
  <th ng-if="indexPattern.timeFieldName" data-test-subj="docTableHeaderField">
    <span>Time <button
      id="docTableHeaderFieldSort{{indexPattern.timeFieldName}}"
      tabindex="0"
      aria-label="{{ getAriaLabelForColumn(indexPattern.timeFieldName) }}"
      class="docTableHeaderButton"
      ng-class="headerClass(indexPattern.timeFieldName)"
      role="button"
      ng-click="cycleSortOrder(indexPattern.timeFieldName)"
      tooltip="Sort by time"
    ></button>
    </span>
  </th>
  <th ng-repeat="name in columns" data-test-subj="docTableHeaderField">
    <span class="table-header-name">
      {{name | shortDots}}
      <button
        id="docTableHeaderFieldSort{{name}}"
        tabindex="0"
        aria-label="{{ getAriaLabelForColumn(name) }}"
        class="docTableHeaderButton"
        ng-class="headerClass(name)"
        ng-click="cycleSortOrder(name)"
        tooltip="{{tooltip(name)}}"
        tooltip-append-to-body="1"
      ></button>
    </span>
    <button
      class="fa fa-remove table-header-move"
      ng-click="onRemoveColumn(name)"
      ng-if="canRemoveColumn(name)"
      tooltip-append-to-body="1"
      tooltip="Remove column"
    ></button>
    <button
      class="fa fa-angle-double-left table-header-move"
      ng-click="moveColumnLeft(name)"
      ng-if="canMoveColumnLeft(name)"
      tooltip-append-to-body="1"
      tooltip="Move column to the left"
    ></button>
    <button
      class="fa fa-angle-double-right table-header-move"
      ng-click="moveColumnRight(name)"
      ng-if="canMoveColumnRight(name)"
      tooltip-append-to-body="1"
      tooltip="Move column to the right"
    ></button>
  </th>
</tr>

You'll just need to add a few styles to .table-header-move class to eliminate the default button appearance and maybe remove the padding.

This will expand the scope of this PR slightly, but code above is already written, and we can close out #12230! 🎯

@aphelionz
Copy link
Contributor Author

@cjcenizal @Bargs This has been updated based on the feedback. Let me know!

Copy link
Contributor

@Bargs Bargs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple last things and then let's merge this sucker!

</span>
<button
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add an aria-label for this button? This should work:

aria-label="Remove {{name}} column"

tooltip-append-to-body="1"
tooltip="Remove column"
></button>
<button
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this one:

aria-label="Move {{name}} column to the left"

tooltip-append-to-body="1"
tooltip="Move column to the left"
></button>
<button
Copy link
Contributor

@cjcenizal cjcenizal Jun 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guy too:

aria-label="Move {{name}} column to the right"

@aphelionz
Copy link
Contributor Author

@cjcenizal done!

Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caught a little typo. :)

ng-if="canMoveColumnRight(name)"
tooltip-append-to-body="1"
tooltip="Move column to the right"
aria-label="Move {{name}} column to the left"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be "Move {{name}} column to the right".

@aphelionz
Copy link
Contributor Author

@cjcenizal fixed :)

Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@cjcenizal cjcenizal merged commit 22a70b7 into elastic:master Jun 20, 2017
@cjcenizal
Copy link
Contributor

Thanks @aphelionz.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants