6

I have a content script which times how long a user views a page. To do this, I inject a content script into each page, start a timer and then emit a message back to the add-on when the onbeforeunload event is triggered.

The message never seems to get passed to the background script however.

Given that my main.js looks like this:

var pageMod = require('page-mod'),
    self = require("self");

pageMod.PageMod({
  include: "http://*",
  contentScriptFile: [self.data.url('jquery.min.js'),
                      self.data.url('content.js')],
  onAttach: function(worker) {
    worker.port.on('pageView', function(request) {
      console.log("Request received");
    });
  }
});

I can send a message to main.js using the following code no problem.

self.port.emit('pageView', { visitTime: time });

I run into a problem when I try to do it as the user leaves the page however. The message is never received when I do it like this:

$(window).bind('onbeforeunload', function(e) {
  self.port.emit('pageView', { visitTime: time });
  // This should prevent the user from seeing a dialog.
  return undefined;
});

I've tried listening for beforeunload too, that doesn't work either. What could be the problem?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
David Tuite
  • 22,258
  • 25
  • 106
  • 176
  • Are you binding the `onbeforeunload` after the document ready? Secondly, did you try to attach the event directly? `window.onbeforeunload = function(e) { self.port.emit('pageView', { visitTime: time }); // This should prevent the user from seeing a dialog. return undefined; };` In jsfiddle binding the `onbeforeunload` with jQuery does not work, the direct way does work – bart s Aug 27 '12 at 12:12
  • I'm pretty sure I did try the direct way (made the question a few days ago) but I'll try again and get back to you. Binding is happening after jQuery ready so that should be ok. – David Tuite Aug 27 '12 at 14:34
  • [try this fiddle](http://jsfiddle.net/CD6DV/1/) and put the jquery and javascript in different order. If I put a `onbeforeunload` in jquery I see 100% handling by javascript and no handling by jQuery. If `beforeunload` is used in jQuery I see intermittent behaviour. Therefore I thinkg javascript is the most stable one. Another thing that you may bounce into: Not all code seems to be executed. Try to add `alert("something");` in the code and you will not see it being executed. If you replace the `return undefined` with a string, at least you should see a dialog to confirm leaving the page – bart s Aug 27 '12 at 16:41
  • Ok played around with this a little bit more. I can replicate all the behavior you mention there in the fiddle but it just doesn't seem to work like that in a FF add-on. As far as I can tell, the `self.port.emit` function is not being executed in the unload function body, just like calls to `alert()` are not executed. – David Tuite Aug 28 '12 at 09:25
  • Indeed there may be problems executing stuff in the eventhandler. As last effort you can try to put your code into a time-out `setTimeout(function() { },0);` use 0 or 1 as the time. – bart s Aug 28 '12 at 10:14

2 Answers2

3

The window object that content scripts access in Firefox browser add-ons is a proxy object and can be a little temperamental. Using window.addEventListener will work.

window.addEventListener('beforeunload', function(e) {
  # Do stuff then return undefined so no dialog pops up.
  return undefined
});
David Tuite
  • 22,258
  • 25
  • 106
  • 176
1

The onbeforeUnload event is not synchronous, so the browser garbage collects the page before it is finished. Use a synchronous AJAX request:

function Data() 
 {
 var client = new XMLHttpRequest();
 client.open("GET", "/request", false); // third paramater indicates sync xhr
 client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
 client.send({ visitTime: time });
 client.onreadystatechange = emitter;
 }

function emitter()
 {
 self.port.emit('pageView', { visitTime: time });
 }

or return a string as an alternative.

Community
  • 1
  • 1
Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265