A G Chrome extension can have a \'browser action\'. Usually the ext developer displays the options when you click on it, meaning every action requires 2 clicks, even the def
It is not possible to add any custom entries to the context menu.
You can, however, dynamically assign a panel to the button with chrome.browserAction.setPopup. You can use an options page to allow the user to choose their preferred option (single-click action, or two-clicks & multiple actions). The fact that the options page is just two clicks away from the button is also quite nice.
Here's sample code to illustrate the concept of toggling between panel and single-click.
background.js
(used in your event / background page):
chrome.browserAction.onClicked.addListener(function() {
// Only called when there's no popup.
alert('Next time you will see a popup again.');
chrome.browserAction.setPopup({
popup: 'popup.html'
});
});
popup.html
, just for the demo (use CSS to make it look better):
<button>Click</button>
<script src="popup.js"></script>
popup.js
, just for the demo. JavaScript has to be placed in a separate file because of the CSP.
document.querySelector('button').onclick = function() {
chrome.browserAction.setPopup({
popup: '' // Empty string = no popup
});
alert('Next time, you will not see the popup.');
// Close panel
window.close();
};
As you can see in this example, the chrome.browserAction.setPopup is also available in a popup page.
PS. manifest.json
, so you can copy-paste the example and play with this answer.
{
"name": "Test badge - minimal example",
"version": "1",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_title": "Some tooltip"
}
}
Example (almost patttern) It also provides a workaround for using a simple onclick listeners (here short property “act”), for now if you use the “Event page” you can not use native onclick
const menuA = [
{ id: 'ItemF', act: (info, tab) => { console.log('Clicked ItemF', info, tab, info.menuItemId); alert('Clicked ItemF') } },
{ id: 'ItemG', act: (info, tab) => { console.log('Clicked ItemG', info, tab, info.menuItemId); alert('Clicked ItemG') } },
{ id: 'ItemH', act: (info, tab) => { console.log('Clicked ItemH', info, tab, info.menuItemId); alert('Clicked ItemH') } },
{ id: 'ItemI', act: (info, tab) => { console.log('Clicked ItemI', info, tab, info.menuItemId); alert('Clicked ItemI') } },
];
const menuB = [
{ id: 'ItemJ', act: (info, tab) => { console.log('Clicked ItemJ', info, tab, info.menuItemId); alert('Clicked ItemJ') } },
{ id: 'ItemK', act: (info, tab) => { console.log('Clicked ItemK', info, tab, info.menuItemId); alert('Clicked ItemK') } },
{ id: 'ItemL', act: (info, tab) => { console.log('Clicked ItemL', info, tab, info.menuItemId); alert('Clicked ItemL') } },
{ id: 'ItemM', act: (info, tab) => { console.log('Clicked ItemM', info, tab, info.menuItemId); alert('Clicked ItemM') } },
];
const rootMenu = [
//
// In real practice you must read chrome.contextMenus.ACTION_MENU_TOP_LEVEL_LIMIT
//
{ id: 'ItemA', act: (info, tab) => { console.log('Clicked ItemA', info, tab, info.menuItemId); alert('Clicked ItemA') }, menu: menuA },
{ id: 'ItemB', act: (info, tab) => { console.log('Clicked ItemB', info, tab, info.menuItemId); alert('Clicked ItemB') }, menu: menuB },
{ id: 'ItemC', act: (info, tab) => { console.log('Clicked ItemC', info, tab, info.menuItemId); alert('Clicked ItemC') } },
{ id: 'ItemD', act: (info, tab) => { console.log('Clicked ItemD', info, tab, info.menuItemId); alert('Clicked ItemD') } },
{ id: 'ItemE', act: (info, tab) => { console.log('Clicked ItemE', info, tab, info.menuItemId); alert('Clicked ItemE') } },
];
const listeners = {};
const contexts = ['browser_action'];
const addMenu = (menu, root = null) => {
for (let item of menu) {
let {id, menu, act} = item;
chrome.contextMenus.create({
id: id,
title: chrome.i18n.getMessage(id),
contexts: contexts,
parentId: root
});
if (act) {
listeners[id] = act;
}
if (menu) {
addMenu(menu, id);
}
}
};
addMenu(rootMenu);
chrome.contextMenus.onClicked.addListener((info, tab) => {
console.log('Activate „chrome.contextMenus -> onClicked Listener“', info, tab);
listeners[info.menuItemId] (info, tab);
});
See some example of «chrome extension tree context menu pattern»
It is now possible, AdBlock chrome extensions has it. Below is working example of "context menu in browser action".
manifest.json:
{
"name": "Custom context menu in browser action",
"version": "1",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_title": "Some tooltip",
"default_popup": "popup.html"
},
"permissions": [
"contextMenus"
],
"icons": {
"16": "icon16.png"
}
}
background.js:
chrome.contextMenus.removeAll();
chrome.contextMenus.create({
title: "first",
contexts: ["browser_action"],
onclick: function() {
alert('first');
}
});
Note that if you use an Event page, you cannot use the onclick
attribute; you'll need to add a listener to chrome.contextMenus.onClicked
instead.