Source: common/Layouter.js

/**
 * Created by seeker910 on 13-12-31.
 */
/*
 layouter 所用到的数据全部来自对象本身属性,不是dom对象数据。
 * */
Rsd.define("Rsd.common.Layouter", {
    extend:'Rsd.common.Object',
    singleton:true,
    xtype: 'layouter',
    constructor: function Layouter () {

    },
    /**
     * @description 处理 dom对象
     * @description 设置位置相关属性:width、height、margin...以及自定义style,display=none 不参与布局
     * */
    layout: function layout(obj) {

        //监控 layout 执行次数
        //console.trace('in layouter',obj.id,obj.width);

        if (Rsd.isCreated(obj) == false) {
            return;
        }

        if (obj.isHidden()) {
            return;
        }

        if (obj.dom == null) {
            return;
        }
        var _sizeUnit = obj.sizeUnit||'px';
        //sytle样式 在属性中控制 布局后的 样式发生改变
        var _element = obj.style.element;
        if(obj.style.element)
        {
            delete obj.style.element;
        }
        
        obj.setElStyle(_element||obj.dom,obj.style,_sizeUnit);
        if(_element)
        {
            obj.style.element = _element;
        }

        //设置 高度 宽度 属性,单独控制
        var _domStyle = {};
        if (!Rsd.isUndefined(obj.width)) {
            _domStyle.width = obj.width;
        }

        if (!Rsd.isUndefined(obj.height) ) {
            _domStyle.height = obj.height;
        }
        if (!Rsd.isUndefined(obj.flex) ) {
            _domStyle.flex = obj.flex;
        }
        obj.setElStyle(obj.dom,_domStyle,_sizeUnit);

        var _names = ['top', 'right', 'bottom', 'left'];
        var _margin = obj.margin;
        obj.margin ={ top: 0, right: 0, bottom: 0, left: 0 };

        if (_margin) {

            var _ms;
            if (Rsd.getType(_margin) == '[object String]') {
                _ms = _margin.split(' ');
                 
                for (var i in _ms) {
                    if ( Rsd.isNumber(Number(_ms[i]))) {
                        obj.margin[_names[i]] = _ms[i] + _sizeUnit;
                    }
                    else {
                        obj.margin[_names[i]] = _ms[i];
                    }
                }
            }
            if (Rsd.getType(_margin) == '[object Array]') {
                _ms = _margin;

                for (var i in _ms) {
                    if ( Rsd.isNumber(Number(_ms[i]))) {
                        obj.margin[_names[i]] = _ms[i] + _sizeUnit;
                    }
                    else {
                        obj.margin[_names[i]] = _ms[i];
                    }
                }
            }
            if (Rsd.getType(_margin) == '[object Object]') {
                _ms = _margin;
                for (var i in _ms) {
                    if (Rsd.isNumber(Number(_ms[i]))) {
                        obj.margin[i] = _ms[i] + _sizeUnit;
                    }
                    else {
                        obj.margin[i] = _ms[i];
                    }
                }
            }
        }

        obj.dom.style.marginTop = obj.margin.top;
        obj.dom.style.marginRight = obj.margin.right;
        obj.dom.style.marginBottom = obj.margin.bottom;
        obj.dom.style.marginLeft = obj.margin.left;

        //debugger;
        var me = this;  
        setTimeout(function () {
            me.layoutContent(obj.header || obj.label, obj.body || obj.ctrl,obj.sizeUnit);
            if(obj.__blockOpacity !==true)
            {
                obj.dom.style.opacity = null;//不能在 show 方法中设置该值,不是所有的控件都会调用 show方法
            }
            
        },0);

    },
    /**
     *  
     *  @description 布局子控件 ,layoutBorder,layoutVbox,layoutHbox,layoutFit,layoutAuto
     * */
    layoutItems:function layoutItems(obj){
        //debugger;
        if (obj.items && Rsd.getType(obj.items) == '[object Array]' && obj.items.length > 0) {

            switch (obj.layout.type.toLowerCase()) {
                case 'border':
                    this.layoutBorder(obj);
                    break;
                case 'vbox':
                    this.layoutVbox(obj);
                    break;
                case 'hbox':
                    this.layoutHbox(obj);
                    break;
                case 'fit':
                    this.layoutFit(obj);
                    break;
                    case 'auto':
                    this.layoutAuto(obj);
                    break;
                default:
                    throw new Error('Object id\'s [' + obj.id+ '] layout value is unknown value [' + obj.layout.type + '] in class ' + obj.$className + '.');
                    break;
            }

        }
    },
    /**
     * 边框布局:以上下左右为起点布局控件
     * 容器:高度和宽度固定
     * 子控件:高度固定,宽度固定 
     * region:top,bottom,left,right,center
     * */
    layoutBorder:function layoutBorder(obj){
        //debugger;
        if(obj.layout.type != 'border')
        {
            return;
        }
        obj.addCls('body','x-layout-border');
        var _item;
        var _i_margins = [0, 0, 0, 0];
        var _sizeUnit = obj.sizeUnit||'px';
        for (var i=0; i< obj.items.length ;i++) {
            _item = obj.items[i]; 
            if(!_item)
            {
                throw new Error('items['+i+'] is null in object '+ obj.id + '.');
            }
            if(!Rsd.isObject(_item))
            {
                throw new Error('items['+i+'] is not a object in object '+ obj.id + '.');
            }
            if(!(_item instanceof  Rsd.common.ComponentX))
            {
                continue;
            }
            if(_item.floating || _item.fixed)
            {
                continue;
            }

            switch (_item.region) {
                case 'top':
                case 'north':
                    _item.addCls('dom','x-layout-border-north');
                    var _position = {};
                    _position.top = _i_margins[0] + _sizeUnit;
                    _position.right = _i_margins[1] + _sizeUnit;
                    _position.bottom = null;
                    _position.left = _i_margins[3] + _sizeUnit;
                    _item.setPosition(_position);
                    if (!_item.height) {
                        continue;
                    }

                    if (typeof (_item.height) == 'string' && parseInt(_item.height)) {
                        _i_margins[0] += parseInt(_item.height);
                    }else
                    {
                        _i_margins[0] += _item.height;
                    }
                    break;
                case 'right':
                case 'east':
                    _item.addCls('dom','x-layout-border-east');
                    var _position = {};
                    _position.top = _i_margins[0] + _sizeUnit;
                    _position.right = _i_margins[1] + _sizeUnit;
                    _position.bottom = _i_margins[2] + _sizeUnit;
                    _position.left = null;
                    _item.setPosition(_position);
                    if (!_item.width) {
                        continue;
                    }

                    if (typeof (_item.width) == 'string' && parseInt(_item.width)) {
                        _i_margins[1] += parseInt(_item.width);
                    }else {
                        _i_margins[1] += _item.width;
                    }

                    break;
                case 'bottom':
                case 'south':
                    _item.addCls('dom','x-layout-border-south');
                    var _position = {};
                    _position.top = null;
                    _position.right = _i_margins[1] + _sizeUnit;
                    _position.bottom = _i_margins[2] + _sizeUnit;
                    _position.left = _i_margins[3] + _sizeUnit;
                    _item.setPosition(_position);
                    if (!_item.height) {
                        continue;
                    }

                    if (typeof (_item.height) == 'string' && parseInt(_item.height))
                     {
                        _i_margins[2] +=  parseInt(_item.height);
                    }
                    else 
                    {
                        _i_margins[2] += _item.height;
                    }

                    break;
                case 'left':
                case 'west':
                    _item.addCls('dom','x-layout-border-west');
                    var _position = {};
                    _position.top = _i_margins[0]+ _sizeUnit;
                    _position.right = null;
                    _position.bottom = _i_margins[2]+ _sizeUnit;
                    _position.left = _i_margins[3]+ _sizeUnit;
                    _item.setPosition(_position);
                    if (!_item.width) {
                        continue;
                    }

                    if (typeof (_item.width) == 'string' && parseInt(_item.width)) {
                        _i_margins[3] += parseInt(_item.width);
                    }
                    else
                    {
                        _i_margins[3] += _item.width;
                    }

                    break;
                case 'center':
                    _item.width = 'auto';
                    _item.height = 'auto';
                    break;
                default:
                    throw new Error('Property region(top/north,right/east,bottom/south,left/west,center) of component['+ _item.$className +'] is unknown value ['+_item.region+'] in '+ obj.$className +'.');
                    break;
            }


        }

        for (var i=0; i< obj.items.length ;i++) {
            _item = obj.items[i];
            if(!(_item instanceof  Rsd.common.ComponentX))
            {
                continue;
            }
            if(_item.floating || _item.fixed)
            {
                continue;
            }
            switch (_item.region) {
                case 'center':
                    _item.width = null;
                    _item.height = null;
                    _item.addCls('dom','x-layout-border-center');
                    var _position = {};
                    _position.top = _i_margins[0] + _sizeUnit;
                    _position.right = _i_margins[1] + _sizeUnit;
                    _position.bottom = _i_margins[2] + _sizeUnit;
                    _position.left = _i_margins[3] + _sizeUnit;

                    _item.setPosition(_position);

                    if(_i_margins[0]==0 && _i_margins[2]==0)
                    {
                        //_item.height = '100%';
                    }

                    if(_i_margins[1]==0 && _i_margins[3]==0) {

                        //_item.width = '100%';
                    }
                    break;
                default:
                    break;
            }
        }

    },
    /**
     * 流式布局:单列多行
     * 容器:高度和宽度固定,
     * 子控件:高度不固,宽度固定 
     * display:flex ,flex-direction:column; 一列多行布局
     * */
    layoutVbox:function layoutVbox(obj){

        if(obj.layout.type != 'vbox')
        {
            return;
        }
        switch (obj.layout.align)
        {
            case 'left':
                obj.addCls('body','x-layout-vbox-left');
                break;
            case 'right':
                obj.addCls('body','x-layout-vbox-right');
                break;
            case 'top':
                obj.addCls('body','x-layout-vbox-top');
                break;
            case 'bottom':
                obj.addCls('body','x-layout-vbox-bottom');
                break;
            case 'center':
                obj.addCls('body','x-layout-vbox-center');
                break;
            default :
                throw new Error('Property align of layout is unknown value ['+_item.align || obj.layout.align+'].');
                break;
        }
    },
    /**
     * 流式布局:单行多列
     * 容器:高度和宽度固定,
     * 子控件:高度固定,宽度不固定 
     * display:flex ,flex-direction:row; 一行多列布局
     * */
    layoutHbox:function layoutHbox(obj){
        if(obj.layout.type != 'hbox')
        {
            return;
        }
        switch (obj.layout.align)
        {
                case 'left':
                    obj.addCls('body','x-layout-hbox-left');
                    break;
                case 'right':
                    obj.addCls('body','x-layout-hbox-right');
                    break;
                case  'top':
                    obj.addCls('body','x-layout-hbox-top');
                case 'bottom':
                    obj.addCls('body','x-layout-hbox-bottom');
                    break;
                case 'center':
                    obj.addCls('body','x-layout-hbox-center');
                    break;
                default :
                    throw new Error('Property align(left,right,top,bottom,center) of layout is unknown value ['+_item.align || obj.layout.align+'].');
                    break;
        }
        
    },
    /***
     * 自适应布局:只有一个子控件,子控件填满整个父控件,随父控件大小变化而变化。
     * 如果有多个控件,只显示第一个子控件
     */
    layoutFit:function layoutFit(obj)
    {
        if(obj.layout.type != 'fit')
        {
            return;
        } 
        obj.addCls('body','x-layout-fit');
        
        var _align = obj.layout.align;
        var  _item; 
        for (var i=0; i< obj.items.length ;i++) {
            _item = obj.items[i];
            if(_item.floating || _item.fixed)
            {
                continue;
            } 
            switch (_align)
            {
                case 'center':
                    _item.addCls('dom','x-layout-fit-center');
                    break;
                case 'left':
                    _item.addCls('dom','x-layout-fit-left');
                    break;
                case 'right':
                    _item.addCls('dom','x-layout-fit-right');
                    break;
                case  'top':
                    _item.addCls('dom','x-layout-fit-top');
                    break;
                case  'bottom':
                    _item.addCls('dom','x-layout-fit-bottom');
                    break;
                default :
                    throw new Error('Property align of layout is unknown value ['+_align+'].');
                    break;
            }  
        } 

    },
    /** 
     * 流式布局:多行多列  
     * 容器:高度和宽度固定,
     * 子控件:高度不固定,宽度不固定
     * 
     * */
    layoutAuto:function layoutAuto(obj){
        if(obj.layout.type != 'auto')
        {
            return;
        } 
        obj.addCls('body','x-layout-auto');
        
        var _align = obj.layout.align;
        var  _item;
        for (var i=0; i< obj.items.length ;i++) {
            _item = obj.items[i];
            if(_item.floating || _item.fixed)
            {
                continue;
            }
           
            switch (_align)
            {
                case 'center':
                    _item.addCls('dom','x-layout-auto-center');
                    break;
                case 'left':
                    _item.addCls('dom','x-layout-auto-left');
                    break;
                case 'right':
                    _item.addCls('dom','x-layout-auto-right');
                    break;
                case  'top':
                    _item.addCls('dom','x-layout-auto-top');
                    break;
                case  'bottom':
                    _item.addCls('dom','x-layout-auto-bottom');
                    break;
                default :
                    throw new Error('Property align of layout is unknown value ['+_align+'].');
                    break;
            } 
        }
    },

    /** 
     * @description 布局 header(label),body(ctrl)
     * */ 
    layoutContent: function layoutContent(header,body,sizeUnit) {

         
        var _h_element = header && header.element;
        var _body_element = body && body.element;
    
        var _position = header && header.position||'top';
        var _space =  parseInt(header && header.space)||0;

        var _sizeUnit = sizeUnit||'px';
        //在存在 label 或 header 时 ,设置body ,ctrl 样式
        if(_body_element && _h_element)
        {
            _body_element.style.flexGrow = 1;
            _body_element.style.flexShrink = 1;
            _body_element.style.flexBasis ='0%';
                
            //调整间隔
            switch (_position.toLowerCase()) {
                case 'top':
                    {
                        //_body_element.style.alignSelf = 'center';
                        _body_element.style.marginTop =  _space + 'px' ;
                    } 
                    break;
                case 'bottom':
                    {
                        //_body_element.style.alignSelf = 'center';
                        _body_element.style.marginBottom =  _space + 'px' ;
                    } 
                    break;
                case 'left':
                    { 
                        _body_element.style.alignSelf = 'center';
                        _body_element.style.marginLeft =  _space+ 'px';
                    }
                        break;
                case 'right':
                    {
                        _body_element.style.alignSelf = 'center';
                        _body_element.style.marginRight =  _space + 'px' ;
                    }
                    break
                default:
                    throw new Error('Property position of header or label is unknown value ['+header.position+'].');
                     
            }
            
        } 
        //设置  label 或 header 样式
        if (_h_element) {

            var _h_style =  header.style || {};
            Rsd.setElStyle(_h_element,_h_style,_sizeUnit);
 
            switch (_position.toLowerCase()) {
                case 'top':
                    {
                        _h_element.style.width = '100%';
                        _h_element.style.textAlign = header.align || 'center';
                        _h_element.style.height = header.height == null ? 'auto' :(Rsd.isNumber(Number(header.height))?(header.height + _sizeUnit):header.height);
                       
                    } 
                    break;
                case 'bottom':
                    {
                        _h_element.style.width = '100%';
                        _h_element.style.textAlign = header.align || 'center';
                        _h_element.style.height = header.height == null ? 'auto' :(Rsd.isNumber(Number(header.height)) ? ( header.height + _sizeUnit):header.height);
                   
                    } 
                    break;
                case 'left':
                    { 
                        _h_element.style.textAlign = header.align || 'right';
                        _h_element.style.height = '100%';
                        _h_element.style.width = header.width == null ? 'auto' : ( Rsd.isNumber(Number(header.width)) ? ( header.width + _sizeUnit):header.width);
                  
                    }
                    break;
                case 'right':
                    {
                        //debugger; 
                        _h_element.style.textAlign = header.align || 'left';  
                        _h_element.style.height = '100%';
                        _h_element.style.width = header.width == null ? 'auto' : (Rsd.isNumber(Number(header.width)) ? ( header.width + _sizeUnit):header.width);
                
                    }
                    break
                default:
                    throw new Error('Property position of header or label is unknown value ['+header.position+'].');
                    break;
            }

            //行高处理
            if(header.lineHeight)
            {
                _h_element.style.lineHeight = header.lineHeight  + _sizeUnit;
            }
            else
            {
                _h_element.style.lineHeight = _h_element.clientHeight?(_h_element.clientHeight + _sizeUnit):'unset';
                
            }

            if(header.content instanceof  Rsd.common.ComponentX)
            {
                header.content.doLayout(); 
            }
        }

        if(body && body.style)
        {
            Rsd.setElStyle(_body_element,body.style,_sizeUnit);
        }
       

    }
});