First, let me describe how you will do it now (January 2018). Please keep in mind that CKEditor 5 is now undergoing a lot of refactoring and everything will change. In the end, I will describe how it will look after the completion of this refactoring. You can skip to a later part if you don't mind waiting another time for the refactoring to come to an end.
EDIT: 1.0.0-beta.1 was released on March 15, so you can skip to the βStarting March 2018β section.
Until March 2018 (up to 1.0.0-alpha.2 )
(If you need to know more about any class API or event, please check out the docs .)
It is best to simply iterate over the entered range.
let data = ''; for ( const child of data.range.getItems() ) { if ( child.is( 'textProxy' ) ) { data += child.data; } }
Note that the TextProxy instance always returns when you iterate over the range, even if the entire range of the Text node is included in the range.
(You can learn more about the structure of the range in CKEditor5 and Angular2 - Getting the exact position of the carriage when clicking inside the editor to capture data .)
Keep in mind that InsertOperation can insert multiple nodes of a different type. Basically, these are just special characters or elements, but more nodes can be provided. Therefore, there is no additional data.item or similar property in data . It may be data.items , but they will be the same as Array.from( data.range.getItems() ) .
Making changes to Document#change
You did not mention what you want to do with this information. Retrieving the contents of a range is easy, but if you want to somehow respond to these changes and change the model, then you need to be careful. When the change event is fired, more changes can be made to the queue. For instance:
- a collaboration service may include several changes at once,
- another function may already have responded to the same change and made changes, which could make the model different.
If you know exactly which feature set you will use, you can simply stick to what I suggested. Just remember that any change you make to the model must be done in the Document#enqueueChanges() block (otherwise it will not be displayed).
If you want to have this solution bulletproof, you probably have to do this:
- While repeating over
data.range children, if you find TextProxy , create a LiveRange covering this node. - Then, in the
enqueueChanges() block, iterate through the saved LiveRange and through their children. - Make your own logic for each instance of
TextProxy found. - Remember
destroy() all LiveRange afterwards.
As you can see, this seems overly complicated. There are some drawbacks to providing an open and flexible structure, such as CKE5, and bearing in mind that all boundary cases are one of them. However, itβs true that it could be easier, so we started refactoring first.
From March 2018 (starting from 1.0.0-beta.1 )
The big change in 1.0.0-beta.1 will be the introduction of the model.Differ class, an updated event structure, and a new API for most of the model.
First of all, Document#event:change will be run after all enqueueChange blocks have enqueueChange . This means that you donβt have to worry about whether another change will change with the change you are responding to in your callback.
In addition, the engine.Document#registerPostFixer() method will be added and you can use it to register callbacks. The change event will be available, but there will be slight differences between the change event and registerPostFixer (we will look at them in the manual and documents).
Secondly, you will have access to an instance of model.Differ , which will save the difference between the state of the model until the first change and the state of the model at the moment when you want to respond to the changes. You will iterate over all the diff elements and check what exactly and where has changed.
In addition, many other changes will be made in refactoring, and a code snippet will be displayed below. So, in the new world, it will look like this:
editor.document.registerPostFixer( writer => { const changes = editor.document.differ.getChanges(); for ( const entry of changes ) { if ( entry.type == 'insert' && entry.name == '$text' ) {
In terms of code, this may be a little more than in the first fragment, but:
- The first fragment was incomplete.
- There are many smaller edge cases in the new approach.
- The new approach is easier to understand - you have all the changes available after everything is done, instead of reacting to the changes when other changes are queued and can go bad with the model.
writer is the object that will be used to make changes to the model (instead of the Document#batch API). It will have methods like insertText() , insertElement() , remove() , etc.
You can check the model.Differ API and tests already, since they are already available on the master branch . (The internal code will change, but the API will remain as it is.)