Source: hui/hui_control.js

'::hui_control::';
'use strict';
//   __    __           ______   ______  _____    __  __     
//  /\ \  /\ \ /'\_/`\ /\  _  \ /\__  _\/\  __`\ /\ \/\ \    
//  \ `\`\\/'//\      \\ \ \/\ \\/_/\ \/\ \ \/\ \\ \ \ \ \   
//   `\ `\ /' \ \ \__\ \\ \  __ \  \ \ \ \ \ \ \ \\ \ \ \ \  
//     `\ \ \  \ \ \_/\ \\ \ \/\ \  \ \ \ \ \ \_\ \\ \ \_\ \ 
//       \ \_\  \ \_\\ \_\\ \_\ \_\  \ \_\ \ \_____\\ \_____\
//        \/_/   \/_/ \/_/ \/_/\/_/   \/_/  \/_____/ \/_____/
//                                                                   

/**
 * @namespace hui.Control
 * @description 基础控件类
 * @public
 * @author haiyang5210
 * @since 2015-06-25 10:48
 */
hui.define('hui_control', ['hui_eventdispatcher'], function () {

    /**  
     * @class hui.Flow
     * @description Javascript简单异步框架。注:异步队列中的函数需要实现callback的接口
     */
    hui.Flow = function () {
        var me = this;
        /**
         * @property {Array} que 保存回调队列
         * @memerberof hui.Flow
         */
        me.que = [hui.fn(me.endFlow, me)]; // 注:存放要调用的函数列表
        me.id = hui.Flow.getIndex(); // 注:仅用于标示,不会被调用(即使删掉也没什么影响)
        me.parentflow = [];
        /**  
         * @method hui.Flow.next
         * @description 开始执行异步队列
         * @public
         * @memerberof hui.Flow
         * @param {Function} callback 嵌套时的回调函数,其实就是hui.Flow.prototype.next
         */
        me.next = function (callback) {
            var args = [].slice.call(arguments, 0);

            // console.log(me.id);
            if (me.que.length > 0) {
                var fn = me.que.shift();
                fn.apply(null, args);
            }
        };
        me.next._isFlowPrivate = hui.Flow.getIdentity();
        me.next.mainFlow = me;

    };
    hui.Flow.getIdentity = (function () {
        var guid = new Date().toString() + Math.random();
        return function (formname) {
            return guid;
        };
    })();
    hui.Flow.getIndex = (function () {
        var guid = 1;
        return function (formname) {
            return guid++;
        };
    })();
    /**  
     * @method hui.Flow.push
     * @description 添加需要异步执行的函数
     * @public
     * @memerberof hui.Flow
     * @param {Function} fn 需要异步执行的函数
     * @return {this} 返回主体以便于后续操作
     * @example
     * function doit() {
     *     alert('a');
     *     
     *     var que1 = new hui.Flow();
     *     que1.push(a);
     *     que1.push(d); 
     *     setTimeout(function(){
     *         que1.next();
     *     },400);
     * }
     *  
     * function a(callback) {
     *     alert('a');
     *     
     *     var que2 = new hui.Flow();
     *     que2.push(b).push(c).push(callback); 
     *     
     *     setTimeout(function(){
     *         que2.next();
     *     },400);
     * }
     * function b(callback) {
     *     alert('b');
     *     callback&&callback();
     * }
     * function c(callback) {
     *     alert('c');
     *     callback&&callback();
     * }
     */
    hui.Flow.prototype.push = function (fn) {
        var me = this;

        if (fn && fn._isFlowPrivate === hui.Flow.getIdentity()) {
            var endFlow = me.que.pop();
            me.que.push(fn);
            me.que.push(endFlow);
            if (fn.mainFlow) {
                fn.mainFlow.parentflow.push(me);
            }
        }
        else {
            var callback = hui.fn(me.next, me);
            callback._isFlowPrivate = hui.Flow.getIdentity();

            var endFlow = me.que.pop();
            me.que.push(function () {
                fn.apply(me, [callback].concat([].slice.call(arguments, 0)));
            });
            me.que.push(endFlow);
        }

        return me;
    };
    hui.Flow.prototype.endFlow = function () {
        var me = this;
        if (me.parentflow) {
            while (me.parentflow.length) {
                me.parentflow.pop().next();
            }
        }
    };

    /**  
     * @class hui.Control
     * @description 基础控件类
     * @param {Object} options 传入的初始化参数  
     * @param {String} pending 子类调用此构造函数时需传入'pending'
     */
    hui.Control = function (options, pending) {
        hui.EventDispatcher.call(this);

        // 状态列表
        options = options || {};
        // 初始化参数
        this.initOptions(options);
        // 生成控件id
        if (!this.id) {
            this.id = hui.Control.makeGUID(this.formname);
        }

        hui.Control.appendControl(options.parentControl, this);

        // 子类调用此构造函数不可以立即执行!!只能放在子类的构造函数中执行!否则实例化时找不到子类中定义的属性!
        // 进入控件处理主流程!
        if (pending != 'pending') {
            this.enterControl();
        }
    };

    /**  
     * @property {Object} hui.Control.prototype 基础控件类原型 
     */
    hui.Control.prototype = {
        /**
         * @method initOptions
         * @description 初始化参数
         * @protected
         * @memerberof hui.Control.prototype
         * @param {Object} options 参数集合
         */
        initOptions: function (options) {
            for (var k in options) {
                if (options.hasOwnProperty(k)) {
                    this[k] = options[k];
                }
            }
        },
        // 注: childControl不能放在这里,放在这里会导致"原型继承属性只是用一个副本的坑"!!
        // cc: [],
        /**
         * @method getClass
         * @description 获取dom子部件的css class
         * @memerberof hui.Control.prototype
         * @protected
         * @return {String}
         */
        getClass: function (opt_key) {
            if (!this.type) {
                return '';
            }

            var me = this,
                type = String(me.type).toLowerCase(),
                className = 'hui_' + type,
                skinName = 'skin_' + type + '_' + me.skin;

            if (opt_key) {
                className += '_' + opt_key;
                skinName += '_' + opt_key;
            }

            if (me.skin) {
                className = skinName + ' ' + className;
            }

            return className;
        },

        /**
         * @method getId
         * @description 获取dom子部件的id
         * @memerberof hui.Control.prototype
         * @public
         * @return {String}
         */
        getId: function (key) {
            var me = this,
                // uiAttr = hui.Control.UI_ATTRIBUTE || 'ui';
                // idPrefix = 'ctrl' + this.type + this.id;
                idPrefix = me.id === undefined ? '' : me.id;

            if (key) {
                idPrefix = idPrefix + key;
            }
            return idPrefix;
        },
        /**
         * @method getMain
         * @description 获取控件的elem(nodejs). 注:控件即使不需要显示任何内容也必须有一个挂载的elem(可以是隐藏的),
         * @memerberof hui.Control.prototype
         * 通过模板解析控件时会用到 [nodejs&browser]
         * @public
         * @return {String}
         */
        getMain: function () {
            var me = this,
                elem;
            elem = me.main ? document.getElementById(me.main) : null;
            return elem;
        },
        mainFocus: function () {
            // Fix IE8 bug: hidden elem focus() cause error
            var main = this.getMain();
            try {
                main.focus();
            }
            catch (e) {}
        },
        /**
         * @method getInnerHTML
         * @description 获取控件的innerHTML
         * @memerberof hui.Control.prototype
         * @public
         * @param {HTMLElement} elem 默认为控件主DOM[可选]
         * @return {String}
         */
        getInnerHTML: function (elem) {
            var me = this,
                elem = elem || me.getMain(),
                html = '';
            if (elem.getInnerHTML) {
                html = elem.getInnerHTML();
            }
            else if (elem.innerHTML !== undefined) {
                html = elem.innerHTML;
            }
            return html;
        },
        /**
         * @method setInnerHTML
         * @description 设定控件的innerHTML[nodejs&browser]
         * @memerberof hui.Control.prototype
         * @public
         * @param {String} html innerHTML
         * @param {HTMLElement} elem 默认为控件主DOM[可选]
         * @return {String}
         */
        setInnerHTML: function (elem, html) {
            if (!html && typeof elem === 'string' && this.getMain) {
                html = elem;
                elem = this.getMain();
            }
            return hui.Control.setInnerHTML(elem, html);
        },
        /**
         * @method render
         * @description 渲染控件
         * @memerberof hui.Control.prototype
         * @public
         */
        render: function () {
            // var me = this;
            // var main = me.getMain();
            // var data = me.model && me.model.getData && typeof me.model.getData === 'function' ? me.model.getData() : {};
            // hui.Control.init(main, data, me);
            // main.setAttribute('_rendered', 'true');
        },
        // 
        /**
         * @description 生成HTML
         * @memerberof hui.Control.prototype
         * @public
         */
        // initView: function (callback) {
        //     callback && callback();
        // },
        /**
         * @method initBehavior
         * @description 绑定事件
         * @memerberof hui.Control.prototype
         * @public
         */
        initBehavior: function () {
            //var me = this;
        },
        initBehaviorByTree: function () {
            var me = this,
                main = me.getMain();
            if (me.cc) {
                for (var i = 0, len = me.cc.length; i < len; i++) {
                    me.cc[i].initBehaviorByTree();
                }
            }
            if (main && main.getAttribute('_initbehavior') != 'true') {
                main.setAttribute('_initbehavior', 'true');
                me.initBehavior();
            }
        },
        /**
         * @method validate
         * @description 验证控件的值
         * @memerberof hui.Control.prototype
         * @public
         */
        validate: function (show_error) {
            var me = this,
                result = true,
                cc = me.cc,
                Validator = hui.Control.getExtClass('hui.Validator'),
                c,
                list,
                m,
                n;

            if (me.rule && !me.isDisabled()) {
                result = false;
                list = String(me.rule).split('||');
                for (var i = 0, len = list.length; i < len && !result; i++) {
                    c = true;
                    m = list[i].split('&&');
                    for (var j = 0, len2 = m.length; j < len2; j++) {
                        n = m[j];
                        c = c && Validator.applyRule(me, n, show_error);
                    }
                    result = result || c;
                }
            }
            // result ===  null
            if (!me.rule && cc && !me.isDisabled()) {
                result = true;
                m = null;
                for (var i = 0, len = cc.length; i < len; i++) {
                    n = cc[i].validate(show_error);
                    result = n && result;
                    m = m === null && !n ? cc[i] : m;
                }
                //m && m.getInput && m.getInput() && m.getInput().focus();
            }

            return result;
        },
        hideError: function () {
            var me = this,
                Validator = hui.Control.getExtClass('hui.Validator');
            Validator.cancelNotice(me.getMain());
            if (me.cc) {
                for (var i = 0, len = me.cc.length; i < len; i++) {
                    me.cc[i].hideError();
                }
            }
            return me;
        },
        showError: function (errorMsg, code) {
            var me = this,
                Validator = hui.Control.getExtClass('hui.Validator'),
                rule = Validator.getRule(me.rule);
            if (rule && code === 'by_code') {
                errorMsg = rule.noticeText[errorMsg];
            }

            Validator.showError(me.getMain(), errorMsg);
            return me;
        },
        showErrorByTree: function (paramMap, code) {
            var me = this,
                value,
                list,
                ctr;
            if (me.cc && paramMap) {
                for (var formname in paramMap) {
                    if (formname && paramMap.hasOwnProperty(formname)) {
                        value = Object.prototype.toString.call(paramMap[formname]) !== '[object Array]' ? [paramMap[formname]] : paramMap[formname];
                        list = me.getByFormnameAll(formname, false);
                        if (list.length < 1) {
                            continue;
                        }
                        for (var i = 0, len = value.length; i < len; i++) {
                            ctr = list[i];
                            if (ctr) {
                                if (Object.prototype.toString.call(value[i]) === '[object Object]' &&
                                    ctr.cc) {
                                    ctr.showErrorByTree(value[i], code);
                                }
                                else if (ctr.showError) {
                                    ctr.showError(value[i], code);
                                }
                                ctr = null;
                            }
                        }
                    }
                }
            }
            return me;
        },
        showOK: function () {
            var me = this,
                Validator = hui.Control.getExtClass('hui.Validator');
            Validator.showOK(me);
            return me;
        },
        showWaiting: function () {
            var me = this,
                Validator = hui.Control.getExtClass('hui.Validator');
            Validator.showWaiting(me);
            return me;
        },
        // 返回控件的值
        //getValue:   new Function(), // 注: 控件直接返回值(对象/数组/字符串)时才能使用getValue! 获取所有子控件的值,应该用getParamMap
        setValue: function (paramMap) {
            var me = this;
            if (me.cc && (/\[object Object\]/.test(Object.prototype.toString.call(paramMap)))) {
                me.setValueByTree(this.value);
            }
            else {
                // 注:在setValue/getValue时不允许使用me.getMain().setAttirbute('value', value)和me.getMain()
                // .getAttirbute('value'),因为value有可能是数组/对象!!
                // 如果确定value是num或str可以在子类中覆盖setValue/getValue!!
                me.getMain().value = paramMap;
            }
            return me;
        },
        /**
         * @method setValueByTree
         * @description 给控件树一次性赋值
         * @memerberof hui.Control.prototype
         * @param {Object} paramMap 值
         */
        setValueByTree: function (paramMap) {
            var me = this,
                value,
                list,
                ctr,
                main;
            if (me.cc && paramMap) {
                for (var formname in paramMap) {
                    if (formname && paramMap.hasOwnProperty(formname)) {
                        value = Object.prototype.toString.call(paramMap[formname]) !== '[object Array]' ? [paramMap[formname]] : paramMap[formname];
                        list = me.getByFormnameAll(formname, false);
                        if (list.length < 1) {
                            continue;
                        }
                        for (var i = 0, len = list.length; i < len; i++) {
                            ctr = list[i];

                            if (ctr.constructor &&
                                ctr.setValue &&
                                ctr.getPresetValue) {
                                var presetValue = ctr.getPresetValue();
                                for (var j = 0, len2 = value.length; j < len2; j++) {
                                    if (value[j] && presetValue === String(value[j])) {
                                        ctr.setValue(value[j]);
                                        break;
                                    }
                                }
                            }
                            else if (ctr.constructor &&
                                ctr.setValue &&
                                ctr.setValue !== hui.Control.prototype.setValue) {
                                ctr.setValue(value[i]);
                            }
                            else if (ctr.cc) {
                                ctr.setValueByTree(value[i]);
                            }
                            else if (ctr.getMain || ctr.main) {
                                main = (ctr.getMain ? ctr.getMain() : document.getElementById(ctr.main)) || {};
                                main.value = value[i];
                            }

                            ctr = null;
                        }
                    }
                }
            }

            return me;
        },
        getValue: function () {
            var me = this,
                main = me.getMain ? me.getMain() : document.getElementById(me.main),
                value = main.value;
            if (me.cc) {
                value = me.getParamMap();
            }
            return value;
        },
        /**
         * @method getParamMap
         * @description 获取子控件的值,返回一个map
         * @memerberof hui.Control.prototype
         * @public
         */
        getParamMap: function () {
            var me = this,
                paramMap = {},
                ctr,
                formname,
                value,
                groupList = {};
            // 如果有子控件建议递归调用子控件的getValue!!
            if (me.cc) {
                for (var i = 0, len = me.cc.length; i < len; i++) {
                    ctr = me.cc[i];
                    formname = hui.Control.prototype.getFormname.call(ctr);
                    groupList[formname] = !!ctr.group;
                    if (String(ctr.isFormItem) !== 'false') {
                        paramMap[formname] = paramMap[formname] ? paramMap[formname] : [];
                        if (ctr.getValue) {
                            value = ctr.getValue();
                            paramMap[formname].push(value);
                        }
                        else if (ctr.getMain || ctr.main) {
                            value = (ctr.getMain ? ctr.getMain() : document.getElementById(ctr.main)).value;
                            paramMap[formname].push(value);
                        }
                        else if (ctr.cc) {
                            value = ctr.getParamMap();
                            paramMap[formname].push(value);
                        }
                    }

                }
                // 注:默认都用数组包装,此处还原为值
                for (var i in paramMap) {
                    if (paramMap[i] && paramMap[i].length < 2) {
                        paramMap[i] = paramMap[i][0] !== undefined ? (groupList[i] ? paramMap[i] : paramMap[i][0]) : '';
                    }
                }
            }

            return paramMap;
        },
        /**
         * @method getByFormname
         * @description 通过formname访问子控件
         * @memerberof hui.Control.prototype
         * @public
         * @param {String} formname 子控件的formname
         * @example 
         * <button hui-type="Button" hui-formname="save">Save</button>
         * var save = hui.Control.getByFormname('save');
         */
        getByFormname: function (formname) {
            var me = this;
            return hui.Control.getByFormname(formname, me);
        },
        getByFormnameAll: function (formname, all) {
            var me = this;
            return hui.Control.getByFormnameAll(formname, me, all);
        },
        /**
         * @method show
         * @description 显示控件
         * @memerberof hui.Control.prototype
         * @public
         */
        show: function () {
            this.getMain().style.display = 'block';
            hui.Control.removeClass(this.getMain(), 'hide');
            return this;
        },

        /**
         * @method hide
         * @description 隐藏控件
         * @memerberof hui.Control.prototype
         * @public
         */
        hide: function () {
            hui.Control.addClass(this.getMain(), 'hide');
            this.getMain().style.display = 'none';
            return this;
        },
        /**
         * @method setDisabled
         * @description 设置控件不可用状态
         * @memerberof hui.Control.prototype
         * @public
         * @param {Boolean} disabled
         */
        setDisabled: function (disabled) {
            var me = this,
                main = me.getMain();
            main.disabled = typeof disabled === 'undefined' ? disabled = true : disabled;

            if (main.disabled) {
                hui.Control.addClass(main, me.getClass('disabled'));
            }
            else {
                hui.Control.removeClass(main, me.getClass('disabled'));
            }
            return me;
        },
        /**
         * @method setReadonly
         * @description 设置控件不可用状态
         * @memerberof hui.Control.prototype
         * @public
         * @param {Boolean} disabled
         */
        setReadonly: function (readOnly) {
            if (typeof readOnly === 'undefined') {
                readOnly = true;
            }
            this.getMain().readOnly = readOnly;
            return this;
        },
        /**
         * @method isDisabled
         * @description 判断控件不可用状态
         * @memerberof hui.Control.prototype
         * @public
         * @return {boolean}
         */
        isDisabled: function () {
            return this.getMain().disabled;
        },
        isReadonly: function () {
            return this.getMain().readOnly;
        },
        /**
         * @method setSize
         * @description 设置控件width和height
         * @memerberof hui.Control.prototype
         * @public
         */
        setSize: function (size) {
            var me = this,
                main = me.getMain();
            me.size = size ? size : me.size || {};
            me.size.width = me.size.width === undefined ? me.size.w : me.size.width;
            me.size.height = me.size.height === undefined ? me.size.h : me.size.height;
            me.size.top = me.size.top === undefined ? me.size.t : me.size.top;
            me.size.bottom = me.size.bottom === undefined ? me.size.b : me.size.bottom;
            me.size.left = me.size.left === undefined ? me.size.l : me.size.left;
            me.size.right = me.size.right === undefined ? me.size.r : me.size.right;

            if (me.size && me.size.width) {
                main.style.width = me.size.width + (typeof me.size.width !== 'string' ? 'px' : '');
            }
            if (me.size && me.size.height) {
                main.style.height = me.size.height + (typeof me.size.height !== 'string' ? 'px' : '');
            }

            if (me.size && me.size.top) {
                main.style.top = me.size.top + (typeof me.size.top !== 'string' ? 'px' : '');
            }
            if (me.size && me.size.bottom) {
                main.style.bottom = me.size.bottom + (typeof me.size.bottom !== 'string' ? 'px' : '');
            }
            if (me.size && me.size.left) {
                main.style.left = me.size.left + (typeof me.size.left !== 'string' ? 'px' : '');
            }
            if (me.size && me.size.right) {
                main.style.right = me.size.right + (typeof me.size.right !== 'string' ? 'px' : '');
            }
        },
        /**
         * @method getFormname
         * @description 获取表单控件的表单名
         * @memerberof hui.Control.prototype
         * @public
         * @param {Object} control
         */
        getFormname: function () {
            var me = this,
                main = me.getMain ? me.getMain() : document.getElementById(me.main);
            var itemName = me.formname || me['name'] || (main ? main.getAttribute('name') : null);
            return itemName;
        },
        /**
         * @method dispose
         * @description 释放控件
         * @memerberof hui.Control.prototype
         * @protected
         */
        dispose: function () {
            var me = this,
                cc,
                main = me.getMain ? me.getMain() : document.getElementById(me.main),
                list;
            // 从父控件的childControl中删除引用
            if (me.parentControl) {
                cc = me.parentControl.cc;
                for (var i = 0, len = cc.length; i < len; i++) {
                    if (cc[i] === me) {
                        cc.splice(i, 1);
                        break;
                    }
                }
            }

            me.disposeChild && me.disposeChild();

            if (main) {
                // 释放控件主区域的常用事件
                list = 'onmouseover|onmouseout|onmousedown|onmouseup|onkeyup|onkeydown|onkeypress|onchange|onpropertychange|' +
                    'onfocus|onblur|onclick|ondblclick|ontouchstart|ontouchmove|ontouchend|ondragover|ondrop|ondragstart'.split('|');
                for (var i = 0, len = list.length; i < len; i++) {
                    try {
                        main[list[i]] = Function('');
                    }
                    catch (e) {}
                }

                // 清空HTML内容
                if (main.setInnerHTML) {
                    main.setInnerHTML(main, '');
                }
                else if (main.innerHTML) {
                    main.innerHTML = '';
                }
                main.parentNode.removeChild(main);
            }

            // 因为使用的属性而非闭包实现的EventDispatcher,因此无需担心内存回收的问题。
        },
        disposeChild: function () {
            var me = this;
            // dispose子控件
            if (me.cc) {
                for (var i = me.cc.length - 1; i > -1; i--) {
                    me.cc[i].dispose();
                    me.cc[i] = null;
                }
                me.cc = [];
            }
        },
        // 
        //  * @method getView 
        //  * @description 获取视图模板名
        //  * @memerberof hui.Control.prototype
        //  * @protected
        //  * @return {String} target名字
        //  * @default 默认为action的id
        //  */
        // getView: function () {
        //     var view = (this.view === null ? '' : this.view);
        //     // 获取view
        //     if (typeof view === 'function') {
        //         view = view();
        //     }
        //     view = hui.Control.getExtClass('hui.Template').getTarget(String(view));

        //     return view;
        // },
        /**
         * @method enterControl
         * @description Control的主要处理流程
         * @memerberof hui.Control.prototype
         * @protected
         * @param {Object} argMap arg表.
         */
        enterControl: function (callback) {
            var uiObj = this,
                parentControl = uiObj.parentControl;
            // 注:默认增加一个空元素作为控件主元素!
            if (typeof uiObj.getMain !== 'function') {
                uiObj.getMain = hui.Control.prototype.getMain;
            }
            var elem = uiObj.getMain() || (uiObj.createMain ? uiObj.createMain() : hui.Control.prototype.createMain.call(uiObj));
            if (!elem) {
                return hui.Control.error('Control\'s main element is invalid');
            }
            else {
                elem.setAttribute('_rendered', '');
                elem.setAttribute('_initbehavior', '');
            }

            var que = new hui.Flow(); // 注:可以参照hui_flow.js文件。非常简单,不到30行代码
            if (elem.getAttribute && !elem.getAttribute('ctrid')) {
                que.push(function (next) {
                    var me = uiObj;
                    var main = me.getMain();
                    // 默认设置value
                    if (uiObj.value !== undefined) {
                        main.value = uiObj.value;
                    }
                    // 便于通过main.getAttribute('ctrid')找到control
                    main.setAttribute('ctrid', uiObj.getId ? uiObj.getId() : uiObj.id);
                    me.getClass && hui.Control.addClass(main, me.getClass());
                    me.setSize && me.setSize();

                    next && next();
                });
            }

            // 初始化Model
            if (elem.getAttribute && elem.getAttribute('_initModel') != 'true') {
                if (uiObj.initModel && uiObj.initModelMethod !== 'async' && uiObj.initModelMethod !== 'skip') {
                    que.push(function (next) {
                        var me = uiObj;
                        me.initModel();

                        next && next();
                    });
                    que.push(function (next) {
                        var me = uiObj;
                        var main = me.getMain();
                        main.getAttribute('_initModel', 'true');
                        next && next();
                    });
                }
                else if (uiObj.initModelAsync && uiObj.initModelMethod !== 'sync' && uiObj.initModelMethod !== 'skip') {
                    que.push(function (next) {
                        uiObj.initModelAsync(next);
                    });
                    que.push(function (next) {
                        var me = uiObj;
                        var main = me.getMain();
                        main.getAttribute('_initModel', 'true');
                        next && next();
                    });
                }
            }

            // 渲染视图
            if (elem.getAttribute && elem.getAttribute('_initView') != 'true') {
                if (uiObj.getView && uiObj.getViewMethod !== 'async' && uiObj.getViewMethod !== 'skip') {
                    que.push(function (next) {
                        var me = uiObj;
                        var main = me.getMain();
                        var tpl = me.getView();
                        var mainHTML = me.model && me.model.getData ? hui.Control.getExtClass('hui.Template').merge(tpl, me.model.getData()) : tpl;
                        hui.Control.prototype.setInnerHTML(main, mainHTML);

                        next && next();
                    });
                    que.push(function (next) {
                        var me = uiObj;
                        var main = me.getMain();
                        main.getAttribute('_initView', 'true');
                        next && next();
                    });
                }
                else if (uiObj.getViewAsync && uiObj.getViewMethod !== 'sync' && uiObj.getViewMethod !== 'skip') {
                    que.push(function (next) {
                        var me = uiObj;
                        me.getViewAsync(function (tpl) {
                            var main = me.getMain();
                            var mainHTML = me.model && me.model.getData ? hui.Control.getExtClass('hui.Template').merge(tpl, me.model.getData()) : tpl;
                            hui.Control.prototype.setInnerHTML(main, mainHTML);

                            next && next();
                        });
                    });
                    que.push(function (next) {
                        var me = uiObj;
                        var main = me.getMain();
                        main.getAttribute('_initView', 'true');

                        next && next();
                    });
                }
                else if (!uiObj.getView && !uiObj.getViewAsync && uiObj.view) {
                    que.push(function (next) {
                        var me = uiObj;
                        var main = me.getMain();
                        var tpl = hui.Control.getExtClass('hui.Template').getTarget(String(uiObj.view));
                        var mainHTML = me.model && me.model.getData ? hui.Control.getExtClass('hui.Template').merge(tpl, me.model.getData()) : tpl;
                        hui.Control.prototype.setInnerHTML(main, mainHTML);

                        next && next();
                    });
                    que.push(function (next) {
                        var me = uiObj;
                        var main = me.getMain();
                        main.getAttribute('_initView', 'true');
                        next && next();
                    });
                }
            }

            que.push(function (next) {
                var me = uiObj;
                var main = me.getMain();
                // 动态生成control需手动维护me.parentControl
                // 回溯找到父控件,若要移动控件,则需手动维护parentControl属性!!
                var parentElement = main;
                while (parentElement && parentElement.tagName && parentElement.parentNode) {
                    parentElement = parentElement.parentNode;
                    //label标签自带control属性!!
                    if (parentElement && hui.Control.isControlMain(parentElement)) {
                        var control = hui.Control.getById(parentElement.getAttribute('ctrid'), parentControl);
                        hui.Control.appendControl(control, me);
                        break;
                    }
                    // 未找到直接父控件则将control从hui.window.childControl移动到action.childControl中
                    else if (~',html,body,'.indexOf(',' + String(parentElement.tagName).toLowerCase() + ',')) {
                        hui.Control.appendControl(null, me);
                        break;
                    }
                }
                next && next();
            });

            // 1. initView()会在render调用父类的render时自动调用,
            // 2. 不管是批量hui.Control.init()还是hui.Control.create(), 都会通过enterControl来执行render
            // 3. initBehavior()会在后面执行
            if (elem.getAttribute && elem.getAttribute('_rendered') != 'true') {
                que.push(function (next) {
                    var me = uiObj;
                    var main = me.getMain();
                    me.render && me.render();

                    if (!me.render || main.getAttribute('_rendered') === 'false') {
                        var data = me.model && me.model.getData && typeof me.model.getData === 'function' ? me.model.getData() : {};
                        hui.Control.init(main, data, me);
                        main.setAttribute('_rendered', 'true');
                    }

                    next && next();
                });
            }
            if (elem.getAttribute && elem.getAttribute('_initbehavior') != 'true') {
                que.push(function (next) {
                    var me = uiObj;
                    if (me.initBehaviorByTree) {
                        me.initBehaviorByTree();
                    }
                    else if (me.initBehavior) {
                        me.initBehavior();
                    }

                    next && next();
                });
            }
            que.push(function (next) {
                var me = uiObj;
                me.finish && me.finish();

                callback && callback();
            });

            que.next();
        },
        /**
         * @method createMain
         * @description 生成主DOM
         * @memerberof hui.Control.prototype
         * @protected
         */
        createMain: function () {
            var me = this,
                tagName = this.tagName || 'DIV',
                main = document.createElement(String(tagName).toUpperCase()),
                control = me.parentControl,
                wrap = null;

            if (!wrap && control && control.getMain) {
                wrap = control.getMain();
            }
            if (!wrap && control && control.main) {
                wrap = document.getElementById(control.main);
            }
            if (!wrap) {
                wrap = document.body || document.documentElement;
            }
            if (me.parentElement) {
                wrap = typeof me.parentElement === 'string' ? (document.getElementById(me.parentElement) || document.documentElement) : me.parentElement;
            }

            wrap.appendChild(main);

            main.id = hui.Control.makeElemGUID(me.id);
            me.main = main.id;

            return main;
        },
        /**
         * @method appendControl
         * @description 父控件添加子控件. 注: 将子控件加到父控件下面的容器中也可以调用appendSelfTo
         * @memerberof hui.Control.prototype
         * @public
         * @param {Control} uiObj 子控件.
         */
        appendControl: function (uiObj) {
            return hui.Control.appendControl(this, uiObj);
        }
    };

    hui.inherits(hui.Control, hui.EventDispatcher);

    /**
     * @method hui.Control.makeGUID
     * @description 获取唯一id
     * @private
     * @return {String}
     */
    hui.Control.makeGUID = (function () {
        var guid = 1;
        return function (formname) {
            return (formname ? formname : 'inner') + '_' + hui.Control.getHashCode('inner') + (guid++);
        };
    })();

    hui.Control.getHashCode = function (str) {
        var hash = 0;
        if (str.length === 0) return hash;
        for (var i = 0; i < str.length; i++) {
            var c = str.charCodeAt(i);
            hash = ((hash << 5) - hash) + c;
            hash = hash & hash; // Convert to 32bit integer
        }
        return hash;
    };

    /**
     * @method hui.Control.makeElemGUID
     * @description 获取唯一id
     * @private
     * @return {String}
     */
    hui.Control.makeElemGUID = (function () {
        var guid = 1;
        return function (id) {
            return (id !== undefined ? id + hui.Control.getHashCode(id) : ('_' + hui.Control.formatDate(new Date(), 'yyyyMMddHHmm') + '_' + (guid++)));
        };
    })();
    /**
     * @method hui.Control.parseCustomAttribute
     * @description 解析自定义ui属性
     * @private
     * @param {String} attrStr ui属性
     * @param {Hashmap} opt_propMap 数据model
     * @return {Hashmap}
     */
    hui.Control.parseCustomAttribute = function (attrStr, opt_propMap) {
        var attrStr = '{' + (attrStr || '') + '}',
            attrs,
            attrValue,
            attrName;

        // 解析ui属性
        attrs = (new Function('return ' + attrStr))();

        for (var j in attrs) {
            if (attrs.hasOwnProperty(j)) {
                // 通过@定义的需要到传入的model中找
                attrValue = attrs[j];
                if (attrValue && typeof attrValue == 'string' && attrValue.indexOf('@') === 0) {
                    attrName = attrValue.substr(1);

                    attrValue = opt_propMap && opt_propMap.get ? opt_propMap.get(attrName) : opt_propMap[attrName];
                    // 默认读取opt_propMap中的,没有再到全局context中取,防止强耦合.
                    if (attrValue === undefined) {
                        attrValue = hui.Control.getExtClass('hui.context').get(attrName);
                    }
                    attrs[j] = attrValue;
                }
            }
        }

        return attrs;
    };

    /**
     * @method hui.Control.isChildControl
     * @description 判断一个解析前DOM元素是否是子控件,是则跳过非父控件的hui.Control.init()
     * @public
     * @param {String} elem DOM元素
     */
    hui.Control.isChildControl = function (elem, list) {
        var result = false;
        // 回溯找到父控件,若要移动控件,则需手动维护parentControl属性!!
        while (elem && elem.tagName && elem.parentNode) {
            elem = elem.parentNode;
            if (~',html,body,'.indexOf(',' + String(elem.tagName).toLowerCase() + ',') == -1) break;
            for (var i = 0, len = list.length; i < len; i++) {
                if (list[i] == elem) {
                    result = true;
                    break;
                }
            }
        }
        return result;
    };

    /**
     * @method hui.Control.isControlMain
     * @description 判断一个解析前DOM元素是否已解析控件
     * @public
     * @param {String} elem DOM元素
     */
    hui.Control.isControlMain = function (elem) {
        var result = false;
        // label的control是DOM
        if (elem && elem.getAttribute && elem.getAttribute('ctrid')) {
            result = true;
        }
        return result;
    };

    /**
     * @method hui.Control.init
     * @description 批量生成控件
     * @public
     * @param {HTMLElement} opt_wrap 渲染的区域容器元素
     * @param {Object}      opt_propMap 控件需要用到的数据Model{@key}
     * @param {Object}      parentControl 渲染的action,不传则默认为window对象
     * @return {Object} 控件集合
     * @example
     * hui.Control.init(hui.bocument.getElementById('content'));
     */
    //hui.Control.init('<div ui="type:"></div>');//暂时禁止此方法生成控件树
    hui.Control.init = function (opt_wrap, opt_propMap, parentControl) {
        if (!opt_wrap || opt_wrap.getAttribute('_rendered') === 'true') {
            return false;
        }

        /*Step 1: 转换string到DOM
        // 容器为空的判断
        if (typeof (opt_wrap) == 'string') {
            hui.bocument.documentElement.setInnerHTML(elem, opt_wrap);
            opt_wrap = hui.bocument.documentElement;
        }*/

        /*Step 2: 转换DOM到control*/
        opt_propMap = opt_propMap || {}; // 这里并不会缓存BaseModel,因此销毁空间时无须担心BaseModel
        // parentControl不传默认为window对象
        parentControl = parentControl || hui.window;
        parentControl.cc = parentControl.cc || [];


        var uiAttr = hui.Control.UI_ATTRIBUTE || 'ui';
        var realEls = [],
            uiEls = [];
        var elem, control;

        // 把dom元素存储到临时数组中
        // 控件渲染的过程会导致elements的改变
        realEls = hui.Control.findAllNodes(opt_wrap);

        // 循环解析自定义的ui属性并渲染控件
        // <div ui="type:'UIType',id:'uiId',..."></div>
        for (var i = 0, len = realEls.length; i < len; i++) {
            elem = realEls[i];
            if (elem && elem.getAttribute && (elem.getAttribute(uiAttr) || elem.getAttribute('hui-type')) && (elem.getAttribute('_initview') !== 'true' || elem.getAttribute('_initbehavior') !== 'true')) {
                uiEls.push(elem);
            }
        }
        for (var i = 0, len = uiEls.length; i < len; i++) {
            elem = uiEls[i];
            if (!hui.Control.isChildControl(elem, uiEls) && elem.getAttribute('_rendered') !== 'true') {

                control = hui.Control.create(elem, {
                    parentControl: parentControl
                });

                /*var attrStr = elem.getAttribute(uiAttr);
            
            var attrs = hui.Control.parseCustomAttribute(attrStr, opt_propMap);
            
            // 主元素参数初始化
            if(attrs.main          == undefined && elem)          {attrs.main = elem.id ? elem.id : hui.Control.makeElemGUID(); elem.id = attrs.main;}
            if(attrs.parentControl == undefined && parentControl) {attrs.parentControl = parentControl;}
            // 生成控件 //这里的parentControl, elem不能去掉!!否则在后面的enterControl理会重复生成elem!!! 
            //control = hui.Control.create( options[ 'type' ], options, parentControl, elem);
            //放在了上上一行,故去掉了parentControl, elem
             
            control = hui.Control.create( attrs[ 'type' ], attrs);
            /**
             * 保留ui属性便于调试与学习
             */
                // elem.setAttribute( uiAttr, '' );
            }
        }

        return parentControl.cc;
    };

    /**
     * @method hui.Control.create
     * @description 创建一个控件对象
     * @public
     * @param {String} type 控件类型
     * @param {Object} options 控件初始化参数
     * @return {hui.Control} 创建的控件对象
     * @example 
     * <button hui-type="Button" id="submit">submit</button>
     * hui.Control.init(hui.bocument.getElementById('submit'));
     */
    hui.Control.create = function (type, options) {
        // 注:扩展了一下,直接支持hui.Control.create(Element);
        if (type && Object.prototype.toString.call(type) != '[object String]' && type.getAttribute) {
            options = options || {};
            if (hui.Control.isControlMain(type)) {
                var control = hui.Control.getById(type.getAttribute('ctrid'));
                if (control) {
                    hui.Control.appendControl(options.parentControl, control);
                }
            }
            var str, attrs;
            try {
                str = type.getAttribute(hui.Control.UI_ATTRIBUTE || 'ui');
                try {
                    attrs = hui.Control.parseCustomAttribute(str);
                }
                catch (e) {
                    attrs = hui.Control.parseCustomAttribute(str.replace(/\\\'/g, '\'').replace(/\\\"/g, '\"')); //"
                }
                // hui-type="TextInput"
                var list = type.attributes;
                for (var i = 0, len = list.length; i < len; i++) {
                    var item = list[i];
                    if (item.nodeName.indexOf('hui-') === 0) {
                        attrs[item.nodeName.replace('hui-', '')] = item.nodeValue;
                    }
                }
            }
            catch (e) {
                hui.window.JSON && hui.window.JSON.stringify && hui.window.console && hui.window.console.error && hui.window.console.error('JSON Error: ', str);
                return;
            }

            var text, action, key;
            for (var i in attrs) {
                text = attrs[i];
                if (text && Object.prototype.toString.call(text) === '[object String]') {
                    if (text.indexOf('&') === 0) {
                        key = text.replace('&', '');
                        attrs[i] = hui.window[key];
                    }
                    else if (text.indexOf('@') === 0 && hui.Action && (typeof hui.Master.get) === 'function') {
                        key = text.replace('&', '');
                        action = hui.Master.get();
                        if (action && action.model && (typeof action.model.get) === 'function') {
                            attrs[i] = action.model.get(key);
                        }
                        else if (action && action.model) {
                            attrs[i] = action.model[key];
                        }
                        else if (action) {
                            attrs[i] = action[key];
                        }

                    }
                }
            }

            for (var i in options) {
                if (i && options.hasOwnProperty(i)) {
                    attrs[i] = attrs[i] !== undefined ? attrs[i] : options[i];
                }
            }
            // 注:每个控件必须有id
            attrs.id = attrs.id ? attrs.id : hui.Control.makeGUID(attrs['formname']);
            // 注:type即elem
            type.id = type.id || hui.Control.makeElemGUID(attrs.id);
            attrs.main = type.id;
            attrs.bocument = type.bocument;

            return hui.Control.create(attrs['type'], attrs);
        }

        options = options || {};

        // 注:创建并渲染控件,每个控件必须有id
        var objId = options.id;
        if (!objId) {
            objId = hui.Control.makeGUID(options['formname']);
            options.id = objId;
        }
        var existControl = hui.Control.getById(objId);
        if (existControl) {
            existControl.dispose();
        }

        var uiClazz = hui[type];
        if (!uiClazz) {
            hui.Control.error('Not use require(\'' + String(type).toLowerCase() + '\') or "' + String(type).toLowerCase() + '.js" is not loaded successfully.');
        }

        // 1. 模版批量生成控件时,options里一般没有m ain,m ain指向元素自身! //注:已改成默认有m ain
        // 2. new的方式创建控件时,options里一般有m ain!
        // 在这里设置m ain属性注意不能覆盖new uiClazz(options)的设置,也便于后面render时重新设置
        //if(options.m ain == undefined && m ain) {options.m ain = m ain;}//注:已移动到hui.Control.init中了

        // 设置临时parentControl放置子控件//注释掉原因:创建控件默认放在hui.window下//放到hui.Control.init中了
        //if(options.parentControl == undefined && parentControl) {options.parentControl = parentControl;}
        // 创建控件对象

        var uiObj = new uiClazz(options);
        uiObj.id = uiObj.id || objId;

        /*Hack方式不利于理解程序,所以去掉!!*/
        // 调用父类的构造函数
        //hui.Control.call( uiObj, options );
        /**
                 * @description 再次调用子类的构造函数
         * @comment 这里为什么不直接放到new uiClazz(options)里呢? 因为调用父类的构造函数会被覆盖掉.
        uiClazz.call( uiObj, options );/*已废弃*
        /**/
        /*uiObj.clazz = uiClazz;// 已经使用this.constructor代替*/
        /*
        // 加到父控件的childControl中
        if (!((uiObj.parentControl && uiObj.parentControl.cc && uiObj.parentControl.cc[objId] == uiObj) &&
            (uiObj.getId && uiObj.getId() !== objId) || (uiObj.id !== objId))) {
            
            if (uiObj.parentControl && uiObj.parentControl.cc && uiObj.parentControl.cc[objId] !== uiObj) {
                hui.Control.appendControl(uiObj.parentControl, uiObj);
                //uiObj.parentControl.cc[objId] = uiObj;
            }
            else if (options.parentControl && options.parentControl.cc && options.parentControl.cc[objId] !== uiObj) {
                hui.Control.appendControl(options.parentControl, uiObj);
                //options.parentControl.cc[objId] = uiObj;
            }
        }
        */
        // 检查是否有 enterControl 方法
        if (!uiObj.enterControl) {
            var child = uiObj,
                parent = hui.Control.prototype;
            for (var key in parent) {
                if (parent.hasOwnProperty(key)) {
                    child[key] = parent[key];
                }
            }
            uiObj.enterControl();
        }


        return uiObj;
    };

    /**
     * @method hui.Control.appendControl
     * @description 父控件添加子控件. 注: 将子控件加到父控件下面的容器中也可以调用appendSelfTo
     * @public
     * @param {Control} uiObj 子控件.
     */
    hui.Control.appendControl = function (parent, uiObj) {
        // parentControl父控件不传则默认为window对象
        // parentControl父控件默认为window对象, 不是的话后面会再改回来. 
        // var parentControl = hui.window;
        // Add: 上面这样做静态没问题,动态生成appendSelfTo就会出问题,因此需要加上options.parentControl
        // Fixme: 第二次执行到这里hui.Master.get()居然是前一个action?
        parent = parent || hui.window;
        parent.cc = parent.cc || [];

        // var ctrId = uiObj.getId ? uiObj.getId() : uiObj.id;
        // 注:从原来的父控件childControl中移除
        if (uiObj.parentControl && uiObj.parentControl.cc && uiObj.parentControl.cc != parent.cc) {
            var list = uiObj.parentControl.cc;
            for (var i = list.length - 1; i > -1; i--) {
                if (list[i] === uiObj) {
                    list.splice(i, 1);
                }
            }
        }

        // !!!悲催的案例,如果将childControl放在prototype里, 这里parent.cc===uiObj.cc!!!
        var exist = false;
        for (var i = 0, len = parent.cc.length; i < len; i++) {
            if (parent.cc[i] === uiObj) {
                exist = true;
                break;
            }
        }
        if (!exist) {
            parent.cc.push(uiObj);
        }
        // 重置parentControl标识
        uiObj.parentControl = parent;
        // !!!不能移动DOM,需自行解决,因为会打乱html布局
        /*var parentNode = parent.getMain ? parent.getMain() : null,
            main = uiObj.getMain();
        if (parentNode && main) {
            parentNode.appendChild(main);
        };*/
    };

    /**
     * @method hui.Control.findAllNodes
     * @description 获取所有子节点element
     * @private
     * @param {HTMLElement} main
     * @param {String} stopAttr 如果元素存在该属性,如'ui',则不遍历其下面的子元素
     */
    hui.Control.findAllNodes = function (main, stopAttr) {
        var childNode,
            elements,
            list,
            childlist,
            node;
        elements = [];
        list = [main];

        while (list.length) {
            childNode = list.pop();
            if (!childNode) continue;
            // Not set 'stopAttr', get all nodeds.
            if (stopAttr === undefined || (childNode.getAttribute && childNode.getAttribute(stopAttr))) {
                elements.push(childNode);
            }
            childlist = childNode.childNodes;
            if (!childlist || childlist.length < 1) continue;
            if (childNode != main && stopAttr !== undefined && childNode.getAttribute(stopAttr)) {
                continue;
            }
            // 注:Nodelist是伪数组且IE不支持Array.prototype.slice.call(Nodelist)转化数组
            for (var i = 0, len = childlist.length; i < len; i++) {
                node = childlist[i];
                list.push(node);
            }
        }
        // 去掉顶层main,如不去掉处理复合控件时会导致死循环!!
        if (elements[0] === main) elements.shift();

        return elements.reverse();
    };
    /**
     * @method hui.Control.findAllControl
     * @description 获取父控件或Action下所有控件
     * @private
     * @param {Object} control
     */
    hui.Control.findAllControl = function (parentControl) {
        var childNode,
            results,
            list,
            control;
        results = [];
        if (Object.prototype.toString.call(parentControl).indexOf('Element') > -1) {
            list = hui.Control.findAllNodes(parentControl);
            for (var i = 0, len = list.length; i < len; i++) {
                if (hui.Control.isControlMain(list[i])) {
                    control = hui.Control.getById(list[i].getAttribute('ctrid'));
                    if (control) {
                        results.push(control);
                    }
                }
            }
        }
        else {
            list = [parentControl];
            while (list.length) {
                childNode = list.pop();
                if (!childNode) continue;

                results.push(childNode);

                if (!childNode.cc) continue;
                list = list.concat(childNode.cc);
            }
            // 去掉顶层父控件或Action,如不去掉处理复合控件时会导致死循环!!
            if (results.length > 0) results.shift();
            // 后序遍历出来的结果,因此需要反转数组
            results.reverse();
        }
        return results;
    };
    // 所有控件实例的索引. 注释掉原因: 建了索引会造成无法GC内存暴涨!
    // hui.Control.elemList = [];
    /**
     * @method hui.Control.findByElem
     * @description 回溯找到当前元素所在的控件
     * @public
     * @param {Element} parentElement DOM元素
     */
    hui.Control.findByElem = function (parentElement) {
        var control = null;
        while (parentElement && parentElement.tagName) {
            //label标签自带control属性!!
            if (parentElement && hui.Control.isControlMain(parentElement)) {
                control = hui.Control.getById(parentElement.getAttribute('ctrid'));
                break;
            }
            else if (~',html,body,'.indexOf(',' + String(parentElement.tagName).toLowerCase() + ',')) {
                break;
            }
            parentElement = parentElement.parentNode;
        }
        return control;
    };

    /**
     * @method hui.Control.getById
     * @description 根据控件id找到对应控件
     * @public
     * @param {Control} [parentControl] 可不传, 默认从当前Action开始找, 如果未使用action则直接从window.cc开始找
     * @param {String} id 控件id
     */
    hui.Control.getById = function (id, parentControl) {
        var list,
            result = null;
        // parentControl || hui.Control.getById(parentControl) || hui.Master.get(parentControl) || hui.Master.get() || window
        if (typeof parentControl == 'string') {
            parentControl = hui.Control.getById(parentControl);
        }
        // 如果传入的parentControl是DOM元素,视为未传入值处理
        parentControl = parentControl && parentControl.getId ? parentControl :
            (hui.Action && hui.Action.ready && hui.Master.get ? (hui.Master.get(parentControl) || hui.Master.get()) : hui.window);

        if (id === undefined || (parentControl && parentControl.getId && id === parentControl.getId())) {
            result = parentControl;
        }
        else if (parentControl) {
            list = hui.Control.findAllControl(parentControl);
            for (var i = 0, len = list.length; i < len; i++) {
                if (list[i].id == id) {
                    result = list[i];
                }
            }
        }

        // If not found then find in 'window.cc'
        if (!result) {
            list = hui.Control.findAllControl(hui.window);
            for (var i = 0, len = list.length; i < len; i++) {
                if (list[i].id == id) {
                    result = list[i];
                }
            }
        }

        return result;
    };
    /**
     * @method hui.Control.getByFormnameAll
     * @description 根据控件formname找到对应控件
     * @static
     * @param {String} formname 控件formname
     * @param {Control} parentNode 父控件
     * @param {Boolean} all 仅查找直接子级,默认所有子级
     */
    hui.Control.getByFormnameAll = function (formname, parentNode, all) {
        var list = [],
            childNodes,
            item,
            /* 强制确认parentControl */
            parentControl = parentNode && typeof parentNode == 'object' ? parentNode : hui.window;

        if (formname) {
            formname = String(formname);

            // 注掉原因:不应该找自身!!
            // // 先查找自身 
            // childNodes = parentControl && parentControl.cc ? parentControl.cc : [];
            // //childNodes.unshift(parentControl);
            // if (parentControl.getFormname && parentControl.getFormname() === formname) {
            //     list.push(parentControl);
            // }

            // 再遍历控件树
            childNodes = parentControl && parentControl.cc ?
                (all === false ? parentControl.cc : hui.Control.findAllControl(parentControl)) : [];
            for (var i = 0, len = childNodes.length; i < len; i++) {
                item = childNodes[i];
                if ((item.getFormname && item.getFormname() === formname) || item['formname'] === formname) {
                    list.push(childNodes[i]);
                }
            }
        }

        return list;
    };
    /**
     * @method hui.Control.getByFormname
     * @description 根据控件formname找到对应控件,只返回一个结果
     * @static
     * @param {String} formname 控件formname
     * @param {Control} parentNode 父控件
     * @example 
     * <button hui-type="Button" hui-formname="save">Save</button>
     * var save = hui.Control.getByFormname('save');
     */
    hui.Control.getByFormname = function (formname, parentNode) {
        var result = null,
            list,
            min = Number.MAX_VALUE,
            deep,
            ctr;

        parentNode = parentNode && typeof parentNode === 'object' ? parentNode : hui.window;

        list = hui.Control.getByFormnameAll(formname, parentNode);
        // 注:默认返回直接子级第一个,直接子级没有才会返回最近子级的第一个
        // 注:要找到所有直接子级等于formname的可以用getByFormnameAll(formname, parentNode, false)
        for (var i = 0, len = list.length; i < len && min > 0; i++) {
            deep = 0;
            ctr = list[i];
            while (ctr.parentControl && ctr.parentControl !== parentNode) {
                deep++;
                ctr = ctr.parentControl;
            }
            if (deep < min) {
                min = deep;
                result = list[i];
            }
        }

        return result;
    };
    /**
     * @method hui.Control.disposeList
     * @description 销毁一组控件
     * @static
     * @param {String} list 一组控件
     */
    hui.Control.disposeList = function (list) {
        if (Object.prototype.toString.call(list) === '[object Array]') {
            for (var i = 0, len = list.length; i < len; i++) {
                if (list[i] && list[i].dispose) {
                    list[i].dispose();
                }
            }
        }
    };

    /**
     * @method hasClass,addClass,removeClass
     * @description 操作目标元素的className
     * @public
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {String} className 要添加的className,允许同时添加多个class,中间使用空白符分隔
     * @remark
     * 使用者应保证提供的className合法性,不应包含不合法字符,className合法字符参考:http://www.w3.org/TR/CSS2/syndata.html。
     * @returns {HTMLElement} 目标元素
     */
    hui.Control.hasClass = function (element, className) {
        return ~(' ' + element.className + ' ').indexOf(' ' + className + ' ');
    };
    hui.Control.addClass = function (element, className) {
        if (~'[object Array][object NodeList]'.indexOf(Object.prototype.toString.call(element))) {
            for (var i = 0, len = element.length; i < len; i++) {
                hui.Control.addClass(element[i], className);
            }
        }
        else if (element) {
            hui.Control.removeClass(element, className);
            element.className = (element.className + ' ' + className).replace(/(\s)+/ig, ' ');
        }
        return element;
    };
    // Support * and ?, like hui.Control.removeClass(elem, 'daneden-*');
    hui.Control.removeClass = function (element, className) {
        if (~'[object Array][object NodeList]'.indexOf(Object.prototype.toString.call(element))) {
            for (var i = 0, len = element.length; i < len; i++) {
                hui.Control.removeClass(element[i], className);
            }
        }
        else if (element) {
            var list = className.replace(/\s+/ig, ' ').split(' '),
                /* Attention: str need two spaces!! */
                str = (' ' + (element.className || '').replace(/(\s)/ig, '  ') + ' '),
                name,
                rex;
            // 用list[i]移除str
            for (var i = 0, len = list.length; i < len; i++) {
                name = list[i];
                name = name.replace(/(\*)/g, '\\S*').replace(/(\?)/g, '\\S?');
                rex = new RegExp(' ' + name + ' ', 'ig');
                str = str.replace(rex, ' ');
            }
            str = str.replace(/(\s)+/ig, ' ');
            str = str.replace(/^(\s)+/ig, '').replace(/(\s)+$/ig, '');
            element.className = str;
        }
        return element;
    };

    /**
     * @method hasCssString, removeCssString, importCssString
     * @description JS操作CSS
     * @public
     * @param {String} <style>的id
     */
    hui.Control.hasCssString = function hasCssString(id) {
        var sheets,
            c,
            result = false;
        if (document.createStyleSheet && (sheets = document.styleSheets)) {
            for (var i = 0, len = sheets.length; i < len; i++) {
                c = sheets[i];
                if (c && c.owningElement && c.owningElement.id === id) {
                    result = c.owningElement;
                    break;
                }
                else if (c && c.ownerNode && c.ownerNode.id === id) {
                    result = c.ownerNode;
                    break;
                }
            }
        }
        else if ((sheets = document.getElementsByTagName('style'))) {
            for (var i = 0, len = sheets.length; i < len; i++) {
                c = sheets[i];
                if (c.id === id) {
                    result = c;
                    break;
                }
            }
        }

        return result;
    };
    hui.Control.removeCssString = function removeCssString(id) {
        var parent,
            result = hui.Control.hasCssString(id);
        if (result) {
            parent = result.parentNode;
            parent.removeChild(result);
        }
    };

    hui.Control.importCssString = function importCssString(cssText, id) {
        hui.Control.removeCssString(id);

        var style = document.createElement('style');
        if (id) {
            style.id = id;
        }
        var head = document.head || document.body || document.documentElement;
        head.insertBefore(style, head.lastChild);
        if (head !== document.documentElement && style.nextSibling) {
            head.insertBefore(style.nextSibling, style);
        }
        style.setAttribute('type', 'text/css');
        // all browsers, except IE before version 9
        if (style.styleSheet) {
            style.styleSheet.cssText = cssText;
        }
        // Internet Explorer before version 9
        else {
            style.appendChild(document.createTextNode(cssText));
        }

        return style;
    };

    /**
     * @method hui.Control.format
     * @description 合并模板和数据
     * @public
     * @param {String} source 待格式化的字符串
     * @param {Object|Array} opts 要合并到字符串中的数据
     * @returns {String} 格式化之后的字符串
     * @example 
     * hui.Control.format('Hello {{user}}', {user: 'Tom'});
     * >> Hello Tom
     */
    hui.Control.format = function (source, opts) {
        function handler(match, key) {
            var type = String(key).indexOf('!!') === 0 ? 'decode' : String(key).indexOf('!') === 0 ? '' : 'encode',
                parts = key.replace(/^!!?/, '').split('.'),
                part = parts.shift(),
                cur = data,
                variable;
            while (part) {
                if (cur[part] !== undefined) {
                    cur = cur[part];
                }
                else {
                    cur = undefined;
                    break;
                }
                part = parts.shift();
            }

            variable = cur;
            if ('[object Function]' === toString.call(variable)) {
                variable = variable(key);
            }
            if (undefined !== variable) {
                variable = String(variable);
                // encodeURIComponent not encode '
                var fr = '&|<|>| |\'|"|\\'.split('|'),
                    to = '&amp;|&lt;|&gt;|&nbsp;|&apos;|&quot;|&#92;'.split('|');
                if (type === 'decode') {
                    for (var i = fr.length - 1; i > -1; i--) {
                        variable = variable.replace(new RegExp('\\' + to[i], 'ig'), fr[i]);
                    }
                }
                else if (type === 'encode') {
                    for (var i = 0, l = fr.length; i < l; i++) {
                        variable = variable.replace(new RegExp('\\' + fr[i], 'ig'), to[i]);
                    }
                }
            }

            return (undefined === variable ? '' : variable);
        }

        source = String(source);
        var data = Array.prototype.slice.call(arguments, 1),
            toString = Object.prototype.toString;
        if (data.length) {
            data = (data.length == 1 ?
                /* ie 下 Object.prototype.toString.call(null) == '[object Object]' */
                (opts !== null && (/\[object (Array|Object)\]/.test(toString.call(opts))) ? opts : data) : data);

            return source.replace(/#\{(.+?)\}/g, handler).replace(/\{\{([^\{]+?)\}\}/g, handler);
        }
        return source;
    };

    /**
     * @method hui.Control.formatDate
     * @description 将Date类型解析为String类型. 
     * @param {Date} date 输入的日期
     * @param {String} fmt 输出日期格式
     * @example
     * hui.Control.formatDate(new Date(2006,0,1), 'yyyy-MM-dd HH:mm');
     */
    hui.Control.formatDate = function (date, fmt) {
        if (!date) date = new Date();
        fmt = fmt || 'yyyy-MM-dd HH:mm';
        var o = {
            'M+': date.getMonth() + 1, //月份      
            'd+': date.getDate(), //日      
            'h+': date.getHours() % 12 === 0 ? 12 : date.getHours() % 12, //小时      
            'H+': date.getHours(), //小时      
            'm+': date.getMinutes(), //分      
            's+': date.getSeconds(), //秒      
            'q+': Math.floor((date.getMonth() + 3) / 3), //季度      
            'S': date.getMilliseconds() //毫秒      
        };
        var week = {
            '0': '/u65e5',
            '1': '/u4e00',
            '2': '/u4e8c',
            '3': '/u4e09',
            '4': '/u56db',
            '5': '/u4e94',
            '6': '/u516d'
        };
        if (/(y+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
        }
        if (/(E+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? '/u661f/u671f' : '/u5468') : '') + week[date.getDay() + '']);
        }
        for (var k in o) {
            if (o.hasOwnProperty(k) && new RegExp('(' + k + ')').test(fmt)) {
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
            }
        }
        return fmt;
    };
    /**
     * @method hui.Control.parseDate
     * @description 将String类型解析为Date类型.  
     * @param {String} fmt 输入的字符串格式的日期
     * @example
     * parseDate('2006-1-1') return new Date(2006,0,1)  
     * parseDate(' 2006-1-1 ') return new Date(2006,0,1)  
     * parseDate('2006-1-1 15:14:16') return new Date(2006,0,1,15,14,16)  
     * parseDate(' 2006-1-1 15:14:16 ') return new Date(2006,0,1,15,14,16);  
     * parseDate('不正确的格式') retrun null  
     */
    hui.Control.parseDate = function (str) {
        str = String(str).replace(/^[\s\xa0]+|[\s\xa0]+$/ig, '');
        var results = null;

        //秒数 #9744242680 
        results = str.match(/^ *(\d{10}) *$/);
        if (results && results.length > 0)
            return new Date(parseInt(str) * 1000);

        //毫秒数 #9744242682765 
        results = str.match(/^ *(\d{13}) *$/);
        if (results && results.length > 0)
            return new Date(parseInt(str));

        //20110608 
        results = str.match(/^ *(\d{4})(\d{2})(\d{2}) *$/);
        if (results && results.length > 3)
            return new Date(parseInt(results[1]), parseInt(results[2]) - 1, parseInt(results[3]));

        //20110608 1010 
        results = str.match(/^ *(\d{4})(\d{2})(\d{2}) +(\d{2})(\d{2}) *$/);
        if (results && results.length > 5)
            return new Date(parseInt(results[1]), parseInt(results[2]) - 1, parseInt(results[3]), parseInt(results[4]), parseInt(results[5]));

        //2011-06-08 
        results = str.match(/^ *(\d{4})[\._\-\/\\](\d{1,2})[\._\-\/\\](\d{1,2}) *$/);
        if (results && results.length > 3)
            return new Date(parseInt(results[1]), parseInt(results[2]) - 1, parseInt(results[3]));

        //2011-06-08 10:10 
        results = str.match(/^ *(\d{4})[\._\-\/\\](\d{1,2})[\._\-\/\\](\d{1,2}) +(\d{1,2}):(\d{1,2}) *$/);
        if (results && results.length > 5)
            return new Date(parseInt(results[1]), parseInt(results[2]) - 1, parseInt(results[3]), parseInt(results[4]), parseInt(results[5]));

        //2011/06\\08 10:10:10 
        results = str.match(/^ *(\d{4})[\._\-\/\\](\d{1,2})[\._\-\/\\](\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2}) *$/);
        if (results && results.length > 6)
            return new Date(parseInt(results[1]), parseInt(results[2]) - 1, parseInt(results[3]), parseInt(results[4]), parseInt(results[5]), parseInt(results[6]));

        return (new Date(str));
    };

    /**
     * @method hui.Control.encode
     * @description 对特殊字符和换行符编解码
     * @param {String} str 待编解码的字符串
     * @param {String} [decode] 是否是解码
     * @example
     * hui.Control.encode('%| |&|;|=|+|<|>|,');
     */
    hui.Control.encode = function (str, decode) {
        str = String(str);
        // encodeURIComponent not encode '
        var fr = '%| |&|;|=|+|<|>|,|"|\'|#|/|\\|\n|\r|\t'.split('|'),
            to = '%25|%20|%26|%3B|%3D|%2B|%3C|%3E|%2C|%22|%27|%23|%2F|%5C|%0A|%0D|%09'.split('|');
        if (decode == 'decode') {
            for (var i = fr.length - 1; i > -1; i--) {
                str = str.replace(new RegExp('\\' + to[i], 'ig'), fr[i]);
            }
        }
        else {
            for (var i = 0, l = fr.length; i < l; i++) {
                str = str.replace(new RegExp('\\' + fr[i], 'ig'), to[i]);
            }
        }
        return str;
    };
    hui.Control.decode = function (str) {
        return this.encode(str, 'decode');
    };
    hui.Control.encodehtml = function (str, decode) {
        str = String(str);
        // encodeURIComponent not encode '
        var fr = '&|<|>| |\'|"|\\'.split('|'),
            to = '&amp;|&lt;|&gt;|&nbsp;|&apos;|&quot;|&#92;'.split('|');
        if (decode == 'decode') {
            for (var i = fr.length - 1; i > -1; i--) {
                str = str.replace(new RegExp('\\' + to[i], 'ig'), fr[i]);
            }
        }
        else {
            for (var i = 0, l = fr.length; i < l; i++) {
                str = str.replace(new RegExp('\\' + fr[i], 'ig'), to[i]);
            }
        }
        return str;
    };
    hui.Control.decodehtml = function (str) {
        return this.encodehtml(str, 'decode');
    };


    //setInnerHTML: function (elem, html){}
    hui.Control.setInnerHTML = function (elem, html) {
        elem = elem && elem.getMain ? elem.getMain() : elem;
        if (elem && elem.innerHTML !== undefined) {
            elem.innerHTML = html;
        }
        return elem;
    };
    hui.Control.setInnerText = function (elem, text) {
        if (!elem) return;
        if (elem.textContent !== undefined) {
            elem.textContent = text;
        }
        else {
            elem.innerText = text;
        }
    };

    hui.Control.error = function (str) {
        if (hui.window && hui.window.console && hui.window.console.error) {
            hui.window.console.error(str);
        }
    };
    hui.Control.log = function (str) {
        if (hui.window && hui.window.console && hui.window.console.log) {
            hui.window.console.log(str);
        }
    };
    hui.Control.getExtClass = function (clazz) {
        var result = function () {};
        switch (clazz) {
        case 'hui.BaseModel':
            if (typeof hui !== 'undefined' && hui.BaseModel) {
                result = hui.BaseModel;
            }
            else {
                result.get = new Function();
                result.set = new Function();
            }
            break;
        case 'hui.Template':
            if (typeof hui !== 'undefined' && hui && hui.Template) {
                result = hui.Template;
            }
            else {
                result.getTarget = new Function();
                result.merge = new Function();
            }
            break;
        case 'hui.Validator':
            if (typeof hui !== 'undefined' && hui.Validator) {
                result = hui.Validator;
            }
            else {
                result.showWaiting = new Function();
                result.showError = new Function();
                result.showOK = new Function();
                result.cancelNotice = new Function();
                result.set = new Function();
            }
            break;
        case 'hui.Action':
            if (typeof hui !== 'undefined' && hui.Validator) {
                result = hui.Validator;
            }
            else {
                result.get = new Function();
            }
            break;
        case 'hui.context':
            if (typeof hui !== 'undefined' && hui.context) {
                result = hui.context;
            }
            else {
                result = {};
                result.get = new Function();
            }
            break;
        default:
        }
        return result;
    };
});