4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
12 * @class Roo.BorderLayout
13 * @extends Roo.LayoutManager
14 * @children Roo.panel.Content
15 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
16 * please see: <br><br>
17 * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
18 * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
21 var layout = new Roo.BorderLayout(document.body, {
55 preferredTabWidth: 150
60 var CP = Roo.panel.Content;
63 layout.add("north", new CP("north", "North"));
64 layout.add("south", new CP("south", {title: "South", closable: true}));
65 layout.add("west", new CP("west", {title: "West"}));
66 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
67 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
68 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
69 layout.getRegion("center").showPanel("center1");
73 <b>The container the layout is rendered into can be either the body element or any other element.
74 If it is not the body element, the container needs to either be an absolute positioned element,
75 or you will need to add "position:relative" to the css of the container. You will also need to specify
76 the container size if it is not the body element.</b>
79 * Create a new BorderLayout
80 * @param {String/HTMLElement/Element} container The container this layout is bound to
81 * @param {Object} config Configuration options
83 Roo.BorderLayout = function(container, config){
84 config = config || {};
85 Roo.BorderLayout.superclass.constructor.call(this, container, config);
86 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
87 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
88 var target = this.factory.validRegions[i];
90 this.addRegion(target, config[target]);
95 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
98 * @cfg {Roo.LayoutRegion} east
101 * @cfg {Roo.LayoutRegion} west
104 * @cfg {Roo.LayoutRegion} north
107 * @cfg {Roo.LayoutRegion} south
110 * @cfg {Roo.LayoutRegion} center
113 * Creates and adds a new region if it doesn't already exist.
114 * @param {String} target The target region key (north, south, east, west or center).
115 * @param {Object} config The regions config object
116 * @return {BorderLayoutRegion} The new region
118 addRegion : function(target, config){
119 if(!this.regions[target]){
120 var r = this.factory.create(target, this, config);
121 this.bindRegion(target, r);
123 return this.regions[target];
127 bindRegion : function(name, r){
128 this.regions[name] = r;
129 r.on("visibilitychange", this.layout, this);
130 r.on("paneladded", this.layout, this);
131 r.on("panelremoved", this.layout, this);
132 r.on("invalidated", this.layout, this);
133 r.on("resized", this.onRegionResized, this);
134 r.on("collapsed", this.onRegionCollapsed, this);
135 r.on("expanded", this.onRegionExpanded, this);
139 * Performs a layout update.
145 var size = this.getViewSize();
154 var rs = this.regions;
155 var north = rs["north"];
156 var south = rs["south"];
157 var west = rs["west"];
158 var east = rs["east"];
159 var center = rs["center"];
160 //if(this.hideOnLayout){ // not supported anymore
161 //c.el.setStyle("display", "none");
163 if(north && north.isVisible()){
164 var b = north.getBox();
165 var m = north.getMargins();
166 b.width = w - (m.left+m.right);
169 centerY = b.height + b.y + m.bottom;
171 north.updateBox(this.safeBox(b));
173 if(south && south.isVisible()){
174 var b = south.getBox();
175 var m = south.getMargins();
176 b.width = w - (m.left+m.right);
178 var totalHeight = (b.height + m.top + m.bottom);
179 b.y = h - totalHeight + m.top;
180 centerH -= totalHeight;
181 south.updateBox(this.safeBox(b));
183 if(west && west.isVisible()){
184 var b = west.getBox();
185 var m = west.getMargins();
186 b.height = centerH - (m.top+m.bottom);
188 b.y = centerY + m.top;
189 var totalWidth = (b.width + m.left + m.right);
190 centerX += totalWidth;
191 centerW -= totalWidth;
192 west.updateBox(this.safeBox(b));
194 if(east && east.isVisible()){
195 var b = east.getBox();
196 var m = east.getMargins();
197 b.height = centerH - (m.top+m.bottom);
198 var totalWidth = (b.width + m.left + m.right);
199 b.x = w - totalWidth + m.left;
200 b.y = centerY + m.top;
201 centerW -= totalWidth;
202 east.updateBox(this.safeBox(b));
205 var m = center.getMargins();
209 width: centerW - (m.left+m.right),
210 height: centerH - (m.top+m.bottom)
212 //if(this.hideOnLayout){
213 //center.el.setStyle("display", "block");
215 center.updateBox(this.safeBox(centerBox));
218 this.fireEvent("layout", this);
222 safeBox : function(box){
223 box.width = Math.max(0, box.width);
224 box.height = Math.max(0, box.height);
229 * Adds a ContentPanel (or subclass) to this layout.
230 * @param {String} target The target region key (north, south, east, west or center).
231 * @param {Roo.panel.Content} panel The panel to add
232 * @return {Roo.panel.Content} The added panel
234 add : function(target, panel){
236 target = target.toLowerCase();
237 return this.regions[target].add(panel);
241 * Remove a ContentPanel (or subclass) to this layout.
242 * @param {String} target The target region key (north, south, east, west or center).
243 * @param {Number/String/Roo.panel.Content} panel The index, id or panel to remove
244 * @return {Roo.panel.Content} The removed panel
246 remove : function(target, panel){
247 target = target.toLowerCase();
248 return this.regions[target].remove(panel);
252 * Searches all regions for a panel with the specified id
253 * @param {String} panelId
254 * @return {Roo.panel.Content} The panel or null if it wasn't found
256 findPanel : function(panelId){
257 var rs = this.regions;
258 for(var target in rs){
259 if(typeof rs[target] != "function"){
260 var p = rs[target].getPanel(panelId);
270 * Searches all regions for a panel with the specified id and activates (shows) it.
271 * @param {String/panel.Content} panelId The panels id or the panel itself
272 * @return {Roo.panel.Content} The shown panel or null
274 showPanel : function(panelId) {
275 var rs = this.regions;
276 for(var target in rs){
278 if(typeof r != "function"){
279 if(r.hasPanel(panelId)){
280 return r.showPanel(panelId);
288 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
289 * @param {Roo.state.Provider} provider (optional) An alternate state provider
291 restoreState : function(provider){
293 provider = Roo.state.Manager;
295 var sm = new Roo.LayoutStateManager();
296 sm.init(this, provider);
300 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
301 * object should contain properties for each region to add ContentPanels to, and each property's value should be
302 * a valid ContentPanel config object. Example:
304 // Create the main layout
305 var layout = new Roo.BorderLayout('main-ct', {
316 // Create and add multiple ContentPanels at once via configs
321 title:'Ext Source Files',
334 * @param {Object} regions An object containing ContentPanel configs by region name
336 batchAdd : function(regions){
338 for(var rname in regions){
339 var lr = this.regions[rname];
341 this.addTypedPanels(lr, regions[rname]);
348 addTypedPanels : function(lr, ps){
349 if(typeof ps == 'string'){
350 lr.add(new Roo.panel.Content(ps));
352 else if(ps instanceof Array){
353 for(var i =0, len = ps.length; i < len; i++){
354 this.addTypedPanels(lr, ps[i]);
357 else if(!ps.events){ // raw config?
359 delete ps.el; // prevent conflict
360 lr.add(new Roo.panel.Content(el || Roo.id(), ps));
362 else { // panel object assumed!
367 * Adds a xtype elements to the layout.
371 xtype : 'ContentPanel',
378 xtype : 'NestedLayoutPanel',
384 items : [ ... list of content panels or nested layout panels.. ]
388 * @param {Object} cfg Xtype definition of item to add.
390 addxtype : function(cfg)
392 // basically accepts a pannel...
393 // can accept a layout region..!?!?
394 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
396 // if (!cfg.xtype.match(/Panel$/)) {
401 if (typeof(cfg.region) == 'undefined') {
402 Roo.log("Failed to add Panel, region was not set");
406 var region = cfg.region;
421 ret = new Roo.panel[cfg.xtype](cfg); // new panel!!!!!
423 var el = this.el.createChild();
424 ret = new Roo.panel[cfg.xtype](el, cfg); // new panel!!!!!
427 this.add(region, ret);
430 // needs grid and region
432 //var el = this.getRegion(region).el.createChild();
433 var el = this.el.createChild();
434 // create the grid first...
436 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
438 if (region == 'center' && this.active ) {
439 cfg.background = false;
441 ret = new Roo.panel[cfg.xtype](grid, cfg); // new panel!!!!!
443 this.add(region, ret);
444 if (cfg.background) {
445 ret.on('activate', function(gp) {
446 if (!gp.grid.rendered) {
455 // create a new Layout (which is a Border Layout...
456 var el = this.el.createChild();
457 var clayout = cfg.layout;
459 clayout.items = clayout.items || [];
460 // replace this exitems with the clayout ones..
461 xitems = clayout.items;
464 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
465 cfg.background = false;
467 var layout = new Roo.BorderLayout(el, clayout);
469 ret = new Roo.panel[cfg.xtype](layout, cfg); // new panel!!!!!
470 //console.log('adding nested layout panel ' + cfg.toSource());
471 this.add(region, ret);
472 nb = {}; /// find first...
476 ret = new Roo.panel[cfg.xtype](cfg); // new panel!!!!!
477 this.add(region, ret);
479 case 'Tree': // our new panel!
480 cfg.el = this.el.createChild();
481 ret = new Roo.panel[cfg.xtype](cfg); // new panel!!!!!
482 this.add(region, ret);
485 case 'ScrollPanel': // ContentPanel (el, cfg)
488 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
490 var el = this.el.createChild();
491 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
494 this.add(region, ret);
498 case 'TreePanel': // our new panel!
499 cfg.el = this.el.createChild();
500 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
501 this.add(region, ret);
504 case 'NestedLayoutPanel':
505 // create a new Layout (which is a Border Layout...
506 var el = this.el.createChild();
507 var clayout = cfg.layout;
509 clayout.items = clayout.items || [];
510 // replace this exitems with the clayout ones..
511 xitems = clayout.items;
514 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
515 cfg.background = false;
517 var layout = new Roo.BorderLayout(el, clayout);
519 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
520 //console.log('adding nested layout panel ' + cfg.toSource());
521 this.add(region, ret);
522 nb = {}; /// find first...
527 // needs grid and region
529 //var el = this.getRegion(region).el.createChild();
530 var el = this.el.createChild();
531 // create the grid first...
533 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
535 if (region == 'center' && this.active ) {
536 cfg.background = false;
538 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
540 this.add(region, ret);
541 if (cfg.background) {
542 ret.on('activate', function(gp) {
543 if (!gp.grid.rendered) {
558 if (typeof(Roo[cfg.xtype]) != 'undefined') {
560 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
561 this.add(region, ret);
564 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
568 // GridPanel (grid, cfg)
575 Roo.each(xitems, function(i) {
576 region = nb && i.region ? i.region : false;
578 var add = ret.addxtype(i);
581 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
583 abn[region] = nb[region] ;
590 // make the last non-background panel active..
591 //if (nb) { Roo.log(abn); }
595 region = this.getRegion(r);
597 // tried using nb[r], but it does not work..
599 region.showPanel(abn[r]);
610 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
611 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
612 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
613 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
616 var CP = Roo.ContentPanel;
618 var layout = Roo.BorderLayout.create({
622 panels: [new CP("north", "North")]
631 panels: [new CP("west", {title: "West"})]
640 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
649 panels: [new CP("south", {title: "South", closable: true})]
656 preferredTabWidth: 150,
658 new CP("center1", {title: "Close Me", closable: true}),
659 new CP("center2", {title: "Center Panel", closable: false})
664 layout.getRegion("center").showPanel("center1");
669 Roo.BorderLayout.create = function(config, targetEl){
670 var layout = new Roo.BorderLayout(targetEl || document.body, config);
671 layout.beginUpdate();
672 var regions = Roo.BorderLayout.RegionFactory.validRegions;
673 for(var j = 0, jlen = regions.length; j < jlen; j++){
675 if(layout.regions[lr] && config[lr].panels){
676 var r = layout.regions[lr];
677 var ps = config[lr].panels;
678 layout.addTypedPanels(r, ps);
686 Roo.BorderLayout.RegionFactory = {
688 validRegions : ["north","south","east","west","center"],
691 create : function(target, mgr, config){
692 target = target.toLowerCase();
693 if(config.lightweight || config.basic){
694 return new Roo.BasicLayoutRegion(mgr, config, target);
698 return new Roo.NorthLayoutRegion(mgr, config);
700 return new Roo.SouthLayoutRegion(mgr, config);
702 return new Roo.EastLayoutRegion(mgr, config);
704 return new Roo.WestLayoutRegion(mgr, config);
706 return new Roo.CenterLayoutRegion(mgr, config);
708 throw 'Layout region "'+target+'" not supported.';