var Search = { settings: { form: '#search-form', formInput: '#search-form :input[name="q"]', closeBtn: '.search-close', suggestions: '#search-form .suggestions', searchContainer: '[data-search-toggle] + div', verticalArrowKeyCodes: [38, 40] }, init: function (settings) { settings = settings || {}; this.settings = _.extend(this.settings, settings); this.bindUI(); }, bindUI: function () { var self = this, verticalArrowKeyCodes = this.settings.verticalArrowKeyCodes, suggestions = $(this.settings.suggestions), searchContainer = $(this.settings.searchContainer); // Search overlay $('[data-search-toggle]').on('click', function (e) { e.preventDefault(); // open the overlay $(this).next('div').toggleClass('active'); $('#q').focus(); // add close button if (!$(self.closeBtn).length) { $('body').append('').find(self.closeBtn).fadeIn(); } }); // Close search overlay $('body').on('click', this.settings.closeBtn, function () { searchContainer.removeClass('active'); $(this).fadeOut(function () { $(this).remove(); }); }); // Close search popup $(document).keydown(function (e) { // Close stuff on escape key if (e.keyCode == 27) { // search overlay if (searchContainer.is(':visible')) $(self.closeBtn).trigger('click'); } }); // Autocomplete $('body').on('keyup', this.settings.formInput, function (e) { // Enter key if (e.which == 13) { var active = suggestions.find('li.active'); if (active.length === 1) { window.location.href = active.find('a[href]:not([href="#"]):not([href^="javascript"]):first').attr('href'); } return false; } // Ignore the following from removing if (_.indexOf(verticalArrowKeyCodes, e.which) >= 0) { return false; } suggestions.find('.active').removeClass('active'); self.delay(function () { self.autocomplete(); }, 700); }); // Results key navigation $('body').on('keydown', this.settings.formInput, function (e) { // Vertical arrows if (_.indexOf(verticalArrowKeyCodes, e.which) >= 0) { var active = suggestions.find('li.active'), items = suggestions.find('li').removeClass('active'), index = items.index(active), item = null; if (e.which == 38) { // down item = items.eq(Math.max(0, index - 1)); } else { // up item = items.eq(Math.min(items.length - 1, index + 1)); } // Make active item.addClass('active'); return false; } }); }, autocomplete: function () { var self = this, form = $(this.settings.form), formInput = $(this.settings.formInput), suggestions = $(this.settings.suggestions), template = _.template('
  • <%= term %>
  • '); if (self.hasOwnProperty('xhr') && self.xhr.readyState != 4) { self.xhr.abort(); } self.xhr = $.ajax({ type: 'GET', url: form.data('suggestions-url'), data: { 'q': formInput.val(), }, dataType: 'json', success: function (data) { suggestions.empty(); if (data.success && data.results) { // Append results $.each(data.results, function (i, item) { suggestions.append(template({'term_encoded': encodeURIComponent(item), 'term': item})); }); } // Trigger event to enable custom callbacks form.trigger('search:suggestions', [data.results]); } }); }, delay: (function () { var timer = 0; return function (callback, ms) { clearTimeout(timer); timer = setTimeout(callback, ms); }; })(), };