Search code examples
javascriptjqueryhtmlrangy

Split SPAN when Inserting HTML Inside of it


I have a setup where I have a large amount of text that is formatted HTML (containing headings and paragraphs)–all inside of a contenteditable div. I've setup a function to insert a custom html entity: <newnote> into the editable div upon clicking a button. This works great except that when inserting the note inside of a span I need to split the span in two and place the <newnote> in between them.

I've looked at lots of functions around the web for inserting text into a DIV, and since it is a requirement that I be inserting HTML it seems like document.createTextNode() is my only choice.

So here is what I've setup thus far, it checks if the parent is a SPAN and then places different content based on that if statement.

function insertNodeAtRange() {
  var newRange = rangy.getSelection().getRangeAt(0);
  var parentElement = newRange.commonAncestorContainer;
  if (parentElement.nodeType == 3) {
      parentElement = parentElement.parentNode;
  }
  var el = document.createElement('newnote');
  el.className = "bold";
  if (parentElement.tagName == 'SPAN') {
      el.appendChild(document.createTextNode(" </span>Test<span> "));
  } else {
      el.appendChild(document.createTextNode(" Test "));
  }
  newRange.insertNode(el);
}

Here is what I have sofar

Thanks in advance for any help...


Solution

  • The main problem with your code is that you were trying to make/modify html by creating a text node. Text nodes do not get parsed as dom.

    This should work for you:

    JSFiddle

    function insertNodeAtRange() {
        var newRange = rangy.getSelection().getRangeAt(0);
        var parentElement = newRange.commonAncestorContainer;
        if (parentElement.nodeType == 3) {
            parentElement = parentElement.parentNode;
        }
        var el = document.createElement('newnote');
        el.className = "bold";
        el.appendChild(document.createTextNode(" Test "));
        newRange.insertNode(el);
        if (parentElement.tagName == 'SPAN') {
            var $newnote = $(el);
            var $span1 = $("<span>");
            var $span2 = $("<span>");
            var left = true;
            $parentElement = $(parentElement);
            $parentElement.contents().each(function (i, node) {
                if (node.isSameNode(el)) {
                    left = false;
                } else if (left) {
                    $span1.append(node);
                } else {
                    $span2.append(node);
                }
            });
            $parentElement.replaceWith($newnote);
            $span1.insertBefore($newnote);
            $span2.insertAfter($newnote);
        }
    }
    

    I just went ahead and inserted the newnote element right away, then got the stuff before that and put it into span1, got the stuff after it and put it into span2, replaced the existing span with newnote and positioned the new spans around newnote.