Внедрение функций JS на страницу из скрипта Greasemonkey в Chrome - PullRequest
38 голосов
/ 20 февраля 2010

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

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

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

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

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

Тогда в моем скрипте есть соответствующая функция:

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, который затем выполняет фактическую обработку. (Поправьте меня, если я здесь не прав.)

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

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

Я быстро взглянул на альтернативы unsafeWindow в вики Greasemonkey, но все они выглядят довольно некрасиво. Я здесь совершенно не на том пути или мне стоит присмотреться к ним?

РАЗРЕШЕНИЕ: Я следовал Макс С. ' совет и теперь он работает как в Firefox, так и в Chrome. Поскольку функции, которые мне нужны были для доступа к странице, требовали обратного вызова к обычным, я переместил весь свой скрипт на страницу, то есть он полностью обернут в функцию, которую он назвал main ().

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

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

Ответы [ 4 ]

67 голосов
/ 20 февраля 2010

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

РЕДАКТИРОВАТЬ: Вот как расширение 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);
15 голосов
/ 26 февраля 2010

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

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();
4 голосов
/ 20 февраля 2010

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

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

myscript.user.js:

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

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

example.com / mypage.html

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

Конечно, это безобразно. Но это работает хорошо.


Метод Content Scope Runner, упомянутый Максом С., лучше, чем взлом местоположения, потому что его легче отлаживать.

2 голосов
/ 23 февраля 2018

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

Этот ответ добавит 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);

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

...