Benutzerskripte (Userscripts)

Userscripts sind Javascript-Dateien, die jedes Mal, wenn der Benutzer eine Scratchseite öffnet, ausgeführt werden. Sie können das HTML des Dokumentes verändern, neue Schaltflächen hinzufügen, das Verhalten des Scratcheditors verändern, und so viel mehr.

Userscripts für Scratch Addons sind, ähnlich wie Userscripts die du vielleicht für Userscriptmanager wie Tampermonkey oder Greasemonkey runterlädst, JavaScript-Programme, die in dem selben Kontext wie der Javascript-Code von Scratch ausgeführt werden. In Browsererweiterungsworten wird dieser Kontext oft “Hauptwelt” genannt.

Obwohl Scratch Addons-Userscripts Teil einer Browsererweiterung sind, können sie keine chrome.*- oder browser.*-APIs aufrufen. Stattdessen gibt Scratch Addons eine addon.*-API vor.

Userscripts im Addon-Manifest deklarieren

Some changes require an extension reload from chrome://extensions to take effect, such as updating the addon manifest file.

Es ist nicht nötig, die Erweiterung neu zu laden, wenn man den Code einer schon existierenden Javascriptdatei ändern. In diesem Fall kannst du einfach die Seite neu laden.

Userscripts werden in einem “userscripts”-Array deklariert.

Jedes Element dieses Arrays muss die folgenden Elemente haben:

  • "url": die relative URL zu einer Javascript-Datei
  • "matches": Die Liste von Scratchseiten, wo das Userscript ausgeführt wird. Siehe matches für mehr Informationen.

Beispielsmanifest:

{
  "name": "Copy link to comment button",
  "description": "Adds a \"Copy Link\" button to all comments on the website, next to the \"Report\" button.",
  "userscripts": [
    {
      "url": "userscript.js",
      "matches": ["projects", "https://scratch.mit.edu/", "profiles", "studios"]
    }
  ],
  "tags": ["community"],
  "enabledByDefault": false
}

Creating your first userscript

Unlike extension content scripts and Tampermonkey userscripts, you must wrap all of your code inside a module default export:

// Example userscript
export default async function ({ addon, console }) {
  console.log("Hello, " + await addon.auth.fetchUsername());
  console.log("How are you today?");
}

Remember that JavaScript allows functions to be declared inside other functions, for example:

export default async function ({ addon, console }) {
  async function sayHelloToUser() {
    console.log("Hello, " + await addon.auth.fetchUsername());
  }

  await sayHelloToUser();
  console.log("How are you today?");
}

You can access many addon.* API utilities from userscripts. For example, you can get the current username, wait until an element exists on the page, or get a reference to the Scratch VM object.

For more information, check the API reference.

Modifying the document HTML

Use browser DOM APIs to customize the HTML of the page.

Here’s an example:

const myButton = document.createElement("button");
myButton.textContent = "Click me!";
myButton.classList.add("button");
myButton.setAttribute("title", "You're hovering a button");

const myContainer = document.querySelector(".container");
myContainer.append(myButton);

Localizing userscripts

Addon userscripts sometimes need to reference English words or sentences. Make sure not to hardcode them, so that they can be part of the translation process.

// Don't do this:
document.querySelector(".sa-find-bar").placeholder = "Find blocks";

To create a translatable string, follow these steps:

  1. Create a file named addon-id.json inside the /addon-l10n/en folder.
  2. Provide an ID for every string:
{
  "addon-id/find": "Find blocks"
}
  1. Make sure to import the msg() function in your userscript. The first line of your userscript should look like this:
export default async function ({ addon, console, msg  }) {
                                              // ^^^
  1. Use the msg() function in your code, instead of a hardcoded string:
document.querySelector(".sa-find-bar").placeholder = msg("find");
For more information about localizing userscripts, see this page.

Technical details

Each userscript file is a JavaScript module that exports a function. Scratch Addons only imports the module if needed, and executes it after the page has fully loaded.

Userscripts are JavaScript modules, so they always run on “strict mode”. This also means that userscripts may use top-level imports to import other JavaScript files.

The order in which userscripts run may vary on each page load. After page load, the user might dynamically enable some addons in a custom order, so order of execution is never guaranteed. Some APIs like addon.tab.appendToSharedSpace attempt to fix any potential race conditions and unexpected behavior when dynamically enabling addons.

runAtComplete

Userscripts may opt-in into being executed before the page has fully loaded by specifying "runAtComplete": false in the addon manifest, once for each userscript.

As of now, only document.head is guaranteed to exist when running a userscript early. In the future, document.body will also be guaranteed to exist, so no userscripts will ever run before the HTML document loaded enough to reach </head> <body>.


Sektions-Seiten

  • Debugging Tips

    Tips to easily debug userscripts, and edge cases to consider.

  • Empfohlene Vorgehensweisen

    Wenn du Code für Userscripts schreibst oder überprüfst, folge diesen empfohlenen Vorgehensweisen.