71c57daa61a47665d01024e6cb41531e97defdd3
[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         switch(cfg.xtype) 
300         {
301             case 'Content':  // ContentPanel (el, cfg)
302             case 'Scroll':  // ContentPanel (el, cfg)
303             case 'View': 
304                 cfg.autoCreate = cfg.autoCreate || true;
305                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
306                 //} else {
307                 //    var el = this.el.createChild();
308                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
309                 //}
310                 
311                 this.add(region, ret);
312                 break;
313             
314             /*
315             case 'TreePanel': // our new panel!
316                 cfg.el = this.el.createChild();
317                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
318                 this.add(region, ret);
319                 break;
320             */
321             
322             case 'Nest': 
323                 // create a new Layout (which is  a Border Layout...
324                 
325                 var clayout = cfg.layout;
326                 clayout.el  = this.el.createChild();
327                 clayout.items   = clayout.items  || [];
328                 
329                 delete cfg.layout;
330                 
331                 // replace this exitems with the clayout ones..
332                 xitems = clayout.items;
333                  
334                 // force background off if it's in center...
335                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
336                     cfg.background = false;
337                 }
338                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
339                 
340                 
341                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
342                 //console.log('adding nested layout panel '  + cfg.toSource());
343                 this.add(region, ret);
344                 nb = {}; /// find first...
345                 break;
346             
347             case 'Grid':
348                 
349                 // needs grid and region
350                 
351                 //var el = this.getRegion(region).el.createChild();
352                 /*
353                  *var el = this.el.createChild();
354                 // create the grid first...
355                 cfg.grid.container = el;
356                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
357                 */
358                 
359                 if (region == 'center' && this.active ) {
360                     cfg.background = false;
361                 }
362                 
363                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
364                 
365                 this.add(region, ret);
366                 /*
367                 if (cfg.background) {
368                     // render grid on panel activation (if panel background)
369                     ret.on('activate', function(gp) {
370                         if (!gp.grid.rendered) {
371                     //        gp.grid.render(el);
372                         }
373                     });
374                 } else {
375                   //  cfg.grid.render(el);
376                 }
377                 */
378                 break;
379            
380            
381             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
382                 // it was the old xcomponent building that caused this before.
383                 // espeically if border is the top element in the tree.
384                 ret = this;
385                 break; 
386                 
387                     
388                 
389                 
390                 
391             default:
392                 /*
393                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
394                     
395                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
396                     this.add(region, ret);
397                 } else {
398                 */
399                     Roo.log(cfg);
400                     throw "Can not add '" + cfg.xtype + "' to Border";
401                     return null;
402              
403                                 
404              
405         }
406         this.beginUpdate();
407         // add children..
408         var region = '';
409         var abn = {};
410         Roo.each(xitems, function(i)  {
411             region = nb && i.region ? i.region : false;
412             
413             var add = ret.addxtype(i);
414            
415             if (region) {
416                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
417                 if (!i.background) {
418                     abn[region] = nb[region] ;
419                 }
420             }
421             
422         });
423         this.endUpdate();
424
425         // make the last non-background panel active..
426         //if (nb) { Roo.log(abn); }
427         if (nb) {
428             
429             for(var r in abn) {
430                 region = this.getRegion(r);
431                 if (region) {
432                     // tried using nb[r], but it does not work..
433                      
434                     region.showPanel(abn[r]);
435                    
436                 }
437             }
438         }
439         return ret;
440         
441     },
442     
443     
444 // private
445     factory : function(cfg)
446     {
447         
448         var validRegions = Roo.bootstrap.layout.Border.regions;
449
450         var target = cfg.region;
451         cfg.mgr = this;
452         
453         var r = Roo.bootstrap.layout;
454         Roo.log(target);
455         switch(target){
456             case "north":
457                 return new r.North(cfg);
458             case "south":
459                 return new r.South(cfg);
460             case "east":
461                 return new r.East(cfg);
462             case "west":
463                 return new r.West(cfg);
464             case "center":
465                 return new r.Center(cfg);
466         }
467         throw 'Layout region "'+target+'" not supported.';
468     }
469     
470     
471 });
472