/*
Implement Github like autocomplete mentions
http://ichord.github.com/At.js
Copyright (c) 2013 chord.luo@gmail.com
Licensed under the MIT license.
*/
/*
本插件操作 textarea 或者 input 内的插入符
只实现了获得插入符在文本框中的位置,我设置
插入符的位置.
*/
(function() {
(function(factory) {
if (typeof define === 'function' && define.amd) {
return define(['jquery'], factory);
} else {
return factory(window.jQuery);
}
})(function($) {
"use strict";
var Caret, Mirror, methods, pluginName;
pluginName = 'caret';
Caret = (function() {
function Caret($inputor) {
this.$inputor = $inputor;
this.domInputor = this.$inputor[0];
}
Caret.prototype.getPos = function() {
var end, endRange, inputor, len, normalizedValue, pos, range, start, textInputRange;
inputor = this.domInputor;
inputor.focus();
if (document.selection) {
/*
#assume we select "HATE" in the inputor such as textarea -> { }.
* start end-point.
* /
* < I really [HATE] IE > between the brackets is the selection range.
* \
* end end-point.
*/
range = document.selection.createRange();
pos = 0;
if (range && range.parentElement() === inputor) {
normalizedValue = inputor.value.replace(/\r\n/g, "\n");
/* SOMETIME !!!
"/r/n" is counted as two char.
one line is two, two will be four. balalala.
so we have to using the normalized one's length.;
*/
len = normalizedValue.length;
/*
<[ I really HATE IE ]>:
the whole content in the inputor will be the textInputRange.
*/
textInputRange = inputor.createTextRange();
/* _here must be the position of bookmark.
/
<[ I really [HATE] IE ]>
[---------->[ ] : this is what moveToBookmark do.
< I really [[HATE] IE ]> : here is result.
\ two brackets in should be in line.
*/
textInputRange.moveToBookmark(range.getBookmark());
endRange = inputor.createTextRange();
/* [--------------------->[] : if set false all end-point goto end.
< I really [[HATE] IE []]>
*/
endRange.collapse(false);
/*
___VS____
/ \
< I really [[HATE] IE []]>
\_endRange end-point.
" > -1" mean the start end-point will be the same or right to the end end-point
* simplelly, all in the end.
*/
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
/*
I really |HATE] IE ]>
<-|
I really[ [HATE] IE ]>
<-[
I reall[y [HATE] IE ]>
will return how many unit have moved.
*/
start = -textInputRange.moveStart("character", -len);
end = -textInputRange.moveEnd("character", -len);
}
}
} else {
start = inputor.selectionStart;
}
return start;
};
Caret.prototype.setPos = function(pos) {
var inputor, range;
inputor = this.domInputor;
if (document.selection) {
range = inputor.createTextRange();
range.move("character", pos);
return range.select();
} else {
return inputor.setSelectionRange(pos, pos);
}
};
Caret.prototype.getPosition = function(pos) {
var $inputor, at_rect, format, h, html, mirror, start_range, x, y;
$inputor = this.$inputor;
format = function(value) {
return value.replace(//g, '>').replace(/`/g, '`').replace(/"/g, '"').replace(/\r\n|\r|\n/g, "
");
};
pos = pos || this.getPos();
start_range = $inputor.val().slice(0, pos);
html = "" + format(start_range) + "";
html += "|";
mirror = new Mirror($inputor);
at_rect = mirror.create(html).rect();
x = at_rect.left - $inputor.scrollLeft();
y = at_rect.top - $inputor.scrollTop();
h = at_rect.height;
return {
left: x,
top: y,
height: h
};
};
Caret.prototype.getOffset = function(pos) {
var $inputor, h, offset, position, range, x, y;
$inputor = this.$inputor;
if (document.selection) {
range = this.domInputor.createTextRange();
if (pos) {
range.move('character', pos);
}
x = range.boundingLeft + $inputor.scrollLeft();
y = range.boundingTop + $(window).scrollTop() + $inputor.scrollTop();
h = range.boundingHeight;
} else {
offset = $inputor.offset();
position = this.getPosition(pos);
x = offset.left + position.left;
y = offset.top + position.top;
h = position.height;
}
return {
left: x,
top: y,
height: h
};
};
return Caret;
})();
Mirror = (function() {
Mirror.prototype.css_attr = ["overflowY", "height", "width", "paddingTop", "paddingLeft", "paddingRight", "paddingBottom", "marginTop", "marginLeft", "marginRight", "marginBottom", "fontFamily", "borderStyle", "borderWidth", "wordWrap", "fontSize", "lineHeight", "overflowX", "text-align"];
function Mirror($inputor) {
this.$inputor = $inputor;
}
Mirror.prototype.mirrorCss = function() {
var css,
_this = this;
css = {
position: 'absolute',
left: -9999,
top: 0,
zIndex: -20000,
'white-space': 'pre-wrap'
};
$.each(this.css_attr, function(i, p) {
return css[p] = _this.$inputor.css(p);
});
return css;
};
Mirror.prototype.create = function(html) {
this.$mirror = $('