0

I'm about to rip my hair out with this. This code will execute just fine in the browser console, but it simply will not run with Greasemonkey or Tampermonkey. I've tried them both and I'm out of ideas as to what could be wrong.

ADDENDUM FOR CLARIFICATION: As this is written below, I don't receive any errors specific to the script or greaskmoney/tampermonkey. I have tried to use waitforKeyElements, but that didn't seem to make any difference. A simple alert will fire, so I'm sure that whatever the error is, it seems specific to the javascript.

For reference, I found the code here.

Thanks in advance.

// ==UserScript==
// @name            name
// @description     description
// @version         1
// @author          me
// @match           https://*.robertsspaceindustries.com/spectrum/community/SC/forum/*
// @icon            https://i.imgur.com/km9uoYJ.png
// ==/UserScript==

function hexToRgb(hex) {
  // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
  var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  hex = hex.replace(shorthandRegex, function(r, g, b) {
    return r + r + g + g + b + b;
  });

  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? "rgb(" + [
    parseInt(result[1], 16),
    parseInt(result[2], 16),
    parseInt(result[3], 16)
  ].join(', ') + ")" : null;
}

// Function to change a color to another one
function colorChange(colorOld, colorNew, strict = false) {
  // If hex notation, convert to rgb
  if (colorOld.includes('#'))
    colorOld = hexToRgb(colorOld);
  // Loop through all elements styles
  [...document.getElementsByTagName('*')].forEach(elm => {
    let cStyle = getComputedStyle(elm);
    [...cStyle].forEach(prop => {
      // Escape if not a string
      if (typeof cStyle[prop] !== 'string') return;
      // Check if colorOld is in property
      if (cStyle[prop].includes(colorOld)){
        // If strict, colorOld is replaced only if it's the only value of the property
        if (!strict || cStyle[prop] === colorOld)
          elm.style[prop] = cStyle[prop].replace(colorOld, colorNew); // Replace color
      }
    })
  })
};

// function () {
//   colorChange('#182436', '#ff0000');
//   console.log('colorChange has run.');
// };

colorChange('#182436', '#ff0000');
Forceflow
  • 27
  • 7
  • What do you mean by _"will not run"_? Are there any errors reported in the console? If so, what are they? Otherwise, how do you know if it runs or not? Have you tried adding some logging? There's a pretty good chance this is simply a duplicate of [Why does jQuery or a DOM method such as getElementById not find the element?](https://stackoverflow.com/q/14028959/283366) – Phil Aug 10 '22 at 05:23
  • Use MutationObserver or waitForKeyElements. – wOxxOm Aug 10 '22 at 06:56
  • As it is written now I receive no errors specific to the script, and I have tried logging, which does fire. However, the results I'm looking for do not happen. That specifically is, changing the first color parameter (#182436) within the colorChange function to the second parameter (#ff000). I have also tried watiforKeyElements, but I don't understand how to use MutationObserver. Guys, I'm interested in learning, but programming isn't my profession and I'm not great at it. Please provide specific examples along with your links to documentation. I'm just a beginner. Thank you for your patience. – Forceflow Aug 10 '22 at 14:43

1 Answers1

1

The most common problem -- and what waitForKeyElements and/or MutationObserver solve -- is that the code is trying to run against elements that haven't yet been added to the page. (Remember we are talking microseconds here... the page is often still being rendered as the JavaScript is executing, and some elements might not be ready when the JavaScript expects them to be.) setTimeout, waitForKeyElements and MutationObserver are all ways to delay the JavaScript until the required elements are present.

You can test if waitForKeyElements or MutationObserver are the solution by just wrapping your code in a setTimeout() function.

// ==UserScript==
// @name            name
// @description     description
// @version         1
// @author          me
// @match           https://*.robertsspaceindustries.com/spectrum/community/SC/forum/*
// @icon            https://i.imgur.com/km9uoYJ.png
// ==/UserScript==

(function() {
    'use strict';

    setTimeout( () => {

        colorChange('#182436', '#ff0000');

    }, 10000);  //10-sec delay

})();

function hexToRgb(hex) {
    //etc (removed for brevity)
}

function colorChange(colorOld, colorNew, strict = false) {
    //etc (removed for brevity)
};

setTimeout is the old way to do this, but it still works and it is dead simple to implement. So, wrap your code in a 10 or 20 or 30 second setTimeout and if it runs, you know that waitForKeyElements or MutationObserver are the answer.

But if a 30 or 120 second setTimeout doesn't work, then it's not just a question of waiting for the right elements to be added to the page, there's more going on.

cssyphus
  • 37,875
  • 18
  • 96
  • 111
  • That did the trick. I was erroneously putting all of the javascript into the setTimeout function. I understand what I was doing wrong now. I was able to reduce the timeout down to 1 second and everything still fires. Thank you for your time! – Forceflow Aug 10 '22 at 18:15