0

I'm working on a chrome translate extension that when holding the ctrl key for seconds,the extension get the word under the cursor,translate it,and then display the result on the top of the word.

When dealing with getting the word under the cursor,I first need to create the range of the word under the cursor.I use the following code snippet to achieve this.I reference to here.https://stackoverflow.com/a/3710561/4244369

var getRangeAtPoint = function(elem, x, y) {
    if (elem.nodeType == elem.TEXT_NODE) {
        var range = elem.ownerDocument.createRange();
        range.selectNodeContents(elem);
        var currentPos = 0;
        var endPos = range.endOffset;
        while (currentPos + 1 < endPos) {
            range.setStart(elem, currentPos);
            range.setEnd(elem, currentPos + 1);
            var range_rect = range.getBoundingClientRect();
            if (range_rect.left <= x && range_rect.right >= x &&
                range_rect.top <= y && range_rect.bottom >= y) {
                range.expand("word");
                return range;
            }
            currentPos += 1;
        }
    } else {
        for (var i = 0; i < elem.childNodes.length; i++) {
            var range = elem.childNodes[i].ownerDocument.createRange();
            range.selectNodeContents(elem.childNodes[i]);
            var range_rect = range.getBoundingClientRect();
            if (range_rect.left <= x && range_rect.right >= x &&
                range_rect.top <= y && range_rect.bottom >= y) {
                range.detach();
                var computed_range = getRangeAtPoint(elem.childNodes[i], x, y);
                if(computed_range){
                    return computed_range;
                }
            } else {
                range.detach();
            }
        }
    }
    return (null);
};

After creating the range,I can use range.toString() to get the word and range.getBoundingClientRect() to decide the position to display the result.It works well until I met the following case:

<p>click the <a href='#'>sample words</a> here</p>

If the cursor is under the word "words",it works properly.However,when the cursor is under the word "sample",after calling range.expand('word'),the client rect is wrong,the width of client rect should be the width of "sample",however,it's the width of "sample words".

I also include a jsfiddle here.https://jsfiddle.net/sangelee/1maqmm89/

Is it the problem of range.expand('word')?How to fix it?Or instead of using range.expand('word'),are there any way to achieve this?Any help is appreciated!ps.I'm using chrome 39.

Community
  • 1
  • 1
sangelee
  • 155
  • 1
  • 8

1 Answers1

0

The issue is with range.expand(), as you suspected. Also, the code to get the caret position as a range can be vastly simplified. Example (WebKit only):

https://jsfiddle.net/e5knrLv8/

The console also reveals that range.expand(), which has always been a WebKit-only non-standard method, has been deprecated in favour of Selection.modify(), which unfortunately is a bit of a pain to use in practice. Here is a revised example using Selection.modify, which does fix your issue:

https://jsfiddle.net/e5knrLv8/1/

Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • The `caretRangeFromPoint` method simplified my work a lot !!And your workaround of using `Selection.modify` works perfectly if the following spaces of the word were not included in the selection.@TimDown – sangelee Mar 10 '15 at 03:43
  • How to remove the following spaces of the word after calling `selection.modify('extend','forward','word')`? @Tim – sangelee Mar 11 '15 at 07:12
  • I found that after calling `range.expand('word')`,the range's properties(startOffset,endOffset,startContainer,endContainer) seems to be set correctly.And I also have found this:[https://github.com/edg2s/rangefix](https://github.com/edg2s/rangefix). – sangelee Mar 11 '15 at 09:02