diff --git a/CHANGELOG.md b/CHANGELOG.md index acaee208..4a0598db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - `trackProximity` turned on by default [#195](https://github.com/mapbox/mapbox-gl-geocoder/issues/195) - Bump suggestions to v1.3.4 - Fix duplicate event bug +- Fix trapped focus [#220](https://github.com/mapbox/mapbox-gl-geocoder/issues/220) ## v3.1.4 diff --git a/lib/index.js b/lib/index.js index 05a97e1f..ea0f819d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -98,7 +98,7 @@ MapboxGeocoder.prototype = { this._inputEl.type = 'text'; this._inputEl.placeholder = this._getPlaceholderText(); - this._inputEl.addEventListener('keydown', this._onKeyDown); + this._inputEl.addEventListener('keydown', debounce(this._onKeyDown, 200)); this._inputEl.addEventListener('change', this._onChange); var actions = document.createElement('div'); @@ -148,16 +148,17 @@ MapboxGeocoder.prototype = { return this; }, - _onKeyDown: debounce(function(e) { - + _onKeyDown: function(e) { + // if target has shadowRoot, then get the actual active element inside the shadowRoot - var target = e.target.shadowRoot + var target = e.target && e.target.shadowRoot ? e.target.shadowRoot.activeElement : e.target; - if (!target.value) { + var value = target ? target.value : ''; + if (!value) { this.fresh = true; // the user has removed all the text - this._clear(e); + if (e.keyCode !== 9) this._clear(e); return (this._clearEl.style.display = 'none'); } @@ -168,7 +169,7 @@ MapboxGeocoder.prototype = { if (target.value.length >= this.options.minLength) { this._geocode(target.value); } - }, 200), + }, _onChange: function() { if (this._inputEl.value) this._clearEl.style.display = 'block'; @@ -397,9 +398,9 @@ MapboxGeocoder.prototype = { /** * Get the language to use in UI elements and when making search requests - * + * * Look first at the explicitly set options otherwise use the browser's language settings - * + * * @returns {String} The language used by the geocoder */ getLanguage: function(){ @@ -407,13 +408,13 @@ MapboxGeocoder.prototype = { return this.options.language || browserLocale; }, - /** + /** * Get the text to use as the search bar placeholder - * + * * If placeholder is provided in options, then use options.placeholder * Otherwise, if language is provided in options, then use the localized string of the first language if available * Otherwise use the default - * + * * @returns {String} the value to use as the search bar placeholder * @private */ diff --git a/test/test.ui.js b/test/test.ui.js index 4b89500b..bf6b227b 100644 --- a/test/test.ui.js +++ b/test/test.ui.js @@ -4,6 +4,7 @@ var once = require('lodash.once'); var MapboxGeocoder = require('../lib/index'); var mapboxgl = require('mapbox-gl'); var test = require('tape'); +var sinon = require('sinon'); mapboxgl.accessToken = process.env.MapboxAccessToken; @@ -123,5 +124,39 @@ test('Geocoder#inputControl', function(tt) { t.end(); }) + tt.test('_clear is not called on keydown (tab), no focus trap', function(t){ + t.plan(3); + setup({}); + + var inputEl = container.querySelector('.mapboxgl-ctrl-geocoder input'); + var focusSpy = sinon.spy(inputEl, 'focus'); + inputEl.focus(); + t.equal(focusSpy.called, true, 'input is focused'); + var keySpy = sinon.spy(geocoder,'_onKeyDown'); + var clearSpy = sinon.spy(geocoder, '_clear'); + geocoder._onKeyDown(new KeyboardEvent('keydown',{ code: 9, keyCode: 9 })); + t.equal(keySpy.called, true, '_onKeyDown called'); + t.equal(clearSpy.called, false, '_clear should not be called'); + + t.end(); + }); + + tt.test('_clear is called on keydown (not tab)', function(t){ + t.plan(3); + setup({}); + + var inputEl = container.querySelector('.mapboxgl-ctrl-geocoder input'); + var focusSpy = sinon.spy(inputEl, 'focus'); + inputEl.focus(); + t.equal(focusSpy.called, true, 'input is focused'); + var keySpy = sinon.spy(geocoder,'_onKeyDown'); + var clearSpy = sinon.spy(geocoder, '_clear'); + geocoder._onKeyDown(new KeyboardEvent('keydown',{ code: 1, keyCode: 1 })); + t.equal(keySpy.called, true, '_onKeyDown called'); + t.equal(clearSpy.called, true, '_clear should be called'); + + t.end(); + }); + tt.end(); });