Lordking
Lordking

Reputation: 1413

Building editor with DOM Range and content editable

I'm trying to build a text editor using DOM Range. Let's say I'm trying to bold selected text. I do it using the following code. However, I couldn't figure out how I would remove the bold if it's already bolded. I'm trying to accomplish this without using the execCommand function.

this.selection = window.getSelection();
this.range = this.selection.getRangeAt(0);

let textNode = document.createTextNode(this.range.toString());
let replaceElm = document.createElement('strong');

replaceElm.appendChild(textNode);
this.range.deleteContents();
this.range.insertNode(replaceElm);

this.selection.removeAllRanges();

Basically, if the selection range is enclosed in <strong> tags, I'd want to remove it.

Upvotes: 2

Views: 661

Answers (1)

Andrei CACIO
Andrei CACIO

Reputation: 2129

Ok so I drafted this piece of code. It basically grabs the current selected node, gets the textual content and removes the style tags.

// Grab the currenlty selected node
// e.g. selectedNode will equal '<strong>My bolded text</strong>'
const selectedNode = getSelectedNode();

// "Clean" the selected node. By clean I mean extracting the text
// selectedNode.textContent will return "My bolded text"
/// cleandNode will be a newly created text type node [MDN link for text nodes][1]
const cleanedNode = document.createTextNode(selectedNode.textContent);

// Remove the strong tag
// Ok so now we have the node prepared. 
// We simply replace the existing strong styled node with the "clean" one. 
// a.k.a undoing the strong style.
selectedNode.parentNode.replaceChild(cleanedNode, selectedNode);

// This function simply gets the current selected node. 
// If you were to select 'My bolded text' it will return 
// the node '<strong> My bolded text</strong>'
function getSelectedNode() {
    var node,selection;

    if (window.getSelection) {
      selection = getSelection();
      node = selection.anchorNode;
    }
    if (!node && document.selection) {
        selection = document.selection
        var range = selection.getRangeAt ? selection.getRangeAt(0) : selection.createRange();
        node = range.commonAncestorContainer ? range.commonAncestorContainer :
               range.parentElement ? range.parentElement() : range.item(0);
    }
    if (node) {
      return (node.nodeName == "#text" ? node.parentNode : node);
    }
};

I don't know if this is a "production" ready soution but I hope it helps. This should work for simple cases. I don't know how it will react with more complex cases. With rich text editing things can get quite ugly.

Keep me posted :)

Upvotes: 2

Related Questions