Question

I have tried a zillion ways of doing this with rangy and the below is the closest I've come. Works perfectly in chrome and IE8 (as it did many other versions I tried), but firefox steadfastly refuses to play ball.

The test() function is applied to a button which is clicked after some bold text on a page is selected. What I want to see is:

<b>blah</b> or <strong>blah</strong>

be replaced with

<span style='font-weight:bold'>blah</span>

In chrome and FF it works and the console.log lines:

[WrappedRange("blah":0, "blah":4)] [object Text]
[WrappedRange("blah":0, "blah":4)] [object Text] 

BUT in FF:

[WrappedRange("blah":0, "blah":4)] [object Text]
[WrappedRange(<SPAN>[1]:0, <SPAN>[1]:1)] [object HTMLSpanElement]

.

function test()
    {
    var sr=rangy.getSelection().getRangeAt(0);
    var oldParent=sameTextParent(sr);
    console.log(sr.inspect()+" "+sr.commonAncestorContainer);
    if(oldParent)
      {
      var newParent=document.createElement("span");
      newParent.style.fontWeight="bold";

      newParent.appendChild(sr.cloneContents());
      oldParent.parentNode.replaceChild(newParent,oldParent);

      rangy.getSelection().selectAllChildren(newParent);
      sr=rangy.getSelection().getRangeAt(0);
      console.log(sr.inspect()+" "+sr.commonAncestorContainer);
      }
    }
  function sameTextParent(r)
    {
    var s=r.startContainer,e=r.endContainer;
    if(s.nodeType!=3||e.nodeType!=3){console.log("not TEXT node!");return null}
    return (s.parentNode==e.parentNode)?s.parentNode:null;
    }

If anyone can show me the error of my ways such that it will work in FF the way it does in IE8 and chrome, I would be eternally grateful.

Was it helpful?

Solution

This is a browser inconsistency. Not a bad one, in my view, because the selection is reasonable in either case, but it's still an inconsistency. The easiest workaround is to create a range that explicitly selects the text node, which will remain unscathed after being added to the selection in all major browsers. Rather than

rangy.getSelection().selectAllChildren(newParent);

... I suggest

var newRange = rangy.createRange();
newRange.setStart(newParent.firstChild, 0);
var lastChild = newParent.lastChild;
newRange.setEnd(lastChild,
    lastChild.nodeType == 3 ? lastChild.length : lastChild.childNodes.length);
rangy.getSelection().setSingleRange(newRange);

The problem is that WebKit mangles ranges as they are added to the selection. The range you create was the same in all browsers but got altered in some browsers when added to the selection, but not Firefox.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top