Skip to content

Commit

Permalink
Fix focus/click race condition on language dropdown (#286)
Browse files Browse the repository at this point in the history
* Fix focus/click race condition on language dropdown

* Fix language dropwdown unit tests

* Fix unit tests in IE

* Ensure linking to other pages works and give examples

* Fix language unit tests
  • Loading branch information
bameyrick authored Mar 15, 2019
1 parent 20bf5ba commit 01a8243
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 29 deletions.
20 changes: 12 additions & 8 deletions src/components/language-selector/language.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export class LanguageSelector {

this.throttledSetOpen = throttle(this.setOpen.bind(this), 200);
this.setAriaAttributes();
this.button.addEventListener('click', this.toggle.bind(this));
this.button.addEventListener('focus', () => this.throttledSetOpen(true));
document.body.addEventListener('click', () => this.throttledSetOpen(false));
this.button.addEventListener('mousedown', this.toggle.bind(this));
this.button.addEventListener('focus', event => this.throttledSetOpen(event, true));
document.body.addEventListener('mousedown', event => this.throttledSetOpen(event, false));
this.setDisplay();
}

Expand All @@ -35,14 +35,18 @@ export class LanguageSelector {
event.stopPropagation();
const isOpen = this.context.classList.contains('language-switcher--open');

this.throttledSetOpen(!isOpen);
this.throttledSetOpen(event, !isOpen);
}

setOpen(open) {
this.button.setAttribute('aria-expanded', open);
setOpen(event, open) {
const delay = event.target.classList.contains('js-language-switcher-item') ? 300 : 0;

this.context.classList[open ? 'add' : 'remove']('language-switcher--open');
this.items.forEach(item => item.setAttribute('tabindex', open ? 0 : -1));
setTimeout(() => {
this.button.setAttribute('aria-expanded', open);

this.context.classList[open ? 'add' : 'remove']('language-switcher--open');
this.items.forEach(item => item.setAttribute('tabindex', open ? 0 : -1));
}, delay);
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/js/utils/trigger-event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function triggerEvent(element, eventType) {
let event;
if (typeof Event === 'function') {
event = new Event(eventType);
} else {
event = document.createEvent('Event');
event.initEvent(eventType, true, true);
}

element.dispatchEvent(event);
}
69 changes: 69 additions & 0 deletions src/patterns/language-selection/examples/many-languages/cy.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
layout: none
---
{% extends "styles/page-template/_template.njk" %}

{% set page = {
"title": "Enw'r gwasanaeth",
"language": {
"languages": [
{
"url": "/patterns/language-selection/examples/many-languages",
"ISOCode": "en-GB",
"text": "English",
"buttonAriaLabel": "Language selector. Current language: English",
"chooseLanguage": "Choose language",
"current": false
},
{
"url": "/patterns/language-selection/examples/many-languages/cy.html",
"ISOCode": "cy",
"text": "Cymraeg",
"buttonAriaLabel": "Dewisydd iaith. Iaith gyfredol: Cymraeg",
"chooseLanguage": "Dewiswch iaith",
"current": true
},
{
"url": "/patterns/language-selection/examples/many-languages/ga.html",
"ISOCode": "ga",
"text": "Gaeilge",
"buttonAriaLabel": "Roghnóir teanga. Teanga reatha: Gaeilge",
"chooseLanguage": "Roghnaigh teanga",
"current": false
},
{
"url": "/patterns/language-selection/examples/many-languages/sco.html",
"ISOCode": "sco",
"text": "Ulstèr-Scotch",
"buttonAriaLabel": "Leid selectgor. Current leid: Ulstèr-Scotch",
"chooseLanguage": "Wale leid",
"current": false
}
]
},
"footer": {
"rows": [
{
"items": [
{
"text": "Cysyllwch a ni",
"url": "#"
},
{
"text": "Cwcis ac preifatrwydd",
"url": "#"
}
]
}
],
"OGLLink": {
"pre": "Mae'r holl gynnwys ar gael o dan y",
"link": "Drwydded Llywodraeth Leol v3.0",
"url": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
"post": ", oni bai y nodir fel arall"
}
}
} %}

{% block content %}
{% endblock %}
69 changes: 69 additions & 0 deletions src/patterns/language-selection/examples/many-languages/ga.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
layout: none
---
{% extends "styles/page-template/_template.njk" %}

{% set page = {
"title": "Enw'r gwasanaeth",
"language": {
"languages": [
{
"url": "/patterns/language-selection/examples/many-languages",
"ISOCode": "en-GB",
"text": "English",
"buttonAriaLabel": "Language selector. Current language: English",
"chooseLanguage": "Choose language",
"current": false
},
{
"url": "/patterns/language-selection/examples/many-languages/cy.html",
"ISOCode": "cy",
"text": "Cymraeg",
"buttonAriaLabel": "Dewisydd iaith. Iaith gyfredol: Cymraeg",
"chooseLanguage": "Dewiswch iaith",
"current": false
},
{
"url": "/patterns/language-selection/examples/many-languages/ga.html",
"ISOCode": "ga",
"text": "Gaeilge",
"buttonAriaLabel": "Roghnóir teanga. Teanga reatha: Gaeilge",
"chooseLanguage": "Roghnaigh teanga",
"current": true
},
{
"url": "/patterns/language-selection/examples/many-languages/sco.html",
"ISOCode": "sco",
"text": "Ulstèr-Scotch",
"buttonAriaLabel": "Leid selectgor. Current leid: Ulstèr-Scotch",
"chooseLanguage": "Wale leid",
"current": false
}
]
},
"footer": {
"rows": [
{
"items": [
{
"text": "Glaoigh orainn",
"url": "#"
},
{
"text": "Fianáin agus príobháideachas",
"url": "#"
}
]
}
],
"OGLLink": {
"pre": "Tá an t-ábhar go léir ar fáil faoin",
"link": "gCeadúnas Oscailte Rialtais v3.0",
"url": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
"post": ", ach amháin nuair a luaitear a mhalairt"
}
}
} %}

{% block content %}
{% endblock %}
24 changes: 12 additions & 12 deletions src/patterns/language-selection/examples/many-languages/index.njk
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,31 @@ layout: none
"language": {
"languages": [
{
"url": "#",
"url": "/patterns/language-selection/examples/many-languages",
"ISOCode": "en-GB",
"text": "English",
"buttonAriaLabel": "Language selector. Current language: English",
"chooseLanguage": "Choose language",
"current": true
},
{
"url": "#",
"url": "/patterns/language-selection/examples/many-languages/cy.html",
"ISOCode": "cy",
"text": "Cymraeg",
"buttonAriaLabel": "Dewisydd iaith. Iaith gyfredol: Cymraeg",
"chooseLanguage": "Dewiswch iaith",
"current": false
},
{
"url": "#",
"url": "/patterns/language-selection/examples/many-languages/ga.html",
"ISOCode": "ga",
"text": "Gaeilge",
"buttonAriaLabel": "Roghnóir teanga. Teanga reatha: Gaeilge",
"chooseLanguage": "Roghnaigh teanga",
"current": false
},
{
"url": "#",
"url": "/patterns/language-selection/examples/many-languages/sco.html",
"ISOCode": "sco",
"text": "Ulstèr-Scotch",
"buttonAriaLabel": "Leid selectgor. Current leid: Ulstèr-Scotch",
Expand All @@ -43,21 +43,21 @@ layout: none
},
"footer": {
"OGLLink": {
"pre": 'All content is available under the',
"link": 'Open Government Licence v3.0',
"url": 'https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/',
"post": ', except where otherwise stated'
"pre": "All content is available under the",
"link": "Open Government Licence v3.0",
"url": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
"post": ", except where otherwise stated"
},
"rows": [
{
"items": [
{
"text": 'Contact us',
"url": '#'
"text": "Contact us",
"url": "#"
},
{
"text": 'Cookies and privacy',
"url": '#'
"text": "Cookies and privacy",
"url": "#"
}
]
}
Expand Down
69 changes: 69 additions & 0 deletions src/patterns/language-selection/examples/many-languages/sco.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
layout: none
---
{% extends "styles/page-template/_template.njk" %}

{% set page = {
"title": "Ainm na seirbhíse",
"language": {
"languages": [
{
"url": "/patterns/language-selection/examples/many-languages",
"ISOCode": "en-GB",
"text": "English",
"buttonAriaLabel": "Language selector. Current language: English",
"chooseLanguage": "Choose language",
"current": false
},
{
"url": "/patterns/language-selection/examples/many-languages/cy.html",
"ISOCode": "cy",
"text": "Cymraeg",
"buttonAriaLabel": "Dewisydd iaith. Iaith gyfredol: Cymraeg",
"chooseLanguage": "Dewiswch iaith",
"current": false
},
{
"url": "/patterns/language-selection/examples/many-languages/ga.html",
"ISOCode": "ga",
"text": "Gaeilge",
"buttonAriaLabel": "Roghnóir teanga. Teanga reatha: Gaeilge",
"chooseLanguage": "Roghnaigh teanga",
"current": false
},
{
"url": "/patterns/language-selection/examples/many-languages/sco.html",
"ISOCode": "sco",
"text": "Ulstèr-Scotch",
"buttonAriaLabel": "Leid selectgor. Current leid: Ulstèr-Scotch",
"chooseLanguage": "Wale leid",
"current": true
}
]
},
"footer": {
"rows": [
{
"items": [
{
"text": "Cuir fios thugainn",
"url": "#"
},
{
"text": "Briosgaidean is prìobhaideachd",
"url": "#"
}
]
}
],
"OGLLink": {
"pre": "Tha an t-susbaint gu lèir ri fhaighinn fo",
"link": "cheadachas an Riaghaltais Fhosgailte v3.0",
"url": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
"post": ", ach a-mhàin far a bheil a chaochladh air a ràdh"
}
}
} %}

{% block content %}
{% endblock %}
26 changes: 17 additions & 9 deletions src/tests/spec/language-selector/language.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import template from 'components/language-selector/_test-template.njk';
import LanguageSelector from 'components/language-selector/language';
import eventMock from 'stubs/event.stub.spec';
import { throttle } from 'throttle-typescript';
import triggerEvent from 'js/utils/trigger-event';

const params = {
allLanguagesUrl: '#',
Expand Down Expand Up @@ -98,7 +99,7 @@ describe('Component: Language Selector', () => {

describe('and toggle is called', function() {
it('event propagation should be stopped', function() {
const mockedEvent = eventMock();
const mockedEvent = eventMock({ target: this.button });

this.languageSelector.toggle(mockedEvent);

Expand All @@ -108,12 +109,14 @@ describe('Component: Language Selector', () => {

describe('and menu is not open', function() {
describe('when button is clicked', function() {
beforeEach(function() {
beforeEach(function(done) {
this.languageSelector.setOpen = chai.spy(this.languageSelector.setOpen);
this.languageSelector.throttledSetOpen = throttle(this.languageSelector.setOpen);

this.languageSelector.toggle(eventMock());
this.languageSelector.toggle(eventMock({ target: this.button }));
this.languageSelector.throttledSetOpen(true);

setTimeout(done);
});

it('setOpen should be throttled and only called once', function() {
Expand All @@ -134,27 +137,32 @@ describe('Component: Language Selector', () => {
});

describe('and menu is open', function() {
beforeEach(function() {
this.languageSelector.setOpen(true);
beforeEach(function(done) {
this.languageSelector.setOpen(eventMock({ target: this.button }), true);
setTimeout(done);
});

describe('when the document body is clicked', function() {
beforeEach(function() {
beforeEach(function(done) {
this.languageSelector.setOpen = chai.spy(this.languageSelector.setOpen);
this.languageSelector.throttledSetOpen = throttle(this.languageSelector.setOpen);

document.body.click();
triggerEvent(document.body, 'mousedown');

setTimeout(done, 300);
});

closeTests();
});

describe('when button is clicked', function() {
beforeEach(function() {
beforeEach(function(done) {
this.languageSelector.setOpen = chai.spy(this.languageSelector.setOpen);
this.languageSelector.throttledSetOpen = throttle(this.languageSelector.setOpen);

this.button.click();
triggerEvent(this.button, 'mousedown');

setTimeout(done);
});

closeTests();
Expand Down

0 comments on commit 01a8243

Please sign in to comment.