Advertisement
Guest User

Untitled

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