1

I am attempting to use javascript to modify a user's selection of text within a non-editable <div> element using Range.setStart and Range.setEnd. Specifically, I want the user to be able to click a sentence and have my code expand the selection to the sentence containing the click, then highlight (and process) it.

Under Chrome, Firefox, and Edge, when I use these functions to change the selection, the new selection is highlighted in the user's browser window. Under Safari 11 under Mac High Sierra, the Range.* functions correctly alter the selection range, but the user's browser window does not change to reflect this. Either there is no highlighting if the user simply clicks, or if the user clicks and drags the initial highlighting remains unchanged.

So far I've found SO answers on this issue for an <input> field on Mobile Safari, such as Programmatically selecting text in an input field on iOS devices (mobile Safari) but not for an uneditable field on desktop Safari.

I will appreciate any hints, workarounds, bug reports, or other solutions, thanks.

Here is a JSBin demonstrating the problem.

And here is source code. Note that Safari does set the range correctly, but fails to highlight it, whereas Chrome, Firefox, and Edge highlighting track with the new range:

function expandHL (){
   let textSel = window.getSelection();
   let newRange = textSel.getRangeAt(0);
   let node = textSel.anchorNode;

   console.log("Initial selection: " + newRange.toString().trim());
  
   // Find and include start of sentence containing clicked region:
    while (newRange.startOffset !== 0) {                         // start of node
        newRange.setStart(node, newRange.startOffset - 1);     // back up 1 char
        if (newRange.toString().search(/^[.!?:\n]\s*/) === 0) { // start of sentence
            newRange.setStart(node, newRange.startOffset + 1); // move forward char
            break;
        }
    }
  console.log("Final selection: " + newRange.toString().trim());
}
   <h3>Demo of Safari highlighting problem.</h3>
      <h4>
        1. Click in the text below: the range is detected 
        and expanded (see console output).  But it is 
        not highlighted as with Chrome or Firefox.<br><br>
        2. Click and drag on the text below: your initial range 
        is highlighted, then expanded but highlighting does not expand 
        with range as with Chrome or Firefox.  WHY?</h4>
      <hr>
    <div onclick="expandHL()">
    Sed ut perspiciatis unde omnis iste natus error sit voluptatem 
      accusantium doloremque laudantium, totam rem aperiam, eaque 
      ipsa quae ab illo inventore veritatis et quasi architecto beatae
      vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit 
      aspernatur aut odit aut fugit, sed quia consequuntur magni
      </div>
CODE-REaD
  • 2,819
  • 3
  • 33
  • 60

1 Answers1

4

Using this SO answer as a starting point I was able to reverse engineer and solve the problem. Apparently Safari and other browsers such as Edge require additional code to update range highlighting (see my question for details). Adding the following two lines to the above code causes these browsers to do so:

textSel.removeAllRanges();
textSel.addRange(newRange);

I'm not sure whether this has been documented yet; if it has I certainly couldn't find mention of it.

For clarity, here is the final solution which works with Chrome, Firefox, Safari, and Edge:

    function expandHL (){
       let textSel = window.getSelection();
       let newRange = textSel.getRangeAt(0);
       let node = textSel.anchorNode;
    
       console.log("Initial selection: " + newRange.toString().trim());
      
       // Find and include start of sentence containing clicked region:
        while (newRange.startOffset !== 0) {                        // start of node
            newRange.setStart(node, newRange.startOffset - 1);      // back up 1 char
            if (newRange.toString().search(/^[.!?:\n]\s*/) === 0) { // start of sentence
                newRange.setStart(node, newRange.startOffset + 1);  // move forward char
                break;
            }
        }
        console.log("Final selection: " + newRange.toString().trim());
        textSel.removeAllRanges();
        textSel.addRange(newRange);
    }
<h3>Demo of Safari highlighting problem (solved).</h3>
      <h4>
        1. Click in the text below: the range is detected 
        and expanded (see console output).  <del>But it is 
        not highlighted as with Chrome or Firefox.</del><br><br>
        2. Click and drag on the text below: your initial range 
        is highlighted, then expanded but highlighting does <del>not</del> expand 
        with range as with Chrome or Firefox.  <del>WHY?</del></h4>
      <hr>
    <div onclick="expandHL()">
    Sed ut perspiciatis unde omnis iste natus error sit voluptatem 
      accusantium doloremque laudantium, totam rem aperiam, eaque 
      ipsa quae ab illo inventore veritatis et quasi architecto beatae
      vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit 
      aspernatur aut odit aut fugit, sed quia consequuntur magni
      </div>
halfer
  • 19,824
  • 17
  • 99
  • 186
CODE-REaD
  • 2,819
  • 3
  • 33
  • 60