Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't chrome.tabs.query() return the tab's URL when called using RequireJS in a Chrome extension?

I have a simple Chrome extension that adds a browser action. When the extension's popup is opened, it needs to access the current tab's URL. Since it doesn't need access to all the tabs, I just have the activeTab permission specified in the manifest:

{
    "manifest_version": 2,
    "name": "RequireJS Test",
    "version": "0.0.1",
    "description": "Test RequireJS and the activeTab permission.",
    "permissions": [
        "activeTab"
    ],
    "browser_action": {
        "default_popup": "popup.html"
    },
    "web_accessible_resources": [
        "js/*",
        "html/*",
        "css/*",
        "img/*"
    ]
}

In theory, that should give the popup access to the active tab's URL, but the URL is not returned when I query the tabs from within a require() call in the popup's main.js file:

require([], function() {
    chrome.tabs.query({"active": true, "lastFocusedWindow": true}, function (tabs) {
        var url = tabs[0].url;
        console.log("URL from main.js", url);
    });

    console.log("URL from global var accessed in main.js", tabURL);
});

The console shows undefined for the URL. However, if I make the same call from a plain .js file that doesn't use require(), it works fine:

chrome.tabs.query({"active": true, "lastFocusedWindow": true}, function (tabs) {
    tabURL = tabs[0].url;
    console.log("URL from get-url.js", tabURL);
});

That displays the correct URL, and I can access that global tabURL inside the require() call just fine. When I right-click the browser button and inspect the popup, the console output looks like this:

URL from get-url.js http://stackoverflow.com/questions/ask
URL from global var accessed in main.js http://stackoverflow.com/questions/ask
URL from main.js undefined

Even stranger is that I've sometimes seen the URL available from within that call to chrome.tabs.query() inside the require() call. But mostly it doesn't work. Something about how RequireJS loads scripts seems to confuse Chrome and take away the URL access for the loaded script. This is in Chrome 40 on Windows.

Obviously, the workaround is to grab the URL in a separate script and store it in a variable, but that feels a bit kludgy. I'd like to see if there's a proper way of getting this to work with RequireJS.

The full plugin source is here if anyone wants to test it on their machine: https://github.com/fwextensions/requirejs-url-test


Edit

As Rob W. explains below, this actually has nothing to do with RequireJS. The only reason that the code in my get-url.js file above returned the correct URL was that it happened to run before the devtools window opened. If I change that file to this:

setTimeout(function() {
chrome.tabs.query({"active": true, "lastFocusedWindow": true}, function (tabs) {
    tabURL = tabs[0].url;
    console.log("URL from get-url.js", tabURL);
});
}, 5000);

Then it runs after the devtools window is open and fails as well. RequireJS isn't the culprit.

like image 592
jdunning Avatar asked Feb 28 '15 20:02

jdunning


People also ask

How do I get the URL of a new tab in Chrome?

code.google.com/chrome/extensions/tabs.html#method-getSelected The docs state the first parameter is the windowId, if you want to use that in options, or background page, you would need to put in the window id or you will get the current tab your viewing which is undefined, options respectively.

How do I find a URL extension?

It's as simple as Right Click > getURL. Open up the Extension popup window and you will be greeted with the parameters in a nicely formatted table.

How do I know how many tabs I have open?

Just simply, enable Talkback mode in accessibility features. Then when you hover (if you have Bluetooth mouse enabled) or tap the tab icon (with your finger) (the :D), it will tell you how many tabs you have open.


2 Answers

You don't see a URL because you've only set the activeTab permission (not the tabs) permission AND the last focused window is the developer tools (for which you don't have activeTab access) (and since Chrome 41, devtools tabs/windows are invisible to extensions, so tabs will be an empty array).

The good news is that this problem is specific to the devtools window being opened for your extension page, so the issue only occurs during development and not during actual use by users.

Extension popups are associated with a window, so you can use chrome.tabs.query with currentWindow:true to get the correct answer:

chrome.tabs.query({
    active: true,
    currentWindow: true
}, function(tabs) {
    var tabURL = tabs[0].url;
    console.log(tabURL);
});
like image 67
Rob W Avatar answered Sep 21 '22 20:09

Rob W


To overcome the devTools bug that Rob W. reported in his post, the following getActiveTab workaround seems to consistently work for me (even when there are multiple devTools windows open). It works by always saving a reference to the activeTabId in the background page, whenever the tabs.onActivated event fires.

var activeTabId;

chrome.tabs.onActivated.addListener(function(activeInfo) {
  activeTabId = activeInfo.tabId;
});

function getActiveTab(callback) {
  chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
    var tab = tabs[0];

    if (tab) {
      callback(tab);
    } else {
      chrome.tabs.get(activeTabId, function (tab) {
        if (tab) {
          callback(tab);
        } else {
          console.log('No active tab identified.');
        }
      });

    }
  });
}
like image 22
jake Avatar answered Sep 18 '22 20:09

jake