Как получить доступ к объектам `window` (целевой странице), когда установлены значения @grant?
Допустим, я работаю со следующей веб-страницей:
<html>
<body>
<span id="click">click me</span>
<script>
var hello = function() {
alert('hello');
}
document.getElementById('click').addEventListener('click', function(e) {
hello();
});
</script>
</body>
</html>
и мой сценарий Greasemonkey:
// ==UserScript==
// @name My Script
// @include http://example.com/hello.html
// @version 1
// @grant none
// ==/UserScript==
window.hello = function() {
alert('goodbye');
}
С отключенным скриптом Greasemonkey, нажав #click
элемент на странице отображает предупреждение "привет". Если скрипт включен, при щелчке на элементе появляется предупреждение "до свидания".
Достаточно просто. hello
функция с веб-страницы заменяется функцией в скрипте Greasemonkey.
Теперь предположим, что я хочу использовать API Greasemonkey. Когда я установил @grant
значение к действительному значению, отличному от 'none' (например, // @grant GM_setClipboard
) [что заставляет Greasemonkey запускать сценарий как "сценарий содержимого", а не в области видимости страницы, как в случае с "none"], сценарий Greasemonkey не работает.
window.hello
больше не нацеливается на правильный объект на странице.
Замена window.hello
с unsafeWindow.hello
похоже, что это будет работать, но вместо этого в консоли JS выдается следующая ошибка:
Ошибка: в доступе отказано в доступе к объекту
Как я могу переписать сценарий Greasemonkey, имея @grant GM_setClipboard
установить цель и заменить оригинал hello
функция на странице?
Системная информация:
- Windows 7 64-битная
- Firefox 32.0
- Greasemonkey 2.2
1 ответ
Когда вы установите @grant
значение, отличное от none, Greasemonkey активирует свою песочницу, а Greasemonkey 2.0 радикально изменил обработку unsafeWindow.
Теперь, чтобы создать или перезаписать переменные в области целевой страницы, вы должны правильно выбрать один из методов. НАПРИМЕР:
Читать:
Простая переменная:
Target page sets: var foo = "bar"; GM script can read: unsafeWindow.foo //-- "bar"
Простой объект:
Target page sets: var obj = {A: 1}; GM script can read: unsafeWindow.obj //-- Object { A: 1 }
Сложный объект: это не всегда возможно.
Звонить:
Простая функция:
Target page sets: function func () {console.log ('Hi');} GM script can call: unsafeWindow.func() //-- "Hi"
Сложная функция: это не всегда возможно.
Написать / Установить:
Простая переменная:
unsafeWindow.foo = "Apple";
Простой объект:
var gmObject = {X: "123"}; unsafeWindow.obj = cloneInto (gmObject, unsafeWindow);
Простая функция:
function gmFunc () { console.log ("Lorem ipsum"); //-- Can use GM_ functions in here! :) } unsafeWindow.func = exportFunction (gmFunc, unsafeWindow);
Рассмотрим этот HTML:
<button id="helloBtn">Say "Hello".</button>
И этот JavaScript:
var simpleGlobalVar = "A simple, global var in the page scope.";
var globalObject = {Letter: "A", Number: 2};
function simpleFunction () {
console.log ("The target page's simpleFunction was called.");
}
var sayHello = function() {
console.log ('Hello.');
}
document.getElementById ('helloBtn').addEventListener ('click', function () {
sayHello ();
} );
который вы можете увидеть вживую на этой странице jsFiddle.
Если вы установите и запустите этот скрипт Greasemonkey для этой страницы:
// ==UserScript==
// @name _Demonstrate accessing target-page variables with @grant values set
// @include http://fiddle.jshell.net/sepwL7n6/*/show/
// @require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @grant GM_addStyle
// ==/UserScript==
console.log ("*** Greasemonkey script start.");
$("body").append ('<div id="gmArea">Added by Greasemonkey:<p></p></div>');
$("#gmArea > p:first").append ('<button id="gmShow">Access select target-page variables and functions</button>');
$("#gmArea > p:first").append ('<button id="gmChange">Change javascript things in the target-page scope.</button>');
$("#gmShow").click ( function () {
//-- Access things from the target-page scope:
console.log ("----------------");
console.log ("==> simpleGlobalVar is: ", unsafeWindow.simpleGlobalVar);
console.log ("==> globalObject is: ", unsafeWindow.globalObject);
console.log ("==> Calling target's simpleFunction():");
unsafeWindow.simpleFunction ();
//-- WARNING! This next technique is not robust, but works in some cases.
console.log ("==> Calling target's button's click().");
unsafeWindow.document.getElementById ('helloBtn').click ();
} );
$("#gmChange").click ( function () {
this.disabled = true; //-- Can only click once.
unsafeWindow.simpleGlobalVar = "Simple var... Intercepted by GM!";
unsafeWindow.globalObject = cloneInto (gmObject, unsafeWindow);
unsafeWindow.sayHello = exportFunction (sayHello, unsafeWindow);
console.log ("==> Target page objects were changed.");
} );
var gmMessageStr = "Function... Intercepted by GM, but also can use GM_ functions!";
function sayHello () {
sayHello.K = (sayHello.K || 0) + 1;
console.log (gmMessageStr);
GM_addStyle ('body {background: ' + (sayHello.K % 2 ? "lime" : "white") + ';}');
}
var gmObject = {message: "Object overridden by GM."};
Откройте консоль и нажмите кнопки, и вы увидите, что скрипт GM может считывать и изменять переменные и функции страницы.
Заметки:
- Это все специфично для Firefox.
- Для кросс-платформенного кода и для некоторых сложных ситуаций вы можете использовать вместо этого инъекцию скрипта. Но внедренный код не может получить прямой доступ
GM_
функции. - Обратите внимание, что эти методы работают только для глобальных переменных и функций javascript.
Оберните свой код в лямбда-функцию, например:
(function(window){ // and more arguments if you need it
console.log(window); // here, should be the real 'window'
})(window.unsafeWindow)