﻿var isIE = (document.all) ? true : false;

var $$ = function(id) {
	return "string" == typeof id ? document.getElementById(id) : id;
};

var Class = {
	create: function() {
		return function() { this.initialize.apply(this, arguments); }
	}
}

var Extend = function(destination, source) {
	for (var property in source) {
		destination[property] = source[property];
	}
}

var Bind = function(object, fun) {
	var args = Array.prototype.slice.call(arguments).slice(2);
	return function() {
		return fun.apply(object, args);
	}
}

var BindAsEventListener = function(object, fun) {
	return function(event) {
		return fun.call(object, Event(event));
	}
}

function Event(e) {
	var oEvent = isIE ? window.event : e;
	if (isIE) {
		oEvent.pageX = oEvent.clientX + document.documentElement.scrollLeft;
		oEvent.pageY = oEvent.clientY + document.documentElement.scrollTop;
		oEvent.preventDefault = function() { this.returnValue = false; };
		oEvent.detail = oEvent.wheelDelta / (-40);
		oEvent.stopPropagation = function() { this.cancelBubble = true; };
	}
	return oEvent;
}

var CurrentStyle = function(element) {
	return element.currentStyle || document.defaultView.getComputedStyle(element, null);
}

function addEventHandler(oTarget, sEventType, fnHandler) {
	if (oTarget.addEventListener) {
		oTarget.addEventListener(sEventType, fnHandler, false);
	} else if (oTarget.attachEvent) {
		oTarget.attachEvent("on" + sEventType, fnHandler);
	} else {
		oTarget["on" + sEventType] = fnHandler;
	}
};

function removeEventHandler(oTarget, sEventType, fnHandler) {
	if (oTarget.removeEventListener) {
		oTarget.removeEventListener(sEventType, fnHandler, false);
	} else if (oTarget.detachEvent) {
		oTarget.detachEvent("on" + sEventType, fnHandler);
	} else {
		oTarget["on" + sEventType] = null;
	}
};


//滑動條程序
var Slider = Class.create();
Slider.prototype = {
	//容器對象，滑塊
	initialize: function(container, bar, options) {
		this.Bar = $$(bar);
		this.Container = $$(container);
		this._timer = null; //自動滑移的定時器
		this._ondrag = false; //解決ie的click問題
		//是否最小值、最大值、中間值
		this._IsMin = this._IsMax = this._IsMid = false;
		//實例化一個拖放對象，並限定範圍
		this._drag = new Drag(this.Bar, { Limit: true, mxContainer: this.Container,
			onStart: Bind(this, this.DragStart), onStop: Bind(this, this.DragStop), onMove: Bind(this, this.Move)
		});

		this.SetOptions(options);

		this.WheelSpeed = Math.max(0, this.options.WheelSpeed);
		this.KeySpeed = Math.max(0, this.options.KeySpeed);

		this.MinValue = this.options.MinValue;
		this.MaxValue = this.options.MaxValue;

		this.RunTime = Math.max(1, this.options.RunTime);
		this.RunStep = Math.max(1, this.options.RunStep);

		this.Ease = !!this.options.Ease;
		this.EaseStep = Math.max(1, this.options.EaseStep);

		this.onMin = this.options.onMin;
		this.onMax = this.options.onMax;
		this.onMid = this.options.onMid;

		this.onDragStart = this.options.onDragStart;
		this.onDragStop = this.options.onDragStop;

		this.onMove = this.options.onMove;

		this._horizontal = !!this.options.Horizontal; //一般不允許修改

		//鎖定拖放方向
		this._drag[this._horizontal ? "LockY" : "LockX"] = true;

		//點擊控制
		addEventHandler(this.Container, "click", BindAsEventListener(this, function(e) { this._ondrag || this.ClickCtrl(e); }));
		//取消冒泡，防止跟Container的click衝突
		addEventHandler(this.Bar, "click", BindAsEventListener(this, function(e) { e.stopPropagation(); }));

		//設置鼠標滾輪控制
		this.WheelBind(this.Container);
		//設置方向鍵控制
		this.KeyBind(this.Container);
		//修正獲取焦點
		var oFocus = isIE ? (this.KeyBind(this.Bar), this.Bar) : this.Container;
		addEventHandler(this.Bar, "mousedown", function() { oFocus.focus(); });
		//ie鼠標捕獲和ff的取消默認動作都不能獲得焦點，所以要手動獲取
		//如果ie把focus設置到Container，那么在出現滾動條時ie的focus可能會導致自動滾屏
	},




	//設置默認屬性
	SetOptions: function(options) {
		this.options = {//默認值
			MinValue: 0, //最小值
			MaxValue: 100, //最大值
			WheelSpeed: 0, //鼠標滾輪速度,越大越快(0則取消鼠標滾輪控制)
			KeySpeed: 0, //方向鍵滾動速度,越大越慢(0則取消方向鍵控制)



			Horizontal: true, //是否水平滑動
			RunTime: 20, //自動滑移的延時時間,越大越慢
			RunStep: 2, //自動滑移每次滑動的百分比
			Ease: false, //是否緩動
			EaseStep: 5, //緩動等級,越大越慢
			onMin: function() { }, //最小值時執行
			onMax: function() { }, //最大值時執行
			onMid: function() { }, //中間值時執行
			onDragStart: function() { }, //拖動開始時執行
			onDragStop: function() { }, //拖動結束時執行
			onMove: function() { } //滑動時執行
		};
		Extend(this.options, options || {});
	},
	//開始拖放滑動
	DragStart: function() {
		this.onDragStart();
		this._ondrag = true;
	},
	//結束拖放滑動
	DragStop: function() {
		this.onDragStop();
		setTimeout(Bind(this, function() { this._ondrag = false; }), 10);
	},
	//滑動中
	Move: function() {
		this.onMove();

		var percent = this.GetPercent();
		//最小值判斷
		if (percent > 0) {
			this._IsMin = false;
		} else {
			if (!this._IsMin) { this.onMin(); this._IsMin = true; }
		}
		//最大值判斷
		if (percent < 1) {
			this._IsMax = false;
		} else {
			if (!this._IsMax) { this.onMax(); this._IsMax = true; }
		}
		//中間值判斷
		if (percent > 0 && percent < 1) {
			if (!this._IsMid) { this.onMid(); this._IsMid = true; }
		} else {
			this._IsMid = false;
		}
	},
	//鼠標點擊控制
	ClickCtrl: function(e) {
		var o = this.Container, iLeft = o.offsetLeft, iTop = o.offsetTop;
		while (o.offsetParent) { o = o.offsetParent; iLeft += o.offsetLeft; iTop += o.offsetTop; }
		//考慮有滾動條，要用pageX和pageY
		this.EasePos(e.pageX - iLeft - this.Bar.offsetWidth / 2, e.pageY - iTop - this.Bar.offsetHeight / 2);
	},
	//鼠標滾輪控制
	WheelCtrl: function(e) {
		var i = this.WheelSpeed * e.detail;
		this.SetPos(this.Bar.offsetLeft + i, this.Bar.offsetTop + i);
		//防止觸發其他滾動條
		e.preventDefault();
	},
	//綁定鼠標滾輪
	WheelBind: function(o) {
		//鼠標滾輪控制
		addEventHandler(o, isIE ? "mousewheel" : "DOMMouseScroll", BindAsEventListener(this, this.WheelCtrl));
	},
	//方向鍵控制
	KeyCtrl: function(e) {
		if (this.KeySpeed) {
			var iLeft = this.Bar.offsetLeft, iWidth = (this.Container.clientWidth - this.Bar.offsetWidth) / this.KeySpeed
			, iTop = this.Bar.offsetTop, iHeight = (this.Container.clientHeight - this.Bar.offsetHeight) / this.KeySpeed;
			//根據按鍵設置值
			switch (e.keyCode) {
				case 37: //左
					iLeft -= iWidth; break;
				case 38: //上
					iTop -= iHeight; break;
				case 39: //右
					iLeft += iWidth; break;
				case 40: //下
					iTop += iHeight; break;
				default:
					return; //不是方向按鍵返回
			}
			this.SetPos(iLeft, iTop);
			//防止觸發其他滾動條
			e.preventDefault();
		}
	},
	//綁定方向鍵
	KeyBind: function(o) {
		addEventHandler(o, "keydown", BindAsEventListener(this, this.KeyCtrl));
		//設置tabIndex使設置對象能支持focus
		o.tabIndex = -1;
		//取消focus時出現的虛線框
		isIE || (o.style.outline = "none");
	},
	//獲取當前值
	GetValue: function() {
		//根據最大最小值和滑動百分比取值
		return this.MinValue + this.GetPercent() * (this.MaxValue - this.MinValue);
	},
	//設置值位置
	SetValue: function(value) {
		//根據最大最小值和參數值設置滑塊位置
		this.SetPercent((value - this.MinValue) / (this.MaxValue - this.MinValue));
	},
	//獲取百分比
	GetPercent: function() {
		//根據滑動條滑塊取百分比
		return this._horizontal ? this.Bar.offsetLeft / (this.Container.clientWidth - this.Bar.offsetWidth)
		: this.Bar.offsetTop / (this.Container.clientHeight - this.Bar.offsetHeight)
	},
	//設置百分比位置
	SetPercent: function(value) {
		//根據百分比設置滑塊位置
		this.EasePos((this.Container.clientWidth - this.Bar.offsetWidth) * value, (this.Container.clientHeight - this.Bar.offsetHeight) * value);
	},
	//自動滑移(是否遞增)
	Run: function(bIncrease) {
		this.Stop();
		//修正一下bIncrease
		bIncrease = !!bIncrease;
		//根據是否遞增來設置值
		var percent = this.GetPercent() + (bIncrease ? 1 : -1) * this.RunStep / 100;
		this.SetPos((this.Container.clientWidth - this.Bar.offsetWidth) * percent, (this.Container.clientHeight - this.Bar.offsetHeight) * percent);
		//如果沒有到極限值就繼續滑移
		if (!(bIncrease ? this._IsMax : this._IsMin)) {
			this._timer = setTimeout(Bind(this, this.Run, bIncrease), this.RunTime);
		}
	},
	//停止滑移
	Stop: function() {
		clearTimeout(this._timer);
	},
	//緩動滑移
	EasePos: function(iLeftT, iTopT) {
		this.Stop();
		//必須是整數，否則可能死循環
		iLeftT = Math.round(iLeftT); iTopT = Math.round(iTopT);
		//如果沒有設置緩動
		if (!this.Ease) { this.SetPos(iLeftT, iTopT); return; }
		//獲取緩動參數
		var iLeftN = this.Bar.offsetLeft, iLeftS = this.GetStep(iLeftT, iLeftN)
	, iTopN = this.Bar.offsetTop, iTopS = this.GetStep(iTopT, iTopN);
		//如果參數有值
		if (this._horizontal ? iLeftS : iTopS) {
			//設置位置
			this.SetPos(iLeftN + iLeftS, iTopN + iTopS);
			//如果沒有到極限值則繼續緩動
			if (this._IsMid) { this._timer = setTimeout(Bind(this, this.EasePos, iLeftT, iTopT), this.RunTime); }
		}
	},
	//獲取步長
	GetStep: function(iTarget, iNow) {
		var iStep = (iTarget - iNow) / this.EaseStep;
		if (iStep == 0) return 0;
		if (Math.abs(iStep) < 1) return (iStep > 0 ? 1 : -1);
		return iStep;
	},
	//設置滑塊位置
	SetPos: function(iLeft, iTop) {
		this.Stop();
		this._drag.SetPos(iLeft, iTop);
	}
};




//拖放程序
var Drag = Class.create();
Drag.prototype = {
  //拖放對象
  initialize: function(drag, options) {
	this.Drag = $$(drag);//拖放對象
	this._x = this._y = 0;//記錄鼠標相對拖放對象的位置
	this._marginLeft = this._marginTop = 0;//記錄margin
	//事件對象(用於綁定移除事件)
	this._fM = BindAsEventListener(this, this.Move);
	this._fS = Bind(this, this.Stop);
	
	this.SetOptions(options);
	
	this.Limit = !!this.options.Limit;
	this.mxLeft = parseInt(this.options.mxLeft);
	this.mxRight = parseInt(this.options.mxRight);
	this.mxTop = parseInt(this.options.mxTop);
	this.mxBottom = parseInt(this.options.mxBottom);
	
	this.LockX = !!this.options.LockX;
	this.LockY = !!this.options.LockY;
	this.Lock = !!this.options.Lock;
	
	this.onStart = this.options.onStart;
	this.onMove = this.options.onMove;
	this.onStop = this.options.onStop;

	this._Handle = $$(this.options.Handle) || this.Drag;
	this._mxContainer = $$(this.options.mxContainer) || null;
	
	this.Drag.style.position = "absolute";
	//透明
	if(isIE && !!this.options.Transparent){
		//填充拖放對象
		with(this._Handle.appendChild(document.createElement("div")).style){
			width = height = "100%"; backgroundColor = "#fff"; filter = "alpha(opacity:0)"; fontSize = 0;
		}
	}
	//修正範圍
	this.Repair();
	addEventHandler(this._Handle, "mousedown", BindAsEventListener(this, this.Start));
  },
  //設置默認屬性
  SetOptions: function(options) {
	this.options = {//默認值
		Handle:			"",//設置觸發對象（不設置則使用拖放對象）
		Limit:			false,//是否設置範圍限制(為true時下面參數有用,可以是負數)
		mxLeft:			0,//左邊限制
		mxRight:		9999,//右邊限制
		mxTop:			0,//上邊限制
		mxBottom:		9999,//下邊限制
		mxContainer:	"",//指定限制在容器內
		LockX:			false,//是否鎖定水平方向拖放
		LockY:			false,//是否鎖定垂直方向拖放
		Lock:			false,//是否鎖定
		Transparent:	false,//是否透明
		onStart:		function(){},//開始移動時執行
		onMove:			function(){},//移動時執行
		onStop:			function(){}//結束移動時執行
	};
	Extend(this.options, options || {});
  },
  //準備拖動
  Start: function(oEvent) {
	if(this.Lock){ return; }
	this.Repair();
	//記錄鼠標相對拖放對象的位置
	this._x = oEvent.clientX - this.Drag.offsetLeft;
	this._y = oEvent.clientY - this.Drag.offsetTop;
	//記錄margin
	this._marginLeft = parseInt(CurrentStyle(this.Drag).marginLeft) || 0;
	this._marginTop = parseInt(CurrentStyle(this.Drag).marginTop) || 0;
	//mousemove時移動 mouseup時停止
	addEventHandler(document, "mousemove", this._fM);
	addEventHandler(document, "mouseup", this._fS);
	if(isIE){
		//焦點丟失
		addEventHandler(this._Handle, "losecapture", this._fS);
		//設置鼠標捕獲
		this._Handle.setCapture();
	}else{
		//焦點丟失
		addEventHandler(window, "blur", this._fS);
		//阻止默認動作
		oEvent.preventDefault();
	};
	//附加程序
	this.onStart();
  },
  //修正範圍
  Repair: function() {
	if(this.Limit){
		//修正錯誤範圍參數
		this.mxRight = Math.max(this.mxRight, this.mxLeft + this.Drag.offsetWidth);
		this.mxBottom = Math.max(this.mxBottom, this.mxTop + this.Drag.offsetHeight);
		//如果有容器必須設置position為relative來相對定位，並在獲取offset之前設置
		!this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" || CurrentStyle(this._mxContainer).position == "absolute" || (this._mxContainer.style.position = "relative");
	}
  },
  //拖動
  Move: function(oEvent) {
	//判斷是否鎖定
	if(this.Lock){ this.Stop(); return; };
	//清除選擇
	window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
	//設置移動參數
	this.SetPos(oEvent.clientX - this._x, oEvent.clientY - this._y);
  },
  //設置位置
  SetPos: function(iLeft, iTop) {
	//設置範圍限制
	if(this.Limit){
		//設置範圍參數
		var mxLeft = this.mxLeft, mxRight = this.mxRight, mxTop = this.mxTop, mxBottom = this.mxBottom;
		//如果設置了容器，再修正範圍參數
		if(!!this._mxContainer){
			mxLeft = Math.max(mxLeft, 0);
			mxTop = Math.max(mxTop, 0);
			mxRight = Math.min(mxRight, this._mxContainer.clientWidth);
			mxBottom = Math.min(mxBottom, this._mxContainer.clientHeight);
		};
		//修正移動參數
		iLeft = Math.max(Math.min(iLeft, mxRight - this.Drag.offsetWidth), mxLeft);
		iTop = Math.max(Math.min(iTop, mxBottom - this.Drag.offsetHeight), mxTop);
	}
	//設置位置，並修正margin
	if(!this.LockX){ this.Drag.style.left = iLeft - this._marginLeft + "px"; }
	if(!this.LockY){ this.Drag.style.top = iTop - this._marginTop + "px"; }
	//附加程序
	this.onMove();
  },
  //停止拖動
  Stop: function() {
	//移除事件
	removeEventHandler(document, "mousemove", this._fM);
	removeEventHandler(document, "mouseup", this._fS);
	if(isIE){
		removeEventHandler(this._Handle, "losecapture", this._fS);
		this._Handle.releaseCapture();
	}else{
		removeEventHandler(window, "blur", this._fS);
	};
	//附加程序
	this.onStop();
  }
};