Esta solução funciona em todos os principais navegadores:
saveSelection()
é anexado ao onmouseup
e onkeyup
eventos da div e salva a seleção para a variável savedRange
.
restoreSelection()
é anexado ao onfocus
evento da div e seleciona novamente a seleção salva em savedRange
.
Isso funciona perfeitamente, a menos que você queira que a seleção seja restaurada quando o usuário clicar na div também (o que é um pouco pouco intuitivo, pois normalmente você espera que o cursor vá para onde você clica, mas o código está incluso)
Para conseguir isso, os eventos onclick
e onmousedown
são cancelados pela função cancelEvent()
que é uma função de navegador cruzado para cancelar o evento. A cancelEvent()
função também executa a restoreSelection()
função porque, como o evento click é cancelado, a div não recebe foco e, portanto, nada é selecionado, a menos que essas funções sejam executadas.
A variável isInFocus
armazena se está em foco e é alterada para "false" onblur
e "true" onfocus
. Isso permite que os eventos de clique sejam cancelados apenas se a div não estiver em foco (caso contrário, você não poderá alterar a seleção).
Se você deseja a seleção para ser a mudança quando o div é focado através de um clique, e não restaurar a seleção onclick
(e somente quando o foco é dado ao elemento programtically usando document.getElementById("area").focus();
ou similar, então simplesmente remover os onclick
e onmousedown
eventos. O onblur
evento eo onDivBlur()
e cancelEvent()
funções também pode ser removido com segurança nessas circunstâncias.
Esse código deve funcionar se cair diretamente no corpo de uma página html, se você quiser testá-lo rapidamente:
<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
trabalhava em navegadores não-IE o_o