HTML の表を,列名をクリックしてソートできるようにしたい.
というようなニーズは結構あって,実際いろんなところでそういう機能を実現する JavaScript のコードが公開されている.いくつか当たってみた中で,一番気に入ったのはこれ (の試作5):
気に入った理由は,
という辺り.ありがたく使わせて頂いております.
実際の表は,<td> の中にテキストが直接書かれているとは限らなく,たとえば <a> で囲まれたテキストが書かれてたりとかすることもあるわけで,一般にはテキストに行き着くまで DOM ツリーを再帰的にたどってやる必要がある.データ取得関数 getfn が分離されているので,こんなコードを書いて getfn として渡してやることにした.
function byStrNoCase (cell) { return extractText(cell).toLowerCase(); } function byInt (cell) { return parseInt(extractText(cell)); } function extractText(node) { var text = ''; if (node.nodeType == 3) { // TEXT_NODE text = node.nodeValue; } else if (node.hasChildNodes()) { var n = node.childNodes.length; for (var i = 0; i < n; i++) { text = text + extractText(node.childNodes[i]); } } return text; }
JavaScript の Array の sort() は,安定であるとは保証されていないらしい.実際,IE は安定なソートをしてくれているっぽいが Firefox だと安定でない.テーブルをかちかちクリックしてソートしたいときというのは,たとえば計算機一覧を,まずホスト名順にソートして,それから管理者順にソートしてから,自分が管理者になってる子たちを見る,なんていう使い方をすることが多いので,ソートは安定であって欲しい.
一番安直にやるには,ソート対象の要素にプロパティとして元の順番も持たせておいて,比較して引き分けだったら元の順番を保存するような比較関数 cmpfn を渡してやればよい.
のだが,元のコードだと,getfn が返した値を Object 型に変換してそれをソートしているので,比較の結果として引き分けにならない.しかたないので,getfn の返した値を Object 型に変換するのではなく,Object のプロパティとして getfn の返した値を持たせてやるように書き換えて使っている.つまり
for(var i=0; i<N; i++) x[i] = Object( getfn( rows[i].cells[index] ) ), x[i].row=rows[i];
の部分を
for(var i=0; i<N; i++) { x[i] = new Object; x[i].v = getfn(rows[i].cells[index]); x[i].row = rows[i]; x[i].idx = i; }
にしてやる.cmpfn は
function cmpAsc(a, b) { if (a.v == b.v) { if (a.idx == b.idx) { return 0; // can't happen } else if (a.idx > b.idx) { return 1; } else { return -1; } } else if (a.v > b.v) { return 1; } else { return -1; } } function cmpDesc(a, b) { return cmpAsc(b, a); }
みたいな感じ.
最終更新時間: 2009-01-04 15:31
* [Christian] Thanks for the great info dog I owe you ... (2012-12-30 13:35:14)