/* jQuery Autocomplete * Version 1.0 * Written by Yehuda Katz (wycats@gmail.com) and Rein Henrichs (reinh@reinh.com) * @requires jQuery v1.2, jQuery dimensions plugin * * Copyright 2007 Yehuda Katz, Rein Henrichs * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * */ /* * @description Form autocomplete plugin using preloaded or Ajax JSON data source * * @example $('input#user-name').autocomplete({list: ["quentin", "adam", "admin"]}) * @desc Simple autocomplete with basic JSON data source * * @example $('input#user-name').autocomplete({ajax: "/usernames.js"}) * @desc Simple autocomplete with Ajax loaded JSON data source * */ (function($) { $.ui = $.ui || {}; $.ui.autocomplete = $.ui.autocomplete || {}; var active; var KEY = { ESC: 27, RETURN: 13, TAB: 9, BS: 8, DEL: 46, UP: 38, DOWN: 40 }; $.fn.autocompleteMode = function(container, input, size, opt) { var original = input.val(); var selected = -1; var self = this; $.data(document.body, "autocompleteMode", true); $("body").one("cancel.autocomplete", function() { input.trigger("cancel.autocomplete"); $("body").trigger("off.autocomplete"); input.val(original); }); $("body").one("activate.autocomplete", function() { // Try hitting return to activate autocomplete and then hitting it again on blank input // to close it. w/o checking the active object first this input.trigger() will barf. active && input.trigger("activate.autocomplete", [$.data(active[0], "originalObject")]); $("body").trigger("off.autocomplete"); }); $("body").one("off.autocomplete", function(e, reset) { container.remove(); $.data(document.body, "autocompleteMode", false); input.unbind("keydown.autocomplete"); $("body").add(window).unbind("click.autocomplete").unbind("cancel.autocomplete").unbind("activate.autocomplete"); }); // If a click bubbles all the way up to the window, close the autocomplete $(window).bind("click.autocomplete", function() { $("body").trigger("cancel.autocomplete"); }); var select = function() { active = $("> *", container).removeClass("active").slice(selected, selected + 1).addClass("active"); input.trigger("itemSelected.autocomplete", [$.data(active[0], "originalObject")]); input.val(opt.insertText($.data(active[0], "originalObject"))); }; container.mouseover(function(e) { // If you hover over the container, but not its children, return if(e.target == container[0]) return; // Set the selected item to the item hovered over and make it active selected = $("> *", container).index($(e.target).is('li') ? $(e.target)[0] : $(e.target).parents('li')[0]); select(); }).bind("click.autocomplete", function(e) { $("body").trigger("activate.autocomplete"); $.data(document.body, "suppressKey", false); }); input .bind("keydown.autocomplete", function(e) { var k = e.which || e.keyCode; // in IE e.which is undefined if(k == KEY.ESC) { $("body").trigger("cancel.autocomplete"); } else if(k == KEY.RETURN) { $("body").trigger("activate.autocomplete"); } else if(k == KEY.UP || k == KEY.TAB || k == KEY.DOWN) { switch(k) { case KEY.DOWN: case KEY.TAB: selected = selected >= size - 1 ? 0 : selected + 1; break; case KEY.UP: selected = selected <= 0 ? size - 1 : selected - 1; break; default: break; } select(); } else { return true; } $.data(document.body, "suppressKey", true); }); }; $.fn.autocomplete = function(opt) { opt = $.extend({}, { timeout: 1000, getList: function(input) { input.trigger("updateList", [opt.list]); }, template: function(str) { return "