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