Skip to content

Instantly share code, notes, and snippets.

@phcostabh
Created October 29, 2013 12:30
Show Gist options
  • Save phcostabh/7213764 to your computer and use it in GitHub Desktop.
Save phcostabh/7213764 to your computer and use it in GitHub Desktop.
Suggest = (function() {
function Suggest(input, options) {
this.$input = $(input);
this.options = options;
this.$suggest = $(options.suggestEl);
}
Suggest.prototype = {
cachedResponse: [],
keys: {
ENTER: 13,
UP: 38,
DOWN: 40
},
enable: function() {
var that = this;
this.$input.on('keyup.suggest', function(event) {
that.processKeyUp(event);
});
this.$input.on('keydown.suggest', function(event) {
that.navigateInSuggestions(event);
});
},
disable: function() {
this.$input.off('keyup.suggest');
this.$input.off('keydown.suggest');
},
processKeyUp: function(event) {
switch (event.keyCode) {
case this.keys.UP:
case this.keys.DOWN:
return;
}
this.query = $.trim(this.$input.val());
var data,
that = this;
data = this.cachedResponse[this.query];
if (!data) {
clearTimeout(this.searchTimeout);
this.searchTimeout = setTimeout(function() {
that.search(that.query);
}, this.options.searchTimeout || 100);
} else {
this.renderSuggestion(data);
}
},
escapeSpecialChars: function(string) {
return string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|#~:"';]/g, "\\$&");
},
search: function(query) {
if (!this.options.url || !query) {
return false;
}
var that = this;
$.ajax({
url: this.options.url + "?q=" + this.escapeSpecialChars(query),
type: "GET",
async: this.options.async || true,
cache: this.options.cache || true,
jsonpCallback: "s",
dataType: "jsonp",
success: function(data, textStatus, jqXHR) {
that.cachedResponse[query] = data.response.docs;
that.renderSuggestion(data.response.docs);
}
});
},
renderSuggestion: function(source) {
var $ul = this.$suggest.find('ul').detach(),
$a = this.$suggest.children('a').detach(),
attributes,
i,
v,
that = this;
$ul.find('li').remove();
for (i = 0, l = source.length; i < l; i++) {
v = source[i];
if (v.t == 2) {
$ul.append(this.renderOne(v.art, v.txt, v.dns, v.url));
}
}
if (this.options.onSelect && typeof this.options.onSelect === "function") {
$ul.on('click', 'li', function() {
var $this = $(this);
that.options.onSelect($this.data('dns'), $this.data('url'));
that.clearSuggest();
});
}
attributes = {
href: URL_LETRAS + '?q=' + encodeURIComponent(this.query),
text: 'Todos os resultados para "' + this.query + '"',
target: '_blank'
};
if ($a.length > 0) {
$a.attr({
href: attributes.href,
target: attributes.target
}).text(attributes.text);
} else {
attributes.class = this.options.allResultsClass;
$a = $('<a/>', attributes);
}
this.$suggest.append($ul);
this.$suggest.append($a);
this.$suggest.addClass('on');
},
renderOne: function(artist, song, dns, url) {
return '<li data-dns="' + dns + '" data-url="' + url + '"><a href="#">' + this.setHint(artist + " - " + song) + '</a></li>';
},
setHint: function(element) {
return element.replace(new RegExp(this.query.split(" ").join("|"), "gi"), "<b>$&</b>");
},
clearSuggest: function($ul) {
this.$suggest.removeClass('on');
},
navigateInSuggestions: function(event) {
var $active = this.$suggest.find('.active'),
$list = this.$suggest.find('ul > li');
switch (event.keyCode) {
case this.keys.UP:
this.moveUp($active, $list);
break;
case this.keys.DOWN:
this.moveDown($active, $list);
break;
case this.keys.ENTER:
$active[0].click();
break;
default:
return;
}
event.stopImmediatePropagation();
event.preventDefault();
},
moveUp: function($active, $list) {
var $item;
if ($active.index() === -1) {
this.$suggest.children('a').addClass('active');
return;
}
if ($active.is('a')) {
$item = $list.eq(-1);
} else {
if ($active.index() === 0) {
$item = this.$suggest.children('a').addClass('active');
} else {
$item = $list.eq($active.index() - 1);
}
}
$active.removeClass('active');
$item.addClass('active');
},
moveDown: function($active, $list) {
var $item;
if ($active.index() === -1) {
$list.eq(0).addClass('active');
return;
}
if ($active.is('a')) {
$item = $list.eq(0).addClass('active');
} else {
if ($active.index() === ($list.length - 1)) {
$item = this.$suggest.children('a').addClass('active');
} else {
$item = $list.eq($active.index() + 1);
}
}
$active.removeClass('active');
$item.addClass('active');
}
};
return Suggest;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment