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