Victor
Victor

Reputation: 13388

Replace string in entire document source code

I have a HTML document, with a string that I want to replace. Here are the strings (9673):

<meta property="og:description" content="***April &amp;nbsp;9673&amp;nbsp;" />
<span class="agent-phone-number">+5 9673</span>
<a href="#shownumber" class="js-agent-phone-number"><span class="agent-phone-number" data-mobile="9673">9673</span></a>
<span class="agent-phone-number">+5 9673</span>
<li><a href="sms:9673" class="js-agent-phone-number-sms"><i class="pgicon pgicon-comment-o"></i>SMS</a></li>

Post loading a document, I want to inject a Javascript to replace the string 9673 to 0000. How do I do that? I only need the Javascript part where it searches entire HTMLL document and replaces the string.

Upvotes: 2

Views: 255

Answers (3)

Dai
Dai

Reputation: 155418

The quick-to-write, slow-to-run answer is to abuse innerHTML:

function replace_9673_everywhere() {
    
    const documentHtml = document.documentElement.innerHTML;
    const newDocumentHtml = documentHtml.replace( /9673/g, '0000' );
    document.documentElement.innerHTML = newDocumentHtml;
}

...but this will probably break the document because it will make the browser re-parse everything (so any current page script-state with DOM element references will be broken).


A better approach is to traverse the DOM as this won't trigger a reparse provided you manipulate Element.attributes and Element.textContent (and #text nodes individually) and avoid using innerHTML / outerHTML entirely:

function replace_9673_everywhere() {
    const rootNode = document.documentElement;
    replace_9673_in_element( rootNode );
}

function replace_9673_in_element( el ) {
    // Replace in attributes:
    for( let i = 0; i < el.attributes.length; i++ ) {
        const attr = el.attributes.item(i);
        if( attr.value.includes( '9673' ) ) {
            attr.value = attr.value.replace( /9673/g, '0000' );
        }
    } 

    // Replace in child nodes (not just Element children):
    for( const childNode of el.childNodes ) {
        if( childNode.nodeType === Node.TEXT_NODE ) {
            if( childNode.textContent.includes( '9673' ) ) {
                childNode.textContent = childNode.textContent.replace( /9673/g, '0000' );
            }
        }
        else if( childNode.nodeType === Node.ELEMENT_NODE ) {
            replace_9673_in_element( childNode );
        }
    }
}

Upvotes: 4

Lionel Rowe
Lionel Rowe

Reputation: 5926

Here's another approach, using TreeWalkers, that targets text nodes and attributes only, without messing with the actual HTML structure.

function* iterateNodes(walker) {
    let next

    while (next = walker.nextNode()) {
        yield next
    }
}

const nodesUnder = (el, nodeFilters) => {
    const walker = document
        .createTreeWalker(el, nodeFilters)

    const nodes = iterateNodes(walker)

    return [...nodes]
}

const htmlEl = document.documentElement

const textNodes = nodesUnder(htmlEl, NodeFilter.SHOW_TEXT)

const attrNodes = nodesUnder(htmlEl, NodeFilter.SHOW_ELEMENT)
    .map(el => [...el.attributes])
    .flat()

;[...textNodes, ...attrNodes].forEach(node => {
    node.nodeValue = node.nodeValue.replace(/9673/g, '0000')
})

console.log(document.querySelector('#outer').outerHTML)
* { font-family: sans-serif }
<div id="outer">
    <div id="changed-9673" data-attr="9673">9673 (changed)</div>
    <custom-element-9673>unchanged</custom-element-9673>
</div>

Upvotes: 1

Shubham Srivastava
Shubham Srivastava

Reputation: 1877

You want something like this

function replace9673() {
  $("html").html($("html").html().replaceAll("9673", "0000"));
}
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<meta property="og:description" content="***April &amp;nbsp;9673&amp;nbsp;" />
</head>

<body>
<span class="agent-phone-number">+5 9673</span>
<a href="#shownumber" class="js-agent-phone-number"><span class="agent-phone-number" data-mobile="9673">9673</span></a>
<span class="agent-phone-number">+5 9673</span>
<li><a href="sms:9673" class="js-agent-phone-number-sms"><i class="pgicon pgicon-comment-o"></i>SMS</a></li>

<button onclick="replace9673()">Click Me</button>
</body>
</html>

Upvotes: 0

Related Questions