Skip to content

Commit d5d6682

Browse files
author
SimonSteinberger
committed
Initial release.
1 parent e804412 commit d5d6682

31 files changed

+825
-1
lines changed

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,27 @@
1-
# JavaScript-autoComplete
1+
JavaScript-autoComplete
2+
===================
3+
24
An extremely lightweight and powerful vanilla JavaScript completion suggester.
5+
6+
Tested in Firefox, Safari, Chrome, Opera, Internet Explorer 8+. No dependencies, written in plain JavaScript.
7+
Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
8+
9+
This plugin was developed by [Pixabay.com](http://pixabay.com/) - an international repository for sharing free public domain images.
10+
We have implemented this piece of software in production on [plainJS](http://plainjs.com/) and we share it - in the spirit of Pixabay - freely with others.
11+
12+
## Demo and Documentation
13+
14+
http://goodies.pixabay.com/javascript/auto-complete/demo.html
15+
16+
## Features
17+
18+
* Lightweight: 5.4 kB of JavaScript - less than 2.4 kB gzipped (smaller IE9+ version available)
19+
* Fully flexible data source
20+
* Smart caching, delay and minimum character settings
21+
* Callbacks
22+
23+
## Changelog
24+
25+
### Version 1.0.0 beta - 2015/05/102
26+
27+
* First release

auto-complete.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.autocomplete-suggestions {
2+
text-align: left; cursor: default; border: 1px solid #ccc; border-top: 0; background: #fff; box-shadow: -1px 1px 3px rgba(0,0,0,.1);
3+
4+
/* core styles should not be changed */
5+
position: absolute; display: none; z-index: 9999; max-height: 254px; overflow: hidden; overflow-y: auto; box-sizing: border-box;
6+
}
7+
.autocomplete-suggestion { position: relative; padding: 0 .6em; line-height: 23px; white-space: nowrap; overflow: hidden; font-size: 1.02em; color: #333; }
8+
.autocomplete-suggestion b { font-weight: normal; color: #1f8dd6; }
9+
.autocomplete-suggestion.selected { background: #f0f0f0; }

auto-complete.ie9.js

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
/*
2+
JavaScript autoComplete v1.0.0 beta
3+
Copyright (c) 2014 Simon Steinberger / Pixabay
4+
GitHub: https://github.com/Pixabay/JavaScript-autoComplete
5+
License: http://www.opensource.org/licenses/mit-license.php
6+
7+
IE9+ version
8+
*/
9+
10+
var autoComplete = (function(){
11+
// "use strict";
12+
function autoComplete(options){
13+
14+
// helper for live binding mouse events
15+
function live(container, event, elClass, cb){
16+
container.addEventListener(event, function(e){
17+
var el = e.target, found;
18+
while (el && !(found = el.className.indexOf(elClass)<0)) el = el.parentElement;
19+
if (found) cb.call(el, e);
20+
});
21+
}
22+
23+
var o = {
24+
selector: 0,
25+
source: 0,
26+
minChars: 3,
27+
delay: 150,
28+
cache: 1,
29+
menuClass: '',
30+
renderItem: function (item, search){
31+
var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi");
32+
return '<div class="autocomplete-suggestion" data-val="' + item + '">' + item.replace(re, "<b>$1</b>") + '</div>';
33+
},
34+
onSelect: function(e, term, item){}
35+
};
36+
for (var k in options) { if (Object.prototype.hasOwnProperty.call(options, k)) o[k]=options[k]; }
37+
38+
// init
39+
var elems = typeof o.selector == 'object' ? [o.selector] : document.querySelectorAll(o.selector);
40+
for (var i=0; i<elems.length; i++) {
41+
var that = elems[i];
42+
43+
// create suggestions container "sc"
44+
that.sc = document.createElement('div');
45+
that.sc.className = 'autocomplete-suggestions '+o.menuClass;
46+
47+
that.setAttribute('data-sc', that.sc);
48+
that.autocompleteAttr = that.getAttribute('autocomplete');
49+
that.setAttribute('autocomplete', 'off');
50+
that.cache = {};
51+
that.last_val = '';
52+
53+
that.updateSC = function(resize, next){
54+
var rect = that.getBoundingClientRect(),
55+
scrollTop = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop,
56+
scrollLeft = (document.documentElement && document.documentElement.scrollLeft) || document.body.scrollLeft;
57+
that.sc.style.left = rect.left + scrollLeft + 'px';
58+
that.sc.style.top = rect.bottom + scrollTop + 1 + 'px';
59+
that.sc.style.width = rect.right - rect.left + 'px'; // outerWidth
60+
61+
if (!resize) {
62+
that.sc.style.display = 'block';
63+
if (!that.sc.maxHeight) { that.sc.maxHeight = parseInt((window.getComputedStyle ? getComputedStyle(that.sc, null) : that.sc.currentStyle).maxHeight); }
64+
if (!that.sc.suggestionHeight) {
65+
var rect2 = that.sc.querySelector('.autocomplete-suggestion').getBoundingClientRect();
66+
that.sc.suggestionHeight = rect2.bottom - rect2.top;
67+
}
68+
if (that.sc.suggestionHeight)
69+
if (!next) that.sc.scrollTop = 0;
70+
else {
71+
var scrTop = that.sc.scrollTop, selTop = next.getBoundingClientRect().top - that.sc.getBoundingClientRect().top;
72+
if (selTop + that.sc.suggestionHeight - that.sc.maxHeight > 0)
73+
that.sc.scrollTop = selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight;
74+
else if (selTop < 0)
75+
that.sc.scrollTop = selTop + scrTop;
76+
}
77+
}
78+
}
79+
window.addEventListener('resize', that.updateSC);
80+
document.body.appendChild(that.sc);
81+
82+
live(that.sc, 'mouseleave', 'autocomplete-suggestion', function(e){
83+
var sel = that.sc.querySelector('.autocomplete-suggestion.selected');
84+
if (sel) setTimeout(function(){ sel.className = sel.className.replace('selected', ''); }, 20);
85+
});
86+
87+
live(that.sc, 'mouseover', 'autocomplete-suggestion', function(e){
88+
var sel = that.sc.querySelector('.autocomplete-suggestion.selected');
89+
if (sel) sel.className = sel.className.replace('selected', '');
90+
e.target.className += ' selected';
91+
});
92+
93+
live(that.sc, 'mouseup', 'autocomplete-suggestion', function(e){
94+
var item = e.target, v = item.getAttribute('data-val');
95+
if (v || ~item.className.indexOf('autocomplete-suggestion ')) { // else outside click
96+
that.value = v;
97+
o.onSelect(e, v, item);
98+
that.focus();
99+
that.sc.style.display = 'none';
100+
}
101+
});
102+
103+
that.blurHandler = function(){
104+
try { var over_sb = document.querySelector('.autocomplete-suggestions:hover'); } catch(e){ var over_sb = 0; }
105+
if (!over_sb) {
106+
that.last_val = that.value;
107+
that.sc.style.display = 'none';
108+
} else that.focus();
109+
};
110+
that.addEventListener('blur', that.blurHandler);
111+
112+
that.focusHandler = function(){
113+
that.last_val = '\n';
114+
var event = document.createEvent('HTMLEvents'); event.initEvent('keyup', true, true); that.dispatchEvent(event);
115+
};
116+
if (!o.minChars) that.addEventListener('focus', that.focusHandler);
117+
118+
var suggest = function(data){
119+
var val = that.value;
120+
that.cache[val] = data;
121+
if (data.length && val.length >= o.minChars) {
122+
var s = '';
123+
for (var i=0;i<data.length;i++) s += o.renderItem(data[i], val);
124+
that.sc.innerHTML = s;
125+
that.updateSC(0);
126+
}
127+
else
128+
that.sc.style.display = 'none';
129+
}
130+
131+
that.keydownHandler = function(e){
132+
var key = window.event ? e.keyCode : e.which;
133+
// down (40), up (38)
134+
if ((key == 40 || key == 38) && that.sc.innerHTML) {
135+
var next, sel = that.sc.querySelector('.autocomplete-suggestion.selected');
136+
if (!sel) {
137+
next = (key == 40) ? that.sc.querySelector('.autocomplete-suggestion') : that.sc.childNodes[that.sc.childNodes.length - 1]; // first : last
138+
next.className += ' selected';
139+
that.value = next.getAttribute('data-val');
140+
} else {
141+
next = (key == 40) ? sel.nextSibling : sel.previousSibling;
142+
if (next) {
143+
sel.className = sel.className.replace('selected', '');
144+
next.className += ' selected';
145+
that.value = next.getAttribute('data-val');
146+
}
147+
else { sel.className = sel.className.replace('selected', ''); that.value = that.last_val; next = 0; }
148+
}
149+
that.updateSC(0, next);
150+
return false;
151+
}
152+
// esc
153+
else if (key == 27) { that.value = that.last_val; that.sc.style.display = 'none'; }
154+
// enter
155+
else if (key == 13) {
156+
var sel = that.sc.querySelector('.autocomplete-suggestion.selected');
157+
if (sel) { o.onSelect(e, sel.getAttribute('data-val'), sel); setTimeout(function(){ that.focus(); that.sc.style.display = 'none'; }, 10); }
158+
}
159+
};
160+
that.addEventListener('keydown', that.keydownHandler);
161+
162+
that.keyupHandler = function(e){
163+
var key = window.event ? e.keyCode : e.which;
164+
if (key != 27 && key != 38 && key != 40 && key != 37 && key != 39) {
165+
var val = that.value;
166+
if (val.length >= o.minChars) {
167+
if (val != that.last_val) {
168+
that.last_val = val;
169+
clearTimeout(that.timer);
170+
if (o.cache) {
171+
if (val in that.cache) { suggest(that.cache[val]); return; }
172+
// no requests if previous suggestions were empty
173+
for (var i=1; i<val.length-o.minChars; i++) {
174+
var part = val.slice(0, val.length-i);
175+
if (part in that.cache && !that.cache[part].length) { suggest([]); return; }
176+
}
177+
}
178+
that.timer = setTimeout(function(){ o.source(val, suggest) }, o.delay);
179+
}
180+
} else {
181+
that.last_val = val;
182+
that.sc.style.display = 'none';
183+
}
184+
}
185+
};
186+
that.addEventListener('keyup', that.keyupHandler);
187+
}
188+
189+
// public destroy method
190+
this.destroy = function(){
191+
for (var i=0; i<elems.length; i++) {
192+
var that = elems[i];
193+
window.removeEventListener('resize', that.updateSC);
194+
that.removeEventListener('blur', that.blurHandler);
195+
that.removeEventListener('focus', that.focusHandler);
196+
that.removeEventListener('keydown', that.keydownHandler);
197+
that.removeEventListener('keyup', that.keyupHandler);
198+
if (that.autocompleteAttr)
199+
that.setAttribute('autocomplete', that.autocompleteAttr);
200+
else
201+
that.removeAttribute('autocomplete');
202+
document.body.removeChild(that.sc);
203+
that = null;
204+
}
205+
};
206+
}
207+
return autoComplete;
208+
})();
209+
210+
(function(){
211+
if (typeof define === 'function' && define.amd)
212+
define('autoComplete', function () { return autoComplete; });
213+
else if (typeof module !== 'undefined' && module.exports)
214+
module.exports = autoComplete;
215+
else
216+
window.autoComplete = autoComplete;
217+
})();

0 commit comments

Comments
 (0)