// NOTE: TextComplete plugin has contenteditable support but it does not work
//       fine especially on old IEs.
//       Any pull requests are REALLY welcome.

+function ($) {
  'use strict';

  // ContentEditable adapter
  // =======================
  //
  // Adapter for contenteditable elements.
  function ContentEditable (element, completer, option) {
    this.initialize(element, completer, option);
  }

  $.extend(ContentEditable.prototype, $.fn.textcomplete.Adapter.prototype, {
    // Public methods
    // --------------

    // Update the content with the given value and strategy.
    // When an dropdown item is selected, it is executed.
    select: function (value, strategy, e) {
      var pre = this.getTextFromHeadToCaret();
      var sel = window.getSelection()
      var range = sel.getRangeAt(0);
      var selection = range.cloneRange();
      selection.selectNodeContents(range.startContainer);
      var content = selection.toString();
      var post = content.substring(range.startOffset);
      var newSubstr = strategy.replace(value, e);
      if ($.isArray(newSubstr)) {
        post = newSubstr[1] + post;
        newSubstr = newSubstr[0];
      }
      pre = pre.replace(strategy.match, newSubstr);
      range.selectNodeContents(range.startContainer);
      range.deleteContents();
      var node = document.createTextNode(pre + post);
      range.insertNode(node);
      range.setStart(node, pre.length);
      range.collapse(true);
      sel.removeAllRanges();
      sel.addRange(range);
    },

    // Private methods
    // ---------------

    // Returns the caret's relative position from the contenteditable's
    // left top corner.
    //
    // Examples
    //
    //   this._getCaretRelativePosition()
    //   //=> { top: 18, left: 200, lineHeight: 16 }
    //
    // Dropdown's position will be decided using the result.
    _getCaretRelativePosition: function () {
      var range = window.getSelection().getRangeAt(0).cloneRange();
      var node = document.createElement('span');
      range.insertNode(node);
      range.selectNodeContents(node);
      range.deleteContents();
      var $node = $(node);
      var position = $node.offset();
      position.left -= this.$el.offset().left;
      position.top += $node.height() - this.$el.offset().top;
      position.lineHeight = $node.height();
      $node.remove();
      return position;
    },

    // Returns the string between the first character and the caret.
    // Completer will be triggered with the result for start autocompleting.
    //
    // Example
    //
    //   // Suppose the html is '<b>hello</b> wor|ld' and | is the caret.
    //   this.getTextFromHeadToCaret()
    //   // => ' wor'  // not '<b>hello</b> wor'
    getTextFromHeadToCaret: function () {
      var range = window.getSelection().getRangeAt(0);
      var selection = range.cloneRange();
      selection.selectNodeContents(range.startContainer);
      return selection.toString().substring(0, range.startOffset);
    }
  });

  $.fn.textcomplete.ContentEditable = ContentEditable;
}(jQuery);

@@ -1057,24 +1057,72 @@
 (value, e);%0A
+      if (typeof newSubstr !== 'undefined') %7B%0A  
       if ($.
@@ -1139,24 +1139,26 @@
 wSubstr)) %7B%0A
+  
         post
@@ -1189,16 +1189,18 @@
         
+  
 newSubst
@@ -1227,16 +1227,18 @@
     
+  
 %7D%0A      
 pre 
@@ -1233,16 +1233,18 @@
 %7D%0A      
+ 
+ 
 pre = pr
@@ -1277,24 +1277,26 @@
 newSubstr);%0A
+  
       range.
@@ -1333,24 +1333,26 @@
 Container);%0A
+  
       range.
@@ -1367,32 +1367,34 @@
 ntents();%0A      
+  
 var node = docum
@@ -1423,32 +1423,34 @@
  + post);%0A      
+  
 range.insertNode
@@ -1455,32 +1455,34 @@
 de(node);%0A      
+ 
+ 
 range.setStart(n
@@ -1501,24 +1501,26 @@
 gth);%0A      
+  
 range.collap
@@ -1525,24 +1525,26 @@
 apse(true);%0A
+  
       sel.re
@@ -1562,24 +1562,26 @@
 es();%0A      
+  
 sel.addRange
@@ -1585,24 +1585,32 @@
 nge(range);%0A
+      %7D%0A
     %7D,%0A%0A    

Update content_editable.js