Binding to an event of the unsafeWindow in Firefox 30 with Greasemonkey 2.0

蹲街弑〆低调 提交于 2019-12-05 19:55:38
Brock Adams

The quick and dirty way to do this, if you don't need any GM_ functions and you don't @require your own jQuery, is to use @grant none mode. This works:

// ==UserScript==
// @name     _unsafeWindow tests
// @include  http://jsbin.com/xaman/*
// @grant    none
// ==/UserScript==

var jQuery = window.jQuery;
jQuery(document).bind ("MyEvent", function () {
    console.log ("From GM script: MyEvent caught!");
} );

If you did need GM_ functions, you can sometimes use the new exportFunction().
Unfortunately, jQuery and jQuery event handling is a special case. Depending on what you try, you will get error messages like:

Permission denied to access property 'handler'
or
CloneNonReflectorsWrite error

I've simply found no way to do this using any of the new unsafeWindow functionality. Your only recourse is to inject the code. Like so:

// ==UserScript==
// @name     _unsafeWindow tests
// @include  http://jsbin.com/xaman/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/
function myEventHandler (zEvent) {
    console.log (
        'From GM script: "' + zEvent.type + '" triggered on ', zEvent.target
    );
}

function bindMyEvent () {
    //-- Gets "jQuery is not defined" if GM script does not also use jQuery.
    jQuery(document).bind ("MyEvent", myEventHandler);
    console.log ("The jQuery version being used is: ", jQuery.fn.jquery);
}

//-- Create A COPY OF myEventHandler in the target page scope:
addJS_Node (myEventHandler);
//-- Create A COPY OF bindMyEvent in the target page scope and immediately run it.
addJS_Node (null, null, bindMyEvent);

function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    if (runOnLoad) {
        scriptNode.addEventListener ("load", runOnLoad, false);
    }
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}

You can test both of these scripts against this jsBin page.


If you need to run/call GM_ functions from within the injected event handler(s), use techniques shown in "How to call Greasemonkey's GM_ functions from code that must run in the target page scope? ".

Just don't bind event handlers on unsafeWindow, use the regular window object instead:

window.document.addEventListener("MyEvent", function() {
  console.log("MyEvent Triggered!");
}, false, true);

Note the fourth parameter (wantsUntrusted) to addEventListener - this one allows your event handler to receive untrusted events.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!