1

Using a Greasemonkey script on a page that has jQuery 1.6.3, I'm trying to get a link to react to mouse clicks.

Here are the interesting parts:

// ==UserScript==
// […]
// @grant   GM_getValue
// @grant   GM_setValue
// @grant   GM_deleteValue
// @grant   unsafeWindow
// ==/UserScript==

if (typeof $ == 'undefined') {
  var $ = unsafeWindow.jQuery;
  if (typeof $ == 'undefined') {
    console.log('jQuery could not be loaded, script will not work.');
  }
}
[…]
document.addEventListener("DOMContentLoaded", function(event) {
  console.log('DOM content loaded.');

  if (settings.firstRun) {
    console.log('Creating welcome window.');
    var hi = $('<div>This is a welcome message. Click the OK link to hide it forever. </div>');
    var ok = $('<a href="javascript:void(0)" id="okay">OK</a>');
    hi.append(ok);
    // el is from earlier
    el.append(hi);
    console.log('Binding click event.');
    ok.click(function(event) { // DOES NOT WORK
      event.preventDefault();
      alert('you clicked OK');
    });
    console.log('Bound.');
  }
  […]
});

My code is working okay in Tampermonkey/Chrome (even when I don't insert the elements into the DOM before binding the event), but not in Greasemonkey/Firefox.

Now I know that the script is getting injected and jQuery is loaded, because the console messages right up to 'Binding click event.' are being shown and the elements are being properly inserted in the DOM. But then the script hiccups at the click binding and stops execution without even an error message.

It works when I use plain JS:

document.getElementById('okay').onclick = function(){ alert('you clicked OK'); };

and it also works from the Firebug console – running this command produces the correct result:

$('#okay').click(function(){ alert('you clicked OK'); });

I could just use plain JS, but I want to maintain a level of consistency and also it irks me that I can't understand the problem. What am I missing?

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
Slampisko
  • 99
  • 11
  • You are using `'undefined'` as String not as Object. And you never append neither `ok` nor `el` to anything – Fuzzyma Jan 25 '15 at 13:28
  • Thank you for the comment! Using `'undefined'` as a string does not seem to be the problem, I copied that from a different SO question and in console, `typeof(foo) == 'undefined'` returns `true` while `typeof(setTimeout) == 'undefined'` returns `false`, which seems to be correct behavior. `el` is a jquery object gotten from the DOM using a selector in an irrelevant piece of code I chose not to include. As I said, the elements are being properly inserted in the DOM. And I append `ok` to `hi`, which I then append to `el`. – Slampisko Jan 25 '15 at 15:50

2 Answers2

1

It seems this code cannot work due to the sanbox on Firefox. Your function can not be passed to unsafeWindow without some interface. To override this problem, a better way to use jQuery is using @require instead.

tsh
  • 4,263
  • 5
  • 28
  • 47
1

If you look in Firefox's Browser Console (ControlShiftJ), you should see an error like:

Error: Permission denied to access property 'handler'        jquery.min.js:2

This is because you can no longer access a page's jQuery that way (fully, without "time-bomb" errors).

As a rule, it's best to @require jQuery for your userscripts, and that avoids all kinds of sneaky conflict problems -- especially when you also use a @grant other than none.


Side note:
There's no point in using document.addEventListener("DOMContentLoaded" ....
Unless you have set @run-at document-start, the script runs at that point, and after jQuery is ready, by default.

Community
  • 1
  • 1
Brock Adams
  • 90,639
  • 22
  • 233
  • 295