(function ($) { /** * Attaches the autocomplete behavior to all required fields. */ Drupal.behaviors.autocomplete = { attach: function (context, settings) { var acdb = []; $('input.autocomplete', context).once('autocomplete', function () { var uri = this.value; if (!acdb[uri]) { acdb[uri] = new Drupal.ACDB(uri); } var $input = $('#' + this.id.substr(0, this.id.length - 13)) .attr('autocomplete', 'OFF') .attr('aria-autocomplete', 'list'); $($input[0].form).submit(Drupal.autocompleteSubmit); $input.parent() .attr('role', 'application') .append($('') .attr('id', $input.attr('id') + '-autocomplete-aria-live') ); new Drupal.jsAC($input, acdb[uri]); }); } }; /** * Prevents the form from submitting if the suggestions popup is open * and closes the suggestions popup when doing so. */ Drupal.autocompleteSubmit = function () { return $('#autocomplete').each(function () { this.owner.hidePopup(); }).length == 0; }; /** * An AutoComplete object. */ Drupal.jsAC = function ($input, db) { var ac = this; this.input = $input[0]; this.ariaLive = $('#' + this.input.id + '-autocomplete-aria-live'); this.db = db; $input .keydown(function (event) { return ac.onkeydown(this, event); }) .keyup(function (event) { ac.onkeyup(this, event); }) .blur(function () { ac.hidePopup(); ac.db.cancel(); }); }; /** * Handler for the "keydown" event. */ Drupal.jsAC.prototype.onkeydown = function (input, e) { if (!e) { e = window.event; } switch (e.keyCode) { case 40: // down arrow. this.selectDown(); return false; case 38: // up arrow. this.selectUp(); return false; default: // All other keys. return true; } }; /** * Handler for the "keyup" event. */ Drupal.jsAC.prototype.onkeyup = function (input, e) { if (!e) { e = window.event; } switch (e.keyCode) { case 16: // Shift. case 17: // Ctrl. case 18: // Alt. case 20: // Caps lock. case 33: // Page up. case 34: // Page down. case 35: // End. case 36: // Home. case 37: // Left arrow. case 38: // Up arrow. case 39: // Right arrow. case 40: // Down arrow. return true; case 9: // Tab. case 13: // Enter. case 27: // Esc. this.hidePopup(e.keyCode); return true; default: // All other keys. if (input.value.length > 0 && !input.readOnly) { this.populatePopup(); } else { this.hidePopup(e.keyCode); } return true; } }; /** * Puts the currently highlighted suggestion into the autocomplete field. */ Drupal.jsAC.prototype.select = function (node) { this.input.value = $(node).data('autocompleteValue'); $(this.input).trigger('autocompleteSelect', [node]); }; /** * Highlights the next suggestion. */ Drupal.jsAC.prototype.selectDown = function () { if (this.selected && this.selected.nextSibling) { this.highlight(this.selected.nextSibling); } else if (this.popup) { var lis = $('li', this.popup); if (lis.length > 0) { this.highlight(lis.get(0)); } } }; /** * Highlights the previous suggestion. */ Drupal.jsAC.prototype.selectUp = function () { if (this.selected && this.selected.previousSibling) { this.highlight(this.selected.previousSibling); } }; /** * Highlights a suggestion. */ Drupal.jsAC.prototype.highlight = function (node) { if (this.selected) { $(this.selected).removeClass('selected'); } $(node).addClass('selected'); this.selected = node; $(this.ariaLive).html($(this.selected).html()); }; /** * Unhighlights a suggestion. */ Drupal.jsAC.prototype.unhighlight = function (node) { $(node).removeClass('selected'); this.selected = false; $(this.ariaLive).empty(); }; /** * Hides the autocomplete suggestions. */ Drupal.jsAC.prototype.hidePopup = function (keycode) { // Select item if the right key or mousebutton was pressed. if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) { this.select(this.selected); } // Hide popup. var popup = this.popup; if (popup) { this.popup = null; $(popup).fadeOut('fast', function () { $(popup).remove(); }); } this.selected = false; $(this.ariaLive).empty(); }; /** * Positions the suggestions popup and starts a search. */ Drupal.jsAC.prototype.populatePopup = function () { var $input = $(this.input); var position = $input.position(); // Show popup. if (this.popup) { $(this.popup).remove(); } this.selected = false; this.popup = $('
')[0]; this.popup.owner = this; $(this.popup).css({ top: parseInt(position.top + this.input.offsetHeight, 10) + 'px', left: parseInt(position.left, 10) + 'px', width: $input.innerWidth() + 'px', display: 'none' }); $input.before(this.popup); // Do search. this.db.owner = this; this.db.search(this.input.value); }; /** * Fills the suggestion popup with any matches received. */ Drupal.jsAC.prototype.found = function (matches) { // If no value in the textfield, do not show the popup. if (!this.input.value.length) { return false; } // Prepare matches. var ul = $('