Range object: differences between Webkit and Mozilla based browsers

匆匆过客 提交于 2019-12-04 06:24:22
Tim Down

There is no rule that says selection boundaries must be expressed in terms of text nodes. Consider a selection inside an element that contains only <img> elements, for example. So, what you're calling bugs in Mozilla are not bugs at all; in fact, WebKit's selection handling is much buggier than Mozilla's. However, your observation that browsers vary in precisely where they consider a selection boundary to lie when it is at the end of a text node is valid and does complicate things. The best way to deal with it really depends on what you're trying to do, which isn't clear from your question.

If you want selection boundaries purely in terms of character offsets within the text content of an element, you can do this (although I'd generally recommend against it for reasons laid out in the linked answer).

Finally, as author of Rangy, I'd like to point out that it's based on the same APIs (DOM Range and Selection) that browsers implement, so I'd say it's no more or less complicated than those APIs. References:

  • Selection (work in progress)
  • DOM 2 Range (implemented by current versions of all major browsers)
  • DOM4 Range (successor to DOM 2 Range, work in progress)
John

You are noticing a bug where Gecko/Firefox and Presto/Opera incorrectly select the node in which the mouse cursor clicked though did not select. Wait, what? What happens is that if the click registers less than HALF of a character (though greater than 0 pixels) it is not VISUALLY selected HOWEVER Firefox and Opera still select the node itself! Trident/IE and WebKit (Chrome/Safari) do not do this.

I have been battling against this bug for some time, filed a bug at Mozilla (can't remember if I did so with Opera since this was last year) and today finally wrote directly to the editors of the DOM4 specification asking them to implement an EXPLICIT clarification for browser vendors on how to define the startContainer.

It IS possible to adapt the code to handle this however I do not have the time to write out all the code for you.

Here is the list of methods we'll use...

window.getSelection().getRangeAt(0).startContainer;

window.getSelection().anchorNode

window.getSelection().focusNode

It's VERY important to remember that the anchorNode is not EXPLICITLY the left starting position though the INITIAL CLICK. If the user click on the right side of text and drags the mouse to the left then the anchor ends up on the RIGHT side of the range. If the user click on the left side of text and then drags the mouse to the right the anchor is then on the left side of the range.

Essentially what you can try to do is see if neither the anchorNode nor the focusNode EXPLICITLY match the startContainer.

var sc = window.getSelection().getRangeAt(0).startContainer;
var an = window.getSelection().anchorNode
var fn = window.getSelection().focusNode

if (sc!==an && sc!==fn) {alert('startContainer bug encountered!');}

Even if you don't need the startContainer in ALL situations you're still going to eventually reference it SO it's best to use an object to represent the startContainer be it if the browser gets it right the first time (Trident/WebKit) or you have to correct it (Gecko/Presto).

This is where it gets a bit tricky especially because different people will have different goals and approaches so I will try to keep the following as generic as possible.

Either you can determine the correct startContainer using anchorNode or focusNode methods OR you can use object detection and W3C compliant methods. Those other methods include....

window.getSelection().getRangeAt(0).startContainer
window.getSelection().getRangeAt(0).startContainer.parentNode
window.getSelection().getRangeAt(0).startContainer.previousSibling
window.getSelection().getRangeAt(0).startContainer.nextSibling
window.getSelection().getRangeAt(0).startContainer.childNodes[]

When dealing with style elements such as s (strike), strong, em (emphasis) and so on you may access the textNode using the firstChild unless you have multiple style elements enclosed around the text.

.nextSibling.firstChild
.nextSibling.firstChild.nodeValue
<em>textNode here</em>

If you're having difficulty with determining what methods are available at what parts I recommending using the in operator. In example...

for (i in window.getSelection())
{
 document.getElementById('textarea_example').value = document.getElementById('textarea_example').value+'\n'+i;
}

...keep in mind that if you're inside of a loop that it may repeat the options in your textarea element so CTRL+f for the first method and erase from it's second instance down to retain only relevant methods.


Remember to use alert and I often use multiple lines to show multiple pieces of information simultaneously to help me determine what I have. In example...

var e1 = scp.nodeName;
if (scp.nextSibling) {var e2 = scp.nextSibling.nodeName;} else {var e2 = 'null';}
var e3 = sc.nodeName;
if (sc.nextSibling) {var e4 = sc.nextSibling.nodeName;} else {var e4 = 'null';}

alert(
'startContainer = '+window.getSelection().getRangeAt(0).startContainer.nodeName
+'\n\n'+
'startContainer = '+window.getSelection().getRangeAt(0).startContainer.nodeValue
+'\n\n'+
e1
+'\n\n'+
e2
+'\n\n'+
e3
+'\n\n'+
e4
+'\n\nanchorNode = '+
window.getSelection().anchorNode.nodeName
+'\n\n'+
window.getSelection().anchorNode.nodeValue
+'\n\nfocusNode = '+
window.getSelection().focusNode.nodeName
+'\n\n'+
window.getSelection().focusNode.nodeValue
);

if (e2=='#text') {alert('e2 = '+scp.nextSibling.nodeValue);}
if (e4=='#text') {alert('e4 = '+scp.nextSibling.nodeValue);}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!