Rethink two-step caret movement #4341
Labels
package:engine
resolution:expired
This issue was closed due to lack of feedback.
status:discussion
status:stale
type:improvement
This issue reports a possible enhancement of an existing feature.
This is a follow-up after the PR with improvements to two-step caret movement, which unfortunately left code complicated and a little hacked. I think that at this point we all agree that we need to return to this subject and maybe start from scratch. I am repasting my post from the PR ckeditor/ckeditor5-engine#1406.
Proposal
Personally, I think that we might be better dropping "override/restore" gravity as it brings a lot of complications. Dropping this solution and managing attributes directly through writer API may simplify this feature. Additionally, we will get rid of weird situations, where gravity overriding might do more than we'd like to, for example:
<$text linkHref="foo.html">foo{}</$text><$text bold="true">bar</$text>
If we override gravity to the ride, we start typing bold. Is it correct? Maybe - I am not saying it is not. But it is more mess and potential problems.
This feature seems like it shouldn't really be that difficult, though I guess that we made it too complicated by using wrong tool (gravity) to approach it.
Finally, even though we use selection gravity, we still use writer API to directly add or remove attributes from the selection anyway!
I have a feeling that there are just three things that should be taken into consideration:
Which leads to those three scenarios:
How would it work for different cases?
Between attributes:
<$text attribute="1">fo{}o</$text><$text attribute="2">bar</$text>
-> not leaving or entering
<$text attribute="1">foo{}</$text><$text attribute="2">bar</$text>
-> has attribute + is leaving, remove attribute, prevent caret move
<$text attribute="1">foo</$text>{}<$text attribute="2">bar</$text>
-> does not have attribute + is entering, add attribute, prevent caret move
<$text attribute="1">foo</$text><$text attribute="2">{}bar</$text>
-> not leaving or entering
<$text attribute="1">foo</$text><$text attribute="2">b{}ar</$text>
<- not leaving or entering
<$text attribute="1">foo</$text><$text attribute="2">{}bar</$text>
<- has attribute + is leaving, remove attribute, prevent caret move
<$text attribute="1">foo</$text>{}<$text attribute="2">bar</$text>
<- does not have attribute + is entering, add attribute, prevent caret move
<$text attribute="1">foo{}</$text><$text attribute="2">bar</$text>
<- not leaving or entering
<$text attribute="1">fo{}o</$text><$text attribute="2">bar</$text>
Inside multiple attributes using 2SCM:
The trick is to handle each attribute separately and cancel handling if one of them was handled. So the
keydown
event should be stopped after 2SCM is used.<$text a="1" b="2">fo{}o</$text>bar
-> not leaving or entering
<$text a="1" b="2">foo{}</$text>bar
-> has attribute
a
+ is leaving, remove attribute, prevent caret move<$text a="1" b="2">foo</$text><$text b="2">{}</$text>bar
-> has attribute
b
+ is leaving, remove attribute, prevent caret move<$text a="1" b="2">foo</$text>{}bar
-> not leaving or entering
<$text a="1" b="2">foo</$text>b{}ar
The beginning of an element:
<paragraph><$text a="1">f{}oo</$text></paragraph>
<- not leaving or entering
<paragraph><$text a="1">{}foo</$text></paragraph>
<- has attribute + is leaving, remove attribute, prevent caret move
<paragraph>{}<$text a="1">foo</$text></paragraph>
The end of an element:
<paragraph><$text a="1">fo{}o</$text></paragraph>
-> not leaving or entering
<paragraph><$text a="1">foo{}</$text></paragraph>
-> has attribute + is leaving, remove attribute, prevent caret move
<paragraph><$text a="1">foo</$text>{}</paragraph>
Approaching from the right side:
<paragraph><$text a="1">foo</$text>b{}ar</paragraph>
<- approaching from the right side, remove attribute
a
, remove attributeb
<paragraph><$text a="1" b="2">foo</$text>{}bar</paragraph>
<- does not have attribute
a
+ is entering, add attribute, prevent caret move<paragraph><$text a="1" b="2">foo</$text><$text a="1">{}</$text>bar</paragraph>
<- does not have attribute
b
+ is entering, add attribute, prevent caret move<paragraph><$text a="1" b="2">foo{}</$text>bar</paragraph>
<- not leaving or entering
<paragraph><$text a="1" b="2">fo{}o</$text>bar</paragraph>
Other questions regarding the solution
How to check "is leaving" and "is entering"?
This seems easy. We already check if the selection is at attribute boundary so we would just add checking if a proper key was pressed.
Clearing attributes set by 2SCM?
There's a question about clearing attributes set by 2SCM. However, maybe we don't need to do anything?
When the selection is moved through API (keypress, mouse click,
directChange == true
) then the attributes are cleared anyway. This means that we don't need to care about additional clearing.* - However this messes up our solution when the caret approaches element from the right because the attribute would be removed first and then selection would clear that. So for that case, we would need more additional handling. I believe it is doable, though.
When the selection is moved because of changes to the model tree (changes in background, collaboration,
directChange == false
) we don't want those changes to affect selection anyway. The only exception would be if the selection is "removed" or the attribute is removed/changed. This should be doable too.What about gravity?
Now, as I am thinking about the solution I described, I got an idea. Maybe we could implement gravity managing as an additional separate feature. It would be much simpler. Basically, if a user clicks left arrow key, gravity is set to right, and when a user clicks right arrow key, gravity is set to right.
This would cover two things:
How would it work?
fo{}o<$text bold="true">bold</$text>bar
-> keep gravity to the left
foo{}<$text bold="true">bold</$text>bar
-> keep gravity to the left
foo<$text bold="true">b{}old</$text>bar
<- keep gravity to the right
foo<$text bold="true">{}bold</$text>bar
<- keep gravity to the right
fo{}o<$text bold="true">bold</$text>bar
The gravity would be also reset on
change:range
withdirectChange
set totrue
.This is just an idea, I didn't think it through and I didn't think what problems it may bring. Also what problems it may bring in conjunction with 2SCM (although it would fix one issue :)).
The text was updated successfully, but these errors were encountered: