Recovering a range using Node, startOffset, and endOffset

I am trying to rebuild a Range() object in a client browser using websites.

https://jsfiddle.net/k36goyec/

First I get a Range object in my browser and Node where the range starts:

 var range = window.getSelection().getRangeAt(0); var node = range.startContainer 

I pass three parameters through websockets to the range-building function in the client browser.

 var text = node.parentNode.textContent; var startOffset = range.startOffset var endOffset = range.endOffset 

this data is passed to my buildRange function:

 /** * */ buildRange: function(text, startOffset, endOffset){ var node = this.getNodeByText(text); // get the Node by its contents var range = document.createRange(); range.setStart(node, startOffset); range.setEnd(node, endOffset); span = document.createElement('span'); span.style.backgroundColor = this.color; $(span).addClass('hl'); range.surroundContents(span); }, 

As you can see below, I get a node in the client browser, iterating over all the elements on the page and comparing its contents with the text:

 /** * */ getNodeByText: function(text){ var all = document.getElementsByTagName("*"); for (var i = 0; i < all.length; i++) { if (all[i].textContent === text) { return all[i]; } } }, 

I use setStart () and setEnd () to set the range of my selection to node.

Problems!

range.startOffset / endOffset indicates the following:

If startNode is a node of type Text, Comment, or CDATASection, then startOffset is the number of characters from the beginning of startNode. For other types of nodes, startOffset is the number of child nodes between the start of startNode.

When I select a range of text, I get the following error:

 IndexSizeError: Index or size is negative or greater than the allowed amount 

This is because I pass the offset as 0, 10 (10 characters selected), but the node is a node element, not the text node.

I just can't reliably get the node text, I can only get the node element itself ...

IN:

How can I reliably rebuild a range using node and offsets?

+7
javascript dom html range
source share
2 answers

Others have already pointed out that the immediate problem you are facing is that when you save the range data, you get an offset into the node text, but when you try to recreate the range, you use the offset as an index into the element and it crashes. If you fix this, you will fix your immediate problem.

Your overall approach, however, is fragile.

Consider a document with this:

 <p>Farmer John has a thousand <b>goats</b></p> <p>and his <b>goats</b> ate all his oats.</p> 

Some problems from my head:

  • If you select the 2nd “goat”, your algorithm recreates the range for the first “goats”, because it only searches for an element that has the same text as the original range.

  • If you select a range starting with "and" in the second line and ending with "ate", the offsets that you get from your original range are indexed in two different text nodes: one text node that contains the text and his and the second text node that contains the text ate all his oats. . Your algorithm assumes that only one note is restored at the destination. There may be more than one.

    The same problem occurs if you have a choice that starts with one in bold and ends outside.

To have something reliable, you need to serialize a range at the beginning that records enough information to ensure accurate deserialization at the destination.

There are many ways to do this. One way could be to ensure that the same DOM structure is present at the beginning and at the destination, and use the Rangy library serialization module to perform serialization and deserialization. If you can provide the same DOM structure from both ends, this is what I would use.

If you cannot provide the same DOM structure at both ends, you will have to collapse yourself. You must identify anchor points that are the same at both ends, and identify the beginning of the node / offset and the end of the node / offset of the range relative to these control points.

+2
source share

The solution to this problem:

I just can't reliably get the node text, I can only get the node element itself ...

To get the actual text of the node, you can use the element's .childnodes property. If you have more than one, you can check for nodeType to indicate which text nodes. To find out what is in any node text, check the nodeValue property.

+1
source share

All Articles