annotate misc/autocomplete.js @ 13:134d4b2e75f6

updated quicktabs and google analytics modules
author danieleb <danielebarchiesi@me.com>
date Tue, 29 Oct 2013 13:48:59 +0000
parents ff03f76ab3fe
children
rev   line source
danielebarchiesi@0 1 (function ($) {
danielebarchiesi@0 2
danielebarchiesi@0 3 /**
danielebarchiesi@0 4 * Attaches the autocomplete behavior to all required fields.
danielebarchiesi@0 5 */
danielebarchiesi@0 6 Drupal.behaviors.autocomplete = {
danielebarchiesi@0 7 attach: function (context, settings) {
danielebarchiesi@0 8 var acdb = [];
danielebarchiesi@0 9 $('input.autocomplete', context).once('autocomplete', function () {
danielebarchiesi@0 10 var uri = this.value;
danielebarchiesi@0 11 if (!acdb[uri]) {
danielebarchiesi@0 12 acdb[uri] = new Drupal.ACDB(uri);
danielebarchiesi@0 13 }
danielebarchiesi@0 14 var $input = $('#' + this.id.substr(0, this.id.length - 13))
danielebarchiesi@0 15 .attr('autocomplete', 'OFF')
danielebarchiesi@0 16 .attr('aria-autocomplete', 'list');
danielebarchiesi@0 17 $($input[0].form).submit(Drupal.autocompleteSubmit);
danielebarchiesi@0 18 $input.parent()
danielebarchiesi@0 19 .attr('role', 'application')
danielebarchiesi@0 20 .append($('<span class="element-invisible" aria-live="assertive"></span>')
danielebarchiesi@0 21 .attr('id', $input.attr('id') + '-autocomplete-aria-live')
danielebarchiesi@0 22 );
danielebarchiesi@0 23 new Drupal.jsAC($input, acdb[uri]);
danielebarchiesi@0 24 });
danielebarchiesi@0 25 }
danielebarchiesi@0 26 };
danielebarchiesi@0 27
danielebarchiesi@0 28 /**
danielebarchiesi@0 29 * Prevents the form from submitting if the suggestions popup is open
danielebarchiesi@0 30 * and closes the suggestions popup when doing so.
danielebarchiesi@0 31 */
danielebarchiesi@0 32 Drupal.autocompleteSubmit = function () {
danielebarchiesi@0 33 return $('#autocomplete').each(function () {
danielebarchiesi@0 34 this.owner.hidePopup();
danielebarchiesi@0 35 }).length == 0;
danielebarchiesi@0 36 };
danielebarchiesi@0 37
danielebarchiesi@0 38 /**
danielebarchiesi@0 39 * An AutoComplete object.
danielebarchiesi@0 40 */
danielebarchiesi@0 41 Drupal.jsAC = function ($input, db) {
danielebarchiesi@0 42 var ac = this;
danielebarchiesi@0 43 this.input = $input[0];
danielebarchiesi@0 44 this.ariaLive = $('#' + this.input.id + '-autocomplete-aria-live');
danielebarchiesi@0 45 this.db = db;
danielebarchiesi@0 46
danielebarchiesi@0 47 $input
danielebarchiesi@0 48 .keydown(function (event) { return ac.onkeydown(this, event); })
danielebarchiesi@0 49 .keyup(function (event) { ac.onkeyup(this, event); })
danielebarchiesi@0 50 .blur(function () { ac.hidePopup(); ac.db.cancel(); });
danielebarchiesi@0 51
danielebarchiesi@0 52 };
danielebarchiesi@0 53
danielebarchiesi@0 54 /**
danielebarchiesi@0 55 * Handler for the "keydown" event.
danielebarchiesi@0 56 */
danielebarchiesi@0 57 Drupal.jsAC.prototype.onkeydown = function (input, e) {
danielebarchiesi@0 58 if (!e) {
danielebarchiesi@0 59 e = window.event;
danielebarchiesi@0 60 }
danielebarchiesi@0 61 switch (e.keyCode) {
danielebarchiesi@0 62 case 40: // down arrow.
danielebarchiesi@0 63 this.selectDown();
danielebarchiesi@0 64 return false;
danielebarchiesi@0 65 case 38: // up arrow.
danielebarchiesi@0 66 this.selectUp();
danielebarchiesi@0 67 return false;
danielebarchiesi@0 68 default: // All other keys.
danielebarchiesi@0 69 return true;
danielebarchiesi@0 70 }
danielebarchiesi@0 71 };
danielebarchiesi@0 72
danielebarchiesi@0 73 /**
danielebarchiesi@0 74 * Handler for the "keyup" event.
danielebarchiesi@0 75 */
danielebarchiesi@0 76 Drupal.jsAC.prototype.onkeyup = function (input, e) {
danielebarchiesi@0 77 if (!e) {
danielebarchiesi@0 78 e = window.event;
danielebarchiesi@0 79 }
danielebarchiesi@0 80 switch (e.keyCode) {
danielebarchiesi@0 81 case 16: // Shift.
danielebarchiesi@0 82 case 17: // Ctrl.
danielebarchiesi@0 83 case 18: // Alt.
danielebarchiesi@0 84 case 20: // Caps lock.
danielebarchiesi@0 85 case 33: // Page up.
danielebarchiesi@0 86 case 34: // Page down.
danielebarchiesi@0 87 case 35: // End.
danielebarchiesi@0 88 case 36: // Home.
danielebarchiesi@0 89 case 37: // Left arrow.
danielebarchiesi@0 90 case 38: // Up arrow.
danielebarchiesi@0 91 case 39: // Right arrow.
danielebarchiesi@0 92 case 40: // Down arrow.
danielebarchiesi@0 93 return true;
danielebarchiesi@0 94
danielebarchiesi@0 95 case 9: // Tab.
danielebarchiesi@0 96 case 13: // Enter.
danielebarchiesi@0 97 case 27: // Esc.
danielebarchiesi@0 98 this.hidePopup(e.keyCode);
danielebarchiesi@0 99 return true;
danielebarchiesi@0 100
danielebarchiesi@0 101 default: // All other keys.
danielebarchiesi@0 102 if (input.value.length > 0 && !input.readOnly) {
danielebarchiesi@0 103 this.populatePopup();
danielebarchiesi@0 104 }
danielebarchiesi@0 105 else {
danielebarchiesi@0 106 this.hidePopup(e.keyCode);
danielebarchiesi@0 107 }
danielebarchiesi@0 108 return true;
danielebarchiesi@0 109 }
danielebarchiesi@0 110 };
danielebarchiesi@0 111
danielebarchiesi@0 112 /**
danielebarchiesi@0 113 * Puts the currently highlighted suggestion into the autocomplete field.
danielebarchiesi@0 114 */
danielebarchiesi@0 115 Drupal.jsAC.prototype.select = function (node) {
danielebarchiesi@0 116 this.input.value = $(node).data('autocompleteValue');
danielebarchiesi@0 117 };
danielebarchiesi@0 118
danielebarchiesi@0 119 /**
danielebarchiesi@0 120 * Highlights the next suggestion.
danielebarchiesi@0 121 */
danielebarchiesi@0 122 Drupal.jsAC.prototype.selectDown = function () {
danielebarchiesi@0 123 if (this.selected && this.selected.nextSibling) {
danielebarchiesi@0 124 this.highlight(this.selected.nextSibling);
danielebarchiesi@0 125 }
danielebarchiesi@0 126 else if (this.popup) {
danielebarchiesi@0 127 var lis = $('li', this.popup);
danielebarchiesi@0 128 if (lis.length > 0) {
danielebarchiesi@0 129 this.highlight(lis.get(0));
danielebarchiesi@0 130 }
danielebarchiesi@0 131 }
danielebarchiesi@0 132 };
danielebarchiesi@0 133
danielebarchiesi@0 134 /**
danielebarchiesi@0 135 * Highlights the previous suggestion.
danielebarchiesi@0 136 */
danielebarchiesi@0 137 Drupal.jsAC.prototype.selectUp = function () {
danielebarchiesi@0 138 if (this.selected && this.selected.previousSibling) {
danielebarchiesi@0 139 this.highlight(this.selected.previousSibling);
danielebarchiesi@0 140 }
danielebarchiesi@0 141 };
danielebarchiesi@0 142
danielebarchiesi@0 143 /**
danielebarchiesi@0 144 * Highlights a suggestion.
danielebarchiesi@0 145 */
danielebarchiesi@0 146 Drupal.jsAC.prototype.highlight = function (node) {
danielebarchiesi@0 147 if (this.selected) {
danielebarchiesi@0 148 $(this.selected).removeClass('selected');
danielebarchiesi@0 149 }
danielebarchiesi@0 150 $(node).addClass('selected');
danielebarchiesi@0 151 this.selected = node;
danielebarchiesi@0 152 $(this.ariaLive).html($(this.selected).html());
danielebarchiesi@0 153 };
danielebarchiesi@0 154
danielebarchiesi@0 155 /**
danielebarchiesi@0 156 * Unhighlights a suggestion.
danielebarchiesi@0 157 */
danielebarchiesi@0 158 Drupal.jsAC.prototype.unhighlight = function (node) {
danielebarchiesi@0 159 $(node).removeClass('selected');
danielebarchiesi@0 160 this.selected = false;
danielebarchiesi@0 161 $(this.ariaLive).empty();
danielebarchiesi@0 162 };
danielebarchiesi@0 163
danielebarchiesi@0 164 /**
danielebarchiesi@0 165 * Hides the autocomplete suggestions.
danielebarchiesi@0 166 */
danielebarchiesi@0 167 Drupal.jsAC.prototype.hidePopup = function (keycode) {
danielebarchiesi@0 168 // Select item if the right key or mousebutton was pressed.
danielebarchiesi@0 169 if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
danielebarchiesi@0 170 this.input.value = $(this.selected).data('autocompleteValue');
danielebarchiesi@0 171 }
danielebarchiesi@0 172 // Hide popup.
danielebarchiesi@0 173 var popup = this.popup;
danielebarchiesi@0 174 if (popup) {
danielebarchiesi@0 175 this.popup = null;
danielebarchiesi@0 176 $(popup).fadeOut('fast', function () { $(popup).remove(); });
danielebarchiesi@0 177 }
danielebarchiesi@0 178 this.selected = false;
danielebarchiesi@0 179 $(this.ariaLive).empty();
danielebarchiesi@0 180 };
danielebarchiesi@0 181
danielebarchiesi@0 182 /**
danielebarchiesi@0 183 * Positions the suggestions popup and starts a search.
danielebarchiesi@0 184 */
danielebarchiesi@0 185 Drupal.jsAC.prototype.populatePopup = function () {
danielebarchiesi@0 186 var $input = $(this.input);
danielebarchiesi@0 187 var position = $input.position();
danielebarchiesi@0 188 // Show popup.
danielebarchiesi@0 189 if (this.popup) {
danielebarchiesi@0 190 $(this.popup).remove();
danielebarchiesi@0 191 }
danielebarchiesi@0 192 this.selected = false;
danielebarchiesi@0 193 this.popup = $('<div id="autocomplete"></div>')[0];
danielebarchiesi@0 194 this.popup.owner = this;
danielebarchiesi@0 195 $(this.popup).css({
danielebarchiesi@0 196 top: parseInt(position.top + this.input.offsetHeight, 10) + 'px',
danielebarchiesi@0 197 left: parseInt(position.left, 10) + 'px',
danielebarchiesi@0 198 width: $input.innerWidth() + 'px',
danielebarchiesi@0 199 display: 'none'
danielebarchiesi@0 200 });
danielebarchiesi@0 201 $input.before(this.popup);
danielebarchiesi@0 202
danielebarchiesi@0 203 // Do search.
danielebarchiesi@0 204 this.db.owner = this;
danielebarchiesi@0 205 this.db.search(this.input.value);
danielebarchiesi@0 206 };
danielebarchiesi@0 207
danielebarchiesi@0 208 /**
danielebarchiesi@0 209 * Fills the suggestion popup with any matches received.
danielebarchiesi@0 210 */
danielebarchiesi@0 211 Drupal.jsAC.prototype.found = function (matches) {
danielebarchiesi@0 212 // If no value in the textfield, do not show the popup.
danielebarchiesi@0 213 if (!this.input.value.length) {
danielebarchiesi@0 214 return false;
danielebarchiesi@0 215 }
danielebarchiesi@0 216
danielebarchiesi@0 217 // Prepare matches.
danielebarchiesi@0 218 var ul = $('<ul></ul>');
danielebarchiesi@0 219 var ac = this;
danielebarchiesi@0 220 for (key in matches) {
danielebarchiesi@0 221 $('<li></li>')
danielebarchiesi@0 222 .html($('<div></div>').html(matches[key]))
danielebarchiesi@0 223 .mousedown(function () { ac.select(this); })
danielebarchiesi@0 224 .mouseover(function () { ac.highlight(this); })
danielebarchiesi@0 225 .mouseout(function () { ac.unhighlight(this); })
danielebarchiesi@0 226 .data('autocompleteValue', key)
danielebarchiesi@0 227 .appendTo(ul);
danielebarchiesi@0 228 }
danielebarchiesi@0 229
danielebarchiesi@0 230 // Show popup with matches, if any.
danielebarchiesi@0 231 if (this.popup) {
danielebarchiesi@0 232 if (ul.children().length) {
danielebarchiesi@0 233 $(this.popup).empty().append(ul).show();
danielebarchiesi@0 234 $(this.ariaLive).html(Drupal.t('Autocomplete popup'));
danielebarchiesi@0 235 }
danielebarchiesi@0 236 else {
danielebarchiesi@0 237 $(this.popup).css({ visibility: 'hidden' });
danielebarchiesi@0 238 this.hidePopup();
danielebarchiesi@0 239 }
danielebarchiesi@0 240 }
danielebarchiesi@0 241 };
danielebarchiesi@0 242
danielebarchiesi@0 243 Drupal.jsAC.prototype.setStatus = function (status) {
danielebarchiesi@0 244 switch (status) {
danielebarchiesi@0 245 case 'begin':
danielebarchiesi@0 246 $(this.input).addClass('throbbing');
danielebarchiesi@0 247 $(this.ariaLive).html(Drupal.t('Searching for matches...'));
danielebarchiesi@0 248 break;
danielebarchiesi@0 249 case 'cancel':
danielebarchiesi@0 250 case 'error':
danielebarchiesi@0 251 case 'found':
danielebarchiesi@0 252 $(this.input).removeClass('throbbing');
danielebarchiesi@0 253 break;
danielebarchiesi@0 254 }
danielebarchiesi@0 255 };
danielebarchiesi@0 256
danielebarchiesi@0 257 /**
danielebarchiesi@0 258 * An AutoComplete DataBase object.
danielebarchiesi@0 259 */
danielebarchiesi@0 260 Drupal.ACDB = function (uri) {
danielebarchiesi@0 261 this.uri = uri;
danielebarchiesi@0 262 this.delay = 300;
danielebarchiesi@0 263 this.cache = {};
danielebarchiesi@0 264 };
danielebarchiesi@0 265
danielebarchiesi@0 266 /**
danielebarchiesi@0 267 * Performs a cached and delayed search.
danielebarchiesi@0 268 */
danielebarchiesi@0 269 Drupal.ACDB.prototype.search = function (searchString) {
danielebarchiesi@0 270 var db = this;
danielebarchiesi@0 271 this.searchString = searchString;
danielebarchiesi@0 272
danielebarchiesi@0 273 // See if this string needs to be searched for anyway.
danielebarchiesi@0 274 searchString = searchString.replace(/^\s+|\s+$/, '');
danielebarchiesi@0 275 if (searchString.length <= 0 ||
danielebarchiesi@0 276 searchString.charAt(searchString.length - 1) == ',') {
danielebarchiesi@0 277 return;
danielebarchiesi@0 278 }
danielebarchiesi@0 279
danielebarchiesi@0 280 // See if this key has been searched for before.
danielebarchiesi@0 281 if (this.cache[searchString]) {
danielebarchiesi@0 282 return this.owner.found(this.cache[searchString]);
danielebarchiesi@0 283 }
danielebarchiesi@0 284
danielebarchiesi@0 285 // Initiate delayed search.
danielebarchiesi@0 286 if (this.timer) {
danielebarchiesi@0 287 clearTimeout(this.timer);
danielebarchiesi@0 288 }
danielebarchiesi@0 289 this.timer = setTimeout(function () {
danielebarchiesi@0 290 db.owner.setStatus('begin');
danielebarchiesi@0 291
danielebarchiesi@0 292 // Ajax GET request for autocompletion. We use Drupal.encodePath instead of
danielebarchiesi@0 293 // encodeURIComponent to allow autocomplete search terms to contain slashes.
danielebarchiesi@0 294 $.ajax({
danielebarchiesi@0 295 type: 'GET',
danielebarchiesi@0 296 url: db.uri + '/' + Drupal.encodePath(searchString),
danielebarchiesi@0 297 dataType: 'json',
danielebarchiesi@0 298 success: function (matches) {
danielebarchiesi@0 299 if (typeof matches.status == 'undefined' || matches.status != 0) {
danielebarchiesi@0 300 db.cache[searchString] = matches;
danielebarchiesi@0 301 // Verify if these are still the matches the user wants to see.
danielebarchiesi@0 302 if (db.searchString == searchString) {
danielebarchiesi@0 303 db.owner.found(matches);
danielebarchiesi@0 304 }
danielebarchiesi@0 305 db.owner.setStatus('found');
danielebarchiesi@0 306 }
danielebarchiesi@0 307 },
danielebarchiesi@0 308 error: function (xmlhttp) {
danielebarchiesi@0 309 alert(Drupal.ajaxError(xmlhttp, db.uri));
danielebarchiesi@0 310 }
danielebarchiesi@0 311 });
danielebarchiesi@0 312 }, this.delay);
danielebarchiesi@0 313 };
danielebarchiesi@0 314
danielebarchiesi@0 315 /**
danielebarchiesi@0 316 * Cancels the current autocomplete request.
danielebarchiesi@0 317 */
danielebarchiesi@0 318 Drupal.ACDB.prototype.cancel = function () {
danielebarchiesi@0 319 if (this.owner) this.owner.setStatus('cancel');
danielebarchiesi@0 320 if (this.timer) clearTimeout(this.timer);
danielebarchiesi@0 321 this.searchString = '';
danielebarchiesi@0 322 };
danielebarchiesi@0 323
danielebarchiesi@0 324 })(jQuery);