The Joy of Browser Selection
By Adrian Sutton
Anyone who’s done much work with JavaScript has probably discovered that the selection APIs are completely different in Internet Explorer vs the rest of the world, what comes as a bit more of a surprise once you start using them in anger is that FireFox is actually quite different to all the other W3C compliant browsers in an important way as well.
If all you ever want to do is retrieve the selection or you only want to work with ranges rather than selection, you’ll probably never encounter this, but as soon as you use window.getSelection().addRange() you’re going to get bitten. The difference is that FireFox will preserve whatever range you give it precisely as you original created it. The other browsers won’t.
Start with a simple document with three paragraphs:
<body> <p>Paragraph 1</p> <p>Paragraph 2</p> <p>Paragraph 3</p> </body>
Create a range where the startContainer and endContainer are the body element:
var range = document.createRange(); range.setStart(document.body, 0); range.setEnd(document.body, 1);
The range now encompasses the entirety of the first paragraph element – including the actual P element itself, not just the text within. Now add that to a selection:
window.getSelection().addRange(range);
In FireFox this selects the paragraph element, but in Opera, Safari and Chrome the selection is now just the text within the paragraph. So in FireFox and only FireFox, the statements below are true:
var selected = window.getSelection().getRangeAt(0); selected.startContainer === range.startContainer === document.body; selected.endContainer === range.endContainer === document.body;
This isn’t an arbitrary change by Opera, Safari and Chrome – as far as I can tell, they really can’t select actual elements, only textual ranges. So if you add a range that includes elements, the selection winds up encompassing just the text of those elements and that’s correctly reflected in the range the selection returns. I’m unsure which behavior is correct or whether this is just a missing part of the standard altogether. It appears that the whole concept of a selection object is an old Netscape 4 thing that has never actually been defined1{#footlink1:1271874401380.footnote}.
Unfortunately, selection is one of those surprisingly difficult concepts to get right in any rich text editor due to the complexity of what users want to select and how that affects the operations they will then perform. With these kinds of differences in browser behavior, JavaScript based editors really are fighting an uphill battle that they shouldn’t have to.
1 – Range has been defined by the W3C, but the selection object doesn’t appear to have been.↩