// --------------------------------------------------------------------
// Author  : mashimonator
// Create  : 2009/02/06
// Update  : 2009/04/20
//         : 2009/05/17 プルダウン選択時にonchangeイベント呼び出し処理を追加
//         : 2009/10/15 プルダウン表示位置の判定処理を追加
//         : 2009/10/15 selected属性に対応
//         : 2009/10/15 optgroup要素に対応
//         : 2009/11/16 value=""の場合に選択出来なくなるバグを修正
// Description : IEでプルダウンのリストが切れるのを防ぐ
// --------------------------------------------------------------------

/*@cc_on 
var doc = document;
eval('var document = doc');
@*/
var stretchDropdown = {
	//-----------------------------------------
	// 設定値
	//-----------------------------------------
	conf : {
		// 対象のクラス名（指定無しの場合は全select要素対象）
		targetClass : 'stretchDropdown',
		// プルダウンに一度に表示する最大行数（超えた場合はスクロールバーが表示される）
		maxRow : 8,
		// 以下 編集不可
		selectSerial : 'stretchDropdownBlock_###_target',
		shimSerial : 'stretchDropdownBlock_###_shim',
		idBaseStr : 'stretchDropdownBlock',
		viewingSerial : null,
		viewingMenu : null,
		viewingShim : null,
		count : 0
	},
	//-----------------------------------------
	// 初期処理
	//-----------------------------------------
	init : function() {
		// IEチェック
		if ( !stretchDropdown.isIE() ) {
			return;
		}
		// 対象のselect要素を取得
		var selects;
		if ( stretchDropdown.conf.targetClass && stretchDropdown.conf.targetClass != '' ) {
			selects = stretchDropdown.getTargetElements('select', stretchDropdown.conf.targetClass);
		} else {
			selects = document.getElementsByTagName('select');
		}
		var len = selects.length;
		for ( var i = 0; i < len; i++ ) {
			// select要素にシリアルを付加
			selects[i].className += ' ' + stretchDropdown.getSelectSerial();
			// イベントに関数を付加
			selects[i].onmousedown = function() {
				var str = this.className.split('_');
				stretchDropdown.createPulldown(str[1]);
			}
			// カウントアップ
			stretchDropdown.conf.count += 1;
		}
		// 疑似プルダウンの削除処理を付加
		stretchDropdown.addEvent( document, 'click', stretchDropdown.removePulldown );
	},
	//-----------------------------------------
	// 疑似プルダウンを表示する
	//-----------------------------------------
	createPulldown : function( serial ) {
		// 既に表示中のmenuがあれば削除する
		if ( stretchDropdown.removePulldownInCreate(serial) ) {
			// クリックされた要素がプルダウン表示中のselect要素であれば抜ける
			return;
		}
		// クリックされたselect要素を取得
		var targetSerial = stretchDropdown.conf.selectSerial.replace( '###', serial );
		var select = stretchDropdown.getTargetElements( 'select', targetSerial );
		// 使用不可
		select[0].disabled = true;
		if ( select[0] ) {
			// div要素を生成
			var div = document.createElement('div');
			div.id = stretchDropdown.conf.idBaseStr + '_menu';
			div.className = stretchDropdown.conf.idBaseStr;
			div.style.zIndex = '150';
			// ul要素を生成
			var ul = document.createElement('ul');
			ul.className = stretchDropdown.conf.idBaseStr + '_list';
			// ---select要素にoptgroup要素が含まるか否かで分岐
			if ( !stretchDropdown.existOptgroup(select[0]) ) {
				var optLen = select[0].options.length;
				for ( var i = 0; i < optLen; i++ ) {
					// li要素を生成
					var li = document.createElement('li');
					li.className = stretchDropdown.conf.idBaseStr + '_value';
					if ( select[0].options[i].selected ) {
						// span要素を生成
						var span = document.createElement('span');
						span.className = stretchDropdown.conf.idBaseStr + '_selected';
						span.innerHTML = select[0].options[i].text;
						// span要素をli要素に追加
						li.appendChild(span);
					} else {
						// a要素を生成
						var a = document.createElement('a');
						a.className = stretchDropdown.conf.idBaseStr + '_link';
						a.innerHTML = select[0].options[i].text;
						// href属性をセット
						a.setAttribute('href',"javascript:stretchDropdown.setSelectValue('" + select[0].options[i].value + "');");
						// a要素をli要素に追加
						li.appendChild(a);
					}
					// li要素をul要素に追加
					ul.appendChild(li);
				}
			} else {
				// select要素の子要素を取得
				var children = select[0].childNodes;
				var len = children.length;
				for (var i = 0; i < len; i++) {
					if ( children[i].nodeType == '1' && children[i].nodeName.match(/optgroup/i) ) {
						//--- optgroup要素の場合
						// li要素を生成
						var li = document.createElement('li');
						li.className = stretchDropdown.conf.idBaseStr + '_value';
						// span要素を生成
						var span = document.createElement('span');
						span.className = stretchDropdown.conf.idBaseStr + '_label';
						span.innerHTML = children[i].getAttribute('label');
						// span要素をli要素に追加
						li.appendChild(span);
						// li要素をul要素に追加
						ul.appendChild(li);
						// optgroup要素の子要素を取得
						var grandchildren = children[i].childNodes;
						var len2 = grandchildren.length;
						for (var x = 0; x < len2; x++) {
							if ( grandchildren[x].nodeType == '1' && grandchildren[x].nodeName.match(/option/i) ) {
								// li要素を生成
								var li = document.createElement('li');
								li.className = stretchDropdown.conf.idBaseStr + '_value';
								if ( grandchildren[x].selected ) {
									// span要素を生成
									var span = document.createElement('span');
									span.className = stretchDropdown.conf.idBaseStr + '_selected';
									span.innerHTML = grandchildren[x].text;
									span.style.paddingLeft = '20px';
									// span要素をli要素に追加
									li.appendChild(span);
								} else {
									// a要素を生成
									var a = document.createElement('a');
									a.className = stretchDropdown.conf.idBaseStr + '_link';
									a.innerHTML = grandchildren[x].text;
									a.style.paddingLeft = '20px';
									// href属性をセット
									a.setAttribute('href',"javascript:stretchDropdown.setSelectValue('" + grandchildren[x].value + "');");
									// a要素をli要素に追加
									li.appendChild(a);
								}
								// li要素をul要素に追加
								ul.appendChild(li);
							}
						}
					}
				}
			}
			// ul要素をdiv要素に追加
			div.appendChild(ul);
			div.style.position = 'absolute';
			div.style.visibility = 'hidden';
			div.style.top = '0px';
			div.style.left = '0px';
			// htmlに反映
			document.body.appendChild(div);
			// select要素のポジション・サイズを取得
			var pos = stretchDropdown.getElementPosition( select[0] );
			var size = stretchDropdown.getElementSize( select[0] );
			var divSize = stretchDropdown.getElementSize( div );
			// div要素の幅をセット
			if ( size.width > divSize.width ) {
				div.style.width = size.width;
				divSize.width = size.width;
			}
			// div要素の高さをセット
			if ( select[0].options.length > stretchDropdown.conf.maxRow && li ) {
				var liSize = stretchDropdown.getElementSize( li );
				div.style.overflowY = 'scroll';
				div.style.borderRight = 'none';
				div.style.height = (liSize.height * stretchDropdown.conf.maxRow) + 'px';
			}
			// ブラウザの画面サイズを取得
			var browserSize = stretchDropdown.getBrowserSize();
			var tmpTop = 0;
			var tmpLeft = 0;
			// プルダウン表示位置（横）設定
			if ( (pos.left + size.width + divSize.width) <= browserSize.width ) {
				// 収まる場合
				tmpLeft = pos.left;
			} else {
				// はみ出る場合
				tmpLeft = (pos.left - (divSize.width - size.width));
			}
			// プルダウン表示位置（縦）設定
			if ( (pos.top + size.height + divSize.height) <= browserSize.height ) {
				// 収まる場合
				tmpTop = (pos.top + size.height + 1);
			} else {
				// はみ出る場合
				tmpTop = (pos.top - (divSize.height + 1));
			}
			// 高さと幅をセット
			div.style.left = tmpLeft + 'px';
			div.style.top = tmpTop + 'px';
			// 擬似プルダウンを表示
			div.style.visibility = 'visible';
			// 表示中の疑似プルダウンを保持
			stretchDropdown.conf.viewingMenu = div;
			// 疑似プルダウンを表示中のselect要素のシリアルを保持
			stretchDropdown.conf.viewingSerial = serial;
			// shimを生成
			stretchDropdown.createShim( tmpTop, tmpLeft, div.scrollWidth, div.scrollHeight, true );
			// focusを移動
			div.focus();
		}
	},
	//-----------------------------------------
	// 疑似プルダウンで選択された値をselect要素にセットする
	//-----------------------------------------
	setSelectValue : function( index ) {
		// 対象のselect要素を取得
		var targetSerial = stretchDropdown.conf.selectSerial.replace( '###', stretchDropdown.conf.viewingSerial );
		var select = stretchDropdown.getTargetElements( 'select', targetSerial );
		// 擬似プルダウンを削除
		stretchDropdown.removePulldown();
		if ( index != undefined && index != null && select[0] ) {
			// 選択された値をselect要素に反映
			var optLen = select[0].options.length;
			for ( var i = 0; i < optLen; i++ ) {
				if ( select[0].options[i].value == index ) {
					select[0].selectedIndex = i;
				}
			}
			// focusを移動
			select[0].focus();
			// onchangeイベントを呼び出し
			if ( select[0].onchange ) {
				select[0].onchange();
			}
		}
	},
	//-----------------------------------------
	// 疑似プルダウンを削除する（新規プルダウン生成時）
	//-----------------------------------------
	removePulldownInCreate : function ( serial ) {
		var state = false;
		// 既に表示中のmenuがあれば削除する
		if ( stretchDropdown.conf.viewingSerial ) {
			var viewingSerial = stretchDropdown.conf.viewingSerial;
			document.body.removeChild(stretchDropdown.conf.viewingMenu);
			stretchDropdown.conf.viewingMenu = null;
			document.body.removeChild(stretchDropdown.conf.viewingShim);
			stretchDropdown.conf.viewingShim = null;
			stretchDropdown.changeSelectDisabled( stretchDropdown.conf.viewingSerial, false);
			stretchDropdown.conf.viewingSerial = null;
			if ( viewingSerial == serial ) {
				// クリックされた要素がプルダウン表示中のselect要素であればtrueをセット
				state = true;
			}
		}
		return state;
	},
	//-----------------------------------------
	// 疑似プルダウンを削除する
	//-----------------------------------------
	removePulldown : function( event ) {
		var element;
		// イベント発生元の要素を取得
		if ( event && event.target ) {
			element = event.target;
		} else if ( window.event && window.event.srcElement ) {
			element = window.event.srcElement;
		}
		if ( element ) {
			// 擬似プルダウンがイベント発生元の場合は抜ける
			if ( stretchDropdown.checkEventTarget(element) ) {
				return;
			}
		}
		// 擬似プルダウンを削除
		if ( stretchDropdown.conf.viewingSerial ) {
			document.body.removeChild(stretchDropdown.conf.viewingMenu);
			stretchDropdown.conf.viewingMenu = null;
			document.body.removeChild(stretchDropdown.conf.viewingShim);
			stretchDropdown.conf.viewingShim = null;
			stretchDropdown.changeSelectDisabled( stretchDropdown.conf.viewingSerial, false);
			stretchDropdown.conf.viewingSerial = null;
		}
	},
	//-----------------------------------------
	// shimを生成する
	//-----------------------------------------
	createShim : function( top, left, width, height, flg ) {
		// iframe要素を生成
		var iframe = document.createElement('iframe');
		// idを設定
		if ( flg ) {
			iframe.id = stretchDropdown.conf.idBaseStr + '_shim';
		}
		// 基本スタイル設定
		iframe.setAttribute('frameBorder', '0');
		iframe.setAttribute('scrolling', 'no');
		iframe.style.border = 'none';
		iframe.style.zIndex = '100';
		// 透明度設定
		if ( !stretchDropdown.isUnderIE7() ) {
			iframe.style.opacity = .00;
			iframe.style.filter = 'alpha(opacity=0)';
			iframe.alpha = 0;
			iframe.allowTransparency = 'true';
		}
		// サイズ設定
		iframe.style.width = width + 'px';
		if ( flg ) {
			iframe.style.height = height + 'px';
		} else {
			iframe.style.height = ( height + 2 ) + 'px';
		}
		// ポジション設定
		iframe.style.position = 'absolute';
		iframe.style.top = top + 'px';
		iframe.style.left = left + 'px';
		// htmlに反映
		document.body.appendChild(iframe);
		if ( flg ) {
			stretchDropdown.conf.viewingShim = iframe;
		}
	},
	//-----------------------------------------
	// select要素のdisabledを切り替える
	//-----------------------------------------
	changeSelectDisabled : function( serial, state ) {
		serial = stretchDropdown.conf.selectSerial.replace( '###', serial );
		var select = stretchDropdown.getTargetElements( 'select', serial );
		var len = select.length;
		for (var i = 0; i < len; i++) {
			select[i].disabled = state;
		}
	},
	//-----------------------------------------
	// イベント発生元が擬似プルダウンかを判定する
	//-----------------------------------------
	checkEventTarget : function( element ) {
		var result = false;
		if ( element.nodeType == '1' && element.className.match(stretchDropdown.conf.idBaseStr) ) {
			result = true;
		}
		return result;
	},
	//-----------------------------------------
	// select要素にoptgroupが含まれるかを返す
	//-----------------------------------------
	existOptgroup : function( element ) {
		var optgroup = element.getElementsByTagName('OPTGROUP');
		if ( optgroup.length && optgroup.length > 0 ) {
			return true;
		} else {
			return false;
		}
	},
	//-----------------------------------------
	// selected属性が指定されているoption要素のテキストを返す
	//-----------------------------------------
	getSelectedOption : function( element ) {
		var result = false;
		var opt = element.getElementsByTagName('OPTION');
		var len = opt.length;
		for (var i = 0; i < len; i++) {
			if ( opt[i].selected ) {
				result = opt[i].innerHTML;
				break;
			}
		}
		return result;
	},
	//-----------------------------------------
	// select要素用シリアルを返す
	//-----------------------------------------
	getSelectSerial : function() {
		return stretchDropdown.conf.selectSerial.replace( '###', stretchDropdown.conf.count );
	},
	//-----------------------------------------
	// 対象要素のサイズを取得する
	//-----------------------------------------
	getElementSize : function( element ) {
		var w = element.offsetWidth;
		var h = element.offsetHeight;
		return ({ 'width': w, 'height': h });
	},
	//-----------------------------------------
	// ブラウザの画面サイズを取得する
	//-----------------------------------------
	getBrowserSize : function() {
		var w = 0;
		var h = 0;
		if ( window.innerWidth ) {
			w = window.innerWidth;
		} else if ( document.documentElement && document.documentElement.clientWidth != 0 ) {
			w = document.documentElement.clientWidth;
		} else if ( document.body ) {
			w = document.body.clientWidth;
		}
		w = (document.documentElement.scrollLeft || document.body.scrollLeft) + w;
		if ( window.innerHeight ) {
			h = window.innerHeight;
		} else if ( document.documentElement && document.documentElement.clientHeight != 0 ) {
			h = document.documentElement.clientHeight;
		} else if ( document.body ) {
			h = document.body.clientHeight;
		}
		h = (document.documentElement.scrollTop || document.body.scrollTop) + h;
		return ({ 'width': w, 'height': h });
	},
	//-----------------------------------------
	// 対象要素のポジションを取得する
	//-----------------------------------------
	getElementPosition : function( element ) {
		var offsetTrail = (typeof element == 'string') ? document.getElementById(element): element;
		var x = 0;
		var y = 0;
		while (offsetTrail) {
			x += offsetTrail.offsetLeft;
			y += offsetTrail.offsetTop;
			offsetTrail = offsetTrail.offsetParent;
		}
		if ( navigator.userAgent.indexOf('Mac') != -1 && typeof doc.body.leftMargin != 'undefined' ) {
			x += document.body.leftMargin;
			y += document.body.topMargin;
		}
		return ({ 'left': x, 'top': y });
	},
	//-----------------------------------------
	// ターゲットタグを取得する
	//-----------------------------------------
	getTargetElements : function( tag, cls ) {
		var elements = new Array();
		var targetElements = document.getElementsByTagName(tag.toUpperCase());
		var len = targetElements.length;
		for ( var i = 0; i < len; i++ ) {
			if ( targetElements[i].className && targetElements[i].className.match(cls) ) {
				elements[elements.length] = targetElements[i];
			}
		}
		return elements;
	},
	//-----------------------------------------
	// IE判定
	//-----------------------------------------
	isIE : function() {
		IE='\v'=='v';
		if(IE){
			return true;
		}else{
			return false;
		}
	},
	//-----------------------------------------
	// IE7以下判定
	//-----------------------------------------
	isUnderIE7 : function() {
		IE='\v'=='v';
		if ( IE ) {
			if ( document.documentMode ) {
				if ( document.documentMode == '7' || document.documentMode == '5' ) {
					return true;
				} else {
					return false;
				}
			} else {
				return true;
			}
		} else {
			return false;
		}
	},
	//-----------------------------------------
	// イベントに関数を付加する
	//-----------------------------------------
	addEvent : function( target, event, func ) {
		try {
			target.addEventListener(event, func, false);
		} catch (e) {
			target.attachEvent('on' + event, func);
		}
	}
}
// 実行
stretchDropdown.addEvent( window, 'load', stretchDropdown.init );
