我已经将excellent answer读到了几乎相同的问题。但是,我尝试了@Reinmar推荐的所有技术,但似乎都没有。
情况是我从编辑器中获取当前的HTML并将某些部分包装在 span 标记中。然后我将现在修改的HTML设置回来并尝试恢复用户的光标位置。没有技术可行。
以下是重现此问题的一个非常简单的示例:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="//cdn.ckeditor.com/4.4.7/standard/ckeditor.js"></script>
</head>
<body>
<textarea id="cktest"><p>Sometimes Lorem. Sometime Ipsum. Always dolor.</p></textarea>
<script type="text/javascript">
(function () {
var checkTimeout;
var bookmark;
var storeCursorLocation = function(editor) {
bookmark = editor.getSelection().createBookmarks();
};
var restoreCursorLocation = function(editor) {
editor.getSelection().selectBookmarks(bookmark);
};
var validateText = function(editor) {
storeCursorLocation(editor);
var data = editor.document.getBody().getHtml();
data = data.replace("Lorem", "<span class='err-item'>Lorem</span>");
editor.document.getBody().setHtml(data);
restoreCursorLocation(editor);
};
CKEDITOR.replace('cktest', {
on: {
'instanceReady': function(evt) {
},
'key' : function(evt) {
clearTimeout(checkTimeout);
checkTimeout = setTimeout(function () {
validateText(evt.editor);
}, 1000);
}
}
});
})();
</script>
</body>
</html>
当用户按下某个键时,此代码启动一个计时器,然后在他们停止按键进行检查后等待1秒钟。
将其复制到新的.html文件并在您喜欢的浏览器中运行(我使用的是Chrome)。
当CKEditor加载时,使用鼠标将光标放在文本中间的某个位置。然后按CTRL键并等待1秒钟。您将看到光标跳回文本的开头。
此代码示例使用
editor.getSelection().createBookmarks();
创建书签。但我也尝试过:
editor.getSelection().createBookmarks(true);
和
editor.getSelection().createBookmarks2();
我还尝试使用
保存范围var ranges = editor.getSelection().getRanges();
和
editor.getSelection().selectRanges(ranges);
答案 0 :(得分:5)
(function () {
var checkTimeout;
var bookmark;
var storeCursorLocation = function( editor ) {
bookmark = editor.getSelection().createBookmarks( true );
};
var restoreCursorLocation = function( editor ) {
//editor.focus();
editor.getSelection().selectBookmarks( bookmark );
};
var validateText = function( editor ) {
storeCursorLocation( editor );
var data = editor.document.getBody().getHtml();
data = data.replace( "spaceflight", "<span class='err-item'>spaceflight</span>" );
editor.document.getBody().setHtml( data );
restoreCursorLocation( editor );
//fire this event after DOM changes if working with widgets
//editor.fire( 'contentDomInvalidated' );
};
var editor = CKEDITOR.replace( 'editor1', {
extraAllowedContent : 'span(err-item)',
on: {
"pluginsLoaded" : function( event ){
editor.on( 'contentDom', function() {
var editable = editor.editable();
editable.attachListener( editable, 'keyup', function( e ) {
clearTimeout( checkTimeout );
checkTimeout = setTimeout(function () {
validateText( editor );
}, 100 );
});
});
}
}
});
})();
我检查了你的代码,做了一些修正,上面似乎工作正常。我知道你说过你已经尝试了但是对我来说createBookmarks(true)
已经做到了。
说明和注释:
createBookmarks(true)
将唯一范围插入HTML。此类书签不受您在DOM中所做更改的影响(当然有限制,例如您的自定义更改会删除书签)。 getBody().getHtml()
和getBody().setHTML()
非常聪明。如果您使用过editor.getData()
,则会删除代表书签的空跨度。
但请注意,此类方法可能会破坏小部件,因此需要在发生此类更改后触发contentDomInvalidated
事件。答案 1 :(得分:1)
在https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
中设置innerHtml时检查默认行为删除所有元素的子元素,解析内容字符串并将结果节点指定为元素的子元素
CKEDITOR中的书签是隐藏的span元素,设置innerHtml将删除所有这些元素。
无论如何,解决方案非常简单。
将storeCursorLocation函数更改为此
var storeCursorLocation = function(editor) {
bookmark = editor.getSelection().createBookmarks(true);
};
当您将true作为参数传递时,它将使用id作为引用而不是存储DOM元素,以便您可以在innerHtml更改后恢复。
<强> {编辑} 强>
从@Reinmar阅读解决方案2 他说
如果你可以避免不受控制的innerHTML更改,而是追加/删除/移动一些节点,那么请记住你必须保留这些元素,这个方法将完美地工作。您还可以移动书签&#39;元素,如果你的修改也应该改变选择。
如果你不能替换元素innerHtml的内容,你就是这样做的。
此解决方案效率较低,但可能在某些情况下有效
将validateText函数更改为此。
var validateText = function(editor) {
storeCursorLocation(editor);
var parent = editor.document.getBody().$.firstChild,
nodes = parent.childNodes,
nodeText,
words,
index = 0,
current,
newElement;
while (index < nodes.length) {
current = nodes[index];
nodeText = current.nodeValue;
if (current.nodeType === Node.TEXT_NODE && nodeText.indexOf('Lorem') !== -1) {
words = nodeText.split('Lorem');
newElement = document.createTextNode(words[0]);
parent.insertBefore(newElement, current);
newElement = document.createTextNode(words[1]);
parent.insertBefore(newElement, current.nextSibling);
newElement = document.createElement('span')
newElement.className = 'err-item';
newElement.innerHTML = 'Lorem';
parent.replaceChild(newElement, current);
break;
}
index++;
}
restoreCursorLocation(editor);
};
基本上我遍历chkeditor主体中第一个p的节点,只替换包含Lorem的文本类型的节点,并将剩余的文本作为文本元素添加到前后。如果你像你一样替换整个文本,它将从DOM中删除书签,所以当你试图恢复它们时,它们不存在。