// フォーム入力チェックプログラム　Ver 2009.04.06
//
// 使用方法
//
// フォームタグのonSubmit属性にreturn fck(this,「引数なし」または''または'文字列'); を指定。
// 第二引数　なし:アラートなし、'':既定のメッセージをアラート、'文字列':文字列をメッセージとしてアラート
// （例）<form name="fml" method="POST" action="./" onSubmit="return fck(this,'エラーだよ');">
//
// チェックしたいフォームコントロールのname属性とチェックパターン名を組み合わせて指定。
// （例）
// idの名前：チェックしたいコントロールのname+_+チェックパターン名
// <span id="dnm1_NOT_NULL" class="fm_err_mes"></span>	インライン要素でメッセージを表示したい場合はspanを使う。
// <div id="dnm2_HIRA" class="fm_err_mes"></div>		ブロック要素でメッセージを表示したい場合はdivを使う。
//
// １つのコントロールに複数の検査を設定可能。
// select,optionでvalue=""がチェックされても未選択とみなす。仕様的にどうか？
//
// エラーメッセージのスタイルはclassを定義してスタイルシートで自由に指定できる。ただし、displayプロパティのみプログラム制御するのでnoneとする。
// （例）
//.fm_err_mes {
//	display: none;
//	font-size: 10pt;
//	color: #ff0000;
//}
//
// Created by Taichi Iwasa


function fck() {

	// 第一引数はフォーム
	var ck_form=arguments[0];
	// 検査パターン格納用変数
	var ck_pat = new Object();
	//
	// 検査条件の追加：正規表現を使って、様々な検査条件を追加できる。
	// プロパティのネーミング規則：パスする検査項目を_（アンダーライン）で連結する。
	
	ck_pat['NOTNULL'] = '.';																	// 必須入力（入力してください。）
	ck_pat['NUM'] = '^[0-9]+$';																	// 半角数字（半角数字のみゆるされます。）
	ck_pat['NUM_NULL'] = '^[0-9]*$'																// 半角数字＋未入力OK（半角数字のみゆるされます。）
	ck_pat['ABC'] = '^[a-zA-Z]+$';																// 半角アルファベット（半角アルファベットのみゆるされます。）
	ck_pat['ABC_NULL'] = '^[a-zA-Z]*$';															// 半角アルファベット＋未入力OK（半角アルファベットのみゆるされます。）
	ck_pat['ABC_SP'] = '^[a-zA-Z ]+$';															// 半角アルファベット＋スペース（半角アルファベットのみゆるされます。）
	ck_pat['ABC_SP_NULL'] = '^[a-zA-Z ]*$';														// 半角アルファベット＋スペース＋未入力OK（半角アルファベットのみゆるされます。）
	ck_pat['NUM_ABC'] = '^[a-zA-Z0-9]+$';														// 半角英数字（半角英数字のみゆるされます。）
	ck_pat['NUM_ABC_NULL'] = '^[a-zA-Z0-9]*$';													// 半角英数字＋未入力OK（半角英数字のみゆるされます。）
	ck_pat['NUM_ABC_SP'] = '^[a-zA-Z0-9 ]+$';													// 半角英数字＋スペース（半角英数字のみゆるされます。）
	ck_pat['NUM_ABC_SP_NULL'] = '^[a-zA-Z0-9 ]*$';												// 半角英数字＋スペース＋未入力OK（半角英数字のみゆるされます。）
	ck_pat['ABC_SIGN'] = '^[a-zA-Z0-9,_~./]+$';													// 半角英数字と英記号（半角英数字と英記号のみゆるされます。）
	ck_pat['ABC_SIGN_NULL'] = '^[a-zA-Z0-9,_~./]*$';											// 半角英数字と英記号＋未入力OK（半角英数字と英記号のみゆるされます。）
	ck_pat['KANAZ'] = '^[ア-ンヴァィゥェォー]+$';												// 全角カタカナ（全角カタカナのみゆるされます。）
	ck_pat['KANAZ_NULL'] = '^[ア-ンヴァィゥェォー]*$';											// 全角カタカナ＋未入力OK（全角カタカナのみゆるされます。）
	ck_pat['KANAZ_SPZ'] = '^[ア-ンヴァィゥェォー　]+$';											// 全角カタカナ＋スペース（全角カタカナのみゆるされます。）
	ck_pat['KANAZ_SPZ_NULL'] = '^[ア-ンヴァィゥェォー　]*$';									// 全角カタカナ＋スペース＋未入力OK（全角カタカナのみゆるされます。）
	ck_pat['HIRA'] = '^[あ-んぁぃぅぇぉー]+$';													// 全角ひらがな（全角ひらがなのみゆるされます。）
	ck_pat['HIRA_NULL'] = '^[あ-んぁぃぅぇぉー]*$';												// 全角ひらがな＋未入力OK（全角ひらがなのみゆるされます。）
	ck_pat['HIRA_SPZ'] = '^[あ-んぁぃぅぇぉー　]+$';											// 全角ひらがな＋スペース（全角ひらがなのみゆるされます。）
	ck_pat['HIRA_SPZ_NULL'] = '^[あ-んぁぃぅぇぉー　]*$';										// 全角ひらがな＋スペース＋未入力OK（全角ひらがなのみゆるされます。）
	ck_pat['KANAH'] = '^[ｱ-ﾝﾞﾟ]+$';																// 半角カタカナ（半角カタカナのみゆるされます。）
	ck_pat['KANAH_SP'] = '^[ｱ-ﾝﾞﾟ ]+$';															// 半角カタカナ＋スペース（半角カタカナのみゆるされます。）
	ck_pat['URL'] = '^(https:\/\/?|ftp:\/\/)([-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]*)$';			// 'URL形式。例: http://www.yourname.jp/'（URLを入力してください。）
	ck_pat['URL_NULL'] = '^((https:\/\/?|ftp:\/\/)([-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]*))*$';	// 'URL形式。例: http://www.yourname.jp/'（URLを入力してください。）
	ck_pat['EMAIL'] = '^[a-zA-Z0-9_\.,-]+@([a-zA-Z0-9_\.,-]+\.[a-zA-Z0-9])+$';					// 'メールアドレスの形式。例: yourname@yourname.com'（メールアドレスを入力してください。）
	ck_pat['EMAIL_NULL'] = '^([a-zA-Z0-9_\.,-]+@([a-zA-Z0-9_\.,-]+\.[a-zA-Z0-9]+))*$';			// 'メールアドレスの形式。例: yourname@yourname.com'（メールアドレスを入力してください。）
	ck_pat['POSTCODE'] = '^[0-9]{3}\-[0-9]{4}$';												// 郵便番号
	ck_pat['POSTCODE_NULL'] = '^([0-9]{3}\-[0-9]{4})*$';										// 郵便番号＋未入力OK
	ck_pat['CHECKED1'] = '1';																	// (radio,checkbox,select)１つチェック必須　1:チェック項目数を表す
	ck_pat['CHECKED1M'] = '+1';																	// (radio,checkbox,select)１つ以上チェック必須　+:以上を表す
	ck_pat['CHECKED2'] = '2';																	// (radio,checkbox,select)２つチェック必須
	ck_pat['CHECKED2M'] = '+2';																	// (radio,checkbox,select)２つ以上チェック必須
	ck_pat['CHECKED3M'] = '+3';																	// (radio,checkbox,select)３つ以上チェック必須
	ck_pat['NOTCHECKED'] = 0;																	// (radio,checkbox,select)未チェック必須
	ck_pat['NOTNULL_NM'] = '.';																	// 必須入力。メッセージ非表示

	// デフォルトのエラーメッセージ格納用変数
	var ck_msg = new Object();
	ck_msg['NOTNULL'] = '【エラー】：入力必須項目です。';
	ck_msg['NUM'] = '【エラー】：半角数字で指定してください。';
	ck_msg['NUM_NULL'] = '【エラー】：半角数字で指定してください。';
	ck_msg['ABC'] = '【エラー】：半角アルファベットで指定してください。';
	ck_msg['ABC_NULL'] = '【エラー】：半角アルファベットで指定してください。';
	ck_msg['ABC_SP'] = '【エラー】： 半角アルファベットで指定してください。';
	ck_msg['ABC_SP_NULL'] = '【エラー】： 半角アルファベットで指定してください。';
	ck_msg['NUM_ABC'] = '【エラー】：半角英数字で指定してください。';
	ck_msg['NUM_ABC_NULL'] = '【エラー】：半角英数字で指定してください。';
	ck_msg['NUM_ABC_SP'] = '【エラー】：半角英数字で指定してくださいす。';
	ck_msg['NUM_ABC_SP_NULL'] = '【エラー】：半角英数字で指定してくださいす。';
	ck_msg['ABC_SIGN'] = '【エラー】：半角英数字と英記号で指定してください。';
	ck_msg['ABC_SIGN_NULL'] = '【エラー】：半角英数字と英記号で指定してください。';
	ck_msg['KANAZ'] = '【エラー】：全角カタカナで指定してください。';
	ck_msg['KANAZ_NULL'] = '【エラー】：全角カタカナで指定してください。';
	ck_msg['KANAZ_SPZ'] = '【エラー】：全角カタカナで指定してください。';
	ck_msg['KANAZ_SPZ_NULL'] = '【エラー】：全角カタカナで指定してください。';
	ck_msg['HIRA'] = '【エラー】：ひらがなで指定してください。';
	ck_msg['HIRA_NULL'] = '【エラー】：ひらがなで指定してください。';
	ck_msg['HIRA_SPZ'] = '【エラー】：ひらがなで指定してください。';
	ck_msg['HIRA_SPZ_NULL'] = '【エラー】：ひらがなで指定してください。';
	ck_msg['KANAH'] = '【エラー】：半角カタカナで指定してください。';
	ck_msg['KANAH_SP'] = '【エラー】：半角カタカナで指定してください。';
	ck_msg['URL'] = '【エラー】：URLを入力してください。';
	ck_msg['URL_NULL'] = '【エラー】：URLを入力してください。';
	ck_msg['EMAIL'] = '【エラー】：メールアドレスを入力してください。';
	ck_msg['EMAIL_NULL'] = '【エラー】：メールアドレスを入力してください。';
	ck_msg['POSTCODE'] = '【エラー】：郵便番号を入力してください。';
	ck_msg['POSTCODE_NULL'] = '【エラー】：郵便番号を入力してください。';
	ck_msg['CHECKED1'] = '【エラー】：選択必須項目です。';
	ck_msg['CHECKED1M'] = '【エラー】：１つ以上の選択必須項目です。';
	ck_msg['CHECKED2'] = '【エラー】：２つ選択必須項目です。';
	ck_msg['CHECKED2M'] = '【エラー】：２つ以上の選択必須項目です。';
	ck_msg['CHECKED3M'] = '【エラー】：３つ以上の選択必須項目です。';
	ck_msg['NOTCHECKED'] = 0;
	ck_pat['NOTNULL_NM'] = '';
	
	var err_cnt = 0;				// エラーの数
	var ele_type;					// 要素のタイプ
	var ck_wk;						// ele_typeが1,2の場合の検査ノードリストを格納
	var ckfn_flg = new Object();	// 処理済み要素を格納していく

	for(var i = 0; i < ck_form.length; i++ ) { 
		if(ckfn_flg[ck_form.elements[i].name]) {			// 処理済みの要素をname属性でチェック（radio,checkbox対策）
			continue;										// 処理済みならスキップ
		} else {
			ckfn_flg[ck_form.elements[i].name] = true;		// 未処理なら処理済みフラグをセット
		}
		
		switch(ck_form.elements[i].type) {
			// 検査しない（スキップする）要素
			case "hidden":
			case "submit":
			case "reset":
			case "button":
			case "image":
				continue;

			// 中身を検査する要素
			case "text":
			case "password":
			case "textarea":
			case "file":
				ele_type = 0;	// エレメントタイプ　0:中身の検査(input)　1:選択状態の検査(radio,checkbox)　2:選択状態の検査(select)
				break;

			// 選択されているか検査するチェック要素
			case "checkbox":
			case "radio":
				ele_type = 1;
				break;

			// 選択されているか検査するセレクト要素
			case "select-one":
			case "select-multiple":
				ele_type = 2;
				break;
			default:
				break;
		}
		
//		window.alert(ck_form.length + ':' + i + ':' + ck_form.elements[i].name);
		
		for(var c in ck_pat) {																// 全ての検査パターンを試す
			var cont_ck = document.getElementById(ck_form.elements[i].name+'_'+c);			// 検査項目抽出
			if(!!cont_ck){																	// 検査項目があるかどうか？
				cont_ck.style.display = 'none';												// タグがspanの場合は、インライン要素として表示
				var err_flg = false;
				if(ele_type == 0) {															// 中身を検査する要素
					if(!ck_form.elements[i].value.match(ck_pat[c])) {
						err_cnt++;															// エラーの数のカウントアップ
						err_flg = true;														// 今回の検査でエラー有り
					}
				} else if(ele_type == 1 || ele_type == 2) {									// 選択されているか検査するボタン要素
					if(ele_type == 1) {
						var ck_wk = document.getElementsByName(ck_form.elements[i].name);	// radio,checkboxの場合の検査対象ノードを取得
					} else {
						ck_wk = ck_form.elements[i].options;								// selectの場合の検査対象ノードを選択
					}
					var ck_cnt_wk = 0;														// チェックされている数をセットする変数の初期化
					for(var k = 0;k < ck_wk.length; k++) {									// 同一の名前のノード分回す
						if(ele_type == 1 && ck_wk[k].checked || 
							ele_type == 2 && ck_wk[k].selected && ck_wk[k].value != "") {	// チェックされているか？select,optionでvalueが""でチェックされても未選択とみなす。仕様的にどうか？
								ck_cnt_wk++;												// チェックされていたらカウントアップ
						}
					}
					if((ck_pat[c].indexOf('+', 0) >= 0 && ck_cnt_wk < eval(ck_pat[c])) || (ck_pat[c].indexOf('+', 0) == -1 && ck_cnt_wk != eval(ck_pat[c]))) {
						err_cnt++;															// エラーの数のカウントアップ
						err_flg = true;														// 今回の検査でエラー有り
					}
				}
				if(err_flg) {																// 今回の検査でエラー有りか？
					if(cont_ck.innerHTML == '') {											// エラーメッセージを省略してあるかどうか？　textContentはie未サポート　innerHTMLはff未サポート
						cont_ck.innerHTML = ck_msg[c];										// エラーメッセージを省略してある場合は、デフォルトのエラーメッセージを表示
					}
					if(cont_ck.tagName.toLowerCase() == 'span' ) {							// HTML,XHTML（Content-Type:application/xhtml+xml）の違いで大文字で返る場合があるので小文字に統一
						cont_ck.style.display = 'inline';									// タグがspanの場合は、インライン要素として表示
					} else {
						cont_ck.style.display = 'block';									// タグがdiv（span以外）の場合は、ブロック要素として表示
					}
				}
			}
		}
	}
	if(err_cnt == 0) {
		return true;	// エラーが無かったらtrueを返す。フォームのアクションを実行する。
	} else {
		if(arguments.length != 1) {															// 引数の数を調べる
			if(arguments[1] == '') {
				window.alert('入力内容を確認してください。');								// この既定メッセージを表示
			} else {
				window.alert(arguments[1]);													// 引数として渡ってきたメッセージを表示
			}
		}
		return false;	// エラーが無かったらfalseを返す。フォームのアクションを中止する。
	}
}

