Ответ 1
вернуться к 2016 году :)
После того, как я наткнулся на это решение, оно мне не подошло, потому что мой DOM заменялся полностью после каждой печати. Я провел больше исследований и пришел с простым решением, которое сохраняет курсор за положением символа, которое идеально подходит для меня.
Идея очень проста.
- найдите длину символов перед кареткой и сохраните ее.
- изменить DOM.
- использование
TreeWalker
дляTreeWalker
толькоtext nodes
context node
и подсчета символов до тех пор, пока мы не получим правильныйtext node
и положение внутри него
Два крайних случая:
-
содержимое полностью удалено, поэтому
text node
:
итак: переместить курсор в начало узла контекста -
там меньше контента, чем указано в
index
:
итак: переместить курсор в конец последнего узла
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>