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