Issue
I want to replace specific texts on a page with javascript. For simplicty lets say I want to replace all letters A with the letter X. Important is that it's not going to break inline HTML.
Is there a simple way to iterate over all DOM elements and only change actual texts?
<span>hello world <a href="/">abcd</a>..</span>
should become
<span>hello world <a href="/">xbcd</a>..</span>
and not
<spxn>hello world <x href="/">xbcd</x>..</spxn>
Solution
Iterate over all text nodes, and change their nodeValue
if they contain an a
:
function getAllTextNodes() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.push(node);
}
return textNodes;
}
getAllTextNodes().forEach((node) => {
const { nodeValue } = node;
const newValue = nodeValue.replace(/a/g, 'x');
if (newValue !== nodeValue) {
node.nodeValue = newValue;
}
});
<a href="/">abcd</a>
You can also create a whitelist or blacklist of parents whose text nodes are changeable, if you want:
function getAllTextNodes() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.push(node);
}
return textNodes;
}
const tagNamesToKeepUnchanged = ['SCRIPT'];
getAllTextNodes().forEach((node) => {
if (tagNamesToKeepUnchanged.includes(node.parentNode.tagName)) {
return;
}
const { nodeValue } = node;
const newValue = nodeValue.replace(/a/g, 'x');
if (newValue !== nodeValue) {
node.nodeValue = newValue;
}
});
const obj = JSON.parse(
document.querySelector('script[type="application/json"]').textContent
);
console.log(obj.key);
<a href="/">abcd</a>
<p>foo bar</p>
<script type="application/json">{"key":"value"}</script>
This will preserve tag names, event listeners, and pretty much everything except the content of certain text nodes.
Answered By - CertainPerformance
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.