javascripttampermonkeyuserscriptsgreasemonkey-4

My script will run in the console, but I can not get it to run in Greasemonkey


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');

Solution

  • 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.