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