slab / quill

Quill is a modern WYSIWYG editor built for compatibility and extensibility
https://quilljs.com
BSD 3-Clause "New" or "Revised" License
43.12k stars 3.35k forks source link

Support for shift + enter #252

Closed EmilStenstrom closed 4 months ago

EmilStenstrom commented 9 years ago

I believe supporting shift + enter should be a a priority. If you want to use div, that's fine, but <div>text</div><div>text</div> should be output with an enter, and <div>text<br>text</div> with shift + enter.

jhchen commented 9 years ago

This is a pretty technically costly feature to add to Quill so there'd have to be a large need from the community for it to become a priority.

davejachimiak commented 9 years ago

Thanks for all of your work on quill.js!

I'm in full support of this and hope it can be prioritized. Inserting <br>s into line <div>s with shift + enter would help my company's content editors. We use line <div>s for denoting paragraphs, but they frequently need a way to just to do a break-line without denoting a separation of paragraphs. Inserting <br>s into line <div>s with shift + enter would achieve this perfectly.

Is there any current workaround to get the functionality I want? I've tried every hack I could think of to no avail.

anovi commented 9 years ago

:+1: I have tried to change DEFAULT_BLOCK_TAG to <p> but realised that it has no sense without line breaks by shift+enter

That-David-Guy commented 8 years ago

Just wondering if there is anymore progress on this? In my editor I'm using the divs as a paragraph so having shift+editor would work great for newlines.

jhchen commented 8 years ago

This is not currently being worked on as it still lacks a compelling real world use case.

From a user of an editor / word processor perspective, it's incredibly confusing to have two ways to have newlines, especially when one looks like two (<br> vs <p> with padding). I can see why a developer might find this convenient to have richer semantic organization as @davejachimiak mentions, but convenient is a long ways from a need. Furthermore Quill is a WYSIWYG editor, not an HTML editor, and having complete control over the HTML markup it generates is not a project goal.

That-David-Guy commented 8 years ago

So there is no way for the user to enter a newline if <div>s are treated as paragraphs?

jhchen commented 8 years ago

A user inserts a newline by hitting enter. If the user hits enter again (leaving the new line blank), they have just created what most readers would consider a new paragraph.

That-David-Guy commented 8 years ago

But only if <div>s are not treated as paragraph (as in Quill's example). But in my case we are treating the <div>s as paragraphs (i.e. they have margin-bottom: 30px) as we don't want the user to have to press enter twice. The vast majority of the time they want paragraphs so that is our default, occasionally they want a new line which we currently can't provide them with Quill (we are actually using ReactQuill which wraps Quill).

Just thought I'll let you know my use case for it.

khmelevskii commented 8 years ago

+1

khmelevskii commented 8 years ago

a very useful feature!

henningborchers commented 8 years ago

+1

jbrooksuk commented 8 years ago

:+1:

We're building an internal document editor which should act similar to Word. This doesn't :(

Joeao commented 8 years ago

@jbrooksuk It doesn't claim to act similar to word. Though, the next update and inclusion of Parchment may provide you with an experience closer to what you're hoping for.

jbrooksuk commented 8 years ago

It doesn't claim to act similar to word.

I know that :)

cydrobolt commented 8 years ago

Using shift + enter in a document and bolding text across the two divs created by shift + enter causes the selected text to "jump" or simply doesn't bold the text. Is this a known bug in Quill? Removing the linebreak allows the user to unbold the text.

Console output:

The given range isn't in document.

image

image

jhchen commented 8 years ago

@cydrobolt I'm assuming you've made some modification to add shift+enter? On the quilljs.com editor shift+enter is the same as enter but in either case bolding across the line does not error.

robert-boulanger commented 7 years ago

@jhchen : I can give you a real world use case. We are writing novels. When we are finished, we have to export the text somehow, so finally a designer can work on this and at least we get a book. The problem is, without shift-enter, everything becomes paragraph

. In the designers software, paragraphs will be formatted like for example text-indent: 30px. because every first line of a paragraph should be intented. But often a writer, doesn't want to have a new paragraph which is intented, but just a new line within the actual paragraph starting at the very left margin. By inserting two normal Returns for a real paragraph and only one for a newline, post production becomes much more complicated, since designers doesn't care about the content. furtheron, I also have a css which says:

.ql-editor p {
    text-indent: 30px;
}

to make reading easier. We are editing our whole books in one document( more then 400 pages when printed). But unfortunatly everything is a new paragraph. By the way, I hoped to get this result with

let Break = Quill.import('blots/break');
    Quill.register(Break)

and define a keybord binding like: (here for Ctrl-Return)

linebreak: {
        key: 13,
        ctrlKey: true,
        handler: function (range, context) {
            this.quill.insertEmbed(range.index, 'break', true, 'user');
            quill.setSelection(range.index + 1, Quill.sources.SILENT);
        }
    }

but can't get any result. But by th way, nevertheless, Quill is the best WYSIWYG Editor for creating huge docs, I have seen so far

tdolsen commented 7 years ago

This is an essential feature of any text editor, whether the output is html or books; there is a clear difference between paragraphs and line breaks, and a text editor not supporting both is severely limiting proper content handling.

I'd love to use Quill over other editors, but this is a deal breaker for us.

robert-boulanger commented 7 years ago

@tdolsen : as well as for us. but a found a nice workaround and with this we can live quite good:

javascript:


var Parchment = Quill.import('parchment');

var LineBreakClass = new Parchment.Attributor.Class('linebreak', 'linebreak', {
  scope: Parchment.Scope.BLOCK
});

Quill.register('formats/linebreak', LineBreakClass);

then inside your keyboard handlers:

...
smartbreak: {
        key: 13,
        shiftKey: true,
        handler: function (range, context) {
            this.quill.setSelection(range.index,'silent');
            this.quill.insertText(range.index, '\n', 'user')
            this.quill.setSelection(range.index +1,'silent');
            this.quill.format('linebreak', true,'user');

        }
    },
    paragraph: {
        key: 13,
        handler: function (range, context) {
            this.quill.setSelection(range.index,'silent');
            this.quill.insertText(range.index, '\n', 'user')
            this.quill.setSelection(range.index +1,'silent');
            let f = this.quill.getFormat(range.index +1);
            if(f.hasOwnProperty('linebreak')) {
                delete(f.linebreak)
                this.quill.removeFormat(range.index +1)
                for(let key in f){
                    this.quill.formatText(range.index +1,key,f[key])

                }
            }

        }
....

and finally css:

.ql-editor p {
    text-indent: 30px;
    margin-top: 10px;
}

p.linebreak-true {
    text-indent: 0px;
    margin-top: 0px;
}

this causes that shift-enter inserts a new line which is a <p< in quill, but it gets a class linebreak.

the css causes, that normal paragraphs appear with a line indent and a top margin, p.linebreak not. so the writer gets the right feeling.

when exporting quills content to a dektop wordprocessor, just handle the linebreak attribute as a normal linefeed and process all others as normal paragraphs.

hope this helps

tdolsen commented 7 years ago

@robert-boulanger: Very much. That should be a workable solution, until native support is added. Thanks!

robert-boulanger commented 7 years ago

@tdolsen : be welcome ;)

VincentGarreau commented 7 years ago

+1 for this feature

RobAley commented 7 years ago

We're looking at moving from Trix to Quill for an (e)book editor we're building, as its more stable, and more flexible with regards to attaching random code in the document. But both Trix and Quill suffer for not handling paragraphs/line breaks in this (correct?!) manner. @robert-boulanger : Thanks, your code will let us work around this for now.

But +1 for adding this behaviour to Quill to make it less susceptible to changes/breakage. Many users who are used to professional writing tools are familiar with this UX pattern.

ozanhazer commented 7 years ago

If I understand correct from the documentations, paragraphs are used to mimic linebreaks and linebreaks are rendered as paragraphs. If I really understand it correct and this is by design then I believe there's a fundamental problem with the domain definition...

A document does not consist of lines and line-breaks, it consists of paragraphs (and headings)... Inside the paragraphs you might want to "break" the line and that's where linebreaks comes into play.

...at least for hypertext documents. For plain text the simplest way to mimic a paragraph is to use double line-breaks since you're limited to ASCII characters. But that was the case before hypertext was invented!?

In the current case you have no control on how paragraphs are displayed, you cannot adjust spacing between elements or you cannot indent the text as @robert-boulanger stated. Or as in my case you have to find a hack to get rid of these empty paragraphs after headings :\

If you still think that this is the correct behaviour, it would be nice to have some notice on the quickstart documentation describing this behaviour to save some hours of the programmers maybe...

fpavlic commented 7 years ago

Jason,

Here you have excellent text editor and I hope you will continue your great work on this. Community that is build around Quill is also great, you have really high quality inputs.

Difference between SHIFT+ENTER and ENTER are widely known and used - this is real life scenario.

If you do not accept that journalist, writers, bloggers use paragraphs that can contain brake-line your are wrong. If user hits enter twice is not solution, as code generated is simply wrong -> there are now three paragraphs instead one.

Than think on programmers perspective, ENTER generates <p></p> there are 7 chars, and SHIFT+ENTER should generate <br/> is 5 chars now. Should we consider now such optimization obsolete ?

Hope you decide to add this high valuable feature.

RobAley commented 7 years ago

Just to add an additional reason/use for this feature. We style paragraphs such that the first paragraph after certain elements (e.g. headings, certain embedded blots) has a different styling (usually not indented and a higher margin-top) to subsequent ones, however in some cases the user wants to put line breaks after those elements to format some content which makes styling much harder when everything is a p.

jhchen commented 7 years ago

Can anyone explain how Word and Docs survived and thrived to become the most ubiquitous writing tools in the world without adding this?

Keep in mind what's being discussed here is not if you can add this. The answer is yes--Parchment granted this ability. The question is if Quill should build and support this in core.

RobAley commented 7 years ago

Because they are general purpose word processors. No one is going to create/compete with them with a quill based editor. Where quill can compete is in more specialised (but still widely used, particularly professional) editors such as those used in publishing. Will quill survive without such a feature? sure. Will quill get wider adoption with such a feature? we think so.

RobAley commented 7 years ago

My wife (who is a big Word user) has just mentioned that in fact word does have this distinction. Googling for it yielded discussions such as :

http://superuser.com/questions/453555/how-to-get-word-to-do-line-break-on-enter-rather-than-paragraph-break (in particular, see the comments (not answers) on the question itself to see the rational/benefits)

I guess Word just hides it better than pro tools.

ozanhazer commented 7 years ago

Yeah word, google docs and macos pages has this ability but it's not visible since there's no spacing around paragraphs by default so you get the same result if you do "enter" or "shift+enter".

Try this for google docs: Add some text and select "Format / Line Spacing / Add spacing before + after paragraph", then experiment with "shift + enter" and "enter" to see the difference.

For Pages in mac you can set the amount of spacing by setting "Before Paragraph" and "After Paragraph" under Format / Style tab.

I'm not using word for some years so cannot remember the exact location but I know that you can customize it through "styles" and apply it to all paragraphs, I did it countless times.

djave-co commented 7 years ago

+1 for this feature

Outside of the points about paragraphs, the line break is frequently used to add additional lines in a bulleted list, so you begin a list and then hold shift to create the extra content.

rpmonteiro commented 7 years ago

I'm trying to implement this functionality, but I'm afraid I'll get the same errors as @cydrobolt (have you found a solution/workaround?), and then have to drop Quill altogether after more than 50h working on it...

@jhchen Even if you don't want to implement this yourself, do you mind just giving some pointers as to how we can implement it ourselves? As you can see, it's a feature A LOT of us desperately need...

Thank you very much. Quill is an amazing library :-)

rpmonteiro commented 7 years ago

Here's an approach that worked for me:

Instead of swimming against the current and modifying the existent Break blot and whatnot (which I spent hours trying to do and couldn't.. 😞 ), I just did some pre and post processing on the HTML itself.

  1. Remove the margins around <p> tags image

  2. Regex to replace </p><p> with a <br> image (I also added a regex for to replace a blockquote tag per line to just put everything in one with `

  3. Now do the other way around: regex to add again the empty lines between paragraphs image (quill seems to automatically add a new blockquote tag per line, so I didn't bother with that one)

  4. ???

  5. profit

We end up with the HTML that we all want, with the nice breaks and all, and when it comes time to render that HTML in Quill, we just bend to its will, and format it back the way Quill likes. image

HTML Out - <p>no<br>margins<br>here</p><p>double paragraph</p> HTML In - <p>no<p>margins</p><p>here</p><p><br></br><p>double paragraph</p>

Hope this helps! Good luck!

djave-co commented 7 years ago

Just to add a further use case, if you enter an address it is essential to have line breaks. At present, I'm looking at 5 paragraphs, like the below:

Address line 1

Address line 2

Address line 3

Rather than

Address line 1 Address line 2 Address line 3

Really hope this could be looked at at some point!

neutralrockets commented 7 years ago

+1 for this feature.

Just wasted a few hours integrating Quill into my project only to realise shift+enter is not supported.

BastiOfBerlin commented 7 years ago

+1 as well.

And since I am working with the Delta format, I cannot use the hack that @rpmonteiro suggested. Currently the paragraphs are simply represented as \n within the format. So I think we need to make up some design decisions on how to reflect and differentiate between simple line-breaks a.k.a. newlines and a new paragraph.

ozanhazer commented 7 years ago

@BastiOfBerlin I agree with you. By design newline is used to adjust spacing, for example a newline is added after headings to leave a space before the next paragraph. Adjusting the spacing should be the job of styles IMO...

vestimir commented 7 years ago

👍 Using this on a site which allows the users to enter poems, the lack of soft enter is crucial for such cases.

gaborsar commented 7 years ago

Google docs inserts a \u000b character rather than a \n - char code 11 instead of 13.

farnabaz commented 7 years ago

Maybe this could done using custom Break blot

let Parchment = Quill.import('parchment');
let Break = Quill.import('blots/break');
let Embed = Quill.import('blots/embed');
Break.prototype.insertInto = function(parent, ref) {
    Embed.prototype.insertInto.call(this, parent, ref)
};
Break.prototype.length= function() {
    return 1;
}
Break.prototype.value= function() {
    return '\n';
}
Quill.register(Break)

and bindings like this

handleEnter: {
    key: 13,
    handler: function (range, context) {
      if (range.length > 0) {
        this.quill.scroll.deleteAt(range.index, range.length);  // So we do not trigger text-change
      }
      let lineFormats = Object.keys(context.format).reduce(function(lineFormats, format) {
        if (Parchment.query(format, Parchment.Scope.BLOCK) && !Array.isArray(context.format[format])) {
          lineFormats[format] = context.format[format];
        }
        return lineFormats;
      }, {});
      var previousChar = this.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
      this.quill.insertText(range.index, '\n', lineFormats, Quill.sources.USER);
      if (previousChar == '' || previousChar == '\n') {
        this.quill.setSelection(range.index + 2, Quill.sources.SILENT);
      } else {
        this.quill.setSelection(range.index + 1, Quill.sources.SILENT);
      }
      this.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;
        this.quill.format(name, context.format[name], Quill.sources.USER);
      });
    }
},
linebreak: {
    key: 13,
    shiftKey: true,
    handler: function (range, context) {
            var nextChar = this.quill.getText(range.index + 1, 1)
            var ee = this.quill.insertEmbed(range.index, 'break', true, 'user');
            if (nextChar.length == 0) {
                // second line break inserts only at the end of parent element
                var ee = this.quill.insertEmbed(range.index, 'break', true, 'user');
            }
            this.quill.setSelection(range.index + 1, Quill.sources.SILENT);
    }
}

DEMO on Codepen

rpmonteiro commented 7 years ago

@farnabaz Thank you very much for sharing this. I'm now working on it and fixing some issues that occur when quill first loads the HTML (as I'm saving it in the DB).

I'll post my findings here once I get this working properly!

rpmonteiro commented 7 years ago

I got it working great.

The code @farnabaz posted worked great, just had some minor tweaks I had to do specific to my use case.

For me, using Quill with React, I was before injecting the HTML into quill's container. But now that we have our fancy linebreaks, the solution was to instead send the HTML via the dangerouslyPasteHTML method of the clipboard module. With that, you can then write a little matcher for our new <br> friend

image

And this concludes dozens and dozens of hours for me of doing RegExp work that can now be replaced by a handful of lines of code.

Thank you very much once again farnabaz, you saved my week! 👍 🍺

farnabaz commented 7 years ago

@rpmonteiro I'm glad to hear it 👍 I updated DEMO with your custom matcher

ollyfg commented 7 years ago

Just FYI, I really need this to format poems correctly, where there are often line breaks that are not paragraph breaks. Reading through this, there are obviously many use cases for this feature (which is also present in Word, Google Docs), so I hope the Quill team steps up and supports this. I will have to try one of the work-arounds, but if they don't work I'm going to have to drop Quill - this really is a deal beaker.

zmartcode commented 7 years ago

hy @ollyfg this one works fine for me: http://codepen.io/farnabaz/pen/VpdaGW . but as you said: should definitely be possible without a workaround ;)

mackermedia commented 7 years ago

@nhunzaker and I had a couple issues with the above codepen solutions:

  1. an extraneous newline added at the end of the editor
  2. you need to press Shift + Enter twice if you're at the end of the current <p> tag to insert a newline.

We've forked and updated the codepen with our solution here: http://codepen.io/mackermedia/pen/gmNwZP

Notable additions:

  1. removing extraneous newline:
    
    var length = quill.getLength()
    var text = quill.getText(length - 2, 2)

// Remove extraneous new lines if (text === '\n\n') { quill.deleteText(quill.getLength() - 2, 2) }


2. handling the double shift+enter bug:

keyboard: { bindings: { linebreak: { key: 13, shiftKey: true, handler: (range) => { let currentLeaf = this.editor.getLeaf(range.index)[0] let nextLeaf = this.editor.getLeaf(range.index + 1)[0]

    this.editor.insertEmbed(range.index, '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 || (currentLeaf.parent !== nextLeaf.parent)) {
      this.editor.insertEmbed(range.index, 'break', true, 'user')
    }

    // Now that we've inserted a line break, move the cursor forward
    this.editor.setSelection(range.index + 1, Quill.sources.SILENT)
  }
}

} }

parterburn commented 7 years ago

We're using Quill as an email composer, trying to replicate Gmail as much as possible. Gmail's default line break is the single br, which IMO is much more flexible. If you need a new paragraph, tap twice.

Is it possible to optionally convert Quill's p default to the br?

bjorn-ali-goransson commented 7 years ago

@jhchen, what @RobAley said. All word processors support shift+Enter for BR:s, but if your copy of Word doesn't have margins on its P:s configured, you won't see it.

If you were to configure margins on your Word document, you'd see what you see on the web.

In MS Word terms, it's called a soft carriage return (or just Soft Return), see here: https://www.computerhope.com/jargon/s/softretu.htm

amitm02 commented 7 years ago

I've sure noticed i've wrote a duplicate - issue #1511. I'll just mention that implementing this will solve the issue and adding a break line within a list item.

suziesirena commented 7 years ago

@farnabaz, your code works well but I have an issue when setting content to the editor.

I use this code to set the editor content : document.querySelector(".ql-editor").innerHTML = content

but the <br> tags are removed in the editor.

Is it the right way to set HTML content to Quill?