2012-12-11 [長年日記]

Tracのクエリページのステータスって不便だよね

クエリページで status != closed を一発で選択できないのが不便。

クエリページで、チェックボックスをダブルクリックしたら、そのチェックボックスグループの選択状態を反転させる、という動作をしてくれたら嬉しいのに。

不便に思ったら改造するのだ

とりあえず、プラグインの名前、パッケージ名、モジュール名、クラス名は、適当だけど QueryStatusHelperPlugin, query, doubleclick, Checkbox にする。変だったらあとで変えればいい。

  1. Ctrl-N - PyDEV Source Folders で QueryStatusHelperPlugin を作って
  2. Ctrl-N - PyDEV Modules で、Package に query, Name に doubleclick を作って
  3. class CheckBox(Component) と実装しておく。

ざっくり構造を考えてみる。大きく二つの部分が必要になりそう:

  1. 「ダブルクリック処理ロジック」 ... チェックボックスをダブルクリックしたら、そのチェックボックスグループの選択状態を反転させる処理
  2. 上記の処理を仕込む処理。

「ダブルクリック処理ロジック」を書く

UI部分なので、JavaScriptで実現する。とりあえず、Aptana でどこでもいいので、どんな名前でもいいのでとりあえず enabler.js というファイルを作って編集していくことにする。
仕込みたい場所、つまりtracのカスタムクエリのページで、Internet Explorer で F12開発者ツール - Ctrl+Bクリックで要素を選択 - チェックボックスをクリック してHTMLソースを調べてみると、status と書いてある部分は id="label_0_status" となってて、status に関連するチェックボックスはすべて name="0_status" という属性を持ってる。
この status に、jQueryのdblclick()を実装してやろう。JavaScriptはとりあえずこんな感じ:

    jQuery('#label_0_status').dblclick(function() {
            jQuery('input[name="0_status"]').each(function() {
                checked = $(this).attr("checked")
                $(this).attr("checked",!checked)
            })
    })
こいつをページ表示時に実行するために、document.ready で囲んでやるとこうなる。
jQuery(document).ready(function() {
    jQuery('#label_0_status').dblclick(function() {
            jQuery('input[name="0_status"]').each(function() {
                checked = $(this).attr("checked")
                $(this).attr("checked",!checked)
            })
    })
});
さて。これをどうやってカスタムクエリにはさんでいくか。

ほかのJavaScriptはどうやって挟まってるのか?

tracのページのJavaScriptを、Internet Explorer の F12開発者ツールを使って調べてみると、chrome/developer/js/log.js というJavaScriptを読み込んでいるのがわかる。
tracdeveloperplugin のソースから、log.js を検索すると、tracdeveloper/log.py でこんな感じになっていた:

59:    add_script(req, 'developer/js/log.js')
このメソッドで「このJavaScriptを使うよー」と宣言してるっぽい。

どこからどのメソッドが呼ばれてるか調べるために、ブレークポイントを張ってコールスタックを見てみると、 chrome.py(1147): が、stream_filters の filter_stream を呼んでる。そこまでの流れはこんな感じになってる:

 328: stream_filters = ExtensionPoint(ITemplateStreamFilter)
  :
1145:     for filter in self.stream_filters:
1146:         stream = filter.filter_stream(req, method, filename, stream, data)

挟み込むところを実装してみる。

ITemplateStreamFilter で実装すればいいことがわかったので、QueryStatusHelperPlugin に implements ITemplateStreamFilter を追加して、ITemplateStreamFilter のメソッドである以下を追加してやる:

def filter_stream(self, req, method, filename, stream, data):
    add_script(req, 'querystatushelper/js/enabler.js')
    return stream
setup.py をコピーして、setup egg_info を実行して、Tracを再起動して、クエリページを開くと、F12開発者ページで スクリプト選択ボックスに enabler.js へのリンクが登場してる。add_scriptはうまく動いてるみたい。
で。enable.js のソースを見ようと選択してみると、あちゃー。/chrome/querystatushelper/js/enabler.js がエラーページを返してるよ。

javascriptファイルを返せるようにする

/chrome/* を処理してるやつがいるはずなので、3回目で見た web/chrome.py の chosen_handler.process_request(req) を追いかけてみる。ブレークポイントを張って、req が enabler.js のリクエストが来たときにステップインしてみると、ここにきた:

327: template_providers = ExtensionPoint(ITemplateProvider)
 :
586: def process_request(self, req):
 :
591:     for provider in self.template_providers:
はい。もうわかりますね。doubleclick.py で ITemplateProvider を実装すればいい。こんな感じかなー:
    # ITemplateProvider methods
    def get_htdocs_dirs(self):
        return [('querystatushelper', pkg_resources.resource_filename('query', 'htdocs'))]
            
    def get_templates_dirs(self):
        return []
で、query/htdocs/js/enabler.js に配置してやったら、tracを再起動してブラウザリロードすれば、エラーページが解消して、JavaScriptがページに読み込まれた。

じっけん

statusラベルをダブルクリックしてみると、期待通りチェックボックスの状態が反転したー。ひとまず完成っ。


«前の日記(2012-12-10) 最新 次の日記(2012-12-12)»