Chrome用 Backlog Wiki and Autofilter 拡張 / あるいは Firefox GM から Chrome 拡張への書き換えメモ

Backlog というチーム向けのバグ・タスク管理 ASP サービスがあるのですが、このタスク一覧を Excel のようにリアルタイムに絞り込んだりソートしたり、まとめて処理をしたり、 Wiki を勝手に拡張する Chrome Extension を作りました。各 OS の Chrome で無料で使えます。

ちなみに、以前作った Firefox GreaseMonkey 拡張の移植版です。

見た目や動作はほぼ一緒です。

Chrome だとクリック一発で入って、またアップデートも確実に行えるのが良いです。

Firefox GreaseMonkey から Chrome Extension へ

個人的なブラウザ環境は、Ubuntu 上の Firefox がうまく動かない時期があったので、 1年以上前に Firefox から Chrome に乗り換えていました。特にヘビーに使う拡張もなかったので移行はすんなりいきました。

GreaseMonkey のような仕組みは Chrome 拡張で出来るということは知っていましたが、まだ絶賛開発中のような状況だったので本格導入はせずに、しばらく様子を見ていました。どうしても調整しないと困るサイトだけ、 GreaseMonkey 互換の範囲で書いてはいました。

そのうちに、何人かの Autofilter のユーザーから Chrome 対応の声がだんだん上がるようになってきました。 Chrome 拡張も安定してさらに Web Store も開店したので、このタイミングなら良いだろうと言うことで、本格導入することにしました。

まず取りかかりとしては、 os0x さんの 続・先取り! Google Chrome Extensions が大変参考になりました。後は、本家ドキュメント(英語) がとてもよくまとまっていますので、一通り読めば大抵のことが出来るようになります。

後は、 GreaseMonkey からの非互換部分を頑張って修正するという作業でした。

コード量の少ない Wiki 拡張(300行弱)を書き直してみたところ、 manifest.json を追加する程度でほとんど動いてしまいました。やっててよかった! Web 標準万歳です。

これにとても encourage されまして、 Autofilter (約3600行)も同じような気持ちで取り組みました。結果、全体の1割程度の修正で動いたのですが、大変苦労しました。ということで、以下はそのときのメモです。

E4X の書き直し

Firefox では、 E4X という XML 構築や操作をリテラルで書けるシンタックスをサポートしています。慣れるとこれが大変便利で、式展開も出来るためコードが分かりやすくなります。 Rhino でも使えるので業務でもよく利用しています。

Autofilter や Wiki 拡張では、 XMLRPC の XML 構築や解釈、あとはヒアドキュメントとして使っていました。これらを E4X を使わない形に書き換えることが修正の主な作業でした。

ヒアドキュメントの書き直し

以下のようなコードを

var str = <>
ABCD
EFGH
</>.toString();

以下のようなコードに書き換えます。

var str = "ABCD\nEFGH";

GreaseMonkey では、追加の CSS はヒアドキュメントで書いて GM_addStyle で入れていましたが、 Chrome では manifest.json に書けば CSS は別ファイルに出来るので楽になりました。

XML リテラルの書き直し

以下のようなコードを

var xml = <a><b>cde</b></a>;

以下のようなヘルパー関数を使ったコードに書き換えます。

var xml = TAG("a",TAG("b","cde"));

function TAG(tag,content) { // E4X like helper
	if (content instanceof Array) {
		content = content.join("");
	}
	return "<"+tag+">"+content+"</"+tag+">";
}

大変そうでしたが、 XML 構築は単純な書き換えだったので楽でした。

DOM 操作の書き直し

以下のような E4X のコードを

function(response) { // XML object
   var struct = response..struct;
   :
}

以下のような XPATH コードに書き直します。

function(response) { // XML object
   var struct = $X("/methodResponse/params/param/value/struct",response);
   :
}

$X は以下のような XPATH のヘルパーです。よくあるコードです。

function $X(xpath, node) {
	node = node || document;
    var res = node.evaluate(xpath, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    var copy = [];
    for (var i=0, j=res.snapshotLength; i<j; i++) {
        copy.push(res.snapshotItem(i));
    }
    return copy;
}

隣接するノードは、childNodes などの DOM 関数で取得するようにしたのですが、そうすると意図しない位置に空白文字があると TextNode が入って来てしまうので、うまくスキップさせたり、逆に必要な TextNode を判定するのが面倒でした。

これまでは E4X がうまく空気を読んでくれていたのだと思います。やはり E4X は偉大です。

XMLRPC 書き直し

ここも E4X のコードをひたすら書き直すだけでした。

Chrome 用の XMLRPC の先行実装をいくつか見たのですが、いまいちだったのでやっぱり自前で XMLRPC を書きました。オブジェクトと XML の変換がちょっと書いてて楽しかったです。

ここの部分は切り出して使えば、汎用の Backlog API コードとして使えそうかもしれません。

JavaScript 仕様

Firefox には 「for each」というループ構文があったのですが、 Chrome には無かったので、単純な for 文に書き直しました。

GreaseMonkey 仕様・GM関数の書き直し

いくつかの GreaseMonkey 仕様を書き直しました。これも対策が本家も含めて多く出回っているので対応は楽でした。

unsafeWindow の削除

GreaseMonkey では問題の多い「unsafeWindow」を使っていました。 Autofilter の場合は、単純に表のページのカレンダーのライブラリを読んでいるだけだったので、カレンダーのライブラリを同梱することにして解決しました。

manifest.json によるパッケージングは便利です。

GM_setValue, getValue

ローカルストレージで書き直しました。

Autofilter ではドメイン間のデータのやりとりはないので、 background.html や メッセージ通信は使っていません。

GM_xmlHttpRequest

こちらも通信先ドメインが同じなので単純に XMLHttpRequest のインタフェースを合わせて自前実装しました。 GET, POST しています。

複数非同期の待ち合わせで JSDeferred を導入し用かどうか悩んだのですが、まずは自前待ち合わせコードで済みそうだったので、導入は見送りました。ただ、これ以上複雑なことをする場合は導入しようと思っています。

CSS, HTML

CSS, HTML はブラウザが変わるとそもそも挙動が変わってしまうので、試行錯誤しながら一つ一つ元の動きになるように直していきました。

セレクタ

Firefox ではいい加減なセレクタを書いていても動いていたのですが、 Chrome だとうまくいかないことが多かったです。

おそらく、隣接セレクタの挙動が何か違っているような気がしました。

tbody がスクロールできない

今回一番苦労した部分です。

Firefox だと、 table の thead, tfoot は固定にして、tbody だけスクロールするということが出来たのですが、 Webkit 系では出来ないようです。

検索して解決方法を探したり、そういうプラグインのコードを読んだりしてみたのですが、 Autofilter で必要な機能を実現する根本的な解決方法は見つかりませんでした。

ということで、もうテーブルによる自動レイアウトはやめて、 tbody, thead, tfoot の display:block にして JS で幅を制御することにしました。個人的にはまだまだ不満点が多いのですが、ユーザーが Firefox との使用感の違いをすぐには認識できないくらいには、うまく動いているようでした。

その他

パッケージングにより、 loading のくるくる回るアイコンが出せるようになりました。



Chrome 拡張はとても面白かったので、今後も Backlog に欲しい機能や、 UI の実験などで積極的に使っていこうと思っています。