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