diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/ja/mozilla/add-ons/webextensions/content_scripts | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/ja/mozilla/add-ons/webextensions/content_scripts')
-rw-r--r-- | files/ja/mozilla/add-ons/webextensions/content_scripts/index.html | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/files/ja/mozilla/add-ons/webextensions/content_scripts/index.html b/files/ja/mozilla/add-ons/webextensions/content_scripts/index.html new file mode 100644 index 0000000000..456ce69ddb --- /dev/null +++ b/files/ja/mozilla/add-ons/webextensions/content_scripts/index.html @@ -0,0 +1,534 @@ +--- +title: コンテンツスクリプト +slug: Mozilla/Add-ons/WebExtensions/Content_scripts +tags: + - WebExtensions +translation_of: Mozilla/Add-ons/WebExtensions/Content_scripts +--- +<div>{{AddonSidebar}}</div> + +<p>コンテンツスクリプトは、特定のウェブページのコンテキストで実行される拡張機能の一部です(拡張機能の一部であるバックグラウンドスクリプトや、ウェブサイト自体の一部であるスクリプト、例えば {{HTMLElement("script")}} 要素みたいなものと対をなすような)。</p> + +<p><a href="/ja/Add-ons/WebExtensions/Background_scripts">バックグラウンドスクリプト</a>はすべての <a href="/ja/Add-ons/WebExtensions/API">WebExtension JavaScript API</a> にアクセスできますが、ウェブページのコンテンツに直接アクセスすることはできません。だからあなたの拡張機能がそれを行う必要がある場合は、コンテンツスクリプトが必要です。</p> + +<p>通常のウェブページで読み込まれたスクリプトと同様に、コンテンツスクリプトは、標準の DOM API を使用してページのコンテンツを読み取り、変更することができます。</p> + +<p>コンテンツスクリプトは、<a href="https://developer.mozilla.org/ja/Add-ons/WebExtensions/Content_scripts#WebExtension_APIs">WebExtension API</a> の小さなサブセット にしかアクセスできませんが、メッセージングシステムを使用して <a href="https://developer.mozilla.org/ja/Add-ons/WebExtensions/Content_scripts#Communicating_with_background_scripts">バックグラウンドスクリプトと通信</a>し、WebExtension API に間接的にアクセスすることができます。</p> + +<div class="note"> +<p>コンテンツスクリプトは次のドメインでブロックされるのに注意してください:</p> + +<ul style="display: grid;"> + <li>accounts-static.cdn.mozilla.net</li> + <li>accounts.firefox.com</li> + <li>addons.cdn.mozilla.net</li> + <li>addons.mozilla.org</li> + <li>api.accounts.firefox.com</li> + <li>content.cdn.mozilla.net</li> + <li>content.cdn.mozilla.net</li> + <li>discovery.addons.mozilla.org</li> + <li>input.mozilla.org</li> + <li>install.mozilla.org</li> + <li>oauth.accounts.firefox.com</li> + <li>profile.accounts.firefox.com</li> + <li>support.mozilla.org</li> + <li>sync.services.mozilla.com</li> + <li>testpilot.firefox.com</li> +</ul> + +<p>このドメインのページにコンテンツスクリプトを挿入しようとすると、そのスクリプトは失敗し、ページは <a href="/ja/docs/Web/Security/CSP">CSP</a> エラーをログに記録します。</p> + +<p>addons.mozilla.org を含む制限のために、ユーザーはインストール後すぐに拡張機能を試して、動かないのに気付くだけでしょう! 適切な警告を追加するか、<code>addons.mozilla.org</code> から動かす <a href="/ja/docs/Mozilla/Add-ons/WebExtensions/onboarding_upboarding_offboarding_best_practices">onboarding page</a> を追加したくなるでしょう。</p> +</div> + +<div class="note"> +<p><code>letfoo</code> や <code>window.foo = "bar"</code> にて、コンテンツスクリプトのグローバルスコープで追加された値は、<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1408996">1408996</a> のバグによって消えることがあります。</p> +</div> + +<h2 id="Loading_content_scripts" name="Loading_content_scripts">コンテンツスクリプトの読み込み</h2> + +<p>次の 3 つの方法のいずれかを使用して、ウェブページにコンテンツスクリプトを読み込むことができます。</p> + +<ol> + <li> + <dl> + <dt><strong>インストール時に、URL パターンにマッチするページ内へ</strong></dt> + <dd><code>manifest.json</code> の <code style="font-style: normal;"><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts</a></code> キーを使用して、URL が<a href="https://developer.mozilla.org/ja/Add-ons/WebExtensions/Match_patterns">指定されたパターンにマッチする</a>ページをロードするたびにコンテンツスクリプトを読み込むようブラウザーに依頼できます。</dd> + </dl> + </li> + <li> + <dl> + <dt><strong>実行時に、URL パターンにマッチするページ内へ</strong></dt> + <dd>{{WebExtAPIRef("contentScripts")}} API を使って、URL が<a href="https://developer.mozilla.org/ja/Add-ons/WebExtensions/Match_patterns">指定されたパターンにマッチする</a>ページをロードするたびにコンテンツスクリプトを読み込むようブラウザーに依頼できます。これは method (1) のようなもので、違いは実行時にコンテンツスクリプトを追加/削除できることです。</dd> + </dl> + </li> + <li> + <dl> + <dt><strong>実行時に、特定のタブへ</strong></dt> + <dd><code><a href="/ja/Add-ons/WebExtensions/API/Tabs/executeScript">tabs.executeScript()</a></code> API を使用すると、ユーザーが<a href="/ja/Add-ons/WebExtensions/user_interface/Browser_action">ブラウザーアクション</a>をクリックした場合など、必要なときにコンテンツスクリプトを特定のタブに読み込むことができます。</dd> + </dl> + </li> +</ol> + +<p><em>フレームごと、拡張機能ごとの</em>グローバルスコープしかありません。これは 1 つのコンテンツスクリプトの変数は、読み込み方にかかわらず、他のコンテンツスクリプトからアクセスできることになります。</p> + +<p>方法 (1) と (2) では<a href="https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/Match_patterns">マッチパターン</a>を使って表現された URL のスクリプトだけを読み込みできます。</p> + +<p>方法 (3) では、拡張機能と一緒にパッケージされたページのスクリプトも読み込みできますが、"about:debugging" や "about:addons"のような権限つきページにはスクリプトを読み込めません。</p> + +<h2 id="Content_script_environment" name="Content_script_environment">コンテンツスクリプト環境</h2> + +<h3 id="DOM_access" name="DOM_access">DOM アクセス</h3> + +<p>コンテンツスクリプトは、普通のページスクリプトと同様に、ページの DOM にアクセスして修正できます。ページスクリプトにてなされた DOM の変更を見ることもできます。</p> + +<p>しかし、コンテンツスクリプトは "DOM のきれいな見た目" を取得します。これはつまり:</p> + +<ul> + <li>コンテンツスクリプトはページスクリプトにて定義された JavaScript 変数を見ることができない</li> + <li>ページスクリプトが組み込み DOM プロパティを再定義した場合、コンテンツスクリプトはそのプロパティの(再定義後でなく)オリジナル値を見ている</li> +</ul> + +<p>Firefox では、この挙動は <a href="/ja/docs/Xray_vision">Xray vision</a> と呼ばれます。</p> + +<p>例えば、次のウェブページを考えます:</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + </head> + + <body> + <script src="page-scripts/page-script.js"></script> + </body> +</html></pre> + +<p>"page-script.js" スクリプトは次を実行します:</p> + +<pre class="brush: js">// page-script.js + +// add a new element to the DOM +let p = document.createElement("p"); +p.textContent = "This paragraph was added by a page script."; +p.setAttribute("id", "page-script-para"); +document.body.appendChild(p); + +// define a new property on the window +window.foo = "This global variable was added by a page script"; + +// redefine the built-in window.confirm() function +window.confirm = function() { + alert("The page script has also redefined 'confirm'"); +}</pre> + +<p>今度は拡張機能がページにコンテンツスクリプトを挿入します:</p> + +<pre class="brush: js">// content-script.js + +// can access and modify the DOM +let pageScriptPara = document.getElementById("page-script-para"); +pageScriptPara.style.backgroundColor = "blue"; + +// can't see page-script-added properties +console.log(window.foo); // undefined + +// sees the original form of redefined properties +window.confirm("Are you sure?"); // calls the original window.confirm()</pre> + +<p>その反対もまた真です; ページスクリプトはコンテンツスクリプトが追加した JavaScript プロパティを見られません。</p> + +<p>このことからすると、コンテンツスクリプトは予言できる振る舞いをする DOM プロパティに依存していて、ページスクリプトにて定義された変数とコンテンツスクリプトで定義する変数の衝突は心配しなくていいです。</p> + +<p>この振る舞いの実用的な結論として、コンテンツスクリプトはページに読み込まれたいかなる JavaScript ライブラリーにもアクセスしません。なので例えば、ページに jQuery が含まれても、コンテンツスクリプトは見ることができません。</p> + +<p>コンテンツスクリプトから JavaScript ライブラリを使いたい場合、ライブラリ自身を、使う方のコンテンツスクリプトと<em>並べて</em>挿入するべきです:</p> + +<pre class="brush: json">"content_scripts": [ + { + "matches": ["*://*.mozilla.org/*"], + "js": ["jquery.js", "content-script.js"] + } +]</pre> + +<div class="blockIndicator note"> +<p><strong>記:</strong> Firefox ではコンテンツスクリプトからページスクリプトによって生成された JavaScript オブジェクトにアクセスしたり、ページスクリプトにコンテンツスクリプトの JavaScript オブジェクトを公開できるようにする API が提供されます。</p> + +<p>詳しくは<a href="/ja/docs/Mozilla/Add-ons/WebExtensions/Sharing_objects_with_page_scripts">ページスクリプトとオブジェクトを共有する</a>のページを見てください。</p> +</div> + +<h3 id="WebExtension_APIs" name="WebExtension_APIs">WebExtension API</h3> + +<p>標準 DOM API に加え、コンテンツスクリプトは次の WebExtension API を使用できます:</p> + +<p><code><a href="/ja/Add-ons/WebExtensions/API/extension">extension</a></code> から:</p> + +<ul> + <li><code><a href="/ja/Add-ons/WebExtensions/API/extension#getURL()">getURL()</a></code></li> + <li><code><a href="/ja/Add-ons/WebExtensions/API/extension#inIncognitoContext">inIncognitoContext</a></code></li> +</ul> + +<p><code><a href="/ja/Add-ons/WebExtensions/API/runtime">runtime</a></code> から:</p> + +<ul> + <li><code><a href="/ja/Add-ons/WebExtensions/API/runtime#connect()">connect()</a></code></li> + <li><code><a href="/ja/Add-ons/WebExtensions/API/runtime#getManifest()">getManifest()</a></code></li> + <li><code><a href="/ja/Add-ons/WebExtensions/API/runtime#getURL()">getURL()</a></code></li> + <li><code><a href="/ja/Add-ons/WebExtensions/API/runtime#onConnect">onConnect</a></code></li> + <li><code><a href="/ja/Add-ons/WebExtensions/API/runtime#onMessage">onMessage</a></code></li> + <li><code><a href="/ja/Add-ons/WebExtensions/API/runtime#sendMessage()">sendMessage()</a></code></li> +</ul> + +<p><code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/i18n">i18n</a></code> から:</p> + +<ul> + <li><code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/i18n/getMessage">getMessage()</a></code></li> + <li><code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/i18n/getAcceptLanguages">getAcceptLanguages()</a></code></li> + <li><code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/i18n/getUILanguage">getUILanguage()</a></code></li> + <li><code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/i18n/detectLanguage">detectLanguage()</a></code></li> +</ul> + +<p>すべてから:</p> + +<ul> + <li><code><a href="https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/API/storage">storage</a></code></li> +</ul> + +<h3 id="XHR_and_Fetch" name="XHR_and_Fetch">XHR と Fetch</h3> + +<p>コンテンツスクリプトは通常の <code><a href="https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest">window.XMLHttpRequest</a></code> と <code><a href="https://developer.mozilla.org/ja/docs/Web/API/Fetch_API">window.fetch()</a></code> API を使ってリクエストを作成できます。</p> + +<div class="blockIndicator note"> +<p>Firefox では、コンテンツスクリプトの (例えば、<code><a href="/ja/docs/Web/API/Fetch_API/Using_Fetch">fetch()</a></code> を使った) リクエストは、拡張機能のコンテキストで起こるので、ページコンテンツを参照する URL を絶対URL で提供せねばなりません。</p> + +<p>Chrome では、リクエストはページのコンテ<span style="display: none;"> </span>キストで起こるので、相対 URL で行われます。例えば、<code>/api</code> は <code>https://[現在のペー<span style="display: none;"> </span>ジの URL]/api</code> に送られます。</p> +</div> + +<p>コンテンツスクリプトは拡張機能の他の部分と同一のクロスドメイン権限を取得します: よって拡張機能が <code>manifest.json</code> の <code><a href="https://developer.mozilla.org/ja/Add-ons/WebExtensions/manifest.json/permissions">permissions</a></code> キーを使ってあるドメインのクロスドメインアクセスを要求している場合、コンテンツスクリプトも同様にそのドメインのアクセスを取得します。</p> + +<p>これはより多く権限付けられた XHR に晒して、コンテンツスクリプトでインスタンスを取得することで達成し、その副作用としてページ自体からのリクエストがそうであるように <code><a href="https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Origin">Origin</a></code> と <code><a href="https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Referer">Referer</a></code> ヘッダーがセットされず、リクエストからクロスオリジンな性質を隠すことが好ましいことがよくあります。</p> + +<div class="blockIndicator note"> +<p>バージョン 58 以降、コンテンツ自体から送られたかのようなリクエストを必要とする拡張機能は <code>content.XMLHttpRequest</code> と <code>content.fetch()</code> を代わりに使うことができます。</p> + +<p>クロスブラウザー拡張機能にとってこれらの存在は機能検出となります。</p> +</div> + +<h2 id="Communicating_with_background_scripts" name="Communicating_with_background_scripts">バックグラウンドスクリプトとの通信</h2> + +<p>コンテンツスクリプトは WebExtension API の大半を直接には使用できませんが、メッセージ API を用いて拡張機能のバックグラウンドスクリプトと通信できて、それゆえにバックグラウンドスクリプトがアクセスできるすべての API に間接的にアクセスできます。</p> + +<p>バックグラウンドスクリプトとコンテンツスクリプトが通信する 2 つのパターンがあります: (オプションなレスポンスつきの)<strong>ワンオフメッセージ</strong>を送るのと、<strong>お互いに息の長いコネクションを確立して</strong>、そこでメッセージを交換するのとです。</p> + +<h3 id="One-off_messages" name="One-off_messages">ワンオフメッセージ</h3> + +<p>レスポンスが必須でないワンオフメッセージを送るには、次の API を使います:</p> + +<table class="fullwidth-table standard-table"> + <thead> + <tr> + <th scope="row"></th> + <th scope="col">コンテンツスクリプト内</th> + <th scope="col">バックグラウンドスクリプト内</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">送信メッセージ</th> + <td><code><a href="/ja/Add-ons/WebExtensions/API/runtime/sendMessage">browser.runtime.sendMessage()</a></code></td> + <td><code><a href="/ja/Add-ons/WebExtensions/API/Tabs/sendMessage">browser.tabs.sendMessage()</a></code></td> + </tr> + <tr> + <th scope="row">受信メッセージ</th> + <td><code><a href="/ja/Add-ons/WebExtensions/API/runtime/onMessage">browser.runtime.onMessage</a></code></td> + <td><code><a href="/ja/Add-ons/WebExtensions/API/runtime/onMessage">browser.runtime.onMessage</a></code></td> + </tr> + </tbody> +</table> + +<p>例えば、ウェブページでのクリックイベントをリッスンするコンテンツスクリプトがここにあります。クリックがリンク上である場合、ターゲット URL をバックグラウンドページにメッセージします。</p> + +<pre class="brush: js">// content-script.js + +window.addEventListener("click", notifyExtension); + +function notifyExtension(e) { + if (e.target.tagName != "A") { + return; + } + browser.runtime.sendMessage({"url": e.target.href}); +}</pre> + +<p>バックグラウンドスクリプトはこのメッセージをリッスンして、<code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/notifications">notifications</a></code> API を使って通知を表示します:</p> + +<pre class="brush: js">// background-script.js + +browser.runtime.onMessage.addListener(notify); + +function notify(message) { + browser.notifications.create({ + "type": "basic", + "iconUrl": browser.extension.getURL("link.png"), + "title": "You clicked a link!", + "message": message.url + }); +} +</pre> + +<p>この例のコードは Github の <a href="https://github.com/mdn/webextensions-examples/tree/master/notify-link-clicks-i18n">notify-link-clicks-i18n</a> のサンプルから簡単に適用できます。</p> + +<h3 id="Connection-based_messaging" name="Connection-based_messaging">コネクションベースのメッセージ</h3> + +<p>ワンオフメッセージの送信は、バックグラウンドスクリプトとコンテンツスクリプトとで多くのメッセージを交換する場合はめんどくさいです。なので代替パターンは、この 2 つのコンテキスト間で寿命の長いコネクションを確立して、メッセージ交換にこのコネクションを使うことです。</p> + +<p>いずれの側にも <code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/runtime/Port">runtime.Port</a></code> オブジェクトがあり、メッセージ交換に使えます。</p> + +<p>コネクションを作成するには:</p> + +<ul> + <li>片方で <code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onConnect">runtime.onConnect</a></code> にてコネクションをリッスンする。</li> + <li>もう片方で次を呼び出す: + <ul> + <li><code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/tabs/connect">tabs.connect()</a></code> (コンテンツスクリプトに接続する場合)</li> + <li><code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/runtime/connect">runtime.connect()</a></code> (バックグラウンドスクリプトに接続する場合)</li> + </ul> + </li> +</ul> + +<p>これは <code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/runtime/Port">runtime.Port</a></code> オブジェクトを返します。</p> + +<ul> + <li><code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onConnect">runtime.onConnect</a></code> リスナーには自身の <code><a href="/ja/docs/Mozilla/Add-ons/WebExtensions/API/runtime/Port">runtime.Port</a></code> オブジェクトが渡される。</li> +</ul> + +<p>それぞれがポートを持ったら、両方が:</p> + +<ul> + <li><code>runtime.Port.postMessage()</code> でメッセージを送って</li> + <li><code>runtime.Port.onMessage</code> でメッセージを受信できるようになる。</li> +</ul> + +<p>例えば、ロードしたらすぐに、このコンテンツスクリプトは:</p> + +<ul> + <li>バックグラウンドに接続し</li> + <li><code>myPort</code> 変数に <code>Port</code> を格納する</li> + <li><code>myPort</code> のメッセージをリッスンする(ログに出す)</li> + <li>ユーザーがドキュメントをクリックしたとき、バックグラウンドスクリプトに <code>myPort</code> を使ってメッセージを送る</li> +</ul> + +<pre class="brush: js">// content-script.js + +var myPort = browser.runtime.connect({name:"port-from-cs"}); +myPort.postMessage({greeting: "hello from content script"}); + +myPort.onMessage.addListener(function(m) { + console.log("In content script, received message from background script: "); + console.log(m.greeting); +}); + +document.body.addEventListener("click", function() { + myPort.postMessage({greeting: "they clicked the page!"}); +});</pre> + +<p>対応するバックグラウンドスクリプトは:</p> + +<ul> + <li>コンテンツスクリプトからの通信試行をリッスンする</li> + <li>通信試行を受け取ったとき: + <ul> + <li><code>portFromCS</code> という名前の変数にポートを格納する</li> + <li>そのポートを使ってコンテンツスクリプトにメッセージを送る</li> + <li>ポートに届いたメッセージをリッスンしてログに出す</li> + </ul> + </li> + <li>ユーザーが拡張機能のブラウザーアクションをクリックしたとき、<code>portFromCS</code> を使ってコンテンツスクリプトにメッセージを送る</li> +</ul> + +<pre class="brush: js">// background-script.js + +var portFromCS; + +function connected(p) { + portFromCS = p; + portFromCS.postMessage({greeting: "hi there content script!"}); + portFromCS.onMessage.addListener(function(m) { + console.log("In background script, received message from content script") + console.log(m.greeting); + }); +} + +browser.runtime.onConnect.addListener(connected); + +browser.browserAction.onClicked.addListener(function() { + portFromCS.postMessage({greeting: "they clicked the button!"}); +}); +</pre> + +<h4 id="Multiple_content_scripts" name="Multiple_content_scripts">複数のコンテンツスクリプト</h4> + +<p>同時に複数のコンテンツスクリプトが通信する場合、各接続を配列に格納するのが良いかもしれません。</p> + +<ul> +</ul> + +<pre class="brush: js">// background-script.js + +var ports = [] + +function connected(p) { + ports[p.sender.tab.id] = p + //... +} + +browser.runtime.onConnect.addListener(connected) + +browser.browserAction.onClicked.addListener(function() { + ports.forEach(p => { + p.postMessage({greeting: "they clicked the button!"}) + }) +});</pre> + +<ul> +</ul> + +<h3 id="Choosing_between_one-off_messages_and_connection-based_messaging" name="Choosing_between_one-off_messages_and_connection-based_messaging">ワンオフメッセージとコネクションベースのメッセージとの選択</h3> + +<p>ワンオフとコネクションベースのメッセージの選択は、拡張機能がどうメッセージを利用すると期待されるかに依存します。</p> + +<p>推奨のベストプラクティスは次の通りです:</p> + +<p><strong>次のときにワンオフメッセージを使用… </strong></p> + +<ul> + <li>メッセージに 1 つだけの応答がある場合</li> + <li>メッセージの受信を少しのスクリプトがリッスンする場合({{WebExtAPIRef("runtime.onMessage")}} 呼び出し)</li> +</ul> + +<p><strong>次のときにコネクションベースメッセージを使用…</strong></p> + +<ul> + <li>スクリプトが、複数のメッセージを交換するセッションに関わる場合</li> + <li>拡張機能がタスクの進捗や、タスクが中断されたのを知る必要がある場合、または初期化されたタスクをメッセージング経由で中断したい場合</li> +</ul> + +<h2 id="Communicating_with_the_web_page" name="Communicating_with_the_web_page">ウェブページとの通信</h2> + +<p>既定では、コンテンツスクリプトはページスクリプトが作成したオブジェクトにアクセスできませんが、DOM <code><a href="/ja/docs/Web/API/Window/postMessage">window.postMessage</a></code> と <code><a href="/ja/docs/Web/API/EventTarget/addEventListener">window.addEventListener</a></code> API を使ってページスクリプトと通信できます。</p> + +<p>例えば:</p> + +<pre class="brush: js">// page-script.js + +var messenger = document.getElementById("from-page-script"); + +messenger.addEventListener("click", messageContentScript); + +function messageContentScript() { + window.postMessage({ + direction: "from-page-script", + message: "Message from the page" + }, "*");</pre> + +<pre class="brush: js">// content-script.js + +window.addEventListener("message", function(event) { + if (event.source == window && + event.data && + event.data.direction == "from-page-script") { + alert("Content script received message: \"" + event.data.message + "\""); + } +});</pre> + +<p>これの完全な動作サンプルは、<a href="https://mdn.github.io/webextensions-examples/content-script-page-script-messaging.html">GitHub のデモページを訪れて</a>指示に従ってください。</p> + +<div class="warning"> +<p><strong>この方法で信頼できないウェブコンテンツと相互作用するには細心の注意が必要です</strong>!<br> + 拡張機能は強力な力を持つコードの権限があり、敵意のあるウェブページは簡単にこの力にアクセスします。</p> + +<p>細かい例を作るには、メッセージを受け取ったコンテンツスクリプトがこのようなことを行うと仮定してください:</p> + +<pre class="brush: js">// content-script.js + +window.addEventListener("message", function(event) { + if (event.source == window && + event.data.direction && + event.data.direction == "from-page-script") { + eval(event.data.message); + } +});</pre> + +<p>今やページスクリプトはコンテンツスクリプトのすべての権限でコードを実行できます。</p> +</div> + +<h2 id="Using_eval_in_content_scripts" name="Using_eval()_in_content_scripts">コンテンツスクリプト内で eval() を使う</h2> + +<dl> + <dt>Chrome では</dt> + <dd>{{jsxref("eval")}} は常にページコンテキストではなくてコンテンツスクリプトのコンテキストで動作します。</dd> + <dt>Firefox では</dt> + <dd> + <p><code>eval()</code> を呼ぶ場合、<strong>コンテンツスクリプト</strong>のコンテキストで動作します。 <code>window.eval()</code> を呼ぶ場合、<strong>ページ</strong>のコンテキストで動作します。, it runs code in the context of the <strong>content script</strong>.</p> + </dd> +</dl> + +<p>例えば、こんなコンテンツスクリプトを考えてみます:</p> + +<pre class="brush: js">// content-script.js + +window.eval('window.x = 1;'); +eval('window.y = 2'); + +console.log(`In content script, window.x: ${window.x}`); +console.log(`In content script, window.y: ${window.y}`); + +window.postMessage({ + message: "check" +}, "*");</pre> + +<p>このコードは単に変数 x と y を、<code>window.eval()</code> と <code>eval()</code> を用いて作成し、値をログに出し、ページにメッセージします。</p> + +<p>メッセージの受信に際し、ページスクリプトは同じ変数をログに出します:</p> + +<pre class="brush: js">window.addEventListener("message", function(event) { + if (event.source === window && event.data && event.data.message === "check") { + console.log(`In page script, window.x: ${window.x}`); + console.log(`In page script, window.y: ${window.y}`); + } +});</pre> + +<p><strong>Chrome では、こんな出力が生成されます:</strong></p> + +<pre>In content script, window.x: 1 +In content script, window.y: 2 +In page script, window.x: undefined +In page script, window.y: undefined</pre> + +<p><strong>Firefox では、こんな出力が生成されます:</strong></p> + +<pre>In content script, window.x: undefined +In content script, window.y: 2 +In page script, window.x: 1 +In page script, window.y: undefined</pre> + +<p>同じことは <code><a href="/ja/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code>、<code><a href="/ja/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a></code>、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Function">Function()</a></code> にも言えます。</p> + +<div class="blockIndicator warning"> +<p><strong>ページのコンテキストでコードを実行するときは特に注意してください!</strong></p> + +<p>ページの環境が悪意をはらんだウェブページにコントロールされ、期待しない方法であなたが操作するオブジェクトを再定義するかもしれません。</p> + +<pre class="brush: js">// page.js redefines console.log + +var original = console.log; + +console.log = function() { + original(true); +} +</pre> + +<pre class="brush: js">// content-script.js calls the redefined version + +window.eval('console.log(false)'); +</pre> +</div> |