Closed fpavlic closed 7 years ago
2019 Developers: Your best shot is here https://codepen.io/mackermedia/pen/gmNwZP
Quill really is great. But, from the blog:
Quill aims to be the defacto rich text editor for the web.
Yet the document model you are so proud of cannot simply produce a <br>
with a shift-enter. Please reconsider this feature.
@VaelVictus your sample is buggy.
You can reproduce with:
Enter
Which, indeed, is why I said it was your best shot in 2019.
@VaelVictus you should try this workaround, works fine for me :)
Original thread is locked now, but I had issues with workarounds and Deltas they produced. When I did setContents
and getContents
I got a different version compared to the original. So I tried to solve the issue myself and came with a solution that works pretty well for me. The whole idea is to place an empty <div></div>
there. Reasons:
div
is a block element and will cause text to break.The only issue I had, was forcing Quill not to place any content into the <div>
. That's why I set height
to 0
and that solved the issue.
So the whole code looks like this:
import Quill from 'quill'
const Embed = Quill.import('blots/embed');
export class SmartBreakBlot extends Embed
{
static create()
{
const node: HTMLElement = super.create();
node.style.height = '0px';
return node
}
}
SmartBreakBlot.blotName = 'smartbreak';
SmartBreakBlot.tagName = 'div';
Quill.register( 'formats/smartbreak', SmartBreakBlot )
...
keyboard:
{
bindings:
{
shiftEnter:
{
key: 13,
shiftKey: true,
handler: ( range ) =>
{
this.editor.insertEmbed(range.index, 'smartbreak', true, 'user');
this.editor.setSelection( range.index + 1, 'silent' );
return false
}
}
}
}
Because the original issue is opened for almost 4-5 years now, I hope this helps.
Shift + Enter
should 100 % come by default.
Quill gets hyped but is still missing standards that other editors have out-of-the-box.
And this issues was brought up already in 2014 ...
Personally I am sticking to SCEditor as long as this is not default.
This "heavy" workaround seems to work: https://codepen.io/mackermedia/pen/gmNwZP
Thanks for that heavy workaround link. I have actually since adopted Pell and this was a driver to do so.
I must admit I was surprised when I realized that Shift + Enter
does not work out of the box. Differentiating between newlines and paragraphs is why there are <br>
and <p>
tags in the first place, and they are not interchangeable. <p>
tags can be styled, while <br>
tags cannot. The difference between the two is a big part in styling HTML documents, and since Quill produces HTML, I expected it to support both.
I quite like Quill, and how easy it is to integrate - I will have a look at the solutions proposed so far to add this functionality, as everyone who will be using it in my project know how to use and need both paragraphs and newlines.
I really think it should be added to the core :+1:
I have same issue course I tried to use Devextreme HTMLEditor which is using Quill, there I see no change to replace it easily. When I try hack it via direct DOM injection Quill removes BR immediately. I hate it boths :(
@VaelVictus you should try this workaround, works fine for me :)
It wourks when u use pure Quiil, but no chance when it is wrapped
@VaelVictus your sample is buggy.
You can reproduce with:
- clear up all content
- hit
Enter
- Newline is appended but cursor isn't moved
I might not understand that code entirely, but changing:
length() {
return 1
}
inside the class to:
length() {
return 0
}
fixed the issue for me.
For anyone using React-Quill this worked for me:
The only problem is that after pressing enter, backspace has to be pressed twice to return to the previous line. If anyone has a solution for that please let me know!
Not sure why answers here are so complicated.
I just did this in the Quill config:
keyboard: {
bindings: {
linebreak: {
key: 13,
shiftKey: true,
handler: function(range) {
this.quill.insertEmbed(range.index, 'breaker', true, Quill.sources.USER);
this.quill.setSelection(range.index + 1, Quill.sources.SILENT);
return false;
}
}
}
}
For the Breaker blot I did:
let Embed = Quill.import('blots/embed');
class Breaker extends Embed {
static tagName = 'br';
static blotName = 'breaker';
}
Quill.register(Breaker);
I had to also add the blotName 'breaker' to the list of formats in the Quill config.
I am using react-quill
, so you might need to translate to vanilla usage if that's what you're doing but this very simple setup worked fine for me, no complicated selections, insertions or anything. Just an embed with a tag of br
, inserted on shift-return
.
I would say that if you're having issues with the way br tags and p tags are rendered in your editor and your actual display of the data then you should look into manually theming quill. I found the quill.core.css file was styling a lot of tags and I wanted a context agnostic editor that left styling to the page it's on.
@NODESPLIT
Not sure why answers here are so complicated.
I just did this in the Quill config:
keyboard: { bindings: { linebreak: { key: 13, shiftKey: true, handler: function(range) { this.quill.insertEmbed(range.index, 'breaker', true, Quill.sources.USER); this.quill.setSelection(range.index + 1, Quill.sources.SILENT); return false; } } } }
For the Breaker blot I did:
let Embed = Quill.import('blots/embed'); class Breaker extends Embed { static tagName = 'br'; static blotName = 'breaker'; } Quill.register(Breaker);
I had to also add the blotName 'breaker' to the list of formats in the Quill config.
I am using
react-quill
, so you might need to translate to vanilla usage if that's what you're doing but this very simple setup worked fine for me, no complicated selections, insertions or anything. Just an embed with a tag ofbr
, inserted onshift-return
.I would say that if you're having issues with the way br tags and p tags are rendered in your editor and your actual display of the data then you should look into manually theming quill. I found the quill.core.css file was styling a lot of tags and I wanted a context agnostic editor that left styling to the page it's on.
This works great when writing text, but not on copy-paste, do you have any fix for that?
Edit: this solution seems to work https://github.com/zenoamaro/react-quill/issues/513#issuecomment-523783053
As for the buggy but useful example provided by @VaelVictus - I improved it by adding/extending a couple of handlers, taking care of the following problems:
The only problem that remains and that I have not been able to solve is the "double backspace" tap that's needed to remove the <p><br></p>
tags that quill won't delete in one tap now.
The example sadly had to be written in old coffee script but just throw it in an online converter and you're ready to go. I hope this helps someone struggling with this feature as much as I did. =)
keyboard: bindings:
handleEnter:
key: 13
handler: (range, context) ->
if range.length > 0
try
that.yquill.scroll.deleteAt range.index, range.length
catch exceptionVar
that.quill.deleteText(0, that.quill.getLength())
return
# So we do not trigger text-change
lineFormats = Object.keys(context.format).reduce(((lineFormats, format) ->
if Parchment.query(format, Parchment.Scope.BLOCK) and !Array.isArray(context.format[format])
lineFormats[format] = context.format[format]
lineFormats
), {})
previousChar = that.quill.getText(range.index - 1, 1)
# Earlier scroll.deleteAt might have messed up our selection,
# so insertText's built in selection preservation is not reliable
that.quill.insertText range.index, '\n', lineFormats, Quill.sources.USER
if previousChar == '' or previousChar == '\n'
that.quill.setSelection range.index + 2, Quill.sources.SILENT
else
that.quill.setSelection range.index + 1, Quill.sources.SILENT
# that.quill.selection.scrollIntoView()
Object.keys(context.format).forEach (name) ->
if lineFormats[name] != null
return
if Array.isArray(context.format[name])
return
if name == 'link'
return
that.quill.format name, context.format[name], Quill.sources.USER
return
if that.quill.getLeaf(range.index)[0].domNode.nodeName == "BR"
that.quill.insertEmbed range.index, 'break', true, 'user'
that.quill.setSelection range.index + 2, Quill.sources.SIL
return
linebreak:
key: 13
shiftKey: true
handler: (range) ->
currentRange = range.index
currentLeaf = that.quill.getLeaf(range.index)[0]
nextLeaf = that.quill.getLeaf(range.index + 1)[0]
# Prohibit soft break when no text is inserted before or when inside of hard-break
if currentLeaf and currentLeaf.domNode.nodeName == "BR" and currentLeaf.parent and currentLeaf.parent.domNode.nodeName == "P" and currentLeaf.next == null
return
else if currentLeaf and currentLeaf.domNode.nodeName == "BR" and currentLeaf.next and currentLeaf.next.domNode.nodeName == "#text"
return
else if currentLeaf and currentLeaf.domNode.nodeName == "BR" and currentLeaf.next and currentLeaf.next.domNode.nodeName == "BR"
return
# Insert first break
that.quill.insertEmbed currentRange, 'break', true, 'user'
# Insert a second break if:
# At the end of the editor, OR next leaf has a different parent (<p>)
if nextLeaf == null or currentLeaf.parent != nextLeaf.parent
that.quill.insertEmbed currentRange, 'break', true, 'user'
# Now that we've inserted a line break, move the cursor forward
that.quill.setSelection currentRange + 1, Quill.sources.SILENT
return
deleteHandler:
key: 'Delete',
handler: (range, context) ->
currentLeaf = that.quill.getLeaf(range.index)[0]
nextLeaf = that.quill.getLeaf(range.index + 1)[0]
if currentLeaf.domNode.nodeName == "BR" and (nextLeaf and nextLeaf.domNode.nodeName == "BR") and range.index > 0
that.quill.deleteText range.index, 1, Quill.sources.USER
that.quill.setSelection range.index, Quill.sources.SILENT
if range.index == 0 and (nextLeaf and nextLeaf.domNode.nodeName != "BR")
that.quill.deleteText range.index, 1, Quill.sources.USER
that.quill.setSelection range.index, Quill.sources.SILENT
else if range.index == 0 and (nextLeaf and nextLeaf.domNode.nodeName == "BR")
that.quill.deleteText range.index - 1, 1, Quill.sources.USER
that.quill.deleteText range.index, 1, Quill.sources.USER
that.quill.deleteText range.index + 1, 1, Quill.sources.USER
that.quill.setSelection range.index + 1, Quill.sources.SILENT
that.quill.deleteText range.index, 1, Quill.sources.USER
else if currentLeaf.domNode.nodeName == "BR" and currentLeaf.parent.domNode.nodeName == "P" and (nextLeaf and nextLeaf.domNode.nodeName == "BR")
if range.index > 0
that.quill.deleteText range.index - 1, 1, Quill.sources.USER
that.quill.setSelection range.index, Quill.sources.SILENT
else if currentLeaf.domNode.nodeName == "BR" and currentLeaf.parent.domNode.nodeName == "P" and (nextLeaf and nextLeaf.domNode.nodeName != "#text")
if range.index > 0
that.quill.deleteText range.index - 1, 1, Quill.sources.USER
that.quill.setSelection range.index, Quill.sources.SILENT
else if range.length == 0 and range.index != 0
that.quill.deleteText range.index, 1, Quill.sources.USER
else
that.quill.deleteText range, Quill.sources.USER
This is such a hacky solution, if one could call it a solution at all. I guess the problem is that the author didn't anticipate this while constructing the inner logic of the project, so it probably isn't trivial to add this in a robust manner. Unfortunately the project i'm working on requires this functionality so i'm giving up on Quill for now.
How in the world is this still an issue? This is literally one of the most obvious features a wysiwyg editor should have. Can someone on the dev team PLEASE explain why you refuse to add this after almost 10 years of requests?
Just use TinyMCE 6. :} You can test for this functionality right here: https://www.tiny.cloud/docs/tinymce/6/
This is by far the best implementation of Shift + Enter for Quill https://codesandbox.io/embed/quill-line-break-br-fully-working-djyoc2?codemirror=1
0) use Enter to insert paragraph, use Shift+Enter to insert break
1) works on paragraphs and bullet lists
2) both Enter and Shift+Enter preserve styles that were applied on previous line
3) When copypasting into editor html with newlines - they are automatically converted to
as one would expect
This is by far the best implementation of Shift + Enter for Quill https://codesandbox.io/embed/quill-line-break-br-fully-working-djyoc2?codemirror=1
0. use Enter to insert paragraph, use Shift+Enter to insert break 1. works on paragraphs and bullet lists 2. both Enter and Shift+Enter preserve styles that were applied on previous line 3. When copypasting into editor html with newlines - they are automatically converted to as one would expect
Worked like charm for quill 1.3.7
, but not for quill 2.0.2
, anyone can do a upgrade?
Hi Jason,
Just wonder how can I add difference between paragraph and new line entries.
For example ENTER should always create new paragraph, but SHIFT+ENTER should add brake-line.
Thanks for you help, Filip