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     
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.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                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
330                 
331                 ret = new Roo[cfg.xtype](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                 /*
371                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
372                     
373                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
374                     this.add(region, ret);
375                 } else {
376                 */
377                     Roo.log(cfg);
378                     throw "Can not add '" + cfg.xtype + "' to Border";
379                     return null;
380              
381                                 
382              // GridPanel (grid, cfg)
383             
384         }
385         this.beginUpdate();
386         // add children..
387         var region = '';
388         var abn = {};
389         Roo.each(xitems, function(i)  {
390             region = nb && i.region ? i.region : false;
391             
392             var add = ret.addxtype(i);
393            
394             if (region) {
395                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
396                 if (!i.background) {
397                     abn[region] = nb[region] ;
398                 }
399             }
400             
401         });
402         this.endUpdate();
403
404         // make the last non-background panel active..
405         //if (nb) { Roo.log(abn); }
406         if (nb) {
407             
408             for(var r in abn) {
409                 region = this.getRegion(r);
410                 if (region) {
411                     // tried using nb[r], but it does not work..
412                      
413                     region.showPanel(abn[r]);
414                    
415                 }
416             }
417         }
418         return ret;
419         
420     },
421     
422     
423 // private
424     factory : function(cfg)
425     {
426         
427         var validRegions = Roo.bootstrap.layout.Border.regions;
428
429         var target = cfg.region;
430         cfg.mgr = this;
431         
432         var r = Roo.bootstrap.layout;
433         
434         switch(target){
435             case "north":
436                 return new r.North(cfg);
437             case "south":
438                 return new r.South(cfg);
439             case "east":
440                 return new r.East(cfg);
441             case "west":
442                 return new r.West(cfg);
443             case "center":
444                 return new r.Center(cfg);
445         }
446         throw 'Layout region "'+target+'" not supported.';
447     }
448     
449     
450 });
451