広告

posted by fanblog
「ここにブログの名前を入れます」は更新を終了しました。記事はすべて新ブログ「Big Bang」に移転済みです。記事のタイトルをクリックすると新ブログの該当記事に移動します。そちらでお楽しみください。

年齢計算フォーム

別のサイトで下のような選択フォームを作りました

1月、3月、5月、7月、8月、10月、12月は日付を31日まで選択できますが、
4月、6月、9月、11月は30日まで、2月は年によって28日か29日になります。
(西暦は大正元年にあたる1912年まで対応)

誤入力を防止するため、存在しない日付は表示しません。

たとえば、今年、今月を選択すれば、1日から今日の日付までしか選べません。

昭和64年は1月7日までなので、昭和64年1月を選べば7日まで、平成元年1月を選べば
8日からの表示となります。

元号年から西暦への変換も出来ます。
たとえば平成1年を選択した後に、西暦を押すと1989年と表示されます。

これを実現するのに以下のソースを書いてFirefoxで試したらうまくいきました。
ところが、IE(インターネット エクスプローラー)ではset_select関数が動きません。

Internet ExplorerではselectタグのinnerHTMLへの挿入はサポートしていないそうです。

フォーム

<!-- 起動するまでdisplay:noneで非表示にして、誤作動防止 -->
<form id="age_form" style="display:none;text-align:center">
<p style="color:#00f;font-weight:bold">年齢計算フォーム</p>
<p>
<input type="radio" name="gengou" onclick="gengou_changed(this)" checked="checked" />
西暦&nbsp;&nbsp;
<input type="radio" name="gengou" onclick="gengou_changed(this)" />
平成&nbsp;&nbsp;
<input type="radio" name="gengou" onclick="gengou_changed(this)" />
昭和&nbsp;&nbsp;
<input type="radio" name="gengou" onclick="gengou_changed(this)" />
大正
</p>
<select onchange="year_changed(this)">
<option value="0">---</option>
</select>
年
<select onchange="month_changed(this)">
<option value="0">---</option>
</select>
月
<select onchange="day_changed(this)">
<option value="0">---</option>
</select>
日
&nbsp;<span></span>
</form>

スクリプト

var today=new Date();
var taisyou_gannen=1912;

//これだとIEでは動きません
var set_select=function(select,min,max,diff){
	var option=select.getElementsByTagName('option');
	var selected=parseInt(option[select.selectedIndex].value,10);

	select.innerHTML='<option value="0">---</option>';

	if(!min&&!max){
		return;
	}

	for(;min<=max;min++){
		var num=min+diff;
		var attr=num==selected?' selected="selected" ':'';

		select.innerHTML+=
			'<option value="'+num+'"'+attr+'>'+min+'</option>';
	}
}

var is_urudoshi=function(year){ //閏年ならtrue
	if(year%4){
		return false;
	}

	if(year%100){
		return true;
	}

	if(year%400){
		return false;
	}

	return true;
}

var day_changed=function(elem){
	var select=elem.parentNode.getElementsByTagName('select');
	var span=elem.parentNode.getElementsByTagName('span');

	if(select.length!=3||span.length!=1){return;}

	var option=select[2].getElementsByTagName('option');
	var day=parseInt(option[select[2].selectedIndex].value,10);

	if(!day){
		span[0].innerHTML='';
		return;
	}

	option=select[1].getElementsByTagName('option');
	var month=parseInt(option[select[1].selectedIndex].value,10);

	option=select[0].getElementsByTagName('option');
	var year=parseInt(option[select[0].selectedIndex].value,10);

	//現在の年齢を算出
	var today_num=(today.getFullYear()*10000)
			+((today.getMonth()+1)*100)+today.getDate();
	var age=Math.floor((today_num-
			((year*10000)+(month*100)+day))/10000);

	span[0].innerHTML='現在の年齢:'+age+'歳';
}

var month_changed=function(elem){
	var input=elem.parentNode.getElementsByTagName('input');
	var select=elem.parentNode.getElementsByTagName('select');

	if(input.length!=4||select.length!=3){return;}

	var option=select[1].getElementsByTagName('option');
	var month=parseInt(option[select[1].selectedIndex].value,10);

	option=select[0].getElementsByTagName('option');
	var year=parseInt(option[select[0].selectedIndex].value,10);

	//誤作動防止のため最大範囲(1〜31)で初期化
	set_select(select[2],1,31,0);

	if(!month){
		//月が「---」なら日も「---」
		set_select(select[2],0,0,0);
	}else if(year==1989&&month==1&&input[1].checked){
		//平成元年は1月8日から
		set_select(select[2],8,31,0);
	}else if(year==1989&&month==1&&input[2].checked){
		//昭和64年は1月7日まで
		set_select(select[2],1,7,0);
	}else if(year==1926&&month==12&&input[2].checked){
		//昭和元年は12月25日から
		set_select(select[2],25,31,0);
	}else if(year==1926&&month==12&&input[3].checked){
		//大正15年は12月25日まで
		//大正最後の日と昭和最初の日は同じ
		set_select(select[2],1,25,0);
	}else if(year==1912&&month==7&&input[3].checked){
		//大正元年は7月30日から
		set_select(select[2],30,31,0);
	}else if(year==today.getFullYear()&&month==today.getMonth()+1){
		//今年の今月なら今日まで表示
		set_select(select[2],1,today.getDate(),0);
	}else if(month==2){
		if(is_urudoshi(year)){
			//閏年の2月は29日まで
			set_select(select[2],1,29,0);
		}else{
			//それ以外の2月は28日まで
			set_select(select[2],1,28,0);
		}
	}else if(month==4||month==6||month==9||month==11){
		//4、6、9、11月は30日まで
		set_select(select[2],1,30,0);
	}

	day_changed(elem);
}

var year_changed=function(elem){
	var input=elem.parentNode.getElementsByTagName('input');
	var select=elem.parentNode.getElementsByTagName('select');

	if(input.length!=4||select.length!=3){return;}

	var option=select[0].getElementsByTagName('option');
	var year=parseInt(option[select[0].selectedIndex].value,10);

	//誤作動防止のため最大範囲(1〜12)で初期化
	set_select(select[1],1,12,0);

	if(!year){
		//年が「---」なら月も「---」
		set_select(select[1],0,0,0);
	}else if(year==today.getFullYear()){
		//今年なら今月まで表示
		set_select(select[1],1,today.getMonth()+1,0);
	}else if(input[2].checked){
		if(year==1989){
			//昭和64年は1月まで(よって平成元年も1月から)
			set_select(select[1],1,1,0);
		}else if(year==1926){
			//昭和元年は12月から
			set_select(select[1],12,12,0);
		}
	}else if(input[3].checked&&year==1912){
		//大正元年は7月から
		//大正のそれ以外の年はすべて1〜12月まである
		set_select(select[1],7,12,0);
	}

	month_changed(elem);
}

var gengou_changed=function(elem){
	var input=elem.parentNode.getElementsByTagName('input');
	var select=
		elem.parentNode.parentNode.getElementsByTagName('select');

	if(input.length!=4||select.length!=3){return;}

	for(var i=0;i<input.length;i++){
		if(input[i].checked){
			//誤作動防止のため最大範囲で初期化
			set_select(select[0],
				taisyou_gannen,today.getFullYear(),0);

			if(i==1){
				//平成元年から今年まで
				set_select(select[0],
					1,today.getFullYear()-1988,1988);
			}else if(i==2){
				//昭和元年から64年まで
				set_select(select[0],1,64,1925);
			}else if(i==3){
				//大正元年から15年まで
				set_select(select[0],1,15,1911);
			}

			break;
		}
	}

	year_changed(select[0]);
}

var load_event=function(){
	var elem=document.getElementById('age_form');
	if(!elem){return;}

	var select=elem.getElementsByTagName('select');
	if(select.length!=3){return;}

	set_select(select[0],taisyou_gannen,today.getFullYear(),0);
	elem.style.display='block'; //フォームを表示
}

// 詳細は別記事「addEventListenerとattachEvent」を見てください
if(window.addEventListener){
	window.addEventListener('load', load_event, false);
}else if(window.attachEvent){
	window.attachEvent('onload', load_event);
}

IEに対応させるためにDOMを使って、set_select関数のソースを書き直したらうまく動きました。

var set_select=function(select,min,max,diff){
	var option=select.getElementsByTagName('option');
	var cnt=parseInt(option[option.length-1].value,10)-diff;

	//maxまでなければ追加

	while(max>cnt){
		cnt++;
		var elem=document.createElement('option');
		elem.setAttribute('value',cnt+diff);
		//optionへのinnerHTMLは書き込み可能
		elem.innerHTML=cnt;
		select.appendChild(elem);
	}

	//max以上あったら削除

	while(max<cnt){
		select.removeChild(option[option.length-1]);
		cnt--;
	}

	cnt=option.length==1?0:parseInt(option[1].value,10)-diff;

	//min以下があったら削除

	while(min>cnt){
		select.removeChild(option[1]);
		cnt++;
	}

	//minまでなければ追加

	while(min<cnt){
		cnt--;
		var elem=document.createElement('option');
		elem.setAttribute('value',cnt+diff);
		//optionへのinnerHTMLは書き込み可能
		elem.innerHTML=cnt;
		select.insertBefore(elem,
				select.getElementsByTagName('option')[1]);
	}

	option=select.getElementsByTagName('option');

	for(var i=1;i<option.length;i++){
		//optionへのinnerHTMLは書き込み可能
		option[i].innerHTML=min++;
	}
}

新ブログ「Big Bang」で続きを読む