web-dev-qa-db-ja.com

ChromeのGreasemonkeyスクリプトからページにJS関数を挿入する

FirefoxとOperaで正常に動作するGreasemonkeyスクリプトがあります。ただし、Chromeで動作させるのに苦労しています。問題は、ページのコードによって呼び出すことができる関数をページに挿入することです。ここに私がこれまでやっていることがあります:

まず、Firefoxの nsafeWindow へのヘルパーリファレンスを取得します。これにより、FFとOpera(およびChrome、私は思った)に同じコードを使用できます。

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

次に、ページに関数を挿入します。それは本当に非常に薄いラッパーであり、my 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で関数呼び出しが実行され、my GMスクリプトのコンテキストで対応する関数を呼び出すタイムアウトがトリガーされます、その後、実際の処理を行います(ここで間違っている場合は修正してください)。

Chromeでは、「Uncaught ReferenceError:setConfigOption is not defined」エラーが表示されます。実際、コンソールに「window.setConfigOption」と入力すると「undefined」が生成されます。 FirebugとOpera開発者コンソールには、関数があります。

これを行う別の方法があるかもしれませんが、私の関数のいくつかはページ上のFlashオブジェクトによって呼び出されるため、ページコンテキストに関数が必要になると思います。

Greasemonkey wikiの nsafeWindowの代替 をざっと見てみましたが、どれもかなり見苦しいです。私はここで完全に間違った方向に進んでいますか、またはこれらをより詳しく調べる必要がありますか?

解像度:私は Max S. 'advice に従いましたが、FirefoxとChromeの両方で動作します= now。ページで使用できるようにする必要がある関数は、通常の関数にコールバックする必要があるため、スクリプト全体をページに移動しました。つまり、「main()」と呼ばれる関数に完全にラップされます。

そのハックの余分なさをもう少し我慢できるようにするために、少なくとも今ではunsafeWindowとwrappedJSObjectの使用をやめることができます。

Greasemonkey wikiから content scope runner を取得することができませんでした。同じことを実行する必要があり、正常に実行されるように見えますが、たとえば、ページの<a>要素から私の関数にアクセスすることはできません。その理由はまだわかりません。

38

Chromeでページで実行されているコードと通信する唯一の方法は、DOMを使用することです。コードに<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);
68
Max Shawabkeh

私はこれを持っています:

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'));

jected.js:

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

main();
15
Bernard Choi

Greasemonkey wikiの nsafeWindowの代替 をざっと見てみましたが、どれもかなり見苦しいです。私はここで完全に間違った方向に進んでいますか、またはこれらをより詳しく調べる必要がありますか?

それは唯一の利用可能なオプションなので、見てください。 location 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.が言及したContent Scope Runnerメソッドは、デバッグが容易であるため、ロケーションハックよりも優れています。

4
NVI

他の答えは、 関数式 を使用するか、 外部追加ファイル をインポートするか、 長いパッチを適用したハック を使用することを強制します。

この回答は、ソースコードから直接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);

バッククォートに注意してください``複数行の文字列の始まりと終わりを定義します。

2
user136036