I am writing a Tampermonkey script to change the name of something on a webpage. However, the script seems to run endlessly. If the script is ran on the corresponding website (https://www.gutenberg.org/files/46/46-h/46-h.htm), it will turn "Scrooge" into "Happy Scrooge" into "Happy Happy Scrooge", etc., instead of just "Scrooge" into "Happy Scrooge".
Eventually, the page runs out of memory and crashes the tab. Even if there is nothing to re-replace, like just "sad" into "happy", it will still crash the tab within the minute. This seems fairly simple to me but I haven't found a solution online. I would appreciate any help!
I am new to web programming so if anyone has any suggestions for cleaning up my code, I would really appreciate it.
// ==UserScript==
// @name Change Name
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Changes the name of something on a webpage.
// @author You
// @match https://www.gutenberg.org/files/46/46-h/46-h.htm
// @grant none
// ==/UserScript==
(function() {
'use strict';
function run () {
var ele = document.querySelectorAll("p");
var i, str, n;
var oldName = "Scrooge";
var newName = "Happy Scrooge";
for (i = 0; i < ele.length; i++) {
str = ele[i].innerHTML;
n = str.indexOf(oldName);
if (n > -1) {
str = str.replace(oldName, newName);
ele[i].innerHTML = str;
} else {
setTimeout(run, 500);
}
}
}
run();
})();
To make sure Happy Scrooge
doesn't get replaced with Happy Happy Scrooge
, I'd use a regular expression instead: match (?<!Happy )Scrooge
and replace with Happy Scrooge
so that a section that's changed doesn't get changed again, with /(?<!Happy )Scrooge/g
.
But the recursive timeout doesn't make sense - just replace everything once:
// ==UserScript==
// @name Change Name
// @match https://www.gutenberg.org/files/46/46-h/46-h.htm
// @grant none
// ==/UserScript==
for (const p of document.querySelectorAll("p")) {
p.innerHTML = p.innerHTML.replace(/(?<!Happy )Scrooge/g, 'Happy Scrooge');
}
Though, at that point, since it doesn't look like Happy Scrooge
exists anywhere in the original HTML, the lookbehind doesn't look to be needed:
p.innerHTML = p.innerHTML.replaceAll('Scrooge', 'Happy Scrooge');