Search code examples
javascriptgoogle-chromefirefoxtampermonkey

Greasemonkey userscript is not loading properly


I am currently making a userscript to interpret the APL programming language in a Stack Exchange chat window. This is the code I have come up with:

// ==UserScript==
// @name     APL chat
// @version  1
// @grant    none
// @match    https://chat.stackexchange.com/*
// @require  https://cdn.jsdelivr.net/npm/apl@0.1.15/lib/apl.min.js
// ==/UserScript==

window.onload = function() {
  var prevCode = "";
  setInterval(function() {
    var codes=document.getElementsByTagName("code");
      //console.log(codes);
    var elem = codes[codes.length-1];
    if((elem != prevCode) && (elem.innerText[0] == '⋄')){
        var result = apl(elem.innerText).toString();
        prevCode = elem;
        var tmp = document.createElement("div");
        tmp.innerHTML = "<pre style=\"color:red\">"+result.replace("\n","<br>")+"</pre>";
        var parent = elem.parentElement;
        parent.appendChild(tmp.firstChild);
            console.log(result);
    }
    },100);
}

When a code block is written to the body with a character in it, it should be executed and displayed in red, underneath the code. However, this doesn't work at all times.

These are the errors I got while testing in the Chat Sandbox:

The script turns on in the correct websites, but in the console in Chrome 87.0.4280.88, I get the following error message:

Uncaught TypeError: Cannot read property 'innerText' of undefined
    at eval (userscript.html?name=APL%20chat.user.js&id=eb8ebba5-9381-48c2-9f2d-d735cbcb847e:1260)

The apl() function takes a single string and interprets in in the APL language, and it is imported from the @require statement, using ngn's javascript APL interpreter.

Another problem is that when I try accessing the apl() function from the @require, it says ReferenceError: apl is not defined. This happens on both Chrome and Firefox.

What is the correct fix for these problems?


Solution

  • The .main class takes some time to appear when you load the chat page and sometimes it loads after your userscript. So you need to find a way to ensure that your code is executed immediately after .main loads. Fortunately, there's a hack to do this.

    const ready = CHAT.Hub.roomReady.fire;
    CHAT.Hub.roomReady.fire = function(...args) {
      ready(...args);
      executeSomeCode(); // chat page loaded
    }
    

    It seems that a function CHAT.Hub.roomReady.fire() is called when the messages load. In this example, we edit it in order to add the code that needs to run.