diff --git a/index.html b/index.html
index 6c6a3d3..ac8e746 100644
--- a/index.html
+++ b/index.html
@@ -172,8 +172,8 @@
cursor: pointer;
}
- .search-suggestion:hover,
- .search-suggestion:focus {
+ .search-suggestion:focus,
+ .search-suggestion.highlight {
background: #333;
}
@@ -297,12 +297,27 @@
const $ = {
el: s => document.querySelector(s),
els: s => [].slice.call(document.querySelectorAll(s) || []),
+ isDown: e => ['c-n', 'down'].includes($.key(e)),
+ isUp: e => ['c-p', 'up'].includes($.key(e)),
jsonp: url => {
let script = document.createElement('script');
script.src = url;
$.el('head').appendChild(script);
},
+
+ key: e => {
+ const ctrl = e.ctrlKey;
+
+ switch (e.which) {
+ case 13: return 'enter';
+ case 27: return 'escape';
+ case 38: return 'up';
+ case 40: return 'down';
+ case 78: return ctrl ? 'c-n' : 'n';
+ case 80: return ctrl ? 'c-p' : 'n';
+ }
+ },
};
class Clock {
@@ -368,9 +383,8 @@
)).join('');
}
- _handleKeydown(event) {
- const isEsc = event.which === 27;
- if (isEsc) this.toggle(false);
+ _handleKeydown(e) {
+ if ($.key(e) === 'escape') this.toggle(false);
}
_registerEvents() {
@@ -503,8 +517,7 @@
`
);
- this._suggestionsEl.classList.add('active');
- this._inputEl.classList.add('bottom-no-radius');
+ this._showSuggestions();
return ++this._totalSuggestions === CONFIG.suggestionsLimit;
}
@@ -516,11 +529,10 @@
}
_clearSuggestions() {
- this._totalSuggestions = 0;
+ this._hideSuggestions();
this._clearClickEvents();
this._suggestionsEl.innerHTML = '';
- this._suggestionsEl.classList.remove('active');
- this._inputEl.classList.remove('bottom-no-radius');
+ this._totalSuggestions = 0;
}
// [[1, 2], [1, 2, 3, 4]] -> [1, 2, 3, 4]
@@ -529,33 +541,29 @@
}
_focusNext() {
- if (this._suggestionEls.length) {
- const active = document.activeElement;
+ const active = $.el('.highlight');
- if (active.classList.contains('js-search-suggestion')) {
- this._suggestionEls.forEach((el, index) => {
- const nextSuggestion = this._suggestionEls[index + 1];
- if (el === active && nextSuggestion) nextSuggestion.focus();
- });
- } else {
- this._suggestionEls[0].focus();
- }
+ if (active) {
+ this._suggestionEls.forEach((el, index) => {
+ const next = this._suggestionEls[index + 1];
+ if (el === active && next) this._highlight(next);
+ });
+ } else {
+ this._highlight(this._suggestionEls[0]);
}
}
_focusPrevious() {
- if (this._suggestionEls.length) {
- const active = document.activeElement;
+ const active = $.el('.highlight');
- if (active.classList.contains('js-search-suggestion')) {
- this._suggestionEls.forEach((el, index) => {
- if (el === active) {
- const previousSuggestion = this._suggestionEls[index - 1];
- if (previousSuggestion) previousSuggestion.focus();
- else this._inputEl.focus();
- }
- });
- }
+ if (active) {
+ this._suggestionEls.forEach((el, index) => {
+ if (el === active) {
+ const previous = this._suggestionEls[index - 1];
+ this._noHighlight();
+ if (previous) this._highlight(previous);
+ }
+ });
}
}
@@ -564,24 +572,46 @@
.map(influencer => influencer.getSuggestionsPromise(input));
}
- _handleKeydown(event) {
- const isDown = event.which === 40;
- const isUp = event.which === 38;
- const isCtrlN = event.which === 78 && event.ctrlKey;
- const isCtrlP = event.which === 80 && event.ctrlKey;
- if (isDown || isUp || isCtrlN || isCtrlP) event.preventDefault();
- if (isDown || isCtrlN) this._focusNext();
- if (isUp || isCtrlP) this._focusPrevious();
+ _handleKeydown(e) {
+ if ($.isDown(e) || $.isUp(e)) e.preventDefault();
+ if ($.isDown(e)) this._focusNext();
+ if ($.isUp(e)) this._focusPrevious();
}
- _registerClickEvents() {
+ _highlight(el) {
+ this._noHighlight();
+ el.classList.add('highlight');
+ this._inputEl.value = el.getAttribute('data-suggestion');
+ this._inputEl.focus()
+ }
+
+ _noHighlight() {
+ this._inputEl.value = this._originalValue;
+ this._suggestionEls.forEach(el => el.classList.remove('highlight'));
+ }
+
+ _showSuggestions() {
+ this._inputEl.classList.add('bottom-no-radius');
+ this._suggestionsEl.classList.add('active');
+ }
+
+ _hideSuggestions() {
+ this._inputEl.classList.remove('bottom-no-radius');
+ this._suggestionsEl.classList.remove('active');
+ }
+
+ _registerEvents() {
this._suggestionEls.forEach(el => {
const value = el.getAttribute('data-suggestion');
+ el.addEventListener('mouseover', this._highlight.bind(this, el));
+ el.addEventListener('mouseout', this._noHighlight.bind(this));
el.addEventListener('click', this._handleClick.bind(null, value));
});
}
_suggest(input) {
+ this._originalValue = this._inputEl.value;
+
Promise.all(this._gatherInfluencers(input)).then(res => {
this._clearSuggestions();
@@ -589,7 +619,7 @@
.some(item => this._appendSuggestion(item, input));
this._suggestionEls = $.els('.js-search-suggestion');
- this._registerClickEvents();
+ this._registerEvents();
});
}
}
@@ -694,29 +724,29 @@
this._submitWithValue = this._submitWithValue.bind(this);
}
- _handleKeypress(event) {
- const newChar = String.fromCharCode(event.which);
+ _handleKeypress(e) {
+ const newChar = String.fromCharCode(e.which);
const newQuery = this._inputEl.value + newChar;
const isNotEmpty = newChar.length;
- const isEnterKey = event.which !== 13;
- if (isNotEmpty && isEnterKey) {
+ if (isNotEmpty && $.key(e) !== 'enter') {
this._help.toggle(false);
this._inputEl.focus();
}
if (CONFIG.instantRedirect) {
this._queryParser
- .instantRedirect(event, newQuery, this._submitWithValue);
+ .instantRedirect(e, newQuery, this._submitWithValue);
}
}
- _handleKeyup(event) {
+ _handleKeyup(e) {
const oldVal = this._inputElVal;
const newVal = this._inputEl.value.trim();
+ const ignored = $.isDown(e) || $.isUp(e);
this._inputElVal = newVal;
- if (CONFIG.suggestions && oldVal !== newVal) {
+ if (CONFIG.suggestions && oldVal !== newVal && !ignored) {
this._suggester.suggest(newVal, this._submitWithValue);
}
}
@@ -732,8 +762,8 @@
this._formEl.addEventListener('submit', this._submitForm, false);
}
- _submitForm(event) {
- if (event) event.preventDefault();
+ _submitForm(e) {
+ if (e) e.preventDefault();
const query = this._inputEl.value.trim();
if (!query || query === '?') {