0

I need to search my entire document for a phone number, and compile a list of elements which have this phone number in them.

However I have encountered afew snags.

  1. I can't simply do document.body.innerHTML and replace the numbers, as this messes up third party scripts.

  2. The following will match the elements, but ONLY if they have the number within them, and nothing else:

    let elements = document.querySelectorAll("a, div, p, li");
    let found = [];
    for (let elm in elements) {
        if (elements.hasOwnProperty(elm)) {
            if (elements[elm].textContent !== undefined && elements[elm].textContent.search("00000 000000") != -1) {
                found.push(elements[elm]);
            }
        }
    }
    

    So the following element will not match:

    <li class="footer__telephone">
        <i class="fa fa-phone" aria-hidden="true"></i>00000 000000
    </li>
    

    Due to having the i tag in there.

  3. Using textContent instead of text also does not work as the parent of an element will then match, but I don't want the parent.

Edit:

<div class="row-block hmpg-text">
      <div class="wrapper">
        <div class="container">
          <div class="row">


            <div class="twelvecol">
                00000 000000
            </div>

          </div>
        </div>
      </div>
    </div>

Lets say the above is my HTML, if I loop through all the elements and test them with testContent then the first is going to be returned as true, to containing my number, but I need the element with the class of twelvecol on it, not the parent which is 4 levels up.

Martyn Ball
  • 4,679
  • 8
  • 56
  • 126
  • Use something like [this](https://stackoverflow.com/questions/2579666/getelementsbytagname-equivalent-for-textnodes) to obtain all text nodes that match your string, then return each text node's parent element. – Phylogenesis May 16 '18 at 10:06
  • 1
    In the example you provided, you will get `li.footer__telephone` as your found element. This is indeed the container of your phone number. What exactly are you trying to find? – samu May 16 '18 at 10:06
  • you can `document.querySelectorAll("*")` – Rainbow May 16 '18 at 10:09
  • @samu this will also get the main `wrapper` as running this through textContent will display ALL the website text. – Martyn Ball May 16 '18 at 10:21
  • 1
    @MartynBall You can always just check just 1 level of textContent, so you will find only related containers. – dfsq May 16 '18 at 10:42
  • @dfsq this won't work, see updated post. – Martyn Ball May 16 '18 at 10:52
  • Yes, it will, you just need to check first level textContent's as I said in my comment. – dfsq May 16 '18 at 10:59

1 Answers1

0

Managed to find an answer, similar to what Phylogenesis said however couldn't get any of them examples working.

function replaceText(el, regex_display, regex_link) {

    // Replace any links
    if (el.tagName === "A") {
        if (regex_link.test(el.getAttribute("href"))) {
            el.setAttribute("href", el.getAttribute("href").replace(regex_link, replacement.replace(/\s/g, '')));
        }
    }
    if (el.nodeType === 3) {
        if (regex_display.test(el.data)) el.data = el.data.replace(regex_display, replacement);
        if (regex_link.test(el.data)) el.data = el.data.replace(regex_link, replacement);
    } else {
        let children = el.childNodes;
        for (let i = 0; i < children.length; i++) {
            replaceText(children[i], regex_display, regex_link);
        }
    }
}

let bodyChildren = document.body.childNodes;

let search_display = new RegExp(search, "g");
let search_link = new RegExp(search.replace(/\s/g, ''), "g");

for (let i = 0; i < bodyChildren.length; i++) {
    replaceText(bodyChildren[i], search_display, search_link);
}
Martyn Ball
  • 4,679
  • 8
  • 56
  • 126