LDR上ではてなブックマーク拡張を使ってはてブコメントを見るuserChrome.js
以前書いた、LDRではてなブックマーク拡張を通してはてブのコメントをみるTomblooパッチをuserChrome.jsを使って書き直してもっと使い易くしたものです。
概要的にははてなブックマーク拡張のコメントビューアー機能をuserChrome.jsからよびだしてLDRの記事についてるはてブコメントを表示するものです。(なのではてなブックマーク拡張はインストールしてないと使えません)
記事にフォーカスがあった状態でmを押すとはてなコメントビューアーが開きます。
jを押すと(次の記事に移動ショートカット)コメントビューアーが開いてたときは閉じるようにしてあります。
以下、技術的な話
まず、userChrome.jsをどうデバッグすればいいのか忘れたので、とりあえずFirebugのコンソールへ吐くlog関数を用意した。
// firebugのコンソールに出力 function fbug(x) { var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator); var Firebug = windowManager.getMostRecentWindow("navigator:browser").Firebug; if (Firebug.Console.isEnabled() && Firebug.toggleBar(true, 'console')) { Firebug.Console.logFormatted(Array.slice(arguments)); } return x; }
もっと手軽に呼べたような気がしたけど…
次はChrome側とContent側でやりとりする方法
Chrome側ってのはuseChrome.jsや拡張機能などのいわゆる特権持ってて何でもできてしまう実行範囲のこと
Content側ってのは通常のWebサイトの実行範囲のこと。
Chrome側からContent側をいじろうとすると、XPCNativeWrapperでラップされているのでそのままではアクセスできません。
wrappedJSObjectを使って回避するのはあまり望ましいやり方ではないと思うので、今回はMessageEventを利用してChromeとContentを行き来してみました。
コードの真ん中ら辺のメイン部分だけ取り出してみると
// docはchrome側のdocument // Chrome側 - 受信 doc.addEventListener("hatenaPingMessage", function (request) { var res = request.data; if (res === "hide") { hBookmark.CommentViewer.hide(); } else { hBookmark.CommentViewer.toggle(res); } }, false); // Content側 - 送信 evalInPage(function() { window.addEventListener("load", function() { window.Keybind.add('m', function(evt) { var item = window.get_active_item(true); var permalink = item.link.replace(/#/, '%23'); pingToChrome(permalink); }); var _j = window.Keybind._keyfunc.j;// jを保存してから書き換える window.Keybind.add('j', function(evt) { _j(); pingToChrome("hide"); }); }, false); // Chrome領域へ通知 function pingToChrome(message) { var request = document.createEvent("MessageEvent"); request.initMessageEvent("hatenaPingMessage", true, false, message, location.protocol + "//" + location.host, "", window); document.dispatchEvent(request);// =>hatenaPingMessage } }, []); } function evalInPage(func, args) { var argStr = JSON.stringify(args || []); safeWindow.location.href = "javascript:void " + func + ".apply(null," + argStr + ")"; }
まずはChrome側のdocumentにイベントを待ち受けるhatenaPingMessageというeventを受け取れるにします。
そして、Content側でスクリプトを実行するためにJavaScript:プロトコルハックを使ってブックマークレット的に実行します。
その中で、hatenaPingMessageというオレオレイベントを発火させるpingToChromeを作って、pingToChromeで発火したイベントをChrome側でキャッチしてChrome権限が必要な処理(はてなコメントビューアーを呼び出す)をしています。
Google Chromeの拡張とかで似たような仕組みになってた気がします。
MessageEventとJavaScript:プロトコルハック
Google Chrome関係のメモ
- ユーザースクリプトとページ側とのやりとり – JavaScriptで遊ぶよ – g:javascript
- 拡張間連携とEvent Driven JavaScript – Constellation Scorpius
FirefoxのChromeについてのメモ
- vimperatorからウィンドウにアクセスする方法 – vimpめも – vimperatorグループ
- XPCNativeWrapperとunsafeWindowの間でデータを送受信する | へびにっき
- XPCNativeWrapper – MDC Doc Center
お知らせ欄
JavaScript Primerの書籍版がAmazonで購入できます。
JavaScriptに関する最新情報は週一でJSer.infoを更新しています。
GitHub Sponsorsでの支援を募集しています。