Skip to content
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

How to add difference between ENTER and SHIFT+ENTER #1187

Closed
fpavlic opened this issue Dec 13, 2016 · 21 comments
Closed

How to add difference between ENTER and SHIFT+ENTER #1187

fpavlic opened this issue Dec 13, 2016 · 21 comments

Comments

@fpavlic
Copy link

fpavlic commented Dec 13, 2016

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

@jhchen
Copy link
Member

jhchen commented Dec 13, 2016

#252

@jhchen jhchen closed this as completed Dec 13, 2016
@VaelVictus
Copy link

VaelVictus commented Jan 22, 2019

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.

@robertu7
Copy link

@VaelVictus your sample is buggy.

You can reproduce with:

  1. clear up all content
  2. hit Enter
  3. Newline is appended but cursor isn't moved

image

@VaelVictus
Copy link

Which, indeed, is why I said it was your best shot in 2019.

@robertu7
Copy link

@VaelVictus you should try this workaround, works fine for me :)

@tomasbonco
Copy link

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:

  1. A div is a block element and will cause text to break.
  2. It's a paired tag. So we can use standard Quill's Embed functionality.

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.

@q2apro
Copy link

q2apro commented Nov 21, 2019

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

@VaelVictus
Copy link

Thanks for that heavy workaround link. I have actually since adopted Pell and this was a driver to do so.

@Mistralys
Copy link

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 👍

@vasva
Copy link

vasva commented Apr 19, 2020

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 :(

@vasva
Copy link

vasva commented Apr 19, 2020

@VaelVictus you should try this workaround, works fine for me :)

It wourks when u use pure Quiil, but no chance when it is wrapped

@IcyFoxe
Copy link

IcyFoxe commented Jul 4, 2020

@VaelVictus your sample is buggy.

You can reproduce with:

  1. clear up all content
  2. hit Enter
  3. Newline is appended but cursor isn't moved

image

I might not understand that code entirely, but changing:

length() {
  return 1
}

inside the class to:

length() {
  return 0
}

fixed the issue for me.

@mylesdawson
Copy link

For anyone using React-Quill this worked for me:

React-Quill Shift+Enter

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!

@NODESPLIT
Copy link

NODESPLIT commented May 17, 2021

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.

@korneSt
Copy link

korneSt commented Jul 5, 2021

@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 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.

This works great when writing text, but not on copy-paste, do you have any fix for that?

Edit: this solution seems to work zenoamaro/react-quill#513 (comment)

@HaloElite
Copy link

HaloElite commented Mar 6, 2023

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:

  • Hard break directly after soft break no longer moves select to wrong position nor needs double pressing enter
  • Next leaf no longer inheriting br tag which was leading to a line break remaining on delete
  • Multi-linebreaks no longer appear

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

@herrbasan
Copy link

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.

@ShaneJohnsonCC
Copy link

ShaneJohnsonCC commented Mar 2, 2024

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?

@VaelVictus
Copy link

Just use TinyMCE 6. :} You can test for this functionality right here: https://www.tiny.cloud/docs/tinymce/6/

@DmitriyKochergin
Copy link

DmitriyKochergin commented Apr 3, 2024

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

  1. use Enter to insert paragraph, use Shift+Enter to insert break
  2. works on paragraphs and bullet lists
  3. both Enter and Shift+Enter preserve styles that were applied on previous line
  4. When copypasting into editor html with newlines - they are automatically converted to
    as one would expect

@uniquejava
Copy link

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests