$(function(){
$('textarea').on('keyup',function(evt){
var pos = getCaretCoordinates(this,this.selectionEnd);
$('div.dropdown').css({
'position': 'absolute',
'top': this.offsetTop - this.scrollTop + 15 + pos.top + 'px',
'left': this.offsetLeft - this.scrollLeft + pos.left + 'px'
});
});
});
var properties = [
'boxSizing',
'width',
'height',
'overflowX',
'overflowY',
'borderTopWidth',
'borderRightWidth',
'borderBottomWidth',
'borderLeftWidth',
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'fontStyle',
'fontVariant',
'fontWeight',
'fontStretch',
'fontSize',
'lineHeight',
'fontFamily',
'textAlign',
'textTransform',
'textIndent',
'textDecoration',
'letterSpacing',
'wordSpacing'
];
var isFirefox = !(window.mozInnerScreenX == null);
var mirrorDiv, computed, style;
getCaretCoordinates = function (element, position) {
// clon del textarea en forma de div
mirrorDiv = document.getElementById(element.nodeName + '--mirror-div');
if (!mirrorDiv) {
mirrorDiv = document.createElement('div');
mirrorDiv.id = element.nodeName + '--mirror-div';//TEXTAREA--mirror-div
document.body.appendChild(mirrorDiv);
}
style = mirrorDiv.style;
computed = getComputedStyle(element);//obtenemos las propiedades del textarea
// estilos por default
style.whiteSpace = 'pre-wrap';
style.wordWrap = 'break-word'; // only for textarea-s
// position off-screen
style.position = 'absolute'; // required to return coordinates properly
style.top = element.offsetTop + parseInt(computed.borderTopWidth) + 'px';
style.left = element.offsetLeft + parseInt(computed.borderLeftWidth) + 'px';
style.visibility = 'hidden'; // no necesitamos que sea visible
// transferir las propiedades al div
properties.forEach(function (prop) {
style[prop] = computed[prop];
});
if (isFirefox) {
style.width = parseInt(computed.width) - 2 + 'px'
// Firefox adds 2 pixels to the padding - https://bugzilla.mozilla.org/show_bug.cgi?id=753662
// Firefox lies about the overflow property for textareas: https://bugzilla.mozilla.org/show_bug.cgi?id=984275
if (element.scrollHeight > parseInt(computed.height))
style.overflowY = 'scroll';
} else {
style.overflow = 'hidden';
// for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'
}
mirrorDiv.textContent = element.value.substring(0, position);
if (element.nodeName === 'INPUT')
mirrorDiv.textContent = mirrorDiv.textContent.replace(/\s/g, "\u00a0");
var span = document.createElement('span');
span.textContent = element.value.substring(position) || '.';
// obtenemos los valores del textarea y los escribimos en caso que se encuentre texto por delante dentro del span para obtener la posision exacta
span.style.backgroundColor = "lightgrey";
mirrorDiv.appendChild(span);
var coordinates = {
top: span.offsetTop + parseInt(computed['borderTopWidth']),
left: span.offsetLeft + parseInt(computed['borderLeftWidth'])
};
return coordinates;
}
textarea{
border: 2px solid gray;
height: 100px;
min-width: 100%;
max-width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<textarea></textarea>
<textarea></textarea>
<div class="dropdown open">
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</div>