1

so I've been trying to learn some javascript and have been working on a very (very) basic userscript that simply changes the text color of a link on a site (not a site I control the source for). Problem is, when the script is run, it changes the link text color, and the link still works, but a few functional elements nearby just stop working entirely (search bar preview, search button, profile dropdown list). My script body is nothing more than:

document.body.innerHTML= document.body.innerHTML.replace(/Advanced\n\s{1,}Search/,"\<span style\=\"color\: \#2898FF\"\> Advanced Search \<\/span\>");

I've also tried running the script as a bookmarklet for in case there's anything wrong with how the userscript is run/the metadata associated with it, but nope, same situation. Would truly appreciate some help ^^

1 Answers1

3

When you do that, all the elements on the page are re-created, so changes on most JavaScript event listener that were on the page would not work anymore:

document.getElementById('click').onclick = () => {
  console.log('Click!');
};

document.getElementById('replace').onclick = () => {
  console.log('Replace!');
  
  document.body.innerHTML= document.body.innerHTML.replace(
    /Advanced\n\s{1,}Search/,
    '\<span style\=\"color\: \#2898FF\"\> Advanced Search \<\/span\>'
  );
};
.as-console-wrapper {
  max-height: 45px !important;
}
<h1>
  Advanced
  Search
</h1>

<button id="click">Click me!</button>
<button id="replace">Replace HTML</button>

Instead, find the exact element or elements you want to update and change some properties on them:

const h1 = document.querySelector('h1');

document.getElementById('click').onclick = () => {
  console.log('Click!');
};

document.getElementById('replace').onclick = () => {
  console.log('Replace!');
  
  h1.textContent = 'Advanced Search';
  h1.style.color = ['red', 'yellow', 'green', 'cyan', 'blue', 'magenta'][Math.round(Math.random() * 5)];
};
.as-console-wrapper {
  max-height: 45px !important;
}
<h1>
  Advanced
  Search
</h1>

<button id="click">Click me!</button>
<button id="replace">Replace HTML</button>
Danziger
  • 19,628
  • 4
  • 53
  • 83
  • Ahh, thanks. That makes sense. Is there any way of preventing it while still having the script run? Such as "reloading" other scripts, or having this one load while all the others do? (Currently it gets run once the page is "idle") Also I appreciate the code, but I'm trying to change this simply for my own satisfaction with the site's aesthetic ^^, so a button might defeat the purpose a bit. – electroshock777 May 10 '20 at 23:59
  • 1
    I know, the button is just there just to demonstrate the events stop working after replacing `.innerHTML`. I don't think there's a simple way to do that, you would be better off just trying to find the specific elements you want to change and updating them. Anyway, a possible solution might be to inject your code using a Chrome extenstion with `"run_at": "document_start`. Maybe you can try some of the alternatives mentioned here: https://stackoverflow.com/questions/19191679/chrome-extension-inject-js-before-page-load – Danziger May 11 '20 at 00:03
  • 1
    Ah, apologies for the misunderstanding. What do you mean by finding the specific elements and updating them? I mean I can use inspect element to adjust it, but sadly that only works in that instance of the site. Also I'm afraid document start doesn't seem to run the script at all (no idea why), so that's why I've been using document idle. – electroshock777 May 11 '20 at 00:10
  • What I mean is to do it like in the example, using `document.getElementById()`, `document.querySelector()`, `document.querySelectorAll()`... or something similar to get a reference to an individual element and update its properties. But yeah, if you use selectors like that, that needs to be site-specific. – Danziger May 11 '20 at 01:49
  • Sorry, at `document_start` the DOM won't be ready yet, so it's not suitable for DOM manipulation. What comes straight after `document_start` is `document_end`, and at this step, the DOM should be ready, according to [the docs](https://developer.chrome.com/extensions/content_scripts), so you could try that insteada. – Danziger May 11 '20 at 01:51