0

I want to get all the DOM elements in an HTML that doesn't contain any node, but text only.

I've got this code right now:

var elements = document.querySelectorAll("body *");
for(var i = 0; i < elements.length; i++) {
    if(!elements[i].hasChildNodes()) {
        console.log(elements[i])
    }
}

This prints of course elements that have absolutely no content (and curiously enough, iframes). Texts are accounted as a child node, so the .childNodes.length equals 1, but I don't know how to distinguish the nodes from the text. typeof the first node is always object, sadly.

How to distinguish the texts from the nodes?

Sergi Juanola
  • 6,531
  • 8
  • 56
  • 93
  • 2
    Do you want nodeType? https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType – epascarello Feb 13 '18 at 18:24
  • duplicate of https://stackoverflow.com/questions/2579666/getelementsbytagname-equivalent-for-textnodes – Pavlo Feb 13 '18 at 18:30
  • @Pavlo: That's not a duplicate. –  Feb 13 '18 at 18:37
  • @clockwork The function he is looking for is on the page `function nativeSelector() { var elements = document.querySelectorAll("body, body *"); var results = []; var child; for(var i = 0; i < elements.length; i++) { child = elements[i].childNodes[0]; if(elements[i].hasChildNodes() && child.nodeType == 3) { results.push(child.nodeValue); } } }` – Pavlo Feb 13 '18 at 19:35
  • @Pavlo: That function doesn't do what he's asking. As I said, it's not a duplicate. –  Feb 13 '18 at 20:37

2 Answers2

0

You can check for elements that have no .firstElementChild, which means it will only have text (or other invisible stuff).

var elements = document.querySelectorAll("body *");

for (var i = 0; i < elements.length; i++) {
  if (!elements[i].firstElementChild) {
    console.log(elements[i].nodeName)
  }
}
<p>
  text and elements <span>text only</span>
</p>

<div>text only</div>

The script that the stack snippet is included because it also only has text. You can filter out scripts if needed. This will also include elements that can not have content, like <input>.

0

Basically you are looking for leaf nodes of DOM with something inside the textContent property of the leaf node.

Let's traverse DOM and work out our little logic on leaf nodes.

const nodeQueue = [ document.querySelector('html') ];    
const textOnlyNodes = [];
const textRegEx = /\w+/gi;

function traverseDOM () {
  let currentNode = nodeQueue.shift();

  // Our Leaf node
  if (!currentNode.childElementCount && textRegEx.test(currentNode.textContent)) {
    textOnlyNodes.push(currentNode);
    return;
  }

  // Nodes with child nodes
  nodeQueue.push(...currentNode.children);
  traverseDOM();
}

childElementCount property make sure that the node is the leaf node and the RegEx test on textContent property is just my understanding of what a text implies in general. You can anytime tune the expression to make it a btter fit for your use case.

Himanshu Singh
  • 970
  • 2
  • 6
  • 18