Skip to content

Instantly share code, notes, and snippets.

@neuhaus
Created January 3, 2026 11:37
Show Gist options
  • Select an option

  • Save neuhaus/f4d8f91639ba7dbf3119ada0d6a44550 to your computer and use it in GitHub Desktop.

Select an option

Save neuhaus/f4d8f91639ba7dbf3119ada0d6a44550 to your computer and use it in GitHub Desktop.
User script for Violentmonkey / Tampermonkey / Greasemonkey to replace text
// ==UserScript==(
// @name Drumpf III
// @match *://*/*
// @grant none
// @run-at document-end
// @version 2.0
// @description Makes you feel better by replacing 'Trump' with 'Drumpf' (asynchronously for no slowdown).
// ==/UserScript==
(() => {
const CHUNK_SIZE = 50;
const queue = [];
let processing = false;
const RE = /\bTrump\b/g;
function replaceInNode(textNode) {
// Skip editable fields (contentEditable without a value is also covered)
if (textNode.parentNode && textNode.parentNode.isContentEditable) return;
if (textNode.parentNode && textNode.parentNode.matches?.('textarea, input')) return;
const txt = textNode.nodeValue;
if (txt && RE.test(txt)) {
textNode.nodeValue = txt.replace(RE, 'Drumpf');
}
}
function processChunk() {
if (queue.length === 0) {
processing = false;
return;
}
let i = 0;
while (i < CHUNK_SIZE && queue.length) {
const node = queue.shift();
if (node && node.parentNode) replaceInNode(node);
i++;
}
setTimeout(processChunk, 0); // yield to UI thread
}
function enqueue(node) {
queue.push(node);
if (!processing) {
processing = true;
processChunk();
}
}
// Walk a subtree and enqueue all Text nodes
function walkAndEnqueue(root) {
// Do not descend into editable containers
if (root.nodeType === Node.ELEMENT_NODE && root.isContentEditable) return;
if (root.matches?.('textarea, input')) return;
const walker = document.createTreeWalker(
root,
NodeFilter.SHOW_TEXT,
null,
false
);
let n;
while ((n = walker.nextNode())) enqueue(n);
}
const observer = new MutationObserver(mutations => {
for (const m of mutations) {
// 4a) New nodes added somewhere in the tree
if (m.type === 'childList') {
for (const added of m.addedNodes) {
// If the added node itself is a Text node → enqueue directly
if (added.nodeType === Node.TEXT_NODE) {
enqueue(added);
} else {
// Normal DOM walk for the rest of the subtree
walkAndEnqueue(added);
}
}
}
}
});
walkAndEnqueue(document.body);
observer.observe(document.body, {
childList: true,
subtree: true
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment