Category Archives: Firebug

Firebug

Firebug 1.2 ‘console’ implementation 和訳

Firebug – Web Development Evolved » Blog Archive » Firebug 1.2 ‘console’ implementationの和訳です。

実装はソースコードに書いてあるのそのまま(あたりまえ)。webページに書かれてある悪意あるコードを特権つきで実行しないようにするための細工だっていうことがわかったところが収穫でした。

Firebug 1.2 ‘console’ implementation

FF3betaでFirebugの1.1のコマンドが動かなくなりました。これを直すのがすごい難しくてコマンドラインとコンソールを作り直す必要がありました。はじめにコンソールについて書いて、次回コマンドラインの実装について書きます(訳注:けっきょく2008.5.16現在まだ書かれてないです)。

Firebugの’console’を使ってWeb開発者はテキストやオブジェクトをFirebugのコンソールパネルに出力することができます。新しいバージョンは emelement messaging を使っています。webページの要素を使ってFirebugに制御フローと値を渡す、っていう意味です。こんなかんじで動きます。

Webページがロードされてからはじめのjavascript関数が呼ばれたりする前に document.createElement() を使ってページにscriptタグを仕込みます。スクリプトは_firebugConsoleという見えないdiv要素とconsole関数を追加します。Webページの開発者が console.log("foo"); を呼ぶとlog()関数は

  1. "foo"という文字列をconsoleのユーザオブジェクトの配列に書き込みます。
  2. _firebugConsole要素のひとつの属性に"foo"オブジェクトのインデックスを書き込みます。
  3. _firebugConsole要素のfirebugAppendConsoleイベントをディスパッチします。

これらは全部標準のDOM操作です。

Firebug側ではfirebugAppendConsoleイベントリスナを_firebugConsole要素に追加しておきます。イベントがやってきたら、要素の属性を使ってユーザーオブジェクトにアクセスしてそれをFirebugのコンソールパネルに書き込みます。

FirebugはユーザーオブジェクトにアクセスすることでFirefoxのセキュリティラッパーテクノロジーを使って、おかしなウェブのコードがextension空間に入ってくるのを防いでいます。

いま(1.2a13)の実装にはもうひとつ間にレイヤがあります。consoleを定義するscriptタグはロードされるページ全部に入れられるわけではありません。かわりに小さな5行でできたwindow.consoleのgetterを定義します。getterはconsoleのコードをロードして、consoleオブジェクトがはじめて使われたときに_firebugConsole要素を作ります。

Mike Shaver, Mark Kahn, Justin Dolskeがこれを作るヒントをくれました。ありがとう。もしコンソールについてソースを見ようと思ったらこのへんになります。

One more Tombloo patch

TomblooをFirefox3で動くようにするパッチをちょこっと改良して追記。拡張機能をインストール/アンインストールして再起動したあとの1回目でTomblooが機能しないのを解決しました。

components/tombloo.jsのいちばんはじめのほうで

const ExtensionManager = getService('/extensions/manager;1', Ci.nsIExtensionManager);

と代入してしてExtensionManagerを利用すると、たぶんXPCOMの追加/削除が行われたあとでcompreg.datなんかを再構築するときのファイル読み込み順依存でnsIExtensionManagerが利用できる/できないが決まって、それがconstに代入されちゃうので、ほんとはXPCOMの初期化が終わったあとに呼び出されるのでnsIExtensionManagerは常に利用できるはずのTomblooServicecreateInstanceの中でもExtensionManagerが存在しなくてこけてるようでした。

XPCOMコンポーネントから他のXPCOMを使うときは、利用可能になるタイミングを意識しておく必要がありそうです。今回はcreateInstanceの中で使うからかんたんに解決できるけど、registerSelfみたいな初期化の過程で呼ばれるようなところの中で使いたかったらどーするんだろう。

Firebugのコマンラインを拡張してincludeできるようにしたら便利でした

さいきんFirebugでコードを書いている。書いてCtrl-Enterを押した瞬間に結果が確認できるので気持ちがいい。Canvasを使えばグラフィックも扱える。BASICでコードを書く感覚を思い出した。

firebug console

Firebug上では、あんまり長いコードを書くのはつらいところが難点だった。自分で拡張してincludeできるようにしたらこれがすごくいい。Firebug上で実行して動作を確認しながら関数を書いていって、うまく動くようになった時点でincludeしているファイルのほうに移動してFirebugのコマンドラインを空にする。vim上でコードを書いてブラウザに戻ってきてreloadするのにくらべてストレスが少ない。

vim上でコードを書き換えたときもCtrl-Enterでもう一度includeされて実行されるので、リロードは発生しないし、Firefoxとvimとをいったりきたりしなくてもいい。

Firebug を「カクカク化」して $x の第 2 引数でコンテキストノードを指定できるようにする。 – IT戦記のはなしの流れで、だれかがuserChrome.jsに書いたらいいじゃん、と書いていたのを思い出してuserChromeで拡張することにした。

[Ext] userChrome.js 0.8 – MozillaZine Forumsからダウンロードした。0.8はFirefox3でしか動かないっぽくて、Firefox2のままにしていたWindowsのほうもFirefox3にしちゃった。

更新 2008.2.25

FirebugCommandLineAPIがあるとかないとかでエラーが出ることがあったのでwatchメソッドでオブジェクトが存在するようになるのを待ってから実行する
を組み合わせて使うようにした。

現在のchrome/userChrome.jsはこうなってる。

( function (parentObject, props, f) {
    var fn = props.reduceRight( function (callback, propname) {
        return function (parentObject) {
            if ( parentObject[propname] ) {
                var newValue = parentObject[propname];
                callback(newValue);
            } else {
                {
                    parentObject.watch( propname, function ( name, oldValue, newValue ) {
                        callback(newValue);
                        unwatch(parentObject, name);
                        return newValue;
                    } );
                }
            }

        };
    }, f);
    fn(parentObject);
} )(window, ['FirebugCommandLineAPI'], function(newvalue) {
        newvalue.prototype.json2infogami = function (firstarg) {
                var infogamiEscape = function (v) { return v.replace(/([_\*])/g, "\\$1" ) };
                var textfilter = infogamiEscape ;
                var a = (firstarg.constructor.name == "Array") ? firstarg : arguments;
                var r = [];
                   for(var i = 0; i < a.length; i++) {
                                         var siteinfo = "";
                         for ( var n in a[i] ) {
                                var v = a[i][n];
                                siteinfo += n + ":    " + textfilter(v) + "\n";
                  }
                  r.push('