]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/yui/build/layout/layout.js
Release 6.2.0beta4
[Github/sugarcrm.git] / include / javascript / yui / build / layout / layout.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.8.0r4
6 */
7 /**
8  * @description <p>Provides a fixed layout containing, top, bottom, left, right and center layout units. It can be applied to either the body or an element.</p>
9  * @namespace YAHOO.widget
10  * @requires yahoo, dom, element, event
11  * @module layout
12  */
13 (function() {
14     var Dom = YAHOO.util.Dom,
15         Event = YAHOO.util.Event,
16         Lang = YAHOO.lang;
17
18     /**
19      * @constructor
20      * @class Layout
21      * @extends YAHOO.util.Element
22      * @description <p>Provides a fixed layout containing, top, bottom, left, right and center layout units. It can be applied to either the body or an element.</p>
23      * @param {String/HTMLElement} el The element to make contain a layout.
24      * @param {Object} attrs Object liternal containing configuration parameters.
25     */
26
27     var Layout = function(el, config) {
28         if (Lang.isObject(el) && !el.tagName) {
29             config = el;
30             el = null;
31         }
32         if (Lang.isString(el)) {
33             if (Dom.get(el)) {
34                 el = Dom.get(el);
35             }
36         }
37         if (!el) {
38             el = document.body;
39         }
40
41         var oConfig = {
42             element: el,
43             attributes: config || {}
44         };
45
46         Layout.superclass.constructor.call(this, oConfig.element, oConfig.attributes);    
47     };
48
49     /**
50     * @private
51     * @static
52     * @property _instances
53     * @description Internal hash table for all layout instances
54     * @type Object
55     */ 
56     Layout._instances = {};
57     /**
58     * @static
59     * @method getLayoutById 
60     * @description Get's a layout object by the HTML id of the element associated with the Layout object.
61     * @return {Object} The Layout Object
62     */ 
63     Layout.getLayoutById = function(id) {
64         if (Layout._instances[id]) {
65             return Layout._instances[id];
66         }
67         return false;
68     };
69
70     YAHOO.extend(Layout, YAHOO.util.Element, {
71         /**
72         * @property browser
73         * @description A modified version of the YAHOO.env.ua object
74         * @type Object
75         */
76         browser: function() {
77             var b = YAHOO.env.ua;
78             b.standardsMode = false;
79             b.secure = false;
80             return b;
81         }(),
82         /**
83         * @private
84         * @property _units
85         * @description An object literal that contains a list of units in the layout
86         * @type Object
87         */
88         _units: null,
89         /**
90         * @private
91         * @property _rendered
92         * @description Set to true when the layout is rendered
93         * @type Boolean
94         */
95         _rendered: null,
96         /**
97         * @private
98         * @property _zIndex
99         * @description The zIndex to set all LayoutUnits to
100         * @type Number
101         */
102         _zIndex: null,
103         /**
104         * @private
105         * @property _sizes
106         * @description A collection of the current sizes of all usable LayoutUnits to be used for calculations
107         * @type Object
108         */
109         _sizes: null,
110         /**
111         * @private
112         * @method _setBodySize
113         * @param {Boolean} set If set to false, it will NOT set the size, just perform the calculations (used for collapsing units)
114         * @description Used to set the body size of the layout, sets the height and width of the parent container
115         */
116         _setBodySize: function(set) {
117             var h = 0, w = 0;
118             set = ((set === false) ? false : true);
119
120             if (this._isBody) {
121                 h = Dom.getClientHeight();
122                 w = Dom.getClientWidth();
123             } else {
124                 h = parseInt(this.getStyle('height'), 10);
125                 w = parseInt(this.getStyle('width'), 10);
126                 if (isNaN(w)) {
127                     w = this.get('element').clientWidth;
128                 }
129                 if (isNaN(h)) {
130                     h = this.get('element').clientHeight;
131                 }
132             }
133             if (this.get('minWidth')) {
134                 if (w < this.get('minWidth')) {
135                     w = this.get('minWidth');
136                 }
137             }
138             if (this.get('minHeight')) {
139                 if (h < this.get('minHeight')) {
140                     h = this.get('minHeight');
141                 }
142             }
143             if (set) {
144                 if (h < 0) {
145                     h = 0;
146                 }
147                 if (w < 0) {
148                     w = 0;
149                 }
150                 Dom.setStyle(this._doc, 'height', h + 'px');
151                 Dom.setStyle(this._doc, 'width', w + 'px');
152             }
153             this._sizes.doc = { h: h, w: w };
154             this._setSides(set);
155         },
156         /**
157         * @private
158         * @method _setSides
159         * @param {Boolean} set If set to false, it will NOT set the size, just perform the calculations (used for collapsing units)
160         * @description Used to set the size and position of the left, right, top and bottom units
161         */
162         _setSides: function(set) {
163             var h1 = ((this._units.top) ? this._units.top.get('height') : 0),
164                 h2 = ((this._units.bottom) ? this._units.bottom.get('height') : 0),
165                 h = this._sizes.doc.h,
166                 w = this._sizes.doc.w;
167             set = ((set === false) ? false : true);
168
169             this._sizes.top = {
170                 h: h1, w: ((this._units.top) ? w : 0),
171                 t: 0
172             };
173             this._sizes.bottom = {
174                 h: h2, w: ((this._units.bottom) ? w : 0)
175             };
176             
177             var newH = (h - (h1 + h2));
178
179             this._sizes.left = {
180                 h: newH, w: ((this._units.left) ? this._units.left.get('width') : 0)
181             };
182             this._sizes.right = {
183                 h: newH, w: ((this._units.right) ? this._units.right.get('width') : 0),
184                 l: ((this._units.right) ? (w - this._units.right.get('width')) : 0),
185                 t: ((this._units.top) ? this._sizes.top.h : 0)
186             };
187             
188             if (this._units.right && set) {
189                 this._units.right.set('top', this._sizes.right.t);
190                 if (!this._units.right._collapsing) { 
191                     this._units.right.set('left', this._sizes.right.l);
192                 }
193                 this._units.right.set('height', this._sizes.right.h, true);
194             }
195             if (this._units.left) {
196                 this._sizes.left.l = 0;
197                 if (this._units.top) {
198                     this._sizes.left.t = this._sizes.top.h;
199                 } else {
200                     this._sizes.left.t = 0;
201                 }
202                 if (set) {
203                     this._units.left.set('top', this._sizes.left.t);
204                     this._units.left.set('height', this._sizes.left.h, true);
205                     this._units.left.set('left', 0);
206                 }
207             }
208             if (this._units.bottom) {
209                 this._sizes.bottom.t = this._sizes.top.h + this._sizes.left.h;
210                 if (set) {
211                     this._units.bottom.set('top', this._sizes.bottom.t);
212                     this._units.bottom.set('width', this._sizes.bottom.w, true);
213                 }
214             }
215             if (this._units.top) {
216                 if (set) {
217                     this._units.top.set('width', this._sizes.top.w, true);
218                 }
219             }
220             this._setCenter(set);
221         },
222         /**
223         * @private
224         * @method _setCenter
225         * @param {Boolean} set If set to false, it will NOT set the size, just perform the calculations (used for collapsing units)
226         * @description Used to set the size and position of the center unit
227         */
228         _setCenter: function(set) {
229             set = ((set === false) ? false : true);
230             var h = this._sizes.left.h;
231             var w = (this._sizes.doc.w - (this._sizes.left.w + this._sizes.right.w));
232             if (set) {
233                 this._units.center.set('height', h, true);
234                 this._units.center.set('width', w, true);
235                 this._units.center.set('top', this._sizes.top.h);
236                 this._units.center.set('left', this._sizes.left.w);
237             }
238             this._sizes.center = { h: h, w: w, t: this._sizes.top.h, l: this._sizes.left.w };
239         },
240         /**
241         * @method getSizes
242         * @description Get a reference to the internal Layout Unit sizes object used to build the layout wireframe
243         * @return {Object} An object of the layout unit sizes
244         */
245         getSizes: function() {
246             return this._sizes;
247         },
248         /**
249         * @method getUnitById
250         * @param {String} id The HTML element id of the unit
251         * @description Get the LayoutUnit by it's HTML id
252         * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
253         */
254         getUnitById: function(id) {
255             return YAHOO.widget.LayoutUnit.getLayoutUnitById(id);
256         },
257         /**
258         * @method getUnitByPosition
259         * @param {String} pos The position of the unit in this layout
260         * @description Get the LayoutUnit by it's position in this layout
261         * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
262         */
263         getUnitByPosition: function(pos) {
264             if (pos) {
265                 pos = pos.toLowerCase();
266                 if (this._units[pos]) {
267                     return this._units[pos];
268                 }
269                 return false;
270             }
271             return false;
272         },
273         /**
274         * @method removeUnit
275         * @param {Object} unit The LayoutUnit that you want to remove
276         * @description Remove the unit from this layout and resize the layout.
277         */
278         removeUnit: function(unit) {
279             delete this._units[unit.get('position')];
280             this.resize();
281         },
282         /**
283         * @method addUnit
284         * @param {Object} cfg The config for the LayoutUnit that you want to add
285         * @description Add a unit to this layout and if the layout is rendered, resize the layout. 
286         * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
287         */
288         addUnit: function(cfg) {
289             if (!cfg.position) {
290                 return false;
291             }
292             if (this._units[cfg.position]) {
293                 return false;
294             }
295             var element = null,
296                 el = null;
297
298             if (cfg.id) {
299                 if (Dom.get(cfg.id)) {
300                     element = Dom.get(cfg.id);
301                     delete cfg.id;
302
303                 }
304             }
305             if (cfg.element) {
306                 element = cfg.element;
307             }
308
309             if (!el) {
310                 el = document.createElement('div');
311                 var id = Dom.generateId();
312                 el.id = id;
313             }
314
315             if (!element) {
316                 element = document.createElement('div');
317             }
318             Dom.addClass(element, 'yui-layout-wrap');
319             if (this.browser.ie && !this.browser.standardsMode) {
320                 el.style.zoom = 1;
321                 element.style.zoom = 1;
322             }
323
324             if (el.firstChild) {
325                 el.insertBefore(element, el.firstChild);
326             } else {
327                 el.appendChild(element);
328             }
329             this._doc.appendChild(el);
330
331             var h = false, w = false;
332
333             if (cfg.height) {
334                 h = parseInt(cfg.height, 10);
335             }
336             if (cfg.width) {
337                 w = parseInt(cfg.width, 10);
338             }
339             var unitConfig = {};
340             YAHOO.lang.augmentObject(unitConfig, cfg); // break obj ref
341
342             unitConfig.parent = this;
343             unitConfig.wrap = element;
344             unitConfig.height = h;
345             unitConfig.width = w;
346
347             var unit = new YAHOO.widget.LayoutUnit(el, unitConfig);
348
349             unit.on('heightChange', this.resize, { unit: unit }, this);
350             unit.on('widthChange', this.resize, { unit: unit }, this);
351             unit.on('gutterChange', this.resize, { unit: unit }, this);
352             this._units[cfg.position] = unit;
353
354             if (this._rendered) {
355                 this.resize();
356             }
357
358             return unit;
359         },
360         /**
361         * @private
362         * @method _createUnits
363         * @description Private method to create units from the config that was passed in.
364         */
365         _createUnits: function() {
366             var units = this.get('units');
367             for (var i in units) {
368                 if (Lang.hasOwnProperty(units, i)) {
369                     this.addUnit(units[i]);
370                 }
371             }
372         },
373         /**
374         * @method resize
375         * @param Boolean/Event set If set to false, it will NOT set the size, just perform the calculations (used for collapsing units). This can also have an attribute event passed to it.
376         * @description Starts the chain of resize routines that will resize all the units.
377         * @return {<a href="YAHOO.widget.Layout.html">YAHOO.widget.Layout</a>} The Layout instance
378         */
379         resize: function(set, info) {
380             /*
381             * Fixes bug #2528175
382             * If the event comes from an attribute and the value hasn't changed, don't process it.
383             */
384             var ev = set;
385             if (ev && ev.prevValue && ev.newValue) {
386                 if (ev.prevValue == ev.newValue) {
387                     if (info) {
388                         if (info.unit) {
389                             if (!info.unit.get('animate')) {
390                                 set = false;
391                             }
392                         }
393                     }
394                 }
395             }
396             set = ((set === false) ? false : true);
397             if (set) {
398                 var retVal = this.fireEvent('beforeResize');
399                 if (retVal === false) {
400                     set = false;
401                 }
402                 if (this.browser.ie) {
403                     if (this._isBody) {
404                         Dom.removeClass(document.documentElement, 'yui-layout');
405                         Dom.addClass(document.documentElement, 'yui-layout');
406                     } else {
407                         this.removeClass('yui-layout');
408                         this.addClass('yui-layout');
409                     }
410                 }
411             }
412             this._setBodySize(set);
413             if (set) {
414                 this.fireEvent('resize', { target: this, sizes: this._sizes, event: ev });
415             }
416             return this;
417         },
418         /**
419         * @private
420         * @method _setupBodyElements
421         * @description Sets up the main doc element when using the body as the main element.
422         */
423         _setupBodyElements: function() {
424             this._doc = Dom.get('layout-doc');
425             if (!this._doc) {
426                 this._doc = document.createElement('div');
427                 this._doc.id = 'layout-doc';
428                 if (document.body.firstChild) {
429                     document.body.insertBefore(this._doc, document.body.firstChild);
430                 } else {
431                     document.body.appendChild(this._doc);
432                 }
433             }
434             this._createUnits();
435             this._setBodySize();
436             Event.on(window, 'resize', this.resize, this, true);
437             Dom.addClass(this._doc, 'yui-layout-doc');
438         },
439         /**
440         * @private
441         * @method _setupElements
442         * @description Sets up the main doc element when not using the body as the main element.
443         */
444         _setupElements: function() {
445             this._doc = this.getElementsByClassName('yui-layout-doc')[0];
446             if (!this._doc) {
447                 this._doc = document.createElement('div');
448                 this.get('element').appendChild(this._doc);
449             }
450             this._createUnits();
451             this._setBodySize();
452             Dom.addClass(this._doc, 'yui-layout-doc');
453         },
454         /**
455         * @private
456         * @property _isBody
457         * @description Flag to determine if we are using the body as the root element.
458         * @type Boolean
459         */
460         _isBody: null,
461         /**
462         * @private
463         * @property _doc
464         * @description Reference to the root element
465         * @type HTMLElement
466         */
467         _doc: null,
468         /**
469         * @private
470         * @method init
471         * @description The Layout class' initialization method
472         */        
473         init: function(p_oElement, p_oAttributes) {
474
475             this._zIndex = 0;
476
477             Layout.superclass.init.call(this, p_oElement, p_oAttributes);
478             
479             if (this.get('parent')) {
480                 this._zIndex = this.get('parent')._zIndex + 10;
481             }
482
483             this._sizes = {};
484             this._units = {};
485
486             var id = p_oElement;
487             if (!Lang.isString(id)) {
488                 id = Dom.generateId(id);
489             }
490             Layout._instances[id] = this;
491         },
492         /**
493         * @method render
494         * @description This method starts the render process, applying classnames and creating elements
495         * @return {<a href="YAHOO.widget.Layout.html">YAHOO.widget.Layout</a>} The Layout instance
496         */        
497         render: function() {
498             this._stamp();
499             var el = this.get('element');
500             if (el && el.tagName && (el.tagName.toLowerCase() == 'body')) {
501                 this._isBody = true;
502                 Dom.addClass(document.body, 'yui-layout');
503                 if (Dom.hasClass(document.body, 'yui-skin-sam')) {
504                     //Move the class up so we can have a css chain
505                     Dom.addClass(document.documentElement, 'yui-skin-sam');
506                     Dom.removeClass(document.body, 'yui-skin-sam');
507                 }
508                 this._setupBodyElements();
509             } else {
510                 this._isBody = false;
511                 this.addClass('yui-layout');
512                 this._setupElements();
513             }
514             this.resize();
515             this._rendered = true;
516             this.fireEvent('render');
517
518             return this;
519         },
520         /**
521         * @private
522         * @method _stamp
523         * @description Stamps the root node with a secure classname for ease of use. Also sets the this.browser.standardsMode variable.
524         */        
525         _stamp: function() {
526             if (document.compatMode == 'CSS1Compat') {
527                 this.browser.standardsMode = true;
528             }
529             if (window.location.href.toLowerCase().indexOf("https") === 0) {
530                 Dom.addClass(document.documentElement, 'secure');
531                 this.browser.secure = true;
532             }
533         },
534         /**
535         * @private
536         * @method initAttributes
537         * @description Processes the config
538         */        
539         initAttributes: function(attr) {
540             Layout.superclass.initAttributes.call(this, attr);
541             /**
542             * @attribute units
543             * @description An array of config definitions for the LayoutUnits to add to this layout
544             * @type Array
545             */
546             this.setAttributeConfig('units', {
547                 writeOnce: true,
548                 validator: YAHOO.lang.isArray,
549                 value: attr.units || []
550             });
551
552             /**
553             * @attribute minHeight
554             * @description The minimum height in pixels
555             * @type Number
556             */
557             this.setAttributeConfig('minHeight', {
558                 value: attr.minHeight || false,
559                 validator: YAHOO.lang.isNumber
560             });
561
562             /**
563             * @attribute minWidth
564             * @description The minimum width in pixels
565             * @type Number
566             */
567             this.setAttributeConfig('minWidth', {
568                 value: attr.minWidth || false,
569                 validator: YAHOO.lang.isNumber
570             });
571
572             /**
573             * @attribute height
574             * @description The height in pixels
575             * @type Number
576             */
577             this.setAttributeConfig('height', {
578                 value: attr.height || false,
579                 validator: YAHOO.lang.isNumber,
580                 method: function(h) {
581                     if (h < 0) {
582                         h = 0;
583                     }
584                     this.setStyle('height', h + 'px');
585                 }
586             });
587
588             /**
589             * @attribute width
590             * @description The width in pixels
591             * @type Number
592             */
593             this.setAttributeConfig('width', {
594                 value: attr.width || false,
595                 validator: YAHOO.lang.isNumber,
596                 method: function(w) {
597                     if (w < 0) {
598                         w = 0;
599                     }
600                     this.setStyle('width', w + 'px');
601                 }
602             });
603
604             /**
605             * @attribute parent
606             * @description If this layout is to be used as a child of another Layout instance, this config will bind the resize events together.
607             * @type Object YAHOO.widget.Layout
608             */
609             this.setAttributeConfig('parent', {
610                 writeOnce: true,
611                 value: attr.parent || false,
612                 method: function(p) {
613                     if (p) {
614                         p.on('resize', this.resize, this, true);
615                     }
616                 }
617             });
618         },
619         /**
620         * @method destroy
621         * @description Removes this layout from the page and destroys all units that it contains. This will destroy all data inside the layout and it's children.
622         */
623         destroy: function() {
624             var par = this.get('parent');
625             if (par) {
626                 par.removeListener('resize', this.resize, this, true);
627             }
628             Event.removeListener(window, 'resize', this.resize, this, true);
629
630             this.unsubscribeAll();
631             for (var u in this._units) {
632                 if (Lang.hasOwnProperty(this._units, u)) {
633                     if (this._units[u]) {
634                         this._units[u].destroy(true);
635                     }
636                 }
637             }
638
639             Event.purgeElement(this.get('element'));
640             this.get('parentNode').removeChild(this.get('element'));
641             
642             delete YAHOO.widget.Layout._instances[this.get('id')];
643             //Brutal Object Destroy
644             for (var i in this) {
645                 if (Lang.hasOwnProperty(this, i)) {
646                     this[i] = null;
647                     delete this[i];
648                 }
649             }
650             
651             if (par) {
652                 par.resize();
653             }
654         },
655         /**
656         * @method toString
657         * @description Returns a string representing the Layout.
658         * @return {String}
659         */        
660         toString: function() {
661             if (this.get) {
662                 return 'Layout #' + this.get('id');
663             }
664             return 'Layout';
665         }
666     });
667     /**
668     * @event resize
669     * @description Fired when this.resize is called
670     * @type YAHOO.util.CustomEvent
671     */
672     /**
673     * @event startResize
674     * @description Fired when the Resize Utility for a Unit fires it's startResize Event.
675     * @type YAHOO.util.CustomEvent
676     */
677     /**
678     * @event beforeResize
679     * @description Fires at the beginning of the resize method. If you return false, the resize is cancelled.
680     * @type YAHOO.util.CustomEvent
681     */
682     /**
683     * @event render
684     * @description Fired after the render method completes.
685     * @type YAHOO.util.CustomEvent
686     */
687
688     YAHOO.widget.Layout = Layout;
689 })();
690 /**
691  * @description <p>Provides a fixed position unit containing a header, body and footer for use with a YAHOO.widget.Layout instance.</p>
692  * @namespace YAHOO.widget
693  * @requires yahoo, dom, element, event, layout
694  * @optional animation, dragdrop, selector
695  */
696 (function() {
697     var Dom = YAHOO.util.Dom,
698         Sel = YAHOO.util.Selector,
699         Event = YAHOO.util.Event,
700         Lang = YAHOO.lang;
701
702     /**
703      * @constructor
704      * @class LayoutUnit
705      * @extends YAHOO.util.Element
706      * @description <p>Provides a fixed position unit containing a header, body and footer for use with a YAHOO.widget.Layout instance.</p>
707      * @param {String/HTMLElement} el The element to make a unit.
708      * @param {Object} attrs Object liternal containing configuration parameters.
709     */
710
711     var LayoutUnit = function(el, config) {
712         
713         var oConfig = {
714             element: el,
715             attributes: config || {}
716         };
717
718         LayoutUnit.superclass.constructor.call(this, oConfig.element, oConfig.attributes);    
719     };
720
721     /**
722     * @private
723     * @static
724     * @property _instances
725     * @description Internal hash table for all layout unit instances
726     * @type Object
727     */ 
728     LayoutUnit._instances = {};
729     /**
730     * @static
731     * @method getLayoutUnitById 
732     * @description Get's a layout unit object by the HTML id of the element associated with the Layout Unit object.
733     * @return {Object} The Layout Object
734     */ 
735     LayoutUnit.getLayoutUnitById = function(id) {
736         if (LayoutUnit._instances[id]) {
737             return LayoutUnit._instances[id];
738         }
739         return false;
740     };
741
742     YAHOO.extend(LayoutUnit, YAHOO.util.Element, {
743         /**
744         * @property STR_CLOSE
745         * @description String used for close button title
746         * @type {String}
747         */
748         STR_CLOSE: 'Click to close this pane.',
749         /**
750         * @property STR_COLLAPSE
751         * @description String used for collapse button title
752         * @type {String}
753         */
754         STR_COLLAPSE: 'Click to collapse this pane.',
755         /**
756         * @property STR_EXPAND
757         * @description String used for expand button title
758         * @type {String}
759         */
760         STR_EXPAND: 'Click to expand this pane.',
761         /**
762             * The class name applied to dynamic tabs while loading.
763             * @property LOADING_CLASSNAME
764             * @type String
765             * @default "disabled"
766             */
767             LOADING_CLASSNAME: 'loading',
768         /**
769         * @property browser
770         * @description A modified version of the YAHOO.env.ua object
771         * @type Object
772         */
773         browser: null,
774         /**
775         * @private
776         * @property _sizes
777         * @description A collection of the current sizes of the contents of this Layout Unit
778         * @type Object
779         */
780         _sizes: null,
781         /**
782         * @private
783         * @property _anim
784         * @description A reference to the Animation instance used by this LayouUnit
785         * @type YAHOO.util.Anim
786         */
787         _anim: null,
788         /**
789         * @private
790         * @property _resize
791         * @description A reference to the Resize instance used by this LayoutUnit
792         * @type YAHOO.util.Resize
793         */
794         _resize: null,
795         /**
796         * @private
797         * @property _clip
798         * @description A reference to the clip element used when collapsing the unit
799         * @type HTMLElement
800         */
801         _clip: null,
802         /**
803         * @private
804         * @property _gutter
805         * @description A simple hash table used to store the gutter to apply to the Unit
806         * @type Object
807         */
808         _gutter: null,
809         /**
810         * @property header
811         * @description A reference to the HTML element used for the Header
812         * @type HTMLELement
813         */
814         header: null,
815         /**
816         * @property body
817         * @description A reference to the HTML element used for the body
818         * @type HTMLElement
819         */
820         body: null,
821         /**
822         * @property footer
823         * @description A reference to the HTML element used for the footer
824         * @type HTMLElement
825         */
826         footer: null,
827         /**
828         * @private
829         * @property _collapsed
830         * @description Flag to determine if the unit is collapsed or not.
831         * @type Boolean
832         */
833         _collapsed: null,
834         /**
835         * @private
836         * @property _collapsing
837         * @description A flag set while the unit is being collapsed, used so we don't fire events while animating the size
838         * @type Boolean
839         */
840         _collapsing: null,
841         /**
842         * @private
843         * @property _lastWidth
844         * @description A holder for the last known width of the unit
845         * @type Number
846         */
847         _lastWidth: null,
848         /**
849         * @private
850         * @property _lastHeight
851         * @description A holder for the last known height of the unit
852         * @type Number
853         */
854         _lastHeight: null,
855         /**
856         * @private
857         * @property _lastTop
858         * @description A holder for the last known top of the unit
859         * @type Number
860         */
861         _lastTop: null,
862         /**
863         * @private
864         * @property _lastLeft
865         * @description A holder for the last known left of the unit
866         * @type Number
867         */
868         _lastLeft: null,
869         /**
870         * @private
871         * @property _lastScroll
872         * @description A holder for the last known scroll state of the unit
873         * @type Boolean
874         */
875         _lastScroll: null,
876         /**
877         * @private
878         * @property _lastCenetrScroll
879         * @description A holder for the last known scroll state of the center unit
880         * @type Boolean
881         */
882         _lastCenterScroll: null,
883         /**
884         * @private
885         * @property _lastScrollTop
886         * @description A holder for the last known scrollTop state of the unit
887         * @type Number
888         */
889         _lastScrollTop: null,
890         /**
891         * @method resize
892         * @description Resize either the unit or it's clipped state, also updating the box inside
893         * @param {Boolean} force This will force full calculations even when the unit is collapsed
894         * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
895         */
896         resize: function(force) {
897             var retVal = this.fireEvent('beforeResize');
898             if (retVal === false) {
899                 return this;
900             }
901             if (!this._collapsing || (force === true)) {
902                 var scroll = this.get('scroll');
903                 this.set('scroll', false);
904
905
906                 var hd = this._getBoxSize(this.header),
907                     ft = this._getBoxSize(this.footer),
908                     box = [this.get('height'), this.get('width')];
909
910                 var nh = (box[0] - hd[0] - ft[0]) - (this._gutter.top + this._gutter.bottom),
911                     nw = box[1] - (this._gutter.left + this._gutter.right);
912
913                 var wrapH = (nh + (hd[0] + ft[0])),
914                     wrapW = nw;
915
916                 if (this._collapsed && !this._collapsing) {
917                     this._setHeight(this._clip, wrapH);
918                     this._setWidth(this._clip, wrapW);
919                     Dom.setStyle(this._clip, 'top', this.get('top') + this._gutter.top + 'px');
920                     Dom.setStyle(this._clip, 'left', this.get('left') + this._gutter.left + 'px');
921                 } else if (!this._collapsed || (this._collapsed && this._collapsing)) {
922                     wrapH = this._setHeight(this.get('wrap'), wrapH);
923                     wrapW = this._setWidth(this.get('wrap'), wrapW);
924                     this._sizes.wrap.h = wrapH;
925                     this._sizes.wrap.w = wrapW;
926
927                     Dom.setStyle(this.get('wrap'), 'top', this._gutter.top + 'px');
928                     Dom.setStyle(this.get('wrap'), 'left', this._gutter.left + 'px');
929
930                     this._sizes.header.w = this._setWidth(this.header, wrapW);
931                     this._sizes.header.h = hd[0];
932
933                     this._sizes.footer.w = this._setWidth(this.footer, wrapW);
934                     this._sizes.footer.h = ft[0];
935
936                     Dom.setStyle(this.footer, 'bottom', '0px');
937
938                     this._sizes.body.h = this._setHeight(this.body, (wrapH - (hd[0] + ft[0])));
939                     this._sizes.body.w =this._setWidth(this.body, wrapW);
940                     Dom.setStyle(this.body, 'top', hd[0] + 'px');
941
942                     this.set('scroll', scroll);
943                     this.fireEvent('resize');
944                 }
945             }
946             return this;
947         },
948         /**
949         * @private
950         * @method _setWidth
951         * @description Sets the width of the element based on the border size of the element.
952         * @param {HTMLElement} el The HTMLElement to have it's width set
953         * @param {Number} w The width that you want it the element set to
954         * @return {Number} The new width, fixed for borders and IE QuirksMode
955         */
956         _setWidth: function(el, w) {
957             if (el) {
958                 var b = this._getBorderSizes(el);
959                 w = (w - (b[1] + b[3]));
960                 w = this._fixQuirks(el, w, 'w');
961                 if (w < 0) {
962                     w = 0;
963                 }
964                 Dom.setStyle(el, 'width', w + 'px');
965             }
966             return w;
967         },
968         /**
969         * @private
970         * @method _setHeight
971         * @description Sets the height of the element based on the border size of the element.
972         * @param {HTMLElement} el The HTMLElement to have it's height set
973         * @param {Number} h The height that you want it the element set to
974         * @return {Number} The new height, fixed for borders and IE QuirksMode
975         */
976         _setHeight: function(el, h) {
977             if (el) {
978                 var b = this._getBorderSizes(el);
979                 h = (h - (b[0] + b[2]));
980                 h = this._fixQuirks(el, h, 'h');
981                 if (h < 0) {
982                     h = 0;
983                 }
984                 Dom.setStyle(el, 'height', h + 'px');
985             }
986             return h;
987         },
988         /**
989         * @private
990         * @method _fixQuirks
991         * @description Fixes the box calculations for IE in QuirksMode
992         * @param {HTMLElement} el The HTMLElement to set the dimension on
993         * @param {Number} dim The number of the dimension to fix
994         * @param {String} side The dimension (h or w) to fix. Defaults to h
995         * @return {Number} The fixed dimension
996         */
997         _fixQuirks: function(el, dim, side) {
998             var i1 = 0, i2 = 2;
999             if (side == 'w') {
1000                 i1 = 1;
1001                 i2 = 3;
1002             }
1003             if ((this.browser.ie < 8) && !this.browser.standardsMode) {
1004                 //Internet Explorer - Quirks Mode
1005                 var b = this._getBorderSizes(el),
1006                     bp = this._getBorderSizes(el.parentNode);
1007                 if ((b[i1] === 0) && (b[i2] === 0)) { //No Borders, check parent
1008                     if ((bp[i1] !== 0) && (bp[i2] !== 0)) { //Parent has Borders
1009                         dim = (dim - (bp[i1] + bp[i2]));
1010                     }
1011                 } else {
1012                     if ((bp[i1] === 0) && (bp[i2] === 0)) {
1013                         dim = (dim + (b[i1] + b[i2]));
1014                     }
1015                 }
1016             }
1017             return dim;
1018         },
1019         /**
1020         * @private
1021         * @method _getBoxSize
1022         * @description Get's the elements clientHeight and clientWidth plus the size of the borders
1023         * @param {HTMLElement} el The HTMLElement to get the size of
1024         * @return {Array} An array of height and width
1025         */
1026         _getBoxSize: function(el) {
1027             var size = [0, 0];
1028             if (el) {
1029                 if (this.browser.ie && !this.browser.standardsMode) {
1030                     el.style.zoom = 1;
1031                 }
1032                 var b = this._getBorderSizes(el);
1033                 size[0] = el.clientHeight + (b[0] + b[2]);
1034                 size[1] = el.clientWidth + (b[1] + b[3]);
1035             }
1036             return size;
1037         },
1038         /**
1039         * @private
1040         * @method _getBorderSizes
1041         * @description Get the CSS border size of the element passed.
1042         * @param {HTMLElement} el The element to get the border size of
1043         * @return {Array} An array of the top, right, bottom, left borders.
1044         */
1045         _getBorderSizes: function(el) {
1046             var s = [];
1047             el = el || this.get('element');
1048             if (this.browser.ie && !this.browser.standardsMode) {
1049                 el.style.zoom = 1;
1050             }
1051             s[0] = parseInt(Dom.getStyle(el, 'borderTopWidth'), 10);
1052             s[1] = parseInt(Dom.getStyle(el, 'borderRightWidth'), 10);
1053             s[2] = parseInt(Dom.getStyle(el, 'borderBottomWidth'), 10);
1054             s[3] = parseInt(Dom.getStyle(el, 'borderLeftWidth'), 10);
1055             
1056             //IE will return NaN on these if they are set to auto, we'll set them to 0
1057             for (var i = 0; i < s.length; i++) {
1058                 if (isNaN(s[i])) {
1059                     s[i] = 0;
1060                 }
1061             }
1062             return s;
1063         },
1064         /**
1065         * @private
1066         * @method _createClip
1067         * @description Create the clip element used when the Unit is collapsed
1068         */
1069         _createClip: function() {
1070             if (!this._clip) {
1071                 this._clip = document.createElement('div');
1072                 this._clip.className = 'yui-layout-clip yui-layout-clip-' + this.get('position');
1073                 this._clip.innerHTML = '<div class="collapse"></div>';
1074                 var c = this._clip.firstChild;
1075                 c.title = this.STR_EXPAND;
1076                 Event.on(c, 'click', this.expand, this, true);
1077                 this.get('element').parentNode.appendChild(this._clip);
1078             }
1079         },
1080         /**
1081         * @private
1082         * @method _toggleClip
1083         * @description Toggle th current state of the Clip element and set it's height, width and position
1084         */
1085         _toggleClip: function() {
1086             if (!this._collapsed) {
1087                 //show
1088                 var hd = this._getBoxSize(this.header),
1089                     ft = this._getBoxSize(this.footer),
1090                     box = [this.get('height'), this.get('width')];
1091
1092
1093                 var nh = (box[0] - hd[0] - ft[0]) - (this._gutter.top + this._gutter.bottom),
1094                     nw = box[1] - (this._gutter.left + this._gutter.right),
1095                     wrapH = (nh + (hd[0] + ft[0]));
1096
1097                 switch (this.get('position')) {
1098                     case 'top':
1099                     case 'bottom':
1100                         this._setWidth(this._clip, nw);
1101                         this._setHeight(this._clip, this.get('collapseSize'));
1102                         Dom.setStyle(this._clip, 'left', (this._lastLeft + this._gutter.left) + 'px');
1103                         if (this.get('position') == 'bottom') {
1104                             Dom.setStyle(this._clip, 'top', ((this._lastTop + this._lastHeight) - (this.get('collapseSize') - this._gutter.top)) + 'px');
1105                         } else {
1106                             Dom.setStyle(this._clip, 'top', this.get('top') + this._gutter.top + 'px');
1107                         }
1108                         break;
1109                     case 'left':
1110                     case 'right':
1111                         this._setWidth(this._clip, this.get('collapseSize'));
1112                         this._setHeight(this._clip, wrapH);
1113                         Dom.setStyle(this._clip, 'top', (this.get('top') + this._gutter.top) + 'px');
1114                         if (this.get('position') == 'right') {
1115                             Dom.setStyle(this._clip, 'left', (((this._lastLeft + this._lastWidth) - this.get('collapseSize')) - this._gutter.left) + 'px');
1116                         } else {
1117                             Dom.setStyle(this._clip, 'left', (this.get('left') + this._gutter.left) + 'px');
1118                         }
1119                         break;
1120                 }
1121
1122                 Dom.setStyle(this._clip, 'display', 'block');
1123                 this.setStyle('display', 'none');
1124             } else {
1125                 //Hide
1126                 Dom.setStyle(this._clip, 'display', 'none');
1127             }
1128         },
1129         /**
1130         * @method getSizes
1131         * @description Get a reference to the internal sizes object for this unit
1132         * @return {Object} An object of the sizes used for calculations
1133         */
1134         getSizes: function() {
1135             return this._sizes;
1136         },
1137         /**
1138         * @method toggle
1139         * @description Toggles the Unit, replacing it with a clipped version.
1140         * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
1141         */
1142         toggle: function() {
1143             if (this._collapsed) {
1144                 this.expand();
1145             } else {
1146                 this.collapse();
1147             }
1148             return this;
1149         },
1150         /**
1151         * @method expand
1152         * @description Expand the Unit if it is collapsed.
1153         * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
1154         */
1155         expand: function() {
1156             if (!this._collapsed) {
1157                 return this;
1158             }
1159             var retVal = this.fireEvent('beforeExpand');
1160             if (retVal === false) {
1161                 return this;
1162             }
1163
1164             this._collapsing = true;
1165             this.setStyle('zIndex', this.get('parent')._zIndex + 1);
1166
1167             if (this._anim) {
1168                 this.setStyle('display', 'none');
1169                 var attr = {}, s;
1170
1171                 switch (this.get('position')) {
1172                     case 'left':
1173                     case 'right':
1174                         this.set('width', this._lastWidth, true);
1175                         this.setStyle('width', this._lastWidth + 'px');
1176                         this.get('parent').resize(false);
1177                         s = this.get('parent').getSizes()[this.get('position')];
1178                         this.set('height', s.h, true);
1179                         var left = s.l;
1180                         attr = {
1181                             left: {
1182                                 to: left
1183                             }
1184                         };
1185                         if (this.get('position') == 'left') {
1186                             attr.left.from = (left - s.w);
1187                             this.setStyle('left', (left - s.w) + 'px');
1188                         }
1189                         break;
1190                     case 'top':
1191                     case 'bottom':
1192                         this.set('height', this._lastHeight, true);
1193                         this.setStyle('height', this._lastHeight + 'px');
1194                         this.get('parent').resize(false);
1195                         s = this.get('parent').getSizes()[this.get('position')];
1196                         this.set('width', s.w, true);
1197                         var top = s.t;
1198                         attr = {
1199                             top: {
1200                                 to: top
1201                             }
1202                         };
1203                         if (this.get('position') == 'top') {
1204                             this.setStyle('top',  (top - s.h) + 'px');
1205                             attr.top.from = (top - s.h);
1206                         }
1207                         break;
1208                 }
1209
1210                 this._anim.attributes = attr;
1211                 var exStart = function() {
1212                     this.setStyle('display', 'block');
1213                     this.resize(true);
1214                     this._anim.onStart.unsubscribe(exStart, this, true);
1215                 };
1216                 var expand = function() {
1217                     this._collapsing = false;
1218                     this.setStyle('zIndex', this.get('parent')._zIndex);
1219                     this.set('width', this._lastWidth);
1220                     this.set('height', this._lastHeight);
1221                     this._collapsed = false;
1222                     this.resize();
1223                     this.set('scroll', this._lastScroll);
1224                     if (this._lastScrollTop > 0) {
1225                         this.body.scrollTop = this._lastScrollTop;
1226                     }
1227                     this._anim.onComplete.unsubscribe(expand, this, true);
1228                     this.fireEvent('expand');
1229                 };
1230                 this._anim.onStart.subscribe(exStart, this, true);
1231                 this._anim.onComplete.subscribe(expand, this, true);
1232                 this._anim.animate();
1233                 this._toggleClip();
1234             } else {
1235                 this._collapsing = false;
1236                 this._toggleClip();
1237                 this._collapsed = false;
1238                 this.setStyle('zIndex', this.get('parent')._zIndex);
1239                 this.setStyle('display', 'block');
1240                 this.set('width', this._lastWidth);
1241                 this.set('height', this._lastHeight);
1242                 this.resize();
1243                 this.set('scroll', this._lastScroll);
1244                 if (this._lastScrollTop > 0) {
1245                     this.body.scrollTop = this._lastScrollTop;
1246                 }
1247                 this.fireEvent('expand');
1248             }
1249             return this;
1250         },
1251         /**
1252         * @method collapse
1253         * @description Collapse the Unit if it is not collapsed.
1254         * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
1255         */
1256         collapse: function() {
1257             if (this._collapsed) {
1258                 return this;
1259             }
1260             var retValue = this.fireEvent('beforeCollapse');
1261             if (retValue === false) {
1262                 return this;
1263             }
1264             if (!this._clip) {
1265                 this._createClip();
1266             }
1267             this._collapsing = true;
1268             var w = this.get('width'),
1269                 h = this.get('height'),
1270                 attr = {};
1271             this._lastWidth = w;
1272             this._lastHeight = h;
1273             this._lastScroll = this.get('scroll');
1274             this._lastScrollTop = this.body.scrollTop;            
1275             this.set('scroll', false, true);
1276             this._lastLeft = parseInt(this.get('element').style.left, 10);
1277             this._lastTop = parseInt(this.get('element').style.top, 10);
1278             if (isNaN(this._lastTop)) {
1279                 this._lastTop = 0;
1280                 this.set('top', 0);
1281             }
1282             if (isNaN(this._lastLeft)) {
1283                 this._lastLeft = 0;
1284                 this.set('left', 0);
1285             }
1286             this.setStyle('zIndex', this.get('parent')._zIndex + 1);
1287             var pos = this.get('position');
1288
1289             switch (pos) {
1290                 case 'top':
1291                 case 'bottom':
1292                     this.set('height', (this.get('collapseSize') + (this._gutter.top + this._gutter.bottom)));
1293                     attr = {
1294                         top: {
1295                             to: (this.get('top') - h)
1296                         }
1297                     };
1298                     if (pos == 'bottom') {
1299                         attr.top.to = (this.get('top') + h);
1300                     }
1301                     break;
1302                 case 'left':
1303                 case 'right':
1304                     this.set('width', (this.get('collapseSize') + (this._gutter.left + this._gutter.right)));
1305                     attr = {
1306                         left: {
1307                             to: -(this._lastWidth)
1308                         }
1309                     };
1310                     if (pos == 'right') {
1311                         attr.left = {
1312                             to: (this.get('left') + w)
1313                         };
1314                     }
1315                     break;
1316             }
1317             if (this._anim) {
1318                 this._anim.attributes = attr;
1319                 var collapse = function() {
1320                     this._collapsing = false;
1321                     this._toggleClip();
1322                     this.setStyle('zIndex', this.get('parent')._zIndex);
1323                     this._collapsed = true;
1324                     this.get('parent').resize();
1325                     this._anim.onComplete.unsubscribe(collapse, this, true);
1326                     this.fireEvent('collapse');
1327                 };
1328                 this._anim.onComplete.subscribe(collapse, this, true);
1329                 this._anim.animate();
1330             } else {
1331                 this._collapsing = false;
1332                 this.setStyle('display', 'none');
1333                 this._toggleClip();
1334                 this.setStyle('zIndex', this.get('parent')._zIndex);
1335                 this.get('parent').resize();
1336                 this._collapsed = true;
1337                 this.fireEvent('collapse');
1338             }
1339             return this;
1340         },
1341         /**
1342         * @method close
1343         * @description Close the unit, removing it from the parent Layout.
1344         * @return {<a href="YAHOO.widget.Layout.html">YAHOO.widget.Layout</a>} The parent Layout instance
1345         */
1346         close: function() {
1347             this.setStyle('display', 'none');
1348             this.get('parent').removeUnit(this);
1349             this.fireEvent('close');
1350             if (this._clip) {
1351                 this._clip.parentNode.removeChild(this._clip);
1352                 this._clip = null;
1353             }
1354             return this.get('parent');
1355         },
1356                 /**
1357         * @property loadHandler
1358         * @description Callback method for the YUI Connection Manager used for load the body using AJAX
1359         * @type Object
1360         */
1361                 loadHandler: {
1362             success: function(o) {
1363                                 this.body.innerHTML = o.responseText;
1364                                 this.resize (true);
1365             },
1366             failure: function(o) {
1367             }
1368         },
1369                 /**
1370         * @property dataConnection
1371         * @description YUI Connection Manager handler
1372         * @type Object
1373         */
1374                 dataConnection: null,
1375                 /**
1376         * @private
1377         * @property _loading
1378         * @description During the loading process this variable will be true
1379         * @type Number
1380         */
1381         _loading: false,
1382                 /**
1383         * @method loadContent
1384         * @description Loading the content of the unit using the connection manager
1385         * @return {object} YUI Connection Manager handler
1386         */
1387         loadContent: function() {
1388                         // load dynamic content unless already loading or loaded and caching
1389                         if (YAHOO.util.Connect && this.get('dataSrc') && !this._loading && !this.get('dataLoaded')) {
1390                         this._loading = true; 
1391                         Dom.addClass(this.body, this.LOADING_CLASSNAME);
1392                                 this.dataConnection = YAHOO.util.Connect.asyncRequest(
1393                             this.get('loadMethod'),
1394                             this.get('dataSrc'), 
1395                             {
1396                                 success: function(o) {
1397                                     this.loadHandler.success.call(this, o);
1398                                     this.set('dataLoaded', true);
1399                                     this.dataConnection = null;
1400                                     Dom.removeClass(this.body, this.LOADING_CLASSNAME);
1401                                                         this._loading = false;
1402                                                         this.fireEvent('load');
1403                                 },
1404                                 failure: function(o) {
1405                                     this.loadHandler.failure.call(this, o);
1406                                     this.dataConnection = null;
1407                                     Dom.removeClass(this.body, this.LOADING_CLASSNAME);
1408                                     this._loading = false;
1409                                                         this.fireEvent('loadError', { error: o });
1410                                 },
1411                                 scope: this,
1412                                 timeout: this.get('dataTimeout')
1413                             }
1414                         );
1415                                 return this.dataConnection;
1416                 }
1417                         return false;
1418         },
1419         /**
1420         * @private
1421         * @method init
1422         * @description The initalization method inherited from Element.
1423         */
1424         init: function(p_oElement, p_oAttributes) {
1425             this._gutter = {
1426                 left: 0,
1427                 right: 0,
1428                 top: 0,
1429                 bottom: 0
1430             };
1431             this._sizes = {
1432                 wrap: {
1433                     h: 0,
1434                     w: 0
1435                 },
1436                 header: {
1437                     h: 0,
1438                     w: 0
1439                 },
1440                 body: {
1441                     h: 0,
1442                     w: 0
1443                 },
1444                 footer: {
1445                     h: 0,
1446                     w: 0
1447                 }
1448             };
1449             
1450             LayoutUnit.superclass.init.call(this, p_oElement, p_oAttributes);
1451
1452             this.browser = this.get('parent').browser;
1453             
1454             var id = p_oElement;
1455             if (!Lang.isString(id)) {
1456                 id = Dom.generateId(id);
1457             }
1458             LayoutUnit._instances[id] = this;
1459
1460             this.setStyle('position', 'absolute');
1461
1462             this.addClass('yui-layout-unit');
1463             this.addClass('yui-layout-unit-' + this.get('position'));
1464
1465
1466             var header = this.getElementsByClassName('yui-layout-hd', 'div')[0];
1467             if (header) {
1468                 this.header = header;
1469             }
1470             var body = this.getElementsByClassName('yui-layout-bd', 'div')[0];
1471             if (body) {
1472                 this.body = body;
1473             }
1474             var footer = this.getElementsByClassName('yui-layout-ft', 'div')[0];
1475             if (footer) {
1476                 this.footer = footer;
1477             }
1478
1479             this.on('contentChange', this.resize, this, true);
1480             this._lastScrollTop = 0;
1481
1482             this.set('animate', this.get('animate'));
1483         },
1484         /**
1485         * @private
1486         * @method initAttributes
1487         * @description Processes the config
1488         */        
1489         initAttributes: function(attr) {
1490             LayoutUnit.superclass.initAttributes.call(this, attr);
1491
1492             /**
1493             * @private
1494             * @attribute wrap
1495             * @description A reference to the wrap element
1496             * @type HTMLElement
1497             */
1498             this.setAttributeConfig('wrap', {
1499                 value: attr.wrap || null,
1500                 method: function(w) {
1501                     if (w) {
1502                         var id = Dom.generateId(w);
1503                         LayoutUnit._instances[id] = this;
1504                     }
1505                 }
1506             });
1507             /**
1508             * @attribute grids
1509             * @description Set this option to true if you want the LayoutUnit to fix the first layer of YUI CSS Grids (margins)
1510             * @type Boolean
1511             */
1512             this.setAttributeConfig('grids', {
1513                 value: attr.grids || false
1514             });
1515             /**
1516             * @private
1517             * @attribute top
1518             * @description The current top positioning of the Unit
1519             * @type Number
1520             */
1521             this.setAttributeConfig('top', {
1522                 value: attr.top || 0,
1523                 validator: Lang.isNumber,
1524                 method: function(t) {
1525                     if (!this._collapsing) {
1526                         this.setStyle('top', t + 'px');
1527                     }
1528                 }
1529             });
1530             /**
1531             * @private
1532             * @attribute left
1533             * @description The current left position of the Unit
1534             * @type Number
1535             */
1536             this.setAttributeConfig('left', {
1537                 value: attr.left || 0,
1538                 validator: Lang.isNumber,
1539                 method: function(l) {
1540                     if (!this._collapsing) {
1541                         this.setStyle('left', l + 'px');
1542                     }
1543                 }
1544             });
1545
1546             /**
1547             * @attribute minWidth
1548             * @description The minWidth parameter passed to the Resize Utility
1549             * @type Number
1550             */
1551             this.setAttributeConfig('minWidth', {
1552                 value: attr.minWidth || false,
1553                 method: function(v) {
1554                     if (this._resize) {
1555                         this._resize.set('minWidth', v);
1556                     }
1557                 },
1558                 validator: YAHOO.lang.isNumber
1559             });
1560
1561             /**
1562             * @attribute maxWidth
1563             * @description The maxWidth parameter passed to the Resize Utility
1564             * @type Number
1565             */
1566             this.setAttributeConfig('maxWidth', {
1567                 value: attr.maxWidth || false,
1568                 method: function(v) {
1569                     if (this._resize) {
1570                         this._resize.set('maxWidth', v);
1571                     }
1572                 },
1573                 validator: YAHOO.lang.isNumber
1574             });
1575
1576             /**
1577             * @attribute minHeight
1578             * @description The minHeight parameter passed to the Resize Utility
1579             * @type Number
1580             */
1581             this.setAttributeConfig('minHeight', {
1582                 value: attr.minHeight || false,
1583                 method: function(v) {
1584                     if (this._resize) {
1585                         this._resize.set('minHeight', v);
1586                     }
1587                 },
1588                 validator: YAHOO.lang.isNumber
1589             });
1590
1591             /**
1592             * @attribute maxHeight
1593             * @description The maxHeight parameter passed to the Resize Utility
1594             * @type Number
1595             */
1596             this.setAttributeConfig('maxHeight', {
1597                 value: attr.maxHeight || false,
1598                 method: function(v) {
1599                     if (this._resize) {
1600                         this._resize.set('maxHeight', v);
1601                     }
1602                 },
1603                 validator: YAHOO.lang.isNumber
1604             });
1605
1606             /**
1607             * @attribute height
1608             * @description The height of the Unit
1609             * @type Number
1610             */
1611             this.setAttributeConfig('height', {
1612                 value: attr.height,
1613                 validator: Lang.isNumber,
1614                 method: function(h) {
1615                     if (!this._collapsing) {
1616                         if (h < 0) {
1617                             h = 0;
1618                         }
1619                         this.setStyle('height', h + 'px');
1620                     }
1621                 }
1622             });
1623
1624             /**
1625             * @attribute width
1626             * @description The width of the Unit
1627             * @type Number
1628             */
1629             this.setAttributeConfig('width', {
1630                 value: attr.width,
1631                 validator: Lang.isNumber,
1632                 method: function(w) {
1633                     if (!this._collapsing) {
1634                         if (w < 0) {
1635                             w = 0;
1636                         }
1637                         this.setStyle('width', w + 'px');
1638                     }
1639                 }
1640             });
1641             /**
1642             * @attribute zIndex
1643             * @description The CSS zIndex to give to the unit, so you can have overlapping elements such as menus in a unit.
1644             * @type {Number}
1645             */
1646             this.setAttributeConfig('zIndex', {
1647                 value: attr.zIndex || false,
1648                 method: function(z) {
1649                     this.setStyle('zIndex', z);
1650                 }
1651             });
1652             /**
1653             * @attribute position
1654             * @description The position (top, right, bottom, left or center) of the Unit in the Layout
1655             * @type {String}
1656             */
1657             this.setAttributeConfig('position', {
1658                 value: attr.position
1659             });
1660             /**
1661             * @attribute gutter
1662             * @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)
1663             * @type String
1664             */
1665             this.setAttributeConfig('gutter', {
1666                 value: attr.gutter || 0,
1667                 validator: YAHOO.lang.isString,
1668                 method: function(gutter) {
1669                     var p = gutter.split(' ');
1670                     if (p.length) {
1671                         this._gutter.top = parseInt(p[0], 10);
1672                         if (p[1]) {
1673                             this._gutter.right = parseInt(p[1], 10);
1674                         } else {
1675                             this._gutter.right = this._gutter.top;
1676                         }
1677                         if (p[2]) {
1678                             this._gutter.bottom = parseInt(p[2], 10);
1679                         } else {
1680                             this._gutter.bottom = this._gutter.top;
1681                         }
1682                         if (p[3]) {
1683                             this._gutter.left = parseInt(p[3], 10);
1684                         } else if (p[1]) {
1685                             this._gutter.left = this._gutter.right;
1686                         } else {
1687                             this._gutter.left = this._gutter.top;
1688                         }
1689                     }
1690                 }
1691             });
1692             /**
1693             * @attribute parent
1694             * @description The parent Layout that we are assigned to
1695             * @type {Object} YAHOO.widget.Layout
1696             */
1697             this.setAttributeConfig('parent', {
1698                 writeOnce: true,
1699                 value: attr.parent || false,
1700                 method: function(p) {
1701                     if (p) {
1702                         p.on('resize', this.resize, this, true);
1703                     }
1704
1705                 }
1706             });
1707             /**
1708             * @attribute collapseSize
1709             * @description The pixel size of the Clip that we will collapse to
1710             * @type Number
1711             */
1712             this.setAttributeConfig('collapseSize', {
1713                 value: attr.collapseSize || 25,
1714                 validator: YAHOO.lang.isNumber
1715             });
1716             /**
1717             * @attribute duration
1718             * @description The duration to give the Animation Utility when animating the opening and closing of Units
1719             */
1720             this.setAttributeConfig('duration', {
1721                 value: attr.duration || 0.5
1722             });
1723             /**
1724             * @attribute easing
1725             * @description The Animation Easing to apply to the Animation instance for this unit.
1726             */
1727             this.setAttributeConfig('easing', {
1728                 value: attr.easing || ((YAHOO.util && YAHOO.util.Easing) ? YAHOO.util.Easing.BounceIn : 'false')
1729             });
1730             /**
1731             * @attribute animate
1732             * @description Use animation to collapse/expand the unit
1733             * @type Boolean
1734             */
1735             this.setAttributeConfig('animate', {
1736                 value: ((attr.animate === false) ? false : true),
1737                 validator: function() {
1738                     var anim = false;
1739                     if (YAHOO.util.Anim) {
1740                         anim = true;
1741                     }
1742                     return anim;
1743                 },
1744                 method: function(anim) {
1745                     if (anim) {
1746                         this._anim = new YAHOO.util.Anim(this.get('element'), {}, this.get('duration'), this.get('easing'));
1747                     } else {
1748                         this._anim = false;
1749                     }
1750                 }
1751             });
1752             /**
1753             * @attribute header
1754             * @description The text to use as the Header of the Unit
1755             */
1756             this.setAttributeConfig('header', {
1757                 value: attr.header || false,
1758                 method: function(txt) {
1759                     if (txt === false) {
1760                         //Remove the footer
1761                         if (this.header) {
1762                             Dom.addClass(this.body, 'yui-layout-bd-nohd');
1763                             this.header.parentNode.removeChild(this.header);
1764                             this.header = null;
1765                         }
1766                     } else {
1767                         if (!this.header) {
1768                             var header = this.getElementsByClassName('yui-layout-hd', 'div')[0];
1769                             if (!header) {
1770                                 header = this._createHeader();
1771                             }
1772                             this.header = header;
1773                         }
1774                         var h = this.header.getElementsByTagName('h2')[0];
1775                         if (!h) {
1776                             h = document.createElement('h2');
1777                             this.header.appendChild(h);
1778                         }
1779                         h.innerHTML = txt;
1780                         if (this.body) {
1781                             Dom.removeClass(this.body, 'yui-layout-bd-nohd');
1782                         }
1783                     }
1784                     this.fireEvent('contentChange', { target: 'header' });
1785                 }
1786             });
1787             /**
1788             * @attribute proxy
1789             * @description Use the proxy config setting for the Resize Utility
1790             * @type Boolean
1791             */
1792             this.setAttributeConfig('proxy', {
1793                 writeOnce: true,
1794                 value: ((attr.proxy === false) ? false : true)
1795             });
1796             /**
1797             * @attribute body
1798             * @description The content for the body. If we find an element in the page with an id that matches the passed option we will move that element into the body of this unit.
1799             */
1800             this.setAttributeConfig('body', {
1801                 value: attr.body || false,
1802                 method: function(content) {
1803                     if (!this.body) {
1804                         var body = this.getElementsByClassName('yui-layout-bd', 'div')[0];
1805                         if (body) {
1806                             this.body = body;
1807                         } else {
1808                             body = document.createElement('div');
1809                             body.className = 'yui-layout-bd';
1810                             this.body = body;
1811                             this.get('wrap').appendChild(body);
1812                         }
1813                     }
1814                     if (!this.header) {
1815                         Dom.addClass(this.body, 'yui-layout-bd-nohd');
1816                     }
1817                     Dom.addClass(this.body, 'yui-layout-bd-noft');
1818
1819
1820                     var el = null;
1821                     if (Lang.isString(content)) {
1822                         el = Dom.get(content);
1823                     } else if (content && content.tagName) {
1824                         el = content;
1825                     }
1826                     if (el) {
1827                         var id = Dom.generateId(el);
1828                         LayoutUnit._instances[id] = this;
1829                         this.body.appendChild(el);
1830                     } else {
1831                         this.body.innerHTML = content;
1832                     }
1833
1834                     this._cleanGrids();
1835
1836                     this.fireEvent('contentChange', { target: 'body' });
1837                 }
1838             });
1839
1840             /**
1841             * @attribute footer
1842             * @description The content for the footer. If we find an element in the page with an id that matches the passed option we will move that element into the footer of this unit.
1843             */
1844             this.setAttributeConfig('footer', {
1845                 value: attr.footer || false,
1846                 method: function(content) {
1847                     if (content === false) {
1848                         //Remove the footer
1849                         if (this.footer) {
1850                             Dom.addClass(this.body, 'yui-layout-bd-noft');
1851                             this.footer.parentNode.removeChild(this.footer);
1852                             this.footer = null;
1853                         }
1854                     } else {
1855                         if (!this.footer) {
1856                             var ft = this.getElementsByClassName('yui-layout-ft', 'div')[0];
1857                             if (!ft) {
1858                                 ft = document.createElement('div');
1859                                 ft.className = 'yui-layout-ft';
1860                                 this.footer = ft;
1861                                 this.get('wrap').appendChild(ft);
1862                             } else {
1863                                 this.footer = ft;
1864                             }
1865                         }
1866                         var el = null;
1867                         if (Lang.isString(content)) {
1868                             el = Dom.get(content);
1869                         } else if (content && content.tagName) {
1870                             el = content;
1871                         }
1872                         if (el) {
1873                             this.footer.appendChild(el);
1874                         } else {
1875                             this.footer.innerHTML = content;
1876                         }
1877                         Dom.removeClass(this.body, 'yui-layout-bd-noft');
1878                     }
1879                     this.fireEvent('contentChange', { target: 'footer' });
1880                 }
1881             });
1882             /**
1883             * @attribute close
1884             * @description Adds a close icon to the unit
1885             */
1886             this.setAttributeConfig('close', {
1887                 value: attr.close || false,
1888                 method: function(close) {
1889                     //Position Center doesn't get this
1890                     if (this.get('position') == 'center') {
1891                         return false;
1892                     }
1893                     if (!this.header && close) {
1894                         this._createHeader();
1895                     }
1896                     var c = Dom.getElementsByClassName('close', 'div', this.header)[0];
1897                     if (close) {
1898                         //Force some header text if there isn't any
1899                         if (!this.get('header')) {
1900                             this.set('header', '&nbsp;');
1901                         }
1902                         if (!c) {
1903                             c = document.createElement('div');
1904                             c.className = 'close';
1905                             this.header.appendChild(c);
1906                             Event.on(c, 'click', this.close, this, true);
1907                         }
1908                         c.title = this.STR_CLOSE;
1909                     } else if (c && c.parentNode) {
1910                         Event.purgeElement(c);
1911                         c.parentNode.removeChild(c);
1912                     }
1913                     this._configs.close.value = close;
1914                     this.set('collapse', this.get('collapse')); //Reset so we get the right classnames
1915                 }
1916             });
1917
1918             /**
1919             * @attribute collapse
1920             * @description Adds a collapse icon to the unit
1921             */
1922             this.setAttributeConfig('collapse', {
1923                 value: attr.collapse || false,
1924                 method: function(collapse) {
1925                     //Position Center doesn't get this
1926                     if (this.get('position') == 'center') {
1927                         return false;
1928                     }
1929                     if (!this.header && collapse) {
1930                         this._createHeader();
1931                     }
1932                     var c = Dom.getElementsByClassName('collapse', 'div', this.header)[0];
1933                     if (collapse) {
1934                         //Force some header text if there isn't any
1935                         if (!this.get('header')) {
1936                             this.set('header', '&nbsp;');
1937                         }
1938                         if (!c) {
1939                             c = document.createElement('div');
1940                             this.header.appendChild(c);
1941                             Event.on(c, 'click', this.collapse, this, true);
1942                         }
1943                         c.title = this.STR_COLLAPSE;
1944                         c.className = 'collapse' + ((this.get('close')) ? ' collapse-close' : '');
1945                     } else if (c && c.parentNode) {
1946                         Event.purgeElement(c);
1947                         c.parentNode.removeChild(c);
1948                     }
1949                 }
1950             });
1951             /**
1952             * @attribute scroll
1953             * @description Adds a class to the unit to allow for overflow: auto (yui-layout-scroll), default is overflow: hidden (yui-layout-noscroll). If true scroll bars will be placed on the element when the content exceeds the given area, false will put overflow hidden to hide the content. Passing null will render the content as usual overflow.
1954             * @type Boolean/Null
1955             */
1956
1957             this.setAttributeConfig('scroll', {
1958                 value: (((attr.scroll === true) || (attr.scroll === false) || (attr.scroll === null)) ? attr.scroll : false),
1959                 method: function(scroll) {
1960                     if ((scroll === false) && !this._collapsed) { //Removing scroll bar
1961                         if (this.body) {
1962                             if (this.body.scrollTop > 0) {
1963                                 this._lastScrollTop = this.body.scrollTop;
1964                             }
1965                         }
1966                     }
1967                     
1968                     if (scroll === true) {
1969                         this.addClass('yui-layout-scroll');
1970                         this.removeClass('yui-layout-noscroll');
1971                         if (this._lastScrollTop > 0) {
1972                             if (this.body) {
1973                                 this.body.scrollTop = this._lastScrollTop;
1974                             }
1975                         }
1976                     } else if (scroll === false) {
1977                         this.removeClass('yui-layout-scroll');
1978                         this.addClass('yui-layout-noscroll');
1979                     } else if (scroll === null) {
1980                         this.removeClass('yui-layout-scroll');
1981                         this.removeClass('yui-layout-noscroll');
1982                     }
1983                 }
1984             });
1985             /**
1986             * @attribute hover
1987             * @description Config option to pass to the Resize Utility
1988             */
1989             this.setAttributeConfig('hover', {
1990                 writeOnce: true,
1991                 value: attr.hover || false,
1992                 validator: YAHOO.lang.isBoolean
1993             });
1994             /**
1995             * @attribute useShim
1996             * @description Config option to pass to the Resize Utility
1997             */
1998             this.setAttributeConfig('useShim', {
1999                 value: attr.useShim || false,
2000                 validator: YAHOO.lang.isBoolean,
2001                 method: function(u) {
2002                     if (this._resize) {
2003                         this._resize.set('useShim', u);
2004                     }
2005                 }
2006             });
2007             /**
2008             * @attribute resize
2009             * @description Should a Resize instance be added to this unit
2010             */
2011
2012             this.setAttributeConfig('resize', {
2013                 value: attr.resize || false,
2014                 validator: function(r) {
2015                     if (YAHOO.util && YAHOO.util.Resize) {
2016                         return true;
2017                     }
2018                     return false;
2019                 },
2020                 method: function(resize) {
2021                     if (resize && !this._resize) {
2022                         //Position Center doesn't get this
2023                         if (this.get('position') == 'center') {
2024                             return false;
2025                         }
2026                         var handle = false; //To catch center
2027                         switch (this.get('position')) {
2028                             case 'top':
2029                                 handle = 'b';
2030                                 break;
2031                             case 'bottom':
2032                                 handle = 't';
2033                                 break;
2034                             case 'right':
2035                                 handle = 'l';
2036                                 break;
2037                             case 'left':
2038                                 handle = 'r';
2039                                 break;
2040                         }
2041
2042                         this.setStyle('position', 'absolute'); //Make sure Resize get's a position
2043                         
2044                         if (handle) {
2045                             this._resize = new YAHOO.util.Resize(this.get('element'), {
2046                                 proxy: this.get('proxy'),
2047                                 hover: this.get('hover'),
2048                                 status: false,
2049                                 autoRatio: false,
2050                                 handles: [handle],
2051                                 minWidth: this.get('minWidth'),
2052                                 maxWidth: this.get('maxWidth'),
2053                                 minHeight: this.get('minHeight'),
2054                                 maxHeight: this.get('maxHeight'),
2055                                 height: this.get('height'),
2056                                 width: this.get('width'),
2057                                 setSize: false,
2058                                 useShim: this.get('useShim'),
2059                                 wrap: false
2060                             });
2061                             
2062                             this._resize._handles[handle].innerHTML = '<div class="yui-layout-resize-knob"></div>';
2063
2064                             if (this.get('proxy')) {
2065                                 var proxy = this._resize.getProxyEl();
2066                                 proxy.innerHTML = '<div class="yui-layout-handle-' + handle + '"></div>';
2067                             }
2068                             this._resize.on('startResize', function(ev) {
2069                                 this._lastScroll = this.get('scroll');
2070                                 this.set('scroll', false);
2071                                 if (this.get('parent')) {
2072                                     this.get('parent').fireEvent('startResize');
2073                                     var c = this.get('parent').getUnitByPosition('center');
2074                                     this._lastCenterScroll = c.get('scroll');
2075                                     c.addClass(this._resize.CSS_RESIZING);
2076                                     c.set('scroll', false);
2077                                 }
2078                                 this.fireEvent('startResize');
2079                             }, this, true);
2080                             this._resize.on('resize', function(ev) {
2081                                 this.set('height', ev.height);
2082                                 this.set('width', ev.width);
2083                             }, this, true);
2084                             this._resize.on('endResize', function(ev) {
2085                                 this.set('scroll', this._lastScroll);
2086                                 if (this.get('parent')) {
2087                                     var c = this.get('parent').getUnitByPosition('center');
2088                                     c.set('scroll', this._lastCenterScroll);
2089                                     c.removeClass(this._resize.CSS_RESIZING);
2090                                 }
2091                                 this.resize();
2092                                 this.fireEvent('endResize');
2093                             }, this, true);
2094                         }
2095                     } else {
2096                         if (this._resize) {
2097                             this._resize.destroy();
2098                         }
2099                     }
2100                 }
2101             });
2102                         /**
2103                  * The unit data source, used for loading content dynamically.
2104                  * @attribute dataSrc
2105                  * @type String
2106                  */
2107                 this.setAttributeConfig('dataSrc', {
2108                     value: attr.dataSrc
2109                 });
2110                 /**
2111                  * The method to use for the data request.
2112                  * @attribute loadMethod
2113                  * @type String
2114                  * @default "GET"
2115                  */
2116                 this.setAttributeConfig('loadMethod', {
2117                     value: attr.loadMethod || 'GET',
2118                     validator: YAHOO.lang.isString
2119                 });     
2120                 /**
2121                  * Whether or not any data has been loaded from the server.
2122                  * @attribute dataLoaded
2123                  * @type Boolean
2124                  */        
2125                 this.setAttributeConfig('dataLoaded', {
2126                     value: false,
2127                     validator: YAHOO.lang.isBoolean,
2128                     writeOnce: true
2129                 });
2130                 /**
2131                  * Number if milliseconds before aborting and calling failure handler.
2132                  * @attribute dataTimeout
2133                  * @type Number
2134                  * @default null
2135                  */
2136                 this.setAttributeConfig('dataTimeout', {
2137                     value: attr.dataTimeout || null,
2138                     validator: YAHOO.lang.isNumber
2139                 });
2140         },
2141         /**
2142         * @private
2143         * @method _cleanGrids
2144         * @description This method attempts to clean up the first level of the YUI CSS Grids, YAHOO.util.Selector is required for this operation.
2145         */
2146         _cleanGrids: function() {
2147             if (this.get('grids')) {
2148                 var b = Sel.query('div.yui-b', this.body, true);
2149                 if (b) {
2150                     Dom.removeClass(b, 'yui-b');
2151                 }
2152                 Event.onAvailable('yui-main', function() {
2153                     Dom.setStyle(Sel.query('#yui-main'), 'margin-left', '0');
2154                     Dom.setStyle(Sel.query('#yui-main'), 'margin-right', '0');
2155                 });
2156             }
2157         },
2158         /**
2159         * @private
2160         * @method _createHeader
2161         * @description Creates the HTMLElement for the header
2162         * @return {HTMLElement} The new HTMLElement
2163         */
2164         _createHeader: function() {
2165             var header = document.createElement('div');
2166             header.className = 'yui-layout-hd';
2167             if (this.get('firstChild')) {
2168                 this.get('wrap').insertBefore(header, this.get('wrap').firstChild);
2169             } else {
2170                 this.get('wrap').appendChild(header);
2171             }
2172             this.header = header;
2173             return header;
2174         },
2175         /**
2176         * @method destroy
2177         * @param {Boolean} force Don't report to the parent, because we are being called from the parent.
2178         * @description Removes this unit from the parent and cleans up after itself.
2179         * @return {<a href="YAHOO.widget.Layout.html">YAHOO.widget.Layout</a>} The parent Layout instance
2180         */
2181         destroy: function(force) {
2182             if (this._resize) {
2183                 this._resize.destroy();
2184             }
2185             var par = this.get('parent');
2186
2187             this.setStyle('display', 'none');
2188             if (this._clip) {
2189                 this._clip.parentNode.removeChild(this._clip);
2190                 this._clip = null;
2191             }
2192
2193             if (!force) {
2194                 par.removeUnit(this);
2195             }
2196             
2197             if (par) {
2198                 par.removeListener('resize', this.resize, this, true);
2199             }
2200             this.unsubscribeAll();
2201             Event.purgeElement(this.get('element'));
2202             this.get('parentNode').removeChild(this.get('element'));
2203
2204             delete YAHOO.widget.LayoutUnit._instances[this.get('id')];
2205             //Brutal Object Destroy
2206             for (var i in this) {
2207                 if (Lang.hasOwnProperty(this, i)) {
2208                     this[i] = null;
2209                     delete this[i];
2210                 }
2211             }
2212         
2213             return par;
2214         },
2215         /**
2216         * @method toString
2217         * @description Returns a string representing the LayoutUnit.
2218         * @return {String}
2219         */        
2220         toString: function() {
2221             if (this.get) {
2222                 return 'LayoutUnit #' + this.get('id') + ' (' + this.get('position') + ')';
2223             }
2224             return 'LayoutUnit';
2225         }
2226     /**
2227     * @event resize
2228     * @description Fired when this.resize is called
2229     * @type YAHOO.util.CustomEvent
2230     */
2231     /**
2232     * @event startResize
2233     * @description Fired when the Resize Utility fires it's startResize Event.
2234     * @type YAHOO.util.CustomEvent
2235     */
2236     /**
2237     * @event endResize
2238     * @description Fired when the Resize Utility fires it's endResize Event.
2239     * @type YAHOO.util.CustomEvent
2240     */
2241     /**
2242     * @event beforeResize
2243     * @description Fired at the beginning of the resize method. If you return false, the resize is cancelled.
2244     * @type YAHOO.util.CustomEvent
2245     */
2246     /**
2247     * @event contentChange
2248     * @description Fired when the content in the header, body or footer is changed via the API
2249     * @type YAHOO.util.CustomEvent
2250     */
2251     /**
2252     * @event close
2253     * @description Fired when the unit is closed
2254     * @type YAHOO.util.CustomEvent
2255     */
2256     /**
2257     * @event beforeCollapse
2258     * @description Fired before the unit is collapsed. If you return false, the collapse is cancelled.
2259     * @type YAHOO.util.CustomEvent
2260     */
2261     /**
2262     * @event collapse
2263     * @description Fired when the unit is collapsed
2264     * @type YAHOO.util.CustomEvent
2265     */
2266     /**
2267     * @event expand
2268     * @description Fired when the unit is exanded
2269     * @type YAHOO.util.CustomEvent
2270     */
2271     /**
2272     * @event beforeExpand
2273     * @description Fired before the unit is exanded. If you return false, the collapse is cancelled.
2274     * @type YAHOO.util.CustomEvent
2275     */
2276     /**
2277     * @event load
2278     * @description Fired when data is loaded via the dataSrc config.
2279     * @type YAHOO.util.CustomEvent
2280     */
2281     /**
2282     * @event loadError
2283     * @description Fired when an error occurs loading data via the dataSrc config. Error message is passed as argument to this event.
2284     * @type YAHOO.util.CustomEvent
2285     */
2286     });
2287
2288     YAHOO.widget.LayoutUnit = LayoutUnit;
2289 })();
2290 YAHOO.register("layout", YAHOO.widget.Layout, {version: "2.8.0r4", build: "2449"});