/*
 */
(function($, undefined) {
    // prevent duplicate loading
    // this is only a problem because we proxy existing functions
    // and we don't want to double proxy them
    // 如果有值在进行赋值，否则赋值为空，确保不是undefined
    $.ued = $.ued || {};
	
	if (!window.JSON) {
		window.JSON = {};
	}
	(function () {
		"use strict";
		function f(n) {
			// Format integers to have at least two digits.
			return n < 10 ? '0' + n : n;
		}

		if (typeof Date.prototype.toJSON !== 'function') {

			Date.prototype.toJSON = function (key) {

				return isFinite(this.valueOf()) ?
					this.getUTCFullYear()     + '-' +
					f(this.getUTCMonth() + 1) + '-' +
					f(this.getUTCDate())      + 'T' +
					f(this.getUTCHours())     + ':' +
					f(this.getUTCMinutes())   + ':' +
					f(this.getUTCSeconds())   + 'Z' : null;
			};

			String.prototype.toJSON      =
				Number.prototype.toJSON  =
				Boolean.prototype.toJSON = function (key) {
					return this.valueOf();
				};
		}

		var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
			escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
			gap,
			indent,
			meta = {    // table of character substitutions
				'\b': '\\b',
				'\t': '\\t',
				'\n': '\\n',
				'\f': '\\f',
				'\r': '\\r',
				'"' : '\\"',
				'\\': '\\\\'
			},
			rep;


		function quote(string) {

	// If the string contains no control characters, no quote characters, and no
	// backslash characters, then we can safely slap some quotes around it.
	// Otherwise we must also replace the offending characters with safe escape
	// sequences.

			escapable.lastIndex = 0;
			return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
				var c = meta[a];
				return typeof c === 'string' ? c :
					'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
			}) + '"' : '"' + string + '"';
		}


		function str(key, holder) {

	// Produce a string from holder[key].

			var i,          // The loop counter.
				k,          // The member key.
				v,          // The member value.
				length,
				mind = gap,
				partial,
				value = holder[key];

	// If the value has a toJSON method, call it to obtain a replacement value.

			if (value && typeof value === 'object' &&
					typeof value.toJSON === 'function') {
				value = value.toJSON(key);
			}

	// If we were called with a replacer function, then call the replacer to
	// obtain a replacement value.

			if (typeof rep === 'function') {
				value = rep.call(holder, key, value);
			}

	// What happens next depends on the value's type.

			switch (typeof value) {
			case 'string':
				return quote(value);

			case 'number':

	// JSON numbers must be finite. Encode non-finite numbers as null.

				return isFinite(value) ? String(value) : 'null';

			case 'boolean':
			case 'null':

	// If the value is a boolean or null, convert it to a string. Note:
	// typeof null does not produce 'null'. The case is included here in
	// the remote chance that this gets fixed someday.

				return String(value);

	// If the type is 'object', we might be dealing with an object or an array or
	// null.

			case 'object':

	// Due to a specification blunder in ECMAScript, typeof null is 'object',
	// so watch out for that case.

				if (!value) {
					return 'null';
				}

	// Make an array to hold the partial results of stringifying this object value.

				gap += indent;
				partial = [];

	// Is the value an array?

				if (Object.prototype.toString.apply(value) === '[object Array]') {

	// The value is an array. Stringify every element. Use null as a placeholder
	// for non-JSON values.

					length = value.length;
					for (i = 0; i < length; i += 1) {
						partial[i] = str(i, value) || 'null';
					}

	// Join all of the elements together, separated with commas, and wrap them in
	// brackets.

					v = partial.length === 0 ? '[]' : gap ?
						'[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
						'[' + partial.join(',') + ']';
					gap = mind;
					return v;
				}

	// If the replacer is an array, use it to select the members to be stringified.

				if (rep && typeof rep === 'object') {
					length = rep.length;
					for (i = 0; i < length; i += 1) {
						if (typeof rep[i] === 'string') {
							k = rep[i];
							v = str(k, value);
							if (v) {
								partial.push(quote(k) + (gap ? ': ' : ':') + v);
							}
						}
					}
				} else {

	// Otherwise, iterate through all of the keys in the object.

					for (k in value) {
						if (Object.prototype.hasOwnProperty.call(value, k)) {
							v = str(k, value);
							if (v) {
								partial.push(quote(k) + (gap ? ': ' : ':') + v);
							}
						}
					}
				}

	// Join all of the member texts together, separated with commas,
	// and wrap them in braces.

				v = partial.length === 0 ? '{}' : gap ?
					'{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
					'{' + partial.join(',') + '}';
				gap = mind;
				return v;
			}
		}

	// If the JSON object does not yet have a stringify method, give it one.

		if (typeof window.JSON.stringify !== 'function') {
			window.JSON.stringify = function (value, replacer, space) {

	// The stringify method takes a value and an optional replacer, and an optional
	// space parameter, and returns a JSON text. The replacer can be a function
	// that can replace values, or an array of strings that will select the keys.
	// A default replacer method can be provided. Use of the space parameter can
	// produce text that is more easily readable.

				var i;
				gap = '';
				indent = '';

	// If the space parameter is a number, make an indent string containing that
	// many spaces.

				if (typeof space === 'number') {
					for (i = 0; i < space; i += 1) {
						indent += ' ';
					}

	// If the space parameter is a string, it will be used as the indent string.

				} else if (typeof space === 'string') {
					indent = space;
				}

	// If there is a replacer, it must be a function or an array.
	// Otherwise, throw an error.

				rep = replacer;
				if (replacer && typeof replacer !== 'function' &&
						(typeof replacer !== 'object' ||
						typeof replacer.length !== 'number')) {
					throw new Error('JSON.stringify');
				}

	// Make a fake root object containing our value under the key of ''.
	// Return the result of stringifying the value.

				return str('', {'': value});
			};
		}


	// If the JSON object does not yet have a parse method, give it one.

		if (typeof window.JSON.parse !== 'function') {
			window.JSON.parse = function (text, reviver) {

	// The parse method takes a text and an optional reviver function, and returns
	// a JavaScript value if the text is a valid JSON text.

				var j;

				function walk(holder, key) {

	// The walk method is used to recursively walk the resulting structure so
	// that modifications can be made.

					var k, v, value = holder[key];
					if (value && typeof value === 'object') {
						for (k in value) {
							if (Object.prototype.hasOwnProperty.call(value, k)) {
								v = walk(value, k);
								if (v !== undefined) {
									value[k] = v;
								} else {
									delete value[k];
								}
							}
						}
					}
					return reviver.call(holder, key, value);
				}


	// Parsing happens in four stages. In the first stage, we replace certain
	// Unicode characters with escape sequences. JavaScript handles many characters
	// incorrectly, either silently deleting them, or treating them as line endings.

				text = String(text);
				cx.lastIndex = 0;
				if (cx.test(text)) {
					text = text.replace(cx, function (a) {
						return '\\u' +
							('0000' + a.charCodeAt(0).toString(16)).slice(-4);
					});
				}

	// In the second stage, we run the text against regular expressions that look
	// for non-JSON patterns. We are especially concerned with '()' and 'new'
	// because they can cause invocation, and '=' because it can cause mutation.
	// But just to be safe, we want to reject all unexpected forms.

	// We split the second stage into 4 regexp operations in order to work around
	// crippling inefficiencies in IE's and Safari's regexp engines. First we
	// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
	// replace all simple value tokens with ']' characters. Third, we delete all
	// open brackets that follow a colon or comma or that begin the text. Finally,
	// we look to see that the remaining characters are only whitespace or ']' or
	// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

				if (/^[\],:{}\s]*$/
						.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
							.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
							.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

	// In the third stage we use the eval function to compile the text into a
	// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
	// in JavaScript: it can begin a block or an object literal. We wrap the text
	// in parens to eliminate the ambiguity.

					j = eval('(' + text + ')');

	// In the optional fourth stage, we recursively walk the new structure, passing
	// each name/value pair to a reviver function for possible transformation.

					return typeof reviver === 'function' ?
						walk({'': j}, '') : j;
				}

	// If the text is not JSON parseable, then a SyntaxError is thrown.

				throw new SyntaxError('JSON.parse');
			};
		}
	}());
	
    if ($.ued.version) {
        return;
    }

    $.extend($.ued, {
        version : "2.0",
        keyCode : {
            TAB : 9,
            ENTER : 13,
            ESCAPE : 27,
            SPACE : 32,
            LEFT : 37,
            UP : 38,
            RIGHT : 39,
            DOWN : 40
        },
        lang : {
            // 获取属性的国际化字符串，如果组件的options中已经设置这个值就直接使用，否则从$.ued.lang[comp]中获取
            _get : function(options, comp, attr) {
                return options[attr] ? options[attr] : $.ued.lang[comp][attr];
            }
        }
    });
    // plugins
    $.fn.extend({
        propAttr : $.fn.prop || $.fn.attr,
        _oldFocus : $.fn.focus, //为避免与jQuery ui冲突导致死循环，这里不要取名为'_focus'
        //设置元素焦点（delay：延迟时间）
        focus : function(delay, fn) {
            return typeof delay === "number" ? this.each(function() {
                var elem = this;
                setTimeout(function() {
                    $(elem).focus();
                    if (fn) {
                        fn.call(elem);
                    }
                }, delay);
            }) : this._oldFocus.apply(this, arguments);
        },
        //获取设置滚动属性的 父元素
        scrollParent : function() {
            var scrollParent;
            if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
                scrollParent = this.parents().filter(function() {
                    return (/(relative|absolute|fixed)/).test($.curCSS(this, 'position', 1)) && (/(auto|scroll)/).test($.curCSS(this, 'overflow', 1) + $.curCSS(this, 'overflow-y', 1) + $.curCSS(this, 'overflow-x', 1));
                }).eq(0);
            } else {
                scrollParent = this.parents().filter(function() {
                    return (/(auto|scroll)/).test($.curCSS(this, 'overflow', 1) + $.curCSS(this, 'overflow-y', 1) + $.curCSS(this, 'overflow-x', 1));
                }).eq(0);
            }
            return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
        },
        //设置或获取元素的垂直坐标
        zIndex : function(zIndex) {
            if (zIndex !== undefined) {
                return this.css("zIndex", zIndex);
            }
            if (this.length) {
                var elem = $(this[0]), position, value;
                while (elem.length && elem[0] !== document) {
                    // Ignore z-index if position is set to a value where z-index is ignored by the browser
                    // This makes behavior of this function consistent across browsers
                    // WebKit always returns auto if the element is positioned
                    position = elem.css("position");
                    if (position === "absolute" || position === "relative" || position === "fixed") {
                        // IE returns 0 when zIndex is not specified
                        // other browsers return a string
                        // we ignore the case of nested elements with an explicit value of 0
                        // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
                        value = parseInt(elem.css("zIndex"), 10);
                        if (!isNaN(value) && value !== 0) {
                            return value;
                        }
                    }
                    elem = elem.parent();
                }
            }
            return 0;
        },
        //设置元素不支持被选择
        disableSelection : function() {
            return this.bind(($.support.selectstart ? "selectstart" : "mousedown" ) + ".om-disableSelection", function(event) {
                event.preventDefault();
            });
        },
        //设置元素支持被选择
        enableSelection : function() {
            return this.unbind(".om-disableSelection");
        }
    });
    $.fn.extend({
		/**
		  * add by ynshen
		  * 扩展show，支持参数visibility（本质是通过样式控制visibility）
		  */
        _oldShow : $.fn.show,
        show : function(type) {
            if (type != "visibility") {
                return this._oldShow.apply(this, arguments);
            } else {
                return this.css("visibility", "visible");
            }
        },
		/**
		  * add by ynshen
		  * 扩展hide，支持参数visibility（本质是通过样式控制visibility）
		  */
        _oldHide : $.fn.hide,
        hide : function(type) {
            if (type != "visibility") {
                return this._oldHide.apply(this, arguments);
            } else {
                return this.css("visibility", "hidden");
            }
        }
    });
	$.extend({
		/**
		  * add by xzjiang
		  * 判断字符串数（中文占俩位）
		  * @param {Object} message
		  */
		getStrLength : function(message) {
			return message.replace(/([\u4E00-\u9FA5\uf900-\ufa2d])/g, 'aa').length;
		}
	});
	
	/**
	  * add by ynshen
	  * 判断浏览器是否支持console对象
	  * 如果不支持（当为IE并且未打开调试窗口时，初始化console对象，并将console.log方法指向window.alert方法）
	  */
	  window.property = {};
	if(!window.console){
		window.console = {};
		window.console.log = function(data){
			window.alert(data)
		}
		//add by rbai(增加time和timeEnd性能测试函数) 
		if(!window.console.time){
			window.console.time = function(name){
				window.property[name] = new Date().getTime();
			}
			window.console.timeEnd = function(name){
				var tempTime = new Date().getTime()
				window.alert(name+'==='+(tempTime - window.property[name])+'ms');
			}
		}
	}
	
	//增加debug模式
	if(!window.DebugModel){
		window.DebugModel = {},window.deBugObj = {};
		window.DebugModel.start = function(name){
			window.deBugObj[name] = +new Date();
		}
		window.DebugModel.end = function(name){
			var tempTime = +new Date();
			var tempConsole = name+'完成花费了'+(tempTime - window.deBugObj[name])+'ms';
			DebugModel._printLog(tempConsole);
		}
		window.DebugModel._printLog = function(log){
			var $debugConsole = $('.ued-debugConsole',$('body'));
			if(!$debugConsole.size()){//如果存在debug控制台元素
				$('body').append('<div class="ued-debugConsole" style="position:absolute;top:10px;left:10px;background:#F9F9F9;border:1px solid #CCC;padding:5px 10px 20px 10px;z-index:99999;color:#666;box-shadow:1px 1px 1px white inset;text-shadow:1px 1px 1px #FFF;">'+
				'<h6 style="border-bottom:1px dashed #999;margin-bottom:5px;">UED DEBUG 控制台</h6>'+
				'<div class="ued-debugContent uew-scroll-webkit" style="max-height:300px;overflow:auto;"></div>'+
				'<a href="javascript:;" class="ued-debugClose" style="position:absolute;bottom:2px;right:5px;">关闭</a>'+
				'</di>');
				$debugContent = $('.ued-debugContent',$('body'));
				DebugModel._initCloseOrShow();
			}
			$('.ued-debugConsole',$('body')).show();
			$debugContent.append('<p>'+ log +'</p>');
		}
		
		window.DebugModel._initCloseOrShow = function($debugConsole){
			$('.ued-debugClose',$('body')).click(function(e) {
				$debugContent.empty();
                $('.ued-debugConsole',$('body')).hide();
            });
			
		}
	}
	/**
	  * add by ynshen
	  * 对象深度复制方法
	  */
	window.DeepCopy = function(obj){
		var copyObj = new Object();
		for (prop in obj)
		{
			if(obj[prop] != null && obj[prop].constructor == Object){
				copyObj[prop] = window.DeepCopy(obj[prop]);
			}
			else{
				copyObj[prop] = obj[prop]
			}
		}
		return copyObj;
	}
	/**
	  * add by ynshen
	  * 扩展Array对象，增加删除数组中指定元素方法
	  */
	Array.prototype.remove = function(element){
		var indexArr = [];
		var outArr = [];
		//找到出现该元素的index并存入数组indexArr
		for(var i = 0;i < this.length;i++){
			if(this[i] == element){
				indexArr.push(i);
			}
		}
		if(indexArr.length > 0){
			for(var j = 0;j < indexArr.length;j++){
				if(j == 0){//切分头部
					outArr = outArr.concat(this.slice(0,indexArr[j]));
				}else{//切分中段
					outArr = outArr.concat(this.slice(indexArr[j - 1] + 1,indexArr[j]));
				}
			}
			//切分尾端
			outArr = outArr.concat(this.slice(indexArr[j - 1] + 1,this.length));
			return outArr;
		}else{
			throw new Error(element + "can't be found in " + this);
		}
	}
	
    // 扩展innerWidth、innerHeight、outerWidth和outerHeight方法，如果不传参则获取值，如果传参则设置计算后的宽高。
    $.each(["Width", "Height"], function(i, name) {
        var side = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"], type = name.toLowerCase(), orig = {
            innerWidth : $.fn.innerWidth,
            innerHeight : $.fn.innerHeight,
            outerWidth : $.fn.outerWidth,
            outerHeight : $.fn.outerHeight
        };

        function reduce(elem, size, border, margin) {
            $.each(side, function() {
                size -= parseFloat($.curCSS(elem, "padding" + this, true)) || 0;
                if (border) {
                    size -= parseFloat($.curCSS(elem, "border" + this + "Width", true)) || 0;
                }
                if (margin) {
                    size -= parseFloat($.curCSS(elem, "margin" + this, true)) || 0;
                }
            });
            return size;
        }

        $.fn["inner" + name] = function(size) {
            if (size === undefined) {
                // 返回innerWidth/innerHeight
                return orig["inner" + name].call(this);
            }
            return this.each(function() {
                // 设置宽度/高度 = (size - padding)
                $(this).css(type, reduce(this, size) + "px");
            });
        };

        $.fn["outer" + name] = function(size, margin) {
            if ( typeof size !== "number") {
                // 返回outerWidth/outerHeight
                return orig["outer" + name].call(this, size);
            }
            return this.each(function() {
                // 设置宽度/高度 = (size - padding - border - margin)
                $(this).css(type, reduce(this, size, true, margin) + "px");
            });
        };
    });
    // selectors
    function focusable(element, isTabIndexNotNaN) {
        var nodeName = element.nodeName.toLowerCase();
        if ("area" === nodeName) {
            var map = element.parentNode, mapName = map.name, img;
            if (!element.href || !mapName || map.nodeName.toLowerCase() !== "map") {
                return false;
            }
            img = $( "img[usemap=#" + mapName + "]" )[0];
            return !!img && visible(img);
        }
        return (/input|select|textarea|button|object/.test(nodeName) ? !element.disabled : "a" == nodeName ? element.href || isTabIndexNotNaN : isTabIndexNotNaN)
        // the element and all of its ancestors must be visible
        && visible(element);
    }

    function visible(element) {
        return !$(element).parents().andSelf().filter(function() {
            return $.curCSS(this, "visibility") === "hidden" || $.expr.filters.hidden(this);
        }).length;
    }


    $.extend($.expr[":"], {
        data : function(elem, i, match) {
            return !!$.data(elem, match[3]);
        },
        focusable : function(element) {
            return focusable(element, !isNaN($.attr(element, "tabindex")));
        },
        tabbable : function(element) {
            var tabIndex = $.attr(element, "tabindex"), isTabIndexNaN = isNaN(tabIndex);
            return (isTabIndexNaN || tabIndex >= 0 ) && focusable(element, !isTabIndexNaN);
        }
    });
    // support
    $(function() {
        var body = document.body, div = body.appendChild( div = document.createElement("div"));
        $.extend(div.style, {
            minHeight : "100px",
            height : "auto",
            padding : 0,
            borderWidth : 0
        });
        // 判断当前浏览器环境是否支持minHeight属性
        $.support.minHeight = div.offsetHeight === 100;
        $.support.selectstart = "onselectstart" in div;
        // set display to none to avoid a layout bug in IE
        // http://dev.jquery.com/ticket/4014
        body.removeChild(div).style.display = "none";
    });

    // deprecated
    $.extend($.ued, {
        // $.ued.plugin is deprecated.  Use the proxy pattern instead.
        plugin : {
            add : function(module, option, set) {
                var proto = $.ued[module].prototype;
                for (var i in set ) {
                    proto.plugins[i] = proto.plugins[i] || [];
                    proto.plugins[i].push([option, set[i]]);
                }
            },
            call : function(instance, name, args) {
                var set = instance.plugins[name];
                if (!set || !instance.element[0].parentNode) {
                    return;
                }
                for (var i = 0; i < set.length; i++) {
                    if (instance.options[set[ i ][0]]) {
                        set[ i ][1].apply(instance.element, args);
                    }
                }
            }
        }
    });

})(jQuery);

(function($, undefined) {
    // jQuery 1.4+
    if ($.cleanData) {
        var _cleanData = $.cleanData;
        $.cleanData = function(elems) {
            for (var i = 0, elem; ( elem = elems[i]) != null; i++) {
				try {
                	$(elem).triggerHandler("ued-remove");
				} catch( e ) {}
            }
            _cleanData(elems);
        };
    }

    $.uedWidget = function(name, base, prototype) {
        var namespace = name.split( "." )[0], fullName;
        name = name.split( "." )[1];
        fullName = namespace + "-" + name;
        // 例如参数name='ued.tabs'，变成namespace='ued',name='tabs',fullName='ued-tabs'
        // base默认为Widget类，组件默认会继承base类的所有方法
        if (!prototype) {
            prototype = base;
            base = $.UEDWidget;
        }
        // create selector for plugin
        $.expr[ ":" ][fullName] = function(elem) {
            return !!$.data(elem, name);
        };
        // 创建命名空间$.ued.tabs
        $[namespace] = $[namespace] || {};
        // 组件的构造函数
        $[ namespace ][name] = function(options, element) {
            // allow instantiation without initializing for simple inheritance
            if (arguments.length) {
                this._createWidget(options, element);
            }
        };
        // 初始化父类，一般调用了$.Widget
        var basePrototype = new base();
        // we need to make the options hash a property directly on the new instance
        // otherwise we'll modify the options hash on the prototype that we're
        // inheriting from
        //		$.each( basePrototype, function( key, val ) {
        //			if ( $.isPlainObject(val) ) {
        //				basePrototype[ key ] = $.extend( {}, val );
        //			}
        //		});
        basePrototype.options = $.extend(true, {}, basePrototype.options);
        // 给om.tabs继承父类的所有原型方法和参数
        $[ namespace ][name].prototype = $.extend(true, basePrototype, {
            namespace : namespace,
            widgetName : name,
            // 组件的事件名前缀，调用_trigger的时候会默认给trigger的事件加上前缀
            // 例如_trigger('create')实际会触发'tabscreate'事件
            widgetEventPrefix : $[ namespace ][name].prototype.widgetEventPrefix || name,
            widgetBaseClass : fullName
        }, prototype);
        // 把tabs方法挂到jquery对象上，也就是$('#tab1').tabs();
        var temp = $.uedWidget.bridge(name, $[ namespace ][name]);
    };

    $.uedWidget.bridge = function(name, object) {
        $.fn[name] = function(options) {
            // 如果tabs方法第一个参数是string类型，则认为是调用组件的方法，否则调用options方法
            var isMethodCall = typeof options === "string", args = Array.prototype.slice.call(arguments, 1), returnValue = this;
            // allow multiple hashes to be passed on init
            options = !isMethodCall && args.length ? $.extend.apply(null, [true, options].concat(args)) : options;
            // '_'开头的方法被认为是内部方法，不会被执行，如$('#tab1').tabs('_init')
            if (isMethodCall && options.charAt(0) === "_") {
                return returnValue;
            }
            if (isMethodCall) {
                this.each(function() {
                    // 执行组件方法
                    var instance = $.data(this, name);
                    if (options == 'options') {
                        returnValue = instance && instance.options;
                        return false;
                    } else {
                        var methodValue = instance && $.isFunction(instance[options]) ? instance[options].apply(instance, args) : instance;
                        if (methodValue !== instance && methodValue !== undefined) {
                            returnValue = methodValue;
                            return false;
                        }
                    }
                });
            } else {
                // 调用组件的options方法
                this.each(function() {
                    var instance = $.data(this, name);
                    if (instance) {
                        // 设置options后再次调用_init方法，第一次调用是在_createWidget方法里面。这个方法需要开发者去实现。
                        // 主要是当改变组件中某些参数后可能需要对组件进行重画
                        instance._setOptions(options || {});
                        $.extend(instance.options, options);
                        $(instance.beforeInitListeners).each(function() {
                            this.call(instance);
                        });
                        instance._init();
                        $(instance.initListeners).each(function() {
                            this.call(instance);
                        });
                    } else {
                        // 没有实例的话，在这里调用组件类的构造函数，并把构造后的示例保存在dom的data里面。注意这里的this是dom，object是模块类
                        $.data(this, name, new object(options, this));
                    }
                });
            }
            return returnValue;
        };
    };
    $.uedWidget.addCreateListener = function(name, fn) {
        var temp = name.split(".");
        $[ temp[0] ][temp[1]].prototype.createListeners.push(fn);
    };
    $.uedWidget.addInitListener = function(name, fn) {
        var temp = name.split(".");
        $[ temp[0] ][temp[1]].prototype.initListeners.push(fn);
    };
    $.uedWidget.addBeforeInitListener = function(name, fn) {
        var temp = name.split(".");
        $[ temp[0] ][temp[1]].prototype.beforeInitListeners.push(fn);
    };
    $.UEDWidget = function(options, element) {
        this.createListeners = [];
        this.initListeners = [];
        this.beforeInitListeners = [];
        // allow instantiation without initializing for simple inheritance
        if (arguments.length) {
            this._createWidget(options, element);
        }
    };
    /**
     * 格式化简单节点数据
     * add by ynshen
     */
    $.formatData = function(easyData, sourcePid) {
        var index;
        var root;
        //寻找根节点
        for (var i = 0; i < easyData.length; i++) {
            if (easyData[i].pid == sourcePid) {
                index = i;
                root = easyData[i];
                root.level = 0;
                break;
            }
        }
        if (root) {
            handleArray(easyData, root);
            return easyData[index];
        } else {
            return null;
        };
    }
    function handleArray(target_, pNode) {
        for (var i = 0; i < target_.length; i++) {
            if (target_[i].pid == pNode.id) {
                if (!pNode.children) {
                    pNode.children = new Array();
                }
                pNode.children.push(target_[i]);
                target_[i].level = pNode.level + 1;
                handleArray(target_, target_[i]);
            }
        }
    }

    /*=============================================*/
    $.UEDWidget.prototype = {
        widgetName : "widget",
        widgetEventPrefix : "",
        options : {
            disabled : false
        },
        _createWidget : function(options, element) {
            // $.widget.bridge stores the plugin instance, but we do it anyway
            // so that it's stored even before the _create function runs
            $.data(element, this.widgetName, this);
            this.element = $(element);
            this.options = $.extend(true, {}, this.options, this._getCreateOptions(), options);
            var self = this;
            //注意，不要少了前边的 "ued-"，不然会与jquery-ui冲突
            this.element.bind("ued-remove._" + this.widgetName, function() {
                self.destroy();
            });
            // 开发者实现
            this._create();
            $(this.createListeners).each(function() {
                this.call(self);
            });
            // 如果绑定了初始化的回调函数，会在这里触发。注意绑定的事件名是需要加上前缀的，如$('#tab1').bind('tabscreate',function(){});
            this._trigger("create");
            // 开发者实现
            $(this.beforeInitListeners).each(function() {
                this.call(self);
            });
            this._init();
            $(this.initListeners).each(function() {
                this.call(self);
            });
        },
        _getCreateOptions : function() {
            return $.metadata && $.metadata.get( this.element[0] )[this.widgetName];
        },
        _create : function() {
        },
        _init : function() {
        },
        destroy : function() {
            this.element.unbind("." + this.widgetName).removeData(this.widgetName);
            this.widget().unbind("." + this.widgetName);
        },
        widget : function() {
            return this.element;
        },

        option : function(key, value) {
            var options = key;
            if (arguments.length === 0) {
                // don't return a reference to the internal hash
                return $.extend({}, this.options);
            }
            if ( typeof key === "string") {
                if (value === undefined) {
                    return this.options[key];
                    // 获取值
                }
                options = {};
                options[key] = value;
            }
            this._setOptions(options);
            // 设置值
            return this;
        },
        _setOptions : function(options) {
            var self = this;
            $.each(options, function(key, value) {
                self._setOption(key, value);
            });
            return this;
        },
        _setOption : function(key, value) {
            this.options[key] = value;
            return this;
        },

        // $.widget中优化过的trigger方法。type是回调事件的名称，如"onRowClick"，event是触发回调的事件（通常没有这个事件的时候传null）
        // 这个方法只声明了两个参数，如有其他参数可以直接写在event参数后面
        _trigger : function(type, event) {
            // 获取初始化配置config中的回调方法
			/**
			  * add by ynshen
			  * 对于多层级的方法进行调用
			  */
            var callback;
			var callbackArr = type.split(".");
			
			if(callbackArr.length > 1){
				var tempCallback = this.options[callbackArr[0]];
				for(var i = 1 ;i < callbackArr.length;i++){
					tempCallback = tempCallback[callbackArr[i]]	;
				}
				callback = tempCallback;
			}else{
				callback = this.options[type]
			}
			
			
            // 封装js标准event对象为jquery的Event对象
            event = $.Event(event);
            event.type = type;
            // copy original event properties over to the new event
            // this would happen if we could call $.event.fix instead of $.Event
            // but we don't have a way to force an event to be fixed multiple times
            if (event.originalEvent) {
                for (var i = $.event.props.length, prop; i; ) {
                    prop = $.event.props[--i];
                    event[prop] = event.originalEvent[prop];
                }
            }
            // 构造传给回调函数的参数，event放置在最后
            var newArgs = [], argLength = arguments.length;
            for (var i = 2; i < argLength; i++) {
                newArgs[i - 2] = arguments[i];
            }
            if (argLength > 1) {
                newArgs[argLength - 2] = arguments[1];
            }
            return !($.isFunction(callback) && callback.apply(this.element, newArgs) === false || event.isDefaultPrevented() );
        }
    };
})(jQuery);
