1

I want to add a random name every time when someone clicks the Enter key. For example: If anyone pressed the Enter key it should create a paragraph block with a new and unique name same as Medium.com text editor.

But as usual contenteditable div just copy the previous element when the Enter key is pressed. But I don't want to copy the element. I want to create a new block with a unique name.

enter image description here

.root {
  border: 1px solid #212121;
}
<div class="root" contenteditable>
  <p name="kLdnD" class="block">Block with random name</p>
  <p name="uIDlf" class="block">Second block</p>
</div>
Tahazzot
  • 1,224
  • 6
  • 27

1 Answers1

1

The following code relies on the fact that on new line the browser duplicates the last child element of the editable div. On key down we handle the case when there are no children yet, and we make sure that the first element will be a paragraph, letting the browser create more paragraphs automatically.

To set the id and name of newly created paragraphs we use the mutation observer API to get notified when a paragraph is added.

Another peculiarity is the second paragraph that we add if the first keystroke is Enter. We need this because the browser displays an empty div and a div with one empty paragraph identically.

<html>
<head>
<script>
    function loaded()
    {
        //  https://stackoverflow.com/questions/105034/how-to-create-guid-uuid
        function uuidv4() {
          return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
          });
        }

        const zzz = document.getElementById("zzz");
        zzz.onkeydown = function(e)
        {
            if(!zzz.children.length)
            {
                let element = document.createElement("p");
                element.innerHTML = "<br />";
                zzz.appendChild(element);
                if(e.code == "Enter")
                {
                    element = document.createElement("p");
                    element.innerHTML = "<br />";
                    zzz.appendChild(element);
                }
                window.getSelection().collapse(element, 0);
                e.preventDefault();
            }
        }
        const observer = new MutationObserver(function(mutationList, observer)
        {
            for(let ilength = mutationList.length, i = 0; i < ilength; ++i)
            {
                const addedNodes = mutationList[i].addedNodes;
                for(let jlength = addedNodes.length, j = 0; j < jlength; ++j)
                {
                    const node = addedNodes[j];
                    const randomNumber = uuidv4();
                    node.id = "pid" + randomNumber;
                    node.setAttribute("name", "pn" + randomNumber);
                }
            }
        });
        observer.observe(zzz, { childList: true });
    }
</script>
</head>
<body onload="javascript:loaded();">
<div id="zzz" contenteditable="true"></div>
</body>
</html>
Danny Apostolov
  • 479
  • 3
  • 8
  • 1
    When my cursor is the center of any text and presses the enter key then it should split the expected text into a new block/ paragraph. See this image https://imgur.com/nvfRCZj – Tahazzot Sep 15 '20 at 12:28
  • 1
    @Md.Tahazzot - there you go, w/ another approach. – Danny Apostolov Sep 15 '20 at 13:23
  • 1
    @Md.Tahazzot - actually the previous code was ignoring the case when you add multiple new lines with a long key press. See the new one. – Danny Apostolov Sep 15 '20 at 13:54
  • 1
    Thank you so much. You have done more than I expected – Tahazzot Sep 15 '20 at 13:56
  • Can you please help me for the last time plz. (If you have time, then) :( If I have another block instead of the paragraph block. Then it just copies the last block on entering. I always want to create a new paragraph block when I click on Enter. https://jsfiddle.net/Md_Tahazzot/4uexcLpm/20/ – Tahazzot Sep 17 '20 at 08:23
  • i'm not sure that it's gonna work. it seems that the contenteditable copies whatever element is right under the keyboard cursor and you have no control over this - it can be the figure element as well (and this is the only element i saw being copied, actually), and it's an empty figure as well. if you want something more complex than the code from my answer, instead of using contenteditable, it seems that you'll need to create a complete edit box based on a div with keyboard event handling etc, from scratch. – Danny Apostolov Sep 17 '20 at 18:24