-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Keep all elements in the document
a.k.a. One API to rule them all
#4009
Comments
How does this solve an issue of the possibility to have How does this solve an issue of needing to use model writer? All algorithms from the model writer would have to be moved to other place anyway (I wouldn't be surprised if that was the place from which we extracted them in the first place). Not to mention that this does not have an impact on view writer. How does this solve overcomplicated API? To me it looks like you want to simplify API by merging some methods together. We don't have overcomplicated API as long as we expose only the highest level to ther user. All that user needs to know now is:
I don't see how those changes present a simpler API to the user. We will still have all the things that you mentioned no matter if we do the change that you described. What I think is that:
So this is my take on the issue. Should we do it? What I see here is that @oskarwrobel had a problem with "view stamps" to markers conversion and you really wanted a possibility to make it easier to create |
I will sum up my post again because I was changing my mind a bit when writing a post and now after talking with @pjasiun. I agree with (real) problems stated in the original post:
I just think that:
|
When we will have just one API we could go further with changes:
Then we will have only one public API. We could make it nicer. I think that we could even inject it to object so, instead of But hey! We can do more. Usually, you add changes the recent So, with all of these change, everything what developer will need to do will be: document.newBatch(); // to start a new undo step
const pElement = document.createElement( 'p' );
divElement.appendChildren( pElement );
pElement.setAttribute( 'foo', true ); To improve performance |
Don't get me wrong. I really like to current API, it's very nice... for us. It does exactly what methods say and there is the 1-1 relation between architecture and the API, no magic. But then, I imagine that someone asks on the StackOverflow: "How I can insert a child element in the CKEditor5?" And what we need to say now is: "It depends. Do you want to modify an element which is added to the document or not? If it's added you need to use Batch API, if not you need to use model writer. But remember that in the second case you can not use markers, LivePositions and liveRanges." After proposed changes, we will be able to simply say: "Use |
I just got the question from @oskarwrobel:
If the experienced CKEditor 5 core developer needs to ask such question I can only imagine how confusion it will be for the community. |
One more advantage of such change would be a separate |
Interesting. This would help with https://github.com/ckeditor/ckeditor5-list/issues/54 I presume. |
Once again we came to the conclusion that this refactoring is needed. By hiding methods like |
One of the things which we need to fix here is that it should be possible to implement most of the simple features without importing anything from the engine. The goal is to unblock implementing features for existing builds. See e.g.: #555 (comment) So, we should have |
This will also allow us to import certain build from CDN in tools like JSFiddle. Then we will be able to prototype features and examples to community questions in a convenient way. |
I've been again thinking today about the problems with creating instances of various classes and our use of the I see this topic as one of the most important issues with the engine (and the whole architecture) right now. It repeats in things like commands and UI, but is most serious here. |
Notes from today's meeting:
|
After reviewing methods we have now on all API levels, I believe that this should be the set of methods we should expose: batch.createText( text, attributes );
batch.createElement( name, attributes );
batch.createDocumentFragment();
batch.insert( item, itemOrPosition, offset );
batch.insertText( text, attributes, itemOrPosition, offset );
batch.insertElement( name, attributes, itemOrPosition, offset );
batch.move( range, targetPosition, offset );
batch.append( item, parent );
batch.appendText( text, attributes, parent );
batch.appendElement( name, attributes, parent );
batch.remove( itemOrRange );
batch.rename( element, newName );
batch.setAttribute( itemOrRange, key, value );
batch.setAttributes( itemOrRange, attributes );
batch.removeAttribute( itemOrRange, key );
batch.clearAttributes( itemOrRange );
batch.setMarker( markerOrName, itemOrRange );
batch.removeMarker( markerOrName );
batch.split( position );
batch.merge( position );
batch.wrap( range, elementOrString );
batch.unwrap( element ); Pair We should remove Batch methods should be smart and useful, instead of being deltas contractors like they are now. The good example is current Note that in the new approach:
Note that it is more efficient to use Document fragment will be now inherited from the element. It will be a special type of an element with no attribute,
Methods to remove from the public API (make them protected mostly): node.setAttribute
node.setAttributesTo
node.removeAttribute
node.clearAttributes
element.clone
element.appendChildren
element.insertChildren
element.removeChildren
text.clone
text.data (setter) |
In fact, we should change the |
We realized that assumption that all created element will land in the document finally and we can already create them in the document (in At the same time, we agreed that operations can be used to modify any model structure, it does not need to be a part of the document. This is why:
|
If we want to keep document read-only, we should also make |
Also, all operations need to have Changes on detached roots which are not document roots (graveyard or editing roots) should not increase version nor be added to the history. |
Also, since document.createText( text, attributes );
document.createElement( name, attributes );
document.createDocumentFragment();
document.createRoot( [ elementName ], [ rootName ] ); //as it is now Later, they will most probably land in the |
Close via ckeditor/ckeditor5-engine#1203. Details will be handled in follow-ups. |
tl;dr: Newly created elements should be immediately added to the special root in the document to handle them the same way as we handle inserted elements.
I was thinking about it before the weekend and I still think it is a good idea, so I'm reporting it.
Problem
The idea arises reading an article about the flux architecture, where model changes only by the one change entry point. For sure, we are far from flux, but the engine has a similar concept: only operations/deltas, change model. Right? Well... not exactly. During the view to model conversion, we build a big part of the model without operations and then insert it into the model using one insert operation.
This is why we have overcomplicated API of inserting, with:
element.insertChildren()
,batch.insertChildren()
which should be used if element is in the model,writer.insertChildren()
which should be used in conversion,InsertOperation
with no real use-case for the end user.See https://github.com/ckeditor/ckeditor5-engine/issues/678, https://github.com/ckeditor/ckeditor5-engine/issues/738.
Also, recently working with @oskarwrobel on ckeditor/ckeditor5-engine#845 we realized that
DocumentFragment
(detached from theDocument
) can't contain markers collection, because makers are based onLiveRanges
,LiveRanges
needschange
event to work and thechange
event is based onDeltas
andOperations
, but to modify document fragment you use writer, not batches. It also means that you can not create aLiveRange
on the detached document fragment.Now it's clear, but it was not obvious for me nor for @scofalik. Considering that we created this code, I can only imagine how complex it would be for others. And note that we are not talking about some low-level API, but about inserting children into an element and creating ranges.
Solution
The solution would be to insert everything into the document immediately after creating an element. Even now we have
$graveyard
where we move removed elements. We could put there, or to the similar root, any element (created, but not yet attached to the real parent).You would create elements in the very similar way as in DOM, using:
document.createElement
. Then the batch/deltas API would be the only proper way to insert element. We could hide other methods and tell all users to use one, high-level API for the tree modifications.It means also that markers and live ranges will work on every document fragment, what is nice.
Disadvantages
There are few.
First, we need 1 more (move) operation every time we add an element to the tree. We could make an exception for text nodes, allowing inserting texts directly into the tree as children, passing a string as a child.
Second, the compression during upload will be most probably less efficient, if we will send every insertion separately, but if it will be a problem we may not sync elements in the special root with new element because they will not be shared between users anyway. It might be tricky, but possible if needed.
Finally, garbage collection of these elements will be more tricky than for not attached elements, but:
Summary
To sum up, I think that, event if the mechanism will be more complicated, it worth to have one mechanism, one API and all tree modifications working the same way, does not matter if an element is in the document or not.
The text was updated successfully, but these errors were encountered: