From 84857762f66e55a52ada8fe8af944a6a1ce60657 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Thu, 6 Feb 2025 11:16:20 +1300 Subject: [PATCH 01/25] Move legacy userScripts API documentation --- files/en-us/_redirects.txt | 6 +- files/en-us/_wikihistory.json | 32 ++--- .../webextensions/api/userscripts/index.md | 2 +- .../api/userscripts_legacy/index.md | 51 ++++++++ .../onbeforescript/index.md | 108 +++++++++++++++++ .../api/userscripts_legacy/register/index.md | 75 ++++++++++++ .../registereduserscript/index.md | 27 +++++ .../registereduserscript/unregister/index.md | 43 +++++++ .../userscriptoptions/index.md | 38 ++++++ .../working_with_userscripts/index.md | 111 ++++++++++++++++++ .../user_script_in_action.png | Bin 0 -> 27302 bytes .../userscriptexample.png | Bin 0 -> 9292 bytes .../manifest.json/user_scripts/index.md | 13 +- .../work_with_contextual_identities/index.md | 2 +- 14 files changed, 484 insertions(+), 24 deletions(-) create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/onbeforescript/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/unregister/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/userscriptoptions/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/user_script_in_action.png create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/userscriptexample.png diff --git a/files/en-us/_redirects.txt b/files/en-us/_redirects.txt index ee51a809e46ed93..472cb91f8eebfad 100644 --- a/files/en-us/_redirects.txt +++ b/files/en-us/_redirects.txt @@ -6123,7 +6123,11 @@ /en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/registerProxyScript /en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy /en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/unregister /en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy /en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/moveInSuccession() /en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/moveInSuccession -/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/RegisteredUserScript/RegisteredUserScript.unregister() /en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/RegisteredUserScript/unregister +/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/RegisteredUserScript/RegisteredUserScript.unregister() /en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/RegisteredUserScript/unregister +/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/RegisteredUserScript/unregister /en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/RegisteredUserScript/unregister +/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/UserScriptOptions /en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/UserScriptOptions +/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/Working_with_userScripts /en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/Working_with_userScripts +/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/onBeforeScript /en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/onBeforeScript /en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows/update() /en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows/update /en-US/docs/Mozilla/Add-ons/WebExtensions/Accessible_guidelines https://extensionworkshop.com/documentation/develop/build-an-accessible-extension/ /en-US/docs/Mozilla/Add-ons/WebExtensions/Add-on_ID https://extensionworkshop.com/documentation/develop/extensions-and-the-add-on-id/ diff --git a/files/en-us/_wikihistory.json b/files/en-us/_wikihistory.json index ebcb67df18cb545..0ea2aba404b972a 100644 --- a/files/en-us/_wikihistory.json +++ b/files/en-us/_wikihistory.json @@ -14426,22 +14426,6 @@ "modified": "2020-10-15T22:20:45.849Z", "contributors": ["rebloor", "irenesmith", "bershanskiy", "pesar81"] }, - "Mozilla/Add-ons/WebExtensions/API/userScripts/RegisteredUserScript/unregister": { - "modified": "2020-10-15T22:22:39.367Z", - "contributors": ["rebloor", "hellosct1", "bershanskiy"] - }, - "Mozilla/Add-ons/WebExtensions/API/userScripts/UserScriptOptions": { - "modified": "2020-06-22T16:28:43.349Z", - "contributors": ["hellosct1", "MelchiorIm3Tal", "irenesmith"] - }, - "Mozilla/Add-ons/WebExtensions/API/userScripts/Working_with_userScripts": { - "modified": "2020-06-22T16:28:43.959Z", - "contributors": ["irenesmith", "hellosct1"] - }, - "Mozilla/Add-ons/WebExtensions/API/userScripts/onBeforeScript": { - "modified": "2020-10-15T22:23:14.808Z", - "contributors": ["chrisdavidmills", "rebloor", "bershanskiy"] - }, "Mozilla/Add-ons/WebExtensions/API/userScripts/register": { "modified": "2020-10-15T22:21:40.204Z", "contributors": [ @@ -14454,6 +14438,22 @@ "stoyanster" ] }, + "Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/RegisteredUserScript/unregister": { + "modified": "2020-10-15T22:22:39.367Z", + "contributors": ["rebloor", "hellosct1", "bershanskiy"] + }, + "Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/UserScriptOptions": { + "modified": "2020-06-22T16:28:43.349Z", + "contributors": ["hellosct1", "MelchiorIm3Tal", "irenesmith"] + }, + "Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/Working_with_userScripts": { + "modified": "2020-06-22T16:28:43.959Z", + "contributors": ["irenesmith", "hellosct1"] + }, + "Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/onBeforeScript": { + "modified": "2020-10-15T22:23:14.808Z", + "contributors": ["chrisdavidmills", "rebloor", "bershanskiy"] + }, "Mozilla/Add-ons/WebExtensions/API/webNavigation": { "modified": "2020-10-15T21:38:48.088Z", "contributors": ["fscholz", "wbamberg", "abbycar"] diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index 6c2897e4a018eff..4c21fb7a6a701a5 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -47,5 +47,5 @@ To use the API, call `{{WebExtAPIRef("userScripts.register","register()")}}` pas ## See also -- [Working with `userScripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/Working_with_userScripts) +- [Working with `userScripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/Working_with_userScripts) - {{WebExtAPIRef("contentScripts","browser.contentScripts")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/index.md new file mode 100644 index 000000000000000..5d375158fd134f8 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/index.md @@ -0,0 +1,51 @@ +--- +title: userScripts (Legacy) +slug: Mozilla/Add-ons/WebExtensions/API/userScripts +page-type: webextension-api +browser-compat: webextensions.api.userScripts_legacy +--- + +{{AddonSidebar}} + +> [!WARNING] +> This is documentation for the legacy `userScripts` API. It's available in Firefox for Manifest V2. For functionality to work with user scripts in Manifest V3 see the new {{WebExtAPIRef("userScripts")}} API. + +Use this API to register user scripts, third-party scripts designed to manipulate webpages or provide new features. Registering a user script instructs the browser to attach the script to pages that match the URL patterns specified during registration. + +This API offers similar capabilities to {{WebExtAPIRef("contentScripts")}} but with features suited to handling third-party scripts: + +- execution is in an isolated sandbox: each user script is run in an isolated sandbox within the web content processes, preventing accidental or deliberate interference among scripts. +- access to the `window` and `document` global values related to the webpage the user script is attached to. +- no access to WebExtension APIs or associated permissions granted to the extension: the API script, which inherits the extension's permissions, can provide packaged WebExtension APIs to registered user scripts. An API script is declared in the extension's manifest file using the "user_scripts" manifest key. + +> [!WARNING] +> This API requires the presence of the [`user_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts) key in the manifest.json, even if no API script is specified. For example. `user_scripts: {}`. + +To use the API, call `{{WebExtAPIRef("userScripts_legacy.register","register()")}}` passing in an object defining the scripts to register. The method returns a Promise that is resolved with a `{{WebExtAPIRef("userScripts_legacy.RegisteredUserScript","RegisteredUserScript")}}` object. + +> [!NOTE] +> User scripts are unregistered when the related extension page (from which the user scripts were registered) is unloaded, so you should register a user script from an extension page that persists at least as long as you want the user scripts to stay registered. + +## Types + +- {{WebExtAPIRef("userScripts_legacy.RegisteredUserScript")}} + - : The `object` returned by the {{WebExtAPIRef("userScripts_legacy.register","register()")}} method. It represents the registered user scripts and is used to deregister the user scripts. + +## Methods + +- {{WebExtAPIRef("userScripts_legacy.register()")}} + - : Registers user scripts. + +## Events + +- {{WebExtAPIRef("userScripts_legacy.onBeforeScript")}} + - : An event available to the API script, registered in[`"user_scripts"`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts), that execute before a user script executes. Use it to trigger the export of the additional APIs provided by the API script, so they are available to the user script. + +## Browser compatibility + +{{Compat}} + +## See also + +- [Working with `userScripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/Working_with_userScripts) +- {{WebExtAPIRef("contentScripts","browser.contentScripts")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/onbeforescript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/onbeforescript/index.md new file mode 100644 index 000000000000000..9d294d2cba3b33e --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/onbeforescript/index.md @@ -0,0 +1,108 @@ +--- +title: userScripts.onBeforeScript (Legacy) +slug: Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/onBeforeScript +page-type: webextension-api-event +browser-compat: webextensions.api.userScripts_legacy.onBeforeScript +--- + +{{AddonSidebar}} + +> [!WARNING] +> This is documentation for the legacy `userScripts` API. It's available in Firefox for Manifest V2. For functionality to work with user scripts in Manifest V3 see the new {{WebExtAPIRef("userScripts")}} API. + +The `onBeforeScript` event of the {{WebExtAPIRef("userScripts_legacy","browser.userScripts")}} is fired before a user script is executed. It can only be included in the API script, the script registered in [`"user_scripts"`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts), where it is used to detect that the custom API methods should be exported to the user script. + +## Syntax + +```js-nolint +browser.userScripts.onBeforeScript.addListener(listener) +browser.userScripts.onBeforeScript.removeListener(listener) +browser.userScripts.onBeforeScript.hasListener(listener) +``` + +Events have three functions: + +- `addListener(listener)` + - : Adds a listener to this event. +- `removeListener(listener)` + - : Stop listening to this event. The `listener` argument is the listener to remove. +- `hasListener(listener)` + - : Check whether `listener` is registered for this event. Returns `true` if it is listening, `false` otherwise. + +## addListener syntax + +### Parameters + +- `listener` + + - : The function called when this event occurs. The function is passed these arguments: + + - `script` + + - : An `object` that represents the user script that matched a web page. Its properties and methods are as follows: + + - `defineGlobals` + - : A method that exports an object containing properties and methods available globally to the user script sandbox. This method must be called synchronously to guarantee that the user script has not executed. + - `export` + - : A method that converts a value to one that the user script code can access. This method is used in API methods exported to the user script to result or resolve non-primitive values. The exported objects can also provide methods that the user script code can access and call. + - `global` + - : An `object` that provides access to the sandbox for the user script. + - `metadata` + - : The `scriptMetadata` property set when the user script was registered using `userScripts.register`. + +## Examples + +An example of how the listener might be used: + +```js +browser.userScripts.onBeforeScript.addListener((script) => { + script; // This is an API object that represents the user script + // that is going to be executed. + + script.metadata; // Access the user script metadata (returns the + // value of the scriptMetadata property from + // the call to userScripts.register). + + // Export some global properties into the user script sandbox + // (this method has to be called synchronously from the + // listener, otherwise the user script may have executed). + script.defineGlobals({ + aGlobalPropertyAccessibleFromUserScriptCode: "prop value", + + myCustomAPIMethod(param1, param2) { + // Custom methods exported from the API script can use + // the WebExtensions APIs available to content scripts. + browser.runtime.sendMessage(/* … */); + // … + + return 123; // primitive values can be returned directly + // … + + // Non primitive values have to be exported explicitly + // using the export method provided by the script API + // object + return script.export({ + objKey1: { + nestedProp: "nestedValue", + }, + // Explicitly exported objects can also provide methods. + objMethod() { + /* … */ + }, + }); + }, + + async myAsyncMethod(param1, param2, param3) { + // exported methods can also be declared as async + }, + }); +}); +``` + +## Browser compatibility + +{{Compat}} + +## See also + +- {{WebExtAPIRef("contentScripts")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md new file mode 100644 index 000000000000000..e40c79b31190e99 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md @@ -0,0 +1,75 @@ +--- +title: userScripts.register() (Legacy) (Legacy) +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/register +page-type: webextension-api-function +browser-compat: webextensions.api.userScripts_legacy.register +--- + +{{AddonSidebar}} + +> [!WARNING] +> This is documentation for the legacy `userScripts` API. It's available in Firefox for Manifest V2. For functionality to work with user scripts in Manifest V3 see the new {{WebExtAPIRef("userScripts")}} API. + +This method enables user scripts to be registered from an extension's pages (such as the background page). + +This method is very similar to the {{WebExtAPIRef("contentScripts.register","contentScripts.register()")}} API method (for example, they both return a promise that resolves to an API object with an {{WebExtAPIRef("userScripts_legacy.RegisteredUserScript.unregister","unregister()")}} method for unregistering the script). There are, however, differences in the options supported. + +This is an asynchronous method that returns a {{JSxRef("Promise")}}. + +## Syntax + +```js-nolint +const registeredUserScript = await browser.userScripts.register( + userScriptOptions // object +); +// … +await registeredUserScript.unregister(); +``` + +### Parameters + +- `userScriptOptions` + + - : `object`. Represents the user scripts to register. It has similar syntax to {{WebExtAPIRef("contentScripts.register","contentScripts.register()")}}. + + The `UserScriptOptions` object has the following properties: + + - `scriptMetadata` {{Optional_Inline}} + - : A `JSON` object containing arbitrary metadata properties associated with the registered user scripts. However, while arbitrary, the object must be serializable, so it is compatible with [the structured clone algorithm.](/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) This metadata is used to pass details from the script to the [API script](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts). For example, providing details of a subset of the APIs that need to be injected by the [API script](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts). The API does not use this metadata, + - `allFrames` {{Optional_Inline}} + - : Same as `all_frames` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. + - `cookieStoreId` {{optional_inline}} + - : An array of cookie store ID strings or a string containing a cookie store ID. Registers the user script in the tabs that belong to the cookie store IDs. This enables scripts to be registered for all default or non-contextual identity tabs, private browsing tabs (if the [extension is enabled in private browsing](https://support.mozilla.org/en-US/kb/extensions-private-browsing)), the tabs of a [contextual identity](/en-US/docs/Mozilla/Add-ons/WebExtensions/Work_with_contextual_identities), or a combination of these. + - `excludeGlobs` {{Optional_Inline}} + - : Same as `exclude_globs` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. + - `excludeMatches` {{Optional_Inline}} + - : Same as `exclude_matches` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. + - `includeGlobs` {{Optional_Inline}} + - : Same as `include_globs` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. + - `js` + - : An array of objects. Each object has either a property named `file`, which is a URL starting at the extension's manifest.json and pointing to a JavaScript file to register, or a property named `code`, which contains JavaScript code to register. + - `matchAboutBlank` {{Optional_Inline}} + - : Same as `match_about_blank` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. + - `matches` + - : Same as `matches` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. + The URL patterns provided in `matches` must be enabled by the host permissions defined in the manifest [`permission`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions) property or enabled by the user from the [`optional_permissions`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions) list. For example, if matches includes `https://mozilla.org/a` a script is only registered if host permissions include, for example, `https://mozilla.org/*`. If the URL pattern isn't enabled, the call to register fails with the error "Permission denied to register a user script for ORIGIN". + - `runAt` {{Optional_Inline}} + - : Same as `run_at` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. + +Unlike content script options, the userScriptOptions object does not have a CSS property. Use {{WebExtAPIRef("contentScripts.register","contentScripts.register()")}} to dynamically register and unregister stylesheets. + +### Return value + +A {{JSxRef("Promise")}} that is fulfilled with a {{WebExtAPIRef("userScripts_legacy.RegisteredUserScript","RegisteredUserScript")}} object that is use to unregister the user scripts. + +> [!NOTE] +> User scripts are unregistered when the related extension page (from which the user scripts were registered) is unloaded, so you should register user scripts from an extension page that persists at least as long as you want the user scripts to stay registered. + +## Browser compatibility + +{{Compat}} + +## See also + +- {{WebExtAPIRef("contentScripts.register","contentScripts.register()")}} +- {{WebExtAPIRef("userScripts_legacy.RegisteredUserScript.unregister","RegisteredUserScript.unregister()")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/index.md new file mode 100644 index 000000000000000..6972d709e0eee47 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/index.md @@ -0,0 +1,27 @@ +--- +title: userScripts.RegisteredUserScript (Legacy) +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/RegisteredUserScript +page-type: webextension-api-type +browser-compat: webextensions.api.userScripts_legacy.RegisteredUserScript +--- + +{{AddonSidebar}} + +> [!WARNING] +> This is documentation for the legacy `userScripts` API. It's available in Firefox for Manifest V2. For functionality to work with user scripts in Manifest V3 see the new {{WebExtAPIRef("userScripts")}} API. + +A `RegisteredUserScript` object is returned by a call to {{WebExtAPIRef("userScripts_legacy.register","userScripts.register()")}} and represents the user scripts registered in that call. + +The object defines a single method, {{WebExtAPIRef("userScripts_legacy.RegisteredUserScript.unregister","unregister()")}}, which is used to unregister the user scripts. + +> [!NOTE] +> If this object is destroyed (for example because it goes out of scope) then the associated scripts will be unregistered automatically, so you should keep a reference to this object for as long as you want the user scripts to stay registered. + +## Methods + +- {{WebExtAPIRef("userScripts_legacy.RegisteredUserScript.unregister","unregister()")}} + - : Unregisters the user scripts represented by this object. + +## Browser compatibility + +{{Compat}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/unregister/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/unregister/index.md new file mode 100644 index 000000000000000..01b5f6ee6e7daaa --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/unregister/index.md @@ -0,0 +1,43 @@ +--- +title: RegisteredUserScript.unregister() (Legacy) +slug: Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/RegisteredUserScript/unregister +page-type: webextension-api-function +browser-compat: webextensions.api.userScripts_legacy.RegisteredUserScript.unregister +--- + +{{AddonSidebar}} + +> [!WARNING] +> This is documentation for the legacy `userScripts` API. It's available in Firefox for Manifest V2. For functionality to work with user scripts in Manifest V3 see the new {{WebExtAPIRef("userScripts")}} API. + +The `unregister()` method of the {{WebExtAPIRef("userScripts_legacy.RegisteredUserScript","RegisteredUserScript")}} object unregisters the user scripts represented by the object, user scripts that were registered using {{WebExtAPIRef("userScripts_legacy.register","userScripts.register()")}}. + +> [!NOTE] +> User Scripts are automatically unregistered when the related extension page (from which the user scripts were registered) is unloaded, so you should register a user script from an extension page that persists at least as long as you want the user scripts to stay registered. + +## Syntax + +```js-nolint +const registeredUserScript = await browser.userScripts.register( + userScriptOptions // object +); +// … +await registeredUserScript.unregister() +``` + +### Parameters + +None. + +### Return value + +A {{JSxRef("Promise")}} that is resolved once the user scripts are unregistered. The promise does not return a value. + +## Browser compatibility + +{{Compat}} + +## See also + +- {{WebExtAPIRef("userScripts_legacy.register","userScripts.register()")}} +- {{WebExtAPIRef("userScripts_legacy.RegisteredUserScript","RegisteredUserScript")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/userscriptoptions/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/userscriptoptions/index.md new file mode 100644 index 000000000000000..8a8fa9ac72e1783 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/userscriptoptions/index.md @@ -0,0 +1,38 @@ +--- +title: UserScripts.UserScriptOptions (Legacy) +slug: Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/UserScriptOptions +page-type: webextension-api-type +--- + +{{AddonSidebar}} + +> [!WARNING] +> This is documentation for the legacy `userScripts` API. It's available in Firefox for Manifest V2. For functionality to work with user scripts in Manifest V3 see the new {{WebExtAPIRef("userScripts")}} API. + +The UserScriptOptions object represents the content scripts to register. It has similar syntax to the contentScript options supported by browser.contentScripts.register. The differences are: + +- it does not support a CSS property (use browser.contentScripts.register to dynamically register/unregister stylesheets) +- It does support an optional scriptMetadata property (as a plain JSON object which contains some metadata properties associated to the registered userScripts) + +The UserScriptOptions object has the following properties: + +- `allFrames` {{optional_inline}} + - : Same as `all_frames` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. +- `excludeGlobs` {{optional_inline}} + - : Same as `exclude_globs` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. +- `excludeMatches` {{optional_inline}} + - : Same as `exclude_matches` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. +- `includeGlobs` {{optional_inline}} + - : Same as `include_globs` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. +- `js` {{optional_inline}} + - : An array of objects. Each object has either a property named `file`, which is a URL starting at the extension's manifest.json and pointing to a JavaScript file to register, or a property named `code`, which is some JavaScript code to register. +- `matchAboutBlank` {{optional_inline}} + - : Same as `match_about_blank` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. +- `matches` + - : Same as `matches` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. +- `runAt` {{optional_inline}} + - : Same as `run_at` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. +- `scriptMetadata` {{optional_inline}} + - : A user script metadata value + +It has similar syntax to the contentScript options supported by browser.contentScripts.register. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/index.md new file mode 100644 index 000000000000000..d384e775e576f22 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/index.md @@ -0,0 +1,111 @@ +--- +title: Working with userScripts +slug: Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/Working_with_userScripts +page-type: guide +--- + +{{AddonSidebar}} + +> [!WARNING] +> This is documentation for the legacy `userScripts` API. It's available in Firefox for Manifest V2. For functionality to work with user scripts in Manifest V3 see the new {{WebExtAPIRef("userScripts")}} API. + +By implementing userScripts, extension developers can modify how sites look and/or work to better meet user needs. + +Implement userScripts in your extension using the following steps: + +1. Define the script in the extension's manifest using the `"user_scripts"` key. +2. Register the userScript +3. Implement the userScript functions + +Let's step through the processes using a small sample web extension that illustrates the process. The example is available in the [webextensions-examples](https://github.com/mdn/webextensions-examples) repository on GitHub. + +## userScripts Manifest + +A user script is identified by the contents of the [user_scripts](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts) key of the extension's manifest. The minimum information for the `user_scripts` key would be: + +```json + "user_scripts": { + "api_script": "customUserScriptAPIs.js" + } +``` + +The "api_script" property indicates the path to the JavaScript file that contains the code for the `userScript`. + +## Load the example extension + +Once you have downloaded the example: + +Navigate to about:debugging, click on **Load Temporary Add-on…** and double-click on the extension's manifest. + +The default code included with the example allows you to load a `userScript` which will "eat" the content of pages matching the Hosts entry. Make any changes you want to make before clicking the **Register script** button at the bottom of the panel. + +In the following image, the extension will "eat" the content of pages whose domain name ends in .org. This is the default behavior for this extension. + +![User script example](userscriptexample.png) + +Nothing will happen until you click the **Register script** button. The button implements the user script according to the settings on this dialog. That means that you can experiment with the behavior of the script without having to implement an extensions yourself. + +## Register the userScript + +Before a userScript can be executed, it must be registered using the `userScripts.register()` method. Here is the code to register the example extension: + +```js +async function registerScript() { + const params = { + hosts: stringToArray(hostsInput.value), + code: codeInput.value, + excludeMatches: stringToArray(excludeMatchesInput.value), + includeGlobs: stringToArray(includeGlobsInput.value), + excludeGlobs: stringToArray(excludeGlobsInput.value), + runAt: runAtInput.value, + matchAboutBlank: stringToBool(matchAboutBlankInput.value), + allFrames: stringToBool(allFramesInput.value), + scriptMetadata: { name: scriptNameInput.value || null }, + }; + + // Store the last submitted values to the extension storage + // (so that they can be restored when the popup is opened + // the next time). + await browser.storage.local.set({ + lastSetValues: params, + }); + + try { + // Clear the last userScripts.register result. + lastResultEl.textContent = ""; + + await browser.runtime.sendMessage(params); + lastResultEl.textContent = "UserScript successfully registered"; + // Clear the last userScripts.register error. + lastErrorEl.textContent = ""; + + // Clear the last error stored. + await browser.storage.local.remove("lastError"); + } catch (e) { + // There was an error on registering the userScript, + // let's show the error message in the popup and store + // the last error into the extension storage. + + const lastError = `${e}`; + // Show the last userScripts.register error. + lastErrorEl.textContent = lastError; + + // Store the last error. + await browser.storage.local.set({ lastError }); + } +} +``` + +This code first initializes the params object to pass values to the [userScripts.register](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/register) method. + +## Implement the userScript functions + +Once the script has been registered, navigate to a page whose domain name ends in .org, and you will see something like this: + +![Status message indicating that websites ending in .org have been eaten: "This page has been eaten. {"OldStoredValue:" "website address", "NewStoredValue:" "website address"}"](user_script_in_action.png) + +## See also + +- {{WebExtAPIRef("userScripts_legacy","userScripts")}} +- {{WebExtAPIRef("userScripts_legacy.register()", "userScripts.register()")}} +- {{WebExtAPIRef("userScripts_legacy.onBeforeScript")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/user_script_in_action.png b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/user_script_in_action.png new file mode 100644 index 0000000000000000000000000000000000000000..68126ffe8abe510a5b9539b5aa880139ad353d1a GIT binary patch literal 27302 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≈uOstS60PoXI~)GgoXe$4vaNh`G%@h_h7xZi!7;$Cm{fCGvug+okk z^jeMJU2+b%=}6D~a$lC}Mub99yI%Pu5nZqj0D}#Be(-k@Jklmm);2%{CW%o-Mh_RR zHuVe?j~(dhEk?yby|km##Jw*Swds+leWgc^JwKn=BX#p%%=Rs9DhmE&>|OhK z1uCQZkS7ob7C@x=?m57WDXN!DtB60Jj@(~Ve3WId?_kKNl%KP&yh{ZDCUyF61Ykn$ z^;%ZEBb-XNu#nX)YF{- zD;rTg6f4AMm_6GxpERqEf#pTp0 zYkraB8bLJKQntslFuZ1WwT3{Hf!4IRiD6r+H^S>_ybo=_KorLWZ7e^#>CU{lJgyQN z8FeOsy(`#M$irr_8(A}qkk2QuKU_l zA2KSr>^B2}p&6lXHV0i3%j+a$KhM0wW1d|1li|&p4x2R1+)glLG|VT|nkJ40Gi~bs z5E1AMh%Pqq`HbBkS=4T(Jaf;V4gC^c&$;?j%br>v{+){+NraOoOZSz!D|WtjFy7`K z8s6wdfb@`aH&dRaR~cdUbZhfE1ccr6*MCQGP>5ZDV5j4o*UmxF3qmKOls|hW8eRe= zw!jNfJH232C{vQC7?uB(Co13j9w?1=WifQ-w%zq%qi)%A9+k^#yN#xP7Y5HP81}}X zixkKMc?FffPBB1&7fGaoUrrN0OblRI_Ge9$=nbB8IFbaQj+vfdR=i7u6`Z6AKX zdNFhD;vc%P+Cr$@pwR(fNckU`@;?+SE>Wn`-vWSOc10FRTks#`BVu>}`nTxG$)e;< z%_DRgxc#5ULBYF$fFYQD&Ypqx@c~d=RX)j_`Tv=h{ByQKI#Bp`F)bx3<5(9xCj-~< zuM(aA?CKprx*5*=+ACRkRDyVly=u}n;(ghOrWeN1uV>oB^R@Y1&(jbHV%UVYJ+gX+ zHEnC~q^*44#iTQID01HS!u%9MJ7E?gZhP`h?WACCMV#Z{VKS|) zFI%A;XT66xoV>rcxAN(u+W25eHpi+_lPSBPPJR93m*=dZ9Z~CQ=bS~@_mxc$pvNA* z%8P#6gRI^Wk-a$;)o{vE&NO`{|9wWe^XRhWT#b+Stf-fgpQ;NJ?S#fMD`7?0TQ`qX z<7d0=@_}kxl@$ekbr~dIRUz0m>Di%KJvNb@sH}!JWm3?r$RSTl`H1U&BDDMrrrAQ8cyON0!V2S#-*M5D4UfDz!w9`EN7jaaf8>5vh2h z(%R^%{$@B}Vk8eMmMcCQ=p>YiLTU_o;9d|jEE>S;XPEJ5QagAlr^ZWI<#LtNK*^qK z+?3NWS>1Y<79>h@Z!~fCA{FlEW zr)ccd69YlWDjD{Fbyr>ATTX^~M^)xIeS27!>Rg4k zgbOwq<_|%x*NC7<-p@$)CuP=rPn%6T8;yy2hDb1Yyjxa7T-|yil-}RhTs?q6k6kPr z5Xwjet}#s7PEAlnDGmO|z_g2ckrW?D-82=cc?fMyZL0sdF7kC}+Sx|X>o|*iCt=8= zd_YKOf$6pK7=R+5{f`bI#T+=kRvT!KUpdF6`d`#PFN7r!_v1qk1hP*tF-chUxFZ%1 zK~9Sy!2K@Am0yQ`87~Xo-oKBl;u0Z$FnL)?9x%%)*wL&L&{=4ay+|O-6MDb3utPHL1(*>?Dlpj1Xkk|6s4)& ZbFi<~xYalA4F$lD&P6?~EKPji{{h(O1r`7R literal 0 HcmV?d00001 diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/userscriptexample.png b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/working_with_userscripts/userscriptexample.png new file mode 100644 index 0000000000000000000000000000000000000000..4179498480800d73e92bbd7a48c8cd7973c4cbe1 GIT binary patch literal 9292 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 literal 0 HcmV?d00001 diff --git a/files/en-us/mozilla/add-ons/webextensions/manifest.json/user_scripts/index.md b/files/en-us/mozilla/add-ons/webextensions/manifest.json/user_scripts/index.md index edcf2620485ff63..c9619e13b230368 100644 --- a/files/en-us/mozilla/add-ons/webextensions/manifest.json/user_scripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/manifest.json/user_scripts/index.md @@ -7,6 +7,9 @@ browser-compat: webextensions.manifest.user_scripts {{AddonSidebar}} +> [!WARNING] +> This key is used by the legacy {{WebExtAPIRef("userScripts_legacy","userScripts")}} API, which is available to extensions using Manifest V2. This key is not required for the version of the {{WebExtAPIRef("userScripts","userScripts")}} API available for use with Manifest V3. + @@ -38,7 +41,7 @@ browser-compat: webextensions.manifest.user_scripts Instructs the browser to load a script packaged in the extension, known as the API script, this script is used to export a set of custom API methods for use in user scripts. The API script path, relative to the manifest.json file, is defined as a `string` in `"api_script"`. > [!NOTE] -> The `user_script` key is required for the {{WebExtAPIRef("userScripts")}} API to function, even if no API script is specified. For example. `user_scripts: {}`. +> The `user_script` key is required for the {{WebExtAPIRef("userScripts_legacy","userScripts")}} API to function, even if no API script is specified. For example. `user_scripts: {}`. The API script: @@ -46,11 +49,11 @@ The API script: - has access to the window and document globals related to the webpage it is attached to. - has access to the same subset of WebExtension APIs usually available in a content script. -The script executes automatically on any webpage defined in `matches` by {{WebExtAPIRef("userScripts.register")}}. However, this is before the user script sandbox object is created and the custom API methods can be exported. +The script executes automatically on any webpage defined in `matches` by {{WebExtAPIRef("userScripts_legacy.register")}}. However, this is before the user script sandbox object is created and the custom API methods can be exported. -To export the custom API methods, the script listens for {{WebExtAPIRef("userScripts.onBeforeScript")}} and then export the custom API methods. +To export the custom API methods, the script listens for {{WebExtAPIRef("userScripts_legacy.onBeforeScript")}} and then export the custom API methods. -Not every user script may need to consume all of the custom API methods. You can, therefore, include details of the APIs needed in `scriptMetadata` when running {{WebExtAPIRef("userScripts.register")}}. The API script then accesses the `scriptMetadata` through the `script` parameter received by the {{WebExtAPIRef("userScripts.onBeforeScript")}} listener (as `script.metadata`). +Not every user script may need to consume all of the custom API methods. You can, therefore, include details of the APIs needed in `scriptMetadata` when running {{WebExtAPIRef("userScripts_legacy.register")}}. The API script then accesses the `scriptMetadata` through the `script` parameter received by the {{WebExtAPIRef("userScripts_legacy.onBeforeScript")}} listener (as `script.metadata`). ## Browser compatibility @@ -58,5 +61,5 @@ Not every user script may need to consume all of the custom API methods. You can ## See also -- {{WebExtAPIRef("userScripts")}} +- {{WebExtAPIRef("userScripts_legacy","userScripts")}} - {{WebExtAPIRef("contentScripts")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/work_with_contextual_identities/index.md b/files/en-us/mozilla/add-ons/webextensions/work_with_contextual_identities/index.md index 10aa2b942bdf7ab..d7637646651a88a 100644 --- a/files/en-us/mozilla/add-ons/webextensions/work_with_contextual_identities/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/work_with_contextual_identities/index.md @@ -33,7 +33,7 @@ Several extension APIs include the `cookieStoreId` in objects to enable extensio - {{WebExtAPIRef("downloads")}} where you can associate a download with a cookie store. - {{WebExtAPIRef("proxy")}} where the details passed into the {{WebExtAPIRef("proxy.onRequest")}} listener identify the cookie store associated with the request. - {{WebExtAPIRef("tabs")}} where you can {{WebExtAPIRef("tabs.create","create")}} a tab in a container tab, {{WebExtAPIRef("tabs.tab","get")}} the `cookieStoreId` for a tab, and {{WebExtAPIRef("tabs.query","query")}} tabs based on their associated cookie store. -- {{WebExtAPIRef("userScripts.register")}} enables you to register a content script restricted to documents associated with one or more `cookieStoreIds`. +- {{WebExtAPIRef("userScripts_legacy.register","userScripts.register")}} (legacy version, Manifest V2 only) enables you to register a content script restricted to documents associated with one or more `cookieStoreIds`. - {{WebExtAPIRef("webRequest")}} where all the events return the `cookieStoreId` of the request. - {{WebExtAPIRef("windows.create")}} where you can specify the cookie store for the tabs added to a window when it's created. From 02602fb8b67e2e716f970b52f163d9a27c94f372 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Thu, 6 Feb 2025 11:19:21 +1300 Subject: [PATCH 02/25] Deleted content --- .../api/userscripts/onbeforescript/index.md | 105 ----------------- .../registereduserscript/unregister/index.md | 40 ------- .../userscripts/userscriptoptions/index.md | 35 ------ .../working_with_userscripts/index.md | 108 ------------------ .../user_script_in_action.png | Bin 27302 -> 0 bytes .../userscriptexample.png | Bin 9292 -> 0 bytes 6 files changed, 288 deletions(-) delete mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/onbeforescript/index.md delete mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/unregister/index.md delete mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptoptions/index.md delete mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/index.md delete mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/user_script_in_action.png delete mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/userscriptexample.png diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/onbeforescript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/onbeforescript/index.md deleted file mode 100644 index 4eec81e52b022a7..000000000000000 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/onbeforescript/index.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: userScripts.onBeforeScript -slug: Mozilla/Add-ons/WebExtensions/API/userScripts/onBeforeScript -page-type: webextension-api-event -browser-compat: webextensions.api.userScripts.onBeforeScript ---- - -{{AddonSidebar}} - -The `onBeforeScript` event of the {{WebExtAPIRef("userScripts","browser.userScripts")}} is fired before a user script is executed. It can only be included in the API script, the script registered in [`"user_scripts"`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts), where it is used to detect that the custom API methods should be exported to the user script. - -## Syntax - -```js-nolint -browser.userScripts.onBeforeScript.addListener(listener) -browser.userScripts.onBeforeScript.removeListener(listener) -browser.userScripts.onBeforeScript.hasListener(listener) -``` - -Events have three functions: - -- `addListener(listener)` - - : Adds a listener to this event. -- `removeListener(listener)` - - : Stop listening to this event. The `listener` argument is the listener to remove. -- `hasListener(listener)` - - : Check whether `listener` is registered for this event. Returns `true` if it is listening, `false` otherwise. - -## addListener syntax - -### Parameters - -- `listener` - - - : The function called when this event occurs. The function is passed these arguments: - - - `script` - - - : An `object` that represents the user script that matched a web page. Its properties and methods are as follows: - - - `defineGlobals` - - : A method that exports an object containing properties and methods available globally to the user script sandbox. This method must be called synchronously to guarantee that the user script has not executed. - - `export` - - : A method that converts a value to one that the user script code can access. This method is used in API methods exported to the user script to result or resolve non-primitive values. The exported objects can also provide methods that the user script code can access and call. - - `global` - - : An `object` that provides access to the sandbox for the user script. - - `metadata` - - : The `scriptMetadata` property set when the user script was registered using `userScripts.register`. - -## Examples - -An example of how the listener might be used: - -```js -browser.userScripts.onBeforeScript.addListener((script) => { - script; // This is an API object that represents the user script - // that is going to be executed. - - script.metadata; // Access the user script metadata (returns the - // value of the scriptMetadata property from - // the call to userScripts.register). - - // Export some global properties into the user script sandbox - // (this method has to be called synchronously from the - // listener, otherwise the user script may have executed). - script.defineGlobals({ - aGlobalPropertyAccessibleFromUserScriptCode: "prop value", - - myCustomAPIMethod(param1, param2) { - // Custom methods exported from the API script can use - // the WebExtensions APIs available to content scripts. - browser.runtime.sendMessage(/* … */); - // … - - return 123; // primitive values can be returned directly - // … - - // Non primitive values have to be exported explicitly - // using the export method provided by the script API - // object - return script.export({ - objKey1: { - nestedProp: "nestedValue", - }, - // Explicitly exported objects can also provide methods. - objMethod() { - /* … */ - }, - }); - }, - - async myAsyncMethod(param1, param2, param3) { - // exported methods can also be declared as async - }, - }); -}); -``` - -## Browser compatibility - -{{Compat}} - -## See also - -- {{WebExtAPIRef("contentScripts")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/unregister/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/unregister/index.md deleted file mode 100644 index e60cb516c90c61f..000000000000000 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/unregister/index.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: RegisteredUserScript.unregister() -slug: Mozilla/Add-ons/WebExtensions/API/userScripts/RegisteredUserScript/unregister -page-type: webextension-api-function -browser-compat: webextensions.api.userScripts.RegisteredUserScript.unregister ---- - -{{AddonSidebar}} - -The `unregister()` method of the {{WebExtAPIRef("userScripts.RegisteredUserScript","RegisteredUserScript")}} object unregisters the user scripts represented by the object, user scripts that were registered using {{WebExtAPIRef("userScripts.register","userScripts.register()")}}. - -> [!NOTE] -> User Scripts are automatically unregistered when the related extension page (from which the user scripts were registered) is unloaded, so you should register a user script from an extension page that persists at least as long as you want the user scripts to stay registered. - -## Syntax - -```js-nolint -const registeredUserScript = await browser.userScripts.register( - userScriptOptions // object -); -// … -await registeredUserScript.unregister() -``` - -### Parameters - -None. - -### Return value - -A {{JSxRef("Promise")}} that is resolved once the user scripts are unregistered. The promise does not return a value. - -## Browser compatibility - -{{Compat}} - -## See also - -- {{WebExtAPIRef("userScripts.register","userScripts.register()")}} -- {{WebExtAPIRef("userScripts.RegisteredUserScript","RegisteredUserScript")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptoptions/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptoptions/index.md deleted file mode 100644 index 1d1f3c8e9ac7139..000000000000000 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptoptions/index.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: UserScripts.UserScriptOptions -slug: Mozilla/Add-ons/WebExtensions/API/userScripts/UserScriptOptions -page-type: webextension-api-type ---- - -{{AddonSidebar}} - -The UserScriptOptions object represents the content scripts to register. It has similar syntax to the contentScript options supported by browser.contentScripts.register. The differences are: - -- it does not support a CSS property (use browser.contentScripts.register to dynamically register/unregister stylesheets) -- It does support an optional scriptMetadata property (as a plain JSON object which contains some metadata properties associated to the registered userScripts) - -The UserScriptOptions object has the following properties: - -- `allFrames` {{optional_inline}} - - : Same as `all_frames` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. -- `excludeGlobs` {{optional_inline}} - - : Same as `exclude_globs` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. -- `excludeMatches` {{optional_inline}} - - : Same as `exclude_matches` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. -- `includeGlobs` {{optional_inline}} - - : Same as `include_globs` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. -- `js` {{optional_inline}} - - : An array of objects. Each object has either a property named `file`, which is a URL starting at the extension's manifest.json and pointing to a JavaScript file to register, or a property named `code`, which is some JavaScript code to register. -- `matchAboutBlank` {{optional_inline}} - - : Same as `match_about_blank` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. -- `matches` - - : Same as `matches` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. -- `runAt` {{optional_inline}} - - : Same as `run_at` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. -- `scriptMetadata` {{optional_inline}} - - : A user script metadata value - -It has similar syntax to the contentScript options supported by browser.contentScripts.register. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/index.md deleted file mode 100644 index 77589718aea64c6..000000000000000 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/index.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: Working with userScripts -slug: Mozilla/Add-ons/WebExtensions/API/userScripts/Working_with_userScripts -page-type: guide ---- - -{{AddonSidebar}} - -By implementing userScripts, extension developers can modify how sites look and/or work to better meet user needs. - -Implement userScripts in your extension using the following steps: - -1. Define the script in the extension's manifest using the `"user_scripts"` key. -2. Register the userScript -3. Implement the userScript functions - -Let's step through the processes using a small sample web extension that illustrates the process. The example is available in the [webextensions-examples](https://github.com/mdn/webextensions-examples) repository on GitHub. - -## userScripts Manifest - -A user script is identified by the contents of the [user_scripts](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts) key of the extension's manifest. The minimum information for the `user_scripts` key would be: - -```json - "user_scripts": { - "api_script": "customUserScriptAPIs.js" - } -``` - -The "api_script" property indicates the path to the JavaScript file that contains the code for the `userScript`. - -## Load the example extension - -Once you have downloaded the example: - -Navigate to about:debugging, click on **Load Temporary Add-on…** and double-click on the extension's manifest. - -The default code included with the example allows you to load a `userScript` which will "eat" the content of pages matching the Hosts entry. Make any changes you want to make before clicking the **Register script** button at the bottom of the panel. - -In the following image, the extension will "eat" the content of pages whose domain name ends in .org. This is the default behavior for this extension. - -![User script example](userscriptexample.png) - -Nothing will happen until you click the **Register script** button. The button implements the user script according to the settings on this dialog. That means that you can experiment with the behavior of the script without having to implement an extensions yourself. - -## Register the userScript - -Before a userScript can be executed, it must be registered using the `userScripts.register()` method. Here is the code to register the example extension: - -```js -async function registerScript() { - const params = { - hosts: stringToArray(hostsInput.value), - code: codeInput.value, - excludeMatches: stringToArray(excludeMatchesInput.value), - includeGlobs: stringToArray(includeGlobsInput.value), - excludeGlobs: stringToArray(excludeGlobsInput.value), - runAt: runAtInput.value, - matchAboutBlank: stringToBool(matchAboutBlankInput.value), - allFrames: stringToBool(allFramesInput.value), - scriptMetadata: { name: scriptNameInput.value || null }, - }; - - // Store the last submitted values to the extension storage - // (so that they can be restored when the popup is opened - // the next time). - await browser.storage.local.set({ - lastSetValues: params, - }); - - try { - // Clear the last userScripts.register result. - lastResultEl.textContent = ""; - - await browser.runtime.sendMessage(params); - lastResultEl.textContent = "UserScript successfully registered"; - // Clear the last userScripts.register error. - lastErrorEl.textContent = ""; - - // Clear the last error stored. - await browser.storage.local.remove("lastError"); - } catch (e) { - // There was an error on registering the userScript, - // let's show the error message in the popup and store - // the last error into the extension storage. - - const lastError = `${e}`; - // Show the last userScripts.register error. - lastErrorEl.textContent = lastError; - - // Store the last error. - await browser.storage.local.set({ lastError }); - } -} -``` - -This code first initializes the params object to pass values to the [userScripts.register](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/register) method. - -## Implement the userScript functions - -Once the script has been registered, navigate to a page whose domain name ends in .org, and you will see something like this: - -![Status message indicating that websites ending in .org have been eaten: "This page has been eaten. {"OldStoredValue:" "website address", "NewStoredValue:" "website address"}"](user_script_in_action.png) - -## See also - -- {{WebExtAPIRef("userScripts")}} -- {{WebExtAPIRef("userScripts.register()", "userScripts.register()")}} -- {{WebExtAPIRef("userScripts.onBeforeScript")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/user_script_in_action.png b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/user_script_in_action.png deleted file mode 100644 index 68126ffe8abe510a5b9539b5aa880139ad353d1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27302 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≈uOstS60PoXI~)GgoXe$4vaNh`G%@h_h7xZi!7;$Cm{fCGvug+okk z^jeMJU2+b%=}6D~a$lC}Mub99yI%Pu5nZqj0D}#Be(-k@Jklmm);2%{CW%o-Mh_RR zHuVe?j~(dhEk?yby|km##Jw*Swds+leWgc^JwKn=BX#p%%=Rs9DhmE&>|OhK z1uCQZkS7ob7C@x=?m57WDXN!DtB60Jj@(~Ve3WId?_kKNl%KP&yh{ZDCUyF61Ykn$ z^;%ZEBb-XNu#nX)YF{- zD;rTg6f4AMm_6GxpERqEf#pTp0 zYkraB8bLJKQntslFuZ1WwT3{Hf!4IRiD6r+H^S>_ybo=_KorLWZ7e^#>CU{lJgyQN z8FeOsy(`#M$irr_8(A}qkk2QuKU_l zA2KSr>^B2}p&6lXHV0i3%j+a$KhM0wW1d|1li|&p4x2R1+)glLG|VT|nkJ40Gi~bs z5E1AMh%Pqq`HbBkS=4T(Jaf;V4gC^c&$;?j%br>v{+){+NraOoOZSz!D|WtjFy7`K z8s6wdfb@`aH&dRaR~cdUbZhfE1ccr6*MCQGP>5ZDV5j4o*UmxF3qmKOls|hW8eRe= zw!jNfJH232C{vQC7?uB(Co13j9w?1=WifQ-w%zq%qi)%A9+k^#yN#xP7Y5HP81}}X zixkKMc?FffPBB1&7fGaoUrrN0OblRI_Ge9$=nbB8IFbaQj+vfdR=i7u6`Z6AKX zdNFhD;vc%P+Cr$@pwR(fNckU`@;?+SE>Wn`-vWSOc10FRTks#`BVu>}`nTxG$)e;< z%_DRgxc#5ULBYF$fFYQD&Ypqx@c~d=RX)j_`Tv=h{ByQKI#Bp`F)bx3<5(9xCj-~< zuM(aA?CKprx*5*=+ACRkRDyVly=u}n;(ghOrWeN1uV>oB^R@Y1&(jbHV%UVYJ+gX+ zHEnC~q^*44#iTQID01HS!u%9MJ7E?gZhP`h?WACCMV#Z{VKS|) zFI%A;XT66xoV>rcxAN(u+W25eHpi+_lPSBPPJR93m*=dZ9Z~CQ=bS~@_mxc$pvNA* z%8P#6gRI^Wk-a$;)o{vE&NO`{|9wWe^XRhWT#b+Stf-fgpQ;NJ?S#fMD`7?0TQ`qX z<7d0=@_}kxl@$ekbr~dIRUz0m>Di%KJvNb@sH}!JWm3?r$RSTl`H1U&BDDMrrrAQ8cyON0!V2S#-*M5D4UfDz!w9`EN7jaaf8>5vh2h z(%R^%{$@B}Vk8eMmMcCQ=p>YiLTU_o;9d|jEE>S;XPEJ5QagAlr^ZWI<#LtNK*^qK z+?3NWS>1Y<79>h@Z!~fCA{FlEW zr)ccd69YlWDjD{Fbyr>ATTX^~M^)xIeS27!>Rg4k zgbOwq<_|%x*NC7<-p@$)CuP=rPn%6T8;yy2hDb1Yyjxa7T-|yil-}RhTs?q6k6kPr z5Xwjet}#s7PEAlnDGmO|z_g2ckrW?D-82=cc?fMyZL0sdF7kC}+Sx|X>o|*iCt=8= zd_YKOf$6pK7=R+5{f`bI#T+=kRvT!KUpdF6`d`#PFN7r!_v1qk1hP*tF-chUxFZ%1 zK~9Sy!2K@Am0yQ`87~Xo-oKBl;u0Z$FnL)?9x%%)*wL&L&{=4ay+|O-6MDb3utPHL1(*>?Dlpj1Xkk|6s4)& ZbFi<~xYalA4F$lD&P6?~EKPji{{h(O1r`7R diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/userscriptexample.png b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/working_with_userscripts/userscriptexample.png deleted file mode 100644 index 4179498480800d73e92bbd7a48c8cd7973c4cbe1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9292 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 From 6882c17b9c3b51b4c0bcc7640ca394100695c57e Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Thu, 6 Feb 2025 11:32:01 +1300 Subject: [PATCH 03/25] Missing slug updates --- .../add-ons/webextensions/api/userscripts_legacy/index.md | 2 +- .../webextensions/api/userscripts_legacy/register/index.md | 2 +- .../api/userscripts_legacy/registereduserscript/index.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/index.md index 5d375158fd134f8..0c9a53de3af87bb 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/index.md @@ -1,6 +1,6 @@ --- title: userScripts (Legacy) -slug: Mozilla/Add-ons/WebExtensions/API/userScripts +slug: Mozilla/Add-ons/WebExtensions/API/userScripts_legacy page-type: webextension-api browser-compat: webextensions.api.userScripts_legacy --- diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md index e40c79b31190e99..ac1154e6276738f 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md @@ -1,6 +1,6 @@ --- title: userScripts.register() (Legacy) (Legacy) -slug: Mozilla/Add-ons/WebExtensions/API/userScripts/register +slug: Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/register page-type: webextension-api-function browser-compat: webextensions.api.userScripts_legacy.register --- diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/index.md index 6972d709e0eee47..69a29af16e3e4fe 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/registereduserscript/index.md @@ -1,6 +1,6 @@ --- title: userScripts.RegisteredUserScript (Legacy) -slug: Mozilla/Add-ons/WebExtensions/API/userScripts/RegisteredUserScript +slug: Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/RegisteredUserScript page-type: webextension-api-type browser-compat: webextensions.api.userScripts_legacy.RegisteredUserScript --- From a55a6d9f41e0f705db63e4fa741f1db0097b538f Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Thu, 6 Feb 2025 11:33:34 +1300 Subject: [PATCH 04/25] remove dup --- .../webextensions/api/userscripts_legacy/register/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md index ac1154e6276738f..c8c669655d5ceff 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts_legacy/register/index.md @@ -1,5 +1,5 @@ --- -title: userScripts.register() (Legacy) (Legacy) +title: userScripts.register() (Legacy) slug: Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/register page-type: webextension-api-function browser-compat: webextensions.api.userScripts_legacy.register From 13926ce36b71f54b1f6c5f6271a898344bdabf93 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Mon, 10 Feb 2025 14:46:53 +1300 Subject: [PATCH 05/25] Updated userScripts main article and type and method stubs --- .../api/userscripts/configureworld/index.md | 34 +++++++++ .../api/userscripts/executionworld/index.md | 37 ++++++++++ .../api/userscripts/getscripts/index.md | 34 +++++++++ .../getworldconfigurations/index.md | 34 +++++++++ .../webextensions/api/userscripts/index.md | 69 ++++++++++++++----- .../api/userscripts/register/index.md | 2 +- .../userscripts/registereduserscript/index.md | 14 ++-- .../resetworldconfiguration/index.md | 34 +++++++++ .../api/userscripts/scriptsource/index.md | 37 ++++++++++ .../api/userscripts/unregister/index.md | 34 +++++++++ .../api/userscripts/update/index.md | 34 +++++++++ .../api/userscripts/userscriptfilter/index.md | 26 +++++++ .../api/userscripts/worldproperties/index.md | 26 +++++++ 13 files changed, 391 insertions(+), 24 deletions(-) create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md new file mode 100644 index 000000000000000..20b7e9fb5696c1e --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md @@ -0,0 +1,34 @@ +--- +title: userScripts.configureWorld() +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/configureWorld +page-type: webextension-api-function +browser-compat: webextensions.api.userScripts.configureWorld +--- + +{{AddonSidebar}} + +This method configures the `USER_SCRIPT` execution environment. + +This is an asynchronous method that returns a {{JSxRef("Promise")}}. + +## Syntax + +```js-nolint +const registeredUserScript = await browser.userScripts.configureWorld( + userScriptOptions // object +); +``` + +### Parameters + +### Return value + +A {{JSxRef("Promise")}} that is … + +## Examples + +{{WebExtExamples}} + +## Browser compatibility + +{{Compat}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md new file mode 100644 index 000000000000000..59dec442654b871 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md @@ -0,0 +1,37 @@ +--- +title: userScripts.ExecutionWorld +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/ExecutionWorld +page-type: webextension-api-type +browser-compat: webextensions.api.userScripts.ExecutionWorld +--- + +{{AddonSidebar}} + +Specifies the execution environment of a script injected with {{WebExtAPIRef("userScripts.register()")}} +or {{WebExtAPIRef("userScripts.update()")}}. + +## Type + +Values of this type are strings. Possible values are: + +- `MAIN` + + The web page execution environment. This environment is shared with the web page without isolation. + Scripts in this environment do not have any access to APIs that are only available to content scripts. + + > [!WARNING] + > Due to the lack of isolation, the web page can detect and interfere with the executed code. + > Do not use the `MAIN` world unless it is acceptable for web pages to read, access, or modify the logic or data that flows through the executed code. + +- `USER_SCRIPT` + + Specifies the user scripts execution environment which is exempt from the page's content security policy (CSP). + +{{WebExtExamples("h2")}} + +## Browser compatibility + +{{Compat}} + +> [!NOTE] +> This API is based on Chromium's [`chrome.scripting`](https://developer.chrome.com/docs/extensions/reference/api/scripting#type-ExecutionWorld) API. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md new file mode 100644 index 000000000000000..733ce98d8919463 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md @@ -0,0 +1,34 @@ +--- +title: userScripts.getScripts() +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/getScripts +page-type: webextension-api-function +browser-compat: webextensions.api.userScripts.getScripts +--- + +{{AddonSidebar}} + +This method returns the extension's registered user scripts. + +This is an asynchronous method that returns a {{JSxRef("Promise")}}. + +## Syntax + +```js-nolint +const registeredUserScript = await browser.userScripts.getScripts( + userScriptOptions // object +); +``` + +### Parameters + +### Return value + +A {{JSxRef("Promise")}} that is … + +## Examples + +{{WebExtExamples}} + +## Browser compatibility + +{{Compat}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md new file mode 100644 index 000000000000000..5ac86ee52ce73f1 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md @@ -0,0 +1,34 @@ +--- +title: userScripts.getWorldConfigurations() +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/getWorldConfigurations +page-type: webextension-api-function +browser-compat: webextensions.api.userScripts.getWorldConfigurations +--- + +{{AddonSidebar}} + +This method returns all the registered world configurations. + +This is an asynchronous method that returns a {{JSxRef("Promise")}}. + +## Syntax + +```js-nolint +const registeredUserScript = await browser.userScripts.getWorldConfigurations( + userScriptOptions // object +); +``` + +### Parameters + +### Return value + +A {{JSxRef("Promise")}} that is … + +## Examples + +{{WebExtExamples}} + +## Browser compatibility + +{{Compat}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index 4c21fb7a6a701a5..0136ef989567cfb 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -10,36 +10,74 @@ browser-compat: webextensions.api.userScripts Use this API to register user scripts, third-party scripts designed to manipulate webpages or provide new features. Registering a user script instructs the browser to attach the script to pages that match the URL patterns specified during registration. > [!NOTE] -> This is documentation for the legacy API version, available in Firefox for Manifest V2. A new API has been designed, see [WECG issue 279](https://github.com/w3c/webextensions/issues/279). This new version of the API will be available in Firefox for use in Manifest V3. Development is tracked in [Firefox bug 1875475](https://bugzil.la/1875475). Chrome includes [an implementation of the new API](https://developer.chrome.com/docs/extensions/reference/api/userScripts). Meanwhile, when using Manifest V3 or higher, use {{WebExtAPIRef("scripting.registerContentScripts()")}} to register scripts. +> This is documentation for the new API version, available in Firefox for Manifest V3. See {{WebExtAPIRef("userScripts_legacy","userScripts (legacy)")}} for information on the API available for use in Firefox with Manifest V2. -This API offers similar capabilities to {{WebExtAPIRef("contentScripts")}} but with features suited to handling third-party scripts: +This API offers capabilities similar to {{WebExtAPIRef("contentScripts")}} but with features suited to handling third-party scripts. -- execution is in an isolated sandbox: each user script is run in an isolated sandbox within the web content processes, preventing accidental or deliberate interference among scripts. -- access to the `window` and `document` global values related to the webpage the user script is attached to. -- no access to WebExtension APIs or associated permissions granted to the extension: the API script, which inherits the extension's permissions, can provide packaged WebExtension APIs to registered user scripts. An API script is declared in the extension's manifest file using the "user_scripts" manifest key. +## Permissions -> [!WARNING] -> This API requires the presence of the [`user_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts) key in the manifest.json, even if no API script is specified. For example. `user_scripts: {}`. +To use this API, you need the `userScripts` permission and `host_permissions` for sites where you want to run scripts. However, the approach to enabling the use of this API varies between browsers: -To use the API, call `{{WebExtAPIRef("userScripts.register","register()")}}` passing in an object defining the scripts to register. The method returns a Promise that is resolved with a `{{WebExtAPIRef("userScripts.RegisteredUserScript","RegisteredUserScript")}}` object. +- In Firefox, `userScripts` is an optional-only permission declared in the [`optional_permissions` manifest key](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions#optional-only_permissions). This means that your extension must request the permission programmatically using {{WebExtAPIRef("permissions.request()")}}. +- in Chrome, `userScripts` is an install time requested permission declared in the [`permissions` manifest key](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions). However, to enable use of the API, users must [turn on the developer environment in Chrome](https://developer.chrome.com/docs/extensions/reference/api/userScripts#developer_mode_for_extension_users). + +## Execution worlds + +When registering a user script (using {{WebExtAPIRef("userScripts.register()")}}) your extension can run it in an isolated, `USER_SCRIPT` world or the `MAIN` world. + +The isolated `USER_SCRIPT` world provides an execution environment that isn't accessible to a host page or other extensions. This means a user script can change its JavaScript environment without affecting the host page or other extensions' user and content scripts. In this environment, user scripts aren't visible to the host page or other extensions' user and content scripts. The API also enables an extension to configure a content security policy (CSP) for the `USER_SCRIPT` world using {{WebExtAPIRef("userScripts.configureWorld()")}}. + +In the `MAIN` world, host pages and other extensions can see and access running user scripts. + +## Messaging + +Like content scripts and offscreen documents, user scripts communicate with other parts of an extension with messages using {{WebExtAPIRef("runtime.sendMessage()")}} and {{WebExtAPIRef("runtime.connect()")}}. However, user scripts receive messages using the dedicated {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}}. Dedicated handlers are used as they make it easier to identify messages from user scripts, which are a less-trusted context. + +Before sending a message, call {{WebExtAPIRef("userScripts.configureWorld()")}} with the `messaging` argument set to `true`. The `csp` and `messaging` arguments can be passed at the same time. + +```js +chrome.userScripts.configureWorld({ + messaging: true, +}); +``` + +## Extension updates + +When an extension updates, user scripts are cleared. To restore scripts, add code to the extension's {{WebExtAPIRef("runtime.onInstalled")}} event handler that respond to the `"update"` reason. > [!NOTE] -> User scripts are unregistered when the related extension page (from which the user scripts were registered) is unloaded, so you should register a user script from an extension page that persists at least as long as you want the user scripts to stay registered. +> User scripts are unregistered when the related extension page (from which the user scripts were registered) is unloaded, so register user scripts from an extension page that persists as long as you want the user scripts to stay registered. ## Types - {{WebExtAPIRef("userScripts.RegisteredUserScript")}} - - : The `object` returned by the {{WebExtAPIRef("userScripts.register","register()")}} method. It represents the registered user scripts and is used to deregister the user scripts. + - : Specifies the execution environment of a script injected with {{WebExtAPIRef("userScripts.register()")}} + or {{WebExtAPIRef("userScripts.update()")}}. +- {{WebExtAPIRef("userScripts.RegisteredUserScript")}} + - : The `object` returned by the {{WebExtAPIRef("userScripts.register","register()")}} method representing registered user scripts. +- {{WebExtAPIRef("userScripts.ScriptSource")}} + - : Specifies the code or a file source for a user script. +- {{WebExtAPIRef("userScripts.UserScriptFilter")}} + - : Specifies a list of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. +- {{WebExtAPIRef("userScripts.WorldProperties")}} + - : The configuration of a `USER_SCRIPT` execution environment. ## Methods +- {{WebExtAPIRef("userScripts.configureWorld()")}} + - : Configures the `USER_SCRIPT` execution environment. +- {{WebExtAPIRef("userScripts.getScripts()")}} + - : Returns the extension's registered user scripts. +- {{WebExtAPIRef("userScripts.getWorldConfigurations()")}} + - : Returns all the registered world configurations. - {{WebExtAPIRef("userScripts.register()")}} - : Registers user scripts. - -## Events - -- {{WebExtAPIRef("userScripts.onBeforeScript")}} - - : An event available to the API script, registered in[`"user_scripts"`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts), that execute before a user script executes. Use it to trigger the export of the additional APIs provided by the API script, so they are available to the user script. +- {{WebExtAPIRef("userScripts.resetWorldConfiguration()")}} + - : Resets the configuration for a user script world. +- {{WebExtAPIRef("userScripts.unregister()")}} + - : Unregisters all the user scripts registered by the extension. +- {{WebExtAPIRef("userScripts.update()")}} + - : Updates one or more of the extension's user scripts. ## Browser compatibility @@ -47,5 +85,4 @@ To use the API, call `{{WebExtAPIRef("userScripts.register","register()")}}` pas ## See also -- [Working with `userScripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts_legacy/Working_with_userScripts) - {{WebExtAPIRef("contentScripts","browser.contentScripts")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md index 0fa12c80df3d7a7..0a39ceaf69729bc 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md @@ -7,7 +7,7 @@ browser-compat: webextensions.api.userScripts.register {{AddonSidebar}} -This method enables user scripts to be registered from an extension's pages (such as the background page). +This method registers user scripts from an extension's pages (such as the background page). This method is very similar to the {{WebExtAPIRef("contentScripts.register","contentScripts.register()")}} API method (for example, they both return a promise that resolves to an API object with an {{WebExtAPIRef("userScripts.RegisteredUserScript.unregister","unregister()")}} method for unregistering the script). There are, however, differences in the options supported. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md index 1a9096e2711b231..23f180bad0e46bc 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md @@ -7,17 +7,17 @@ browser-compat: webextensions.api.userScripts.RegisteredUserScript {{AddonSidebar}} -A `RegisteredUserScript` object is returned by a call to {{WebExtAPIRef("userScripts.register","userScripts.register()")}} and represents the user scripts registered in that call. +An object representing a registered user script. -The object defines a single method, {{WebExtAPIRef("userScripts.RegisteredUserScript.unregister","unregister()")}}, which is used to unregister the user scripts. +## Type -> [!NOTE] -> If this object is destroyed (for example because it goes out of scope) then the associated scripts will be unregistered automatically, so you should keep a reference to this object for as long as you want the user scripts to stay registered. +Values of this type are ?. Possible values are: -## Methods +- `` -- {{WebExtAPIRef("userScripts.RegisteredUserScript.unregister","unregister()")}} - - : Unregisters the user scripts represented by this object. +- `` + + . ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md new file mode 100644 index 000000000000000..36e14280da4e9cb --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md @@ -0,0 +1,34 @@ +--- +title: userScripts.resetWorldConfiguration() +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/resetWorldConfiguration +page-type: webextension-api-function +browser-compat: webextensions.api.userScripts.resetWorldConfiguration +--- + +{{AddonSidebar}} + +Resets the configuration for a user script world. Any scripts inject into the world are moved to the default world configuration. + +This is an asynchronous method that returns a {{JSxRef("Promise")}}. + +## Syntax + +```js-nolint +const registeredUserScript = await browser.userScripts.resetWorldConfiguration( + userScriptOptions // object +); +``` + +### Parameters + +### Return value + +A {{JSxRef("Promise")}} that is … + +## Examples + +{{WebExtExamples}} + +## Browser compatibility + +{{Compat}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md new file mode 100644 index 000000000000000..59dec442654b871 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md @@ -0,0 +1,37 @@ +--- +title: userScripts.ExecutionWorld +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/ExecutionWorld +page-type: webextension-api-type +browser-compat: webextensions.api.userScripts.ExecutionWorld +--- + +{{AddonSidebar}} + +Specifies the execution environment of a script injected with {{WebExtAPIRef("userScripts.register()")}} +or {{WebExtAPIRef("userScripts.update()")}}. + +## Type + +Values of this type are strings. Possible values are: + +- `MAIN` + + The web page execution environment. This environment is shared with the web page without isolation. + Scripts in this environment do not have any access to APIs that are only available to content scripts. + + > [!WARNING] + > Due to the lack of isolation, the web page can detect and interfere with the executed code. + > Do not use the `MAIN` world unless it is acceptable for web pages to read, access, or modify the logic or data that flows through the executed code. + +- `USER_SCRIPT` + + Specifies the user scripts execution environment which is exempt from the page's content security policy (CSP). + +{{WebExtExamples("h2")}} + +## Browser compatibility + +{{Compat}} + +> [!NOTE] +> This API is based on Chromium's [`chrome.scripting`](https://developer.chrome.com/docs/extensions/reference/api/scripting#type-ExecutionWorld) API. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md new file mode 100644 index 000000000000000..43aee5340a1e9fe --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md @@ -0,0 +1,34 @@ +--- +title: userScripts.unregister() +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/unregister +page-type: webextension-api-function +browser-compat: webextensions.api.userScripts.unregister +--- + +{{AddonSidebar}} + +Unregisters all the user scripts registered by the extension. + +This is an asynchronous method that returns a {{JSxRef("Promise")}}. + +## Syntax + +```js-nolint +const registeredUserScript = await browser.userScripts.unregister( + userScriptOptions // object +); +``` + +### Parameters + +### Return value + +A {{JSxRef("Promise")}} that is … + +## Examples + +{{WebExtExamples}} + +## Browser compatibility + +{{Compat}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md new file mode 100644 index 000000000000000..78ce1b561550e02 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md @@ -0,0 +1,34 @@ +--- +title: userScripts.update() +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/update +page-type: webextension-api-function +browser-compat: webextensions.api.userScripts.update +--- + +{{AddonSidebar}} + +Updates one or more of the extension's user scripts. + +This is an asynchronous method that returns a {{JSxRef("Promise")}}. + +## Syntax + +```js-nolint +const registeredUserScript = await browser.userScripts.update( + userScriptOptions // object +); +``` + +### Parameters + +### Return value + +A {{JSxRef("Promise")}} that is … + +## Examples + +{{WebExtExamples}} + +## Browser compatibility + +{{Compat}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md new file mode 100644 index 000000000000000..cd176db44090f59 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md @@ -0,0 +1,26 @@ +--- +title: userScripts.UserScriptFilter +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/UserScriptFilter +page-type: webextension-api-type +browser-compat: webextensions.api.userScripts.UserScriptFilter +--- + +{{AddonSidebar}} + +Specifies the code or a file source for a user script. + +## Type + +Values of this type are ?. Possible values are: + +- `` + +- `` + + . + +{{WebExtExamples("h2")}} + +## Browser compatibility + +{{Compat}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md new file mode 100644 index 000000000000000..0376567651fe242 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md @@ -0,0 +1,26 @@ +--- +title: userScripts.WorldProperties +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/WorldProperties +page-type: webextension-api-type +browser-compat: webextensions.api.userScripts.WorldProperties +--- + +{{AddonSidebar}} + +The configuration of a `USER_SCRIPT` execution environment. + +## Type + +Values of this type are ?. Possible values are: + +- `` + +- `` + + . + +{{WebExtExamples("h2")}} + +## Browser compatibility + +{{Compat}} From 2c4ed84528b71e2f8b03443104ea1faebf217f65 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Tue, 11 Feb 2025 04:37:07 +1300 Subject: [PATCH 06/25] Correct ScriptSource stub --- .../api/userscripts/scriptsource/index.md | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md index 59dec442654b871..25a5f6db5579551 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md @@ -1,31 +1,21 @@ --- -title: userScripts.ExecutionWorld -slug: Mozilla/Add-ons/WebExtensions/API/userScripts/ExecutionWorld +title: userScripts.ScriptSource +slug: Mozilla/Add-ons/WebExtensions/API/userScripts/ScriptSource page-type: webextension-api-type -browser-compat: webextensions.api.userScripts.ExecutionWorld +browser-compat: webextensions.api.userScripts.ScriptSource --- {{AddonSidebar}} -Specifies the execution environment of a script injected with {{WebExtAPIRef("userScripts.register()")}} -or {{WebExtAPIRef("userScripts.update()")}}. +Specifies the code or a file source for a user script. ## Type -Values of this type are strings. Possible values are: +Values of this type are ?. Possible values are: -- `MAIN` +- `id` - The web page execution environment. This environment is shared with the web page without isolation. - Scripts in this environment do not have any access to APIs that are only available to content scripts. - - > [!WARNING] - > Due to the lack of isolation, the web page can detect and interfere with the executed code. - > Do not use the `MAIN` world unless it is acceptable for web pages to read, access, or modify the logic or data that flows through the executed code. - -- `USER_SCRIPT` - - Specifies the user scripts execution environment which is exempt from the page's content security policy (CSP). +- `` {{WebExtExamples("h2")}} From e076b22c708d54912df0a2935d69a9274f6aea5b Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Tue, 11 Feb 2025 10:19:19 +1300 Subject: [PATCH 07/25] Type details --- .../api/userscripts/executionworld/index.md | 15 +++------ .../webextensions/api/userscripts/index.md | 10 +++--- .../userscripts/registereduserscript/index.md | 31 ++++++++++++++----- .../api/userscripts/scriptsource/index.md | 14 ++++----- .../api/userscripts/userscriptfilter/index.md | 11 +++---- .../api/userscripts/worldproperties/index.md | 15 ++++----- 6 files changed, 52 insertions(+), 44 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md index 59dec442654b871..3ada4829506fdea 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md @@ -7,31 +7,26 @@ browser-compat: webextensions.api.userScripts.ExecutionWorld {{AddonSidebar}} -Specifies the execution environment of a script injected with {{WebExtAPIRef("userScripts.register()")}} +The execution environment for a script injected with {{WebExtAPIRef("userScripts.register()")}} or {{WebExtAPIRef("userScripts.update()")}}. ## Type -Values of this type are strings. Possible values are: +Values of this type are a string. Possible values are: - `MAIN` - The web page execution environment. This environment is shared with the web page without isolation. - Scripts in this environment do not have any access to APIs that are only available to content scripts. + The web page execution environment. This environment is shared with the web page without isolation. Scripts in this environment don't have access to the APIs that are only available to content scripts. > [!WARNING] - > Due to the lack of isolation, the web page can detect and interfere with the executed code. - > Do not use the `MAIN` world unless it is acceptable for web pages to read, access, or modify the logic or data that flows through the executed code. + > Web pages can detect and interfere with the executed code due to the lack of isolation. Therefore, don't use the `MAIN` world unless it's acceptable for web pages to read, access, or modify the logic or data that flows through the executed code. - `USER_SCRIPT` - Specifies the user scripts execution environment which is exempt from the page's content security policy (CSP). + Specifies the user scripts execution environment, which is exempt from the page's content security policy (CSP). {{WebExtExamples("h2")}} ## Browser compatibility {{Compat}} - -> [!NOTE] -> This API is based on Chromium's [`chrome.scripting`](https://developer.chrome.com/docs/extensions/reference/api/scripting#type-ExecutionWorld) API. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index 0136ef989567cfb..fa88265dac3f212 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -50,15 +50,15 @@ When an extension updates, user scripts are cleared. To restore scripts, add cod ## Types -- {{WebExtAPIRef("userScripts.RegisteredUserScript")}} - - : Specifies the execution environment of a script injected with {{WebExtAPIRef("userScripts.register()")}} +- {{WebExtAPIRef("userScripts.ExecutionWorld")}} + - : The execution environment for a script injected with {{WebExtAPIRef("userScripts.register()")}} or {{WebExtAPIRef("userScripts.update()")}}. - {{WebExtAPIRef("userScripts.RegisteredUserScript")}} - - : The `object` returned by the {{WebExtAPIRef("userScripts.register","register()")}} method representing registered user scripts. + - : An `object` returned by {{WebExtAPIRef("userScripts.getScripts","getScripts()")}}, {{WebExtAPIRef("userScripts.register","register()")}}, and {{WebExtAPIRef("userScripts.update","update()")}} representing registered user scripts. - {{WebExtAPIRef("userScripts.ScriptSource")}} - - : Specifies the code or a file source for a user script. + - : The code or a file source for a user script. - {{WebExtAPIRef("userScripts.UserScriptFilter")}} - - : Specifies a list of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. + - : A list of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} or {{WebExtAPIRef("userScripts.unregister()")}}. - {{WebExtAPIRef("userScripts.WorldProperties")}} - : The configuration of a `USER_SCRIPT` execution environment. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md index 23f180bad0e46bc..99fdf8277fbce45 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md @@ -7,17 +7,32 @@ browser-compat: webextensions.api.userScripts.RegisteredUserScript {{AddonSidebar}} -An object representing a registered user script. +An object representing registered user scripts. ## Type -Values of this type are ?. Possible values are: - -- `` - -- `` - - . +Values of this type are an object containing these properties: + +- `allFrames` {{optional_inline}} + - : `boolean`. If `allFrames` is `true`, the script is injected into all of a page's frames. By default, it's `false` and the script is only injected into the top frame. +- `id` + - : `string`. The ID of a user script. This property must not start with a '\_', which is reserved as a prefix for generated script IDs. +- `js` + - : `array` of {{WebExtAPIRef("userScripts.ScriptSource")}}. The scripts to inject into matching pages. +- `matches` {{optional_inline}} + - : `array` of `string`. [Match patterns](/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) for the pages to run the script in. `matches` or `includeGlobs` must be specified. +- `excludeMatches` {{optional_inline}} + - : `array` of `string`. [Match patterns](/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) for pages that the script must not be run in. +- `includeGlobs` {{optional_inline}} + - : `string`. Glob patterns for the pages to run the script in. `matches` or `includeGlobs` must be specified. +- `excludeGlobs` {{optional_inline}} + - : `string`. Glob patterns for pages that the script must not be run in. +- `runAt` {{optional_inline}} + - : {{WebExtAPIRef("extensionTypes.RunAt")}}. The earliest the script is injected into a tab. Defaults to "document_idle". +- `world` {{optional_inline}} + - : {{WebExtAPIRef("userScripts.ExecutionWorld")}}. The execution environment to use to run the scripts. Defaults to "USER_SCRIPT". +- `worldId` {{optional_inline}} + - : `string`. ID of a user script world execute the script in. Only valid if `world` is `USER_SCRIPT` or omitted. If `worldId` is omitted, the script is execute in the default `USER_SCRIPT` world (""). Values with leading underscores (`_`) are reserved. The maximum length is 256 characters. ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md index 25a5f6db5579551..2592683e1e652a3 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md @@ -7,21 +7,21 @@ browser-compat: webextensions.api.userScripts.ScriptSource {{AddonSidebar}} -Specifies the code or a file source for a user script. +The code or source file for a user script. ## Type -Values of this type are ?. Possible values are: +Values of this type are an object containing these properties: -- `id` +- `file` {{optional_inline}} + - : `string`. The path of the file containing the user script code. The path is relative to the extension's root directory. +- `allFrames` {{optional_inline}} + - : `code`. JavaScript code for the user script. -- `` +`file` or `code` must be specified. {{WebExtExamples("h2")}} ## Browser compatibility {{Compat}} - -> [!NOTE] -> This API is based on Chromium's [`chrome.scripting`](https://developer.chrome.com/docs/extensions/reference/api/scripting#type-ExecutionWorld) API. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md index cd176db44090f59..d827bdf3939dae4 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md @@ -7,17 +7,14 @@ browser-compat: webextensions.api.userScripts.UserScriptFilter {{AddonSidebar}} -Specifies the code or a file source for a user script. +A list of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} or {{WebExtAPIRef("userScripts.unregister()")}}. ## Type -Values of this type are ?. Possible values are: +Values of this type are an object containing these properties: -- `` - -- `` - - . +- `ids` {{optional_inline}} + - : `array` of `string`. IDs of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. {{WebExtExamples("h2")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md index 0376567651fe242..a02ac731cbddac5 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md @@ -11,13 +11,14 @@ The configuration of a `USER_SCRIPT` execution environment. ## Type -Values of this type are ?. Possible values are: - -- `` - -- `` - - . +Values of this type are an object containing these properties: + +- `worldId` {{optional_inline}} + - : `string`. The identifier for the world. Values with leading underscores (`_`) are reserved. The maximum length is 256. Defaults to the default `USER_SCRIPT` world (""). +- `csp` {{optional_inline}} + - : string`. The world's Content Security Policy (CSP). Defaults to the standard content scripts CSP, which prohibits dynamic code execution, such as`eval()`. +- `messaging` {{optional_inline}} + - : `boolean`. Whether the {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}} event handlers are exposed. Defaults to hiding these messaging APIs. {{WebExtExamples("h2")}} From fbae88528df96e77a3e289e604a86215c979ef6c Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Wed, 12 Feb 2025 10:37:55 +1300 Subject: [PATCH 08/25] userScript method details --- .../api/userscripts/configureworld/index.md | 15 ++-- .../api/userscripts/getscripts/index.md | 15 ++-- .../getworldconfigurations/index.md | 14 ++-- .../webextensions/api/userscripts/index.md | 14 ++-- .../api/userscripts/register/index.md | 68 +++++++------------ .../userscripts/registereduserscript/index.md | 8 +-- .../resetworldconfiguration/index.md | 15 ++-- .../api/userscripts/unregister/index.md | 15 ++-- .../api/userscripts/update/index.md | 36 ++++++++-- 9 files changed, 105 insertions(+), 95 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md index 20b7e9fb5696c1e..b1d2bd4c605c741 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md @@ -7,27 +7,28 @@ browser-compat: webextensions.api.userScripts.configureWorld {{AddonSidebar}} -This method configures the `USER_SCRIPT` execution environment. +Configures a `USER_SCRIPT` execution environment for the extension. This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const registeredUserScript = await browser.userScripts.configureWorld( - userScriptOptions // object +const configuredWorld = await browser.userScripts.configureWorld( + properties // object ); ``` ### Parameters -### Return value +- `properties` + - : {{WebExtAPIRef("userScripts.WorldProperties")}}. Details of the configuration for a `USER_SCRIPT` world. -A {{JSxRef("Promise")}} that is … +### Return value -## Examples +A {{JSxRef("Promise")}} fulfilled with no arguments if the request is successful. If the request fails, the promise is rejected with an error message. -{{WebExtExamples}} +{{WebExtExamples("h2")}} ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md index 733ce98d8919463..b0cc5cab835115e 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md @@ -7,27 +7,28 @@ browser-compat: webextensions.api.userScripts.getScripts {{AddonSidebar}} -This method returns the extension's registered user scripts. +Returns user scripts registered by the extension. This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const registeredUserScript = await browser.userScripts.getScripts( - userScriptOptions // object +const gettingUserScripts = await browser.userScripts.getScripts( + filter // object ); ``` ### Parameters -### Return value +- `filter` {{optional_inline}} + - : {{WebExtAPIRef("userScripts.UserScriptFilter")}}. A list of user script IDs to return. -A {{JSxRef("Promise")}} that is … +### Return value -## Examples +A {{JSxRef("Promise")}} fulfilled with an array of {{WebExtAPIRef("userScripts.RegisteredUserScript")}} objects. If no matching user scripts are found, the array is empty. If the request fails, the promise is rejected with an error message. -{{WebExtExamples}} +{{WebExtExamples("h2")}} ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md index 5ac86ee52ce73f1..ecb1cc96bcde1c9 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md @@ -7,27 +7,25 @@ browser-compat: webextensions.api.userScripts.getWorldConfigurations {{AddonSidebar}} -This method returns all the registered world configurations. +Returns all the `USER_SCRIPT` world configurations registered by the extension with {{WebExtAPIRef("userScripts.configureWorld()")}}. This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const registeredUserScript = await browser.userScripts.getWorldConfigurations( - userScriptOptions // object -); +const gettingWorldConfigurations = await browser.userScripts.getWorldConfigurations(); ``` ### Parameters -### Return value +This function takes no parameters. -A {{JSxRef("Promise")}} that is … +### Return value -## Examples +A {{JSxRef("Promise")}} fulfilled with an array of {{WebExtAPIRef("userScripts.WorldProperties")}} objects. If the request fails, the promise is rejected with an error message. -{{WebExtExamples}} +{{WebExtExamples("h2")}} ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index fa88265dac3f212..857a86a3a5332c0 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -65,19 +65,19 @@ When an extension updates, user scripts are cleared. To restore scripts, add cod ## Methods - {{WebExtAPIRef("userScripts.configureWorld()")}} - - : Configures the `USER_SCRIPT` execution environment. + - : Configures a `USER_SCRIPT` execution environment for the extension. - {{WebExtAPIRef("userScripts.getScripts()")}} - - : Returns the extension's registered user scripts. + - : Returns user scripts registered by the extension. - {{WebExtAPIRef("userScripts.getWorldConfigurations()")}} - - : Returns all the registered world configurations. + - : Returns all the extension's registered world configurations. - {{WebExtAPIRef("userScripts.register()")}} - - : Registers user scripts. + - : Registers user scripts for the extension. - {{WebExtAPIRef("userScripts.resetWorldConfiguration()")}} - - : Resets the configuration for a user script world. + - : Resets the configuration for a `USER_SCRIPT` world registered by the extension. - {{WebExtAPIRef("userScripts.unregister()")}} - - : Unregisters all the user scripts registered by the extension. + - : Unregisters user scripts registered by the extension. - {{WebExtAPIRef("userScripts.update()")}} - - : Updates one or more of the extension's user scripts. + - : Updates user scripts registered by the extension. ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md index 0a39ceaf69729bc..889cbcd0e07a97f 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md @@ -7,9 +7,7 @@ browser-compat: webextensions.api.userScripts.register {{AddonSidebar}} -This method registers user scripts from an extension's pages (such as the background page). - -This method is very similar to the {{WebExtAPIRef("contentScripts.register","contentScripts.register()")}} API method (for example, they both return a promise that resolves to an API object with an {{WebExtAPIRef("userScripts.RegisteredUserScript.unregister","unregister()")}} method for unregistering the script). There are, however, differences in the options supported. +Registers user scripts for the extension. This is an asynchronous method that returns a {{JSxRef("Promise")}}. @@ -17,56 +15,38 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ```js-nolint const registeredUserScript = await browser.userScripts.register( - userScriptOptions // object -); -// … -await registeredUserScript.unregister(); + scripts // object +) ``` ### Parameters -- `userScriptOptions` - - - : `object`. Represents the user scripts to register. It has similar syntax to {{WebExtAPIRef("contentScripts.register","contentScripts.register()")}}. - - The `UserScriptOptions` object has the following properties: - - - `scriptMetadata` {{Optional_Inline}} - - : A `JSON` object containing arbitrary metadata properties associated with the registered user scripts. However, while arbitrary, the object must be serializable, so it is compatible with [the structured clone algorithm.](/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) This metadata is used to pass details from the script to the [API script](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts). For example, providing details of a subset of the APIs that need to be injected by the [API script](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/user_scripts). The API does not use this metadata, - - `allFrames` {{Optional_Inline}} - - : Same as `all_frames` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. - - `cookieStoreId` {{optional_inline}} - - : An array of cookie store ID strings or a string containing a cookie store ID. Registers the user script in the tabs that belong to the cookie store IDs. This enables scripts to be registered for all default or non-contextual identity tabs, private browsing tabs (if the [extension is enabled in private browsing](https://support.mozilla.org/en-US/kb/extensions-private-browsing)), the tabs of a [contextual identity](/en-US/docs/Mozilla/Add-ons/WebExtensions/Work_with_contextual_identities), or a combination of these. - - `excludeGlobs` {{Optional_Inline}} - - : Same as `exclude_globs` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. - - `excludeMatches` {{Optional_Inline}} - - : Same as `exclude_matches` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. - - `includeGlobs` {{Optional_Inline}} - - : Same as `include_globs` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. - - `js` - - : An array of objects. Each object has either a property named `file`, which is a URL starting at the extension's manifest.json and pointing to a JavaScript file to register, or a property named `code`, which contains JavaScript code to register. - - `matchAboutBlank` {{Optional_Inline}} - - : Same as `match_about_blank` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. - - `matches` - - : Same as `matches` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. - The URL patterns provided in `matches` must be enabled by the host permissions defined in the manifest [`permission`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions) property or enabled by the user from the [`optional_permissions`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions) list. For example, if matches includes `https://mozilla.org/a` a script is only registered if host permissions include, for example, `https://mozilla.org/*`. If the URL pattern isn't enabled, the call to register fails with the error "Permission denied to register a user script for ORIGIN". - - `runAt` {{Optional_Inline}} - - : Same as `run_at` in the [`content_scripts`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts) key. - -Unlike content script options, the userScriptOptions object does not have a CSS property. Use {{WebExtAPIRef("contentScripts.register","contentScripts.register()")}} to dynamically register and unregister stylesheets. +- `scripts` + + - : `array` of {{WebExtAPIRef("userScripts.RegisteredUserScript")}}. Details of user scripts to register. + + Each {{WebExtAPIRef("userScripts.RegisteredUserScript")}} object must contain the `js` property as a non-empty array and a non-empty array in either `matches` or `includeGlobs`. ### Return value -A {{JSxRef("Promise")}} that is fulfilled with a {{WebExtAPIRef("userScripts.RegisteredUserScript","RegisteredUserScript")}} object that is use to unregister the user scripts. +A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are registered. If any user scripts fail to register or the request fails for another reason, the promise is rejected with an error message. -> [!NOTE] -> User scripts are unregistered when the related extension page (from which the user scripts were registered) is unloaded, so you should register user scripts from an extension page that persists at least as long as you want the user scripts to stay registered. +## Examples -## Browser compatibility +This snippet registers hello world code into the `"myScriptId"` execution world to run in all websites matching `"*://example.com/*"`. -{{Compat}} +```js +await browser.userScripts.register([ + { + worldId: "myScriptId", + js: [{ code: "console.log('Hello world!');" }], + matches: ["*://example.com/*"], + }, +]); +``` + +{{WebExtExamples}} -## See also +## Browser compatibility -- {{WebExtAPIRef("contentScripts.register","contentScripts.register()")}} -- {{WebExtAPIRef("userScripts.RegisteredUserScript.unregister","RegisteredUserScript.unregister()")}} +{{Compat}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md index 99fdf8277fbce45..8ac9d9c2b2d333d 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md @@ -15,16 +15,16 @@ Values of this type are an object containing these properties: - `allFrames` {{optional_inline}} - : `boolean`. If `allFrames` is `true`, the script is injected into all of a page's frames. By default, it's `false` and the script is only injected into the top frame. -- `id` +- `id` {{optional_inline}} for {{WebExtAPIRef("userScripts.update()")}} calls, required for {{WebExtAPIRef("userScripts.register()")}} - : `string`. The ID of a user script. This property must not start with a '\_', which is reserved as a prefix for generated script IDs. -- `js` +- `js` {{optional_inline}} for {{WebExtAPIRef("userScripts.update()")}} calls, required for {{WebExtAPIRef("userScripts.register()")}} - : `array` of {{WebExtAPIRef("userScripts.ScriptSource")}}. The scripts to inject into matching pages. - `matches` {{optional_inline}} - - : `array` of `string`. [Match patterns](/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) for the pages to run the script in. `matches` or `includeGlobs` must be specified. + - : `array` of `string`. [Match patterns](/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) for the pages to run the script in. `matches` or `includeGlobs` must be specified in {{WebExtAPIRef("userScripts.register()")}} calls. - `excludeMatches` {{optional_inline}} - : `array` of `string`. [Match patterns](/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) for pages that the script must not be run in. - `includeGlobs` {{optional_inline}} - - : `string`. Glob patterns for the pages to run the script in. `matches` or `includeGlobs` must be specified. + - : `string`. Glob patterns for the pages to run the script in. `matches` or `includeGlobs` must be specified {{WebExtAPIRef("userScripts.register()")}} calls. - `excludeGlobs` {{optional_inline}} - : `string`. Glob patterns for pages that the script must not be run in. - `runAt` {{optional_inline}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md index 36e14280da4e9cb..7ee3b1a2ba5dbdd 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md @@ -7,27 +7,28 @@ browser-compat: webextensions.api.userScripts.resetWorldConfiguration {{AddonSidebar}} -Resets the configuration for a user script world. Any scripts inject into the world are moved to the default world configuration. +Resets the configuration of a `USER_SCRIPT` world registered by the extension. Any scripts injected into the world are moved to the default `USER_SCRIPT` world configuration. This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const registeredUserScript = await browser.userScripts.resetWorldConfiguration( - userScriptOptions // object +const resettingWorldConfiguration = await browser.userScripts.resetWorldConfiguration( + worldId // string ); ``` ### Parameters -### Return value +- `worldId` {{optional_inline}} + - : `string` The ID of the `USER_SCRIPT` world to reset. If omitted or empty, resets the default world's configuration. -A {{JSxRef("Promise")}} that is … +### Return value -## Examples +A {{JSxRef("Promise")}} fulfilled with no arguments if the world configuration is reset. If the request fails, the promise is rejected with an error message. -{{WebExtExamples}} +{{WebExtExamples("h2")}} ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md index 43aee5340a1e9fe..f20fd4d3aa2acbc 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md @@ -7,27 +7,28 @@ browser-compat: webextensions.api.userScripts.unregister {{AddonSidebar}} -Unregisters all the user scripts registered by the extension. +Unregisters user scripts registered by the extension. This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const registeredUserScript = await browser.userScripts.unregister( - userScriptOptions // object +const unregisteringUserScripts = await browser.userScripts.unregister( + filter // object ); ``` ### Parameters -### Return value +- `filter` {{optional_inline}} + - : {{WebExtAPIRef("userScripts.UserScriptFilter")}}. A list of user script IDs to return. -A {{JSxRef("Promise")}} that is … +### Return value -## Examples +A {{JSxRef("Promise")}} fulfilled with no arguments if the user scripts are unregistered. If the request fails, the promise is rejected with an error message. -{{WebExtExamples}} +{{WebExtExamples("h2")}} ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md index 78ce1b561550e02..b62a331bce66265 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md @@ -7,26 +7,54 @@ browser-compat: webextensions.api.userScripts.update {{AddonSidebar}} -Updates one or more of the extension's user scripts. +Updates user scripts registered by the extension. This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const registeredUserScript = await browser.userScripts.update( - userScriptOptions // object +const updatingUserScript = await browser.userScripts.update( + scripts // object ); ``` ### Parameters +- `scripts` + + - : `array` of {{WebExtAPIRef("userScripts.RegisteredUserScript")}}. Details of user scripts to update. + + Each {{WebExtAPIRef("userScripts.RegisteredUserScript")}} must specify at least one property. Properties that are `null` or omitted are not changed. Passing an empty array clears the array. + ### Return value -A {{JSxRef("Promise")}} that is … +A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are updated. If any user scripts fail to update or the request fails for another reason, the promise is rejected with an error message. ## Examples +This snippet updates `matches` for all registered user scripts. + +```js +await browser.userScripts.update([ + { + worldId: "myScriptId", + matches: ["*://example.com/*"], + }, +]); +``` + +This snippet updates `matches` for all user scripts running in the `"myScriptId"` world. + +```js +await browser.userScripts.update([ + { + worldId: "myScriptId", + matches: ["*://example.com/*"], + }, +]); +``` + {{WebExtExamples}} ## Browser compatibility From 1cc58fae63bd78732e2326db8715ff86ac2760d9 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Thu, 13 Feb 2025 05:04:35 +1300 Subject: [PATCH 09/25] Adds permissions details --- .../mozilla/add-ons/webextensions/api/userscripts/index.md | 2 +- .../manifest.json/optional_permissions/index.md | 7 ++++--- .../webextensions/manifest.json/permissions/index.md | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index 857a86a3a5332c0..d1a54011a9d8b25 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -18,7 +18,7 @@ This API offers capabilities similar to {{WebExtAPIRef("contentScripts")}} but w To use this API, you need the `userScripts` permission and `host_permissions` for sites where you want to run scripts. However, the approach to enabling the use of this API varies between browsers: -- In Firefox, `userScripts` is an optional-only permission declared in the [`optional_permissions` manifest key](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions#optional-only_permissions). This means that your extension must request the permission programmatically using {{WebExtAPIRef("permissions.request()")}}. +- In Firefox, `userScripts` is an optional-only permission declared in the [`optional_permissions` manifest key](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions#optional-only_permissions). Your extension must check that the permission has been granted using {{WebExtAPIRef("permissions.contains()")}} and, if not, request it using {{WebExtAPIRef("permissions.request()")}}. - in Chrome, `userScripts` is an install time requested permission declared in the [`permissions` manifest key](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions). However, to enable use of the API, users must [turn on the developer environment in Chrome](https://developer.chrome.com/docs/extensions/reference/api/userScripts#developer_mode_for_extension_users). ## Execution worlds diff --git a/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md b/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md index 1ecc507fd48d7ab..05d6d24ac1681a6 100644 --- a/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md @@ -108,10 +108,11 @@ These optional permissions are granted silently, without a user prompt: ### Optional-only permissions -Optional permissions are generally available for use in the [`permissions`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions#api_permissions) key so they can be requested at install time. However, some browsers support the concept of optional-only permissions, permissions that can only be requested at runtime using the {{webextapiref("permissions.request()")}} API. In addition, optional-only permissions must be requested individually and alone through the {{webextapiref("permissions.request()")}} API. +Optional permissions are generally available for use in the [`permissions`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions#api_permissions) key, so they can be requested at install time. However, some browsers support the concept of optional-only permissions, permissions that can only be requested at runtime. For example, in Firefox, optional-only permissions can be granted by the user from the [extension's options page](/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface/Options_pages) or using {{webextapiref("permissions.request()")}}. Optional-only permissions must be requested individually and alone through the {{webextapiref("permissions.request()")}} API. -> [!NOTE] -> No optional-only permissions were generally available at the time of writing, December 2024. +The optional-only API permissions are: + +- 'userScripts' (Firefox only) ## Examples diff --git a/files/en-us/mozilla/add-ons/webextensions/manifest.json/permissions/index.md b/files/en-us/mozilla/add-ons/webextensions/manifest.json/permissions/index.md index 31bc59664f12777..8567d1f415f8092 100644 --- a/files/en-us/mozilla/add-ons/webextensions/manifest.json/permissions/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/manifest.json/permissions/index.md @@ -132,6 +132,7 @@ These permissions are available in Manifest V2 and above unless otherwise noted: - `theme` - `topSites` - `unlimitedStorage` +- `userScripts` (This permission is [optional-only](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions#optional-only_permissions) in Firefox. In Chrome, the extension user must also activate [developer mode](https://developer.chrome.com/docs/extensions/reference/api/userScripts#developer_mode_for_extension_users).) - `webNavigation` - `webRequest` - `webRequestAuthProvider` (Manifest V3 and above) @@ -196,7 +197,7 @@ The `unlimitedStorage` permission: - Enables extensions to exceed any quota imposed by the {{WebExtAPIRef("storage/local", "storage.local")}} API - In Firefox, enables extensions to create a ["persistent" IndexedDB database](/en-US/docs/Web/API/IndexedDB_API) without the browser prompting the user for permission at the time the database is created. -## Example +## Examples ```json "permissions": ["*://developer.mozilla.org/*"] From de94fad3490614da07c434b068ce44606e148fa1 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Thu, 13 Feb 2025 10:46:42 +1300 Subject: [PATCH 10/25] runtime API additions --- .../webextensions/api/runtime/index.md | 8 +- .../api/runtime/messagesender/index.md | 3 + .../api/runtime/onuserscriptconnect/index.md | 134 ++++++++++++++++++ .../api/runtime/onuserscriptmessage/index.md | 119 ++++++++++++++++ .../webextensions/api/runtime/port/index.md | 2 +- 5 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md create mode 100644 files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/index.md index 3b1a2683508ce87..fb74482e15c045c 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/index.md @@ -70,9 +70,9 @@ It also provides messaging APIs enabling you to: - {{WebExtAPIRef("runtime.connectNative()")}} - : Connects the extension to a native application on the user's computer. - {{WebExtAPIRef("runtime.sendMessage()")}} - - : Sends a single message to event listeners within your extension or a different extension. Similar to {{WebExtAPIRef('runtime.connect')}} but only sends a single message, with an optional response. + - : Sends a message to event listeners within your extension or a different extension. Similar to {{WebExtAPIRef('runtime.connect')}} but only sends a single message, with an optional response. - {{WebExtAPIRef("runtime.sendNativeMessage()")}} - - : Sends a single message from an extension to a native application. + - : Sends a message from an extension to a native application. - {{WebExtAPIRef("runtime.getPlatformInfo()")}} - : Returns information about the current platform. - {{WebExtAPIRef("runtime.getBrowserInfo()")}} @@ -98,10 +98,14 @@ It also provides messaging APIs enabling you to: - : Fired when a connection is made with either an extension process or a content script. - {{WebExtAPIRef("runtime.onConnectExternal")}} - : Fired when a connection is made with another extension. +- {{WebExtAPIRef("runtime.onserScriptConnect")}} + - : Fired when a connection is made with a user script registered by the extension. - {{WebExtAPIRef("runtime.onMessage")}} - : Fired when a message is sent from either an extension process or a content script. - {{WebExtAPIRef("runtime.onMessageExternal")}} - : Fired when a message is sent from another extension. Cannot be used in a content script. +- {{WebExtAPIRef("runtime.onUserScriptMessage")}} + - : Fired when a message is sent from a user script registered by the extension. - {{WebExtAPIRef("runtime.onPerformanceWarning")}} - : Fired when a runtime performance issue is detected for the extension. - {{WebExtAPIRef("runtime.onRestartRequired")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/messagesender/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/messagesender/index.md index 2aea678bd5fd2ca..4e17ac8fac95e59 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/messagesender/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/messagesender/index.md @@ -37,6 +37,9 @@ Values of this type are objects. They contain the following properties: If the sender is a script running in a web page (including content and normal page scripts), then `url` is the web page URL. If the script is running in an iframe, `url` is the iframe's URL. +- `userScriptWorldId` {{optional_inline}} + - : `string`. The `worldId` of the `USER_SCRIPT` world that sent the message. Only present in {{WebExtAPIRef("runtime.onUserScriptMessage")}} and in {{WebExtAPIRef("port.sender")}} for {{WebExtAPIRef("runtime.onUserScriptConnect")}}. + {{WebExtExamples}} ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md new file mode 100644 index 000000000000000..c5d86b2f41ccefc --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md @@ -0,0 +1,134 @@ +--- +title: runtime.onUserScriptConnect +slug: Mozilla/Add-ons/WebExtensions/API/runtime/onUserScriptConnect +page-type: webextension-api-event +browser-compat: webextensions.api.runtime.onUserScriptConnect +--- + +{{AddonSidebar}} + +Fired when a connection is made with a user script from one of the extension's [`USER_SCRIPT` worlds](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/ExecutionWorld). + +A user script can only connect and then sent messages from a `USER_SCRIPT` world that is configured by {{WebExtAPIRef('userScripts.configureWorld()')}} with `messaging` set to `true`. + +## Syntax + +```js-nolint +browser.runtime.onUserScriptConnect.addListener(listener) +browser.runtime.onUserScriptConnect.removeListener(listener) +browser.runtime.onUserScriptConnect.hasListener(listener) +``` + +Events have three functions: + +- `addListener(listener)` + - : Adds a listener to this event. +- `removeListener(listener)` + - : Stop listening to this event. The `listener` argument is the listener to remove. +- `hasListener(listener)` + - : Checks whether a `listener` is registered for this event. Returns `true` if it is listening, `false` otherwise. + +## addListener syntax + +### Parameters + +- `function` + + - : The function called when this event occurs. The function is passed this argument: + + - `port` + - : {{WebExtAPIRef('runtime.Port')}}. An object connecting the current script to the other context. + +## Examples + +This user script: + +- Connects to the background script and stores `Port` in a variable `myPort`. +- Listens for messages on `myPort` and logs them. +- Sends messages to the background script using `myPort` when the user clicks the document. + +```js +// user-script.js + +let myPort = browser.runtime.connect({ name: "port-from-us" }); +myPort.postMessage({ greeting: "hello from user script" }); + +myPort.onMessage.addListener((m) => { + console.log("In the user script, received message from background script: "); + console.log(m.greeting); +}); + +document.body.addEventListener("click", () => { + myPort.postMessage({ greeting: "they clicked the page!" }); +}); +``` + +The corresponding background script: + +- Listens for connection attempts from the user script, and when it receives a connection attempt: + + - Stores the port in a variable named `portFromUS`. + - Sends the content script a message using the port. + - Starts listening to messages received on the port and logs them. + +- Sends messages to the content script using `portFromUS` when the user clicks the extension's browser action. + +```js +// background-script.js + +let portFromCS; + +function connected(p) { + portFromUS = p; + portFromUS.postMessage({ greeting: "hi there user script!" }); + portFromUS.onMessage.addListener((m) => { + console.log("In background script, received message from user script"); + console.log(m.greeting); + }); +} + +browser.runtime.onUserScriptConnect.addListener(connected); + +browser.browserAction.onClicked.addListener(() => { + portFromUS.postMessage({ greeting: "they clicked the button!" }); +}); +``` + +{{WebExtExamples}} + +## Browser compatibility + +{{Compat}} + +> [!NOTE] +> This API is based on Chromium's [`chrome.runtime`](https://developer.chrome.com/docs/extensions/reference/api/runtime#event-onUserScriptConnect) API. This documentation is derived from [`runtime.json`](https://chromium.googlesource.com/chromium/src/+/master/extensions/common/api/runtime.json) in the Chromium code. + + diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md new file mode 100644 index 000000000000000..9643e986f2f97c8 --- /dev/null +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md @@ -0,0 +1,119 @@ +--- +title: runtime.onUserScriptMessage +slug: Mozilla/Add-ons/WebExtensions/API/runtime/onUserScriptMessage +page-type: webextension-api-event +browser-compat: webextensions.api.runtime.onUserScriptMessage +--- + +{{AddonSidebar}} + +Use this event to listen for messages sent from one of the extension's [`USER_SCRIPT` worlds](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/ExecutionWorld). + +A user script can only send messages using {{WebExtAPIRef('runtime.sendMessage')}} from a `USER_SCRIPT` world that is configured by {{WebExtAPIRef('userScripts.configureWorld()')}} with `messaging` set to `true`. + +Along with the message, the listener is passed: + +- a `sender` object with details about the message sender. +- a `sendResponse` function the listener can use to send a response back to the sender. + +## Syntax + +```js-nolint +browser.runtime.onUserScriptMessage.addListener() +browser.runtime.onUserScriptMessage.removeListener(listener) +browser.runtime.onUserScriptMessage.hasListener(listener) +``` + +Events have three functions: + +- `addListener(listener)` + - : Adds a listener to this event. +- `removeListener(listener)` + - : Stop listening to this event. The `listener` argument is the listener to remove. +- `hasListener(listener)` + - : Checks whether a `listener` is registered for this event. Returns `true` if it is listening, `false` otherwise. + +## addListener syntax + +### Parameters + +- `listener` + + - : The function called when this event occurs. The function is passed these arguments: + + - `message` + - : `object`. The message. This is a JSON-ifiable object. + - `sender` + - : A {{WebExtAPIRef('runtime.MessageSender')}} object representing the sender of the message. + - `sendResponse` + + - : A function to call, at most once, to send a response to the message. The function takes one argument, which is any JSON-ifiable object. This argument is passed back to the message sender. + + If you have more than one `onUserScriptMessage` listener in the same document, then only one can send a response. + + To send a response synchronously, call `sendResponse` before the listener function returns. To send a response asynchronously, do one of these: + + - keep a reference to the `sendResponse` argument and return `true` from the listener function. You can then call `sendResponse` after the listener function has returned. + - return a [`Promise`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) from the listener function and resolve the promise when the response is ready. + +## Examples + +In this example, a user script in a `USER_SCRIPT` world with the ID `myScriptWorld` sends a message to the extension that registered it: + +```js +// The user script +// Send a message to the extension that registered the user script +browser.runtime.sendMessage("my message"); +``` + +```js +// The extension that registered the user script + +function handleMessage(message, sender) { + // check that the message originated from "myScriptWorld" world + if (sender.userScriptWorldI === "myScriptWorld") { + // process message + } +} + +browser.runtime.onUserScriptMessage.addListener(handleMessage); +``` + +{{WebExtExamples}} + +## Browser compatibility + +{{Compat}} + +> [!NOTE] +> This API is based on Chromium's [`chrome.runtime`](https://developer.chrome.com/docs/extensions/reference/api/runtime#event-onUserScriptMessage) API. This documentation is derived from [`runtime.json`](https://chromium.googlesource.com/chromium/src/+/master/extensions/common/api/runtime.json) in the Chromium code. + + diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/port/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/port/index.md index ef731d291cc1ec8..8ec547bdbd37810 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/port/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/port/index.md @@ -89,7 +89,7 @@ Values of this type are objects. They contain the following properties: - `postMessage` - : `function`. Send a message to the other end. This takes one argument, which is a serializable value (see [Data cloning algorithm](/en-US/docs/Mozilla/Add-ons/WebExtensions/Chrome_incompatibilities#data_cloning_algorithm)) representing the message to send. It will be delivered to any script listening to the port's `onMessage` event, or to the native application if this port is connected to a native application. - `sender` {{optional_inline}} - - : {{WebExtAPIRef('runtime.MessageSender')}}. Contains information about the sender of the message. This property will only be present on ports passed to `onConnect`/`onConnectExternal` listeners. + - : {{WebExtAPIRef('runtime.MessageSender')}}. Contains information about the sender of the message. Only present on ports passed to the {{WebExtAPIRef('runtime.onConnect')}}, {{WebExtAPIRef('runtime.onConnectExternal')}}, or {{WebExtAPIRef("runtime.onUserScriptConnect")}} listeners. ## Lifecycle From 98201579776dedf715e2558a3a622edd3617ede1 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Fri, 14 Feb 2025 04:52:03 +1300 Subject: [PATCH 11/25] Release note --- files/en-us/mozilla/firefox/releases/136/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/files/en-us/mozilla/firefox/releases/136/index.md b/files/en-us/mozilla/firefox/releases/136/index.md index 5470ccc71d164c8..797777910511043 100644 --- a/files/en-us/mozilla/firefox/releases/136/index.md +++ b/files/en-us/mozilla/firefox/releases/136/index.md @@ -59,6 +59,7 @@ This article provides information about the changes in Firefox 136 that affect d ## Changes for add-on developers - {{WebExtAPIRef("menus.update")}} and {{WebExtAPIRef("menus.remove")}} and the aliases {{WebExtAPIRef("contextMenus.update")}} and {{WebExtAPIRef("contextMenus.remove")}} now reject with an error when the menu item doesn't exist. Previously, the error was ignored and the promise fulfilled. ([Firefox bug 1688743](https://bugzil.la/1688743)). +- A new version of the {{WebExtAPIRef("userScripts")}} API is available. This version of the API is for use in Manifext V3 extensions and provides broad compatibility with Chrome, although [permissons mechanisms](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts#permissions) differ across the browsers. ([Firefox bug 1943050](https://bugzil.la/1943050)). ### Removals From f5f897af5681163c24dda1d899fc971923961765 Mon Sep 17 00:00:00 2001 From: rebloor Date: Wed, 19 Feb 2025 05:58:08 +1300 Subject: [PATCH 12/25] Apply suggestions from review Co-authored-by: Rob Wu --- .../webextensions/api/runtime/onuserscriptmessage/index.md | 5 +++-- .../webextensions/api/userscripts/executionworld/index.md | 2 +- .../mozilla/add-ons/webextensions/api/userscripts/index.md | 6 +++--- .../webextensions/api/userscripts/scriptsource/index.md | 2 +- .../webextensions/api/userscripts/unregister/index.md | 2 +- .../webextensions/api/userscripts/userscriptfilter/index.md | 2 +- .../webextensions/api/userscripts/worldproperties/index.md | 4 ++-- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md index 9643e986f2f97c8..e55090c69c86bad 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md @@ -19,7 +19,7 @@ Along with the message, the listener is passed: ## Syntax ```js-nolint -browser.runtime.onUserScriptMessage.addListener() +browser.runtime.onUserScriptMessage.addListener(listener) browser.runtime.onUserScriptMessage.removeListener(listener) browser.runtime.onUserScriptMessage.hasListener(listener) ``` @@ -71,8 +71,9 @@ browser.runtime.sendMessage("my message"); function handleMessage(message, sender) { // check that the message originated from "myScriptWorld" world - if (sender.userScriptWorldI === "myScriptWorld") { + if (sender.userScriptWorldId === "myScriptWorld") { // process message + console.log(message); } } diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md index 3ada4829506fdea..a75bc297ad7bda9 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md @@ -23,7 +23,7 @@ Values of this type are a string. Possible values are: - `USER_SCRIPT` - Specifies the user scripts execution environment, which is exempt from the page's content security policy (CSP). + The default execution environment for user scripts. This environment is isolated from the page's context and other `USER_SCRIPT` worlds. Extension APIs are unavailable, unlike [`ISOLATED` worlds of content scripts](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/ExecutionWorld). Several `USER_SCRIPT` worlds can exist when scripts are registered with `worldId`. {WebExtAPIRef("userScripts.configureWorld()")}} is used to change the configuration of a `USER_SCRIPT` world. {{WebExtExamples("h2")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index d1a54011a9d8b25..27994e4fab753cc 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -31,12 +31,12 @@ In the `MAIN` world, host pages and other extensions can see and access running ## Messaging -Like content scripts and offscreen documents, user scripts communicate with other parts of an extension with messages using {{WebExtAPIRef("runtime.sendMessage()")}} and {{WebExtAPIRef("runtime.connect()")}}. However, user scripts receive messages using the dedicated {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}}. Dedicated handlers are used as they make it easier to identify messages from user scripts, which are a less-trusted context. +Like content scripts and other extension scripts, user scripts communicate with other parts of an extension with messages using {{WebExtAPIRef("runtime.sendMessage()")}} and {{WebExtAPIRef("runtime.connect()")}}. However, user scripts receive messages using the dedicated {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}}. Dedicated handlers are used as they make it easier to identify messages from user scripts, which are a less-trusted context. -Before sending a message, call {{WebExtAPIRef("userScripts.configureWorld()")}} with the `messaging` argument set to `true`. The `csp` and `messaging` arguments can be passed at the same time. +To enable messaging APIs, call {{WebExtAPIRef("userScripts.configureWorld()")}} with the `messaging` argument set to `true` before registering a user script. The `csp` and `messaging` arguments can be passed at the same time. ```js -chrome.userScripts.configureWorld({ +browser.userScripts.configureWorld({ messaging: true, }); ``` diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md index 2592683e1e652a3..2b3d711d5e65687 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md @@ -18,7 +18,7 @@ Values of this type are an object containing these properties: - `allFrames` {{optional_inline}} - : `code`. JavaScript code for the user script. -`file` or `code` must be specified. +`file` or `code` must be specified, not both. {{WebExtExamples("h2")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md index f20fd4d3aa2acbc..d4ff798855cce92 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md @@ -22,7 +22,7 @@ const unregisteringUserScripts = await browser.userScripts.unregister( ### Parameters - `filter` {{optional_inline}} - - : {{WebExtAPIRef("userScripts.UserScriptFilter")}}. A list of user script IDs to return. + - : {{WebExtAPIRef("userScripts.UserScriptFilter")}}. A list of user script IDs to unregister. If not specified, all user scripts are unregistered. ### Return value diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md index d827bdf3939dae4..c852418e3140828 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md @@ -14,7 +14,7 @@ A list of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts Values of this type are an object containing these properties: - `ids` {{optional_inline}} - - : `array` of `string`. IDs of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. + - : `array` of `string`. IDs of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. This matches scripts by the `id` field of {{WebExtAPIRef("RegisteredUserScript")}}. {{WebExtExamples("h2")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md index a02ac731cbddac5..8ba7c1d08b28755 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md @@ -16,9 +16,9 @@ Values of this type are an object containing these properties: - `worldId` {{optional_inline}} - : `string`. The identifier for the world. Values with leading underscores (`_`) are reserved. The maximum length is 256. Defaults to the default `USER_SCRIPT` world (""). - `csp` {{optional_inline}} - - : string`. The world's Content Security Policy (CSP). Defaults to the standard content scripts CSP, which prohibits dynamic code execution, such as`eval()`. + - : string`. The world's Content Security Policy (CSP). Defaults to the standard content scripts CSP, which prohibits dynamic code execution, such as `eval()`. - `messaging` {{optional_inline}} - - : `boolean`. Whether the {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}} event handlers are exposed. Defaults to hiding these messaging APIs. + - : `boolean`. Whether the {{WebExtAPIRef("runtime.sendMessage")}} and {{WebExtAPIRef("runtime.connect")}} methods are exposed to the user script world. Defaults to hiding these messaging APIs. The {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}} event handlers are triggered when these methods are called. {{WebExtExamples("h2")}} From b0009364f9c4c441babaa27585995ec21ebcdfda Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Wed, 19 Feb 2025 07:07:37 +1300 Subject: [PATCH 13/25] Removed based on chromium notes --- .../api/runtime/onuserscriptconnect/index.md | 33 ------------------- .../api/runtime/onuserscriptmessage/index.md | 33 ------------------- 2 files changed, 66 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md index c5d86b2f41ccefc..b33733631dc197e 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md @@ -99,36 +99,3 @@ browser.browserAction.onClicked.addListener(() => { ## Browser compatibility {{Compat}} - -> [!NOTE] -> This API is based on Chromium's [`chrome.runtime`](https://developer.chrome.com/docs/extensions/reference/api/runtime#event-onUserScriptConnect) API. This documentation is derived from [`runtime.json`](https://chromium.googlesource.com/chromium/src/+/master/extensions/common/api/runtime.json) in the Chromium code. - - diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md index e55090c69c86bad..29e42d7c6efa264 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md @@ -85,36 +85,3 @@ browser.runtime.onUserScriptMessage.addListener(handleMessage); ## Browser compatibility {{Compat}} - -> [!NOTE] -> This API is based on Chromium's [`chrome.runtime`](https://developer.chrome.com/docs/extensions/reference/api/runtime#event-onUserScriptMessage) API. This documentation is derived from [`runtime.json`](https://chromium.googlesource.com/chromium/src/+/master/extensions/common/api/runtime.json) in the Chromium code. - - From 5675d2288a4fe2d4e20cdb6e641b1d0234a5c67c Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Wed, 19 Feb 2025 07:10:42 +1300 Subject: [PATCH 14/25] Eval space fix? --- .../webextensions/api/userscripts/worldproperties/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md index 8ba7c1d08b28755..d7fbff75e2c408c 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md @@ -16,7 +16,7 @@ Values of this type are an object containing these properties: - `worldId` {{optional_inline}} - : `string`. The identifier for the world. Values with leading underscores (`_`) are reserved. The maximum length is 256. Defaults to the default `USER_SCRIPT` world (""). - `csp` {{optional_inline}} - - : string`. The world's Content Security Policy (CSP). Defaults to the standard content scripts CSP, which prohibits dynamic code execution, such as `eval()`. + - : string`. The world's Content Security Policy (CSP). Defaults to the standard content scripts CSP, which prohibits dynamic code execution, such as` eval()`. - `messaging` {{optional_inline}} - : `boolean`. Whether the {{WebExtAPIRef("runtime.sendMessage")}} and {{WebExtAPIRef("runtime.connect")}} methods are exposed to the user script world. Defaults to hiding these messaging APIs. The {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}} event handlers are triggered when these methods are called. From 23d1d2e625073b6c96a27820ccf75ce5dd2704ac Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Wed, 19 Feb 2025 11:24:21 +1300 Subject: [PATCH 15/25] Runtime event permission requirements Removed inappropriate onUserScriptConnect example --- .../api/runtime/onuserscriptconnect/index.md | 59 +------------------ .../api/runtime/onuserscriptmessage/index.md | 2 + 2 files changed, 5 insertions(+), 56 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md index b33733631dc197e..c32d91dda88d140 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md @@ -9,6 +9,8 @@ browser-compat: webextensions.api.runtime.onUserScriptConnect Fired when a connection is made with a user script from one of the extension's [`USER_SCRIPT` worlds](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/ExecutionWorld). +In Firefox, this event requires the [`userScripts` permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts#permissions). In Chrome, the event is always present, including in extensions that don't declare the `userScripts` permission and have no code to fire the event. + A user script can only connect and then sent messages from a `USER_SCRIPT` world that is configured by {{WebExtAPIRef('userScripts.configureWorld()')}} with `messaging` set to `true`. ## Syntax @@ -39,62 +41,7 @@ Events have three functions: - `port` - : {{WebExtAPIRef('runtime.Port')}}. An object connecting the current script to the other context. -## Examples - -This user script: - -- Connects to the background script and stores `Port` in a variable `myPort`. -- Listens for messages on `myPort` and logs them. -- Sends messages to the background script using `myPort` when the user clicks the document. - -```js -// user-script.js - -let myPort = browser.runtime.connect({ name: "port-from-us" }); -myPort.postMessage({ greeting: "hello from user script" }); - -myPort.onMessage.addListener((m) => { - console.log("In the user script, received message from background script: "); - console.log(m.greeting); -}); - -document.body.addEventListener("click", () => { - myPort.postMessage({ greeting: "they clicked the page!" }); -}); -``` - -The corresponding background script: - -- Listens for connection attempts from the user script, and when it receives a connection attempt: - - - Stores the port in a variable named `portFromUS`. - - Sends the content script a message using the port. - - Starts listening to messages received on the port and logs them. - -- Sends messages to the content script using `portFromUS` when the user clicks the extension's browser action. - -```js -// background-script.js - -let portFromCS; - -function connected(p) { - portFromUS = p; - portFromUS.postMessage({ greeting: "hi there user script!" }); - portFromUS.onMessage.addListener((m) => { - console.log("In background script, received message from user script"); - console.log(m.greeting); - }); -} - -browser.runtime.onUserScriptConnect.addListener(connected); - -browser.browserAction.onClicked.addListener(() => { - portFromUS.postMessage({ greeting: "they clicked the button!" }); -}); -``` - -{{WebExtExamples}} +{{WebExtExamples("h2")}} ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md index 29e42d7c6efa264..21ed448f11c69e6 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md @@ -9,6 +9,8 @@ browser-compat: webextensions.api.runtime.onUserScriptMessage Use this event to listen for messages sent from one of the extension's [`USER_SCRIPT` worlds](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/ExecutionWorld). +In Firefox, this event requires the [`userScripts` permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts#permissions). In Chrome, the event is always present, including in extensions that don't declare the `userScripts` permission and have no code to fire the event. + A user script can only send messages using {{WebExtAPIRef('runtime.sendMessage')}} from a `USER_SCRIPT` world that is configured by {{WebExtAPIRef('userScripts.configureWorld()')}} with `messaging` set to `true`. Along with the message, the listener is passed: From e26c5434a44078ac7b76398f5c8bb1bd588db474 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Wed, 19 Feb 2025 13:49:51 +1300 Subject: [PATCH 16/25] Additional information about configurations --- .../api/userscripts/configureworld/index.md | 11 ++++++++++- .../api/userscripts/resetworldconfiguration/index.md | 6 ++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md index b1d2bd4c605c741..866cbab72ae24d1 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md @@ -7,7 +7,11 @@ browser-compat: webextensions.api.userScripts.configureWorld {{AddonSidebar}} -Configures a `USER_SCRIPT` execution environment for the extension. +Configures `USER_SCRIPT` execution environments for the extension. + +Changes to world configurations only apply to new instances of the world: A configuration won't apply to a world initialized by the execution of a user script in a document until the document is reloaded. However, the browser may revoke certain privileges when a configuration is updated. For example, message calls from a `USER_SCRIPT` world may fail if the extension sets `messaging` to `false`. + +World configurations persist until the extension is updated or the configuration is reset by {{WebExtAPIRef("userScripts.resetWorldConfiguration()")}}. This is an asynchronous method that returns a {{JSxRef("Promise")}}. @@ -22,8 +26,13 @@ const configuredWorld = await browser.userScripts.configureWorld( ### Parameters - `properties` + - : {{WebExtAPIRef("userScripts.WorldProperties")}}. Details of the configuration for a `USER_SCRIPT` world. + When `worldId` is omitted or the string is empty, the update is applied to the default world and all worlds without an explicit configuration. When `worldId` is specified only that world is configured. + + When updating the default world and worlds without an explicit configuration, when properties are omitted the {{WebExtAPIRef("userScripts.WorldProperties")}} defaults are used. + ### Return value A {{JSxRef("Promise")}} fulfilled with no arguments if the request is successful. If the request fails, the promise is rejected with an error message. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md index 7ee3b1a2ba5dbdd..c39f700f692d880 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md @@ -7,7 +7,9 @@ browser-compat: webextensions.api.userScripts.resetWorldConfiguration {{AddonSidebar}} -Resets the configuration of a `USER_SCRIPT` world registered by the extension. Any scripts injected into the world are moved to the default `USER_SCRIPT` world configuration. +Resets the configuration of a `USER_SCRIPT` world set by {{WebExtAPIRef("userScripts.configureWorld")}} to the defaults specified in {{WebExtAPIRef("userScripts.WorldProperties")}}. When the default world is reset, all worlds without an explicit configuration are also reset. + +Any scripts injected into a reset world are moved to the default `USER_SCRIPT` world. This is an asynchronous method that returns a {{JSxRef("Promise")}}. @@ -22,7 +24,7 @@ const resettingWorldConfiguration = await browser.userScripts.resetWorldConfigur ### Parameters - `worldId` {{optional_inline}} - - : `string` The ID of the `USER_SCRIPT` world to reset. If omitted or empty, resets the default world's configuration. + - : `string` The ID of the `USER_SCRIPT` world to reset. If omitted or empty, resets the configuration of the default world and all worlds without a configuration set by {{WebExtAPIRef("userScripts.configureWorld")}}. ### Return value From ef4ae427898283255b9dffa3e35c3caee2c259df Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Thu, 20 Feb 2025 04:54:05 +1300 Subject: [PATCH 17/25] Final feedback updates --- .../userscripts/registereduserscript/index.md | 2 +- .../api/userscripts/update/index.md | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md index 8ac9d9c2b2d333d..2f3d1f29e587688 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md @@ -15,7 +15,7 @@ Values of this type are an object containing these properties: - `allFrames` {{optional_inline}} - : `boolean`. If `allFrames` is `true`, the script is injected into all of a page's frames. By default, it's `false` and the script is only injected into the top frame. -- `id` {{optional_inline}} for {{WebExtAPIRef("userScripts.update()")}} calls, required for {{WebExtAPIRef("userScripts.register()")}} +- `id` - : `string`. The ID of a user script. This property must not start with a '\_', which is reserved as a prefix for generated script IDs. - `js` {{optional_inline}} for {{WebExtAPIRef("userScripts.update()")}} calls, required for {{WebExtAPIRef("userScripts.register()")}} - : `array` of {{WebExtAPIRef("userScripts.ScriptSource")}}. The scripts to inject into matching pages. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md index b62a331bce66265..a0334ffeaf2d42e 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md @@ -25,7 +25,7 @@ const updatingUserScript = await browser.userScripts.update( - : `array` of {{WebExtAPIRef("userScripts.RegisteredUserScript")}}. Details of user scripts to update. - Each {{WebExtAPIRef("userScripts.RegisteredUserScript")}} must specify at least one property. Properties that are `null` or omitted are not changed. Passing an empty array clears the array. + Properties that are `null` or omitted are not changed. Passing an empty array to `matches`, `excludeMatches`, `globs` and `excludeGlobs` clears these properties. ### Return value @@ -33,24 +33,26 @@ A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user sc ## Examples -This snippet updates `matches` for all registered user scripts. +This snippet shows two examples of updates to a user scripts. The first update fails because it attempts to create an invalid script registration. The second example shows a successful update. ```js -await browser.userScripts.update([ +// Valid registration: +await browser.userScripts.register([ { worldId: "myScriptId", + js: [{ code: "console.log('Hello world!');" }], matches: ["*://example.com/*"], }, ]); -``` -This snippet updates `matches` for all user scripts running in the `"myScriptId"` world. +// Invalid! Would result in script without matches or includeGlobs! +await browser.userScripts.update([{ matches: [] }]); -```js +// Valid: replaces matches with includeGlobs. await browser.userScripts.update([ { - worldId: "myScriptId", - matches: ["*://example.com/*"], + matches: [], + includeGlobs: ["*example*"], }, ]); ``` From 0350cdb3561b7bb46f73627923db543f28d00ad9 Mon Sep 17 00:00:00 2001 From: rebloor Date: Fri, 21 Feb 2025 04:55:09 +1300 Subject: [PATCH 18/25] Apply suggestions from review Co-authored-by: Rob Wu --- .../api/runtime/onuserscriptconnect/index.md | 2 +- .../api/runtime/onuserscriptmessage/index.md | 2 +- .../add-ons/webextensions/api/userscripts/index.md | 10 +++++----- .../webextensions/api/userscripts/register/index.md | 2 +- .../api/userscripts/resetworldconfiguration/index.md | 4 ++-- .../api/userscripts/scriptsource/index.md | 2 +- .../webextensions/api/userscripts/unregister/index.md | 2 +- .../webextensions/api/userscripts/update/index.md | 4 ++-- .../api/userscripts/userscriptfilter/index.md | 2 +- .../api/userscripts/worldproperties/index.md | 2 +- .../webextensions/manifest.json/permissions/index.md | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md index c32d91dda88d140..e69f817e594eef3 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptconnect/index.md @@ -9,7 +9,7 @@ browser-compat: webextensions.api.runtime.onUserScriptConnect Fired when a connection is made with a user script from one of the extension's [`USER_SCRIPT` worlds](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/ExecutionWorld). -In Firefox, this event requires the [`userScripts` permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts#permissions). In Chrome, the event is always present, including in extensions that don't declare the `userScripts` permission and have no code to fire the event. +In Firefox, this event requires the [`userScripts` permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts#permissions). In Chrome, the event is always present, including in extensions that don't declare the `userScripts` permission. A user script can only connect and then sent messages from a `USER_SCRIPT` world that is configured by {{WebExtAPIRef('userScripts.configureWorld()')}} with `messaging` set to `true`. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md index 21ed448f11c69e6..dfa2f28aa62103d 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/runtime/onuserscriptmessage/index.md @@ -9,7 +9,7 @@ browser-compat: webextensions.api.runtime.onUserScriptMessage Use this event to listen for messages sent from one of the extension's [`USER_SCRIPT` worlds](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts/ExecutionWorld). -In Firefox, this event requires the [`userScripts` permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts#permissions). In Chrome, the event is always present, including in extensions that don't declare the `userScripts` permission and have no code to fire the event. +In Firefox, this event requires the [`userScripts` permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts#permissions). In Chrome, the event is always present, including in extensions that don't declare the `userScripts` permission. A user script can only send messages using {{WebExtAPIRef('runtime.sendMessage')}} from a `USER_SCRIPT` world that is configured by {{WebExtAPIRef('userScripts.configureWorld()')}} with `messaging` set to `true`. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index 27994e4fab753cc..a2ca67c329a0043 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -12,18 +12,18 @@ Use this API to register user scripts, third-party scripts designed to manipulat > [!NOTE] > This is documentation for the new API version, available in Firefox for Manifest V3. See {{WebExtAPIRef("userScripts_legacy","userScripts (legacy)")}} for information on the API available for use in Firefox with Manifest V2. -This API offers capabilities similar to {{WebExtAPIRef("contentScripts")}} but with features suited to handling third-party scripts. +This API offers capabilities similar to {{WebExtAPIRef("scripting")}} but with features suited to handling third-party scripts. ## Permissions To use this API, you need the `userScripts` permission and `host_permissions` for sites where you want to run scripts. However, the approach to enabling the use of this API varies between browsers: -- In Firefox, `userScripts` is an optional-only permission declared in the [`optional_permissions` manifest key](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions#optional-only_permissions). Your extension must check that the permission has been granted using {{WebExtAPIRef("permissions.contains()")}} and, if not, request it using {{WebExtAPIRef("permissions.request()")}}. +- In Firefox, `userScripts` is an [optional-only permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions#optional-only_permissions) declared in the `optional_permissions` manifest key. Your extension must check that the permission has been granted by checking the availability of the `userScripts` API namespace or using {{WebExtAPIRef("permissions.contains()")}} and, if not, request it using {{WebExtAPIRef("permissions.request()")}}. - in Chrome, `userScripts` is an install time requested permission declared in the [`permissions` manifest key](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions). However, to enable use of the API, users must [turn on the developer environment in Chrome](https://developer.chrome.com/docs/extensions/reference/api/userScripts#developer_mode_for_extension_users). ## Execution worlds -When registering a user script (using {{WebExtAPIRef("userScripts.register()")}}) your extension can run it in an isolated, `USER_SCRIPT` world or the `MAIN` world. +When registering a user script (using {{WebExtAPIRef("userScripts.register()")}}) your extension can run it in an isolated `USER_SCRIPT` world or the `MAIN` world. The isolated `USER_SCRIPT` world provides an execution environment that isn't accessible to a host page or other extensions. This means a user script can change its JavaScript environment without affecting the host page or other extensions' user and content scripts. In this environment, user scripts aren't visible to the host page or other extensions' user and content scripts. The API also enables an extension to configure a content security policy (CSP) for the `USER_SCRIPT` world using {{WebExtAPIRef("userScripts.configureWorld()")}}. @@ -33,7 +33,7 @@ In the `MAIN` world, host pages and other extensions can see and access running Like content scripts and other extension scripts, user scripts communicate with other parts of an extension with messages using {{WebExtAPIRef("runtime.sendMessage()")}} and {{WebExtAPIRef("runtime.connect()")}}. However, user scripts receive messages using the dedicated {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}}. Dedicated handlers are used as they make it easier to identify messages from user scripts, which are a less-trusted context. -To enable messaging APIs, call {{WebExtAPIRef("userScripts.configureWorld()")}} with the `messaging` argument set to `true` before registering a user script. The `csp` and `messaging` arguments can be passed at the same time. +To enable messaging APIs, call {{WebExtAPIRef("userScripts.configureWorld()")}} with the `messaging` argument set to `true` before registering a user script. ```js browser.userScripts.configureWorld({ @@ -54,7 +54,7 @@ When an extension updates, user scripts are cleared. To restore scripts, add cod - : The execution environment for a script injected with {{WebExtAPIRef("userScripts.register()")}} or {{WebExtAPIRef("userScripts.update()")}}. - {{WebExtAPIRef("userScripts.RegisteredUserScript")}} - - : An `object` returned by {{WebExtAPIRef("userScripts.getScripts","getScripts()")}}, {{WebExtAPIRef("userScripts.register","register()")}}, and {{WebExtAPIRef("userScripts.update","update()")}} representing registered user scripts. + - : An `object` returned by {{WebExtAPIRef("userScripts.getScripts","getScripts()")}} and the input to {{WebExtAPIRef("userScripts.register","register()")}} and {{WebExtAPIRef("userScripts.update","update()")}} representing registered user scripts. - {{WebExtAPIRef("userScripts.ScriptSource")}} - : The code or a file source for a user script. - {{WebExtAPIRef("userScripts.UserScriptFilter")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md index 889cbcd0e07a97f..240521ec87ddb41 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md @@ -29,7 +29,7 @@ const registeredUserScript = await browser.userScripts.register( ### Return value -A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are registered. If any user scripts fail to register or the request fails for another reason, the promise is rejected with an error message. +A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are registered. If any user scripts fail to register or the request fails for another reason, none of the scripts register and the promise is rejected with an error message. ## Examples diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md index c39f700f692d880..f87511d7b2cda34 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md @@ -9,7 +9,7 @@ browser-compat: webextensions.api.userScripts.resetWorldConfiguration Resets the configuration of a `USER_SCRIPT` world set by {{WebExtAPIRef("userScripts.configureWorld")}} to the defaults specified in {{WebExtAPIRef("userScripts.WorldProperties")}}. When the default world is reset, all worlds without an explicit configuration are also reset. -Any scripts injected into a reset world are moved to the default `USER_SCRIPT` world. +Changes to world configurations only apply to new instances of the world: A configuration won't apply to a world initialized by the execution of a user script in a document until the document is reloaded. However, the browser may revoke certain privileges when a configuration is updated. For example, message calls from a `USER_SCRIPT` world may fail when `messaging` is reset to `false`. This is an asynchronous method that returns a {{JSxRef("Promise")}}. @@ -17,7 +17,7 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ```js-nolint const resettingWorldConfiguration = await browser.userScripts.resetWorldConfiguration( - worldId // string + worldId // optional string ); ``` diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md index 2b3d711d5e65687..03fbee8c37b4939 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/scriptsource/index.md @@ -7,7 +7,7 @@ browser-compat: webextensions.api.userScripts.ScriptSource {{AddonSidebar}} -The code or source file for a user script. +The code or source file for a user script. This describes the object values of the "js" property in {{WebExtAPIRef("userScripts.RegisteredUserScript","RegisteredUserScript")}}. ## Type diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md index d4ff798855cce92..342b6b6a0eadd36 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md @@ -15,7 +15,7 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ```js-nolint const unregisteringUserScripts = await browser.userScripts.unregister( - filter // object + filter // optional object ); ``` diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md index a0334ffeaf2d42e..7f681ab98ef8525 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md @@ -15,7 +15,7 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ```js-nolint const updatingUserScript = await browser.userScripts.update( - scripts // object + scripts // array of objects ); ``` @@ -29,7 +29,7 @@ const updatingUserScript = await browser.userScripts.update( ### Return value -A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are updated. If any user scripts fail to update or the request fails for another reason, the promise is rejected with an error message. +A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are updated. If any user scripts fail to update or the request fails for another reason, none of the scripts are updated and the promise is rejected with an error message. ## Examples diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md index c852418e3140828..4a1d431f91b2a51 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md @@ -14,7 +14,7 @@ A list of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts Values of this type are an object containing these properties: - `ids` {{optional_inline}} - - : `array` of `string`. IDs of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. This matches scripts by the `id` field of {{WebExtAPIRef("RegisteredUserScript")}}. + - : `array` of `string`. IDs of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. This matches scripts by the `id` field of {{WebExtAPIRef("userScripts.RegisteredUserScript","RegisteredUserScript")}}. {{WebExtExamples("h2")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md index d7fbff75e2c408c..3775cedf8165e1b 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md @@ -16,7 +16,7 @@ Values of this type are an object containing these properties: - `worldId` {{optional_inline}} - : `string`. The identifier for the world. Values with leading underscores (`_`) are reserved. The maximum length is 256. Defaults to the default `USER_SCRIPT` world (""). - `csp` {{optional_inline}} - - : string`. The world's Content Security Policy (CSP). Defaults to the standard content scripts CSP, which prohibits dynamic code execution, such as` eval()`. + - : string`. The world's Content Security Policy (CSP). Defaults to the [default CSP for content scripts](/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy#csp_for_content_scripts), which prohibits dynamic code execution, such as` eval()`. - `messaging` {{optional_inline}} - : `boolean`. Whether the {{WebExtAPIRef("runtime.sendMessage")}} and {{WebExtAPIRef("runtime.connect")}} methods are exposed to the user script world. Defaults to hiding these messaging APIs. The {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}} event handlers are triggered when these methods are called. diff --git a/files/en-us/mozilla/add-ons/webextensions/manifest.json/permissions/index.md b/files/en-us/mozilla/add-ons/webextensions/manifest.json/permissions/index.md index 8567d1f415f8092..2a1c670f9840d42 100644 --- a/files/en-us/mozilla/add-ons/webextensions/manifest.json/permissions/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/manifest.json/permissions/index.md @@ -132,7 +132,7 @@ These permissions are available in Manifest V2 and above unless otherwise noted: - `theme` - `topSites` - `unlimitedStorage` -- `userScripts` (This permission is [optional-only](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions#optional-only_permissions) in Firefox. In Chrome, the extension user must also activate [developer mode](https://developer.chrome.com/docs/extensions/reference/api/userScripts#developer_mode_for_extension_users).) +- 'userScripts' (see [userScripts permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts#permissions)) - `webNavigation` - `webRequest` - `webRequestAuthProvider` (Manifest V3 and above) From 800c1f2adb7ff17af96b6c010c98634d4f9e3341 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Fri, 21 Feb 2025 05:06:45 +1300 Subject: [PATCH 19/25] Corrections to suggested changes --- .../mozilla/add-ons/webextensions/api/userscripts/index.md | 2 +- .../add-ons/webextensions/api/userscripts/register/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index a2ca67c329a0043..6973855640ed76f 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -54,7 +54,7 @@ When an extension updates, user scripts are cleared. To restore scripts, add cod - : The execution environment for a script injected with {{WebExtAPIRef("userScripts.register()")}} or {{WebExtAPIRef("userScripts.update()")}}. - {{WebExtAPIRef("userScripts.RegisteredUserScript")}} - - : An `object` returned by {{WebExtAPIRef("userScripts.getScripts","getScripts()")}} and the input to {{WebExtAPIRef("userScripts.register","register()")}} and {{WebExtAPIRef("userScripts.update","update()")}} representing registered user scripts. + - : An `object` returned by {{WebExtAPIRef("userScripts.getScripts","getScripts()")}} representing registered user scripts and used as input to {{WebExtAPIRef("userScripts.register","register()")}} and {{WebExtAPIRef("userScripts.update","update()")}}. - {{WebExtAPIRef("userScripts.ScriptSource")}} - : The code or a file source for a user script. - {{WebExtAPIRef("userScripts.UserScriptFilter")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md index 240521ec87ddb41..bb53868da96b6e7 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md @@ -29,7 +29,7 @@ const registeredUserScript = await browser.userScripts.register( ### Return value -A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are registered. If any user scripts fail to register or the request fails for another reason, none of the scripts register and the promise is rejected with an error message. +A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are registered. If any user scripts fail to register or the request fails for another reason, none of the scripts are registered and the promise is rejected with an error message. ## Examples From 5750c8b1789cc8317d03b35dec2feffb409427e0 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Fri, 21 Feb 2025 05:56:10 +1300 Subject: [PATCH 20/25] Further feedback updates --- .../webextensions/api/userscripts/configureworld/index.md | 2 +- .../mozilla/add-ons/webextensions/api/userscripts/index.md | 6 ++++-- .../add-ons/webextensions/api/userscripts/register/index.md | 2 +- .../api/userscripts/registereduserscript/index.md | 2 +- .../api/userscripts/resetworldconfiguration/index.md | 2 +- .../webextensions/api/userscripts/unregister/index.md | 2 +- .../add-ons/webextensions/api/userscripts/update/index.md | 2 +- .../webextensions/api/userscripts/worldproperties/index.md | 2 +- .../manifest.json/optional_permissions/index.md | 1 + 9 files changed, 12 insertions(+), 9 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md index 866cbab72ae24d1..0431a68fd9711cb 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md @@ -18,7 +18,7 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const configuredWorld = await browser.userScripts.configureWorld( +let configuredWorld = browser.userScripts.configureWorld( properties // object ); ``` diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index 6973855640ed76f..086eae2a76d8029 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -23,12 +23,14 @@ To use this API, you need the `userScripts` permission and `host_permissions` fo ## Execution worlds -When registering a user script (using {{WebExtAPIRef("userScripts.register()")}}) your extension can run it in an isolated `USER_SCRIPT` world or the `MAIN` world. +When a user script is registered or updated (using {{WebExtAPIRef("userScripts.register()")}} or {{WebExtAPIRef("userScripts.update()")}}), your extension can set it to run in an isolated `USER_SCRIPT` world or the `MAIN` world. The isolated `USER_SCRIPT` world provides an execution environment that isn't accessible to a host page or other extensions. This means a user script can change its JavaScript environment without affecting the host page or other extensions' user and content scripts. In this environment, user scripts aren't visible to the host page or other extensions' user and content scripts. The API also enables an extension to configure a content security policy (CSP) for the `USER_SCRIPT` world using {{WebExtAPIRef("userScripts.configureWorld()")}}. In the `MAIN` world, host pages and other extensions can see and access running user scripts. +These execution world values are defined in {{WebExtAPIRef("userScripts.ExecutionWorld","ExecutionWorld")}}. + ## Messaging Like content scripts and other extension scripts, user scripts communicate with other parts of an extension with messages using {{WebExtAPIRef("runtime.sendMessage()")}} and {{WebExtAPIRef("runtime.connect()")}}. However, user scripts receive messages using the dedicated {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}}. Dedicated handlers are used as they make it easier to identify messages from user scripts, which are a less-trusted context. @@ -85,4 +87,4 @@ When an extension updates, user scripts are cleared. To restore scripts, add cod ## See also -- {{WebExtAPIRef("contentScripts","browser.contentScripts")}} +- {{WebExtAPIRef("scripting","browser.scripting")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md index bb53868da96b6e7..9d2c575372ee5ee 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md @@ -14,7 +14,7 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const registeredUserScript = await browser.userScripts.register( +let registeredUserScript = browser.userScripts.register( scripts // object ) ``` diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md index 2f3d1f29e587688..c84478c05c994b8 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md @@ -7,7 +7,7 @@ browser-compat: webextensions.api.userScripts.RegisteredUserScript {{AddonSidebar}} -An object representing registered user scripts. +An object representing registered user scripts. Returned by {{WebExtAPIRef("userScripts.getScripts","getScripts()")}} and used as input to {{WebExtAPIRef("userScripts.register","register()")}} and {{WebExtAPIRef("userScripts.update","update()")}}. ## Type diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md index f87511d7b2cda34..19a2bb1c6094885 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md @@ -16,7 +16,7 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const resettingWorldConfiguration = await browser.userScripts.resetWorldConfiguration( +let resettingWorldConfiguration = browser.userScripts.resetWorldConfiguration( worldId // optional string ); ``` diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md index 342b6b6a0eadd36..9bb326f8208961b 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md @@ -14,7 +14,7 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const unregisteringUserScripts = await browser.userScripts.unregister( +let unregisteringUserScripts = browser.userScripts.unregister( filter // optional object ); ``` diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md index 7f681ab98ef8525..a1ffad9ed4f9eb4 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md @@ -14,7 +14,7 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax ```js-nolint -const updatingUserScript = await browser.userScripts.update( +let updatingUserScript = browser.userScripts.update( scripts // array of objects ); ``` diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md index 3775cedf8165e1b..386ed6f0fd4e880 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md @@ -7,7 +7,7 @@ browser-compat: webextensions.api.userScripts.WorldProperties {{AddonSidebar}} -The configuration of a `USER_SCRIPT` execution environment. +The configuration of a `USER_SCRIPT` execution environment. Used in {{WebExtAPIRef("userScripts.configureWorld")}} and {{WebExtAPIRef("userScripts.getWorldConfigurations")}}. ## Type diff --git a/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md b/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md index 05d6d24ac1681a6..7e2cea4fecb60c1 100644 --- a/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md @@ -88,6 +88,7 @@ The optional API permissions are: - `tabHide` - `tabs` - `topSites` +- 'userScripts' ([optional-only](#optional-only_permissions)) - `webNavigation` - `webRequest` - `webRequestBlocking` From 10d4a8078625df50640e7b3f14160ba1bab6f34f Mon Sep 17 00:00:00 2001 From: rebloor Date: Fri, 21 Feb 2025 05:57:51 +1300 Subject: [PATCH 21/25] Apply suggestions from review Co-authored-by: Rob Wu --- .../api/userscripts/resetworldconfiguration/index.md | 1 + .../webextensions/manifest.json/optional_permissions/index.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md index 19a2bb1c6094885..adb9ac24ab5baba 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md @@ -9,6 +9,7 @@ browser-compat: webextensions.api.userScripts.resetWorldConfiguration Resets the configuration of a `USER_SCRIPT` world set by {{WebExtAPIRef("userScripts.configureWorld")}} to the defaults specified in {{WebExtAPIRef("userScripts.WorldProperties")}}. When the default world is reset, all worlds without an explicit configuration are also reset. +Changes to world configurations only apply to new instances of the world: A configuration won't apply to a world initialized by the execution of a user script in a document until the document is reloaded. However, the browser may revoke certain privileges when a configuration is updated. For example, message calls from a `USER_SCRIPT` world may fail when `messaging` is reset to `false`. Changes to world configurations only apply to new instances of the world: A configuration won't apply to a world initialized by the execution of a user script in a document until the document is reloaded. However, the browser may revoke certain privileges when a configuration is updated. For example, message calls from a `USER_SCRIPT` world may fail when `messaging` is reset to `false`. This is an asynchronous method that returns a {{JSxRef("Promise")}}. diff --git a/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md b/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md index 7e2cea4fecb60c1..8b39c0cc021933a 100644 --- a/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/manifest.json/optional_permissions/index.md @@ -113,7 +113,7 @@ Optional permissions are generally available for use in the [`permissions`](/en- The optional-only API permissions are: -- 'userScripts' (Firefox only) +- 'userScripts' (see [userScripts permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts#permissions)) ## Examples From fed7682ad059479c391d09a1aa0c4134bf94ce1c Mon Sep 17 00:00:00 2001 From: rebloor Date: Sun, 23 Feb 2025 05:47:39 +1300 Subject: [PATCH 22/25] Apply suggestions from review Co-authored-by: Rob Wu --- .../mozilla/add-ons/webextensions/api/userscripts/index.md | 2 +- .../add-ons/webextensions/api/userscripts/register/index.md | 2 +- .../webextensions/api/userscripts/registereduserscript/index.md | 2 +- .../webextensions/api/userscripts/userscriptfilter/index.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index 086eae2a76d8029..f96f334f4c9cf8e 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -16,7 +16,7 @@ This API offers capabilities similar to {{WebExtAPIRef("scripting")}} but with f ## Permissions -To use this API, you need the `userScripts` permission and `host_permissions` for sites where you want to run scripts. However, the approach to enabling the use of this API varies between browsers: +To use this API, you need the `userScripts` permission and [`host_permissions`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/host_permissions) for sites where you want to run scripts. However, the approach to enabling the use of this API varies between browsers: - In Firefox, `userScripts` is an [optional-only permission](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions#optional-only_permissions) declared in the `optional_permissions` manifest key. Your extension must check that the permission has been granted by checking the availability of the `userScripts` API namespace or using {{WebExtAPIRef("permissions.contains()")}} and, if not, request it using {{WebExtAPIRef("permissions.request()")}}. - in Chrome, `userScripts` is an install time requested permission declared in the [`permissions` manifest key](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions). However, to enable use of the API, users must [turn on the developer environment in Chrome](https://developer.chrome.com/docs/extensions/reference/api/userScripts#developer_mode_for_extension_users). diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md index 9d2c575372ee5ee..4abd3a52b1d0c36 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md @@ -15,7 +15,7 @@ This is an asynchronous method that returns a {{JSxRef("Promise")}}. ```js-nolint let registeredUserScript = browser.userScripts.register( - scripts // object + scripts // array of objects ) ``` diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md index c84478c05c994b8..defe1752ef5ccc5 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md @@ -32,7 +32,7 @@ Values of this type are an object containing these properties: - `world` {{optional_inline}} - : {{WebExtAPIRef("userScripts.ExecutionWorld")}}. The execution environment to use to run the scripts. Defaults to "USER_SCRIPT". - `worldId` {{optional_inline}} - - : `string`. ID of a user script world execute the script in. Only valid if `world` is `USER_SCRIPT` or omitted. If `worldId` is omitted, the script is execute in the default `USER_SCRIPT` world (""). Values with leading underscores (`_`) are reserved. The maximum length is 256 characters. + - : `string`. ID of a user script world the script executes in. Only valid if `world` is `USER_SCRIPT` or omitted. If `worldId` is omitted, the script is executed in the default `USER_SCRIPT` world (""). Values with leading underscores (`_`) are reserved. The maximum length is 256 characters. Pass this `worldId` to {{WebExtAPIRef("userScripts.configureWorld")}} to configure the behavior of a world. ## Browser compatibility diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md index 4a1d431f91b2a51..b21c23698a3a0ef 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md @@ -14,7 +14,7 @@ A list of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts Values of this type are an object containing these properties: - `ids` {{optional_inline}} - - : `array` of `string`. IDs of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. This matches scripts by the `id` field of {{WebExtAPIRef("userScripts.RegisteredUserScript","RegisteredUserScript")}}. + - : `array` of `string`. IDs of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. This matches scripts by the `id` field of {{WebExtAPIRef("userScripts.RegisteredUserScript","RegisteredUserScript")}}. If not specified, all user scripts are matched. {{WebExtExamples("h2")}} From c8c17db091c97f96147d03c061320da80c03b08e Mon Sep 17 00:00:00 2001 From: rebloor Date: Sun, 23 Feb 2025 05:51:38 +1300 Subject: [PATCH 23/25] Remove unnecessary space Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../webextensions/api/userscripts/registereduserscript/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md index defe1752ef5ccc5..6c19a9ee2aaa4e5 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md @@ -32,7 +32,7 @@ Values of this type are an object containing these properties: - `world` {{optional_inline}} - : {{WebExtAPIRef("userScripts.ExecutionWorld")}}. The execution environment to use to run the scripts. Defaults to "USER_SCRIPT". - `worldId` {{optional_inline}} - - : `string`. ID of a user script world the script executes in. Only valid if `world` is `USER_SCRIPT` or omitted. If `worldId` is omitted, the script is executed in the default `USER_SCRIPT` world (""). Values with leading underscores (`_`) are reserved. The maximum length is 256 characters. Pass this `worldId` to {{WebExtAPIRef("userScripts.configureWorld")}} to configure the behavior of a world. + - : `string`. ID of a user script world the script executes in. Only valid if `world` is `USER_SCRIPT` or omitted. If `worldId` is omitted, the script is executed in the default `USER_SCRIPT` world (""). Values with leading underscores (`_`) are reserved. The maximum length is 256 characters. Pass this `worldId` to {{WebExtAPIRef("userScripts.configureWorld")}} to configure the behavior of a world. ## Browser compatibility From 8bbd328618db257de87052f07b35f6e625fb5700 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Mon, 24 Feb 2025 00:12:00 +0100 Subject: [PATCH 24/25] Update files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md Co-authored-by: rebloor --- .../webextensions/api/userscripts/registereduserscript/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md index 6c19a9ee2aaa4e5..b0496fda6aaee74 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md @@ -32,7 +32,7 @@ Values of this type are an object containing these properties: - `world` {{optional_inline}} - : {{WebExtAPIRef("userScripts.ExecutionWorld")}}. The execution environment to use to run the scripts. Defaults to "USER_SCRIPT". - `worldId` {{optional_inline}} - - : `string`. ID of a user script world the script executes in. Only valid if `world` is `USER_SCRIPT` or omitted. If `worldId` is omitted, the script is executed in the default `USER_SCRIPT` world (""). Values with leading underscores (`_`) are reserved. The maximum length is 256 characters. Pass this `worldId` to {{WebExtAPIRef("userScripts.configureWorld")}} to configure the behavior of a world. + - : `string`. ID of a user script world the script executes in. Only valid if `world` is `USER_SCRIPT` or omitted. If `worldId` is omitted, the script is executed in the default `USER_SCRIPT` world (""). Values with leading underscores (`_`) are reserved. The maximum length is 256 characters. A world can be used by several scripts as their execution environment. To configure the behavior of a world, pass its `worldId` to {{WebExtAPIRef("userScripts.configureWorld")}} before the first script executes in that world. ## Browser compatibility From b8ed93ad7ae3c4344707e2722c3a12efa719f2c2 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Tue, 25 Feb 2025 05:39:50 +1300 Subject: [PATCH 25/25] Final review tweaks --- .../webextensions/api/userscripts/configureworld/index.md | 2 -- .../webextensions/api/userscripts/executionworld/index.md | 2 +- .../webextensions/api/userscripts/getscripts/index.md | 2 -- .../api/userscripts/getworldconfigurations/index.md | 2 -- .../mozilla/add-ons/webextensions/api/userscripts/index.md | 6 +++--- .../add-ons/webextensions/api/userscripts/register/index.md | 4 +--- .../api/userscripts/registereduserscript/index.md | 6 +++--- .../api/userscripts/resetworldconfiguration/index.md | 3 --- .../webextensions/api/userscripts/unregister/index.md | 2 -- .../add-ons/webextensions/api/userscripts/update/index.md | 6 ++---- .../webextensions/api/userscripts/userscriptfilter/index.md | 2 +- .../webextensions/api/userscripts/worldproperties/index.md | 4 ++-- 12 files changed, 13 insertions(+), 28 deletions(-) diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md index 0431a68fd9711cb..d9bf72c29bf8cd3 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/configureworld/index.md @@ -13,8 +13,6 @@ Changes to world configurations only apply to new instances of the world: A conf World configurations persist until the extension is updated or the configuration is reset by {{WebExtAPIRef("userScripts.resetWorldConfiguration()")}}. -This is an asynchronous method that returns a {{JSxRef("Promise")}}. - ## Syntax ```js-nolint diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md index a75bc297ad7bda9..80cb94894c8368f 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/executionworld/index.md @@ -23,7 +23,7 @@ Values of this type are a string. Possible values are: - `USER_SCRIPT` - The default execution environment for user scripts. This environment is isolated from the page's context and other `USER_SCRIPT` worlds. Extension APIs are unavailable, unlike [`ISOLATED` worlds of content scripts](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/ExecutionWorld). Several `USER_SCRIPT` worlds can exist when scripts are registered with `worldId`. {WebExtAPIRef("userScripts.configureWorld()")}} is used to change the configuration of a `USER_SCRIPT` world. + The default execution environment for user scripts. This environment is isolated from the page's context and other `USER_SCRIPT` worlds. Extension APIs are unavailable, unlike [`ISOLATED` worlds of content scripts](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/ExecutionWorld). Several `USER_SCRIPT` worlds can exist when scripts are registered with `worldId`. {{WebExtAPIRef("userScripts.configureWorld()")}} is used to change the configuration of a `USER_SCRIPT` world. {{WebExtExamples("h2")}} diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md index b0cc5cab835115e..0a88640bab5e879 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getscripts/index.md @@ -9,8 +9,6 @@ browser-compat: webextensions.api.userScripts.getScripts Returns user scripts registered by the extension. -This is an asynchronous method that returns a {{JSxRef("Promise")}}. - ## Syntax ```js-nolint diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md index ecb1cc96bcde1c9..5881977e71d9ccb 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/getworldconfigurations/index.md @@ -9,8 +9,6 @@ browser-compat: webextensions.api.userScripts.getWorldConfigurations Returns all the `USER_SCRIPT` world configurations registered by the extension with {{WebExtAPIRef("userScripts.configureWorld()")}}. -This is an asynchronous method that returns a {{JSxRef("Promise")}}. - ## Syntax ```js-nolint diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md index f96f334f4c9cf8e..92cbf7ab4df10a7 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/index.md @@ -25,7 +25,7 @@ To use this API, you need the `userScripts` permission and [`host_permissions`]( When a user script is registered or updated (using {{WebExtAPIRef("userScripts.register()")}} or {{WebExtAPIRef("userScripts.update()")}}), your extension can set it to run in an isolated `USER_SCRIPT` world or the `MAIN` world. -The isolated `USER_SCRIPT` world provides an execution environment that isn't accessible to a host page or other extensions. This means a user script can change its JavaScript environment without affecting the host page or other extensions' user and content scripts. In this environment, user scripts aren't visible to the host page or other extensions' user and content scripts. The API also enables an extension to configure a content security policy (CSP) for the `USER_SCRIPT` world using {{WebExtAPIRef("userScripts.configureWorld()")}}. +A `USER_SCRIPT` world provides an isolated execution environment that isn't accessible to a host page or other extensions. This means a user script can change its JavaScript environment without affecting the host page or other extensions' user and content scripts. In this environment, user scripts aren't visible to the host page or other extensions' user and content scripts. The API also enables an extension to configure a content security policy (CSP) for the `USER_SCRIPT` world using {{WebExtAPIRef("userScripts.configureWorld()")}}. In the `MAIN` world, host pages and other extensions can see and access running user scripts. @@ -33,7 +33,7 @@ These execution world values are defined in {{WebExtAPIRef("userScripts.Executio ## Messaging -Like content scripts and other extension scripts, user scripts communicate with other parts of an extension with messages using {{WebExtAPIRef("runtime.sendMessage()")}} and {{WebExtAPIRef("runtime.connect()")}}. However, user scripts receive messages using the dedicated {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}}. Dedicated handlers are used as they make it easier to identify messages from user scripts, which are a less-trusted context. +Like content scripts and other extension scripts, user scripts communicate with other parts of an extension with messages using {{WebExtAPIRef("runtime.sendMessage()")}} and {{WebExtAPIRef("runtime.connect()")}}. However, extensions receive messages using the dedicated {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}}. Dedicated handlers are used as they make it easier to identify messages from user scripts, which are a less-trusted context. To enable messaging APIs, call {{WebExtAPIRef("userScripts.configureWorld()")}} with the `messaging` argument set to `true` before registering a user script. @@ -45,7 +45,7 @@ browser.userScripts.configureWorld({ ## Extension updates -When an extension updates, user scripts are cleared. To restore scripts, add code to the extension's {{WebExtAPIRef("runtime.onInstalled")}} event handler that respond to the `"update"` reason. +When an extension updates, user scripts are cleared. To restore scripts, add code to the extension's {{WebExtAPIRef("runtime.onInstalled")}} event handler that responds to the `"update"` reason. > [!NOTE] > User scripts are unregistered when the related extension page (from which the user scripts were registered) is unloaded, so register user scripts from an extension page that persists as long as you want the user scripts to stay registered. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md index 4abd3a52b1d0c36..711565b0a3209db 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/register/index.md @@ -9,8 +9,6 @@ browser-compat: webextensions.api.userScripts.register Registers user scripts for the extension. -This is an asynchronous method that returns a {{JSxRef("Promise")}}. - ## Syntax ```js-nolint @@ -29,7 +27,7 @@ let registeredUserScript = browser.userScripts.register( ### Return value -A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are registered. If any user scripts fail to register or the request fails for another reason, none of the scripts are registered and the promise is rejected with an error message. +A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are registered. If any user scripts fail to register or the request fails for another reason, none of the scripts are registered, and the promise is rejected with an error message. ## Examples diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md index b0496fda6aaee74..7acc884ad31d8c9 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/registereduserscript/index.md @@ -24,13 +24,13 @@ Values of this type are an object containing these properties: - `excludeMatches` {{optional_inline}} - : `array` of `string`. [Match patterns](/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) for pages that the script must not be run in. - `includeGlobs` {{optional_inline}} - - : `string`. Glob patterns for the pages to run the script in. `matches` or `includeGlobs` must be specified {{WebExtAPIRef("userScripts.register()")}} calls. + - : `string`. Glob patterns for the pages to run the script in. `matches` or `includeGlobs` must be specified in {{WebExtAPIRef("userScripts.register()")}} calls. - `excludeGlobs` {{optional_inline}} - : `string`. Glob patterns for pages that the script must not be run in. - `runAt` {{optional_inline}} - - : {{WebExtAPIRef("extensionTypes.RunAt")}}. The earliest the script is injected into a tab. Defaults to "document_idle". + - : {{WebExtAPIRef("extensionTypes.RunAt")}}. The earliest the script is injected into a tab. Defaults to `"document_idle"`. - `world` {{optional_inline}} - - : {{WebExtAPIRef("userScripts.ExecutionWorld")}}. The execution environment to use to run the scripts. Defaults to "USER_SCRIPT". + - : {{WebExtAPIRef("userScripts.ExecutionWorld")}}. The execution environment to use to run the scripts. Defaults to `"USER_SCRIPT"`. - `worldId` {{optional_inline}} - : `string`. ID of a user script world the script executes in. Only valid if `world` is `USER_SCRIPT` or omitted. If `worldId` is omitted, the script is executed in the default `USER_SCRIPT` world (""). Values with leading underscores (`_`) are reserved. The maximum length is 256 characters. A world can be used by several scripts as their execution environment. To configure the behavior of a world, pass its `worldId` to {{WebExtAPIRef("userScripts.configureWorld")}} before the first script executes in that world. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md index adb9ac24ab5baba..7f329cfda9a2c95 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/resetworldconfiguration/index.md @@ -10,9 +10,6 @@ browser-compat: webextensions.api.userScripts.resetWorldConfiguration Resets the configuration of a `USER_SCRIPT` world set by {{WebExtAPIRef("userScripts.configureWorld")}} to the defaults specified in {{WebExtAPIRef("userScripts.WorldProperties")}}. When the default world is reset, all worlds without an explicit configuration are also reset. Changes to world configurations only apply to new instances of the world: A configuration won't apply to a world initialized by the execution of a user script in a document until the document is reloaded. However, the browser may revoke certain privileges when a configuration is updated. For example, message calls from a `USER_SCRIPT` world may fail when `messaging` is reset to `false`. -Changes to world configurations only apply to new instances of the world: A configuration won't apply to a world initialized by the execution of a user script in a document until the document is reloaded. However, the browser may revoke certain privileges when a configuration is updated. For example, message calls from a `USER_SCRIPT` world may fail when `messaging` is reset to `false`. - -This is an asynchronous method that returns a {{JSxRef("Promise")}}. ## Syntax diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md index 9bb326f8208961b..86ff593da45da1f 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/unregister/index.md @@ -9,8 +9,6 @@ browser-compat: webextensions.api.userScripts.unregister Unregisters user scripts registered by the extension. -This is an asynchronous method that returns a {{JSxRef("Promise")}}. - ## Syntax ```js-nolint diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md index a1ffad9ed4f9eb4..cab52a74b8213d8 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/update/index.md @@ -9,8 +9,6 @@ browser-compat: webextensions.api.userScripts.update Updates user scripts registered by the extension. -This is an asynchronous method that returns a {{JSxRef("Promise")}}. - ## Syntax ```js-nolint @@ -25,11 +23,11 @@ let updatingUserScript = browser.userScripts.update( - : `array` of {{WebExtAPIRef("userScripts.RegisteredUserScript")}}. Details of user scripts to update. - Properties that are `null` or omitted are not changed. Passing an empty array to `matches`, `excludeMatches`, `globs` and `excludeGlobs` clears these properties. + Properties that are `null` or omitted are not changed. Passing an empty array to `matches`, `excludeMatches`, `globs`, and `excludeGlobs` clears these properties. ### Return value -A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are updated. If any user scripts fail to update or the request fails for another reason, none of the scripts are updated and the promise is rejected with an error message. +A {{JSxRef("Promise")}} fulfilled with no arguments if all the requested user scripts are updated. If any user scripts fail to update or the request fails for another reason, none of the scripts are updated, and the promise is rejected with an error message. ## Examples diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md index b21c23698a3a0ef..46927cf60763339 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/userscriptfilter/index.md @@ -11,7 +11,7 @@ A list of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts ## Type -Values of this type are an object containing these properties: +Values of this type are an object containing this property: - `ids` {{optional_inline}} - : `array` of `string`. IDs of user scripts to be processed by {{WebExtAPIRef("userScripts.getScripts()")}} and {{WebExtAPIRef("userScripts.unregister()")}}. This matches scripts by the `id` field of {{WebExtAPIRef("userScripts.RegisteredUserScript","RegisteredUserScript")}}. If not specified, all user scripts are matched. diff --git a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md index 386ed6f0fd4e880..d95937f4349decf 100644 --- a/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md +++ b/files/en-us/mozilla/add-ons/webextensions/api/userscripts/worldproperties/index.md @@ -14,9 +14,9 @@ The configuration of a `USER_SCRIPT` execution environment. Used in {{WebExtAPIR Values of this type are an object containing these properties: - `worldId` {{optional_inline}} - - : `string`. The identifier for the world. Values with leading underscores (`_`) are reserved. The maximum length is 256. Defaults to the default `USER_SCRIPT` world (""). + - : `string`. The identifier for the world. Values with leading underscores (`_`) are reserved. The maximum length is 256 characters. Defaults to the default `USER_SCRIPT` world (""). - `csp` {{optional_inline}} - - : string`. The world's Content Security Policy (CSP). Defaults to the [default CSP for content scripts](/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy#csp_for_content_scripts), which prohibits dynamic code execution, such as` eval()`. + - : `string`. The world's Content Security Policy (CSP). Defaults to the [default CSP for content scripts](/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy#csp_for_content_scripts), which prohibits dynamic code execution, such as `eval()`. - `messaging` {{optional_inline}} - : `boolean`. Whether the {{WebExtAPIRef("runtime.sendMessage")}} and {{WebExtAPIRef("runtime.connect")}} methods are exposed to the user script world. Defaults to hiding these messaging APIs. The {{WebExtAPIRef("runtime.onUserScriptMessage")}} and {{WebExtAPIRef("runtime.onUserScriptConnect")}} event handlers are triggered when these methods are called.