From e37fd0510f99158159de844a14c1cfcd5db638f9 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Fri, 4 Jan 2019 16:40:05 -0500 Subject: [PATCH] Add example for access keys in menus and feature detection (#390) --- menu-accesskey-visible/README.md | 29 ++++++++ .../_locales/en/messages.json | 16 +++++ menu-accesskey-visible/background.js | 71 +++++++++++++++++++ menu-accesskey-visible/manifest.json | 21 ++++++ 4 files changed, 137 insertions(+) create mode 100644 menu-accesskey-visible/README.md create mode 100644 menu-accesskey-visible/_locales/en/messages.json create mode 100644 menu-accesskey-visible/background.js create mode 100644 menu-accesskey-visible/manifest.json diff --git a/menu-accesskey-visible/README.md b/menu-accesskey-visible/README.md new file mode 100644 index 0000000..399d0b3 --- /dev/null +++ b/menu-accesskey-visible/README.md @@ -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. diff --git a/menu-accesskey-visible/_locales/en/messages.json b/menu-accesskey-visible/_locales/en/messages.json new file mode 100644 index 0000000..dfb0db4 --- /dev/null +++ b/menu-accesskey-visible/_locales/en/messages.json @@ -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 '&&'." + } +} diff --git a/menu-accesskey-visible/background.js b/menu-accesskey-visible/background.js new file mode 100644 index 0000000..b9d8889 --- /dev/null +++ b/menu-accesskey-visible/background.js @@ -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}`); + } +}); diff --git a/menu-accesskey-visible/manifest.json b/menu-accesskey-visible/manifest.json new file mode 100644 index 0000000..c6b62d6 --- /dev/null +++ b/menu-accesskey-visible/manifest.json @@ -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" + ] +}