I’ll burn this whole city down
In Safari 2.0 (and presumably all versions since 1.3), the javascript method window.getSelection() returns a Selection object, but not the same one that Mozilla/Gecko browsers return. Instead it is more of a bastardization of the DOM’s Range object. Of course, this isn’t documented anywhere. No, I found this by reading the source code for the window.getSelection method itself.
What’s perplexing is that WebCore does have a DOM-compatible Range implementation, and yet window.getSelection() still returns this not-quite Selection object instead. What’s even more amazing, is that the type property of this object (i.e.: window.getSelection().type) returns Range, even though it isn’t a Range! This is probably a bug.
The only workaround I found for this was here and suggests converting the Selection item in Safari to a string and working with it from there, but in my case there’s already code expecting a Range and so that method wouldn’t work. I had to dig to find out what the hell window.getSelection() was returning, and seeing how it was so hard for me to find, I figured I should publish it in case someone else needs it.
To save you the trouble, here’s a table with comparisons of Safari Selection objects properties/methods with the equivalents for the W3C/Mozilla implemented Range object, since that’s basically the equivalent and many of the field values (if not their names) are the same. Using this, you can write Safari specific JS that will pull what you need from Selection in place of a W3C compliant Range object.
| Safari/AppleWebKit | W3C/Mozilla | |
| Properties: | ||
| anchorNode | startContainer | |
| anchorOffset | startOffset | |
| baseNode | startContainer | |
| baseOffset | startOffset | |
| focusNode | endContainer | |
| focusOffset | endOffset | |
| extentNode | endContainer | |
| extentOffset | endOffset | |
| isCollapsed | collapsed | |
| Methods: | ||
| setBaseAndExtent(start, end) | setStart(start) and setEnd(end) | |
| collapse() | collapse() | |
I think I might start a “Friends don’t let friends use Safari” campaign.
Edit: So I ordered a copy of the O’Reilly fifth edition javascript book and they have what might be the best cop-out ever. From page 342, emphasis mine:
function getSelectedText() { if(window.getSelection){ // This techniquge is the most likely to be standardized // getSelection() returns a Selection object, which we do not document. return window.getSelection().toString(); } /* … */ }