Incremental Search //JavaScript Repository
Description
Auto-complete for inputs similar to gmail.
Created: 2005.08.06 - Modified 2013.09.17
Created: 2005.08.06 - Modified 2013.09.17
Dependencies
Code (Download)
//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/dhtml/incremental-search [rev. #5]
IncrementalSearch = function (input, callback, className) {
var i, $ = this;
($.input = input).autocomplete = "off", $.callback = callback || function () { },
$.className = className || "", $.hide(), $.visible = 0;
for(i in { keydown: 0, focus: 0, blur: 0, keyup: 0, keypress: 0 })
addEvent(input, i, $._handler, $);
};
with({ p: IncrementalSearch.prototype }) {
p.show = function () {
for(var $ = this, s = document.body.appendChild($.c).style, o = $.input, x = o.offsetLeft,
y = o.offsetTop + o.offsetHeight; o = o.offsetParent; x += o.offsetLeft, y += o.offsetTop);
s.left = x + "px", s.top = y + "px",
$.l.length ? (s.display = "block", !$.visible && ($._callEvent("onshow"), ++$.visible), $.highlite(0)) : s.display = "none";
};
p.hide = function () {
var $ = this, s = ($.c && $.c.parentNode && $.c.parentNode.removeChild($.c),
$.c = document.createElement("div")).style;
$.l = [], $.i = -1, $.c.className = $.className, s.position = "absolute", s.display = "none";
$._old = null, $.visible && ($._callEvent("onhide"), --$.visible);
};
p.add = function (s, x, data) {
var $ = this, l = 0, d = document, i = $.l.length, v = $.input.value.length,
o = ($.l[i] = [s, data, $.c.appendChild(d.createElement("div"))])[2];
if(x instanceof Array || (x = [x]), o.i = i, o.className = "normal", !isNaN(x[0]))
for(var j = -1, k = x.length; ++j < k; o.appendChild(d.createTextNode(
s.substring(l, x[j]))).parentNode.appendChild(d.createElement(
"span")).appendChild(d.createTextNode(s.substring(x[j],
l = x[j] + v))).parentNode.className = "highlited");
for(x in o.appendChild(d.createTextNode(s.substr(l))), { click: 0, mouseover: 0 })
addEvent(o, x, $._handler, $);
};
p.highlite = function (i) {
var $ = this;
$._invalid(i) || ($._invalid($.i) || ($.l[$.i][2].className = "normal"),
$.l[$.i = i][2].className += " selected", $._callEvent("onhighlite", $.l[i][0], $.l[i][1]));
};
p.select = function (i) {
var $ = this;
$._invalid(i = isNaN(i) ? $.i : i) || ($._callEvent("onselect",
$.input.value = $.l[$.i][0], $.l[i][1]), $.hide());
};
p.next = function () {
var $ = ($ = this, $.highlite(($.i + 1) % $.l.length));
};
p.previous = function () {
var $ = ($ = this, $.highlite((!$.i ? $.l.length : $.i) - 1));
};
p._fadeOut = function () {
var f = (f = function () { arguments.callee.x.hide(); }, f.x = this, setTimeout(f, 200));
};
p._handler = function (e) {
var $ = this, t = e.type, k = e.key;
t == "focus" || t == "keyup" ? k != 40 && k != 38 && k != 13 && $._old != $.input.value && ($.hide(), $.callback($, $.input.value))
: t == "keydown" ? k == 40 ? $.next() : k == 38 ? $.previous() : $._old = $.input.value
: t == "keypress" ? k == 13 && (e.preventDefault(), $.select())
: t == "blur" ? $._fadeOut() : t == "click" ? $.select()
: $.highlite((/span/i.test((e = e.target).tagName) ? e.parentNode : e).i);
};
p._invalid = function (i) {
return isNaN(i) || i < 0 || i >= this.l.length;
}
p._callEvent = function (e) {
var $ = this;
return $[e] instanceof Function ? $[e].apply($, [].slice.call(arguments, 1)) : undefined;
};
}
Example (Example)
<style type="text/css">
/*container da lista | container of the list*/
.autocomplete{
cursor: pointer;
border: 1px solid #999;
border-top: none;
background: #eee;
}
/*items da listagem | items of the list*/
.autocomplete .normal{border-top: 1px solid #999;}
/*selectedionado item | selected item*/
.autocomplete .selected{background: #ddf;}
/*caracteres que combinaram | characters that matched*/
.autocomplete .highlited{font-weight: bold; color: #008;}
</style>
<form action="">
<fieldset>
<legend>Preenchimento din?mico | Dynamic filling</legend>
<label for="listB">
Busca case-insensitive em todas as partes da string.
<br />Case-insensitive search in all the parts of the string.
</label>
<input type="text" id="listB" />
<br /><label for="listA">
Busca case-sensitive come?ando a partir do inicio da string.
<br />Case-sensitive search starting from the beginning of the string.
</label>
<input type="text" id="listA" />
<p>Para corrigir o bug do IE ao criar elementos sobre <select>'s, olhe o exemplo dispon?vel aqui:
<a href="/geral/hittest#example-header" title="Hit Test">Hit Test</a>.
<br />To correct the IE bug when creating elements over <select>'s, look at the example available here:
<a href="/geral/hittest#example-header" title="Hit Test">Hit Test</a>.
</p>
</fieldset>
</form>
<div id="label" style="clear: both;"></div>
<script type="text/javascript">
//<![CDATA[
var list = [
"Osama Bin Laden", "Ed?lson Pereira de Carvalho", "Jonas Raoni Soares Silva",
"Carlos R. L. Rodrigues", "George Bush", "Pedro de Lara", "Britney Spears", "Charles Bronson",
"Roberto Jefferson", "Silvio Santos", "Tati Quebra Barraco", "William Bonner"
].sort();
document.getElementById("label").innerHTML = "<br /><b>Nomes Dispon?veis | Available names:</b><br />" + list.join("<br />");
//-- Busca simples / Simple search ------------------
new IncrementalSearch(document.forms[0].listA, function(o, search){
if(!search)
return;
for(var i = -1, l = list.length; ++i < l;)
/*se encontrou "search" no come?o da string (index == 0)
if "search" was found in the beginning of the string (index == 0)*/
if(!list[i].indexOf(search))
/*adiciona o item na listagem, informando que a posi??o onde a palavra foi encontrada ? 0
adds the item to the list, telling that the position where the word was found is 0*/
o.add(list[i], 0);
/*shows the list
exibe a listagem*/
o.show();
}, "autocomplete");
//-- Busca m?ltiplas ocorr?ncias / Searches for multiple matches ----
function getNames(o, search){
if(search = search.toLowerCase())
for(var i = -1, l = list.length; ++i < l;){
/*procura todas as ocorr?ncias de "search" e adiciona os ?ndices em um array
searches all the matches of "search" and adds the indexes in an array */
for(var j = 0, indices = []; j = list[i].toLowerCase().indexOf(search, j) + 1;
indices[indices.length] = j - 1);
/*se alguma ocorr?ncia foi encontrada, adiciona o item e passa a posi??o das ocorr?ncias
if any ocurrence was found, adds the item and pass the position of the matches*/
if(indices.length)
o.add(list[i], indices);
}
o.show();
}
new IncrementalSearch(document.forms[0].listB, getNames, "autocomplete");
//]]>
</script>
Help
CSS Classes
- .NameOfTheClass
- It's applied to the div that contains the list.
- .NameOfTheClass .normal
- It's applied on every list item.
- .NameOfTheClass .selected
- It's applied on the selected item.
- .NameOfTheClass .highlited
- It's applied just on the characters that matched the search.
Constructor
- IncrementalSearch(field: HTMLInputElement, searchCallback: Function(IncrementalSearch, String): void, className: String)
-
Generates an instance of IncrementalSearch.
- input
- input element that will be linked with the auto-complete
- searchCallback
- callback function that will be called whenever the user changes the input content, the first parameter is the IncrementalSearch instance itself and the second parameter is the current input text
- className
- CSS classname that will be used by the auto-complete
Methods
- IncrementalSearch.show(void): void
- Shows the list.
- IncrementalSearch.hide(void): void
- Clears and hides the list.
- IncrementalSearch.add(caption: String, [matchIndexes: Object = null], [data: Object = null]): void
-
Adds an item to the list.
- caption
- text that will be shown in the list
- matchIndexes
- position where the searched string (the current input text) was found, if there's more than one match of the searched string and you want to highlight them, then just send an array containing all the indexes, if you don't send anything, the text won't be highlighted
- data
- can be anything, this data will be associated with the item and, you'll have access to it through the IncrementalSearch's events
- IncrementalSearch.next(void): void
- Focus the next item on the list.
- IncrementalSearch.previous(void): void
- Focus the previous item on the list.
- IncrementalSearch.highlite(index: Integer): void
-
Focus a determinated item.
- index
- position of the item that should be focused
- IncrementalSearch.select([index: Integer = CURRENT_ITEM]): void
-
Selects the item specified in index, calls the onselect event and closes the list.
- index
- position of the item that should be selected
Events
- IncrementalSearch.onhighlite: Function(caption: String, data: Object): void
-
Occurs whenever an item receives focus.
- caption
- contains the item text
- data
- contains the data that was previously associated with the item
- IncrementalSearch.onselect: Function(caption: String, data: Object): void
-
Occurs whenever an item is selected.
- caption
- contains the item text
- data
- contains the data that was previously associated with the item
- IncrementalSearch.onshow: Function(void): void
- Occurs when the list is shown.
- IncrementalSearch.onhide: Function(void): void
- Occurs when the list is hidden.
Properties
- IncrementalSearch.input: HTMLInputElement
- References to the linked field.
- IncrementalSearch.callback: Function(IncrementalSearch, String): void
- References to the callback function.
- IncrementalSearch.className: String
- CSS classname that will be used by the IncrementalSearch.
- IncrementalSearch.visible: Boolean
- Indicates if the list is visible.
- IncrementalSearch.c: HTMLElement
- It's the <div> that contains the list (it's recreated whenever the list is hidden).
- IncrementalSearch.i: Integer
- Keeps the index of the focused item.
- IncrementalSearch.l: Array
- It's an array containing information about the items, each line is an item, the first column is the item text, the second contains the data that was associated with the item and the third is a reference to the <div> item on the list.
Rank (Votes: 99)
3.24