Thiago Moraes
Thiago Moraes

Reputation: 617

Update Panel content after a click on a widget of a Firefox add-on

My add-on needs to make two things:

  1. When I click on a Widget, some contentScript executes and some data is returned to the add-on
  2. This data should be shown in the Panel attached to the Widget.
  3. If I click again, data must be updated and Panel content as well.

Here's what I have on Mozilla's sdk 1.15.

The "from widget" message is printed as expected, but the "from panel" one is not.

I have two questions:

  1. If I want to show foo in my Panel, is this the correct way to do it? How do I update the panel with the info passed from the content script?
  2. Why does my postMessage doesnt receive the message my Widget has sent?

    var widgets = require('sdk/widget');
    var tabs = require('sdk/tabs');
    var self = require('sdk/self');
    var data = require('sdk/self').data;
    
    var requestsPanel = require('sdk/panel').Panel({
        width:215,
        height:160,
        contentURL: data.url('requests.html'), //this is just dummy data
    });
    
    // try to receive data DOESN'T WORK
    requestsPanel.on('message', function (foo) {
        console.log('from panel', foo);
    });
    
    var widget = widgets.Widget({
        id: 'div-show',
        label: 'Show requests',
        contentURL: data.url('favicon.ico'),
        panel: requestsPanel,
        onClick: function() {
            worker = tabs.activeTab.attach({
                contentScript: "self.port.on('getData', function () {"+
                                    "var foo = [1,2,3];"+
                                    "self.port.emit('sendData', foo);"+
                                "});"
            });
            // request to check for generated requests
            worker.port.emit('getData');
    
            // check the return from generated requests
            worker.port.on('sendData', function (foo){
                console.log('from widget', foo);
                requestsPanel.postMessage(foo);
            });
        }
    });
    

Upvotes: 0

Views: 696

Answers (1)

ZER0
ZER0

Reputation: 25322

The Panel's postMessage send a message to the contentScript of the panel. You do not have any content script in this code for the panel: as you said, requests.html is just dummy data. What you have to do, is remove the requestsPanel.on('message') from your code, and put the listener in the document loaded by the panel.

To be clear, your requests.html will looks like:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>It's my panel</title>
        <script>
          addon.on('message', function(data){
            console.log(data)
          })
        </script>
        </head>
    <body>
    </body>
</html>

In this way you can easily update any DOM element of the document itself once you get data. Notice that I used the object addon. As you can read from the documentation linked above, for "trusted content" (document that comes with your add-on, so from data folder), you don't need to add a content script, but you can use the document's script itself, and having the object addon to exchange messages. The addon object behaves like the self in the content script.

I would also suggest you to use contentScriptFile in your widget, instead of contentScript, especially if you want to submit to addons.mozilla.org. And you should declare worker, otherwise will be a undeclared global variable – it's better nowadays having "use strict" at the beginning of our JS file, in order to have strict mode too.

Remember also that as soon as you write code for Firefox's add-on, you can take advantages of all the ES6 features are already implemented in the browser, like destructuring assignment, let, const, arrows functions, and so on.

So, for instance, instead of:

var self = require('sdk/self'); // this is useless also in the current code
var data = require('sdk/self').data;

You can have:

const { data } = require('sdk/self');

And instead of:

   worker.port.on('sendData', function (foo){
        console.log('from widget', foo);
        requestsPanel.postMessage(foo);
    });

You could have:

   worker.port.on('sendData', foo => {
        console.log('from widget', foo);
        requestsPanel.postMessage(foo);
    });

And if you remove the log, it will be simply:

   worker.port.on('sendData', foo => requestsPanel.postMessage(foo));

Hope it helps!

Upvotes: 2

Related Questions