diff --git a/src/typeahead/input.js b/src/typeahead/input.js index 88a007cb..0fc8c323 100644 --- a/src/typeahead/input.js +++ b/src/typeahead/input.js @@ -43,7 +43,10 @@ var Input = (function() { // if no hint, noop all the hint related functions if (this.$hint.length === 0) { - this.setHintValue = this.getHintValue = this.clearHint = _.noop; + this.clearHint = + this.setHintValue = + this.getHintValue = + this.clearHintIfInvalid = _.noop; } // ie7 and ie8 don't support the input event @@ -192,7 +195,8 @@ var Input = (function() { setInputValue: function setInputValue(value, silent) { this.$input.val(value); - !silent && this._checkInputValue(); + // silent prevents any additional events from being triggered + silent ? this.clearHint() : this._checkInputValue(); }, getHintValue: function getHintValue() { @@ -204,11 +208,21 @@ var Input = (function() { }, resetInputValue: function resetInputValue() { - this.$input.val(this.query); + this.setInputValue(this.query, true); }, clearHint: function clearHint() { - this.$hint.val(''); + this.setHintValue(''); + }, + + clearHintIfInvalid: function clearHintIfInvalid() { + var val, hint, valIsPrefixOfHint; + + val = this.getInputValue(); + hint = this.getHintValue(); + valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; + + (val === '' || !valIsPrefixOfHint) && this.clearHint(); }, getLanguageDirection: function getLanguageDirection() { diff --git a/src/typeahead/typeahead.js b/src/typeahead/typeahead.js index 3f6e399d..17595f4d 100644 --- a/src/typeahead/typeahead.js +++ b/src/typeahead/typeahead.js @@ -96,7 +96,6 @@ var Typeahead = (function() { _onCursorMoved: function onCursorMoved() { var datum = this.dropdown.getDatumForCursor(); - this.input.clearHint(); this.input.setInputValue(datum.value, true); this.eventBus.trigger('cursorchanged', datum.raw, datum.datasetName); @@ -198,7 +197,7 @@ var Typeahead = (function() { }, _onQueryChanged: function onQueryChanged(e, query) { - this.input.clearHint(); + this.input.clearHintIfInvalid(); query.length >= this.minLength ? this.dropdown.update(query) : @@ -224,19 +223,19 @@ var Typeahead = (function() { }, _updateHint: function updateHint() { - var datum, inputValue, query, escapedQuery, frontMatchRegEx, match; + var datum, val, query, escapedQuery, frontMatchRegEx, match; datum = this.dropdown.getDatumForTopSuggestion(); if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) { - inputValue = this.input.getInputValue(); - query = Input.normalizeQuery(inputValue); + val = this.input.getInputValue(); + query = Input.normalizeQuery(val); escapedQuery = _.escapeRegExChars(query); - frontMatchRegEx = new RegExp('^(?:' + escapedQuery + ')(.*$)', 'i'); + frontMatchRegEx = new RegExp('^(?:' + escapedQuery + ')(.+$)', 'i'); match = frontMatchRegEx.exec(datum.value); - this.input.setHintValue(inputValue + (match ? match[1] : '')); + match ? this.input.setHintValue(val + match[1]) : this.input.clearHint(); } }, @@ -256,7 +255,6 @@ var Typeahead = (function() { }, _select: function select(datum) { - this.input.clearHint(); this.input.setQuery(datum.value); this.input.setInputValue(datum.value, true); @@ -281,8 +279,6 @@ var Typeahead = (function() { }, setVal: function setVal(val) { - this.input.clearHint(); - if (this.isActivated) { this.input.setInputValue(val); } diff --git a/test/input_view_spec.js b/test/input_view_spec.js index 0d3d416f..67294e74 100644 --- a/test/input_view_spec.js +++ b/test/input_view_spec.js @@ -299,6 +299,32 @@ describe('Input', function() { }); }); + describe('#clearHintIfInvalid', function() { + it('should clear hint if input value is empty string', function() { + this.view.setInputValue('', true); + this.view.setHintValue('cheese'); + this.view.clearHintIfInvalid(); + + expect(this.view.getHintValue()).toBe(''); + }); + + it('should clear hint if input value is not prefix of input', function() { + this.view.setInputValue('milk', true); + this.view.setHintValue('cheese'); + this.view.clearHintIfInvalid(); + + expect(this.view.getHintValue()).toBe(''); + }); + + it('should not clear hint if input value is prefix of input', function() { + this.view.setInputValue('che', true); + this.view.setHintValue('cheese'); + this.view.clearHintIfInvalid(); + + expect(this.view.getHintValue()).toBe('cheese'); + }); + }); + describe('#getLanguageDirection', function() { it('should return the language direction of the input', function() { this.$input.css('direction', 'ltr'); diff --git a/test/typeahead_view_spec.js b/test/typeahead_view_spec.js index a1eef77d..27005392 100644 --- a/test/typeahead_view_spec.js +++ b/test/typeahead_view_spec.js @@ -37,7 +37,6 @@ describe('Typeahead', function() { this.dropdown.trigger('suggestionClicked'); expect(spy).toHaveBeenCalled(); - expect(this.input.clearHint).toHaveBeenCalled(); expect(this.input.setQuery).toHaveBeenCalledWith(testDatum.value); expect(this.input.setInputValue) .toHaveBeenCalledWith(testDatum.value, true); @@ -51,12 +50,6 @@ describe('Typeahead', function() { this.dropdown.getDatumForCursor.andReturn(testDatum); }); - it('should clear the hint', function() { - this.dropdown.trigger('cursorMoved'); - - expect(this.input.clearHint).toHaveBeenCalled(); - }); - it('should update the input value', function() { this.dropdown.trigger('cursorMoved'); @@ -201,7 +194,6 @@ describe('Typeahead', function() { this.input.trigger('enterKeyed', $e); expect(spy).toHaveBeenCalled(); - expect(this.input.clearHint).toHaveBeenCalled(); expect(this.input.setQuery).toHaveBeenCalledWith(testDatum.value); expect(this.input.setInputValue) .toHaveBeenCalledWith(testDatum.value, true); @@ -233,7 +225,6 @@ describe('Typeahead', function() { this.input.trigger('tabKeyed', $e); expect(spy).toHaveBeenCalled(); - expect(this.input.clearHint).toHaveBeenCalled(); expect(this.input.setQuery).toHaveBeenCalledWith(testDatum.value); expect(this.input.setInputValue) .toHaveBeenCalledWith(testDatum.value, true); @@ -446,10 +437,10 @@ describe('Typeahead', function() { }); describe('when input triggers queryChanged', function() { - it('should clear the hint', function() { + it('should clear the hint if it has become invalid', function() { this.input.trigger('queryChanged', testDatum.value); - expect(this.input.clearHint).toHaveBeenCalled(); + expect(this.input.clearHintIfInvalid).toHaveBeenCalled(); }); it('should empty dropdown if the query is empty', function() {