Skip to content

Commit ff7346a

Browse files
authored
fix focus trap (#220)
* do not clear if user is tabbing through * Update CHANGELOG.md * build out logic to make this function testable * test there is no focus trap * wrap debounce around function in addeventlistener to properly test on _onKeyDown function
1 parent bdc7d51 commit ff7346a

File tree

3 files changed

+49
-12
lines changed

3 files changed

+49
-12
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Upgrade dev dependencies
88
- Remove hardcoded IDs in bounding box exception list
99
- Fix duplicate event bug
10+
- Fix trapped focus [#220](https://github.com/mapbox/mapbox-gl-geocoder/issues/220)
1011

1112
## v3.1.6
1213
- Resolve npm publish failure

lib/index.js

+13-12
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ MapboxGeocoder.prototype = {
9898
this._inputEl.type = 'text';
9999
this._inputEl.placeholder = this._getPlaceholderText();
100100

101-
this._inputEl.addEventListener('keydown', this._onKeyDown);
101+
this._inputEl.addEventListener('keydown', debounce(this._onKeyDown, 200));
102102
this._inputEl.addEventListener('change', this._onChange);
103103

104104
var actions = document.createElement('div');
@@ -148,16 +148,17 @@ MapboxGeocoder.prototype = {
148148
return this;
149149
},
150150

151-
_onKeyDown: debounce(function(e) {
152-
151+
_onKeyDown: function(e) {
152+
153153
// if target has shadowRoot, then get the actual active element inside the shadowRoot
154-
var target = e.target.shadowRoot
154+
var target = e.target && e.target.shadowRoot
155155
? e.target.shadowRoot.activeElement
156156
: e.target;
157-
if (!target.value) {
157+
var value = target ? target.value : '';
158+
if (!value) {
158159
this.fresh = true;
159160
// the user has removed all the text
160-
this._clear(e);
161+
if (e.keyCode !== 9) this._clear(e);
161162
return (this._clearEl.style.display = 'none');
162163
}
163164

@@ -168,7 +169,7 @@ MapboxGeocoder.prototype = {
168169
if (target.value.length >= this.options.minLength) {
169170
this._geocode(target.value);
170171
}
171-
}, 200),
172+
},
172173

173174
_onChange: function() {
174175
if (this._inputEl.value) this._clearEl.style.display = 'block';
@@ -399,23 +400,23 @@ MapboxGeocoder.prototype = {
399400

400401
/**
401402
* Get the language to use in UI elements and when making search requests
402-
*
403+
*
403404
* Look first at the explicitly set options otherwise use the browser's language settings
404-
*
405+
*
405406
* @returns {String} The language used by the geocoder
406407
*/
407408
getLanguage: function(){
408409
var browserLocale = navigator.language || navigator.userLanguage || navigator.browserLanguage;
409410
return this.options.language || browserLocale;
410411
},
411412

412-
/**
413+
/**
413414
* Get the text to use as the search bar placeholder
414-
*
415+
*
415416
* If placeholder is provided in options, then use options.placeholder
416417
* Otherwise, if language is provided in options, then use the localized string of the first language if available
417418
* Otherwise use the default
418-
*
419+
*
419420
* @returns {String} the value to use as the search bar placeholder
420421
* @private
421422
*/

test/test.ui.js

+35
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var once = require('lodash.once');
44
var MapboxGeocoder = require('../lib/index');
55
var mapboxgl = require('mapbox-gl');
66
var test = require('tape');
7+
var sinon = require('sinon');
78

89
mapboxgl.accessToken = process.env.MapboxAccessToken;
910

@@ -123,5 +124,39 @@ test('Geocoder#inputControl', function(tt) {
123124
t.end();
124125
})
125126

127+
tt.test('_clear is not called on keydown (tab), no focus trap', function(t){
128+
t.plan(3);
129+
setup({});
130+
131+
var inputEl = container.querySelector('.mapboxgl-ctrl-geocoder input');
132+
var focusSpy = sinon.spy(inputEl, 'focus');
133+
inputEl.focus();
134+
t.equal(focusSpy.called, true, 'input is focused');
135+
var keySpy = sinon.spy(geocoder,'_onKeyDown');
136+
var clearSpy = sinon.spy(geocoder, '_clear');
137+
geocoder._onKeyDown(new KeyboardEvent('keydown',{ code: 9, keyCode: 9 }));
138+
t.equal(keySpy.called, true, '_onKeyDown called');
139+
t.equal(clearSpy.called, false, '_clear should not be called');
140+
141+
t.end();
142+
});
143+
144+
tt.test('_clear is called on keydown (not tab)', function(t){
145+
t.plan(3);
146+
setup({});
147+
148+
var inputEl = container.querySelector('.mapboxgl-ctrl-geocoder input');
149+
var focusSpy = sinon.spy(inputEl, 'focus');
150+
inputEl.focus();
151+
t.equal(focusSpy.called, true, 'input is focused');
152+
var keySpy = sinon.spy(geocoder,'_onKeyDown');
153+
var clearSpy = sinon.spy(geocoder, '_clear');
154+
geocoder._onKeyDown(new KeyboardEvent('keydown',{ code: 1, keyCode: 1 }));
155+
t.equal(keySpy.called, true, '_onKeyDown called');
156+
t.equal(clearSpy.called, true, '_clear should be called');
157+
158+
t.end();
159+
});
160+
126161
tt.end();
127162
});

0 commit comments

Comments
 (0)