Yahoo! UI Library

layout  2.5.2

Yahoo! UI Library > layout > layoutunit.js (source view)

Show Private Show Protected
/**
 * @description <p>Provides a fixed position unit containing a header, body and footer for use with a YAHOO.widget.Layout instance.</p>
 * @namespace YAHOO.widget
 * @requires yahoo, dom, element, event, layout
 * @optional animation, dragdrop, selector
 * @beta
 */
(function() {
    var Dom = YAHOO.util.Dom,
        Sel = YAHOO.util.Selector,
        Event = YAHOO.util.Event,
        Lang = YAHOO.lang;

    /**
     * @constructor
     * @class LayoutUnit
     * @extends YAHOO.util.Element
     * @description <p>Provides a fixed position unit containing a header, body and footer for use with a YAHOO.widget.Layout instance.</p>
     * @param {String/HTMLElement} el The element to make a unit.
     * @param {Object} attrs Object liternal containing configuration parameters.
    */

    var LayoutUnit = function(el, config) {
        
        var oConfig = {
            element: el,
            attributes: config || {}
        };

        LayoutUnit.superclass.constructor.call(this, oConfig.element, oConfig.attributes);    
    };

    /**
    * @private
    * @static
    * @property _instances
    * @description Internal hash table for all layout unit instances
    * @type Object
    */ 
    LayoutUnit._instances = {};
    /**
    * @static
    * @method getLayoutUnitById 
    * @description Get's a layout unit object by the HTML id of the element associated with the Layout Unit object.
    * @return {Object} The Layout Object
    */ 
    LayoutUnit.getLayoutUnitById = function(id) {
        if (LayoutUnit._instances[id]) {
            return LayoutUnit._instances[id];
        }
        return false;
    };

    YAHOO.extend(LayoutUnit, YAHOO.util.Element, {
        /**
        * @property STR_CLOSE
        * @description String used for close button title
        * @type {String}
        */
        STR_CLOSE: 'Click to close this pane.',
        /**
        * @property STR_COLLAPSE
        * @description String used for collapse button title
        * @type {String}
        */
        STR_COLLAPSE: 'Click to collapse this pane.',
        /**
        * @property STR_EXPAND
        * @description String used for expand button title
        * @type {String}
        */
        STR_EXPAND: 'Click to expand this pane.',
        /**
        * @property browser
        * @description A modified version of the YAHOO.env.ua object
        * @type Object
        */
        browser: null,
        /**
        * @private
        * @property _sizes
        * @description A collection of the current sizes of the contents of this Layout Unit
        * @type Object
        */
        _sizes: null,
        /**
        * @private
        * @property _anim
        * @description A reference to the Animation instance used by this LayouUnit
        * @type YAHOO.util.Anim
        */
        _anim: null,
        /**
        * @private
        * @property _resize
        * @description A reference to the Resize instance used by this LayoutUnit
        * @type YAHOO.util.Resize
        */
        _resize: null,
        /**
        * @private
        * @property _clip
        * @description A reference to the clip element used when collapsing the unit
        * @type HTMLElement
        */
        _clip: null,
        /**
        * @private
        * @property _gutter
        * @description A simple hash table used to store the gutter to apply to the Unit
        * @type Object
        */
        _gutter: null,
        /**
        * @property header
        * @description A reference to the HTML element used for the Header
        * @type HTMLELement
        */
        header: null,
        /**
        * @property body
        * @description A reference to the HTML element used for the body
        * @type HTMLElement
        */
        body: null,
        /**
        * @property footer
        * @description A reference to the HTML element used for the footer
        * @type HTMLElement
        */
        footer: null,
        /**
        * @private
        * @property _collapsed
        * @description Flag to determine if the unit is collapsed or not.
        * @type Boolean
        */
        _collapsed: null,
        /**
        * @private
        * @property _collapsing
        * @description A flag set while the unit is being collapsed, used so we don't fire events while animating the size
        * @type Boolean
        */
        _collapsing: null,
        /**
        * @private
        * @property _lastWidth
        * @description A holder for the last known width of the unit
        * @type Number
        */
        _lastWidth: null,
        /**
        * @private
        * @property _lastHeight
        * @description A holder for the last known height of the unit
        * @type Number
        */
        _lastHeight: null,
        /**
        * @private
        * @property _lastTop
        * @description A holder for the last known top of the unit
        * @type Number
        */
        _lastTop: null,
        /**
        * @private
        * @property _lastLeft
        * @description A holder for the last known left of the unit
        * @type Number
        */
        _lastLeft: null,
        /**
        * @private
        * @property _lastScroll
        * @description A holder for the last known scroll state of the unit
        * @type Boolean
        */
        _lastScroll: null,
        /**
        * @private
        * @property _lastCenetrScroll
        * @description A holder for the last known scroll state of the center unit
        * @type Boolean
        */
        _lastCenterScroll: null,
        /**
        * @private
        * @property _lastScrollTop
        * @description A holder for the last known scrollTop state of the unit
        * @type Number
        */
        _lastScrollTop: null,
        /**
        * @method resize
        * @description Resize either the unit or it's clipped state, also updating the box inside
        * @param {Boolean} force This will force full calculations even when the unit is collapsed
        * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
        */
        resize: function(force) {
            YAHOO.log('Resize', 'info', 'LayoutUnit');
            var retVal = this.fireEvent('beforeResize');
            if (retVal === false) {
                return this;
            }
            if (!this._collapsing || (force === true)) {
                var scroll = this.get('scroll');
                this.set('scroll', false);


                var hd = this._getBoxSize(this.header),
                    ft = this._getBoxSize(this.footer),
                    box = [this.get('height'), this.get('width')];


                var nh = (box[0] - hd[0] - ft[0]) - (this._gutter.top + this._gutter.bottom),
                    nw = box[1] - (this._gutter.left + this._gutter.right);

                var wrapH = (nh + (hd[0] + ft[0])),
                    wrapW = nw;

                if (this._collapsed && !this._collapsing) {
                    this._setHeight(this._clip, wrapH);
                    this._setWidth(this._clip, wrapW);
                    Dom.setStyle(this._clip, 'top', this.get('top') + this._gutter.top + 'px');
                    Dom.setStyle(this._clip, 'left', this.get('left') + this._gutter.left + 'px');
                } else if (!this._collapsed || (this._collapsed && this._collapsing)) {
                    wrapH = this._setHeight(this.get('wrap'), wrapH);
                    wrapW = this._setWidth(this.get('wrap'), wrapW);
                    this._sizes.wrap.h = wrapH;
                    this._sizes.wrap.w = wrapW;

                    Dom.setStyle(this.get('wrap'), 'top', this._gutter.top + 'px');
                    Dom.setStyle(this.get('wrap'), 'left', this._gutter.left + 'px');

                    this._sizes.header.w = this._setWidth(this.header, wrapW);
                    this._sizes.header.h = hd[0];

                    this._sizes.footer.w = this._setWidth(this.footer, wrapW);
                    this._sizes.footer.h = ft[0];

                    Dom.setStyle(this.footer, 'bottom', '0px');

                    this._sizes.body.h = this._setHeight(this.body, (wrapH - (hd[0] + ft[0])));
                    this._sizes.body.w =this._setWidth(this.body, wrapW);
                    Dom.setStyle(this.body, 'top', hd[0] + 'px');

                    this.set('scroll', scroll);
                    this.fireEvent('resize');
                }
            }
            return this;
        },
        /**
        * @private
        * @method _setWidth
        * @description Sets the width of the element based on the border size of the element.
        * @param {HTMLElement} el The HTMLElement to have it's width set
        * @param {Number} w The width that you want it the element set to
        * @return {Number} The new width, fixed for borders and IE QuirksMode
        */
        _setWidth: function(el, w) {
            if (el) {
                var b = this._getBorderSizes(el);
                w = (w - (b[1] + b[3]));
                w = this._fixQuirks(el, w, 'w');
                Dom.setStyle(el, 'width', w + 'px');
            }
            return w;
        },
        /**
        * @private
        * @method _setHeight
        * @description Sets the height of the element based on the border size of the element.
        * @param {HTMLElement} el The HTMLElement to have it's height set
        * @param {Number} h The height that you want it the element set to
        * @return {Number} The new height, fixed for borders and IE QuirksMode
        */
        _setHeight: function(el, h) {
            if (el) {
                var b = this._getBorderSizes(el);
                h = (h - (b[0] + b[2]));
                h = this._fixQuirks(el, h, 'h');
                Dom.setStyle(el, 'height', h + 'px');
            }
            return h;
        },
        /**
        * @private
        * @method _fixQuirks
        * @description Fixes the box calculations for IE in QuirksMode
        * @param {HTMLElement} el The HTMLElement to set the dimension on
        * @param {Number} dim The number of the dimension to fix
        * @param {String} side The dimension (h or w) to fix. Defaults to h
        * @return {Number} The fixed dimension
        */
        _fixQuirks: function(el, dim, side) {
            var i1 = 0, i2 = 2;
            if (side == 'w') {
                i1 = 1;
                i2 = 3;
            }
            if (this.browser.ie && !this.browser.standardsMode) {
                //Internet Explorer - Quirks Mode
                var b = this._getBorderSizes(el),
                    bp = this._getBorderSizes(el.parentNode);
                if ((b[i1] === 0) && (b[i2] === 0)) { //No Borders, check parent
                    if ((bp[i1] !== 0) && (bp[i2] !== 0)) { //Parent has Borders
                        dim = (dim - (bp[i1] + bp[i2]));
                    }
                } else {
                    if ((bp[i1] === 0) && (bp[i2] === 0)) {
                        dim = (dim + (b[i1] + b[i2]));
                    }
                }
            }
            return dim;
        },
        /**
        * @private
        * @method _getBoxSize
        * @description Get's the elements clientHeight and clientWidth plus the size of the borders
        * @param {HTMLElement} el The HTMLElement to get the size of
        * @return {Array} An array of height and width
        */
        _getBoxSize: function(el) {
            var size = [0, 0];
            if (el) {
                if (this.browser.ie && !this.browser.standardsMode) {
                    el.style.zoom = 1;
                }
                var b = this._getBorderSizes(el);
                size[0] = el.clientHeight + (b[0] + b[2]);
                size[1] = el.clientWidth + (b[1] + b[3]);
            }
            return size;
        },
        /**
        * @private
        * @method _getBorderSizes
        * @description Get the CSS border size of the element passed.
        * @param {HTMLElement} el The element to get the border size of
        * @return {Array} An array of the top, right, bottom, left borders.
        */
        _getBorderSizes: function(el) {
            var s = [];
            el = el || this.get('element');
            if (this.browser.ie && !this.browser.standardsMode) {
                el.style.zoom = 1;
            }
            s[0] = parseInt(Dom.getStyle(el, 'borderTopWidth'), 10);
            s[1] = parseInt(Dom.getStyle(el, 'borderRightWidth'), 10);
            s[2] = parseInt(Dom.getStyle(el, 'borderBottomWidth'), 10);
            s[3] = parseInt(Dom.getStyle(el, 'borderLeftWidth'), 10);
            
            //IE will return NaN on these if they are set to auto, we'll set them to 0
            for (var i = 0; i < s.length; i++) {
                if (isNaN(s[i])) {
                    s[i] = 0;
                }
            }
            return s;
        },
        /**
        * @private
        * @method _createClip
        * @description Create the clip element used when the Unit is collapsed
        */
        _createClip: function() {
            if (!this._clip) {
                this._clip = document.createElement('div');
                this._clip.className = 'yui-layout-clip yui-layout-clip-' + this.get('position');
                this._clip.innerHTML = '<div class="collapse"></div>';
                var c = this._clip.firstChild;
                c.title = this.STR_EXPAND;
                Event.on(c, 'click', this.expand, this, true);
                this.get('element').parentNode.appendChild(this._clip);
            }
        },
        /**
        * @private
        * @method _toggleClip
        * @description Toggle th current state of the Clip element and set it's height, width and position
        */
        _toggleClip: function() {
            if (!this._collapsed) {
                //show
                var hd = this._getBoxSize(this.header),
                    ft = this._getBoxSize(this.footer),
                    box = [this.get('height'), this.get('width')];


                var nh = (box[0] - hd[0] - ft[0]) - (this._gutter.top + this._gutter.bottom),
                    nw = box[1] - (this._gutter.left + this._gutter.right),
                    wrapH = (nh + (hd[0] + ft[0]));

                switch (this.get('position')) {
                    case 'top':
                    case 'bottom':
                        this._setWidth(this._clip, nw);
                        this._setHeight(this._clip, this.get('collapseSize'));
                        Dom.setStyle(this._clip, 'left', (this._lastLeft + this._gutter.left) + 'px');
                        if (this.get('position') == 'bottom') {
                            Dom.setStyle(this._clip, 'top', ((this._lastTop + this._lastHeight) - (this.get('collapseSize') - this._gutter.top)) + 'px');
                        } else {
                            Dom.setStyle(this._clip, 'top', this.get('top') + this._gutter.top + 'px');
                        }
                        break;
                    case 'left':
                    case 'right':
                        this._setWidth(this._clip, this.get('collapseSize'));
                        this._setHeight(this._clip, wrapH);
                        Dom.setStyle(this._clip, 'top', (this.get('top') + this._gutter.top) + 'px');
                        if (this.get('position') == 'right') {
                            Dom.setStyle(this._clip, 'left', (((this._lastLeft + this._lastWidth) - this.get('collapseSize')) - this._gutter.left) + 'px');
                        } else {
                            Dom.setStyle(this._clip, 'left', (this.get('left') + this._gutter.left) + 'px');
                        }
                        break;
                }

                Dom.setStyle(this._clip, 'display', 'block');
                this.setStyle('display', 'none');
            } else {
                //Hide
                Dom.setStyle(this._clip, 'display', 'none');
            }
        },
        /**
        * @method getSizes
        * @description Get a reference to the internal sizes object for this unit
        * @return {Object} An object of the sizes used for calculations
        */
        getSizes: function() {
            return this._sizes;
        },
        /**
        * @method toggle
        * @description Toggles the Unit, replacing it with a clipped version.
        * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
        */
        toggle: function() {
            if (this._collapsed) {
                this.expand();
            } else {
                this.collapse();
            }
            return this;
        },
        /**
        * @method expand
        * @description Expand the Unit if it is collapsed.
        * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
        */
        expand: function() {
            if (!this._collapsed) {
                return this;
            }
            var retVal = this.fireEvent('beforeExpand');
            if (retVal === false) {
                return this;
            }

            this._collapsing = true;
            this.setStyle('zIndex', this.get('parent')._zIndex + 1);

            if (this._anim) {
                this.setStyle('display', 'none');
                //Animation Fails Here
                var attr = {}, s;

                switch (this.get('position')) {
                    case 'left':
                    case 'right':
                        this.set('width', this._lastWidth, true);
                        this.setStyle('width', this._lastWidth + 'px');
                        this.get('parent').resize(false);
                        s = this.get('parent').getSizes()[this.get('position')];
                        this.set('height', s.h, true);
                        var left = s.l;
                        attr = {
                            left: {
                                to: left
                            }
                        };
                        if (this.get('position') == 'left') {
                            attr.left.from = (left - s.w);
                            this.setStyle('left', (left - s.w) + 'px');
                        }
                        break;
                    case 'top':
                    case 'bottom':
                        this.set('height', this._lastHeight, true);
                        this.setStyle('height', this._lastHeight + 'px');
                        this.get('parent').resize(false);
                        s = this.get('parent').getSizes()[this.get('position')];
                        this.set('width', s.w, true);
                        var top = s.t;
                        attr = {
                            top: {
                                to: top
                            }
                        };
                        if (this.get('position') == 'top') {
                            this.setStyle('top',  (top - s.h) + 'px');
                            attr.top.from = (top - s.h);
                        }
                        break;
                }

                this._anim.attributes = attr;
                var exStart = function() {
                    this.setStyle('display', 'block');
                    this.resize(true);
                    this._anim.onStart.unsubscribe(exStart, this, true);
                };
                var expand = function() {
                    this._collapsing = false;
                    this.setStyle('zIndex', this.get('parent')._zIndex);
                    this.set('width', this._lastWidth);
                    this.set('height', this._lastHeight);
                    this._collapsed = false;
                    this.resize();
                    this.set('scroll', this._lastScroll);
                    if (this._lastScrollTop > 0) {
                        this.body.scrollTop = this._lastScrollTop;
                    }
                    this._anim.onComplete.unsubscribe(expand, this, true);
                    this.fireEvent('expand');
                };
                this._anim.onStart.subscribe(exStart, this, true);
                this._anim.onComplete.subscribe(expand, this, true);
                this._anim.animate();
                this._toggleClip();
            } else {
                this._collapsing = false;
                this._toggleClip();
                this.setStyle('zIndex', this.get('parent')._zIndex);
                this.setStyle('display', 'block');
                this.set('width', this._lastWidth);
                this.set('height', this._lastHeight);
                this._collapsed = false;
                this.resize();
                this.set('scroll', this._lastScroll);
                if (this._lastScrollTop > 0) {
                    this.body.scrollTop = this._lastScrollTop;
                }
                this.fireEvent('expand');
            }
            return this;
        },
        /**
        * @method collapse
        * @description Collapse the Unit if it is not collapsed.
        * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
        */
        collapse: function() {
            if (this._collapsed) {
                return this;
            }
            var retValue = this.fireEvent('beforeCollapse');
            if (retValue === false) {
                return this;
            }
            if (!this._clip) {
                this._createClip();
            }
            this._collapsing = true;
            var w = this.get('width'),
                h = this.get('height'),
                attr = {};
            this._lastWidth = w;
            this._lastHeight = h;
            this._lastScroll = this.get('scroll');
            this._lastScrollTop = this.body.scrollTop;            
            this.set('scroll', false, true);
            this._lastLeft = parseInt(this.get('element').style.left, 10);
            this._lastTop = parseInt(this.get('element').style.top, 10);
            if (isNaN(this._lastTop)) {
                this._lastTop = 0;
                this.set('top', 0);
            }
            if (isNaN(this._lastLeft)) {
                this._lastLeft = 0;
                this.set('left', 0);
            }
            this.setStyle('zIndex', this.get('parent')._zIndex + 1);
            var pos = this.get('position');

            switch (pos) {
                case 'top':
                case 'bottom':
                    this.set('height', (this.get('collapseSize') + (this._gutter.top + this._gutter.bottom)));
                    attr = {
                        top: {
                            to: (this.get('top') - h)
                        }
                    };
                    if (pos == 'bottom') {
                        attr.top.to = (this.get('top') + h);
                    }
                    break;
                case 'left':
                case 'right':
                    this.set('width', (this.get('collapseSize') + (this._gutter.left + this._gutter.right)));
                    attr = {
                        left: {
                            to: -(this._lastWidth)
                        }
                    };
                    if (pos == 'right') {
                        attr.left = {
                            to: (this.get('left') + w)
                        };
                    }
                    break;
            }
            if (this._anim) {
                this._anim.attributes = attr;
                var collapse = function() {
                    this._collapsing = false;
                    this._toggleClip();
                    this.setStyle('zIndex', this.get('parent')._zIndex);
                    this._collapsed = true;
                    this.get('parent').resize();
                    this._anim.onComplete.unsubscribe(collapse, this, true);
                    this.fireEvent('collapse');
                };
                this._anim.onComplete.subscribe(collapse, this, true);
                this._anim.animate();
            } else {
                this._collapsing = false;
                this.setStyle('display', 'none');
                this._toggleClip();
                this.setStyle('zIndex', this.get('parent')._zIndex);
                this.get('parent').resize();
                this._collapsed = true;
                this.fireEvent('collapse');
            }
            return this;
        },
        /**
        * @method close
        * @description Close the unit, removing it from the parent Layout.
        * @return {<a href="YAHOO.widget.Layout.html">YAHOO.widget.Layout</a>} The parent Layout instance
        */
        close: function() {
            this.setStyle('display', 'none');
            this.get('parent').removeUnit(this);
            this.fireEvent('close');
            if (this._clip) {
                this._clip.parentNode.removeChild(this._clip);
                this._clip = null;
            }
            return this.get('parent');
        },
        /**
        * @private
        * @method init
        * @description The initalization method inherited from Element.
        */
        init: function(p_oElement, p_oAttributes) {
            YAHOO.log('init', 'info', 'LayoutUnit');
            this._gutter = {
                left: 0,
                right: 0,
                top: 0,
                bottom: 0
            };
            this._sizes = {
                wrap: {
                    h: 0,
                    w: 0
                },
                header: {
                    h: 0,
                    w: 0
                },
                body: {
                    h: 0,
                    w: 0
                },
                footer: {
                    h: 0,
                    w: 0
                }
            };
            
            LayoutUnit.superclass.init.call(this, p_oElement, p_oAttributes);

            this.browser = this.get('parent').browser;
            
            var id = p_oElement;
            if (!Lang.isString(id)) {
                id = Dom.generateId(id);
            }
            LayoutUnit._instances[id] = this;

            this.setStyle('position', 'absolute');

            this.addClass('yui-layout-unit');
            this.addClass('yui-layout-unit-' + this.get('position'));


            var header = this.getElementsByClassName('yui-layout-hd', 'div')[0];
            if (header) {
                this.header = header;
            }
            var body = this.getElementsByClassName('yui-layout-bd', 'div')[0];
            if (body) {
                this.body = body;
            }
            var footer = this.getElementsByClassName('yui-layout-ft', 'div')[0];
            if (footer) {
                this.footer = footer;
            }

            this.on('contentChange', this.resize, this, true);
            this._lastScrollTop = 0;

            this.set('animate', this.get('animate'));
        },
        /**
        * @private
        * @method initAttributes
        * @description Processes the config
        */        
        initAttributes: function(attr) {
            LayoutUnit.superclass.initAttributes.call(this, attr);

            /**
            * @private
            * @attribute wrap
            * @description A reference to the wrap element
            * @type HTMLElement
            */
            this.setAttributeConfig('wrap', {
                value: attr.wrap || null,
                method: function(w) {
                    if (w) {
                        var id = Dom.generateId(w);
                        LayoutUnit._instances[id] = this;
                    }
                }
            });
            /**
            * @attribute grids
            * @description Set this option to true if you want the LayoutUnit to fix the first layer of YUI CSS Grids (margins)
            * @type Boolean
            */
            this.setAttributeConfig('grids', {
                value: attr.grids || false
            });
            /**
            * @private
            * @attribute top
            * @description The current top positioning of the Unit
            * @type Number
            */
            this.setAttributeConfig('top', {
                value: attr.top || 0,
                validator: Lang.isNumber,
                method: function(t) {
                    if (!this._collapsing) {
                        this.setStyle('top', t + 'px');
                    }
                }
            });
            /**
            * @private
            * @attribute left
            * @description The current left position of the Unit
            * @type Number
            */
            this.setAttributeConfig('left', {
                value: attr.left || 0,
                validator: Lang.isNumber,
                method: function(l) {
                    if (!this._collapsing) {
                        this.setStyle('left', l + 'px');
                    }
                }
            });

            /**
            * @attribute minWidth
            * @description The minWidth parameter passed to the Resize Utility
            * @type Number
            */
            this.setAttributeConfig('minWidth', {
                value: attr.minWidth || false,
                validator: YAHOO.lang.isNumber
            });

            /**
            * @attribute maxWidth
            * @description The maxWidth parameter passed to the Resize Utility
            * @type Number
            */
            this.setAttributeConfig('maxWidth', {
                value: attr.maxWidth || false,
                validator: YAHOO.lang.isNumber
            });

            /**
            * @attribute minHeight
            * @description The minHeight parameter passed to the Resize Utility
            * @type Number
            */
            this.setAttributeConfig('minHeight', {
                value: attr.minHeight || false,
                validator: YAHOO.lang.isNumber
            });

            /**
            * @attribute maxHeight
            * @description The maxHeight parameter passed to the Resize Utility
            * @type Number
            */
            this.setAttributeConfig('maxHeight', {
                value: attr.maxHeight || false,
                validator: YAHOO.lang.isNumber
            });

            /**
            * @attribute height
            * @description The height of the Unit
            * @type Number
            */
            this.setAttributeConfig('height', {
                value: attr.height,
                validator: Lang.isNumber,
                method: function(h) {
                    if (!this._collapsing) {
                        this.setStyle('height', h + 'px');
                    }
                }
            });

            /**
            * @attribute width
            * @description The width of the Unit
            * @type Number
            */
            this.setAttributeConfig('width', {
                value: attr.width,
                validator: Lang.isNumber,
                method: function(w) {
                    if (!this._collapsing) {
                        this.setStyle('width', w + 'px');
                    }
                }
            });
            /**
            * @attribute position
            * @description The position (top, right, bottom, left or center) of the Unit in the Layout
            * @type {String}
            */
            this.setAttributeConfig('position', {
                value: attr.position
            });
            /**
            * @attribute gutter
            * @description The gutter that we should apply to the parent Layout around this Unit. Supports standard CSS markup: (2 4 0 5) or (2) or (2 5)
            * @type String
            */
            this.setAttributeConfig('gutter', {
                value: attr.gutter || 0,
                validator: YAHOO.lang.isString,
                method: function(gutter)