Search code examples
javascriptgreasemonkeyjavascript-injection

Convert Greasemonkey script into an injectable JS (no addons)


Thank you in advance for your assistance. Basically I'm using Rambox Pro (basic browser with injecting JS & CSS support only) into webpages as my workstation & I'm using Notion & want this particular Greasemonkey script in Rambox Pro. I'm hoping to do so by injecting it in (by the JS option).

Orignal link to post & the link to the specific JS script.

I have gone as far as altering out the GM_addstyle into a document.body.appendChild by help here (but get a console timeout error), hence not using GM. I ignored the timeout error & tried to use the script but I get an error Katex is unknown so i tried to import Katex with <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.js"></script> but i keep getting Uncaught SyntaxError: Unexpected token < error

I've since given up on trying to convert it myself - could anyone help me convert this script fully into purely injectable JS. The code is: (copied from link)

// ==UserScript==
// @name Inline Math for Notion.so
// @homepageURL https://www.notion.so/evertheylen/Notion-Inline-Math-9c5047a4e7c84643848b3630db8d5a5e
// @version 0.2.1
// @match https://www.notion.so/*
// @grant GM_addStyle
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.js
// ==/UserScript==

// Instructions for use:
//   - Make sure you have at least one normal math block on your page
//   - Use inline code starting with "math:". For example: `math: f(x) = x^2`
//   - Press F2 to rerender all inline math. You can of course change the shortcut in the code below.
//   - The inline math will revert to inline code when the block becomes active.

GM_addStyle(`
.notion-frame span .katex {
    padding-right: 0 !important;
}
`)

function rerender_all() {
    var code = document.querySelectorAll("span[style*=\"monospace\"]")
    code.forEach(function(el) {
        var s = el.textContent
        if (s.startsWith("math:")) {
            el.style.color = null
            el.style.background = null
            s = s.slice(5).trim()
            console.log("rendering ", s)
            katex.render(s, el, {throwOnError: false, font: 'mathit'})
        }
    })
}

window.addEventListener('keydown', function(e) {
    if (e.key == "F7" && !e.ctrlKey && !e.shiftKey && !e.altKey) {
        console.log("rerender!");
        rerender_all()
    }
}, true)

// I don't know a good way to trigger rerender automatically yet
//document.addEventListener('DOMContentLoaded', rerender_all, false);

Side-note, if relevant - I am injecting CSS into it too (if matters) and RamboxPro does not support any extensions (just injection of JS & CSS) (It has the normal web developer mode). I am of any assistance if needed should this be possible/feasible.

Also - there is no need to check if the page is right (if it matters) as the JS & CSS injections are app independent (aka I'll be only injection this on the notion app that loads the notion pages)

Thanks


Solution

  • GreaseMonkey script is just JavaScript.

    One consideration is the GM APIs which in this case is // @grant GM_addStyle

    1- Change

    GM_addStyle(`
    .notion-frame span .katex {
        padding-right: 0 !important;
    }
    `)
    

    change to:

    const style = document.createElement('style');
    style.textContent = `.notion-frame span .katex { padding-right: 0 !important; }`;
    (document.head || document.body).appendChild(style);
    

    2- get the @require

    const script = document.createElement('script');
    script.src = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.js';
    (document.head || document.body).appendChild(script);
    

    3- You need a method to inject the script into the target location i.e. https://www.notion.so/*

    Here is an example of the reworked user-script. You still need a method to inject it.

    // inject CSS
    const style = document.createElement('style');
    style.textContent = `.notion-frame span .katex { padding-right: 0 !important; }`;
    (document.head || document.body).appendChild(style);
    
    const script1 = document.createElement('script');
    script1.textContent = `
    // inject the script to run after remtoe scritp is loaded
    function runCode() {
        function rerender_all() {
            var code = document.querySelectorAll('span[style*="monospace"]')
            code.forEach(function(el) {
                var s = el.textContent
                if (s.startsWith("math:")) {
                    el.style.color = null
                    el.style.background = null
                    s = s.slice(5).trim()
                    console.log("rendering ", s)
                    katex.render(s, el, {throwOnError: false, font: 'mathit'})
                }
            })
        }
    
        window.addEventListener('keydown', function(e) {
            if (e.key == "F7" && !e.ctrlKey && !e.shiftKey && !e.altKey) {
                console.log("rerender!");
                rerender_all()
            }
        }, true)
      }
    `;
    document.body.appendChild(script1);
    
    
    // wait for the external script to laod
    const script2 = document.createElement('script');
    script2.onload = runCode;
    (document.head || document.body).appendChild(script2);
    script2.src = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.js';