17

I am trying to apply style to the text selected by the user(mouse drag) for which I need to get the start and end index of the selected text.

I have tried using "indexOf(...)" method. but it returns the first occurrence of the selected substring. I want the actual position of the substring with respect to the original string. For example.., if I select the letter 'O' at position 3 [YOLO Cobe], I expect the index as 3 but the indexOf() method returns 1 which is the first occurrence of 'O' in [YOLO Cobe].

Is there any other method of getting the actual start and end index of selected text and not the first occurrence ?

function getSelectionText()
{
    var text = "";
    if (window.getSelection) {
        text = window.getSelection().toString();
    }
    return text;
}
document.getElementById('ip').addEventListener('mouseup',function(e)
{
        var txt=this.innerText;
        console.log(txt);
        var selectedText = getSelectionText();
        console.log(selectedText);
        var start = txt.indexOf(selectedText);
        var end = start + selectedText.length;
        if (start >= 0 && end >= 0){
         console.log("start: " + start);
         console.log("end: " + end);
        }
});
<div id="ip">YOLO Cobe</div>
Keekz
  • 185
  • 2
  • 10

3 Answers3

19

What you are looking for is available inside object returned by window.getSelection()

document.getElementById('ip').addEventListener('mouseup',function(e)
{
        var txt = this.innerText;
        var selection = window.getSelection();
        var start = selection.anchorOffset;
        var end = selection.focusOffset;
        if (start >= 0 && end >= 0){
         console.log("start: " + start);
         console.log("end: " + end);
        }
});
<div id="ip">YOLO Cobe</div>

And here is example for more complex selections on page based on @Kaiido comment:

document.addEventListener('mouseup',function(e)
{
        var txt = this.innerText;
        var selection = window.getSelection();
        var start = selection.anchorOffset;
        var end = selection.focusOffset;
        console.log('start at postion', start, 'in node', selection.anchorNode.wholeText)
        console.log('stop at position', end, 'in node', selection.focusNode.wholeText)
});
<div><span>Fragment1</span> fragment2 <span>fragment3</span></div>
pawelbylina
  • 1,387
  • 10
  • 17
  • 3
    baseOffset is a Chrome quirk. The official property is `anchorOffset`. Also, you may want to point out that these are ordered by the selection order (that is if you selected from right to left could have `start: 7 end: 2` and also that these indice are relative to their own `[anchor/focus]Node`. They may not be the same node. – Kaiido Jun 13 '19 at 07:11
1

window.getSelection().anchorOffset will give you the index that you are looking for.

MDN link: https://developer.mozilla.org/en-US/docs/Web/API/Selection/anchorOffset

Kaisar
  • 53
  • 5
-4

I tried using the anchorOffset and focusOffset from the getSelection() method and it wasn't giving me the desired index.

So I came up with this solution myself (Note: it worked in chrome, don't know about other browsers)

HTML

<input type="text" class="input" hidden />
<textarea> remind me to be here to morrow </textarea>

JS

let text = document.querySelector("textarea");
let input = document.querySelector(".input");

In this instance, "here to morrow" is the highlighted portion.

For the selected text I did

input.value = getSelection();
let selectedText = input.value;

For the starting index of the selected text, I did

let start = body.value.indexOf(getSelection());
let end = start + selectedText.lenght;

Hope this proves useful

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103