Skip to content

Commit

Permalink
Navigation for typeahead suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderkalach committed Sep 27, 2015
1 parent 3fd31fe commit 6ad9c60
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 2 deletions.
36 changes: 36 additions & 0 deletions app/javascript/dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
var dom = (function() {
return {

/**
* Add css class
* @param elm
* @param className
* @returns {*}
*/
addClass: function(elm, className) {
if (elm.className.length) {
elm.className += ' ';
}
elm.className += className;

return elm;
},

/**
* Remove css class
* @param elm
* @param className
* @returns {*}
*/
removeClass: function(elm, className) {
var classes = elm.className.split(' ');
var removeIndex = classes.indexOf(className);
if (removeIndex != -1) {
delete classes[removeIndex];
}
elm.className = classes.join(' ');

return elm;
}
};
})();
22 changes: 22 additions & 0 deletions app/javascript/search-form-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@
* @param {KeyboardEvent} ev
*/
App.SearchFormView.prototype.onKeyDown = function(ev) {
if (ev.keyCode == 38 && app.views.typeahead.hasSuggestions()) {
ev.preventDefault();
}
if (ev.keyCode == 13 && app.views.typeahead.hasActiveSuggestion()) {
ev.stopPropagation();
ev.preventDefault();
}
this.oldInputValue = this.input.value;
};

Expand All @@ -53,6 +60,21 @@
* @param {KeyboardEvent} ev
*/
App.SearchFormView.prototype.onKeyUp = function(ev) {
if (app.views.typeahead.hasSuggestions()) {
if (ev.keyCode == 13 && app.views.typeahead.hasActiveSuggestion()) {
app.views.typeahead.useActiveSuggestion();
return;
}
if (ev.keyCode == 40 || ev.keyCode == 38) {
if (ev.keyCode == 40) {
app.views.typeahead.nextSuggestion();
} else {
app.views.typeahead.prevSuggestion();
}
return;
}
}

var oldValue = this.oldInputValue;
delete this.oldInputValue;
if (oldValue == this.input.value) {
Expand Down
67 changes: 67 additions & 0 deletions app/javascript/typeahead-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* @constructor
*/
App.TypeaheadView = function() {
this.suggestions = [];
this.activeSuggestionIndex = null;
this.el = document.getElementById('typeahead');
this.el.addEventListener('click', this.onSuggestionClick.bind(this));
window.addEventListener('click', this.hide.bind(this));
Expand Down Expand Up @@ -42,6 +44,8 @@
var t = app.template('template-typeahead');
this.el.innerHTML = t({suggestions: data.result});
this.show();
this.activeSuggestionIndex = null;
this.suggestions = this.el.getElementsByClassName('suggestion');
} else {
this.hide();
}
Expand All @@ -59,5 +63,68 @@
*/
App.TypeaheadView.prototype.hide = function() {
this.el.style.display = 'none';
this.activeSuggestionIndex = null;
this.suggestions = [];
};

/**
* @returns {Number}
*/
App.TypeaheadView.prototype.hasSuggestions = function() {
return this.suggestions.length;
};

/**
* @returns {boolean}
*/
App.TypeaheadView.prototype.hasActiveSuggestion = function() {
return this.activeSuggestionIndex !== null;
};

/**
* Move selection to the next suggestion (Downwards Arrow)
*/
App.TypeaheadView.prototype.nextSuggestion = function() {
this.moveToSuggestion(
this.activeSuggestionIndex === null ? 0 : (this.activeSuggestionIndex + 1)
);
};

/**
* Move selection to the previous suggestion (Upwards Arrow)
*/
App.TypeaheadView.prototype.prevSuggestion = function() {
this.moveToSuggestion(this.activeSuggestionIndex - 1);
};

/**
* Move selection to a suggestion
* @param index
*/
App.TypeaheadView.prototype.moveToSuggestion = function(index) {
if (this.activeSuggestionIndex !== null) {
dom.removeClass(this.suggestions[this.activeSuggestionIndex], 'active');
}
var maxIndex = this.suggestions.length - 1;
if (index > maxIndex) {
index = 0;
} else if (index < 0) {
index = maxIndex;
}
dom.addClass(this.suggestions[index], 'active');
this.activeSuggestionIndex = index;
};

/**
* Search by selected suggestion
*/
App.TypeaheadView.prototype.useActiveSuggestion = function() {
if (this.activeSuggestionIndex === null) {
return;
}
var q = this.suggestions[this.activeSuggestionIndex].getAttribute('data-value');
app.setCurrentSearch(q);
app.search(q);
this.hide();
};
})(App);
2 changes: 1 addition & 1 deletion app/less/search-form.less
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ body {margin: 0; font-family: arial, helvetica, clean, sans-serif;}
li {
cursor:pointer; padding: 5px;

&:hover {
&:hover, &.active {
background-color: @typeahead-hover-color;
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/templates/index.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<script id="template-typeahead" type="text/html">
<ul>
{{each suggestions}}
<li data-value="{{=title}}">{{=title}}</li>
<li class="suggestion" data-value="{{=title}}">{{=title}}</li>
{{done}}
</ul>
</script>
Expand Down

0 comments on commit 6ad9c60

Please sign in to comment.