Ticket T973477
Visible to All Users

HtmlEditor - How to add the <br /> tag with shift+enter

created 4 years ago

Hello,

I'm trying to integrate the SHIFT+Enter (<br>) functionality as explained in this support ticket: T959240

I converted the script into a Typescript / react based component but when i try Shift+Enter my cursor only moves one position to the right.

This is the code i wrote:

TypeScript
import * as React from 'react'; import HtmlEditor from 'devextreme-react/html-editor'; import { Toolbar, Item } from 'devextreme-react/html-editor'; import { Button, Popup, TextArea } from 'devextreme-react'; import * as Quill from 'devextreme-quill'; import { useCallback, useRef, useState, useEffect } from 'react'; const Parchment = Quill.import("parchment"); const Break = Quill.import("blots/break"); const Embed = Quill.import("blots/embed"); //not in use? const Delta = Quill.import("delta"); const ENTER = 'enter'; Break.prototype.optimize = function () { }; //Break.prototype.insertInto = function (parent : any, ref : any) { // Embed.prototype.insertInto.call(this, parent, ref); //}; Break.prototype.length = function () { return 1; }; Break.prototype.value = function () { return "\n"; }; export default () => { const htmlRef = useRef<HtmlEditor>(null); const [text, setText] = useState("<p>test text</p><p>test<br>text</p>"); const [showHtmlPopup, setShowHtmlPopup] = useState(false); //register bindings for SHIFT + ENTER useEffect(() => { const quill = htmlRef.current?.instance.getQuillInstance(); if (!quill) return; console.log("quill instance", quill); quill.clipboard.addMatcher("BR", function () { const newDelta = new Delta(); newDelta.insert({ break: "" }); return newDelta; }); quill.keyboard.addBinding({ key: ENTER, handler: function (range: any, context: any) { if (range.length > 0) { quill.scroll.deleteAt(range.index, range.length); // So we do not trigger text-change } let lineFormats: any = Object.keys(context.format).reduce(function ( lineFormats: any, format: any ) { if ( Parchment.query(format, Parchment.Scope.BLOCK) && !Array.isArray(context.format[format]) ) { lineFormats[format] = context.format[format]; } return lineFormats; }, {}); const previousChar: any = 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 quill.insertText(range.index, "\n", lineFormats, Quill.sources.USER); if (previousChar === "" || previousChar === "\n") { quill.setSelection(range.index + 2, Quill.sources.SILENT); } else { quill.setSelection(range.index + 1, Quill.sources.SILENT); } 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; quill.format(name, context.format[name], Quill.sources.USER); }); } }); quill.keyboard.addBinding({ key: ENTER, shiftKey: true, handler: function (range: any, context: any) { const nextChar: string = quill.getText(range.index + 1, 1); quill.insertEmbed(range.index, "break", true, "user"); if (nextChar.length === 0) { // second line break inserts only at the end of parent element quill.insertEmbed(range.index, "break", true, "user"); } quill.setSelection(range.index + 1, Quill.sources.SILENT); } }); var enterHandlers: any = quill.keyboard.bindings[ENTER]; var customHandlers: any = enterHandlers.splice(enterHandlers.length - 2); enterHandlers.unshift(...customHandlers); }, []); const showEditHtmlPopUp = useCallback(() => { setShowHtmlPopup(true); }, []) const hidePopup = useCallback(() => setShowHtmlPopup(false), []); const valueChanged = useCallback((e: any) => setText(e.value), []) return <> <HtmlEditor height="100%" ref={htmlRef} value={text} onValueChanged={valueChanged} > <Toolbar > <Item formatName="undo" /> <Item formatName="redo" /> <Item formatName="separator" /> <Item formatName="size" /> <Item formatName="separator" /> <Item formatName="bold" /> <Item formatName="italic" /> <Item formatName="strike" /> <Item formatName="underline" /> <Item formatName="separator" /> <Item formatName="alignLeft" /> <Item formatName="alignCenter" /> <Item formatName="alignRight" /> <Item formatName="alignJustify" /> <Item formatName="separator" /> <Item formatName="header" /> <Item formatName="separator" /> <Item formatName="orderedList" /> <Item formatName="bulletList" /> <Item formatName="separator" /> <Item formatName="color" /> <Item formatName="background" /> <Item formatName="separator" /> <Item formatName="link" /> <Item formatName="image" /> <Item formatName="separator" /> <Item formatName="clear" /> <Item formatName="blockquote" /> <Item formatName="separator" /> <Item formatName="insertTable" /> <Item formatName="insertRowAbove" /> <Item formatName="insertRowBelow" /> <Item formatName="insertColumnLeft" /> <Item formatName="insertColumnRight" /> <Item formatName="deleteRow" /> <Item formatName="deleteColumn" /> <Item formatName="deleteTable" /> <Item formatName="separator" /> <Item> <Button icon="variable" type="normal" stylingMode="text" hint="Edit html" onClick={showEditHtmlPopUp} /> </Item> </Toolbar> </HtmlEditor> <Popup title="Edit html" visible={showHtmlPopup} onHiding={hidePopup} deferRendering > <TextArea value={text} onValueChanged={valueChanged} height="100%" /> </Popup> </>; }

using packages:

"devextreme": "^20.2.5",
"devextreme-quill": "^0.10.2",
"devextreme-react": "^20.2.5",

Did something change in the last release of devextreme? How can i get the Shift + Enter to work in the Html Editor with React / Typescript?

Kind regards,
Vincent

Answers approved by DevExpress Support

created 4 years ago (modified 3 years ago)

Hello Vincent,

In v21.2.3 we added a public allowSoftLineBreak option that you can use to enable/disable breaking content into multiple lines within a single block element (by the Shift+Enter key combination).

Previous versions:

I've checked the solution from HtmlEditor - <br /> tag for v20.2 with shift+enter ticket, and it's working as expected.
I've adopted it to React - https://codesandbox.io/s/overview-devextreme-html-editor-forked-nbbo1?file=/App.js
Please check it in your application. If you have any further questions, we'll be happy to help.

    Show previous comments (4)
    Artem (DevExpress Support) 3 years ago

      Hi Vincent,

      In v21.2.3 we added a public allowSoftLineBreak option that you can use to enable/disable breaking content into multiple lines within a single block element (by the Shift+Enter key combination). You can find the full list of DevExtreme component enhancements on our What's New page.

      Feel free to test this feature and share your results.

      VB VB
      Vincent Bloemen 3 years ago

        Hello,

        Thanks for the update.
        I was already aware of this new feature and i'm already using it in my projects!

        Sincerely yours,
        Vincent

        Artem (DevExpress Support) 3 years ago

          Thank you for the update, Vincent. Should you have further questions, feel free to contact us.

          Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

          Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.