penkzhou
penkzhou

Reputation: 1210

How to implement Chrome extension 's chrome.tabs.sendMessage API in Firefox addon

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?

Upvotes: 3

Views: 2830

Answers (1)

Rob W
Rob W

Reputation: 348972

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);
    }
});

Upvotes: 5

Related Questions