在CKEditor中将光标设置到特定位置 [英] Set cursor to specific position in CKEditor

查看:4311
本文介绍了在CKEditor中将光标设置到特定位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一种方法可以将光标位置设置为CKEditor中的已知索引?



我想这样做,因为当我更改编辑器内的html重置光标到插入元素的开始,这是一个问题,因为我在用户键入时随时更改内容。



如果我知道我想在编辑器中将光标设置为已知字符位置,例如100,这是否可能?



(我问了一个相关问题,但我)

解决方案

设置选择的基本方法是通过创建 a Range ,设置其位置和选择 :如果您不知道Range API(或者至少是范围之外的想法),您可以使用将无法使用选择。这是一个很好的介绍 - DOM范围规范(是的,它是一个规格,但它是好的)。 CKEditor的Range API 非常相似,但有点大。



例如:

  //在编辑器中有这个HTML:
// < p id =someId1> foo< em id =someId2> bar< / em>。< / p&

var range = editor.createRange();
range.setStart(editor.document.getById('someId1'),0); //< p> ^ foo
range.setEnd(editor.document.getById('someId2').getFirst(),1); //< em> b ^ ar< / em>

editor.getSelection()。selectRanges([range]);

//将选择:
//< p id =someId1> [foo< em id =someId2> b] ar< / em> ; / p>

或其他情况:

  //在编辑器中有此HTML:
//< p> foo bar。< / p&
var range = editor.createRange();
range.moveToElementEditablePosition(editor.aditable(),true); // bar。^< / p>

editor.getSelection()。selectRanges([range]);

//将选择:
//< p> foo bar。^< / p>



更改DOM后还原选择



很多时候你不想选择一个新的范围,而是恢复一个旧的选择或范围。首先,您需要知道的是,如果您进行了不受控制的DOM更改,则无法正确恢复选择。您需要能够跟踪选择的开始和结束的容器和偏移量。



范围保留对其开始和结束容器的引用(在 startContainer endContainer 属性)。不幸的是,此引用可能违反了以下规定:




  • 覆盖 innerHTML

  • 移动DOM节点,

  • 删除DOM节点。



同样可能发生偏移( startOffset endOffset 属性) - 如果你删除一个开始/结束容器的孩子



因此,在某些情况下,当我们想要记住一个选择位置时,范围实例是没有帮助的。



首先,这是我们的计划:


  1. 我们得到当前的选择位置。

  2. 我们存储它(以某种方式)。

  3. / li>
  4. 我们还原选择。

使用范围复数形式,因为Firefox支持多个范围选择 - 一个选择可以包含多个范围(尝试例如在选择时使用CTRL键)。



解决方案1 - 范围



  var ranges = editor.getSelection()。getRanges 

//使DOM更改。

editor.getSelection()。selectRanges(ranges);

这是最简单的解决方案。



解决方案2 - 通过侵入式书签



  var bookmarks = editor.getSelection()。createBookmarks(); 

//使DOM更改。

editor.getSelection()。selectBookmarks(bookmarks);

createBookmarks 方法insert invisible < span>



如果您可以选择一个特殊属性(包括 data-cke-bookmark 避免不受控制的 innerHTML 更改,而是附加/删除/移动一些节点,那么只需记住您必须保留这些< span> 元素和这个方法将工作完美。



默认书签保留对其< span> 元素,但您也可以创建将 true 传递到 createBookmarks 方法的序列化书签。这种类型的书签将通过id保留对节点的引用,因此您可以覆盖整个 innerHTML



注意:方法也可在 Range API 中找到。



这是最流行的方法,因为你有选择的完全控制,你可以更改DOM,虽然你需要照顾书签'跨度



解决方案3 - 通过非侵入性书签



  var bookmarks = editor.getSelection()。createBookmarks2(); 

//使DOM更改。

editor.getSelection()。selectBookmarks(bookmarks);

注意:在此解决方案中,我们使用createBookmarks2 方法。



这里我们还创建一个书签对象数组,但我们不会在DOM中插入任何元素。这些书签通过地址存储它们的位置。 地址是父项中的祖先索引数组。



此解决方案与解决方案1非常相似,但您可以覆盖整个 innerHTML ,因为它(很可能>不改变书签节点的地址。尽管在这种情况下,您应该将 true 传递给 createBookmarks2 以获取规范化地址,因为相邻的文本节点将被加入设置 innerHTML 时会删除空白。



总结...



...使用DOM和选择不是微不足道的。你需要知道你在做什么,你需要知道DOM,你需要为你的问题选择正确的解决方案。最常见的是第二个,但这取决于一个案件。


Is there a way to set the cursor position to a known index inside CKEditor?

I want to do this because when I change the html inside the editor it resets the cursor to the start of the inserted element, which is a problem as I'm changing the content on the fly as the user types.

If I know that I want to set the cursor back to a known character position, say 100, inside the editor, is this possible?

(I asked a related question but I think I was overcomplicating the issue with example code.)

解决方案

The basic way of setting selection is by creating a Range, setting its position and selecting it.

Note: if you don't know the Range API (or at least the idea which stands behind ranges), you won't be able to use selection. Here's a pretty good introduction - DOM Range spec (yep, it is a spec, but it's good). CKEditor's Range API is very similar, but a little bit bigger.

For example:

// Having this HTML in editor:
// <p id="someId1">foo <em id="someId2">bar</em>.</p>

var range = editor.createRange();
range.setStart( editor.document.getById( 'someId1' ), 0 ); // <p>^foo
range.setEnd( editor.document.getById( 'someId2' ).getFirst(), 1 ); // <em>b^ar</em>

editor.getSelection().selectRanges( [ range ] );

// Will select:
// <p id="someId1">[foo <em id="someId2">b]ar</em>.</p>

Or other case:

// Having this HTML in editor:
// <p>foo bar.</p>
var range = editor.createRange();
range.moveToElementEditablePosition( editor.editable(), true ); // bar.^</p>

editor.getSelection().selectRanges( [ range ] );

// Will select:
// <p>foo bar.^</p>

Restoring selection after changing DOM

But very often you don't want to select a new range, but to restore an old selection or range. First thing you need to know is that it is impossible to correctly restore selection if you made an uncontrolled DOM changes. You need to be able to keep track of the containers and offsets of the selection's start and end.

Range keeps the references to its start and end containers (in startContainer and endContainer properties). Unfortunately, this references may be violated by:

  • overwriting innerHTML,
  • moving DOM nodes around,
  • deleting DOM nodes.

The same may happen with offsets (startOffset and endOffset properties) - if you removed one of start/end container's child nodes these offsets may need to be updated.

So in some situations range instance is not helpful when we want to remember a selection position. I'll explain three basic ways to deal with this problem.

First, this is our plan:

  1. We get the current selection position.
  2. We store it (somehow).
  3. We do the DOM changes.
  4. We restore selection.

Note: From now on I use "ranges" in plural form because Firefox supports multiple range selections - one selection can contain more than one range (try e.g. to use CTRL key while making selections).

Solution 1 - by a range

var ranges = editor.getSelection().getRanges();

// Make DOM changes.

editor.getSelection().selectRanges( ranges );

This is the simplest solution. It will work only if the DOM changes which we made haven't outdated ranges or we know how to update them.

Solution 2 - by an intrusive bookmarks

var bookmarks = editor.getSelection().createBookmarks();

// Make DOM changes.

editor.getSelection().selectBookmarks( bookmarks );

Bookmarks created by the createBookmarks method insert invisible <span> elements with special attributes (including data-cke-bookmark) at the selection's ranges start and end points.

If you can avoid uncontrolled innerHTML changes and instead append/remove/move some nodes, then just remember that you have to preserve these <span> elements and this method will work perfectly. You can also move bookmarks' elements if your modifications should change the selection as well.

By default bookmarks keep references to their <span> elements, but you can also create serializable bookmarks passing true to the createBookmarks method. This kind of bookmarks will keep references to nodes by ids, so you can overwrite entire innerHTML.

Note: This method is also available in a Range API.

This is the most popular method, because you have the full control over selection and you can change DOM, although you need to take care of bookmarks' spans.

Solution 3 - by a non intrusive bookmarks

var bookmarks = editor.getSelection().createBookmarks2();

// Make DOM changes.

editor.getSelection().selectBookmarks( bookmarks );

Note: In this solution we use createBookmarks2 method.

Here we also create an array of bookmarks objects, but we do not insert any elements into DOM. These bookmarks store their positions by the addresses. Address is an array of ancestors' indexes in their parents.

This solution is very similar to solution 1, but you can overwrite entire innerHTML, because it (most likely ;>) won't change the addresses of bookmarks' nodes. Although, in such a case you should pass true to createBookmarks2 to get normalized addresses because adjacent text nodes will be joined and empty ones removed when setting innerHTML.

To sum up...

... Working with DOM and selection isn't trivial. You need to know what you're doing, you need to know DOM and you need to pick the right solution for your problem. Most often it will be the second one, but it depends on a case.

这篇关于在CKEditor中将光标设置到特定位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆