Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
474 views
in Technique[技术] by (71.8m points)

javascript - Get the word upon which the caret sits within a contenteditable div?

I am trying to extract a single word from a content editable div at the position, when the mouse is clicked. For example:

Lorem ipsum dolor sit amet, cons|ectetur adipiscing elit. Cras vestibulum gravida tincidunt. Proin justo dolor, iaculis vulputate eleifend et, facilisis eu erat.*

Using the | to represent the caret, the function should return "consectetur".

My code:

window.onload = function () {
        document.getElementById("text-editor").onclick = function () {
            var caretPos = 0, containerEl = null, sel, range;
            if (window.getSelection) {
                sel = window.getSelection();
                if (sel.rangeCount) {
                    range = sel.getRangeAt(0);
                    if (range.commonAncestorContainer.parentNode == this) {
                        caretPos = range.endOffset;
                    }
                }
            } else if (document.selection && document.selection.createRange) {
                range = document.selection.createRange();
                if (range.parentElement() == this) {
                    var tempEl = document.createElement("span");
                    this.insertBefore(tempEl, this.firstChild);
                    var tempRange = range.duplicate();
                    tempRange.moveToElementText(tempEl);
                    tempRange.setEndPoint("EndToEnd", range);
                    caretPos = tempRange.text.length;
                }
            }
            var prevSpace, nextSpace, text = this.innerText;
            
            prevSpace = text.substring(0,caretPos).lastIndexOf(" ");
            nextSpace = text.indexOf(" ", caretPos + 1);
            nextSpace == -1 ? nextSpace = text.length - 1 : false;
            prevSpace++;
            console.log([prevSpace,caretPos,nextSpace].join("|"));
            var word = text.substring(prevSpace, nextSpace);
            //Removes punctuation and whitespace.
            var patt = new RegExp("([A-Za-z0-9']*)","g");
            word = patt.exec(word)[0];
            document.getElementById("current-word").innerHTML = word;
        };
    };

A function is bound to the mouse click event of the contenteditable div, which calculates the caret position and then finds the indexes of the preceding and following space characters (or beginning or end of the string altogether) and uses substring to determine the word. There is a quick regex match to remove punctuation and whitespace and we finally end up with the correct word.

This worked fine, when there was a single text node inside the contenteditable div, but as soon as I started dropping and other assorted tags, the part of the method that calculated the caret position stopped working, always calculating it to be 0. Is there a way to calculate the caret position in HTML like it did with the text?

If not, can anyone suggest an alternate method?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You could use the new TextRange module of my Rangy library for this, although it's enormous overkill just for that one feature. Here's the code you'd need:

var sel = rangy.getSelection();
sel.expand("word");
var word = sel.text();
alert(word);

Otherwise, if you can live with no support for pre-Blink Opera (up to and including version 12) and Firefox < 4, you could use Selection.modify() (WebKit, Firefox) and the expand() method of TextRange (IE). Here's an example.

Demo: http://jsfiddle.net/timdown/dBgHn/1/

Code:

function getWord() {
    var sel, word = "";
    if (window.getSelection && (sel = window.getSelection()).modify) {
        var selectedRange = sel.getRangeAt(0);
        sel.collapseToStart();
        sel.modify("move", "backward", "word");
        sel.modify("extend", "forward", "word");
        
        word = sel.toString();
        
        // Restore selection
        sel.removeAllRanges();
        sel.addRange(selectedRange);
    } else if ( (sel = document.selection) && sel.type != "Control") {
        var range = sel.createRange();
        range.collapse(true);
        range.expand("word");
        word = range.text;
    }
    alert(word);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...