[JS] Tabキーによる移動を禁止してTabを入力する。



# Update
* 2018/01/10 14:59  
  @hoo-chan さんにご提示頂いたコードを元に再構成。  
  コードは解説が要らないくらいシンプル＆スマートに。  
  元記事は「出来の悪い元記事」として残します。  

# やりたいこと
* テキストエリアやテキストボックスで、タブを入力したい。

# スニペット
```javascript:javascript

// element: Tabを入力できるようにしたい要素
element.addEventListener("keydown", input_tab);

function input_tab(event) {
	if (event.key === "Tab") {
		// デフォルト動作停止
		event.preventDefault();
		//  Tabを挿入。範囲指定時は置換。
		var TAB = "\t";
		var value = this.value;
		var sPos = this.selectionStart;
		var ePos = this.selectionEnd;
		var result = value.slice(0, sPos) + TAB + value.slice(ePos);
		var cPos = sPos + TAB.length;
		this.value = result;
		this.setSelectionRange(cPos, cPos);
	}
}
```

tabの挿入には `setRangeText()` を使うと更に簡単に書けますが、現状IE/Edgeが未対応であるため、今回は使用しない方法で記載します。


# サンプル
```html:sample.html
<html>
	<head>
	</head>
	<body>
		▼タブで移動<br>
		<textarea rows=3 cols=40></textarea><br>
		<input type=text>
		<input type=password>
		<br>
		<br>
		▼タブ入力可（タブでの移動禁止）<br>
		<textarea rows=3 cols=40 class="tab_input"></textarea><br>
		<input type=text     class="tab_input">
		<input type=password class="tab_input">

		<script>
			// Tabを入力できるようにしたい要素
			var elements = document.getElementsByClassName("tab_input");
			for ( var i = 0; i < elements.length; i++ ){
				elements[i].addEventListener("keydown", input_tab);
			}

			function input_tab(event) {
				if (event.key === "Tab") {
					// デフォルト動作停止
					event.preventDefault();
					//  タブを挿入。範囲指定時は置換。
					var TAB = "\t";
					var value = this.value;
					var sPos = this.selectionStart;
					var ePos = this.selectionEnd;
					var result = value.slice(0, sPos) + TAB + value.slice(ePos);
					var cPos = sPos + TAB.length;
					this.value = result;
					this.setSelectionRange(cPos, cPos);
				}
			}
		</script>
	</body>
</html>

```

# 出来の悪い元記事


## スニペット
```javascript:javascript
function tab_input(element){
	//	フォーカスイン
	element.addEventListener("focus", function(event) {
		//	Tabキーの挙動をフォーカス移動ではなくタブ入力にする。
		window.document.onkeydown = function(event){
			// 9 = Tab
			if(event.keyCode === 9) {
				// デフォルト動作停止
				event.preventDefault();

				//	Tabを挿入。範囲指定時は置換。
				var obj  = event.target;		// オブジェクト取得
				var sPos = obj.selectionStart;	// 入力（選択）開始位置
				var ePos = obj.selectionEnd;	// 入力（選択）終了位置
				var result  = obj.value.substr(0, sPos) + "\t" + obj.value.substr(ePos);
				obj.value	=	result;

				// 入力したタブの後ろを選択。
				var cPos	=	sPos + "\t".length;
				obj.setSelectionRange(cPos, cPos);
			}
		};
	},false);

	//	フォーカスアウト
	element.addEventListener("blur", function(event) {
		// デフォルト動作を行うように再設定
		window.document.onkeydown = function(event){
			return true;
		};
	},false);
}
```

## 簡単に解説
* まず、Tabキーによるコントロールの移動を禁止する。  
  `window.document.onkeydown` イベントの処理でタブキーが押された時に `event.preventDefault();` を実行して、デフォルト動作をしないよう設定する。
* だがそれだけでは影響範囲が「ページ上の全てのコントロール」になってしまう。  
  対象となるコントロールを限定するため以下のようにする。
  * 対象コントロールにフォーカスインしたら `window.document.onkeydown` のイベント処理を登録。
  * 対象コントロールからフォーカスアウトしたらイベント処理を解放。
* Tabを入力する処理については特記事項なし。

## サンプル
```html:sample.html
<html>
	<head>
	</head>
	<body>
		▼タブで移動<br>
		<textarea rows=3 cols=40></textarea><br>
		<input type=text>
		<input type=password>
		<br>
		<br>
		▼タブ入力可（タブでの移動禁止）<br>
		<textarea rows=3 cols=40 class="tab_input"></textarea><br>
		<input type=text     class="tab_input">
		<input type=password class="tab_input">

		<script>
			//	"tab_input"クラスが設定されているコントロールを対象として設定
			let elements = document.getElementsByClassName("tab_input");
			for( let element of elements ){
				tab_input(element);
			}

			function tab_input(element){
				//	フォーカスイン
				element.addEventListener("focus", function(event) {
					//	タブキーの挙動をフォーカス移動ではなくタブ入力にする。
					window.document.onkeydown = function(event){
						// 9 = Tab
						if(event.keyCode === 9) {
							// デフォルト動作停止
							event.preventDefault();

							//	タブを挿入。範囲指定時は置換。
							var obj  = event.target;		// オブジェクト取得
							var sPos = obj.selectionStart;	// 入力（選択）開始位置
							var ePos = obj.selectionEnd;	// 入力（選択）終了位置
							var result  = obj.value.substr(0, sPos) + "\t" + obj.value.substr(ePos);
							obj.value	=	result;

							// 入力したタブの後ろを選択。
							var cPos	=	sPos + "\t".length;
							obj.setSelectionRange(cPos, cPos);
						}
					};
				},false);

				//	フォーカスアウト
				element.addEventListener("blur", function(event) {
					// デフォルト動作を行うように再設定
					window.document.onkeydown = function(event){
						return true;
					};
				},false);
			}
		</script>
	</body>
</html>
```