Merge pull request #3622 from alphagov/searchbox-make-autofocus-optional

Autofocus off by default on live-search
This commit is contained in:
Pea M. Tyczynska
2020-09-29 10:58:00 +01:00
committed by GitHub
14 changed files with 156 additions and 43 deletions

View File

@@ -3,13 +3,26 @@
Modules.Autofocus = function() { Modules.Autofocus = function() {
this.start = function(component) { this.start = function(component) {
var forceFocus = $(component).data('forceFocus'); var $component = $(component),
forceFocus = $component.data('forceFocus'),
labelText = $('label[for="' + $component.attr('id') + '"]').eq(0).text().trim(),
clearAriaLabel = evt => {
$component.removeAttr('aria-label');
$component.off('blur', clearAriaLabel);
};
// if the page loads with a scroll position, we can't assume the item to focus onload // if the page loads with a scroll position, we can't assume the item to focus onload
// is still where users intend to start // is still where users intend to start
if (($(window).scrollTop() > 0) && !forceFocus) { return; } if (($(window).scrollTop() > 0) && !forceFocus) { return; }
$(component).filter('input, textarea, select').eq(0).trigger('focus'); // screenreaders announce the page title when a new page loads
// this will be lost when focus is moved to our form control so add it to the label instead
$component.attr('aria-label', document.title + ' - ' + labelText);
$component.filter('input, textarea, select').eq(0).trigger('focus');
// the page title prefix is only needed on page load so remove once focus has shifted
$component.on('blur', clearAriaLabel);
}; };
}; };

View File

@@ -1,21 +1,25 @@
{% from "components/textbox.html" import textbox %}
{% macro live_search( {% macro live_search(
target_selector=None, target_selector=None,
show=False, show=False,
form=None, form=None,
label=None label=None,
autofocus=False
) %} ) %}
{%- set search_label = label or form.search.label.text %} {%- set search_label = label or form.search.label.text %}
{%- set param_extensions = {
"label": {"text": search_label},
"autocomplete": "off",
} %}
{% if autofocus %}
{% set x=param_extensions.__setitem__("attributes", {"data-module": "autofocus"}) %}
{% endif %}
{% if show %} {% if show %}
<div data-module="autofocus">
<div class="live-search js-header" data-module="live-search" data-targets="{{ target_selector }}"> <div class="live-search js-header" data-module="live-search" data-targets="{{ target_selector }}">
{{ form.search(param_extensions={ {{ form.search(param_extensions=param_extensions) }}
"label": {"text": search_label},
"autocomplete": "off"
}) }}
<div role="region" aria-live="polite" class="live-search__status govuk-visually-hidden"></div> <div role="region" aria-live="polite" class="live-search__status govuk-visually-hidden"></div>
</div> </div>
</div>
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}

View File

@@ -14,7 +14,13 @@
back_link=url_for('.choose_broadcast_library', service_id=current_service.id, broadcast_message_id=broadcast_message.id), back_link=url_for('.choose_broadcast_library', service_id=current_service.id, broadcast_message_id=broadcast_message.id),
)}} )}}
{{ live_search(target_selector='.file-list-item', show=show_search_form, form=search_form, label='Search by name') }} {{ live_search(
target_selector='.file-list-item',
show=show_search_form,
form=search_form,
label='Search by name',
autofocus=True)
}}
{% for area in library|sort %} {% for area in library|sort %}
<div class="file-list-item"> <div class="file-list-item">

View File

@@ -16,7 +16,13 @@
back_link=url_for('.choose_broadcast_library', service_id=current_service.id, broadcast_message_id=broadcast_message.id), back_link=url_for('.choose_broadcast_library', service_id=current_service.id, broadcast_message_id=broadcast_message.id),
)}} )}}
{{ live_search(target_selector='.govuk-checkboxes__item', show=show_search_form, form=search_form, label='Search by name') }} {{ live_search(
target_selector='.govuk-checkboxes__item',
show=show_search_form,
form=search_form,
label='Search by name',
autofocus=True)
}}
{% call form_wrapper() %} {% call form_wrapper() %}
{{ form.areas }} {{ form.areas }}

View File

@@ -3,14 +3,16 @@
{% from "components/live-search.html" import live_search %} {% from "components/live-search.html" import live_search %}
{% from "components/button/macro.njk" import govukButton %} {% from "components/button/macro.njk" import govukButton %}
{% set page_title = "Email branding" %}
{% block per_page_title %} {% block per_page_title %}
Email branding {{ page_title }}
{% endblock %} {% endblock %}
{% block platform_admin_content %} {% block platform_admin_content %}
<h1 class="heading-medium">Email branding</h1> <h1 class="heading-medium">{{ page_title }}</h1>
{{ live_search(target_selector='.email-brand', show=True, form=search_form) }} {{ live_search(target_selector='.email-brand', show=True, form=search_form, autofocus=True) }}
<nav> <nav>
{% for brand in email_brandings %} {% for brand in email_brandings %}
<div class="email-brand"> <div class="email-brand">

View File

@@ -3,14 +3,16 @@
{% from "components/live-search.html" import live_search %} {% from "components/live-search.html" import live_search %}
{% from "components/button/macro.njk" import govukButton %} {% from "components/button/macro.njk" import govukButton %}
{% set page_title = "Letter branding" %}
{% block per_page_title %} {% block per_page_title %}
Letter branding {{ page_title }}
{% endblock %} {% endblock %}
{% block platform_admin_content %} {% block platform_admin_content %}
<h1 class="heading-medium">Letter branding</h1> <h1 class="heading-medium">{{ page_title }}</h1>
{{ live_search(target_selector='.letter-brand', show=True, form=search_form) }} {{ live_search(target_selector='.letter-brand', show=True, form=search_form, autofocus=True) }}
<nav> <nav>
{% for brand in letter_brandings %} {% for brand in letter_brandings %}
<div class="letter-brand"> <div class="letter-brand">

View File

@@ -6,20 +6,28 @@
{% from "components/live-search.html" import live_search %} {% from "components/live-search.html" import live_search %}
{% from "components/form.html" import form_wrapper %} {% from "components/form.html" import form_wrapper %}
{% set page_title = "Accept our data sharing and financial agreement" %}
{% block per_page_title %} {% block per_page_title %}
Accept our data sharing and financial agreement {{ page_title }}
{% endblock %} {% endblock %}
{% block maincolumn_content %} {% block maincolumn_content %}
{{ page_header( {{ page_header(
'Accept our data sharing and financial agreement', page_title,
back_link=url_for('main.request_to_go_live', service_id=current_service.id) back_link=url_for('main.request_to_go_live', service_id=current_service.id)
) }} ) }}
{% call form_wrapper() %} {% call form_wrapper() %}
<p class="govuk-body"> <p class="govuk-body">
{{ form.organisations.label.text }} {{ form.organisations.label.text }}
</p> </p>
{{ live_search(target_selector='.multiple-choice', show=True, form=search_form, label='Search by name') }} {{ live_search(
target_selector='.multiple-choice',
show=True,
form=search_form,
label='Search by name',
autofocus=True)
}}
{{ radios(form.organisations, hide_legend=True) }} {{ radios(form.organisations, hide_legend=True) }}
{{ sticky_page_footer('Continue') }} {{ sticky_page_footer('Continue') }}
{% endcall %} {% endcall %}

View File

@@ -5,14 +5,16 @@
{% from "components/live-search.html" import live_search %} {% from "components/live-search.html" import live_search %}
{% from "components/form.html" import form_wrapper %} {% from "components/form.html" import form_wrapper %}
{% block org_page_title %} {% set page_title = "Default email branding" %}
Default email branding
{% block per_page_title %}
{{ page_title }}
{% endblock %} {% endblock %}
{% block maincolumn_content %} {% block maincolumn_content %}
{{ page_header( {{ page_header(
"Default email branding", page_title,
back_link=url_for('.organisation_settings', org_id=current_org.id) back_link=url_for('.organisation_settings', org_id=current_org.id)
) }} ) }}
{% call form_wrapper(data_kwargs={'preview-type': 'email'}) %} {% call form_wrapper(data_kwargs={'preview-type': 'email'}) %}
@@ -22,7 +24,13 @@
</div> </div>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-full"> <div class="govuk-grid-column-full">
{{ live_search(target_selector='.multiple-choice', show=True, form=search_form, label='Search branding styles by name') }} {{ live_search(
target_selector='.multiple-choice',
show=True,
form=search_form,
label='Search branding styles by name',
autofocus=True
) }}
{{ radios(form.branding_style) }} {{ radios(form.branding_style) }}
</div> </div>
</div> </div>

View File

@@ -5,14 +5,16 @@
{% from "components/page-header.html" import page_header %} {% from "components/page-header.html" import page_header %}
{% from "components/form.html" import form_wrapper %} {% from "components/form.html" import form_wrapper %}
{% block org_page_title %} {% set page_title = "Default letter branding" %}
Default letter branding
{% block per_page_title %}
{{ page_title }}
{% endblock %} {% endblock %}
{% block maincolumn_content %} {% block maincolumn_content %}
{{ page_header( {{ page_header(
"Default letter branding", page_title,
back_link=url_for('.organisation_settings', org_id=current_org.id) back_link=url_for('.organisation_settings', org_id=current_org.id)
) }} ) }}
{% call form_wrapper(data_kwargs={'preview-type': 'letter'}) %} {% call form_wrapper(data_kwargs={'preview-type': 'letter'}) %}
@@ -22,7 +24,13 @@
</div> </div>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-full"> <div class="govuk-grid-column-full">
{{ live_search(target_selector='.multiple-choice', show=True, form=search_form, label='Search by name') }} {{ live_search(
target_selector='.multiple-choice',
show=True,
form=search_form,
label='Search by name',
autofocus=True
) }}
{{ radios(form.branding_style, hide_legend=True) }} {{ radios(form.branding_style, hide_legend=True) }}
</div> </div>
</div> </div>

View File

@@ -5,17 +5,24 @@
{% from "components/live-search.html" import live_search %} {% from "components/live-search.html" import live_search %}
{% from "components/form.html" import form_wrapper %} {% from "components/form.html" import form_wrapper %}
{% set page_title = "Link service to organisation" %}
{% block service_page_title %} {% block service_page_title %}
Link service to organisation {{ page_title }}
{% endblock %} {% endblock %}
{% block maincolumn_content %} {% block maincolumn_content %}
{{ page_header( {{ page_header(
'Link service to organisation', page_title,
back_link=url_for('.service_settings', service_id=current_service.id) back_link=url_for('.service_settings', service_id=current_service.id)
) }} ) }}
{{ live_search(target_selector='.multiple-choice', show=True, form=search_form, label='Search by name') }} {{ live_search(
target_selector='.multiple-choice',
show=True, form=search_form,
label='Search by name',
autofocus=True
) }}
{% call form_wrapper() %} {% call form_wrapper() %}
{% if has_organisations %} {% if has_organisations %}
{{ radios(form.organisations) }} {{ radios(form.organisations) }}

View File

@@ -5,14 +5,16 @@
{% from "components/live-search.html" import live_search %} {% from "components/live-search.html" import live_search %}
{% from "components/form.html" import form_wrapper %} {% from "components/form.html" import form_wrapper %}
{% set page_title = "Set email branding" %}
{% block service_page_title %} {% block service_page_title %}
Set email branding {{ page_title }}
{% endblock %} {% endblock %}
{% block maincolumn_content %} {% block maincolumn_content %}
{{ page_header( {{ page_header(
'Set email branding', page_title,
back_link=url_for('.service_settings', service_id=current_service.id) back_link=url_for('.service_settings', service_id=current_service.id)
) }} ) }}
{% call form_wrapper(data_kwargs={'preview-type': 'email'}) %} {% call form_wrapper(data_kwargs={'preview-type': 'email'}) %}
@@ -22,7 +24,13 @@
</div> </div>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-full"> <div class="govuk-grid-column-full">
{{ live_search(target_selector='.multiple-choice', show=True, form=search_form, label='Search branding styles by name') }} {{ live_search(
target_selector='.multiple-choice',
show=True,
form=search_form,
label='Search branding styles by name',
autofocus=True
) }}
{{ radios(form.branding_style) }} {{ radios(form.branding_style) }}
</div> </div>
</div> </div>

View File

@@ -5,14 +5,16 @@
{% from "components/page-footer.html" import page_footer %} {% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %} {% from "components/form.html" import form_wrapper %}
{% set page_title = "Set letter branding" %}
{% block service_page_title %} {% block service_page_title %}
Set letter branding {{ page_title }}
{% endblock %} {% endblock %}
{% block maincolumn_content %} {% block maincolumn_content %}
{{ page_header( {{ page_header(
'Set letter branding', page_title,
back_link=url_for('.service_settings', service_id=current_service.id) back_link=url_for('.service_settings', service_id=current_service.id)
) }} ) }}
{% call form_wrapper(data_kwargs={'preview-type': 'letter'}) %} {% call form_wrapper(data_kwargs={'preview-type': 'letter'}) %}
@@ -22,7 +24,13 @@
</div> </div>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-full"> <div class="govuk-grid-column-full">
{{ live_search(target_selector='.multiple-choice', show=True, form=search_form, label='Search by name') }} {{ live_search(
target_selector='.multiple-choice',
show=True,
form=search_form,
label='Search by name',
autofocus=True
) }}
{{ radios(form.branding_style, hide_legend=True) }} {{ radios(form.branding_style, hide_legend=True) }}
</div> </div>
</div> </div>

View File

@@ -2,15 +2,16 @@
{% from "components/live-search.html" import live_search %} {% from "components/live-search.html" import live_search %}
{% extends "withnav_template.html" %} {% extends "withnav_template.html" %}
{% set page_title = "Copy an existing template" %}
{% block service_page_title %} {% block service_page_title %}
Copy an existing template {{ page_title }}
{% endblock %} {% endblock %}
{% block maincolumn_content %} {% block maincolumn_content %}
<div class="bottom-gutter-1-2"> <div class="bottom-gutter-1-2">
<h1 class="heading-large">Copy an existing template</h1> <h1 class="heading-large">{{ page_title }}</h1>
{{ copy_folder_path(template_folder_path, current_service.id, from_service, current_user) }} {{ copy_folder_path(template_folder_path, current_service.id, from_service, current_user) }}
</div> </div>
{% if not services_templates_and_folders.templates_to_show %} {% if not services_templates_and_folders.templates_to_show %}
@@ -18,7 +19,12 @@
This folder is empty This folder is empty
</p> </p>
{% else %} {% else %}
{{ live_search(target_selector='#template-list .template-list-item', show=True, form=search_form) }} {{ live_search(
target_selector='#template-list .template-list-item',
show=True,
form=search_form,
autofocus=True
) }}
<nav id="template-list"> <nav id="template-list">
{% for item in services_templates_and_folders %} {% for item in services_templates_and_folders %}
<div class="template-list-item {% if item.ancestors %}template-list-item-hidden-by-default{% endif %} {% if not item.ancestors %}template-list-item-without-ancestors{% endif %}"> <div class="template-list-item {% if item.ancestors %}template-list-item-hidden-by-default{% endif %} {% if not item.ancestors %}template-list-item-without-ancestors{% endif %}">

View File

@@ -1,3 +1,5 @@
const helpers = require('./support/helpers.js');
beforeAll(() => { beforeAll(() => {
require('../../app/assets/javascripts/autofocus.js'); require('../../app/assets/javascripts/autofocus.js');
}); });
@@ -8,16 +10,19 @@ afterAll(() => {
describe('Autofocus', () => { describe('Autofocus', () => {
const labelText = 'Search by name';
let focusHandler; let focusHandler;
let search; let search;
beforeEach(() => { beforeEach(() => {
document.title = 'Find services by name - GOV.UK Notify';
// set up DOM // set up DOM
document.body.innerHTML = document.body.innerHTML =
`<div> `<div>
<label class="form-label" for="search"> <label class="form-label" for="search">
Search by name ${labelText}
</label> </label>
<input autocomplete="off" class="form-control form-control-1-1" id="search" name="search" type="search" value="" data-module="autofocus"> <input autocomplete="off" class="form-control form-control-1-1" id="search" name="search" type="search" value="" data-module="autofocus">
</div>`; </div>`;
@@ -45,6 +50,28 @@ describe('Autofocus', () => {
}); });
test('has a label including the page title when the module starts', () => {
// start module
window.GOVUK.modules.start();
expect(search.hasAttribute('aria-label')).toBe(true);
expect(search.getAttribute('aria-label')).toEqual(document.title + ' - ' + labelText);
});
test('gets the original label back when focus moves away', () => {
// start module
window.GOVUK.modules.start();
// shift focus away from textbox
helpers.triggerEvent(search, 'blur');
expect(search.hasAttribute('aria-label')).toBe(false);
});
test('is not focused if the window has scrolled', () => { test('is not focused if the window has scrolled', () => {
// mock the window being scrolled 25px // mock the window being scrolled 25px