コードが機能しない理由を理解するために、以前の回答の一部を含めます。
window
コンテンツ スクリプトは、ページのグローバルオブジェクトにアクセスできません。コンテンツ スクリプトの場合、以下が適用されます。
- 変数は、
window
ページのグローバル オブジェクトを参照していません。代わりに、ページ上の「レイヤー」という新しいコンテキストを参照します。ページの DOM は完全にアクセス可能です。#実行環境
で構成されるドキュメントが与えられた場合 <iframe id="frameName" src="http://domain/"></iframe>
:
- フレームのコンテンツへのアクセスは、ページの同一オリジン ポリシーによって制限されます。拡張機能のアクセス許可は、ポリシーを緩和しません。
frames[0]
とframes['frameName']
、(通常はフレームに含まれるグローバルwindow
オブジェクトを参照) はundefined
です。
var iframe = document.getElementById('frameName');
iframe.contentDocument
document
コンテンツ スクリプトはページの DOM にアクセスできるため、含まれているフレームのオブジェクトを返します。このプロパティはnull
、Same origin ポリシーが適用される場合です。
iframe.contentDocument.defaultView
(window
ドキュメントに関連付けられたオブジェクトを参照) はundefinedです。
iframe.contentWindow
未定義 です。
同じ起源のフレームの解決策
あなたの場合、次のいずれかが機能します。
// jQuery:
$("#iframe1").contents()[0].execCommand( ... );
// VanillaJS
document.getElementById("iframe1").contentDocument.execCommand( ... );
// "Unlock" contentWindow property by injecting code in context of page
var s = document.createElement('script');
s.textContent = 'document.getElementById("iframe1").contentWindow.document.execCommand( ... );';
document.head.appendChild(s);
一般的なソリューション
一般的な解決策は"all_frames": true
、マニフェスト ファイルで使用しており、次のようなものを使用します。
if (window != top) {
parent.postMessage({fromExtension:true}, '*');
addEventListener('message', function(event) {
if (event.data && event.data.inserHTML) {
document.execCommand('insertHTML', false, event.data.insertHTML);
}
});
} else {
var test_html = 'test string';
// Explanation of injection at https://stackoverflow.com/a/9517879/938089 :
// Run code in the context of the page, so that the `contentWindow`
// property becomes accessible
var script = document.createElement('script');
script.textContent = '(' + function(s_html) {
addEventListener('message', function(event) {
if (event.data.fromExtension === true) {
var iframe = document.getElementById('iframe1');
if (iframe && (iframe.contentWindow === event.source)) {
// Window recognised, post message back
iframe.contentWindow.postMessage({insertHTML: s_html}, '*');
}
}
});
} + ')(' + JSON.stringify(test_html) + ');';
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
}
このデモは教育のみを目的としています。このデモを実際の拡張機能で使用しないでください。なんで?postMessage
メッセージをやり取りするために使用されるためです。これらのイベントは、セキュリティ リーク (XSS: 任意の HTML インジェクション) を引き起こすクライアントによっても生成される可能性があります。
代替手段postMessage
は Chrome のメッセージ API です。デモについては、この回答を参照してください。window
ただし、オブジェクトを比較することはできません。あなたができるwindow.name
ことは、プロパティを信頼することです。プロパティは、iframeの属性window.name
の値に自動的に設定されname
ます (iframe が読み込まれるときに 1 回だけ)。