You noticed an error in which Gecko / Firefox and Presto / Opera incorrectly chose the node that the mouse cursor clicked into, although they did not. What to expect? It happens that if a click is registered less than a HALF character (although it exceeds 0 pixels), it is NOT VISUALLY selected. HOWEVER Firefox and Opera still choose node itself! Trident / IE and WebKit (Chrome / Safari) do not.
I struggled with this error for a while, filed a mistake in Mozilla (I canβt remember if I did it with Opera, as it was last year), and today, finally, it is written directly to the editors of the DOM4 specification, asking them to clarify EXPLICIT for browser providers on how to define startContainer
.
You can adapt the code to handle this, but I donβt have time to write all the code for you.
Here is a list of the methods we will use ...
window.getSelection().getRangeAt(0).startContainer; window.getSelection().anchorNode window.getSelection().focusNode
It is VERY important to remember that anchorNode is not EXPLICITLY left source position, although INITIAL CLICK. If the user clicks on the right side of the text and drags the mouse to the left, then the anchor ends on the right side of the range. If the user clicks on the left side of the text and then drags the mouse to the right, then the anchor is on the left side of the range.
Essentially, you can try to make sure that neither anchorNode nor focusNode
EXPLICITLY match 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 do not need startContainer
in ALL situations, you are still going to reference it. It is best to use an object to represent startContainer
if it is right the first time (Trident / WebKit), or you should fix it (Gecko / Presto).
This is where it gets a little complicated, especially because different people will have different goals and approaches, so I will try to keep the following as general as possible.
Either you can determine the correct startContainer
using the anchorNode
or focusNode
, or you can use object detection methods and W3C compatible methods. These 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 using style elements like s
(strike), strong
, em
(highlight), etc. you can access the firstChild
with firstChild
if you don't have several style elements wrapped around the text.
.nextSibling.firstChild .nextSibling.firstChild.nodeValue <em>textNode here</em>
If you find it difficult to determine which methods are available in those parts that I recommend using the in operator. In the example ...
for (i in window.getSelection()) { document.getElementById('textarea_example').value = document.getElementById('textarea_example').value+'\n'+i; }
... keep in mind that if you are inside a loop, it can repeat the parameters in the textarea element, so CTRL + f for the first method and remove the second instance down to save only the corresponding methods.
Remember to use an alert, and I often use multiple lines to simultaneously display multiple pieces of information to help me determine what I have. In the 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);}
If you find this answer suitable to help you move in the right direction, vote to accept this answer so that others can find it and find out the causes of the problem, so that they can also skip disappointment and get the solution working.