diff options
author | Jelle van der Waa <jelle@vdwaa.nl> | 2018-11-24 22:48:07 +0100 |
---|---|---|
committer | Jelle van der Waa <jelle@archlinux.org> | 2019-02-18 16:42:51 +0100 |
commit | 37a51bc78902a213dde155a76a9fa290cd776fd7 (patch) | |
tree | 31494a41fcb4bd000248e66779b81fed71f8d460 /sitestatic/homepage.js | |
parent | d1674c1d12f3e57c3a22ed6103b2d022016700e5 (diff) | |
download | archweb-37a51bc78902a213dde155a76a9fa290cd776fd7.tar.gz archweb-37a51bc78902a213dde155a76a9fa290cd776fd7.zip |
homepage: use self written typeahead implementation
Use a self written typeahead inmplemenation which gets rid of the
jQuery requirement. This saves upgrading issues and reduces the amount
of data to be loaded for the homepage by half.
Diffstat (limited to 'sitestatic/homepage.js')
-rw-r--r-- | sitestatic/homepage.js | 157 |
1 files changed, 133 insertions, 24 deletions
diff --git a/sitestatic/homepage.js b/sitestatic/homepage.js index d0dc3444..b46cf0b4 100644 --- a/sitestatic/homepage.js +++ b/sitestatic/homepage.js @@ -1,26 +1,135 @@ -!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return e&&this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.chrome||e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery); - -function setupTypeahead() { - $('#pkgsearch-field').typeahead({ - source: function(query, callback) { - $.getJSON('/opensearch/packages/suggest', {q: query}, function(data) { - callback(data[1]); - }); - }, - matcher: function(item) { return true; }, - sorter: function(items) { return items; }, - menu: '<ul class="pkgsearch-typeahead"></ul>', - items: 10, - updater: function(item) { - $('#pkgsearch-field').val(item); - $('#pkgsearch-form').submit(); - return item; +"use strict"; + +(function() { + const input = document.getElementById('pkgsearch-field'); + const form = document.getElementById('pkgsearch-form'); + var list; + + function resetResults() { + if (!list) return; + list.style.display = "none"; + list.innerHTML = ""; + } + + function getCompleteList() { + if (!list) { + list = document.createElement("UL"); + list.setAttribute("class", "pkgsearch-typeahead"); // remove + form.appendChild(list); + setListLocation(); + } + return list; + } + + function onListClick(e) { + let target = e.target; + while (!target.getAttribute('data-value')) { + target = target.parentNode; + } + input.value = target.getAttribute('data-value'); + form.submit(); + } + + function setListLocation() { + if (!list) return; + const rects = input.getClientRects()[0]; + list.style.top = (rects.y + rects.height) + "px"; + list.style.left = rects.x + "px"; + } + + function loadData(data) { + const letter = data[0]; + const pkgs = data[1].slice(0, 10); // Show maximum of 10 results + + resetResults(); + + if (pkgs.length === 0) { + return; + } + + const ul = getCompleteList(); + ul.style.display = "block"; + const fragment = document.createDocumentFragment(); + + for (let i = 0; i < pkgs.length; i++) { + const item = document.createElement("li"); + const text = pkgs[i].replace(letter, '<b>' + letter + '</b>'); + item.innerHTML = '<a href="#">' + text + '</a>'; + item.setAttribute('data-value', pkgs[i]); + fragment.appendChild(item); + } + + ul.appendChild(fragment); + ul.addEventListener('click', onListClick); + } + + function fetchData(letter) { + fetch('/opensearch/packages/suggest?q=' + letter).then(function(response) { + return response.json(); + }).then(function(data) { + loadData(data); + }); + } + + function onInputClick() { + if (input.value === "") { + resetResults(); + return; + } + fetchData(input.value); + } + + function onKeyDown(e) { + if (!list) return; + + const elem = document.querySelector(".pkgsearch-typeahead li.active"); + switch(e.keyCode) { + case 13: // enter + if (elem) { + input.value = elem.getAttribute('data-value'); + form.submit(); + } else { + form.submit(); } - }).attr('autocomplete', 'off'); - $('#pkgsearch-field').keyup(function(e) { - if (e.keyCode === 13 && - $('ul.pkgsearch-typeahead li.active').size() === 0) { - $('#pkgsearch-form').submit(); + e.preventDefault(); + break; + case 38: // up + if (elem && elem.previousElementSibling) { + elem.className = ""; + elem.previousElementSibling.className = "active"; } - }); -} + e.preventDefault(); + break; + case 40: // down + if (elem && elem.nextElementSibling) { + elem.className = ""; + elem.nextElementSibling.className = "active"; + } else if (!elem && list.childElementCount !== 0) { + list.children[0].className = "active"; + } + e.preventDefault(); + break; + } + } + + // debounce https://davidwalsh.name/javascript-debounce-function + function debounce(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; + } + + input.addEventListener("input", onInputClick); + input.addEventListener("keydown", onKeyDown); + window.addEventListener('resize', debounce(setListLocation, 150)); + document.addEventListener("click", resetResults); +}()); |