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

TOP

9 Comments to “about:feeds の置換で自前のXUL製フィードビューアを使う”

自作フィードビューワ内でスクリプトを使うなら、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&quot;
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"&gt;
<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という形でブラックボックス化してましたね。

TOP

TOP