Внедрение JS-функций на страницу из Greasemonkey script в Chrome

У меня есть Greasemonkey script, который отлично работает в Firefox и Opera. Однако я борюсь с тем, чтобы заставить его работать в Chrome. Проблема заключается в вводе функции на страницу, которая может быть вызвана кодом со страницы. Вот что я делаю до сих пор:

Во-первых, я получаю справочную ссылку на unsafeWindow для Firefox. Это позволяет мне иметь тот же код для FF и Opera (и Chrome, я думал).

var uw = (this.unsafeWindow) ? this.unsafeWindow : window;

Затем я добавляю функцию на страницу. Это действительно очень тонкая оболочка, которая ничего не делает, кроме вызова соответствующей функции в контексте моего GM script:

uw.setConfigOption = function(newValue) {
    setTimeout(setConfigOption, 0, newValue);
}

Тогда в моей script:

setConfigOption = function(newValue) {
    // do something with it, e.g. store in localStorage
}

Наконец, я добавляю HTML-код на страницу со ссылкой для вызова функции.

var p = document.createElement('p');
p.innerHTML = '<a href="javascript:setConfigOption(1)">set config option to 1</a>';
document.getElementById('injection-point').appendChild(p);

Подводя итог: В Firefox, когда пользователь нажимает на эту вложенную ссылку, он выполняет вызов функции на unsafeWindow, который затем запускает таймаут, который вызывает соответствующую функцию в контексте моего GM script, который затем выполняет фактическую обработку. (Исправьте меня, если я ошибаюсь здесь.)

В Chrome я просто получаю сообщение об ошибке "Uncaught ReferenceError: setConfigOption не определено". И действительно, ввод "window.setConfigOption" в консоль дает "undefined". В Firebug и консоли разработчика Opera есть функция.

Может быть, есть еще один способ сделать это, но некоторые из моих функций вызывают объект Flash на странице, который, я считаю, требует, чтобы у меня были функции в контексте страницы.

Я быстро взглянул на альтернативы unsafeWindow на wiki Greasemonkey, но все они выглядят довольно уродливо. Неужели я полностью на неправильном пути здесь, или мне нужно более внимательно изучить их?

РЕШЕНИЕ: Я последовал за Max S. ' советы, и теперь он работает как в Firefox, так и в Chrome. Поскольку функции, которые мне нужно было для доступа к странице, приходилось переходить в обычные, я переместил всю страницу script на страницу, т.е. Она полностью завернута в функцию, которую он назвал "main()".

Чтобы сделать лишнюю уродство этого взлома немного более терпимым, я мог бы по крайней мере отказаться от использования unsafeWindow и wrappedJSObject сейчас.

Мне еще не удалось получить бегун области содержимого из работы wiki Greasemonkey. Он должен делать то же самое и, кажется, исполняется просто отлично, но мои функции никогда не доступны для элементов <a> на странице, например. Я еще не понял, почему это так.

Ответ 1

Единственный способ связаться с кодом, запущенным на странице в Chrome, - через DOM, поэтому вам придется использовать взломать как вставить тег <script> с вашим кодом. Обратите внимание, что это может оказаться ошибкой, если ваш script должен запускаться перед всем остальным на странице.

EDIT: Здесь расширение Nice Alert делает следующее:

function main () {
  // ...
  window.alert = function() {/* ... */};
  // ...
}

var script = document.createElement('script');
script.appendChild(document.createTextNode('('+ main +')();'));
(document.body || document.head || document.documentElement).appendChild(script);

Ответ 2

У меня есть это:

contentscript.js:

function injectJs(link) {
var scr = document.createElement('script');
scr.type="text/javascript";
scr.src=link;
document.getElementsByTagName('head')[0].appendChild(scr)
//document.body.appendChild(scr);
}

injectJs(chrome.extension.getURL('injected.js'));

injected.js:

function main() {
     alert('Hello World!');
}

main();

Ответ 3

Я быстро взглянул на альтернативы unsafeWindow в wiki Greasemonkey, но все они выглядят довольно уродливо. Неужели я полностью на неправильном пути здесь, или мне нужно более внимательно изучить их?

Вы должны посмотреть, потому что это только доступный параметр. Я предпочел бы использовать местоположение hack.

myscript.user.js:

function myFunc(){
  alert('Hello World!');
}

location.href="javascript:(function(){" + myFunc + "})()"

example.com/mypage.html

<script>
myFunc() // Hello World!
</script>

Конечно, это уродливо. Но он хорошо работает.


Метод охвата контента, упомянутый Max S., лучше, чем хакерство местоположения, потому что его легче отлаживать.

Ответ 4

Другие ответы заставляют вас использовать выражения функций, импортировать внешний файл или использовать длинный исправленный хак.

Этот ответ добавит javascript на страницу непосредственно из вашего исходного кода. Он будет использовать ECMAScript 6 (ES6) литералы шаблонов, чтобы легко получить многострочную строку javascript на странице.

var script = document.createElement('script'); 
script.type = "text/javascript"; 
script.innerHTML = ` 
   function test() {
      alert(1);
   }
`;
document.getElementsByTagName('head')[0].appendChild(script);

Обратите внимание на обратные метки ``, которые определяют начало и конец многострочной строки.