/**
 * select2
 * class=sel2selを付けたプルダウンに対して絞り込みを行う機能を追加します。
 * classの付加とJS読み込みで自動的に動作します。
 * 「*」をクリックでテキストボックスを表示/削除します。
 * プルダウンのonChangeでも削除されます。(onChangeのため、一つしか選択肢がない場合は自動で消えません)
 * option数が非常に多い倍は処理時間がかかるかもしれません。
 *
 * jQuery1.12の機能で作成しています。
 * 8.4.3.0 (2023/03/31) jQuery 3.6 系に合わせて修正
 */

this.select2 = function(){
	var xOffset = 30;
	var yOffset = -60;

	// 絞り込み動作
	var sel2sel = function(_tgtid,_txt){
		// IEに対応しなくて良い場合はcssでコントロール可能で、こちらの方が高速(適当)
/*		$("#"+_tgtid+" option").each(function(i){
			if(_txt == ""){$(this).css("display","inline");}
			else{
				if( $(this).text().indexOf(_txt)>=0 ){
					$(this).css("display","inline");
				}
				else{
					$(this).css("display","none");
				}
			}
		});
*/
		// IEに対応させる場合は保存したorgoptionを走査してから置き換え
		// この場合はselectedを取得してから戻してやる必要がある
		var _orgoptions = document.getElementById(_tgtid).orgoptions;
		var _tgtjq = $("#"+_tgtid);
		var _selected = _tgtjq.val();
		var _newoptions = new Array();
		for( i=0; i<_orgoptions.length; i++ ){
			if (_txt == ""){ // 元に戻す(すべて追加)
				_newoptions.push($(_orgoptions[i]).prop('outerHTML'));
			}
			else if( _orgoptions[i].tagName == "OPTGROUP" ){ // optionGroupの場合内部のOptionを走査する必要あり
				// optionGroupは入れ子にはならないはず。面倒なので関数を分けずにここでやってしまう。
				var _groupChildren = $(_orgoptions[i]).children();
				var _grpFlg = false;
				var _thisGroup = null;
				if( !_groupChildren ){ continue; }
				for( j=0; j<_groupChildren.length; j++ ){
					if( _groupChildren[j].innerText.indexOf(_txt)>=0){
						if( ! _grpFlg ){
							// グループを維持するため、手動でグループを作成する(とりあえずラベルだけ)
							_grpFlg = true;
							_thisGroup = $("<optgroup> </optgroup>").prop("label",_orgoptions[i].label);
						}
						if( $(_groupChildren[j]).prop('disabled') ){ continue; }
						_thisGroup.append($(_groupChildren[j]).prop('outerHTML'));
					}
				}
				if( _grpFlg ){ _newoptions.push($(_thisGroup).prop('outerHTML'));  }
			}
			else if( _orgoptions[i].innerText.indexOf(_txt)>=0){ // 合致したもの
				if( $(_orgoptions[i]).prop('disabled') ){ continue; }
				_newoptions.push($(_orgoptions[i]).prop('outerHTML'));
			}
		}
		$("#"+_tgtid).children().remove();
		_tgtjq.append(_newoptions.join(" ")).val(_selected); // 選択を戻す
		if( _tgtjq.val() == null ){ _tgtjq.prop("selectedIndex", 0); } // nullの場合は先頭選択
		// IE対応ここまで
	}

	var sel2inputDel = function(_tgt){
		setTimeout(function() {
			sel2sel(_tgt,"");
			$(document.getElementById(_tgt+"sel2outer")).remove();
		}, 100);
	}

	// オプション保存、*の追加
	var sel2create = function(_this){
		var thisoptions = $(_this).children();
		_this.orgoptions = thisoptions.clone();
		$(_this).after("<span class='select2' targetId='"+_this.id+"'>*</span>");
		// 8.4.3.0 (2023/03/31) jQuery.fn.change() event shorthand is deprecated
//		$(_this).change( function(){sel2inputDel(_this.id)} );
		$(_this).on( "change", function(){sel2inputDel(_this.id)} );
//		$(_this).width($(_this).width()); // 8.0.0.1 (2021/10/08) Delete
	}
	select2.sel2create = sel2create; // 外部からCallできるようにプロパティに設定しておく

	// *追加の実行
	$("SELECT.sel2sel").each(function(i){
		sel2create(this);
	});

	// inputタグ表示/削除イベント
	$(document).on("click",".select2",function(e){
		var tgtId = this.getAttribute("targetId");
		var thisId = tgtId + "sel2";
		var outerId = tgtId + "sel2outer";
		if( document.getElementById(thisId) ){
			sel2inputDel(tgtId) // 削除
		}
		else{ // 表示
			$("body").append("<div id='"+outerId+"' style='position:absolute;background-color:silver;'> <input size='7' name='dummy' id='"+thisId+"' class='sel2input' targetId='"+tgtId
				+"' /><span class='select2' style='cursor:default' targetId='"+tgtId+"'>×</span></div>");
			$("#"+outerId)
			.css("top",(e.pageY - xOffset) + "px")
			.css("left",(e.pageX + yOffset) + "px")
			// 8.4.3.0 (2023/03/31) jQuery.fn.focus() event shorthand is deprecated
//			.children("input")[0].focus();
			.children("input")[0].trigger('focus');
		}
	});

	// 絞り込みイベント
	$(document).on("keyup",".sel2input", function(e){ // V3の場合はkeyupではなくchangeで変更させた方が良い
		if(e.keyCode == 13){
			var tgtId = this.getAttribute("targetId");
			// 8.4.3.0 (2023/03/31) jQuery.fn.change() event shorthand is deprecated
//			$(this).change();
			$(this).trigger( "change" );
			// 8.4.3.0 (2023/03/31) jQuery.fn.focus() event shorthand is deprecated
//			$("#"+tgtId).focus();
			$("#"+tgtId).trigger('focus');
		}
		else{
			var tgtId = this.getAttribute("targetId");
			sel2sel(tgtId,this.value);
		}
	});

	//動的追加処理に対応する方法の例(IEは11のみ対応)
	function mo_callback(mutations){
		mutations.forEach( mutation => { // 個別の（動的な）要素変更情報
			mutation.addedNodes.forEach( node => { // 追加された要素（ノードリスト）
				if( node.tagName==='SELECT' && $(node).hasClass('sel2sel') ) { //変更ノードを指定
					sel2create(node);
				}
			});
		});
	}
	var options = {childList: true, subtree:true};
	var mo = new MutationObserver(mo_callback);
	mo.observe(document, options); // 特定の親を指定しずらいので、負荷がかかるのを承知でdocumentの子孫ノード全てを指定
	//動的追加対応ここまで
}

// 自動実行
$(document).ready(function(){
	select2();
});
