Now browsing the SCRAPBLOG weblog archives.

[userChrome.css] ブックマークメニューのショートカットキーを表示しない

ブックマークメニューの「ブックマークの管理…」の横にある「Ctrl+Shift+B」のようなショートカットキーの表示が意外と幅を取って邪魔なので、 userChrome.css にて非表示にする。下記コードは Firefox 3 専用。

userChrome.css

/* [Firefox3] ブックマークメニューのショートカットキーを表示しない */
#bookmarksMenuPopup .menu-accel {
    display: none !important;
}

適用前

適用後

TOP

contenteditable 属性

position: absolute; な要素に対して Firefox 3 で導入された contenteditable="true" 属性を付加すると、内容の編集以外にもその要素をドラッグ&ドロップで位置を変更したり、リサイズしたりすることが可能。
テストケース

Firefox 3 でのセキュリティに関する変更 (Web ページからの chrome コンテントへのアクセスがデフォルトで制限される) 影響で、 ScrapBook の付箋アノテーション機能が壊れていた。 chrome.manifest で contentaccessible フラグを使えばこの制限を解除できるが、せっかくなのでこの機会に前から考えていた contenteditable 属性を使って付箋アノテーション機能を改善してみた。

TOP

[userChrome.css] ダウンロードマネージャのファイル名の文字サイズを調整

Firefox 3 で一新されるダウンロードマネージャで、ファイル名の文字サイズがやや大きめになっている。日本語版 Windows XP ではどうもしっくりこない気がするので、 userChrome.css によって普通の文字サイズに変更し、ついでに太字で強調する。

userChrome.css

/* [Firefox3] ダウンロードマネージャのファイル名 */
#downloadView label.name {
    font-size: 1em !important;
    font-weight: bold;
}

適用前

適用後

TOP

[userChrome.css] ロケーションバーのポップアップのタイトルの文字サイズを調整

Firefox 3 の新機能のひとつである、ロケーションバーに入力した文字列にマッチする候補を表示する機能(いわゆる awesomebar)で、ポップアップ中のタイトルの文字サイズがやや大きめになっている。日本語版 Windows XP だとどうもしっくりこない気がするので、 userChrome.css によって普通の文字サイズに変更する。

userChrome.css

/* [Firefox3] ロケーションバーのポップアップのタイトルの文字サイズ */
#PopupAutoCompleteRichResult .ac-normal-text {
    font-size: 1em !important;
}

適用前

適用後

TOP

[Exception… “‘Component is not available’ when calling method: [nsIHandlerService::getTypeFromExtension]

2008/5/3 追記
この問題は解決済みです。

Firefox 3にて、XULから <script type="application/x-javascript" src="chrome://myext/content/test.js" /> のようにして JavaScript を読み込む際、その JavaScript ファイルがjar形式アーカイブの中身ではなくて純粋なローカルファイルである場合(つまり chrome.manifest にて content myext content/myext/ のようにしている場合)、以下の例外がエラーコンソールに出力される。

エラー: [Exception… “‘Component is not available’ when calling method: [nsIHandlerService::getTypeFromExtension]” nsresult: “0x80040111 (NS_ERROR_NOT_AVAILABLE)” location: “” data: no]

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9pre) Gecko/2008042606 Minefield/3.0pre

TOP

nsIWebBrowserPersist の基本的な使い方 (5) ~ ダウンロード進捗状況

nsIWebBrowserPersist で HTTP によってダウンロードする際、ダウンロードの進捗状況を監視する。
サンプルコードは nsIWebBrowserPersist の基本的な使い方 (1) ~ 基本形 をベースとしており、一部省略しています。

saveURI の場合

nsIWebBrowserPersist の progressListener プロパティに nsIWebProgressListener インタフェースを実装したオブジェクトを自前で作成してセットすると、ダウンロードの状況の変化によって以下のメソッドが呼び出される。

メソッド名 呼び出されるタイミング
onStateChange 引数 aStateFlags の値を調べ、 nsIWebProgressListener.STATE_START フラグが立っている場合はダウンロード開始、 nsIWebProgressListener.STATE_STOP フラグが立っている場合はダウンロード終了。
onProgressChange ダウンロード進行中に呼び出される。引数 aCurSelfProgress, aMaxSelfProgress の値を調べることで、合計何バイト中の何バイトをダウンロードしたかがわかる。
onLocationChange 呼び出し無し。(xul:tabbrowser 要素の持つ nsIWebProgress オブジェクト専用?)
onStatusChange
onSecurityChange
wbp.progressListener = {
    // implements nsIWebProgressListener
    onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) {
        if (aStateFlags & Ci.nsIWebProgressListener.STATE_START)
            dump("started
");
        if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP)
            dump("stopped
");
    },
    onProgressChange: function (aWebProgress, aRequest,
                                aCurSelfProgress, aMaxSelfProgress,
                                aCurTotalProgress, aMaxTotalProgress) {
        dump("downloading... " + aCurSelfProgress + "/" + aMaxSelfProgress + "
");
    },
    onLocationChange: function (aWebProgress, aRequest, aLocation) {},
    onStatusChange  : function (aWebProgress, aRequest, aStatus, aMessage) {},
    onSecurityChange: function (aWebProgress, aRequest, aState) {},
};

saveChannel の場合

saveURI の場合と異なり、なぜか nsIWebProgressListener の onProgressChange メソッドが呼び出されない。代わりに、 nsIChannel の notificationCallbacks プロパティに nsIProgressEventSink インタフェースを実装する。
参考: nsIWebBrowserPersist.saveChannel – やんばるもじら

channel.notificationCallbacks = {
    QueryInterface: function (aIID) {
        if (aIID.equals(Ci.nsIProgressEventSink))
            return this;
        Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
        return null;
    },
    // implements nsIInterfaceRequestor
    getInterface: function (aIID, aInstance) {
        return this.QueryInterface(aIID);
    },
    // implements nsIProgressEventSink
    onProgress: function (aRequest, aContext, aProgress, aProgressMax) {
        dump("downloading... " + aProgress + "/" + aProgressMax + "
");
    },
    onStatus: function (aRequest, aContext, aStatus, aStatusArg) {},
};

nsIChannel.notificationCallbacks プロパティは nsIInterfaceRequestor 型であり、 nsIChannel オブジェクトに発生する様々なイベントに応じて、まずはじめに getInterface メソッドが呼び出される。 getInterface メソッドは引数にて指定されたインタフェースへと QI して返すだけ。

なお、 nsIChannel.asyncOpen によって要求開始した場合、 notificationCallbacks に nsIRequestObserver インタフェースを実装することで、要求開始時と要求終了時に onStartRequest, onStopRequest メソッドが呼び出されるが、 nsIWebBrowserPersist.saveChannel によるダウンロードではこの呼び出しは発生しない。

別の方法として、 notificationCallbacks プロパティに nsIWebBrowserPersist オブジェクト自体をセットする手もあるようだ。

wbp.progressListener = {
    /* snip */
};

channel.notificationCallbacks = wbp;

参考

nsIWebProgressListener.idl
nsIInterfaceRequestor.idl
nsIProgressEventSink.idl

関連記事

nsIWebBrowserPersist の基本的な使い方 (1) ~ 基本形
nsIWebBrowserPersist の基本的な使い方 (2) ~ persistFlags
nsIWebBrowserPersist の基本的な使い方 (3) ~ 各種ヘッダの追加
nsIWebBrowserPersist の基本的な使い方 (4) ~ POST メソッド
nsIWebBrowserPersist の基本的な使い方 (5) ~ ダウンロード進捗状況
つづく…?

TOP

nsIWebBrowserPersist の基本的な使い方 (4) ~ POST メソッド

HTTP の POST メソッドで Web サーバへ要求し、その回答結果をファイルへ保存する。
ほとんど nsIHttpChannel の使用がメインですので、ファイル保存する場合以外にも応用可能です。
また、サンプルコードは nsIWebBrowserPersist の基本的な使い方 (1) ~ 基本形 をベースとしており、一部省略しています。

saveURI の場合

saveURI の第4引数 aPostData を使えばできるはずだが、現在調査中…

saveChannel の場合

例によって nsIURL オブジェクトから nsIHttpChannel オブジェクトを生成する。

// make nsIHttpChannel
var ioSvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
var channel = ioSvc.newChannelFromURI(url).QueryInterface(Ci.nsIHttpChannel);

POST するデータは以下のような文字列とする。以下の場合は文字列全体を単純に encodeURI 関数で URL エンコードすれば良いが、キーや値に & や = を含む場合を考慮した、より一般的な URL エンコードの方法については後述する。

var postStr = encodeURI("foo=bar&baz=eek&名前=太郎");

POST する文字列から nsIStringInputStream を生成し、 nsIHttpChannel を nsIUploadChannel へ QI してからストリームをセットする。今回の例では Content-type は application/x-www-form-urlencoded だが、 XML データを POST する場合などは適宜 application/xml とかにする。

// make nsIStringInputStream to post
var inputStream = Cc["@mozilla.org/io/string-input-stream;1"]
                  .createInstance(Ci.nsIStringInputStream);
inputStream.setData(postStr, postStr.length);

// set nsIStringInputStream to nsIUploadChannel
var uploadChannel = channel.QueryInterface(Ci.nsIUploadChannel);
uploadChannel.setUploadStream(inputStream, "application/x-www-form-urlencoded", -1);

nsIWebBrowserPersist で送信する前に、 nsIHttpChannel オブジェクトの requestMethod プロパティを POST にするのを忘れずに。これをしないと、なぜか PUT メソッドでの要求になってしまう。

// must do this otherwise request method will be "PUT"
channel.requestMethod = "POST";

// save channel to file
var wbp = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
          .createInstance(Ci.nsIWebBrowserPersist);
wbp.saveChannel(channel, file);

POST する文字列の URL エンコード

POST する文字列がユーザからの入力である場合、 & や = を含む場合を考慮し、以下のように encodeURIComponent を使って URL エンコードする。

// make string to post
var postObj = {
    "foo": "bar",
    "baz": "eek",
    "名前": "山田=太郎&花子",
};
var pairs = [];
for (var [key, val] in Iterator(postObj)) {
    pairs.push(encodeURIComponent(key) + "=" + encodeURIComponent(val));
}
var postStr = pairs.join("&");

関連記事

nsIWebBrowserPersist の基本的な使い方 (1) ~ 基本形
nsIWebBrowserPersist の基本的な使い方 (2) ~ persistFlags
nsIWebBrowserPersist の基本的な使い方 (3) ~ 各種ヘッダの追加
nsIWebBrowserPersist の基本的な使い方 (4) ~ POST メソッド
nsIWebBrowserPersist の基本的な使い方 (5) ~ ダウンロード進捗状況
つづく…?

TOP

FireGestures キープレスジェスチャの機能割り当て

現在のところ、 FireGestures のキープレスジェスチャは、以下のように割り当てが固定されていた。

  • Shift キーを押しながらマウスジェスチャ: マウスが通過したリンクをタブで開く
  • Ctrl キーを押しながらマウスジェスチャ: マウスが通過したリンク先を保存する

しかし、 AMO のディスカッション Is it possible to harmonize Keypress gestures ? にて、 Firefox の標準動作では、

  • リンク上で Ctrl + クリック: リンクをタブで開く
  • リンク上で Alt + クリック: リンク先を保存する

なので、これに合わせて以下のような割り当てにしたらどうかという提案があった。

  • Ctrl キーを押しながらマウスジェスチャ: マウスが通過したリンクをタブで開く
  • Alt キーを押しながらマウスジェスチャ: マウスが通過したリンク先を保存する

なるほど確かにこれは理にかなっていると思ったが、残念なことに Linux では Alt キーを押しながらの右クリックはアプリケーションのコンテキストメニューを表示するための特別な役割があるようで、リンク上で Alt + クリックや、 Alt キーを押しながらのジェスチャができないことがわかった。

やはり、キープレスジェスチャは Ctrl / Shift キー、ということにするしかなさそうだ。

TOP

[userChrome.js] リアルタイムタブプレビュー

タブ上にマウスをかざすと、サムネイルプレビューをリアルタイムに表示する userChrome.js 用スクリプトです。
Opera や Seamonkey にある機能とほぼ同じですが、サムネイルのプレビューを一定間隔で更新するので、読み込み中のタブの状態を、タブを切り替えることなくチェックしたりできます。
スクリプトはこちら: xuldev.org :: userChrome.js scripts » Tab Preview

Tab Preview

userChrome.js スクリプト配布ページ

これまでに掲載した userChrome.js 用スクリプトを整理して配布ページを作りました。
いくつかのスクリプトを新たに追加し、これまでのスクリプトも一通り見直して修正しています。
xuldev.org :: userChrome.js scripts

TOP

nsIWebBrowserPersist の基本的な使い方 (3) ~ 各種ヘッダの追加

リファラを指定する

事前準備として、リファラの URL 文字列から nsIURL オブジェクトを生成する。

var refURL = Cc["@mozilla.org/network/standard-url;1"].createInstance(Ci.nsIURL);
refURL.spec = "http://www.itmedia.co.jp/";
saveURI の場合

saveURI メソッドの第3引数 aReferrer に nsIURI オブジェクトを指定することでリファラをセットできる。
Live HTTP Headers で要求時のヘッダを見ると、「Referer: http://www.itmedia.co.jp/」というヘッダが付いている。

wbp.saveURI(url, null, refURL, null, null, file);
saveChannel の場合

nsIHttpChannel の referrer プロパティに nsIURI オブジェクトを指定する。

channel.referrer = refURL;

任意のヘッダを指定する

saveURI の場合

saveURI メソッドの第5引数 aExtraHeaders にヘッダを文字列として指定すると、HTTP要求時にそのヘッダを追加できる。
ヘッダは「Foo: bar
」のような形式で指定する。ただし、既存ヘッダを上書きすることはできず、必ず追加される。
例えば以下のようにすると、「Accept-Encoding: gzip,deflate, xxx」となる。

wbp.saveURI(url, null, null, null, "Accept-Encoding: xxx
", file);
saveChannel の場合

nsIHttpChannel では、 setRequestHeader メソッドで自由にヘッダを追加できる。
第3引数 aMerge を true にすると既存ヘッダを上書きせずに追加し、 false にすると既存ヘッダを上書きする。

channel.setRequestHeader("User-Agent", "HTTP Downloader", false);

以下のようにすると、「Accept-Encoding」ヘッダ自体を送らなくすることができる。

channel.setRequestHeader("Accept-Encoding", null, false);

関連記事

nsIWebBrowserPersist の基本的な使い方 (1) ~ 基本形
nsIWebBrowserPersist の基本的な使い方 (2) ~ persistFlags
nsIWebBrowserPersist の基本的な使い方 (3) ~ 各種ヘッダの追加
nsIWebBrowserPersist の基本的な使い方 (4) ~ POST メソッド
nsIWebBrowserPersist の基本的な使い方 (5) ~ ダウンロード進捗状況
つづく…?

TOP