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