fix layout height calc
[roojs1] / Roo / bootstrap / layout / Border.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11 /**
12  * @class Roo.bootstrap.layout.Border
13  * @extends Roo.bootstrap.layout.Manager
14  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
15  * please see: examples/bootstrap/nested.html<br><br>
16  
17 <b>The container the layout is rendered into can be either the body element or any other element.
18 If it is not the body element, the container needs to either be an absolute positioned element,
19 or you will need to add "position:relative" to the css of the container.  You will also need to specify
20 the container size if it is not the body element.</b>
21
22 * @constructor
23 * Create a new Border
24 * @param {Object} config Configuration options
25  */
26 Roo.bootstrap.layout.Border = function(config){
27     config = config || {};
28     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
29     
30     
31     
32     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33         if(config[region]){
34             config[region].region = region;
35             this.addRegion(config[region]);
36         }
37     },this);
38     
39 };
40
41 Roo.bootstrap.layout.Border.regions =  ["center", "north","south","east","west"];
42
43 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
44     
45     parent : false, // this might point to a 'nest' or a ???
46     
47     /**
48      * Creates and adds a new region if it doesn't already exist.
49      * @param {String} target The target region key (north, south, east, west or center).
50      * @param {Object} config The regions config object
51      * @return {BorderLayoutRegion} The new region
52      */
53     addRegion : function(config)
54     {
55         if(!this.regions[config.region]){
56             var r = this.factory(config);
57             this.bindRegion(r);
58         }
59         return this.regions[config.region];
60     },
61
62     // private (kinda)
63     bindRegion : function(r){
64         this.regions[r.config.region] = r;
65         
66         r.on("visibilitychange",    this.layout, this);
67         r.on("paneladded",          this.layout, this);
68         r.on("panelremoved",        this.layout, this);
69         r.on("invalidated",         this.layout, this);
70         r.on("resized",             this.onRegionResized, this);
71         r.on("collapsed",           this.onRegionCollapsed, this);
72         r.on("expanded",            this.onRegionExpanded, this);
73     },
74
75     /**
76      * Performs a layout update.
77      */
78     layout : function()
79     {
80         if(this.updating) {
81             return;
82         }
83         
84         // render all the rebions if they have not been done alreayd?
85         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
86             if(this.regions[region] && !this.regions[region].bodyEl){
87                 this.regions[region].onRender(this.el)
88             }
89         },this);
90         
91         var size = this.getViewSize();
92         var w = size.width;
93         var h = size.height;
94         var centerW = w;
95         var centerH = h;
96         var centerY = 0;
97         var centerX = 0;
98         //var x = 0, y = 0;
99
100         var rs = this.regions;
101         var north = rs["north"];
102         var south = rs["south"]; 
103         var west = rs["west"];
104         var east = rs["east"];
105         var center = rs["center"];
106         //if(this.hideOnLayout){ // not supported anymore
107             //c.el.setStyle("display", "none");
108         //}
109         if(north && north.isVisible()){
110             var b = north.getBox();
111             var m = north.getMargins();
112             b.width = w - (m.left+m.right);
113             b.x = m.left;
114             b.y = m.top;
115             centerY = b.height + b.y + m.bottom;
116             centerH -= centerY;
117             north.updateBox(this.safeBox(b));
118         }
119         if(south && south.isVisible()){
120             var b = south.getBox();
121             var m = south.getMargins();
122             b.width = w - (m.left+m.right);
123             b.x = m.left;
124             var totalHeight = (b.height + m.top + m.bottom);
125             b.y = h - totalHeight + m.top;
126             centerH -= totalHeight;
127             south.updateBox(this.safeBox(b));
128         }
129         if(west && west.isVisible()){
130             var b = west.getBox();
131             var m = west.getMargins();
132             b.height = centerH - (m.top+m.bottom);
133             b.x = m.left;
134             b.y = centerY + m.top;
135             var totalWidth = (b.width + m.left + m.right);
136             centerX += totalWidth;
137             centerW -= totalWidth;
138             west.updateBox(this.safeBox(b));
139         }
140         if(east && east.isVisible()){
141             var b = east.getBox();
142             var m = east.getMargins();
143             b.height = centerH - (m.top+m.bottom);
144             var totalWidth = (b.width + m.left + m.right);
145             b.x = w - totalWidth + m.left;
146             b.y = centerY + m.top;
147             centerW -= totalWidth;
148             east.updateBox(this.safeBox(b));
149         }
150         if(center){
151             var m = center.getMargins();
152             var centerBox = {
153                 x: centerX + m.left,
154                 y: centerY + m.top,
155                 width: centerW - (m.left+m.right),
156                 height: centerH - (m.top+m.bottom)
157             };
158             //if(this.hideOnLayout){
159                 //center.el.setStyle("display", "block");
160             //}
161             center.updateBox(this.safeBox(centerBox));
162         }
163         this.el.repaint();
164         this.fireEvent("layout", this);
165     },
166
167     // private
168     safeBox : function(box){
169         box.width = Math.max(0, box.width);
170         box.height = Math.max(0, box.height);
171         return box;
172     },
173
174     /**
175      * Adds a ContentPanel (or subclass) to this layout.
176      * @param {String} target The target region key (north, south, east, west or center).
177      * @param {Roo.ContentPanel} panel The panel to add
178      * @return {Roo.ContentPanel} The added panel
179      */
180     add : function(target, panel){
181          
182         target = target.toLowerCase();
183         return this.regions[target].add(panel);
184     },
185
186     /**
187      * Remove a ContentPanel (or subclass) to this layout.
188      * @param {String} target The target region key (north, south, east, west or center).
189      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
190      * @return {Roo.ContentPanel} The removed panel
191      */
192     remove : function(target, panel){
193         target = target.toLowerCase();
194         return this.regions[target].remove(panel);
195     },
196
197     /**
198      * Searches all regions for a panel with the specified id
199      * @param {String} panelId
200      * @return {Roo.ContentPanel} The panel or null if it wasn't found
201      */
202     findPanel : function(panelId){
203         var rs = this.regions;
204         for(var target in rs){
205             if(typeof rs[target] != "function"){
206                 var p = rs[target].getPanel(panelId);
207                 if(p){
208                     return p;
209                 }
210             }
211         }
212         return null;
213     },
214
215     /**
216      * Searches all regions for a panel with the specified id and activates (shows) it.
217      * @param {String/ContentPanel} panelId The panels id or the panel itself
218      * @return {Roo.ContentPanel} The shown panel or null
219      */
220     showPanel : function(panelId) {
221       var rs = this.regions;
222       for(var target in rs){
223          var r = rs[target];
224          if(typeof r != "function"){
225             if(r.hasPanel(panelId)){
226                return r.showPanel(panelId);
227             }
228          }
229       }
230       return null;
231    },
232
233    /**
234      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
235      * @param {Roo.state.Provider} provider (optional) An alternate state provider
236      */
237    /*
238     restoreState : function(provider){
239         if(!provider){
240             provider = Roo.state.Manager;
241         }
242         var sm = new Roo.LayoutStateManager();
243         sm.init(this, provider);
244     },
245 */
246  
247  
248     /**
249      * Adds a xtype elements to the layout.
250      * <pre><code>
251
252 layout.addxtype({
253        xtype : 'ContentPanel',
254        region: 'west',
255        items: [ .... ]
256    }
257 );
258
259 layout.addxtype({
260         xtype : 'NestedLayoutPanel',
261         region: 'west',
262         layout: {
263            center: { },
264            west: { }   
265         },
266         items : [ ... list of content panels or nested layout panels.. ]
267    }
268 );
269 </code></pre>
270      * @param {Object} cfg Xtype definition of item to add.
271      */
272     addxtype : function(cfg)
273     {
274         // basically accepts a pannel...
275         // can accept a layout region..!?!?
276         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
277         
278         
279         // theory?  children can only be panels??
280         
281         //if (!cfg.xtype.match(/Panel$/)) {
282         //    return false;
283         //}
284         var ret = false;
285         
286         if (typeof(cfg.region) == 'undefined') {
287             Roo.log("Failed to add Panel, region was not set");
288             Roo.log(cfg);
289             return false;
290         }
291         var region = cfg.region;
292         delete cfg.region;
293         
294           
295         var xitems = [];
296         if (cfg.items) {
297             xitems = cfg.items;
298             delete cfg.items;
299         }
300         var nb = false;
301         
302         if ( region == 'center') {
303             Roo.log("Center: " + cfg.title);
304         }
305         
306         
307         switch(cfg.xtype) 
308         {
309             case 'Content':  // ContentPanel (el, cfg)
310             case 'Scroll':  // ContentPanel (el, cfg)
311             case 'View': 
312                 cfg.autoCreate = cfg.autoCreate || true;
313                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
314                 //} else {
315                 //    var el = this.el.createChild();
316                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
317                 //}
318                 
319                 this.add(region, ret);
320                 break;
321             
322             /*
323             case 'TreePanel': // our new panel!
324                 cfg.el = this.el.createChild();
325                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
326                 this.add(region, ret);
327                 break;
328             */
329             
330             case 'Nest': 
331                 // create a new Layout (which is  a Border Layout...
332                 
333                 var clayout = cfg.layout;
334                 clayout.el  = this.el.createChild();
335                 clayout.items   = clayout.items  || [];
336                 
337                 delete cfg.layout;
338                 
339                 // replace this exitems with the clayout ones..
340                 xitems = clayout.items;
341                  
342                 // force background off if it's in center...
343                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
344                     cfg.background = false;
345                 }
346                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
347                 
348                 
349                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
350                 //console.log('adding nested layout panel '  + cfg.toSource());
351                 this.add(region, ret);
352                 nb = {}; /// find first...
353                 break;
354             
355             case 'Grid':
356                 
357                 // needs grid and region
358                 
359                 //var el = this.getRegion(region).el.createChild();
360                 /*
361                  *var el = this.el.createChild();
362                 // create the grid first...
363                 cfg.grid.container = el;
364                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
365                 */
366                 
367                 if (region == 'center' && this.active ) {
368                     cfg.background = false;
369                 }
370                 
371                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
372                 
373                 this.add(region, ret);
374                 /*
375                 if (cfg.background) {
376                     // render grid on panel activation (if panel background)
377                     ret.on('activate', function(gp) {
378                         if (!gp.grid.rendered) {
379                     //        gp.grid.render(el);
380                         }
381                     });
382                 } else {
383                   //  cfg.grid.render(el);
384                 }
385                 */
386                 break;
387            
388            
389             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
390                 // it was the old xcomponent building that caused this before.
391                 // espeically if border is the top element in the tree.
392                 ret = this;
393                 break; 
394                 
395                     
396                 
397                 
398                 
399             default:
400                 /*
401                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
402                     
403                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
404                     this.add(region, ret);
405                 } else {
406                 */
407                     Roo.log(cfg);
408                     throw "Can not add '" + cfg.xtype + "' to Border";
409                     return null;
410              
411                                 
412              
413         }
414         this.beginUpdate();
415         // add children..
416         var region = '';
417         var abn = {};
418         Roo.each(xitems, function(i)  {
419             region = nb && i.region ? i.region : false;
420             
421             var add = ret.addxtype(i);
422            
423             if (region) {
424                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
425                 if (!i.background) {
426                     abn[region] = nb[region] ;
427                 }
428             }
429             
430         });
431         this.endUpdate();
432
433         // make the last non-background panel active..
434         //if (nb) { Roo.log(abn); }
435         if (nb) {
436             
437             for(var r in abn) {
438                 region = this.getRegion(r);
439                 if (region) {
440                     // tried using nb[r], but it does not work..
441                      
442                     region.showPanel(abn[r]);
443                    
444                 }
445             }
446         }
447         return ret;
448         
449     },
450     
451     
452 // private
453     factory : function(cfg)
454     {
455         
456         var validRegions = Roo.bootstrap.layout.Border.regions;
457
458         var target = cfg.region;
459         cfg.mgr = this;
460         
461         var r = Roo.bootstrap.layout;
462         Roo.log(target);
463         switch(target){
464             case "north":
465                 return new r.North(cfg);
466             case "south":
467                 return new r.South(cfg);
468             case "east":
469                 return new r.East(cfg);
470             case "west":
471                 return new r.West(cfg);
472             case "center":
473                 return new r.Center(cfg);
474         }
475         throw 'Layout region "'+target+'" not supported.';
476     }
477     
478     
479 });
480