Andrew Regan
Andrew Regan

Reputation: 5113

Content-script events sent by functions/callbacks not received by Add-on script

I'm using a context-menu item click to show a dialog (using JQuery/Bootstrap) that lets users submit the text they selected to a web service via AJAX (this all works perfectly). Once submitted, I intend to display an Add-on SDK notification to say 'Thanks for your submission'.

Now, I know I need to send a message from the content script to the Add-on script to show the notification, but my message doesn't arrive when sent from a callback function.

My add-on code (extract):

var pageMod = require("page-mod");
pageMod.PageMod({
  include: ['*'],
  contentScriptWhen: "end",
  contentScriptFile: [ data.url("js/content.js") ],

  onAttach: function onAttach( worker, mod) {
    worker.port.on("submittedNotif", function(msg) {
        console.log('Hello');
        notifications.notify({ ... });
    })
  }
});

Content-script follows. I've indicated the situations where the message arrived, and where it doesn't.

// Handle the context-menu Item's click and show the dialog

self.on("click", function(node,data) {
    self.port.emit("submittedNotif", '*** DOES NOT ARRIVE ***');
    showDialog( 'DialogName', function (response) { /* Do stuff */ });
})

self.port.emit("submittedNotif", '*** Arrives OK ***');

function showDialog( str, response) {
    // Dialog stuff
    self.port.emit("submittedNotif", '*** DOES NOT ARRIVE ***');
}

I'm told self is a global object, so I shouldn't have to pass it as a parameter, surely. It's just not clear to me how trying to send via self.port.emit should work differently depending on where it's used within the content script. I'm not aware of any threading issue, for example. Perhaps this is a gap in my JavaScript knowledge, but can anyone tell me what I'm doing wrong?

Upvotes: 0

Views: 914

Answers (2)

Andrew Regan
Andrew Regan

Reputation: 5113

I solved my own problem. Here's how, and what I learned.

Firstly, the content-script, and the context-menu Item's click handler:

self.on("click", function(node,data) {
    self.postMessage({ kind:'submittedNotif', msg: 'Just clicked'})
    showDialog( self, 'DialogName', function (response) { /* Do stuff */ });
})

Now, the old self.port.emit got me nowhere, but switching to self.postMessage and adding an onMessage() to the context-menu Item finally gives me the event I want.

I now also pass self to the showDialog() method [which goes against what I was told about self being global...?!], as the parameter 'eventHandler':

function showDialog( eventHandler, str, response) {
    // Dialog stuff
    eventHandler.postMessage({ kind:'submittedNotif', msg: 'Thank you for your submission'});
}

Again, I drop the self.port.emit, switching to self.postMessage, and calling that on the handler that was passed-in.

And finally, the notifications.notify({ ... }); call gets moved from the PageMod's onAttach() to the menu Item's onMessage(). In short, everything that happens in response to that click now happens within the scope of the menu item.

All works now. Perhaps this all seems obvious in retrospect - but the documentation definitely confused rather than clarified, especially the difference between port and postMessage()

Upvotes: 0

therealjeffg
therealjeffg

Reputation: 5830

It isn't clear to me where the click event would come from in

self.on('click')

What you need to do instead is bind a click handler to something in the page's DOM that would get clicked, eg your dialog tha you mention. Check out this fairly simple builder example that does this by by emitting an event when a confirm dialog is shown:

https://builder.addons.mozilla.org/addon/1049875/latest/

main.js:

var data = require("self").data;
var notifications = require("notifications");
var pageMod = require("page-mod");
pageMod.PageMod({
  include: ['*'],
  contentScriptWhen: "end",
  contentScriptFile: [ data.url("jquery.js"), data.url("content.js") ],

  onAttach: function onAttach( worker, mod) {
    worker.port.on("submittedNotif", function(msg) {
        notifications.notify({
            title: 'Notification!',
            text: 'This is the notification: '+ msg
        });
    })
  }
});

content.js:

$(function() {
    if(confirm("send submitted event?")) {
        self.port.emit("submittedNotif", '*** DOES NOT ARRIVE ***');
        showDialog( 'DialogName', function (response) { /* Do stuff */ });
    }
});


//self.port.emit("submittedNotif", '*** Arrives OK ***');

function showDialog( str, response) {
    // Dialog stuff
    self.port.emit("submittedNotif", '*** DOES NOT ARRIVE ***');
}

Upvotes: 1

Related Questions