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