Firefox への Feedly Cloud 用フィードリーダー追加

Google Reader から Feedly Cloud へ乗り換えしたので、 Firefox のブックマークメニューの「このページを購読...」からフィードを追加できるようにした。

手順

(1) Firefox で Feedly Could を開く。

(2) Feedly Could を開いたタブで、スクラッチパッド(「ツール」→「Web 開発」→「スクラッチパッド」)を開く。

(3) 以下のコードを貼り付けて、「実行」する。

navigator.registerContentHandler(
    "application/vnd.mozilla.maybe.feed",
    "http://cloud.feedly.com/#subscription/feed/%s",
    "feedly"
);

(4) タブ内の上部に「"feedly" (cloud.feedly.com) をフィードリーダーとして追加しますか?」と通知バーが表示されるので、「フィードリーダーを追加」ボタンをクリックする。

(5) 以降、何らかのフィードを開いてブックマークメニューから「このページを購読...」を選択すると、フィードリーダーの一覧に「feedly」が表示されるようになる。

navigator.registerContentHandler によるフィードリーダーの追加は、現在開いているページと同一ドメインでないと許可されないので、必ず上記(1)の手順で Feedly Could を開いておくことが重要。

別解

エラーコンソールを開いて下記のコードを実行する。この場合、前述のような同一ドメインの制約はない。

Components.classes["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Components.interfaces.nsIWebContentHandlerRegistrar).
registerContentHandler(
    "application/vnd.mozilla.maybe.feed",
    "http://cloud.feedly.com/#subscription/feed/%s",
    "feedly",
    null
);

参考

Firefox へのフィードリーダーの追加 | MDN

TOP

nsIZipWriter を使ってフォルダ丸ごと圧縮

前提

・Firefox 21~24.0a1
・変数 srcDir は圧縮元フォルダの nsILocalFile オブジェクト
・変数 zipFile は圧縮先ファイルの nsILocalFile オブジェクト
srcDir の中身のファイルをすべて圧縮して新規のアーカイブ zipFile を生成する

nsIZipWriter インスタンス生成

はじめに nsIZipWriter インスタンスを生成し、 open メソッドで圧縮先ファイルを開く。
圧縮率はデフォルト(レベル6)とする。

// |zipFile| is a nsILocalFile object corresponding to the zip file
var zipWriter = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter);
const PR_WRONLY = 0x02;
const PR_CREATE_FILE = 0x08;
zipWriter.open(zipFile, PR_WRONLY | PR_CREATE_FILE);
var zipLevel = Ci.nsIZipWriter.COMPRESSION_DEFAULT;

フォルダ/ファイルのエントリ追加

srcDir を起点に、フォルダ内のファイルへ再帰的にアクセスする。

(function(dir) {
    var fileEnum = dir.directoryEntries;
    while (fileEnum.hasMoreElements()) {
        var file = fileEnum.getNext().QueryInterface(Ci.nsILocalFile);
        if (file.isDirectory()) {
            // [ToDo]            
            // go to sub folder recursively
            arguments.callee.call(this, file);
        }
        else if (file.isFile()) {
            // [ToDo]            
        }
    }
}).call(this, srcDir);
// |srcDir| is a nsILocalFile object corresponding to the folder where will be archived

変数 file がフォルダなら、 addEntryDirectory でエントリを追加する。第3引数 false だと即座に圧縮される。
変数 file がファイルなら、 addEntryFile でエントリを追加する。第4引数 false だと即座に圧縮される。
変数 file が通常のフォルダでもファイルでもなく、ショートカット(シンボリックリンク)などの場合は何もしない。

エントリ名は、圧縮元フォルダを起点にした圧縮元ファイルのパス。例えば、圧縮元ファイルのパスが「C:\Users\Hoge\SourceDirectory\AAA\BBB\ccc.txt」なら、エントリ名は「AAA/BBB/ccc.txt」となる。フォルダの場合はエントリ名の末尾に「/」を付ける。

        var entry = file.path.substr(srcDir.path.length + 1).replace("\\", "/", "g");
        if (file.isDirectory()) {
            entry += "/";
            zipWriter.addEntryDirectory(entry, file.lastModifiedTime * 1000, false);
            // go to sub folder recursively
            arguments.callee.call(this, file);
        }
        else if (file.isFile()) {
            zipWriter.addEntryFile(entry, zipLevel, file, false);
        }

最後に圧縮先ファイルを閉じる。

zipWriter.close();

processQueue を使って後からまとめて圧縮

addEntryDirectory, addEntryFile の最後の引数を true にすると、その時点では圧縮されず、後で processQueue メソッド呼び出し時にまとめて圧縮される。

        if (file.isDirectory()) {
            entry += "/";
            zipWriter.addEntryDirectory(entry, file.lastModifiedTime * 1000, true);
            arguments.callee.call(this, file);
        }
        else if (file.isFile()) {
            zipWriter.addEntryFile(entry, zipLevel, file, true);
        }

processQueue の第1引数には nsIRequestObserver オブジェクトを渡す。
nsIRequestObserver は最初のファイル圧縮前に呼び出される onStartRequest と、最後のファイル圧縮後に呼び出される onStopRequest メソッドを持つ。

    zipWriter.processQueue({
        onStartRequest: function(aReuqest, aContext) {
        },
        onStopRequest: function(aRequest, aContext) {
            zipWriter.close();
        },
    }, null);

TOP

xul:textbox を最終行までスクロールする

multiline="true" な複数行の xul:textbox 要素を最終行までスクロールする。

// assuming that elt is a xul:textbox element
elt.inputField.scrollTop = elt.inputField.scrollHeight;

TOP

XUL Document をタブで開いたときにタブにアイコンを表示する

アドオンマネージャ(about:addons)をタブで開いたとき、タブにアドオンを示すパズルピース型のアイコンが表示される。これを自分の拡張機能でも実現したい。

まず、XUL Document 内にXHTML名前空間でlinkタグを埋め込む。

<window title="My Add-on"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">

    <xhtml:link rel="shortcut icon" href="chrome://myaddon/skin/icon.png" />

    ...

</window>

これだけだとなぜかXULのレイアウトがバグるので、CSSでlinkタグを非表示にする。

    <xhtml:link rel="shortcut icon" href="chrome://myaddon/skin/icon.png" style="display: none;" />

TOP

xul:prefwindow の設定ダイアログにヘルプボタンを表示する

Firefox 本体の「オプション」ダイアログのように、 xul:prefwindow 要素で作った設定ダイアログに、「ヘルプ」ボタンを表示したい。

xul:prefwindow の buttons 属性?

xul:prefwindow 要素の buttons 属性の説明を読むと、表示したいボタンをカンマ区切りで指定する、と書いてあるので以下のようにしてみた。しかし、OKボタン・キャンセルボタンは表示されるものの、ヘルプボタンは表示されなかった。

<prefwindow buttons="accpet,cancel,help">

ちなみに、 xul:dialog 要素のダイアログであれば、上記方法でもヘルプボタンが表示される。

xul:prefpane の helpURI 属性?

xul:prefpane 要素の helpURI 属性の説明を読むと、設定用パネルに関連付けられた URI を指定する、と書いてあるので以下のようにしてみた。しかし、依然としてヘルプボタンは表示されなった。

<prefpane helpURI="http://www.example.com/">

xul:prefpane の helpTopic 属性!

MDC のドキュメントには説明が無いが、以下のように各設定パネル(xul:prefpane 要素)に helpTopic 属性を指定することで、ようやくヘルプボタンの表示が可能となった。なお、 helpTopic の値は各設定パネルを識別可能な文字列を適当に入れておけばよい。

<prefpane helpTopic="general">

別解

別解として、スクリプトを使って動的にヘルプボタンを見えるようにする方式もある。

<prefwindow onload="document.documentElement.getButton('help').hidden = false;">

余談

設定ダイアログに一切のボタンを表示させたくない場合、 xul:prefwindow 要素の buttons 属性にカンマ一文字を指定する。

<prefwindow buttons=",">

ヘルプボタンクリック時の動作

次に、ヘルプボタンをクリックして、特定のURLをブラウザで開くようにする。
ヘルプボタンクリック時の動作は xul:prefwindow 要素の ondialoghelp 属性に指定する。

<prefwindow ondialoghelp="openHelpURI();">

URLをブラウザで開く際、設定ダイアログがモーダル(instantApply が false)の場合は新しいウィンドウで、モードレス(instantApply が true)の場合は新しいタブで開きたい。そこで、 chrome://browser/content/utilityOverlay.js を読み込んでおくと色々面倒なことを解決してくれる openUILinkIn というユーティリティ関数が使えるようになる。ただし Firefox のアドオン限定。

<script type="application/x-javascript" src="chrome://browser/content/utilityOverlay.js" />
<script type="application/x-javascript"><![CDATA[
    function openHelpURI() {
        var where = document.documentElement.instantApply ? "tab" : "window";
        openUILinkIn("http://www.example.com/", where);
    }
]]></script>

TOP