diff --git a/auto-complete.js b/auto-complete.js index 2f5a88c..0331ba6 100644 --- a/auto-complete.js +++ b/auto-complete.js @@ -1,34 +1,38 @@ /* - JavaScript autoComplete v1.0.4 - Copyright (c) 2014 Simon Steinberger / Pixabay - GitHub: https://github.com/Pixabay/JavaScript-autoComplete - License: http://www.opensource.org/licenses/mit-license.php -*/ + JavaScript autoComplete v1.0.4 + Copyright (c) 2014 Simon Steinberger / Pixabay + GitHub: https://github.com/Pixabay/JavaScript-autoComplete + License: http://www.opensource.org/licenses/mit-license.php + */ -var autoComplete = (function(){ +var autoComplete = (function() { // "use strict"; - function autoComplete(options){ + function autoComplete(options) { if (!document.querySelector) return; // helpers - function hasClass(el, className){ return el.classList ? el.classList.contains(className) : new RegExp('\\b'+ className+'\\b').test(el.className); } + function hasClass(el, className) { + return el.classList ? el.classList.contains(className) : new RegExp('\\b' + className + '\\b').test(el.className); + } - function addEvent(el, type, handler){ - if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler); + function addEvent(el, type, handler) { + if (el.attachEvent) el.attachEvent('on' + type, handler); else el.addEventListener(type, handler); } - function removeEvent(el, type, handler){ + + function removeEvent(el, type, handler) { // if (el.removeEventListener) not working in IE11 - if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler); + if (el.detachEvent) el.detachEvent('on' + type, handler); else el.removeEventListener(type, handler); } - function live(elClass, event, cb, context){ - addEvent(context || document, event, function(e){ + + function live(elClass, event, cb, context) { + addEvent(context || document, event, function(e) { var found, el = e.target || e.srcElement; while (el && !(found = hasClass(el, elClass))) el = el.parentElement; if (found) cb.call(el, e); }); } - var o = { + var defaultOptions = { selector: 0, source: 0, minChars: 3, @@ -37,165 +41,205 @@ var autoComplete = (function(){ offsetTop: 1, cache: 1, menuClass: '', - renderItem: function (item, search){ + renderItem: function(item, search) { // escape special characters search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi"); return '
' + item.replace(re, "$1") + '
'; }, - onSelect: function(e, term, item){} + onSelect: function(e, term, item) { + } }; - for (var k in options) { if (options.hasOwnProperty(k)) o[k] = options[k]; } + for (var option in options) { + if (options.hasOwnProperty(option)) defaultOptions[option] = options[option]; + } // init - var elems = typeof o.selector == 'object' ? [o.selector] : document.querySelectorAll(o.selector); - for (var i=0; i 0) - that.sc.scrollTop = selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight; + var scrTop = this.suggestionsContainer.scrollTop, selTop = next.getBoundingClientRect().top - this.suggestionsContainer.getBoundingClientRect().top; + if (selTop + this.suggestionsContainer.suggestionHeight - this.suggestionsContainer.maxHeight > 0) + this.suggestionsContainer.scrollTop = selTop + this.suggestionsContainer.suggestionHeight + scrTop - this.suggestionsContainer.maxHeight; else if (selTop < 0) - that.sc.scrollTop = selTop + scrTop; + this.suggestionsContainer.scrollTop = selTop + scrTop; } } - } - addEvent(window, 'resize', that.updateSC); - document.body.appendChild(that.sc); + }; + addEvent(window, 'resize', elem.updateSuggestionsContainer); + document.body.appendChild(elem.suggestionsContainer); - live('autocomplete-suggestion', 'mouseleave', function(e){ - var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); - if (sel) setTimeout(function(){ sel.className = sel.className.replace('selected', ''); }, 20); - }, that.sc); + live('autocomplete-suggestion', 'mouseleave', function() { + var sel = elem.suggestionsContainer.querySelector('.autocomplete-suggestion.selected'); + if (sel) setTimeout(function() { + sel.className = sel.className.replace('selected', ''); + }, 20); + }, elem.suggestionsContainer); - live('autocomplete-suggestion', 'mouseover', function(e){ - var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); + live('autocomplete-suggestion', 'mouseover', function() { + var sel = elem.suggestionsContainer.querySelector('.autocomplete-suggestion.selected'); if (sel) sel.className = sel.className.replace('selected', ''); this.className += ' selected'; - }, that.sc); + }, elem.suggestionsContainer); - live('autocomplete-suggestion', 'mousedown', function(e){ + live('autocomplete-suggestion', 'mousedown', function(e) { if (hasClass(this, 'autocomplete-suggestion')) { // else outside click var v = this.getAttribute('data-val'); - that.value = v; - o.onSelect(e, v, this); - that.sc.style.display = 'none'; + elem.value = v; + defaultOptions.onSelect(e, v, this); + elem.suggestionsContainer.style.display = 'none'; } - }, that.sc); + }, elem.suggestionsContainer); - that.blurHandler = function(){ - try { var over_sb = document.querySelector('.autocomplete-suggestions:hover'); } catch(e){ var over_sb = 0; } + elem.blurHandler = function() { + var that = this, + over_sb; + try { + over_sb = document.querySelector('.autocomplete-suggestions:hover'); + } catch (e) { + over_sb = 0; + } if (!over_sb) { - that.last_val = that.value; - that.sc.style.display = 'none'; - setTimeout(function(){ that.sc.style.display = 'none'; }, 350); // hide suggestions on fast input - } else if (that !== document.activeElement) setTimeout(function(){ that.focus(); }, 20); + this.last_val = this.value; + this.suggestionsContainer.style.display = 'none'; + setTimeout(function() { + that.suggestionsContainer.style.display = 'none'; + }, 350); // hide suggestions on fast input + } else if (this !== document.activeElement) setTimeout(function() { + this.focus(); + }, 20); }; - addEvent(that, 'blur', that.blurHandler); + addEvent(elem, 'blur', elem.blurHandler); - var suggest = function(data){ - var val = that.value; - that.cache[val] = data; - if (data.length && val.length >= o.minChars) { + var suggest = function(data) { + var val = elem.value; + elem.cache[val] = data; + if (data.length && val.length >= defaultOptions.minChars) { var s = ''; - for (var i=0;i 40) && key != 13 && key != 27) { - var val = that.value; - if (val.length >= o.minChars) { - if (val != that.last_val) { - that.last_val = val; - clearTimeout(that.timer); - if (o.cache) { - if (val in that.cache) { suggest(that.cache[val]); return; } + var val = this.value; + if (val.length >= defaultOptions.minChars) { + if (val != this.last_val) { + this.last_val = val; + clearTimeout(this.timer); + if (defaultOptions.cache) { + if (val in this.cache) { + suggest(this.cache[val]); + return; + } // no requests if previous suggestions were empty - for (var i=1; iAdvanced suggestions handling and custom layout minChars: 1, source: function(term, suggest){ term = term.toLowerCase(); - var choices = ['ActionScript', 'AppleScript', 'Asp', 'Assembly', 'BASIC', 'Batch', 'C', 'C++', 'CSS', 'Clojure', 'COBOL', 'ColdFusion', 'Erlang', 'Fortran', 'Groovy', 'Haskell', 'HTML', 'Java', 'JavaScript', 'Lisp', 'Perl', 'PHP', 'PowerShell', 'Python', 'Ruby', 'Scala', 'Scheme', 'SQL', 'TeX', 'XML']; + var choices = ['ActionScript', 'AppleScript', 'Asp', 'Assembly', 'BASIC', 'Batch', 'C', 'C++', 'CSS', 'Clojure', 'COBOL', 'ColdFusion', 'Erlang', 'Fortran', 'Groovy', 'Haskell', 'HTML', 'Java', 'JavaScript', 'Plankalkül', 'Lisp', 'Perl', 'PHP', 'PowerShell', 'Python', 'Ruby', 'Scala', 'Scheme', 'SQL', 'TeX', 'XML']; var suggestions = []; for (i=0;i