リストをURLポップアップに。

もしかしたら需要があるかもしれないのでとりあえず公開。
このBlogはSerene Bachで運用しています。これは数あるBlogシステムの中でもたいへん扱いやすく優れたシステムですが、いくつか気になるところもあり、そのひとつとして、独自タグを置換する形でシステム側が吐き出すhtmlコードが変更できない点が挙げられます。
例えばアーカイブやカテゴリのリスト。{archives_list}や{category_list}という独自タグを記述するだけで<ul><li>...という形式のリストを自動的に出力してくれるのですが、長く書きためていたりカテゴリが乱立してたりするとこのリストがどんどん長くなっていって大変なことに。
それならリストの代わりにselect要素を応用したいわゆるURLポップアップを使おう、というのは誰もが思いつく解決策ですが、さて困ったことにこれが一筋縄ではいかないのです。理由は前述のとおり、この部分はシステムが出力するコードに依存するため、単にテンプレートをいじっただけでは変更できないのです。
プラグイン等で吐き出されるコード自体を変えてしまうのがスマートな手段ではありますが、そういうプラグインを探しても見つからなかった(探し方が悪い?)ので、だったら出力されたものを後から書き替えてしまえ!という方向で考えてみました。

既に出力されたhtmlコードを後から書き替える手段としてjavascript-DOMを用いています。つまりjavascriptが無効な環境では通常通りリストで表示されます。そもそもURLポップアップもjavascriptを用いていますので、無効な環境でのアクセシビリティも確保できます。

主となるスクリプトは以下のとおり。ヘッダー内の<script>要素に貼り付けてもいいし、別ファイルで保存してそこから読み込んでもOK(こっち推奨)。要は「ListToPopUp」という関数にアクセスできるようになってればいいです。

function ListToPopUp () {
var all_div = document.getElementsByTagName('div');

for (var i = 0; i < all_div.length; i++) {

if (all_div[i].className == 'list-to-popup') {

var form = document.createElement('form');
var select = document.createElement('select');

if(navigator.userAgent.indexOf("MSIE")!=-1) {
select.setAttribute('onchange',new Function("window.location.href = this.value"));
} else {
select.setAttribute('onchange',"window.location.href = this.value");
}
form.appendChild(select);
all_div[i].appendChild(form);

var option = document.createElement('option');
option.setAttribute('value',"");
var selectName = document.createTextNode('Select...');
option.appendChild(selectName);
select.appendChild(option);

var all_li = all_div[i].getElementsByTagName('li');

for (var n = 0; n < all_li.length; n++) {
var srcName = all_li[n].firstChild.getAttribute('href');
var a = all_li[n].firstChild;

if (a.firstChild.nodeValue) {
var selectNameText = a.firstChild.nodeValue;
var countText = all_li[n].lastChild.nodeValue;
selectNameText = selectNameText+countText;

option = document.createElement('option');
option.setAttribute('value',srcName);
selectName = document.createTextNode(selectNameText);
option.appendChild(selectName);
select.appendChild(option);
}
}
all_div[i].removeChild(all_div[i].getElementsByTagName('ul')[0]);
}
}
}

めちゃくちゃ荒削りですみません。
やってることはすごく単純で、"list-to-popup"というclassが設定されたdivを探し出して、その中にあるliのテキストとURLを逐次抜き出し、option要素として整形したうえで新しく作ったformのselect要素に放り込み、最後は乱暴にもulごと削除しちゃってるだけです。
全部のdivを評価しているのでかなり非効率ですが汎用性は高い…ハズ。idで指定したものを検索したほうがスマートではありますが、複数のリストを変更する場合に不都合なのであえてこういう形に。

実装の方法はカンタン。たとえばアーカイブのリストをURLポップアップ化したいなら、まずテンプレートの{archives_list}を"list-to-popup"というclassが設定されたdivで囲む。あとはListToPopUp関数をonloadで実行させるだけ。

〜(略)〜
<body onload="ListToPopUp();">
〜(略)〜
<div class="list-to-popup">{archives_list}</div>
〜(略)〜

注意点として、<div class="list-to-popup">と{archives_list}の間に改行等は一切入れないでください。
どんなテンプレートでも動作しそうですし、ちょっと応用すればSerene Bach以外でも使えると思いますが、もちろん全てチェックしたわけではないのであしからず。また、突貫工事もいいとこなのでSafariとFireFoxではチェックしてますがWindows系ブラウザでは全くチェックしてません(だってVirtualPC立ち上げるのめんどくさいんだもん)。DOM非対応の古いブラウザではそもそも動作しません。

ちなみにウチはあんまり書いてないからアーカイブの項目も少ないし、内容も偏りまくっててカテゴリもそんな大した数じゃないのでこれの恩恵はあまり享受してません(笑)。

(※追記) スクリプト一部修正。個別記事で正常に反映されない問題を解決しました。

(※追記) MSIEで動作しなかったので(原因はIEのsetAttribute実装バグ)、ブラウザ分岐処理を追加しました。

カテゴリ:Web | - | trackbacks (0)

<< iPhone。 | 明日。 >>

Trackbacks