Range Object: Differences Between Webkit and Mozilla Browsers

At the moment I am having problems writing an abstraction level for Mozilla and Webkit browsers to use the DOM range object (getting and processing user settings).

I also tried to look at frameworks such as Rangy, but it seems difficult for my task (I have no idea where in the code I can find the information I need. If someone can give me a hint, I would be grateful!).

I want just:

  • return the link to the text node selection begins and its offset
  • return the link to the text node selection ends and its offset

So far my layer looks like this:

var SEL_ABSTR = { get_selection: function(window_object) { return window_object.getSelection(); }, get_range: function(selection) { return (selection.getRangeAt) ? selection.getRangeAt(0) : selection.createRange(); }, get_range_info: function(range, div_ele) { var first_node, start_offset; var last_node, end_offset; if (range.startContainer == div_ele) { // selections affects the containing div first_node = div_ele.childNodes[0]; last_node = first_node; start_offset = 0; end_offset = first_node.nodeValue.length; } else if (range.startOffset == range.startContainer.nodeValue.length && range.endOffset == 0) { // known bug in Firefox alert('firefox bug'); first_node = range.startContainer.nextSibling.childNodes[0]; last_node = first_node; start_offset = 0; end_offset = first_node.nodeValue.length; } else { first_node = range.startContainer; last_node = range.endContainer; start_offset = range.startOffset; end_offset = range.endOffset; } return { first_node: first_node, start_offset: start_offset, last_node: last_node, end_offset: end_offset, orig_diff: end_offset - start_offset }; }, }; 

I discovered two Mozilla errors:

  • Sometimes, when the entire text (if its only) node is selected in the containing div, I return a link to this div instead of a link to the text node. Now I can process it and return a link to the child div, which is the text node

  • Sometimes I return a link to my previous sister with an offset == prevSibling.length and a link to nextSibling with an offset == 0. But the correct link would be in the middle. I can also handle this.

So what else for Mozilla? Webkit works great!

It should be assumed that the DOM object is standard (and I'm not talking about IE, this is another task ...)

hello!


More details here:

This was not a critical assessment of Ranga. So I'm sorry if that sounds like this. I can imagine that handling these various APIs is not easy in itself.

You are right, I was not defined in relation to the task that I am trying to accomplish. My structure is pretty simple: I have a div (with the attribute contenteditable = true) and the text inside this div (one text node at the beginning).

Starting with this structure, you can now select the text with the mouse and add a property to it; this property is then expressed by the range covering the selected text and the class assigned to this range representing the selected property. Now you can select the text and property again. If it is the same text and another property, another class will be assigned to this range or deleted if the property already exists. If you select text that spans several intervals, they will be separated to express this structure (perhaps you remember my post in July).

 <div contenteditable="true"> hello I am <span class="red">text but I am also <span class="underline">underlined</span></span> <span class="underline"> also without color</span> </div> 

Now the algorithm works fine for "symmetric" cases: I can build a complex structure and then undo it back. It works great for Safari and Chrome. Now, of course, I have to develop an algorithm.

But at the moment I have problems with Mozilla, because I do not understand the system for objects in the DOM range: startContainer, endContainer, startOffset, endOffset

In my perception of my particular case with a div containing only text fields and spaces, I assume:

  • that startContainer and endContainer always point to a text field that is affected by mouse selection (there are no empty spans, they always contain either other intervals or text), marking the beginning and end of the whole selection
  • that startOffset and endOffset indicate the position of the selection in the text box at the beginning and at the end

In the above code, I have identified two cases in which Mozilla acts differently than webkit.

So, if I knew the Mozilla DOM range rules, I could undo this in my layer so that the behavior is the same for webkit and Mozilla.

Thank you very much for your response.

+6
source share
2 answers

There is no rule according to which selection boundaries should be expressed in terms of text nodes. Consider a selection inside an element that contains only <img> elements, for example. So, the fact that you are causing errors in Mozilla is not an error; in fact, handling the WebKit selection is much worse than Mozilla . However, your observation that browsers differ in the place where they consider the selection border to be false when it is at the end of the node text is valid and complicates the situation. The best way to handle this really depends on what you are trying to do, which is unclear from your question.

If you want the selection borders to be purely in terms of character offsets in the text content of the element, you can do this (although I would recommend against it the reasons outlined in the linked answer).

Finally, as the author of Rangy, I would like to point out that it is based on the same APIs (DOM Range and Selection) that are implemented by browsers, so I would say that it is no more or less complicated than these APIs. References:

  • Selection (work in progress)
  • DOM 2 Range (implemented by current versions of all major browsers)
  • DOM4 Range (successor to the DOM 2 range, work in progress)
+3
source

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.

+3
source

Source: https://habr.com/ru/post/897687/


All Articles