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