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         //if (!cfg.xtype.match(/Panel$/)) {
269         //    return false;
270         //}
271         var ret = false;
272         
273         if (typeof(cfg.region) == 'undefined') {
274             Roo.log("Failed to add Panel, region was not set");
275             Roo.log(cfg);
276             return false;
277         }
278         var region = cfg.region;
279         delete cfg.region;
280         
281           
282         var xitems = [];
283         if (cfg.items) {
284             xitems = cfg.items;
285             delete cfg.items;
286         }
287         var nb = false;
288         
289         switch(cfg.xtype) 
290         {
291             case 'ContentPanel':  // ContentPanel (el, cfg)
292             case 'ScrollPanel':  // ContentPanel (el, cfg)
293             case 'ViewPanel': 
294                 if(cfg.autoCreate) {
295                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
296                 } else {
297                     var el = this.el.createChild();
298                     ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
299                 }
300                 
301                 this.add(region, ret);
302                 break;
303             
304             
305             case 'TreePanel': // our new panel!
306                 cfg.el = this.el.createChild();
307                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
308                 this.add(region, ret);
309                 break;
310             
311             case 'NestedLayoutPanel': 
312                 // create a new Layout (which is  a Border Layout...
313                 var el = this.el.createChild();
314                 var clayout = cfg.layout;
315                 delete cfg.layout;
316                 clayout.items   = clayout.items  || [];
317                 // replace this exitems with the clayout ones..
318                 xitems = clayout.items;
319                  
320                 
321                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
322                     cfg.background = false;
323                 }
324                 var layout = new Roo.BorderLayout(el, clayout);
325                 
326                 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
327                 //console.log('adding nested layout panel '  + cfg.toSource());
328                 this.add(region, ret);
329                 nb = {}; /// find first...
330                 break;
331                 
332             case 'GridPanel': 
333             
334                 // needs grid and region
335                 
336                 //var el = this.getRegion(region).el.createChild();
337                 var el = this.el.createChild();
338                 // create the grid first...
339                 
340                 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
341                 delete cfg.grid;
342                 if (region == 'center' && this.active ) {
343                     cfg.background = false;
344                 }
345                 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
346                 
347                 this.add(region, ret);
348                 if (cfg.background) {
349                     ret.on('activate', function(gp) {
350                         if (!gp.grid.rendered) {
351                             gp.grid.render();
352                         }
353                     });
354                 } else {
355                     grid.render();
356                 }
357                 break;
358            
359            
360            
361                 
362                 
363                 
364             default:
365                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
366                     
367                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
368                     this.add(region, ret);
369                 } else {
370                 
371                     alert("Can not add '" + cfg.xtype + "' to BorderLayout");
372                     return null;
373                 }
374                 
375              // GridPanel (grid, cfg)
376             
377         }
378         this.beginUpdate();
379         // add children..
380         var region = '';
381         var abn = {};
382         Roo.each(xitems, function(i)  {
383             region = nb && i.region ? i.region : false;
384             
385             var add = ret.addxtype(i);
386            
387             if (region) {
388                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
389                 if (!i.background) {
390                     abn[region] = nb[region] ;
391                 }
392             }
393             
394         });
395         this.endUpdate();
396
397         // make the last non-background panel active..
398         //if (nb) { Roo.log(abn); }
399         if (nb) {
400             
401             for(var r in abn) {
402                 region = this.getRegion(r);
403                 if (region) {
404                     // tried using nb[r], but it does not work..
405                      
406                     region.showPanel(abn[r]);
407                    
408                 }
409             }
410         }
411         return ret;
412         
413     },
414     
415     
416 // private
417     factory : function(cfg)
418     {
419         
420         var validRegions = ["north","south","east","west","center"];
421
422         var target = cfg.region;
423         cfg.manager = this;
424         
425         var r = Roo.bootstrap.layout;
426         
427         switch(target){
428             case "north":
429                 return new r.North(cfg);
430             case "south":
431                 return new r.South(cfg);
432             case "east":
433                 return new r.East(cfg);
434             case "west":
435                 return new r.West(cfg);
436             case "center":
437                 return new r.Center(cfg);
438         }
439         throw 'Layout region "'+target+'" not supported.';
440     }
441 };
442     
443     
444 });
445