mirror of
https://github.com/mdn/webextensions-examples.git
synced 2026-04-16 06:18:35 +02:00
Add example for access keys in menus and feature detection (#390)
This commit is contained in:
29
menu-accesskey-visible/README.md
Normal file
29
menu-accesskey-visible/README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# menu-accesskey-visible
|
||||||
|
|
||||||
|
Demonstrates access keys in the [menus API](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/menus/).
|
||||||
|
|
||||||
|
**This add-on uses the `menus` namespace to access the functions it needs to create menu items. Note that Chrome, Edge, and Opera all use the `contextMenus` namespace for this, so this extension will not work in these browsers. For compatibility with these browsers, Firefox also offers the `contextMenus` namespace, so to make this extension work with other browsers, use `contextMenus`.**
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
This extension adds a menu item that has an access key.
|
||||||
|
An access key allows users to activate the menu item with one keystroke.
|
||||||
|
On Linux and Windows, the chosen access key is underlined.
|
||||||
|
On macOS, access keys are supported too, but without visual indicators.
|
||||||
|
|
||||||
|
When an access key is shared by multiple menu items, pressing the key
|
||||||
|
will switch between the menu items that share the access key. Otherwise
|
||||||
|
(if an access key is bound to one menu item only), the menu item is clicked.
|
||||||
|
|
||||||
|
The menu item in this demo logs a message to the extension's console upon
|
||||||
|
click. This console can be shown via the "Debug" button at `about:debugging` .
|
||||||
|
|
||||||
|
## What it shows
|
||||||
|
|
||||||
|
* Specifying access keys via `&` in the menu item title.
|
||||||
|
* Detecting feature support, exemplified by detecting support for the `visible`
|
||||||
|
property of the `menus.update` API that was also introduced in Firefox 63.
|
||||||
|
|
||||||
|
As access keys are only supported in Firefox 63 and later, this example also
|
||||||
|
shows how one can detect the feature support in the browser and fall back to
|
||||||
|
menu items without access keys if needed.
|
||||||
16
menu-accesskey-visible/_locales/en/messages.json
Normal file
16
menu-accesskey-visible/_locales/en/messages.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"extensionName": {
|
||||||
|
"message": "Menu item with access key",
|
||||||
|
"description": "Name of the extension."
|
||||||
|
},
|
||||||
|
|
||||||
|
"extensionDescription": {
|
||||||
|
"message": "Demonstrates access keys in context menu items (if supported).",
|
||||||
|
"description": "Description of the add-on."
|
||||||
|
},
|
||||||
|
|
||||||
|
"menuItemWithAccessKey": {
|
||||||
|
"message": "Click &here && look at the extension's console",
|
||||||
|
"description": "Title of context menu item that logs a message on click. The letter after the first '&' is used as an access key. To show a single '&' in the menu, use '&&'."
|
||||||
|
}
|
||||||
|
}
|
||||||
71
menu-accesskey-visible/background.js
Normal file
71
menu-accesskey-visible/background.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs feature detection, to detect whether access keys are supported.
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
* Whether access keys are supported in extension menu item labels.
|
||||||
|
*/
|
||||||
|
function detectAccessKeyMenuFeature() {
|
||||||
|
// Access keys are supported since Firefox 63:
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/63#Menus
|
||||||
|
//
|
||||||
|
// Before Firefox 63, any '&' in the menu label would appear literally. There
|
||||||
|
// is no direct way to detect whether access keys are supported, so we will
|
||||||
|
// indirectly detect support, via another feature that shipped in the same
|
||||||
|
// release: the 'visible' property in the menus API, as shown below.
|
||||||
|
|
||||||
|
// API parameters in the WebExtensions API are often validated immediately.
|
||||||
|
// If validation fails, an error is thrown.
|
||||||
|
// We can take advantage of this behavior to detect feature support:
|
||||||
|
// If a property is not supported, an error is thrown.
|
||||||
|
try {
|
||||||
|
// If the feature is supported, then the API will be invoked. Pass an unused
|
||||||
|
// menu item ID to make sure that we do not modify existing menu items.
|
||||||
|
browser.menus.update("Some ID that is not used by any existing menu item", {
|
||||||
|
visible: true,
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Side note: In Firefox 63, the menus.getTargetElement API was introduced.
|
||||||
|
// So the above try-catch could also have been replaced with this:
|
||||||
|
//
|
||||||
|
// return !!browser.menus.getTargetElement;
|
||||||
|
//
|
||||||
|
// The example uses try-catch anyway to demonstrate feature detection based
|
||||||
|
// on parameter properties.
|
||||||
|
}
|
||||||
|
|
||||||
|
var IS_ACCESS_KEY_SUPPORTED = detectAccessKeyMenuFeature();
|
||||||
|
|
||||||
|
function formatMenuLabel(menuLabel) {
|
||||||
|
if (!IS_ACCESS_KEY_SUPPORTED) {
|
||||||
|
// Access keys not supported (e.g. Firefox 62 and older).
|
||||||
|
// Remove ampersands to prevent them from showing up literally.
|
||||||
|
menuLabel = menuLabel.replace(/&(&?)/g, "$1");
|
||||||
|
}
|
||||||
|
return menuLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "menuItemWithAccessKey" message is defined in _locales/en/messages.json
|
||||||
|
// and contains a '&' to specify an access key.
|
||||||
|
// To support Firefox 62 an earlier (where access keys were not recognized),
|
||||||
|
// the example below uses formatMenuLabel to post-process the message if
|
||||||
|
// access keys are not supported.
|
||||||
|
//
|
||||||
|
// If you are not interested in supporting Firefox 62 and earlier, remove all
|
||||||
|
// of the above code, and remove "formatMenuLabel(" and ")" below.
|
||||||
|
|
||||||
|
browser.menus.create({
|
||||||
|
id: "menu_item_with_access_key",
|
||||||
|
title: formatMenuLabel(browser.i18n.getMessage("menuItemWithAccessKey")),
|
||||||
|
contexts: ["page"]
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.menus.onClicked.addListener((info, tab) => {
|
||||||
|
if (info.menuItemId === "menu_item_with_access_key") {
|
||||||
|
console.log(`Clicked at ${info.pageUrl} in tab at index ${tab.index}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
21
menu-accesskey-visible/manifest.json
Normal file
21
menu-accesskey-visible/manifest.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "__MSG_extensionName__",
|
||||||
|
"description": "__MSG_extensionDescription__",
|
||||||
|
"version": "1.0",
|
||||||
|
"default_locale": "en",
|
||||||
|
"applications": {
|
||||||
|
"gecko": {
|
||||||
|
"strict_min_version": "56.0a1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"background": {
|
||||||
|
"scripts": ["background.js"]
|
||||||
|
},
|
||||||
|
|
||||||
|
"permissions": [
|
||||||
|
"menus"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user