3

I'm working on a Firefox addon development with Addon-Builder. I have no idea about how to implement Chrome extension 's chrome.tabs.sendMessage API in Firefox addon. The code is like this (the code is in the background.js, something like main.js in the Firefox addon):

function sendMessageToTabs(message, callbackFunc){
    chrome.tabs.query({}, function(tabsArray){
        for(var i=0; i<tabsArray.length; i++){
            //console.log("Tab id: "+tabsArray[i].id);
            chrome.tabs.sendMessage(tabsArray[i].id,message,callbackFunc);
        }
    });
}

So, How can I achieve this?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
penkzhou
  • 1,200
  • 13
  • 30

1 Answers1

5

In add-ons build using the Add-on SDK, content scripts are managed by main.js. There's no built-in way to access all of your add-on's content scripts. To send a message to all tabs, you need to manually keep track of the content scripts.

One-way messages are easily implemented by the existing APIs. Callbacks are not built-in, though.

My browser-action SDK library contains a module called "messaging", which implements the Chrome messaging API. In the following example, the content script and the main script use an object called "extension". This object exposes the onMessage and sendMessage methods, modelled after the Chrome extension messaging APIs.

The following example adds a content script to every page on Stack Overflow, and upon click, the titles of the tabs are logged to the console (the one opened using Ctrl + Shift + J).

lib/main.js

// https://github.com/Rob--W/browser-action-jplib/blob/master/lib/messaging.js
const { createMessageChannel, messageContentScriptFile } = require('messaging');
const { PageMod } = require('sdk/page-mod');
const { data } = require('sdk/self');
 
// Adds the message API to every page within the add-on
var ports = [];
var pagemod = PageMod({
    include: ['http://stackoverflow.com/*'],
    contentScriptWhen: 'start',
    contentScriptFile: [messageContentScriptFile, data.url('contentscript.js')],
    contentScriptOptions: {
        channelName: 'whatever you want',
        endAtPage: false
    },
    onAttach: function(worker) {
        var extension = createMessageChannel(pagemod.contentScriptOptions, worker.port);
        ports.push(extension);
        worker.on('detach', function() {
            // Remove port from list of workers when the content script is deactivated.
            var index = ports.indexOf(extension);
            if (index !== -1) ports.splice(index, 1);
        });
    }
});
function sendMessageToTabs(message, callbackFunc) {
    for (var i=0; i<ports.length; i++) {
        ports[i].sendMessage(message, callbackFunc);
    }     
}
    
// Since we've included the browser-action module, we can use it in the demo
var badge = require('browserAction').BrowserAction({
    default_title: 'Click to send a message to all tabs on Stack Overflow'
});
badge.onClicked.addListener(function() {
    sendMessageToTabs('gimme title', function(response) {
        // Use console.error to make sure that the log is visible in the console.
        console.error(response);
    });
});

For the record, the interesting part of main.js is inside the onAttach event.

data/contentscript.js

extension.onMessage.addListener(function(message, sender, sendResponse) {
    if (message === 'gimme title') {
        sendResponse(document.title);
    }
});
Community
  • 1
  • 1
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • I try to use your code.But it can't receive the msg from main.js. – penkzhou Jul 22 '13 at 11:55
  • @penkzhou Have you included my library? I've published the [browser-action](https://builder.addons.mozilla.org/package/196189/revision/12/) module in the Add-on builder, so you should be able to find it. I've tested the code before posting, so I'm sure that it works as intended. Compare the code in my answer with the code in your add-on, and see if anything is different. – Rob W Jul 22 '13 at 12:34
  • Yes.I forget the include: ['http://stackoverflow.com/*']. when I open the page in stackoverflow.com,it print the right info.Thanks. – penkzhou Jul 22 '13 at 13:18
  • Hi,Rob.Here is my understanding about your library:Everytime I open a new Tab page,the `onAttach` in the `PageMod` will be triggered and a new `worker` will be produced.So every page will be related a worker and the `extension`.The `main.js` can communicate with the `pagemod`'s contentscripts through the `extension` variable.Similarly,the `panel`'s contentscripts communicate with `main.js` through the `extension` variable.If the web page want to trigger the `panel`,it should send msg to the `main.js`,then `main.js` communicate with the `panel`.Right? – penkzhou Jul 23 '13 at 02:23
  • Exactly. Web page -> `document.defaultView.postMessage` or document.dispatchEvent` -> (content script) -> (receive message) ; `extension.sendMessage` -> (main script) -> (receive message on `extension.onMessage` -> ... to panel. – Rob W Jul 23 '13 at 08:27
  • Ok.How about `chrome.extension.sendMessage`? Can it be replaced with `extension` in your library? – penkzhou Jul 23 '13 at 08:32
  • 1
    @penkzhou `extension.sendMessage`? Where (content script/page/main script/panel)? – Rob W Jul 23 '13 at 08:45
  • So in the chrome extension,the contentscript is executed in every page, it doesn't need to have a specific variable to communicate for each tab, it just use `chrome.tabs.sendMessage` to communicate with specific tab? – penkzhou Jul 23 '13 at 08:50
  • Sorry.The `chrome.extension.sendMessage` is in the main.js. – penkzhou Jul 23 '13 at 08:51
  • forget to tell you the `chrome.extension.sendMessage` is in the main.js. – penkzhou Jul 23 '13 at 14:21
  • @penkzhou Panels in Firefox add-ons are more like normal pages in Chrome extensions. If you want to send a message to the panel, use the page-mod/page-worker APIs, or apply my answer to the panel to get the `extension.sendMessage/onMessage` API. – Rob W Jul 23 '13 at 14:48
  • You mean the extension. sendMessage api send msg to the normal page, something like popup page or panel? – penkzhou Jul 23 '13 at 14:53
  • @penkzhou Sorry, I didn't understand your last comment. – Rob W Jul 23 '13 at 14:57
  • I want to ask you can I use your library to implement the `chrome.extension.sendMessage` in the main.js. In your [comment](http://stackoverflow.com/questions/17778772/how-to-implement-chrome-extension-s-chrome-tabs-sendmessage-api-in-firefox-addo#comment25993161_17783378) I can't get the point. – penkzhou Jul 23 '13 at 15:19
  • @penkzhou [Panels](https://addons.mozilla.org/en-US/developers/docs/sdk/Firefox-22/modules/sdk/panel.html) implement content scripts, so yes. – Rob W Jul 23 '13 at 15:21
  • Ok,so the `chrome.extension.sendMessage` send msg to panel's contentscript? – penkzhou Jul 23 '13 at 15:25
  • @penkzhou No, `extension.sendMessage` will send the message, and the `extension` object is obtained in the same way as in my answer. – Rob W Jul 23 '13 at 15:25