#11064 closed Bug (fixed)
[Blink/Webkit] Can not select all when widget is last element
| Reported by: | Piotr Jasiun | Owned by: | Marek Lewandowski |
|---|---|---|---|
| Priority: | Must have (possibly next milestone) | Milestone: | CKEditor 4.6.1 |
| Component: | General | Version: | 4.0 |
| Keywords: | Blink Webkit | Cc: |
Description (last modified by )
- open Chrome or Opera,
- go to http://ckeditor.dev/plugins/image2/samples/image2.html
- copy an image as a last element of content,
- try to select all (CTRL+A).
You should be not able to do this.
On IE10 and FF everything works fine.
You can also reproduce that bug using:
<p>AA</p> <p contenteditable="false">BB</p>
Do not forget to set allowedContent: true on editor to use this sample code.
Related browsers bugs:
- Blink's bug: https://code.google.com/p/chromium/issues/detail?id=415474
- Webkit's bug: https://bugs.webkit.org/show_bug.cgi?id=136911
Change History (25)
comment:1 Changed 12 years ago by
| Keywords: | Blink added |
|---|---|
| Status: | new → confirmed |
| Version: | → 3.0 |
comment:2 Changed 12 years ago by
| Version: | 3.0 → 4.0 |
|---|
Since we no longer develop 3.0 I'm setting start version to 4.0.
comment:3 Changed 12 years ago by
| Summary: | [Blink]Can not select all when widget is last element → [Blink] Can not select all when widget is last element |
|---|
comment:4 Changed 12 years ago by
Most likely due to the same issue you can't also use ctrl+end hotkey which should move cursor to the end of the document.
comment:6 Changed 11 years ago by
DUP reported: #12454.
I also noticed that we haven't reported this on Blink's and Webkit's bug trackers.
comment:7 Changed 11 years ago by
| Keywords: | Webkit added |
|---|---|
| Summary: | [Blink] Can not select all when widget is last element → [Blink/Webkit] Can not select all when widget is last element |
comment:8 Changed 11 years ago by
| Description: | modified (diff) |
|---|
- Blink's bug: https://code.google.com/p/chromium/issues/detail?id=415474
- Webkit's bug: https://bugs.webkit.org/show_bug.cgi?id=136911
comment:9 Changed 11 years ago by
| Description: | modified (diff) |
|---|
comment:12 Changed 9 years ago by
| Milestone: | → CKEditor 4.6.1 |
|---|---|
| Priority: | Normal → High |
comment:13 Changed 9 years ago by
| Owner: | set to kkrzton |
|---|---|
| Status: | confirmed → assigned |
comment:14 Changed 9 years ago by
| Milestone: | CKEditor 4.6.1 |
|---|---|
| Priority: | Must have (possibly next milestone) → Normal |
| Status: | assigned → review |
This one is tricky and required a quite complex workaround. In Blink/WebKit browsers it is possible to select all content with non-editable element at the beginning/end only when there is non empty element before/after (so in fact non-editable is no longer at the beginning/end).
The proposed solution adds such element on Ctrl/Cmd + A and reselects the content. The filler element is invisible and positioned absolutely so it does not influence how the content looks in any way but makes it possible to select it all. Filler element is removed when selection changes or key is used.
As agreed earlier the whole workaround was created as a separate plugin.
Pushed fix to t/11064.
comment:15 Changed 9 years ago by
| Priority: | Normal → Must have (possibly next milestone) |
|---|
comment:16 Changed 9 years ago by
| Milestone: | → CKEditor 4.6.1 |
|---|
comment:17 Changed 9 years ago by
| Status: | review → review_failed |
|---|
Functionality
Not able to select all with widget focused
- Open an editor with a widget at the end, e.g. basic test End with a widget.
- Focus the editor by clicking it.
- Press
CTRL+A.
Expected: Filler gets inserted, all the content get selected.
Actual: The filler is not created, wrong selection.
It also affects "Only non-editable" case.
Reason
The reason for it is that the fake selection container is created (div[data-cke-hidden-sel=1]) and placed at the end of the document.
The simplest starting solution is to check:
var lastChild = editable.getLast( function( elem ) {
return elem.getName && !elem.hasAttribute( 'data-cke-temp' );
} ).$
Going further theres a centralized temp method.
Empty paragraph gets inserted
- Open an editor with a widget at the end, e.g. basic test End with a widget.
- Focus the editor by clicking it.
- Press
CTRL+A. - Press
CTRL+Xto cut the content. - Press
CTRL+Vto paste the contnet.
Expected: Same content gets pasted.
Actual: An empty paragraph gets inserted at the end. As a result widgetselection won't kick in for ctrl+a afterwards, because you have an empty paragraph tailing.
Code
- Key checks should be moved outside of the
addFillersmethod, to keep clear responsibility. - Can't we use keyup event here instead of adding a timeout?
- Instead of using getChild to obtain first/last children(https://github.com/cksource/ckeditor-dev/blob/3b0a5da873be64d0258b4de92f2b999f656d0729/plugins/widgetselection/plugin.js#L103) you could use [getFirst](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-getFirst) / [getLast] methods.
Docs
- Initial comment block should be preceded with a
@fileOverviewtag, so that it doesn't get picked by jsduck as a global leftover entry.
Other
- I've added elementspath to the manual test, so that it's easier to see the path.
Further development
It would be nice also extend this to support expanding selection e.g. with shift + left arrow.
comment:18 Changed 9 years ago by
| Status: | review_failed → review |
|---|
Pushed changes to t/11064.
Fixed
@fileOverviewadded to file description.- Key checks moved outside
addFillersmethod. - Adjusted manual tests - while the basic and paste manual tests were intended to not use
clipboardplugin as I addedimage2plugin (which requireswidgetwhich requiresclipboardplugin) it was included anyway. I fixed those tests so all combinations: withoutclipboardandundo, with onlyclipboard, with onlyundo, with bothclipbaordandundocould be tested
Issue 1
This is the funny one. Actually, the cause was a little different and I was able to recreate this issue on a master branch.
When you select the widget, the fake selection container is created. Then, when you press Ctrl/Cmd + A the whole content gets selected. It gets selected because of fake selection container (it works same as widgetselection filler in this situation). But when you release the keys, selectionChange (or selectionCheck) is fired - the selection was changed so fake selection container is removed (by widget plugin which manages it). When fake selection container gets removed it breaks again the selection (due to bug causing this issue) and caret is supposed to be moved to the last element which is non-existent fake selection container.
The good part is I adjusted the solution to be aware of temporary elements as you suggested and it solved this issue.
Issue 2
Solved by filtering fillers on paste. Also added paste unit test.
Keyup event
I recheck the possibility to use keyup event instead of deferred keydown, however there are few issues with it. The keyup event is not fired in every situation we would like it to be fired to used it for this fix. Consider the following key sequences (action - event fired):
Ctrl/Cmdpressed - keydownApressed - keydownAreleased - noneCtrl/Cmdreleased - keyup
and
Ctrl/Cmdpressed - keydownApressed - keydownCtrl/Cmdreleased - keyupAreleased - keyup
If we would rely on keyup for the first situation the select all would be fired after A and Ctrl/Cmd key release. For the second one it would be fired after releasing Ctrl/Cmd. If you compare it to a browsers which supports such selection natively (e.g. Firefox) you can clearly see that the whole content gets selected on keydown event (so you could just press Ctrl/Cmd + A without releasing it and content will be selected). To sum up my suggestion will be to stay with a keydown event.
comment:19 Changed 9 years ago by
All the test cases I discovered earlier are fixed - great!
Please, check the changes I made on top of yours:
- We also need to add
selectallplugin integration, I already added manual test for that, and also integration code in the widgetselection plugin itself.
Code
- I've removed
evtparameter fromaddFillermethod as it's no longer in use. - Removing filler on paste - I think that the safest way is to remove any filler element, despite of it's position - but let's make it as a follow up in 4.6.2.
Tests
- I've added undo to the most manual tests. It will make manual testing easier.
- I removed tests related to not having undo loaded, as missing undo plugin should not affect in any way the solution.
- I've
paste.mdhas becomeimage2.mdmanual test - the purpose there is to test widgets + clipboard integration with widgetselection.
comment:20 follow-up: 21 Changed 9 years ago by
| Status: | review → review_failed |
|---|
Looks good :)
Just two thing to consider:
1. Fillers are added/removed only when not the whole content is selected. When adding it makes selecting on a whole content possible, when removing it works as a cleanup (meaning that previously the whole content was selected). While adding fillers before selectAll command makes perfect sense I have some doubts about removing them after command excution.
First of all, the fillers will not be removed because the whole content is selected (the code disallows to do so because it will break the selection again - due to the bug). I think this will make sense for the case when using selectAll command deselects content or changes selection (changes from select all ofc), but I am not sure if such situation may happen with current implementation.
2. I think that the safest way is to remove any filler element, despite of it's position - cleanPasteData method removes both fillers from the beginning and end so it should be sufficent, because for now those are the only allowed filler types. Or maybe you meant the g flag in the replace method in case of duplicate fillers?
comment:21 Changed 9 years ago by
| Owner: | changed from kkrzton to Marek Lewandowski |
|---|---|
| Status: | review_failed → review |
Replying to k.krzton:
1. Fillers are added/removed only when not the whole content is selected. When adding it makes selecting on a whole content possible, when removing it works as a cleanup (meaning that previously the whole content was selected). While adding fillers before selectAll command makes perfect sense I have some doubts about removing them after command excution.
First of all, the fillers will not be removed because the whole content is selected (the code disallows to do so because it will break the selection again - due to the bug). I think this will make sense for the case when using
selectAllcommand deselects content or changes selection (changes from select all ofc), but I am not sure if such situation may happen with current implementation.
I see now, in fact this code was effectively doing nothing. Removed.
2. I think that the safest way is to remove any filler element, despite of it's position - cleanPasteData method removes both fillers from the beginning and end so it should be sufficent, because for now those are the only allowed filler types. Or maybe you meant the
gflag in the replace method in case of duplicate fillers?
Well, I'd say a mix of two - cleanPasteData could be simply modified to remove any elements with any data-cke-filler-webkit attribute value, and the regexp would be global just like you suggested.
In a similar fashion removeFillers would remove _any_ *[data-cke-filler-webkit] element. It would be simpler, and safer in case when some external API adds something to the end of the editable. But it deserves to be extracted into a follow-up ticket in 4.6.2.
On top of that I added minor API docs changes.
comment:22 Changed 9 years ago by
| Status: | review → review_passed |
|---|
Ok, looks good :)
I will create the follow-up ticket with the proposed improvements described.
comment:23 Changed 9 years ago by
| Resolution: | → fixed |
|---|---|
| Status: | review_passed → closed |
Merged to master with c08aa2c.
comment:25 Changed 8 years ago by
| Description: | modified (diff) |
|---|

This issue seems to be a little bit older than widgets.
With TC provided by @pjasun I wasn't able to select and copy text from CKEditor 3.0 (in both 3.x and 4.x).