在正确的光标位置重新聚焦CKEditor

Refocus CKEditor at correct cursor position

本文关键字:聚焦 CKEditor 新聚焦 光标 位置      更新时间:2023-09-26

我正在构建一个CMS系统,在那里我使用jQuery和CKEditor内联编辑内容。当编辑器被模糊时,用户被要求确认他/她想要放弃编辑。如果选择"否",则应该取消模糊事件,编辑器在不改变光标位置的情况下保持焦点。因为在我看来这是不可能的,我尝试在模糊完成后重新对焦编辑器。下面的代码片段来自blur事件处理程序:

var $this = $(this);
if (confirm('Discard your changes?')) {
    $this.html($this.data('previous'));
} else {
    // Optimally prevent the blur event, but alternatively
    // reintroduce focus at correct position...
    $this.data('editor').focus();
}

请注意,focus调用是在$this.data('editor')中包含的编辑器实例上完成的,但结果似乎与我直接在$this上执行相同。

这个解决方案的问题是,虽然它重新引入了焦点,但光标现在位于文本的开头,这对最终用户来说是非常不直观和烦人的,他们认为什么都没有改变。另一方面,仅仅放弃焦点不是一种选择,因为我不希望用户能够阻止重置内容,然后继续进行其他更改,认为更改是持久化的。

因此,我想要一个解决方案,我可以完全防止模糊,或重新引入光标在它的最后位置。

原生解决方案(通过window.getSelection()...)是不安全的,因为浏览器以不同的方式实现此API或/并存在错误。问题是选择制度、范围和可满足性(一般)的"标准"非常差、模糊和被忽视。CKEditor绕过了这些问题(许多kLOC),并通过自己的API保持了可移植性和可预测性。

所以不要重新发明轮子,继续使用以下代码(在最新的Chrome和IE10中进行了测试):

var editor = CKEDITOR.instances.editor1;
editor.on( 'blur', function() {
    console.log( 'Editor blurred.' );
    var range = editor.getSelection().getRanges()[ 0 ]; // store the selection
    if ( confirm( 'Discard your changes?' ) ) {
        console.log( 'Changes discarded.' );
    } else {
        editor.focus(); // focus the instance again
        range.select(); // restore previous selection
    }   
} );

如果您将此代码与缓存数据检查(editor.getData())混合使用,则可以在没有实际更改时轻松避免confirm():

var editor = CKEDITOR.instances.editor1, cached;
editor.on( 'blur', function() {
    console.log( 'Editor blurred.' );
    var range = editor.getSelection().getRanges()[ 0 ]
    if ( editor.getData() != cached && confirm( 'Discard your changes?' ) ) {
        console.log( 'Changes discarded.' );
    } else {
        editor.once( 'focus', function( event ) { 
           event.cancel();  // cancel the *very next* event, nothing will be cached
        }, null, null, 0 );
        editor.focus();
        range.select();
    }   
} );
editor.on( 'focus', function() {
    console.log( 'Cached editor contents.' );
    cached = editor.getData();
} );

我不确定它是否适用于CKEditor,但与文本区域为例,您可以通过使用

获得当前光标位置:

var cursor = window.getSelection().getRangeAt(0).startOffset;

在这个问题中有一个jQuery函数:光标在文本区的位置(字符索引,而不是x/y坐标)

将光标设置在正确位置与选择文本的特定部分相同,更多信息在这里:使用JavaScript突出显示文本范围

我想它需要一点思考,因为CKEditor很可能会取代文本区