Guest
Public paste!

neofreko

By: a guest | Apr 22nd, 2009 | Syntax: JavaScript | Size: 8.67 KB | Hits: 67 | Expires: Never
Copy text to clipboard
  1. // $Id: autocomplete.js,v 1.17 2007/01/09 07:31:04 drumm Exp $
  2.  
  3. /**
  4.  * Attaches the autocomplete behaviour to all required fields
  5.  */
  6. Drupal.autocompleteAutoAttach = function () {
  7.     var acdb = [];
  8.     $('input.autocomplete').each(function () {
  9.         var uri = this.value;
  10.         if (!acdb[uri]) {
  11.             acdb[uri] = new Drupal.ACDB(uri);
  12.         }
  13.         var input = $('#' + this.id.substr(0, this.id.length - 13))
  14.         .attr('autocomplete', 'OFF')[0];
  15.         $(input.form).submit(Drupal.autocompleteSubmit);
  16.         new Drupal.jsAC(input, acdb[uri]);
  17.     });
  18. }
  19.  
  20. /**
  21.  * Prevents the form from submitting if the suggestions popup is open
  22.  * and closes the suggestions popup when doing so.
  23.  */
  24. Drupal.autocompleteSubmit = function () {
  25.     return $('#autocomplete').each(function () {
  26.         this.owner.hidePopup();
  27.     }).size() == 0;
  28. }
  29.  
  30. /**
  31.  * An AutoComplete object
  32.  */
  33. Drupal.jsAC = function (input, db) {
  34.     var ac = this;
  35.     this.input = input;
  36.     this.db = db;
  37.  
  38.     $(this.input)
  39.     .keydown(function (event) {
  40.         return ac.onkeydown(this, event);
  41.     })
  42.     .keyup(function (event) {
  43.         ac.onkeyup(this, event)
  44.     })
  45.     .blur(function () {
  46.         ac.hidePopup(); ac.db.cancel();
  47.     });
  48.  
  49. };
  50.  
  51. /**
  52.  * Handler for the "keydown" event
  53.  */
  54. Drupal.jsAC.prototype.onkeydown = function (input, e) {
  55.     if (!e) {
  56.         e = window.event;
  57.     }
  58.     switch (e.keyCode) {
  59.         case 40: // down arrow
  60.             this.selectDown();
  61.             return false;
  62.         case 38: // up arrow
  63.             this.selectUp();
  64.             return false;
  65.         default: // all other keys
  66.             return true;
  67.     }
  68. }
  69.  
  70. /**
  71.  * Handler for the "keyup" event
  72.  */
  73. Drupal.jsAC.prototype.onkeyup = function (input, e) {
  74.     if (!e) {
  75.         e = window.event;
  76.     }
  77.     switch (e.keyCode) {
  78.         case 16: // shift
  79.         case 17: // ctrl
  80.         case 18: // alt
  81.         case 20: // caps lock
  82.         case 33: // page up
  83.         case 34: // page down
  84.         case 35: // end
  85.         case 36: // home
  86.         case 37: // left arrow
  87.         case 38: // up arrow
  88.         case 39: // right arrow
  89.         case 40: // down arrow
  90.             return true;
  91.  
  92.         case 9:  // tab
  93.         case 27: // esc
  94.             this.hidePopup(e.keyCode);
  95.             return true;
  96.  
  97.         case 13: // enter
  98.             this.hidePopup(e.keyCode);
  99.             if (input.value.length > 0) {
  100.                 //console.log('ret false');
  101.                 this.db.cancel();
  102.                 this.input.form.submit();
  103.                 return false;
  104.             } else {
  105.                 //console.log('ret true');
  106.                 return true;
  107.             }
  108.  
  109.         default: // all other keys
  110.             if (input.value.length > 0)
  111.                 this.populatePopup();
  112.             else
  113.                 this.hidePopup(e.keyCode);
  114.             return true;
  115.     }
  116. }
  117.  
  118. /**
  119.  * Puts the currently highlighted suggestion into the autocomplete field
  120.  */
  121. Drupal.jsAC.prototype.select = function (node) {
  122.     this.input.value = node.autocompleteValue;
  123. }
  124.  
  125. /**
  126.  * Highlights the next suggestion
  127.  */
  128. Drupal.jsAC.prototype.selectDown = function () {
  129.     if (this.selected && this.selected.nextSibling) {
  130.         this.highlight(this.selected.nextSibling);
  131.     }
  132.     else {
  133.         var lis = $('li', this.popup);
  134.         if (lis.size() > 0) {
  135.             this.highlight(lis.get(0));
  136.         }
  137.     }
  138. }
  139.  
  140. /**
  141.  * Highlights the previous suggestion
  142.  */
  143. Drupal.jsAC.prototype.selectUp = function () {
  144.     if (this.selected && this.selected.previousSibling) {
  145.         this.highlight(this.selected.previousSibling);
  146.     }
  147. }
  148.  
  149. /**
  150.  * Highlights a suggestion
  151.  */
  152. Drupal.jsAC.prototype.highlight = function (node) {
  153.     if (this.selected) {
  154.         $(this.selected).removeClass('selected');
  155.     }
  156.     $(node).addClass('selected');
  157.     this.selected = node;
  158. }
  159.  
  160. /**
  161.  * Unhighlights a suggestion
  162.  */
  163. Drupal.jsAC.prototype.unhighlight = function (node) {
  164.     $(node).removeClass('selected');
  165.     this.selected = false;
  166. }
  167.  
  168. /**
  169.  * Hides the autocomplete suggestions
  170.  */
  171. Drupal.jsAC.prototype.hidePopup = function (keycode) {
  172.     // Select item if the right key or mousebutton was pressed
  173.     if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
  174.         this.input.value = this.selected.autocompleteValue;
  175.     }
  176.     // Hide popup
  177.     var popup = this.popup;
  178.     if (popup) {
  179.         this.popup = null;
  180.         $(popup).fadeOut('fast', function() {
  181.             $(popup).remove();
  182.         });
  183.     }
  184.     this.selected = false;
  185. }
  186.  
  187. /**
  188.  * Positions the suggestions popup and starts a search
  189.  */
  190. Drupal.jsAC.prototype.populatePopup = function () {
  191.     // Show popup
  192.     if (this.popup) {
  193.         $(this.popup).remove();
  194.     }
  195.     this.selected = false;
  196.     this.popup = document.createElement('div');
  197.     this.popup.id = 'autocomplete';
  198.     this.popup.owner = this;
  199.     $(this.popup).css({
  200.         marginTop: this.input.offsetHeight +'px',
  201.         //width: (this.input.offsetWidth - 4) +'px',
  202.         display: 'none'
  203.     });
  204.     $(this.input).before(this.popup);
  205.  
  206.     // Do search
  207.     this.db.owner = this;
  208.     this.db.search(this.input.value);
  209. }
  210.  
  211. /**
  212.  * Fills the suggestion popup with any matches received
  213.  */
  214. Drupal.jsAC.prototype.found = function (matches) {
  215.     // If no value in the textfield, do not show the popup.
  216.     if (!this.input.value.length) {
  217.         return false;
  218.     }
  219.  
  220.     // Prepare matches
  221.     var ul = document.createElement('ul');
  222.     var ac = this;
  223.     for (key in matches) {
  224.         var li = document.createElement('li');
  225.         $(li)
  226.         .html('<div>'+ matches[key] +'</div>')
  227.         .mousedown(function () {
  228.             ac.select(this);
  229.         })
  230.         .mouseover(function () {
  231.             ac.highlight(this);
  232.         })
  233.         .mouseout(function () {
  234.             ac.unhighlight(this);
  235.         });
  236.         li.autocompleteValue = key;
  237.         $(ul).append(li);
  238.     }
  239.  
  240.     // Show popup with matches, if any
  241.     if (this.popup) {
  242.         if (ul.childNodes.length > 0) {
  243.             $(this.popup).empty().append(ul).show();
  244.         }
  245.         else {
  246.             $(this.popup).css({
  247.                 visibility: 'hidden'
  248.             });
  249.             this.hidePopup();
  250.         }
  251.     }
  252. }
  253.  
  254. Drupal.jsAC.prototype.setStatus = function (status) {
  255.     switch (status) {
  256.         case 'begin':
  257.             $(this.input).addClass('throbbing');
  258.             break;
  259.         case 'cancel':
  260.         case 'error':
  261.         case 'found':
  262.             $(this.input).removeClass('throbbing');
  263.             break;
  264.     }
  265.     this.status = status;// will be usefull in xhrcallback
  266. }
  267.  
  268. /**
  269.  * An AutoComplete DataBase object
  270.  */
  271. Drupal.ACDB = function (uri) {
  272.     this.uri = uri;
  273.     this.delay = 300;
  274.     this.cache = {};
  275. }
  276.  
  277. /**
  278.  * Performs a cached and delayed search
  279.  */
  280. Drupal.ACDB.prototype.search = function (searchString) {
  281.     var db = this;
  282.     this.searchString = searchString;
  283.  
  284.     // See if this key has been searched for before
  285.     if (this.cache[searchString]) {
  286.         return this.owner.found(this.cache[searchString]);
  287.     }
  288.  
  289.     // Initiate delayed search
  290.     if (this.timer) {
  291.         clearTimeout(this.timer);
  292.     }
  293.     this.timer = setTimeout(function() {
  294.         db.owner.setStatus('begin');
  295.  
  296.         // Ajax GET request for autocompletion
  297.         $.ajax({
  298.             type: "GET",
  299.             url: db.uri +'/'+ Drupal.encodeURIComponent(searchString),
  300.             success: function (data) {
  301.                 // Parse back result
  302.                 var matches = Drupal.parseJson(data);
  303.                 if (typeof matches['status'] == 'undefined' || matches['status'] != 0) {
  304.                     db.cache[searchString] = matches;
  305.                     // Verify if these are still the matches the user wants to see
  306.                     if (db.searchString == searchString) {
  307.                         db.owner.found(matches);
  308.                     }
  309.                     db.owner.setStatus('found');
  310.                 }
  311.             },
  312.             error: function (xmlhttp) {
  313.                 if (db.owner.status != 'cancel') // supress error when user is canceling the request
  314.                     alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ db.uri);
  315.             }
  316.         });
  317.     }, this.delay);
  318. }
  319.  
  320. /**
  321.  * Cancels the current autocomplete request
  322.  */
  323. Drupal.ACDB.prototype.cancel = function() {
  324.     if (this.owner) this.owner.setStatus('cancel');
  325.     if (this.timer) clearTimeout(this.timer);
  326.     this.searchString = '';
  327. }
  328.  
  329. // Global Killswitch
  330. if (Drupal.jsEnabled) {
  331.     $(document).ready(Drupal.autocompleteAutoAttach);
  332. }