123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- // 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 (typeof newSubstr !== 'undefined') {
- if ($.isArray(newSubstr)) {
- post = newSubstr[1] + post;
- newSubstr = newSubstr[0];
- }
- pre = pre.replace(strategy.match, newSubstr);
- range.selectNodeContents(range.startContainer);
- range.deleteContents();
-
- // create temporary elements
- var preWrapper = document.createElement("div");
- preWrapper.innerHTML = pre;
- var postWrapper = document.createElement("div");
- postWrapper.innerHTML = post;
-
- // create the fragment thats inserted
- var fragment = document.createDocumentFragment();
- var childNode;
- var lastOfPre;
- while (childNode = preWrapper.firstChild) {
- lastOfPre = fragment.appendChild(childNode);
- }
- while (childNode = postWrapper.firstChild) {
- fragment.appendChild(childNode);
- }
-
- // insert the fragment & jump behind the last node in "pre"
- range.insertNode(fragment);
- range.setStartAfter(lastOfPre);
-
- 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);
|