如何在没有“不安全窗口”的情况下编程

How to program without "unsafeWindow"?

本文关键字:不安全窗口 情况下 编程 窗口 不安全      更新时间:2023-09-26

在我的Greasemonkey脚本中,我想重写一个仍然存在于网页中的函数。

所以我使用这个JavaScript代码:

var oldDoWork = DoWork;
unsafeWindow.DoWork = function()
{
    // Do some new work
    ...
    oldDoWork(); // Call the old function
}

但是这种方法有两个问题:

  1. unsafeWindow功能是一个安全问题,来自Greasemonkey说。
  2. 在这个新函数中,我们不能使用GM_getValueGM_setValue。使用计时器的解决方案会导致异步作业的一些其他问题。

如何在不使用unsafeWindow的情况下管理上述代码?

要避免使用unsafeWindow,您可以使用:

location.assign("javascript:YOUR_CODE_GOES_HERE");

但是这也不允许你使用GM_*函数。

使用GM_* "out of the GM scope"的唯一方法是使用计时器。

所以基本上,你的问题的答案是:你的方法是正确的,你只是无能为力。

如果你的函数没有返回任何东西,那么我建议你使用location.assign

如果您想避免unsafeWindow,请将与页面的JS交互的代码注入到页面中。参见addJS_Node()

要从这些事件中触发GM_函数,应该能够通过:进行交互。

  • 编写节点并监听DOMSubtreeModified(在W3C规范中已弃用)。但是,FF/GM的一个bug现在阻止了这一点。

  • 发送自定义事件。同样,GM/FF的bug和功能现在阻止了这一点。请注意,例如,当用户物理单击时,click事件可以调用使用GM_函数的代码。但是,以编程方式生成相同的单击事件,它会失败,并出现"Greasemonkey access violation: unsafeWindow cannot call..."错误。

所以,目前,解决方法仍然是使用定时器,但你可以避免unsafeWindow,如果你愿意:
//--- Put everything that goes into the main page, inside myJS().
function myJS () {
    window.oldDoWork = DoWork;
    window.DoWork = function() {
        // Do some new work
        callGM_setValue ("From target page", "some value");
        window.oldDoWork(); // Call the old function
    }
    function callGM_setValue (varName, varValue) {
        //--- Generate and dispatch a synthetic event.
        var zEvent  = document.createEvent ("CustomEvent");
        zEvent.initCustomEvent (
            "messageToGM_setvalue", true, false,
            {Name: varName, Value: varValue}
        );
        document.body.dispatchEvent (zEvent);
    }
}
document.body.addEventListener (
    "messageToGM_setvalue", fireGM_setValue, false
);
function fireGM_setValue (zEvent) {
    /*--- setTimeout remains one of the few things that can cleanse
        the calling tree of it's "unsafe" origins.
    */
    setTimeout (function() {
        GM_setValue (zEvent.detail.Name, zEvent.detail.Value);
    }, 0);
}
addJS_Node (null, null, myJS);
function addJS_Node (text, s_URL, funcToRun) {
    var D           = document;
    var scriptNode  = D.createElement ('script');
    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);
}