How about appending a span element to the cloning div and setting the fake cursor based on this span's offsets? I have updated your fiddle here. Also here's the JS bit only
// http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea
var map = [];
var pan = '<span>|</span>'
//found @ http://davidwalsh.name/detect-scrollbar-width
function getScrollbarWidth() {
var scrollDiv = document.createElement("div");
scrollDiv.className = "scrollbar-measure";
document.body.appendChild(scrollDiv);
// Get the scrollbar width
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
// Delete the DIV
document.body.removeChild(scrollDiv);
return scrollbarWidth;
}
function getCaret(el) {
if (el.selectionStart) {
return el.selectionStart;
} else if (document.selection) {
el.focus();
var r = document.selection.createRange();
if (r == null) {
return 0;
}
var re = el.createTextRange(),
rc = re.duplicate();
re.moveToBookmark(r.getBookmark());
rc.setEndPoint('EndToStart', re);
return rc.text.length;
}
return 0;
}
$(function() {
var span = $('#pos span');
var textarea = $('textarea');
var note = $('#note');
css = getComputedStyle(document.getElementById('textarea'));
try {
for (i in css) note.css(css[i]) && (css[i] != 'width' && css[i] != 'height') && note.css(css[i], css.getPropertyValue(css[i]));
} catch (e) {}
note.css('max-width', '300px');
document.getElementById('note').style.visibility = 'hidden';
var height = note.height();
var fakeCursor, hidePrompt;
textarea.on('keyup click', function(e) {
if (document.getElementById('textarea').scrollHeight > 100) {
note.css('max-width', 300 - getScrollbarWidth());
}
var pos = getCaret(textarea[0]);
note.text(textarea.val().substring(0, pos));
$(pan).appendTo(note);
span.text(pos);
if (hidePrompt) {
hidePrompt.remove();
}
if (fakeCursor) {
fakeCursor.remove();
}
fakeCursor = $("<div style='width:5px;height:30px;background-color: #777;position: absolute;z-index:10000'> </div>");
fakeCursor.css('opacity', 0.5);
fakeCursor.css('left', $('#note span').offset().left + 'px');
fakeCursor.css('top', textarea.offset().top + note.height() - (30 + textarea.scrollTop()) + 'px');
hidePrompt = fakeCursor.clone();
hidePrompt.css({
'width': '2px',
'background-color': 'white',
'z-index': '1000',
'opacity': '1'
});
hidePrompt.appendTo(textarea.parent());
fakeCursor.appendTo(textarea.parent());
return true;
});
});
UPDATE: I can see that there's an error if the first line contains no hard line-breaks but if it does it seems to work well.