Search code examples
javascriptjqueryrangeselectionwysihtml5

Replace certain last words typed with html in contenteditable div


I'm trying to replace certain keywords in a content-editable div with hyper-links on the fly as the user is typing. I have it working great with the first word they type by first splitting the entire string by " ", then grabbing the most recent word and if it's one of my keywords, I find the start index and end index in the entire string then do:

range.setStart(myDiv.firstChild, startOfWordIndex);
range.setEnd(myDiv.firstChild, endOfWordIndex);
range.deleteContents();
range.insertNode(...);

where the node I'm inserting is a hyper-link I've created but didn't type it all out here for brevity's sake.

My problem is, after that node is inserted, I can no longer use the myDiv.firstChild in my setStart() method because I new have new nodes in front of where the user is typing.

This is my first crack at content-editable html so I'm not sure how to grab the last node nor am I sure that using the start and end indices of my word would work there anyway since those are based on the entire length of the div contents.

Any help would be most appreciated.


Solution

  • After some sleep, I got this sorted out on my own: Heavily commented in case in can help someone else.

    function replaceLastWordWithLink(editContent) {
        var selection, selectedRange, range, node, frag, el, selectionText, wordStart, wordEnd, currentWord;
        // set the selection
        selection = window.getSelection();
        // set the range by the cursor
        selectedRange = selection.getRangeAt(0);
        // set the "global" range
        range = document.createRange();
        // get all node contents of global range
        range.selectNodeContents(editContent);
        // get the node the cursor is in
        node = selectedRange.startContainer;
        // point the global range to node the cusor is in and start of 0
        range.setStart(node, 0);
        // point the global range to node the cursor is in and end of where cursor is
        range.setEnd(node, selectedRange.startOffset);
        // create the fragment for the contents
        frag = range.cloneContents();
        // create a pseudo element to place the fragment in
        el = document.createElement("span");
        // place fragment in pseudo element
        el.appendChild(frag);
        // get the text from the pseduo element
        selectionText = el.innerText;
        // pattern to see if there are spaces
        spacePattern = /\s/;
        if (!spacePattern.test(selectionText)) {
            // no spaces so the start of the word index is at 0
            wordStart = 0;
            // no spaces so end of the word index is just where the cusor is (the total length of the text)
            wordEnd = selectionText.length;
        } else {
            // split off the last word in the text
            currentWord = selectionText.split(/\s/).reverse()[0].toLowerCase();
            // get the start of the word's index in the string
            wordStart = selectionText.lastIndexOf(currentWord);
            // get the end of the word's index by adding start of word index to the word length
            wordEnd = wordStart + currentWord.length;
        }
        // now set the range to the current word
        range.setStart(node, wordStart);
        range.setEnd(node, wordEnd);
        // now remove the current word
        range.deleteContents();
        // now replace the word with the link
        var el = document.createElement("a");
        el.href = "http://www.yahoo.com";
        el.text = selectedText;
        range.insertNode(el);
    }