「Greasemonkeyスクリプトとウインドウ間で安全に通信する」にて、DOM イベントを用いた Web ページと Greasemonkey スクリプトとの通信について述べられています。そちらでは dispatchEvent メソッドの返り値による 1 bit 通信に触れていますが、やはりもっと自由にデータをやり取りしたいもの。そのためにはどのような方法があるでしょうか。
真っ先に思いつくのは、Web ページ側でイベントオブジェクトを作成した際、独自プロパティを追加する方法ですが、これはだめです。Greasemonkey スクリプト側ではイベントオブジェクトの独自プロパティを取得できません。event.wrappedJSObject.myProperty
のように wrappedJSObject を介せば取得できますが、せっかく安全のため Firefox 側でラッパーに包んでくれたのに、それを外すべきではありません。wrappedJSObject は危険です。
こんなこともあろうかと DOM 3 Events 草案では CustomEvent というイベントが用意されています。これを使えばイベントオブジェクトに独自のデータを保持できます。しかし、Firefox 3 は DOM 3 Events に対応していません。終了。
Firefox 3 では新しく CommandEvent というイベントに対応しています。これは XUL での利用を考えて追加されたものですが、Web ページから作成することもできます。CommandEvent には文字列型の command プロパティがあるので、ここにデータを格納できます。JSON などを使えば複雑な構造のデータもやり取り可能です。
// Greasemonkey スクリプト
document.addEventListener("GMPingCommand", function (request) {
var response = document.createEvent("CommandEvent");
response.initCommandEvent("GMPongCommand", true, false,
'You said "' + request.command + '"');
document.dispatchEvent(response);
}, false);
// Web ページ
window.addEventListener("load", function (event) {
var request = document.createEvent("CommandEvent");
request.initCommandEvent("GMPingCommand", true, false,
"Hello, world!");
document.dispatchEvent(request);
}, false);
document.addEventListener("GMPongCommand", function (response) {
alert(response.command); // => You said "Hello, world!"
}, false);
Firefox 3 では新しく DataContainerEvent というイベントに対応しています。これも XUL での利用を考えて追加されたものですが、Web ページから作成することもできます。DataContainerEvent に専用の初期化メソッドはありませんが、getData メソッドと setData メソッドがあります。つまり、このイベントオブジェクトは辞書として扱えるのです。基本的に任意の型の値を格納できますが、Web ページと Greasemonkey スクリプトの間で使おうとするとセキュリティ制限がかかります。
Web ページで値を設定し、Greasemonkey スクリプトでそれを取得する場合、プリミティブ値 (undefined、null、文字列値、数値、真偽値) はそのまま取得できますが、JavaScript のオブジェクトや配列は取得できず null が返ります。Window オブジェクトや DOM ノードオブジェクトはラッパーに包まれます。なお、存在しないキーの値を取得しようとすると null が返ります。
逆に、Greasemonkey スクリプトで値を設定し、Web ページでそれを取得する場合、JavaScript のオブジェクトや配列もそのまま返されます。しかし、権限の異なるオブジェクトをさらすことになるので、データのやり取りはプリミティブ値のみにとどめるべきでしょう。Window オブジェクトや DOM ノードオブジェクトに関しては、ラッパーを値に設定してもラッパーが外されて返されます。
セコメントをする