JS - surroundContents saves only text selection about 20% of selection attempts

I use the mouseup event to fire a function that selects text and surrounds the selected text with span (function from):

function highlightText(e) { var t = window.getSelection().toString(); if (t) { $("#mySpan").remove(); var range = window.getSelection().getRangeAt(0); newNode = document.createElement("span"); newNode.id = 'mySpan'; range.surroundContents(newNode); } } 

The main problem that I am facing is that as long as surroundContents is turned on, the text remains highlighted only about 20% of the selection attempts (otherwise the highlight disappears immediately). I tried adding setTimeout without calling surroundContent for 1s. I also tried removing the remove () statement, but still no good.

Any ideas on why this is happening?

+7
javascript highlighting
source share
2 answers

I had the same issue with Chromium on Android. In some specific cases, calling range.surroundContents(newNode) causes a very strange page reload behavior and so on. After checking the function documentation :

This method is almost equivalent to newNode.appendChild (range.extractContents ()); range.insertNode (newNode). After surrounding the boundary points, the range includes newNode.

Thus, it was obvious to apply a different way of highlighting the text. I found mark.js library that did exactly what I wanted without this annoying side effect. (Here's a JSFiddle sample that shows how it used to highlight only the selection). The difference is that the library did not use range.surroundContents(newNode) and newNode.appendChild , but rather node.replaceChild .

Based on this, here is the solution to the problem that I had, and I think this applies to your case.

 function surroundRangeWithSpan(range) { var span = document.createElement('span'); // The text is within the same node (no other html elements inside of it) if (range.startContainer.isEqualNode(range.endContainer) && range.startContainer.childNodes.length == 0) { // Here you customise your <span> element customSurroundContents(range, span); } else { // Here you have to break the selection down } return span; } function customSurroundContents(range, span) { var node = range.commonAncestorContainer; var startNode = node.splitText(range.startOffset); var ret = startNode.splitText(range.toString().length); span.textContent = startNode.textContent; startNode.parentNode.replaceChild(span, startNode); } 

And you pass window.getSelection().getRangeAt(0) to the function.

+2
source share

The likely cause of the failure is selected text, which includes only the beginning or end of a non-text node, and not both of them.

So, if this code were run only by selecting β€œThis is Bo” in the following, it would fail (and throw an exception), because it also does not commit the closing tag in the selection:

 This is <em>bold</em> 

So in summary:

 This is <em>bo 

Link: https://developer.mozilla.org/en-US/docs/Web/API/Range/surroundContents

+1
source share

All Articles