Tengo un contentEditable
div, el innerHTML
del cual se puede actualizar a través de AJAX durante la edición. El problema es que cuando cambias el contenido del div, mueve el cursor al final del div (o pierde el foco dependiendo del navegador). ¿Qué es una buena solución entre navegadores para almacenar la posición de intercalación antes de cambiar innerHTML
y luego restaurarla?Guardar y restaurar la posición de intercalación para contentEditable div
Respuesta
Puede usar Rangy, mi rango de explorador cruzado y la biblioteca de selección. Tiene un selection save and restore module que parece adecuado para sus necesidades.
El enfoque no es complicado: inserta elementos marcadores al principio y al final de cada rango seleccionado y utiliza esos elementos marcadores para restaurar los límites del rango nuevamente más tarde, lo que podría implementarse sin Rangy en poco código (y podría incluso adaptar Rangy's own code). La principal ventaja de Rangy es soporte para IE < = 8.
Sé que esto es un hilo antiguo, pero pensé que iba a proporcionar una solución alternativa no-biblioteca
http://jsfiddle.net/6jbwet9q/9/
Probado en cromo, FF , e IE10 + le permite cambiar, eliminar y restaurar html mientras retiene la posición/selección del cursor.
HTML
<div id=bE contenteditable=true></div>
JS
function saveRangePosition()
{
var range=window.getSelection().getRangeAt(0);
var sC=range.startContainer,eC=range.endContainer;
A=[];while(sC!==bE){A.push(getNodeIndex(sC));sC=sC.parentNode}
B=[];while(eC!==bE){B.push(getNodeIndex(eC));eC=eC.parentNode}
return {"sC":A,"sO":range.startOffset,"eC":B,"eO":range.endOffset};
}
function restoreRangePosition(rp)
{
bE.focus();
var sel=window.getSelection(),range=sel.getRangeAt(0);
var x,C,sC=bE,eC=bE;
C=rp.sC;x=C.length;while(x--)sC=sC.childNodes[C[x]];
C=rp.eC;x=C.length;while(x--)eC=eC.childNodes[C[x]];
range.setStart(sC,rp.sO);
range.setEnd(eC,rp.eO);
sel.removeAllRanges();
sel.addRange(range)
}
function getNodeIndex(n){var i=0;while(n=n.previousSibling)i++;return i}
Parece que se está convirtiendo cada límite de rango de selección en una ruta y viceversa. Este es un gran enfoque siempre que la estructura del DOM sea la misma antes y después de los cambios 'innerHTML', que no se garantiza que sea cierto. –
¿Es posible arreglar este código para varios divs contentibles? Para poder seleccionar, digamos, 1 de 3 div contented, y luego recuperar la posición de donde quiero insertar. – PhyCoMath
de nuevo a 2016 :)
Después me encontré con esta solución, y no me conviene, porque mi DOM reemplazó completamente después de cada tipeo Hago más reasech y vengo con una solución simple que guarda el cursor por la posición del personaje que funciona perfecto para mí.
La idea es muy simple.
- encuentra la longitud de los caracteres antes del cursor y guárdalo.
- cambiar el DOM.
- usando
TreeWalker
caminar justo entext nodes
decontext node
y contando caracteres hasta que llegamos a la derechatext node
y la posición dentro de él
Dos caso extremo:
contenido eliminado por completo lo que no hay
text node
:
so: mover el cursor al inicio del nodo de contextohay menos contenido entonces el
index
señaló en:
así: mueve el cursor hasta el final del último nodo
function saveCaretPosition(context){
var selection = window.getSelection();
var range = selection.getRangeAt(0);
range.setStart( context, 0);
var len = range.toString().length;
return function restore(){
var pos = getTextNodeAtPosition(context, len);
selection.removeAllRanges();
var range = new Range();
range.setStart(pos.node ,pos.position);
selection.addRange(range);
}
}
function getTextNodeAtPosition(root, index){
var lastNode = null;
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT,function next(elem) {
if(index >= elem.textContent.length){
index -= elem.textContent.length;
lastNode = elem;
return NodeFilter.FILTER_REJECT
}
return NodeFilter.FILTER_ACCEPT;
});
var c = treeWalker.nextNode();
return {
node: c? c: root,
position: c? index: 0
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.min.js"></script>
<link href="https://rawgit.com/PrismJS/prism/gh-pages/themes/prism.css" rel="stylesheet"/>
<style>
*{
outline:none
}
</style>
<h3>Edit the CSS Snippet </H3>
<pre>
<code class="language-css" contenteditable=true >p { color: red }</code>
</pre>
<script >
var code = document.getElementsByTagName('code')[0];
code.addEventListener('input',function() {
var restore = saveCaretPosition(this);
Prism.highlightElement(this);
restore();
})
</script>
¿Qué sucede si tiene saltos de línea y otros elementos de formato dentro del elemento editable? –
te refieres como
de ? todavía debería funcionar. ese código se compila para el editor de texto enriquecido que cambia elementos alrededor del cursor cuando el usuario escribe –
Tengo un contenido editable con roturas y tal y funciona. Si lo usa para una función de deshacer, almacene la última pulsación de tecla en un manejador onKeyDown y use 'range.setStart (pos.node, pos.position- (lastKeypress == 13? 0: 1));' para evitar que el cursor se active en un paseo :-) – Tschallacka
- 1. contenteditable texto seleccionado guardar y restaurar
- 2. Establecer la posición de intercalación justo después del elemento insertado en un contentEditable div
- 3. jquery Establecer la posición del cursor en contenteditable div
- 4. Guardar y restaurar la posición y el tamaño del formulario
- 5. Cómo guardar y restaurar la posición de ListView en Android
- 6. editor de texto contentEditable y el cursor de posición
- 7. Ajuste de la posición de intercalación a un nodo vacío dentro de un elemento contentEditable
- 8. ¿Cómo encontrar la posición del cursor en una DIV contenteditable?
- 9. Guardar y restaurar CGContext
- 10. JavaScript 'contenteditable' - obtener/establecer Caret Posición
- 11. Cambiar la posición del cursor en la div contenteditable después de cambiar innerHTML
- 12. ¿Cómo guardar y restaurar un formulario?
- 13. Guardar y restaurar aplicaciones y diseño
- 14. ¿Cómo obtengo la posición actual de intercalación?
- 15. guardar y restaurar variables de shell
- 16. Guardar y restaurar el estado de vim
- 17. Establecer la posición de intercalación en javafx.scene.control.TextArea y javafx.scene.control.TextField
- 18. ContentEditable DIV - deshabilitar la función de arrastrar y soltar
- 19. Guardar y restaurar geometrías en OpenLayers
- 20. Guardar y restaurar ver estado android
- 21. Insertar texto en Javascript contenteditable div
- 22. ¿Es posible crear un script para guardar y restaurar permisos?
- 23. WPF GridSplitter - guardar y restaurar la ubicación AND dividir proporcionalmente
- 24. ¿Obtiene la posición de intercalación en la entrada de HTML?
- 25. Extrayendo texto de un contentEditable div
- 26. contenteditable div no realmente editable en webkit
- 27. ¿Cómo encontrar la posición de intercalación en un NSTextView?
- 28. reemplazar el texto seleccionado en contenteditable div
- 29. posición: absolute, div under div
- 30. ¿Cómo obtener la posición de currículum dentro de div satisfactoria con elementos secundarios html?
fantástico. Tuve cierta inquietud sobre el uso de una biblioteca aleatoria de un tipo en SO, pero hizo lo que quería en 2 líneas de código. ¡Gracias! – thedayturns
@thedayturns: Esa es la actitud correcta para tener, así que no te culpo :) Me alegro de que haya sido útil. –
@TimDown ¿Rangy es compatible con múltiples divs contentos? Al igual, la posición de guardado del cursor sobre tres divs diferentes. Por el hecho de ser, quiero usar 1 editor para 3 campos diferentes. – PhyCoMath