Problem:
In CKEditor 4 this problem was solved by the magicline plugin. We need some solution for CKEditor 5 as well.
The discussion started in relation to autoparagraphing. Interesting comments:
If you would like this feature to be implemented ASAP, please react with ๐ to this post.
DUP reported in https://github.com/ckeditor/ckeditor5/issues/685.
I promised to describe here some simpler workarounds for this problem. They are much easier to implement than Magicline and perhaps might even be a good start for us.
Additionally, I noticed two things when describing these solutions:
Pros:
Cons:
getData()
if it was called while an image was selected.Like in solution 1 but add these paragraphs only when someone:
Pros:
Cons:
DUP reported in https://github.com/ckeditor/ckeditor5/issues/935.
DUP reported in https://github.com/ckeditor/ckeditor5-engine/issues/1400.
What's the good solution? ๐ข
@Reinmar Don't you think this should be categorized as a bug rather than an enhancement?
Most people type and then insert image at the end of the editor and as a result, cannot continue writing afterward.
Also, I think when a user clicks on image caption and hit enter, it should result in a new paragraph. Maybe, this can be a quick fix for images while the best solution is being decided on.
You may be right. For me, it's a missing feature because I know that it's how browsers work and we need to implement a feature which will allow reaching those places. For the users, this is purely a bug.
Still, it won't change much on how this ticket will be treated. We'd like to close it ASAP because we know that it makes for a bad UX, but we also know the scope of the problem (which is big).
BTW, @oleq, you can start processing this issue in the back of your head ;)
cc @dkonopka too
@Reinmar I totally understand the scope and complications of this problem.
That's why I suggested that maybe initially we can just add a new paragraph when a user clicks on image's caption and hit enter. This won't be a solution when image caption is disabled, but I believe in any case that should be the behavior for captions. (Maybe, I'm wrong).
Thanks for the amazing job you guys are doing with ckeditor5.
That's a good question. In CKEditor 4 Enter opens widget dialogs (e.g. image properties). In CKEditor 5 we don't use dialogs and we used Tab for navigation so far. This leaves Enter unused.
My only worry with using only a keystroke is its discoverability. Still, it might be a good (and quick) start.
is there any estimate for this issue?
We're about to merge a change which is going to allow inserting paragraphs before/after widgets by using Enter (to insert a paragraph after a widget) and Shift+Enter (to insert a paragraph before a widget). It works like this:
It doesn't solve this issue completely. It's sort of a workaround until we'll be able to introduce something with better discoverability (something that reacts to the mouse โ like CKEditor 4's magicline).
Still, we'd like to hear your feedback.
PS. This change is going to be released around the next week.
I think having a temporary fix is great, as this issue breaks the editor for users.
My concern would be that in other editors, pressing enter whilst selecting an image often deletes the image, as the intention is to replace it with a new line. (Albeit, most commonly when the image is inline, which isn't the case with ckeditor5)
Instead of waiting for magicline, gapcursor, etc., I think it would be worth mapping the suggested approach above to directional keys too, as mentioned in https://github.com/ckeditor/ckeditor5/issues/407#issuecomment-355927497
My concern would be that in other editors, pressing enter whilst selecting an image often deletes the image
I'm worried about this too. Although, I've realised recently when working on shift+enter that pressing enter on non-collapsed selections might be very uncommon. And that the expected result (inserting a line break) is quite surprising (at least for me) when experienced live.
Anyway, you may be right that with block images we're safer here. If we'd introduce the same for inline images it would be worse.
Instead of waiting for magicline, gapcursor, etc., I think it would be worth mapping the suggested approach above to directional keys too, as mentioned in #407 (comment)
I'm worried that the users would not know that they need to remove these paragraphs that they created this way (if they don't want to type in them). It's not typical for arrow keys to insert new elements.
Therefore, we considered this option but with an additional mechanism which would delete these paragraphs once you'd leave them without typing anything. Plus, which makes all this more complex, these paragraphs should not appear in the model (should be view-layer-only) to not cause some messy behaviours during real-time collaboration and when autosaving the content.
One of the options for the magic-paragraphs is what @fredck proposed some time ago โ that they are always present in the view at the beginning/end of the content if starts/ends with a block widget, regardless of where you currently have the selection. They may have a minimal height (even 0px
) to not be visible when the selection is somewhere else. Thanks to that:
height:0px
style to show this paragraph.Still, the question is whether they should be present in the model. If we'll decide that yes, then getting rid of them in getData()
will not be hard. If not, we still have the problem how to render them in the view without polluting the model with them.
I'm worried that the users would not know that they need to remove these paragraphs that they created this way (if they don't want to type in them). It's not typical for arrow keys to insert new elements.
Yeah, it's not ideal. I was thinking along the lines of removing them if they were still empty when the caret moves away. But thinking about it again, deleting is very well understood; I suspect users would remove any unintentional paragraphs without much fuss.
I think the bigger issue, as with the enter
key is discoverability.
One of the options for the magic-paragraphs is what @fredck proposed some time ago ...
That approach would certainly solve a lot more of these kinds of quirks.
As it's a temporary workaround, I think having these "magic paragraphs" in the model and filtering them out when calling getData()
(or similar), would be a pretty reasonable compromise. However, I don't know the implications of this on collaborative editing.
Since this problem is a bug from user's perspective any way that quickly can help user accessing those areas would be great and I think what @Reinmar proposed would definitely work for now.
Also, when user selects the caption input, I think hitting enter there should result in a new paragraph.
Also, when user selects the caption input, I think hitting enter there should result in a new paragraph.
This is unrelated to this ticket. If you'd like to discuss this topic, please report a separate ticket.
that they are always present in the view at the beginning/end of the content
Never talked about the "beginning", but it is an interesting case as well. It may have a more complex UX because while it is ok to have some empty space at the end of the content, it is a no go to have it at the beginning of it. Anyway, it's curious to give it a try.
In any case, I would break this into separate steps... first solving the problem at the end of the document, which may be simpler, then thinking about the beginning of it.
As for the "view vs model" thing, it would be "technically wrong" to have it in the model, as it is not aware of the UX quirks and it should ideally land in the view. Ofc, this will all depend on how easily it can be implemented and, if we face limitations, whichever solution is ok, as long as the problem is solved.
If this problem is solved, it will be the most complete WYSIWYG editor.
When you click on the image widget, how about show toolbar with the ability to insert an upper or lower line?
When you click on the image widget, how about show toolbar with the ability to insert an upper or lower line?
@dvlpr91, the following (or something similar) is what we want to achieve in the future:
https://sdk.ckeditor.com/samples/magicline.html
That's a complex feature, so we're considering bringing something simpler first ("magic paragraph").
Just for reference: Prosemirror solves this issue with a gapcursor plugin: https://github.com/ProseMirror/prosemirror-gapcursor/tree/master/src
You can see it in action here: https://apricot-ravioli.glitch.me/
@Reinmar Is the best way to insert the previous / next line by pressing the 'enter' key or the 'shift + enter' key while the image block is selected? (or keyboard directional key)
They are not available in mobile.
(Because of my English level, there is a possibility of misunderstanding and talking about what I read.)
@Reinmar Is the best way to insert the previous / next line by pressing the 'enter' key or the 'shift + enter' key while the image block is selected?
I think it's not the best way. We introduced it only because we could do that quickly. We know that it's not accessible by mouse and on touch devices. We will work on a complete solution one day. We just needed to buy some time now, because a complete solution will take time.
@Reinmar I see. In fact, I didn't know much about it because I didn't check it out. I hope it goes well!
I have to install CKEditor 4 now thanks to this bug.
The Enter key idea is only work for the developer of webpage. No one can find the Enter key solution by themselves.
Why not just add a "<p> </p>"
under the image?
Thanks for the feedback. We were aware it's only temporary and that it's far from perfect, but we have many other topics that we need to work on now.
Regarding inserting an empty <p>
, that's something we were considering but it's not a solution in many cases. E.g. when there's an image at the end of a table cell, if you'd add a paragraph there, there would be a blank line that you don't want to have there. Also, the problem with inaccessible places exists also between images and at the beginning of the content. We can't insert paragraphs everywhere.
So, it's tricky. We need to find a solution that doesn't break other features and doesn't pollute the content.
DUP reported in https://github.com/ckeditor/ckeditor5/issues/1546.
DUP reported in https://github.com/ckeditor/ckeditor5/issues/1621.
DUP reported in https://github.com/ckeditor/ckeditor5/issues/1703.
I played a bit with displaying "magic blocks" between widgets and at the beginning/end of the content and it works quite well. I use a view post fixer to add them and UIElement to render them (in a quite transparent way).
It fixes the Ctrl+A issue too:
And it helps in some other cases with the selection. I wonder if we could go this wway... to show them always between such blocks.
If those blocks would look good, then maybe... :trollface:. Maybe such blocks could be invisible when you do not have mouse pointer in proximity and we could show them dynamically? That would look kind of like the magic line from CKE 4.
OK, I pushed the code to https://github.com/ckeditor/ckeditor5-core/compare/poc-magic-block. It should be used together with https://github.com/ckeditor/ckeditor5-engine/compare/t/1727 which resolves an issue that I stumbled upon: https://github.com/ckeditor/ckeditor5-engine/issues/1727.
The implementation is really simple. I use a view postfixer to add those blocks between widgets and at the start/end of the content. I render them using UIElements so the view layer knows that they are not part of the model. Finally, I handle clicking on those blocks by inserting a model paragraph at the block position. And that's it.
Some ideas for improvements:
.image + .image
) but we can't help with that. I'd just recommend avoiding making them too big.It'd be also great if those blocks were reachable by arrow keys.
Example content: <p>foo[]</p><image/><image/>
They could indeed be invisible. However, I think they should appear when the user has the mouse somewhere close to them (discoverability)... which becomes complicated, so perhaps they should always be visible but less intrusive?
I thought about giving them some padding, some negative margin and just using your typical on hover callback... Maybe that would be enough to make it work? I am also afraid about discoverability but in the case when you have an unreachable area you are going to move your mouse pointer in the space between images anyway.
If you'd start typing here, the text would appear in a new paragraph. The only problem at this stage is... where should the model selection be
I think that we could insert paragraph temporarily together with handling for this case:
If you don't type in the paragraph which you created by clicking the magicblock, we could remove that paragraph.
OTOH: what if you wanted to have an empty paragraph there (for some reason, like, I can't believe I am writing this, but, _additional spacing_)?
If you'd start typing here, the text would appear in a new paragraph. The only problem at this stage is... where should the model selection be
That's going to look really bad for real-time collab scenarios (although, we can perhaps hide it on other clients?). And you wouldn't like that paragraph in your data too, so we'd need to skip it in the data pipeline. If that's fine, then I'd go this way. I'd like to avoid exceptions in the selection post-fixer rules.
OTOH: what if you wanted to have an empty paragraph there (for some reason, like, I can't believe I am writing this, but, _additional spacing_)?
Good point. Also, if we'd always add (and keep that paragraph), if the user actually wants to remove it, that'd be really easy โ just press backspace/delete.
What if the image is floated (aligned to the side)? Are you displaying those blocks too then? If so, then what they look like?
They are normal elements in the content. We could do some tricks like also floating those blocks and giving them the same width as the images they surround.
In my POC they are displayed where the image would be if it wasn't floated. It's also where the block will appear if you click that magicblock so it's actually quite predictable.
Currently, when an image is selected, when the user presses tab
, the caption field is selected. When pressing tab
a second time, the focus of CKE is lost. May I suggest that in this case a new paragraph is inserted? Maybe the same when the user presses the down arrow key
or the right arrow key
?
May I suggest that in this case a new paragraph is inserted? Maybe the same when the user presses the
down arrow key
or theright arrow key
?
I'm afraid that could be a baffling behavior for screen reader users. Some concepts like focus cycling (using tab) or caret movement (arrows) are deep-rooted concepts that should not be changed unless absolutely necessary.
@Reinmar
They may have a minimal height (even
0px
) to not be visible when the selection is somewhere else. Thanks to that:
Is it possible what minimal height isn't working for selection? I'm getting magic block and image both selected after image click.
No, it's this bug: https://github.com/ckeditor/ckeditor5-engine/issues/1727 which requires this change: https://github.com/ckeditor/ckeditor5-engine/compare/t/1727. No official PR for it yet because this change requires documentation and tests.
Hi @Reinmar,
Have you found a solution to this problem? I am also struggling for a work-around for a few days now, but whatever I check, I got stuck ;) To be honest, it is a basic requirement, to be able to continue editing after inserting an image. The lack of this prevents us to adopt CKEditor 5 in our new project. It cannot be unsolvable.
See my comment for #2067.
Thank you,
Zsolt
The only solution right now is to press Enter or Shift+Enter when having that image selected. That's the workaround we introduced some time ago. It's not meant to be the target solution, but it was possible to implement it quickly.
A full solution (something like https://github.com/ckeditor/ckeditor5/issues/407#issuecomment-484408847) will be one of our priorities during the upcoming months. I think it's quite safe to assume this will land in Q1 2020. There's a slight chance it will land sooner than that, but the end of the year is always crazy, so dunno about this.
Hi! Our users complained they were stuck after adding an image and could not add anything else.
Until the full solution is finished I found that adding help text solves the discoverability issue with the SHIFT+ENTER and ENTER keyboard shortcuts. The trick to avoid adding visual clutter is to only show it when the text either starts or ends with a figure.
Without a figure nothing changes:
Figure in the middle of text, nothing changes:
No text above the figure:
No text on either side:
Here is a simplified code example using bootstrap:
html:
<div id="fig-help-top" class="alert alert-danger mb-0" role="alert">
Note: to add text above the figure, select the figure and press SHIFT+ENTER
</div>
<textarea id="editor"></textarea>
<div id="fig-help-bottom" class="alert alert-danger" role="alert">
Note: to add text after the figure, select the figure and press ENTER
</div>
javascript:
function refreshHelper(text){
var showStart = text.startsWith("<figure");
var showEnd = text.endsWith("</figure>");
// show/hide the divs using jQuery, Vue, etc...
}
ClassicEditor
.create( document.querySelector( 'editor' ))
.then( function(editor) {
refreshHelper(editor.getData());
editor.model.document.on( 'change:data', function( evt, data ) {
refreshHelper(editor.getData());
} );
} );
Its not perfect but new users were able to work with that without staying stuck. For our project this was sufficient.
Hi guys,
Just before you decide that Enter or Shift enter when on an image solves the problem, please very much be aware that this does not work when the image floats, for example having "side" alignment. Please, please do test with it with side aligment as well. A single image on one row is not enough to have for a decent design...
Thank you,
@Reinmar, I like the idea of "magic blocks", do they work also when the image floats?
Hi there ! Love so much Ckeditor 5, thanks for your hard work on this hot topic o/ This is an issue almost every customers and testers noticed and complained about when using our CMS ( https://fireblogcms.com/ , a CMS headless dedicated to blogging with a GraphQL API ) : when a media is inserted at the very bottom of the editor (instagram widget, image, video), people remain stucked and can't figure out by themselves out to create a new paragraph. Before trying to hack this in our own way, can you confirm that resolution of this complex issue is still not planned for now ?
Maybe a simple workaround for us could simply to add a paragraph at the end of the editor when people click on this area , can we do this with ckeditor API ?
PS : +1 for @gkzsolt comment on floating images
@Reinmar
Edit: I stopped being lazy and read this thread, it seems the consensus is that the current solution is already considered to be unsatisfactory. I copied this comment mostly verbatim from an issue I opened talking about the same thing. I see your aiming for Q1 2020 - I think this is really important to fix ASAP.
Continuation...
This is a very unusable and unintuitive solution. From plentiful experience, I guarantee that we'll receive support tickets from confused users about this. You should not have to refer to a shortcut that isn't obvious in order to do basic things like add a line before a table.
Plus, should not the fact that you've received an issue report be evidence enough that a more user-friendly and intuitive solution is necessary? I actually played around for a few minutes trying to figure out if you'd added some kind of shortcut for it, and I could not find one. That alone is indication of poor UX.
Could it not be possible to have a "virtual" caret position, before a widget? Or, perhaps, a "virtual" line, which can be selected WITHOUT selecting the table? In almost ANY text editor, you can select newline characters. But CKEditor goes against the grain, there.
It would be so much more intuitive if you hooked onto the "Left" or "Right" arrow keys and, if the caret is on the table, add a new line before it.
This is was Slack do, now that they support WYSIWYG.
Microsoft Word handles this a bit differently, though, it is still somewhat intuitive. They have a little drag handle, which looks similar to CKEditor's Table selection handle. You can just drag the table down, even if there are no lines after the table. It will create enough lines for you to place the table where the user dropped it. If they did what Slack did, AND had the drag handle, then that would be even better.
Either way, the current solution is poor. You cannot expect users of CKEditor to pass on a list of instructions on how to use a simple WYSIWYG on any software CKEditor is integrated in.
CKEditor is such a well-made piece of software, but there's these rough edges which are concerning, and may even necessitate a switch to a different piece of software by vendors if they are not addressed.
@yann-yinn - completely agree. This is not a good solution.
This week I got the same kind of issue: a customer was totally blocked after inserting a table at the end of the editor. In this case hitting "_enter_" after selecting table does not work, and i had to solve the problem myself : cut the table, insert a paragraph, move cursor up, paste the table. (beyond that, table widget is pretty impressive and customer managed to create a complex table with some complex stuff inside without any issues, great job guys! )
Hey there, hope this might help some people, here is what I tried for our editor to insert automatically a new empty paragraph when inserting an image, blockquote, media or table at the end of the doc. This way, you can just click on the empty paragraph after the media to continue writing.
Heavily inspired by https://github.com/ckeditor/ckeditor5/issues/1255#issuecomment-423499870
editor.model.document.on("change:data", (eventInfo, data) => {
// Insert automatically a paragraph after an image or a block,
// Otherwise redactors are stuck at the bottom of the page and
// can't add a new line.
//
// No idea what i am doing, here, i mainly copy-pasted this code:
// https://github.com/ckeditor/ckeditor5/issues/1255#issuecomment-423499870
// and made some little changes
const changes = editor.model.document.differ.getChanges();
editor.model.change((writer, data) => {
for (const entry of changes) {
// if an image, table, blockQuote or media is inserted.
if (
entry.type === "insert" &&
["image", "table", "blockQuote", "media"].includes(entry.name)
) {
// Get last node of the doc
const docNodes = entry.position.root._children._nodes;
const lastDocNode = docNodes[docNodes.length - 1];
// add a empty paragraph automatically if this the last node of the doc.
if (lastDocNode.index === entry.position.index) {
const position = entry.position.nodeAfter;
const paragraph = writer.createElement("paragraph");
writer.insert(paragraph, position, "after");
}
}
}
});
});
Hi @yann-yinn,
this is a good idea, but it could be improved a little. First, you are using some private properties here, which isn't a good practice. Second, this kind of code should be introduced as a post-fixer (you can read about post-fixers here: https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_model_document-Document.html#function-registerPostFixer).
if (lastDocNode.index === entry.position.index) {
This might be incorrect in some edge cases if you are just checking indexes. Also, it is better not to narrow down to root only. I'd check if the image is the last element of it's parent, not matter what the parent is. This way you also fix the issue for table cells and probably other cases that might come up in future.
So, instead of the condition you suggested, I'd go with this:
const insertedElement = entry.position.nodeAfter;
if ( !insertedElement.nextSibling ) {
writer.insertElement( 'paragraph', insertedElement, 'after');
}
Let me know if that works for you.
@scofalik yes, thanks a lot for your help โค๏ธ . It seems to work like a charm, and this is a huge UX improvment for our writers ๐ . (edit: and yep, thanks to your condition, automatic new lines also works inside a table, so cool :) )
Here is my final code
editor.model.document.registerPostFixer(writer => {
// Insert automatically a paragraph after an image or a block,
// Otherwise redactors are stuck at the bottom of the page and
// can't add a new line.
// @see https://github.com/ckeditor/ckeditor5/issues/407#issuecomment-602111695
const changes = editor.model.document.differ.getChanges();
editor.model.change(writer => {
for (const entry of changes) {
// if an image, table, blockQuote or media is inserted.
if (
entry.type === "insert" &&
["image", "table", "blockQuote", "media"].includes(entry.name)
) {
const insertedElement = entry.position.nodeAfter;
if (!insertedElement.nextSibling) {
writer.insertElement("paragraph", insertedElement, "after");
// According to the ckeditor doc, we have to return true
// if some changes have been made by our postFixer
return true;
}
}
}
});
});
I closed #6618 as a DUP of this ticket because the only solution that I'd accept here is one which also works well with arrow keys.
DUP reported in #6704.
For those who participated in this issue, I just wanted to let you know that the feature is being developed and the MVP already landed in master
branch of the project ๐ย
There are still tons of improvements down the road (keyboard support in particular) so stay tuned.
If you're interested in remaining issues, you can find them under a dedicated label.
Looks great!
Perhaps it's just me, but the arrow seemed to me at first sight unintuitive.
What I'm primarily trying to do is to put some text above the image, so I would expect the arrow to point upwards (in direction of my desired action). The fact that this action moves the image down (downward arrow) is just incidental.
What I'm primarily trying to do is to put some text above the image, so I would expect the arrow to point upwards (in direction of my desired action). The fact that this action moves the image down (downward arrow) is just incidental.
We considered arrows but they looked a lot more like "move this image one block up/down". The "enter key" arrow is not perfect too, but we couldn't think of a better icon so far.
Does this fix allow to insert anything after an image ? We are waiting for this possibility for almost a year already, and _can not upgrade to ckeditor 5_ because it is unusable this way. There are tons of duplicate reports, and I see talking about "unaccessible places", "magic lines", a.s.o. many things I don't follow, but one use case is very simple:
You create a document, insert an image at the end and then cannot continue. You are doomed, there is no way to get past that image.
At least that was the situation last autumn/winter. So not _before_ the image, and not a text _inline with_ the image. A text below the image. Is that possible?
You can select the image and press Enter (to insert after the image) or Shift-Enter (to insert before the image).
Does this fix allow to insert anything after an image ?
Still, I'm also curious about this question.
Does this fix allow to insert anything after an image ?
Yes. It inserts a paragraph. You can start typing or insert another image, table, etc.
@oleq great work I can't wait to try it out!
@oleq thank you so much, another huge ux improvement for ckeditor :D !
The tooltip seen on hover for this item doesn't appear to be localized yet, FYI
@otherblandart The feature is new and it will take some time for translations to arrive. Stay tuned or... if you want to contribute to the project, you can translate these labels by yourself.ย
Thanks for your notice!
We extended the feature with another way to reach the space before/after a block โ now the arrow keys can do that too.
We'll keep working on improving this concept, but I now consider the base case closed :) Finally ๐
You can see the potential followups in https://github.com/ckeditor/ckeditor5/labels/squad%3Amagic.
Most helpful comment
For those who participated in this issue, I just wanted to let you know that the feature is being developed and the MVP already landed in
master
branch of the project ๐ยThere are still tons of improvements down the road (keyboard support in particular) so stay tuned.
If you're interested in remaining issues, you can find them under a dedicated label.