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