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     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                 /*
345                  *var el = this.el.createChild();
346                 // create the grid first...
347                 cfg.grid.container = el;
348                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
349                 */
350                 
351                 if (region == 'center' && this.active ) {
352                     cfg.background = false;
353                 }
354                 
355                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
356                 
357                 this.add(region, ret);
358                 /*
359                 if (cfg.background) {
360                     // render grid on panel activation (if panel background)
361                     ret.on('activate', function(gp) {
362                         if (!gp.grid.rendered) {
363                     //        gp.grid.render(el);
364                         }
365                     });
366                 } else {
367                   //  cfg.grid.render(el);
368                 }
369                 */
370                 break;
371            
372            
373             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
374                 // it was the old xcomponent building that caused this before.
375                 // espeically if border is the top element in the tree.
376                 ret = this;
377                 break; 
378                 
379                     
380                 
381                 
382                 
383             default:
384                 /*
385                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
386                     
387                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
388                     this.add(region, ret);
389                 } else {
390                 */
391                     Roo.log(cfg);
392                     throw "Can not add '" + cfg.xtype + "' to Border";
393                     return null;
394              
395                                 
396              
397         }
398         this.beginUpdate();
399         // add children..
400         var region = '';
401         var abn = {};
402         Roo.each(xitems, function(i)  {
403             region = nb && i.region ? i.region : false;
404             
405             var add = ret.addxtype(i);
406            
407             if (region) {
408                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
409                 if (!i.background) {
410                     abn[region] = nb[region] ;
411                 }
412             }
413             
414         });
415         this.endUpdate();
416
417         // make the last non-background panel active..
418         //if (nb) { Roo.log(abn); }
419         if (nb) {
420             
421             for(var r in abn) {
422                 region = this.getRegion(r);
423                 if (region) {
424                     // tried using nb[r], but it does not work..
425                      
426                     region.showPanel(abn[r]);
427                    
428                 }
429             }
430         }
431         return ret;
432         
433     },
434     
435     
436 // private
437     factory : function(cfg)
438     {
439         
440         var validRegions = Roo.bootstrap.layout.Border.regions;
441
442         var target = cfg.region;
443         cfg.mgr = this;
444         
445         var r = Roo.bootstrap.layout;
446         Roo.log(target);
447         switch(target){
448             case "north":
449                 return new r.North(cfg);
450             case "south":
451                 return new r.South(cfg);
452             case "east":
453                 return new r.East(cfg);
454             case "west":
455                 return new r.West(cfg);
456             case "center":
457                 return new r.Center(cfg);
458         }
459         throw 'Layout region "'+target+'" not supported.';
460     }
461     
462     
463 });
464