How to wrap part of the whole text_node nodeValue object in an html element?

I repeat all node text in an html document to surround some words with a specific range.

The change nodeValuedoes not allow me to embed html. spanescaped to display in plain text, and I don't want that.

Here is what I still have:

var elements = document.getElementsByTagName('*');

for (var i = 0; i < elements.length; i++) {
  var element = elements[i];

  for (var j = 0; j < element.childNodes.length; j++) {
    var node = element.childNodes[j];

    if (node.nodeType === Node.TEXT_NODE) {
      node.nodeValue = node.nodeValue.replace(/Questions/, "<span>Questions</span>");
    }
  }
}
<p>Questions1</p>
<p>Questions 2</p>
<p>Questions 3</p>
<p>Questions 4</p>
Run codeHide result
+4
source share
3 answers

I think you need to rewrite all the DOM and every match ... look here:

function replacer(node, parent) { 
  var r = /Questions/g;
  var result = r.exec(node.nodeValue);
  if(!result) { return; }
  
  var newNode = this.createElement('span');
  
  newNode.innerHTML = node
    .nodeValue
    .replace(r, '<span class="replaced">$&</span>')
  ;
  
  parent.replaceChild(newNode, node);
}


document.addEventListener('DOMContentLoaded', () => {
  function textNodesIterator(e, cb) {
    if (e.childNodes.length) {
      return Array
        .prototype
        .forEach
        .call(e.childNodes, i => textNodesIterator(i, cb))
      ;
    } 

    if (e.nodeType == Node.TEXT_NODE && e.nodeValue) {
      cb.call(document, e, e.parentNode);
    }
  }

  document
    .getElementById('highlight')
    .onclick = () => textNodesIterator(
    document.body, replacer
  );
});
.replaced {background: yellow; }
.replaced .replaced {background: lightseagreen; }
.replaced .replaced .replaced {background: lightcoral; }
<button id="highlight">Highlight</button>
<hr>
<p>Questions1</p>
<p>Questions 2</p>
<p>Questions 3</p>
<p>Questions 4</p>
<p>Questions 5 Questions 6</p>
<div>
  <h1>Nesting</h1>
  Questions <strong>Questions 4</strong>
  <div> Questions <strong>Questions 4</strong></div>
  
  
  <div> 
    Questions <strong>Questions 4</strong>
    
  <div> Questions <strong>Questions 4</strong></div>
  </div>
</div>
Run codeHide result
+2
source

Finally, I could do this without adding extra markup, apart from the required range:

Update

jsFiddle

var elements = document.body.getElementsByTagName('*');;

for (var i = 0; i < elements.length; i++) {
  var element = elements[i];

  for (var j = 0; j < element.childNodes.length; j++) {
    var node = element.childNodes[j],
      par = node.parentElement;

    // as well as checking the nodeType as text, we make sure the 
    // parent element doesn't have the class "foo", so that we only
    // wrap the keyword once, instead of being in a loop to infinity
    if (node.nodeType === Node.TEXT_NODE && !par.classList.contains('foo')) {
      updateText(node, par);
    }
  }
}

function updateText(el, par) {
  var nv = el.nodeValue,
    txt = nv.replace(/Questions/g, '<span class="foo">Questions</span> ');

  // replace the whole old text node with the new modified one
  // and inject it as parent HTML
  par.innerHTML = par.innerHTML.replace(nv, txt);
}
.foo {color: white; background-color: green; padding: 5px;}
<div id="wrapper">
  this is test looking for the the word Questions.
  <br>
  <div id="test">
    <p>Lorem ipsum dolor Questions sit amet, <strong>consectetur</strong> adipisicing elit.</p>
    <p>Questions 1</p>
    <p>Questions 2</p>
    <p>Questions 3</p>
    <p>Questions 4</p>
  </div>
  <div>Lorem ipsum dolor sit amet, Questions consectetur adipisicing elit. Ipsa sed Questions ratione dolorem at repellendus animi eveniet similique repellat, sequi rem numquam debitis sit reprehenderit laborum dicta omnis iure quidem atque?</div>
</div>
Run codeHide result
+1
source

, , .

, :

document.body.innerHTML = document.body.innerHTML.replaceAll(myVar, "<"+myTag+">"+myVar+</"+myTag+">");

Additional information on fooobar.com/questions/282 / ... and in the comments.

String.prototype.replaceAll = function(search, replacement) {
var target = this;
return target.split(search).join(replacement);
};

document.body.innerHTML = document.body.innerHTML.replaceAll("Questions", "<b>Questions</b>");
<p>Questions1</p>
<p>Questions 2</p>
<p>Questions 3</p>
<p>Questions 4</p>
Run codeHide result

Good example to learn!

-2
source

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


All Articles