I have been working on something I am calling JS-Proofs (or jPaq Proofs). While working on the menu I was faced with the annoying issue of either not having whitespaces between my elements in the markup or removing them some other way. Since my favorite language is JS, I decided to write a function that would remove all of the text nodes with whitespaces for me. This evolved into a more general function which retrieves an array of all the text nodes contained by a given element:


/**
 * Gets an array of the matching text nodes contained by the specified element.
 * @param  {!Element} elem
 *     The DOM element which will be traversed.
 * @param  {function(!Node,!Element):boolean} opt_fnFilter
 *     Optional function that if a true-ish value is returned will cause the
 *     text node in question to be added to the array to be returned from
 *     getTextNodesIn().  The first argument passed will be the text node in
 *     question while the second will be the parent of the text node.
 * @return {!Array.}
 *     Array of the matching text nodes contained by the specified element.
 */
function getTextNodesIn(elem, opt_fnFilter) {
  var textNodes = [];
  if (elem) {
    for (var nodes = elem.childNodes, i = nodes.length; i--;) {
      var node = nodes[i], nodeType = node.nodeType;
      if (nodeType == 3) {
        if (!opt_fnFilter || opt_fnFilter(node, elem)) {
          textNodes.push(node);
        }
      }
      else if (nodeType == 1 || nodeType == 9 || nodeType == 11) {
        textNodes = textNodes.concat(getTextNodesIn(node, opt_fnFilter));
      }
    }
  }
  return textNodes;
}

What is kind of cool about the above function is that it not only allows you to get all of the child text nodes, but all descendant text nodes. This function also provides the capability of specifying an optional filtering function to just return text nodes that match a criteria. The function will be passed the text node in question and the parent of that text node. In order to specify that the text node should be added to the array returned from getTextNodesIn you must return a true-ish value.

The following is an example of how to use this function in order to remove all whitespace text nodes from an element:


var menu = document.getElementById('divMenu');
getTextNodesIn(menu, function(textNode, parent) {
  if (/^\s+$/.test(textNode.nodeValue)) {
    parent.removeChild(textNode);
  }
});

In the strictest sense I am actually kind of hacking the new function that I defined but it gets the job done. šŸ˜Ž


2 Comments

Navin Samuel · March 16, 2017 at 1:21 AM

You can use the TreeWalker APIs for this.

function textNodesUnder(el){
var n, a=[], walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
while(n=walk.nextNode()) a.push(n);
return a;
}

Ref: http://stackoverflow.com/questions/10730309/find-all-text-nodes-in-html-page

    Jan Varga · September 29, 2020 at 6:20 AM

    createTreeWalker is deprecated for some reason

Leave a Reply

Your email address will not be published. Required fields are marked *