S_a_k_Uの日記みたいなDB

~サクゥーと呼ばないで~

数値入力で動的にカンマを入れる(改)

こちらを参考にさせて頂いて、想定どおりの動きに改造してみた。
+naminamiからのリクエストで、キー入力そのものを制限してみたり。
その他、コメントいれたり、構造化してみたり。
一応、IE6SP2とFirefox2.0.0.12で動作を確認。
これをJSFのカスタムタグにした方がええんか、標準のタグ+JavaScriptな感じがええんか、ちょっと考えてみよう。
追記(28-Feb-2008):
FirefoxでdoCheckKeyCodeがちゃんと動作してねかったよ(汗
こちらを参考にイベントからキーコードは拾えるようにしたけど、キーコードがブラウザ毎に違ってるしorz
実際「;+れ』」キーとShiftキーを使って、+を入力するとFirefoxだと61で、IEだと187だし。
charCodeで、と思ったらonkeydownイベントではcharCodeが取れないときたもんだ。
ちょっとそのヘンも調べてみるか。

<HTML>
<head>
<script type="text/javascript">


var lastVal = "";


/*
  数値をカンマ編集する
*/
function doFormatNum(e) {

	var curVal = e.value;

	// 値に変更のないキー入力を無視する
	if (lastVal == curVal) {
		return;
	}

	// 現在のカーソル位置を取得する
	var pos = getCursorPosition(e);

	// カンマなしの数値にする
	var val = curVal;
	while (val.indexOf(",") > -1) {
		val = val.replace(",", "");
	}

	// 値が数値でない場合は、警告&Undoする
	if ((curVal != "+") && (curVal != "-") && (curVal != ".") && (isNaN(val) == true)) {

		alert("数値じゃないです");

		e.value = lastVal;

		setCursorPosition(e, pos - 1);

	} else {

		// 数値をカンマ編集する
		var newVal = formatNumeric(val);

		// カンマ編集した値を設定する
		e.value = newVal;

		// カーソルの位置を設定する(カンマ編集によるズレを考慮)
		setCursorPosition(e, getMovePosition(curVal, newVal, pos));

		// 前回値としてカンマ編集した値を保持する
		lastVal = newVal;

	}

	return;

}


/*
  移動するカーソル位置を取得する(カンマを入れるとカーソルをズラす)
*/
function getMovePosition(curVal, newVal, pos) {

	var tmpCurVal = curVal;
	var curCommaCnt = 0;
	while (tmpCurVal.indexOf(",") > -1) {
		if (tmpCurVal.indexOf(",") <= pos) {
			curCommaCnt++;
		}
		tmpCurVal = tmpCurVal.replace(",", "");
	}

	var tmpNewVal = newVal;
	var newCommaCnt = 0;
	while (tmpNewVal.indexOf(",") > -1) {
		if (tmpNewVal.indexOf(",") <= pos) {
			newCommaCnt++;
		}
		tmpNewVal = tmpNewVal.replace(",", "");
	}

	// カーソル位置より前にカンマが挿入されたため文字数分ズラす
	if (newCommaCnt > curCommaCnt) {
		return pos + (newCommaCnt - curCommaCnt);
	} 

	// カーソル位置の移動なし
	return pos;

}


/*
  カンマ付きのフォーマットに変換する
*/
function formatNumeric(val) {

	var dec = val.length;
	if (val.indexOf(".") > -1) {
		dec = val.indexOf(".");
	}

	var ret = "";
	if (dec > 0) {
	
		for ( var i = dec ; i > 0 ; i-- ) {
			var num = val.substr(i - 1, 1);
			if ((i != dec) && (((dec - i) % 3) == 0) && (num != "-") && (num != "+")) {
				ret = "," + ret;
			}			
			ret = num + ret;
		}

		if (val.indexOf(".") > -1) {
			ret = ret + val.substr(dec);
		}
		
	} else {

		ret = val;
		
	}

	return ret;

}


/*
  カーソルの位置を取得する
*/
function getCursorPosition(e) {

	if (e.createTextRange) {

		var docRange = document.selection.createRange();
		var range = e.createTextRange();
		range.setEndPoint('EndToStart', docRange);
		return range.text.length;


	} else if (e.setSelectionRange) {

		return e.selectionStart;

	}

	return;

}


/*
  カーソルの位置を設定する
*/
function setCursorPosition(e, position) {

	if (e.createTextRange) {

		var range = e.createTextRange();
		range.move('character', position);
		range.select();

	} else if (e.setSelectionRange) {

		e.setSelectionRange(position, position);

	}

	return;

}


/*
  キー入力を制限する
*/
function doCheckKeyCode(mode) {

	var code = getWindowEvent().keyCode;

	// Enter or Shift or Tab or 矢印 or BackSpace or Delete or Home or End
	if ((code == 13) || (code == 16) || (code == 9) || ((code >= 37) && (code <= 40)) || (code == 8) || (code == 46) || (code == 36) || (code == 35)) {
			return true;
	}
	
	// 数字
	if ((mode == "0") || (mode == "1")) {
		if (((code >= 48) && (code <= 57)) || ((code >= 96) && (code <= 105))) {
			return true;
		}
	}
	
	// + or - or .
	if (mode == "1") {
		if ((code == 107) || (code == 109) || (code == 110) || (code == 187) || (code == 189) || (code == 190)) {
			return true;
		}
	}


	return false;
	
}


/*
  イベントを取得する
*/
function getWindowEvent() {

	if (window.event) {
		return window.event;
	}
	
	var caller = arguments.callee.caller;
	while (caller) {
		var ob = caller.arguments[0];
		if (ob) {
			if ((ob.constructor == KeyboardEvent) || (ob.constructor == MouseEvent)) {
				return ob;
			}
		}
		caller = caller.caller;
	}
	
	return null;
	
}


</script>
</head>
<body>
<input type="text" id="num" onkeydown="return doCheckKeyCode(1);" onkeyup="doFormatNum(this);" size="50" />
</body>
</HTML>