« Firefox Developers Conference Summer 2007 | [userChrome.js] 軽量マウスジェスチャー(ホイールジェスチャ・ロッカージェスチャ対応版) ~途中経過~ » |
about:feeds の置換で自前のXUL製フィードビューアを使う
昨年開催された Firefox Developers Conference にて、 Firefox 2 で新たに搭載された Feed Content Access API を利用した独自フィードビューアの実装例を示したのだが、 Firefox 標準のフィードプレビュー (chrome://browser/content/feeds/subscribe.xhtml) を自前のXUL製フィードビューアに置き換える方法がわからず、やむを得ず自前のXUL製フィードビューアの chrome URL を「はてなRSS」や「livedoor reader」と同じようにWebサービスとして登録し、フィードを読み込むとその chrome URL へ遷移させることでビューアを置き換えるようにしていた。
(詳しくは FeedContentAccessAPI.pdf の「第二段階」を参照)
しかし、 nanto さんによる XPCOM コンポーネントの置換: Days on the Moon のやり方をそのまんま使って「about:feeds」を置換することで、前述のような遠回りなやり方をせずとも、いとも簡単に Firefox 標準のフィードプレビューを自前のXUL製フィードビューアに置き換えることに成功した。「about:feeds」を置換するにあたり、自分で考えてコードを書く必要のある部分はせいぜい nsIAboutModule の newChannel メソッドくらいのもので、以下のように自前のXUL製フィードビューアの chrome URL でチャネルを作って返すだけ。
newChannel: function(aURI) { var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); var channel = ios.newChannel("chrome://sample/content/feedview.xul", null, null); channel.originalURI = aURI; return channel; },
この方法のおいしいところは、 Feed Stream Converter 側でパースした結果を nsIFeedResultService 経由で自前のXUL製フィードビューア側から取り出して使うことができるという点である。前述の苦し紛れの方法(Webサービスとして登録した chrome URL へ遷移)ではそれが不可能なので、遷移した先のXULで XMLHttpRequest とかを使って改めてフィードの取得とパースをしてやる必要があった。
ちなみに nsIFeedResultService とは、 Feed Stream Converter がフィードをパースした結果をグローバルにアクセス可能なオブジェクトとして保持することで、実際にフィードの画面表示を行う Feed Writer から参照できるようにするための XPCOM である。 Feed Stream Converter がパース結果を nsIFeedResultService へ登録する処理の流れは FeedConverter.js の handleResult を見ればわかる。 Firefox 標準のフィードプレビューを使う設定になっている場合、つまり設定値「browser.feeds.handler」が「ask」の場合、 nsIFeedResultService#addFeedResult でパース結果を登録してから「about:feeds」のチャネルを開くのに対して、Webサービスを使用する設定の場合、つまり設定値「browser.feeds.handler」が「web」の場合、 nsIWebContentConverterService#loadPreferredHandler を使って新たな URI をロードし直すだけの処理となっている。
なお、 nsIFeedResultService からのパース結果の取り出し方は、 FeedWriter.js の _getContainer を見ればわかる。
var channel = window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell_MOZILLA_1_8_BRANCH) .currentDocumentChannel; var feedSvc = Cc["@mozilla.org/browser/feeds/result-service;1"] .getService(Ci.nsIFeedResultService); var result = feedSvc.getFeedResult(channel.originalURI); // nsIFeedResult
自作フィードビューワ内でスクリプトを使うなら、getURIFlags()でALLOW_SCRIPTも返したほうがいいかと思います。
また、そもそもこの場合なら、XPCOMコンポーネントの置換を行わなくても、chrome.manifest内でoverride命令を使うことにより置換可能です。
override chrome://browser/content/feeds/subscribe.xhtml chrome://sample/content/feedview.xul
http://developer.mozilla.org/ja/docs/Chrome_Registration#override
なお、MDCの例示内ではchrome.manifestからの相対URIを使って上書きしていますが、これはTrunkでのみ利用可能で、Firefox 2以前では絶対URI (chrome URIを含む)を指定しないといけません。
nantoさん、コメントありがとうございます。
早速 subscribe.xhtml へのオーバーレイを試してみましたが、どうもうまくいきません。そもそも XHTML へのオーバーレイを今までやったことがないのであまり自信がありませんが、何か間違っていますでしょうか。
—
chrome.manifest:
overlay chrome://browser/content/feeds/subscribe.xhtml chrome://sample/content/feedView.xul
—
feedView.xul:
<?xml version="1.0" encoding="UTF-8"?>
<xul:overlay id="feedSubscribeOverlay"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<html id="feedHandler">
<body>
<div>This is test.</div>
</body>
</html>
</xul:overlay>
—
overlayではなくoverrideです。日本語にするとどちらも上書きですが。
—- chrome.manifest
content myfeedpreview content/
override chrome://browser/content/feeds/subscribe.xhtml chrome://myfeedpreview/content/preview.xhtml
—- content/preview.xhtml
Viewing Feed…
Viewing Feed…
すみません、タグが抜けてしまいました。上の例ではXHTMLで置き換えていますが、もちろんXULで置き換えることもできます。
—- chrome.manifest
content myfeedpreview content/
override chrome://browser/content/feeds/subscribe.xhtml chrome://myfeedpreview/content/preview.xul
—- content/preview.xul
<?xml version=”1.0″ encoding=”utf-8″?>
<?xml-stylesheet type=”text/css” href=”chrome://global/skin/”?>
<window xmlns=”http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul”>
<label>Viewing Feed…</label>
</window>
おお、overlayではなくてoverrideでしたね。そんなものがあることをすっかり忘れていました。
さっそく試しに以下のようにすると、
override chrome://browser/content/feeds/subscribe.xhtml chrome://browser/content/bookmarks/bookmarksPanel.xul
確かにブックマークサイドバーのXULへ遷移するのですが、今度は以下のようなエラーが出て怒られてしまいます。
エラー: uncaught exception: Permission denied to get property UnnamedClass.classes
このケースのoverrideではchrome権限で動作しない(?)ということでしょうか。
むう、chrome://original/content/でもchrome://browser/content/feeds/subscribe.xhtmlでも問題ないのに、なぜかabout:feedsだとchrome権限が消えてますね(Fx 2.0.0.4/Trunk 20070618で確認)。どうもバグっぽい挙動ですが。とにかく、この場合この手は使えませんね。すみませんでした。
細かいところはよくわかりませんが、chrome権限の有無がoriginalURIの方をもとに判断しているということのようですね。バグなのか仕様なのか、難しいところです。
どちらにしろabout:feedsの置換方式はばっちりですので、良かったです。
> なぜかabout:feedsだとchrome権限が消えてますね(Fx 2.0.0.4/Trunk 20070618で確認)。どうもバグっぽい挙動ですが。
私の記憶違いでなければ、
デフォルトのフィードリーダーは、最初は about:feeds ではなかったのですが、chrome 権限があるとセキュリティ的にまずいということで(どうまずいのかは理解してませんが)、about:feeds にして chrome 権限を落とすようにしたという経緯があったので、バグではなく意図した挙動だと思います。
Bug 336903 – New feed view run under chrome context
https://bugzilla.mozilla.org/show_bug.cgi?id=336903
これですか。確かに仕様のようですね。
フィード内容の整形にXPCOMコンポーネントを使っていたはずという思い込みから勘違いしていました。実際はBrowserFeedWriterという形でブラックボックス化してましたね。