Extensions Context Menu API Proposal
NOTE: This document is now out of date. The API evolved some while behind the experimental flag, and is becoming fully supported in chrome 6. For details on the current implementation you can see
Status
Being implemented behind the --enable-experimental-extension-apis flag so we can collect developer feedback. Should be landing in the tree relatively soon.
Provide a way for extensions to add items to the context (aka "right click") menu for web pages.
Use cases
Many features that extensions want to expose are only applicable to certain kinds of content. Some examples include saving selected text or link urls to a extension-local or web based notepad, removing particular images from a page, filling in form fields, and looking up words in an online dictionary.
Could this API be part of the web platform?
Probably not, since many actions people would like to add are logically "browser-level" functionality.
Do you expect this API to be fairly stable?
Yes, once we get some experience with an experimental version.
What UI does this API expose?
New menu items & submenus in context menus.
How could this API be abused?
Someone could create menu items with innocuous-sounding or misleading names (or even duplicates of built-in menu items) to trick users to click on them.
How would you implement your desired features if this API didn't exist?
You could (and perhaps some extensions do?) inject script into all pages to intercept onmousedown and create your own custom html menu implementation. But that is a terrible user experience since it prevents the browser-native menu from appearing.
Draft API spec
Initially these functions will only be callable from an extension's background page. This will likely not be sufficient, since a frequent use case for context menus is to operate on the specific link/image/etc. that the menu was activated on. See the "Future Improvements" section below for ideas about this.
Note: because this will be initially available as an experiment, the API methods will at first be chrome.experimental.contextMenu.methodname
chrome.contextMenu.create(object properties, function onCreatedCallback);
Defaults to PAGE, which means "none of the rest" are selected (no link, no image, etc.). If 'ALL' is in the array, the item will appear in all contexts regardless of the rest of the items in the array.
The tab parameter is the tab where the click happened, of the same form as that returned by chrome.tabs.get.
chrome.contextMenu.remove(id);
Examples
Define the currently selected word(s)
The following code would live in your background page, and you would need to have "tabs" specified in the permissions section of your manifest.
function getDefinition(info, tab) {
if (!info.selectionText || info.selectionText.length == 0) {
return;
}
var maxLength = 1024;
var searchText = (info.selectionText.length <= maxLength) ?
info.selectionText : info.selectionText.substr(0, maxLength);
var url = "http://www.google.com/search?q=define:" + escape(searchText);
chrome.tabs.create({"url": url});
}
chrome.contextMenu.create({"title": "Define '%s'", "onclick": getDefinition,
"contexts":["SELECTION"]});
Remove an image from a page
The following code would live in your background page, and you would need to have an entry in the permissions section of your manifest which allowed you to run chrome.tabs.executeScript on the page where the image had its context menu activated. This example highlights one of the limitations of the initial proposal, which is that you don't have any way to determine the actual unique node that was clicked on, so it removes any instances of the image from the page.
chrome.contextMenu.create({"title": "Remove This Image", "contexts": ["IMAGE"],
"onclick": function(info, tab) {
var frameUrl = info.frameUrl ? info.frameUrl : "";
var code =
"var imgs = document.getElementsByTagName('img');" +
"var srcUrl = unescape('" + escape(info.srcUrl) + "');" +
"for (var i in imgs) {" +
" var img = imgs[i];" +
" if (img.src == srcUrl) {" +
" img.parentNode.removeChild(img);" +
" }" +
"}";
chrome.tabs.executeScript(tab.id, {"allFrames": true, "code": code});
}});
UI Design
-Extension items appear towards the bottom of the context menu, above "Inspect element", sorted by extension name.
-We will show at most one top-level menu item per extension. If an extension adds more than 1 item, we automatically push the items into a submenu, with the extension name as the top-level item.
-The extension's icon will appear to the left of the top-level item to help the user understand which extension added what items, and help to mitigate the spoofing concerns raised above.
Future Improvements
- Provide a mechanism for getting a handle to the precise node in the DOM where the menu was activated. This could mean one of the following ideas:
- Add a removeAll() method so you don't have to keep track of id's if you don't want to.
-Add a way to limit your menu items to specific tabs or frame urls (by a given match pattern, or perhaps automatically limit to only sites you have content script permissions for)
-Some people have asked for a onBeforeShow() event to fire before the menu items are displayed, but this may be infeasible given chrome's multiprocess architecture and desire to keep the UI very responsive.
|