0

Let's say I have a DIV containing text, like so:

<div>
Hello world

test

Hello world

test 2

Hello world
</div>

My function for getting the word when selecting the text is:

function getWord() {
    var txt = document.getSelection();
    var txtRange = txt.getRangeAt(0);
    return txtRange;
}

Let's say I select the middle "Hello world", which is the 2nd occurrence. How do I get the occurrence, which in this case would be 2?

Gregory R.
  • 1,815
  • 1
  • 20
  • 32

3 Answers3

1

You can try following code.

document.addEventListener('selectionchange', (evt) => {
  var selection=document.getSelection();
  var selectedText = selection.getRangeAt(0).toString();
  var divText=document.getElementById("mydiv").innerText;
  var totalOccurance=(divText.match(new RegExp(selectedText, "g")) || []).length;
  console.log(totalOccurance)
});
<div id="mydiv">
Hello world

test

Hello world

test 2

Hello world
</div>

If you want to ignore enter too then you following code

document.addEventListener('selectionchange', (evt) => {
  var selection=document.getSelection();
  var selectedText = selection.getRangeAt(0).toString().replace(/\n/g, " ");
  var divText=document.getElementById("mydiv").innerText.replace(/\n/g, " ");
  var totalOccurance=(divText.match(new RegExp(selectedText, "g")) || []).length;
  console.log(totalOccurance)
});
<div id="mydiv">
Hello world

test

Hello world

test 2

Hello world
</div>

If You want to find out which one word you selected then use this example

Example 3

document.addEventListener('selectionchange', (evt) => {
  var selection=document.getSelection();
  if(selection){
  var selectedText = selection.getRangeAt(0).toString().replace(/\n/g," ").replace(/ +(?= )/g,'');
  var divText=document.getElementById("mydiv").innerText.replace(/\n/g," ").replace(/ +(?= )/g,'');
  if(selectedText){
var reg=new RegExp(selectedText, "g");
var array1 = reg.exec(divText)
var index=[];
while (array1 !== null) {
  index.push(array1.index);
  array1 = reg.exec(divText)
}
var position=selection.anchorOffset-1;
var p=index.filter(x=>x<=position)
console.log(p.length);
   }
  }
});
   
<div id="mydiv">
Hello world

test

Hello world

test 2 

Hello world
</div> 

Codepen Link

https://codepen.io/hackersourabh/pen/dyMWKVm?editors=1011

Sourabh Somani
  • 2,138
  • 1
  • 13
  • 27
  • This gets the total number of occurrences. I'm looking to get the occurrence of the selected. For example, if I select the first "Hello world", i want it to return 1. If the 2nd "Hello world", then 2; and so on. Thank you. – Gregory R. Aug 27 '20 at 18:27
  • Okay got it. let me change it – Sourabh Somani Aug 27 '20 at 18:29
  • I have done could you please check last example @GregoryR. – Sourabh Somani Aug 27 '20 at 20:13
  • Ok, I tried it out. Works most of the time, but I encountered some problems. When I try the word "test", sometimes it returns 0, and sometimes I get an error: Uncaught IndexSizeError: Failed to execute 'getRangeAt' on 'Selection': 0 is not a valid index. at pen.js:-15 – Gregory R. Aug 27 '20 at 20:27
  • Only two things I am doing from `selection` I am getting **offset** second from the `regex` I am keeping **index** – Sourabh Somani Aug 27 '20 at 20:30
  • I have added one if condition – Sourabh Somani Aug 27 '20 at 20:32
  • I think it's even worse now. I'm still getting the error sometimes and try selecting the word "test". You'll see it's returning index 0 for both the 1st or 2nd word. – Gregory R. Aug 27 '20 at 20:42
  • Hi Could you please check one more time I got this issue so I replaced `'\n'` with space `replace(/\n/g," ")` because when you was selecting \n on that time you was also on that time you have `\n` with you – Sourabh Somani Aug 28 '20 at 19:02
  • You can also run 3rd example – Sourabh Somani Aug 28 '20 at 19:18
0

The concept is to get the index of the selected string and then compute the occurrence index. Fiddle Link

<div id="mydiv" onmouseup="alert(getOccuranceIndex(this));"
onmousedown="prepare(this)>
Hello world

test

Hello world

test 2

Hello world
</div>


var getOccuranceIndex= (function() {

    function getSel() {
        var sel = null;
        if (
            typeof document.selection != "undefined" &&
            document.selection &&
            document.selection.type == "Text"
        ) {
            sel = document.selection;
        } else if (
            window.getSelection &&
            window.getSelection().rangeCount > 0
        ) {
            sel = window.getSelection();
        }
        return sel;
    }

    function createRangeFromSel(sel) {
        var rng = null;
        if (sel.createRange) {
            rng = sel.createRange();
        } else if (sel.getRangeAt) {
            rng = sel.getRangeAt(0);
            if (rng.toString() == "") rng = null;
        }
        return rng;
    }

    return function(el) {
        var sel = getSel(),
            rng, r2, i = -1;
        if (sel) {
            rng = createRangeFromSel(sel);
            if (rng) {

                if (rng.parentElement) {
                    if (rng.parentElement() == el) {
                        r2 = document.body.createTextRange();
                        r2.moveToElementText(el);
                        r2.collapse(true);
                        r2.setEndPoint("EndToStart", rng);
                        i = r2.text.length;
                    }
                } else {
                    if (
                        rng.startContainer &&
                        rng.endContainer &&
                        rng.startContainer == rng.endContainer &&
                        rng.startContainer == rng.commonAncestorContainer &&
                        rng.commonAncestorContainer.parentNode == el
                    ) {    
                        i = rng.startOffset;
                    }
                }
            }
        }
                if(i<1) return 1;
        var actualString = el.innerHTML;
                var target = getSel().toString();
console.log(target);
            var reg = new RegExp(target, 'gi');
                var resArr = actualString.substring(0,i-1).match(reg);
            if(resArr==null) return 1; //this is the first occurance;
            return resArr.length+1;
    };

})();

function prepare(el) {
    if (el.normalize) {
        el.normalize();
    }
}

This helped a lot https://bytes.com/topic/javascript/answers/153164-return-selectionstart-div

  • I tried this one but was having issues. It was always returning 1, and didn't work for text in multiple lines separated by
    . I have posted a solution that works well. Thank you.
    – Gregory R. Aug 28 '20 at 14:45
0

I have the solution:

function getWord() {
    var txt = document.getSelection();
    var txtRange = txt.getRangeAt(0);
    return txtRange;
}

var t = getWord();
var text = document.getElementsByClassName("content")[0];
var precedingRange = document.createRange();
    precedingRange.setStartBefore(text.firstChild);
    precedingRange.setEnd(t.startContainer, t.startOffset);

var textPrecedingSelection = precedingRange.toString();
var count = (textPrecedingSelection.match(new RegExp(t.toString().trim(), 'gi')) || []).length + 1;

alert("Word occurrence: " + count);
Gregory R.
  • 1,815
  • 1
  • 20
  • 32