137 lines
3.5 KiB
JavaScript
137 lines
3.5 KiB
JavaScript
// http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea
|
|
var clone, getCaret;
|
|
getCaret = function(el) {
|
|
var r, rc, re;
|
|
if (el.selectionStart) {
|
|
return el.selectionStart;
|
|
} else if (document.selection) {
|
|
el.focus();
|
|
r = document.selection.createRange();
|
|
if (!r) return 0;
|
|
re = el.createTextRange();
|
|
rc = re.duplicate();
|
|
re.moveToBookmark(r.getBookmark());
|
|
rc.setEndPoint("EndToStart", re);
|
|
return rc.text.length;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
clone = null;
|
|
|
|
$.fn.caret = function(){
|
|
return getCaret(this[0]);
|
|
};
|
|
|
|
/**
|
|
This is a jQuery plugin to retrieve the caret position in a textarea
|
|
|
|
@module $.fn.caretPosition
|
|
**/
|
|
$.fn.caretPosition = function(options) {
|
|
var after, before, getStyles, guard, html, important, insertSpaceAfterBefore, letter, makeCursor, p, pPos, pos, span, styles, textarea, val;
|
|
if (clone) {
|
|
clone.remove();
|
|
}
|
|
span = $("#pos span");
|
|
textarea = $(this);
|
|
|
|
getStyles = function(el) {
|
|
if (el.currentStyle) {
|
|
return el.currentStyle;
|
|
} else {
|
|
return document.defaultView.getComputedStyle(el, "");
|
|
}
|
|
};
|
|
|
|
styles = getStyles(textarea[0]);
|
|
clone = $("<div><p></p></div>").appendTo("body");
|
|
p = clone.find("p");
|
|
clone.width(textarea.width());
|
|
clone.height(textarea.height());
|
|
|
|
important = function(prop) {
|
|
return styles.getPropertyValue(prop);
|
|
};
|
|
|
|
clone.css({
|
|
border: "1px solid black",
|
|
padding: important("padding"),
|
|
resize: important("resize"),
|
|
"max-height": textarea.height() + "px",
|
|
"overflow-y": "auto",
|
|
"word-wrap": "break-word",
|
|
position: "absolute",
|
|
left: "-7000px"
|
|
});
|
|
|
|
p.css({
|
|
margin: 0,
|
|
padding: 0,
|
|
"word-wrap": "break-word",
|
|
"letter-spacing": important("letter-spacing"),
|
|
"font-family": important("font-family"),
|
|
"font-size": important("font-size"),
|
|
"line-height": important("line-height")
|
|
});
|
|
|
|
pos = options && (options.pos || options.pos === 0) ? options.pos : getCaret(textarea[0]);
|
|
val = textarea.val().replace("\r", "");
|
|
if (options && options.key) {
|
|
val = val.substring(0, pos) + options.key + val.substring(pos);
|
|
}
|
|
before = pos - 1;
|
|
after = pos;
|
|
insertSpaceAfterBefore = false;
|
|
|
|
// if before and after are \n insert a space
|
|
if (val[before] === "\n" && val[after] === "\n") {
|
|
insertSpaceAfterBefore = true;
|
|
}
|
|
|
|
guard = function(v) {
|
|
var buf;
|
|
buf = v.replace(/</g, "<");
|
|
buf = buf.replace(/>/g, ">");
|
|
buf = buf.replace(/[ ]/g, "​ ​");
|
|
return buf.replace(/\n/g, "<br />");
|
|
};
|
|
|
|
makeCursor = function(pos, klass, color) {
|
|
var l;
|
|
l = val.substring(pos, pos + 1);
|
|
if (l === "\n") return "<br>";
|
|
return "<span class='" + klass + "' style='background-color:" + color + "; margin:0; padding: 0'>" + guard(l) + "</span>";
|
|
};
|
|
|
|
html = "";
|
|
if (before >= 0) {
|
|
html += guard(val.substring(0, pos - 1)) + makeCursor(before, "before", "#d0ffff");
|
|
if (insertSpaceAfterBefore) {
|
|
html += makeCursor(0, "post-before", "#d0ffff");
|
|
}
|
|
}
|
|
|
|
if (after >= 0) {
|
|
html += makeCursor(after, "after", "#ffd0ff");
|
|
if (after - 1 < val.length) {
|
|
html += guard(val.substring(after + 1));
|
|
}
|
|
}
|
|
|
|
p.html(html);
|
|
clone.scrollTop(textarea.scrollTop());
|
|
letter = p.find("span:first");
|
|
pos = letter.offset();
|
|
if (letter.hasClass("before")) {
|
|
pos.left = pos.left + letter.width();
|
|
}
|
|
|
|
pPos = p.offset();
|
|
return {
|
|
left: pos.left - pPos.left,
|
|
top: (pos.top - pPos.top) - clone.scrollTop()
|
|
};
|
|
|
|
};
|