editableなリストボックス

select要素のラベル部分をクリックするとテキストエリアに化けて編集できるようになる、というものが確かどこかのライブラリで提供されていたと思うんですが、どうにも見当たらなかったので、やや違うアプローチで自作してみた。

<select name="job">
  <option value="技術系">技術系</option>
  <option value="営業系">営業系</option>
  <option value="事務系">事務系</option>
  <option value="管理職">管理職</option>
  <option value="その他">その他</option>
</select>

こういったリストで「その他」が選択された場合のみ自由記述にしたい、というケースはありがち(なハズ)。今回はリストの最後の要素が選択された場合にtype=textな入力フィールドと入れ替えるという手法にしてみる。ついでに入力フィールドからフォーカスが外れた際は、記入した値を追加したリストに戻すようにしてみた。

<script language="JavaScript" src="prototype.js"></script>
<script language="JavaScript">
var AlterList = {
    prepare: function(tar) {
        var _that = this;
        var maxlen = 0;
        var size = $(tar).options.length;
        var val = $(tar).options[size-1].text;
        var newid = $(tar).name + '_alter';
        new Insertion.After($(tar), '<input type="text" id="'+newid
            +'" name="'+tar.name+'" value="'+val+'">');
        Element.hide(newid);
        $(tar).onchange = function() {
            _that.alter(this, newid);
        };
        $(newid).onblur = function() {
            _that.repair(this, tar);
        };
    },
    alter: function(tar, alt) {
        var size = tar.options.length;
        if (size == tar.selectedIndex + 1) {
            Element.hide(tar);
            Element.show(alt);
            $(alt).focus();
        }
    },
    repair: function(tar, org) {
        Element.show(org);
        var size = $(org).options.length;
        var orgtext = $(org).options[size-1].text;
        if (orgtext != $(tar).value) {
            $(org).options[size-1].text = $(tar).value;
            $(org).options[size-1].value = $(tar).value;
            $(org).options.length++;
            $(org).options[size].text = orgtext;
            $(tar).value = orgtext;
        }
        Element.hide(tar);
    }
}
AlterList.prepare('name_of_select_element');
</script>

自力でinsertionさせるのが面倒だったので、prototype.jsを使っちゃいました。

動作サンプルが置けないのが、はてダの残念な点。