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