Search code examples
javascriptrangy

rangy fix boundaries


When selecting text there is some variation on exactly where the selection starts and ends as in sometimes it starts at the end of the previous element and sometimes at the start of the textnode. I'm trying to normalize this so it always starts at the beginning of the element containing the text and ends at the end of the element containing the text and make it consistent across browsers.

e.g. <b>mouse></b><i>cat</i>

When selecting "cat", chrome always seems to do the right thing and return a selection with startContainer cat and startOffset 0. Firefox and occasionally IE8 will often start at the end of the previous element (mouse) with startOffset 5

My crude attempt to fix this has not been successful:

  var sr=rangy.getSelection().getRangeAt(0);
  var sc=sr.startContainer;
  if(sc.nodeType!=3||sr.startOffset==sc.length)
    {
    sr.setStartAfter(sc);   //move start to next node in range
    }
  rangy.getSelection().setSingleRange(sr);
  console.log(sr.inspect());

What am I missing?


Solution

  • Ok I think I've cracked it but I am very open to comments or suggestions on how to improve it. Somehow it lacks elegance and I feel there should be a better way. The problem only seems to need fixing in firefox. Chrome and IE8 never seem to select outside the element the text is contained in. Anyway this is what seems to work for me. (so far)

    var sr=rangy.getSelection().getRangeAt(0);
    var sc=sr.startContainer,ec=sr.endContainer;
    if(sc.nodeType!=3||sr.startOffset==sc.length)
      {
      sc=(sc.nextSibling)?sc.nextSibling:sc.parentNode.nextSibling;
      if(sc.nodeType!=3)sc=sc.firstChild;
      sr.setStart(sc,0);
      }
    if(ec.nodeType!=3||sr.endOffset==0)
      {
      ec=(ec.previousSibling)?ec.previousSibling:ec.parentNode.previousSibling;
      if(ec.nodeType!=3)ec=ec.lastChild;
      sr.setEnd(ec,ec.length);
     }
    rangy.getSelection().setSingleRange(sr);
    console.log(sr.inspect());