-3

I'm trying to change the color of every user's profile link in my browser using a userscript. My code:

// ==UserScript==
// @name         Color changer
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  none
// @author       You
// @match        https://puzzling.stackexchange.com/questions/*
// @grant        none
// ==/UserScript==

let users = document.getElementsByClassName("user-details");

for (let user of users) {
    user.getElementsByTagName("a")[0].style.color = "red";
}

For some reason,

  • for some posts this only changes the color of the OP's link in every question page, not the links of the commenters and answerers.

Error:

ERROR: Execution of script 'New Userscript' failed! user.getElementsByTagName(...)[0] is undefined
  • for some posts this doesn't work at all.

Error:

ERROR: Execution of script 'New Userscript' failed! user.getElementsByTagName(...)[0] is undefined
  • for some posts this only changes the color of the OP's link and answer's link in every question page, not the links of the commenters.

No error.


How can I change the color of all the user profile links in the page?

Red
  • 26,798
  • 7
  • 36
  • 58
  • Are you able to share more of your code? I set up a little example using only your code and what I expect your HTML looks like here and it works just fine: https://codesandbox.io/s/keen-villani-7onis – LMulvey Nov 20 '20 at 18:13
  • 1
    [You should NOT be using `.getElementsByClassName()` or `getElementsByTagName()` in 2020 and especially not in a loop.](https://stackoverflow.com/questions/54952088/how-to-modify-style-to-html-elements-styled-externally-with-css-using-js/54952474#54952474) – Scott Marcus Nov 20 '20 at 18:14
  • @LMulvey Just go to any puzzling stackexchange post, and run the userscript. – Red Nov 20 '20 at 18:18

2 Answers2

1

Try this:

document.querySelectorAll('.user-details a').forEach( item => item.style.color = "red")

You can make more complex CSS selectors with "querySelectorAll".

The user comments have a different CSS class attached to them so you would then need to :

document.querySelectorAll('.comment-user').forEach( item => item.style.color = "red")

OR ... If you want to do both you can try separating multiple CSS queries with a comma:

document.querySelectorAll('.user-details a, .comment-user').forEach( item => item.style.color = "red")
David Kerr
  • 1,058
  • 1
  • 8
  • 12
1

Generally, you should NOT be using .getElementsByClassName() or .getElementsByTagName() in 2020 and especially not in a loop. As my other post gets into, these are some of the earliest DOM querying methods and they return "live" node lists, which can be costly, especially when used in conjunctions with a loop. .querySelectorAll() is the modern alternative and is what you really should be using.

You just need to properly query for all the <a> descendants of any user-details element and loop through the results, adding a new class to use for each one (you also should be avoiding inline styles when you can as they lead to duplication of code, don't scale well, and are hard to override). Instead, use CSS classes, which are easy to add and remove.

document.querySelector(".user-details a").forEach(function(item){
  item.classList.add("newColor");
});

And, of course, make sure you have the newColor class defined in your CSS:

.newColor { color: someColorYouWant; }
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • Thanks! But this gives me `forEach is not a function error`. I've tried replacing `forEach` to `forEach.call`, but another error comes. – Red Nov 21 '20 at 13:06
  • That would only happen if you were testing in an old browser that pre-dates `.forEach()`, like IE. You can fix it by making the line `Array.protype.slice.call(document.querySelector(".user-details a")).forEach(function(item){ item.classList.add("newColor");` – Scott Marcus Nov 21 '20 at 23:53