Greasemonkeyスクリプトとウインドウ間で安全に通信する

追記2008.6.24

イベントによる通信について、nanto_viさんがGreasemonkey スクリプトとイベントで通信: Days on the Moonでより有用でフォーマルな情報を提供されています。



まじめに書こうと思ったら予想より使えなかった。

むかしsnj14がはてなブックマークが勝手にj/kにキー割り当てて、サービスはデータを出すだけにしてUIはユーザが好きにできるようにするべきだっていうのを書いてた気がするけど見つけられませんでした。

自分は、そうはいってもfirefox+Greasemonkey+LDRizeのようなUIの統一を図るスクリプトが極めてマイナーな現状でサービスがいらんことすんなっていうのも、ついていけない正しい話だなーと思ってるので、まずはLDRizeがあったら独自のバインディングをやめる、という妥協策が必要だと思う。そうすればはてなブックマークでj/kを押すけどLDRizeは使ってないひとたちを救済しつつsnj14の理想の世界をまた一歩実現に近づけることができる。



Firebug1.2のconsoleの実装と同じように、てきとうなDOMイベントを作って、それを使って通信すればGreasemonkeyとふつうのウインドウ間でunsafeWindowsを使わずに安全に通信することができてLDRizeがあるかどうかも分かる。

Greasemonkey側で

    document.addEventListener( 'LDRizePing', function (ev) {
       var ev = document.createEvent("Events");
                ev.initEvent("LDRizePong", true, true);
                document.dispatchEvent(ev);
    }, false);

ふつうのwindow側で

window.onload = function () {
    document.addEventListener( 'LDRizePong', function (ev) {
        alert( "LDRize exists!" );
    }, false );
    var ev = document.createEvent("Events");
        ev.initEvent("LDRizePing", true, true);
        document.dispatchEvent(ev);
}

ってやったらLDRizeが存在すればpongがかえってくる。
なんかDOM:element.dispatchEvent - MDCにはイベントハンドラでpreventDefaultしたらfalseになるよって書いてあるけどDOMeventだからなのか、常にtrueが返ってきました。
cancelableでinitEventしないと(第3引数をtrueにしないと)preventDefaultしてもfalseになりません(nanto_viさんありがとうございます)。1bitですむ通信ならこれで可能。


リスナがいてもいなくても常にいないときもtrueでした。

あとgreasemonkeyがDOMContentReadyまで実行されないのでふつうのウインドウはそれよりあとまで待たないといけない。onloadはやだからDOMContentReadyでsetTimeoutして実行とかが一番いいけどひどい実装だ。



GM <-> chrome ではprefをwatchするといいとか、そういうのと似たようなアプローチ。JUIのときにinucaraさんがAutoPagerizeにまかせるか自分でやるか迷ったけど自分で実装する方にした、というはなしをされてたので思い出してこうしたら存在するかが分かるっていうのを書こうと思いつつ書いてなかったけど、いまごろなんか思い出した。


AutoPagerizePingとかLDRizePingとか増えるたびに増やしてたら相手にしてられないので、もっとおおざっぱにjsでUIを作るようなのをdisableにするかどうかくらいの粒度にするべきか。


まずはGMスクリプトの側が存在するかどうかをチェックできる手段を用意してあげるべきだと思う。