diff --git editablefields.css editablefields.css
old mode 100644
new mode 100755
index 91a73ba..5fd3bab
--- editablefields.css
+++ editablefields.css
@@ -3,12 +3,24 @@
   padding-right:18px;
 }
 
-div.editablefields_clicktoedit_message { 
+.editablefields .editablefields_clicktoedit_message {
   position: absolute;
-  cursor:pointer;
-  font-size:xx-small;
-  opacity:0.5;
-  display:block;
+  cursor: pointer;
+  font-size: xx-small;
+  opacity: 0.5;
+  /*display: block;*/
   margin-top: -1em;
   z-index: 200;
 }
+
+.editablefields:hover .editablefields_clicktoedit_message {
+  display: inline;
+}
+
+.editablefields_clicktoedit_message:hover {
+  opacity: 1;
+}
+
+.editablefields-hide {
+  display: none;
+}
diff --git editablefields.info editablefields.info
old mode 100644
new mode 100755
index ed4620f..a535273
--- editablefields.info
+++ editablefields.info
@@ -3,6 +3,7 @@ name = Editablefields
 description = "Allows you to make some view fields editable"
 dependencies[] = content
 dependencies[] = ajax_load
+dependencies[] = jquery_update
 package = CCK
 version = "6.x-2.x-dev"
 
diff --git editablefields.js editablefields.js
index 4ef723e..2a2b97a 100755
--- editablefields.js
+++ editablefields.js
@@ -1,44 +1,51 @@
 // $Id: editablefields.js,v 1.1.2.14.2.16 2010/03/26 11:35:22 janvandiepen Exp $
 
+/**
+ * We use event delegation extensively for performance reasons.
+ * $.live() function can achieve the same effect but is not
+ * as efficient as this implementation. This also takes care of any additional DOM
+ * changes that might happen in the page (ie. AJAX, AHAH, etc)
+ *
+ * Further reading about event delegation:
+ *   http://blogs.sitepoint.com/2008/07/23/javascript-event-delegation-is-easier-than-you-think/
+ *   http://developer.yahoo.com/yui/examples/event/event-delegation.html
+ *   http://icant.co.uk/sandbox/eventdelegation/
+ *
+ **/
+
+// @todo: Can only have one active clicktoedit datepicker field.
+// @todo: (related to above todo) clicktoedit datepicker fields load twice after changing date.
 Drupal.behaviors.editablefields = function(context) {
-  $('div.editablefields-html-load', context).not('.clicktoedit').not('.editablefields-processed').each(function() {
-    $(this).addClass('editablefields-processed');
-    Drupal.editablefields.html_init(this);
-  });
-  $('div.editablefields', context).not('.clicktoedit').not('.editablefields-processed').each(function() {
+  // load the ajax-editable fields
+  $('div.editablefields.ajax-editable', context).not('.editablefields-processed').each(function() {
     $(this).addClass('editablefields-processed');
     Drupal.editablefields.load(this);
   });
-  $('div.editablefields', context).filter('.clicktoedit').not('.editablefields-processed').each(function() {
-    var len=$(this).html().length;
-    $(this).prepend(Drupal.settings.editablefields.clicktoedit_message);
-    if (len > 0) {
-      $(".editablefields_clicktoedit_message",this).fadeOut(3000);
-      $(this).mouseover(function() {
-        $(".editablefields_clicktoedit_message",this).fadeIn(500);
-      });
-      $(this).mouseout(function() {
-        $(".editablefields_clicktoedit_message",this).fadeOut(500);
-      });
-    }
-    $(this).click(Drupal.editablefields.init);
-  });
-  $('div.field-label, div.field-label-inline-first, div.field-label-inline, div.field-label-inline-last', context).not('.label-processed').each(function() {
-    $(this).click(function() {
-      $(this).addClass('highlighted');
-      $(this).parent().find('.editablefields').each(function() {
-        $(this).unbind("click",Drupal.editablefields.init);
-        Drupal.editablefields.load(this);
-      });
-      return false;
+
+  // We are not taking 'context' into consideration on purpose here
+  // in order to add event handlers only once per page.
+  if (!$('body').hasClass('editablefields-processed')) {
+    $('body').addClass('editablefields-processed');
+
+    // bind a global document event handler
+    $(document).bind('change click', function(event){
+      if (event.type == 'change') {
+        if ($(event.target).is('input, textarea, select')) {
+          if ($(event.target).parents('.editablefields').not('.ajax-editable').length) {
+            Drupal.editablefields.onchange($(event.target).parents('.editablefields'));
+          }
+        }
+      }
+      else if (event.type == 'click') {
+        if ($(event.target).not('.ajax-editable').is('.editablefields')) {
+          Drupal.editablefields.init.call($(event.target));
+        }
+        else if ($(event.target).parent('.editablefields').not('.ajax-editable').length) {
+          Drupal.editablefields.init.call($(event.target).parent('.editablefields'));
+        }
+      }
     });
-  });
-  $('div.editablefields', context).submit(function() {
-    return false;
-  });
-  $('input', context).not(':hidden').focus();
-  $('select', context).not(':hidden').focus();
-  $('textarea', context).not(':hidden').focus();
+  }
 }
 
 // Initialize settings array.
@@ -48,40 +55,13 @@ Drupal.editablefields = {};
 Drupal.editablefields.checkbox_fix_index = 0;
 
 Drupal.editablefields.init = function() {
-  $(this).unbind("click",Drupal.editablefields.init);
+  $(this).unbind("click");
   $(this).parents('div.field').find('.field-label, .field-label-inline-first, .field-label-inline, .field-label-inline-last').addClass('highlighted');
   $(this).addClass('editablefields-processed');
   $(this).children().hide();
   Drupal.editablefields.load(this);
 }
 
-Drupal.editablefields.html_init = function(element) {
-  if ($(element).hasClass("editablefields_REMOVE") ) {
-    $(element).hide();
-  }
-  else {
-    var uniqNum = Drupal.editablefields.checkbox_fix_index++;
-    $(element).find(':input').each(function() {
-      // Create a unique id field for checkboxes.
-      if ($(this).attr("type") == 'checkbox' || $(this).attr("type") == 'radio') {
-        $(this).attr("id", $(this).attr("id") + '-' + uniqNum);
-        $(this).click(function() {
-          Drupal.editablefields.onchange(this);
-        });
-      } 
-      else {
-        $(this).change(function() {
-          Drupal.editablefields.onchange(this);
-        });
-      }
-    });
-
-    $(element).find(':input').blur(function() {
-      Drupal.editablefields.onblur(this);
-    });
-  }
-}
-
 Drupal.editablefields.view = function(element) {
   if ($(element).hasClass("editablefields_REMOVE") ) {
     $(element).hide();
@@ -102,17 +82,17 @@ Drupal.editablefields.view = function(element) {
         }
         $(element).html(response.content);
         Drupal.attachBehaviors(element);
-        var len=response.content.length;
-        $(element).prepend(Drupal.settings.editablefields.clicktoedit_message);
-        if (len > 0) {
-          $(".editablefields_clicktoedit_message",element).fadeOut(3000);
-          $(element).mouseover(function() {
-            $(".editablefields_clicktoedit_message",this).fadeIn(500);
-          });
-          $(element).mouseout(function() {
-            $(".editablefields_clicktoedit_message",this).fadeOut(500);
-          });
+        var len = response.content.length;
+
+        // there is not way for the server to know which formatter we are using for this field as the view is not
+        // available during this request so we add the message with JS instead.
+        if(len) {
+          $(element).prepend(Drupal.settings.editablefields.clicktoedit_message);
         }
+        else {
+          $(element).prepend(Drupal.settings.editablefields.clicktoedit_message_empty);
+        }
+
         $(element).bind("click",Drupal.editablefields.init);
         $(element).removeClass('editablefields_throbber');
         $(element).removeClass('editablefields-processed');
@@ -142,6 +122,14 @@ Drupal.editablefields.load = function(element) {
       url: url,
       type: 'GET',
       success: function(response) {
+        // If new datePopup settings were added, add our own onClose handler.
+        // We need to do this before calling the returned callbacks.
+        if (response.scripts.setting.datePopup) {
+          for(var id in response.scripts.setting.datePopup) {
+            response.scripts.setting.datePopup[id].settings['onClose'] = Drupal.editablefields.datepickerOnClose;
+          }
+        }
+
         // Call all callbacks.
         if (response.__callbacks) {
           $.each(response.__callbacks, function(i, callback) {
@@ -149,27 +137,44 @@ Drupal.editablefields.load = function(element) {
           });
         }
         $(element).html(response.content);
+
+        var isAjaxEditable = $(element).hasClass('ajax-editable');
+
         Drupal.attachBehaviors(element);
         var uniqNum = Drupal.editablefields.checkbox_fix_index++;
-        $(element).find(':input').each(function() {
+        $(element).find(':input').not(':hidden').each(function() {
+          var $this = $(this);
+
           // Create a unique id field for checkboxes 
-          if ($(this).attr("type") == 'checkbox' || $(this).attr("type") == 'radio') {
-            $(this).attr("id", $(this).attr("id") + '-' + uniqNum);
-            $(this).click(function() {
+          if ($this.attr("type") == 'checkbox' || $this.attr("type") == 'radio') {
+            $this.attr("id", $this.attr("id") + '-' + uniqNum);
+          }
+
+          // attach onChange event only for ajax-editable fields
+          if(isAjaxEditable) {
+            $this.change(function() {
               Drupal.editablefields.onchange(this);
             });
-          } else {
-            $(this).change(function() {
-              Drupal.editablefields.onchange(this);
+          }
+
+          // datepicker fields are handled by the Drupal.editablefields.datepickerOnClose handler
+          //if (!$('[id*="datepicker"]', $this)) {
+            // add blur handler
+            $this.blur(function() {
+              window.setTimeout(function () {
+                Drupal.editablefields.onblur($this)
+              }, 10);
             });
+          //}
+
+          // Autofocus loaded elements. We need a small timeout here.
+          if(!isAjaxEditable) {
+            window.setTimeout(function(){
+              $this.focus();
+            }, 20);
           }
         });
 
-        $(element).find(':input').blur(function() {
-          window.setTimeout(function () {
-            Drupal.editablefields.onblur(this)
-          }, 10);
-        });
         $(element).removeClass('editablefields_throbber');
       },
       error: function(response) {
@@ -250,9 +255,9 @@ Drupal.editablefields.onchange = function(element) {
   return false;
 };
 
-Drupal.editablefields.onblur = function(element) {
+Drupal.editablefields.onblur = function(element, forceClose) {
   // the matrix field should not close when leaving any of its textboxes.
-  if ($(element).parents('table.matrix')) {
+  if (!forceClose && $(element).parents('table.matrix')) {
     return false;
   }
 
@@ -270,3 +275,13 @@ Drupal.editablefields.onblur = function(element) {
 
   return false;
 };
+
+/**
+ * OnClose handler for datepicker fields.
+ * This makes sure that clicktoedit datepicker fields automatically
+ * blur when the datepicker gets closed. Otherwise we will have multiple
+ * datepickers with the same ID on the page.
+ */
+Drupal.editablefields.datepickerOnClose = function(dateText, inst) {
+  Drupal.editablefields.onblur($(this), true);
+}
diff --git editablefields.module editablefields.module
index 6cd34e4..d260255 100755
--- editablefields.module
+++ editablefields.module
@@ -53,6 +53,12 @@ function editablefields_theme() {
       'arguments' => array('element' => NULL),
       'function' => 'theme_editablefields_formatter_editable',
       ),
+    'editablefields_clicktoedit_message' => array(
+      'arguments' => array(),
+      ),
+    'editablefields_clicktoedit_message_empty' => array(
+      'arguments' => array(),
+      ),
     );
 }
 
@@ -91,6 +97,16 @@ function theme_editablefields_formatter_editable($element) {
   if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) {
   }
 
+  // to disable overriding textareas just set this variable to 0
+  if(variable_get('editablefields_textareas_resizable_threshold', 25)) {
+    static $textareas_count = 0;
+    if($field['type'] == 'text' && $field['widget']['type'] == 'text_textarea') {
+      if ($textareas_count++ >= variable_get('editablefields_textareas_resizable_threshold', 25)) {
+        drupal_add_js(drupal_get_path('module', 'editablefields') . '/editablefields_overrides.js');
+      }
+    }
+  }
+
   // See if access to this form element is restricted,
   // if so, skip widget processing and just set the value.
   if (!node_access('update', $node) || !content_access('edit', $field)) {
@@ -114,13 +130,17 @@ function theme_editablefields_formatter_editable($element) {
           'url_html' => url('editablefields_html', array('absolute' => TRUE)),
           'url_submit' => url('editablefields_submit', array('absolute' => TRUE)),
           'url_view' => url('editablefields_view', array('absolute' => TRUE)),
-          'clicktoedit_message' => '<div class="editablefields_clicktoedit_message">'. t('[edit]') .'</div>',
+          'clicktoedit_message' => theme('editablefields_clicktoedit_message'),
+          'clicktoedit_message_empty' => theme('editablefields_clicktoedit_message_empty'),
         );
         drupal_add_js(array('editablefields' => $settings), 'setting');
       }
       $theme = $formatter['module'] . '_formatter_' . $formatter_name;
       $class = "editablefields";
-      if ($element['#formatter'] == 'clicktoedit') {
+      if ($element['#formatter'] == 'editable') {
+        $class .= " ajax-editable";
+      }
+      elseif ($element['#formatter'] == 'clicktoedit') {
         $class .= " clicktoedit";
       }
       elseif ($element['#formatter'] == 'editable_html') {
@@ -139,7 +159,18 @@ function theme_editablefields_formatter_editable($element) {
       $post = '</div>';
 
       if ($element['#formatter'] != 'editable_html') {
-        return $pre . theme($theme, $element) . $post;
+        $themed_element = theme($theme, $element);
+
+        // add the edit link for clicktoedit formatters
+        if ($element['#formatter'] == 'clicktoedit') {
+          if (!empty($themed_element)) {
+            $pre .= theme('editablefields_clicktoedit_message');
+          }
+          else {
+            $pre .= theme('editablefields_clicktoedit_message_empty');
+          }
+        }
+        return $pre . $themed_element . $post;
       }
       else {
         // $node seems to be incomplete, so we reload it
@@ -150,6 +181,14 @@ function theme_editablefields_formatter_editable($element) {
   }
 }
 
+function theme_editablefields_clicktoedit_message() {
+  return '<span class="editablefields_clicktoedit_message editablefields-hide">'. t('[edit]') .'</span>';
+}
+
+function theme_editablefields_clicktoedit_message_empty() {
+  return '<span class="editablefields_clicktoedit_message">'. t('[edit]') .'</span>';
+}
+
 /**
  * Implementation of hook_forms().
  */
diff --git editablefields_overrides.js editablefields_overrides.js
new file mode 100755
index 0000000..5ba8c55
--- /dev/null
+++ editablefields_overrides.js
@@ -0,0 +1,69 @@
+
+/**
+ * This file normally gets included if the number of generated html_edit textareas
+ * exceeds 'editablefields_textareas_resizable_threshold' variable.
+ *
+ * @see theme_editablefields_formatter_editable in editablefields.module
+ */
+
+// Adds the 'grippie' functionality to resizable textareas when the user clicks in them.
+Drupal.behaviors.editablefields_overrides = function(context) {
+  // add this only once per page. We are not taking 'context' into consideration on purpose here.
+  if(!$('body').hasClass('editablefields-overrides-processed')) {
+    $('body').addClass('editablefields-overrides-processed');
+
+    // @todo: find a way to add the same functionality on focus event.
+    $(document).bind('click', function(event){
+      // add textarea handler
+      if ($(event.target).is('textarea.resizable')) {
+        Drupal.editablefields_overrides.textarea($(event.target).parent());
+      }
+    });
+  }
+}
+
+/**
+ * This file is included after misc/textarea.js so this simply overrides the default behavior.
+ */
+Drupal.behaviors.textarea = function(context) {}
+
+// initialize
+Drupal.editablefields_overrides = {};
+
+/**
+ * Clone of Drupal.behaviors.textarea
+ */
+Drupal.editablefields_overrides.textarea = function(context) {
+  $('textarea.resizable:not(.textarea-processed)', context).each(function() {
+    // Avoid non-processed teasers.
+    if ($(this).is(('textarea.teaser:not(.teaser-processed)'))) {
+      return false;
+    }
+    var textarea = $(this).addClass('textarea-processed'), staticOffset = null;
+
+    // When wrapping the text area, work around an IE margin bug.  See:
+    // http://jaspan.com/ie-inherited-margin-bug-form-elements-and-haslayout
+    $(this).wrap('<div class="resizable-textarea"><span></span></div>')
+      .parent().append($('<div class="grippie"></div>').mousedown(startDrag));
+
+    var grippie = $('div.grippie', $(this).parent())[0];
+    grippie.style.marginRight = (grippie.offsetWidth - $(this)[0].offsetWidth) +'px';
+
+    function startDrag(e) {
+      staticOffset = textarea.height() - e.pageY;
+      textarea.css('opacity', 0.25);
+      $(document).mousemove(performDrag).mouseup(endDrag);
+      return false;
+    }
+
+    function performDrag(e) {
+      textarea.height(Math.max(32, staticOffset + e.pageY) + 'px');
+      return false;
+    }
+
+    function endDrag(e) {
+      $(document).unbind("mousemove", performDrag).unbind("mouseup", endDrag);
+      textarea.css('opacity', 1);
+    }
+  });
+};
