2012-12-14 [長年日記]

昨日は、statusとvoteについて、ラベルをダブルクリックしたらチェックボックスが反転するところまで実装できた。こんなかんじ:

jQuery(document).ready(function() {
    handler = function(event) {
        field = this.id.slice(6)
        jQuery('input[name="' + field + '"]').each(function() {
            checked = jQuery(this).attr("checked")
            jQuery(this).attr("checked", !checked)
        })
    }
    checkboxes = jQuery("#filters input[type='checkbox']");
    fields = []
    for (i in checkboxes) {
        fields[checkboxes[i].name] = true;
    }
    for (field in fields) {
        jQuery('#label_' + field).dblclick(handler)
    }
});
今日はその続き。そうそう、jQueryって書くの面倒だから$って書くことにする。

クエリ条件は Add の次のドロップダウンを選ぶことで追加できるんだけど、当然ながら、追加したチェックボックスでも同じようにダブルクリックを処理できることが期待されるはず。だけど、今の実装では、Document.ready 時点で存在するチェックボックスに機能追加してるので、後から追加した条件では機能しなかった。今日はそれをまず直す。Add でクエリ条件を追加したら、それをトリガーに、追加したクエリ条件のチェックボックスのラベルに dblclick をバインドしたい。

IEのF12開発ツールで Ctrl-B でドロップダウンを選択してみると、id=add_filter_0 という名前の要素が見つかった。こいつのイベント処理は、query.js (126) にあった:

126: $("#filters select[name^=add_filter_]").change(function(event) {
 :
171: var control = createCheckbox(propertyName, option,
172:                              propertyName + "_" + option);
同じように onchangeのときに、我がQueryStatusHelperPluginで dblclickイベントに handler をバインドしてやればいいはず。こんなかんじ:
$("#filters select[name^=add_filter_]").change(binder)
…… と思ったんだけど、残念ながらこっちの処理のほうが早くて、query.js側のonchangeの後ではなくて、直前にバインドされてしまって、処理したいときには追加すべきチェックボックスがまだ存在しない、という状況になってしまった。

じゃー。こっちの onchange は setTimeout してやればいいんじゃないか。こんなかんじ:

setTimeout(function(){ $("#filters select[name^=add_filter_]").change(binder)}, 1000)
…… と思ったんだけど、実装してみたら、確かに query.js 側のonchangeの後に処理されるようになったのだが、query.js側のchangeハンドラがイベントの selectIndex をクリアしてしまっていて、こっちが処理したいときには、新たに追加されたチェックボックスの名前がわからない、という状況になってしまった。

しかたないので、document.ready の時と同じように、見つかった全部のチェックボックスに dblclickハンドラを追加しちゃえー。こんなかんじ:

setTimeout(function(){ $("#filters select[name^=add_filter_]").change(function() {
   $('#label_' + field).dblclick(handler);
}) });
……と思ったんだけど、残念、反転処理が偶数回追加されちゃうと、元に戻っちゃう、という状況になってしまった。

しかたないので、見つかった全部のチェックボックスでいったん dblclickハンドラがあれば外して、あらためて全部にdblclickハンドラを追加する、という処理にしてみた。こんな感じ:

$('#label_' + field).unbind('dblclick', handler).dblclick(handler)

できた、できた。

整形すると、結局、こんな感じになった:
QueryStatusHelperPlugin/query/htdocs/js/enabler.js

(function($) {
    // event source であるラベル の  id と一致するチェックボックスの状態を反転する
    var flip = function(event) {
        field = this.id.slice(6)
        $('input[name="' + field + '"]').each(function() {
            checked = $(this).attr("checked")
            $(this).attr("checked", !checked)
        })
    }
    // event source であるチェックボックスと同名のチェックボックスをすべてクリアし、sourceだけをチェックする
    var selectone = function(event) {
        $('input[name="' + this.name + '"]').attr('checked', false);
        $(this).attr('checked', 'checked');
    }
    // ページ内にある検索条件のチェックボックスにselectoneを、それらを束ねるラベルに flip をバインドする。
    // すでにflipがバインドされている可能性があるので、一度外してみてから再バインドする。
    var binder = function() {
        checkboxes = $("#filters input[type='checkbox']");
        for (i in checkboxes) {
            $('#label_' + checkboxes[i].name).unbind('dblclick', flip).dblclick(flip)
        }
        checkboxes.dblclick(selectone);
    };
    $(document).ready(function() {
        // On Ready
        binder();
        // On Change
        setTimeout(function() {
            $("#filters select[name^=add_filter_]").change(binder)
        }, 1000);
    })
})(jQuery);

なお参考までに、いまバインドされてるchangeハンドラはこんな感じでとれた:

orgonchange = $($("#filters select[name^=add_filter_]")[0]).data('events')['change'][0].handler;


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