API Docs for: 1.0.0
Show:

File: js\flyingon.js

/*
* flyingon javascript library v0.0.1.0
* https://github.com/freeoasoft/flyingon
*
* Copyright 2014, yaozhengyang
* licensed under the LGPL Version 3 licenses
*/



//启用严格模式
'use strict';



/**
 * @class flyingon
 * @static
 * @description flyingon全局名字空间
 */
var flyingon;


//基础api扩展
(function(fn) {
  
    
    if (typeof require === 'function' && typeof module === 'object' && module) //兼容cmd
    {
        fn(module.exports = flyingon = {});
    }
    else if (typeof define === 'function' && define.amd) //兼容amd
    {  
        flyingon = {};

        define(function (require, exports, module) {

            fn(module.exports = flyingon);
        });
    }
    else //普通浏览环境
    {
        fn(flyingon = window.flyingon || (window.flyingon = {}));  
    }


})(function (flyingon) {
    
    
    /**
     * @property version
     * @type string
     * @for flyingon
     * @description flyingon版本号
     */
    flyingon.version = '1.0.1';



    //空函数
    function fn() {};
        
        
    /**
     * @method create
     * @for flyingon
     * @description 以指定原型创建对象
     * @param {object} prototype 新创建对象的原型
     * @return {object} 新创建的对象
     * @example 
     * //创建一个原型为null的对象
     * flyingon.create(null);
     * @example 
     * //创建一个原型为数组的对象
     * flyingon.create([]);
     */
    flyingon.create = Object.create || function (prototype) {

        if (prototype)
        {
            fn.prototype = prototype;
            return new fn();
        }

        return {};
    };


    /**
     * @method extend
     * @for flyingon
     * @description 复制源对象成员至目标对象
     * @param {object} target 目标对象
     * @param {object} source 源对象(可以有多个源对象)
     * @param {boolean} deep 是否深复制
     * @return {object} 目标对象
     * @example
     * flyingon.extend({}, { a: 1, b: [1, 2] }, { c: 3 }, true);
     */
    flyingon.extend = function extend(target, source, deep) {

        var index = arguments.length - 1,
            item;
            
        target = target || {};
        
        if (arguments[index] === true)
        {
            deep = true;
            index--;
        }

        while (index > 0 && (item = arguments[index--]))
        {
            if (deep)
            {
                for (var name in item)
                {
                    var value = item[name];
                    
                    if (value && typeof value === 'object')
                    {
                        target[name] = extend(target[name], value, true);
                    }
                    else
                    {
                        target[name] = value;
                    }
                }
            }
            else
            {
                for (var name in item)
                {
                    target[name] = item[name];
                }
            }
        }

        return target;
    };
        

    /**
     * @method each
     * @for flyingon
     * @description 循环处理
     * @param {string|any[]} values 循环目标
     * @param {function} fn 循环函数
     * @param {object} [context] 指定函数上下文(this)
     * @example
     * flyingon.each('1,2,3,4,5', function (item, index) {
     * 
     *      //...
     * });
    * @example
     * flyingon.each([1,2,3,4,5], function (item, index) {
     * 
     *      //...
     * });
     */
    flyingon.each = function (values, fn, context) {

        if (values)
        {
            if (typeof values === 'string')
            {
                values = values.match(/\w+/g);
            }

            for (var i = 0, l = values.length; i < l; i++)
            {
                fn.call(context || flyingon, values[i], i);
            }
        }
    };



});

  

//模块,类,属性及事件
(function (flyingon) {
    

    
    var create = flyingon.create,
        
        extend = flyingon.extend,

        slice = [].slice,

        components = flyingon.components || (flyingon.components = create(null)), //已注册所有组件类型集合
    
        anonymous = 1,
        
        modules = create(null), //模块集合

        module_stack = [], //模块栈

        module_current, //当前模块

        fragments = flyingon.fragments || (flyingon.fragments = create(null)), //功能片段集合

        class_name = 'class name can use only letters and numbers and begin with a upper letter!',

        class_fn = 'class fn must be a function!';
    

    
    //模块名
    flyingon.moduleName = 'flyingon';

    //控件class前缀
    flyingon.className = 'f';



    //设置默认模块
    modules.flyingon = flyingon;



    /**
     * @method use
     * @for flyingon
     * @description 使用指定模块
     * @param {string} name 模块名称, 多级名称用"."分隔
     * @return {object} 模块对象
     * @example
     * flyingon.use('a.b');
     */
    flyingon.use = function (name) {
        
        switch (typeof name)
        {
            case 'string':
                return parse_module(name);

            case 'object':
                return name || flyingon;
        }
        
        return flyingon; 
    };


     /**
     * @method defineModule
     * @for flyingon
     * @description 定义或切换当前模块
     * @param {string} name 模块名称, 多级名称用"."分隔
     * @param {function} [callback] 模块定义函数, 不传入表示切换当前模块
     * @return {object} 模块对象
     * @example
     * flyingon.use('a.b');
     */
    flyingon.defineModule = function (name, callback) {

        var item, fn;

        //生成模块
        switch (typeof name)
        {
            case 'string':
                item = parse_module(name);
                break;
                
            case 'function':
                item = module_current || flyingon;
                callback = name;
                break;

            case 'object':
                item = name || flyingon;
                
            default:
                item = flyingon;
                break;
        }

        //处理回调
        if (typeof callback === 'function')
        {
            //如果正在动态加载脚本或还有依赖的js没有加载完成则先注册 否则立即执行
            if (!(fn = flyingon.require) || 
                !(fn = fn.callback) || 
                !fn(load_module, [item, callback]))
            {
                load_module(item, callback);
            }
        }
        else
        {
            module_stack.push(module_current = item);
        }

        return item;
    };

    
    /**
     * @method endModule
     * @for flyingon
     * @description 结束当前切换当前模块
     * @return {object} 模块对象
     * @example
     * flyingon.endModule();
     */
    flyingon.endModule = function () {
        
        var stack = module_stack;
        
        stack.pop();
        return module_current = stack[stack.length - 1] || flyingon;
    };

  
    //解析模块
    function parse_module(name) {
            
        var keys = modules,
            list, 
            item,
            any;

        if (item = keys[name])
        {
            return item;
        }

        if (list = name.match(/\w+/g))
        {
            item = module_stack[module_stack.length - 1] || keys;

            for (var i = 0, l = list.length; i < l; i++)
            {
                if (any = item[name = list[i]])
                {
                    item = any;
                }
                else
                {
                    any = (any = item.moduleName) ? any + '.' + name : name;
                    item = keys[any] = item[name] = create(null);
                    item.moduleName = any;
                }
            }

            return item;
        }

        throw 'module name can use only letters and numbers!';
    };


    //执行模块函数
    function load_module(target, callback) {

        try
        {
            //记录当前模块
            module_stack.push(module_current = target);
            callback.call(target, target, flyingon);
        }
        finally
        {
            flyingon.endModule();
        }
    };



    /**
     * @method fragment
     * @for flyingon
     * @description 定义或扩展功能片段
     * @param {string} name 片段名称
     * @param {function|object} fn 类型是函数时表示功能实现, 类型是对象时表示对比对象扩展定义名称的片段
     * @example
     * //定义功能片段
     * flyingon.fragment('test', function () {
     * 
     *      this.fn = function () {};
     * });
     * @example
     * //给定义的类扩展功能片段
     * Object.extend(function () {
     * 
     *      flyingon.fragment('test', this);
     * });
     */
    flyingon.fragment = function (name, fn) {

        var any;

        if (typeof fn === 'function')
        {
            fragments[name] = fn;
        }
        else if (any = fragments[name])
        {
            any.apply(fn, slice.call(arguments, 2));
        }
    };

    


    /**
     * @class Class
     * @description 通过flyingon.defineClass或{父类}.extend定义的类
     */


    /**
     * @method defineClass
     * @for flyingon
     * @description 定义类方法, 此方法大多数情况下可使用{父类}.extend替换, 比如Object.extend表示从Object继承定义子类
     * @param {string} [name] 类名称, 只能包含英文字母及数字且首字母需大写
     * @param {function} [superclass] 父类, 省略时表示从Object继承
     * @param {function} fn 类实现, 函数内this指向类原型, 参数(base:父类原型, self:当前类原型)
     * @param {boolean} [property] 是否支持属性, 默认支持, 可以从非属性类继承生成非属性类, 不能从属性类继承生成非属性类
     * @return {Class} 生成的类
     * @example
     * //从Object继承定义父类
     * var BaseClass = flyingon.defineClass(function () {
     * 
     *      //定义字符串类型的name属性, 默认值为空字符串
     *      this.defineProperty('name', '');
     * 
     *      //定义方法
     *      this.fn = function () {};
     * });
     * @example
     * //从BaseClass继承派生子类
     * var ChildClass = flyingon.defineClass(BaseClass, function (base) {
     * 
     *      //重载父类方法
     *      this.fn = function () {
     * 
     *          //调用父类方法
     *          base.fn.call(this);
     *      };
     * });
     */
    flyingon.defineClass = function (name, superclass, fn, property) {

        //处理参数
        if (typeof name !== 'string') //不传name则创建匿名类
        {
            property = fn;
            fn = superclass;
            superclass = name;
            name = null;
        }
        else if (!/^[A-Z]\w*$/.test(name))
        {
            throw class_name;
        }

        if (typeof fn !== 'function')
        {
            if (typeof superclass === 'function')
            {
                property = fn;
                fn = superclass;
                superclass = Object;
            }
            else
            {
                throw class_fn;
            }
        }
        else if (!superclass || typeof superclass !== 'function') //处理父类
        {
            superclass = Object;
        }

        return defineClass(name, superclass, fn, property);
    };
    
    
    /**
     * @method extend
     * @for Class
     * @description 从当前类派生生成子类
     * @param {string} [name] 类名称, 只能包含英文字母及数字且首字母需大写
     * @param {function} fn 类实现, 函数内this指向类原型, 参数(base:父类原型, self:当前类原型)
     * @param {boolean} [property] 是否支持属性, 默认支持, 可以从非属性类继承生成非属性类, 不能从属性类继承生成非属性类
     * @return {Class} 生成的类
     * @example
     * //从Object继承定义父类
     * var BaseClass = Object.extend(function () {
     * 
     *      //定义字符串类型的name属性, 默认值为空字符串
     *      this.defineProperty('name', '');
     * 
     *      //定义方法
     *      this.fn = function () {};
     * });
     * @example
     * //从BaseClass继承派生子类
     * var ChildClass = BaseClass.extend(function (base) {
     * 
     *      //重载父类方法
     *      this.fn = function () {
     * 
     *          //调用父类方法
     *          base.fn.call(this);
     *      };
     * });
     */
    Object.extend = function (name, fn, property) {

        //处理参数
        if (typeof name !== 'string') //不传name则创建匿名类
        {
            property = fn;
            fn = name;
            name = null;
        }
        else if (!/^[A-Z]\w*$/.test(name))
        {
            throw class_name;
        }

        if (typeof fn !== 'function')
        {
            throw class_fn;
        }
        
        return defineClass(name, this, fn, property);
    };



    //定义简单类
    Object.extend._ = function (superclass, fn) {

        if (!fn)
        {
            fn = superclass;
            superclass = Object;
        }
        
        function Class() {};

        var base = superclass.prototype,
            prototype = Class.prototype = create(base);

        prototype.Class = Class;
        fn.call(prototype, base, prototype);

        return Class;
    };


    //定义类
    function defineClass(name, superclass, fn, property) {


        var Class, base, prototype, module, fullName, any;


        //定义类
        function Class() {

            var init = this.init;

            if (init)
            {
                init.apply(this, arguments);
            }
        };


        //创建原型
        prototype = create(base = superclass.prototype || Object.prototype);

        //设置base属性
        prototype.base = base;


        //父类不是flyingon类
        any = !base.__flyingon_class;

        
        //如果指定要生成属性或父类支持属性则处理属性相关功能
        if (property || (property == null && any) || base.__defaults)
        {
            //生成默认值集合
            prototype.__defaults = create(base.__defaults || null);

            //生成属性集合
            prototype.__properties = create(base.__properties || null);
            
            //父类不是flyingon类则生成属性相关方法
            if (any)
            {
                prototype.defineProperty = defineProperty;
                prototype.storage = storage;
                prototype.get = get;
                prototype.set = set;
                prototype.defaultValue = defaultValue;
                prototype.properties = properties;
                prototype.getOwnPropertyNames = getOwnPropertyNames;
                prototype.notify = notify;
                prototype.watch = watch;
                prototype.unwatch = unwatch;
            }
        }
        
            
        //父类不是flyingon类则生成事件相关方法
        if (any)
        {
            prototype.__flyingon_class = true;

            prototype.on = on;
            prototype.once = once;
            prototype.off = off;
            prototype.trigger = trigger;
            prototype.is = is;
            prototype.toString = toString;
            prototype.dispose = dispose;
        }
        
    
        //获取当前模块
        module = module_current || flyingon;

        //fullName
        fullName = name ? module.moduleName + '-' + name : 'anonymous-type-' + anonymous++;
        
        //类型标记
        prototype[fullName] = true;

        //获取当前类型
        prototype.Class = prototype.constructor = Class;


        //记录未执行的类扩展函数
        Class.__class_fn = fn;

        //注:为提升初始化性能,函数使用延迟执行
        //如果类未实例化过,其原型成员可能未完全创建
        prototype.init = delay_init;

     
        //注册类型(匿名类不注册)
        if (name)
        {
            //类名
            Class.typeName = name;

            //输出及注册类
            module[name] = components[fullName] = Class;
        }
        

        //类全名
        Class.fullName = fullName;
        
        //类原型
        Class.prototype = prototype;

        //所属模块
        Class.module = module;

        //父类
        Class.superclass = superclass;

        //注册组件
        Class.register = superclass.register || register;

        //初始化类方法(可调用此方法强制类初始化)
        Class.init = init;

        //派生子类方法
        Class.extend = Object.extend;

        //返回当前类型
        return Class;
    };


    //延时构造函数
    function delay_init() {

        var init;

        this.Class.init();

        if (init = this.init)
        {
            init.apply(this, arguments);
        }
    };


    /**
     * @static
     * @method init
     * @for Class
     * @description 类初始化方法, 默认情况下在第一次实例化类时会自动初始化, 如有特殊需要可手动调用此方法对类进行初始化
     * @return {Class} 返回当前类
     */
    function init() {

        var prototype = this.prototype, 
            base = prototype.base,
            any;

        if ((any = this.superclass) && any.__class_fn)
        {
            any.init();
        }

        //执行扩展
        if (any = this.__class_fn)
        {
            any.call(prototype, base, prototype);

            //初始化类
            if (any = prototype.__class_init)
            {
                any.call(prototype, this, base, prototype);
            }

            delete this.__class_fn;

            //如果没有生成新的构造函数则删除延时构造函数
            if (prototype.init === delay_init)
            {
                delete prototype.init;
            }
        }

        return this;
    };


    /**
     * @method is
     * @for Class
     * @description 检测当前对象是否指定类型
     * @param {function} type 指定的类型
     * @return {boolean} 是否指定类型  
     */
    function is(type) {

        return type && (this instanceof type || ((type = type.fullName) && this[type]));
    };


    /**
     * @method toString
     * @for Class
     * @description 返回类的字符串表示
     * @return {string} 类字符串表示
     */
    function toString() {

        return '[object ' + this.fullName + ']';
    };
    

    /**
     * @method defineProperty
     * @for Class
     * @description 定义属性
     * @param {string} name 属性名, 不能包含英文字母及数字且以英文字母开头
     * @param {any} defaultValue 属性默认值, 如果attributes中未指定dataType, 会自动从此值推导出默认值
     * @param {object=} attributes 属性参数 { dataType: string, check: function, set: function }
     * @return {function} 属性函数
     */
    function defineProperty(name, defaultValue, attributes) {

        var fn, any;

        if (!/^[a-z][\w$]*$/.test(name))
        {
            throw 'property name "' + name + '" is not legal!';
        }

        if (attributes)
        {
            attributes.name = name;
        }
        else
        {
            attributes = { name: name };
        }
     
        //处理默认值
        if (typeof defaultValue === 'function')
        {
            attributes.fn = defaultValue;
            attributes.defaultValue = defaultValue = null;
        }
        else
        {
            attributes.defaultValue = defaultValue;
        }
      
        (this.__defaults || (this.__defaults = create(null)))[name] = defaultValue;
        (this.__properties|| (this.__properties = create(null)))[name] = attributes;
        
        //根据默认值生成数据类型
        if (!(any = attributes.dataType))
        {
            any = attributes.dataType = typeof defaultValue;
        }
        
        //创建读写方法
        this[name] = fn = attributes.fn || property_fn(name, any, attributes.check, attributes.set);

        //标记是属性方法
        fn.property = true;
        
        //扩展至选择器
        if (any = this.__selector_extend)
        {
            (any.prototype || any)[name] = selector_extend(name);
        }

        return fn;
    };
    

    function property_fn(key, dataType, check, set) {

        return function (value) {

            var storage = this.__storage,
                name = key,
                any = (storage || this.__defaults)[name];

            if (value === void 0)
            {
                return any;
            }

            //基本类型转换(根据默认值的类型自动转换)
            switch (dataType)
            {
                case 'boolean':
                    value = !!value && value !== 'false';
                    break;

                case 'int':
                    value = value | 0;
                    break;

                case 'number':
                    value = +value || 0;
                    break;

                case 'string':
                    value = '' + value;
                    break;

                case 'date':
                    value = value ? Date.create(value) : null; //自定义扩展Date.create函数解决不同浏览对日期格式解析不一致的问题
                    break;
            }

            if (check)
            {
                value = check.call(this, value)
            }

            if (any !== value)
            {
                (storage || (this.__storage = create(this.__defaults)))[name] = value;

                if (set)
                {
                    set.call(this, value, any);
                }

                if ((storage = this.__watches) && (storage[name] || storage['*']))
                {
                    this.notify(name, value, any);
                }
            }

            return this;
        };
    };


    //扩展至选择器
    function selector_extend(name) {
      
        return function (value) {
              
            var index = 0,
                key = name,
                item,
                fn;

            if (value === void 0)
            {
                while (item = this[index++])
                {
                    if (fn = item[key])
                    {
                        return fn.call(item);
                    }
                }
            }

            while (item = this[index++])
            {
                if (fn = item[key])
                {
                    fn.apply(item, arguments);
                }
            }
            
            return this;
        };
    };
        

    /**
     * @method storage
     * @for Class
     * @description 获取对象存储器
     * @return {object} 对象存储器或默认存储器
     */
    function storage() {

        return this.__storage || (this.__storage = create(this.__defaults));
    };


    /**
     * @method get
     * @for Class
     * @description 获取指定名称的属性值
     * @param {string} name 属性名
     * @return {any} 属性值
     */
    function get(name) {
      
        var any;

        if ((any = (this.__storage || this.__defaults)[name]) !== void 0)
        {
            return any;
        }

        if (any = this.__custom_get)
        {
            return any.call(this, name);
        }
    };
    
    
    /**
     * @method set
     * @for Class
     * @description 设置指定名称的属性值
     * @param {string} name 属性名
     * @param {any} value 属性值
     * @return {object} 当前实例对象
     */
    function set(name, value) {
        
        var fn;

        if ((fn = this[name]) && fn.property)
        {
            fn.call(this, value);
        }
        else if (fn = this.__custom_set)
        {
            fn.call(this, name, value);
        }
        else
        {
            (this.__storage || (this.__storage = create(this.__defaults)))[name] = value;
        }
        
        return this;
    };


    /**
     * @method defaultValue
     * @for Class
     * @description 获取或设置属性默认值
     * @param {string} name 属性名
     * @param {any=} value 默认值, 未传入此值时表示读取默认值, 否则表示设置默认值
     * @return {(any|object)} 读取默认值时返回默认值, 否则返回当前实例对象
     */
    function defaultValue(name, value) {

        var defaults = this.__defaults;

        if (value === void 0)
        {
            return defaults[name];
        }

        defaults[name] = value;
        defaults = this.__properties;
        
        (defaults[name] = flyingon.extend({}, defaults[name])).defaultValue = value;
                
        return this;
    };


    /**
     * @method properties
     * @for Class
     * @description 获取属性值集合
     * @param {boolean=} deep 是否返回父类的属性值
     * @param {function=} filter 过滤条件
     * @return {object[]} 属性值集合
     */
    function properties(deep, filter) {

        var keys = this.__properties,
            items = [],
            item;
        
        if (typeof deep === 'function')
        {
            filter = deep;
        }
        
        deep = deep === false ? this.base.__properties : null;
            
        for (var name in keys)
        {
            if ((item = keys[name]) && 
                (!deep || deep[name] !== item) && 
                (!filter || filter(item)))
            {
                items.push(item);
            }
        }

        return items;
    };


    /**
     * @method notify
     * @for Class
     * @description 通知对象属性值变更
     * @param {string} name 属性名
     * @param {any} newValue 新属性值
     * @param {any} oldValue 原属性值
     * @return {object} 当前实例对象
     */
    function notify(name, newValue, oldValue) {

        var watches = this.__watches,
            any;

        if (watches)
        {
            if (any = watches[name])
            {
                do_notify.call(this, any, name, newValue, oldValue);
            }

            if (name !== '*' && (any = watches['*']))
            {
                do_notify.call(this, any, '*', newValue, oldValue);
            }
        }

        return this;
    };


    function do_notify(list, name, value, oldValue) {

        var item = list[0],
            index = 1;

        if (item)
        {
            this.pushBack(item, value);
        }

        while (item = list[index++])
        {
            item.call(this, name, value, oldValue);
        }
    };


    /**
     * @method watch
     * @for Class
     * @description 观测属性变更
     * @param {string} name 属性名
     * @param {function} fn 属性值变更后的回调方法
     * @return {object} 当前实例对象
     */
    function watch(name, fn) {

        if (typeof name === 'function')
        {
            fn = name;
            name = '*';
        }
        else if (typeof fn !== 'function')
        {
            return;
        }

        var watches = this.__watches || (this.__watches = {}),
            any = watches[name];

        if (any)
        {
            any.push(fn);
        }
        else
        {
            watches[name] = ['', fn];
        }

        return this;
    };


    /**
     * @method unwatch
     * @for Class
     * @description 取消属性变更观测
     * @param {string} name 属性名, 传入"*"表示取消所有观测
     * @param {function=} fn 注册的属性变更方法
     * @return {object} 当前实例对象
     */
    function unwatch(name, fn) {

        if (typeof name === 'function')
        {
            fn = name;
            name = '*';
        }

        var watches = this.__watches,
            any;

        if (watches && (any = watches[name]))
        {
            if (fn)
            {
                for (var i = any.length - 1; i >= 1; i--)
                {
                    if (any[i] === fn)
                    {
                        any.splice(i, 1);
                    }
                }
            }
            else
            {
                any.splice(i, 1);
            }

            if (any.length === 1 && !any[0])
            {
                delete watches[name];
            }
        }

        return this;
    };

    
    /**
     * @method on
     * @for Class
     * @description 绑定事件处理 注:type不带on
     * @param {string} type 事件类型
     * @param {function=} fn 事件处理方法
     * @return {object} 当前实例对象
     */
    function on(type, fn) {

        if (type && typeof fn === 'function')
        {
            var events = this.__events || (this.__events = create(null));

            (events[type] || (events[type] = [])).push(fn);

            if (fn = this.__event_on)
            {
                fn.apply(this, type);
            }
        }

        return this;
    };

    
    /**
     * @method once
     * @for Class
     * @description 绑定事件处理, 执行一次后自动移除绑定 注:type不带on
     * @param {string} type 事件类型
     * @param {function=} fn 事件处理方法
     * @return {object} 当前实例对象
     */
    function once(type, fn) {

        var self = this;

        function callback() {

            fn.apply(self, arguments);
            self.off(type, callback);
        };

        return this.on(type, callback);
    };

        
    /**
     * @method off
     * @for Class
     * @description 移除事件处理
     * @param {string=} type 事件类型, 不传值时表示移除所有事件处理
     * @param {function=} fn 事件处理方法, 不传值时表示移除指定类型的所有事件处理
     * @return {object} 当前实例对象
     */
    function off(type, fn) {

        var events = this.__events,
            items;

        if (events)
        {
            if (type)
            {
                if (fn)
                {
                    if (items = events[type])
                    {
                        for (var i = items.length - 1; i >= 0; i--)
                        {
                            if (items[i] === fn)
                            {
                                items.splice(i, 1);
                            }
                        }

                        if (!items.length)
                        {
                            events[type] = null;
                        }
                    }
                }
                else if (events[type])
                {
                    events[type] = null;
                }
            }
            else
            {
                for (var type in events)
                {
                    this.off(type);
                }

                this.__events = null;
            }

            if (fn = this.__event_off)
            {
                fn.call(this, type);
            }
        }

        return this;
    };

    
    /**
     * @method trigger
     * @for Class
     * @description 分发事件
     * @param {(string|flyingon.Event)=} e 事件参数
     * @param {...any=} 自定义事件参数 按name, value的方式传入
     * @return {boolean} 是否阻止默认处理
     * @example
     * //分发类型为test的事件(有一个自定义的data参数, 值为1)
     * flyingon.trigger('test', 'data', 1);
     */
    function trigger(e) {

        var type = e.type || (e = new flyingon.Event(e)).type,
            index = 1,
            start,
            target,
            events,
            length,
            fn;

        e.target = this;
        
        //初始化自定义参数
        while (start = arguments[index++])
        {
            e[start] = arguments[index++];
        }

        start = target = flyingon;
        
        do
        {
            if ((events = target.__events) && (events = events[type]) && (length = events.length))
            {
                index = 0;
                
                do
                {
                    if ((fn = events[index++]) && !fn.disabled)
                    {
                        if (fn.call(target, e) === false)
                        {
                            e.defaultPrevented = true;
                        }

                        if (e.cancelBubble)
                        {
                            return !e.defaultPrevented;
                        }
                    }
                }
                while (index < length);
            }
            
            if (start !== target)
            {
                target = (fn = target.eventBubble) && target[fn];
            }
            else if (start !== this)
            {
                target = this;
            }
            else
            {
                break;
            }
        }
        while (target);

        return !e.defaultPrevented;
    };


    /**
     * @method getOwnPropertyNames
     * @for Class
     * @description 获取自身属性名集合(不包含默认值)
     * @return {string[]} 属性名集合
     */
    function getOwnPropertyNames() {
        
        var storage = this.__storage,
            defaults,
            any;

        if (storage)
        {
            if (any = Object.getOwnPropertyNames)
            {
                return any(storage);
            }

            defaults = this.__defaults;
            any = [];

            for (var name in storage)
            {
                if (storage[name] !== defaults[name])
                {
                    any.push(name);
                }
            }

            return any;
        }

        return [];
    };


     /**
     * @method dispose
     * @for Class
     * @description 销毁对象
     * @return {object} 当前实例对象
     */
    function dispose() {

        if (this.__events)
        {
            this.off();
        }

        return this;
    };
    


    /**
     * @static
     * @method register
     * @for Class
     * @description 注册类
     * @param {string=} name 注册名称, 省略时默认以类名注册
     * @param {boolean=} force 名称已经注册过时是否强制覆盖
     * @return {Class} 当前类
     */
    function register(name, force) {
    
        if (name || (name = this.typeName))
        {
            if (!force && components[name])
            {
                throw 'component "' + name + '" has exist';
            }

            return components[this.nickName = name] = this;
        }

        return this;
    };
    


    /**
     * @method defaultValue
     * @for flyingon
     * @description 获取或修改指定类的默认值
     * @param {Class} Class 指定的目标类
     * @param {string} name 属性名
     * @param {any=} value 默认值, 未传入时表示读取默认值, 否则表示设置默认值
     */
    flyingon.defaultValue = function (Class, name, value) {

        var properties = (Class = Class.prototype || Class).__properties,
            any;

        if (properties && (any = properties[name]))
        {
            if (value === void 0)
            {
                return any.defaultValue;
            }

            if (typeof value !== any.dataType)
            {
                throw 'type is defferent!';
            }

            any.defaultValue = Class.__defaults[name] = value;
        }
    };


    
    //输出全局事件方法

    /**
     * @method on
     * @for flyingon
     * @description 绑定事件处理 注:type不带on
     * @param {string} type 事件类型
     * @param {function=} fn 事件处理方法
     * @return {object} 当前实例对象
     */
    flyingon.on = on;

    /**
     * @method once
     * @for flyingon
     * @description 绑定事件处理, 执行一次后自动移除绑定 注:type不带on
     * @param {string} type 事件类型
     * @param {function=} fn 事件处理方法
     * @return {object} 当前实例对象
     */
    flyingon.once = once;

    /**
     * @method off
     * @for flyingon
     * @description 移除事件处理
     * @param {string=} type 事件类型, 不传值时表示移除所有事件处理
     * @param {function=} fn 事件处理方法, 不传值时表示移除指定类型的所有事件处理
     * @return {object} 当前实例对象
     */
    flyingon.off = off;
    
    /**
     * @method trigger
     * @for flyingon
     * @description 分发事件
     * @param {(string|flyingon.Event)=} e 事件参数
     * @param {...any=} 自定义事件参数 按name, value的方式传入
     * @return {boolean} 是否阻止默认处理
     * @example
     * //分发类型为test的事件(有一个自定义的data参数, 值为1)
     * flyingon.trigger('test', 'data', 1);
     */
    flyingon.trigger = trigger;
    
    

})(flyingon);



/**
 * @class flyingon.Event
 * @description 事件基类
 */
Object.extend('Event', function () {

    

    this.init = function (type) {

        this.type = type;
    };
    
    
    
    /**
     * @readonly
     * @property type
     * @type {string}
     * @description 事件类型
     */
    this.type = null;


    /**
     * @readonly
     * @property target
     * @type {object}
     * @description 触发事件目标对象
     */
    this.target = null;


    /**
     * @readonly
     * @property cancelBubble
     * @type {boolean}
     * @description 是否取消冒泡
     */
    this.cancelBubble = false;

    
    /**
     * @readonly
     * @property defaultPrevented
     * @type {boolean}
     * @description 是否阻止默认动作
     */
    this.defaultPrevented = false;


    /**
     * @method stop
     * @description 停止事件冒泡
     * @param {boolean} prevent 是否同时禁止默认事件处理
     * @return {object} 当前对象实例
     */
    this.stop = function (prevent) {

        this.cancelBubble = true;
        prevent && (this.defaultPrevented = true);
        
        if (arguments[1] !== false && this.original_event)
        {
            flyingon.dom_stop(this.original_event, prevent);
        }

        return this;
    };


    /**
     * @method prevent
     * @description 禁止默认事件处理
     * @return {object} 当前对象实例
     */
    this.prevent = function () {

        this.defaultPrevented = true;
        
        if (arguments[0] !== false && this.original_event)
        {
            flyingon.dom_prevent(this.original_event);
        }

        return this;
    };

    
    
}, false);




//编码对象
flyingon.encode = function encode(data) {

    if (!data)
    {
        return '';
    }

    var list = [],
        fn = encodeURIComponent,
        value,
        any;

    for (var name in data)
    {
        value = data[name];
        name = fn(name);

        if (value === null)
        {
            list.push(name, '=null', '&');
            continue;
        }

        switch (typeof value)
        {
            case 'undefined':
                list.push(name, '=&');
                break;

            case 'boolean':
            case 'number':
                list.push(name, '=', value, '&');
                break;

            case 'string':
            case 'function':
                list.push(name, '=', fn(value), '&');
                break;

            default:
                if (value instanceof Array)
                {
                    for (var i = 0, l = value.length; i < l; i++)
                    {
                        if ((any = value[i]) === void 0)
                        {
                            list.push(name, '=&');
                        }
                        else
                        {
                            list.push(name, '=', fn(any), '&'); //数组不支持嵌套
                        }
                    }
                }
                else
                {
                    list.push(name, '=', encode(value), '&');
                }
                break;
        }
    }

    list.pop();
    return list.join('');
};
    
    

//html编码函数
flyingon.html_encode = (function () {
    
    var map = flyingon.create(null);

    map['&'] = '&amp;';
    map['<'] = '&lt;';
    map['>'] = '&gt;';
    map['\''] = '&apos;';
    map['"'] = '&quot;';

    return function (text) {

        if (text && typeof text === 'string')
        {
            var keys = map;

            return text.replace(/([&<>'"])/g, function (_, key) {

                return keys[key];
            });
        }

        return '' + text;
    };

})();


//html解码函数
flyingon.html_decode = (function () {
    
    var map = flyingon.create(null);

    map['amp'] = '&';
    map['lt'] = '<';
    map['gt'] = '>';
    map['apos'] = '\'';
    map['quot'] = '"';

    return function (text) {

        var keys = map;

        return text && text.replace(/&(\w+);/g, function (_, key) {

            return keys[key] || key;
        });
    };

})();



flyingon.parseJSON = typeof JSON !== 'undefined' 

    ? function (text) {

        return JSON.parse(text);
    }

    : function (text) {

        if (typeof text === 'string')
        {
            if (/[a-zA-Z_$]/.test(text.replace(/"(?:\\"|[^"])*?"|null|true|false|\d+[Ee][-+]?\d+/g, '')))
            {
                throw 'json parse error!';
            }

            return new Function('return ' + text)();
        }

        return text;
    };




/**
 * @class flyingon.Async
 * @description 异步处理类
 */
flyingon.Async = Object.extend(function () {


    
    /**
     * @method sleep
     * @description 延时
     * @param {int} time 延时时间
     * @param {function} [done] 延时成功后调用方法
     * @param {function} [fail] 延时失败后调用方法
     * @return {object} 当前实例对象
     */
    this.sleep = function (time, done, fail) {
        
        if (done !== false || fail !== false)
        {
            var fn = function (value) {

                var as = new flyingon.Async();

                setTimeout(function () {

                    as.resolve(value);
                    as = null;

                }, time | 0);

                return as;
            };
            
            done = done !== false ? 1 : 0;
            
            if (fail !== false)
            {
                done += 2;
            }

            return registry(this, false, fn, done);
        }
                            
        return this;
    };
    
       
    /**
     * @method done
     * @description 注册成功执行函数或异步通知
     * @param {boolean} [asyn] 是否异步
     * @param {function} fn 调用方法
     * @return {object} 当前实例对象
     */
    this.done = function (asyn, fn) {

        return registry(this, asyn, fn, 1);
    };


    /**
     * @method fail
     * @description 注册执行失败函数或异步通知
     * @param {boolean} [asyn] 是否异步
     * @param {function} fn 调用方法
     * @return {object} 当前实例对象
     */
    this.fail = function (asyn, fn) {

        return registry(this, asyn, fn, 2);
    };
    
    
    /**
     * @method complete
     * @description 注册执行完毕函数或异步通知
     * @param {boolean} [asyn] 是否异步
     * @param {function} fn 调用方法
     * @return {object} 当前实例对象
     */
    this.complete = function (asyn, fn) {
        
        return registry(this, asyn, fn, 3);
    };


    //注册回调函数
    function registry(self, asyn, fn, state) {

        if (!fn)
        {
            fn = asyn;
            asyn = false;
        }
        
        if (fn)
        {
            var list = self.__list || (self.__list = []);

            list.push([asyn, fn, state, 0]);

            if (self.__state)
            {
                check_done(self);
            }
        }
        
        return self;
    };
    
    
    /**
     * @method resolve
     * @description 成功执行通知
     * @param {any} value 自定义通知参数
     * @return {object} 当前实例对象
     */
    this.resolve = function (value) {

        return complete(this, 1, value);
    };


    /**
     * @method reject
     * @description 失败执行通知
     * @param {string} error 错误信息
     * @param {boolean} [bubble] 是否向上冒泡
     * @return {object} 当前实例对象
     */
    this.reject = function (error, bubble) {
        
        this.bubble = bubble; //是否向上冒泡
        return complete(this, 2, void 0, error);
    };
    
        
    function complete(self, state, value, error) {
        
        var list = self.__list;
        
        self.__state = state;
        self.__value = value;
        self.__error = error;
        
        check_done(self);

        return self;
    };
        

    //检测是否完结
    function check_done(self) {
      
        var list = self.__list,
            index = 0,
            item,
            as;

        if (list)
        {
            while (item = list[index++])
            {
                //同步阻塞则退出
                if (!item[0] && (index > 1 || item[3]))
                {
                    return;
                }
                
                //异步等待且正在等待异步返回则继续处理下一条
                if (item[3])
                {
                    continue;
                }
                
                //执行
                if (typeof (as = item[1]) === 'function')
                {
                    try
                    {
                        switch (item[2])
                        {
                            case 1:
                                as = self.__state === 1 && as.call(self, self.__value);
                                break;
                                
                            case 2:
                                as = self.__state === 2 && as.call(self, self.__error);
                                break;
                                
                            case 3:
                                as = as.call(self, self.__value, self.__error);
                                break;
                        }
                    }
                    catch (e) //执行出错先移除当前项然后继续错误处理
                    {
                        self.__state = 2;
                        self.__error = e;
                        
                        //清除出错前的所有项
                        list.splice(0, index);
                        index = 0;
                        
                        continue;
                    }
                }
                
                //如果执行结果是异步
                if (as && as['flyingon.Async'] && !as.__state)
                {
                    //标记正在等待异步返回
                    item[3] = 1;
                    (as.__back_list || (as.__back_list = [])).push(list, item, self);
                }
                else
                {
                    list.splice(--index, 1);
                }
            }
            
            if (list.length > 0)
            {
                return;
            }
            
            index = 0;
        }
        
        //回溯检测
        if (list = self.__back_list)
        {
            while (item = list[index++])
            {
                item.splice(item.indexOf(list[index++]), 1);
                item = list[index++];
                
                //如果失败且未停止冒泡则向上传递错误信息
                if (self.__error && self.bubble)
                {
                    item.__state = 2;
                    item.__error = self.__error;
                }
                
                check_done(item);
            }
            
            list.length = 0;
            self.__back_list = null;
        }
    };
    


     /**
     * @method progress
     * @description 注册执行进度函数
     * @param {function} fn 执行函数
     * @return {object} 当前实例对象
     */
    this.progress = function (fn) {

        if (typeof fn === 'function')
        {
            (this.__progress || (this.__progress = [])).push(fn);
        }
        
        return this;
    };


     /**
     * @method notify
     * @description 执行进度通知
     * @param {any} value 自定义参数
     * @return {object} 当前实例对象
     */
    this.notify = function (value) {

        var list = this.__progress;
        
        if (list)
        {
            for (var i = 0, l = list.length; i < l; i++)
            {
                list[i].call(this, value);
            }
        }
        
        return this;
    };
    
    
}, false);

    

/**
 * @method delay
 * @for flyingon
 * @description 异步延时处理
 * @param {int} [delay] 指定延时时间
 * @param {function} fn 执行函数
 * @return {object} 当前实例对象
 */
flyingon.delay = function (delay, fn) {

    var as = new flyingon.Async();

    setTimeout(function () {

        if (typeof fn === 'function')
        {
            fn.call(as);
            fn = null;
        }
        else
        {
            as.resolve();
        }

        as = null;

    }, delay | 0);

    return as;
};




//扩展数组方法
(function () {


    //转换数组项为键值对
    this.pair = function (value) {

        var map = flyingon.create(null);

        if (value === void 0)
        {
            value = true;
        }

        for (var i = 0, l = this.length; i < l; i++)
        {
            map[this[i]] = value;
        }

        return map;
    };


    this.indexOf || (this.indexOf = function (item, index) {

        if ((index |= 0) < 0)
        {
            return -1;
        }

        var length = this.length;

        while (index < length)
        {
            if (this[index] === item)
            {
                return index;
            }

            index++;
        }

        return -1;
    });


    this.lastIndexOf || (this.lastIndexOf = function (item, index) {

        if ((index |= 0) > 0)
        {
            return -1;
        }

        if (!index)
        {
            if (arguments.length > 1)
            {
                return -1;
            }

            index = -1;
        }

        index += this.length;

        while (index >= 0)
        {
            if (this[index] === item)
            {
                return index;
            }

            index--;
        }

        return -1;
    });


    this.forEach || (this.forEach = function (fn) {

        var context = arguments[1];

        for (var i = 0, l = this.length; i < l; i++)
        {
            fn.call(context, this[i], i, this);
        }
    });


    this.map || (this.map = function (fn) {

        var context = arguments[1],
            length = this.length,
            list = new Array(length);

        for (var i = 0; i < length; i++)
        {
            list[i] = fn.call(context, this[i], i, this);
        }

        return list;
    });


    this.filter || (this.filter = function (fn) {

        var context = arguments[1],
            list = [];

        for (var i = 0, l = this.length; i < l; i++)
        {
            if (fn.call(context, this[i], i, this))
            {
                list.push(this[i]);
            }
        }

        return list;
    });


    this.some || (this.some = function (fn) {

        var context = arguments[1];

        for (var i = 0, l = this.length; i < l; i++)
        {
            if (fn.call(context, this[i], i, this))
            {
                return true;
            }
        }

        return false;
    });


    this.every || (this.every = function (fn) {

        var context = arguments[1];

        for (var i = 0, l = this.length; i < l; i++)
        {
            if (!fn.call(context, this[i], i, this))
            {
                return false;
            }
        }

        return true;
    });


    this.reduce || (this.reduce = function (fn) {

        var value = arguments[1],
            index = 0, 
            length = this.length;

        if (value === void 0)
        {
            value = this[0];
            index = 1;
        }
        
        while (index < length)
        {
            value = fn(value, this[index], index++, this);
        }

        return value;
    });


    this.reduceRight || (this.reduceRight = function (fn) {

        var value = arguments[1],
            index = this.length - 1;

        if (value === void 0)
        {
            value = this[index--];
        }
        
        while (index >= 0)
        {
            value = fn(value, this[index], index--, this);
        }

        return value;
    });
  


}).call(Array.prototype);




Function.prototype.bind || (Function.prototype.bind = function (context) {

    var fn = this;

    if (arguments.length > 1)
    {
        var list = [].slice.call(arguments, 1),
            push = list.push;

        return function () {

            var data = list.slice(0);

            if (arguments.length > 0)
            {
                push.apply(data, arguments);
            }

            return fn.apply(context || this, data);
        };
    }

    return function () {

        return fn.apply(context || this, arguments);
    };
});



(function () {
    

    var regex = /([yMdhmsSq]+)/g;
    
    var keys1 = {
    
        'GMT': 'toGMTString',
        'ISO': 'toISOString',
        'UTC': 'toUTCString',
        'date': 'toDateString',
        'time': 'toTimeString',
        'locale': 'toLocaleString',
        'locale-date': 'toLocaleDateString',
        'locale-time': 'toLocaleTimeString'
    };

    var keys2 = {

        'y': 'getFullYear',
        'd': 'getDate',
        'h': 'getHours',
        'm': 'getMinutes',
        's': 'getSeconds',
        'S': 'getMilliseconds'
    };


    this.format = function (format) {

        var any;

        if (format)
        {
            if (any = keys1[format])
            {
                return this[any]();
            }

            any = this;

            return format.replace(regex, function (_, text) {

                var length = text.length;

                switch (text = text.charAt(0))
                {
                    case 'M':
                        text = any.getMonth() + 1;
                        break;

                    case 'q':
                        text = (any.getMonth() + 3) / 3 | 0;
                        break;

                    default:
                        text = any[keys2[text]]();
                        break;
                }

                text = '' + text;

                if (length === 1 || (length -= text.length) <= 0)
                {
                    return text;
                }

                //substr负索引有IE7下有问题
                return '0000'.substring(0, length) + text;
            });
        }
        
        return this.toString();
    };


    this.addYear = function (value) {

        this.setFullYear(this.getFullYear() + (value | 0));
        return this;
    };


    this.addMonth = function (value) {

        this.setMonth(this.getMonth() + (value | 0));
        return this;
    };


    this.addDate = function (value) {

        this.setDate(this.getDate() + (value | 0));
        return this;
    };



    //解决不同浏览器对字符串解析不同的问题(不同浏览器之间存在很多差别)
    //比如IE不支持new Date('2017-1-1 1:1:1')
    Date.create = function (value) {

        if (value)
        {
            var date = new Date(value),
                any = date.valueOf();

            if (any === any)
            {
                return date;
            }

            if (typeof value === 'string' && (value = value.match(/\d+/g)))
            {
                any = value[1] | 0;
                return new Date(value[0], any > 0 ? any - 1 : 0, value[2] | 0, value[3] | 0, value[4] | 0, value[5] | 0);
            }
        }

        return null;
    };



}).call(Date.prototype);




/**
 * @class f-collection
 * @extension
 * @description 集合功能片段
 */
flyingon.fragment('f-collection', function () {



    var array = Array.prototype;



    /**
     * @property length
     * @type {int}
     * @description 子项总数量
     */
    this.length = 0;


    /**
     * @method indexOf
     * @description 获取指定子项的索引号(与数组同名方法相同)
     * @param {any} item 子项
     * @return {int} 索引号, -1表示不存在
     */

    /**
     * @method lastIndexOf
     * @description 从后向前获取指定子项的索引号(与数组同名方法相同)
     * @param {any} item 子项
     * @return {int} 索引号, -1表示不存在
     */
    this.indexOf = this.lastIndexOf = [].indexOf;



    /**
     * @method push
     * @description 在集合的末尾添加一个或多个子项(与数组同名方法相同)
     * @param {...*} item 子项
     * @return {int} 子项总数量
     */
    this.push = function () {

        if (arguments.length > 0)
        {
            this.__check_items(this.length, arguments, 0);
            array.push.apply(this, arguments);
        }

        return this.length;
    };


    /**
     * @method pop
     * @description 弹出最后一个子项(与数组同名方法相同)
     * @return {any} 弹出的子项
     */
    this.pop = function () {
        
        var item = array.pop.call(this);

        if (item)
        {
            this.__remove_items(this.length - 1, [item]);
        }

        return item;
    };


    /**
     * @method unshift
     * @description 在集合的开始位置插入一个或多个子项(与数组同名方法相同)
     * @param {...any} item 子项
     * @return {int} 子项总数量
     */
    this.unshift = function () {

        if (arguments.length > 0)
        {
            this.__check_items(0, arguments, 0);
            array.unshift.apply(this, arguments);
        }

        return this.length;
    };


    /**
     * @method shift
     * @description 弹出第一个子项(与数组同名方法相同)
     * @return {any} 弹出的子项
     */
    this.shift = function () {
        
        var item = array.shift.call(this);

        if (item)
        {
            this.__remove_items(0, [item]);
        }

        return item;
    };


    /**
     * @method splice
     * @description 在集合的指定位置移除或插入一个或多个子项(与数组同名方法相同)
     * @param {int} index 索引号
     * @param {int=} length 要移除的子项数量 
     * @param {...*=} item 要插入的子项
     * @return {object[]} 移除的子项集合
     */
    this.splice = function (index, length) {
            
        var any = this.length;

        if (arguments.length > 2)
        {
            if ((index |= 0) < 0)
            {
                index += any;
            }

            if (index < 0)
            {
                index = 0;
            }
            else if (index > any)
            {
                index = any;
            }

            this.__check_items(index, arguments, 2);
            
            any = array.splice.apply(this, arguments);
        }
        else //注:IE8不支持 array.splice(0)清空所有项,必须指明长度
        {
            any = array.splice.call(this, 0, length === void 0 ? any : length);
        }

        if (any.length > 0)
        {
            this.__remove_items(index, any);
        }

        return any;
    };

        

    //增加子项前检测处理
    this.__check_items = function (index, items, start) {
    };


    //移除子项处理
    this.__remove_items = function (index, items) {
    };


    
    /**
     * @method children
     * @description 获取子项集合
     * @return {object[]} 子项集合
     */
    this.children = function () {

        return array.slice.call(this, 0);
    };



});




//序列化功能扩展
flyingon.fragment('f-serialize', function () {
    
    
       
    //设置不反序列化Class属性
    this.deserialize_Class = true;
    
    
    
    //序列化方法
    this.serialize = function (writer) {

        var any;
        
        if ((any = this.Class) && (any = any.nickName || any.Class))
        {
            writer.writeProperty('Class', any);
        }
        
        if (any = this.__storage)
        {
            writer.writeProperties(any, this.getOwnPropertyNames(), this.__watches);
        }
    };
    
        
    //反序列化方法
    this.deserialize = function (reader, values) {

        var bind = this.addBind,
            value,
            any;
        
        for (var name in values)
        {
            if ((value = values[name]) === void 0)
            {
                continue;
            }
            
            if (bind && typeof value === 'string' && value.charAt(0) === '{' && (any = value.match(/^\{\{(\w+)\}\}$/)))
            {
                this.addBind(name, any[1]);
            }
            else if (any = this['deserialize_' + name])
            {
                if (any !== true)
                {
                    any.call(this, reader, value);
                }
            }
            else
            {
                this.set(name, value);
            }
        }
    };


});



//读序列化类
flyingon.SerializeReader = Object.extend(function () {

    

    var components = flyingon.components;
    
    var Array = window.Array;
    
    

    this.deserialize = function (data) {

        if (data)
        {
            if (typeof data === 'string')
            {
                data = flyingon.parseJSON(data);
            }

            if (typeof data === 'object')
            {
                data = data instanceof Array ? this.readArray(data) : this.readObject(data);
                this.all = this.callback = null;
            }
        }

        return data;
    };


    this.readArray = function (data, type) {

        if (data)
        {
            var array = [],
                any;

            for (var i = 0, l = data.length; i < l; i++)
            {
                if ((any = data[i]) && typeof any === 'object')
                {
                    if (type || !(any instanceof Array))
                    {
                        any = this.readObject(any, type);
                    }
                    else
                    {
                        any = this.readArray(any);
                    }
                }

                array.push(any);
            }

            return array;
        }

        return null;
    };


    this.readObject = function (data, type) {

        if (data)
        {
            var target, any;

            if (any = data.Class)
            {
                if (any = components[any])
                {
                    target = new any();
                }
                else
                {
                    target = new flyingon.HtmlElement();
                    target.tagName = data.Class;
                }

                target.deserialize(this, data);
                
                if (any = data.id)
                {
                    read_reference.call(this, target, any);
                }
            }
            else if (type)
            {
                if ((target = new type()).deserialize)
                {
                    target.deserialize(this, data);
                    
                    if (any = data.id)
                    {
                        read_reference.call(this, target, any);
                    }
                }
                else
                {
                    this.readProperties(target, data); 
                }
            }
            else
            {
                this.readProperties(target = {}, data); 
            }
            
            return target;
        }

        return null;
    };
    
    
    function read_reference(target, id) {
        
        var list = this.callback;
        
        (this.all || (this.all = {}))[id] = target;

        if (list && (list = list[id]))
        {
            for (var i = 0, l = list.length; i < l; i++)
            {
                list[i](target);
            }

            list[id] = target = null;
        }
    };

    
    this.readProperties = function (target, data) {
      
        var any;

        for (var name in data)
        {
            if ((any = data[name]) && typeof any === 'object')
            {
                any = any instanceof Array ? this.readArray(any) : this.readObject(any);
            }

            target[name] = any;
        }
    };
    
    
    this.readReference = function (name, callback) {
      
        var all = this.all,
            any;
        
        if (all && (any = all[name]))
        {
            callback(any);
        }
        else if (any = this.callback)
        {
            (any[name] || (any[name] = [])).push(callback);
        }
        else
        {
            (this.callback = {})[name] = [callback];
        }
    };
      
        

}, false);



//写序列化类
flyingon.SerializeWriter = Object.extend(function () {


    
    var Array = window.Array;
    
    var id = 1;
    
    
    
    this.serialize = function (value) {

        if (value && typeof value === 'object')
        {
            var data = this.data = [];
            
            if (value instanceof Array)
            {
                this.writeArray(value);
            }
            else
            {
                this.writeObject(value);
            }

            data.pop();
            
            return data.join('');
        }
        
        return '' + value;
    };


    this.write = function (value) {

        if (value != null)
        {
            switch (typeof value)
            {
                case 'boolean':
                    this.data.push(value ? true : false, ',');
                    break;

                case 'number':
                    this.data.push(+value || 0, ',');
                    break;

                case 'string':
                    this.data.push('"', value.replace(/"/g, '\\"'), '"', ',');
                    break;
                    
                case 'function':
                    this.data.push('"', ('' + value).replace(/"/g, '\\"'), '"', ',');
                    break;

                default:
                    if (value instanceof Array)
                    {
                        this.writeArray(value);
                    }
                    else
                    {
                        this.writeObject(value);
                    }
                    break;
            }
        }
        else
        {
            this.data.push(null, ',');
        }
    };


    this.writeArray = function (value) {

        var data = this.data,
            length;
        
        if (value != null)
        {
            if ((length = value.length) > 0)
            {
                data.push('[');
                
                for (var i = 0; i < length; i++)
                {
                    this.write(value[i]);
                }
                
                data.pop();
                data.push(']', ',');
            }
            else
            {
                data.push('[]', ',');
            }
        }
        else
        {
            data.push(null, ',');
        }
    };


    this.writeObject = function (value) {

        var data = this.data;
        
        if (value != null)
        {
            if (value instanceof Date)
            {
                writer.push('"', value, '"', ',');
                return;
            }

            data.push('{');

            if (value.serialize)
            {
                value.serialize(this);
            }
            else
            {
                for (var name in value)
                {
                    data.push('"', name, '":');
                    this.write(value[name]);
                }
            }

            data.push(data.pop() === ',' ? '}' : '{}', ',');
        }
        else
        {
            data.push(null, ',');
        }
    };


    this.writeProperties = function (storage, keys, watches) {

        var data = this.data,
            name,
            any;
        
        for (var i = 0, l = keys.length; i < l; i++)
        {
            name = keys[i];
            
            if (watches && (any = watches[name]) && (any = any[0]))
            {
                data.push('"', name, '":"{{', any.replace(/"/g, '\\"'),'}}"', ',');
            }
            else
            {
                data.push('"', name, '":');
                this.write(storage[name]);
            }
        }
    };
    
    
    this.writeProperty = function (name, value, array) {
      
        if (name)
        {
            this.data.push('"', name, '":');

            if (array)
            {
                this.writeArray(value);
            }
            else
            {
                this.write(value);
            }
        }
    };
    
    
    this.writeReference = function (name, value) {
        
        if (name && value)
        {
            var id = value.id;
            
            if (id && typeof id === 'function')
            {
                id = id();
            }
            
            this.data.push('"', name, '":', id || ('__auto_id_' + id++));
        }
    };

    

}, false);




/**
 * @class flyingon.Dropdown
 * @description 数据列表, 主要给列表框, 下拉框及下拉树或需要翻译的地方等使用
 */
(function (Class) {


    //等待注册集合
    var wait = Class.wait = flyingon.create(null);

    
    //注册的所有数据列表集合
    Class.all = flyingon.create(null);


    //根据列表创建DataList
    Class.create = function (list, callback, context) {

        if (list)
        {
            var any;

            if (list instanceof Class)
            {
                callback && callback.call(context, list);
                return list;
            }

            if (typeof list === 'string')
            {
                if (any = Class.all[list])
                {
                    callback && callback.call(context, any);
                }
                else if (callback)
                {
                    (wait[name] || (wait[name] = [])).push(callback, context);
                }

                return any;
            }

            list = list instanceof Array ? list : (list == null ? [] : [list]);

            if ((any = list[0]) && typeof any === 'object')
            {
                any = create(any);
            }
            else
            {
                any = new flyingon.DataList();
            }

            any.load(list);

            callback && callback.call(context, any);
            return any;
        }
    };


    function create(item) {

        var keys = [];

        if ('value' in item)
        {
            keys.push('value');

            if ('text' in item)
            {
                keys.push('text');
            }
        }

        for (var name in item)
        {
            keys.push(name);

            if (keys.length > 1)
            {
                break;
            }
        }

        return new flyingon.DataList(name = keys[0] || 'value', keys[1] || name);
    };



})(flyingon.DataList = Object.extend(function () {
    

    
    var wait = this.Class.wait;

    var array = Array.prototype;



    this.init = function (valueField, displayField) {

        if (this.valueField = valueField || '')
        {
            this.displayField = displayField || valueField;
            this.keys = flyingon.create(null);
        }
        else
        {
            this.displayField = '';
        }
    };



    this.length = 0;
    

    this.load = function (list, childrenName) {

        var keys;

        if (list && list.length > 0)
        {
            array.push.apply(this, list);

            if (keys = this.keys)
            {
                append_keys(keys, this.valueField, list, childrenName);
            }

            this.trigger('load');
        }

        return this;
    };



    function append_keys(keys, field, list, children) {

        for (var i = 0, l = list.length; i < l; i++)
        {
            var item = list[i],
                any;

            if (item && (any = item[field]) != null)
            {
                keys[any] = item;

                if (children && (any = item[children]) && any.length > 0)
                {
                    append_keys(keys, field, any, children);
                }
            }
        }
    };



    this.clear = function () {

        if (this.keys)
        {
            this.keys = flyingon.create(null);
        }

        array.splice.call(this, 0);
        return this;
    };


    //获取指定项的值
    this.value = function (item) {

        var field = this.valueField;
        return field ? (item ? item[field] : '') : item;
    };


    //获取指定值对应的显示文本
    this.text = function (value, separator, separator2) {

        var keys = this.keys;
        
        if (keys)
        {
            var field = this.displayField,
                any;

            if (separator)
            {
                value = value ? value.split(separator) : [value];

                for (var i = 0, l = value.length; i < l; i++)
                {
                    value[i] = (any = keys[value[i]]) && any[field] || '';
                }

                return value.join(separator2 || separator);
            }

            if (any = keys[value])
            {
                return field ? any[field] : any;
            }
        }

        return value;
    };


    //根据值指定值查找下拉项
    this.find = function (value) {

        var keys = this.keys;
        return keys ? keys[value] : value;
    };


    //根据指定值查询多个下拉项
    this.select = function (value, separator) {

        var keys = this.keys;

        value = keys ? value.split(separator || ',') : [value];

        if (keys)
        {
            for (var i = 0, l = value.length; i < l; i++)
            {
                value[i] = keys[value[i]];
            }
        }

        return value;
    };


    /**
     * 注册
     */
    this.register = function (name, force) {
        
        if (name)
        {
            var any = Class.all;
    
            if (!force && any[name])
            {
                throw 'register name "' + name + '" has exist!';
            }
    
            any[name] = this;

            if (any = wait[name])
            {
                delete wait[name];

                for (var i = any.length - 1; i >= 0; i--)
                {
                    wait[i++].call(wait[i], this);
                }
            }
        }

        return this;
    };


    this.dispose = function () {

        this.keys = null;
        array.splice.call(this, 0);
    };
    

}, false));




//行集合类
flyingon.RowCollection = Object.extend._(function () {
    

    //记录数
    this.length = 0;

    
    //查找数据行
    this.find = function (filter) {
    
        var list = new flyingon.RowCollection(),
            index = 0,
            length = this.length,
            row;
        
        for (var i = 0; i < length; i++)
        {
            if ((row = this[i]) && (!filter || filter(row)))
            {
                list[index++] = row;
            }
        }
        
        list.length = index;
        return list;
    };
    
        
    //查找所有下级行
    this.findAll = function (filter) {

        var list = arguments[1] || new flyingon.RowCollection(),
            row;
        
        for (var i = 0, l = this.length; i < l; i++)
        {
            if ((row = this[i]) && (!filter || filter(row)))
            {
                list[list.length++] = row;
            }
            
            if (row.length > 0)
            {
                row.findAll(filter, list);
            }
        }
        
        return list;
    };
    
            
    this.toJSON = function (change, names) {
        
        var writer = ['['],
            row,
            data,
            tag,
            any;
        
        if (change && names)
        {
            if (typeof names === 'string')
            {
                names = names.match(/\w+/g);
            }
            
            names = names && names.length > 0 ? new RegExp('^(' + names.join('|') + ')$', 'i') : null;
        }
        
        for (var i = 0, l = this.length; i < l; i++)
        {
            if ((row = this[i]) && (data = row.data))
            {
                if (tag)
                {
                    writer.push(',');
                }
                else
                {
                    tag = true;
                }
                
                if (change && (any = row.originalData))
                {
                    write_change(writer, data, any, names, this.tables);
                }
                else
                {
                    write_object(writer, data);
                }
            }
        }
        
        writer.push(']');
        
        return writer.join('');
    };
    
    
    function write_object(writer, data) {
        
        var tag;
        
        writer.push('{');
        
        for (var name in data)
        {
            if (tag)
            {
                writer.push(',');
            }
            else
            {
                tag = true;
            }
            
            writer.push('"', name, '":');
            write_value(writer, data[name]);
        }
        
        writer.push('}');
    };
    
    
    function write_array(writer, data) {
        
        writer.push('[');
        
        for (var i = 0, l = data.length; i < l; i++)
        {
            if (i > 0)
            {
                writer.push(',');
            }

            write_value(writer, data[i]);
        }
        
        writer.push(']');
    };
    
    
    function write_value(writer, value) {
    
        if (value == null)
        {
            writer.push('null');
            return;
        }

        switch (typeof value)
        {
            case 'string':
                writer.push('"', value.replace(/"/g, '\\"'), '"');
                break;

            case 'object':
                if (value instanceof Array)
                {
                    write_array(writer, value);
                }
                else if (value instanceof Date)
                {
                    writer.push('"', value, '"');
                }
                else
                {
                    write_object(writer, value);
                }
                break;

            default:
                writer.push(value);
                break;
        }
    };
    
    
    function write_change(writer, data, originalData, names, tables) {
        
        var value, oldValue;
        
        writer.push('{');
        
        for (var name in data)
        {
            value = data[name];
            oldValue = originalData[name];
            
            if (value !== oldValue || names && names.test(name))
            {
                if (value == null)
                {
                    writer.push('"', name, '":null', ',');
                    continue;
                }
                
                switch (typeof value)
                {
                    case 'string':
                        writer.push('"', name, '":"', value.replace(/"/g, '\\"'), '"', ',');
                        break;

                    case 'object':
                        if (tables && (oldValue = tables[name]))
                        {
                            oldValue = oldValue.toJSON(true);
                            
                            if (oldValue.length > 2)
                            {
                                writer.push('"', name, '":', oldValue, ',');
                            }
                        }
                        else 
                        {
                            writer.push('"', name, '":');
                            
                            if (value instanceof Array)
                            {
                                write_array(writer, value);
                            }
                            else if (value instanceof Date)
                            {
                                writer.push('"', value, '"');
                            }
                            else
                            {
                                write_object(writer, value);
                            }
                            
                            writer.push(',');
                        }
                        break;

                    default:
                        writer.push('"', name, '":', value, ',');
                        break;
                }
            }
        }
        
        writer.push(writer.pop() === ',' ? '}' : '{}');
    };
    
    
});



//数据集功能片段
flyingon.fragment('f-dataset', function () {
    
    
        
    /**
     * 加载数据
     * @param {object[]} list 数据列表
     * @param {string} [primaryKey] 主键
     * @param {string} [children] 树型数据的子项属性名, 传入此值则当作树型数据解析
     * @return {object} 当前实例对象
     */
    this.load = function (list, primaryKey, children) {
        
        if (list && list.length > 0)
        {
            var dataset = this.dataset,
                parent = dataset ? this : null;

            dataset = dataset || this;
        
            dataset.__new_id = load_data(dataset, 
                parent, 
                list, 
                dataset.primaryKey = primaryKey, 
                children, 
                dataset.__new_id++);
            
            dataset.trigger('load', 'parent', parent);
        }
        
        return this;
    };
    
    
    function load_data(dataset, parent, list, primaryKey, children, uniqueId) {
        
        var target = parent || dataset,
            rowType = flyingon.DataRow,
            keys1 = dataset.__keys1,
            keys2 = dataset.__keys2,
            index = target.length,
            length = list.length,
            data,
            row,
            id;
            
        for (var i = 0; i < length; i++)
        {
            row = new rowType();
            row.dataset = dataset;
            
            if (parent)
            {
                row.parent = parent;
            }
            
            row.data = data = list[i] || {};
            
            keys1[row.uniqueId = uniqueId++] = row;
            
            if (primaryKey)
            {
                keys2[row.id = data[primaryKey]] = row;
            }
                        
            target[index++] = row;
            
            if (children && (data = data[children]) && data.length > 0)
            {
                uniqueId = load_data(dataset, row, data, primaryKey, null, children, uniqueId)
            }
        }

        target.length = index;
        
        return uniqueId;
    };

            

    //扩展集合操作功能
    flyingon.fragment('f-collection', this);
    
    
    //插入子项
    this.__check_items = function (index, items, start) {

        var Class = flyingon.DataRow,
            rows = [],
            dataset = this.dataset,
            parent = null,
            keys1,
            keys2,
            primaryKey,
            row,
            data;
                
        if (dataset)
        {
            parent = this;
        }
        else
        {
            dataset = this;
        }

        keys1 = dataset.__keys1;
        keys2 = (primaryKey = dataset.primaryKey) && dataset.__keys2;

        for (var i = start, l = items.length; i < l; i++)
        {
            if ((data = items[i]) && data.dataset)
            {
                row = data;
            }
            else
            {
                row = new Class();
            
                row.dataset = dataset;
                row.parent = parent;
                row.data = data = data || {};
                row.state = 'add';
            }
            
            keys1[row.uniqueId = dataset.__new_id++] = row;
            
            if (primaryKey)
            {
                keys2[row.id = data[primaryKey]] = row;
            }
        
            dataset.__change_rows.push(row);
            rows.push(row);
        }

        dataset.trigger('add', 'parent', parent, 'index', index, 'rows', rows);
    };


    //移除子项
    this.__remove_items = function (index, items) {

        var dataset = this.dataset,
            parent = null,
            keys1,
            keys2,
            primaryKey,
            row;
                    
        if (dataset)
        {
            parent = this;
        }
        else
        {
            dataset = this;
        }

        keys1 = dataset.__keys1;
        keys2 = dataset.primaryKey && dataset.__keys2;

        dataset.trigger('remove', 'parent', parent, 'index', index, 'rows', items);

        for (var i = 0, l = items.length; i < l; i++)
        {
            row = this[i];
 
            delete keys1[row.uniqueId];

            if (primaryKey)
            {
                delete keys2[row.id];
            }

            row.dataset = row.parent = null;
        }

        if (row.uniqueId === dataset.__current_id)
        {
            dataset.moveTo(this[index] || this[--index]);
        }
    };

    
    //删除指定属性
    this.removeProperty = function (name) {
     
        if (name)
        {
            var row, data;
        
            for (var i = this.length - 1; i >= 0; i--)
            {
                if ((row = this[i]) && (data = row.data))
                {
                    delete data[name];
                    
                    if (data = row.originalData)
                    {
                        delete data[name];
                    }
                    
                    if (row.length > 0)
                    {
                        row.removeProperty(name);
                    }
                }
            }
        }
        
        return this;
    };
    
    
});



//数据行基类
flyingon.DataRow = Object.extend._(flyingon.RowCollection, function () {
    
    

    //默认事件
    var default_event = new flyingon.Event();
    
        

    //所属数据集
    this.dataset = null;
    
    //父级行
    this.parent = null;
    
    
    //id
    this.id = null;

    //唯一id
    this.uniqueId = 0;
    
    
    //当前数据
    this.data = null;
    
    
    //原始数据
    this.originalData = null;
    
        
    //数据行状态
    //normal        未变更状态
    //add           增加状态
    //change        已修改状态
    this.state = 'normal';
                
    
                
    //获取指定列的值
    this.get = function (name) {
        
        var data;
        
        if (data = name && this.data)
        {
            return data[name];                
        }
    };
    

    //获取指定列的原始值
    this.originalValue = function (name) {

        var data;
        
        if (name && (data = this.originalData || this.data))
        {
            return data[name];
        }
    };
    
    
    //设置指定列的值
    this.set = function (name, value, trigger) {
        
        var data, oldValue;
        
        //不允许设置值为undefined
        if (name && value !== void 0 && (data = this.data) && value !== (oldValue = data[name]))
        {
            var dataset = this.dataset, 
                event, 
                key, 
                any;
            
            if (trigger !== false)
            {
                event = default_event;
                event.type = 'change';
                event.row = this;
                event.name = name;
                event.value = value;
                event.oldValue = oldValue;
                
                if (dataset.trigger(event) === false)
                {
                    return this;
                }
                
                if ((any = event.value) !== value && any !== void 0)
                {
                    value = any;
                }
            }
            
            if (this.state === 'normal')
            {
                this.originalData = any = {};

                for (key in data)
                {
                    any[key] = data[key];
                }

                this.state = 'change';

                dataset.__change_rows.push(this);
            }

            data[name] = value;

            //触发变更动作
            dataset.dispatch('change', this, name);
        }
        
        return this;
    };
    
    
    //回滚指定值
    this.rollback = function (name) {
        
        var data = name && this.originalData;
        
        if (data)
        {
            this.data[name] = data[name];
        }
    };
    
    
    
    //从所属行集中移除当前行
    this.remove = function () {
        
        var parent = this.parent || this.dataset;
        
        if (parent)
        {
            parent.splice(parent.indexOf(this), 1);
        }
        
        return this;
    };
    
    
    
    //扩展数据集功能
    flyingon.fragment('f-dataset', this);
    

    
    //获取树级别
    this.level = function () {
     
        var level = 0,
            parent = this;
        
        while (parent = parent.parent)
        {
            level++;
        }
        
        return level;
    };
    
    
    //统计所有子节点的数量
    this.total = function () {
        
        var length = this.length,
            count = length;
        
        if (length > 0)
        {
            for (var i = 0; i < length; i++)
            {
                var row = this[i];
                
                if (row.length > 0)
                {
                    count += row.count();
                }
            }
        }
        
        return count;
    };
    
    
        
});



//数据集
flyingon.DataSet = flyingon.defineClass(flyingon.RowCollection, function () {
    
    
    
    this.init = function () {
       
        //id生成器
        this.__new_id = 1;
        
        //uniqueId集合
        this.__keys1 = flyingon.create(null);
        
        //id集合
        this.__keys2 = flyingon.create(null);
        
        //变更的数据行集合
        this.__change_rows = [];
    };
    


    //主键
    this.primaryKey = '';

    
        
    //扩展数据集功能
    flyingon.fragment('f-dataset', this);
    
    
    
    //获取或设置当前行
    this.current = function () {
        
        var id = this.__current_id;
        return id && this.__keys1[id] || null;
    };
    
    
    //移动到第一行
    this.first = function () {
        
        var row = this[0];
        
        if (row)
        {
            this.moveTo(row);
        }

        return this;
    };
    
    
    //移动到上一行
    this.previous = function () {
        
        var row = this.current(),
            parent = row && row.parent || this,
            index = row ? parent.indexOf(row) - 1 : 0;
        
        if (row = parent[index])
        {
            this.moveTo(row);
        }

        return this;
    };
    
    
    //移动到下一行
    this.next = function () {
        
        var row = this.current(),
            parent = row && row.parent || this,
            index = row ? parent.indexOf(row) + 1 : 0;
        
        if (row = parent[index])
        {
            this.moveTo(row);
        }

        return this;
    };
    
    
    //移动到最后一行
    this.last = function () {
        
        var row = this[this.length - 1];
        
        if (row)
        {
            this.moveTo(row);
        }

        return this;
    };
    
    
    //移动到指定行
    this.moveTo = function (row) {
        
        var id = this.__current_id,
            oldValue = id && this.__keys1[id] || null;
        
        if (oldValue !== row && this.trigger('move', 'value', row, 'oldValue', oldValue) !== false)
        {
            this.__current_id = row && row.uniqueId;

            //触发当前行移动动作
            this.dispatch('move', row);
        }
        
        return this;
    };
    
    
    
    //通过id查找数据行
    this.id = function (id) {
        
        return this.__keys2(id) || null;
    };
    
    
    //通过唯一id查找数据行
    this.uniqueId = function (id) {
        
        return this.__keys1[id] || null;
    };
    
        
    
    //获取变更的数据行
    this.getChanges = function (state) {
    
        var list = new flyingon.RowCollection(),
            rows = this.__change_rows,
            length = rows.length;
        
        if (length > 0)
        {
            if (state && typeof state === 'string')
            {
                var index = 0,
                    row;

                for (var i = 0; i < length; i++)
                {
                    if ((row = rows[i]) && state.indexOf(row.state) >= 0)
                    {
                        list[index++] = row;
                    }
                }

                list.length = index;
            }
            else
            {
                rows.push.apply(list, rows);
            }
        }
        
        return list;
    };
    
    
    //接收所有修改
    this.acceptChanges = function () {
        
        var rows = this.__change_rows,
            length = rows.length,
            row;
        
        if (length > 0)
        {
            for (var i = 0; i < length; i++)
            {
                if (row = rows[i])
                {
                    row.originalData = null;
                    row.state = 'normal';
                }
            }
            
            rows.length = 0;
        }
        
        return this;
    };
  
    
    //拒绝所有修改
    this.rejectChanges = function () {
        
        var rows = this.__change_rows,
            length = rows.length,
            row,
            data,
            any;
        
        if (length > 0)
        {
            for (var i = length - 1; i >= 0; i--)
            {
                if (row = rows[i])
                {
                    if (any = row.originalData)
                    {
                        data = row.data;

                        for (var name in any)
                        {
                            data[name] = any[name];
                        }

                        row.originalData = null;
                        row.state = 'normal';

                        this.dispatch('change', row);
                    }
                    else
                    {
                        row.remove();
                    }
                }
            }
            
            rows.length = 0;
        }
        
        return this;
    };
    
    
    
    //订阅或取消订阅变更动作
    this.subscribe = function (control, cancel) {
        
        if (control && control.subscribeBind)
        {
            var list = this.__subscribe,
                index;
            
            if (list)
            {
                index = list.indexOf(control);
                
                if (cancel)
                {
                    if (index >= 0)
                    {
                        list.splice(index, 1);
                    }
                }
                else if (index < 0)
                {
                    list.push(control);
                }
            }
            else if (!cancel)
            {
                (this.__subscribe = []).push(control);
            }
        }

        return this;
    };


    

    var action_cache = { type: '', row: null, name: null, current: false };
    
    
    //派发变更动作
    this.dispatch = function (type, row, name) {
        
        var list;
        
        if (type && (list = this.__subscribe))
        {
            var action = action_cache,
                current;

            action.type = type;
            action.name = name || null;

            if (action.row = row)
            {
                current = row ? row.uniqueId === this.__current_id : false;
            }
            else
            {
                action.row = this.current();
                current = true;
            }

            for (var i = 0, l = list.length; i < l; i++)
            {
                if (current || list[i].__subscribe_all)
                {
                    list[i].subscribeBind(this, action);
                }
            }
        }

        return this;
    };
    
    
    //绑定数据源
    this.bind = function () {
        
        var row;
        
        if (!this.__current_id && (row = this[0]))
        {
            this.__current_id = row && row.uniqueId;
        }
        
        this.dispatch('bind');
        return this;
    };


    //添加或移除表达式
    this.expression = function (name, get, set) {

        var keys;

        if (name && typeof name === 'string')
        {
            if (typeof get === 'function')
            {
                if (typeof set !== 'function')
                {
                    set = null;
                }

                keys = this.__expression_keys || (this.__expression_keys = flyingon.create(null));
                keys[name] = [get, set];
            }
            else if (keys = this.__expression_keys)
            {
                delete keys[name];
            }
        }

        return this;
    };


    //获取绑定值
    this.getBindingValue = function (name, action) {

        var any = this.__expression_keys;

        if (any && (any = any[name]))
        {
            return any[0].call(this, action.row);
        }

        any = (any = action.row.data) && any[name];
        return any !== void 0 ? any : '';
    };


    //设置绑定值
    this.setBindingValue = function (name, value, row) {

        var any = this.__expression_keys;

        if (any && (any = any[name]))
        {
            if (any = any[1])
            {
                any.call(this, value, row || this.current());
            }
        }
        else
        {
            (row || this.current()).set(name, value);
        }

        return this;
    };

    
        
}, false);




/**
 * @class f-bindable
 * @extension
 * @description 可绑定功能片段
 */
flyingon.fragment('f-bindable', function () {
    
    

    /**
     * @method dataset
     * @description 获取或设置关联的数据集
     * @param {?flyingon.DataSet=} value 未传入值时表示获取值, 否则表示设置值
     * @return {(?flyingon.DataSet|object)} 获取值时返回数据集对象或null, 否则返回当前对象实例
     */
    this.defineProperty('dataset', null, {
        
        fn: function (value) {

            var any = this.__dataset || null;

            if (value === void 0)
            {
                return any;
            }

            if (any === value)
            {
                return this;
            }

            if (this.__watch_list && flyingon.__do_watch(this, 'dataset', value) === false)
            {
                return this;
            }

            this.__dataset = value;

            if (any) 
            {
                any.subscribe(this, true);
            }

            if (value) 
            {
                value.subscribe(this);
            }

            return this;
        }
    });
    
    
    /**
     * @method addBind
     * @description 添加属性绑定
     * @param {string} name 属性名
     * @param {string} fieldName 数据集字段名
     * @return {object} 当前实例对象
     */
    this.addBind = function (name, fieldName) {
        
        if (name && fieldName)
        {
            var watches = this.__watches || (this.__watches = {}),
                any;

            if (any = watches[name])
            {
                any[0] = fieldName;
            }
            else
            {
                watches[name] = [fieldName];
            }
        }
        
        return this;
    };
    
    
    /**
     * @method removeBind
     * @description 移除属性绑定
     * @param {string} name 属性名
     * @return {object} 当前实例对象
     */
    this.removeBind = function (name) {
        
        var watches = this.__watches,
            any;
        
        if (watches && (any = watches[name]) && any[0])
        {
            if (any[1])
            {
                any[0] = '';
            }
            else
            {
                delete watches[name];
            }
        }
        
        return this;
    };

    
    /**
     * @method subscribeBind
     * @description 接收数据集变更动作处理
     * @param {flyingon.DataSet} dataset 数据集
     * @param {object} action 数据集动作 { name: string, row: DataRow }
     * @return {object} 当前实例对象
     */
    this.subscribeBind = function (dataset, action) {
        
        var watches = this.__watches;
        
        if (watches)
        {
            var bind = action.name, 
                key, 
                any;

            for (var name in watches)
            {
                if ((any = watches[name]) && (key = any[0]) && (!bind || key === bind))
                {
                    //禁止自身回推
                    any[0] = '';

                    try
                    {
                        this.set(name, dataset.getBindingValue(key, action));
                    }
                    finally
                    {
                        //回退缓存
                        any[0] = key;
                    }
                }
            }
        }
        
        return this;
    };
    
    
    /**
     * @method pushBack
     * @description 回推数据至数据集
     * @param {string} name 属性名
     * @param {any} value 属性值
     * @return {object} 当前实例对象
     */
    this.pushBack = function (name, value) {
        
        var target = this,
            dataset;
 
        do
        {
            if (dataset = target.__dataset)
            {
                dataset.setBindingValue(name, value);
                return this;
            }
        }
        while (target = target.parent);

        return this;
    };

    
    
});




(function () {


    
    var components = flyingon.components;
    
    var reader = new flyingon.SerializeReader();



    //初始化唯一id组件集
    if (!flyingon.__uniqueId)
    {
        (flyingon.__uniqueId = flyingon.create(null)).id = 1;
    }



    //根据选项创建界面元素
    flyingon.ui = function (options) {

        var control = new (components[options.Class] || arguments[1] || flyingon.HtmlElement)();

        control.deserialize(reader, options);

        return control;
    };


    flyingon.__find_id = function (list, id) {

        var exports = [],
            index = 0,
            item,
            any;
            
        while (item = list[index++])
        {
            if ((any = item.__storage) && any.id === id)
            {
                exports.push(item);
            }
        }

        return exports;
    };


    flyingon.__find_type = function (list, name) {

        var Class = flyingon.components[name],
            exports = [],
            index = 0,
            item;

        if (Class)
        {
            while (item = list[index++])
            {
                if (item instanceof Class)
                {
                    exports.push(item);
                }
            }
        }

        return exports;
    };


    flyingon.__find_class = function (list, name) {

        var exports = [],
            index = 0,
            item,
            any;
        
        while (item = list[index++])
        {
            if ((any = item.__class_keys) && any[name])
            {
                exports.push(item);
            }
        }

        return exports;
    };


})();




//可视组件基础功能扩展
flyingon.fragment('f-visual', function () {


    //根据uniqueId组织的控件集合
    var uniqueId = flyingon.__uniqueId;


    //有效属性集合
    var attributes = flyingon.create(null);


    
    //扩展至选择器
    this.__selector_extend = flyingon.Query;
    
                
    //向上冒泡对象名
    this.eventBubble = 'parent';
    

    //父控件
    this.parent = null;


    //是否已经渲染
    this.rendered = false;



    this.__uniqueId = 0;
    
    //唯一id
    this.uniqueId = function () {
        
        var id = this.__uniqueId;
        return id || (uniqueId[this.__uniqueId = id = uniqueId.id++] = this, id);
    };
    

    
    //读取自定义值
    this.__custom_get = function (name) {

        var fn, any;

        if (name && (any = name.indexOf(':')) > 0) //class: or style:
        {
            if (fn = this[name.substring(0, ++any)])
            {
                fn.call(this, name.substring(any));
            }
            else
            {
                throw '"' + name + '" is not a valid property!';
            }
        }

        return (this.__storage || this.__defaults)[name];
    };


    //设置自定义值
    this.__custom_set = function (name, value) {

        var fn, any;

        if (name && (any = name.indexOf(':')) > 0) //class: or style:
        {
            if (fn = this[name.substring(0, ++any)])
            {
                fn.call(this, name.substring(any), value);
            }
            else
            {
                throw '"' + name + '" is not a valid property!';
            }
        }
        else
        {
            (this.__storage || (this.__storage = flyingon.create(this.__defaults)))[name] = value;

            //如果是有效的属性名则当作自定义属性处理
            if ((any = attributes[name]) === true || (any == null && (attributes[name] = flyingon.__check_attribute(name))))
            {
                if (any = this.__view_patch)
                {
                    any[name] = value;
                }
                else
                {
                    this.renderer.set(this, name, value);
                }
            }
        }
    };
    

        
    //从父控件中移除
    this.remove = function () {
        
        var parent = this.parent,
            index;
        
        if (parent && (index = parent.indexOf(this)) >= 0)
        {
            parent.splice(index, 1);
        }
    };


    //从父控件中独立出来(不销毁)
    this.alone = function () {

        var parent = this.parent,
            index;

        if (parent && (index = parent.indexOf(this)) >= 0)
        {
            parent.splice(index, 1);
            this.autoDispose = false;
        }
    };
    


    //id
    this.defineProperty('id', '', {
     
        set: function (value, oldValue) {

            var any;

            if (this.rendered)
            {
                if (any = this.__view_patch)
                {
                    any.id = value;
                }
                else
                {
                    this.renderer.set(this, 'id', value);
                }
            }
        }
    });


    
    //指定class名 与html一样
    this['class'] = this.defineProperty('className', '', {

        set: function (value) {

            var any;

            this.fullClassName = value = value ? this.defaultClass + ' ' + value : this.defaultClass;

            if (this.rendered)
            {
                if (any = this.__view_patch)
                {
                    any['class'] = value;
                }
                else
                {
                    this.renderer.set(this, 'class', value);
                }
            }
        }
    });
    
    
    //是否包含指定class
    this.hasClass = function (name) {

        var keys;
        return name && (keys = this.__class_keys) && keys[name] || false;
    };


    //添加class
    this.addClass = function (name) {

        var list, keys, any;

        if (name && (list = name.match(/[\w-]+/g)))
        {
            if (keys = this.__class_keys)
            {
                any = list.length;

                while (any--)
                {
                    if (keys[name = list[any]])
                    {
                        list.splice(any, 1);
                    }
                    else
                    {
                        keys[name] = true;
                    }
                }
                
                if (list.length > 0)
                {
                    this.className(this.__storage.className + ' ' + list.join(' '));
                }
            }
            else
            {
                init_class(this, list);
            }
        }

        return this;
    };


    //移除class
    this.removeClass = function (name) {

        var list, keys, index;

        if (name && (list = name.match(/\w+/g)) && (keys = this.__class_keys))
        {
            index = list.length;

            while (index--)
            {
                if (keys[name = list[index]])
                {
                    keys[name] = false;
                }
                else
                {
                    list.splice(index, 1);
                }
            }
            
            if (list.length > 0)
            {
                sync_class(this, keys, list);
            }
        }

        return this;
    };


    //切换class 有则移除无则添加
    this.toggleClass = function (name) {

        var list, keys, index;

        if (name && (list = name.match(/\w+/g)))
        {
            if (keys = this.__class_keys)
            {
                index = list.length;

                while (index--)
                {
                    keys[name = list[index]] = !keys[name];
                }
                
                sync_class(this, keys, list);
            }
            else
            {
                init_class(this, list);
            }
        }

        return this;
    };


    //初始化class集合
    function init_class(self, list) {

        var keys = self.__class_keys = {},
            index = 0,
            any;

        while (any = list[index++])
        {
            keys[any] = true;
        }

        self.className(list.join(' '));
    };


    //同步class
    function sync_class(self, keys, list) {

        var any = [];

        for (var name in keys)
        {
            if (keys[name])
            {
                any.push(name);
            }
        }

        self.className(any.join(' '));
    };



    //class
    this['class:'] = function (name, value) {

        if (value)
        {
            this.addClass(name);
        }
        else
        {
            this.removeClass(name);
        }
    };



    //变更指令
    this['#model'] = function (vm, name) {

        this.on('change', function (e) {

            vm.$set(name, e.value);
        });
    };


        
    //控件类初始化处理
    this.__class_init = function (Class, base) {
     
        var module = Class.module,
            name = Class.typeName;
        
        //绑定渲染器
        if (this.renderer === base.renderer)
        {
            flyingon.renderer.bind(this, name);
        }

        if (name)
        {
            name = ((module.className || module.moduleName) + '-' + name).toLowerCase();
            
            if (base = base.defaultClass)
            {
                 name = base + ' ' + name;
            }
            
            this.fullClassName = this.defaultClass = name;
        }
    };
    


});





//全局动态执行js, 防止局部执行增加作用域而带来变量冲突的问题
flyingon.globalEval = function (text) {

    if (window.execScript)
    {
        //ie8不支持call, ie9的this必须是window否则会出错
        window.execScript(text);
    }
    else
    {
        window['eval'](text);
    }
};


//转换url为绝对路径
flyingon.absoluteUrl = (function () {

    var dom = document.createElement('a'),
        base = location.href.replace(/[?#][\s\S]*/, ''),
        regex;

    dom.href = '';

    if (!dom.href)
    {
        dom = document.createElement('div');
        regex = /"/g;
    }

    return function (url, path) {

        if (url)
        {
            if (regex)
            {
                dom.innerHTML = '<a href="' + url.replace(regex, '%22') + '"></a>';
                url = dom.firstChild.href;
            }
            else
            {
                dom.href = url;
                url = dom.href;
            }
        }
        else
        {
            url = base;
        }

        return path ? url.substring(0, url.lastIndexOf('/') + 1) : url;
    };

})();



//获取当前正在执行的js绝对路径
flyingon.__script_src = function () {

    var any;

    // firefox, chrome
    if (any = document.currentScript)
    {
        return any.src;
    }

    try
    {
        any();
    }
    catch (e)
    {
        //ie10
        if ((any = e.fileName || e.sourceURL || e.stack || e.stacktrace) &&
            (any = /((?:http|https|file):\/\/.*?\/[^:]+)(?::\d+)?:\d+/.exec(any)))
        {
            return any[1];
        }
    }

    // IE5-9
    any = document.scripts;

    for (var i = any.length - 1; i >= 0; i--)
    {
        if (any[i].readyState === 'interactive')
        {
            return flyingon.absoluteUrl(any[i].src);
        }
    }

};


//head兼容处理
document.head || (document.head = document.getElementsByTagName('head')[0]);


//创建脚本标签
flyingon.script = !-[1,] || document.documentMode === 9 ? (function () { //ie8不支持onload, ie9支持但是执行顺序无法保证

    var list = [],
        head = document.head;

    function change() {

        var dom, callback;

        while ((dom = list[0]) && dom.readyState === 'loaded')
        {
            list.shift();

            dom.onreadystatechange = null;
            
            //不使用appendChild防止低版本IE在标签未闭合时出错
            head.insertBefore(dom, head.lastChild || null);

            if (callback = list.shift())
            {
                callback.call(dom);
            }
        }
    };

    return function (src, callback) {

        var dom = document.createElement('script');

        list.push(dom, callback);

        dom.onreadystatechange = change;
        dom.src = src; //会立即发送请求,但只有添加进dom树才会执行

        return dom;
    };

})() : function (src, callback) {

    var dom = document.createElement('script');

    dom.onload = dom.onerror = function () {

        dom = dom.onload = dom.onerror = null;

        if (callback)
        {
            callback.call(this);
            callback = null;
        }
    };

    dom.async = false;
    dom.src = src;

    document.head.appendChild(dom);
    return dom;
};



//创建link标签
flyingon.link = function (href, type, rel) {

    var dom = document.createElement('link');

    dom.href = href;
    dom.type = type || 'text/css';
    dom.rel = rel || 'stylesheet';

    document.head.appendChild(dom);

    return dom;
};


//动态添加样式表
flyingon.style = function (cssText) {

    var dom = document.createElement('style');  

    dom.setAttribute('type', 'text/css');  

    if (dom.styleSheet) // IE  
    {
        dom.styleSheet.cssText = cssText;  
    }
    else // w3c  
    {
        dom.appendChild(document.createTextNode(cssText));  
    }

    document.head.appendChild(dom);
    return dom;
};


//dom事件扩展
(function (window, flyingon) {

    

    var on = 'addEventListener';


    
    //以下为通用事件扩展(IE8以下浏览器不支持addEventListener)
    //IE的attachEvent中this为window且执行顺序相反
    if (!window[on])
    {
        on = false;
    }


    //触发dom事件
    function trigger(e) {

        var items = this.__events,
            fn;

        if (items = items && items[e.type])
        {
            e.target || (e.target = e.srcElement);

            for (var i = 0, l = items.length; i < l; i++)
            {
                if ((fn = items[i]) && !fn.disabled)
                {
                    if (fn.call(this, e) === false && e.returnValue !== false)
                    {
                        flyingon.dom_prevent(e);
                    }

                    if (e.cancelBubble)
                    {
                        break;
                    }
                }
            }
        }
    };
    
    
    //修复attachEvent的this指向不正确的问题
    function trigger_fixed(dom) {
        
        function fn(e) {
          
            trigger.call(fn.dom, e || window.event); 
        };
        
        fn.dom = dom;
        
        //防止IE内存泄露
        dom = null;
        
        return fn;
    };

    
    //挂起函数
    function suspend(e) {
      
        flyingon.dom_stop(e); //有些浏览器不会设置cancelBubble
    };



    //组件dom默认事件
    flyingon.dom_prevent = function (event) {

        event.returnValue = false;
        event.preventDefault && event.preventDefault();
    };


    //停止dom事件冒泡
    flyingon.dom_stop = function (event, prevent) {

        if (prevent)
        {
            event.returnValue = false;
            event.preventDefault && event.preventDefault();
        }

        event.cancelBubble = true;
        event.stopPropagation && event.stopPropagation();
    };



    //只执行一次绑定的事件
    flyingon.dom_once = function (dom, type, fn) {

        function callback() {

            fn.apply(this, arguments);
            flyingon.dom_off(dom, type, callback);
        };

        flyingon.dom_on(dom, type, callback);
    };


    //添加dom事件绑定
    flyingon.dom_on = function (dom, type, fn, capture) {

        if (dom && type && fn)
        {
            var events = dom.__events,
                items;

            if (events)
            {
                if (items = events[type])
                {
                    items.push(fn);
                    return this;
                }
            }
            else
            {
                events = dom.__events = {};
            }

            events[type] = [fn];

            if (on)
            {
                dom[on](type, trigger, capture);
            }
            else
            {
                dom.attachEvent('on' + type, events.trigger || (events.trigger = trigger_fixed(dom)));
            }
        }
    };

    
    //暂停dom事件处理
    flyingon.dom_suspend = function (dom, type) {
        
        var items = dom && dom.__events;

        if (items = items && items[type])
        {
            items.unshift(suspend);
        }
    };
    
    
    //继续dom事件处理
    flyingon.dom_resume = function (dom, type) {
        
        var items = dom && dom.__events;

        if ((items = items && items[type]) && items[0] === suspend)
        {
            items.shift();
        }
    };
    

    //移除dom事件绑定
    flyingon.dom_off = function (dom, type, fn) {

        var events = dom && dom.__events,
            items;

        if (items = events && events[type])
        {
            if (fn)
            {
                for (var i = items.length - 1; i >= 0; i--)
                {
                    if (items[i] === fn)
                    {
                        items.splice(i, 1);
                    }
                }

                if (items.length > 0)
                {
                    return;
                }
            }

            if (on)
            {
                dom.removeEventListener(type, trigger);
            }
            else
            {
                dom.detachEvent('on' + type, events.trigger);
            }

            delete events[type];

            for (type in events)
            {
                return;
            }

            if (fn = events.trigger)
            {
                events.trigger = fn.dom = null;
            }
            
            dom.__events = void 0;
        }
    };


    //触发事件
    flyingon.dom_trigger = function (dom, event) {

        if (dom && event)
        {
            return trigger.call(dom, event.type ? event : { type: event });
        }
    };

    

})(window, flyingon);




//dom样式扩展
(function (document, flyingon) {
    
    


    var style1 = flyingon.create(null),

        style2 = flyingon.create(null),

        fixed = flyingon.create(null); //自定义css兼容处理

        


    (function check_css(style1, style2) {

        var style = document.documentElement.style,
            list1 = [],
            list2,
            list3,
            any;

        for (var name in style)
        {
            switch (name)
            {
                case 'cssFloat':
                case 'styleFloat':
                    list1.push('float');
                    break;

                case 'cssText':
                    break;

                default:
                    list1.push(name);
                    break;
            }
        }

        any = list1.join(',');

        if (name = any.match(/\b(webkit|ms|moz|o)[A-Z]/))
        {
            name = name[1];

            any = any.replace(new RegExp('\\b' + name + '(?=[A-Z])', 'g'), '-' + name);

            any = any.replace(/([A-Z])/g, function (_, name) {

                return '-' + name.toLowerCase();
            });

            list2 = any.split(',');
            list3 = any.replace(new RegExp('-' + name + '-', 'g'), '').split(',');
        }
        else
        {
            list2 = list3 = list1;
        }

        for (var i = 0, l = list1.length; i < l; i++)
        {
            any = list3[i];
            style1[any] = list1[i];
            style2[any] = list2[i];
        }

    })(style1, style2);



    //获取可用样式名
    //name: 要获取的样式名,按css连字符的写法,如:background-color
    flyingon.css_name = function (name, css) {

        return (css ? style2 : style1)[name] || '';
    };


    //获取css名字映射
    flyingon.css_map = function (css) {

        return css ? style2 : style1;
    };
    
    
    //设置css样式值
    //dom:      目标dom
    //name:     要设置样式名,按css连字符的写法,如:background-color
    //value:    样式值
    flyingon.css_value = function (dom, name, value) {

        var any;

        if (any = style1[name])
        {
            dom.style[any] = value;
        }
        else if (any = fixed[name])
        {
            any(value, dom);
        }
    };
    
    
    //注册样式兼容处理
    //name:     要处理的样式名
    //set:      转换样式值的方法
    flyingon.css_fixed = function (name, set) {

        if (name && set && !style1[name])
        {
            fixed[name] = set;
        }
    };


    //处理ie允许选中
    flyingon.css_fixed('user-select', (function () {

        function event_false() {

            return false;
        };

        return function (value, dom) {

            if (dom)
            {
                (dom === document.body ? document : dom).onselectstart = value === 'none' ? event_false : null;
            }
        };

    })());
    
    
    
})(document, flyingon);



//检查属性名是否合法
flyingon.__check_attribute = function () {

    var div = document.createElement('div');

    return function (name) {

        try
        {
            div.setAttribute(name, '');
            return true;
        }
        catch (e)
        {
            return false;
        }
    };

}();



//html文档树加载完毕
flyingon.ready = function () {

    var list;

    function ready() {

        var any = list;

        if (any)
        {
            any.ready = true;

            flyingon.dom_off(document, 'DOMContentLoaded', ready);
            flyingon.dom_off(window, 'load', ready);

            for (var i = 0; i < any.length; i++) //执行过程中可能会加入函数,故不能缓存length
            {
                any[i++].call(any[i]);
            }

            list = null;
        }
    };

    if (document.readyState !== 'complete')
    {
        list = [];

        flyingon.dom_on(document, 'DOMContentLoaded', ready);
        flyingon.dom_on(window, 'load', ready);
    }

    return function (fn, context) {

        if (typeof fn === 'function')
        {
            if (list)
            {
                list.push(fn, context);
            }
            else
            {
                fn.call(context);
            }
        }
        else if (list && !list.ready)
        {
            ready();
        }
    };

}();



//根据id查找对应的dom
flyingon.dom_id = function (id) {
    
    if (id)
    {
        if (id.charAt(0) === '#')
        {
            id = id.substring(1);
        }

        return document.getElementById(id);
    }
};



//dom测试
flyingon.dom_test = function () {

    var dom = document.createElement('div'),
        list;

    dom.id = 'f-dom-test';
    dom.style.cssText = 'position:absolute;overflow:hidden;margin:0;border:0;padding:0;left:-10px;top:0;width:0;height:0;';

    if (document.body)
    {
        document.body.appendChild(dom);
    }
    else
    {
        list = [];

        flyingon.ready(function () {

            var index = 0,
                fn;

            list = null;
            document.body.appendChild(dom);

            while (fn = this[index++])
            {
                fn.call(this[index++], dom);
            }

        }, list);
    }
    
    return function (fn, context) {

        if (list)
        {
            list.push(fn, context);
        }
        else
        {
            fn.call(context, dom);
        }
    };

}();




//在dom元素内插入html片段
flyingon.dom_html = function (host, html, refChild) {
    
    if (host && html)
    {
        var after, tag, any;

        if (refChild || (refChild = host.lastChild) && (after = 1))
        {
            tag = after ? refChild : refChild.previousSibling;

            if (any = refChild.insertAdjacentHTML)
            {
                any.call(refChild, after ? 'afterend' : 'beforebegin', html);
            }
            else
            {
                any = document.createRange();
                html = any.createContextualFragment(html);

                if (after)
                {
                    any.setStartAfter(refChild);
                    host.appendChild(html);
                }
                else
                {
                    any.setStartBefore(refChild);
                    host.insertBefore(html, refChild);
                }
            }

            return tag ? tag.nextSibling : host.firstChild;
        }

        host.innerHTML = html;
        return host.firstChild;
    }
};




//拖动基础方法
flyingon.dom_drag = function (context, event, begin, move, end, locked, delay) {

    var dom = event.dom || event.target || event.srcElement,
        on = flyingon.dom_on,
        off = flyingon.dom_off,
        x1 = event.clientX,
        y1 = event.clientY,
        distanceX = 0,
        distanceY = 0,
        style,
        x0,
        y0;

    function start(e) {
        
        if (begin)
        {
            e.dom = dom;
            begin.call(context, e);
            dom = e.dom;
        }

        if (style = dom && dom.style)
        {
            x0 = dom.offsetLeft;
            y0 = dom.offsetTop;
        }
        
        flyingon.dom_suspend(dom, 'click', true);
        flyingon.css_value(document.body, 'user-select', 'none');
        
        if (dom.setCapture)
        {
            dom.setCapture();
        }
        
        start = null;
    };
    
    function mousemove(e) {

        var x = e.clientX - x1,
            y = e.clientY - y1;

        if (!start || (x < -2 || x > 2 || y < -2 || y > 2) && start(e))
        {
            if (move)
            {
                e.dom = dom;
                e.distanceX = x;
                e.distanceY = y;
                
                move.call(context, e);
                
                x = e.distanceX;
                y = e.distanceY;
            }
            
            distanceX = x;
            distanceY = y;
            
            if (style && locked !== true)
            {
                if (locked !== 'x')
                {
                    style.left = (x0 + x) + 'px';
                }

                if (locked !== 'y')
                {
                    style.top = (y0 + y) + 'px';
                }
            }
            
            flyingon.dom_stop(e, true);
        }
    };

    function mouseup(e) {

        off(document, 'mousemove', mousemove);
        off(document, 'mouseup', mouseup);

        if (!start)
        {
            flyingon.css_value(document.body, 'user-select', '');
            
            if (dom.setCapture)
            {
                dom.releaseCapture();
            }

            setTimeout(resume, 0);
            
            if (end)
            {
                e.dom = dom;
                e.distanceX = distanceX;
                e.distanceY = distanceY;
                
                end.call(context, e);
            }

            context = dom = null;
        }
    };
    
    function resume() {
      
        flyingon.dom_resume(dom, 'click', true);
    };
    
    if (delay === false)
    {
        start(event);
    }

    on(document, 'mousemove', mousemove);
    on(document, 'mouseup', mouseup);
    
    flyingon.dom_stop(event, true);
};




//对齐到指定的dom
//dom: 要对齐的dom元素
//rect: 停靠范围
//direction: 停靠方向 bottom:下面 top:上面 right:右边 left:左边
//align: 对齐 left|center|right|top|middle|bottom
//reverse: 空间不足时是否反转方向
flyingon.dom_align = function (dom, rect, direction, align, reverse) {

    var width = dom.offsetWidth,
        height = dom.offsetHeight,
        style = dom.style,
        x = document.body.scrollLeft,
        y = document.body.scrollTop,
        x1 = x + rect.left,
        y1 = y + rect.top,
        x2 = x + rect.right,
        y2 = y + rect.bottom;

    //检测是否需倒转方向
    if (reverse !== false)
    {
        dom = document.documentElement;

        x = window.innerWidth || dom.offsetWidth || 0,
        y = window.innerHeight || dom.offsetHeight || 0;

        switch (direction)
        {
            case 'left':
                if (x1 < width && x - x2 >= width)
                {
                    direction = 'right';
                }
                break;

            case 'top':
                if (y1 < height && y - y2 >= height)
                {
                    direction = 'bottom';
                }
                break;

            case 'right':
                if (x1 >= width && x < x2 + width)
                {
                    direction = 'left';
                }
                break;

            default: 
                if (y1 >= height && y < y2 + height)
                {
                    direction = 'top';
                }
                break;
        }
    }

    if (direction === 'left' || direction === 'right')
    {
        x = direction === 'left' ? x1 - width : x2;

        switch (align)
        {
            case 'middle':
                y = y1 + (y2 - y1 - height >> 1);
                break;

            case 'bottom':
                y = y2 - height;
                break;

            default:
                y = y1;
                break;
        }
    }
    else
    {
        switch (align)
        {
            case 'center':
                x = x1 - (x2 - x1 - width >> 1);
                break;

            case 'right':
                x = x2 - width;
                break;

            default:
                x = x1;
                break;
        }

        y = direction === 'top' ? y1 - height : y2;
    }
    
    style.left = x + 'px';
    style.top = y + 'px';

    return { left: x, top: y };
};




//显示或隐藏摭罩层
flyingon.dom_overlay = (function () {
    
    var list = [],
        overlay = document.createElement('div');

    overlay.className = 'f-overlay';

    return function (dom, visible) {

        if (dom)
        {
            var any;

            if (visible === false)
            {
                if (list[list.length - 1] === dom)
                {
                    dom.flyingon_overlay = false;
                    list.pop();
                    
                    while (dom = list[list.length - 1])
                    {
                        overlay.style.zIndex = dom.style.zIndex;

                        if (any = dom.parentNode)
                        {
                            any.insertBefore(overlay, dom);
                            return;
                        }

                        dom.flyingon_overlay = false;
                        list.pop();
                    }
                    
                    if (any = overlay.parentNode)
                    {
                        any.removeChild(overlay);
                    }
                }
            }
            else if (any = dom.parentNode)
            {
                overlay.style.zIndex = dom.style.zIndex;
                any.insertBefore(overlay, dom);

                dom.flyingon_overlay = true;
                list.push(dom);
            }
        }
    };

})();




//单位换算
(function (flyingon) {


    var create = flyingon.create,
    
        unit = (flyingon.pixel_unit = pixel_unit).unit = create(null), //单位换算列表

        pixel_cache = (flyingon.pixel = pixel).cache = create(null),

        pixel_persent = create(null),

        sides_cache = (flyingon.pixel_sides = pixel_sides).cache = create(null),

        sides_persent = create(null); 
            
    
    //初始化默认值
    unit.em = unit.rem = 12;
    unit.ex = 6;
    unit.pc = 16;
    unit.px = 1;
    unit.pt = 4 / 3;
    
    unit.mm = (unit.cm = 96 / 2.54) / 10;
    unit['in'] = 96;
    

    //或者或设置象素转换单位
    function pixel_unit(name, value) {

        if (value === void 0)
        {
            return unit[name];
        }

        if (unit[name] !== value)
        {            
            var cache = pixel_cache;

            unit[name] = value;

            for (var key in cache)
            {
                if (key.indexOf(name) > 0)
                {
                    cache[key] = void 0;
                }
            }
        }
    };


    //转换css尺寸为像素值
    //注: em与rem相同, 且在初始化时有效
    function pixel(value, size) {

        var any = pixel_cache[value],
            unit;

        if (any !== void 0)
        {
            return any;
        }

        if (any = pixel_persent[value])
        {
            return any * size / 100 + 0.5 | 0;
        }

        if (any = value.match(/[+-]?\d+(.\d+)?|[\w%]+/g))
        {
            if (unit = any[1])
            {
                if (unit === '%')
                {
                    return (pixel_persent[value] = any[0]) * size / 100 + 0.5 | 0;
                }

                any = any[0] * (unit[unit.toLowerCase()] || 1) + 0.5 | 0;
            }
            else
            {
                any = +any[0] + 0.5 | 0;
            }
        }
        else
        {
            any = 0;
        }

        return pixel_cache[value] = any; 
    };
    
    
    //转换4边尺寸为像素值(margin, padding的百分比是以父容器的宽度为参照, border-width不支持百分比)
    function pixel_sides(value, width) {
        
        var any = sides_cache[value];
        
        if (any)
        {
            return any;
        }

        if (any = sides_persent[value])
        {
            return sides(value, any, width);
        }

        any = +value;

        if (any === any || !(any = value.match(/[+-]?[\w%.]+/g)))
        {
            return sides_cache[value] = {

                left: any |= 0, 
                top: any, 
                right: any, 
                bottom: any
            };
        }

        if (value.indexOf('%') < 0)
        {
            return sides_cache[value] = sides(any, width);
        }

        return sides(sides_persent[value] = any, width);
    };
    
        
    function sides(sides, width) {
        
        var value = {},
            fn = pixel;
        
        switch (sides.length)
        {
            case 1:
                value.left = value.top = value.right = value.bottom = fn(sides[0], width);
                break;

            case 2:
                value.left = value.right = fn(sides[1], width);
                value.top = value.bottom = fn(sides[0], width);
                break;

            case 3:
                value.left = value.right = fn(sides[1], width);
                value.top = fn(sides[0], width);
                value.bottom = fn(sides[2], width);
                break;

            default:
                value.left = fn(sides[3], width);
                value.top = fn(sides[0], width);
                value.right = fn(sides[1], width);
                value.bottom = fn(sides[2], width);
                break;
        }

        return value;
    };
    

})(flyingon);




//计算单位换算关系
flyingon.dom_test(function (div) {

    var unit = flyingon.pixel_unit.unit;

    //计算单位换算列表
    div.innerHTML = '<div style="position:absolute;left:-10000in;"></div>' +
        '<div style="position:absolute;overflow:scroll;left:-10000em;top:-10000ex;width:100px;height:100px;">' +
            '<div style="width:200px;height:200px;"></div>' + 
        '</div>';

    unit.px = 1;
    unit.pt = (unit.pc = (unit['in'] = -div.children[0].offsetLeft / 10000) / 6) / 12;
    unit.mm = (unit.cm = unit['in'] / 2.54) / 10;

    div = div.children[1];
    unit.em = unit.rem = -div.offsetLeft / 10000;
    unit.ex = -div.offsetTop / 10000;

    //竖直滚动条宽度
    flyingon.vscroll_width = div.offsetWidth - div.clientWidth;

    //水平滚动条高度
    flyingon.hscroll_height = div.offsetHeight - div.clientHeight;
});





//鼠标事件类型
flyingon.MouseEvent = flyingon.Event.extend(function () {


    this.init = function (event) {

        //关联的原始事件
        this.original_event = event;

        //事件类型
        this.type = event.type;

        //是否按下ctrl键
        this.ctrlKey = event.ctrlKey;

        //是否按下shift键
        this.shiftKey = event.shiftKey;

        //是否按下alt键
        this.altKey = event.altKey;

        //是否按下meta键
        this.metaKey = event.metaKey;

        //事件触发时间
        //this.timeStamp = event.timeStamp;

        //鼠标按键处理
        //IE678 button: 1->4->2 W3C button: 0->1->2
        //本系统统一使用which 左中右 1->2->3
        if (!(this.which = event.which))
        {
            this.which = event.button & 1 ? 1 : (event.button & 2 ? 3 : 2);
        }
        
        //包含滚动距离的偏移位置
        //this.pageX = event.pageX;
        //this.pageY = event.pageY;

        //不包含滚动距离的偏移位置
        this.clientX = event.clientX;
        this.clientY = event.clientY;

        //相对屏幕左上角的偏移位置
        //this.screenX = event.screenX;
        //this.screenY = event.screenY;

    };

    
});




//键盘事件类型
flyingon.KeyEvent = flyingon.Event.extend(function () {


    this.init = function (event) {

        //关联的原始dom事件
        this.original_event = event;

        //事件类型
        this.type = event.type;

        //是否按下ctrl键
        this.ctrlKey = event.ctrlKey;

        //是否按下shift键
        this.shiftKey = event.shiftKey;

        //是否按下alt键
        this.altKey = event.altKey;

        //是否按下meta键
        this.metaKey = event.metaKey;

        //事件触发时间
        //this.timeStamp = event.timeStamp;

        //键码
        this.which = event.which || event.charCode || event.keyCode;

    };

    
});




//Ajax类
flyingon.Ajax = flyingon.Async.extend(function () {

    
    
    //请求的url
    this.url = '';
    
    //指定版本号
    this.version = '';

    //method
    this.method = 'GET';

    //text || json || xml
    this.dataType = 'text';

    //内容类型
    this.contentType = 'application/x-www-form-urlencoded';

    //自定义http头
    this.header = null;
    
    //是否异步
    this.async = true;
        
    //是否支持跨域资源共享(CORS)
    this.CORS = false;
    
    //jsonp回调名称
    this.jsonp = 'jsonp';
    
    //超时时间
    this.timeout = 0;
    

    
    this.send = function (url, options) {

        var list = [], //自定义参数列表
            data, 
            get,
            any;
        
        if (options)
        {
            for (var name in options)
            {
                if (name !== 'data')
                {
                    this[name] = options[name];
                }
                else
                {
                    data = options[name];
                }
            }
        }
        
        //执行发送前全局start事件
        if (any = flyingon.Ajax.start)
        {
            for (var i = 0, l = any.length; i < l; i++)
            {
                if (any[i].call(this, url) === false)
                {
                    return false;
                }
            }
            
            url =  this.url;
        }
        
        if (!(this.url = url))
        {
            return false;
        }
              
        if ((get = /get|head|options/i.test(this.method)) && data)
        {
            list.push(flyingon.encode(data));
            data = null;
        }
        
        any = this.dataType === 'jsonp';
        
        if (this.version)
        {
            list.push('ajax-version=', this.version);
        }
                
        if (any || list.length > 0)
        {
            list.start = url.indexOf('?') >= 0 ? '&' : '?';
        }

        //jsonp
        if (any)
        {
            any = get ? jsonp_get : jsonp_post;
        }
        else
        {
            any = ajax_send;
        }
        
        any(this, url, list, data);

        return this;
    };

    
    
    //发送ajax请求
    function ajax_send(self, url, list, data) {
    
        var xhr = self.xhr = new XMLHttpRequest(),
            any;
        
        if (list.start)
        {
            url = url + list.start + list.join('&');
        }
              
        //CORS
        if (self.CORS)
        {
            //withCredentials是XMLHTTPRequest2中独有的
            if ('withCredentials' in xhr)
            {
                xhr.withCredentials = true;
            }
            else if (any = window.XDomainRequest)
            {
                xhr = new any();
            }
        }
        
        if ((any = self.timeout) > 0)
        {
            self.__timer = setTimeout(function () {

                xhr.abort();
                self.fail('timeout');

            }, any);
        }

        xhr.onreadystatechange = function () {

            ajax_done(self, xhr, url);
        };
        
        xhr.open(self.method, url, self.async);
          
        if (any = self.header)
        {
            for (var name in any)
            {
                xhr.setRequestHeader(name, any[name]);
            }
        }

        xhr.setRequestHeader('Content-Type', self.contentType);

        if (data)
        {
            data = flyingon.encode(data);
            xhr.setRequestHeader('Content-Length', data.length);
        }

        xhr.send(data);
    };
    

    //处理响应结果
    function ajax_done(self, xhr, url) {

        var any = xhr.readyState;

        if (any === 4)
        {
            if (any = self.__timer)
            {
                clearTimeout(any);
                self.__timer = 0;
                any = void 0;
            }

            if (xhr.status < 300)
            {
                try
                {
                    switch (self.dataType)
                    {
                        case 'json':
                            self.resolve(flyingon.parseJSON(xhr.responseText));
                            break;
                            
                        case 'xml':
                            self.resolve(xhr.responseXML);
                            break;
                            
                        default:
                            self.resolve(xhr.responseText);
                            break;
                    }
                }
                catch (e)
                {
                    self.reject(e);
                }
            }
            else
            {
                self.reject(any = xhr.statusText);
            }
            
            //结束处理
            ajax_end(self, url, any);
            
            //清除引用
            self.xhr = self.onreadystatechange = null;
        }
        else
        {
            self.notify(any);
        }
    };
    
    
    //ajax执行完毕
    function ajax_end(self, url, error) {
        
        var end = flyingon.Ajax.end;
        
        //执行全局ajax执行结束事件
        if (end)
        {
            for (var i = 0, l = end.length; i < l; i++)
            {
                end[i].call(self, url, error);
            }
        }
    };
        
    
    //jsonp_get
    function jsonp_get(self, url, list) {
        
        var target = jsonp_get,
            any = target.cache || (target.cache = []),
            name = any.pop() || 'flyingon_callback' + (++target.id || (target.id = 1));
        
        window[name] = function (data) {
        
            self.resolve(data);
            ajax_end(self, url);
        };
        
        list.push(self.jsonp || 'jsonp', '=', name);
        
        if (!self.version)
        {
            list.push('jsonp-version=' + (++target.version || (target.version = 1)));
        }
        
        flyingon.script(url = url + list.start + list.join('&'), function (src, error) {
            
            any.push(name);

            if (error)
            {
                self.reject(error);
                ajax_end(self, url, error);
            }

            window[name] = void 0;
            this.parentNode.removeChild(this);
            
            self = null;
        });
    };
    
    
    //jsonp_post
    function jsonp_post(self, url, list, data) {
                
        var iframe = jsonp_iframe(),
            flag;
        
        //处理url
        list.push('jsonp=post');
        url = url + list.start + list.join('&');
                    
        function load() {
          
            if (flag)
            {
                //IE67可能需要设置成同源的url才能取值
                this.contentWindow.location = 'about:blank';

                jsonp_end(self, url, this.contentWindow.name);
                jsonp_iframe(this);

                flyingon.dom_off(this, 'load', load);
                self = iframe = list = data = null;
            }
            else
            {
                flag = 1;
                
                //解决IE6在新窗口打开的BUG
                this.contentWindow.name = this.name; 

                //动态生成表单提交数据
                jsonp_form(this, url, data, self.method);
            }
        };
        
        //IE6不能触发onload事件, 如果要兼容ie6, 需要使用attachEvent绑定事件
        flyingon.dom_on(iframe, 'load', load);
        
        iframe.src = 'about:blank';
        document.head.appendChild(iframe);
    };
    
    
    //获取或缓存iframe
    function jsonp_iframe(iframe) {
        
        var any = jsonp_iframe.cache || (jsonp_iframe.cache = []);
        
        if (iframe)
        {
            any.push(iframe);
            iframe.parentNode.removeChild(iframe);
        }
        else
        {
            iframe = any.pop();
            
            if (!iframe)
            {
                iframe = document.createElement('iframe');
                iframe.name = 'jsonp-iframe';
            }
            
            return iframe;
        }
    };
    

    //生成jsonp提交表单
    function jsonp_form(iframe, url, data, method) {
        
        var array = ['<form id="form" enctype="application/x-www-form-urlencoded"'];
        
        array.push(' action="', url, '" method="', 'GET', '">'); //method || 'POST'
        
        for (var name in data)
        {
            array.push('<input type="hidden" name="', name, '"');
            
            if (typeof (name = data[name]) === 'string')
            {
                name = name.replace(/"/g, '\\"');
            }
            
            array.push(' value="', name, '" />');
        }
        
        array.push('</form>', '<script>form.submit();</script>');
        
        iframe.contentWindow.document.write(array.join(''));
    };
    

    //jsonp返回结果处理
    function jsonp_end(self, url, text) {

        try
        {
            self.resolve(flyingon.parseJSON(text));
            ajax_end(self, url);
        }
        catch (e)
        {
            self.reject(e);
            ajax_end(self, url, e);
        }
    };

    

});



//自定义ajax开始提交方法
flyingon.ajaxStart = function (fn) {

    (flyingon.Ajax.start || (flyingon.Ajax.start = [])).push(fn);
};


//自定义ajax执行结束方法
flyingon.ajaxEnd = function (fn) {

    (flyingon.Ajax.end || (flyingon.Ajax.end = [])).push(fn);
};


//ajax提交(默认为GET方式提交)
flyingon.ajax = function (url, options) {

    return new flyingon.Ajax().send(url, options);
};


//POST提交
//在IE6时会可能会出错, asp.net服务端可实现IHttpAsyncHandler接口解决些问题 
flyingon.ajaxPost = function (url, options) {

    options = options || {};
    options.method = 'POST';

    return new flyingon.Ajax().send(url, options);
};


//jsonp get提交
flyingon.jsonp = function (url, options) {

    options = options || {};
    options.dataType = 'jsonp';

    return new flyingon.Ajax().send(url, options);
};


//jsonp post提交
//服务器需返回 <script>window.name = 'xxx';</script> 形式的内容且不能超过2M大小
flyingon.jsonpPost = function (url, options) {

    options = options || {};
    options.dataType = 'jsonp';
    options.method = 'POST';

    return new flyingon.Ajax().send(url, options);
};




//资源加载
(function (flyingon) {



    var create = flyingon.create,

        require_version = '', //引入资源版本

        version_files = create(null), //特殊指定的引入资源版本

        path_map = create(null), //相对地址对应绝对地址映射关系

        require_merge = create(null), //引入资源合并关系
        
        i18n_cache = create(null), //本地化信息集合
        
        change_files = create(null), //待切换资源文件集合

        require_keys = { //引入资源变量
            
            layout: 'default', //当前布局
            skin: 'default', //当前皮肤
            i18n: navigator.language || 'zh-CN'    //当前本地化名称
        };



    //资源加载函数
    function require(depends, callback) {

        if (depends)
        {
            switch (typeof depends)
            {
                case 'string':
                    require.require([require.path(depends)], callback);
                    return;

                case 'function':
                    depends.call(flyingon, flyingon);
                    return;
            }
            
            if (depends instanceof Array)
            {
                var list = [],
                    url;

                for (var i = 0, l = depends.length; i < l; i++)
                {
                    if ((url = depends[i]) && typeof url === 'string')
                    {
                        list.push(require.path(url));
                    }
                }

                if (list.length > 0)
                {
                    require.require(list, callback);
                    return;
                }
            }
        }
        
        if (typeof callback === 'function')
        {
            callback.call(flyingon, flyingon);
        }
    };


    //根目录
    require.__root_path = '';


    //相对基础目录
    require.__base_path = '';



    //指定引入资源起始路径
    require.base = function (path) {

        if (path === void 0)
        {
            return require.__base_path;
        }

        if (path && typeof path === 'string')
        {
            if (path.charAt(0) === '/')
            {
                path = require.__root_path + path.substring(1);
            }
            else if (path.indexOf('://') < 0)
            {
                path = require.__root_path + path;
            }
            
            if (path.charAt(path.length - 1) !== '/')
            {
                path += '/';
            }
        }
        else
        {
            path = require.__root_path;
        }

        require.__base_path = path;
    };


    //指定引入资源版本号
    require.version = function (version, files) {

        if (typeof version === 'string')
        {
            require_version = version;
        }
        else
        {
            files = version;
        }

        if (files)
        {
            var keys = version_files;
            
            for (var name in files)
            {
                keys[name] = files[name];
            }
        }
    };


    //指定引入资源合并关系
    require.merge = function (values) {

        if (values)
        {
            var keys = require_merge,
                value;
            
            for (var name in values)
            {
                if (typeof (value = values[name]) === 'string')
                {
                    keys[value] = name;
                }
                else
                {
                    for (var i = 0, l = value.length; i < l; i++)
                    {
                        keys[value[i]] = name;
                    }
                }
            }
        }
    };
    
        
    //转换相对地址为绝对地址
    require.path = function (url) {

        var file = url = require_merge[url] || url,
            change,
            name,
            index,
            any;

        //如果已经缓存则直接返回
        if (any = path_map[file])
        {
            return any;
        }

        //替换当前语言及主题
        if ((index = url.indexOf('{')) >= 0 && 
            (any = url.indexOf('}')) > index &&
            (name = url.substring(index + 1, any)) &&
            (any = require_keys[name]))
        {
            file = url.replace('{' + name + '}', any);
            
            if (any = path_map[file])
            {
                return any;
            }
        }
        else
        {
            change = false;
        }

        //添加版本号
        if (any = version_files[url] || require_version)
        {
            any = file + (url.indexOf('?') >= 0 ? '&' : '?') + 'require-version=' + any;
        }
        else
        {
            any = file;
        }

        //获取url绝对路径
        // '/xxx': 相对网站根目录
        // './xxx': 相对flyingon.js文件目录
        // 'xxx': 相对flyingon.js文件目录
        // '../xxx': 相对flyingon.js文件上级目录
        if (url.charAt(0) === '/')
        {
            any = require.__root_path + any.substring(1);
        }
        else if (url.indexOf('://') < 0)
        {
            any = require.__base_path + any;
        }
        
        //记录多语言及皮肤
        if (change !== false)
        {
            (change_files[name] || (change_files[name] = {}))[any] = url;
        }

        return path_map[file] = any;
    };
    
        
    
    //获取或设置资源变量值
    require.key = function (name, value, callback, set) {
        
        var keys = require_keys;
        
        if (!value)
        {
            return keys[name];
        }
        
        if (value && keys[name] !== value)
        {
            //设置当前变量
            keys[name] = value;

            set && set();
         
            if (keys = change_files[name])
            {
                require.__change(keys, name, callback);
            }
        }
    };
    


    //获取或设置当前皮肤
    flyingon.skin = function (name) {

        return require.key('skin', name);
    };
    
    
    //获取指定key的本地化信息
    flyingon.i18ntext = function (key, text) {

        return i18n_cache[key] || (text != null ? text : key);
    };


    //获取或设置当前本地化名称
    flyingon.i18n = function (name, values) {

        if (values && typeof values === 'object')
        {
            i18n(name, values);
        }
        else if (typeof name === 'object')
        {
            i18n(null, name);
        }
        else
        {
            return require.key('i18n', name, null, function () {
            
                //国际化时先清空缓存
                i18n_cache = create(null);

                if (typeof values === 'function')
                {
                    values();
                }
            });
        }
    };

    
    //定义国际化集合
    function i18n(name, values) {

        var keys = i18n_cache;
        
        if (name)
        {
            name += '.';

            for (var key in values)
            {
                keys[name + key] = values[key];
            }
        }
        else
        {
            for (name in values)
            {
                keys[name] = values[name];
            }
        }
    };
    
    

    //资源加载函数
    flyingon.require = require;



})(flyingon);




//资源加载
(function (flyingon) {



    var create = flyingon.create,

        require = flyingon.require, //资源加载函数

        require_keys = create(null), //所有资源文件集合加载状态 0:未加载 1:已请求 2:已响应 3:已执行

        require_back = create(null), //资源回溯关系
        
        require_wait = 0, //等待加载的请求数
        
        require_list = []; //当前要加载的资源集合
 


    //设置根目录
    require.__root_path = flyingon.absoluteUrl('/');
    

    //设置相对起始目录
    //如果当前js路径包含"flyingon/",则取此上级目录
    //否则取要目录
    require.__base_path = (function () {
        
        var url = flyingon.__script_src() || flyingon.absoluteUrl(''),
            index = url.indexOf('flyingon/');

        if (index >= 0)
        {
            return url.substring(0, index);
        }

        return require.__root_path;

    })();


    //切换皮肤或多语言资源
    require.__change = function (keys, name, callback) {
        
        var list = document.getElementsByTagName(name === 'skin' ? 'link' : 'script'),
            any;

        //删除原dom节点
        for (var i = list.length - 1; i >= 0; i--)
        {
            if ((any = list[i]) && keys[any.src || any.href])
            {
                any.parentNode.removeChild(any);
            }
        }

        list = [];

        for (any in keys)
        {
            if (keys[any])
            {
                list.push(require.path(keys[any]));

                //移除缓存
                require_keys[any] = 0;
            }
        }
        
        require.require(list, callback || function () {});
    };


                    
    //添加回调函数(有依赖时才会添加成功)
    require.callback = function (callback, args) {
      
        var list = require_list;

        if (list && list.length > 0)
        {
            (list.callback || (list.callback = [])).push(callback, args || [flyingon]);
            return true;
        }
    };


    //资源加载处理
    require.require = function (list, callback) {

        var keys = require_keys,
            back = require_back,
            items,
            src,
            css,
            value;

        //有callback则为按需加载, 否则为依赖加载
        items = callback ? [] : require_list;

        for (var i = 0, l = list.length; i < l; i++)
        {
            if ((src = list[i]) && (value = keys[src]) !== 3)
            {
                //样式
                if (src.indexOf(css || '.css') > 0)
                {
                    if (!value)
                    {
                        //标记css文件已经加载
                        keys[src] = 3; 

                        //创建link标签加载样式
                        flyingon.link(src);
                    }
                }
                else if (!items[src])
                {
                    //去重处理
                    items[src] = true;

                    //添加进资源列表
                    items.push(src);
                    
                    //设置回溯关系
                    (back[src] || (back[src] = [])).push(items);
                }
            }
        }

        //按需加载
        if (callback)
        {
            //未执行完成则注册回调
            if (items.length > 0)
            {
                items.callback = [callback, [flyingon]];
                load_script(items);
            }
            else //已经加载完成则直接执行回调
            {
                callback.call(flyingon, flyingon);
            }
        }
    };

       
    //加载引入资源
    function load_script(list) {

        //乱序加载测试
        //list.sort(function(a, b) { return Math.random() > 0.5 ? -1 : 1; });

        var keys = require_keys,
            src;
        
        for (var i = 0, l = list.length; i < l; i++)
        {
            if (!keys[src = list[i]])
            {
                //标记已发送请求
                keys[src] = 1;

                //增加待请求数量
                require_wait++;

                //创建加载脚本标签
                flyingon.script(src, load_done);
            }
        }
    };

    
    //脚本加载完毕后处理
    function load_done() {

        var keys = require_keys,
            back = require_back,
            list = require_list,
            wait = --require_wait, //同步待请求的数量
            src = this.src,
            index = list.indexOf(src);
        
        //移除自身引用
        if (index >= 0)
        {
            list.splice(index, 1);
        }

        //如果资源中包含需引入的资源则继续加载
        if (list.length > 0)
        {
            //初始化当前引入对象
            require_list = [];
            
            //标记请求已响应未执行
            keys[src] = 2;
            
            //设置回溯父地址
            list.src = src;

            //继续加载资源
            load_script(list);
        }
        else
        {
            //标记请求已执行
            keys[src] = 3;
            
            //回溯检测
            check_back(keys, back, src);
        }
        
        //如果没有待发送的请求则表示有循环引用
        if (!wait)
        {
            check_cycle(keys, back);

            if (require.wait)
            {
                require.wait();
                require.wait = null;
            }
        }
    };
    
    
    //回溯检测引入的资源是否已加载完成
    function check_back(keys, back, src) {
      
        var items = back[src],
            list,
            parent,
            any;

        //处理完毕则移除回溯关系
        delete back[src];

        if (!items)
        {
            return;
        }
        
        //循环检测
        for (var i = items.length - 1; i >= 0; i--)
        {
            list = items[i];
            
            if ((any = list.indexOf(src)) >= 0)
            {
                list.splice(any, 1);
            }
            
            if (list.length > 0)
            {
                continue;
            }

            //移除当前项
            items.splice(i, 1);

            //如果有回溯
            if (any = list.src)
            {
                //标记请求已执行
                keys[any] = 3;

                //添加回溯
                (parent || (parent = [])).push(any);
            }
            
            //执行回调
            if (any = list.callback)
            {
                list.callback = null;
                
                for (var j = 0, l = any.length; j < l; j++)
                {
                    any[j++].apply(flyingon, any[j]);
                }
            }
        }

        //继续向上回溯检测
        if (parent)
        {
            for (var i = 0, l = parent.length; i < l; i++)
            {
                check_back(keys, back, parent[i]);
            }
        }
    };
    
    
    //检测循环引用, 如果存在则打破(最先移除最后发起的请求)
    function check_cycle(keys, back) {
        
        var names = [],
            src,
            list;
        
        for (src in back)
        {
            names.push(src);
        }
        
        for (var i = names.length - 1; i >= 0; i--)
        {
            if ((list = back[src = names[i]]) && has_cycle(back, list, src))
            {
                //移除循环引用
                for (var j = i; j >= 0; j--)
                {
                    list = back[names[j]];
                    
                    if (!list)
                    {
                        continue;
                    }
                    
                    for (var k = list.length - 1; k >= 0; k--)
                    {
                        if (list[k] && list[k].src === src)
                        {
                            check_back(keys, back, src);
                            break;
                        }
                    }
                }
            }
        }
    };
    
    
    //检测是否存在循环引用
    function has_cycle(back, list, src) {
        
        var name, any;
        
        for (var i = list.length - 1; i >= 0; i--)
        {
            if ((any = list[i]) && (name = any.src))
            {
                if (name === src)
                {
                    return true;
                }
                
                if ((any = back[name]) && has_cycle(back, any, src))
                {
                    return true;
                }
            }
        }
    };



    //加载完毕后处理
    require.done = function (callback) {

        if (require_wait > 0)
        {
            require.wait = callback;
        }
        else
        {
            callback();
        }
    };
    
        
    

    //加载组件
    flyingon.load = function (url, callback) {

        if (url)
        {
            if (url.indexOf('.js') > 0)
            {
                flyingon.require(url, callback);
            }
            else
            { 
                flyingon.ajax(flyingon.require.path(url)).done(function (html) {

                    html && html_load(url, html, callback);

                }).fail(function (error) {
                    
                    console && console.error(error);
                });
            }
        }
    };


    function html_load(url, html, callback) {

        var template = {},
            script = [];

        //抽出模板和脚本
        html.replace(/<(script|template|style)([^>]*)>\s*([\s\S]*?)\s*<\/\1>/gm, function (_, type, head, text) {

            switch (type)
            {
                case 'template':
                    if (head = head.match(/id="([^"]+)"|'([^']+)'/))
                    {
                        template['#' + (head[1] || head[2])] = text.replace(/[\r\n]+\s*/gm, '').replace(/(['"])/gm, '\\$1');
                    }
                    break;

                case 'link':
                    if (head = head.match(/href="([^"]+)"|'([^']+)'/))
                    {
                        flyingon.link(head[1] || head[2]);
                    }
                    break;

                case 'style':
                    flyingon.style(text);
                    break;

                case 'script':
                    if (head = head.match(/src=("[^"]"|'[^']')/))
                    {
                        script.push('flyingon.require(', head[1], ');\n');
                    }
                    else
                    {
                        script.push('flyingon.defineModule(function () {\n\n\n\n', text, '\n\n\n\n});\n\n');
                    }
                    break;
            }
        });

        if (script.length > 0)
        {
            script.push('\n\n//# sourceURL=', url);
            
            html = script.join('');

            for (var name in template)
            {
                html = html.replace(new RegExp(name, 'gm'), template[name]);
            }

            flyingon.globalEval(html);
        }

        flyingon.require.done(callback);
    };



})(flyingon);




(function () {



    //插件缓存
    var cache = flyingon.create(null);


    //一次只能加载一个插件
    var loading = [];


    //加载插件
    function load_plugin(url, callback) {

        var value = cache[url];

        if (value)
        {
            if (value instanceof Array)
            {
                callback && value.push(callback);
            }
            else
            {
                callback && callback(value);
            }

            return;
        }

        loading.push(url, callback);

        if (loading.length > 2)
        {
            return;
        }

        value = cache[url] = [];
        callback && value.push(callback);

        //注册插件加载回调
        flyingon.__load_plugin = function (Class) {

            cache[url] = Class;
        };

        flyingon.load(url, function () {

            var Class = cache[url],
                any = value;

            flyingon.__load_plugin = null;

            //移除待加载项
            loading.splice(0, 2);

            if (Class instanceof Array)
            {
                cache[url] = null;
                throw '"' + url + '" not include any flyingon.Plugin!';
            }

            for (var i = 0, l = any.length; i < l; i++)
            {
                any[i](Class);
            }

            if ((any = loading).length > 0)
            {
                load_plugin(any.shift(), any.shift());
            }
        });

    };



    //url:              url, 包含插件地址及多级hash控制
    //options.text:     页头文字
    //options.icon:     页头图标
    //options.closable: 页签是否可关闭
    //options.target:   打开页面方式 _blank:在新页面打开 _self:在当前页面打开 other:在指定key为指定值的页面中打开
    function route(tab, url, options) {

        var page, url, any;
        
        if (!tab || !(tab instanceof flyingon.Tab))
        {
            throw 'rout tab must be a flyingon.Tab!';
        }

        if (!url || !(url = url.replace(/^[#!]+/g, '')))
        {
            throw 'route options.url can not be empty!';
        }

        if (!tab.__on_route)
        {
            tab.on('tab-change', route.__tab_change);
            tab.__on_route = true;
        }

        //打开页面方式(未设置页头时永远在当前页面打开)
        switch (any = tab.header() ? options.target : '_self')
        {
            case '_blank': //在新页面打开
                any = null;
                break;

            case '_self': //在当前页面打开
                if ((page = tab.selectedPage()) && page.url === url)
                {
                    return;
                }

                any = null;
                break;

            default: //在指定的target名称中打开
                if ((page = tab.findByKey(any)) && page.url === url)
                {
                    if (!page.selected())
                    {
                        tab.selectedPage(page, 'route');
                        
                        page.route.update();
                        page[0].openPlugin(page.route.next(), false);
                    }

                    return;
                }
                break;
        }
        
        if (page)
        {
            page[0].closePlugin();
            page.splice(0);
        }
        else
        {
            tab.push(page = new flyingon.TabPage().layout('fill'));
        }

        //设置页面key
        if (any)
        {
            page.key(any);
        }

        new Root().load(route.current = page, url, options);
    };


    //预加载hash插件
    route.preload = function (hash) {

        if (hash && (hash = hash.replace(/^[#!]+/g, '')))
        {
            load_plugin(hash.split('#')[0]);
        }
    };

    

    //路由
    flyingon.route = route;



    var Root = Object.extend(function () {



        //插件地址
        this.plugin = '';



        this.load = function (page, url, options) {

            var any;

            page.route = this;

            route.__update(page.url = this.url = url);

            //检测是否以iframe方式加载
            if (url.indexOf('iframe:') === 0)
            {
                url = url.substring(7);
            }
            else
            {
                this.parse(url);
                
                if (any = options.icon)
                {
                    page.icon(any);
                }

                if (any = options.text)
                {
                    page.text(any);
                }
                else
                {
                    page.parent.header(0);
                }

                page.closable(options.closable !== false);
                page.parent.selectedPage(page, 'route');
 
                any = this;

                load_plugin(this.plugin, function (Class) {

                    var route = any,
                        plugin;

                    page.push(plugin = new Class());

                    plugin.loadPlugin(route = route.next());
                    plugin.openPlugin(route, true);

                    page = any = null;

                    //立即更新视图
                    flyingon.update();
                });
            }
        };


        //解析url
        this.parse = function (url) {

            var tokens = url.split('#'),
                last = this, 
                any;

            this.plugin = tokens[0];

            for (var i = 1, l = tokens.length; i < l; i++)
            {
                if (any = tokens[i])
                {
                    last = last.__next = new Route(this, any);
                }
            }
        };


        //获取下一个参数
        this.next = function () {

            return this.__next || (this.__next = new Route(this, ''));
        };


        //更新hash
        this.update = function () {

            var url = this.plugin,
                next = this,
                value;

            while ((next = next.__next) && (value = next.value))
            {
                url += '#' + value;
            }
 
            route.__update(url);
        };


    }, false);



    var Route = Object.extend(function () {

        
        //当前hash值
        this.value = '';


        this.init = function (root, value) {

            this.__root = root;
            this.value = value;
        };


        //修改当前hash值
        this.change = function (value) {

            this.value = '' + value;
            this.__root.update();
        };


        //清除后述参数
        this.clear = function () {

            this.__next = null;
            this.__root.update();
        };


        //获取下一个参数
        this.next = function () {

            return this.__next || (this.__next = new Route(this.__root, ''));
        };


        //分发至指定控件
        this.dispatch = function (control) {

            var fn;

            if (control)
            {
                if (fn = control.subscribeRoute)
                {
                    fn.call(control, this);
                }
                else
                {
                    for (var i = 0, l = control.length; i < l; i++)
                    {
                        if (fn = control[i].subscribeRoute)
                        {
                            fn.call(control[i], this);
                        }
                    }
                }
            }
        };


    }, false);



})();




(function () {



    var callback = [];

    var hash = location.hash.replace(/^[#!]+/, '');

    
    //打开页面有hash时需处理
    if (callback.hash = hash)
    {
        //预加载插件资源
        flyingon.route.preload(hash);
    }


    //侦听路由变化
    this.listen = function (fn) {

        if (typeof fn === 'function')
        {
            var hash = callback.hash;

            callback.push(fn);

            if (hash)
            {
                callback.hash = '';
                execute(hash, false);
            }
        }
    };


    //定制页面变更事件
    this.__tab_change = function (e) {
        
        if (e.target === this)
        {
            var page = flyingon.route.current = e.current;

            if (page)
            {
                page.route.update();
                e.tag !== 'route' && execute(page.url, true);
            }
            else
            {
                execute(location.hash = hash = '', true);
            }
        }
    };


    //更新路由地址
    this.__update = function (url) {
        
        location.hash = hash = url ? '#!' + url : ''; 
    };


    function execute(hash, route) {

        var list = callback;

        for (var i = 0, l = list.length; i < l; i++)
        {
            list[i](hash, route); //第二个参数标记是路由还是切换
        }
    };


    //执行路由
    function route() {

        if (location.hash !== hash)
        {
            execute(location.hash.replace(/^[#!]+/g, ''), false);
        }
    };


    //定时检测hash
    function check() {

        route();
        setTimeout(check, 200);
    };


    if ('onhashchange' in window)
    {
        flyingon.dom_on(window, 'hashchange', route);
    }
    else
    {
        setTimeout(check, 200);
    }


}).call(flyingon.route);





/*


本系统选择器从按照左到右的顺序解析, 请注意相关性能


本系统支持的基础选择器如下(注:本系统不支持html标签选择器):

*                       通用控件选择器
.N                      class选择器
#N                      id选择器
N                       类型选择器


本系统支持的组合选择器如下:

A,B                     或者选择器
A B                     后代选择器
A>B                     子选择器
A+B                     毗邻选择器
A~B                     后续兄弟选择器
AB                      并且选择器


本系统支持的属性选择器如下:

[name]                  具有name属性的控件
[name=value]            name属性值等于value的控件
[name~=value]           name属性值有多个空格分隔,其中一个值等于value的控件
[name|=value]           name属性值有多个连字号分隔(hyphen-separated)的值,其中一个值以value开头的控件, 主要用于lang属性, 比如en,en-us,en-gb等等
[name^=value]           name属性值以value开头的控件
[name$=value]           name属性值以value结尾的控件
[name*=value]           name属性值包含value的控件


本系统支持的伪类控件如下:

:focus                  控件有焦点
:enabled                控件可用
:disabled               控件被禁用
:checked                控件已选中

:has(selector)          控件下属子控件包含选择器selector规定的控件
:not(selector)          控件下属子控件不包含选择器selector规定的控件

:empty                  控件不包含任何子控件

:only                   控件是父控件中的唯一子控件
:first                  控件是父控件中的第一个子控件
:last                   控件是父控件中的最后一个子控件
:odd                    控件在父控件中的索引号是单数, 索引从0开始
:even                   控件在父控件中的索引号是双数, 索引从0开始
:eq(n)                  控件在父控件中的索引号等于n, n<0表示倒序, 索引从0开始
:gt(n)                  控件在父控件中的索引号大于n, 索引从0开始
:lt(n)                  控件在父控件中的索引号小于n, 索引从0开始


本系统不支持css伪类及伪元素


*/



//解析选择器
(function () {
        
    
    
    //解析缓存
    var parse_cache = flyingon.create(null);
    
    

    //解析选择器
    function parse(tokens, index) {

        var Class = flyingon.Selector_node,
            relation = ' ',
            nodes, 
            node, 
            token;

        while (token = tokens[index++])
        {
            //switch代码在chrome下的效率没有IE9好,不知道什么原因,有可能是其操作非合法变量名的时候性能太差
            switch (token)
            {
                case '#':   //id选择器标记
                case '.':   //class选择器标记
                    node = new Class(relation, token, tokens[index++], node);
                    relation = '';
                    break;

                case '*':  //全部元素选择器标记
                    node = new Class(relation, '*', '*', node);
                    relation = '';
                    break;

                case ' ':  //后代选择器标记
                case '\t':
                    if (!relation) //忽略其它类型后的空格
                    {
                        relation = ' ';
                    }
                    break;

                case '>':  //子元素选择器标记
                case '+':  //毗邻元素选择器标记
                case '~':  //之后同级元素选择器标记
                    relation = token;
                    break;

                case ',':  //组合选择器标记
                    if (node)
                    {
                        nodes = nodes || new flyingon.Selector_nodes();
                        nodes[nodes.length++] = node.top;
                    }

                    node = null;
                    relation = ' ';
                    break;

                case '[': //属性 [name[?="value"]]
                    if (!node || relation) //未指定节点则默认添加*节点
                    {
                        node = new Class(relation, '*', '*', node);
                        relation = '';
                    }

                    index = parse_property(node, tokens, index);
                    break;

                case ':': //伪类
                    if (!node || relation) //未指定节点则默认添加*节点
                    {
                        node = new Class(relation, '*', '*', node);
                        relation = '';
                    }

                    token = new flyingon.Selector_pseudo(node, tokens[index++]);
                    
                    //处理参数
                    if (tokens[index] === '(')
                    {
                        index = parse_pseudo(token, tokens, ++index);
                    }
                    break;

                default: //类名 token = ""
                    node = new Class(relation, '', token, node);
                    relation = '';
                    break;
            }
        }
        
        if (nodes)
        {
            if (node)
            {
                nodes[nodes.length++] = node.top;
            }
            
            return nodes;
        }

        return node && node.top || node;
    };


    //解析属性
    function parse_property(node, tokens, index) {

        var target, token, any;

        while (token = tokens[index++])
        {
            switch (token)
            {
                case ']':
                    return index;

                case '*': // *= 包含属性值XX
                case '^': // ^= 属性值以XX开头
                case '$': // $= 属性值以XX结尾
                case '~': // ~= 匹配以空格分隔的其中一段值 如匹配en US中的en
                case '|': // |= 匹配以-分隔的其中一段值 如匹配en-US中的en
                    if (target)
                    {
                        target.relation = token;
                    }
                    break;

                case '=':
                    if (target)
                    {
                        target.relation += '=';
                    }
                    break;

                case ' ':
                case '\t':
                    break;

                default:
                    if (target)
                    {
                        switch (token)
                        {
                            case 'undefined':
                                token = undefined;
                                break;
                                
                            case 'null':
                                token = null;
                                break;
                                
                            case 'true':
                                token = true;
                                break;
                                
                            case 'false':
                                token = false;
                                break;
                                
                            default:
                                if ((any = token.charAt(0)) === '"' || any === "'")
                                {
                                    token = token.substring(1, token.length - 1);
                                }
                                else
                                {
                                    token = +token;
                                }
                                break;
                        }
                        
                        target.value = token;
                    }
                    else
                    {
                        target = new flyingon.Selector_property(node, token);
                    }
                    break;
            }
        }

        return index;
    };
    

    //解析伪类参数
    function parse_pseudo(target, tokens, index) {

        var start = index,
            flag = 1,
            any;
        
        while (flag && (any = tokens[index++]))
        {
            switch (any)
            {
                case '(':
                    flag++;
                    break;
                    
                case ')':
                    flag--;
                    break;
            }
        }
        
        any = tokens.slice(start, index - 1).join('');

        switch (target.name)
        {
            case 'eq':
            case 'gt':
            case 'lt':
                any |= 0;
                break;
        }
        
        target.value = any;
        return index;
    };
    
        
    //创建解析选择器方法
    flyingon.__parse_selector = function (selector, cache) {

        if (!selector || typeof selector !== 'string')
        {
            return null;
        }
        
        if (cache !== false && (cache = parse_cache[selector]))
        {
            return cache;
        }
        
        cache = selector.match(/"[^"]*"|'[^']*'|[\w-]+|[*.#\[\]:(), \t>+~=|^$]/g);
        return parse_cache[selector] = parse(cache, 0);
    };

    
})();



//选择器节点类
flyingon.Selector_node = Object.extend(function () {
    
    

    this.init = function (relation, type, name, node) {
       
        this.find = this[this.relation = relation];
        this.filter = this[this.type = type];
        this.name = name;
        
        if (node)
        {
            if (relation)
            {
                node.next = this;
            }
            else
            {
                node[node.length++] = this;
            }
            
            this.top = node.top || node;
        }
        else
        {
            this.top = this;
        }
    };
    
    
        
    //关系符
    this.relation = '';
    
    
    //节点类型
    this.type = '';
    
    
    //节点名称
    this.name = '';
    
    
    //子项数
    this.length = 0;
    
    
    //下一节点
    this.next = null;
    
    
    
    //选择节点
    this.select = function (controls) {
        
        var index, any;
        
        controls = this.find(controls);

        if (controls[0])
        {
            index = 0;

            while (any = this[index++])
            {
                controls = any.filter(controls);
            }

            if (controls[0] && (any = this.next))
            {
                controls = any.select(controls);
            }
        }

        return controls;
    };
    
    
    //检查控件是否符合选择器要求
    this.check = function (controls) {
    
        var index = 0,
            any;
        
        while (any = this[index++])
        {
            if (!(controls = any.filter(controls, [])).length)
            {
                return controls;
            }
        }

        return (any = this.next) ? any.find(controls) : controls;
    };
    
    
    
    this[''] = function (controls, cache) {

        var name = this.name;
        return name ? flyingon.__find_type(controls, name) : [];
    };
    
        
    this['*'] = function (controls, cache) {

        return controls;
    };
    
    
    this['.'] = function (controls, cache) {

        var name = this.name;;
        return name ? flyingon.__find_class(controls, name) : [];
    };
    

    this['#'] = function (controls, cache) {

        var name = this.name;;
        return name ? flyingon.__find_id(controls, name) : [];
    };
    
    
    
    //后代选择器
    this[' '] = function (controls) {
        
        var index = 0,
            exports,
            item,
            any;
        
        while (item = controls[index++])
        {
            if (item.length > 0 && item.all)
            {
                any = item.all();

                if (exports)
                {
                    any.push.apply(exports, any);
                }
                else
                {
                    exports = any;
                }
            }
        }

        if (exports && exports[0])
        {
            return this.filter(exports, 1);
        }
 
        return exports || [];
    };

    
    //子控件选择器
    this['>'] = function (controls) {

        var index = 0,
            exports = [],
            item,
            any;

        while (item = controls[index++])
        {
            if (item.length > 0)
            {
                exports.push.apply(exports, item);
            }
        }

        return exports[0] && this.filter(exports, 2) || exports;
    };
    
    
    //毗邻控件选择器
    this['+'] = function (controls) {

        var exports = [],
            index = 0,
            length = 0,
            item;

        while (item = controls[index++])
        {
            if (item = item.nextSibling)
            {
                exports[length++] = item;
            }
        }
 
        return exports[0] ? this.filter(exports) : exports;
    };
    
    
    //后续兄弟控件选择器
    this['~'] = function (controls) {

        var exports = [],
            index = 0,
            length = 0,
            item;
        
        while (item = controls[index++])
        {
            while (item = item.nextSibling)
            {
                exports[length++] = item;
            }
        }
 
        return exports[0] ? this.filter(exports) : exports;
    };

    
    
}, false);



//复合选择器节点类
flyingon.Selector_nodes = Object.extend(function () {
    
    
    
    this.type = ',';
    
    
    //子节点数量
    this.length = 0;
    
    
    //选择节点
    this.select = function (controls, exports) {
        
        var index = 1,
            list,
            item;
        
        if (item = this[0])
        {
            exports = item.select(controls, exports);

            while (item = this[index++])
            {
                list = item.select(controls, []);

                if (list.length > 0)
                {
                    exports.push.apply(exports, list);
                }
            }
        }

        return exports;
    };
    
    
    
}, false);



//选择器属性类
flyingon.Selector_property = Object.extend(function () {
    
    
    
    this.init = function (node, name) {
       
        this.name = name;
        node[node.length++] = this;
    };
    
    
    
    //节点类型
    this.type = '[]';
    
    
    //属性名称
    this.name = '';
    
    
    //关系符
    this.relation = '';
    
    
    //属性值
    this.value = '';



    this.filter = function (controls) {

        var exports = [],
            name = this.name,
            fn;

        if (name && (fn = this[this.relation]))
        {
            fn.call(this, controls, name, exports, 0);
        }

        return exports;
    };
    
    
    
    this[''] = function (controls, name, exports, length) {
        
        var index = 0,
            item;

        while (item = controls[index++])
        {
            if (item[name] !== void 0)
            {
                exports[length++] = item;
            }
        }
    };
    
    
    this['='] = function (controls, name, exports, length) {
        
        var value = this.value,
            index = 0,
            item,
            any;

        while (item = controls[index++])
        {
            if ((any = item[name]) !== void 0)
            {
                if (typeof any === 'function')
                {
                    any = any.call(item);
                }

                if (any === value)
                {
                    exports[length++] = item;
                }
            }
        }
    };
    
    
    // *= 包含属性值XX (由属性解析)
    this['*='] = function (controls, name, exports, length) {
        
        var value = this.value,
            index = 0,
            item,
            any;

        while (item = controls[index++])
        {
            if ((any = item[name]) !== void 0)
            {
                if (typeof any === 'function')
                {
                    any = any.call(item);
                }

                any = '' + any;

                if (any.indexOf(value) >= 0)
                {
                    exports[length++] = item;
                }
            }
        }
    };
    
    
    // ^= 属性值以XX开头 (由属性解析)
    this['^='] = function (controls, name, exports, length) {
        
        var value = this.value,
            index = 0,
            item,
            any;

        while (item = controls[index++])
        {
            if ((any = item[name]) !== void 0)
            {
                if (typeof any === 'function')
                {
                    any = any.call(item);
                }

                any = '' + any;

                if (any.indexOf(value) === 0)
                {
                    exports[length++] = item;
                }
            }
        }
    };
    
    
    // $= 属性值以XX结尾 (由属性解析)
    this['$='] = function (controls, name, exports, length) {
        
        var value = this.value,
            count = value.length,
            index = 0,
            item,
            any;

        while (item = controls[index++])
        {
            if ((any = item[name]) !== void 0)
            {
                if (typeof any === 'function')
                {
                    any = any.call(item);
                }

                any = '' + any;

                if (any.lastIndexOf(value) === any.length - count)
                {
                    exports[length++] = item;
                }
            }
        }
    };
    
    
    // ~= 匹配以空格分隔的其中一段值 如匹配en US中的en (由属性解析)
    this['~='] = function (controls, name, exports, length) {
        
        var regex = this.regex || (this.regex = new RegExp('(?:^|\s+)' + this.value + '(?:\s+|$)')),
            index = 0,
            item,
            any;

        while (item = controls[index++])
        {
            if ((any = item[name]) !== void 0)
            {
                if (typeof any === 'function')
                {
                    any = any.call(item);
                }

                if (regex.text(any))
                {
                    exports[length++] = item;
                }
            }
        }
    };


    this['|='] = function (controls, name, exports, length) {
        
        var regex = this.regex || (this.regex = new RegExp('\b' + this.value + '\b')),
            index = 0,
            item,
            any;

        while (item = controls[index++])
        {
            if ((any = item[name]) !== void 0)
            {
                if (typeof any === 'function')
                {
                    any = any.call(item);
                }

                if (regex.text(any))
                {
                    exports[length++] = item;
                }
            }
        }
    };
        
    
}, false);



//选择器伪类类
flyingon.Selector_pseudo = Object.extend(function () {
    
    
    
    this.init = function (node, name) {
       
        this.name = name;
        node[node.length++] = this;
    };
    
    
    
    //节点类型
    this.type = ':';
    
    
    //伪类名称
    this.name = '';
    
    
    //伪类参数值
    this.value = 0;
    


    this.filter = function (controls) {

        var exports = [],
            name = this.name,
            fn;

        if (name && (fn = this[name]))
        {
            fn.call(this, controls, exports, 0);
        }

        return exports;
    };
    

    this.active = function (controls, exports, length) {

    };
    
    
    this.disabled = function (controls, exports, length) {

        var index = 0,
            item;

        while (item = controls[index++])
        {
            if ((item.__storage || item.__defaults).disabled)
            {
                exports[length++] = item;
            }
        }
    };
    

    this.enabled = function (controls, exports, length) {

        var index = 0,
            item;

        while (item = controls[index++])
        {
            if (!(item.__storage || item.__defaults).disabled)
            {
                exports[length++] = item;
            }
        }
    };

    
    this.checked = function (controls, exports, length) {

        var index = 0,
            item;

        while (item = controls[index++])
        {
            if ((item.__storage || item.__defaults).checked)
            {
                exports[length++] = item;
            }
        }
    };

    
    
    this.has = function (controls, exports, length) {

        var selector = this.value;

        if (selector)
        {
            selector = flyingon.__parse_selector(selector);

            
        }

        return controls;
    };
    
    
    this.not = function (controls, exports, length) {

    };
    
    

    this.empty = function (controls, exports, length) {

        var index = 0,
            item;

        while (item = controls[index++])
        {
            if (item.length <= 0)
            {
                exports[length++] = item;
            }
        }
    };
    
    
    this.only = function (controls, exports, length) {
        
        var index = 0,
            item;

        while (item = controls[index++])
        {
            if (item.parent.length === 1)
            {
                exports[length++] = item;
            }
        }
    };

    
    this.first = function (controls, exports, length) {

        var index = 0,
            item;

        while (item = controls[index++])
        {
            if (item = item.parent[0])
            {
                exports[length++] = item;
            }
        }
    };

        
    this.last = function (controls, exports, length) {

        var index = 0,
            item;

        while (item = controls[index++])
        {
            if (!item.nextSibling)
            {
                exports[length++] = item;
            }
        }
    };

    
    this.odd = function (controls, exports, length) {
        
        var value = this.value,
            index = 0,
            item,
            any;

        while (item = controls[index++])
        {
            if (!(((any = item.parent) && any.indexOf(item)) & 1))
            {
                exports[length++] = item;
            }
        }
    };
    
    
    this.even = function (controls, exports, length) {
        
        var value = this.value,
            index = 0,
            item,
            any;

        while (item = controls[index++])
        {
            if (((any = item.parent) && any.indexOf(item)) & 1)
            {
                exports[length++] = item;
            }
        }
    };
    
        
    this.eq = function (controls, exports, length) {
        
        var value = this.value,
            index = 0,
            item;

        while (item = controls[index++])
        {
            if (((any = item.parent) && any.indexOf(item)) === value)
            {
                exports[length++] = item;
            }
        }
    };
    
        
    this.gt = function (controls, exports, length) {

        var value = this.value,
            index = 0,
            item;

        while (item = controls[index++])
        {
            if (((any = item.parent) && any.indexOf(item)) > value)
            {
                exports[length++] = item;
            }
        }
    };

    
    this.lt = function (controls, exports, length) {

        var value = this.value,
            index = 0,
            item,
            any;

        while (item = controls[index++])
        {
            if (((any = item.parent) && any.indexOf(item)) < value)
            {
                exports[length++] = item;
            }
        }
    };

    
}, false);



//选择器查询类
flyingon.Query = Object.extend(function () {
    
    
    
    //选择器解析缓存
    var parse = flyingon.__parse_selector;
    

    //选择数量
    this.length = 0;
    
    
    this.init = function (selector, context) {
       
        var list, item, index, length, cache, any;
        
        if (context && (any = parse(selector)) && (list = any.select(context)) && (length = list.length) > 0)
        {
            index = this.length;
            cache = flyingon.create(null);

            //去重处理
            for (var i = 0; i < length; i++)
            {
                if ((item = list[i]) && (any = item.__uniqueId || item.uniqueId()) && !cache[any])
                {
                    cache[any] = true;
                    this[index++] = item;
                }
            }
        }
    };
    
    
    
    this.find = function (selector) {
        
        var target = new this.Class(selector, this);

        target.previous = this;
        return target;
    };


    //
    this.children = function (step, start, end) {

    };
    
    
    this.end = function () {
      
        return this.previous || this;
    };
    
        

    this.on = function (type, fn) {

        if (type && fn)
        {
            var index = 0,
                item;

            while (item = this[index++])
            {
                item.on(type, fn);
            }
        }
        
        return this;
    };
    
    
    this.once = function (type, fn) {

        if (type && fn)
        {
            var index = 0,
                item;

            while (item = this[index++])
            {
                item.once(type, fn);
            }
        }
        
        return this;
    };

    
    this.off = function (type, fn) {

        var index = 0,
            item;

        while (item = this[index++])
        {
            item.off(type, fn);
        }
        
        return this;
    };


    this.trigger = function (e) {

        if (e)
        {
            var index = 0,
                item;

            while (item = this[index++])
            {
                item.trigger.apply(item, arguments);
            }
        }
        
        return this;
    };

    

    this.hasClass = function (className) {

        var item;
        return className && (item = this[0]) ? item.hasClass(className) : false;
    };

    
    this.addClass = function (className) {

        if (className)
        {
            var index = 0,
                item;

            while (item = this[index++])
            {
                item.addClass(className);
            }
        }
        
        return this;
    };

    
    this.removeClass = function (className) {

        if (className)
        {
            var index = 0,
                item;

            while (item = this[index++])
            {
                item.removeClass(className);
            }
        }
        
        return this;
    };

    
    this.toggleClass = function (className) {

        if (className)
        {
            var index = 0,
                item;

            while (item = this[index++])
            {
                item.toggleClass(className);
            }
        }
        
        return this;
    };

    
    
}, false);




//控件渲染器
(function () {
    
    

    //是否右向顺序
    flyingon.rtl = false;



    var self = this;

    //注册的渲染器集合
    var registry_list = flyingon.create(null);

    //唯一id
    var uniqueId = flyingon.__uniqueId;

    //创建html的dom节点(给createView用)
    var dom_html = document.createElement('div');

    //margin border padding css样式缓存
    var sides_cache = flyingon.create(null);

    //css名称映射
    var css_map = flyingon.css_map(true);

    //style名称映射
    var style_map = flyingon.css_map();

    //定位属性映射
    var location_map = {

        32: ['minWidth', 'min-width'],
        64: ['maxWidth', 'max-width'],
        128: ['minHeight', 'min-height'],
        256: ['maxHeight', 'max-height']
    };




    //滚动条位置控制
    this.__scroll_html = '<div class="f-scroll" style="position:static;overflow:hidden;visibility:hidden;margin:0;border:0;padding:0;width:1px;height:1px;"></div>';

       
    //设置text属性名
    this.__text_name = 'textContent' in document.head ? 'textContent' : 'innerText';

    
    //是否支持auto尺寸
    this.__auto_size = 1;


    //是否设置padding
    this.padding = 1;
    



    function css_sides(value) {

        var any = +value;

        if (any === any)
        {
            return sides_cache[value] = (any | 0) + 'px';
        }

        return sides_cache[value] = value ? value.replace(/(\d+)(\s+|$)/g, '$1px$2') : '';
    };



    //创建控件视图
    this.createView = function (control, position) {

        var host = dom_html,
            view,
            any;

        this.render(any = [], control);

        host.innerHTML = any.join('');

        view = host.firstChild;
        host.removeChild(view); //需先从父节点移除,否则在IE下会被销毁

        host.innerHTML = '';

        if (position !== false && !(any = view.style).position)
        {
            any.position = 'relative';
        }

        this.mount(control, view);

        return view;
    };


    //渲染html
    this.render = function (writer, control, className, cssText) {

        writer.push('<div');

        this.renderDefault(writer, control, className, cssText);

        writer.push('></div>');
    };


    //渲染控件默认样式及属性
    this.renderDefault = function (writer, control, className, cssText) {

        var storage = control.__storage || control.__defaults,
            encode = flyingon.html_encode,
            html = control.__as_html,
            any;

        control.rendered = true;
        
        if (any = control.__id || storage.id)
        {
            writer.push(' id="', encode(any), '"');
        }

        writer.push(' class="', encode(control.fullClassName), 
            html ? ' f-html' : ' f-absolute', 
            className ? ' ' + className : '',
            '" style="');

        if (cssText)
        {
            writer.push(cssText);
        }

        if (any = control.__style)
        {
            this.__render_style(writer, control, any, encode);
        }

        if (any = control.__location_dirty)
        {
            control.__location_dirty = 0;

            if (html)
            {
                this.__render_location(writer, control, any);
            }
        }

        if (any = storage.border)
        {
            writer.push('border-width:', sides_cache[any] || css_sides(any), ';');
        }
        
        if ((any = storage.padding) && this.padding)
        {
            writer.push('padding:', sides_cache[any] || css_sides(any), ';');
        }

        if (!storage.visible)
        {
            writer.push('display:none;');
        }

        writer.push('"');
    };


    this.__render_style = function (writer, control, values, encode) {

        var map = css_map,
            value, 
            any;

        for (var name in values)
        {
            if (name === 'cssText' || (value = values[name]) === '')
            {
                continue;
            }

            switch (any = this[name])
            {
                case 1: //直接设置样式
                    writer.push(name, ':', encode(value), ';');
                    break;

                case 2: //需要检测前缀
                    writer.push(map[name], ':', encode(value), ';');
                    break;

                case 9: //特殊样式
                    (control.__style_patch || (control.__style_patch = {}))[name] = value;
                    break;

                default:
                    if (typeof any !== 'function')
                    {
                        if (any = map[name])
                        {
                            writer.push(any, ':', encode(value), ';');
                            self[name] = any === name ? 1 : 2; //直接设置样式标记为1,需要加前缀标记为2
                            break;
                        }

                        self[name] = 9; //标记为特殊样式
                    }
                    
                    if (!(any = control.__style_patch))
                    {
                        any = control.__view_patch || (control.__view_patch = {});
                        any = any.__style_patch = controls.__style_patch = {};
                    }

                    any[name] = value;
                    break;
            }
        }
    };


    this.__render_location = function (writer, control, dirty) {

        var values = control.__storage || control.__defaults,
            flag = 1,
            name,
            value,
            any;

        while (dirty >= flag)
        {
            if (dirty & flag)
            {
                switch (flag)
                {
                    case 1:
                    case 2:
                        if (value = values[name = flag === 1 ? 'width' : 'height'])
                        {
                            if (value === 'default' || value === 'auto')
                            {
                                writer.push(name, ':auto;');
                            }
                            else
                            {
                                writer.push(name, ':', value >= 0 ? value + 'px' : value, ';');
                            }
                        }
                        break;

                    case 4:
                        if (value = values.margin)
                        {
                            writer.push('margin:', sides_cache[value] || css_sides(value), ';');
                        }
                        break;

                    case 8:
                        if (value = values.border)
                        {
                            writer.push('border-width:', sides_cache[value] || css_sides(value), ';');
                        }
                        break;

                    case 16:
                        if (this.padding && (value = values.padding))
                        {
                            writer.push('padding:', sides_cache[value] || css_sides(value), ';');
                        }
                        break;

                    case 32:
                    case 64:
                    case 128:
                    case 256:
                        any = location_map[flag];

                        if (value = values[any[0]])
                        {
                            writer.push(any[1], ':', value > 0 ? value + 'px' : value, ';');
                        }
                        break;

                    case 512:
                    case 1024:
                        if (value = values[name = flag < 1000 ? 'left' : 'top'])
                        {
                            writer.push(name, ':', (any = +value) === any ? value + 'px' : value, ';');
                        }
                        break;
                }
            }

            flag <<= 1;
        }
    };




    //挂载视图
    this.mount = function (control, view) {

        var any;
        
        control.view = view;

        if (!(any = control.__uniqueId))
        {
            any = uniqueId;
            any[any = any.id++] = control;
        }

        view.flyingon_id = any;

        //应用补丁
        if (any = control.__view_patch)
        {
            control.__view_patch = null;
            this.__apply_patch(control, view, any);
        }

        //触发控件挂载过程
        if (any = control.onmount)
        {
            any.call(control, view);
        }
    };


    //取消视图挂载
    this.unmount = function (control, remove) {

        var view = control.view,
            any;

        if (view)
        {
            //触发注销控件挂载过程
            if (any = control.onunmount)
            {
                any.call(control, view);
            }

            control.view = null;

            if (remove !== false && (any = view.parentNode))
            {
                any.removeChild(view);
            }
        }
    };



    //更新顶级控件
    this.__update_top = function (control, width, height) {

        var view = control.view,
            index = view.className.indexOf(' f-rtl');

        control.__location_values = null;
        control.left = control.top = 0;

        control.measure(width, height, width, height, height ? 3 : 1);

        if (flyingon.rtl)
        {
            if (index < 0)
            {
                view.className += ' f-rtl';
            }
        }
        else if (index >= 0)
        {
            view.className = view.className.replace(' f-rtl', '');
        }
        
        if (control.__update_dirty || control.__arrange_dirty)
        {
            this.update(control);
        }
    };


    //更新视图
    this.update = function (control) {

        if (control.__as_html)
        {
            this.locate_html(control);
        }
        else
        {
            this.locate(control);
        }
    };


    //按照html方式定位
    this.locate_html = function (control) {

        var dirty = control.__location_dirty;
        
        if (dirty)
        {
            this.__locate_html(control);
        }

        control.__update_dirty = false;
    };


    //按照html方式定位控件
    this.__locate_html = function (control) {

        var style = control.view.style,
            values = control.__storage || control.__defaults,
            dirty = control.__location_dirty,
            flag = 1,
            name,
            value,
            any;

        control.__location_dirty = 0;

        while (dirty >= flag)
        {
            if (dirty & flag)
            {
                switch (flag)
                {
                    case 1:
                    case 2:
                        if (value = values[name = flag === 1 ? 'width' : 'height'])
                        {
                            if (value === 'default' || value === 'auto')
                            {
                                style[name] = 'auto';
                            }
                            else
                            {
                                style[name] = value >= 0 ? value + 'px' : value;
                            }
                        }
                        break;

                    case 4:
                    case 16:
                        value = values[name = flag === 4 ? 'margin' : 'padding'];
                        style[name] = sides_cache[value] || css_sides(value);
                        break;

                    case 8:
                        value = values.border;
                        style.borderWidth = sides_cache[value] || css_sides(value);
                        break;

                    case 32:
                    case 64:
                    case 128:
                    case 256:
                        any = location_map[flag];
                        value = values[name = any[0]];
                        style[name] = value > 0 ? value + 'px' : value;
                        break;

                    case 512:
                    case 1024:
                        value = values[name = flag < 1000 ? 'left' : 'top'];
                        style[name] = (any = +value) === any ? value + 'px' : value;
                        break;
                }
            }

            flag <<= 1;
        }
    };


    //定位控件
    this.locate = function (control) {

        var style = control.view.style,
            cache = control.__style_cache,
            value = this.__auto_size && control.__auto_size,
            left = control.offsetLeft,
            top = control.offsetTop,
            width = (value & 1) ? 'auto' : control.offsetWidth,
            height = (value & 2) ? 'auto' : control.offsetHeight,
            any;

        control.__update_dirty = false;

        if (any = !cache)
        {
            cache = control.__style_cache = {};
        }

        if (any || left !== cache.left)
        {
            //右向顺序设置right,否则设置left
            style[flyingon.rtl ? 'right' : 'left'] = (cache.left = left) + 'px';
        }

        if (any || top !== cache.top)
        {
            style.top = (cache.top = top) + 'px';
        }

        if (any || width !== cache.width)
        {
            cache.width = width;
            style.width = (value & 1) ? width : width + 'px';
        }

        if (any || height !== cache.height)
        {
            cache.height = height;
            style.height = (value & 2) ? height : height + 'px';
        }

        if (any = control.__location_dirty)
        {
            control.__location_dirty = 0;

            if (any & 8)
            {
                value = control.border();
                style.borderWidth = sides_cache[value] || css_sides(value);
            }

            if ((any & 16) && this.padding)
            {
                value = control.padding();
                style.padding = sides_cache[value] || css_sides(value);
            }
        }

        return cache;
    };



    //需要处理视图补丁的控件集合
    var controls = [];

    //子项变更补丁集合
    var children = [];

    //延迟更新队列
    var update_list = [];
    
    //更新定时器
    var update_delay;
    
        
    //立即更新所有控件
    flyingon.update = function () {
        
        var list = update_list,
            index = 0,
            item,
            node;

        if (update_delay)
        {
            clearTimeout(update_delay);
        }

        flyingon.__update_patch();
        
        while (item = list[index++])
        {
            if (item.__update_dirty)
            {
                if ((node = item.view) && (node = node.parentNode))
                {
                    item.renderer.__update_top(item, node.clientWidth, node.clientHeight);
                }
            }
            else           
            {
                switch (item.__arrange_dirty)
                {
                    case 2:
                        item.renderer.update(item);
                        break;

                    case 1:
                        update_children(item);
                        break;
                }
            }
        }
        
        list.length = update_delay = 0;
    };


    //递归更新子控件
    function update_children(control) {

        control.__arrange_dirty = 0;

        for (var i = 0, l = control.length; i < l; i++)
        {
            var item = control[i];

            switch (item.__arrange_dirty)
            {
                case 2:
                    item.renderer.update(item);
                    break;

                case 1:
                    update_children(item);
                    break;
            }
        }
    };
    

    //延时更新
    flyingon.__update_delay = function (control) {
      
        if (update_list.indexOf(control) < 0)
        {
            update_list.push(control);
            update_delay || (update_delay = setTimeout(flyingon.update, 0)); //定时刷新
        }
    };


    //更新所有挂起的dom补丁(在调用控件update前需要先更新补丁)
    flyingon.__update_patch = function () {

        var list = children,
            index = 0,
            item,
            view,
            any;

        //先处理子项变更
        while (item = list[index++])
        {
            if (any = item.__children_patch)
            {
                item.__children_patch = null;
                item.renderer.__children_patch(item, any);
            }
        }

        //再处理视图变更
        list = controls;
        index = 0;

        while (item = list[index++])
        {
            if ((any = item.__view_patch) && (view = item.view))
            {
                item.__view_patch = null;
                item.renderer.__apply_patch(item, view, any);
            }
        }

        children.length = controls.length = 0;
    };



    //设置属性值
    this.set = function (control, name, value) {

        var any = control.__view_patch;

        if (any)
        {
            any[name] = value;
        }
        else
        {
            (control.__view_patch = {})[name] = value;
            
            if (control.view)
            {
                controls.push(control);
                update_delay || (update_delay = setTimeout(flyingon.update, 0)); //定时刷新
            }
        }
    };


    //应用dom补丁
    this.__apply_patch = function (control, view, patch) {

        var fn, value;

        for (var name in patch)
        {
            //已处理过则不再处理
            if ((value = patch[name]) === null)
            {
                continue;
            }

            if (fn = this[name])
            {
                if (typeof fn === 'function')
                {
                    fn.call(this, control, view, value);
                }
            }
            else //作为属性处理
            {
                if (value || value === 0)
                {
                    view.setAttribute(name, value);
                }
                else
                {
                    view.removeAttribute(name);
                }
            }
        }
    };


    //样式补丁
    this.__style_patch = function (control, view, value) {

        var map = style_map,
            style = view.style,
            any;

        control.__style_patch = null;

        for (var name in value)
        {
            switch (any = this[name])
            {
                case 0: //不处理
                    break;

                case 1: //直接设置样式
                    style[name] = value[name];
                    break;

                case 2: //需要检测前缀
                    style[map[name]] = value[name];
                    break;

                case 9: //特殊样式
                    flyingon.css_value(view, name, value[name]);
                    break;

                default:
                    if (typeof any !== 'function')
                    {
                        if (any = map[name])
                        {
                            style[any] = value[name];
                            self[name] = any === name ? 1 : 2; //直接设置样式标记为1,需要加前缀标记为2
                        }
                        else
                        {
                            flyingon.css_value(view, name, value[name]);
                            self[name] = 9; //标记为特殊样式
                        }
                    }
                    else
                    {
                        any.call(this, control, view, value[name]);
                    }
                    break;
            }
        }
    };



    this.visible = function (control, view, value) {

        view.style.display = value ? '' : 'none';
    };


    this.focus = function (control) {

        control.view.focus();
    };


    this.blur = function (control) {

        control.view.blur();
    };



    //渲染子项
    this.__render_children = function (writer, control, items, start, end) {

        var item;

        while (start < end)
        {
            if (item = items[start++])
            {
                item.view || item.renderer.render(writer, item);
            }
        }
    };


    //挂载子控件
    this.__mount_children = function (control, view, items, start, end, node) {

        var item, any;

        while (start < end)
        {
            if (item = items[start++])
            {
                //如果子控件已经包含view
                if (any = item.view)
                {
                    view.insertBefore(any, node);
                }
                else //子控件不包含view则分配新渲染的子视图
                {
                    item.renderer.mount(item, node);
                    node = node.nextSibling;
                }
            }
        }
    };


    //取消挂载子控件
    this.__unmount_children = function (control) {

        for (var i = control.length - 1; i >= 0; i--)
        {
            var item = control[i];

            if (item && item.view && !item.parent)
            {
                item.renderer.unmount(item, false);
            }
        }
    };


    //排列
    this.__arrange = function (control) {

        var list = [],
            style = control.__style,
            auto = control.__auto_size,
            hscroll, 
            vscroll,
            any;

        if (auto & 1)
        {
            control.__hscroll = false;
        }
        else
        {
            //处理自动滚动
            switch (style && (style['overflow-x'] || style.overflow)) //有些浏览器读不到overflowX的值
            {
                case 'scroll':
                    control.__hscroll = true;
                    break;

                case 'hidden':
                    control.__hscroll = false;
                    break;
                    
                default:
                    hscroll = true;
                    break;
            }
        }

        if (auto & 2)
        {
            control.__vscroll = false;
        }
        else
        {
            switch (style && (style['overflow-y'] || style.overflow))
            {
                case 'scroll':
                    control.__vscroll = true;
                    break;

                case 'hidden':
                    control.__vscroll = false;
                    break;

                default:
                    vscroll = true;
                    break;
            }
        }

        //筛选出非隐藏控件
        for (var i = 0, l = control.length; i < l; i++)
        {
            if ((any = control[i]) && (any.__storage || any.__defaults).visible)
            {
                list.push(any);
            }
        }

        //排列
        flyingon.arrange(control, list, hscroll, vscroll);

        this.__sync_scroll(control);

        control.__arrange_dirty = 0;
    };


    //同步滚动条状态
    //overflow:auto在某些情况下可能会不准确,通过直接设置scroll或hidden解决些问题
    this.__sync_scroll = function (control) {

        var style = (control.view_content || control.view).style;

        style.overflowX = control.__hscroll ? 'scroll' : 'hidden';
        style.overflowY = control.__vscroll ? 'scroll' : 'hidden';
    };



    //注册子项变更补丁
    this.__children_dirty = function (control) {

        children.push(control);
        update_delay || (update_delay = setTimeout(flyingon.update, 0)); //定时刷新
    };


    //子项补丁
    this.__children_patch = function (control, patch) {

        for (var i = 0, l = patch.length; i < l; i++)
        {
            switch (patch[i++])
            {
                case 1: //增加子项
                    this.__insert_patch(control, patch[i++], patch[i]);
                    break;

                case 2: //删除子项
                    this.__remove_patch(control, patch[++i]);
                    break;
            }
        }
    };
    

    //插入子项
    this.__insert_patch = function (control, index, items) {

        var view = control.view_content || control.view;
        this.__unmount_html(control, view, items, 0, items.length, view.children[index] || null);
    };


    //插入未挂载的html片段
    this.__unmount_html = function (control, view, items, start, end, tag) {

        var writer = [],
            node = tag && tag.previousSibling,
            item;

        this.__render_children(writer, control, items, start, end);
        
        writer[0] && flyingon.dom_html(view, writer.join(''), tag);

        node = node && node.nextSibling || view.firstChild;

        this.__mount_children(control, view, items, start, end, node);
    };


    //移除子项
    this.__remove_patch = function (control, items) {

        var item, node;
        
        for (var i = 0, l = items.length; i < l; i++)
        {
            if (item = items[i])
            {
                //允许自动销毁且没有父控件则销毁控件
                if (item.autoDispose && !item.parent)
                {
                    item.dispose();
                }
                else if ((node = item.view) && (item = node.parentNode)) //否则从dom树移除
                {
                    item.removeChild(node);
                }
            }
        }
    };



    //控件顺序发生变化的补丁
    this.__view_order = function (control, view) {

        var item, last, node, tag;

        view = control.view_content || view;

        if ((last = view.lastChild) && last.className === 'f-scroll')
        {
            tag = last;
            last = last.previousSibling;
        }

        for (var i = control.length - 1; i >= 0; i--)
        {
            if ((item = control[i]) && (node = item.view))
            {
                if (node !== last)
                {
                    view.insertBefore(node, tag || null);
                }

                last = (tag = node).previousSibling;
            }
        }
    };

 

    //销毁视图
    this.dispose = function (control) {

        var view = control.view,
            any;

        if (view)
        {
            if (any = view.parentNode)
            {
                any.removeChild(view);
            }

            this.unmount(control);

            view.innerHTML = '';
        }
    };




    //创建渲染器或给渲染器取别名
    flyingon.renderer = function (name, parent, fn) {

        if (!name)
        {
            throw 'renderer name not allow empty!'
        }

        if (typeof parent === 'function')
        {
            fn = parent;
            parent = '';
        }
        else if (typeof fn !== 'function') //给指定的类型绑定渲染器
        {
            return;
        }
        
        if (parent && (parent = registry_list[parent]))
        {
            fn.__parent = parent;
        }

        registry_list[fn.__name = name] = fn;
    };


    //绑定渲染器至目标对象
    flyingon.renderer.bind = function (target, name) {

        var renderer = registry_list[name];

        if (renderer && typeof renderer === 'function')
        {
            renderer = init_renderer(renderer);
        }

        if (renderer)
        {
            target.renderer = renderer;
        }
        else if (!target.renderer)
        {
            target.renderer = self;
        }
    };


    //初始化渲染器
    function init_renderer(fn) {

        var parent = fn.__parent,
            target,
            name;

        parent = parent && init_renderer(parent) || self;

        if (name = fn.__name)
        {
            target = flyingon.create(parent);
            fn.call(target, parent);

            return registry_list[name] = target;
        }
    };



}).call(flyingon.create(null));




flyingon.renderer('HtmlElement', function (base) {



    var tags = flyingon.create(null);

    var check_tag = document.createElement('div');


    tags.div = 'div';
    tags.span = 'span';
    tags.input = 'input';


    this.__scroll_html = '';



    //渲染html
    this.render = function (writer, control, className, cssText) {

        var storage = control.__storage || control.__defaults,
            tagName, 
            any;

        //注:IE8下不支持自定义标签,不支持的标签全部使用div
        if (!(tagName = tags[any = control.tagName]))
        {
            check_tag.innerHTML = '<' + any + '></' + any + '>';
            tags[any] = tagName = check_tag.firstChild ? any : 'div';
        }

        //标注内容已渲染
        control.__content_render = true;

        writer.push('<', tagName);
        
        this.renderDefault(writer, control, className, cssText);
        
        writer.push('>');

        if (any = storage.text)
        {
            if (!storage.html)
            {
                any = flyingon.html_encode(any);
            }

            writer.push(any);
        }
        else if (control.length > 0 && control.__visible)
        {
            this.__render_children(writer, control, control, 0, control.length);
        }

        writer.push('</', tagName, '>');
    };


    
    this.mount = function (control, view) {

        base.mount.call(this, control, view);

        if (control.__content_render)
        {
            this.__mount_children(control, view, control, 0, control.length, view.firstChild);
        }
    };


    this.unmount = function (control) {

        this.__unmount_children(control);
        base.unmount.call(this, control);
    };



    //定位控件时
    this.locate = function (control) {

        base.locate.call(this, control);
        
        if (control.length > 0)
        {
            this.__locate_children(control);
        }
    };


    //按照html方式定位控件时
    this.locate_html = function (control) {

        var dirty = control.__location_dirty;
        
        if (dirty)
        {
            this.__locate_html(control);
        }

        control.__update_dirty = false;

        if (control.length > 0)
        {
            this.__locate_children(control);
        }
    };


    //定位子控件
    this.__locate_children = function (control) {

        for (var i = 0, l = control.length; i < l; i++)
        {
            var item = control[i];

            if (item && item.view)
            {
                item.renderer.locate_html(item);
            }
        }

        control.__arrange_dirty = 0;
    };



    this.__measure_auto = function (control, auto) {

        var view = control.view;

        if (auto & 2)
        {
            if (control.__content_render)
            {
                this.locate(control);
            }
            
            control.offsetHeight = view && view.offsetHeight || 0;
        }
    };



    this.text = function (control, view, value) {

        if (control.html())
        {
            view.innerHTML = value;
        }
        else
        {
            view[this.__text_name] = value;
        }
    };



});




flyingon.renderer('Label', function (base) {



    this.render = function (writer, control, className, cssText) {

        var storage = control.__storage || control.__defaults,
            text = storage.text;

        if (text && !storage.html)
        {
            text = flyingon.html_encode(text);
        }

        writer.push('<span');
        
        this.renderDefault(writer, control, className, cssText);
        
        writer.push('>', text, '</span>');
    };



    this.locate = function (control) {

        var cache = base.locate.call(this, control),
            height = control.offsetHeight;

        if (cache.lineHeight !== height)
        {
            control.view.style.lineHeight = (cache.lineHeight = height) + 'px';
        }

        return cache;
    };



    this.__measure_auto = function (control, auto) {

        var view = control.view;

        if (auto & 1)
        {
            control.offsetWidth = view && view.offsetWidth || 0;
        }

        if (auto & 2)
        {
            view.style.width = control.offsetWidth + 'px';
            control.offsetHeight = view && view.offsetHeight || 0;
        }
    };



    this.text = function (control, view) {

        var storage = control.__storage || control.__defaults;

        if (storage.html)
        {
            view.innerHTML = storage.text;
        }
        else
        {
            view[this.__text_name] = storage.text;
        }
    };



});




flyingon.renderer('Button', function (base) {

    

    this.render = function (writer, control, className, cssText) {

        writer.push('<button type="button"');
        
        this.renderDefault(writer, control, className, cssText);
        
        writer.push('>');

        this.__render_content(writer, control);
        
        writer.push('</button>');
    };


    this.__render_content = function (writer, control) {

        var encode = flyingon.html_encode,
            storage = control.__storage || control.__defaults,
            any;

        if (any = storage.icon)
        {
            writer.push('<span class="', encode(any), '" style="width:', 
                any = storage.iconSize, 'px;height:', any, 'px;">', '</span>');
            
            any = true;
        }

        if (any = storage.text)
        {
            if (any && storage.vertical)
            {
                writer.push('<br/>');
            }

            if (!storage.html)
            {
                any = encode(any);
            }

            writer.push('<span>', any, '</span>');
        }
    };


    this.__measure_auto = function (control, auto) {

        var view = control.view;

        if (auto & 1)
        {
            control.offsetWidth = view && view.offsetWidth || 0;
        }

        if (auto & 2)
        {
            view.style.width = control.offsetWidth + 'px';
            control.offsetHeight = view && view.offsetHeight || 0;
        }
    };


    this.icon = this.iconSize = this.vertical = function (control, view, value) {

        var writer = [];

        this.__render_content(writer, control);
        view.innerHTML = writer.join('');
    };


    this.text = this.html = function (control, view) {

        var storage = control.__storage || control.__defaults;

        if (storage.html)
        {
            view.lastChild.innerHTML = storage.text;
        }
        else
        {
            view.lastChild[this.__text_name] = storage.text;
        }
    };



});




flyingon.renderer('LinkButton', function (base) {



    this.render = function (writer, control, className, cssText) {

        var storage = control.__storage || control.__defaults,
            any;
        
        writer.push('<a type="button"');
        
        this.renderDefault(writer, control, className, cssText);

        if (any = storage.href)
        {
            writer.push(' href="', flyingon.html_encode(any), '"');
        }
        
        writer.push('>');

        if (any = storage.text)
        {
            if (!storage.html)
            {
                any = flyingon.html_encode(any);
            }

            writer.push(any);
        }
        
        writer.push('</a>');
    };



    this.__measure_auto = function (control, auto) {

        var view = control.view;

        if (auto & 1)
        {
            control.offsetWidth = view && view.offsetWidth || 0;
        }

        if (auto & 2)
        {
            view.style.width = control.offsetWidth + 'px';
            control.offsetHeight = view && view.offsetHeight || 0;
        }
    };


    this.text = this.html = function (control, view) {

        var storage = control.__storage || control.__defaults;

        if (storage.html)
        {
            view.innerHTML = storage.text;
        }
        else
        {
            view[this.__text_name] = storage.text;
        }
    };


    this.href = function (control, view, value) {

        view.href = value;
    };



});




flyingon.renderer('Image', function (base) {



    this.render = function (writer, control, className, cssText) {

        var encode = flyingon.html_encode,
            storage = control.__storage || control.__defaults,
            src = storage.src,
            alt = storage.alt;

        if (src)
        {
            src = encode(src);
        }

        if (alt)
        {
            alt = encode(alt);
        }

        writer.push('<img');
        
        this.renderDefault(writer, control, className, cssText);
        
        writer.push(' src="', src, '" alt="', alt, '"></img>');
    };



    this.src = function (control, view, value) {

        view.src = value;
    };


    this.alt = function (control, view, value) {

        view.alt = value;
    };



});




flyingon.renderer('Slider', function (base) {


    this.render = function (writer, control, className, cssText) {

        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);

        writer.push('>',
                '<div class="f-slider-bar" onclick="flyingon.Slider.onclick.call(this, event)"><div></div></div>',
                '<div class="f-slider-button" onmousedown="flyingon.Slider.onmousedown.call(this, event)"><div></div></div>',
            '</div>');
    };



    this.locate = function (control) {

        base.locate.call(this, control);
        this.refresh(control);
    };


    flyingon.Slider.onclick = function (e) {

        var control = flyingon.findControl(this),
            storage = control.__storage || control.__defaults,
            size = control.view.offsetWidth - storage.buttonSize,
            x = e.offsetX;

        if (x === void 0)
        {
            x = e.clientX - control.view.getBoundingClientRect().left;
        }

        x /= size;
        x = (storage.max - storage.min) * (x > 1 ? 1 : x) | 0;

        control.value(x);
        control.trigger('change', 'value', x);
    };


    flyingon.Slider.onmousedown = function (e) {

        var control = flyingon.findControl(this),
            storage = control.__storage || control.__defaults,
            context = { control: control },
            size = context.size = control.view.offsetWidth - storage.buttonSize,
            value = storage.value * size / (storage.max - storage.min) + 0.5 | 0;

        e.dom = this;

        context.min = -value;
        context.max = size - value;

        flyingon.dom_drag(context, e, null, check_move, move_end, 'y');
    };


    function check_move(e) {

        var x = e.distanceX;

        if (x < this.min)
        {
            e.distanceX = this.min;
        }
        else if (x > this.max)
        {
            e.distanceX = this.max;
        }
    };


    function move_end(e) {

        var control = this.control,
            storage = control.__storage || control.__defaults,
            x = e.distanceX - this.min;

        x = (storage.max - storage.min) * x / this.size | 0;

        control.value(x);
        control.trigger('change', 'value', x);
    };


    this.refresh = function (control) {

        var storage = control.__storage || control.__defaults,
            view = control.view,
            style = view.lastChild.style,
            width = view.offsetWidth - storage.buttonSize;

        style.left = (storage.value * width / (storage.max - storage.min) | 0) + 'px';
        style.width = storage.buttonSize + 'px';
    };


});




flyingon.renderer('ProgressBar', function (base) {


    this.render = function (writer, control, className, cssText) {

        var value = (control.__storage || control.__defaults).value;

        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);

        writer.push('>',
                '<div class="f-progressbar-back" style="width:', value, '%;"></div>',
                '<div class="f-progressbar-text"><span>', value, '%</span></div>',
            '</div>');
    };


    this.value = function (control, view, value) {

        view.firstChild.style.width = value + 'px';
        view.lastChild.firstChild[this.__text_name] = value + '%';
    };


    this.text = function (control, view, value) {

        view.lastChild.style.display = value ? '' : 'none';
    };


});




//容器控件渲染器
flyingon.renderer('Panel', function (base) {
    
    

    //不设置auto尺寸
    this.__auto_size = 0;


    //不渲染padding
    this.padding = 0;
    



    //渲染html
    this.render = function (writer, control, className, cssText) {

        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);
        
        writer.push(' onscroll="flyingon.__dom_scroll.call(this, event)">');

        if (control.length > 0 && control.__visible)
        {
            control.__content_render = true;
            this.__render_children(writer, control, control, 0, control.length);
        }

        //滚动位置控制(解决有右或底边距时拖不到底的问题)
        writer.push(this.__scroll_html, '</div>');
    };


    //重新渲染内容
    this.__render_content = function (control, view) {

        var writer = [];

        //标记已渲染
        control.__content_render = true;

        this.__render_children(writer, control, control, 0, control.length);

        writer.push(this.__scroll_html);

        view.innerHTML = writer.join('');
        this.mount(control, view);
    };



    this.mount = function (control, view) {

        base.mount.call(this, control, view);

        if (control.__content_render)
        {
            view = control.view_content || view;
            this.__mount_children(control, view, control, 0, control.length, view.firstChild);
        }
    };


    this.unmount = function (control) {

        control.view = control.view_content = null;

        this.__unmount_children(control);
        base.unmount.call(this, control);
    };



    //作为html方式定位控件时需特殊处理
    this.locate_html = function (control) {

        var any = control.__location_dirty,
            width = 0,
            height = 0;
        
        if (any)
        {
            this.__locate_html(control);
        }

        control.__update_dirty = false;

        //如果需要适应容器,则计算容器大小(对性能有影响)
        if ((any = control.view) && (any = any.parentNode) && control.adaption())
        {
            width = any.clientWidth;
            height = any.clientHeight;
        }
        
        control.measure(width, height, width, height);
        this.locate(control);
    };


    this.locate = function (control) {

        base.locate.call(this, control);

        if (control.length > 0 && !control.__content_render)
        {
            this.__render_content(control, control.view_content || control.view);
        }
      
        //需要排列先重排
        if (control.__arrange_dirty > 1)
        {
            this.__arrange(control);
            this.__locate_scroll(control);
        }
 
        //定位子控件
        for (var i = 0, l = control.length; i < l; i++)
        {
            var item = control[i];

            if (item && item.view)
            {
                item.renderer.locate(item);
            }
        }
    };


    //定位滚动条
    this.__locate_scroll = function (control) {

        var style = (control.view_content || control.view).lastChild.style, //内容位置控制(解决有右或底边距时拖不到底的问题)
            cache = control.__scroll_cache || (control.__scroll_cache = {}),
            any;

        if (control.__hscroll_length !== (any = control.arrangeRight))
        {
            style.width = (control.__hscroll_length = any) + 'px'; 
        }

        if (control.__vscroll_length !== (any = control.arrangeBottom))
        {
            style.height = (control.__vscroll_length = any) + 'px'; 
        }
    };



});




flyingon.renderer('GroupBox', 'Panel', function (base) {



    this.render = function (writer, control, className, cssText) {

        var storage = control.__storage || control.__defaults,
            head = storage.header,
            text = storage.text,
            any;

        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);
        
        if (text)
        {
            text = flyingon.html_encode(text);
        }

        if (any = control.format)
        {
            text = any.call(control, text);
        }

        writer.push('>',
            '<div class="f-groupbox-head" style="height:', head, 'px;line-height:', head, 'px;text-align:', storage.align, ';" onclick="flyingon.GroupBox.onclick.call(this, event)">',
                '<span class="f-groupbox-icon ', (any = storage.icon) ? any : '" style="display:none;', '"></span>',
                '<span class="f-groupbox-text">', text, '</span>',
                '<span class="f-groupbox-flag f-groupbox-', storage.collapsed ? 'close"' : 'open"', storage.collapsable === 2 ? '' : ' style="display:none;"', '></span>',
                '<span class="f-groupbox-line"></span>',
            '</div>',
            '<div class="f-groupbox-body" style="top:', head, 'px;overflow:auto;', storage.collapsed ? '' : '', '">');

        if (control.length > 0 && control.__visible)
        {
            control.__content_render = true;
            this.__render_children(writer, control, control, 0, control.length);
        }

        writer.push(this.__scroll_html, '</div></div>');
    };
    

    this.mount = function (control, view) {

        control.view_content = view.lastChild;
        base.mount.call(this, control, view);
    };


    flyingon.GroupBox.onclick = function (e) {

        var control = flyingon.findControl(this);

        if (control.collapsable())
        {
            control.collapsed(!control.collapsed());
        }
    };



    this.header = function (control, view, value) {

        view.firstChild.style.height = view.lastChild.style.top = value + 'px';
    };


    this.text = function (control, view, value) {

        view = view.firstChild.firstChild.nextSibling;

        if (control.format)
        {
            if (value)
            {
                value = flyingon.html_encode(value);
            }

            view.innerHTML = control.format(value);
        }
        else
        {
            view[this.__text_name] = value;
        }
    };


    this.icon = function (control, view, value) {

        view = view.firstChild.firstChild;
        view.className = 'f-groupbox-icon' + (value ? ' ' + value : '');
        view.style.display = value ? '' : 'none';
    };


    this.collapsable = function (control, view, value) {

        view.firstChild.lastChild.style.display = value === 2 ? '' : 'none';
    };


    this.collapsed = function (control, view, value) {

        view.firstChild.lastChild.previousSibling.className = 'f-groupbox-flag f-groupbox-' + (value ? 'close' : 'open');
        view.lastChild.style.display = value ? 'none' : '';
    };


    this.align = function (control, view, value) {

        view.firstChild.style.textAlign = value;
    };


});




//容器控件渲染器
flyingon.renderer('ScrollPanel', function (base) {
    
    
    
    //不设置auto尺寸
    this.__auto_size = 0;


    //不渲染padding
    this.padding = 0;




    //渲染html
    this.render = function (writer, control, className, cssText) {

        var text = this.__scroll_html;

        //滚动位置控制(解决有右或底边距时拖不到底的问题)
        //使用模拟滚动条解决IE拖动闪烁问题
        //此处只渲染一个空的壳,实现渲染内容在locate的时候根据需要渲染
        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);
        
        writer.push('>',
            '<div class="f-scrollpanel-scroll" onscroll="flyingon.__dom_scroll.call(this, event)">',
                text,
            '</div>',
            '<div class="f-scrollpanel-body" style="overflow:hidden;">',
                text,
            '</div>',
        '</div>');
    };


    
    this.mount = function (control, view) {

        control.view_content = view.lastChild;
        
        base.mount.call(this, control, view);

        control.on('mousewheel', mousewheel);
    };


    this.unmount = function (control, remove) {

        control.view_content = null;

        this.__unmount_children(control);
        base.unmount.call(this, control, remove);
    };


    function mousewheel(event) {

        this.view.firstChild.scrollTop -= event.wheelDelta * 100 / 120;
        flyingon.dom_stop(event);
    };



    this.locate = function (control) {

        var cache = base.locate.call(this, control),
            start, 
            end, 
            any;

        //需要排列先重排
        if (control.__arrange_dirty > 1)
        {
            start = control.__visible_start;
            end = control.__visible_end + 1;

            this.__arrange(control);

            control.__compute_visible();

            //隐藏原来显示的子项
            if (start >= 0)
            {
                while (start <= end)
                {
                    if ((any = control[start++]) && !any.__visible_area)
                    {
                        this.__locate_position(any);
                    }
                }
            }
        }

        any = control.view_content.style;
        any[flyingon.rtl ? 'left' : 'right'] = (control.__vscroll ? flyingon.vscroll_width : 0) + 'px';
        any.bottom = (control.__hscroll ? flyingon.hscroll_height : 0) + 'px';

        start = control.__visible_start;
        end = control.__visible_end + 1;

        if (start >= 0)
        {
            //插入未挂载的子控件
            if (control.__visible_unmount)
            {
                control.__visible_unmount = false;
                this.__insert_children(control, control.view_content, start, end);
            }
            
            //定位子控件
            while (start < end)
            {
                any = control[start++];

                if (any && any.view)
                {
                    any.renderer.locate(any);
                }
            }
        }

        return cache;
    };


    //仅更新位置信息
    this.__locate_position = function (control) {

        var style = control.view.style,
            cache = control.__locate_cache,
            any;

        if (cache)
        {
            if (cache.left !== (any = control.offsetLeft))
            {
                style.left = (cache.left = any) + 'px';
            }

            if (cache.top !== (any = control.offsetTop))
            {
                style.top = (cache.top = any) + 'px';
            }
        }
    };


    this.__sync_scroll = function (control) {

        var view = control.view,
            style1 = view.firstChild.firstChild.style, //模拟滚动条控制
            style2 = view.lastChild.lastChild.style; //内容位置控制(解决有右或底边距时拖不到底的问题)

        style1.overflowX = control.__hscroll ? 'scroll' : 'hidden';
        style1.overflowY = control.__vscroll ? 'scroll' : 'hidden';

        style1.width = style2.width = control.arrangeRight + 'px'; 
        style1.height = style2.height = control.arrangeBottom + 'px'; 
    };


    //插入视图补丁
    this.__insert_children = function (control, view, start, end) {

        var tag = view.lastChild || null,
            last = -1,
            item,
            node;
            
        //处理插入带view的节点
        for (var i = end - 1; i >= start; i--)
        {
            if (item = control[i])
            {
                if (node = item.view)
                {
                    if (node.parentNode !== view)
                    {
                        view.insertBefore(node, tag || null);
                    }

                    if (last > 0)
                    {
                        this.__unmount_html(control, view, control, i + 1, last, tag);
                        last = -1;
                    }

                    tag = node;
                }
                else if (last < 0)
                {
                    last = i + 1;
                }
            }
        }

        if (last > 0)
        {
            this.__unmount_html(control, view, control, start, last, tag);
        }
    };

 

    this.scroll = function (control, x, y) {

        var view = control.view.lastChild;

        this.locate(control);
        
        if (view.scrollLeft !== x)
        {
            view.scrollLeft = x;
        }

        if (view.scrollTop !== y)
        {
            view.scrollTop = y;
        }
    };


});




flyingon.renderer('Splitter', function (base) {



    //渲染html
    this.render = function (writer, control, className, cssText) {

        writer.push('<div');

        this.renderDefault(writer, control, className, (cssText || '') + 'cursor:ew-resize;');

        writer.push(' onmousedown="flyingon.Splitter.onmousedown.call(this, event)"><div></div></div>');
    };
    

    this.locate = function (control) {

        var vertical = control.offsetWidth > control.offsetHeight;

        base.locate.call(this, control);

        if (control.vertical !== vertical)
        {
            control.vertical = vertical;
            control.view.style.cursor = vertical ? 'ns-resize' : 'ew-resize';
        }
    };


    flyingon.Splitter.onmousedown = function (e) {
            
        var control = flyingon.findControl(this),
            data = resize_data(control);

        if (data)
        {
            flyingon.dom_drag(data, e, null, do_resize, null, true);
        }
    };


    function resize_data(control) {

        var parent = control.parent,
            vertical = control.vertical,
            dock = (control.__storage || control.__defaults).dock;

        if (parent && (control = parent[parent.indexOf(control) - 1]))
        {
            return [control, vertical, vertical ? control.offsetHeight : control.offsetWidth, dock === 'right' || dock === 'bottom'];
        }
    };


    function do_resize(event) {

        var control = this[0],
            vertical = this[1],
            style = control.__style,
            name = vertical ? 'distanceY' : 'distanceX',
            size = this[2] + (this[3] ? -event[name] : event[name]),
            visible = 'visible';

        if (size < 4)
        {
            size = 0;
            visible = 'hidden';
        }

        if (!style || !style.visibility !== visible)
        {
            control.style('visibility', visible);
        }

        control[vertical ? 'height' : 'width'](size);
    };

     

});




flyingon.renderer('ListBox', function (base) {



    this.render = function (writer, control, className, cssText) {

        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);

        writer.push(' onclick="flyingon.ListBox.onclick.call(this, event)"></div>');
    };



    flyingon.ListBox.onclick = function (e) {

        var dom = e.target || e.srcElement;

        while (dom !== this)
        {
            var index = dom.getAttribute('index');

            if (index)
            {
                change(flyingon.findControl(this), this, index | 0);
                return;
            }

            dom = dom.parentNode;
        }
    };


    function change(control, view, index) {

        var storage = control.storage(),
            checked = storage.checked,
            selected = control.__selected,
            value = index >= 0 ? (value = control.__list).value(value[index]) : '',
            any;

        //多选
        if (checked === 'checkbox')
        {
            if (selected && (any = selected.indexOf(index)) >= 0)
            {
                selected.splice(any, 1);
                change_selected(view, index, false, checked);

                any = storage.value.split(storage.separator);
                any.splice(any.indexOf(value), 1);

                storage.value = any.join(storage.separator);
            }
            else
            {
                change_selected(view, index, true, checked);

                if (selected)
                {
                    selected.push(index);
                }
                else
                {
                    selected = [index];
                }

                storage.value = (any = storage.value) ? any + storage.separator + value : value;
            }

            index = selected;
        }
        else if (index === selected)
        {
            return;
        }
        else
        {
            if (selected >= 0) //清除原选中
            {
                change_selected(view, selected, false, checked);
            }

            if (index >= 0)
            {
                change_selected(view, index, true, checked);
            }

            storage.value = value;
        }

        control.__selected = index;
        control.trigger('change', 'value', storage.value);
    };


    function change_selected(view, index, selected, checked) {

        if (view = view.children[index])
        {
            var name = ' f-listbox-selected',
                index = view.className.indexOf(name);

            if (selected)
            {
                if (index < 0)
                {
                    view.className += name;
                }
            }
            else if (index >= 0)
            {
                view.className = view.className.replace(name, '');
            }
            else
            {
                return;
            }

            if (checked !== 'none' && (view = view.firstChild))
            {
                view.checked = selected;
            }
        }
    };


    this.locate = function (control) {

        base.locate.call(this, control);
        control.__list && this.content(control);
    };


    this.content = function (control) {

        var writer = [],
            list = control.__list,
            valueField = list.valueField,
            displayField = list.displayField,
            template = control.__template,
            encode = flyingon.html_encode,
            storage = control.__storage || control.__defaults,
            value = storage.value,
            checked = storage.checked,
            checkbox = checked === 'checkbox',
            selected = checkbox ? (control.__selected = []) : 0,
            clear = !checkbox && storage.clear ? 1 : 0,
            columns = storage.columns,
            itemHeight = storage.itemHeight,
            style = ' style="height:' + itemHeight + 'px;line-height:' + itemHeight + 'px;',
            left = flyingon.rtl ? 'right:' : 'left:',
            top = 0,
            index = 0,
            length = list.length,
            width,
            item,
            key,
            x,
            y,
            any;

        if (checkbox)
        {
            value = value.split(storage.separator || ',').pair();
        }

        if (columns <= 0)
        {
            columns = length;
        }

        if (columns > 1)
        {
            any = control.offsetWidth - control.borderLeft - control.borderRight - control.paddingLeft - control.paddingRight;

            if (control.offsetHeight - control.borderTop - control.borderBottom - control.paddingTop - control.paddingBottom <
                Math.ceil(length / columns) * itemHeight)
            {
                any -= flyingon.vscroll_width;
            }

            width = any / columns | 0;
            style += 'width:' + (width - 10) + 'px;';
        }
        else
        {
            width = 0;
            style += flyingon.rtl ? 'left:0;' : 'right:0;'; //单列时充满可用空间
        }

        if (!template && (template = storage.template))
        {
            if (typeof template === 'string')
            {
                template = new flyingon.view.Template(template).parse(true);
            }

            control.__template = template = template instanceof Array ? template : [template];
        }

        while (index < length)
        {
            item = list[index];
            any = index + clear;

            if (columns > 1)
            {
                x = (any % columns) * width;
                y = (any / columns | 0) * itemHeight;
            }
            else
            {
                x = 0;
                y = any * itemHeight;
            }

            key = valueField ? (item ? item[valueField] : '') : item;

            if (checkbox)
            {
                if (any = value[key])
                {
                    selected.push(index);
                }
            }
            else if (any = value === key)
            {
                control.__selected = index;
            }
            
            writer.push('<div class="f-listbox-item', any ? ' f-listbox-selected"' : '"', 
                style, 'top:', y, 'px;', left, x, 'px;" index="', index++, '">');

            if (checked !== 'none')
            {
                writer.push('<input type="', checked, '"', any ? ' checked="checked"' : '', '/>');
            }

            if (template)
            {
                any = template.length;

                for (var j = 0; j < any; j++)
                {
                    render_template(writer, item, index, template[j], encode);
                }
            }
            else
            {
                any = item;

                if (displayField)
                {
                    any = any && any[displayField] || '';
                }

                if (any && typeof any === 'string')
                {
                    any = encode(any);
                }

                writer.push(any);
            }

            writer.push('</div>');
        }

        //生成清除项
        if (clear)
        {
            writer.push('<div class="f-listbox-item f-listbox-clear"', style, 'top:0;', left, '0;" index="-1"><span>', 
                flyingon.i18ntext('listbox.clear'), '</span></div>');
        }

        control.view.innerHTML = writer.join('');
    };


    function render_template(writer, item, index, template, encode) {

        var tag = template.Class || 'div',
            text,
            any;

        writer.push('<', tag);

        for (var name in template)
        {
            switch (name)
            {
                case 'Class':
                case 'children':
                    break;

                default:
                    if ((any = template[name]) != null)
                    {
                        if (name.charAt(0) === ':')
                        {
                            name = name.substring(1);

                            if (any === '{{index}}')
                            {
                                any = index;
                            }
                            else if (any === '{{item}}')
                            {
                                any = item;
                            }
                            else
                            {
                                any = item ? item[any] : '';
                            }
                        }

                        if (any && typeof any === 'string')
                        {
                            any = encode(any);
                        }

                        if (name === 'text')
                        {
                            text = any;
                        }
                        else
                        {
                            writer.push(' ', name, '="', any, '"');
                        }
                    }
                    break;
            }
        }

        writer.push('>');

        if (text)
        {
            writer.push(text);
        }
        else if (any = template.children)
        {
            if (any instanceof Array)
            {
                for (var i = 0, l = any.length; i < l; i++)
                {
                    render_template(writer, item, index, any[i], encode);
                }
            }
            else
            {
                render_template(writer, item, index, any, encode);
            }
        }

        writer.push('</', tag, '>');
    };



});




flyingon.renderer('RadioButton', function (base) {



    this.render = function (writer, control, className, cssText) {

        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);
        
        writer.push('><input type="radio" name="', control.name(), control.checked() ? '" checked="checked' : '',
            '" class="f-radio-input" onchange="flyingon.RadioButton.onchange.call(this)" /></div>');
    };



    flyingon.RadioButton.onchange = function () {

        var control = flyingon.findControl(this);

        control.rendered = false;
        control.checked(this.checked);
        control.rendered = true;

        control.trigger('change', 'value', this.checked);
    };


    this.checked = function (control, view, value) {

        view.firstChild.checked = value;
    };

    
});




flyingon.renderer('CheckBox', function (base) {



    this.render = function (writer, control, className, cssText) {

        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);
        
        writer.push('><input type="checkbox" name="', control.name(), control.checked() ? '" checked="checked' : '',
            '" class="f-checkbox-input" onchange="flyingon.CheckBox.onchange.call(this)" /></div>');
    };



    flyingon.CheckBox.onchange = function () {

        var control = flyingon.findControl(this);

        control.rendered = false;
        control.checked(this.checked);
        control.rendered = true;

        control.trigger('change', 'value', this.checked);
    };


    this.checked = function (control, view, value) {

        view.firstChild.checked = value;
    };


});




flyingon.renderer('TextBox', function (base) {



    this.render = function (writer, control, className, cssText) {

        var text = control.__text = control.text();

        if (text)
        {
            text = flyingon.html_encode(text);
        }

        writer.push('<input');
        
        this.renderDefault(writer, control, className, cssText);
        
        writer.push(' type="text" value="', text, 
            '" oninput="flyingon.TextBox.oninput.call(this)"',
            ' onchange="flyingon.TextBox.onchange.call(this)"/>');
    };


    flyingon.TextBox.oninput = function (e) {

        var control = flyingon.findControl(this);
        control.renderer.oninput(control, this, e);
    };


    flyingon.TextBox.onchange = function () {

        var control = flyingon.findControl(this);

        try
        {
            control.rendered = false;
            control.value(this.value);
        }
        finally
        {
            control.rendered = true;
        }
        
        this.value = control.text();

        control.trigger('change', 'value', control.value());
    };


    this.text = function (control, view, value) {

        view.value = control.text();
    };


});




flyingon.renderer('Number', 'TextBox', function (base) {


    this.oninput = function (control, view) {

        var value = +view.value;

        if (value !== value)
        {
            view.value = control.__text;
        }
        else
        {
            control.__text = value;
        }
    };


});




flyingon.renderer('TextButton', function (base) {

    

    this.render = function (writer, control, className, cssText) {

        var storage = control.__storage || control.__defaults,
            text = control.text(),
            size = storage.buttonSize;

        if (text)
        {
            text = flyingon.html_encode(text);
        }

        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);

        writer.push('>',
                '<div class="f-textbutton-body" style="right:', size, 'px;">',
                    '<input type="text" class="f-textbutton-text" value="', text, 
                    storage.inputable ? '' : '" readonly="readonly',
                    '" onchange="flyingon.TextButton.onchange.call(this)"/>',
                '</div>',
                '<div class="f-textbutton-button ', storage.button, 
                    '" style="width:', size, 'px;" onclick="flyingon.TextButton.onclick.call(this)"></div>',
            '</div>');
    };


    flyingon.TextButton.onclick = function () {

        var control = flyingon.findControl(this),
            storage = control.__storage;

        if (!storage || !(storage.disabled || storage.readonly))
        {
            control.__on_click();
        }
    };


    flyingon.TextButton.onchange = function () {

        var control = flyingon.findControl(this);

        control.rendered = false;
        control.value(this.value);
        control.rendered = true;

        control.view.firstChild.firstChild.value = control.text();

        control.trigger('change', 'value', this.value);
    };



    this.button = function (control, view, value) {

        view.lastChild.className = 'f-textbutton-button ' + value;
    };


    this.buttonSize = function (control, view, value) {

        view.firstChild.style.right = view.lastChild.style.width = value + 'px';
    };


    this.text = function (control, view) {

        view.firstChild.firstChild.value = control.text();
    };


    this.inputable = function (control, view, value) {

        view = view.firstChild.firstChild;

        if (value)
        {
            view.removeAttribute('readonly');
        }
        else
        {
            view.setAttribute('readonly', 'readonly');
        }
    };



});




flyingon.renderer('Calendar', function (base) {



    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    //var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

    var weeks = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];



    this.render = function (writer, control, className, cssText) {

        writer.push('<div');
        
        this.renderDefault(writer, control, className, (cssText || '') + 'padding:8px;');
        
        writer.push(' onclick="flyingon.Calendar.onclick.call(this, event)"></div>');
    };



    flyingon.Calendar.onclick = function (e) {

        var control = flyingon.findControl(this),
            dom = e.target || e.srcElement,
            data = control.__data,
            any;

        switch (dom.getAttribute('tag'))
        {
            case 'to-year':
                render_year(control, data);
                break;

            case 'to-month':
                render_month(control, data);
                break;

            case 'to-date':
                render_date(control, data);
                break;

            case 'date-2':
                data[4] -= 1;
                render_date(control, data);
                break;

            case 'date-1':
                if (--data[5] < 1)
                {
                    data[5] = 12;
                    data[4]--;
                }

                render_date(control, data);
                break;

            case 'date+1':
                if (++data[5] > 12)
                {
                    data[5] = 1;
                    data[4]++;
                }

                render_date(control, data);
                break;

            case 'date+2':
                data[4] += 1;
                render_date(control, data);
                break;

            case 'month-2':
                data[4] -= 10;
                render_month(control, data);
                break;

            case 'month-1':
                data[4] -= 1;
                render_month(control, data);
                break;

            case 'month+1':
                data[4] += 1;
                render_month(control, data);
                break;

            case 'month+2':
                data[4] += 10;
                render_month(control, data);
                break;

            case 'year-2':
                data[4] -= 100;
                render_year(control, data);
                break;

            case 'year-1':
                data[4] -= 20;
                render_year(control, data);
                break;

            case 'year+1':
                data[4] += 20;
                render_year(control, data);
                break;

            case 'year+2':
                data[4] += 100;
                render_year(control, data);
                break;

            case 'today':
                any = new Date();
                data[0] = data[4] = any.getFullYear();
                data[1] = data[5] = any.getMonth() + 1;
                data[2] = any.getDate();

                do_change(control, data, render_date);
                break;

            case 'clear':
                data[0] = data[1] = data[2] = 0;
                
                if (raise_change(control, null))
                {
                    render_date(control, data);
                }
                break;

            case 'year':
                data[0] = data[4] = +dom.innerHTML;
                (control.month() ? render_month : render_date)(control, data);
                break;

            case 'month':
                data[0] = data[4];
                data[1] = data[5] = +dom.getAttribute('value');

                if (control.month())
                {
                    do_change(control, data, render_month);
                }
                else
                {
                    render_date(control, data);
                }
                break;
                
            case 'date':
                if (dom.className.indexOf('f-calendar-disabled') < 0)
                {
                    any = data[5] + (dom.getAttribute('offset') | 0);

                    if (any < 1)
                    {
                        any = 12;
                        data[4]--;
                    }
                    else if (any > 12)
                    {
                        any = 1;
                        data[4]++;
                    }
                    else
                    {
                        data[4];
                    }

                    data[0] = data[4];
                    data[1] = data[5] = any;
                    data[2] = +dom.innerHTML;

                    do_change(control, data, render_date);
                }
                break;
        }
    };


    flyingon.Calendar.onchange = function () {

        var control = flyingon.findControl(this),
            values = this.value.match(/\d+/g);

        this.value = control.__data[3] = values ? check_time(values) : '00:00:00';
    };


    function do_change(control, data, fn) {

        var storage = control.__storage || control.__defaults,
            value,
            any;

        if (storage.month)
        {
            value = data[0] + '-' + data[1];
        }
        else
        {
            value = data[0] + '/' + data[1] + '/' + data[2];

            if (storage.time)
            {
                any = data[3].split(':');
                value += ' ' + any[0] + ':' + any[1] + ':' + any[2];
            }

            value = Date.create(value);
        }

        if (raise_change(control, value))
        {
            fn && fn(control, data);
            return true;
        }
    };


    function raise_change(control, value) {

        if (control.value() !== value)
        {
            control.rendered = false;
            control.value(value);
            control.rendered = true;

            control.trigger('change', 'value', value);
        }

        return control.trigger('selected', 'value', value) !== false;
    };


    function check_time(values) {

        var list = [],
            max = 24,
            any;

        for (var i = 0; i < 3; i++)
        {
            if (any = values[i])
            {
                //substr在IE7下使用负索引有问题
                if (any > max)
                {
                    any = max;
                }
                else if ((any = '' + any).length === 1)
                {
                    any = '0' + any;
                }
            }
            else
            {
                any = '00';
            }

            list.push(any);
            max = 60;
        }

        return list.join(':');
    };


    this.locate = function (control) {

        base.locate.call(this, control);

        control.__data = null;
        render(control);
    };


    function render(control) {

        var storage = control.__storage || control.__defaults,
            data = control.__data,
            any;

        if (!data)
        {
            any = storage.value;

            control.__data = data = [

                any ? any.getFullYear() : 0, 
                any ? any.getMonth() + 1 : 0,
                any ? any.getDate() : 0,
                '',
                (any = any || new Date()).getFullYear(),
                any.getMonth() + 1
            ];

            if (storage.time && !storage.month)
            {
                 data[3] = check_time([any.getHours(), any.getMinutes(), any.getSeconds()]);
            }
        }

        if (storage.month)
        {
            render_month(control, data);
        }
        else
        {
            render_date(control, data);
        }
    };


    function render_year(control, data) {

        var writer = [],
            storage = control.__storage || control.__defaults,
            min = storage.min,
            max = storage.max,
            check = control.oncheck,
            year,
            text,
            name,
            any;

        min && (min = min.match(/\d+/g));
        max && (max = max.match(/\d+/g));

        any = (clientHeight(control) - 30) / 4 | 0;
        text = '<div style="height:' + any + 'px;line-height:' + any + 'px;">';

        year = (data[4] / 20 | 0) * 20 + 1;

        any = flyingon.i18ntext('calendar.title', 'Y')[0];
        any = any.replace('Y', year) + ' - ' + any.replace('Y', year + 19);
        any = '<span tag="to-' + (control.month() ? 'month">' : 'date">') + any + '</span>';

        render_head(writer, data, 'year', any);

        writer.push('<div class="f-calendar-year">');

        any = data[0];

        for (var i = 0; i < 4; i++)
        {
            writer.push(text);

            for (var j = 0; j < 5; j++)
            {
                name = year === any ? 'f-calendar-selected ' : '';

                if (min && check_min(min, year) ||
                    max && check_max(max, year) ||
                    check && check(year) === false)
                {
                    name += 'f-calendar-disabled ';
                }

                writer.push('<span class="', name, '" tag="year">', year++, '</span>');
            }

            writer.push('</div>');
        }

        control.view.innerHTML = writer.join('');
    };


    function render_month(control, data) {

        var writer = [],
            i18n = flyingon.i18ntext,
            storage = control.__storage || control.__defaults,
            min = storage.min,
            max = storage.max,
            check = control.oncheck,
            keys = i18n('calendar.month', '') || months,
            year = data[4],
            month,
            name,
            text,
            any;

        if (min = min && min.match(/\d+/g))
        {
            min[1] || (min[1] = 0);
        }

        if (max = max && max.match(/\d+/g))
        {
            max[1] || (max[1] = 12);
        }

        any = '<span tag="' + (control.month() ? 'to-year">' : 'to-date">')
            + i18n('calendar.title', 'Y')[0].replace('Y', year)
            + '</span>';

        render_head(writer, data, 'month', any);

        any = (clientHeight(control) - 30) / 3 | 0;
        text = '<div style="height:' + any + 'px;line-height:' + any + 'px;">';

        writer.push('<div class="f-calendar-month">');

        any = data[1];

        for (var i = 0; i < 3; i++)
        {
            writer.push(text);

            for (var j = 0; j < 4; j++)
            {
                month = i * 4 + j + 1;

                name = month === any ? 'f-calendar-selected ' : '';

                if (min && check_min(min, year, month) ||
                    max && check_max(max, year, month) ||
                    check && check(year, month) === false)
                {
                    name += 'f-calendar-disabled';
                }

                writer.push('<span class="', name, '" value="', month, '" tag="month">', keys[month - 1], '</span>');
            }

            writer.push('</div>');
        }

        writer.push('</div>');

        control.view.innerHTML = writer.join('');
    };


    function render_date(control, data) {

        var writer = [],
            i18n = flyingon.i18ntext,
            storage = control.__storage || control.__defaults,
            min = storage.min,
            max = storage.max,
            foot = storage.today || storage.clear || storage.time,
            check = control.oncheck,
            index = 0,
            week, //每月第一天是星期几
            last, //上一个月最大天数
            days, //本月最大天数
            text,
            name,
            year,
            month,
            date,
            selected,
            offset,
            any;

        if (min = min && min.match(/\d+/g))
        {
            min[1] || (min[1] = 0);
            min[2] || (min[2] = 0);
        }

        if (max = max && max.match(/\d+/g))
        {
            max[1] || (max[1] = 12);
            max[2] || (max[2] = 31);
        }

        //title标题
        name = i18n('calendar.title', ['Y', 'M', 'M Y']);

        year = name[0].replace('Y', data[4]);
        month = name[1].replace('M', (i18n('calendar.month', '') || months)[data[5] - 1]);
        
        any = name[2].replace('Y', '<span tag="to-year">' + year + '</span>');
        any = any.replace('M', '<span tag="to-month">' + month + '</span>');

        render_head(writer, data, 'date', any);

        //渲染周
        any = i18n('calendar.week', '') || weeks;

        writer.push('<div class="f-calendar-week" style="height:25px;line-height:25px;">');

        for (var i = 0; i < 7; i++)
        {
            writer.push('<span>', any[i], '</span>');
        }

        writer.push('</div><div class="f-calendar-line" style="height:1px;"></div><div class="f-calendar-space" style="height:4px;"></div>');
  
        any = new Date(data[4], data[5], 1);
        
        week = any.getDay();
        any.setDate(-1);

        last = any.getDate() + 1;

        any = new Date(data[4], data[5] + 1, 1);
        any.setDate(-1);

        days = any.getDate() + 1;

        any = (clientHeight(control) - (foot ? 90 : 60)) / 6 | 0;
        text = '<div class="f-calendar-date" style="height:' + any + 'px;line-height:' + any + 'px;">';

        //共渲染6行
        for (var i = 0; i < 6; i++)
        {
            writer.push(text);

            while (index++ < 7)
            {
                date = i * 7  - week + index;

                year = data[4];
                month = data[5];

                if (date < 1)
                {
                    if (--month < 1)
                    {
                        year--;
                        month = 12;
                    }

                    date += last;
                    offset = -1;
                }
                else if (date > days)
                {
                    if (++month > 12)
                    {
                        year++;
                        month = 1;
                    }

                    date -= days;
                    offset = 1;
                }
                else
                {
                    offset = 0;
                }

                name = offset ? 'f-calendar-dark ' : '';

                if (data[2] === date && data[1] === month && data[0] === year)
                {
                    name += 'f-calendar-selected ';
                }

                if (min && check_min(min, year, month, date) ||
                    max && check_max(max, year, month, date) ||
                    check && check(year, month, date) === false)
                {
                    name += 'f-calendar-disabled ';
                }

                if (index === 1 || index === 7)
                {
                    name += 'f-calendar-weekend';
                }

                writer.push('<span class="', name, '" tag="date" offset="', offset, '">', date, '</span>');
            }

            index = 0;

            writer.push('</div>');
        }
        
        if (foot)
        {
            writer.push('<div class="f-calendar-space" style="height:4px;"></div><div class="f-calendar-foot" style="height:25px;line-height:25px;">');

            storage.time && writer.push('<input type="text" class="f-calendar-time" value="', data[3], '" onchange="flyingon.Calendar.onchange.call(this)"/>');

            storage.clear && writer.push('<span class="f-calendar-clear" tag="clear">', i18n('calendar.clear', 'clear'), '</span>');
            
            storage.today && writer.push('<span class="f-calendar-today" tag="today">', i18n('calendar.today', 'today'), '</span>');

            writer.push('</div>');
        }

        control.view.innerHTML = writer.join('');
    };


    function render_head(writer, data, tag, text) {

        writer.push('<div class="f-calendar-head" style="height:30px;line-height:30px;">',
                '<span class="f-calendar-before2" tag="', tag, '-2"></span>',
                '<span class="f-calendar-before1" tag="', tag, '-1"></span>',
                '<span class="f-calendar-title">', text, '</span>',
                '<span class="f-calendar-after1" tag="', tag, '+1"></span>',
                '<span class="f-calendar-after2" tag="', tag, '+2"></span>',
            '</div>');
    };

    
    function clientHeight(control) {

        return control.offsetHeight 
            - control.borderTop - control.borderBottom 
            - control.paddingTop - control.paddingBottom;
    };


    function check_min(min, year, month, date) {

        var any = year - min[0];

        if (any < 0)
        {
            return true;
        }

        if (any === 0 && month > 0)
        {
            any = month - min[1];

            if (any < 0)
            {
                return true;
            }

            return any === 0 && date < min[2];
        }
    };


    function check_max(max, year, month, date) {

        var any = year - max[0];

        if (any > 0)
        {
            return true;
        }

        if (any === 0 && month > 0)
        {
            any = month - max[1];

            if (any > 0)
            {
                return true;
            }

            return any === 0 && date > max[2];
        }
    };


    this.refresh = function (control) {

        control.__data = null;
        render(control);
    };
    

});




flyingon.fragment('f-tree-renderer', function (base) {


    this.unmount = function (control, remove) {

        this.__unmount_children(control);

        control.view_content = null;
        base.unmount.call(this, control, remove);
    };


    this.__children_patch = function (control, patch) {

        var view = control.view_content || control.view,
            last = view.lastChild;

        base.__children_patch.apply(this, arguments);

        //最后一个节点发生变化且是线条风格则需处理
        if (last !== view.lastChild && (last = last.firstChild) && 
            last.className.indexOf(' f-tree-node-last') >= 0)
        {
            remove_line(last, control.isTreeNode ? control.level() + 1 : 0);
        }
    };


    //移除节点线条
    function remove_line(node, level) {

        node.className = node.className.replace(' f-tree-node-last', '');

        node = node.nextSibling;
        node.className = node.className.replace(' f-tree-list-last', '');

        if (node = node.firstChild)
        {
            remove_background(node, level);
        }
    };


    //移除子节点线条背景
    function remove_background(node, level) {

        var dom;

        while (node)
        {
            if (dom = node.firstChild)
            {
                dom.children[level].style.background = '';

                if (dom = node.lastChild.firstChild)
                {
                    remove_background(dom, level);
                }
            }

            node = node.nextSibling;
        }
    };


});



flyingon.renderer('Tree', function (base) {



    this.__scroll_html = '';



    this.render = function (writer, control, className, cssText) {

        var storage = control.__storage || control.__defaults,
            length = control.length;
        
        writer.push('<div');
        
        this.renderDefault(writer, control, 
            (className || '') + 'f-tree-theme-' + storage.theme + 
                (!storage.checked ? ' f-tree-no-check' : '') + 
                (!storage.icon ? ' f-tree-no-icon' : ''));
        
        writer.push(' onclick="flyingon.Tree.onclick.call(this, event)">');

        if (length > 0 && control.__visible)
        {
            control.__content_render = true;
            this.__render_children(writer, control, control, 0, length);
        }

        //滚动位置控制(解决有右或底边距时拖不到底的问题)
        writer.push('</div>');
    };



    this.__render_children = function (writer, control, items, start, end) {

        var line = (control.__storage || control.__defaults).theme === 'line',
            format = control.format,
            last = control[control.length - 1],
            item;

        while (start < end)
        {
            if (item = items[start++])
            {
                item.view || item.renderer.render(writer, item, format, 0, item === last, line);
            }
        }
    };



    flyingon.Tree.onclick = function (e) {

        var tree = flyingon.findControl(this),
            dom = e.target || e.srcElement,
            node = flyingon.findControl(dom);

        while (dom && dom !== this)
        {
            switch (dom.getAttribute('tag'))
            {
                case 'folder':
                    tree[node.expanded ? 'collapse' : 'expand'](node);
                    return;

                case 'check':
                    node.checked(!node.checked());
                    return;

                case 'node':
                    tree.trigger('node-click', 'node', node);
                    tree.current(node);
                    return;

                default:
                    dom = dom.parentNode;
                    break;
            }
        }
    };


    
    flyingon.fragment('f-tree-renderer', this, base);


    this.mount = function (control, view) {

        var node = control.__current;

        base.mount.call(this, control, view);

        if (control.__content_render)
        {
            this.__mount_children(control, view, control, 0, control.length, view.firstChild);
        }

        node && node.view && setTimeout(function () {

            control.renderer.scrollTo(control, node);
            
        }, 500);
    };
    

    this.theme = function (control, view, value) {

        view.className = view.className.replace(/f-tree-theme-\w+/, 'f-tree-theme-' + value);
    };


    this.checked = function (control, view, value) {

        var name = view.className;

        if (value)
        {
            name = name.replace(' f-tree-no-check', '');
        }
        else
        {
            name += ' f-tree-no-check';
        }

        view.className = name;
    };


    this.icon = function (control, view, value) {

        var name = view.className;

        if (value)
        {
            name = name.replace(' f-tree-no-icon', '');
        }
        else
        {
            name += ' f-tree-no-icon';
        }

        view.className = name;
    };


    this.scrollTo = function (control, node) {

        var view = control.view,
            dom = node.view,
            y = view.scrollTop,
            top = dom.offsetTop,
            height;

        if (top < y)
        {
            view.scrollTop = top;
        }
        else if (top > y + (height = view.clientHeight))
        {
            view.scrollTop = top + dom.offsetHeight - height;
        }
    };


});



flyingon.renderer('TreeNode', function (base) {



    this.render = function (writer, node, format, level, last, line, space) {

        var encode = flyingon.html_encode,
            storage = node.__storage || node.__defaults,
            icon,
            text,
            any;

        node.rendered = true;

        writer.push('<div class="', encode(node.fullClassName), '">',
            '<div class="f-tree-node', 
                last && line ? ' f-tree-node-last' : '',
                node.__current ? ' f-tree-node-current': '',
                (any = storage.className) ? ' ' + encode(any) : '',
            (any = storage.id) ? '" id="' + encode(any) + '"' : '', '" tag="node">');

        if (space)
        {
            writer.push(space);
        }

        if (any = storage.delay)
        {
            storage.delay = false;
        }
        
        if (any || node.length > 0)
        {
            if (any || !node.expanded)
            {
                icon = 'f-tree-icon-close';
                writer.push('<span class="f-tree-folder f-tree-close" tag="folder"></span>');
            }
            else
            {
                icon = 'f-tree-icon-open';
                writer.push('<span class="f-tree-folder f-tree-open" tag="folder"></span>');
            }
        }
        else
        {
            icon = 'f-tree-icon-file';
            writer.push('<span class="f-tree-file"></span>');
        }

        text = (text = storage.text) ? encode(text) : '';

        if (format)
        {
            text = format(node, text);
        }

        writer.push('<span class="f-tree-check f-tree-', storage.checked ? 'checked' : 'unchecked', '" tag="check"></span>',
            '<span class="f-tree-icon ', storage.icon || icon, '" tag="icon"></span>',
            '<span class="f-tree-text" tag="text">', text, '</span></div>',
            '<div class="f-tree-list', last && line ? ' f-tree-list-last' : '', '">');

        if (node.expanded && node.length > 0)
        {
            this.__render_children(writer, node, node, 0, node.length, format, ++level, last, line);
        }

        writer.push('</div></div>');
    };


    //渲染子项
    this.__render_children = function (writer, node, items, start, end, format, level, last, line) {

        var item, space, any;

        node.__content_render = true;

        //如果未传入渲染参数则初始化渲染参数
        if (format === void 0 && (item = node.parent))
        {
            level = 1;
            last = item[item.length - 1] === node;
            
            do
            {
                if (item.isTreeNode)
                {
                    level++;
                }
                else
                {
                    format = item.format || null;
                    line = (item.__storage || item.__defaults).theme === 'line';
                    break;
                }
            }
            while (item = item.parent);
        }

        space = last && line ? ' style="background:none;"' : '';
        space = '<span class="f-tree-space"' + space + '></span>';

        if (level > 1)
        {
            space = new Array(level + 1).join(space);
        }

        any = items.length;
            
        while (start < end)
        {
            if (item = items[start++])
            {
                if (item.view)
                {
                    item.renderer.unmount(item);
                }

                item.renderer.render(writer, item, format, level, start === any, line, space);
            }
        }
    };

        
    
    flyingon.fragment('f-tree-renderer', this, base);


    this.mount = function (control, view) {

        var dom = control.view_content = view.lastChild;

        base.mount.call(this, control, view);

        if (control.__content_render)
        {
            this.__mount_children(control, view, control, 0, control.length, dom.firstChild);
        }
    };
    


    this.checked = function (node, view, value) {

        value = value ? 'checked' : (node.checkedChildren ? 'checked2' : 'unchecked');
        find_dom(view, 'check', 'f-tree-check f-tree-' + value);
    };


    this.icon = function (node, view, value) {

        find_dom(view, 'icon', 'f-tree-icon ' + value);
    };


    this.text = function (node, view, value) {

        var any;

        if (view = find_dom(view, 'text'))
        {
            while ((any = node.parent) && any.isTreeNode)
            {
                node = any;
            }

            if (any = node && node.format)
            {
                view.innerHTML = format(flyingon.html_encode(value));
            }
            else
            {
                view[this.__text_name] = value;
            }
        }
    };


    this.expand = function (node) {

        var view = node.view,
            folder = find_dom(view, 'folder'),
            icon = find_dom(view, 'icon'),
            any;

        if (node.length > 0)
        {
            if (folder)
            {
                folder.className = 'f-tree-folder f-tree-open';
            }

            if (icon)
            {
                icon.className = 'f-tree-icon f-tree-icon-open';
            }

            view = view.lastChild;

            if (!node.__content_render)
            {
                this.__render_children(any = [], node, node, 0, node.length);

                view.innerHTML = any.join('');

                this.__mount_children(node, view, node, 0, node.length, view.firstChild);
            }
            
            view.style.display = '';
        }
        else
        {
            if (folder)
            {
                folder.className = 'f-tree-file';
                folder.removeAttribute('tag');
            }

            if (icon)
            {
                icon.className = 'f-tree-icon f-tree-icon-file';
            }

            view.lastChild.style.display = 'none';
        }
    };


    this.collapse = function (node) {

        var view = node.view;

        view.lastChild.style.display = 'none';

        find_dom(view, 'folder', 'f-tree-folder f-tree-close');
        
        if (view = find_dom(view, 'icon'))
        {
            view.className = view.className.replace('f-tree-icon-open', 'f-tree-icon-close');
        }
    };


    function find_dom(view, tag, className) {

        var node = view.firstChild.lastChild;

        while (node)
        {
            if (node.getAttribute('tag') === tag)
            {
                if (className)
                {
                    node.className = className;
                }

                return node;
            }

            node = node.previousSibling;
        }
    };



    this.current = function (node, current) {

        var dom = node.view.firstChild,
            name = dom.className,
            key = ' f-tree-node-current';

        if (current)
        {
            if (name.indexOf(key) < 0)
            {
                dom.className += key;
            }
        }
        else
        {
            dom.className = name.replace(key, '');
        }
    };



});




flyingon.renderer('GridColumn', function (base) {



    this.render = function (writer, column, height) {

        var cells = column.__cells;

        if (cells[1])
        {
            render_multi(writer, column, cells, height);
        }
        else
        {
            render_header(writer, column, cells[0] || column.__set_title('')[0], 0, column.__size, height);
        }
    };



    function render_multi(writer, column, cells, height) {

        var width = column.__size,
            length = cells.length,
            y1 = 0,
            y2,
            cell;

        for (var i = 0; i < length; i++)
        {
            cell = cells[i];

            y2 = cell.__height;
            y2 = y2 > 0 ? y2 : (height / (length - i) | 0);
   
            render_header(writer, column, cell, y1, cell.__size || column.__size, y2);

            y1 += y2;
            height -= y2;
        }
    };



    function render_header(writer, column, cell, y, width, height) {

        cell.row = null;
        cell.column = column;
        cell.__as_html = true;

        cell.renderer.render(writer, cell, 'f-grid-cell' + column.fullClassName, 
            'left:' + column.__start +
            'px;top:' + y +
            'px;width:' + width + 
            'px;height:' + height + 
            'px;line-height:' + height + 'px;' + 
            (cell.columnSpan ? 'z-index:1;' : ''));
    };



    this.mount = function (column, view, fragment, tag) {

        var grid = column.grid,
            cells = column.__cells,
            index = 0,
            cell,
            node;

        column.view = true;

        while ((cell = cells[index++]) && (node = view.firstChild))
        {
            cell.parent = grid;
            cell.renderer.mount(cell, node);

            fragment.insertBefore(node, tag);
        }
    };


    this.unmount = function (column, cells) {

        var index = 0,
            cell;

        column.view = false;
        cells || (cells = column.__cells);

        while (cell = cells[index++])
        {
            if (cell.view)
            {
                cell.parent = null;
                cell.renderer.unmount(cell, false);
            }
        }
    };



    this.readonly = function (column, readonly) {


    };


    //计算网格高度
    this.__resize_height = function (column, height) {

        var cells = column.__cells,
            length = cells.length,
            index,
            cell,
            style,
            size,
            y;

        if (length > 1)
        {
            index = y = 0;

            while (cell = cells[index])
            {
                size = cell.__height;
                size = size > 0 ? size : height / (length - index) | 0;

                style = cell.view.style;
                style.top = y + 'px';
                style.height = style.lineHeight = size + 'px';

                y += size;
                height -= size;

                index++;
            }
        }
        else
        {
            style = cells[0].view.style;
            style.height = style.lineHeight = height + 'px';
        }
    };
    

});



flyingon.renderer('GridRow', function (base) {


    var id = 1;


    this.show = function (fragment, writer, row, columns, start, end, y, height, tag) {

        var cells = row.__cells,
            cell,
            view,
            style,
            column,
            any;

        if (!cells)
        {
            row.view = true; //标记已渲染
            cells = row.__cells = {};
        }

        while (start < end)
        {
            column = columns[start];
            any = column.__name || (column.__name = '__column_' + id++);

            if (cell = cells[any])
            {
                //处理树列
                if (column.__tree_cell)
                {
                    fragment.appendChild(view = row.view);
                    
                    if (cell.__top !== y)
                    {
                        view.style.top = y + 'px';
                    }

                    if (cell.__show_tag !== tag)
                    {
                        style = view.style;
                        style.left = column.__start +  'px';
                        style.height = ((any = cell.rowSpan) ? ++any * height : height) + 'px';
                    }
                }

                fragment.appendChild(view = cell.view);

                //自定义显示前处理
                if (any = column.onshowing)
                {
                    any.call(column, cell, row);
                }

                if (cell.__top !== y)
                {
                    view.style.top = (cell.__top = y) + 'px';
                }

                if (cell.__show_tag !== tag)
                {
                    cell.__show_tag = tag;

                    style = view.style;
                    style.left = column.__start + 'px';

                    any = (any = cell.columnSpan) ? column.__span_size(any) : 0;
                    style.width = column.__size + any + 'px';

                    style.height = ((any = cell.rowSpan) ? ++any * height : height) + 'px';
                }
            }
            else if (cell = this.render(writer, row, column, y, height))
            {
                cell.__top = y;
                cell.__show_tag = tag;
                cells[any] = cell;
            }

            start++;
        }
    };


    this.render = function (writer, row, column, y, height) {

        var cell = column.createControl(row, column.__name),
            width = column.__size,
            span,
            any;

        //自定义渲染单元格
        if (any = column.onrender)
        {
            any.call(column, cell, row, column);

            if (any = cell.rowSpan) 
            {
                if ((any |= 0) > 0)
                {
                    span = 1;
                    height += any * height;
                }
                else
                {
                    any = 0;
                }

                cell.rowSpan = any;
            }

            if (any = cell.columnSpan) 
            {
                if ((any |= 0) > 0)
                {
                    span = 1;
                    width += column.__span_size(any);
                }
                else
                {
                    any = 0;
                }

                cell.columnSpan = any;
            }
        }

        cell.row = row;
        cell.column = column;
        cell.__as_html = true;

        //自定义显示前处理
        if (any = column.onshowing)
        {
            any.call(column, cell, row);
        }

        if (column.__tree_cell)
        {
            this.render_tree(writer, row, column, y, height, cell);
        }

        any = (any = column.__align) ? 'text-align:' + any + ';' : '';

        if (span)
        {
            any += 'z-index:1;';
        }

        cell.renderer.render(writer, cell, 'f-grid-cell' + column.fullClassName 
                + (row.__checked ? ' f-grid-checked' : '')
                + (row.__current ? ' f-grid-current' : ''),
            'left:' + column.__start + 
            'px;top:' + y + 
            'px;width:' + width + 
            'px;height:' + height + 
            'px;line-height:' + height + 'px;' +
            any);

        return cell;
    };


    this.render_tree = function (writer, row, column, y, height, cell) {

        var expand = row.length > 0 ? (row.expanded ? 'expand' : 'collapse') : 'file',
            icon = column.__tree_icon,
            width = 16;

        if (icon)
        {
            width += 16;

            if (icon = column.grid.onicon)
            {
                icon = icon.call(column.grid, row, column);
            }

            if (!icon)
            {
                icon = 'f-grid-icon-' + expand;
            }
        }

        while (row = row.parent)
        {
            width += 16;
        }

        writer.push('<div class="f-grid-tree" style="',
                'left:' + column.__start + 
                'px;top:' + y + 
                'px;width:' + width + 
                'px;height:' + height + 
                'px;line-height:' + height + 'px;">' +
                '<span class="f-grid-', expand, '" tag="', expand, '"', '></span>',
                '<span class="f-grid-icon', icon ? ' ' + icon : '" style="display:none;', '"></span>',
            '</div>');

        cell.padding('0 2 0 ' + (width + 2));
    };


    this.mount = function (view, row, columns, start, end, fragment, tag) {

        var grid = row.grid,
            cells = row.__cells,
            column,
            cell,
            node,
            name;

        while (start < end)
        {
            if ((column = columns[start++]) && (name = column.__name) && (cell = cells[name]))
            {
                if (node = cell.view)
                {
                    tag = node.nextSibling || null;
                }
                else if (node = view.firstChild)
                {
                    if (column.__tree_cell)
                    {
                        fragment.insertBefore(node, tag);

                        row.view = node;
                        node.row = row;
                        node.column = column;

                        node = view.firstChild;
                    }

                    fragment.insertBefore(node, tag);

                    cell.parent = grid;
                    cell.renderer.mount(cell, node);
                }
            }
        }

        return tag;
    };


    this.unmount = function (row) {

        var cells = row.__cells,
            any;

        for (var name in cells)
        {
            if (any = cells[name])
            {
                any.parent = any.row = any.column = null;
                any.renderer.unmount(any, false);

                cells[name] = null;
            }
        }
    };


    this.checked = function (row, view, value) {

        set_class(row.__cells, ' f-grid-checked', value);
    };


    this.current = function (row, view, value) {

        set_class(row.__cells, ' f-grid-current', value);
    };


    function set_class(cells, name, set) {

        var cell;

        if (set)
        {
            for (var key in cells)
            {
                if (cell = cells[key])
                {
                    cell.view.className += name;
                }
            }
        }
        else
        {
            for (var key in cells)
            {
                if (cell = cells[key])
                {
                    cell.view.className = cell.view.className.replace(name, '');
                }
            }
        }
    };


});



flyingon.renderer('GroupGridRow', 'GridRow', function (base) {


    this.render = function (writer, row, column, y, height) {

        var cell = new flyingon.Label(),
            storage = column.__storage,
            summary = storage && storage.summary,
            fn,
            any;

        cell.__as_html = true;

        if (summary && (any = storage.name))
        {
            fn = column.__summary_fn || (column.__summary_fn = flyingon.Grid.summary(summary));
            any = row.compute(column, any, fn[0], fn[1]);

            if ((fn = column.onsummary) && (fn = fn.call(column, row, any, summary)))
            {
                any = fn;
            }
            else
            {
                any = summary + '=' + any.toFixed(storage.precision);
            }

            cell.text(any);
        }

        cell.renderer.render(writer, cell, 'f-grid-group-row',
            'left:' + column.__start + 
            'px;top:' + y + 
            'px;width:' + column.__size + 
            'px;height:' + height + 
            'px;line-height:' + height + 'px;');

        return cell;
    };


    this.unmount = function (row) {

        var view = row.view_group;

        base.unmount.call(this, row);

        if (view)
        {
            view.row = row.view_group = null;
        }
    };


});



flyingon.renderer('Grid', function (base) {



    //拖动列时的辅助线
    var dom_drag = document.createElement('div');

    //调整列宽时的辅助线
    var dom_resize = document.createElement('div');


    //textContent || innerText
    var text_name = this.__text_name;

    //是否禁止列头点击事件
    var click_disabled = false;

    //可输入标签
    var input_tag = 'input,select,textarea'.toUpperCase().split(',');

    //更新标记
    var update_tag = 1;

    //动态管理子节点的临时节点
    var dom_fragment = document.createDocumentFragment();

    //动态生成html片段的dom容器
    var dom_host = document.createElement('div');

    //html模板
    var template = '<div class="f-grid-center"></div>'
        + '<div class="f-grid-right" style="display:none;"></div>'
        + '<div class="f-grid-left" style="display:none;"></div>'
        + '<div class="f-grid-group" style="display:none;"></div>';



    this.padding = 0;


    
    //初始化dom
    dom_drag.innerHTML = '<div class="f-grid-drag-body"><div></div></div>';
    dom_drag.className = 'f-grid-drag';
    dom_drag.style.width = '20px';

    dom_resize.className = 'f-grid-resize-thumb';




    this.render = function (writer, grid, className, cssText) {

        var storage = grid.__storage || grid.__defaults,
            group = storage.group,
            header = storage.header,
            top = group + header,
            block = template;

        writer.push('<div');

        this.renderDefault(writer, grid, className, cssText);

        writer.push(' onclick="flyingon.Grid.onclick.call(this, event)" onkeydown="flyingon.Grid.onkeydown.call(this, event)">',
            '<div class="f-grid-head" onmousedown="flyingon.Grid.onmousedown.call(this, event)">',
                '<div class="f-grid-group-box" style="height:', group, 'px;line-height:', group, 'px;', group < 2 ? 'display:none;' : '', '"></div>',
                '<div class="f-grid-column-head" style="height:', header, 'px;', header < 2 ? 'display:none;' : '', '" onmouseover="flyingon.Grid.onmouseover.call(this, event)">', 
                    block,
                    '<div class="f-grid-resize" style="display:none;" onmousedown="flyingon.Grid.resize.call(this, event)"></div>',
                    '<div class="f-grid-sort" style="left:-100px;"></div>',
                '</div>',
                '<div class="f-grid-filter" style="display:none;">', block, '</div>',
            '</div>',
            '<div class="f-grid-scroll" style="top:', top, 'px;" onscroll="flyingon.Grid.onscroll.call(this)">',
                this.__scroll_html,
            '</div>',
            '<div class="f-grid-body" style="top:', top, 'px;" tabindex="0">',
                '<div class="f-grid-middle">', block, '</div>',
                '<div class="f-grid-bottom" style="display:none;">', block, '</div>',
                '<div class="f-grid-top" style="display:none;">', block, '</div>',
            '</div>',
        '</div>');
    };



    this.mount = function (grid, view) {

        var dom = view.firstChild,
            any;

        grid.view_group = any = dom.firstChild;
        grid.view_head = any = any.nextSibling;
        grid.view_resize = (grid.view_sort = any.lastChild).previousSibling;
        grid.view_filter = any.nextSibling;

        grid.view_scroll = any = dom.nextSibling;
        grid.view_body = any.nextSibling;

        base.mount.call(this, grid, view);

        grid.on('mousewheel', mousewheel);
        grid.on('change', change_event);
    };


    this.unmount = function (grid) {

        base.unmount.call(this, grid);
        grid.view_group = grid.view_head = grid.view_resize = grid.view_sort = 
        grid.view_filter = grid.view_scroll = grid.view_body = null;
    };

    
    function mousewheel(e) {

        this.view_scroll.scrollTop -= e.wheelDelta * 100 / 120;
        flyingon.dom_stop(e);
    };


    function change_event(e) {

        var control = e.target;

        if (control.__column_check)
        {
            control.row.checked(!control.row.__checked);
        }
        else
        {
            control.parent.__change_value(control);
        }
    };
    


    flyingon.Grid.onkeydown = function (e) {

        if (e.keyCode === 9)
        {
            setTimeout(sync_focus, 0);
        }
    };
    

    //同步使用tab造成焦点位置变化的问题
    function sync_focus() {

        var dom = document.activeElement,
            cell,
            grid,
            any,
            x;

        if (dom && (cell = flyingon.findControl(dom)))
        {
            grid = cell.parent;

            dom = cell.view;
            any = dom.parentNode;

            x = dom.offsetLeft;

            if (x < grid.scrollLeft || x + dom.offsetWidth > any.offsetWidth)
            {
                grid.view_scroll.scrollLeft = cell.column.__start;
            }

            if (dom.offsetTop + dom.offsetHeight > any.offsetHeight)
            {
                grid.view_scroll.scrollTop = dom.offsetTop;
            }
        }
    };



    flyingon.Grid.onclick = function (e) {

        if (click_disabled)
        {
            click_disabled = false;
        }
        else
        {
            var grid = flyingon.findControl(this),
                dom = e.target || e.srcElement,
                any;

            switch (dom.getAttribute('tag'))
            {
                case 'expand':
                    change_expand(grid, any = dom.parentNode.row, dom, 'collapse');
                    grid.__view.__collapse_row(any);
                    break;

                case 'collapse':
                    change_expand(grid, any = dom.parentNode.row, dom, 'expand');
                    grid.__view.__expand_row(any);
                    break;

                default:
                    if ((any = flyingon.findControl(dom)) && !any.__column_check)
                    {
                        if (any.row) //数据行
                        {
                            grid.__set_current(any.row);
                        }
                        else if (any.column && !any.columnSpan && any.column.name()) //列头且无跨列
                        {
                            sort_column(grid, any);
                        }
                    }
                    break;
            }
        }
    };


    function change_expand(grid, row, dom, name) {

        dom.className = 'f-grid-' + name;
        dom.setAttribute('tag', name);

        if ((dom = dom.nextSibling) && dom.className.indexOf('f-grid-icon') >= 0)
        {
            var icon = grid.onicon;

            if (icon)
            {
                icon = icon.call(grid, row, dom.parentNode.column);
            }

            if (!icon)
            {
                icon = 'f-grid-icon-' + name;
            }

            dom.className = 'f-grid-icon ' + icon;
        }
    };


    function sort_column(grid, cell) {

        var dom = grid.view_sort,
            desc = dom.cell === cell && !dom.desc;

        dom.cell = cell;
        dom.desc = desc;
        dom.className = 'f-grid-sort' + (desc ? ' f-grid-sort-desc' : '');

        grid.sort(cell.column.name(), desc);

        sync_sort(dom);
    };


    function sync_sort(dom) {

        var cell = dom.cell,
            view,
            any;
            
        if (cell && (view = cell.view))
        {
            if (any = view.parentNode)
            {
                dom.style.left = any.offsetLeft + view.offsetLeft + view.offsetWidth - 18 + 'px';
                dom.style.top = view.offsetTop + (view.offsetHeight - 16 >> 1) + 'px';
            }
            else
            {
                dom.style.left = '-100px';
            }
        }
    };


    flyingon.Grid.onmouseover = function (e) {

        var dom = e.target || e.srcElement,
            grid,
            column,
            cell,
            any;

        if (dom.className.indexOf('f-grid-cell') >= 0 && 
            (cell = flyingon.findControl(dom)) &&
            (grid = flyingon.findControl(this)) &&
            (column = cell.column))
        {
            //处理跨列
            if (any = cell.columnSpan)
            {
                column = grid.__columns[column.__index + any];
            }

            if (column && column.resizable())
            {
                var head = grid.view_resize,
                    style = head.style;

                head.column = column;

                style.left = dom.parentNode.offsetLeft + dom.offsetLeft + dom.offsetWidth - 3 + 'px';
                style.top = dom.offsetTop + 'px';
                style.height = dom.offsetHeight + 'px';
                style.display = '';
            }
        }
    };


    flyingon.Grid.resize = function (e) {

        var grid = flyingon.findControl(this),
            left = 0,
            dom = this,
            any;

        grid.__column_dirty = true;
        grid.view.appendChild(e.dom = dom_resize);

        dom = grid.view_head;
        dom.style.cursor = 'ew-resize';

        any = e.dom.style;
        any.left = this.offsetLeft + (this.offsetWidth >> 1) + 1 + 'px';
        any.top = dom.offsetTop + 'px';
        any.bottom = grid.view_body.style.bottom;

        flyingon.dom_drag({

            grid: grid, 
            column: any = this.column,
            size: any.__size

        }, e, resize_start, do_resize, resize_end, 'y', false);
    };


    function resize_start() {

        click_disabled = true;
    };


    function do_resize(e) {

        var size = this.size;

        if (size + e.distanceX < 1)
        {
            e.distanceX = -size + 1;
        }
    };


    function resize_end(e) {

        var grid = this.grid,
            column = this.column,
            any = this.size + e.distanceX;

        click_disabled = false;

        grid.view_head.style.cursor = '';
        grid.view.removeChild(dom_resize);

        if (column.__size !== any)
        {
            column.storage().size = any;

            //触发列调整大小事件
            if (any = grid.oncolumnresize)
            {
                any.call(grid, column, storage.__size, this.size);
            }

            grid.update(true);
        }
    };



    flyingon.Grid.onmousedown = function (e) {

        var dom = e.target || e.srcElement,
            cell,
            any;

        if (input_tag.indexOf(dom.tagName) < 0)
        {
            if (any = dom.getAttribute('column-name'))
            {
                check_drag(this, dom, null, any, 1);
            }
            else
            {
                cell = flyingon.findControl(dom);

                while (cell)
                {
                    if (any = cell.column)
                    {
                        check_drag(this, dom, any, '', (cell.columnSpan | 0) + 1);
                        break;
                    }

                    cell = cell.parent;
                }
            }
        }
    };


    function check_drag(view, dom, column, name, count) {

        var grid = flyingon.findControl(view),
            from;

        if (column)
        {
            name = column.name();
        }
        else if (name && (column = grid.__columns.find(name)))
        {
             from = true;
        }
    
        column && column.draggable() && flyingon.dom_drag({

                grid: grid,
                column: column,
                dom: dom, 
                name: name,
                index: column.__index,
                count: count,
                from: from  //标记从分组框拖出
            },
            event,
            start_drag,
            do_drag,
            end_drag);
    };


    function start_drag(e) {

        var grid = this.grid,
            storage = grid.__storage || grid.__defaults,
            dom = this.dom,
            thumb = this.thumb = dom_drag,
            count = this.count,
            style,
            any;

        this.group = any = storage.group;
        this.header = storage.header;

        any = grid.view.firstChild.getBoundingClientRect();

        this.left = any.left;
        this.top = any.top;

        //从分组框拖出
        if (this.from)
        {
            dom.style.cssText = 'position:absolute;z-index:2;left:' 
                + dom.offsetLeft + 'px;top:' 
                + dom.offsetTop + 'px;';

            any = grid.__groups;
            any.splice(any.indexOf(this.name), 1);

            //清空原分组信息避免拖动结束后无法设置groups
            grid.__storage.groups = ' ';
        }
        else //拖动列
        {
            any = dom.cloneNode(true);

            style = any.style;
            style.borderWidth = '1px';
            style.left = dom.offsetLeft + dom.parentNode.offsetLeft + 'px';
            style.top = dom.offsetTop + dom.parentNode.parentNode.offsetTop + 'px';

            dom = any;

            //隐藏列头
            any = grid.__columns;

            while (count--)
            {
                any[this.index + count].__visible = false;
            }

            grid.update(true);
        }

        e.dom = dom;
        dom.style.zIndex = 2;

        any = grid.view.firstChild;
        any.appendChild(thumb);
        any.appendChild(dom);
        
        click_disabled = true;
    };


    function do_drag(event) {

        var grid = this.grid,
            style = this.thumb.style,
            x = event.clientX - this.left,
            y = event.clientY - this.top,
            view,
            height;

        //拖动到分组框
        if (this.to = this.name && y < this.group)
        {
            y = 4;
            height = this.group - 8;

            if (grid.__groups)
            {
                x = group_index(this, grid.view_group, x);
            }
            else
            {
                this.at = 0;
                x = 8;
            }
        }
        else //拖到列区
        {
            x = column_index(this, grid, x);
            y = this.group;
            height = this.header;
        }

        style.left = x - 11 + 'px';
        style.top = y + 'px';
        style.height = height + 'px';
    };


    function group_index(context, dom, x) {

        var index = 0,
            left = 0,
            width = 0;

        dom = dom.firstChild;

        while (dom)
        {
            left = dom.offsetLeft;
            width = dom.offsetWidth;

            if (left + (width >> 1) > x)
            {
                context.at = index;
                return left - 4;
            }

            if (left + width > x)
            {
                break;
            }

            index++;
            dom = dom.nextSibling;
        }

        context.at = index;
        return left + width + 4;
    };


    function column_index(context, grid, x) {

        var columns = grid.__columns,
            locked = columns.__locked,
            start = locked[0],
            end = columns.length,
            offset = 0,
            left = 0,
            size = 0,
            column;

        //在左锁定区
        if (start && locked[2] > x)
        {
            end = start;
            start = 0;
        }
        else if (locked[1] && x > (offset = columns.__arrange_size - locked[3])) //在右锁定区
        {
            start = end - locked[1];
            x += offset;
        }
        else //滚动区域
        {
            offset = -grid.scrollLeft | 0;
            x -= offset;
        }

        console.log(columns[2].__visible);

        while (start < end)
        {
            column = columns[start++];

            if (column.__visible)
            {
                left = column.__start;
                size = column.__size;

                if (left + (size >> 1) > x)
                {
                    context.at = start - 1;
                    return left + offset;
                }

                if (left + size > x)
                {
                    break;
                }
            }
        }

        context.at = start;
        return left + size + offset;
    };

    
    function end_drag(event) {

        var grid = this.grid,
            columns = grid.__columns,
            index = this.index,
            count = this.count,
            list = [],
            any;

        click_disabled = false;

        if (any = this.thumb)
        {
            any.parentNode.removeChild(any);
        }

        if (any = event.dom)
        {
            any.parentNode.removeChild(any);
        }

        //拖到分组框
        if (this.to)
        {
            for (var i = 0; i < count; i++)
            {
                list.push(columns[index + i].name());
            }

            if (any = grid.__groups)
            {
                any.splice(this.at, 0, list.join(' '));
                any = any.join(' ');
            }
            else
            {
                any = list.join(' ');
            }

            grid.groups(any);
        }
        else 
        {
            //从分组框拖出时需同步分组
            if (this.from)
            {
                grid.groups(grid.__groups.join(' '));
            }

            //显示列
            for (var i = 0; i < count; i++)
            {
                columns[index + i].__visible = true;
            }

            //如果顺序发生变化则调整列顺序
            if (this.at !== index)
            {
                reorder_column(columns, this.at, index, count);
            }

            grid.update(true);
        }
    };


    //调整列顺序
    function reorder_column(columns, newIndex, oldIndex, count) {

        var splice = [].splice,
            list = splice.call(columns, oldIndex, count || (count = 1));

        if (list[0])
        {
            if (newIndex > oldIndex)
            {
                newIndex -= count;
            }

            if (list[1])
            {
                list.unshift(newIndex, 0);
                splice.apply(columns, list);
            }
            else
            {
                splice.call(columns, newIndex, 0, list[0]);
            }
        }
    };



    flyingon.Grid.onscroll = function () {

        var grid = flyingon.findControl(this),
            x = this.scrollLeft,
            y = this.scrollTop;

        if (grid.scrollLeft !== x)
        {
            grid.renderer.__do_hscroll(grid, grid.scrollLeft = x);
            sync_sort(grid.view_sort);
        }

        if (grid.scrollTop !== y)
        {
            grid.renderer.__do_vscroll(grid, grid.scrollTop = y);
        }
    };



    this.locate = function (grid) {

        base.locate.call(this, grid);
        this.content(grid, grid.view);
    };


    this.locate_html = function (grid) {


    };



    //列头大小发生变化
    this.header = function (grid, view, value) {

        var columns = grid.__columns,
            storage = grid.__storage || grid.__defaults,
            group = storage.group,
            header = storage.header,
            style;

        grid.view_body.style.top = grid.view_scroll.style.top = group + header + 'px';

        if (value > 1)
        {
            style = grid.view_head.style;
            style.display = header > 1 ? '' : 'none';
            style.height = header + 'px';

            for (var i = columns.length - 1; i >= 0; i--)
            {
                var column = columns[i];

                if (column.view)
                {
                    column.renderer.__resize_height(column, header);
                }
            }
        }
        else
        {
            style = grid.view_group.style;
            style.display = group > 1 ? '' : 'none';
            style.height = style.lineHeight = group + 'px';
        }
    };


    //内容发生变化
    this.content = function (grid, view) {

        this.show(grid,
            grid.scrollLeft | 0,
            grid.scrollTop | 0,
            grid.offsetWidth - grid.borderLeft - grid.borderRight,
            grid.offsetHeight - grid.borderTop - grid.borderBottom);
    };



    //显示指定范围的表格内容
    this.show = function (grid, x, y, width, height) {

        var storage = grid.__storage || grid.__defaults,
            columns = grid.__columns,
            rows = grid.__rows,
            height = grid.offsetHeight - grid.borderTop - grid.borderBottom,
            any;

        //显示分组
        if ((any = storage.group) > 0)
        {
            height -= any;
        }

        //计算列宽度
        any = columns.__arrange_size !== width;

        if (grid.__column_dirty || any && columns.__persent)
        {
            grid.__column_dirty = false;

            columns.__show_tag = update_tag++;
            columns.__compute_size(width);
            columns.__compute_visible(x);
        }
        else if (any || columns.__arrange_start !== x)
        {
            columns.__arrange_size = width;
            columns.__compute_visible(x);
        }

        //控制水平滚动条
        if (columns.__size > width)
        {
            any = flyingon.hscroll_height;
            height -= any;
        }
        else
        {
            any = 1;
        }

        grid.view_body.style.bottom = any + 'px';
        grid.view_scroll.firstChild.style.width = columns.__size + 'px';

        //显示列头
        if ((any = storage.header) > 0)
        {
            height -= any;
            this.__show_header(grid, columns, any);
        }

        //显示过滤栏
        if ((any = storage.filter) > 0)
        {
            height -= any;
            this.__show_filter(grid, columns, any);
        }

        //显示内容
        any = this.__show_body(grid, grid.currentView(), height);

        //排列横向锁定区域
        this.__layout_locked(grid, columns.__locked, any);
    };



    //显示列头
    this.__show_header = function (grid, columns, height) {

        var view = grid.view_head.children[3],
            locked = columns.__locked,
            any;

        //group
        view = view.previousSibling;

        //left lock
        if (any = locked[0])
        {
            this.show_header(view, columns, 0, any, height);
        }

        //right lock
        view = view.previousSibling;

        if (any = locked[1])
        {
            this.show_header(view, columns, columns.length - any, columns.length, height);
        }

        //scroll
        this.show_header(view.previousSibling, columns, columns.__show_start, columns.__show_end, height);

        //sort arrow
        sync_sort(grid.view_sort);
    };



    //排列横向锁定区域
    this.__layout_locked = function (grid, locked, vscroll) {

        var view = grid.view_head,
            left = locked[2],
            right = locked[3],
            group = grid.__group_size,
            scroll = grid.scrollLeft | 0;

        if (vscroll = vscroll && right > 0)
        {
            right += 1;
        }

        layout_locked(view, left, vscroll ? right + flyingon.vscroll_width : right, group, scroll);

        layout_locked(view = grid.view_body.firstChild, left, right, group, scroll);
        layout_locked(view = view.nextSibling, left, right, group, scroll);
        layout_locked(view.nextSibling, left, right, group, scroll);
    };


    function layout_locked(view, left, right, group, scroll) {

        var dom = view.firstChild,
            style = dom.style;

        //center
        style[flyingon.rtl ? 'right' : 'left'] = -scroll + 'px';

        //right
        dom = dom.nextSibling;
        style = dom.style;

        if (right > 0)
        {
            style.width = right + 'px';
            style.display = '';
        }
        else
        {
            style.display = 'none';
        }

        //left
        dom = dom.nextSibling;
        style = dom.style;

        if (left > 0)
        {
            style.width = left + 'px';
            style.display = '';
        }
        else
        {
            style.display = 'none';
        }

        //group
        style = dom.nextSibling.style;

        if (group > 0)
        {
            style.width = group + 'px';
            style.display = '';
        }
        else
        {
            style.display = 'none';
        }
    };



    //显示列头
    this.show_header = function (view, columns, start, end, height) {

        var writer = [],
            tag = columns.__show_tag,
            fragment = dom_fragment,
            index = start,
            column,
            node,
            tag,
            style,
            cells,
            cell,
            any;

        while (index < end)
        {
            if ((column = columns[index++]).__visible)
            {
                if (column.view)
                {
                    any = 0;
                    cells = column.__cells;

                    if (style = column.__show_tag !== tag)
                    {
                        column.__show_tag = tag;
                    }

                    while (cell = cells[any++])
                    {
                        fragment.appendChild(node = cell.view);

                        if (style)
                        {
                            style = node.style;
                            style.left = column.__start + 'px';
                            style.width = (cell.__size || column.__size) + 'px';
                        }
                    }
                }
                else
                {
                    column.__show_tag = tag;
                    column.renderer.render(writer, column, height);
                }
            }
        }

        if (writer[0])
        {
            any = dom_host;
            any.innerHTML = writer.join('');

            tag = fragment.firstChild;

            while (start < end)
            {
                if ((column = columns[start++]).__visible)
                {
                    if (node = column.view)
                    {
                        tag = node.nextSibling || null;
                    }
                    else
                    {
                        column.renderer.mount(column, any, fragment, tag);
                    }
                }
            }
        }

        //移除原来显示的节点
        while (any = view.lastChild)
        {
            view.removeChild(any);
        }

        view.appendChild(fragment);
    };


    //显示过滤栏
    this.__show_filter = function (grid, column, height) {

    };


    //显示内容
    this.__show_body = function (grid, rows, height) {

        var view = grid.view_body.lastChild,
            storage = grid.__storage || grid.__defaults,
            start = grid.__locked_top,
            end = rows.length,
            rowHeight = rows.__row_height = storage.rowHeight,
            tree = storage.treeColumn,
            size = end * rowHeight,
            vscroll = size > height,
            any;

        //记录是否树列
        if (any = tree && grid.__columns.find(tree))
        {
            any.__tree_cell = true;
            any.__tree_icon = storage.treeIcon;
        }

        grid.view_scroll.firstChild.style.height = (size || 1) + 'px';
        grid.view_body.style[flyingon.rtl ? 'left' : 'right'] = (vscroll ? flyingon.vscroll_width : 0) + 'px';

        //显示顶部锁定
        if (start > 0)
        {
            view.style.display = '';
            view.style.height = (size = start * rowHeight) + 'px';

            height -= size;

            this.__show_rows(grid, view, rows, 0, start);
        }
        else
        {
            size = 0;
            view.style.display = 'none';
        }

        //显示底部锁定
        view = view.previousSibling;

        if ((any = grid.__locked_bottom) > 0)
        {
            view.style.display = '';
            view.style.height = (size = any * rowHeight) + 'px';

            height -= size;

            this.__show_rows(grid, view, rows, end - any, end);
            end -= any;
        }
        else
        {
            view.style.display = 'none';
        }

        //调整滚动区位置
        view = view.previousSibling;
        view.style.top = -(grid.scrollTop | 0) + 'px';

        //显示滚动区
        rows.__arrange_size = height;

        if (vscroll)
        {
            this.__visible_rows(grid, rows, grid.scrollTop | 0);
        }
        else
        {
            rows.__show_start = start;
            rows.__show_end = end;
        }

        this.__show_rows(grid, view, rows, rows.__show_start, rows.__show_end, true);

        return vscroll;
    };


    //计算行滚动行显示范围
    this.__visible_rows = function (grid, rows, top, scroll) {

        var start = grid.__locked_top,
            end = rows.length - grid.__locked_bottom,
            rowHeight = rows.__row_height,
            any;

        if (top > 0)
        {
            start += top / rowHeight | 0;
        }

        any = (rows.__arrange_size / rowHeight) | 0;
        any += start + 3; //多渲染部分行以减少滚动处理

        if (any < end)
        {
            end = any;
        }

        if (scroll && rows.__show_start <= start && rows.__show_end >= end)
        {
            return true;
        }

        if (any = grid.onrowstart)
        {
            any = any.call(grid, rows, start);

            if (any >= 0)
            {
                start = 0;
            }
        }
        
        rows.__show_start = start;
        rows.__show_end = end;
    };


    //显示表格行集
    this.__show_rows = function (grid, view, rows, start, end, scroll) {

        var columns = grid.__columns,
            locked = columns.__locked,
            rowHeight = rows.__row_height,
            column_start = locked[0],
            column_end = columns.length,
            top = scroll ? start * rowHeight : 0,
            any;

        //group
        view = view.lastChild;

        if (any = grid.__group_size)
        {
            this.show_group(grid, view, rows, start, end, top, rowHeight);
        }
        else if (view.firstChild)
        {
            view.innerHTML = ''; //销毁原分组行视图
        }

        //left lock
        view = view.previousSibling;

        if (column_start)
        {
            this.show_rows(grid, view, rows, start, end, columns, 0, column_start, top, rowHeight);
        }
        else if (view.firstChild)
        {
            view.innerHTML = '';
        }

        //right lock
        view = view.previousSibling;

        if (any = locked[1])
        {
            this.show_rows(grid, view, rows, start, end, columns, column_end - any, column_end, top, rowHeight);
        }
        else if (view.firstChild)
        {
            view.innerHTML = '';
        }

        //scroll
        this.show_rows(grid, view.previousSibling, rows, start, end, columns, columns.__show_start, columns.__show_end, top, rowHeight);
    };


    //显示表格行
    this.show_rows = function (grid, view, rows, start, end, columns, column_start, column_end, top, height) {

        var writer = [], 
            tag = columns.__show_tag,
            fragment = dom_fragment, 
            row, 
            any;

        for (var i = start; i < end; i++)
        {
            if (row = rows[i])
            {
                row.__show_index = i; //记录显示行索引以便于事件处理
                row.renderer.show(fragment, writer, row, columns, column_start, column_end, top, height, tag);

                top += height;
            }
        }

        if (writer[0])
        {
            any = dom_host;
            any.innerHTML = writer.join('');

            tag = fragment.firstChild;

            for (var i = start; i < end; i++)
            {
                tag = (row = rows[i]).renderer.mount(any, row, columns, column_start, column_end, fragment, tag);
            }
        }

        while (any = view.lastChild)
        {
            view.removeChild(any);
        }

        view.appendChild(fragment);
    };


    //显示分组行头
    this.show_group = function (grid, view, rows, start, end, top, height) {

        var writer = [],
            fragment = dom_fragment,
            tag = grid.__columns.__show_tag,
            size = grid.__group_size,
            fn = grid.ongroup,
            index = start,
            row,
            node,
            text,
            any;

        while (index < end)
        {
            if (row = rows[index])
            {
                if (row.__group_row)
                {
                    //记录行索引以支持事件定位
                    row.__show_index = index;

                    text = any = fn && fn(row) || row.text + ' (' + row.total + ')';

                    if (node = row.view_group)
                    {
                        fragment.appendChild(node);

                        if (row.__text !== text)
                        {
                            node.firstChild.nextSibling[text_name] = row.__text = text;
                        }

                        if (row.__top !== top)
                        {
                            node.style.top = (row.__top = top) - 1 + 'px';
                        }
                    }
                    else
                    {
                        writer.push('<div class="f-grid-group-row" style="top:', (row.__top = top) - 1, 
                                'px;height:', height + 1, 
                                'px;line-height:', height, 
                                'px;min-width:', size, 'px;',
                                'px;text-align:left;">',
                            '<span class="f-grid-', row.expanded ? 'expand" tag="expand"' : 'collapse" tag="collapse"',
                            ' style="margin-left:', row.level * 20, 'px;"></span>',
                            '<span> ', row.__text = text, '</span>', 
                            '<div class="f-grid-group-line" style="top:0;bottom:auto;"></div>',
                            '<div class="f-grid-group-line"></div>',
                        '</div>');
                    }
                }

                top += height;
            }

            index++;
        }

        view.style.height = top + 'px';

        if (writer[0])
        {
            any = dom_host;
            any.innerHTML = writer.join('');

            tag = fragment.firstChild;

            while (start < end)
            {
                if ((row = rows[start]) && row.__group_row)
                {
                    if (node = row.view_group)
                    {
                        tag = node.nextSibling || null;
                    }
                    else
                    {
                        node = any.firstChild;
                        node.row = row;
                        row.view_group = node;

                        fragment.insertBefore(node, tag);
                    }
                }

                start++;
            }
        }

        while (any = view.lastChild)
        {
            view.removeChild(any);
        }

        view.appendChild(fragment);
    };



    //渲染分组框
    this.__render_group = function (grid) {

        var writer = [],
            groups = grid.__groups,
            columns = grid.__columns,
            column,
            cells,
            name;

        if (groups)
        {
            for (var i = 0, l = groups.length; i < l; i++)
            {
                if (column = columns.find(name = groups[i]))
                {
                    column.__visible = false;
                    cells = column.__cells;

                    writer.push('<span class="f-grid-group-cell" column-name="', name, '">', 
                            column.__find_text() || name, 
                        '</span>');
                }
            }
        }
        else
        {
            writer.push('<span class="f-information">', flyingon.i18ntext('grid.group'), '</span>');
        }

        grid.view_group.innerHTML = writer.join('');
    };



    //处理水平滚动
    this.__do_hscroll = function (grid, left) {

        var columns = grid.__columns,
            view = grid.view_head.firstChild,
            height = (grid.__storage || grid.__defaults).header,
            name = flyingon.rtl ? 'right' : 'left',
            scroll = -left + 'px',
            update = !columns.__compute_visible(left, true), //计算可见列范围并获取是否超出上次的渲染范围
            start = columns.__show_start,
            end = columns.__show_end;

        //重渲染列头
        if (height > 0)
        {
            //控制滚动位置
            view.style[name] = scroll;

            //超出上次渲染的范围则重新渲染
            if (update)
            {
                this.show_header(view, columns, start, end, height);
            }
        }

        view = grid.view_body.firstChild;
        view.firstChild.style[name] = scroll;

        view = view.nextSibling;
        view.firstChild.style[name] = scroll;

        view.nextSibling.firstChild.style[name] = scroll;

        if (update)
        {
            var rows = grid.currentView(),
                any;
            
            select_cache(grid, true);

            view =  grid.view_body.firstChild;
            height = rows.__row_height;

            if (any = grid.__locked_top)
            {
                this.show_rows(grid, view.nextSibling.firstChild, rows, 0, any, columns, start, end, 0, height);
            }

            if (any = grid.__locked_bottom)
            {
                this.show_rows(grid, view.nextSibling.nextSibling.firstChild, rows, rows.length - any, rows.length, columns, start, end, 0, height);
            }

            this.show_rows(grid, view.firstChild, rows, any = rows.__show_start, rows.__show_end, columns, start, end, any * height, height);
        
            select_cache(grid);
        }
    };


    //处理竖直滚动
    this.__do_vscroll = function (grid, top) {

        var rows = grid.currentView(),
            view = grid.view_body.firstChild;

        select_cache(grid, true);
            
        view.style.top = -top + 'px';

        if (!this.__visible_rows(grid, rows, top, true))
        {
            this.__show_rows(grid, view, rows, rows.__show_start, rows.__show_end, true);
        }

        select_cache(grid);
    };



    function select_cache(grid, start) {

        var view = grid.view_body,
            dom = document.activeElement, 
            any;

        if (start)
        {
            any = dom;

            while (any = any.parentNode)
            {
                if (any === view)
                {
                    select_cache.dom = dom;
                    view.focus();
                    return;
                }
            }
        }
        else if (any = select_cache.dom)
        {
            if (dom === view)
            {
                any.focus();
            }
            else
            {
                select_cache.dom = null;
            }
        }
    };



});




flyingon.renderer('Tab', function (base) {




    this.__scroll_html = '';




    this.render = function (writer, control, className, cssText) {

        var storage = control.__storage || control.__defaults,
            any;

        control.__content_render = true;

        writer.push('<div');
        
        this.renderDefault(writer, control, (className || '') + 'f-tab-direction-' + storage.direction, cssText);
        
        writer.push('><div class="f-tab-head f-tab-theme-', storage.theme, '">',
                    '<div class="f-tab-line"></div>',
                    '<div class="f-tab-content"></div>',
                    '<div class="f-tab-move f-tab-forward" onclick="flyingon.Tab.forward.call(this)"><a class="f-tab-move-link"><span class="f-tab-move-icon"></span></a></div>',
                    '<div class="f-tab-move f-tab-back" onclick="flyingon.Tab.back.call(this)"><a class="f-tab-move-link"><span class="f-tab-move-icon"></span></a></div>',
                '</div>',
            '<div class="f-tab-body">');

        if (any = control.selectedPage())
        {
            any.renderer.render(writer, any, false); 
        }

        writer.push('</div></div>');
    };



    flyingon.Tab.forward = function () {

        var control = control = flyingon.findControl(this);

        if ((control.__scroll_header -= 100) < 0)
        {
            control.__scroll_header = 0;
        }

        update_header(control);
    };


    flyingon.Tab.back = function () {

        var control = control = flyingon.findControl(this);

        control.__scroll_header += 100;
        update_header(control);
    };



    this.mount = function (control, view) {

        var page = control.selectedPage();

        base.mount.call(this, control, view);
        
        this.__insert_head(control);

        if (page)
        {
            page.renderer.mount(page, view.lastChild.firstChild);
        }
    };


    this.unmount = function (control, remove) {

        this.__unmount_children(control);
        base.unmount.call(this, control, remove);
    };



    this.selected = function (control, view, page) {

        //移动到当前位置
        var storage = control.__storage || control.__defaults,
            size = storage.size,
            space = storage.space,
            head,
            start;

        if (!page.view)
        {
            view.lastChild.appendChild(page.renderer.createView(page, false));
            page.renderer.locate(page);
        }

        head = page.view_head;

        if (size > 0)
        {
            start = control.indexOf(page) * (size + space);
        }
        else if ('left,right'.indexOf(storage.direction) >= 0)
        {
            size = head.offsetWidth;
            start = head.offsetTop - space;
        }
        else
        {
            size = head.offsetHeight;
            start = head.offsetLeft - space;
        }

        view = view.firstChild.firstChild.nextSibling;
        space = -view.offsetLeft;

        //如果起始位置在可见区或可见区的右边
        if (start > space)
        {
            //如果整个页头在可见区则不调整位置
            size = head.offsetLeft + size;
            start = view.parentNode.offsetWidth;

            if (size < space + start)
            {
                return;
            }

            start = size - start + 80; //后移一点方便点击后一节点
        }
        else if ((start -= 50) < 0) //前移一点方便点击前一节点
        {
            start = 0;
        }

        if (control.__scroll_header !== start)
        {
            control.__scroll_header = start;
            control.__update_dirty || update_header(control);
        }
    };


    //页签风格变更处理
    this.theme = function (control, view, value) {

        view.className = view.className.replace(/f-tab-type-\w+/, 'f-tab-type-' + value);
    };

    

    this.__insert_head = function (control) {

        var view = control.view.firstChild.firstChild.nextSibling,
            item, 
            node, 
            tag;        
            
        //处理插入带view的节点
        for (var i = control.length - 1; i >= 0; i--)
        {
            if (item = control[i])
            {
                if (node = item.view_head)
                {
                    if (node.parentNode === view)
                    {
                        tag = node;
                        continue;
                    }
                }
                else
                {
                    item.renderer.__render_header(item);
                    node = item.view_head;
                }

                if (tag)
                {
                    view.insertBefore(node, tag);
                }
                else
                {
                    view.appendChild(node);
                }

                tag = node;
            }
        }
    };


    this.__insert_patch = function (control, index, items) {

        this.__insert_head(control);
    };


    this.__remove_patch = function (control, items) {

        var view = control.view.firstChild.firstChild.nextSibling,
            index = 0, 
            item,
            any;

        while (item = items[index++])
        {
            //移除节点且还未移除视图
            if (item.parent !== control && (any = item.view_head) && (any.parentNode === view))
            {
                view.removeChild(any);
            }
        }

        base.__remove_patch.apply(this, arguments);
    };



    this.locate = function (control) {

        var page = control.selectedPage();

        base.locate.call(this, control);
        
        if (control.__reset_header)
        {
            control.__reset_header = false;
            reset_header(control);
        }

        if (control.length > 0)
        {
            if (control.header() > 0)
            {
                update_header(control);
            }

            this.__arrange(control);
        }

        if (page)
        {
            if (!page.view)
            {
                control.view.lastChild.appendChild(page.renderer.createView(page, false));
            }

            page.renderer.locate(page);
        }

        control.__arrange_dirty = 0;
    };


    
    function update_header(control) {

        var view = control.view.firstChild.firstChild.nextSibling,
            node = view.firstChild,
            length = control.length,
            name = flyingon.rtl ? 'right' : 'left',
            storage = control.__storage || control.__defaults,
            vertical = 'left,right'.indexOf(storage.direction) >= 0,
            space = storage.space,
            style, //默认样式
            total, //容器空间
            size,
            any;

        any = storage.header - storage.offset;

        if (vertical)
        {
            style = 'margin-top:' + space + 'px;width:' + any + 'px;line-height:' + (storage.size - 2) + 'px;';
            total = control.offsetHeight - control.borderTop - control.borderBottom - storage.start;
        }
        else
        {
            style = 'margin-' + name + ':' + space + 'px;height:' + any + 'px;line-height:' + (any - 2) + 'px;';
            total = control.offsetWidth - control.borderLeft - control.borderRight - storage.start;
        }

        //充满可用空间
        if (storage.fill)
        {
            //计算可用大小
            total -= space * (length + 1) + storage.end;

            any = style + (vertical ? 'height:' : 'width:');

            while (node)
            {
                size = total / length | 0;
                node.style.cssText = any + size + 'px;';

                node = node.nextSibling;

                length--;
                total -= size;
            }
            
            length = 0;
        }
        else
        {
            any = (size = storage.size) > 0 ? size + 'px;' : 'auto;';

            if (vertical)
            {
                style += 'height:' + any + 'margin-top:' + space + 'px;';
            }
            else
            {
                style += 'width:' + any + 'margin-' + name + ':' + space + 'px;';
            }

            while (node)
            {
                node.style.cssText = style;
                node = node.nextSibling;
            }

            if (size > 0)
            {
                length = (size + space) * length + space;
            }
            else
            {
                length = (vertical ? view.offsetHeight : view.offsetWidth) + space;
            }
        }

        //有滚动条
        if ((any = length - total) > 0)
        {
            any += storage.scroll - 1;

            if (control.__scroll_header > any)
            {
                control.__scroll_header = size = any;
            }
            else
            {
                size = control.__scroll_header - storage.scroll + 1;
            }
        }
        else
        {
            control.__scroll_header = size = any = 0;
        }

        view.style[vertical ? 'top' : name] = -(storage.start + size) + 'px';

        node = view.nextSibling;
        node.style.display = node.nextSibling.style.display = any > 0 ? '' : 'none';
    };


    //重算页头
    function reset_header(control) {

        var view = control.view,
            storage = control.__storage || control.__defaults,
            style1 = view.firstChild.style, //head
            style2 = view.lastChild.style, //body
            direction = storage.direction,
            header = storage.header,
            text = ':' + header + 'px',
            any;

        view.className = view.className.replace(/f-tab-direction-\w+/, 'f-tab-direction-' + direction);
        
        switch (direction)
        {
            case 'left':
                style1.cssText = 'right:auto;width' + text;
                style2.cssText = direction + text;
                text = 'height';
                break;

            case 'right':
                style1.cssText = 'left:auto;width' + text;
                style2.cssText = direction + text;
                text = 'height';
                break;

            case 'bottom':
                style1.cssText = 'top:auto;height' + text;
                style2.cssText = direction + text;
                text = 'width';
                break;

            default:
                style1.cssText = 'bottom:auto;height' + text;
                style2.cssText = direction + text;
                text = 'width';
                break;
        }

        if (header > 0)
        {
            view = view.firstChild.firstChild;

            if (view = view.nextSibling)
            {
                view.style.cssText = any = direction + ':' + storage.offset + 'px';
                text = text + ':' + storage.scroll + 'px;display:none;' + any;
                
                while (view = view.nextSibling)
                {
                    view.style.cssText = text;
                }
            }

            style1.display = '';
        }
        else
        {
            style1.display ='none';
        }
    };


    this.__arrange = function (control) {
        
        var storage = control.__storage || control.__defaults,
            header = storage.header,
            width = control.offsetWidth - control.borderLeft - control.borderRight - control.paddingLeft - control.paddingRight,
            height = control.offsetHeight - control.borderTop - control.borderBottom - control.paddingTop - control.paddingBottom;

        if (header > 0)
        {
            if ('left,right'.indexOf(storage.direction) >= 0)
            {
                width -= header;
            }
            else
            {
                height -= header;
            }
        }

        for (var i = control.length - 1; i >= 0; i--)
        {
            var item = control[i];

            item.measure(width, height, width, height, 3);
            item.locate(0, 0);
        }
    };



});



flyingon.renderer('TabPage', 'Panel', function (base) {



    this.__render_header = function (control) {

        var node = control.view_head = document.createElement('span'),
            writer = [],
            encode = flyingon.html_encode,
            storage = control.__storage || control.__defaults,
            any;

        node.className = 'f-tab-item' + (control.selected() ? ' f-tab-selected' : '');

        writer.push('<a class="f-tab-link">',
            '<span class="f-tab-icon ', (any = storage.icon) ? encode(any) : 'f-tab-icon-none', '"></span>',
            '<span class="f-tab-text">', (any = storage.text) ? encode(any) : '', '</span>');

        if ((any = storage.buttons) && (any = encode(any).replace(/(\w+)\W*/g, '<span class="f-tab-button $1" tag="button"></span>')))
        {
            writer.push(any);
        }

        writer.push('<span class="f-tab-close"', storage.closable ? '' : ' style="display:none"', ' tag="close"></span>',
            '</a>');

        node.innerHTML = writer.join('');
        
        node.page = control;
        node.onclick = onclick;
    };


    function onclick(e) {

        var page = this.page,
            target = (e || (e = window.event)).target || e.srcElement;

        while (target && target !== this)
        {
            switch (target.getAttribute('tag'))
            {
                case 'close':
                    page.remove();
                    return;

                case 'button':
                    this.trigger('button-click', 'page', page);
                    return;
            }

            target = target.parentNode;
        }

        page.parent.selectedPage(page, 'click');
    };


    this.unmount = function (control, remove) {

        var view = control.view_head;

        control.view_head = view.control = view.onclick = null;

        base.unmount.call(this, control, remove);
    };



    this.icon = function (control, value) {

        control.view_head.firstChild.firstChild.className = 'f-tab-icon ' + (value || 'f-tab-icon-none');
    };


    this.text = function (control, value) {

        control.view_head.firstChild.firstChild.nextSibling[this.__text_name] = value;
    };


    this.buttons = function (control, value) {

        var last = (view = control.view_head).firstChild.lastChild,
            node = last.previousSibling;

        while (node && node.getAttribute('tag') === 'button')
        {
            node = node.previousSibling;
            view.removeChild(node.nextSibling);
        }

        if (value)
        {
            value = flyingon.html_encode(any).replace(/(\w+)\W*/g, '<span class="f-tab-button $1" tag="button"></span>');
            flyingon.dom_html(view, value, last);
        }
    };


    this.closable = function (control, value) {

        control.view_head.firstChild.lastChild.style.display = value ? '' : 'none';
    };


    this.selected = function (control, value) {

        if (control.view)
        {
            control.view.style.display = value ? '' : 'none';
        }

        control.view_head.className = 'f-tab-item' + (value ? ' f-tab-selected' : '');
    };


});




flyingon.renderer('Popup', 'Panel', function (base) {



    //弹出层管理器
    var stack = [];

    //当前弹出层
    var current = null;

    //注册事件函数
    var on = flyingon.dom_on;

    //注销事件函数
    var off = flyingon.dom_off;

    

    //处理全局点击事件,点击当前弹出层以外的区域则关闭当前弹出层
    on(document, 'mousedown', function (e) { 

        var control;

        if (control = current) {

            var view = control.view,
                reference = control.__view_reference,
                any = e.target;

            while (any)
            {
                if (any === view || any === reference)
                {
                    return;
                }

                any = any.parentNode;
            }

            //调用关闭弹出层方法, 关闭类型为'auto'
            if (control.trigger('autoclosing', 'dom', e.target) !== false)
            {
                control.close('auto');
            }
        }
    });
    

    //处理全局键盘事件,点击Esc则退出当前窗口
    on(document, 'keydown', function (e) { 

        var control;

        if ((control = current) && e.which === 27)
        {
            control.close('cancel');
        }
    });




    //打开弹出层
    //reference: 停靠参考物
    this.show = function (control, reference, offset, direction, align, reverse) {

        var rect = (control.__view_reference = reference.view || reference).getBoundingClientRect();
            
        if (offset)
        {
            rect = {

                top: rect.top - (offset[0] | 0),
                right: rect.right + (offset[1] | 0),
                bottom: rect.bottom + (offset[2] | 0),
                left: rect.left - (offset[3] | 0)
            };
        }

        this.showAt(control, 0, 0);

        rect = flyingon.dom_align(control.view, rect, direction, align, reverse);

        control.offsetLeft = rect.left;
        control.offsetTop = rect.top;
    };


    //在指定的位置打开弹出层
    this.showAt = function (control, left, top) {

        var view = control.view || this.createView(control, false);

        document.body.appendChild(view);

        control.trigger('showing');

        control.measure(document.body.clientWidth, 0);
        control.locate(left | 0, top | 0);

        flyingon.__update_patch();
        
        this.update(control);

        stack.push(current = control);
        
        if ((control.__closeAway = control.closeAway()) && !closeAway.count++)
        {
            closeAway.count = 1;
            on(document, 'mousemove', closeAway);
        }

        if (control.__closeLeave = control.closeLeave())
        {
            on(view, 'mouseout', closeLeave);
        }
        
        control.trigger('shown');
    };


    function closeAway(e) {
        
        var control, any;

        if ((control = current) && (any = control.__closeAway))
        {
            var rect = control.__view_rect,
                x = e.clientX,
                y = e.clientY;

            if (rect)
            {
                if (rect.left - x > any.x1 || x - rect.right > any.x2 || 
                    rect.top - y > any.y1 || y - rect.bottom > any.y2)
                {
                    control.close('auto');
                }
            }
            else
            {
                control.__view_rect = rect = control.view.getBoundingClientRect();

                control.__closeAway = {

                    x1: (any = rect.left - x) > 0 ? any + 4 : 4,
                    x2: (any = x - rect.right) > 0 ? any + 4 : 4,
                    y1: (any = rect.top - y) > 0 ? any + 4 : 4,
                    y2: (any = y - rect.bottom) > 0 ? any + 4 : 4
                };
            }
        }
    };


    function closeLeave(e) {

        var control = current;

        if (control && control.view === this)
        {
            var rect = this.getBoundingClientRect(),
                x = e.clientX,
                y = e.clientY;

            if (x >= rect.right || y >= rect.bottom || x <= rect.left || y <= rect.top)
            {
                control.close('auto');
            }
        }
    };



    //关闭弹出层(弹出多级窗口时只有最后一个可以成功关闭)
    this.close = function (control) {

        var view = control.view,
            any;

        control.__view_reference = null;

        //注销事件
        if (control.__closeAway)
        {
            control.__closeAway = control.__view_rect = null;

            if (!--closeAway.count)
            {
                off(document, 'mousemove', closeAway);
            }
        }

        if (control.__closeLeave)
        {
            off(view, 'mouseout', closeLeave);
        }

        stack.pop();
        current = stack[stack.length - 1];

        if (any = view.parentNode)
        {
            any.removeChild(view);
        }
    };



});




flyingon.renderer('Dialog', 'Panel', function (base) {



    this.render = function (writer, control, className, cssText) {

        var storage = control.__storage || control.__defaults,
            head = storage.header,
            text = storage.text,
            any;

        writer.push('<div');
        
        this.renderDefault(writer, control, className, cssText);
        
        if (text)
        {
            text = flyingon.html_encode(text);
        }

        if (any = control.format)
        {
            text = any.call(control, text);
        }

        writer.push('>',
            '<div class="f-dialog-head" style="height:', head, 'px;line-height:', head, 'px;" onmousedown="flyingon.Dialog.onmousedown.call(this, event)" onclick="flyingon.Dialog.onclick.call(this, event)">',
                '<span class="f-dialog-icon ', (any = storage.icon) ? any : '" style="display:none;', '"></span>',
                '<span class="f-dialog-text">', text, '</span>',
                '<span class="f-dialog-close"', storage.closable ? '' : ' style="display:none;"', ' tag="close"></span>',
                '<span class="f-dialog-line"></span>',
            '</div>',
            '<div class="f-dialog-body" style="top:', head, 'px;">');

        if (control.length > 0 && control.__visible)
        {
            control.__content_render = true;
            this.__render_children(writer, control, control, 0, control.length);
        }

        writer.push(this.__scroll_html, '</div></div>');
    };
    



    flyingon.Dialog.onclick = function (e) {

        var control = flyingon.findControl(this),
            dom = e.target || e.srcElement;

        if (dom.getAttribute('tag') === 'close')
        {
            control.close();
        }
        else
        {
            control.active();
        }
    };
    
    
    flyingon.Dialog.onmousedown = function (e) {

        var control = flyingon.findControl(this);
        
        if (control.movable())
        {
            control.active();
            control.renderer.movable(control, e);
        }
    };



    this.mount = function (control, view) {

        control.view_content = view.lastChild;
        base.mount.call(this, control, view);
    };



    this.active = function (control, active) {

        var view = control.view,
            name = ' f-dialog-active';

        if (active)
        {
            if (view.className.indexOf(name) < 0)
            {
                view.className += name;
            }
        }
        else
        {
            view.className = view.className.replace(name, '');
        }
    };


    this.header = function (control, view, value) {

        view.firstChild.style.height = view.lastChild.style.top = value + 'px';
    };


    this.text = function (control, view, value) {

        view = view.firstChild.firstChild.nextSibling;

        if (control.format)
        {
            if (value)
            {
                value = flyingon.html_encode(value);
            }

            view.innerHTML = control.format(value);
        }
        else
        {
            view[this.__text_name] = value;
        }
    };


    this.icon = function (control, view, value) {

        view = view.firstChild.firstChild;
        view.className = 'f-groupbox-icon' + (value ? ' ' + value : '');
        view.style.display = value ? '' : 'none';
    };


    this.closable = function (control, view, value) {

        view.firstChild.lastChild.style.display = value ? '' : 'none';
    };



    this.show = function (control, overlay) {

        var body = document.body,
            view = control.view || this.createView(control, false),
            width = body.clientWidth;

        body.appendChild(view);
        
        control.trigger('showing');

        control.measure(width, 0);

        this.center(control);

        if (overlay)
        {
            flyingon.dom_overlay(view);
        }

        flyingon.__update_patch();
        this.update(control);
        
        control.trigger('shown');
    };

    
    this.center = function (control) {

        var body = document.body,
            style = control.view.style;

        style.left = (control.offsetLeft = body.clientWidth - control.offsetWidth >> 1) + 'px';
        style.top = (control.offsetTop = ((window.innerHeight || document.documentElement.clientHeight) 
            - control.offsetHeight >> 1) - body.clientLeft) + 'px';
    };


    this.movable = function (control, event) {

        event.dom = control.view;
        flyingon.dom_drag(control, event);
        
        event.dom = null;
    };



    this.close = function (control) {

        var view = control.view,
            any;

        if (any = view.parentNode)
        {
            any.removeChild(view);
        }

        if (view.flyingon_overlay)
        {
            flyingon.dom_overlay(view, false);
        }
    };



});




flyingon.showMessage = function (title, text, type, buttons, focus) {

    var dialog, any;

    if (arguments.length < 4)
    {
        focus = buttons;
        buttons = type;
        type = '';
    }

    buttons = buttons ? '' + buttons : 'ok';

    any = buttons.match(/\w+/g);
    buttons = [];

    for (var i = 0, l = any.length; i < l; i++)
    {
        buttons.push({

            Class: 'Button',
            height: 25,
            style: 'min-width:80px;margin-top:8px;',
            tag: any[i],
            text: flyingon.i18ntext('system.' + any[i], any[i])
        });
    }

    dialog = flyingon.ui({

        layout: 'vertical-line',
        width: 300,
        height: 'auto',
        padding: 0,
        text: title,

        children: [
            { 
                Class: 'Panel', 
                layout: 'dock',
                height: 'auto',
                padding: 8,
                minHeight: 60,
                style: 'overflow:hidden;',
                children: [
                    { Class: 'Label', dock: 'left', width: 50, height: 50, visible: type, className: 'f-message-icon' + (type ? ' f-message-' + type : '') },
                    { Class: 'Label', dock: 'fill', height: 'auto', text: text }
                ]
            },
            {
                Class: 'div', 
                height: 40,
                className: 'f-message-foot', 
                style: 'overflow:hidden;',
                children: buttons
            }
        ]

    }, flyingon.Dialog).showDialog();

    any = dialog.offsetHeight / 200;

    if (any > 1)
    {
        any = 300 * any;

        dialog.width(any > 800 ? 800 : any);
        dialog.showDialog();
    }

    dialog.view.lastChild.firstChild.nextSibling.children[focus | 0].focus();

    dialog.on('click', function (e) {

        var tag = e.target.tag();

        if (tag)
        {
            this.close(tag);
        }
    });

    return dialog;

};





/**
 * @class flyingon.Control
 * @uses f-bindable
 * @uses f-collection
 * @description 控件基类
 */
//IE7点击滚动条时修改className会造成滚动条无法拖动,需在改变className后设置focus获取焦点解决此问题
Object.extend('Control', function () {

    
    
    var create = flyingon.create;
  
    var pixel = flyingon.pixel;

    var pixel_sides = flyingon.pixel_sides;

          
    /**
     * @property defaultWidth
     * @type {int}
     * @description 控件默认宽度(width === 'default'时的宽度)
     */
    this.defaultWidth = 100;

    //控件默认高度(height === 'default'时的高度)
    this.defaultHeight = 25;
    

    //控件坐标
    this.offsetLeft = this.offsetTop = this.offsetWidth = this.offsetHeight = 0;

    //外边距
    this.marginLeft = this.marginTop = this.marginRight = this.marginBottom = 0;

    //边框宽度
    this.borderLeft = this.borderTop = this.borderRight = this.borderBottom = 0;

    //内边距
    this.paddingLeft = this.paddingTop = this.paddingRight = this.paddingBottom = 0;

    //滚动条位置
    this.scrollLeft = this.scrollTop = 0;

        
    
    //扩展可视组件功能
    flyingon.fragment('f-visual', this);

    
    //扩展可绑定功能
    flyingon.fragment('f-bindable', this);
    


    //获取焦点指令
    this['#focused'] = function (value) {

        if (value)
        {
            this.focus();
        }
        else
        {
            this.blur();
        }
    };



    this.__visible = true;


    /**
     * @method visible
     * @description 是否可见
     * @param {boolean} value
     */
    this.defineProperty('visible', true, {
        
        group: 'layout',

        set: function (value) {

            var any;

            this.__visible = value;
            
            if (this.rendered)
            {
                if (any = this.__view_patch)
                {
                    any.visible = value;
                }
                else
                {
                    this.renderer.set(this, 'visible', value);
                }
            }

            this.__update_dirty || this.invalidate();
        }
        
    });
        



    //定位属性变化
    this.__location_dirty = 0;


    //定义定位属性
    var define = function (self, name, defaultValue, dirty) {
   
        return self.defineProperty(name, defaultValue, {
            
            group: 'layout',

            set: function () {

                this.__location_dirty |= dirty;
                this.__update_dirty || this.invalidate();
            }
        });
    };
    

    //左边距
    define(this, 'left', '', 512);

    //顶边距
    define(this, 'top', '', 1024);

    //宽度
    //default: 默认
    //auto: 自动
    //number: 指定象素
    //number + css单位
    define(this, 'width', 'default', 1);

    //高度
    //default: 默认
    //auto: 自动
    //number: 指定象素
    //number + css单位
    define(this, 'height', 'default', 2);


    //最小宽度
    this['min-width'] = define(this, 'minWidth', '', 32);

    //最大宽度
    this['max-width'] = define(this, 'maxWidth', '', 64);

    //最小高度
    this['min-height'] = define(this, 'minHeight', '', 128);

    //最大高度
    this['max-height'] = define(this, 'maxHeight', '', 256);


    //外边距
    define(this, 'margin', '', 4);

    //边框宽度
    define(this, 'border', '', 8);

    //内边距
    define(this, 'padding', '', 16);


    define = function (self, name, defaultValue, dirty) {
   
        return self.defineProperty(name, defaultValue, {
            
            group: 'layout',

            set: function () {

                if (!this.__as_html && !this.__update_dirty)
                {
                    this.invalidate();
                }
            }
        });
    };


    //控件横向对齐方式
    //left      左边对齐
    //center    横向居中对齐
    //right     右边对齐
    this['align-x'] = define(this, 'alignX', 'left');

    //控件纵向对齐方式
    //top       顶部对齐
    //middle    纵向居中对齐
    //bottom    底部对齐
    this['align-y'] = define(this, 'alignY', 'top');
    
    //控件停靠方式(此值仅在当前布局类型为停靠布局(dock)时有效)
    //left:     左停靠
    //top:      顶部停靠
    //right:    右停靠
    //bottom:   底部停靠
    //fill:     充满
    define(this, 'dock', 'left');



    //设置自定义样式
    this.defineProperty('style', '', {
        
        group: 'appearance',

        fn: function (name, value) {

            var style = this.__style,
                any;

            if (name === void 0)
            {
                if (style && (any = style.cssText) === false)
                {
                    return style.cssText = style_text(style);
                }

                return any || '';
            }

            name = '' + name;

            //单个设置样式
            if (value !== void 0)
            {
                this['style:'](name, value);
                return this;
            }
            
            if (name.length < 36 && name.indexOf(':') < 0) //读指定名称的样式
            {
                return style && style[name] || '';
            }
            
            if (value = name.match(/\:|[^\s:;]+(\s+[^\s:;]+)?/g))
            {
                set_style.call(this, style, value);
            }

            return this;
        }
    });

    
    //设置样式
    this['style:'] = function (name, value) {

        var style = this.__style,
            watches,
            any;

        if (!name || (any = style && style[name] || '') === value)
        {
            return;
        }

        (style || (style = this.__style = {}))[name] = value;

        if (watches = this.__watches)
        {
            if (watches['style:' + name])
            {
                this.notify('style:' + name, value, any);
            }

            if (watches.style)
            {
                any = style.cssText || '';
                this.notify('style', style_text(style), any);
            }
        }
        else
        {
            style.cssText = false;
        }

        if (this.rendered)
        {
            (this.__style_patch || style_patch(this))[name] = value;
        }
    };


    //批量设置样式
    function set_style(style, list) {

        var watches = this.__watches,
            render = this.rendered,
            index = 0,
            length = list.length,
            name,
            value,
            patch,
            any;

        style = style || (this.__style = {});

        while (index < length)
        {
            while ((name = list[index++]) === ':')
            {
            }

            if (!name)
            {
                continue;
            }

            //值为''表示清除原有样式
            if (list[index++] === ':')
            {
                value = list[index++] || '';
            }
            else
            {
                index--;
                value = '';
            }

            if ((any = style && style[name] || '') !== value)
            {
                style[name] = value;

                if (watches && watches['style:' + name])
                {
                    this.notify('style:' + name, value, any);
                }

                if (render)
                {
                    (patch || (patch = this.__style_patch || style_patch(this)))[name] = value;
                }
                else
                {
                    patch = true;
                }
            }
        }

        if (patch)
        {
            if (watches && watches.style)
            {
                any = style.cssText || '';
                this.notify('style', style_text(style), any);
            }
            else
            {
                style.cssText = false;
            }
        }
    };


    //创建样式补丁
    function style_patch(self) {

        var view = self.__view_patch,
            patch = self.__style_patch = {};
        
        if (view)
        {
            view.__style_patch = patch;
        }
        else
        {
            self.renderer.set(self, '__style_patch', patch);
        }

        return patch;
    };


    //获取样式文本
    function style_text(style) {

        var list = [],
            value;

        for (var name in style)
        {
            if (name !== 'cssText' && (value = style[name]) !== '')
            {
                list.push(name, ':', value, ';');
            }
        }

        return style.cssText = list.join('');
    };

    

    //定义attribute属性
    define = function (self, name, defaultValue, attributes) {

        attributes = attributes || {};

        attributes.set = function (value) {

            var any;

            if (any = this.__view_patch)
            {
                any[name] = value;
            }
            else
            {
                this.renderer.set(this, name, value);
            }
        };

        self.defineProperty(name, defaultValue, attributes);
    };

    
    //tab顺序
    define(this, 'tabindex', 0);
    
    
    //是否禁用
    define(this, 'disabled', false);
    

    //是否只读
    define(this, 'readonly', false);


    //提示信息
    define(this, 'title', '');


    //快捷键
    define(this, 'accesskey', '');
    
    
    
    //是否可调整大小或调整大小的方式
    //none  不可调整
    //x     只能调整宽度
    //y     只能调整高度
    //all   宽度高度都可调整
    this.defineProperty('resizable', 'none');
    
    
    //是否可移动
    this.defineProperty('movable', false);
    
    
    //是否要放置移动或拖动
    this.defineProperty('droppable', false);


    //自定义标记键值
    this.defineProperty('key', '');


    //自定义标记
    this.defineProperty('tag', null);




    //获取定位属性值
    this.locationValue = function (name) {

        return (this.__location_values || this.__storage || this.__defaults)[name];
    };


    

    //测量控件大小
    //containerWidth    容器宽度
    //containerHeight   容器高度
    //availableWidth    可用宽度 
    //availableHeight   可用高度
    //defaultToFill     默认宽度或高度是否转成充满 0:不转 1:宽度转 2:高度转 3:宽高都转
    this.measure = function (containerWidth, containerHeight, availableWidth, availableHeight, defaultToFill) {
        
        var storage = this.__storage || this.__defaults,
            location = this.__location_values || storage,
            minWidth = location.minWidth,
            maxWidth = location.maxWidth,
            minHeight = location.minHeight,
            maxHeight = location.maxHeight,
            width = location.width,
            height = location.height,
            auto = 0,
            fn = pixel_sides,
            cache = fn.cache,
            any;

        any = cache[any = location.margin] || fn(any, containerWidth);

        this.marginLeft = any.left;
        this.marginTop = any.top;
        this.marginRight = any.right;
        this.marginBottom = any.bottom;

        //不支持在布局中修改边框和内边距
        any = cache[any = storage.border] || fn(any, 0); //border不支持百分比

        this.borderLeft = any.left;
        this.borderTop = any.top;
        this.borderRight = any.right;
        this.borderBottom = any.bottom;

        //不支持在布局中修改边框和内边距
        any = cache[any = storage.padding] || fn(any, containerWidth);

        this.paddingLeft = any.left;
        this.paddingTop = any.top;
        this.paddingRight = any.right;
        this.paddingBottom = any.bottom;

        fn = pixel;
        cache = fn.cache;

        minWidth = minWidth > 0 ? minWidth | 0 : cache[minWidth] || fn(minWidth, containerWidth);
        maxWidth = maxWidth > 0 ? maxWidth | 0 : cache[maxWidth] || fn(maxWidth, containerWidth);

        minHeight = minHeight > 0 ? minHeight | 0 : cache[minHeight] || fn(minHeight, containerHeight);
        maxHeight = maxHeight > 0 ? maxHeight | 0 : cache[maxHeight] || fn(maxHeight, containerHeight);

        //处理宽度
        switch (width)
        {
            case 'default':
                if (defaultToFill & 1)
                {
                    any = availableWidth >= 0 ? availableWidth : containerWidth;
                    width = any - this.marginLeft - this.marginRight;
                }
                else
                {
                    width = this.defaultWidth;
                }
                break;
                
            case 'auto':
                auto = 1;
                width = availableWidth || this.defaultWidth;
                break;

            default:
                width = (any = +width) === any ? any | 0 : cache[width] || fn(width, containerWidth);
                break;
        }

        if (any < 0)
        {
            width = 0;
        }

        //处理高度
        switch (height)
        {
            case 'default':
                if (defaultToFill & 2)
                {
                    any = availableHeight >= 0 ? availableHeight : containerHeight;
                    height = any - this.marginTop - this.marginBottom;
                }
                else
                {
                    height = this.defaultHeight;
                }
                break;
                
            case 'auto':
                auto |= 2;
                height = availableHeight || this.defaultHeight;
                break;

            default:
                height = (any = +height) === any ? any | 0 : cache[height] || fn(height, containerHeight);
                break;
        }

        if (height < 0)
        {
            height = 0;
        }

        this.__auto_size = auto; 
        
        //处理最小及最大宽度
        if (width < minWidth)
        {
            width = minWidth;
        }
        else if (maxWidth > 0 && width > maxWidth)
        {
            width = maxWidth;
        }
        
        //处理最小及最大高度
        if (height < minHeight)
        {
            height = minHeight;
        }
        else if (maxHeight > 0 && height > maxHeight)
        {
            height = maxHeight;
        }
        
        //设置大小
        this.offsetWidth = width;
        this.offsetHeight = height;
        
        //测量后处理
        if ((fn = this.onmeasure) && fn.call(this, auto) !== false)
        {
            //处理最小及最大宽度
            if (this.offsetWidth !== width)
            {
                if ((width = this.offsetWidth) < minWidth)
                {
                    this.offsetWidth = width = minWidth;
                }
                else if (maxWidth > 0 && width > maxWidth)
                {
                    this.offsetWidth = width = maxWidth;
                }
            }

            //处理最小及最大高度
            if (this.offsetHeight !== height)
            {
                if ((height = this.offsetHeight) < minHeight)
                {
                    this.offsetHeight = height = minHeight;
                }
                else if (maxHeight > 0 && height > maxHeight)
                {
                    this.offsetHeight = height = maxHeight;
                }
            }
        }
    };
    
        
    //定位控件
    this.locate = function (x, y, alignWidth, alignHeight, container) {
        
        var width = this.offsetWidth,
            height = this.offsetHeight,
            any;

        if (alignWidth > 0 && (any = alignWidth - width))
        {
            switch ((this.__location_values || this.__storage || this.__defaults).alignX)
            {
                case 'center':
                    x += any >> 1;
                    break;

                case 'right':
                    x += any;
                    break;
                    
                default:
                    x += this.marginLeft;
                    break;
            }
        }
        else
        {
            x += this.marginLeft;
        }

        if (alignHeight > 0 && (any = alignHeight - height))
        {
            switch ((this.__location_values || this.__storage || this.__defaults).alignY)
            {
                case 'middle':
                    y += any >> 1;
                    break;

                case 'bottom':
                    y += any;
                    break;
                    
                default:
                    y += this.marginTop;
                    break;
            }
        }
        else
        {
            y += this.marginTop;
        }
        
        this.offsetLeft = x;
        this.offsetTop = y;
        
        if ((any = this.onlocate) && any.call(this) !== false)
        {
            x = this.offsetLeft;
            y = this.offsetTop;
        }

        if (container)
        {
            container.arrangeX = (x += width + this.marginRight);
            container.arrangeY = (y += height + this.marginBottom);

            if (x > container.arrangeRight)
            {
                container.arrangeRight = x;
            }

            if (y > container.arrangeBottom)
            {
                container.arrangeBottom = y;
            }
        }
    };
    

    // this.clientWidth = function () {
    
    //     return this.offsetWidth - this.borderLeft - this.borderRight - this.paddingLeft - this.paddingRight;
    // };


    // this.clientHeight = function () {

    //     return this.offsetHeight - this.borderTop - this.borderBottom - this.paddingTop - this.paddingBottom;
    // };

    

    //是否可获取焦点
    this.canFocus = function () {

        return !!this.tabindex;
    };


    this.focus = function () {

        this.rendered && this.renderer.focus(this);
    };


    this.blur = function () {

        this.rendered && this.renderer.blur(this);
    };
    
           
      

    this.__update_dirty = true;

    //使布局无效
    this.invalidate = function () {

        var parent = this.parent;

        this.__update_dirty = true;

        if (parent)
        {
            parent.__arrange_delay(2);
        }
        else if (this.__top_control)
        {
            flyingon.__update_delay(this);
        }

        return this;
    };


    this.__arrange_dirty = 0;

    //启用延时排列
    this.__arrange_delay = function (dirty) {

        if (this.__arrange_dirty < dirty)
        {
            var parent = this.parent;

            this.__arrange_dirty = dirty;

            if (parent)
            {
                parent.__arrange_delay(1);
            }
            else if (this.__top_control)
            {
                flyingon.__update_delay(this);
            }
        }
    };

        
    
    //滚动事件处理
    this.__do_scroll = function (x, y) {
        
    };

    
    
    //扩展可序列化功能
    flyingon.fragment('f-serialize', this);


    
    //序列化方法
    this.serialize = function (writer) {

        var any;
        
        if ((any = this.Class) && (any = any.nickName || any.fullName))
        {
            writer.writeProperty('Class', any);
        }
        
        if (any = this.__storage)
        {
            writer.writeProperties(any, this.getOwnPropertyNames(), this.__watches);
        }

        if (any = this.__style)
        {
            serialize_style(writer, any, this.__watches);
        }
    };


    function serialize_style(writer, style, watches) {

        var list = [],
            key,
            value,
            any;

        for (var name in style)
        {
            if (name !== 'cssText' && (value = style[name]) !== '')
            {
                if (watches && (any = watches[key = 'style:' + name]) && (any = any[0]))
                {
                    writer.writeProperty(key, '{{' + any + '}}');
                }
                else
                {
                    list.push(name, ':', value, ';');
                }
            }
        }

        if (list[0])
        {
            writer.writeProperty('style', list.join(''));
        }
    };
    
    

    //被移除或关闭时是否自动销毁
    this.autoDispose = true;
    
    
    //销毁控件    
    this.dispose = function () {
    
        var storage = this.__storage,
            any;

        //触发销毁过程
        if (any = this.distroyed)
        {
            any.call(this);
        }
        
        if (this.view)
        {
            this.renderer.dispose(this);
        }

        if (any = this.__dataset)
        {
            any.subscribe(this, true);
            this.__dataset = null;
        }
        
        if (this.__events)
        {
            this.off();
        }
        
        this.parent = this.__loop_vm = this.__list = null;

        return this;
    };
    
    

}).register();




flyingon.Control.extend('HtmlElement', function (base) {


    this.tagName = 'div';


    //内容文本
    this.defineProperty('text', '', {
        
        set: function (value) {

            this.length > 0 && this.splice(0);
            this.rendered && this.renderer.set(this, 'text', value);
        }
    });


    //设置的text是否html(注意html注入漏洞)
    this.defineProperty('html', false);


    //是否排列子控件(如果子控件或子子控件不包含布局控件,此值设为false可提升性能)
    this.defineProperty('arrange', true);
    
    

    //扩展容器功能
    flyingon.fragment('f-container', this, true);



    //测量自动大小
    this.onmeasure = function (auto) {
        
        var tag = (this.offsetHeight << 16) + this.offsetWidth;

        if (this.__size_tag !== tag)
        {
            this.__size_tag = tag;
            this.__arrange_dirty = 2;
        }

        if (auto)
        {
            this.renderer.__measure_auto(this, auto);
        }
        else
        {
            return false;
        }
    };



    this.serialize = function (writer) {
        
        base.serialize.call(this, writer);
        
        if (this.length > 0)
        {
            writer.writeProperty('children', this, true);
        }
        
        return this;
    };
    

    this.dispose = function () {

        for (var i = this.length - 1; i >= 0; i--)
        {
            this[i].dispose(false);
        }

        base.dispose.apply(this, arguments);
        return this;
    };



});




flyingon.Control.extend('Label', function (base) {
   
    

    this.defaultWidth = 60;


    
    function define(self, name, defaultValue) {

        self.defineProperty(name, defaultValue, {
            
            set: function () {

                this.rendered && this.renderer.set(this, 'text');
            }
        });
    };


    //标签文本
    define(this, 'text', '');


    //文本是否html
    define(this, 'html', false);


    
    
    //测量自动大小
    this.onmeasure = function (auto) {
        
        if (auto)
        {
            this.renderer.__measure_auto(this, auto);
        }
        else
        {
            return false;
        }
    };
    


}).register();




flyingon.Control.extend('Button', function (base) {
   
    

    var define = function (self, name, defaultValue) {

        return self.defineProperty(name, defaultValue, {

            set: function (value) {

                this.rendered && this.renderer.set(this, name, value);
            }
        });
    };

    
    //图标
    define(this, 'icon', '');


    //图标大小
    this['icon-size'] = define(this, 'iconSize', 16);


    //图标和文字是否竖排
    define(this, 'vertical', false);


    //文本内容
    define(this, 'text', '');
    
    
    //文本内容是否html格式
    define(this, 'html', false);


        
    //测量自动大小
    this.onmeasure = function (auto) {
        
        if (auto)
        {
            this.renderer.__measure_auto(this, auto);
        }
        else
        {
            return false;
        }
    };
       


}).register();




flyingon.Control.extend('LinkButton', function (base) {
   


    var define = function (self, name, defaultValue) {

        return self.defineProperty(name, defaultValue, {

            set: function (value) {

                this.rendered && this.renderer.set(this, name, value);
            }
        });
    };

    
    //文本内容
    define(this, 'text', '');
    
    
    //文本内容是否html格式
    define(this, 'html', false);


    //链接地址
    define(this, 'href', '');
    

        
    //测量自动大小
    this.onmeasure = function (auto) {
        
        if (auto)
        {
            this.renderer.__measure_auto(this, auto);
        }
        else
        {
            return false;
        }
    };
       


}).register();




flyingon.Control.extend('Image', function (base) {



    this.defaultWidth = 400;

    this.defaultHeight = 300;



    this.defineProperty('src', '', {
            
        set: function (value) {

            this.rendered && this.renderer.set(this, 'src', value);
        }
    });


    this.defineProperty('alt', '', {
            
        set: function (value) {

            this.rendered && this.renderer.set(this, 'alt', value);
        }
    });



}).register();




flyingon.Control.extend('Slider', function (base) {



    var define = function (self, name, defaultValue) {

        return self.defineProperty(name, defaultValue, {

            dataType: 'int',

            check: function (value) {

                return value < 0 ? 0 : value;
            },

            set: function () {

                if (this.rendered && !this.__location_dirty)
                {
                    this.renderer.set(this, 'refresh');
                }
            }
        });
    };



    define(this, 'value', 0);


    define(this, 'min', 0);


    define(this, 'max', 100);


    define(this, 'buttonSize', 8);



}).register();




flyingon.Control.extend('ProgressBar', function (base) {



    this.defaultHeight = 20;

    this.defaultValue('border', 1);



    this.defineProperty('value', 0, {

        dataType: 'int',

        check: function (value) {

            if (value < 0)
            {
                return 0;
            }

            return value > 100 ? 100 : value;
        },

        set: function (value) {

            this.rendered && this.renderer.set(this, 'value', value);
        }
    });


    this.defineProperty('text', true, {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'text', value);
        }
    });


}).register();




//集合功能扩展
flyingon.fragment('f-container', function (childrenClass, arrange) {



    if (childrenClass === true)
    {
        childrenClass = null;
        arrange = true;
    }


    //子控件类
    this.childrenClass = childrenClass || flyingon.Control;


    //是否需要排列
    this.__arrange_dirty = arrange ? 2 : 0;

    

    flyingon.fragment('f-collection', this);


    this.__check_error = function (Class) {

        throw '"' + this.Class.fullName + '" type can push "' + Class.fullName + '" type only!';
    };

  

    //分离子控件(不销毁)
    this.detach = function (index, length) {

        var items = this.splice.apply(this, arguments),
            length = items.length,
            item;

        if (length > 0)
        {
            for (var i = 0; i < length; i++)
            {
                if (item = items[i])
                {
                    item.parent = null;
                    item.autoDispose = false;
                }
            }
        }

        return items;
    };


    //添加子项前检测处理
    this.__check_items = function (index, items, start) {

        var Class = this.childrenClass,
            html = this instanceof flyingon.HtmlElement,
            patch = this.__content_render && [],
            item,
            any;

        while (item = items[start])
        {
            if (item.__flyingon_class)
            {
                if (item instanceof Class)
                {
                    if ((any = item.parent) && any !== this)
                    {
                        any.__remove_items(any.indexOf(item), [item]);
                    }
                }
                else
                {
                    this.__check_error(Class);
                }
            }
            else if ((item = this.__create_child(item, Class)) instanceof Class)
            {
                items[start] = item;
            }
            else
            {
                this.__check_error(Class);
            }

            item.parent = this;
            item.__as_html = html;

            if (patch)
            {
                patch.push(item);
            }

            start++;
        }

        this.__all && this.__clear_all();

        if (patch && patch[0])
        {
            this.__children_dirty(1, index, patch);
        }

        if (arrange && this.__arrange_dirty < 2)
        {
            this.__arrange_delay(2);
        }
    };


    //创建控件方法
    this.__create_child = flyingon.ui;


    //移除多个子项
    this.__remove_items = function (index, items) {

        var patch = [],
            item;

        this.__all && this.__clear_all();

        for (var i = items.length - 1; i >= 0; i--)
        {
            if (item = items[i])
            {
                item.parent = null;
                item.autoDispose = true;

                patch.push(item);
            }
        }

        //注册子项变更补丁
        if (patch[0])
        {
            this.__children_dirty(2, -1, patch);
        }

        if (arrange && this.__arrange_dirty < 2)
        {
            this.__arrange_delay(2);
        }
    };


    //注册子项变更补丁
    this.__children_dirty = function (type, index, items) {

        var patch = this.__children_patch;

        if (patch)
        {
            var any = patch.length - 3;

            //相同类型进行合并处理
            if (type === patch[any++] && patch[any++] === index)
            {
                any = patch[any + 1];
                any.apply(any, items);
            }
            else
            {
                patch.push(type, index, items);
            }
        }
        else
        {
            this.__children_patch = [type, index, items];
            this.renderer.__children_dirty(this);
        }
    };



    //清除all缓存
    this.__clear_all = function () {

        var any = this.parent;

        this.__all = null;

        while (any && any.__all)
        {
            any.__all = null;
            any = any.parent;
        }
    };



    //使用选择器查找子控件
    this.find = function (selector) {

        return new flyingon.Query(selector, [this]);
    };


    //查找指定id的子控件
    this.findById = function (id, deep) {

        var query = new flyingon.Query(),
            list;

        if (id)
        {
            list = flyingon.__find_id(deep !== false ? this.all() : this, id);
            list.push.apply(query, list);
        }

        return query;
    };


    //查找指定类型的子控件
    this.findByType = function (name, deep) {

        var query = new flyingon.Query(),
            list;

        if (name)
        {
            list = flyingon.__find_type(deep !== false ? this.all() : this, name);
            list.push.apply(query, list);
        }

        return query;
    };


    //查找指定class的子控件
    this.findByClass = function (name, deep) {

        var query = new flyingon.Query(),
            list;

        if (name)
        {
            list = flyingon.__find_class(deep !== false ? this.all() : this, name);
            list.push.apply(query, list);
        }

        return query;
    };


    //获取所有子控件
    this.all = function () {

        return this.__all || (this.__all = all(this, []));
    };


    function all(self, list) {

        var item, any;

        for (var i = 0, l = self.length; i < l; i++)
        {
            if (item = self[i])
            {
                list.push(item);

                if (any = item.all)
                {
                    list.push.apply(list, any.call(item));
                }
            }
        }

        return list;
    };


    
    //查找拖拉放置目标及位置
    this.findDropTarget = function (x, y) {
        
        var control = this.findAt(x, y);

        if (control)
        {
            //
            
            return [this, control];
        }
        
        return [this, null];
    };
    
    
    
    //查找指定坐标的子控件
    this.findAt = function (x, y) {
      
        return this;
    };
    
  
    
    this.deserialize_children = function (reader, values) {
      
        if (typeof values === 'function')
        {
            var any = [];

            values(any); //values(values = []); 在IE7下会出错
            values = any;
        }

        this.push.apply(this, reader.readArray(values, this.childrenClass));
    };



    //接收数据集变更动作处理
    this.subscribeBind = function (dataset, action) {
        
        var item;
        
        this.base.subscribeBind.call(this, dataset, action);

        //向下派发
        for (var i = 0, l = this.length; i < l; i++)
        {
            if ((item = this[i]) && !item.__dataset)
            {
                item.subscribeBind(dataset, action);
            }
        }
        
        return this;
    };


});




/**
 * @class flyingon.Panel
 * @extends flyingon.Control
 * @description 面板容器类
 */
flyingon.Control.extend('Panel', function (base) {



    
    //重写默认宽度
    this.defaultWidth = 300;
    
    //重写默认高度
    this.defaultHeight = 150;

        

    //排列区域
    this.arrangeLeft = this.arrangeTop = 
    this.arrangeRight = this.arrangeBottom = 
    this.arrangeWidth = this.arrangeHeight = 0;



    //重写默认为可放置移动或拖动对象
    this.defaultValue('droppable', true);



    //当前布局
    this.defineProperty('layout', null, {
     
        group: 'locate',
        query: true,

        set: function (value) {

            this.__layout = null;
            this.__arrent_dirty < 2 && this.__arrange_delay();
        }
    });


    //作为html布局时是否需要适应容器
    this.defineProperty('adaption', false);
    
    

    //扩展容器功能
    flyingon.fragment('f-container', this, true);



    //测量自动大小
    this.onmeasure = function (auto) {
        
        var tag = (this.offsetHeight << 16) + this.offsetWidth;

        if (this.__size_tag !== tag)
        {
            this.__size_tag = tag;
            this.__arrange_dirty = 2;
        }

        if (auto)
        {
            this.renderer.locate(this);
            this.__update_dirty = false;

            if (auto & 1)
            {
                this.offsetWidth = this.arrangeRight + this.borderLeft + this.borderRight;
            }
            
            if (auto & 2)
            {
                this.offsetHeight = this.arrangeBottom + this.borderTop + this.borderBottom;
            }
        }
        else
        {
            return false;
        }
    };
    
        
    
    //查找指定坐标的子控件
    this.findAt = function (x, y) {
      
        if (this.length <= 0)
        {
            return this;
        }

        var layout = flyingon.getLayout(this),
            any;
    
        x += this.scrollLeft - this.borderLeft;
        y += this.scrollTop - this.borderTop;

        if (any = layout.__sublayouts)
        {
            return (any = layout.controlAt(any, x, y)) ? any.controlAt(x, y) : null;
        }

        return layout.controlAt(this, x, y);
    };    


 
    this.serialize = function (writer) {
        
        base.serialize.call(this, writer);
        
        if (this.length > 0)
        {
            writer.writeProperty('children', this, true);
        }
        
        return this;
    };
    

    this.dispose = function () {

        for (var i = this.length - 1; i >= 0; i--)
        {
            this[i].dispose(false);
        }

        base.dispose.apply(this, arguments);
        return this;
    };



}).register();




flyingon.Panel.extend('GroupBox', function (base) {



    this.defaultValue('border', 1);



    //页头高度
    this.defineProperty('header', 25, {

        set: function (value) {
            
            this.rendered && this.renderer.set(this, 'header', value);
            this.__update_dirty || this.invalidate();
        }
    });



    function define(self, name, defaultValue) {

        self.defineProperty(name, defaultValue, {

            set: function (value) {
                
                this.rendered && this.renderer.set(this, name, value);
            }
        });
    };

 
    //文字对齐
    define(this, 'align', 'left');


    //图标
    define(this, 'icon', '');


    //text
    define(this, 'text', '');


    //是否可收收拢
    //0: 不可折叠
    //1: 可折叠不显示折叠图标
    //2: 可折叠且显示折叠图标
    define(this, 'collapsable', 0);


    //是否折叠
    this.defineProperty('collapsed', false, {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'collapsed', value);

            if (!value && (value = this.mutex()))
            {
                this.__do_mutex(value);
            }

            this.__update_dirty || this.invalidate();
        }
    });


    //折叠互斥组(同一时刻只有一个分组框可以打开)
    this.defineProperty('mutex', '');


    this.__do_mutex = function (value) {

        var parent = this.parent,
            item;

        if (parent)
        {
            for (var i = 0, l = parent.length; i < l; i++)
            {
                if ((item = parent[i]) && item !== this && item.__do_mutex && item.mutex() === value)
                {
                    item.collapsed(true);
                }
            }
        }
    };


    //测量自动大小
    this.onmeasure = function (auto) {
        
        if (this.collapsed())
        {
            this.offsetHeight = this.header();
            return false;
        }
        
        if (auto)
        {
            base.onmeasure.call(this, auto);
            this.offsetHeight += this.header();
        }
        else
        {
            return false;
        }
    };

    
    this.arrangeArea = function () {

        var header = this.header();

        this.arrangeHeight -= header;
        this.arrangeBottom -= header;
    };



}).register();




flyingon.Panel.extend('ScrollPanel', function (base) {


    //预渲染
    //none: 不启用
    //x:    水平方向预渲染
    //y:    竖直方向预渲染
    //xy:   水平及竖直方向同时预渲染
    this.defineProperty('prerender', 'none');



    //可见区范围
    this.__visible_start = this.__visible_end = -1;

    //可见区是否有未渲染的子控件
    this.__visible_unmount = true;



    //计算可见控件集合
    this.__compute_visible = function () {

        var start = -1,
            end = -1,
            x = this.scrollLeft, 
            y = this.scrollTop,
            right = this.offsetWidth,
            bottom = this.offsetHeight,
            view = true,
            item,
            any;

        any = this.prerender();
        right += x + (any.indexOf('x') >= 0 ? right : 0);
        bottom += y + (any.indexOf('y') >= 0 ? bottom : 0);

        for (var i = 0, l = this.length; i < l; i++)
        {
            if ((item = this[i]) &&
                (item.__visible_area = (any = item.offsetLeft) < right && any + item.offsetWidth > x && 
                (any = item.offsetTop) < bottom && any + item.offsetHeight > y))
            {
                if (view && !item.view)
                {
                    view = false; //标记有未渲染的子控件
                }

                if (start < 0)
                {
                    start = i;
                }

                end = i;
            }
        }

        this.__visible_start = start;
        this.__visible_end = end;
        this.__visible_unmount = !view;
    };



    //处理滚动
    this.__do_scroll = function (x, y) {
    
        this.scrollLeft = x;
        this.scrollTop = y;
        
        this.__compute_visible();
        this.renderer.scroll(this, x, y);
    };



}).register();




flyingon.Control.extend('Splitter', function (base) {



    this.defaultWidth = this.defaultHeight = 4;


    //是否竖直方向
    this.vertical = false;




}).register();




flyingon.Panel.extend('Plugin', function (base) {



    this.loadPlugin = function (route) {

    };


    this.openPlugin = function (route) {

    };


    this.closePlugin = function () {

    };
    


    this.__class_init = function (Class) {

        var fn = flyingon.__load_plugin;

        base.__class_init.apply(this, arguments);

        if (fn && (Class !== flyingon.Plugin))
        {
            fn(Class);
        }
    };



}).register();




flyingon.plugin = function (superclass, fn) {

    if (!fn)
    {
        fn = superclass;
        superclass = flyingon.Plugin;
    }

    return superclass.extend(fn).init();
};




flyingon.Control.extend('ListBox', function (base) {



    this.defaultWidth = 200;

    this.defaultHeight = 100;


    this.defaultValue('border', 1);



    function define(self, name, defaultValue, clear) {

        return self.defineProperty(name, defaultValue, {

            set: function () {

                this.__template = null;
                this.__list && this.renderer.set(this, 'content');
            }
        });
    };



    //选中类型
    //none
    //radio
    //checkbox
    define(this, 'checked', 'none');


    //指定渲染列数
    //0     在同一行按平均宽度渲染
    //大于0 按指定的列数渲染
    define(this, 'columns', 1);


    //是否可清除
    define(this, 'clear', false);


    //子项模板
    define(this, 'template', null);


    //子项高度
    this['item-height'] = define(this, 'itemHeight', 21);



    //列表项集合
    this.defineProperty('items', null, {

        set: function (value) {

            //转换成flyingon.DataList
            flyingon.DataList.create(value, set_list, this);
        }
    });


    function set_list(list) {

        this.__list = list;
        this.rendered && this.renderer.set(this, 'content');
    };


    //默认选中值
    this.defineProperty('value', '', {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'change');
        }
    });

    
    //多值时的分隔符
    this.defineProperty('separator', ',');



}).register();




flyingon.Control.extend('RadioButton', function (base) {


    this.defineProperty('name', false, {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'name', value);
        }
    });


    this.value = this.defineProperty('checked', false, {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'checked', value);
        }
    });



}).register();




flyingon.Control.extend('CheckBox', function (base) {


    this.defineProperty('name', false, {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'name', value);
        }
    });


    this.value = this.defineProperty('checked', false, {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'checked', value);
        }
    });


}).register();




flyingon.fragment('f-textbox', function () {



    this.defineProperty('placeholder', '');



    this.selectionStart = function (value) {
        
        return this.renderer.selectionStart(value);
    };


    this.selectionEnd = function (value) {

        return this.renderer.selectionEnd(value);
    };


    this.select = function () {

        return this.renderer.select();
    };



});



flyingon.Control.extend('TextBox', function (base) {
    


    this.defineProperty('value', '', {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'text', value);
        }
    });


    this.text = function () {

        return (this.__storage || this.__defaults).value;
    };


    flyingon.fragment('f-textbox', this);
    

    this['max-length'] = this.defineProperty('maxLength', 0);



}).register();




flyingon.TextBox.extend('Number', function (base) {


    this.__scale = this.__value = 0;


    this.defineProperty('value', 0, {

        set: function (value) {

            this.__value = value;
            this.rendered && this.renderer.set(this, 'text', value);
        }
    });


    //小数位数
    this.defineProperty('scale', 0, {

        check: function (value) {

            return this.__scale = (value |= 0) > 0 ? value : 0;
        }
    });


    this.text = function () {

        return this.__value.toFixed(this.__scale);
    };



}).register();




flyingon.Control.extend('TextButton', function (base) {



    //弹出层控件
    var popup_cache;


    function define(self, name, defaultValue, key) {

        return self.defineProperty(name, defaultValue, {

            set: function (value) {
    
                this.rendered && this.renderer.set(this, key || name, value);
            }
        });
    };


    //值
    define(this, 'value', null, 'text');


    //格式化
    define(this, 'format', '', 'text');


    //是否可输入
    define(this, 'inputable', false);



    this.text = function () {

        var storage = this.__storage || this.__defaults,
            format = storage.format;

        return format ? format.replace(/\{\{value\}\}/g, value) : '' + storage.value;
    };



    //按钮图片
    define(this, 'button', '');


    //按钮大小
    this['button-size'] = define(this, 'buttonSize', 16);



    flyingon.fragment('f-textbox', this);



    this.__on_click = function () {

        this.trigger('button-click');
    };


    this.__get_popup = function () {

        var popup = popup_cache;

        if (popup)
        {
            popup.close('auto');
        }
        else
        {
            popup = popup_cache = new flyingon.Popup();

            popup.autoDispose = false;

            popup.on('closed', function () {

                this.detach(0);
            });

            popup.width('auto').height('auto');
        }

        return popup;
    };



}).register();




/**
 * 下拉框定义
 */
flyingon.fragment('f-ComboBox', function () {


    //选中类型
    //none
    //radio
    //checkbox
    this.defineProperty('checked', 'none');



    //指定渲染列数
    //0     在同一行按平均宽度渲染
    //大于0 按指定的列数渲染
    this.defineProperty('columns', 1);


    //是否生成清除项
    this.defineProperty('clear', false);


    //子项模板
    this.defineProperty('template', null);


    //子项高度
    this['item-height'] = this.defineProperty('itemHeight', 21);


    //下拉框宽度
    this['popup-width'] = this.defineProperty('popupWidth', 'default');


    //最大显示项数量
    this['max-items'] = this.defineProperty('maxItems', 10);



    //下拉列表
    this.defineProperty('items', null, {

        set: function (value) {

            //转换成flyingon.DataList
            flyingon.DataList.create(value, this.__set_items, this);
        }
    });


    //设置下拉列表
    this.__set_items = function (list) {

        this.__list = list;
        this.rendered && this.renderer.set(this, 'text');
    };


    //多值时的分隔符
    this.defineProperty('separator', ',');


});



flyingon.TextButton.extend('ComboBox', function (base) {


    
    //缓存的列表控件
    var listbox_cache; 



    this.defaultValue('button', 'f-combobox-button');



    //扩展下拉框定义
    flyingon.fragment('f-ComboBox', this);


    //默认选中值
    this.defineProperty('value', '', {

        set: function () {

            this.__list && this.renderer.set(this, 'text');
        }
    });



    this.text = function () {

        var list = this.__list;

        if (list)
        {
            var storage = this.__storage || this.__defaults;
            return list.text(storage.value, storage.checked === 'checkbox' ? storage.separator || ',' : '');
        }

        return '';
    };



    //弹出日历窗口
    this.popup = this.__on_click = function () {

        var popup = this.__get_popup(),
            storage = this.__storage || this.__defaults,
            listbox = this.__get_listbox(),
            length,
            height,
            any;

        this.__before_popup(popup, listbox, storage);

        listbox.border(0)
            .checked(listbox.__checked = storage.checked)
            .columns(any = storage.columns)
            .clear(storage.clear)
            .template(storage.template)
            .itemHeight(height = storage.itemHeight)
            .width(storage.popupWidth)
            .separator(storage.separator)
            .items(storage.items)
            .value(storage.value);

        if (any > 0)
        {
            length = this.__list ? this.__list.length : 0;

            if (storage.clear)
            {
                length++;
            }

            length = Math.min(length, storage.maxItems);

            if (any > 1)
            {
                length = (length + any - 1) / any | 0;
            }

            height *= length;
        }

        listbox.height(height + 2);

        listbox.target = this;
        listbox.popup = popup;

        popup.push(listbox);
        popup.show(this);
    };


    this.__before_popup = function (popup, listbox, storage) {
    };


    this.__get_listbox = function () {

        return listbox_cache = new flyingon.ListBox().on('change', function (e) {
            
            this.target.value(e.value);

            if (this.__checked !== 'checkbox')
            {
                this.popup.close();
            }
        });
    };



}).register();




//日历控件
flyingon.Control.extend('Calendar', function (base) {



    this.defaultWidth = this.defaultHeight = 240;


    this.defaultValue('border', 1);

    this.defaultValue('padding', 8);


    function define(self, name, defaultValue, type) {

        self.defineProperty(name, defaultValue, {

            dataType: type,

            set: function () {

                if (this.rendered && !this.__location_dirty)
                {
                    this.renderer.set(this, 'refresh');
                }
            }
        });
    };


    //日期值
    define(this, 'value', null, 'date');


    //最小可选值
    define(this, 'min', '');


    //最大可选值
    define(this, 'max', '');


    //是否编辑年月
    define(this, 'month', false);


    //是否显示时间
    define(this, 'time', false);


    //是否显示今天按钮
    define(this, 'today', false);


    //是否显示清除按钮
    define(this, 'clear', false);
    
    
    
}).register();




flyingon.fragment('f-Date', function () {


    this.defineProperty('format', 'yyyy/M/dd', {
        
        set: function () {

            this.rendered && this.renderer.set(this, 'text');
        }
    });


    //最小可选值
    this.defineProperty('min', '');


    //最大可选值
    this.defineProperty('max', '');


    //是否显示时间
    this.defineProperty('time', false);


    //是否显示今天按钮
    this.defineProperty('today', false);


    //是否显示清除按钮
    this.defineProperty('clear', false);


});




flyingon.TextButton.extend('Date', function (base) {


    //日历控件
    var calendar_cache;


    this.defaultValue('button', 'f-date-button');


    //日期值
    this.defineProperty('value', null, {
        
        dataType: 'date',

        set: function () {

            this.rendered && this.renderer.set(this, 'text');
        }
    });



    flyingon.fragment('f-Date', this);



    this.text = function () {

        var storage = this.__storage || this.__defaults,
            value = storage.value;

        return value ? value.format(storage.format) : '';
    };


    //弹出日历窗口
    this.popup = this.__on_click = function () {

        var popup = this.__get_popup(),
            storage = this.__storage || this.__defaults,
            calendar = calendar_cache;

        if (!calendar)
        {
            calendar = calendar_cache = new flyingon.Calendar();
            calendar.border(0).on('selected', function (e) {
                
                this.target.value(e.value);
                this.popup.close();
            });
        }

        calendar.value(storage.value)
            .min(storage.min)
            .max(storage.max)
            .time(storage.time)
            .today(storage.today)
            .clear(storage.clear);

        calendar.oncheck = this.oncheck;
        calendar.target = this;
        calendar.popup = popup;

        popup.push(calendar);
        popup.show(this);
    };



}).register();




flyingon.TextBox.extend('Time', function (base) {


    //值
    this.defineProperty('value', '', {
        
        check: function (value) {

            if (value && (value = value.match(/\d+/g)))
            {
                value.length = 3;

                value[1] |= 0;
                value[2] |= 0;

                return value.join(':');
            }

            return '';
        },

        set: function () {

            this.rendered && this.renderer.set(this, 'text');
        }

    });


    //格式化
    this.defineProperty('format', '', {
        
        set: function () {

            this.rendered && this.renderer.set(this, 'text');
        }
    });


    this.text = function () {

        var storage = this.__storage || this.__defaults,
            value = storage.value,
            format;

        if (value && (format = storage.format))
        {
            value = value.split(':');
            return new Date(2000, 1, 1, value[0] | 0, value[1] | 0, value[2] | 0).format(format);
        }

        return value;
    };



}).register();




flyingon.TextButton.extend('Month', function (base) {



    //日历控件
    var calendar_cache;


    this.defaultValue('button', 'f-date-button');



    //日期值
    this.defineProperty('value', null, {
        
        dataType: 'date',

        set: function () {

            this.rendered && this.renderer.set(this, 'text');
        }
    });


    this.defineProperty('format', 'yyyy-MM', {
        
        set: function () {

            this.rendered && this.renderer.set(this, 'text');
        }
    });


    //最小可选值
    this.defineProperty('min', '');


    //最大可选值
    this.defineProperty('max', '');



    this.text = function () {

        var storage = this.__storage || this.__defaults,
            value = storage.value;

        return value ? value.format(storage.format) : ''
    };


    //弹出日历窗口
    this.popup = this.__on_click = function () {

        var popup = this.__get_popup(),
            storage = this.__storage || this.__defaults,
            calendar = calendar_cache;

        if (!calendar)
        {
            calendar = calendar_cache = new flyingon.Calendar();
            calendar.border(0).month(true).on('selected', function (e) {
                
                this.target.value(e.value);
                this.popup.close();
            });
        }

        calendar.value(storage.value).min(storage.min).max(storage.max);

        calendar.oncheck = this.oncheck;
        calendar.target = this;
        calendar.popup = popup;

        popup.push(calendar);
        popup.show(this);
    };



}).register();




Object.extend('TreeNode', function () {



    //扩展可视组件功能
    flyingon.fragment('f-visual', this);



    //标记是树节点
    this.isTreeNode = true;


    //是否展开
    this.expanded = false;


    //选中的子项数量
    this.checkedChildren = 0;
    


    function define(self, name, defaltValue) {

        return self.defineProperty(name, defaltValue, {

            set: function (value) {

                this.rendered && this.renderer.set(this, name, value);
            }
        });
    };


    //节点图标
    define(this, 'icon', '');


    //节点文本
    define(this, 'text', '');


    //是否禁用
    define(this, 'disabled', false);


    //是否选中
    this.defineProperty('checked', false, {
        
        set: function (value) {

            var parent = this.parent;

            while (parent && parent.isTreeNode)
            {
                if (!(value ? parent.checkedChildren++ : --parent.checkedChildren) && 
                    parent.view && !parent.checked())
                {
                    parent.renderer.set(parent, 'checked', false);
                }

                parent = parent.parent;
            }

            this.rendered && this.renderer.set(this, 'checked', value);
            this.trigger('checked-change', 'value', value);
        }
    });



    //是否启用延时加载
    this.defineProperty('delay', false);



    //扩展容器功能
    flyingon.fragment('f-container', this, flyingon.TreeNode);


    //创建子控件
    this.__create_child = function (options, Class) {

        var node = new Class(),
            storage = node.__storage || (node.__storage = flyingon.create(node.__defaults));

        for (var name in options)
        {
            switch (name)
            {
                case 'text':
                case 'icon':
                    storage[name] = '' + options[name];
                    break;

                case 'checked':
                    storage[name] = !!options[name];
                    break;

                case 'expanded':
                    if (options[name])
                    {
                        node.expanded = true;
                    }
                    break;

                case 'children':
                case 'items':
                    node.push.apply(node, options[name]);
                    break;

                default:
                    storage[name] = options[name];
                    break;
            }
        }

        return node;
    };


    //获取节点级别
    this.level = function () {

        var target = this.parent,
            index = 0;

        while (target && target.isTreeNode)
        {
            index++;
            target = target.parent;
        }

        return index;
    };



}).register();




flyingon.Control.extend('Tree', function (base) {



    this.defaultWidth = 200;
    
    this.defaultHeight = 300;

        
    this.defaultValue('border', 1);
    

    this.defaultValue('padding', 2);



    function define(self, name, defaltValue) {

        return self.defineProperty(name, defaltValue, {

            set: function (value) {

                this.rendered && this.renderer.set(this, name, value);
            }
        });
    };


    //树风格
    //default   默认风格
    //blue      蓝色风格
    //plus      加减风格
    //line      线条风格
    define(this, 'theme', 'default');



    //是否显示检查框
    define(this, 'checked', false);


    //是否显示图标
    define(this, 'icon', true);


    //是否可编辑
    this.defineProperty('editable', false);


    //格式化函数
    this.format = null;



    //扩展容器功能
    flyingon.fragment('f-container', this, flyingon.TreeNode.init());


    this.__create_child = flyingon.TreeNode.prototype.__create_child;



    //展开节点
    this.expand = function (node) {

        if (node)
        {
            this.__expand_node(node);
        }
        else
        {
            for (var i = 0, l = this.length; i < l; i++)
            {
                this.__expand_node(this[i]);
            }
        }

        return this;
    };


    this.__expand_node = function (node) {

        if (!node.expanded && this.trigger('expand', 'node', node) !== false)
        {
            node.expanded = true;
            node.rendered && node.renderer.set(node, 'expand');
        }
    };


    //展开节点至指定级别
    this.expandTo = function (node, level) {

        if (arguments.length < 2)
        {
            level = node;
            node = null;
        }

        this.__expand_to(node || this, level | 0);
        return this;
    };


    this.__expand_to = function (nodes, level) {

        level--;

        for (var i = nodes.length - 1; i >= 0; i--)
        {
            var node = nodes[i];

            if (!node.expanded)
            {
                if (this.trigger('expand', 'node', node) === false)
                {
                    continue;
                }

                node.expanded = true;
                node.rendered && node.renderer.set(node, 'expand');
            }

            if (node.length > 0)
            {
                if (level)
                {
                    this.__expand_to(node, level);
                }
                else
                {
                    //收拢最后一级
                    for (var j = node.length - 1; j >= 0; j--)
                    {
                        var item = node[j];

                        if (item.expanded && this.trigger('collapse', 'node', node) !== false)
                        {
                            item.expanded = false;
                            item.rendered && item.renderer.set(item, 'collapse');
                        }
                    }
                }
            }
        }
    };


    //收拢节点
    this.collapse = function (node) {

        if (node)
        {
            this.__collapse_node(node);
        }
        else
        {
            for (var i = 0, l = this.length; i < l; i++)
            {
                this.__collapse_node(this[i]);
            }
        }

        return this;
    };


    //收拢节点
    this.__collapse_node = function (node) {

        if (node.expanded && node.length > 0 && this.trigger('collapse', 'node', node) !== false)
        {
            node.expanded = false;
            node.rendered && node.renderer.set(node, 'collapse');
        }
    };



    this.beginEdit = function () {

    };


    this.endEdit = function () {

    };


    this.findNode = function (fn) {

        if (typeof fn === 'function')
        {
            return find(this, fn);
        }
    };


    function find(nodes, fn) {

        for (var i = 0, l = nodes.length; i < l; i++)
        {
            var node = nodes[i];

            if (fn(node))
            {
                return node;
            }

            if (node.length > 0 && (node = find(node, fn)))
            {
                return node;
            }
        }
    };


    this.current = function (node) {

        var any = this.__current;
        
        if (any)
        {
            any.__current = false;
        }

        if (this.__current = node)
        {
            node.__current = true;
        }

        if (this.rendered)
        {
            any && any.renderer.current(any, false);
            node && node.renderer.current(node, true);
        }
    };


    this.scrollTo = function (node) {

        this.rendered && this.renderer.scrollTo(this, node);
    };


    this.dispose = function () {

        for (var i = this.length - 1; i >= 0; i--)
        {
            this[i].dispose(false);
        }

        base.dispose.apply(this, arguments);
        return this;
    };



}).register();




(flyingon.GridColumn = Object.extend(function () {



    var Class = flyingon.Label;

    var create = flyingon.create;



    this.init = function (options) {

        //列头控件集合
        this.__cells = [];

        if (options)
        {
            var properties = this.__properties;

            for (var name in options)
            {
                if (properties[name])
                {
                    this[name](options[name]);
                }
            }
        }
    };



    //列类型
    this.type = '';


    //绑定的字段名
    this.defineProperty('name', '', { 
        
        set: function (value) {

            var grid = this.grid;

            this.__name = value;
               
            if (grid && grid.rendered)
            {
                grid.__columns.__keys = null;
                grid.update();
            }
        }
    });


    //标题 值为数组则为多行标题
    this.defineProperty('title', null, { 
        
        set: function (value) {

            var any;

            if (this.view)
            {
                this.view = false;

                //销毁原单元格
                if (any = this.__cells)
                {
                    for (var i = any.length - 1; i >= 0; i--)
                    {
                        any[i].view = null;
                        any[i].dispose();
                    }

                    any = any.__span;
                }

                this.__set_title(value);

                if (this.grid)
                {
                    //原来有跨列可现在有跨列则需重计算列
                    this.grid.update(any || this.__cells.__span > 0);
                }
            }
            else
            {
                this.__set_title(value);
            }
        }
    });


    //列大小(支持固定数字及百分比)
    this.defineProperty('size', '100', {

        set: function (value) {

            var grid;
            
            if (this.view && (grid = this.grid))
            {
                grid.update(true);
            }
        }
    });


    this.fullClassName = this.defaultClass = '';

    //自定义class
    this.defineProperty('className', '', {

        set: function (value) {

            if (value && this.defaultClass)
            {
                value += ' ' + this.defaultClass;
            }

            this.fullClassName = value ? ' ' + value : '';
        }
    });


    //对齐方式
    //left
    //center
    //right
    this.defineProperty('align', '', {

        set: function (value) {

            this.__align = value;
        }
    });


    //是否只读
    this.defineProperty('readonly', false, {

        set: function (value) {

            this.__readonly = value;
            this.view && this.renderer.set(this, name, value);
        }   
    });


    this.__visible = true;

    //是否显示
    this.defineProperty('visible', true, {

        set: function (value) {

            var grid = this.grid;

            this.__visible = value;

            if (grid && grid.rendered)
            {
                grid.update(true);
            }
        }
    });


    //是否可调整列宽
    this.defineProperty('resizable', true);


    //是否可点击列头排序
    this.defineProperty('sortable', true);


    //是否可拖动调整顺序
    this.defineProperty('draggable', true);


    //过滤方式
    this.defineProperty('filter', 'auto');


    //汇总设置
    //MAX:      最大值
    //MIN:      最小值
    //AVG:      平均值
    //SUM:      求和
    this.defineProperty('summary', '', { 
        
        set: function update() {

            var grid = this.grid;

            if (grid && grid.rendered)
            {
                grid.__summary_list = this.__summary_fn = null;
                grid.update();
            }
        }
    });


    //汇总数字精度
    this.defineProperty('precision', 0);



    this.__set_title = function (title) {

        var cells = this.__cells;

        cells.length = 0;
        this.__span = false;

        if (title instanceof Array)
        {
            for (var i = 0, l = title.length; i < l; i++)
            {
                this.__create_header(Class, cells, title[i]);
            }
        }
        else
        {
            this.__create_header(Class, cells, title);
        }

        return cells;
    };


    this.__create_header = function (Class, cells, title) {

        var control, size, span;

        if (title && typeof title === 'object')
        {
            size = title.size | 0;
            span = title.span | 0;

            if (control = title.control)
            {
                control = flyingon.ui(control);
            }
            else
            {
                title = title.text;
            }
        }
        
        if (!control)
        {
            control = new Class();

            if (title)
            {
                (control.__storage = create(control.__defaults)).text = '' + title;
            }
        }

        if (size > 0)
        {
            control.__height = size;
        }

        if (span > 0)
        {
            control.__span = span;
            this.__span = true;
        }

        cells.push(control);
    };


    this.index = function () {

        var columns = this.grid.__columns;

        if (columns.__show_tag !== this.__show_tag)
        {
            return columns.indexOf(this);
        }

        return this.__index;
    };


    this.__find_text = function () {

        var title = this.title(),
            any;

        if (title && typeof title === 'object')
        {
            if (title instanceof Array)
            {
                if ((any = title[0]) && any.__span)
                {
                    return any && any.text || any;
                }

                any = title[title.length - 1];
                return any && any.text || any;
            }
            
            return title.text;
        }

        return title;
    };


    this.__span_size = function (count) {

        var columns = this.grid.__columns,
            index = this.__index,
            size = 0,
            column;

        while (count > 0 && (column = columns[index + count]))
        {
            size += column.__size;
            count--;
        }

        return size;
    };


    //创建单元格控件
    this.createControl = function (row, name) {

       var control = new Class();
        
        if (name)
        {
            (control.__storage = create(control.__defaults)).text = row.data[name];
        }

        return control;
    };



    //绑定表格列渲染器
    flyingon.renderer.bind(this, 'GridColumn');



    //列初始化处理
    this.__class_init = function (Class, base) {
     
        var any;

        if (any = this.defaultClass)
        {
            this.fullClassName = ' ' + any;
        }
    };



})).register = function (name, force) {
    
    if (name)
    {
        var all = flyingon.GridColumn.all || (flyingon.GridColumn.all = flyingon.create(null));

        if (!force && all[name])
        {
            throw 'column "' + name + '" has exist';
        }

        all[this.type = name] = this;
    }

    return this;
};



//行号列
flyingon.GridColumn.extend(function (base) {


    this.defaultClass = 'f-grid-column-no';


    this.__name = '__column_no';


    this.defaultValue('size', 25);


    this.defaultValue('draggable', false);


    this.defaultValue('resizable', false);


    //是否显示行号
    this.defineProperty('no', false, {

        set: function (value) {
            
            this.__show_no = value;
        }
    });


    this.onshowing = function (cell, row) {

        if (this.__show_no)
        {
            cell.text(row.__show_index + 1);
        }
    };


}).register('no');



//选择列
flyingon.GridColumn.extend(function (base) {


    var Class = flyingon.CheckBox;


    this.defaultClass = 'f-grid-column-check';


    this.__name = '__column_check';
    

    this.defaultValue('size', 30);


    this.defaultValue('draggable', false);


    this.defaultValue('resizable', false);


    //创建单元格控件
    this.createControl = function (row) {

       var control = new Class();
        
        control.__column_check = true;

        if (row.__checked)
        {
            control.checked(true);
        }

        return control;
    };


}).register('check');



//检查框列
flyingon.GridColumn.extend(function (base) {


    var Class = flyingon.CheckBox;


    //创建单元格控件
    this.createControl = function (row, name) {

       var control = new Class();
        
        if (name && row.data[name])
        {
            control.checked(true);
        }

        return control;
    };


}).register('checkbox');



//文本框列
flyingon.GridColumn.extend(function (base) {


    var Class = flyingon.TextBox;


    //创建单元格控件
    this.createControl = function (row, name) {

       var control = new Class();
        
        if (name)
        {
            control.value(row.data[name]);
        }

        return control;
    };


}).register('textbox');



//文本按钮列
flyingon.GridColumn.extend(function (base) {


    var Class = flyingon.TextButton;


    //创建单元格控件
    this.createControl = function (row, name) {

       var control = new Class();
        
        if (name)
        {
            control.value(row.data[name]);
        }

        return control;
    };


}).register('textbutton');



//数字列
flyingon.GridColumn.extend(function (base) {


    var Class = flyingon.Number;


    //创建单元格控件
    this.createControl = function (row, name) {

       var control = new Class();
        
        if (name)
        {
            control.value(row.data[name]);
        }

        return control;
    };


}).register('number');



//下拉框列
flyingon.GridColumn.extend(function (base) {


    var Class = flyingon.ComboBox;

    var keys = 'inputable,checked,columns,clear,template,itemHeight,separator,popupWidth,maxItems'.split(',').pair();


    //是否可输入
    this.defineProperty('inputable', false);


    //扩展下拉框定义
    flyingon.fragment('f-ComboBox', this);


    this.__set_items = function (list) {

        var controls = this.__wait;

        this.__list = list;

        if (controls)
        {
            this.__wait = null;

            for (var i = controls.length - 1; i >= 0; i--)
            {
                controls[i].items(list);
            }
        }
    };


    //创建单元格控件
    this.createControl = function (row, name) {

        var control = new Class(),
            names,
            any;

        if (any = this.__list)
        {
            control.items(any);
        }
        else
        {
            (this.__wait || (this.__wait = [])).push(control);
        }
        
        if (any = this.__storage)
        {
            names = keys;

            for (var key in any)
            {
                if (names[key])
                {
                    control[key](any[key]);
                }
            }
        }
        
        if (name)
        {
            control.value(row.data[name]);
        }

        return control;
    };



}).register('combobox');



//日期列
flyingon.GridColumn.extend(function (base) {


    var Class = flyingon.Date;

    var keys = 'format,min,max,time,today,clear'.split(',').pair();


    flyingon.fragment('f-Date', this);
    

    //创建单元格控件
    this.createControl = function (row, name) {

        var control = new Class(),
            names,
            any;
                
        if (any = this.__storage)
        {
            names = keys;

            for (var key in any)
            {
                if (names[key])
                {
                    control[key](any[key]);
                }
            }
        }

        if (name)
        {
            control.value(row.data[name]);
        }

        return control;
    };


}).register('date');



//时间列
flyingon.GridColumn.extend(function (base) {


    var Class = flyingon.Time;


    //创建单元格控件
    this.createControl = function (row, name) {

       var control = new Class();
        
        if (name)
        {
            control.value(row.data[name]);
        }

        return control;
    };


}).register('time');



//表格列集合
flyingon.GridColumns = Object.extend(function () {


    this.init = function (grid) {

        this.grid = grid;
        this.__locked = [0, 0, 0, 0];
    };

    

    flyingon.fragment('f-collection', this);


    
    this.__check_items = function (index, items, start) {

        var Class = flyingon.GridColumn,
            columns = Class.all,
            grid = this.grid,
            end = items.length,
            any;

        this.__keys = null;

        while (start < end)
        {
            any = items[start];

            if (any instanceof Class)
            {
                if (any.grid)
                {
                    any.remove();
                }
            }
            else
            {
                items[start] = any = new (any && columns[any.type] || Class)(any);
            }

            any.grid = grid;
            start++;
        }

        grid.rendered && grid.update(true);
    };


    this.__remove_items = function (index, items) {

        var grid = this.grid,
            item;

        this.__keys = null;

        for (var i = 0, l = items.length; i < l; i++)
        {
            item = items[i];
            item.grid = null;

            if (item.view)
            {
                item.renderer.unmount(item);
            }
        }

        grid.rendered && grid.update(true);
    };



    //计算可见列索引范围
    this.__compute_visible = function (x, scroll) {

        var locked = this.__locked,
            start = locked[0],
            end = this.length,
            column,
            left,
            any;

        if (end <= 0)
        {
            return;
        }

        this.__arrange_start = x;

        x += locked[2];
        end -= locked[1];

        //计算开始位置
        for (var i = start; i < end; i++)
        {
            if ((column = this[i]) && column.__visible && column.__start + column.__size >= x)
            {
                start = i;
                break;
            }
        }

        //计算结束位置
        any = x + this.__arrange_size - locked[2] - locked[3];

        for (var i = start; i < end; i++)
        {
            if ((column = this[i]) && column.__visible && column.__start > any)
            {
                end = i + 1;
                break;
            }
        }

        //记录可见范围
        this.__visible_start = start;
        this.__visible_end = end;

        //滚动时如果未超出上次渲染范围则返回true
        if (scroll && this.__show_start <= start && this.__show_end >= end)
        {
            return true;
        }

        //多渲染部分列以减少滚动处理
        any = end + 2;
        end = this.length - locked[1];
        end = any > end ? end : any;

        //处理跨列偏移
        start -= this[start].__offset; 

        if (any = this.grid.oncolumnstart)
        {
            any = any.call(this.grid, this, start);

            if (any >= 0)
            {
                start = any;
            }
        }

        this.__show_start = start;
        this.__show_end = end;
    };


    //计算列宽
    this.__compute_size = function (width) {

        var locked = this.__locked,
            group = this.grid.__group_size, //分组偏移大小
            size = group,
            mod = 0,
            start = locked[0],
            end = this.length,
            any;

        this.__arrange_size = width;
        this.__persent = false;

        //计算前锁定
        if (start > 0)
        {
            mod = compute_size(this, width, group, 0, start, mod);

            group = 0;
            size += (locked[2] = this.__size);
        }

        //计算后锁定
        if ((any = locked[1]) > 0)
        {
            mod = compute_size(this, width, 0, end - any, end, mod);
            end -= any;

            size += (locked[3] = this.__size);
        }

        //计算滚动区
        compute_size(this, width, group + locked[2], start, end, mod);

        this.__size += size;
    };


    //计算列大小
    function compute_size(columns, total, left, start, end, mod) {

        var width = 0,
            span = -1,
            persent,
            column,
            size,
            any;

        while (start < end)
        {
            column = columns[start];

            column.__index = start++;
            column.__offset = 0; //前置偏移

            if (!column.__visible)
            {
                continue;
            }

            size = (column.__storage || column.__defaults).size;
            
            if (size >= 0)
            {
                size |= 0;
            }
            else if ((size = parseFloat(size)) > 0)
            {
                persent = true;

                any = size * total / 100;
                size = any | 0;

                if ((any -= size) > 0 && (mod += any) >= 1)
                {
                    mod--;
                    size++;
                }
            }

            column.__start = left;
            column.__size = size;

            left += size;
            width += size;

            //检测是否需要跨列处理
            if (span < 0 && column.__span)
            {
                span = start - 1;
            }
        }

        //记录宽度和
        columns.__size = width;

        //处理跨列
        if (span >= 0)
        {
            start = span;

            while (start < end)
            {
                column = columns[start];

                if (column.__span)
                {
                    compute_span(columns, start, end, column.__cells);
                }

                start++;
            }
        }

        if (persent)
        {
            columns.__persent = true;
        }

        return mod;
    };


    //计算跨列
    function compute_span(columns, index, end, cells) {

        for (var i = cells.length - 1; i >= 0; i--)
        {
            var cell = cells[i],
                span = cell.__span,
                count = span, //实际跨列数
                column,
                size;

            if (span > 0)
            {
                size = columns[index].__size;

                while (span > 0) //计算到结束位置则提前终止
                {
                    if (index + span < end && (column = columns[index + span]))
                    {
                        if (column.__offset < span)
                        {
                            column.__offset = span;
                        }

                        if (column.__visible)
                        {
                            size += column.__size;
                        }
                    }
                    else
                    {
                        count--;
                    }

                    span--;
                }

                cell.__size = size;
            }

            //实际跨列数
            cell.columnSpan = count;
        }
    };


    //缓存列名
    function cache_name(columns) {

        var keys = columns.__keys = flyingon.create(null),
            index = 0,
            column,
            any;

        while (column = columns[index++])
        {
            if ((any = column.__storage) && (any = any.name))
            {
                keys[any] = column;
            }
        }

        return keys;
    };


    //查找指定名称的表格列
    this.find = function (name) {

        return (this.__keys || cache_name(this))[name];
    };


    //同步因分组隐藏的列
    this.__sync_visible = function () {

        for (var i = this.length - 1; i >= 0; i--)
        {
            var column = this[i],
                storage;

            if (!column.__visible && (!(storage = column.__storage) || storage.visible))
            {
                column.__visible = true;
            }
        }
    };


    this.dispose = function () {

        for (var i = this.length - 1; i >= 0; i--)
        {
            var item = this[i];

            item.grid = null;

            if (item.view)
            {
                item.renderer.unmount(item);
            }
        }

        this.grid = null;
    };


});



//表格行
flyingon.GridRow = Object.extend._(function () {

    
    //行id
    this.id = 0;

    //上级行
    this.parent = null;

    //行数据
    this.data = null;
    
    //是否展开
    this.expanded = false;



    //获取行级别
    this.level = function () {

        var parent = this.parent,
            level = 0;

        while (parent)
        {
            level++;
            parent = parent.parent;
        }

        return level;
    };


    //获取或设置当前行是否勾选
    this.checked = function (checked) {

        if (checked === void 0)
        {
            return this.__checked || false;
        }

        if (this.__checked !== (checked = !!checked))
        {
            var rows = this.grid.__checked_rows;

            if (checked)
            {
                rows.push(this);
            }
            else
            {
                rows.splice(rows.indexOf(this), 1);
            }

            this.view && this.renderer.set(this, 'checked', this.__checked = checked);
        }
    };


    //销毁
    this.dispose = function () {

        var length = this.length;

        if (length > 0)
        {
            for (var i = length - 1; i >= 0; i--)
            {
                this[i].dispose();
            }
        }

        this.grid = null;
        this.view && this.renderer.unmount(this);
    };



    flyingon.renderer.bind(this, 'GridRow');

    
});



//分组行
flyingon.GroupGridRow = Object.extend._(function (base) {



    //分组行标记
    this.__group_row = true;


    //上级行
    this.parent = null;

    //行数据
    this.data = null;


    //分组列名
    this.name = '';

    //行级别
    this.level = 0;


    //是否展开
    this.expanded = false;


    //总子项数(含子项的子项)
    this.total = 0;



    //计算汇总信息
    this.compute = function (column, name, fn, summary) {

        var data = this.data,
            any;

        if (data && name in data)
        {
            any = data[name];
        }
        else if ((any = this.length) > 0)
        {
            //如果子行是分组行,先计算子分组
            if (this.__sub_group)
            {
                for (var i = 0; i < any; i++)
                {
                    this[i].compute(column, name, fn);
                }
            }

            (data || (this.data = {}))[name] = any = fn(this, name);
        }
        else
        {
            any = 0;
        }
        
        return summary ? summary(this, name, any) : any;
    };



    //销毁
    this.dispose = function () {

        var length = this.length;

        if (length > 0)
        {
            for (var i = length - 1; i >= 0; i--)
            {
                this[i].dispose();
            }
        }

        this.grid = null;
        this.view && this.renderer.unmount(this);
    };


    flyingon.renderer.bind(this, 'GroupGridRow');


});



//表格视图
flyingon.GridView = flyingon.defineClass(Array, function () {



    var create = Object.create;



    this.init = function (grid) {

        this.grid = grid;
        this.view = []; //显示视图集
        this.keys = flyingon.create(null);
    };



    //从dataset加载数据行
    this.dataset = function (dataset) {

        var grid = this.grid,
            any;

        if (this.length > 0)
        {
            this.dispose(false);
        }

        init_rows(flyingon.GridRow, this.keys, grid, this, null, dataset);

        if (this.__group_view = !!(any = grid.__groups))
        {
            group_view(this, any);
        }

        this.__dirty = true;
    };


    //根据数据集初始化表格行
    function init_rows(Class, keys, grid, view, parent, rows) {

        var row, any;

        for (var i = 0, l = view.length = rows.length; i < l; i++)
        {            
            any = rows[i];

            row = view[i] = new Class();
            row.grid = grid;
            row.parent = parent;
            row.data = any.data;

            keys[row.id = any.uniqueId] = row;

            if (any.length > 0)
            {
                init_rows(Class, keys, grid, row, row, any);
            }
        }
    };


    //切换分组
    this.__change_group = function (groups) {

        //如果当前是分组视图,需先销毁原分组行
        if (this.__group_view)
        {
            ungroup_view(this);
        }

        //如果当前有排序则重新排序
        if (this.__sort)
        {
            this.sort.apply(this, this.__sort);
        }

        //标记是否分组视图
        if (this.__group_view = !!groups)
        {
            group_view(this, groups);
        }
        
        this.__dirty = true;
    };


    //分组视图
    function group_view(self, groups) {

        var rows = self.splice(0);

        if (rows.length > 0)
        {
            rows = group_rows(flyingon.GroupGridRow, self.grid, null, rows, groups, 0, 0);
            rows.push.apply(self, rows);
        }
    };


    function group_rows(Class, grid, parent, rows, groups, index, level) {

        var view = [],
            name = groups[index++],
            keys = group_data(rows, name),
            next = !!groups[index],
            row,
            text;

        for (var i = 0, l = keys.length; i < l; i++)
        {
            if (rows = keys[text = keys[i]])
            {
                row = new Class();

                row.grid = grid;
                row.parent = parent;
                row.name = name,
                row.text = text;

                row.level = level;
                row.total = rows.length;
                
                //标记子行是否是分组行
                if (row.__sub_group = next)
                {
                    rows = group_rows(Class, grid, row, rows, groups, index, level + 1);
                }

                view.push.apply(row, rows);
                view.push(row);
            }
        }

        return view;
    };


    function group_data(rows, name) {

        var keys = [],
            row,
            data,
            key,
            any;

        for (var i = 0, l = rows.length; i < l; i++)
        {
            if ((row = rows[i]) && (data = row.data) && (key = data[name]) != null)
            {
                if (any = keys[key])
                {
                    any.push(row);
                }
                else
                {
                    keys.push(key);
                    keys[key] = [row];
                }
            }
        }

        if (keys.length > 0)
        {
            keys.sort();
        }

        return keys;
    };


    //解除分组
    function ungroup_view(self) {

        var rows = self.splice(0),
            any;

        //显示分组列
        self.grid.__columns.__sync_visible();

        if (rows.length > 0)
        {
            ungroup_rows(rows, any = []);
            any.push.apply(self, any);
        }
    };


    function ungroup_rows(rows, exports) {

        var splice = exports.splice,
            row, 
            any;

        for (var i = 0, l = rows.length; i < l; i++)
        {
            if (row = rows[i])
            {
                row.renderer.unmount(row);

                if (row.__sub_group)
                {
                    ungroup_rows(row, exports);
                }
                else if ((any = splice.call(row, 0)).length > 0)
                {
                    for (var j = any.length - 1; i >= 0; i--)
                    {
                        any[j].parent = null;
                    }

                    exports.push.apply(exports, any);
                }
            }
        }
    };



    //同步展开视图
    this.__sync_view = function () {

        var view = this.view;

        this.__dirty = false;

        view.length = 0;

        if (this.__group_view)
        {
            sync_view(view, this);
        }
        else
        {
            view.push.apply(view, view.slice.call(this, 0));
        }

        return view;
    };


    function sync_view(view, rows) {

        for (var i = 0, l = rows.length; i < l; i++)
        {
            var row = rows[i];

            view.push(row);

            if (row.expanded && row.length > 0)
            {
                sync_view(view, row);
            }
        }
    };



    //展开指定行(仅供界面操作用)
    this.__expand_row = function (row) {

        if (row && !row.expanded && this.grid.trigger('expand', 'row', row) !== false)
        {
            row.expanded = true;

            if (row.length > 0)
            {
                var view = this.view,
                    rows = [row.__show_index + 1, 0];

                expand_rows(row, rows);
                rows.splice.apply(view, rows);

                this.grid.update();
            }
            else
            {
                return false; //告知展开后无子节点
            }
        }
    };


    //收拢指定行(仅供界面操作用)
    this.__collapse_row = function (row) {

        if (row && row.expanded && row.length > 0 && this.grid.trigger('collapse') !== false)
        {
            row.expanded = false;

            this.view.splice(row.__show_index + 1, expand_count(row));
            this.grid.update();
        }
    };


    //获取展开表格行集合
    function expand_rows(rows, exports) {

        var row;

        for (var i = 0, l = rows.length; i < l; i++)
        {
            if (row = rows[i])
            {
                exports.push(row);

                if (row.expanded && row.length > 0)
                {
                    expand_rows(row, exports);
                }
            }
        }
    };


    //获取展开表格行数量
    function expand_count(rows) {

        var length = rows.length,
            count = length,
            row;

        for (var i = 0; i < length; i++)
        {
            if ((row = rows[i]) && row.expanded)
            {
                count += expand_count(row);
            }
        }

        return count;
    };


    //根据id查找指定行
    this.find = function (id) {

        return this.keys[id] || null;
    };


    //排序
    this.sort = function (name, desc, tree) {

        if (this.length > 0)
        {
            var sort = this.view.sort,
                fn;

            if (desc)
            {
                fn = function (a, b) {

                    return a.data[name] > b.data[name] ? -1 : 1;
                };
            }
            else
            {
                fn = function (a, b) {

                    return a.data[name] > b.data[name] ? 1 : -1;
                };
            }
        
            if (this.__group_view)
            {
                sort_group(this, fn, sort, tree);
            }
            else if (tree)
            {
                sort_tree(this, fn, sort);
            }
            else
            {
                sort.call(this, fn);
            }

            this.__sort = [name, desc, tree];
            this.__dirty = true;
        }
    };


    function sort_group(rows, fn, sort, tree) {

        for (var i = rows.length - 1; i >= 0; i--)
        {
            var row = rows[i];

            if (row.__sub_group)
            {
                sort_group(row, fn, sort, tree);
            }
            else if (tree)
            {
                sort_tree(row, fn, sort);
            }
            else
            {
                sort.call(row, fn);
            }
        }
    };


    function sort_tree(rows, fn, sort) {

        sort.call(rows, fn);

        for (var i = rows.length - 1; i >= 0; i--)
        {
            var row = rows[i];

            if (row[0])
            {
                sort_tree(row, fn, sort);
            }
        }
    };


    //通过数据源增加表格行
    this.__add = function (index, rows, parent) {

        if (parent)
        {
            parent = this.keys[parent.uniqueId] || null;
        }

        rows = create_rows(flyingon.GridRow, this.keys, this.grid, parent, rows);

        if (parent || !this.__group_view)
        {
            rows.unshift(index, 0);
            rows.splice.apply(parent || this, rows);
        }
        else
        {

        }

        this.__dirty = true;
        this.grid.update(false);
    };


    function create_rows(Class, keys, grid, parent, items) {

        var rows = [],
            row, 
            any;

        for (var i = 0, l = items.length; i < l; i++)
        {            
            any = items[i];

            row = new Class();
            row.grid = grid;
            row.parent = parent;
            row.data = any.data;

            keys[row.id = any.uniqueId] = row;

            if (any.length > 0)
            {
                init_rows(Class, keys, grid, row, row, any);
            }

            rows.push(row);
        }

        return rows;
    };


    //通过数据源移除表格行
    this.__remove = function (index, rows, parent) {

        var keys = this.keys,
            group = false,
            row;

        if (parent)
        {
            parent = keys[parent.uniqueId];
        }

        if (parent || !this.__group_view)
        {
            group = true;
            rows.splice.call(parent || this, index, rows.length);
        }

        for (var i = rows.length - 1; i >= 0; i--)
        {
            if (row = keys[rows[i].uniqueId])
            {
                if (group)
                {
                
                }

                row.view = false;
                row.dispose();
            }
        }

        this.__dirty = true;
        this.grid.update(false);
    };



    //销毁
    this.dispose = function () {

        for (var i = this.length - 1; i >= 0; i--)
        {
            this[i].dispose();
        }

        this.view.splice.call(this, 0);
        this.view.length = 0;

        if (arguments[0] === false)
        {
            this.keys = flyingon.create(null);
        }
        else
        {
            this.grid = this.keys = null;
        }
    };


});



//表格控件
flyingon.Control.extend('Grid', function (base) {



    this.init = function () {

        this.__columns = new flyingon.GridColumns(this);
        this.__view = new flyingon.GridView(this);
        this.__checked_rows = [];
    };



    this.defaultWidth = 800;

    this.defaultHeight = 400;


    this.defaultValue('border', 1);



    //默认锁定行
    this.__locked_top = this.__locked_bottom = 0;


    //列位置或顺序已经变更
    this.__column_dirty = true;


    //分组偏移
    this.__group_size = 0;



    //表格列
    this.defineProperty('columns', null, {

        fn: function (value) {

            var columns = this.__columns;

            if (value === void 0)
            {
                return columns;
            }

            if (value >= 0)
            {
                return columns[value];
            }

            if (typeof value === 'string')
            {
                value = flyingon.parseJSON(value);
            }

            if (value instanceof Array)
            {
                columns.push.apply(columns, value);
            }
            else
            {
                columns.push(value);
            }
            
            return this;
        }
    });


    //分组框高度
    this.defineProperty('group', 0, {

        set: function (value) {
            
            if (value > 0)
            {
                this.renderer.set(this, '__render_group');
            }

            if (this.rendered)
            {
                this.renderer.set(this, 'header', 1);
                this.update();
            }
        }
    });


    //列头大小
    this.defineProperty('header', 30, {

        set: function (value) {

            if (this.rendered)
            {
                this.renderer.set(this, 'header', 2);
                this.update();
            }
        }
    });


    //过滤栏高度
    this.defineProperty('filter', 0, {

        set: function (value) {

            if (this.rendered)
            {
                this.renderer.set(this, 'filter', value);
                this.update();
            }
        }
    });


    //锁定 锁定多个方向可按 left->right->top->bottom 顺序以空格分隔
    this.defineProperty('locked', '', {

        set: function (value) {

            var locked = this.__columns.__locked;

            locked[0] = locked[1] = locked[2] = locked[3] = 
            this.__locked_top = this.__locked_bottom = 0;

            if (value && (value = value.match(/\d+/g)))
            {
                locked[0] = value[0] | 0;
                locked[1] = value[1] | 0;

                this.__locked_top = value[2] | 0;
                this.__locked_bottom = value[3] | 0;
            }

            this.rendered && this.update(true);
        }
    });


    //行高
    this['row-height'] = this.defineProperty('rowHeight', 25);


    //分组设置
    this.defineProperty('groups', '', {

        set: function (value) {

            var view = this.__view;

            this.__groups = value = value && value.match(/\w+/g) || null;
            this.__group_size = value ? value.length * 20 : 0;

            if (view.length > 0)
            {
                view.__change_group(value);
            }

            this.trigger(value ? 'group' : 'ungroup');

            this.renderer.set(this, '__render_group');
            this.rendered && this.update(true);
        }
    });


    //是否只读
    this.defineProperty('readonly', true);


    //选择模式
    //0  仅选择单元格
    //1  选择行
    //2  选择列
    //3  选择行及列
    this['selected-mode'] = this.defineProperty('selectedMode', 0);


    //树列名
    this['tree-column'] = this.defineProperty('treeColumn', '', {

        set: function (value) {

            this.__tree_column = value;
        }
    });


    //树列是否显示图标
    this['tree-icon'] = this.defineProperty('treeIcon', true);


    //数据集
    this.defineProperty('dataset', null, {

        fn: function (value) {

            var any = this.__dataset || null;

            if (value === void 0)
            {
                return any;
            }

            if (any === value && this.__watch_list && flyingon.__do_watch(this, 'dataset', value) === false)
            {
                return this;
            }

            this.__dataset = value;

            if (any) 
            {
                any.grid = null;
                any.subscribe(this, true);
                any.off('add', add_rows);
                any.off('remove', remove_rows);
            }

            if (value) 
            {
                value.subscribe(value.grid = this);
                value.on('add', add_rows);
                value.on('remove', remove_rows);

                this.subscribeBind(value, { type: 'bind' });
            }
            else
            {
                this.__view.dispose(false);
            }

            this.rendered && this.update();

            return this;
        }
    });


    
    //获取指定索引行或行集合
    this.rows = function (index) {
        
        var view = this.__view;

        if (index === void 0)
        {
            return view;
        }

        return view[index] || null;
    };



    //获取当前渲染视图
    this.currentView = function () {
    
        var view = this.__view;
        return view.__dirty ? view.__sync_view() : view.view;
    };



    function add_rows(e) {

        var grid = this.grid;

        grid.__view.__add(e.index, e.rows, e.parent);
        grid.update(false);
    };


    function remove_rows(e) {

        var grid = this.grid;

        grid.__view.__remove(e.index, e.rows, e.parent);
        grid.update(false);
    };



    //展开行
    this.expand = function (row) {

        var view = this.__view,
            dirty;

        if (row)
        {
            if (!row.expanded && this.trigger('expand', 'row', row) !== false)
            {
                dirty = 1;
                row.expanded = true;
            }
        }
        else
        {
            for (var i = 0, l = view.length; i < l; i++)
            {
                if ((row = view[i]) && !row.expanded && this.trigger('expand', 'row', row) !== false)
                {
                    dirty = 1;
                    row.expanded = true;
                }
            }
        }

        if (dirty)
        {
            view.__dirty = true;
            this.rendered && this.update();
        }

        return this;
    };


    //展开行到指定级别
    this.expandTo = function (row, level) {

        if (arguments.length < 2)
        {
            level = row;
            row = null;
        }

        if (this.__expand_to(row || this.__view, level | 0))
        {
            this.__view.__dirty = true;
            this.rendered && this.update();
        }

        return this;
    };

    
    this.__expand_to = function (rows, level) {

        var dirty;

        level--;

        for (var i = rows.length - 1; i >= 0; i--)
        {
            var row = rows[i];

            if (!row.expanded)
            {
                if (this.trigger('expand', 'row', row) === false)
                {
                    continue;
                }

                row.expanded = true;
                dirty = 1;
            }

            if (row.length > 0)
            {
                if (level)
                {
                    if (this.__expand_to(row, level))
                    {
                        dirty = 1;
                    }
                }
                else
                {
                    //收拢最后一级
                    for (var j = row.length - 1; j >= 0; j--)
                    {
                        var item = row[j];

                        if (item.expanded && this.trigger('collapse', 'row', row) !== false)
                        {
                            item.expanded = false;
                            dirty = 1;
                        }
                    }
                }
            }
        }

        return dirty;
    };


    //收拢行
    this.collapse = function (row) {

        var view = this.__view,
            dirty;

        if (row)
        {
            if (row.expanded && this.trigger('collapse', 'row', row) !== false)
            {
                dirty = 1;
                row.expanded = false;
            }
        }
        else
        {

            for (var i = 0, l = view.length; i < l; i++)
            {
                if ((row = view[i]) && row.expanded && this.trigger('collapse', 'row', row) !== false)
                {
                    dirty = 1;
                    row.expanded = false;
                }
            }
        }

        if (dirty)
        {
            view.__dirty = true;
            this.rendered && this.update();
        }

        return this;
    };


    //获取勾选中的行集合
    this.checkedRows = function () {

        return this.__checked_rows;
    };


    //获取当前行
    this.current = function () {

        return this.__current || null;
    };


    //切换当前行
    this.__set_current = function (row, sync) {

        var any = this.__current;

        if (any !== row)
        {
            this.__current = row;

            if (this.rendered)
            {
                any && any.renderer.set(any, 'current', any.__current = false);
                row && row.renderer.set(row, 'current', row.__current = true);
            }

            if (sync !== false && (any = this.__dataset))
            {
                any.moveTo(row && any.uniqueId(row.id) || null);
            }
        }
    };


    
    //标记订阅所有dataset变更动作
    this.__subscribe_all = true;


    //处理数据源变更通知
    this.subscribeBind = function (dataset, action) {

        var view = this.__view,
            row = action.row || dataset.current(),
            any;

        row = row && view.find(row.uniqueId) || null;

        switch (action.type)
        {
            case 'move':
                this.__set_current(row, false);
                break;

            case 'change':
                if (row && (any = row.__cells) && (any = any[action.name]))
                {
                    (any.value || any.text).call(any, row.data[action.name]);
                }
                break;

            case 'bind':
                view.dataset(dataset);
                this.__set_current(row, false);
                break;
        }
    };


    //值变更处理
    this.__change_value = function (control) {

        var dataset = this.__dataset,
            column = control.column,
            name,
            any;

        if (dataset && column && (name = column.__name))
        {
            if (any = dataset.uniqueId(control.row.id))
            {
                any.set(name, (control.value || control.text).call(control));
            }
        }
    };



    this.sort = function (name, desc) {

        if (name)
        {
            this.__view.sort(name, desc, !!this.__tree_column);
            this.update(false);
        }
    };


    //刷新表格
    this.update = function (change) {

        if (this.rendered)
        {
            var patch = this.__view_patch;

            if (change)
            {
                this.__column_dirty = true;
            }

            if (!patch || !patch.content)
            {
                this.renderer.set(this, 'content', true);
            }
        }
        
        return this;
    };



    this.dispose = function () {

        this.__columns.dispose();
        this.__view.dispose();

        this.__columns = this.__view = this.__checked_rows = null;

        base.dispose.call(this);
    };



}).register();



//定义或获取表格汇总函数
flyingon.Grid.summary = (function () {
    

    var keys = flyingon.create(null);


    function fn(type, fn, summary) {

        //不区分大小写
        type = type.toLowerCase();

        if (typeof fn === 'function')
        {
            keys[type] = [fn, summary];
        }
        else
        {
            return keys[type] || keys.sum;
        }
    };


    fn('sum', function (row, name) {

        var value = 0,
            any;

        for (var i = row.length - 1; i >= 0; i--)
        {
            if ((any = row[i]) && (any = any.data))
            {
                value += any[name];
            }
        }

        return value;
    });


    fn('avg', keys.sum[0], function (row, name, value) {

        return value / row.total;
    });


    fn('max', function (row, name) {

        var value = -Infinity,
            any;

        for (var i = row.length - 1; i >= 0; i--)
        {
            if ((any = row[i]) && (any = any.data) && (any = any[name]) > value)
            {
                value = any;
            }
        }

        return value;
    });


    fn('min', function (row, name) {

        var value = Infinity,
            any;

        for (var i = row.length - 1; i >= 0; i--)
        {
            if ((any = row[i]) && (any = any.data) && (any = any[name]) < value)
            {
                value = any;
            }
        }

        return value;
    });


    return fn;

})();




flyingon.Panel.extend('TabPage', function (base) {



    this.defaultValue('layout', 'vertical-line');

    

    //自定义key
    this.defineProperty('key', '');


    
    function define(self, name, defaultValue) {

        return self[name] = self.defineProperty(name, defaultValue, {

            set: function (value) {
            
                this.rendered && this.renderer[name](this, value);
            }
        });
    };
    

    //图标
    define(this, 'icon', '');


    //页头文字
    define(this, 'text', '');


    //自定义button列表
    define(this, 'buttons', '');

    
    //是否可关闭
    define(this, 'closable', false);



    this.selected = function () {

        var parent = this.parent,
            storage;

        return parent && (storage = parent.__storage) && parent[storage.selected] === this || false;
    };
    


}).register();




flyingon.Control.extend('Tab', function (base) {



    this.defineWidth = this.defaultHeight = 300;

    this.defaultValue('border', 1);
    

    //页头偏移距离
    this.__scroll_header = 0;


    //是否需要重算页头
    this.__reset_header = true;



    //页头样式
    //default   默认样式
    //dot       圆点样式
    this.defineProperty('theme', 'default', {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'theme', value);
        }
    });



    //定义页面签属性
    var define = function (self, name, defaultValue, view) {

        self.defineProperty(name, defaultValue, {

            set: function (value) {

                this.__reset_header = true;
                this.__update_dirty || this.invalidate();
            }
        });
    };


    //页签方向
    //top       顶部页签
    //left      左侧页签
    //right     右侧页签
    //bottom    底部页签
    define(this, 'direction', 'top');


    //页头大小
    define(this, 'header', 30);


    //页头偏移
    define(this, 'offset', 2);


    //滚动按钮大小
    define(this, 'scroll', 16);



    define = function (self, name, defaultValue) {

        self.defineProperty(name, defaultValue, {

            set: function () {

                this.__update_dirty || this.invalidate();
            }
        });
    };



    //页签大小
    define(this, 'size', 60);


    //是否自动充满
    define(this, 'fill', false);


    //开始位置
    define(this, 'start', 0);


    //结束位置
    define(this, 'end', 0);


    //页签间距
    define(this, 'space', 2);



    //选中页索引
    this.defineProperty('selected', -1, { 

        set: function (value) {

            this.__selectedPage !== true && this.selectedPage(this[value], false);
        }
    });



    //获取或设置选中页面
    this.selectedPage = function (page, tag) {

        var selected = this.__selectedPage,
            any;

        if (page === void 0)
        {
            return selected !== void 0 ? selected : (this.__selectedPage = this[this.selected()]);
        }

        if (selected !== page && (!page || page.parent === this))
        {
            if (selected && selected.view_head)
            {
                 selected.renderer.selected(selected, false);
            }

            if (page)
            {
                if (page && page.view_head)
                {
                    page.renderer.selected(page, true);
                }

                this.rendered && this.renderer.set(this, 'selected', page, 'tag', tag);

                any = this.indexOf(page);
            }
            else
            {
                page = null;
                any = -1;
            }

            if (arguments[1] !== false)
            {
                this.__selectedPage = true;
                this.selected(any);
            }

            this.__selectedPage = page;
            this.trigger('tab-change', 'current', page, 'last', selected, 'tag', tag);
        }

        return this;
    };



    //扩展容器功能
    flyingon.fragment('f-container', this, flyingon.TabPage, true);


    var remove_items = this.__remove_items;


    this.__remove_items = function (index, items) {

        var selected = this.selected();

        remove_items.apply(this, arguments);

        this.selectedPage(this[selected] || this[--selected] || null, 'remove');
    };


    this.findByKey = function (key, selected) {

        for (var i = this.length - 1; i >= 0; i--)
        {
            if (this[i].key() === key)
            {
                selected && this.selected(i);
                return this[i];
            }
        }
    };


    this.findByText = function (text, selected) {

        for (var i = this.length - 1; i >= 0; i--)
        {
            if (this[i].text() === text)
            {
                selected && this.selected(i);
                return this[i];
            }
        }
    };



}).register();




/**
* 弹出层组件
* 
* 事件:
* open: 打开事件
* autoclosing: 鼠标点击弹出层外区域时自动关闭前事件(可取消)
* closing: 关闭前事件(可取消)
* closed: 关闭后事件
*/
flyingon.Panel.extend('Popup', function () {



    //设置为顶级控件
    this.__top_control = true;


    //弹出层是否已显示
    this.shown = false;

    
    this.defaultValue('border', 1);

    this.defaultValue('width', 'auto');

    this.defaultValue('height', 'auto');


    //鼠标移出弹出层时是否自动关闭
    this.defineProperty('closeLeave', false);


    //鼠标离弹出层越来越远时是否自动关闭
    this.defineProperty('closeAway', false);
    
    
    //停靠方向 bottom:下面 top:上面 right:右边 left:左边
    this.defineProperty('direction', 'bottom');
    
    
    //对齐 left|center|right|top|middle|bottom
    this.defineProperty('align', 'left');
    
    
    //空间不足时是否反转方向
    this.defineProperty('reverse', true);



    //打开弹出层
    this.show = function (reference, offset) {

        this.renderer.show(this, reference, offset, this.direction(), this.align(), this.reverse());
        this.shown = true;

        return this;
    };


    //在指定的位置打开弹出层
    this.showAt = function (left, top) {

        this.renderer.showAt(this, left, top);
        this.shown = true;

        return this;
    };



    //关闭弹出层(弹出多级窗口时只有最后一个可以成功关闭)
    //closeType: 关闭类型 ok, cancel, auto
    this.close = function (closeType) {

        closeType = closeType || 'ok';

        if (this.trigger('closing', 'closeType', closeType) === false)
        {
            return false;
        }

        this.rendered && this.renderer.close(this);
        this.shown = false;

        this.trigger('closed', 'closeType', closeType);

        if (this.autoDispose)
        {
            this.dispose();
        }

        return this;
    };
    


}).register();




flyingon.Panel.extend('Dialog', function (base) {



    //窗口栈
    var stack = [];



    //设置为顶级控件
    this.__top_control = true;


    //窗口是否已显示
    this.shown = false;


    this.defaultValue('border', 1);

    this.defaultValue('padding', 2);

    this.defaultValue('movable', true);



    //头部高度        
    this.defineProperty('header', 28, {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'header', value);
            this.__update_dirty || this.invalidate();
        }
    });


    //窗口图标        
    this.defineProperty('icon', '', {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'icon', value);
        }
    });


    //窗口标题
    this.defineProperty('text', '', {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'text', value);
        }
    });


    //是否显示关闭按钮
    this.defineProperty('closable', true, {

        set: function (value) {

            this.rendered && this.renderer.set(this, 'closable', value);
        }
    });



    //测量自动大小
    this.onmeasure = function (auto) {
        
        if (auto)
        {
            base.onmeasure.call(this, auto);

            if (auto & 2)
            {
                this.offsetHeight += this.header();
            }
        }
        else
        {
            return false;
        }
    };


    this.arrangeArea = function () {

        var header = this.header();

        this.arrangeHeight -= header;
        this.arrangeBottom -= header;
    };



    this.show = function () {
        
        this.renderer.show(this);
        this.shown = true;

        this.active();

        return this;
    };


    this.showDialog = function () {
        
        this.renderer.show(this, true);
        this.shown = true;

        this.active();

        return this;
    };


    this.moveTo = function (x, y) {

        this.shown && this.renderer.moveTo(this, x, y);
    };


    this.center = function () {

        this.shown && this.renderer.center(this);
    };


    this.active = function () {

        var last = stack[stack.length - 1];

        if (last !== this)
        {
            var index = stack.indexOf(this);

            if (index >= 0)
            {
                stack.splice(index, 1);
            }

            stack.push(this);

            if (last)
            {
                last.renderer.active(last, false);
                last.trigger('deactivated');
            }

            this.renderer.active(this, true);
            this.trigger('activated');
        }
        else if (last)
        {
            this.renderer.active(this, true);
        }
    };


    this.activated = function () {

        return stack[stack.length - 1] === this;
    };

        
    this.close = function (closeType) {

        if (!closeType)
        {
            closeType = 'ok';
        }

        if (this.trigger('closing', 'closeType', closeType) !== false)
        {
            this.rendered && this.renderer.close(this);
            this.shown = false;

            stack.splice(stack.indexOf(this), 1);

            stack[0] && stack[stack.length - 1].active();

            this.trigger('closed', 'closeType', closeType);

            if (this.autoDispose)
            {
                this.dispose();
            }
        }

        return this;
    };



}).register();




//子布局
flyingon.Sublayout = flyingon.Control.extend(function (base) {
       
    
        
    //子项占比
    this.defineProperty('scale', 0, {
     
        check: function (value) {

            return value > 0 ? value : 0;
        }
    });
    
    
    //布局
    this.defineProperty('layout', null, {
     
        set: function () {

            this.__layout = null;
        }
    });
    
    
    //指定默认大小
    this.defaultWidth = this.defaultHeight = 200;
    
        
    
    this.onmeasure = function (auto) {

        flyingon.arrange(this, this.__children, false, false, true);
        
        if (auto)
        {
            if (auto & 1)
            {
                this.offsetWidth = this.arrangeRight + this.borderLeft + this.borderRight;
            }
            
            if (auto & 2)
            {
                this.offsetHeight = this.arrangeBottom + this.borderTop + this.borderBottom;
            }
        }
        else
        {
            return false;
        }
    };
    
        
    this.onlocate = function () {
        
        var items = this.__children,
            x = this.offsetLeft,
            y = this.offsetTop,
            item;
        
        //处理定位偏移
        if (items && (x || y))
        {
            for (var i = items.length - 1; i >= 0; i--)
            {
                if (item = items[i])
                {
                    item.offsetLeft += x;
                    item.offsetTop += y;
                }
            }
        }
        
        return false;
    };


    this.controlAt = function (x, y) {

        var layout = this.__layout;
        return layout ? layout.controlAt(this.__children, x, y) : null;
    };
    
    
    //重载方法禁止绘制
    this.update = function () {};
    
    
});




//布局基类
flyingon.Layout = Object.extend(function () {

    

    
    //布局类型
    this.type = '';

    
    
    //自适应布局条件
    this.defineProperty('condition', null);
    
    
    //布局间隔宽度
    //length	规定以具体单位计的值 比如像素 厘米等
    //number%   控件客户区宽度的百分比
    this.defineProperty('spacingX', '2');

    //布局间隔高度
    //length	规定以具体单位计的值 比如像素 厘米等
    //number%   控件客户区高度的百分比
    this.defineProperty('spacingY', '2');

   
    //子项定位属性值
    this.defineProperty('location', null, {

        set: function (value) {

            this.__location = typeof value === 'function' ? value : null;
        }
    });

    
    //分割子布局
    this.defineProperty('sublayouts', null, {
       
        set: function (value) {

            this.__sublayouts = !!value;
        }
    });
    
    
        
    
    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

    };
    
    
    //重排
    this.rearrange = function (container, items, hscroll, vscroll) {
 
        var flag = false;
        
        if (hscroll && (hscroll === 1 || container.arrangeRight > container.arrangeLeft + container.arrangeWidth))
        {
            if ((container.arrangeHeight -= flyingon.hscroll_height) < 0)
            {
                container.arrangeHeight = 0;
            }
            
            hscroll = false;
            flag = true;
        }
        
        if (vscroll && (vscroll === 1 || container.arrangeBottom > container.arrangeTop + container.arrangeHeight))
        {
            if ((container.arrangeWidth -= flyingon.vscroll_width) < 0)
            {
                container.arrangeWidth = 0;
            }
            
            vscroll = false;
            flag = true;
        }
        
        if (flag)
        {
            container.arrangeRight = container.arrangeLeft;
            container.arrangeBottom = container.arrangeTop;
            
            this.arrange(container, items, hscroll, vscroll);
            return true;
        }
    };
    
    
    
    //查找指定坐标的子控件
    this.controlAt = function (items, x, y) {
        
        var item, any;
        
        for (var i = 0, l = items.length; i < l; i++)
        {
            if ((item = items[i]) && 
                x >= (any = item.offsetLeft) && x <= any + item.offsetWidth &&
                y >= (any = item.offsetTop) && y <= any + item.offsetHeight)
            {
                return items[i];
            }
        }

        return null;
    };
    
       
    
    //扩展可序列化功能
    flyingon.fragment('f-serialize', this);
    
    
    
    //设置不反序列化type属性
    this.deserialize_type = true;
    


});




//布局基础方法
(function () {



    //注册的布局列表
    var all = flyingon.Layout.all = flyingon.create(null); 
    
    //已定义的布局集合
    var layouts = flyingon.create(null); 

    //反序列化读
    var reader = new flyingon.SerializeReader();

    


    //重写布局类注册方法
    flyingon.Layout.register = function (name, force) {

        if (name)
        {
            if (!force && all[name])
            {
                throw 'layout "' + name + '" has exist';
            }

            layouts[name] = [all[this.type = name] = this, null];
        }

        return this;
    };



    //获取或切换而已或定义布局
    flyingon.layout = function (name, values) {
    
        if (name && values && typeof values !== 'function') //定义布局
        {
            layouts[name] = [values, null];
        }
        else
        {
            return flyingon.load.key('layout', name, values); //获取或设置当前布局
        }
    };
    
    
    
    //排列容器控件
    flyingon.arrange = function (container, items, hscroll, vscroll, sublayout) {
        
        var auto = container.__auto_size & 2, 
            any;

        //计算排列区域
        container.arrangeLeft = container.paddingLeft;
        container.arrangeTop = container.paddingTop;

        any = container.borderLeft + container.borderRight + container.paddingLeft + container.paddingRight;
        any = container.offsetWidth - any;

        container.arrangeWidth = any > 0 ? any : 0;

        //高度为auto时排列高度为0
        if (auto)
        {
            any = 0;
        }
        else
        {
            any = container.borderTop + container.borderBottom + container.paddingTop + container.paddingBottom;
            any = container.offsetHeight - any;
            
            if (any < 0)
            {
                any = 0;
            }
        }
        
        container.arrangeHeight = any;
        
        if (any = container.arrangeArea)
        {
            any.call(container);

            //高度为auto时保证排列高度为0
            if (auto)
            {
                container.arrangeHeight = 0;
            }
        }

        container.arrangeRight = container.arrangeLeft;
        container.arrangeBottom = container.arrangeTop;
        
        //排列子控件
        if (items && items.length > 0)
        {
            arrange(any = flyingon.getLayout(container), container, items, hscroll, vscroll, sublayout);
                    
            if (hscroll)
            {
                container.__hscroll = container.arrangeRight > container.arrangeLeft + container.arrangeWidth;
            }

            if (vscroll)
            {
                container.__vscroll = container.arrangeBottom > container.arrangeTop + container.arrangeHeight;
            }
            
            container.arrangeRight += container.paddingRight;
            container.arrangeBottom += container.paddingBottom;
        }
        else
        {
            container.__hscroll = container.__vscroll = false;
        }
    };
    
    
    //获取指定控件关联的布局实例
    flyingon.getLayout = function (container) {
        
        var layout = container.__layout,
            any;
        
        //获取当前布局对象
        if (!layout && typeof (any = container.layout) === 'function')
        {
            layout = container.__layout = find_layout(any.call(container));
        }
        
        //数组按自适应布局处理
        if (layout instanceof Array)
        {
            layout = check_adaption(layout, container.offsetWidth, container.offsetHeight);
        }
        
        return layout;
    };
    

                
    //查找布局实例
    function find_layout(key) {
      
        if (key)
        {
            if (typeof key === 'string')
            {
                if (key = layouts[key])
                {
                    return key[1] || (key[1] = deserialize_layout(key[0]));
                }
            }
            else
            {
                return deserialize_layout(key);
            }
        }
  
        return new all.flow();
    };


    //检测自适应
    function check_adaption(layouts, width, height) {

        var layout, item, condition, value;

        for (var i = 0, l = layouts.length; i < l; i++)
        {
            if (item = layouts[i])
            {
                if (condition = item.condition)
                {
                    if ((value = condition.width) && (width < value[0] || width > value[1]))
                    {
                        continue;
                    }

                    if ((value = condition.height) && (height < value[0] || height > value[1]))
                    {
                        continue;
                    }

                    layout = item;
                    break;
                }
                else
                {
                    layout = item;
                }
            }
        }

        if (layout)
        {
            return layout.__layout || (layout.__layout = deserialize_layout(layout, false));
        }

        return new all.flow();
    };
    

    //反序列化布局实例
    function deserialize_layout(data, adaption) {
        
        if (typeof data === 'function')
        {
            return new data();
        }

        //数组为自适应布局
        if (adaption !== false && data instanceof Array)
        {
            return data;
        }
        
        var layout = new (all[data && data.type] || all.flow)();
        
        layout.deserialize(reader, data);
        return layout;
    };


    //内部排列方法
    function arrange(layout, container, items, hscroll, vscroll) {

        var sublayouts, location, item;
                            
        //处理子布局(注:子布局不支持镜象,由上层布局统一处理)
        if (sublayouts = layout.__sublayouts)
        {
            if (sublayouts === true)
            {
                sublayouts = layout.__sublayouts = init_sublayouts(layout.sublayouts());
            }
 
            //分配置子布局子项
            allot_sublayouts(sublayouts, items);
             
            //先排列子布局
            items = sublayouts;
        }
        
        if (location = layout.__location) //处理强制子项值
        { 
            for (var i = items.length - 1; i >= 0; i--)
            {
                item = items[i];
                location.prototype = item.__storage || item.__defaults;

                item.__location_values = new location(container, item, i);
            }

            location.prototype = null;
        }
        else //清空原有强制子项属性
        {
            for (var i = items.length - 1; i >= 0; i--)
            {
                item = items[i];
                item.__location_values = null;
            }
        }
        
        //排列
        if (hscroll || vscroll)
        {
            arrange_auto(layout, container, items, hscroll, vscroll);
        }
        else
        {
            layout.arrange(container, items);
        }
    };
    
    
    //初始化子布局
    function init_sublayouts(values) {
        
        var index = values.length;
        
        if (!index)
        {
            values = [values];
            index = 1;
        }
        
        var reader = flyingon.SerializeReader,
            layouts = new Array(values.length),
            fixed = 0,
            weight = 0,
            layout,
            scale,
            any;
        
        while (any = values[--index])
        {
            (layout = layouts[index] = new flyingon.Sublayout()).deserialize(reader, any);
            
            if (scale = layout.scale())
            {
                if (layout.fixed = any = scale | 0)
                {
                    fixed += any;
                }

                if (layout.weight = any = scale - any)
                {
                    weight += any;
                }
            }
            else
            {
                layout.fixed = 0;
                weight += (layout.weight = 1);
            }
        }
        
        layouts.fixed = fixed;
        layouts.weight = weight;
        
        return layouts;
    };
    
    
    //分配子布局子项
    function allot_sublayouts(layouts, items) {
        
        var margin = items.length - layouts.fixed, //余量
            weight = layouts.weight,
            index = 0;
        
        if (margin < 0)
        {
            margin = 0;
        }
        
        for (var i = 0, l = layouts.length; i < l; i++)
        {
            var layout = layouts[i],
                length = layout.fixed,
                scale = layout.weight,
                value;
            
            if (scale)
            {
                value = margin * scale / weight | 0;
                weight -= scale;
                
                length += value;
                margin -= value;
            }

            layout.__children = items.slice(index, index += length);
        }
    };
        

    //自动滚动条排列
    function arrange_auto(layout, container, items, hscroll, vscroll) {

        var x, y;

        //上次有水平滚动条先减去滚动条高度
        if (hscroll && container.hscroll)
        {
            if ((container.arrangeHeight -= flyingon.hscroll_height) < 0)
            {
                container.arrangeHeight = 0;
            }

            x = true;
        }

        //上次有竖直滚动条先减去滚动条宽度
        if (vscroll && container.vscroll)
        {
            if ((container.arrangeWidth -= flyingon.vscroll_width) < 0)
            {
                container.arrangeWidth = 0;
            }

            y = true;
        }

        //按上次状态排列
        layout.arrange(container, items, x ? false : hscroll, y ? false : vscroll);

        //按水平滚动条排列后但结果无水平滚动条
        if (x = x && container.arrangeRight <= container.arrangeLeft + container.arrangeWidth)
        {
            container.arrangeHeight += flyingon.hscroll_height;
        }

        //按竖直滚动条排列后但结果无竖直滚动条
        if (y = y && container.arrangeBottom <= container.arrangeTop + container.arrangeHeight)
        {
            container.arrangeWidth += flyingon.vscroll_width;
        }

        //出现上述情况则重排
        if (x || y)
        {
            layout.arrange(container, items);
        }
    };

        

})();



//充满容器空间
flyingon.Layout.extend(function (base) {


    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var x = container.arrangeLeft,
            y = container.arrangeTop,
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            control;
        
        for (var i = 0, l = items.length; i < l; i++)
        {
            control = items[i];
            control.measure(width, height, width, height, 3);
            control.locate(x, y, width, height);
        }
    };
    
    
}).register('fill');



//单列布局类
flyingon.Layout.extend(function (base) {

        
    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var x = container.arrangeLeft,
            y = container.arrangeTop,
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            right = x + width,
            spacingX = flyingon.pixel(this.spacingX(), width),
            control;
        
        //先按无滚动条的方式排列
        for (var i = 0, l = items.length; i < l; i++)
        {
            control = items[i];
            control.measure(width, height, right - x || -1, height, 2);
            control.locate(x, y, 0, height, container);

            if (hscroll && container.arrangeRight > right)
            {
                return this.rearrange(container, items, 1, false);
            }

            x = container.arrangeX + spacingX;
        }
    };
    
    
}).register('line');



//纵向单列布局类
flyingon.Layout.extend(function (base) {

        
    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var x = container.arrangeLeft,
            y = container.arrangeTop,
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            bottom = y + height,
            spacingY = flyingon.pixel(this.spacingY(), height),
            control;
        
        //先按无滚动条的方式排列
        for (var i = 0, l = items.length; i < l; i++)
        {
            control = items[i];
            control.measure(width, height, width, bottom - height || -1, 1);
            control.locate(x, y, width, 0, container);

            if (vscroll && container.arrangeBottom > bottom)
            {
                return this.rearrange(container, items, false, 1);
            }

            y = container.arrangeY + spacingY;
        }
    };
    
    
}).register('vertical-line');



//流式布局类
flyingon.Layout.extend(function (base) {



    //行高
    this.defineProperty('lineHeight', '0', {
     
        dataType: 'int',
        check: function (value) {

            return value > 0 ? value : 0;
        }
    });
    
    

    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var x = container.arrangeLeft,
            y = container.arrangeTop,
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            right = x + width,
            bottom = y + height,
            pixel = flyingon.pixel,
            spacingX = pixel(this.spacingX(), width),
            spacingY = pixel(this.spacingY(), height),
            lineHeight = pixel(this.lineHeight(), height),
            left = x,
            control;

        for (var i = 0, l = items.length; i < l; i++)
        {
            (control = items[i]).measure(width, height, right - x || -1, lineHeight || -1);

            //处理换行
            if (x > left && (x + control.offsetWidth + control.marginRight > right))
            {
                x = left;
                y = (lineHeight ? y + lineHeight : container.arrangeBottom) + spacingY;
            }

            control.locate(x, y, 0, lineHeight, container);

            //出现滚动条后重排
            if (vscroll && container.arrangeBottom > bottom)
            {
                return this.rearrange(container, items, false, 1);
            }

            x = container.arrangeX + spacingX;
        }
    };

    
}).register('flow');



//纵向流式布局类
flyingon.Layout.extend(function (base) {


    //行宽
    this.defineProperty('lineWidth', '0', {
     
        dataType: 'int',
        check: function (value) {

            return value > 0 ? value : 0;
        }
    });


    
    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var x = container.arrangeLeft,
            y = container.arrangeTop,
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            right = x + width,
            bottom = y + height,
            pixel = flyingon.pixel,
            spacingX = pixel(this.spacingX(), width),
            spacingY = pixel(this.spacingY(), height),
            lineWidth = pixel(this.lineWidth(), width),
            top = y,
            control;

        for (var i = 0, l = items.length; i < l; i++)
        {
            (control = items[i]).measure(width, height, lineWidth || -1, bottom - y || -1);

            //处理换行
            if (y > top && (y + control.offsetHeight + control.marginBottom > bottom))
            {
                x = (lineWidth ? x + lineWidth : container.arrangeRight) + spacingX;
                y = top;
            }

            control.locate(x, y, lineWidth, 0, container);

            //出现滚动条后重排
            if (hscroll && container.arrangeRight > right)
            {
                return this.rearrange(container, items, 1, false);
            }

            y = container.arrangeY + spacingY;
        }
    };

    
}).register('vertical-flow');



//停靠布局类
flyingon.Layout.extend(function (base) {

    
    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var x = container.arrangeLeft,
            y = container.arrangeTop,
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            right = container.arrangeRight = x + width, //不允许出现滚动条
            bottom = container.arrangeBottom = y + height, //不允许出现滚动条
            arrangeWidth = width,
            arrangeHeight = height,
            pixel = flyingon.pixel,
            spacingX = pixel(this.spacingX(), width),
            spacingY = pixel(this.spacingY(), height),
            list,
            control;

        for (var i = 0, l = items.length; i < l; i++)
        {
            control = items[i];

            switch (control.locationValue('dock'))
            {
                case 'left':
                    control.measure(arrangeWidth, arrangeHeight, width, height, 2);
                    control.locate(x, y, 0, height);

                    x = control.offsetLeft + control.offsetWidth + control.marginRight + spacingX;

                    if ((width = right - x) < 0)
                    {
                        width = 0;
                    }
                    break;

                case 'top':
                    control.measure(arrangeWidth, arrangeHeight, width, height, 1);
                    control.locate(x, y, width, 0);

                    y = control.offsetTop + control.offsetHeight + control.marginBottom + spacingY;

                    if ((height = bottom - y) < 0)
                    {
                        height = 0;
                    }
                    break;

                case 'right':
                    control.measure(arrangeWidth, arrangeHeight, width, height, 2);
                    
                    right -= control.offsetWidth - control.marginLeft - control.marginRight;
                    control.locate(right, y, 0, height);

                    if ((width = (right -= spacingX) - x) < 0)
                    {
                        width = 0;
                    }
                    break;

                case 'bottom':
                    control.measure(arrangeWidth, arrangeHeight, width, height, 1);
                    
                    bottom -= control.offsetHeight - control.marginTop - control.marginBottom;
                    control.locate(x, bottom, width, 0);

                    if ((height = (bottom -= spacingY) - y) < 0)
                    {
                        height = 0;
                    }
                    break;

                default:
                    (list || (list = [])).push(control);
                    continue;
            }
        }
        
        //排列充满项
        if (list)
        {
            for (var i = 0, l = list.length; i < l; i++)
            {
                control.measure(arrangeWidth, arrangeHeight, width, height, 3);
                control.locate(x, y, width, height);
            }
        }
    };

    
}).register('dock');



//层叠布局类
flyingon.Layout.extend(function (base) {

    
    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var x = container.arrangeLeft,
            y = container.arrangeTop,
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            control;

        for (var i = 0, l = items.length; i < l; i++)
        {
            control = items[i];
            control.measure(width, height);
            control.locate(x, y, width, height, container);
        }
        
        //检查是否需要重排
        if (hscroll || vscroll)
        {
            this.rearrange(container, items, hscroll, vscroll);
        }
    };
    
    
    //查找指定坐标的子控件
    this.controlAt = function (items, x, y) {
        
        return -1;
    };
    
    
}).register('cascade');



//绝对定位布局类
flyingon.Layout.extend(function (base) {

    
    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var x = container.arrangeLeft,
            y = container.arrangeTop,
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            right = x + width,
            bottom = y + height,
            fn = flyingon.pixel,
            control,
            location,
            left,
            top;

        for (var i = 0, l = items.length; i < l; i++)
        {
            control = items[i];
            location = control.__location_values || control.__storage || control.__defaults;

            left = x + fn(location.left, width);
            top = y + fn(location.top, height);

            control.measure(width, height, right - x, bottom - y);
            control.locate(left, top, 0, 0, container);
        }
    };
    
    
    //查找指定坐标的子控件
    this.controlAt = function (items, x, y) {
        
        return -1;
    };
    
    
}).register('absolute');



//均分布局
flyingon.Layout.extend(function (base) {
    


    //固定大小
    this.defineProperty('size', 20);
    
    
    
    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var x = container.arrangeLeft,
            y = container.arrangeTop,
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            length = items.length,
            size = this.size(),
            weight = length - 1,
            spacing = width - size * length,
            control,
            value;

        for (var i = 0; i < length; i++)
        {
            (control = items[i]).measure(width, height, size, height, 3);
            control.locate(x, y, 0, height, container);
            
            value = spacing / weight | 0;
            
            x += control.offsetWidth + value;
            
            spacing -= value;
            weight--;
        }
    };
    
    
    //查找指定坐标的子控件
    this.controlAt = function (items, x, y) {
        
        var item, any;
        
        for (var i = 0, l = items.length; i < l; i++)
        {
            if ((item = items[i]) && x >= (any = item.offsetLeft) && x <= any + item.offsetWidth)
            {
                return items[i];
            }
        }

        return null;
    };
    
    
}).register('uniform');




//表格布局类
flyingon.Layout.extend(function (base) {

    

    //行列格式: row[column ...] ... row,column可选值: 
    //整数            固定行高或列宽 
    //数字+%          总宽度或高度的百分比 
    //数字+*          剩余空间的百分比, 数字表示权重, 省略时权重默认为100
    //数字+css单位    指定单位的行高或列宽
    //列可嵌套表或表组 表或表组可指定参数
    //参数集: <name1=value1 ...>   多个参数之间用逗号分隔
    //嵌套表: {<参数集> row[column ...] ...} 参数集可省略
    //示例(九宫格正中内嵌九宫格,留空为父表的一半): '*[* * *] *[* *{(50% 50%) L*[* * *]^3} *] *[* * *]'
    
    
    var parse_list = flyingon.create(null),
        
        regex_loop = /L([^L\^]+)\^(\d+)/g,
                
        regex_parse = /[*%.\w]+|[\[\]{}()!]/g;
    
    
    

    //是否纵向布局
    this.defineProperty('vertical', false);
    
    
    //内容区域
    this.defineProperty('data', '*[* * *] *[* * *] *[* * *]', {
     
        set: function () {

            this.__data = null;
        }
    });

    
    //自动循环的记录数
    this.defineProperty('auto', 0);
    
    
    
    //排列布局
    this.arrange = function (container, items, hscroll, vscroll) {

        var data = this.__data || (this.__data = parse(this.data())),
            vertical = this.vertical(),
            width = container.arrangeWidth,
            height = container.arrangeHeight,
            pixel = flyingon.pixel,
            spacingX = pixel(this.spacingX(), width),
            spacingY = pixel(this.spacingY(), height);
            
        //测量
        data.measure(width, height, spacingX, spacingY, vertical, this.auto(), items);
                
        //排列
        (vertical ? arrange_vertical : arrange)(container, width, height, data, items, 0, container.arrangeLeft, container.arrangeTop);

        //检查是否需要重排
        if (hscroll || vscroll)
        {
            this.rearrange(container, items, hscroll, vscroll);
        }
    };
    
    
    function arrange(container, width, height, group, items, index, x, y) {
        
        var lineWidth = group.width,
            cell, 
            control, 
            any;
        
        for (var i = 0, l = group.length; i < l; i++)
        {
            if (cell = group[i]) 
            {
                if (!cell.disabled)
                {
                    if (any = cell.group)
                    {
                        index = arrange_vertical(container, width, height, any, items, index, x, y + cell.start);
                        
                        if (index < 0)
                        {
                            return -1;
                        }
                    }
                    else if (control = items[index++])
                    {
                        control.measure(width, height, lineWidth, any = cell.size, 3);
                        control.locate(x, y + cell.start, lineWidth, any, container);
                    }
                    else
                    {
                        return -1;
                    }
                }
            }
        }
        
        return index;
    };

        
    function arrange_vertical(container, width, height, group, items, index, x, y) {
        
        var lineHeight = group.height,
            cell, 
            control, 
            any;
        
        for (var i = 0, l = group.length; i < l; i++)
        {
            if (cell = group[i]) 
            {
                if (!cell.disabled)
                {
                    if (any = cell.group)
                    {
                        index = arrange(container, width, height, any, items, index, x + cell.start, y);
                        
                        if (index < 0)
                        {
                            return -1;
                        }
                    }
                    else if (control = items[index++])
                    {
                        control.measure(width, height, any = cell.size, lineHeight, 3);
                        control.locate(x + cell.start, y, any, lineHeight, container);
                    }
                    else
                    {
                        return -1;
                    }
                }
            }
        }
        
        return index;
    };
    

    
    //解析布局
    function parse(text) {
        
        var items = parse_list[text],
            tokens;
        
        if (items)
        {
            return items.clone();
        }
        
        items = new Group();
        
        if (tokens = parse_loop(text || (text = '')).match(regex_parse))
        {
            items.parse(tokens, 0);
        }

        return parse_list[text] = items;
    };
        
    
    //解析循环
    function parse_loop(text) {
    
        var regex = regex_loop,
            loop;
        
        function fn(_, text, length) {
            
            var items = [];
            
            do
            {
                items.push(text);
            }
            while (--length > 0);
            
            loop = true;
            
            return items.join(' ');
        };
        
        do
        {
            loop = false;
            text = text.replace(regex, fn);
        }
        while (loop);
        
        return text;
    };
    
    
        
    //布局单元格
    var Cell = Object.extend(function () {
        
                
        //值
        this.value = 0;
        
        //单位
        this.unit = '';
        
        //是否禁用
        this.disabled = false;
        
        //子组
        this.group = null;
        
        
        //开始坐标
        this.start = 0;
        
        //大小
        this.size = 0;
        
        
        
        //复制
        this.clone = function () {
          
            var cell = new Cell(),
                any;
            
            cell.value = this.value;
            cell.unit = this.unit;
            cell.size = this.size;
            cell.disabled = this.disabled;
            
            if (any = this.group)
            {
                cell.group = any.clone();
            }
                        
            return cell;
        };
        
        
    }, false);
    
    
    
    //布局组
    var Group = Object.extend(function () {
        

        var pixel = flyingon.pixel,
            parse = parseFloat;
        
        
        //子项数
        this.length = 0;
                
        //子项固定值总数
        this.fixed = 0;
                
        //子项权重总数
        this.weight = 0;
        
        //子项百分比集合
        this.persent = null;
                
        //参数集
        this.parameters = null;
        
        
        //开始位置
        this.start = 0;
        
        //大小
        this.size = 0;
        
        
        
        //解析
        this.parse = function (tokens, index) {

            var length = this.length,
                token,
                cell, 
                value;

            while (token = tokens[index++])
            {
                switch (token)
                {
                    case '[':
                    case '{':
                        if (!cell)
                        {
                            cell = this[length++] = new Cell();
                            cell.value = 100;
                            cell.weight = 100;

                            this.width += 100;
                        }

                        index = (cell.group = new Group()).parse(tokens, index);
                        break;

                    case ']':
                    case '}':
                        this.length = length;
                        return index;

                    case '(':
                        while ((token = tokens[index++]) !== ')')
                        {
                            if (token.indexOf('%') < 0)
                            {
                                token = pixel(token);
                            }

                            (this.parameters || (this.parameters = [])).push(token);
                        }
                        break;

                    case '!':
                        cell && (cell.disabled = true);
                        break;

                    default:
                        cell = this[length++] = new Cell();
                        
                        if (token === '*')
                        {
                            cell.value = 100;
                            cell.unit = '*';

                            this.weight += 100;
                        }
                        else if ((value = parse(token)) === value) //可转为有效数字
                        {
                            switch (cell.unit = token.replace(value, ''))
                            {
                                case '*':
                                    this.weight += value;
                                    break;

                                case '%':
                                    (this.percent || (this.persent = [])).push(this.value);
                                    break;

                                default:
                                    this.fixed += (value = cell.size = pixel(token));
                                    break;
                            }

                            cell.value = value;
                        }
                        break;
                }
            }

            this.length = length;
            return index;
        };
        
        
        //获取可用单元格总数
        this.count = function (index) {
            
            var count = 0,
                any;
            
            index |= 0;
            
            while (any = this[index++])
            {
                if (any.disabled)
                {
                    continue;
                }

                if (any = any.group)
                {
                    count += any.count();
                }
                else
                {
                    count++;
                }
            }
            
            return count;
        };
        
        
        //复制子项
        function copy_cell(start, end) {
            
            var length = this.length,
                cell;
            
            for (var i = start; i < end; i++)
            {
                if (cell = this[i])
                {
                    switch (cell.unit)
                    {
                        case '*':
                            this.weight += cell.value;
                            break;
                            
                        case '%':
                            this.persent.push(cell.value);
                            break;
                            
                        default:
                            this.fixed += cell.value;
                            break;
                    }
  
                    this[length++] = cell.clone();
                }
            }
            
            this.length = length;
        };
        
        
        //计算自动增长
        function auto_cell(auto, total) {
            
            var start, end, any;
            
            if (auto === false)
            {
                if (auto = this.__auto)
                {
                    [].splice.call(this, auto.length);
                        
                    this.fixed = auto.fixed;
                    this.weight = auto.weight;
                    
                    if (any = auto.persent)
                    {
                        this.persent.splice(any);
                    }
                }
            }
            else if (auto > 0 && (total -= this.count()) > 0)
            {
                if ((start = (end = this.length) - auto) < 0)
                {
                    start = 0;
                }
                
                if ((auto = this.count(start)) > 0)
                {
                    //记录原始auto值
                    this.__auto = {

                        length: end,
                        fixed: this.fixed,
                        weight: this.weight,
                        persent: (any = this.persent) && any.length
                    };
                    
                    auto = Math.ceil(total / auto);
                    
                    for (var i = 0; i < auto; i++)
                    {
                        copy_cell.call(this, start, end);
                    }

                    return this.length;
                }
            }
        };
        
        
        //测量
        this.measure = function (width, height, spacingX, spacingY, vertical, auto, items) {
            
            var keys = [width, height, spacingX, spacingY, vertical, auto, 0];
            
            if (auto > 0)
            {
                keys[6] = auto_cell.call(this, auto, items.length);
            }
            else if (this.__auto)
            {
                auto_cell.call(this, false);
            }
            
            //如果缓存了排列则跳过
            if (this.__keys !== (keys = keys.join(',')))
            {
                this.compute(width, height, spacingX, spacingY, vertical);                
                this.__keys = keys;
            }
        };
        
        
        //计算位置
        this.compute = function (width, height, spacingX, spacingY, vertical) {
            
            var list = this.parameters,
                weight = this.weight,
                start = 0,
                length = this.length,
                cell,
                size,
                spacing, 
                any;
            
            this.width = width;
            this.height = height;

            if (list)
            {
                if (any = list[0])
                {
                    spacingX = any > 0 ? any : pixel(any, spacingX);
                }

                if (any = list[1])
                {
                    spacingY = any > 0 ? any : pixel(any, spacingY);
                }
            }
            
            if (vertical = !vertical)
            {
                size = height;
                spacing = spacingY;
            }
            else
            {
                size = width;
                spacing = spacingX;
            }
            
            //计算百分比
            if (size > 0 && (list = this.persent))
            {
                list = list.slice(0);
                any = 0;
                
                for (var i = list.length - 1; i >= 0; i--)
                {
                    any += (list[i] = (size * list[i] / 100 + 0.5) | 0);
                }
                
                if ((size -= any) < 0)
                {
                    size = 0;
                }
                
                list.index = 0;
            }
            
            //减去固定尺寸
            if (size > 0 && (size -= this.fixed + spacing * (length - 1)) < 0)
            {
                size = 0;
            }
            
            //计算余量
            for (var i = 0; i < length; i++)
            {
                if (cell = this[i])
                {
                    switch (cell.unit)
                    {
                        case '*':
                            if (size > 0)
                            {
                                any = cell.value;
                                size -= (cell.size = any * size / weight | 0);
                                weight -= any;
                            }
                            else
                            {
                                cell.size = 0;
                            }
                            break;
                            
                        case '%':
                            cell.size = list[list.index++] || 0;
                            break;
                    }
                    
                    cell.start = start;
                    start += cell.size + spacing;
                    
                    //排列子项
                    if (any = cell.group)
                    {
                        if (vertical)
                        {
                            any.compute(width, cell.size, spacingX, spacingY, vertical);
                        }
                        else
                        {
                            any.compute(cell.size, height, spacingX, spacingY, vertical);
                        }
                    }
                }
            }
        };
            
        
        //复制
        this.clone = function () {
            
            var target = new this.Class(),
                length = this.length,
                any;
            
            target.length = length;
            target.fixed = this.fixed;
            target.weight = this.weight;
            target.parsent = (any = this.persent) && any.slice(0);
            target.parameters = this.parameters;
            
            if ((any = this.length) > 0)
            {
                for (var i = 0; i < any; i++)
                {
                    target[i] = this[i].clone(); 
                }
            }
            
            return target;
        };

        
    }, false);
    
    
}).register('table');




(function (flyingon) {



    var components = flyingon.components;

    var unkown = flyingon.HtmlElement;

    var reader = new flyingon.SerializeReader();


    var uniqueId = flyingon.__uniqueId;


    var create = flyingon.create;


    var array_base = Array.prototype;

    var array_like = create(array_base);

    var slice = array_base.slice;

    var push = array_base.push;

    var splice = array_base.splice;


    //当前依赖参数
    //0: 控件id
    //1: 模板节点
    //2: 绑定名称
    var depend_target;

    var depend_cache = [null, null, null];





    //创建视图
    flyingon.view = function (options) {

        var template = view_template('view', options),
            defaults = options.defaults,
            control,
            vm,
            any;

        template.parse();

        if (vm = template.analyse())
        {
            vm = new (compile_object(vm, ''))(null, defaults);
        }

        template = template.ast;

        if (!(control = options.control))
        {
            control = template.Class;

            if (any = components[control])
            {
                control = new any();
            }
            else
            {
                control = new unkown();
                control.tagName = control;
            }
        }

        if (any = options.creating)
        {
            any.call(control, vm || {});
        }

        if (vm)
        {
            init_control(control, control.vmodel = vm, template);
        }
        else
        {
            control.deserialize(reader, template);
        }

        if (any = options.created)
        {
            any.call(control, vm || {});
        }

        if (any = options.host)
        {
            flyingon.show(control, any);
        }

        return control;
    };


    //创建部件
    flyingon.widget = function (name, options) {

        if (typeof name !== 'string')
        {
            options = name;
            name = '';
        }

        var template = view_template('widget', options),
            Class = components[template.parse().Class] || unkown;

        Class = Class.extend(widget_fn);

        Class.__widget_options = options;
        Class.__widget_template = template;

        if (name)
        {
            Class.register(name, options.force);
        }
        else //匿名widget立即初始化类
        {
            Class.init();
        }

        return Class;
    };


    function widget_fn(base) {

        var template = this.Class.__widget_template,
            options = this.Class.__widget_options,
            vmodel = template.analyse(),
            creating = options.creating,
            created = options.created,
            defaults,
            any;

        template = template.ast;

        if (vmodel)
        {
            vmodel = compile_object(any = vmodel, '');

            defaults = options.defaults;

            if (typeof defaults === 'function')
            {
                defaults = defaults.call(this, vmodel.prototype);
            }

            for (name in any)
            {
                if (any[name])
                {
                    widget_property(this, name, defaults && defaults[name] || null);
                }
            }
        
            //扩展widget元型或视图模型
            if (any = options.extend)
            {
                any.call(this, vmodel.prototype);
            }

            this.init = function () {

                var vm = this.vmodel = new vmodel(null, defaults),
                    any;

                if (any = creating)
                {
                    any.call(this, vm);
                }

                init_control(this, vm, template);

                if (any = created)
                {
                    any.call(this, vm);
                }
            };

            this.dispose = function () {

                var vm = this.vmodel;

                if (vm)
                {
                    vm.$dispose();
                    this.vmodel = null;
                }

                base.dispose.apply(this, arguments);
                return this;
            };
        }
        else
        {
            //扩展widget元型或视图模型
            if (any = options.extend)
            {
                any.call(this, {});
            }

            this.init = function () {

                var any;

                if (any = creating)
                {
                    any.call(this, {});
                }

                this.deserialize(reader, template);

                if (any = created)
                {
                    any.call(this, {});
                }
            };
        }

    };

    
    function widget_property(self, name, defaultValue) {

        var key1 = name,
            key2 = name;

        if (name.indexOf('-') > 0)
        {
            key1 = name.replace(/-(\w)/g, camelize);
        }
        else
        {
            key2 = name.replace(/([A-Z])/g, '-$1').toLowerCase();
        }

        self[key2] = self.defineProperty(key1, defaultValue || null, {

            set: function (value) {

                this.vmodel.$set(name, value);
            }
        });
    };


    function camelize(_, key) {

        return key.toUpperCase();
    };


    function view_template(name, options) {

        if (!options)
        {
            throw name + ' options must input a object!';
        }

        var template = options.template;

        if (!template)
        {
            throw name + ' options template not allow empty!';
        }

        if (typeof template === 'string' && template.charAt(0) === '#')
        {
            template = (template = flyingon.dom_id(template)) && template.innerHTML || '';
        }

        return new flyingon.view.Template(template);
    };




    //添加自定义观测
    function watch(name, fn) {

        if (typeof name === 'function')
        {
            fn = name;
            name = '*';
        }
        else if (typeof fn !== 'function')
        {
            throw 'watch must input a function!';
        }

        (this.__watches || (this.__watches = [])).push(name || '*', fn);
        return this;
    };


    //触发观测通知
    function notify(vm, name, value, oldValue) {

        var target = vm,
            list,
            event,
            index,
            key;

        do
        {
            if (list = target.__watches)
            {
                index = 0;

                while (key = list[index++])
                {
                    if (key === '*' || name === '*' || key === name)
                    {
                        list[index++].call(target, event || (event = {
                            
                            target: vm,
                            name: name,
                            newValue: value,
                            oldValue: oldValue
                        }));
                    }
                    else
                    {
                        index++;
                    }
                }
            }
        }
        while(target = target.__parent); //向上冒泡
    };




    //获取绑定值
    function bind_value(control, vm, scope, node) {

        var any;

        switch (node[1])
        {
            case 0: //property
                if (node[3])
                {
                    vm = bind_vm(control, vm, scope, node);
                }

                if (any = depend_target)
                {
                    property_track(vm, node[2], any);
                }

                return vm[node[2]];

            case 1: //loop item
                if (scope && (scope = scope[node[2]]))
                {
                    vm = scope.__loop_vm;

                    if (!node[0] && (any = depend_target))
                    {
                        item_track(vm, scope, any);
                    }

                    return vm[scope.__loop_index];
                }

                return find_item(control, node[2]);

            case 2: //loop index
                if (scope)
                {
                    scope = scope[node[2]];

                    if (any = depend_target)
                    {
                        item_track(scope.__loop_vm, scope, any);
                    }

                    return scope.__loop_index;
                }

                return find_index(control, node[2]);

            case 3: //function
                return bind_function(control, vm, scope, node);
        }
    };


    //获取绑定的视图模型
    function bind_vm(control, vm, scope, node) {

        var list = node[3],
            item = list[0],
            index = 1;

        if (item[1] === 1) //loop item
        {
            if (scope && (scope = scope[item[2]]))
            {
                vm = scope.__loop_vm[scope.__loop_index];
            }
            else
            {
                vm = find_item(control, item[2]);
            }
        }
        else
        {
            vm = (vm.__top || vm)[item[2]];
        }

        while (item = list[index++])
        {
            vm = vm[item[2]];
        }

        return vm;
    };


    //获取绑定的函数返回值
    function bind_function(control, vm, scope, node, event) {

        var list = node[4], 
            args = [], 
            index = 0, 
            item;

        //函数只能在顶级视图模型中
        vm = vm.__top || vm;
      
        if (list = node[4])
        {
            while (item = list[index++])
            {
                args.push(bind_value(control, vm, scope, item));
            }
        }

        args.push(control);
        event && args.push(event);

        return vm[node[2]].apply(vm, args);
    };


    //绑定事件
    function bind_event(vm, node) {

        return function (e) {

            bind_function(this, vm, null, node, e);
        };
    };


    //获取控件相关的item变量作用域
    function find_item(control, name) {

        var vm;

        do
        {
            if ((vm = control.__loop_vm) && vm.__item_name === name)
            {
                return vm[control.__loop_index];
            }
        }
        while (control = control.parent);
    };


    //索引绑定的循环索引号
    function find_index(control, name) {

        var vm;

        do
        {
            if ((vm = control.__loop_vm) && vm.__index_name === name)
            {
                return control.__loop_index;
            }
        }
        while (control = control.parent);

        return -1; //出错了
    };




    //添加对象属性变化依赖追踪
    function property_track(vm, name, depends) {

        var keys = vm.__depends || (vm.__depends = create(null));
        push.apply(keys[name] || (keys[name] = []), depends);
    };


    //添加数组项值变化依赖追踪
    function item_track(vm, control, depends) {

        var keys = keys = vm.__depends || (vm.__depends = create(null)),
            id = control.__uniqueId || (control.__uniqueId = uniqueId.id++);

        push.apply(keys[id] || (keys[id] = []), depends);
    };


    //更新指定绑定
    function update_bind(vm, scope, depends) {

        var index = 0,
            item;

        while (item = depends[index++])
        {
            item.set(depends[index++], bind_value(item, vm, scope, depends[index++]));
        }
    };




    //编译对象视图模型类
    function compile_object(node, name) {


        var self = Class.prototype;

        var keys1 = self.__keys1 = create(null);

        var keys2 = self.__keys2 = create(null);


        function Class(parent, value) {

            var keys, fn;

            this.__top = (this.__parent = parent) ? parent.__top : this;
            
            if (value)
            {
                if (typeof value === 'object')
                {
                    keys = this.__keys1;

                    for (var name in keys)
                    {
                        if (fn = keys[name])
                        {
                            this[name] = new fn(this, value[name]);
                        }
                        else
                        {
                            this[name] = value[name];
                        }
                    }
                }
                else if (parent)
                {
                    throw '"' + this.$name + '" must input a object!';
                }
            }
            else
            {
                keys = this.__keys2;

                for (var name in keys)
                {
                    this[name] = new keys[name](this);
                }

                value = null;
            }

            this.$data = value;
        };


        self.$name = name;
        self.$watch = watch;
        self.$get = object_get;
        self.$set = object_set;
        self.$replace = object_replace;
        self.$update = object_update;
        self.$dispose = object_dispose;


        //顶层视图绑定事件
        if (!name)
        {
            self.eventBubble = '__up_vm';

            self.$on = flyingon.on;
            self.$once = flyingon.once
            self.$off = flyingon.off;
            self.$trigger = flyingon.trigger;
        }


        for (var name in node)
        {
            var item = node[name];

            if (item[1] > 0) //function || item || index
            {
                continue;
            }

            switch (item[0])
            {
                case 1: //object
                    keys1[name] = keys2[name] = compile_object(item[4], item[1]);
                    break;

                case 2: //loop
                    keys1[name] = keys2[name] = compile_array(item);
                    break;

                default:
                    keys1[name] = 0;
                    break;
            }
        }


        return Class;
    };


    function object_get(name) {

        var value;

        if (value = depend_target)
        {
            property_track(this, name, value);
        }

        return this[name];
    };


    function object_set(name, value) {

        var any = this.__keys1[name];

        if (any)
        {
            if (any = this[name])
            {
                any.$replace(value);
                notify(this, name, value, any);
            }
        }
        else if (any === 0 && (any = this[name]) !== value)
        {
            this[name] = value;

            notify(this, name, value, any);

            if ((any = this.__depends) && (any = any[name]))
            {
                update_bind(this, null, any);
            }
        }

        return this;
    };


    function object_replace(value, update) {

        var keys = this.__keys1,
            data = this.$data;

        //记录原始数据
        this.$data = value = value && typeof value === 'object' ? value : null;

        for (var name in keys)
        {
            if (keys[name])
            {
                this[name].$replace(value && value[name], false);
            }
            else if (value || data)
            {
                this[name] = value && value[name];
            }
        }

        if (update !== false)
        {
            this.$update();
        }
    };


    function object_update() {

        var keys = this.__depends;

        if (keys)
        {
            for (var name in keys)
            {
                update_bind(this, null, keys[name]);
            }
        }

        if (keys || this.__top.__created)
        {
            keys = this.__keys2;

            for (var name in keys)
            {
                this[name].$update();
            }
        }
    };

    
    function object_dispose() {

        var keys = this.__keys1;

        for (var name in keys)
        {
            if (keys[name])
            {
                this[name].$dispose();
            }
            else
            {
                this[name] = null;
            }
        }

        this.__top = this.__parent = this.__depends = this.__watches = this.$data = null;
    };


           

    //编译数组视图模型类
    function compile_array(node) {

        
        var self = Class.prototype = create(array_like);


        function Class(parent, value) {

            var fn = this.__item_fn,
                length = value && value.length;

            this.__top = (this.__parent = parent).__top;
            
            if (length > 0)
            {
                if (fn)
                {
                    this.length = length;

                    for (var i = 0; i < length; i++)
                    {
                        this[i] = new fn(this, value[i]);
                    }
                }
                else
                {
                    push.apply(this, value);
                }
            }
        };


        self.__item_name = node.item;
        self.__index_name = node.index;


        self.$name = node[2];
        self.$watch = watch;
        self.$get = array_get;
        self.$set = array_set;
        self.$replace = array_replace;
        self.$update = array_update;
        self.$dispose = array_dispose;
        

        //数组项是一个对象
        if (node[0] === 1 || (node = node[4]) && node[0] === 1)
        {
            self.__item_fn = compile_object(node[4], node[2]);
        }
        else if (node && node[0] === 2) //数组项是一个数组
        {
            self.__item_fn = compile_array(node[4]);
        }

        return Class;
    };


    function array_get(index) {

        var value;

        if (value = depend_target)
        {
            item_track(this, this.__controls[index], value);
        }

        return this[index];
    };


    function array_set(index, value) {

        var control, any;

        if (index >= 0)
        {
            if (index < this.length)
            {
                any = this[index];

                if (any && any.$replace)
                {
                    any.$replace(value);
                }
                else if (any !== value)
                {
                    this[index] = value;

                    if ((any = this.__depends) && 
                        (index = this.__controls[index]) && 
                        (index = index.__uniqueId) &&
                        (any = any[index]))
                    {
                        update_bind(this, null, any);
                    }
                }
            }
        }
        else if (index === 'length')
        {
            this.splice(value);
        }

        return this;
    };


    function array_replace(value, update) {

        var l1 = this.length,
            l2 = (value && value.length) | 0,
            any;

        if (l2 <= 0)
        {
            if (l1 > 0)
            {
                this.splice(0);
            }
            
            return this;
        }

        if (l1 > l2)
        {
            this.splice(l2);
            l1 = l2;
        }

        if (l1 > 0)
        {
            if (this.__item_fn)
            {
                for (var i = 0; i < l1; i++)
                {
                    this[i].$replace(value[i]);
                }
            }
            else
            {
                any = slice.call(value, 0, l1);
                any.unshift(0, l1);

                splice.apply(this, any); 
            }

            if (update !== false)
            {
                this.$update();
            }
        }

        if (l1 < l2)
        {
            this.push.apply(this, slice.call(value, l1));
        }

        return this;
    };


    function array_update(deep) {

        var keys = this.__depends;

        if (keys)
        {
            for (var key in keys)
            {
                update_bind(this, null, keys[key]);
            }
        }

        if (deep !== false && this.__item_fn && this.__controls)
        {
            for (var i = 0, l = this.length; i < l; i++)
            {
                this[i].$update();
            }
        }
    };


    function array_dispose() {

        if (this.__item_fn)
        {
            for (var i = this.length - 1; i >= 0; i--)
            {
                this[i].$dispose();
            }
        }

        this.__top = this.__parent = this.__depends = this.__watches = 
        this.__controls = this.__template = this.__tag = this.__container = null;

        return this;
    };


    //类数组方法扩展
    array_like.push = function (item) {

        var index = this.length,
            length = arguments.length;

        if (length > 0)
        {
            if (this.__item_fn)
            {
                append_check(this, arguments, 0);
            }

            push.apply(this, arguments);

            //插入节点
            if (this.__controls)
            {
                append_loop(this, index, index += length);
            }
        }

        return index;
    };


    array_like.pop = function () {
        
        var length = this.length;

        if (length > 0)
        {
            remove_item(this, length - 1);
            return array_base.pop.call(this);
        }
    };


    array_like.unshift = function (item) {

        var length = arguments.length;

        if (length > 0)
        {
            if (this.__item_fn)
            {
                append_check(this, arguments, 0);
            }

            array_base.unshift.apply(this, arguments);

            //插入节点
            if (this.__controls)
            {
                append_loop(this, 0, length); 
            }

            if (length < this.length)
            {
                adjust_index(this, length, length);
            }
        }

        return this.length;
    };


    array_like.shift = function () {
        
        var item;

        if (this.length > 0)
        {
            remove_item(this, 0);

            item = array_base.shift.call(this);

            if (this.length > 1)
            {
                adjust_index(this, 0, -1);
            }

            return item;
        }
    };


    array_like.splice = function (index, length) {

        var l1 = this.length,
            l2 = arguments.length,
            any;

        if ((index |= 0) < 0 && (index += l1) < 0)
        {
            index = 0;
        }
        else if (index > l1)
        {
            index = l1;
        }

        if (l2 > 2 && this.__item_fn)
        {
            append_check(this, arguments, 2);
        }

        any = splice.apply(this, arguments);

        if (any.length > 0)
        {
            remove_items(this, index, any);
        }

        //插入节点
        if ((l2 -= 2) > 0 && this.__controls)
        {
            append_loop(this, index, index += l2); 
        }

        if (index < this.length && (l2 -= any.length))
        {
            adjust_index(this, index, l2);
        }

        return any;
    };


    array_like.sort = function (fn) {

        var sort = array_base.sort,
            length = this.length;

        if (length > 1)
        {
            var controls = this.__controls,
                item;
            
            //如果有子循环则移动视图(解决嵌套数组更新的问题)
            if (this.__item_fn)
            {
                if (controls)
                {
                    //先记录原控件
                    for (var i = length - 1; i >= 0; i--)
                    {
                        this[i].__control = controls[i];
                    }

                    //排序
                    sort.call(this, fn);

                    //再按照新的位置重编控件索引
                    for (var i = length - 1; i >= 0; i--)
                    {
                        item = this[i];
                        controls[i] = item.__control;
                        item.__control = null;
                    }

                    adjust_sort(this, controls);
                }
                else
                {
                    sort.call(this, fn);
                }
            }
            else //否则直接同步绑定
            {
                sort.call(this, fn);
                controls && this.$update();
            }
        }
    };


    array_like.reverse = function () {
             
        if (this.length > 1)
        {       
            var controls = this.__controls,
                reverse = array_base.reverse;

            //如果有子循环则移动视图(解决嵌套数组更新的问题)
            if (this.__item_fn)
            {
                if (controls)
                {
                    reverse.call(this);
                    controls.reverse();

                    adjust_sort(this, controls);
                }
                else
                {
                    reverse.call(this);
                }
            }
            else //否则直接同步绑定
            {
                reverse.call(this);
                controls && this.$update();
            }
        }
    };


    function append_check(vm, list, index) {

        var fn = vm.__item_fn;

        for (var i = index, l = list.length; i < l; i++)
        {
            list[i] = new fn(vm, list[i]);
        }
    };


    function remove_item(vm, index) {
    
        var controls = vm.__controls,
            control,
            any;

        if (controls)
        {
            control = controls[index]
            controls.splice(index, 1);

            if (control && (any = vm.__depends))
            {
                delete any[control.__uniqueId];
            }

            if (any = vm.__container)
            {
                any.splice(index, 1);
            }
        }

        if (vm.__item_fn)
        {
            vm[index].$dispose();
        }
    };


    function remove_items(vm, index, list) {

        var controls = vm.__controls,
            depends = vm.__depends,
            length = list.length,
            any;

        if (controls)
        {
            if (depends)
            {
                for (var i = 0; i < length; i++)
                {
                    if (any = controls[index + i])
                    {
                        delete depends[any.__uniqueId];
                    }
                }
            }
            
            controls.splice(index, length);

            if (any = vm.__container)
            {
                any.splice(index, length);
            }
        }
        
        if (vm.__item_fn)
        {
            for (var i = 0; i < length; i++)
            {
                list[i].$dispose();
            }
        }
    };


    function adjust_index(vm, start, offset) {

        var controls = vm.__controls,
            control;

        for (var i = start, l = controls.length; i < l; i++)
        {
            if (control = controls[i])
            {
                control.__loop_index += offset;
            }
        }

        if (vm.__index_name && vm.__depends)
        {
            vm.$update(false);
        }
    };


    function adjust_sort(vm, list) {

        var parent = vm.__container,
            item;

        if (parent)
        {
            for (var i = list.length - 1; i >= 0; i--)
            {
                (parent[i] = item = list[i]).__loop_index = i;
            }

            if (vm.__depends)
            {
                vm.$update(false);
            }

            parent.renderer.set(parent, '__view_order');
            parent.invalidate();
        }
    };




    //根据编译后的视图模型初始化或创建控件
    function init_control(control, vm, template) {

        var scope = create(null),
            any;

        //标记已创建控件
        vm.__created = true;

        bind_control(control, vm, scope, template);

        if (any = template.children)
        {
            create_children(control, vm, scope, any, components);
        }
    };


    function create_control(vm, scope, template, components, type) {

        var control, any;

        any = template.Class;

        if (type || (type = components[any]))
        {
            control = new type();
        }
        else
        {
            control = new unkown();
            control.tagName = any;
        }

        if (any = control.vm)
        {
            any.__up_vm = vm.__top;
        }

        bind_control(control, vm, scope, template);

        if (any = template.children)
        {
            create_children(control, vm, scope, any, components);
        }

        return control;
    };


    function bind_control(control, vm, scope, template) {

        var depend = depend_target = depend_cache,
            node,
            any;

        depend[0] = control;

        for (var name in template)
        {
            switch (name)
            {
                case 'Class':
                case 'children':
                case '#loop':
                    break;

                case '#model': //模型指令特殊处理
                    if (any = control[name])
                    {
                        node = template[name];
                        any.call(control, node[3] ? bind_vm(control, vm, scope, node) : vm, node[2]); 
                    }
                    break;

                default:
                    node = template[name];

                    switch (name.charAt(0))
                    {
                        case ':': //绑定
                            depend[1] = name = name.substring(1);
                            depend[2] = node;

                            control.set(name, bind_value(control, vm, scope, node));
                            break;

                        case '@': //事件
                            control.on(name.substring(1), bind_event(vm, node));
                            break;

                        case '#': //指令
                            if (any = control[name])
                            {
                                depend[1] = name;
                                depend[2] = node;

                                any.call(control, bind_value(control, vm, scope, node));
                            }
                            break;

                        default:
                            if (node && (typeof node === 'string') && node.charAt(0) === '{' && (any = node.match(/^\{\{(\w+)\}\}$/)))
                            {
                                control.addBind(name, any[1]);
                            }
                            else
                            {
                                control.set(name, node);
                            }
                            break;
                    }
            }
        }

        depend_target = null;
    };


    function create_children(parent, vm, scope, template, components) {

        var controls = [],
            node;

        for (var i = 0, l = template.length; i < l; i++)
        {
            if ((node = template[i]) && node['#loop'])
            {
                controls.push.apply(controls, create_loop(parent, vm, scope, node, components));
            }
            else
            {
                controls.push(create_control(vm, scope, node, components));
            }
        }

        if (controls[0])
        {
            parent.push.apply(parent, controls);
        }
    };


    function create_loop(parent, vm, scope, template, components) {

        var controls = [], 
            item = template['#loop'],
            loop = item[2],
            any;
        
        if (item[3])
        {
            vm = bind_vm(parent, vm, scope, item)[loop];
        }
        else if (any = scope && scope[loop])
        {
            vm = any.__loop_vm[any.__loop_index];
        }
        else
        {
            vm = vm[loop];
        }

        vm.__template = template;
        vm.__container = parent;
        vm.__controls = controls;
        vm.__tag = parent.lastChild; //记录标记位作为插入的起点,如果手动移动此控件后果自负

        if ((any = vm.length) > 0)
        {
            loop_controls(controls, vm, 0, any, scope, components);
        }

        return controls;
    };


    function loop_controls(list, vm, start, end, scope, components) {

        var top = vm.__top,
            template = vm.__template,
            tag = template.Class,
            type = components[tag],
            node = template['#loop'],
            item = node.item,
            index = node.index,
            control,
            any;
        
        if (item || index)
        {
            while (start < end)
            {
                if (type)
                {
                    control = new type();
                }
                else
                {
                    control = new unkown();
                    control.tagName = tag;
                }

                if (any = control.vm)
                {
                    any.__up_vm = top;
                }

                //为后述查找缓存数据
                control.__loop_vm = vm;
                control.__loop_index = start++;
                
                if (item)
                {
                    scope[item] = control;
                }

                if (index)
                {
                    scope[index] = control;
                }

                bind_control(control, top, scope, template);
                list.push(control);

                if (any = template.children)
                {
                    create_children(control, top, scope, any, components);
                }
            }

            item && (scope[item] = null);
            index && (scope[index] = null);
        }
        else
        {
            while (start++ < end)
            {
                list.push(control = create_control(top, scope, template, components, type));
            }
        }
    };


    function append_loop(vm, index, end) {

        var list = [],
            parent = vm.__container,
            controls = vm.__controls,
            control = parent,
            scope = {},
            name,
            any;

        while (control)
        {
            if (any = control.__item_vm)
            {
                if (name = any.item)
                {
                    scope[name] = control;
                }

                if (name = any.index)
                {
                    scope[name] = control;
                }
            }

            control = control.parent;
        }

        loop_controls(list, vm, index, end, scope, components);

        if (any = controls[0])
        {
            any = parent.indexOf(any);
        }
        else if (any = vm.__tag)
        {
            any = parent.indexOf(any) + 1;
        }
        else
        {
            any = 0;
        }

        list.unshift(index, 0);
        controls.splice.apply(controls, list);

        list[0] += any;
        parent.splice.apply(parent, list);
    };




})(flyingon);




//视图模板类
flyingon.view.Template = Object.extend(function () {



    //标签嵌套规则
    var rule = flyingon.view.rule = flyingon.create(null);



    this.init = function (template) {

        if (typeof template === 'string')
        {
            this.template = template;
        }
        else
        {
            this.ast = template;
        }
    };




    //解析html模板生成虚拟树
    this.parse = function (multi) {

        var ast = this.ast,
            any;

        if (!ast && (any = this.template))
        {
            any = any.replace(/<!--[\s\S]*?-->/g, '').replace(/>\s+<\s*\//g, '></');
            any = any.match(/[<=/]|[\w-:#@]+|\>[^<>]+(?=\<\s*\/)|[>/]|"[^"]*"|'[^']*'/g);

            ast = parse(any, []);

            if (!multi && ast instanceof Array)
            {
                if (ast[1])
                {
                    throw 'template can only one root node!';
                }

                ast = ast[0];
            }

            if (ast)
            {
                if (ast['#loop'])
                {
                    throw 'template root nood can not use "#loop"!';
                }
            }
            else
            {
                throw 'template can not be empty!';
            }

            this.ast = ast;
        }

        return ast;
    };



    //分析模板生成模型结构
    this.analyse = function () {

        var vm = this.vm,
            any;

        if (vm === void 0 && (any = this.ast || this.parse()))
        {
            analyse_object(vm = {}, any);

            for (any in vm)
            {
                return this.vm = vm;
            }

            return this.vm = null;
        }

        return vm;
    };



    //解析html模板
    function parse(tokens, array) {

        var regex_node = /[^\w-]/,
            regex_name = /[^\w-:#@]/,
            stack = [],
            flag, //属性分析阶段标记
            index = 0,
            item,
            name,
            token,
            any;

        while (token = tokens[index++])
        {
            switch (token)
            {
                case '<':
                    if (flag)
                    {
                        throw parse_error(token, item);
                    }

                    token = tokens[index++];

                    //下一个符号是关闭结点
                    if (token === '/')
                    {
                        if (!item || tokens[index] !== item.Class || tokens[index + 1].charAt(0) !== '>')
                        {
                            throw '"' + token + tokens[index] + tokens[index + 1] + '" not a valid close tag!';
                        }

                        index++;
                        stack.pop();
                        item = stack[stack.length - 1];
                        break;
                    }

                    if (token.match(regex_node))
                    {
                        throw '"' + token + '" not a valid node name!';
                    }

                    any = { Class: token };

                    //添加子项
                    if (item)
                    {
                        (item.children || (item.children = [])).push(any);
                    }
                    else
                    {
                        array.push(any);
                    }

                    stack.push(item = any);
                    flag = true; //标记处于属性分析阶段
                    break;

                case '/':
                    if (flag && tokens[index++] === '>')
                    {
                        flag = false; //标记属性分析阶段结束

                        if (name)
                        {
                            item[name] = true;
                            name = null;
                        }

                        stack.pop();
                        item = stack[stack.length - 1];
                        break;
                    }

                    throw parse_error(token, item);

                case '>':
                    if (flag)
                    {
                        flag = false; //标记属性分析阶段结束

                        if (name)
                        {
                            item[name] = true;
                            name = null;
                        }
                    }
                    break;

                case '=':
                    if (flag && name)
                    {
                        switch (token = tokens[index++])
                        {
                            case '<':
                            case '>':
                            case '/':
                            case '=':
                                throw parse_error(token, item);
                        }

                        any = token.charAt(0);
                        any = any === '"' || any === '\'' ? token.substring(1, token.length - 1) : token;

                        item[name] = any;
                        name = null;
                        break;
                    }

                    throw parse_error(token, item);


                default:
                    if (flag)
                    {
                        if (name)
                        {
                            item[name] = true;
                        }

                        flag = token.charAt(0);

                        //处理标签间的文本
                        if (item && flag === '>')
                        {
                            name = null;
                            flag = false;

                            if ((token = token.substring(1)).indexOf('&') >= 0)
                            {
                                token = flyingon.html_decode(token);
                            }

                            item.text = token;
                        }
                        else
                        {
                            if (token.match(regex_name))
                            {
                                throw '"<' + item.Class + '...' + token + '" not a valid attribute name!';
                            }

                            name = token;
                        }
                    }
                    break;
            }
        }

        return array;
    };


    function parse_error(token, item) {

        return '"' + (item ? '<' + item[0] + '...' : '') + token + '" has syntax error!';
    };




    //分析生成的节点格式
    //[type, subtype, name, path, detail]
    //[0, 0, name, path, null]    无父级节点
    //[0, 1, name, path, null]    loop item变量(0可能会升级成1或者2)
    //[0, 2, name, null, null]    loop index变量
    //[0, 3, name, path, detail]  函数, detail为参数列表
    //[1, 0, name, path, detail]  对象节点, detail为属性列表
    //[1, 1, name, path, detail]  升级为对象节点的loop item变量, detail为属性列表
    //[2, 0, name, path, detail]  数组节点, detail是item变量
    //[2, 1, name, path, detail]  升级为数组节点的loop item变量, detail是item变量
    

    function analyse_object(node, ast) {

        var item, any;

        //节点容错处理
        if ((item = ast.Class) && (item = rule[item]) && (any = ast.children) && any[0])
        {
            check_rule(item, ast, any);
        }

        for (var name in ast)
        {
            switch (name)
            {
                case 'Class':
                case 'children':
                case '#loop':
                    any = null;
                    break;

                default:
                    any = ast[name];
                    break;
            }

            if (any)
            {
                switch (name.charAt(0))
                {
                    case '#': //指令
                    case ':': //绑定
                        ast[name] = any.indexOf('(') > 0 ? analyse_function(node, any) : analyse_name(node, any, 0, 0);
                        break;

                    case '@': //事件
                        ast[name] = analyse_function(node, any);
                        break;
                }
            }
        }

        if (ast = ast.children)
        {
            any = 0;

            while (item = ast[any++])
            {
                (item['#loop'] ? analyse_loop : analyse_object)(node, item);
            }
        }
    };


    function analyse_loop(node, ast) {

        var keys = ast['#loop'].match(/[\w.-]+/g),
            loop,
            item,
            index,
            any;

        if (keys && (loop = keys[0]))
        {
            loop = analyse_name(node, loop, 2, 0);

            //第一个变量是item, 第二个变量是index
            //可以省略index, 但是不可以省略item
            if (item = keys[1])
            {
                check_loop(node, item);

                //在loop中记录item信息并添加进作用域
                any = loop[4] = node[loop.item = item] = [0, 1, item, null, null, 0];
                any.loop = loop;

                if (index = keys[2])
                {
                    check_loop(node, index);

                    //添加进作用域
                    node[loop.index = index] = loop[5] = [0, 2, index, null, null, 0];
                }
            }

            //在作用域范围内分析模板
            analyse_object(node, ast);

            if (item)
            {
                //标记超出作用域
                node[item] = 0;

                //如果item变量未使用则移除
                if (!any[0] && !any[5])
                {
                    loop.item = loop[4] = null;
                }

                if (index)
                {
                    //如果index变量未使用则移除
                    if (!node[index][5])
                    {
                        loop[5] = loop.index = null;
                    }

                    //标记超出作用域
                    node[index] = 0;
                }
            }
        }
        else
        {
            analyse_object(node, ast);
        }

        ast['#loop'] = loop;
    };


    function check_loop(node, name) {

        if (name.indexOf('.') >= 0)
        {
            throw 'loop "' + name + '" can not include "."!';
        }

        if (node[name])
        {
            throw 'loop "' + name + '" has be used!';
        }
    };


    function analyse_name(node, name, type, subtype) {

        var keys = name.match(/[\w-]+/g),
            list = null, //上级列表
            item;

        for (var i = 0, l = keys.length - 1; i < l; i++)
        {
            if (item = node[name = keys[i]])
            {
                switch (item[0])
                {
                    case 1: //对象
                        node = item[4];
                        break;

                    case 0: //数组item变量升级为对象,否则穿透抛出异常
                        item[0] = 1;
                        node = item[4] || (item[4] = {}); 
                        break;
                }
            }
            else if (item === 0)
            {
                throw '"' + name + '" is out of scope range!';
            }
            else
            {
                item = node[name] = [1, 0, name, list ? list.slice(0) : null, node = {}]; //创建新对象
            }

            if (list)
            {
                list.push(item);
            }
            else
            {
                list = [item];
            }
        }

        if (item = node[name = keys.pop()])
        {
            if (type)
            {
                if (item[0])
                {
                    throw '"' + name + '" has be used!';
                }

                item[0] = type;
            }
            else if (item[1])
            {
                item[5]++;
            }

            return item;
        }
        
        if (item === 0)
        {
            throw '"' + name + '" is out of scope range!';
        }

        return node[name] = [type, subtype, name, list, null];
    };


    function analyse_function(node, name) {

        var list = name.match(/[\w-.]+/g),
            args,
            item,
            index,
            any;

        if ((name = list[0]).indexOf('.') >= 0)
        {
            throw 'function "' + name + '" can not include "."!';
        }
        
        if ((item = node[name]) && item[1] !== 2)
        {
            throw 'function name "' + name + '" has be used!';
        }

        //函数支持重载,同一函数可传入不同的参数,所以每次分析都重新生成新节点
        item = node[name] = [0, 3, list[0], null, null];

        if (list[1])
        {
            args = [];
            index = 1;

            while (name = list[index++])
            {
                if (any = node[name])
                {
                    any[5]++; //标记变量被引用
                }
                else
                {
                    any = analyse_name(node, name, 0, 0);
                }

                args.push(any);
            }
            
            item[4] = args;
        }

        return item;
    };


    //检查标签规则,符合配置规则时替换标签以解决html不合法嵌套带来的dom结构混乱的问题
    function check_rule(rule, ast, children) {

        var check = rule[0],
            tag = rule[1] || check,
            flag = typeof check === 'string';
        
        for (var i = 0, l = children.length; i < l; i++)
        {
            if (flag ? children[i].Class !== check : !check.test(children[i].Class))
            {
                children[i] = { Class: tag, children: [children[i]] };
            }
        }
    };



    //默认html规则
    //参数1: string|Regex 替换条件 字符串表示是否与指定的类型相同
    //参数2: string       要替换成的类型 与第二项相同时可省略

    rule.table = [/tbody|thead|tfoot/, 'tbody'];

    rule.thead = rule.tbody = rule.tfoot = ['tr'];

    rule.tr = [/td|th/, 'td'];

    rule.ol = rule.ul = ['li'];

    rule.dl = ['dt'];

    rule.dt = ['dd'];

    rule.select = ['option'];


}, false);




//宿主容器
(function (flyingon, document) {
    
   
          
    /*

    W3C事件规范:

    A: 鼠标事件 mousedown -> mouseup -> click -> mousedown -> mouseup -> click -> dblclick
    注: IE8以下会忽略第二个mousedown和click事件

    1. mousedown 冒泡 鼠标按下时触发
    2. mousemove 冒泡 鼠标在元素内部移动时重复的触发
    3. mouseup 冒泡 释放鼠标按键时触发
    4. click 冒泡 单击鼠标按键或回车键时触发
    5. dblclick 冒泡 双击鼠标按键时触发
    6. mouseover 冒泡 鼠标移入一个元素(包含子元素)的内部时触发
    7. mouseout 冒泡 鼠标移入另一个元素(包含子元素)内部时触发
    8. mouseenter 不冒泡 鼠标移入一个元素(不包含子元素)内部时触发
    9. mouseleave 不冒泡 鼠标移入另一个元素(不包含子元素)内部时触发


    B: 键盘事件

    1. keydown 冒泡 按下键盘上的任意键时触发 如果按住不放会重复触发
    2. keypress 冒泡 按下键盘上的字符键时触发 如果按住不放会重复触发
    3. keyup 冒泡 释放键盘上的按键时触发


    C: 焦点事件

    1. focus 不冒泡 元素获得焦点时触发
    2. blur 不冒泡 元素失去焦点时触发
    3. focusin 冒泡 元素获得焦点时触发
    4. focusout 冒泡 元素失去焦点时触发

    */
   
    
    var MouseEvent = flyingon.MouseEvent;
        
    var KeyEvent = flyingon.KeyEvent;
    
    var on = flyingon.dom_on;
    
    //鼠标按下事件
    var mousedown = null;
    
    //调整大小参数
    var resizable = 0;
    
    //移动控件参数
    var movable = null;
    
    //默认拖动事件
    var ondragstart = null;

    //获取属性值
    var attr = document.getAttribute;
    



    //在指定dom容器显示控件
    flyingon.show = function (control, host) {

        if (typeof host === 'string')
        {
            host = document.getElementById(host);
        }
        
        if (!host)
        {
            throw 'can not find host!';
        }

        var width = host.clientWidth,
            height = host.clientHeight;

        //挂载之前处理挂起的ready队列
        flyingon.ready();
        flyingon.__update_patch();

        if (!control.__top_control)
        {
            control.__top_control = true;
            control.fullClassName += ' f-host';
        }

        host.appendChild(control.view || control.renderer.createView(control));
        control.renderer.__update_top(control, width, height);
    };


    //隐藏控件
    flyingon.hide = function (control, dispose) {

        if (control.__top_control)
        {
            var view = control.view,
                any;

            control.__top_control = false;

            if (view && (any = view.parentNode))
            {
                any.removeChild(view);
            }

            control.fullClassName = control.fullClassName.replace(' f-host', '');

            if (dispose !== false)
            {
                control.dispose();
            }
        }
    };

    
            
    //查找与指定dom关联的控件
    flyingon.findControl = function (dom) {
        
        var id;
        
        while (dom)
        {
            if (id = dom.flyingon_id)
            {
                return flyingon.__uniqueId[id];
            }
            
            dom = dom.parentNode;
        }
    };


        
    //通用鼠标事件处理
    function mouse_event(e) {
        
        var control = flyingon.findControl(e.target);
        
        if (control && !control.disabled())
        {
            control.trigger(new MouseEvent(e));
        }
    };
    
    
    //通用键盘事件处理
    function key_event(e) {
        
        var control = flyingon.findControl(e.target);
        
        if (control && !control.disabled())
        {
            control.trigger(new KeyEvent(e));
        }
    };
    
    
    //检查调整尺寸方向
    function check_resize(value, e) {
        
        var dom = this.view,
            rect = dom.getBoundingClientRect(),
            side = 0,
            cursor = '',
            x,
            y;
        
        if (value !== 'x')
        {
            x = e.clientY - rect.top;
            
            if (x >= 0 && x <= 4)
            {
                side = 1;
                cursor = 's';                
            }
            else
            {
                y = this.offsetHeight;
                
                if (x >= y - 4 && x <= y)
                {
                    side = 2;
                    cursor = 'n';
                }
            }
        }
        
        if (value !== 'y')
        {
            x = e.clientX - rect.left;
            
            if (x >= 0 && x <= 4)
            {
                side |= 4;
                cursor += 'e';
            }
            else
            {
                y = this.offsetWidth;
                
                if (x >= y - 4 && x <= y)
                {
                    side |= 8;
                    cursor += 'w';
                }
            }
        }

        if (cursor)
        {
            cursor += '-resize';
        }
        else if (value = this.__style)
        {
            cursor = value.cursor;
        }
        
        dom.style.cursor = cursor || '';
        
        return side;
    };
    
    
    function do_resize(data) {
        
        var side = data.side;
        
        if ((side & 1) === 1) //top
        {
            this.height(data.height - data.distanceY);
        }
        else if ((side & 2) === 2) //bottom
        {
            this.height(data.height + data.distanceY);
        }
        
        if ((side & 4) === 4) //left
        {
            this.width(data.width - data.distanceX);
        }
        else if ((side & 8) === 8) //right
        {
            this.width(data.width + data.distanceX);
        }

        clear_selection();
    };
    
    
    
    function move_start(e) {
        
        if (this.trigger('move-start') !== false)
        {
            var view = this.view,
                dom = view.cloneNode(true),
                style = view.style,
                rect = view.getBoundingClientRect(),
                data = { dom: dom, left: rect.left, top: rect.top },
                control = this,
                any;

            style.borderStyle = 'dashed';
            style.borderColor = 'red';

            style = dom.style;
            style.opacity = 0.2;
            style.left = rect.left + 'px';
            style.top = rect.top + 'px';

            document.body.appendChild(dom);

            //获取移动容器及偏移位置
            while (any = control.parent)
            {
                control = any;
            }

            rect = control.view.getBoundingClientRect();

            data.host = control;
            data.offsetX = e.clientX - rect.left;
            data.offsetY = e.clientY - rect.top;

            return data;
        }
    };
    
    
    function do_move(data, e) {
        
        var style = data.dom.style,
            x = data.distanceX,
            y = data.distanceY,
            list = data.host.findDropTarget(data.offsetX + x, data.offsetY + y),
            parent = list[0],
            item = list[1];

        if (item)
        {
            if (this !== item)
            {
                parent.splice(parent.indexOf(item), 0, item);
            }
        }
        else if (this.parent !== parent)
        {
        }
        
        style.left = data.left + x + 'px';
        style.top = data.top + y + 'px';
        
        this.trigger('move');
    };
    
    
    function move_end(data, e) {
        
        var dom = data.dom,
            style1 = dom.style,
            style2 = this.view.style,
            parent;

        if (parent = dom.parentNode)
        {
            parent.removeChild(dom);
        }

        style2.borderStyle = style1.borderStyle;
        style2.borderColor = style1.borderColor;
        
        this.trigger('move-end');
    };
    

    function clear_selection() {

        var fn = window.getSelection;

        if (fn)
        {
            fn.call(window).removeAllRanges();
        }
        else
        {
            document.selection.empty();
        }
    };
    

    on(document, 'mousedown', function (e) {
        
        var control = flyingon.findControl(e.target),
            parent,
            any;
        
        if (control && !control.disabled() && control.trigger(mousedown = new MouseEvent(e)) !== false)
        {
            if (any = resizable)
            {
                resizable = {
                 
                    side: any,
                    width: control.offsetWidth,
                    height: control.offsetHeight
                };
            }
            else if ((parent = control.parent) && (any = control.movable) && any.call(control))
            {
                any = movable = (control.__move_start || move_start).call(control, e);
            }
            
            // if (any && (any = control.view))
            // {
            //     any.setCapture && any.setCapture();
            //     any = document.body;

            //     flyingon.css_value(any, 'user-select', 'none');

            //     ondragstart = any.ondragstart;
                
            //     any.ondragstart = function () {
                  
            //         return false;
            //     };
            // }
        }

    });
    
    
    on(document, 'mousemove', function (e) {
        
        var start = mousedown,
            control,
            any;
        
        if (start && (control = start.target))
        {
            var x = e.clientX - start.clientX,
                y = e.clientY - start.clientY;
                
            if (any = resizable)
            {
                any.distanceX = x;
                any.distanceY = y;

                do_resize.call(control, any);
            }
            else if (any = movable)
            {
                any.distanceX = x;
                any.distanceY = y;
                
                (control.__do_move || do_move).call(control, any, e);
            }
            else
            {
                e = new MouseEvent(e);
                
                e.mousedown = start;
                e.distanceX = x;
                e.distanceY = y;
                
                control.trigger(e);
            }
        }
        else if ((control = flyingon.findControl(e.target)) && 
            !control.disabled() && control.trigger(new MouseEvent(e)) !== false &&
            (any = control.resizable) && any.call(control) !== 'none')
        {
            resizable = (control.__check_resize || check_resize).call(control, any, e);
        }
    });
    
    
    //按下鼠标时弹起处理
    on(document, 'mouseup', function (e) {
        
        var start = mousedown,
            control,
            any;
        
        if (start && (control = start.target))
        {
            if (any = resizable)
            {
                resizable = 0;
            }
            else if (any = movable)
            {
                (control.__move_end || move_end).call(control, any, e);
                movable = null;
            }

            e = new MouseEvent(e);

            e.mousedown = start;
            e.distanceX = e.clientX - start.clientX;
            e.distanceY = e.clientY - start.clientY;

            control.trigger(e);

            // if (any = control.view)
            // {
            //     any.setCapture && any.releaseCapture();
            //     any = document.body;
                
            //     flyingon.css_value(any, 'user-select', '');

            //     if (any.ondragstart = ondragstart)
            //     {
            //         ondragstart = null;
            //     }
            // }
            
            mousedown = null;
        }
        else if ((control = flyingon.findControl(e.target)) && !control.disabled())
        {
            control.trigger(new MouseEvent(e));
        }

    });
        
            
    on(document, 'click', mouse_event);
    
    
    on(document, 'dblclick', mouse_event);
    
    
    on(document, 'mouseover', mouse_event);
    
    
    on(document, 'mouseout', mouse_event);
    
    
    
    on(document, 'keydown', key_event);
    
    on(document, 'keypress', key_event);
    
    on(document, 'keyup', key_event);



    /* 各浏览器对focusin/focusout事件的支持区别

    	                                    IE6/7/8	    IE9/10	    Firefox5	Safari5	    Chrome12	Opera11
    e.onfocusin	                            Y	        Y	        N	        N	        N	        Y
    e.attachEvent('onfocusin',fn)	        Y	        Y	        N	        N	        N	        Y
    e.addEventListener('focusin',fn,false)	N	        Y	        N	        Y	        Y	        Y

    */

    //IE
    // if ('onfocusin' in document)
    // {
    //     on(document, 'focusin', focus);
    //     on(document, 'focusout', blur);
    // }
    // else //w3c标准使用捕获模式
    // {
    //     on(document, 'focus', focus, true);
    //     on(document, 'blur', blur, true);
    // }


    function focus(e) {

        if (focus.__disabled)
        {
            return true;
        }

        var control = flyingon.findControl(e.target);

        if (control && control.canFocus && !control.disabled() && control.canFocus() && 
            control.trigger('focus') !== false)
        {
            control.focus();
            flyingon.activeControl = control;
        }
        else if (control = flyingon.activeControl)
        {
            try
            {
                focus.__disabled = true;
                control.renderer.focus(control);
            }
            finally
            {
                focus.__disabled = false;
            }
        }
    };


    function blur(e) {

        var control = flyingon.findControl(e.target);

        if (control && control === flyingon.activeControl && control.trigger('blur') !== false)
        {
            control.blur();
            flyingon.activeControl = null;
        }
    };



    //滚事件不冒泡,每个控件自己绑定
    flyingon.__dom_scroll = function (event) {
      
        var control = flyingon.findControl(this);

        if (control && !control.disabled())
        {
            if (control.trigger('scroll') !== false)
            {
                control.__do_scroll(control.scrollLeft = this.scrollLeft, control.scrollTop = this.scrollTop);
            }
            else
            {
                try
                {
                    this.onscroll = null;
                    this.scrollTop = control.scrollTop;
                    this.scrollLeft = control.scrollLeft;
                }
                finally
                {
                    this.onscroll = scroll;
                }
            }
        }
    };


    
    //滚轮事件兼容处理firefox和其它浏览器不一样
    on(document, document.mozHidden ? 'DOMMouseScroll' : 'mousewheel', function (e) {

        var control = flyingon.findControl(e.target);

        if (control && !control.disabled())
        {
            //firefox向下滚动是3 其它浏览器向下滚动是-120 此处统一转成-120
            control.trigger('mousewheel', 'original_event', e, 'wheelDelta', e.wheelDelta || -e.detail * 40 || -120);
        }
    });



    
})(flyingon, document);




flyingon.renderer('Highlight', function (base) {


    var styles = flyingon.create(null),
        cache;


    this.render = function (writer, control, className, cssText) {
        
        writer.push('<div');
        
        this.renderDefault(writer, control, className, (cssText || '') + 'overflow:auto');
        
        writer.push('><pre style="margin:0;width:auto;height:auto;"><code style="overflow:visible;"></code></pre></div>');
    };



    this.theme = function (control, view, value) {

        if (!styles[value])
        {
            flyingon.link(flyingon.require.path('flyingon/third/highlight/styles/' + value + '.css'));
        }
    };


    this.code = function (control, view, value) {

        var hljs = window.hljs,
            any;

        if (hljs)
        {
            view = view.firstChild.firstChild;
            view.className = control.language();
            view[this.__text_name] = value;

            try
            {
                hljs.highlightBlock(view); //不支持IE8以下浏览器
            }
            catch (e)
            {
            }
        }
        else if (any = cache)
        {
            any.push(control);
        }
        else
        {
            cache = [control];

            this.theme(control, view, control.theme());
            flyingon.script(flyingon.require.path('flyingon/third/highlight/highlight.js'), init);
        }
    };
        

    function init() {
        
        var list = cache,
            index = 0,
            control;

        while (control = list[index++])
        {
            control.renderer.code(control, control.view, control.code());
        }

        cache = null;
    };

        
});



flyingon.Control.extend('Highlight', function (base) {


    this.defaultWidth = 400;

    this.defaultHeight = 200;


    //当前语言
    this.defineProperty('language', 'javascript', {
        
        set: function (value) {

            this.rendered && this.renderer.set(this, 'code', this.code());
        }
    });


    //当前主题
    this.defineProperty('theme', 'vs', {
     
        set: function (value) {

            this.rendered && this.renderer.set(this, 'theme', value);
        }
    });


    //代码内容
    this.defineProperty('code', '', {
        
        set: function (value) {

            this.renderer.set(this, 'code', value);
        }
    });


}).register();