[Webkit/Blink] New strategy for Filling Character handling to avoid changes in DOM
— at Version 15
At the moment…
Basic concepts
- FillingChar (FC) is a ZWS text node.
selection.selectRanges()
creates FC in Webkits to put selection in tricky places.
- FC is not welcome in data returned from the editor and Undo Manager snapshots.
- There may be a single FC in the editor at the time. There could be many other ZWSs there as well, as a regular user content.
Lifespan of FC
- FC is removed from DOM as soon as possible, when no longer necessary.
- FC is removed from DOM on
#selectionChange
.
- FC always survives first
#selectionChange
.
- It is removed on the second event because the first one is always fired by
selectRanges()
(so it isn't nuked right after created).
- FC is removed from DOM before (on) certain
#keydown
events (<kbd>ENTER</kbd>, <kbd>LEFT/RIGHT ARROW</kbd>, <kbd>BACKSPACE</kbd>, etc.) to not to disrupt the commands.
FC and data processing
- On
#beforeGetData
and #beforeUndoImage
, if the selection is in the FC text node, a "native bookmark" is created and saved because changes in DOM done in the next point will break the selection.
- On
#beforeGetData
and #beforeUndoImage
, the FC's content (if present) is saved and then replaced in DOM with
- nothing (FC becomes an empty text node)
, if the white–space is right after it
- Data is retrieved from editor DOM (
editor.getData()
), or an undo snapshot is created (CKEDITOR.instances.editor.undoManager.snapshots.map( s => s.contents )
). Both data and snapshots are FC–free.
- On
#getData
and #afterUndoImage
FC's text in DOM is reverted back to the state saved on #beforeGetData
or #beforeUndoImage
.
- On
#getData
and #afterUndoImage
the native selection, devastated on #beforeGetData
or #beforeUndoImage
by changes to FC text content, is finally restored.
Problems
- Because FC is removed from DOM on various data operations:
- A native
#selectionchange
is fired by document
. It creates an infinite loop (#13593) if such listener is to be used in the editor.
- IME (Composition) gets broken when Undo Manager snapshot is taken. This is because FC is removed from DOM and the native selection changes. Try
setInterval( function() { var i = new CKEDITOR.plugins.undo.Image( CKEDITOR.instances.editor ); console.log( i.contents ) }, 2000 );
and start composition.
A new approach
Basic concepts
- When retrieving data or creating Undo Manager snapshots, remove FC from HTML strings, but not from DOM.
- How to tell which ZWSs are user content in HTML string and which belong to FC then?!
- The trick is to use a number of ZWS for FCSeq. Like 7, or 8. Or 42.
- It makes finding FCSeq in the contents much easier. If there are always 7 ZWS for FCSeq, any group of 7 ZWS can be removed and, if there are like 10 ZWS, the algorithm will know that 3 ZWS belong to the user content (still 7 to left to purge).
getData
- Do noting on
#beforeGetData
.
- Remove a pre–defined number of ZWS from HTML string (don't touch the DOM).
getSnapshot
- Remove a pre–defined number of ZWS from HTML string (don't touch the DOM).
SelectionChange, keyboard events
- FCSeq is removed from DOM on
selectionChange
and on keyboard events, just like in the "old approach".
Problem with bookmarks
createBookmark2( true )
is used to create undo snapshots. It normalizes snapshot content so adjacent text nodes are considered a single text node.
- Because FCSeq is removed from HTML string while a snapshot is being taken (previously removed from DOM before the operation), addresses and offsets in the bookmark may be incorrect.
- The bookmarking algorithm must be smart to anticipate that the FCSeq visible in DOM will be gone in the snapshot data.
- Bookmark addresses and offsets must be corrected so when the bookmark is restored, the selection is correctly anchored.
- It is fun!
Pushed branch:t/13816 (previously "zws") with the new approach.