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