home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / CMS / drupal-6.0.exe / drupal-6.0 / misc / autocomplete.js < prev    next >
Encoding:
JavaScript  |  2008-01-04  |  7.0 KB  |  299 lines

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