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

Open filters on page load #3131

Merged
merged 3 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions app/assets/javascripts/components/option-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
this.hasFilter = this.$optionSelect.getAttribute('data-filter-element') || ''

this.checkedCheckboxes = []

this.mq = window.matchMedia('(min-width: 641px)')
this.isClosedOnLoad = this.$optionSelect.getAttribute('data-closed-on-load')
this.isClosedOnLoadMobile = this.$optionSelect.getAttribute('data-closed-on-load-mobile')
}

OptionSelect.prototype.init = function () {
Expand Down Expand Up @@ -57,25 +61,13 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
var button = this.$optionSelect.querySelector('.js-container-button')
button.addEventListener('click', this.toggleOptionSelect.bind(this))

var closedOnLoad = this.$optionSelect.getAttribute('data-closed-on-load')
var closedOnLoadMobile = this.$optionSelect.getAttribute('data-closed-on-load-mobile')

// By default the .filter-content container is hidden on mobile
// By checking if .filter-content is hidden, we are in mobile view given the current implementation
var isFacetsContentHidden = this.isFacetsContainerHidden()

// Check if the option select should be closed for mobile screen sizes
var closedForMobile = closedOnLoadMobile === 'true' && isFacetsContentHidden

// Always set the contain height to 200px for mobile screen sizes
if (closedForMobile) {
this.setContainerHeight(200)
}

if (closedOnLoad === 'true' || closedForMobile) {
this.close()
// Toggle option visibility depending on screen size (min-width: 641px) and
// presence of any 'closed' properties (`data-closed-on-load`, `data-closed-on-load-mobile`).
// See https://github.com/alphagov/govuk-frontend/blob/main/packages/govuk-frontend/src/govuk/settings/_media-queries.scss#L10-L14
if (this.mq.matches) {
this.toggleVisibility(true)
} else {
this.setupHeight()
this.toggleVisibility(false)
}

var checkedString = this.checkedString()
Expand All @@ -84,6 +76,22 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
}
}

OptionSelect.prototype.toggleVisibility = function (isTabletOrLarger) {
if (isTabletOrLarger) {
if (this.isClosedOnLoad === 'true') {
this.close()
} else {
this.setupHeight()
}
} else {
if (this.isClosedOnLoadMobile === 'true' || this.isClosedOnLoad === 'true') {
this.close()
} else {
this.setContainerHeight(201)
}
}
}

OptionSelect.prototype.typeFilterText = function (event) {
event.stopPropagation()
var ENTER_KEY = 13
Expand Down
4 changes: 4 additions & 0 deletions app/assets/javascripts/modules/mobile-filters-modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
this.triggerElement.addEventListener('click', this.module.toggle)
this.triggerElement.setAttribute('aria-controls', this.module.id)
this.triggerElement.setAttribute('aria-expanded', 'false')
// Open filter on page load if data attribute "open_on_load" is present
if (this.triggerElement.getAttribute('data-open-on-load') === 'true') {
this.triggerElement.click()
}
}

if (this.clearFiltersTrigger) {
Expand Down
4 changes: 4 additions & 0 deletions app/models/content_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ def filter
content_item_hash.dig("details", "filter") || {}
end

def open_filter_on_load
content_item_hash.dig("details", "open_filter_on_load") || ""
end

def reject
content_item_hash.dig("details", "reject") || {}
end
Expand Down
1 change: 1 addition & 0 deletions app/views/finders/_filter_button.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
data-track-label=""
data-module="ga4-event-tracker"
data-ga4-expandable=""
data-open-on-load="<%= @content_item.open_filter_on_load %>"
>
Filter <span class="govuk-visually-hidden"> results</span>
<span class="js-selected-filter-count"><%= sanitize facet_tags.display_total_selected_filters %></span>
Expand Down
174 changes: 97 additions & 77 deletions spec/javascripts/modules/mobile-filters-modal.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
describe('Mobile filters modal', function () {
describe('Mobile filters', function () {
'use strict'

var container
Expand Down Expand Up @@ -44,107 +44,127 @@ describe('Mobile filters modal', function () {
container.addEventListener('submit', function (e) {
e.preventDefault()
})

var element = $('[data-module="mobile-filters-modal"]')[0]
new GOVUK.Modules.MobileFiltersModal(element).init()
})

afterEach(function () {
document.body.removeChild(container)
})

describe('open button', function () {
describe('Mobile filters modal', function () {
beforeEach(function () {
document.querySelector('.js-toggle-mobile-filters').click()
})

afterEach(function () {
document.querySelector('.js-toggle-mobile-filters').click()
})

it('should show the modal', function () {
var modal = document.querySelector('.facets')
expect($(modal).hasClass('facets--visible')).toBe(true)
var element = $('[data-module="mobile-filters-modal"]')[0]
new GOVUK.Modules.MobileFiltersModal(element).init()
})

it('should hide the modal', function () {
var modal = document.querySelector('.facets')
document.querySelector('.js-toggle-mobile-filters').click()
expect($(modal).hasClass('facets--visible')).toBe(false)
describe('open button', function () {
beforeEach(function () {
document.querySelector('.js-toggle-mobile-filters').click()
})

afterEach(function () {
document.querySelector('.js-toggle-mobile-filters').click()
})

it('should show the modal', function () {
var modal = document.querySelector('.facets')
expect($(modal).hasClass('facets--visible')).toBe(true)
})

it('should hide the modal', function () {
var modal = document.querySelector('.facets')
document.querySelector('.js-toggle-mobile-filters').click()
expect($(modal).hasClass('facets--visible')).toBe(false)
})
})
})

describe('open', function () {
beforeEach(function () {
var modal = document.querySelector('.facets')
modal.open()
describe('open', function () {
beforeEach(function () {
var modal = document.querySelector('.facets')
modal.open()
})

afterEach(function () {
var modal = document.querySelector('.facets')
modal.close()
})

it('should show the modal', function () {
var modal = document.querySelector('.facets')
expect($(modal).hasClass('facets--visible')).toBe(true)
})
})

afterEach(function () {
var modal = document.querySelector('.facets')
modal.close()
describe('close', function () {
it('should hide the modal', function () {
var modal = document.querySelector('.facets')
modal.open()
modal.close()
expect($(modal).hasClass('facets--visible')).toBe(false)
})
})

it('should show the modal', function () {
var modal = document.querySelector('.facets')
expect($(modal).hasClass('facets--visible')).toBe(true)
describe('clear filters', function () {
it('should reset checkboxes, clear text input and <select> values', function () {
var modal = document.querySelector('.facets')
modal.clearFilters()
expect($(modal).find('input:checked').length).toBe(0)
// number of text inputs with value should now be 0
expect($(modal).find('input[type="text"]')
.filter(function () { return $(this).val() }).length).toBe(0)
expect($(modal).find('select').val()).toBe('')
})
})
})

describe('close', function () {
it('should hide the modal', function () {
var modal = document.querySelector('.facets')
modal.open()
modal.close()
expect($(modal).hasClass('facets--visible')).toBe(false)
describe('accessibility', function () {
it('should add aria-expanded="false" on load to the Filter button', function () {
var button = document.querySelector('.js-toggle-mobile-filters')
expect(button.getAttribute('aria-expanded')).toEqual('false')
})

it('should set aria-expanded to true when clicking the Filter button', function () {
var button = document.querySelector('.js-toggle-mobile-filters')
button.click()
expect(button.getAttribute('aria-expanded')).toEqual('true')
})

it('should add aria-controls on load to the Filter button', function () {
var button = document.querySelector('.js-toggle-mobile-filters')
expect(button.getAttribute('aria-controls')).toEqual('facet-wrapper')
expect(document.querySelector('#facet-wrapper')).not.toEqual(null)
})
})
})

describe('clear filters', function () {
it('should reset checkboxes, clear text input and <select> values', function () {
var modal = document.querySelector('.facets')
modal.clearFilters()
expect($(modal).find('input:checked').length).toBe(0)
// number of text inputs with value should now be 0
expect($(modal).find('input[type="text"]')
.filter(function () { return $(this).val() }).length).toBe(0)
expect($(modal).find('select').val()).toBe('')
describe('ga4 tracking', function () {
it('adds the ga4 event tracker to the button', function () {
var button = document.querySelector('.js-toggle-mobile-filters')
var expected = {
event_name: 'select_content',
type: 'finder',
text: 'Filter',
section: 'Filter',
index: {
index_section: 0,
index_section_count: 5
}
}
expect(button.getAttribute('data-ga4-event')).toEqual(JSON.stringify(expected))
})
})
})

describe('accessibility', function () {
it('should add aria-expanded="false" on load to the Filter button', function () {
var button = document.querySelector('.js-toggle-mobile-filters')
expect(button.getAttribute('aria-expanded')).toEqual('false')
})

it('should set aria-expanded to true when clicking the Filter button', function () {
var button = document.querySelector('.js-toggle-mobile-filters')
button.click()
expect(button.getAttribute('aria-expanded')).toEqual('true')
})
describe('Mobile filters modal (open on load)', function () {
beforeEach(function () {
container.querySelector('button').dataset.openOnLoad = true

it('should add aria-controls on load to the Filter button', function () {
var button = document.querySelector('.js-toggle-mobile-filters')
expect(button.getAttribute('aria-controls')).toEqual('facet-wrapper')
expect(document.querySelector('#facet-wrapper')).not.toEqual(null)
var element = $('[data-module="mobile-filters-modal"]')[0]
new GOVUK.Modules.MobileFiltersModal(element).init()
})
})

describe('ga4 tracking', function () {
it('adds the ga4 event tracker to the button', function () {
var button = document.querySelector('.js-toggle-mobile-filters')
var expected = {
event_name: 'select_content',
type: 'finder',
text: 'Filter',
section: 'Filter',
index: {
index_section: 0,
index_section_count: 5
}
}
expect(button.getAttribute('data-ga4-event')).toEqual(JSON.stringify(expected))
describe('open on load', function () {
it('should show the modal', function () {
var modal = document.querySelector('.facets')
expect($(modal).hasClass('facets--visible')).toBe(true)
})
})
})
})