views:

817

answers:

2
<script>
    var is_gecko = /gecko/i.test(navigator.userAgent);
    var is_ie    = /MSIE/.test(navigator.userAgent);

    function insertNodeAtSelStart()
    {
     if(is_gecko)
     {
      var S = window.getSelection();
      if(!S.isCollapsed)
      {
       var R = S.getRangeAt(0);
       var R1 = R.cloneRange();
       var NN = document.createElement("startMarker");
       R1.insertNode(NN);
       NN.parentNode.removeChild(NN);
      }
     }

     if(is_ie)
     {
      // IE-specific code
     }
    }
</script>

<div>
    <span>one two three</span>
</div>

<input type="button" value="Insert node at selection start" onclick="insertNodeAtSelStart();" />

The first time I click the button after loading the page and selecting some text, Firefox clears the selection. Subsequently, it does not. Is this a bug in my code or in Firefox?

+3  A: 

Firefox clears the selection when you disturb it by successfully inserting the Node inside its start point.

For me, a second click sometimes (depending on what range of text is selected) fails with a:

Error: uncaught exception: [Exception... "Index or size is negative or greater than the allowed amount"  code: "1" nsresult: "0x80530001 (NS_ERROR_DOM_INDEX_SIZE_ERR)"  location: "..."]

on the insertNode call. Since the insertion is unsuccessful the selection is not cleared. Presumably this is what is happening for you — check your Error Console.

This failure does appear to be a Firefox bug. I can't quite track down the exact conditions that trigger it, but it is to do with what node boundaries are in the selection.

I can make your example always work (and clear the selection) by calling document.body.normalize() to return the whole span content to a single Text node, after it has been split by the insert/remove cycle.

bobince
Thank you. My opinion is that it should not clear the selection, and the fact that it does clear it the first time is a bug in Firefox. Off to https://bugzilla.mozilla.org/ then, I guess.
matthewk
It's arguable whether the selection collapsing is a bug; certainly other applications do the same thing when a change is made to selected content. It should be possible to remember the old selection range and set it back once you've finished processing.
bobince
OK, I've managed to work out how to remember the old selection range and set it back afterwards, which is good enough. Thanks.
matthewk
+2  A: 

Indeed, you stumbled upon an ugly Gecko bug that keeps crawling back to life for too many years :( And yes, the latest development build still presents this bug.

Anyway, if you don't want to wait for a fix from Mozilla, a simpler/faster workaround would be to collapse the range before inserting the new node.

For conformity, here's the (somehow simplified) sample used for testing your code:

<p id="para">select two or more letters, then </p>
<input id="butt" type="button" value="click me">
<script type="text/javascript">
  if (!window.getSelection)
    throw new Error("MSIE, you're not welcome!");

  var marker = document.createElement('span');
  marker.style.color = '#6C6';
  marker.appendChild(document.createTextNode('|'));

  function insertNodeAtSelStart() {
    // window.getSelection().getRangeAt(0).insertNode(marker.cloneNode(true));
    var r = window.getSelection().getRangeAt(0);
    var n = marker.cloneNode(true);
    r.collapse(true); // workaround for Gecko :(
    r.insertNode(n);  // Gecko sometimes(?!) fails with NS_ERROR_DOM_INDEX_SIZE_ERR
  }
  document.getElementById('butt').onclick = insertNodeAtSelStart;
</script>

OT, that's not "is _ gecko", "is _ not _ ie" would be more appropriate, as this code should run as expected on every browser except MSIE ;-)

altblue
+1 good alternative workaround
bobince