Busca Incremental //Repositório JavaScript

Descrição

Auto preenchimento para inputs semelhante ao gmail.
Criado: 2005.08.06 - Modificado 2013.09.17

Dependências

Código (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.keyValue;
        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;
    };
}

Exemplo (Exemplo)

<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 &lt;select&gt;'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 &lt;select&gt;'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>

Ajuda

Classes CSS

.NomeDaClasse
É aplicado ao div que contém a listagem.
.NomeDaClasse .normal
É aplicado em todos os itens da listagem.
.NomeDaClasse .selected
É aplicado apenas ao item que estiver selecionado.
.NomeDaClasse .highlited
É aplicado apenas aos caracteres que satisfizeram os critérios da busca.

Construtor

IncrementalSearch(field: HTMLInputElement, searchCallback: Function(IncrementalSearch, String): void, className: String)
Gera uma instância de IncrementalSearch.
input
elemento input que será linkado com o auto-complete
searchCallback
função de callback que será chamada quando o usuário alterar o conteúdo do input, o primeiro parâmetro é a própria instância do IncrementalSearch e o segundo parâmetro é o texto contido atualmente no input
className
nome da classe CSS que será usada pelo auto-complete

Métodos

IncrementalSearch.show(void): void
Exibe a listagem.
IncrementalSearch.hide(void): void
Limpa e esconde a listagem.
IncrementalSearch.add(caption: String, [matchIndexes: Object = null], [data: Object = null]): void
Adiciona um item a listagem.
caption
texto que será exibido na listagem
matchIndexes
posição onde a string procurada (o texto que está no input) foi encontrada, se houver mais de uma ocorrência do termo procurado e você quiser aplicar o highlight neles, basta informar uma array contendo todos os índices, caso não seja informado nada, o highlight não será aplicado
data
pode conter qualquer coisa, este dado será associado ao item e, você terá acesso a ele pelos eventos do IncrementalSearch
IncrementalSearch.next(void): void
Foca o próximo item na listagem.
IncrementalSearch.previous(void): void
Foca o item anterior na listagem.
IncrementalSearch.highlite(index: Integer): void
Foca um determinado item.
index
posição do item que deve receber foco
IncrementalSearch.select([index: Integer = CURRENT_ITEM]): void
Seleciona o item especificado em index, chama o evento onselect e fecha a listagem.
index
posição do item que deve ser selecionado

Eventos

IncrementalSearch.onhighlite: Function(caption: String, data: Object): void
Este evento é chamado quando um item da listagem recebe foco.
caption
contém o texto do item
data
contém o dado que foi associado ao item selecionado
IncrementalSearch.onselect: Function(caption: String, data: Object): void
Este evento é chamado quando um item da listagem é selecionado com um click ou com o enter.
caption
contém o texto do item
data
contém o dado que foi associado ao item selecionado
IncrementalSearch.onshow: Function(void): void
Este evento é chamado quando a listagem é exibida.
IncrementalSearch.onhide: Function(void): void
Este evento é chamado quando a listagem é escondida.

Propriedades

IncrementalSearch.input: HTMLInputElement
Referência ao campo informado no constructor.
IncrementalSearch.callback: Function(IncrementalSearch, String): void
Referência a função de callback informadada no constructor.
IncrementalSearch.className: String
Nome da classe CSS que foi informada no constructor.
IncrementalSearch.visible: Boolean
Indica se a listagem está sendo exibida.
IncrementalSearch.c: HTMLElement
É o <div> que contém a listagem (é recriado sempre que a listagem é fechada).
IncrementalSearch.i: Integer
Mantém o índice do item atualmente focado.
IncrementalSearch.l: Array
É uma array contendo informações sobre os itens, cada linha é um item e, a primeira coluna é o texto do item, a segunda contém o dado associado ao item e a terceira é uma referência ao <div> do item na listagem.

Ranque (Votos: 74)

4.32