Skip to content

Commit 5c503b3

Browse files
committed
Make filter sidebar more semantically meaningful
Why these changes are being introduced: VoiceOver (and possibly other screen readers) do not interpret the current sidebar drawers as disclosure triangles. As such, one must tab through every available filter, even if that filter category is collapsed. Relevant ticket(s): * https://mitlibraries.atlassian.net/browse/GDT-161 How this addresses that need: This refactors filter categories as `details` tags, so screen readers will recognize them as expandable elements. Side effects of this change: * Some tests have been updated a result of changes to class names. * We had previously been opening/closing categories with an `onclick`, was a quick-and-dirty way to get things working but not very good practice. I took this opportunity to change that too an event listener and moved it to the `filters.js` file that we added for the mobile filter toggle button. * I've removed the transition rules for the filters, since `details` does not support them natively.
1 parent 2d04743 commit 5c503b3

File tree

5 files changed

+28
-32
lines changed

5 files changed

+28
-32
lines changed

app/assets/stylesheets/partials/_filters.scss

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#filters {
2-
.category {
2+
details.filter-category {
33
position: relative;
44
margin-bottom: 0.5em;
55
border: 1px solid $gray-l3;
66
border-radius: 3px;
77
}
88

9-
button.filter-label {
9+
summary.filter-label {
1010
display: flex;
1111
justify-content: space-between;
1212
width: 100%;
@@ -47,12 +47,6 @@
4747
}
4848
}
4949

50-
.filter-options {
51-
max-height: 0;
52-
transition: max-height 0.5s ease-in-out;
53-
overflow: hidden;
54-
}
55-
5650
ul.category-terms {
5751
border-collapse: separate;
5852
border-spacing: 0px 4px;

app/javascript/filters.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
// These elements aren't loaded with the initial DOM, they appear later.
22
function initFilterToggle() {
33
var filter_toggle = document.getElementById('filter-toggle');
4-
var filter_panel = document.getElementById('filters');
4+
var filter_panel = document.getElementById('filter-container');
5+
var filter_categories = document.getElementsByClassName('filter-category');
56
filter_toggle.addEventListener('click', event => {
67
filter_panel.classList.toggle('hidden-md');
78
filter_toggle.classList.toggle('expanded');
8-
9+
});
10+
[...filter_categories].forEach(element => {
11+
element.addEventListener('click', event => {
12+
element.getElementsByClassName('filter-label')[0].classList.toggle('expanded');
13+
});
914
});
1015
}
1116

app/views/search/_filter.html.erb

+7-11
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
<% return if values.blank? %>
22

3-
<div class="category">
4-
<button class="filter-label <%= 'expanded' if @enhanced_query[category].present? || first == true %>"
5-
onclick="toggleFilter(this)"><%= nice_labels[category] || category %></button>
3+
<details class="filter-category" <%= 'open' if @enhanced_query[category].present? || first == true %>>
4+
<summary class="filter-label<%= ' expanded' if @enhanced_query[category].present? || first == true %>">
5+
<%= nice_labels[category] || category %>
6+
</summary>
67
<div class="filter-options">
78
<ul class="category-terms list-unbulleted">
89
<% values.each do |term| %>
910
<li class="term">
1011
<% if filter_applied?(@enhanced_query[category.to_sym], term['key']) %>
1112
<a href="<%= results_path(remove_filter(@enhanced_query, category, term['key'])) %>" class="applied">
12-
<span class="sr">Remove applied filter?</span>
13+
<span class="sr">Remove applied filter:</span>
1314
<% else %>
1415
<a href="<%= results_path(add_filter(@enhanced_query, category, term['key'])) %>">
16+
<span class="sr">Apply filter:</span>
1517
<% end %>
1618
<span class="name"><%= term['key'] %></span>
1719
<span class="count"><%= term['docCount'] %> <span class="sr">records</span></span>
@@ -20,10 +22,4 @@
2022
<% end %>
2123
</ul>
2224
</div>
23-
</div>
24-
25-
<script>
26-
function toggleFilter(e) {
27-
e.parentNode.getElementsByClassName("filter-label")[0].classList.toggle("expanded");
28-
}
29-
</script>
25+
</details>

app/views/search/results.html.erb

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<div class="space-wrap">
44

55
<%= render partial: "shared/site_title" %>
6+
67
<%= render partial: "form" %>
78
<%= render partial: "search_summary" %>
89

@@ -17,9 +18,9 @@
1718

1819
<div class="<%= @filters.present? ? 'layout-1q3q' : 'layout-3q1q' %> layout-band top-space">
1920
<% if @filters.present? %>
20-
<aside class="col1q filter-container">
21+
<aside id="filters" class="col1q">
2122
<button id="filter-toggle"><span class="filter-toggle-name">Filter your results: <%= results_summary(@pagination[:hits]) %></span><span class="filter-toggle-hide">Hide filters</span></button>
22-
<div id="filters" class="hidden-md">
23+
<div id="filter-container" class="hidden-md">
2324
<div class="hidden-md">
2425
<h2 class="hd-3">Filter your results</h2>
2526
<h3 class="hd-4"><em><%= results_summary(@pagination[:hits]) %></em></h3>

test/controllers/search_controller_test.rb

+9-9
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class SearchControllerTest < ActionDispatch::IntegrationTest
135135
get '/results?q=data'
136136
assert_response :success
137137
assert_select '#filters'
138-
assert_select '#filters .category .filter-label', { minimum: 1 }
138+
assert_select '#filters .filter-category .filter-label', { minimum: 1 }
139139
end
140140
end
141141

@@ -211,7 +211,7 @@ class SearchControllerTest < ActionDispatch::IntegrationTest
211211
assert_select '#filters', { count: 0 }
212212

213213
# Filters are not shown
214-
assert_select '#filters .category h3', { count: 0 }
214+
assert_select '#filters .filter-category h3', { count: 0 }
215215

216216
# Pagination is not shown
217217
assert_select '#pagination', { count: 0 }
@@ -427,31 +427,31 @@ def source_filter_count(controller)
427427
ClimateControl.modify ACTIVE_FILTERS: '' do
428428
get '/results?q=data'
429429
assert_response :success
430-
assert_select '#filters .category .filter-label', { minimum: 1 }
430+
assert_select '#filters .filter-category .filter-label', { minimum: 1 }
431431
end
432432

433433
# Ask for a single filter, get that filter.
434434
ClimateControl.modify ACTIVE_FILTERS: 'subjects' do
435435
get '/results?q=data'
436436
assert_response :success
437-
assert_select '#filters .category .filter-label', { count: 1 }
438-
assert_select '#filters .category:first-of-type .filter-label', 'Subject'
437+
assert_select '#filters .filter-category .filter-label', { count: 1 }
438+
assert_select '#filters .filter-category:first-of-type .filter-label', 'Subject'
439439
end
440440

441441
# The order of the terms matter, so now Format should be first.
442442
ClimateControl.modify ACTIVE_FILTERS: 'format, contentType, source' do
443443
get '/results?q=data'
444444
assert_response :success
445-
assert_select '#filters .category .filter-label', { count: 3 }
446-
assert_select '#filters .category:first-of-type .filter-label', 'Format'
445+
assert_select '#filters .filter-category .filter-label', { count: 3 }
446+
assert_select '#filters .filter-category:first-of-type .filter-label', 'Format'
447447
end
448448

449449
# Including extra values does not affect anything - "nonsense" is extraneous.
450450
ClimateControl.modify ACTIVE_FILTERS: 'contentType, nonsense, source' do
451451
get '/results?q=data'
452452
assert_response :success
453-
assert_select '#filters .category .filter-label', { count: 2 }
454-
assert_select '#filters .category:first-of-type .filter-label', 'Content type'
453+
assert_select '#filters .filter-category .filter-label', { count: 2 }
454+
assert_select '#filters .filter-category:first-of-type .filter-label', 'Content type'
455455
end
456456
end
457457
end

0 commit comments

Comments
 (0)