]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/yui/build/layout/layout.js
Release 6.5.0
[Github/sugarcrm.git] / include / javascript / yui / build / layout / layout.js
1 /*
2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 2.9.0
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'), true);
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._zIndex);
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._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._zIndex = this.getStyle('zIndex');
1239                 this.setStyle('zIndex', this.get('parent')._zIndex);
1240                 this.setStyle('display', 'block');
1241                 this.set('width', this._lastWidth);
1242                 this.set('height', this._lastHeight);
1243                 this.resize();
1244                 this.set('scroll', this._lastScroll);
1245                 if (this._lastScrollTop > 0) {
1246                     this.body.scrollTop = this._lastScrollTop;
1247                 }
1248                 this.fireEvent('expand');
1249             }
1250             return this;
1251         },
1252         /**
1253         * @method collapse
1254         * @description Collapse the Unit if it is not collapsed.
1255         * @return {<a href="YAHOO.widget.LayoutUnit.html">YAHOO.widget.LayoutUnit</a>} The LayoutUnit instance
1256         */
1257         collapse: function() {
1258             if (this._collapsed) {
1259                 return this;
1260             }
1261             var retValue = this.fireEvent('beforeCollapse');
1262             if (retValue === false) {
1263                 return this;
1264             }
1265             if (!this._clip) {
1266                 this._createClip();
1267             }
1268             this._collapsing = true;
1269             var w = this.get('width'),
1270                 h = this.get('height'),
1271                 attr = {};
1272             this._lastWidth = w;
1273             this._lastHeight = h;
1274             this._lastScroll = this.get('scroll');
1275             this._lastScrollTop = this.body.scrollTop;            
1276             this.set('scroll', false, true);
1277             this._lastLeft = parseInt(this.get('element').style.left, 10);
1278             this._lastTop = parseInt(this.get('element').style.top, 10);
1279             if (isNaN(this._lastTop)) {
1280                 this._lastTop = 0;
1281                 this.set('top', 0);
1282             }
1283             if (isNaN(this._lastLeft)) {
1284                 this._lastLeft = 0;
1285                 this.set('left', 0);
1286             }
1287             this._zIndex = this.getStyle('zIndex');
1288             this.setStyle('zIndex', this.get('parent')._zIndex + 1);
1289             var pos = this.get('position');
1290
1291             switch (pos) {
1292                 case 'top':
1293                 case 'bottom':
1294                     this.set('height', (this.get('collapseSize') + (this._gutter.top + this._gutter.bottom)));
1295                     attr = {
1296                         top: {
1297                             to: (this.get('top') - h)
1298                         }
1299                     };
1300                     if (pos == 'bottom') {
1301                         attr.top.to = (this.get('top') + h);
1302                     }
1303                     break;
1304                 case 'left':
1305                 case 'right':
1306                     this.set('width', (this.get('collapseSize') + (this._gutter.left + this._gutter.right)));
1307                     attr = {
1308                         left: {
1309                             to: -(this._lastWidth)
1310                         }
1311                     };
1312                     if (pos == 'right') {
1313                         attr.left = {
1314                             to: (this.get('left') + w)
1315                         };
1316                     }
1317                     break;
1318             }
1319             if (this._anim) {
1320                 this._anim.attributes = attr;
1321                 var collapse = function() {
1322                     this._collapsing = false;
1323                     this._toggleClip();
1324                     this.setStyle('zIndex', this.get('parent')._zIndex);
1325                     this._collapsed = true;
1326                     this.get('parent').resize();
1327                     this._anim.onComplete.unsubscribe(collapse, this, true);
1328                     this.fireEvent('collapse');
1329                 };
1330                 this._anim.onComplete.subscribe(collapse, this, true);
1331                 this._anim.animate();
1332             } else {
1333                 this._collapsing = false;
1334                 this.setStyle('display', 'none');
1335                 this._toggleClip();
1336                 this.setStyle('zIndex', this.get('parent')._zIndex);
1337                 this.get('parent').resize();
1338                 this._collapsed = true;
1339                 this.fireEvent('collapse');
1340             }
1341             return this;
1342         },
1343         /**
1344         * @method close
1345         * @description Close the unit, removing it from the parent Layout.
1346         * @return {<a href="YAHOO.widget.Layout.html">YAHOO.widget.Layout</a>} The parent Layout instance
1347         */
1348         close: function() {
1349             this.setStyle('display', 'none');
1350             this.get('parent').removeUnit(this);
1351             this.fireEvent('close');
1352             if (this._clip) {
1353                 this._clip.parentNode.removeChild(this._clip);
1354                 this._clip = null;
1355             }
1356             return this.get('parent');
1357         },
1358                 /**
1359         * @property loadHandler
1360         * @description Callback method for the YUI Connection Manager used for load the body using AJAX. NOTE: e.responseText is loaded via innerHTML.
1361         * @type Object
1362         */
1363                 loadHandler: {
1364             success: function(o) {
1365                                 this.body.innerHTML = o.responseText;
1366                                 this.resize (true);
1367             },
1368             failure: function(o) {
1369             }
1370         },
1371                 /**
1372         * @property dataConnection
1373         * @description YUI Connection Manager handler
1374         * @type Object
1375         */
1376                 dataConnection: null,
1377                 /**
1378         * @private
1379         * @property _loading
1380         * @description During the loading process this variable will be true
1381         * @type Number
1382         */
1383         _loading: false,
1384                 /**
1385         * @method loadContent
1386         * @description Loading the content of the unit using the connection manager
1387         * @return {object} YUI Connection Manager handler
1388         */
1389         loadContent: function() {
1390                         // load dynamic content unless already loading or loaded and caching
1391                         if (YAHOO.util.Connect && this.get('dataSrc') && !this._loading && !this.get('dataLoaded')) {
1392                         this._loading = true; 
1393                         Dom.addClass(this.body, this.LOADING_CLASSNAME);
1394                                 this.dataConnection = YAHOO.util.Connect.asyncRequest(
1395                             this.get('loadMethod'),
1396                             this.get('dataSrc'), 
1397                             {
1398                                 success: function(o) {
1399                                     this.loadHandler.success.call(this, o);
1400                                     this.set('dataLoaded', true);
1401                                     this.dataConnection = null;
1402                                     Dom.removeClass(this.body, this.LOADING_CLASSNAME);
1403                                                         this._loading = false;
1404                                                         this.fireEvent('load');
1405                                 },
1406                                 failure: function(o) {
1407                                     this.loadHandler.failure.call(this, o);
1408                                     this.dataConnection = null;
1409                                     Dom.removeClass(this.body, this.LOADING_CLASSNAME);
1410                                     this._loading = false;
1411                                                         this.fireEvent('loadError', { error: o });
1412                                 },
1413                                 scope: this,
1414                                 timeout: this.get('dataTimeout')
1415                             }
1416                         );
1417                                 return this.dataConnection;
1418                 }
1419                         return false;
1420         },
1421         /**
1422         * @private
1423         * @method init
1424         * @description The initalization method inherited from Element.
1425         */
1426         init: function(p_oElement, p_oAttributes) {
1427             this._gutter = {
1428                 left: 0,
1429                 right: 0,
1430                 top: 0,
1431                 bottom: 0
1432             };
1433             this._sizes = {
1434                 wrap: {
1435                     h: 0,
1436                     w: 0
1437                 },
1438                 header: {
1439                     h: 0,
1440                     w: 0
1441                 },
1442                 body: {
1443                     h: 0,
1444                     w: 0
1445                 },
1446                 footer: {
1447                     h: 0,
1448                     w: 0
1449                 }
1450             };
1451             
1452             LayoutUnit.superclass.init.call(this, p_oElement, p_oAttributes);
1453
1454             this.browser = this.get('parent').browser;
1455             
1456             var id = p_oElement;
1457             if (!Lang.isString(id)) {
1458                 id = Dom.generateId(id);
1459             }
1460             LayoutUnit._instances[id] = this;
1461
1462             this.setStyle('position', 'absolute');
1463
1464             this.addClass('yui-layout-unit');
1465             this.addClass('yui-layout-unit-' + this.get('position'));
1466
1467
1468             var header = this.getElementsByClassName('yui-layout-hd', 'div')[0];
1469             if (header) {
1470                 this.header = header;
1471             }
1472             var body = this.getElementsByClassName('yui-layout-bd', 'div')[0];
1473             if (body) {
1474                 this.body = body;
1475             }
1476             var footer = this.getElementsByClassName('yui-layout-ft', 'div')[0];
1477             if (footer) {
1478                 this.footer = footer;
1479             }
1480
1481             this.on('contentChange', this.resize, this, true);
1482             this._lastScrollTop = 0;
1483
1484             this.set('animate', this.get('animate'));
1485         },
1486         /**
1487         * @private
1488         * @method initAttributes
1489         * @description Processes the config
1490         */        
1491         initAttributes: function(attr) {
1492             LayoutUnit.superclass.initAttributes.call(this, attr);
1493
1494             /**
1495             * @private
1496             * @attribute wrap
1497             * @description A reference to the wrap element
1498             * @type HTMLElement
1499             */
1500             this.setAttributeConfig('wrap', {
1501                 value: attr.wrap || null,
1502                 method: function(w) {
1503                     if (w) {
1504                         var id = Dom.generateId(w);
1505                         LayoutUnit._instances[id] = this;
1506                     }
1507                 }
1508             });
1509             /**
1510             * @attribute grids
1511             * @description Set this option to true if you want the LayoutUnit to fix the first layer of YUI CSS Grids (margins)
1512             * @type Boolean
1513             */
1514             this.setAttributeConfig('grids', {
1515                 value: attr.grids || false
1516             });
1517             /**
1518             * @private
1519             * @attribute top
1520             * @description The current top positioning of the Unit
1521             * @type Number
1522             */
1523             this.setAttributeConfig('top', {
1524                 value: attr.top || 0,
1525                 validator: Lang.isNumber,
1526                 method: function(t) {
1527                     if (!this._collapsing) {
1528                         this.setStyle('top', t + 'px');
1529                     }
1530                 }
1531             });
1532             /**
1533             * @private
1534             * @attribute left
1535             * @description The current left position of the Unit
1536             * @type Number
1537             */
1538             this.setAttributeConfig('left', {
1539                 value: attr.left || 0,
1540                 validator: Lang.isNumber,
1541                 method: function(l) {
1542                     if (!this._collapsing) {
1543                         this.setStyle('left', l + 'px');
1544                     }
1545                 }
1546             });
1547
1548             /**
1549             * @attribute minWidth
1550             * @description The minWidth parameter passed to the Resize Utility
1551             * @type Number
1552             */
1553             this.setAttributeConfig('minWidth', {
1554                 value: attr.minWidth || false,
1555                 method: function(v) {
1556                     if (this._resize) {
1557                         this._resize.set('minWidth', v);
1558                     }
1559                 },
1560                 validator: YAHOO.lang.isNumber
1561             });
1562
1563             /**
1564             * @attribute maxWidth
1565             * @description The maxWidth parameter passed to the Resize Utility
1566             * @type Number
1567             */
1568             this.setAttributeConfig('maxWidth', {
1569                 value: attr.maxWidth || false,
1570                 method: function(v) {
1571                     if (this._resize) {
1572                         this._resize.set('maxWidth', v);
1573                     }
1574                 },
1575                 validator: YAHOO.lang.isNumber
1576             });
1577
1578             /**
1579             * @attribute minHeight
1580             * @description The minHeight parameter passed to the Resize Utility
1581             * @type Number
1582             */
1583             this.setAttributeConfig('minHeight', {
1584                 value: attr.minHeight || false,
1585                 method: function(v) {
1586                     if (this._resize) {
1587                         this._resize.set('minHeight', v);
1588                     }
1589                 },
1590                 validator: YAHOO.lang.isNumber
1591             });
1592
1593             /**
1594             * @attribute maxHeight
1595             * @description The maxHeight parameter passed to the Resize Utility
1596             * @type Number
1597             */
1598             this.setAttributeConfig('maxHeight', {
1599                 value: attr.maxHeight || false,
1600                 method: function(v) {
1601                     if (this._resize) {
1602                         this._resize.set('maxHeight', v);
1603                     }
1604                 },
1605                 validator: YAHOO.lang.isNumber
1606             });
1607
1608             /**
1609             * @attribute height
1610             * @description The height of the Unit
1611             * @type Number
1612             */
1613             this.setAttributeConfig('height', {
1614                 value: attr.height,
1615                 validator: Lang.isNumber,
1616                 method: function(h) {
1617                     if (!this._collapsing) {
1618                         if (h < 0) {
1619                             h = 0;
1620                         }
1621                         this.setStyle('height', h + 'px');
1622                     }
1623                 }
1624             });
1625
1626             /**
1627             * @attribute width
1628             * @description The width of the Unit
1629             * @type Number
1630             */
1631             this.setAttributeConfig('width', {
1632                 value: attr.width,
1633                 validator: Lang.isNumber,
1634                 method: function(w) {
1635                     if (!this._collapsing) {
1636                         if (w < 0) {
1637                             w = 0;
1638                         }
1639                         this.setStyle('width', w + 'px');
1640                     }
1641                 }
1642             });
1643             /**
1644             * @attribute zIndex
1645             * @description The CSS zIndex to give to the unit, so you can have overlapping elements such as menus in a unit.
1646             * @type {Number}
1647             */
1648             this.setAttributeConfig('zIndex', {
1649                 value: attr.zIndex || false,
1650                 method: function(z) {
1651                     this.setStyle('zIndex', z);
1652                 }
1653             });
1654             /**
1655             * @attribute position
1656             * @description The position (top, right, bottom, left or center) of the Unit in the Layout
1657             * @type {String}
1658             */
1659             this.setAttributeConfig('position', {
1660                 value: attr.position
1661             });
1662             /**
1663             * @attribute gutter
1664             * @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)
1665             * @type String
1666             */
1667             this.setAttributeConfig('gutter', {
1668                 value: attr.gutter || 0,
1669                 validator: YAHOO.lang.isString,
1670                 method: function(gutter) {
1671                     var p = gutter.split(' ');
1672                     if (p.length) {
1673                         this._gutter.top = parseInt(p[0], 10);
1674                         if (p[1]) {
1675                             this._gutter.right = parseInt(p[1], 10);
1676                         } else {
1677                             this._gutter.right = this._gutter.top;
1678                         }
1679                         if (p[2]) {
1680                             this._gutter.bottom = parseInt(p[2], 10);
1681                         } else {
1682                             this._gutter.bottom = this._gutter.top;
1683                         }
1684                         if (p[3]) {
1685                             this._gutter.left = parseInt(p[3], 10);
1686                         } else if (p[1]) {
1687                             this._gutter.left = this._gutter.right;
1688                         } else {
1689                             this._gutter.left = this._gutter.top;
1690                         }
1691                     }
1692                 }
1693             });
1694             /**
1695             * @attribute parent
1696             * @description The parent Layout that we are assigned to
1697             * @type {Object} YAHOO.widget.Layout
1698             */
1699             this.setAttributeConfig('parent', {
1700                 writeOnce: true,
1701                 value: attr.parent || false,
1702                 method: function(p) {
1703                     if (p) {
1704                         p.on('resize', this.resize, this, true);
1705                     }
1706
1707                 }
1708             });
1709             /**
1710             * @attribute collapseSize
1711             * @description The pixel size of the Clip that we will collapse to
1712             * @type Number
1713             */
1714             this.setAttributeConfig('collapseSize', {
1715                 value: attr.collapseSize || 25,
1716                 validator: YAHOO.lang.isNumber
1717             });
1718             /**
1719             * @attribute duration
1720             * @description The duration to give the Animation Utility when animating the opening and closing of Units
1721             */
1722             this.setAttributeConfig('duration', {
1723                 value: attr.duration || 0.5
1724             });
1725             /**
1726             * @attribute easing
1727             * @description The Animation Easing to apply to the Animation instance for this unit.
1728             */
1729             this.setAttributeConfig('easing', {
1730                 value: attr.easing || ((YAHOO.util && YAHOO.util.Easing) ? YAHOO.util.Easing.BounceIn : 'false')
1731             });
1732             /**
1733             * @attribute animate
1734             * @description Use animation to collapse/expand the unit
1735             * @type Boolean
1736             */
1737             this.setAttributeConfig('animate', {
1738                 value: ((attr.animate === false) ? false : true),
1739                 validator: function() {
1740                     var anim = false;
1741                     if (YAHOO.util.Anim) {
1742                         anim = true;
1743                     }
1744                     return anim;
1745                 },
1746                 method: function(anim) {
1747                     if (anim) {
1748                         this._anim = new YAHOO.util.Anim(this.get('element'), {}, this.get('duration'), this.get('easing'));
1749                     } else {
1750                         this._anim = false;
1751                     }
1752                 }
1753             });
1754             /**
1755             * @attribute header
1756             * @description The html to use as the Header of the Unit (sets via innerHTML)
1757             * @type {HTML}
1758             */
1759             this.setAttributeConfig('header', {
1760                 value: attr.header || false,
1761                 method: function(txt) {
1762                     if (txt === false) {
1763                         //Remove the footer
1764                         if (this.header) {
1765                             Dom.addClass(this.body, 'yui-layout-bd-nohd');
1766                             this.header.parentNode.removeChild(this.header);
1767                             this.header = null;
1768                         }
1769                     } else {
1770                         if (!this.header) {
1771                             var header = this.getElementsByClassName('yui-layout-hd', 'div')[0];
1772                             if (!header) {
1773                                 header = this._createHeader();
1774                             }
1775                             this.header = header;
1776                         }
1777                         var h = this.header.getElementsByTagName('h2')[0];
1778                         if (!h) {
1779                             h = document.createElement('h2');
1780                             this.header.appendChild(h);
1781                         }
1782                         h.innerHTML = txt;
1783                         if (this.body) {
1784                             Dom.removeClass(this.body, 'yui-layout-bd-nohd');
1785                         }
1786                     }
1787                     this.fireEvent('contentChange', { target: 'header' });
1788                 }
1789             });
1790             /**
1791             * @attribute proxy
1792             * @description Use the proxy config setting for the Resize Utility
1793             * @type Boolean
1794             */
1795             this.setAttributeConfig('proxy', {
1796                 writeOnce: true,
1797                 value: ((attr.proxy === false) ? false : true)
1798             });
1799             /**
1800             * @attribute body
1801             * @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. (sets via innerHTML)
1802             * @type {HTML}
1803             */
1804             this.setAttributeConfig('body', {
1805                 value: attr.body || false,
1806                 method: function(content) {
1807                     if (!this.body) {
1808                         var body = this.getElementsByClassName('yui-layout-bd', 'div')[0];
1809                         if (body) {
1810                             this.body = body;
1811                         } else {
1812                             body = document.createElement('div');
1813                             body.className = 'yui-layout-bd';
1814                             this.body = body;
1815                             this.get('wrap').appendChild(body);
1816                         }
1817                     }
1818                     if (!this.header) {
1819                         Dom.addClass(this.body, 'yui-layout-bd-nohd');
1820                     }
1821                     Dom.addClass(this.body, 'yui-layout-bd-noft');
1822
1823
1824                     var el = null;
1825                     if (Lang.isString(content)) {
1826                         el = Dom.get(content);
1827                     } else if (content && content.tagName) {
1828                         el = content;
1829                     }
1830                     if (el) {
1831                         var id = Dom.generateId(el);
1832                         LayoutUnit._instances[id] = this;
1833                         this.body.appendChild(el);
1834                     } else {
1835                         this.body.innerHTML = content;
1836                     }
1837
1838                     this._cleanGrids();
1839
1840                     this.fireEvent('contentChange', { target: 'body' });
1841                 }
1842             });
1843
1844             /**
1845             * @attribute footer
1846             * @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. (sets via innerHTML)
1847             * @type {HTML}
1848             */
1849             this.setAttributeConfig('footer', {
1850                 value: attr.footer || false,
1851                 method: function(content) {
1852                     if (content === false) {
1853                         //Remove the footer
1854                         if (this.footer) {
1855                             Dom.addClass(this.body, 'yui-layout-bd-noft');
1856                             this.footer.parentNode.removeChild(this.footer);
1857                             this.footer = null;
1858                         }
1859                     } else {
1860                         if (!this.footer) {
1861                             var ft = this.getElementsByClassName('yui-layout-ft', 'div')[0];
1862                             if (!ft) {
1863                                 ft = document.createElement('div');
1864                                 ft.className = 'yui-layout-ft';
1865                                 this.footer = ft;
1866                                 this.get('wrap').appendChild(ft);
1867                             } else {
1868                                 this.footer = ft;
1869                             }
1870                         }
1871                         var el = null;
1872                         if (Lang.isString(content)) {
1873                             el = Dom.get(content);
1874                         } else if (content && content.tagName) {
1875                             el = content;
1876                         }
1877                         if (el) {
1878                             this.footer.appendChild(el);
1879                         } else {
1880                             this.footer.innerHTML = content;
1881                         }
1882                         Dom.removeClass(this.body, 'yui-layout-bd-noft');
1883                     }
1884                     this.fireEvent('contentChange', { target: 'footer' });
1885                 }
1886             });
1887             /**
1888             * @attribute close
1889             * @description Adds a close icon to the unit
1890             */
1891             this.setAttributeConfig('close', {
1892                 value: attr.close || false,
1893                 method: function(close) {
1894                     //Position Center doesn't get this
1895                     if (this.get('position') == 'center') {
1896                         return false;
1897                     }
1898                     if (!this.header && close) {
1899                         this._createHeader();
1900                     }
1901                     if (!this.header) {
1902                         return;
1903                     }
1904                     var c = this.header ? Dom.getElementsByClassName('close', 'div', this.header)[0] : null;
1905                     
1906                     if (close) {
1907                         //Force some header text if there isn't any
1908                         if (!this.get('header')) {
1909                             this.set('header', '&nbsp;');
1910                         }
1911                         if (!c) {
1912                             c = document.createElement('div');
1913                             c.className = 'close';
1914                             this.header.appendChild(c);
1915                             Event.on(c, 'click', this.close, this, true);
1916                         }
1917                         c.title = this.STR_CLOSE;
1918                     } else if (c && c.parentNode) {
1919                         Event.purgeElement(c);
1920                         c.parentNode.removeChild(c);
1921                     }
1922                     this._configs.close.value = close;
1923                     this.set('collapse', this.get('collapse')); //Reset so we get the right classnames
1924                 }
1925             });
1926
1927             /**
1928             * @attribute collapse
1929             * @description Adds a collapse icon to the unit
1930             */
1931             this.setAttributeConfig('collapse', {
1932                 value: attr.collapse || false,
1933                 method: function(collapse) {
1934                     //Position Center doesn't get this
1935                     if (this.get('position') == 'center') {
1936                         return false;
1937                     }
1938                     if (!this.header && collapse) {
1939                         this._createHeader();
1940                     }
1941                     if (!this.header) {
1942                         return;
1943                     }
1944                     var c = this.header ? Dom.getElementsByClassName('collapse', 'div', this.header)[0] : null;
1945                     
1946                     if (collapse) {
1947                         //Force some header text if there isn't any
1948                         if (!this.get('header')) {
1949                             this.set('header', '&nbsp;');
1950                         }
1951                         if (!c) {
1952                             c = document.createElement('div');
1953                             this.header.appendChild(c);
1954                             Event.on(c, 'click', this.collapse, this, true);
1955                         }
1956                         c.title = this.STR_COLLAPSE;
1957                         c.className = 'collapse' + ((this.get('close')) ? ' collapse-close' : '');
1958                     } else if (c && c.parentNode) {
1959                         Event.purgeElement(c);
1960                         c.parentNode.removeChild(c);
1961                     }
1962                 }
1963             });
1964             /**
1965             * @attribute scroll
1966             * @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.
1967             * @type Boolean/Null
1968             */
1969
1970             this.setAttributeConfig('scroll', {
1971                 value: (((attr.scroll === true) || (attr.scroll === false) || (attr.scroll === null)) ? attr.scroll : false),
1972                 method: function(scroll) {
1973                     if ((scroll === false) && !this._collapsed) { //Removing scroll bar
1974                         if (this.body) {
1975                             if (this.body.scrollTop > 0) {
1976                                 this._lastScrollTop = this.body.scrollTop;
1977                             }
1978                         }
1979                     }
1980                     
1981                     if (scroll === true) {
1982                         this.addClass('yui-layout-scroll');
1983                         this.removeClass('yui-layout-noscroll');
1984                         if (this._lastScrollTop > 0) {
1985                             if (this.body) {
1986                                 this.body.scrollTop = this._lastScrollTop;
1987                             }
1988                         }
1989                     } else if (scroll === false) {
1990                         this.removeClass('yui-layout-scroll');
1991                         this.addClass('yui-layout-noscroll');
1992                     } else if (scroll === null) {
1993                         this.removeClass('yui-layout-scroll');
1994                         this.removeClass('yui-layout-noscroll');
1995                     }
1996                 }
1997             });
1998             /**
1999             * @attribute hover
2000             * @description Config option to pass to the Resize Utility
2001             */
2002             this.setAttributeConfig('hover', {
2003                 writeOnce: true,
2004                 value: attr.hover || false,
2005                 validator: YAHOO.lang.isBoolean
2006             });
2007             /**
2008             * @attribute useShim
2009             * @description Config option to pass to the Resize Utility
2010             */
2011             this.setAttributeConfig('useShim', {
2012                 value: attr.useShim || false,
2013                 validator: YAHOO.lang.isBoolean,
2014                 method: function(u) {
2015                     if (this._resize) {
2016                         this._resize.set('useShim', u);
2017                     }
2018                 }
2019             });
2020             /**
2021             * @attribute resize
2022             * @description Should a Resize instance be added to this unit
2023             */
2024
2025             this.setAttributeConfig('resize', {
2026                 value: attr.resize || false,
2027                 validator: function(r) {
2028                     if (YAHOO.util && YAHOO.util.Resize) {
2029                         return true;
2030                     }
2031                     return false;
2032                 },
2033                 method: function(resize) {
2034                     if (resize && !this._resize) {
2035                         //Position Center doesn't get this
2036                         if (this.get('position') == 'center') {
2037                             return false;
2038                         }
2039                         var handle = false; //To catch center
2040                         switch (this.get('position')) {
2041                             case 'top':
2042                                 handle = 'b';
2043                                 break;
2044                             case 'bottom':
2045                                 handle = 't';
2046                                 break;
2047                             case 'right':
2048                                 handle = 'l';
2049                                 break;
2050                             case 'left':
2051                                 handle = 'r';
2052                                 break;
2053                         }
2054
2055                         this.setStyle('position', 'absolute'); //Make sure Resize get's a position
2056                         
2057                         if (handle) {
2058                             this._resize = new YAHOO.util.Resize(this.get('element'), {
2059                                 proxy: this.get('proxy'),
2060                                 hover: this.get('hover'),
2061                                 status: false,
2062                                 autoRatio: false,
2063                                 handles: [handle],
2064                                 minWidth: this.get('minWidth'),
2065                                 maxWidth: this.get('maxWidth'),
2066                                 minHeight: this.get('minHeight'),
2067                                 maxHeight: this.get('maxHeight'),
2068                                 height: this.get('height'),
2069                                 width: this.get('width'),
2070                                 setSize: false,
2071                                 useShim: this.get('useShim'),
2072                                 wrap: false
2073                             });
2074                             
2075                             this._resize._handles[handle].innerHTML = '<div class="yui-layout-resize-knob"></div>';
2076
2077                             if (this.get('proxy')) {
2078                                 var proxy = this._resize.getProxyEl();
2079                                 proxy.innerHTML = '<div class="yui-layout-handle-' + handle + '"></div>';
2080                             }
2081                             this._resize.on('startResize', function(ev) {
2082                                 this._lastScroll = this.get('scroll');
2083                                 this.set('scroll', false);
2084                                 if (this.get('parent')) {
2085                                     this.get('parent').fireEvent('startResize');
2086                                     var c = this.get('parent').getUnitByPosition('center');
2087                                     this._lastCenterScroll = c.get('scroll');
2088                                     c.addClass(this._resize.CSS_RESIZING);
2089                                     c.set('scroll', false);
2090                                 }
2091                                 this.fireEvent('startResize');
2092                             }, this, true);
2093                             this._resize.on('resize', function(ev) {
2094                                 this.set('height', ev.height);
2095                                 this.set('width', ev.width);
2096                             }, this, true);
2097                             this._resize.on('endResize', function(ev) {
2098                                 this.set('scroll', this._lastScroll);
2099                                 if (this.get('parent')) {
2100                                     var c = this.get('parent').getUnitByPosition('center');
2101                                     c.set('scroll', this._lastCenterScroll);
2102                                     c.removeClass(this._resize.CSS_RESIZING);
2103                                 }
2104                                 this.resize();
2105                                 this.fireEvent('endResize');
2106                             }, this, true);
2107                         }
2108                     } else {
2109                         if (this._resize) {
2110                             this._resize.destroy();
2111                         }
2112                     }
2113                 }
2114             });
2115                         /**
2116                  * The unit data source, used for loading content dynamically.
2117                  * @attribute dataSrc
2118                  * @type String
2119                  */
2120                 this.setAttributeConfig('dataSrc', {
2121                     value: attr.dataSrc
2122                 });
2123                 /**
2124                  * The method to use for the data request.
2125                  * @attribute loadMethod
2126                  * @type String
2127                  * @default "GET"
2128                  */
2129                 this.setAttributeConfig('loadMethod', {
2130                     value: attr.loadMethod || 'GET',
2131                     validator: YAHOO.lang.isString
2132                 });     
2133                 /**
2134                  * Whether or not any data has been loaded from the server.
2135                  * @attribute dataLoaded
2136                  * @type Boolean
2137                  */        
2138                 this.setAttributeConfig('dataLoaded', {
2139                     value: false,
2140                     validator: YAHOO.lang.isBoolean,
2141                     writeOnce: true
2142                 });
2143                 /**
2144                  * Number if milliseconds before aborting and calling failure handler.
2145                  * @attribute dataTimeout
2146                  * @type Number
2147                  * @default null
2148                  */
2149                 this.setAttributeConfig('dataTimeout', {
2150                     value: attr.dataTimeout || null,
2151                     validator: YAHOO.lang.isNumber
2152                 });
2153         },
2154         /**
2155         * @private
2156         * @method _cleanGrids
2157         * @description This method attempts to clean up the first level of the YUI CSS Grids, YAHOO.util.Selector is required for this operation.
2158         */
2159         _cleanGrids: function() {
2160             if (this.get('grids')) {
2161                 var b = Sel.query('div.yui-b', this.body, true);
2162                 if (b) {
2163                     Dom.removeClass(b, 'yui-b');
2164                 }
2165                 Event.onAvailable('yui-main', function() {
2166                     Dom.setStyle(Sel.query('#yui-main'), 'margin-left', '0');
2167                     Dom.setStyle(Sel.query('#yui-main'), 'margin-right', '0');
2168                 });
2169             }
2170         },
2171         /**
2172         * @private
2173         * @method _createHeader
2174         * @description Creates the HTMLElement for the header
2175         * @return {HTMLElement} The new HTMLElement
2176         */
2177         _createHeader: function() {
2178             var header = document.createElement('div');
2179             header.className = 'yui-layout-hd';
2180             if (this.get('firstChild')) {
2181                 this.get('wrap').insertBefore(header, this.get('wrap').firstChild);
2182             } else {
2183                 this.get('wrap').appendChild(header);
2184             }
2185             this.header = header;
2186             return header;
2187         },
2188         /**
2189         * @method destroy
2190         * @param {Boolean} force Don't report to the parent, because we are being called from the parent.
2191         * @description Removes this unit from the parent and cleans up after itself.
2192         * @return {<a href="YAHOO.widget.Layout.html">YAHOO.widget.Layout</a>} The parent Layout instance
2193         */
2194         destroy: function(force) {
2195             if (this._resize) {
2196                 this._resize.destroy();
2197             }
2198             var par = this.get('parent');
2199
2200             this.setStyle('display', 'none');
2201             if (this._clip) {
2202                 this._clip.parentNode.removeChild(this._clip);
2203                 this._clip = null;
2204             }
2205
2206             if (!force) {
2207                 par.removeUnit(this);
2208             }
2209             
2210             if (par) {
2211                 par.removeListener('resize', this.resize, this, true);
2212             }
2213             this.unsubscribeAll();
2214             Event.purgeElement(this.get('element'), true);
2215             this.get('parentNode').removeChild(this.get('element'));
2216
2217             delete YAHOO.widget.LayoutUnit._instances[this.get('id')];
2218             //Brutal Object Destroy
2219             for (var i in this) {
2220                 if (Lang.hasOwnProperty(this, i)) {
2221                     this[i] = null;
2222                     delete this[i];
2223                 }
2224             }
2225         
2226             return par;
2227         },
2228         /**
2229         * @method toString
2230         * @description Returns a string representing the LayoutUnit.
2231         * @return {String}
2232         */        
2233         toString: function() {
2234             if (this.get) {
2235                 return 'LayoutUnit #' + this.get('id') + ' (' + this.get('position') + ')';
2236             }
2237             return 'LayoutUnit';
2238         }
2239     /**
2240     * @event resize
2241     * @description Fired when this.resize is called
2242     * @type YAHOO.util.CustomEvent
2243     */
2244     /**
2245     * @event startResize
2246     * @description Fired when the Resize Utility fires it's startResize Event.
2247     * @type YAHOO.util.CustomEvent
2248     */
2249     /**
2250     * @event endResize
2251     * @description Fired when the Resize Utility fires it's endResize Event.
2252     * @type YAHOO.util.CustomEvent
2253     */
2254     /**
2255     * @event beforeResize
2256     * @description Fired at the beginning of the resize method. If you return false, the resize is cancelled.
2257     * @type YAHOO.util.CustomEvent
2258     */
2259     /**
2260     * @event contentChange
2261     * @description Fired when the content in the header, body or footer is changed via the API
2262     * @type YAHOO.util.CustomEvent
2263     */
2264     /**
2265     * @event close
2266     * @description Fired when the unit is closed
2267     * @type YAHOO.util.CustomEvent
2268     */
2269     /**
2270     * @event beforeCollapse
2271     * @description Fired before the unit is collapsed. If you return false, the collapse is cancelled.
2272     * @type YAHOO.util.CustomEvent
2273     */
2274     /**
2275     * @event collapse
2276     * @description Fired when the unit is collapsed
2277     * @type YAHOO.util.CustomEvent
2278     */
2279     /**
2280     * @event expand
2281     * @description Fired when the unit is exanded
2282     * @type YAHOO.util.CustomEvent
2283     */
2284     /**
2285     * @event beforeExpand
2286     * @description Fired before the unit is exanded. If you return false, the collapse is cancelled.
2287     * @type YAHOO.util.CustomEvent
2288     */
2289     /**
2290     * @event load
2291     * @description Fired when data is loaded via the dataSrc config.
2292     * @type YAHOO.util.CustomEvent
2293     */
2294     /**
2295     * @event loadError
2296     * @description Fired when an error occurs loading data via the dataSrc config. Error message is passed as argument to this event.
2297     * @type YAHOO.util.CustomEvent
2298     */
2299     });
2300
2301     YAHOO.widget.LayoutUnit = LayoutUnit;
2302 })();
2303 YAHOO.register("layout", YAHOO.widget.Layout, {version: "2.9.0", build: "2800"});