Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging Text Nodes Together After Inserting Span

I have an extension where I am storing/retrieving a section of the DOM structure (always a selection of text on the screen) the user has selected. When I am storing a selection, I enclose the section in a SPAN tag, and highlight the text in yellow. This causes the DOM structure around the selected text to split up into various text nodes. This causes a problem for me as when I try to restore this selection (without refreshing the page) it causes problems as the DOM structure has been modified.

My question is how do I prevent the DOM structure from splitting up after inserting the SPAN? If this cannot be achieved, how would I reassemble the DOM structure after removing the SPAN tag to its original state?

//Insert the span
var sel = restoreSelection(mootsOnPage[i].startXPath);
var range = sel.getRangeAt(0).cloneRange();
var newNode = document.createElement('span');
newNode.className = 'highlightYellow';
range.surroundContents(newNode); 


//Original DOM structure
<p>Hello there, how are you today</p>


//What the DOM looks like after insertion of SPAN
<p>
  "Hello there, "
  <span class="highlightYellow">how</span
  " are you today"
</p>
like image 818
Jon Avatar asked Mar 24 '12 05:03

Jon


3 Answers

Use element.normalize().

After you remove the span you inserted, you can use the element.normalize() method to merge the extra text nodes that were created as a result of the insertion/removal of the span. The normalize() method puts the specified element and all of its subtree into a "normalized" form (i.e. no text nodes in the subtree are empty and there are no adjacent text nodes). Found, thanks to @tcovo's comment.

Text nodes inside of an element are broken apart if you insert nodes and then remove them. Unfortunately they don't automatically re-merge once the extra node is removed. To answer peoples' questions as to "why" this matters, it usually causes issues when working with text highlighting in your UI.

like image 171
trip41 Avatar answered Nov 20 '22 16:11

trip41


The very act of inserting a <span> tag will alter the DOM. That's, somewhat by definition, what you're doing when you call surroundContents(). You can't add a span tag without altering the DOM which includes splitting text nodes and adding new elements for the span.

Further, unless the selected text includes only whole text nodes and the selection never starts/stops in the middle of a text node, you will have to split text nodes to put the span in the right place. When you later remove the span tags, you will have extra text nodes. That shouldn't really matter to anything, but if you really think you have to get the split text nodes back to the way they were, I can think of a couple options:

1) Save the original parentNode before the span is inserted into it. Clone it, add your span to the clone, replace the original node with the clone and save the original. When you want to restore, put the original back and remove the cloned one.

2) When you remove the span, run a function that looks for neighboring text nodes and combine them.

3) Figure out why it matters that there are more text nodes afterwards than there were before because this should not matter to any code or display.

like image 31
jfriend00 Avatar answered Nov 20 '22 16:11

jfriend00


When using normalize() pay attention! It will strip away nodes like <br/> and will alter the text and its visualisation.

normalize() is good, but it has its drawbacks.

So <p>"this is an "<br/>"example"</p> will turn into <p>this is an example</p>

Is there a way to use normalize() but keeping the <br/>s?

like image 3
Tom Oeser Avatar answered Nov 20 '22 16:11

Tom Oeser