关于firefox:在Tampermonkey中可以调用复杂的页面函数,但在Greasemonkey中不起作用吗?

Call to a complex page function works in Tampermonkey but not Greasemonkey?

我正在尝试为XenForo论坛打开一个覆盖对话框,重用现有的库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ==UserScript==
// @name         FooBar
// @match        https://xenforo.com/community/
// @grant        GM_getValue
// ==/UserScript==

(function() {
'use strict';

unsafeWindow.XenForo.createOverlay(null, $(`

    <form id="efd_form">
       
            <h2 class="heading h1">Greasemonkey test
            <h3 class="primaryContent">${GM_getValue('lorem', 'Lorem ipsum dolor sit amet …')}
       
    </form>

`), { noCache: true }).load();
})();

当您使用Tampermonkey(Firefox / Chromium)访问https://xenforo.com/community/时,此脚本将打开简单对话框。
但是,当您使用Greasemonkey(Firefox)尝试时,什么也没有发生。 是否可以在访问GM_getValue的同时实现此目的?


如果您检查Firefox的浏览器控制台,则会看到类似以下错误消息:

$ is not defined ... FooBar.user.js

这是因为使用了none以外的@grant,在Greasemonkey(以及Tampermonkey-ish)中打开了沙箱。这意味着该脚本无法直接看到页面的javascript,因此该脚本的jQuery未定义***。

在您的代码中,您不能使用unsafeWindow技术来调用XenForo.createOverlay(),因为该函数需要在页面范围内定义/有效的jQuery对象(并且出于更复杂的原因)。
设置@grant值后,请参阅如何访问"窗口"(目标页面)对象。这种情况属于"复杂功能:并非总是可能"的情况。

因此,您需要注入调用XenForo.createOverlay()的代码。
但是,有一个障碍。由于GM_getValue()在页面范围内不可用,因此需要分别注入GM_getValue调用的结果。

该脚本说明了该过程,并且可以在两种浏览器上使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// ==UserScript==
// @name     FooBar
// @match    https://xenforo.com/community/
// @grant    GM_getValue
// ==/UserScript==

unsafeWindow.GM_simplevar = GM_getValue ('lorem', 'Hello world!');

function GM_usePagesOverlay ($) {
    XenForo.createOverlay (null, $(`
   
        <form id="efd_form">
           
                <h2 class="heading h1">Greasemonkey test
                <h3 class="primaryContent">${GM_simplevar}
           
        </form>
   
    `), { noCache: true }).load ();
}

withPages_jQuery (GM_usePagesOverlay);

function withPages_jQuery (NAMED_FunctionToRun) {
    //--- Use named functions for clarity and debugging...
    var funcText        = NAMED_FunctionToRun.toString ();
    var funcName        = funcText.replace (/^function\\s+(\\w+)\\s*\\((.|\
|\
)+$/,"$1");
    var script          = document.createElement ("script");
    script.textContent  = funcText +"\
\
";
    script.textContent += 'jQuery(document).ready(function() {'+funcName+'(jQuery);});';
    document.body.appendChild (script);
}

为了在页面范围和用户脚本范围之间进行更复杂的数据交换,您可能需要使用消息传递。

*** Tampermonkey的行为违反了沙盒范例,可能是一个安全漏洞,它允许不良网页访问特权的GM_功能-有必要对此进行调查... :)