anotheruser1488182
anotheruser1488182

Reputation: 335

Ckeditor - Add multiple child elements to list element

In CKeditor is it possible to add multiple child elements to a list element?

E.g.

 - Heading

   Paragraph
 - Heading2

   Paragraph2

Backstory- I've created a style that lets the user style up an order list. Part of this style is to have a heading and a paragrpah within each list item element.

Problem- When the adding the heading element and pressing enter, to be able to add the paragraph, a new list item is added instead. If the shift+enter/shift+enter button combination is pressed, a new list is created without creating a new list item, however the cursor remains within the heading element, and so no paragraph can be added this way.

Is there a way around this?

Upvotes: 0

Views: 737

Answers (1)

anotheruser1488182
anotheruser1488182

Reputation: 335

I've found a way to fix the problem by overriding the key press event in CKEditor. When a key is pressed, it checks that:

  1. It was the Enter key that was pressed;
  2. The cursor is within a list;
  3. The node the cursor is in isn't empty;
  4. The cursor is at the end of the node.

If so it

  1. Adds a paragraph after the current node.
  2. Moves the cursor into it.

The code:

CKEDITOR.on(
    'instanceReady',
    function(ev) {
        var editorInstance = CKEDITOR.instances[ev.editor.name];
        var editorWindow = editorInstance.window.$;
        var editorDocument = $editor_instance.document.$;
        var editorBody = editorDocument.body;

        /***
         * Fix the editor not letting you add sub elements to lists
         */
        editorInstance.on( 'key', function( event ) {
            // Get the HTML event
            var e = event.data;
            // If the enter key was pressed
            if(e.keyCode == 13) { 
                // Find which element the cursor is in
                var selection = editorWindow.getSelection();
                var cursorElem = $(selection.anchorNode);
                // Only override the default behaviour if we're in a list element, and the user has typed something
                if(cursorElem.closest('li').length && cursorElem.text().trim().length) {
                    // get the current cursor position
                    var range = editorWindow.getSelection().getRangeAt(0)
                    // create range to find how many characters are after the cursor
                    var postRange = editorDocument.createRange();
                    postRange.selectNodeContents(cursorElem[0]);
                    postRange.setStart(range.endContainer, range.endOffset);
                    var nextText = postRange.cloneContents();
                    var isAtEnd = nextText.textContent.length === 0;
                    // Only override if we're at the end of the list element
                    if(isAtEnd) {
                        // cancel the default event
                        event.cancel();
                        // get the element to add the new paragraph after
                        var after = cursorElem;
                        // if the cursor is in a TEXT not instead of an actual HTML node then get the parent HTML code
                        if(cursorElem[0].nodeType == Node.TEXT_NODE) {
                            after = cursorElem.parent();
                        }
                        // Add the new paragraph
                        after.after('<p></p>');
                        var newParagraph = after.next();

                        // set selection to the new paragraph
                        var range = editorDocument.createRange();
                        range.setStart(newParagraph[0], 0);
                        selection.removeAllRanges();
                        selection.addRange(range);
                    }
                }
            } 
        });

    }
);

CSS needed to make the new paragraph display:

p {
    min-height: 1em;
}

P.s. Thanks for this answer showing how to check if the cursor was at the end of an element Contenteditable DIV - how can I determine if the cursor is at the start or end of the content

Upvotes: 0

Related Questions