Set browser action contextmenu label for specific window

人走茶凉 提交于 2019-12-12 02:26:51

问题


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:

  1. Open new tab in window 1. Label is now "Disable for foo.com"
  2. 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!
  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!