Esta solución funciona en todos los principales navegadores:
saveSelection()
se adjunta a los eventos onmouseup
y onkeyup
del div y guarda la selección en la variable savedRange
.
restoreSelection()
se adjunta al onfocus
evento del div y vuelve a seleccionar la selección guardada en savedRange
.
Esto funciona perfectamente a menos que desee que se restaure la selección cuando el usuario hace clic en el div también (lo cual es un poco poco intuitivo, ya que normalmente espera que el cursor vaya donde hace clic, pero el código está incluido para completar)
Para lograr esto, los eventos onclick
y onmousedown
son cancelados por la función cancelEvent()
que es una función de navegador cruzado para cancelar el evento. La cancelEvent()
función también ejecuta la restoreSelection()
función porque a medida que se cancela el evento de clic, el div no recibe el foco y, por lo tanto, no se selecciona nada a menos que se ejecute esta función.
La variable isInFocus
almacena si está enfocada y se cambia a "falso" onblur
y "verdadero" onfocus
. Esto permite que los eventos de clic se cancelen solo si el div no está enfocado (de lo contrario, no podría cambiar la selección).
Si desea que la selección se cambie cuando el div se enfoca con un clic y no se restaura la selección onclick
(y solo cuando se le da foco al elemento mediante programación document.getElementById("area").focus();
o similar, simplemente elimine los eventos onclick
y onmousedown
. El onblur
evento y las funciones onDivBlur()
y cancelEvent()
También se puede eliminar de forma segura en estas circunstancias.
Este código debería funcionar si se deja caer directamente en el cuerpo de una página html si desea probarlo rápidamente:
<div id="area" style="width:300px;height:300px;" onblur="onDivBlur();" onmousedown="return cancelEvent(event);" onclick="return cancelEvent(event);" contentEditable="true" onmouseup="saveSelection();" onkeyup="saveSelection();" onfocus="restoreSelection();"></div>
<script type="text/javascript">
var savedRange,isInFocus;
function saveSelection()
{
if(window.getSelection)//non IE Browsers
{
savedRange = window.getSelection().getRangeAt(0);
}
else if(document.selection)//IE
{
savedRange = document.selection.createRange();
}
}
function restoreSelection()
{
isInFocus = true;
document.getElementById("area").focus();
if (savedRange != null) {
if (window.getSelection)//non IE and there is already a selection
{
var s = window.getSelection();
if (s.rangeCount > 0)
s.removeAllRanges();
s.addRange(savedRange);
}
else if (document.createRange)//non IE and no selection
{
window.getSelection().addRange(savedRange);
}
else if (document.selection)//IE
{
savedRange.select();
}
}
}
//this part onwards is only needed if you want to restore selection onclick
var isInFocus = false;
function onDivBlur()
{
isInFocus = false;
}
function cancelEvent(e)
{
if (isInFocus == false && savedRange != null) {
if (e && e.preventDefault) {
//alert("FF");
e.stopPropagation(); // DOM style (return false doesn't always work in FF)
e.preventDefault();
}
else {
window.event.cancelBubble = true;//IE stopPropagation
}
restoreSelection();
return false; // false = IE style
}
}
</script>
contentEditable
trabajaba en los navegadores no-IE O_O