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