Userscripts

Userscripts are JavaScript files that are executed every time the user loads a Scratch page. They can modify the document’s HTML, add new buttons, customize Scratch editor behavior, and so much more.

Similarly to userscripts that you might download for userscript managers like Tampermonkey or Greasemonkey, Scratch Addons userscripts consist of pieces of JavaScript that are executed in the same execution context as the JavaScript code from Scratch itself. In browser extension vocabulary, this execution context is often called the “main world”.

Even though Scratch Addons userscripts are part of a browser extension, they cannot access any chrome.* or browser.* APIs. Instead, Scratch Addons offers an addon.* API.

Declarando userscripts no manifesto do addon

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

It’s not necessary to reload the extension when changing the source of an already existing userscript JavaScript file. In those cases, reloading the page is enough.

Userscripts são declarados dentro de um array conhecido como “userscripts”.

Cada item do array tem que possuir as seguintes propriedades:

  • "url": the relative URL to a JavaScript file.
  • "matches": the list of Scratch pages where the userscript will run. See matches for more information.

Manifest de exemplo:

{
  "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
}

Criando seu primeiro 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?");
}

Lembre-se que o JavaScript permite que funções sejam declaradas dentro de outras funções, por exemplo:

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.

Para mais informações, olhe o API reference.

Modificando o documento HTML

Use o browser DOM APIs para customizar o HTML da pagina.

Aqui um exemplo:

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

Traduzindo 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";

Para criar um novo texto, siga esses passos:

  1. Create a file named addon-id.json inside the /addon-l10n/en folder.
  2. Adicione um ID para cada texto:
{
  "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.

Detalhes técnicos

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


Páginas de Seção