﻿// JScript 文件

var YAO = function(){
	var D = window.document, 
	documentElement = D.documentElement,
    defaultView = D.defaultView,
	head = D.getElementsByTagName('head')[0],
	body = D.body,
	OA = '[object Array]', 
	OF = "[object Function]", 
	OP = Object.prototype,
	userAgent = navigator.userAgent,
	specialChar = {
		'\b': '\\b',
		'\t': '\\t',
		'\n': '\\n',
		'\f': '\\f',
		'\r': '\\r',
		 '"': '\\"',
		'\\': '\\\\'
	},
	webkitKeymap = {
		63232: 38, // up
		63233: 40, // down
		63234: 37, // left
		63235: 39, // right
		63276: 33, // page up
		63277: 34, // page down
		25: 9 // SHIFT-TAB (Safari provides a different key code in
	}, 
	patterns = {
		HYPHEN: /(-[a-z])/i,
		ROOT_TAG: /body|html/i,
		CLASS_RE_TOKENS: /([\.\(\)\^\$\*\+\?\|\[\]\{\}])/g
	},
	reCache = {},
	listeners = [],
	lastError = null,
	CUSTOM_ATTRIBUTES = (!documentElement.hasAttribute) ? { // IE < 8
		'for': 'htmlFor',
		'class': 'className'
	} : { // w3c
		'htmlFor': 'for',
		'className': 'class'
	}, 
	nt = 'nodType',
	_CLASS = 'class', 
	CLASS_NAME = 'className', 
	EMPTY = '', 
	SPACE = ' ', 
	C_START = '(?:^|\\s)', 
	C_END = '(?= |$)', 
	_G = 'g';
	
	return {
		version: 'v1.0.1 Beta',
		// 常规验证
		isArray: function(obj){
			return OP.toString.apply(obj) === OA;
		},
		isString: function(s){
			return typeof s === 'string';
		},
		isBoolean: function(b){
			return typeof b === 'boolean';
		},
		isFunction: function(fn){
			return OP.toString.apply(fn) === OF;
		},
		isNull: function(obj){
			return obj === null;
		},
		isNumber: function(num){
			return typeof num === 'number' && isFinite(num);
		},
		isObject: function(str){
			return (str && (typeof str === "object" || this.isFunction(str))) || false;
		},
		isUndefined: function(obj){
			return typeof obj === 'undefined';
		},
		isElement: function(obj){
			return obj && obj.nodeType === 1;
		},
		isHash: function(obj){
			return obj instanceof Hash;
		},
		isJSON: function(str){
			var json = str.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
			return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(json);
		},
		isXMLDoc: function(obj){
			return obj.documentElement && !obj.body || obj.tagName && obj.ownerDocument && !obj.ownerDocument.body;
		},
		hasOwnProperty: function(obj, prper){
			if (OP.hasOwnProperty) {
				return obj.hasOwnProperty(prper);
			}
			return !this.isUndefined(obj[prper]) && obj.constructor.prototype[prper] !== obj[prper];
		},
		// 字符串处理
		trim: function(str){
			try {
				return str.replace(/^\s+/, '').replace(/\s+$/, '');
			}
			catch(e){
				return str;
			}
		},
		stripTags: function(){
			return str.replace(/<\/?[^>]+>/gi, '');
		},
		stripScripts: function(str){
			return str.replace(/<script[^>]*>([\\S\\s]*?)<\/script>/g, '');
		},
		encodeHTML: function(str){
			return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
		},
		decodeHTML: function(str){
			return str.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
		},
		stringBuffer: function(){
			var a = [], i;
			for (i = 0; i < arguments.length; ++i) {
				a.push(arguments[i]);
			}
			return a.join('');
		},
		toCamel: function(property){
			var x = {};
            function G(y, z){
                return z.toUpperCase();
            }
            return x[property] || (x[property] = property.indexOf("-") === -1 ? property : property.replace(/-([a-z])/gi, G));
		},
		formatNumber: function(b, e){
			e = e || '';
			b += '';
			var d = b.split('.');
			var a = d[0];
			var c = d.length > 1 ? '.' + d[1] : '';
			var f = /(\d+)(\d{3})/;
			while (f.test(a)) {
				a = a.replace(f, '$1,$2');
			}
			return e + a + c;
		},
		unformatNumber: function(a){
			return a.replace(/([^0-9\.\-])/g, '') * 1;
		},
		// 对象关键字和方法获取
		keys: function(obj){
			var b = [];
			for (var p in obj) {
				b.push(p);
			}
			return b;
		},
		values: function(obj){
			var a = [];
			for (var p in obj) {
				a.push(obj[p]);
			}
			return a;
		},
		// 继承处理
		extend: function(sub, sup, override){
			if (!sup || !sub) {
				throw new Error('extend failed, please check that all dependencies are included.');
			}
			var F = function(){
			}, p;
			F.prototype = sup.prototype;
			sub.prototype = new F();
			sub.prototype.constructor = sub;
			sub.superclass = sup.prototype;
			if (sup.prototype.constructor === OP.constructor) {
				sup.prototype.constructor = sup;
			}
			if (override) {
				for (p in override) {
					sub.prototype[p] = override[p];
				}
			}
		},
		// 继承父类的指定方法
		augmentProto: function(sub, sup){
			if (!sub || !sup) {
				throw new Error('augment failed, please check that all dependencies are included.');
			}
			var d = sub.prototype, g = sup.prototype, b = arguments, c, h;
			if (b[2]) {
				for (c = 2; c < b.length; c += 1) {
					d[b[c]] = g[b[c]];
				}
			}
			else {
				for (h in g) {
					if (!d[h]) {
						d[h] = g[h];
					}
				}
			}
		},
		// 复制单体父类的全部或者指定方法
		augmentObject: function(e, d){
			if (!d || !e) {
				throw new Error('augment failed, please check that all dependencies are included.');
			}
			var b = arguments, c, f;
			if (b[2]) {
				if (this.isString(b[2])) {
					e[b[2]] = d[b[2]];
				}
				else {
					for (c = 0; c < b[2].length; c += 1) {
						e[b[2][c]] = d[b[2][c]];
					}
				}
			}
			else {
				for (f in d) {
					e[f] = d[f];
				}
			}
			return e;
		},
		clone: function(d, f){
			var e = function(){
			}, b, c = arguments;
			e.prototype = d;
			b = new e;
			if (f) {
				for (p in f) {
					b[p] = f[p];
				}
			}
			return b;
		},
		// Cookie
		cookie: {
			set: function(g, c, f, b){
				var e = new Date(), a = new Date();
				if (f == null || f == 0) {
					f = 1;
				}
				a.setTime(e.getTime() + 3600000 * 24 * f);
				D.cookie = g + '=' + encodeURI(c) + ';expires=' + a.toGMTString() + ';domain=' + b + '; path=/';
			},
			get: function(e){
				var b = D.cookie, d = e + '=', c = b.indexOf('; ' + d), a = D.cookie.indexOf(';', c);
				if (c === -1) {
					c = b.indexOf(d);
					if (c != 0) {
						return null;
					}
				}
				else {
					c += 2;
				}
				if (a === -1) {
					a = b.length;
				}
				return decodeURI(b.substring(c + d.length, a));
			},
			del: function(b, a){
				if (this.get(b)) {
					D.cookie = b + '=' + ((domain) ? '; domain=' + a : '') + '; expires=Thu, 01-Jan-70 00:00:01 GMT';
				}
			}
		},
		// 浏览器检测
		userAgent: function(){
			var C = {
				ie: 0,
				opera: 0,
				gecko: 0,
				webkit: 0,
				mobile: null,
				air: 0,
				caja: 0
			}, B = userAgent, A;
			if ((/KHTML/).test(B)) {
				C.webkit = 1;
			}
			A = B.match(/AppleWebKit\/([^\s]*)/);
			if (A && A[1]) {
				C.webkit = parseFloat(A[1]);
				if (/ Mobile\//.test(B)) {
					C.mobile = 'Apple';
				}
				else {
					A = B.match(/NokiaN[^\/]*/);
					if (A) {
						C.mobile = A[0];
					}
				}
				A = B.match(/AdobeAIR\/([^\s]*)/);
				if (A) {
					C.air = A[0];
				}
			}
			if (!C.webkit) {
				A = B.match(/Opera[\s\/]([^\s]*)/);
				if (A && A[1]) {
					C.opera = parseFloat(A[1]);
					A = B.match(/Opera Mini[^;]*/);
					if (A) {
						C.mobile = A[0];
					}
				}
				else {
					A = B.match(/MSIE\s([^;]*)/);
					if (A && A[1]) {
						C.ie = parseFloat(A[1]);
					}
					else {
						A = B.match(/Gecko\/([^\s]*)/);
						if (A) {
							C.gecko = 1;
							A = B.match(/rv:([^\s\)]*)/);
							if (A && A[1]) {
								C.gecko = parseFloat(A[1]);
							}
						}
					}
				}
			}
			A = B.match(/Caja\/([^\s]*)/);
			if (A && A[1]) {
				C.caja = parseFloat(A[1]);
			}
			return C;
		}(),
		// 事件处理
		addListener: function(el, sType, fn, obj, overrideContext, bCapture){
			var oEl = null, context = null, wrappedFn = null;
			if (YAO.isString(el)) {
				oEl = YAO.getEl(el);
				el = oEl;
			}
			if (!el || !fn || !fn.call) {
				return false;
			}
			context = el;
			if (overrideContext) {
				if (overrideContext === true) {
					context = obj;
				}
				else {
					context = overrideContext;
				}
			}
			wrappedFn = function(e){
				return fn.call(context, YAO.getEvent(e, el), obj);
			};
			try {
				try {
					el.addEventListener(sType, wrappedFn, bCapture);
				} 
				catch (e) {
					try {
						el.attachEvent('on' + sType, wrappedFn);
					} 
					catch (e) {
						el['on' + sType] = wrappedFn;
					}
				}
			} 
			catch (e) {
				lastError = e;
				YAO.removeListener(el, sType, wrappedFn, bCapture);
				return false;
			}
			if ('unload' != sType) {
				// cache the listener so we can try to automatically unload
				listeners[listeners.length] = [el, sType, fn, wrappedFn, bCapture];
			}
			return true;
		},
		on: function(el, sType, fn){
			return YAO.addListener(el, sType, fn, el, true, false);
		},
		removeListener: function(el, sType, fn, bCapture){
			try {
				if (window.removeEventListener) {
					return function(el, sType, fn, bCapture){
						el.removeEventListener(sType, fn, (bCapture));
					};
				}
				else {
					if (window.detachEvent) {
						return function(el, sType, fn){
							el.detachEvent("on" + sType, fn);
						};
					}
					else {
						return function(){
						};
					}
				}
			} 
			catch (e) {
				lastError = e;
				return false;
			}
			
			return true;
		},
		isMouseLeaveOrEnter: function(e, handler){
			if (e.type !== 'mouseout' && e.type !== 'mouseover') {
				return false;
			}
			var reltg = e.relatedTarget ? e.relatedTarget : (e.type === 'mouseout' ? e.toElement : e.fromElement);
			
			while (reltg && reltg !== handler) {
				reltg = reltg.parentNode;
			}
			return (reltg !== handler);
		},
		stopEvent: function(evt){
			this.stopPropagation(evt);
			this.preventDefault(evt);
		},
		stopPropagation: function(evt){
			if (evt.stopPropagation) {
				evt.stopPropagation();
			}
			else {
				evt.cancelBubble = true;
			}
		},
		preventDefault: function(evt){
			if (evt.preventDefault) {
				evt.preventDefault();
			}
			else {
				evt.returnValue = false;
			}
		},
		getEvent: function(e, boundEl){
			var ev = e || window.event;
			
			if (!ev) {
				var c = this.getEvent.caller;
				while (c) {
					ev = c.arguments[0];
					if (ev && Event == ev.constructor) {
						break;
					}
					c = c.caller;
				}
			}
			
			return ev;
		},
		getCharCode: function(ev){
			var code = ev.keyCode || ev.charCode || 0;
			
			// webkit key normalization
			if (this.userAgent.webkit && (code in webkitKeymap)) {
				code = webkitKeymap[code];
			}
			return code;
		},
		_unload: function(e){
			var j, l;
			if (listeners) {
				for (j = listeners.length - 1; j > -1; j--) {
					l = listeners[j];
					if (l) {
						this.removeListener(l[0], l[1], l[3], l[4]);
					}
				}
				l = null;
			}
			
			this.removeListener(window, "unload", YAO._unload);
		},
		purge: function(d){
			var a = d.attributes, i, l, n;
			if (a) {
				l = a.length;
				for (i = 0; i < l; ++i) {
					n = a[i].name;
					if (typeof d[n] === 'function') {
						d[n] = null;
					}
				}
			}
			a = d.childNodes;
			if (a) {
				l = a.length;
				for (i = 0; i < l; i += 1) {
					YAO.purge(d.childNodes[i]);
				}
			}
		},
		// DOM处理
		getEl: function(elem){
			var elemID, E, m, i, k, length, len;
			if (elem) {
				if (elem[nt] || elem.item) {
					return elem;
				}
				if (this.isString(elem)) {
					elemID = elem;
					elem = D.getElementById(elem);
					if (elem && elem.id === elemID) {
						return elem;
					}
					else {
						if (elem && elem.all) {
							elem = null;
							E = D.all[elemID];
							for (i = 0, len = E.length; i < len; i += 1) {
								if (E[i].id === elemID) {
									return E[i];
								}
							}
						}
					}
					return elem;
				}
				else {
					if (elem.DOM_EVENTS) {
						elem = elem.get("element");
					}
					else {
						if (this.isArray(elem)) {
							m = [];
							for (k = 0, length = elem.length; k < length; k += 1) {
								m[m.length] = YAO.getEl(elem[k]);
							}
							return m;
						}
					}
				}
			}
			return null;
		},
		hasClass: function(el, className){
			var ret = false, current;
			
			if (el && className) {
				current = this.getAttribute(el, CLASS_NAME) || EMPTY;
				if (className.exec) {
					ret = className.test(current);
				}
				else {
					ret = className && (SPACE + current + SPACE).indexOf(SPACE + className + SPACE) > -1;
				}
			}
			else {
				throw new Error('hasClass called with invalid arguments');
			}
			
			return ret;
		},
		addClass: function(el, className){
			var ret = false, current;
			
			if (el && className) {
				current = this.getAttribute(el, CLASS_NAME) || EMPTY;
				if (!this.hasClass(el, className)) {
					this.setAttribute(el, CLASS_NAME, this.trim(current + SPACE + className));
					ret = true;
				}
			}
			else {
				throw new Error('addClass called with invalid arguments');
			}
			
			return ret;
		},
		removeClass: function(el, className){
			var ret = false, current, newClass, attr;
			
			if (el && className) {
				current = this.getAttribute(el, CLASS_NAME) || EMPTY;
				this.setAttribute(el, CLASS_NAME, current.replace(this.getClassRegex(className), EMPTY));
				
				newClass = this.getAttribute(el, CLASS_NAME);
				if (current !== newClass) { // else nothing changed
					this.setAttribute(el, CLASS_NAME, this.trim(newClass)); // trim after comparing to current class
					ret = true;
					
					if (this.getAttribute(el, CLASS_NAME) === '') { // remove class attribute if empty
						attr = (el.hasAttribute && el.hasAttribute(_CLASS)) ? _CLASS : CLASS_NAME;
						el.removeAttribute(attr);
					}
				}
			}
			else {
				throw new Error('removeClass called with invalid arguments');
			}
			
			return ret;
		},
		replaceClass: function(el, classObj){
			var className, from, to, ret = false, current;
			
			if (el && classObj) {
				from = classObj.from;
				to = classObj.to;
				
				if (!to) {
					ret = false;
				}
				else {
					if (!from) { // just add if no "from"
						ret = this.addClass(el, classObj.to);
					}
					else {
						if (from !== to) { // else nothing to replace
							// May need to lead with DBLSPACE?
							current = this.getAttribute(el, CLASS_NAME) || EMPTY;
							className = (SPACE + current.replace(this.getClassRegex(from), SPACE + to)).split(this.getClassRegex(to));
							
							// insert to into what would have been the first occurrence slot
							className.splice(1, 0, SPACE + to);
							this.setAttribute(el, CLASS_NAME, this.trim(className.join(EMPTY)));
							ret = true;
						}
					}
				}
			}
			else {
				throw new Error('replaceClass called with invalid arguments');
			}
			
			return ret;
		},
		setAttribute: function(el, attr, val){
			attr = CUSTOM_ATTRIBUTES[attr] || attr;
			el.setAttribute(attr, val);
		},
		getAttribute: function(el, attr){
			attr = CUSTOM_ATTRIBUTES[attr] || attr;
			return el.getAttribute(attr);
		},
		getClassRegex: function(className){
			var re;
			if (className !== undefined) { // allow empty string to pass
				if (className.exec) { // already a RegExp
					re = className;
				}
				else {
					re = reCache[className];
					if (!re) {
						// escape special chars (".", "[", etc.)
						className = className.replace(patterns.CLASS_RE_TOKENS, '\\$1');
						re = reCache[className] = new RegExp(C_START + className + C_END, _G);
					}
				}
			}
			return re;
		},
		getElByClassName: function(className, tag, rootTag){
			var elems = [], i, tempCnt = this.getEl(rootTag).getElementsByTagName(tag), len = tempCnt.length;
			for (i = 0; i < len; ++i) {
				if (this.hasClass(tempCnt[i], className)) {
					elems.push(tempCnt[i]);
				}
			}
			if (elems.length < 1) {
				return false;
			}
			else {
				return elems;
			}
		},
		getStyle: function(el, property){
			if (defaultView && defaultView.getComputedStyle) {
				var value = null;
				if (property === 'float') {
					property = 'cssFloat';
				}
				var computed = defaultView.getComputedStyle(el, '');
				if (computed) {
					value = computed[this.toCamel(property)];
				}
				return el.style[property] || value;
			}
			else {
				if (documentElement.currentStyle && this.userAgent.ie) {
					switch (this.toCamel(property)) {
						case 'opacity':
							var val = 100;
							try {
								val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity;
							} 
							catch (e) {
								try {
									val = el.filters('alpha').opacity;
								} 
								catch (e) {
								}
							}
							return val / 100;
							break;
						case 'float':
							property = 'styleFloat';
						default:
							var value = el.currentStyle ? el.currentStyle[property] : null;
							return (el.style[property] || value);
					}
				}
				else {
					return el.style[property];
				}
			}
		},
		setStyle: function(el, property, val){
			if (this.userAgent.ie) {
				switch (property) {
					case 'opacity':
						if (this.isString(el.style.filter)) {
							el.style.filter = 'alpha(opacity=' + val * 100 + ')';
							if (!el.currentStyle || !el.currentStyle.hasLayout) {
								el.style.zoom = 1;
							}
						}
						break;
					case 'float':
						property = 'styleFloat';
					default:
						el.style[property] = val;
				}
			}
			else {
				if (property === 'float') {
					property = 'cssFloat';
				}
				el.style[property] = val;
			}
		},
		setStyles: function(el, propertys){
			var p;
			for (p in propertys) {
				this.setStyle(el, p, propertys[p]);
			}
			return el;
		},
		getElementsBy: function(method, tag, root){
			tag = tag || "*";
			var m = [];
			if (root) {
				root = this.getEl(root);
				if (!root) {
					return m;
				}
			}
			else {
				root = D;
			}
			var oElem = root.getElementsByTagName(tag);
			if (!oElem.length && (tag === "*" && root.all)) {
				oElem = root.all;
			}
			for (var n = 0, j = oElem.length; n < j; ++n) {
				if (method(oElem[n])) {
					m[m.length] = oElem[n];
				}
			}
			return m;
		},
		getDocumentWidth: function(){
			var k = this.getScrollWidth();
			var j = Math.max(k, this.getViewportWidth());
			return j;
		},
		getDocumentHeight: function(){
			var k = this.getScrollHeight();
			var j = Math.max(k, this.getViewportHeight());
			return j;
		},
		/*
		
		对于document.compatMode，很多朋友可能都根我一样很少接触，知道他的存在却不清楚他的用途。今天在ext中看到 document.compatMode的使用，感觉这个对于我们开发兼容性的web页面还是很有帮助，我们都知道，IE对盒模型的渲染在 Standards Mode和Quirks Mode是有很大差别的，在Standards Mode下对于盒模型的解释和其他的标准浏览器是一样，但在Quirks Mode模式下则有很大差别，而在不声明Doctype的情况下，IE默认又是Quirks Mode。所以为兼容性考虑，我们可能需要获取当前的文档渲染方式。

      document.compatMode正好派上用场，它有两种可能的返回值：BackCompat和CSS1Compat，对其解释如下：

BackCompat Standards-compliant mode is not switched on. (Quirks Mode)

CSS1Compat Standards-compliant mode is switched on. (Standards Mode)

     在实际的项目中，我们还需要在获取浏览是否IE，这样就可以得到IE的渲染模式了。在Ext中的代码：isBorderBox=isIE&&!isStrict。

当文档有了标准声明时， document.compatMode 的值就等于 "CSS1compat"， 因此， 我们可以根据 document.compatMode 的值来判断文档是否加了标准声明

var height = document.compatMode=="CSS1Compat" ? document.documentElement.clientHeight : document.body.clientHeight;


document.compatMode用来判断当前浏览器采用的渲染方式。

官方解释：

BackCompat：标准兼容模式关闭。
CSS1Compat：标准兼容模式开启。

当document.compatMode等于BackCompat时，浏览器客户区宽度是document.body.clientWidth；
当document.compatMode等于CSS1Compat时，浏览器客户区宽度是document.documentElement.clientWidth。

浏览器客户区高度、滚动条高度、滚动条的Left、滚动条的Top等等都是上面的情况。

一个准确获取网页客户区的宽高、滚动条宽高、滚动条Left和Top的代码：

if (document.compatMode == "BackCompat") {
cWidth = document.body.clientWidth;
cHeight = document.body.clientHeight;
sWidth = document.body.scrollWidth;
sHeight = document.body.scrollHeight;
sLeft = document.body.scrollLeft;
sTop = document.body.scrollTop;
}
else { //document.compatMode == "CSS1Compat"
cWidth = document.documentElement.clientWidth;
cHeight = document.documentElement.clientHeight;
sWidth = document.documentElement.scrollWidth;
sHeight = document.documentElement.scrollHeight;
sLeft = document.documentElement.scrollLeft == 0 ? document.body.scrollLeft : document.documentElement.scrollLeft;
sTop = document.documentElement.scrollTop == 0 ? document.body.scrollTop : document.documentElement.scrollTop;
}

（以上代码兼容目前流行的全部浏览器，包括：IE、Firefox、Safari、Opera、Chrome）
		
		*/
		getScrollWidth: function(){
			var j = (D.compatMode === "CSS1Compat") ? D.documentElement.scrollWidth : body.scrollWidth;
			return j;
		},
		getScrollHeight: function(){
			var j = (D.compatMode === "CSS1Compat") ? D.documentElement.scrollHeight: body.scrollHeight ;
			return j;
		},
		getXScroll: function(){
			var j = self.pageXOffset || documentElement.scrollLeft || body.scrollLeft;
			return j;
		},
		getYScroll: function(){
			var j = self.pageYOffset || documentElement.scrollTop || body.scrollTop;
			return j;
		},
		getViewportWidth: function(){
			var j = self.innerWidth, k = D.compatMode;
			if (k || c) {
				j = (k === "CSS1Compat") ? D.documentElement.clientWidth : body.clientWidth;
			}
			return j;
		},
		getViewportHeight: function(){
			var j = self.innerHeight, k = D.compatMode;
			if ((k || c) && !this.userAgent.opera) {
				j = (k === "CSS1Compat") ? documentElement.clientHeight : body.clientHeight;
			}
			return j;
		},
		getPageXY: function(el){
			var x = this.getPageX(el), y = this.getPageY(el);
			return [x, y];
		},
		getPageX: function(el){
			var box = null, parentNode = null, left = 0;
			if (el.getBoundingClientRect) {
				box = el.getBoundingClientRect();
				left = box.left + Math.max(D.documentElement.scrollLeft, D.body.scrollLeft);
			}
			else {
				left = el.offsetLeft;
				parentNode = el.offsetParent;
				if (parentNode != el) {
					while (parentNode) {
						left += parentNode.offsetLeft;
						parentNode = parentNode.offsetParent;
					}
				}
			}
			return left;
		},
		getPageY: function(el){
			var box = null, parentNode = null, top = 0;
			if (el.getBoundingClientRect) {
				box = el.getBoundingClientRect();
				top = box.top + Math.max(D.documentElement.scrollTop, D.body.scrollTop);
			}
			else {
				top = el.offsetTop;
				parentNode = el.offsetParent;
				if (parentNode != el) {
					while (parentNode) {
						top += parentNode.offsetTop;
						parentNode = parentNode.offsetParent;
					}
				}
			}
			return top;
		},
		removeChildren: function(j){
			var parent = null;
			if (!(parent = this.getEl(j))) {
				return false;
			}
			while (j.firstChild) {
				j.firstChild.parentNode.removeChild(j.firstChild);
			}
			return j;
		},
		prependChild: function(k, j){
			if (!(k = this.getEl(k)) || !(j = this.getEl(j))) {
				return false;
			}
			if (k.firstChild) {
				k.insertBefore(j, k.firstChild);
			}
			else {
				k.appendChild(j);
			}
			return k;
		},
		insertBefore: function(Y, G){
			Y = this.getEl(Y);
			G = this.getEl(G);
			if (!Y || !G || !G.parentNode) {
				return null;
			}
			return G.parentNode.insertBefore(Y, G);
		},
		insertAfter: function(l, j){
			var k = j.parentNode;
			if (k.lastChild === j) {
				k.appendChild(l);
			}
			else {
				k.insertBefore(l, j.nextSibling);
			}
		},
		setOpacity: function(el, val){
			this.setStyle(el, 'opacity', val);
		},
		// 创建DOM
		Builder: function(){
			var nidx = 0,
			NODEMAP = {
				AREA: 'map',
				CAPTION: 'table',
				COL: 'table',
				COLGROUP: 'table',
				LEGEND: 'fieldset',
				OPTGROUP: 'select',
				OPTION: 'select',
				PARAM: 'object',
				TBODY: 'table',
				TD: 'table',
				TFOOT: 'table',
				TH: 'table',
				THEAD: 'table',
				TR: 'table'
			},
			ATTR_MAP = {
				'className': 'class',
				'htmlFor': 'for',
				'readOnly': 'readonly',
				'maxLength': 'maxlength',
				'cellSpacing': 'cellspacing'
			},
			EMPTY_TAG = /^(?:BR|FRAME|HR|IMG|INPUT|LINK|META|RANGE|SPACER|WBR|AREA|PARAM|COL)$/i;
			
			return {
				// 追加Link节点（添加CSS样式表）
				css: function(url, cssId, charset){
					var c = charset || 'utf-8', link = null;
					link = this.node('link', {
						'id': cssId || ('link-' + (nidx++)),
						'type': 'text/css',
						'charset': c,
						'rel': 'stylesheet',
						'href': url
					});
					head.appendChild(link);
					return link;
				},
				// 追加Script节点
				script: function(url, scriptId, charset){
					var c = charset || 'utf-8';
					return body.appendChild(this.node('script', {
						'id': scriptId || ('script-' + (nidx++)),
						'type': 'text/javascript',
						'charset': c,
						'src': url
					}));
				},
				// 创建元素节点
				node: function(tag, attr, children){
					tag = tag.toUpperCase();
					// try innerHTML approach
					var parentTag = NODEMAP[tag] || 'div', parentElement = D.createElement(parentTag), elem = null;
					try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
						if (EMPTY_TAG.test(tag)) {
						//alert(tag);
						}
						else {
							parentElement.innerHTML = "<" + tag + "></" + tag + ">";
						}
					} 
					catch (e) {
					}
					elem = parentElement.firstChild;
					
					// see if browser added wrapping tags
					if (elem && (elem.tagName.toUpperCase() != tag)) {
						elem = elem.getElementsByTagName(tag)[0];
					}
					// fallback to createElement approach
					if (!elem) {
						if (YAO.isString(tag)) {
							elem = D.createElement(tag);
						}
					}
					// abort if nothing could be created
					if (!elem) {
						return;
					}
					else {
						if (attr) {
							this.attributes(elem, attr);
						}
						if (children) {
							this.child(elem, children);
						}
						return elem;
					}
				},
				text: function(str){
					return D.createTextNode(str);
				},
				// 追加子节点
				child: function(parent, child){
					if (child.tagName) {
						parent.appendChild(child);
						return false;
					}
					if (YAO.isArray(child)) {
						var i, length = child.length;
						for (i = 0; i < length; i += 1) {
							if (child[i].tagName) {
								parent.appendChild(child[i]);
							}
							else {
								if (YAO.isString(child[i])) {
									parent.appendChild(this.text(child[i]));
								}
							}
						}
					}
					else {
						if (YAO.isString(child)) {
							parent.appendChild(this.text(child));
						}
					}
				},
				// 给节点添加属性
				attributes: function(elem, attr){
					var attrName = '', i;
					for (i in attr) {
						if (attr[i] && YAO.hasOwnProperty(attr, i)) {
							attrName = i in ATTR_MAP ? ATTR_MAP[i] : i;
							if (attrName === 'class') {
								elem.className = attr[i];
							}
							else {
								elem.setAttribute(attrName, attr[i]);
							}
						}
					}
					return elem;
				}
			}
		}(),
		// 加载JS，并且在加载完成后执行回调函数
		loadScript: function(url, callback){
			var script = this.Builder.script(url);
			if (script.readyState) { //IE
				script.onreadystatechange = function(){
					if (script.readyState === "loaded" || script.readyState === "complete") {
						script.onreadystatechange = null;
						callback();
					}
				};
			}
			else { //Others
				script.onload = function(){
					callback();
				};
			}
		},
		// 是否为Y节点的后代节点
		isAncestor: function(Y, x){
			var G = false;
			Y = this.getEl(Y);
			x = this.getEl(x);
			if ((Y && x) && (Y[nt] && x[nt])) {
				if (Y.contains && Y !== x) {
					G = Y.contains(x);
				}
				else {
					if (Y.compareDocumentPosition) {
						G = !!(Y.compareDocumentPosition(x) & 16);
					}
				}
			}
			else {
				return false;
			}
			return G;
		},
		// 批处理函数
		batch: function(el, method, o, override){
			var id = el, that = this;
			el = that.getEl(el);
			var scope = (override) ? o : window;
			if (!el || el.tagName || !el.length) {
				if (!el) {
					return false;
				}
				return method.call(scope, el, o);
			}
			var collection = [];
			for (var i = 0, len = el.length; i < len; ++i) {
				if (!el[i]) {
					id = el[i];
				}
				collection[collection.length] = method.call(scope, el[i], o);
			}
			return collection;
		},
		// DOM透明过度
		fadeUp: function(elem){
			if (elem) {
				var level = 0, that = this, fade = function(){
					var timer = null;
					level += 0.05;
					if (timer) {
						clearTimeout(timer);
						timer = null;
					}
					if (level > 1) {
						that.setOpacity(elem, 1);
						return false;
					}
					else {
						that.setOpacity(elem, level);
					}
					timer = setTimeout(fade, 50);
				};
				fade();
			}
		},
		// 隔行换色和鼠标划过换色
		zebra: function(){
			var j, length = arguments.length, that = this;
			for (j = 0; j < length; ++j) {
				(function(config){
					var root = that.getEl(config.rootTag) || (config.root || null), rows = root.getElementsByTagName(config.rowTag) || (config.rows || null), i, len = rows.length, lastClass = [];
					if (root && rows && len > 1) {
						for (var i = 0; i < len; ++i) {
							rows[i].className = i % 2 === 0 ? 'even' : 'odd';
							lastClass[i] = rows[i].className;
							that.on(rows[i], 'mouseover', function(index){
								return function(){
									that.replaceClass(this, lastClass[index], 'hover');
								}
							}(i), rows[i], true);
							that.on(rows[i], 'mouseout', function(index){
								return function(){
									that.replaceClass(this, 'hover', lastClass[index]);
								}
							}(i), rows[i], true);
						}
					}
					else {
						return false;
					}
				})(arguments[j]);
			}
		},
		// DOM加速度平滑滚动
		moveElement: function(element, finalX, finalY, speed, callback){
			var elem = this.isString(element) ? this.getEl(element) : element, style = null, xpos = 0, ypos = 0, dist = 0, that = this;
			if (elem) {
				if (elem.movement) {
					clearTimeout(elem.movement);
				}
				if (!this.getStyle(elem, 'left')) {
					this.setStyle(elem, 'left', 0);
				}
				if (!this.getStyle(elem, 'top')) {
					this.setStyle(elem, 'top', 0);
				}
				xpos = parseInt(this.getStyle(elem, 'left'), 10);
				ypos = parseInt(this.getStyle(elem, 'top'), 10);
				if (xpos === finalX && ypos === finalY) {
					if (callback) {
						callback();
					}
					else {
						return true;
					}
				}
				if (xpos < finalX) {
					dist = Math.ceil((finalX - xpos) / 10);
					xpos += dist;
				}
				else {
					if (xpos > finalX) {
						dist = Math.ceil((xpos - finalX) / 10);
						xpos -= dist;
					}
				}
				if (ypos < finalY) {
					dist = Math.ceil((finalY - ypos) / 10);
					ypos += dist;
				}
				else {
					if (ypos > finalY) {
						dist = Math.ceil((ypos - finalY) / 10);
						ypos -= dist;
					}
				}
				this.setStyle(elem, 'left', (xpos + 'px'));
				this.setStyle(elem, 'top', (ypos + 'px'));
				elem.movement = setTimeout(function(){
					that.moveElement(element, finalX, finalY, speed, callback);
				}, speed);
			}
		},
		fixPosition: function(elem, pos, elemWidth, elemHeight, isScroll){
			var IE6 = this.userAgent.ie === 6 ? true : false, left = 0, top = 0, position = pos.toUpperCase(), documentWidth = this.getDocumentWidth(), documentHeight = this.getDocumentHeight(), viewportWidth = this.getViewportWidth(), viewportHeight = this.getViewportHeight(), xScroll = this.getXScroll(), yScroll = this.getYScroll();
			
			if (position === 'RIGHT') {
				left = xScroll + (viewportWidth - elemWidth);
				if (IE6) {
					top = yScroll + (viewportHeight - elemHeight);
				}
				else {
					top = viewportHeight - elemHeight;
				}
				if (elemWidth > viewportWidth) {
					left = 0;
					top = 0;
				}
			}
			else {
				if (position === 'LEFT') {
					left = 0;
					if (IE6) {
						top = yScroll + (viewportHeight - elemHeight);
					}
					else {
						top = viewportHeight - elemHeight;
					}
					if (elemHeight > viewportHeight) {
						top = 0;
					}
				}
				else {
					if (position === 'CENTER') {
						left = xScroll + ((viewportWidth - elemWidth) / 2);
						if (IE6) {
							top = yScroll + ((viewportHeight - elemHeight) / 2);
						}
						else {
							top = (viewportHeight - elemHeight) / 2;
						}
						if (elemWidth > viewportWidth) {
							if ((elemWidth < documentWidth) && ((elemWidth + xScroll) < documentWidth)) {
								left = xScroll;
								top = yScroll;
							}
							else {
								left = documentWidth - elemWidth;
								top = documentHeight - elemHeight;
							}
						}
						else {
							if (elemWidth > documentWidth) {
								left = 0;
								top = 0;
							}
						}
					}
				}
			}
			
			if (isScroll && position !== 'CENTER') {
				this.setStyles(elem, {
					margin: '0',
					left: left + 'px',
					top: (top + elemHeight) + 'px'
				});
			}
			else {
				this.setStyles(elem, {
					margin: '0',
					left: left + 'px',
					top: top + 'px'
				});
			}
			
			if (!IE6) {
				this.setStyle(elem, 'position', 'fixed');
			}
		},
		// ajax请求
		ajaxRequest: function(config){
			var oXhr, method = config.method ? config.method.toUpperCase() : 'GET', url = config.url || '', fn = config.fn || null, postData = config.data || null, elem = config.id ? YAO.getEl(config.id) : (config.element || null), load = config.loadFn ? config.loadFn : (config.loading || '正在获取数据，请稍后...'), that = this;
			if (!url) {
				return;
			}
			if (window.XMLHttpRequest) {
				oXhr = new XMLHttpRequest();
			}
			else {
				if (window.ActiveXObject) {
					oXhr = new ActiveXObject("Microsoft.XMLHTTP");
				}
			}
			if (oXhr) {
				try {
					oXhr.open(method, url, true);
					oXhr.onreadystatechange = function(){
						if (oXhr.readyState !== 4) {
							return false
						}
						if (oXhr.readyState === 4) {
							if (oXhr.status === 200 || location.href.indexOf('http') === -1) {
								if (fn) {
									fn.success(oXhr);
								}
								else {
									elem.innerHTML = oXhr.responseText;
								}
							}
							else {
								if (fn) {
									fn.failure(oXhr.status);
								}
								else {
									if (that.isFunction(load)) {
										load();
									}
									else {
										elem.innerHTML = load;
									}
								}
							}
						}
					};
					oXhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
					if (postData) {
						oXhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
					}
					oXhr.send(postData);
				} 
				catch (e) {
					throw new Error(e);
					return false;
				}
			}
			else {
				throw new Error("Your browser does not support XMLHTTP.");
				return false;
			}
		},
		/*
		 * http://www.JSON.org/json2.js
         * 2009-09-29
         * Douglas Corckford
		 */
		JSON: function(){
			function f(n){
				return n < 10 ? '0' + n : n;
			}
			
			Date.prototype.toJSON = function(){
				return this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z';
			};
			
			function stringify(value, whitelist){
				var a, i, k, l, r = /["\\\x00-\x1f\x7f-\x9f]/g, v, that = this;
				switch (typeof value) {
					case 'string':
						return r.test(value) ? '"' +
						value.replace(r, function(a){
							var c = specialChar[a];
							if (c) {
								return c;
							}
							c = a.charCodeAt();
							return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
						}) +
						'"' : '"' + value + '"';
					case 'number':
						return isFinite(value) ? String(value) : 'null';
					case 'boolean':
					case 'null':
						return String(value);
					case 'object':
						if (!value) {
							return 'null';
						}
						
						if (that.isFunction(value.toJSON)) {
							return stringify(value.toJSON());
						}
						a = [];
						if (that.isNumber(value.length) && !(value.propertyIsEnumerable('length'))) {
						
							l = value.length;
							for (i = 0; i < l; i += 1) {
								a.push(stringify(value[i], whitelist) || 'null');
							}
							
							return '[' + a.join(',') + ']';
						}
						if (whitelist) {
							l = whitelist.length;
							for (i = 0; i < l; i += 1) {
								k = whitelist[i];
								if (that.isString(k)) {
									v = stringify(value[k], whitelist);
									if (v) {
										a.push(stringify(k) + ':' + v);
									}
								}
							}
						}
						else {
							for (k in value) {
								if (that.isString(k)) {
									v = stringify(value[k], whitelist);
									if (v) {
										a.push(stringify(k) + ':' + v);
									}
								}
							}
						}
						return '{' + a.join(',') + '}';
				}
			}
			
			return {
				stringify: stringify,
				parse: function(text, filter){
					var j;
					
					function walk(k, v){
						var i, n;
						if (v && that.isObject(v)) {
							for (i in v) {
								if (OP.hasOwnProperty.apply(v, [i])) {
									n = walk(i, v[i]);
									if (n !== undefined) {
										v[i] = n;
									}
									else {
										delete v[i];
									}
								}
							}
						}
						return filter(k, v);
					}
					
					if (/^[\],:{}\s]*$/.test(text.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
						j = eval('(' + text + ')');
						
						return that.isFunction(filter) ? walk('', j) : j;
					}
					
					throw new SyntaxError('parseJSON');
				}
			};
		}()
	};
	
	YAO.on(window, "unload", YAO._unload);
}();



