Last active
February 25, 2022 05:41
-
-
Save mrcoles/76b79473be0572e79434c2b579f0e16a to your computer and use it in GitHub Desktop.
Replace all instances of one word with another in a web page
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ### Replace words in document | |
// | |
// Update all instances of `fromWord` to `toWord` within the text | |
// in the current document. | |
// | |
function replaceWordsInDocument(fromWord, toWord) { | |
if (/\s/.test(fromWord)) { | |
throw new Error('You must enter a single word without whitespace'); | |
} | |
const textNodes = iterAllTextNodes(); | |
replaceInNodes(fromWord, toWord, textNodes); | |
} | |
// ### Iterate all text nodes | |
// | |
// Returns a generator that yields all the text nodes within a | |
// document (excluding those within link, style, and script tags) | |
// | |
function* iterAllTextNodes() { | |
const ignoreNodes = new Set(['LINK', 'STYLE', 'SCRIPT']); | |
for (const elt of document.querySelectorAll('*')) { | |
if (!ignoreNodes.has(elt.nodeName)) { | |
for (const node of elt.childNodes) { | |
if (node.nodeType === 3) { | |
yield node; | |
} | |
} | |
} | |
} | |
} | |
// ### Replace in nodes | |
// | |
// Replaces all instances of fromText with toText within | |
// the textNodes. Matches whole words and expects | |
// `fromText` to have no whitespaces. Matches are also | |
// case-insensitve, and replacements attempt to replicate | |
// the original capitalization found in the node. | |
// | |
// - fromText (string) representing one word with no spaces | |
// - toText (string) | |
// - textNodes (nodeList of text nodes) | |
// | |
function replaceInNodes(fromText, toText, textNodes) { | |
const fromLower = fromText.toLowerCase(); | |
const replacements = { | |
[fromLower]: toText.toLowerCase(), | |
[fromText.toUpperCase()]: toText.toUpperCase(), | |
[capitalize(fromText)]: capitalize(toText) | |
} | |
for (const node of textNodes) { | |
const newText = node.nodeValue.split(/(\s+)/).map((token, i) => { | |
if (i % 2 === 0) { | |
const tokenLower = token.toLowerCase(); | |
if (tokenLower === fromLower) { | |
return replacements[token] || toText; | |
} | |
} | |
return token; | |
}).join(''); | |
// looks faster to only set if changed https://jsperf.com/node-nodevalue | |
if (newText !== node.nodeValue) { | |
node.nodeValue = newText; | |
} | |
} | |
} | |
// ### Helpers | |
// | |
const capitalize = (text) => text.substring(0, 1).toUpperCase() + text.toLowerCase().substring(1); | |
// ### Run it | |
// | |
replaceWordsInDocument('you', 'y\'all'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This uses some es6 features like generators, arrow functions, and computed property keys, which may not work in some older browsers.
Usage:
😉