イベントの抜け道
windowの共有の次は、スクリプト間のイベント伝播だ。GM_AutoPagerizeLoaded、GM_MinibufferLoadedのような専用イベントを用意しても、スクリプト間では伝播されないようになったので(同じスクリプト内ならイベントも伝播する。MinibufferとLDRizeを同じスクリプトにつっこんだら動く、というのもそういうことだ)、どうにかしてこれを伝播可能にしたい。
似たような事例というのは案外転がっているもので、ググっていたらこういうの(http://wp.serpere.info/archives/1107)に行き当たった。
XPCNativeWrapperの外側でスクリプトを評価する関数。Firebugも同じことをしている。unsafeWindowを触らないので安全。
function evalInPage(fun) {location.href = "javascript:void (" + fun + ")()";
}
これは面白い!Function.prototype.toString が関数のソースコードを返すことを利用した、巧妙にして簡潔なハック。
次のように引数を渡せるように改良すればさらに強力になる(引数に渡せるのはJSON化可能な値のみ)。
function evalInPage(func, args) {var argStr = JSON.stringify(args || []);
location.href = "javascript:void "+ func +".apply(null,"+ argStr +")";
}
http://wp.serpere.info/archives/1107
GM_xmlhttpRequest を使って別ドメインから得たデータを、unsafeWindow 上のライブラリを使って表示する、といったコードが安全かつ自然に書けるようになる。
つまり、スクリプトから実行してうまくいかないんなら、ページ側で実行してもらいましょう、という話。今回のスクリプトにしても、元ページの初期化関数にタダ乗りするようにしたのは、このページを見たおかげ。
課題とか
こいつを上手くMinibufferあたりに組み込んでやると、イベントの発火は可能になる。ページ側での実行になるのでLDRize等の他のスクリプトからイベントを参照することも可能だ、というところまでは確認した。イベントの授受は元々非同期前提の動作なので、そのへんも問題ない。
残る問題はAutoPagerizeのほう。普通に動かすだけなら今でも問題ないが、イベント伝播も元通りにしようとするといささか困った点が出てくる。GM_AutoPagerizeLoadedとGM_AutoPagerizeNextPageLoadedのふたつのイベントはごく普通のイベントなので問題はない。
今回APIを使ったのもそのあたりが原因で、MutationイベントであるAutoPagerize_DOMNodeInsertedをページ側で実行してもらおうとしたとき、発火対象ノードを一意に定める必要が出てくる。このイベントは実質AutoPagerizeのAPIみたいなもんで、これに対してaddEventListnerを設定することで新しく追加されたノードをいじれて、非常に使いやすい。
ノードそのものはJSON化不可なので、引数にしたところで意味がない。思いつく範囲では、ページ側に渡すスクリプトに、セレクタを利用するquerySelectorや、XPathを使うevaluateなどを用いたノード特定用の部品を組み込めばいいのだろうが……。少なくとも、テキストノードを選択することがうまく出来ないquerySelectorのほうは、選択肢から除外して良さそうだ。