问题
I have a Chrome extension that adds a browser button. The browser button has 1 custom contextmenu item, either "Disable for DOMAIN" or "Re-enable for DOMAIN". That's 2 variables depending on the active tab: enabled/disabled and its domain name.
I use chrome.tabs.onUpdated to track new tabs and chrome.tabs.onActivated to track tab switches. When either happens, I update the label according to those 2 variables. E.g. "Re-enable for twitter.com" or "Disable for google.com".
The problem occurs when you have more than 1 window:
- Open new tab in window 1. Label is now "Disable for foo.com"
- Open link in that tab in new window (2). Window 2's label is now "Disable for bar.com".
- BUT window 1's label has changed to that too!
- Switch back to window 1 (still on foo.com) (this doesn't trigger ANY tab event). Label is "Disable for bar.com" < WRONG
Another scenario is opening devtools, which changes all DOMAIN to devtools in all labels in all windows.
How do I differentiate between windows? There is 1 browser action PER window, but there's only 1 contextmenu label to change (which changes them all). There's no way too know which window is active/which window's browseraction I'm clicking. There's no tab event for switching windows, so I can't change the label then.
I was checking out AdBlock's code, but it has the same bug: if you open a new window where AdBlock is disabled, it removes contextmenu items on all windows and doesn't put them back until you switch tabs (onActivated).
Tabs events code, if it helps:
chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
console.log('onUpdated', tabId, info, tab);
if ( info.status && tab.active ) {
updateLabelStatus(tab);
}
});
chrome.tabs.onActivated.addListener(function(info) {
console.log('onActivated', info);
chrome.tabs.get(info.tabId, function(tab) {
updateLabelStatus(tab);
});
});
function updateLabelStatus(tab) {
var host = rweb.host(tab.url);
chrome.storage.local.get('disabled', function(items) {
var disabled = items.disabled || {};
updateLabel(host in disabled, host, tab.id);
});
}
function updateLabel(disabled, host, tabId) {
// Update label
var newLabel = labels[ Number(disabled) ].replace('DOMAIN', host);
// >> THIS IS WHERE I MIGHT WANT TO SPECIFY A WINDOW <<
chrome.contextMenus.update(browserActionMenuItemId, {"title": newLabel});
}
Related Chromium bug: https://code.google.com/p/chromium/issues/detail?id=469417
回答1:
Oh, of course there's an API for that: chrome.windows. Stupid.
This baby fixed it:
chrome.windows.onFocusChanged.addListener(function(windowId) {
chrome.windows.get(windowId, {"populate": true}, function(window) {
var e = chrome.runtime.lastError; // Stut up, Chrome
if ( !window ) return;
console.log('onFocusChanged', windowId, window);
for ( var i=window.tabs.length-1; i>=0; i-- ) {
var tab = window.tabs[i];
if ( tab.active ) {
updateLabelStatus(tab);
break;
}
};
});
});
Also important: in updateLabel() I did a few chrome.browserAction.setBadgeBackgroundColor without specifying tabId, but without it, it'll change the bgcolor for all windows' open tabs.
Well, that was no fun debugging for 3 hours. (2.5 of which I didn't know about chrome.windows, damnit!)
回答2:
a simpler solution can be to pass a tabId when calling browserActions (setBadgeText, setBadgeBackgroundColor, setIcon, etc), as suggested by the documentation.
example
来源:https://stackoverflow.com/questions/29184242/set-browser-action-contextmenu-label-for-specific-window