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 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
15 * please see: <br><br>
16 * <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>
17 * <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>
20 var layout = new Roo.BorderLayout(document.body, {
54 preferredTabWidth: 150
59 var CP = Roo.ContentPanel;
62 layout.add("north", new CP("north", "North"));
63 layout.add("south", new CP("south", {title: "South", closable: true}));
64 layout.add("west", new CP("west", {title: "West"}));
65 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
66 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
67 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
68 layout.getRegion("center").showPanel("center1");
72 <b>The container the layout is rendered into can be either the body element or any other element.
73 If it is not the body element, the container needs to either be an absolute positioned element,
74 or you will need to add "position:relative" to the css of the container. You will also need to specify
75 the container size if it is not the body element.</b>
78 * Create a new BorderLayout
79 * @param {String/HTMLElement/Element} container The container this layout is bound to
80 * @param {Object} config Configuration options
82 Roo.BorderLayout = function(container, config){
83 config = config || {};
84 Roo.BorderLayout.superclass.constructor.call(this, container, config);
85 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
86 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
87 var target = this.factory.validRegions[i];
89 this.addRegion(target, config[target]);
94 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
96 * Creates and adds a new region if it doesn't already exist.
97 * @param {String} target The target region key (north, south, east, west or center).
98 * @param {Object} config The regions config object
99 * @return {BorderLayoutRegion} The new region
101 addRegion : function(target, config){
102 if(!this.regions[target]){
103 var r = this.factory.create(target, this, config);
104 this.bindRegion(target, r);
106 return this.regions[target];
110 bindRegion : function(name, r){
111 this.regions[name] = r;
112 r.on("visibilitychange", this.layout, this);
113 r.on("paneladded", this.layout, this);
114 r.on("panelremoved", this.layout, this);
115 r.on("invalidated", this.layout, this);
116 r.on("resized", this.onRegionResized, this);
117 r.on("collapsed", this.onRegionCollapsed, this);
118 r.on("expanded", this.onRegionExpanded, this);
122 * Performs a layout update.
125 if(this.updating) return;
126 var size = this.getViewSize();
135 var rs = this.regions;
136 var north = rs["north"];
137 var south = rs["south"];
138 var west = rs["west"];
139 var east = rs["east"];
140 var center = rs["center"];
141 //if(this.hideOnLayout){ // not supported anymore
142 //c.el.setStyle("display", "none");
144 if(north && north.isVisible()){
145 var b = north.getBox();
146 var m = north.getMargins();
147 b.width = w - (m.left+m.right);
150 centerY = b.height + b.y + m.bottom;
152 north.updateBox(this.safeBox(b));
154 if(south && south.isVisible()){
155 var b = south.getBox();
156 var m = south.getMargins();
157 b.width = w - (m.left+m.right);
159 var totalHeight = (b.height + m.top + m.bottom);
160 b.y = h - totalHeight + m.top;
161 centerH -= totalHeight;
162 south.updateBox(this.safeBox(b));
164 if(west && west.isVisible()){
165 var b = west.getBox();
166 var m = west.getMargins();
167 b.height = centerH - (m.top+m.bottom);
169 b.y = centerY + m.top;
170 var totalWidth = (b.width + m.left + m.right);
171 centerX += totalWidth;
172 centerW -= totalWidth;
173 west.updateBox(this.safeBox(b));
175 if(east && east.isVisible()){
176 var b = east.getBox();
177 var m = east.getMargins();
178 b.height = centerH - (m.top+m.bottom);
179 var totalWidth = (b.width + m.left + m.right);
180 b.x = w - totalWidth + m.left;
181 b.y = centerY + m.top;
182 centerW -= totalWidth;
183 east.updateBox(this.safeBox(b));
186 var m = center.getMargins();
190 width: centerW - (m.left+m.right),
191 height: centerH - (m.top+m.bottom)
193 //if(this.hideOnLayout){
194 //center.el.setStyle("display", "block");
196 center.updateBox(this.safeBox(centerBox));
199 this.fireEvent("layout", this);
203 safeBox : function(box){
204 box.width = Math.max(0, box.width);
205 box.height = Math.max(0, box.height);
210 * Adds a ContentPanel (or subclass) to this layout.
211 * @param {String} target The target region key (north, south, east, west or center).
212 * @param {Roo.ContentPanel} panel The panel to add
213 * @return {Roo.ContentPanel} The added panel
215 add : function(target, panel){
217 target = target.toLowerCase();
218 return this.regions[target].add(panel);
222 * Remove a ContentPanel (or subclass) to this layout.
223 * @param {String} target The target region key (north, south, east, west or center).
224 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
225 * @return {Roo.ContentPanel} The removed panel
227 remove : function(target, panel){
228 target = target.toLowerCase();
229 return this.regions[target].remove(panel);
233 * Searches all regions for a panel with the specified id
234 * @param {String} panelId
235 * @return {Roo.ContentPanel} The panel or null if it wasn't found
237 findPanel : function(panelId){
238 var rs = this.regions;
239 for(var target in rs){
240 if(typeof rs[target] != "function"){
241 var p = rs[target].getPanel(panelId);
251 * Searches all regions for a panel with the specified id and activates (shows) it.
252 * @param {String/ContentPanel} panelId The panels id or the panel itself
253 * @return {Roo.ContentPanel} The shown panel or null
255 showPanel : function(panelId) {
256 var rs = this.regions;
257 for(var target in rs){
259 if(typeof r != "function"){
260 if(r.hasPanel(panelId)){
261 return r.showPanel(panelId);
269 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
270 * @param {Roo.state.Provider} provider (optional) An alternate state provider
272 restoreState : function(provider){
274 provider = Roo.state.Manager;
276 var sm = new Roo.LayoutStateManager();
277 sm.init(this, provider);
281 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
282 * object should contain properties for each region to add ContentPanels to, and each property's value should be
283 * a valid ContentPanel config object. Example:
285 // Create the main layout
286 var layout = new Roo.BorderLayout('main-ct', {
297 // Create and add multiple ContentPanels at once via configs
302 title:'Ext Source Files',
315 * @param {Object} regions An object containing ContentPanel configs by region name
317 batchAdd : function(regions){
319 for(var rname in regions){
320 var lr = this.regions[rname];
322 this.addTypedPanels(lr, regions[rname]);
329 addTypedPanels : function(lr, ps){
330 if(typeof ps == 'string'){
331 lr.add(new Roo.ContentPanel(ps));
333 else if(ps instanceof Array){
334 for(var i =0, len = ps.length; i < len; i++){
335 this.addTypedPanels(lr, ps[i]);
338 else if(!ps.events){ // raw config?
340 delete ps.el; // prevent conflict
341 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
343 else { // panel object assumed!
348 * Adds a xtype elements to the layout.
352 xtype : 'ContentPanel',
359 xtype : 'NestedLayoutPanel',
365 items : [ ... list of content panels or nested layout panels.. ]
369 * @param {Object} cfg Xtype definition of item to add.
371 addxtype : function(cfg)
373 // basically accepts a pannel...
374 // can accept a layout region..!?!?
375 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
377 if (!cfg.xtype.match(/Panel$/)) {
382 if (typeof(cfg.region) == 'undefined') {
383 Roo.log("Failed to add Panel, region was not set");
387 var region = cfg.region;
400 case 'ContentPanel': // ContentPanel (el, cfg)
401 case 'ScrollPanel': // ContentPanel (el, cfg)
403 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
405 var el = this.el.createChild();
406 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
409 this.add(region, ret);
413 case 'TreePanel': // our new panel!
414 cfg.el = this.el.createChild();
415 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
416 this.add(region, ret);
419 case 'NestedLayoutPanel':
420 // create a new Layout (which is a Border Layout...
421 var el = this.el.createChild();
422 var clayout = cfg.layout;
424 clayout.items = clayout.items || [];
425 // replace this exitems with the clayout ones..
426 xitems = clayout.items;
429 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
430 cfg.background = false;
432 var layout = new Roo.BorderLayout(el, clayout);
434 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
435 //console.log('adding nested layout panel ' + cfg.toSource());
436 this.add(region, ret);
437 nb = {}; /// find first...
442 // needs grid and region
444 //var el = this.getRegion(region).el.createChild();
445 var el = this.el.createChild();
446 // create the grid first...
448 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
450 if (region == 'center' && this.active ) {
451 cfg.background = false;
453 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
455 this.add(region, ret);
456 if (cfg.background) {
457 ret.on('activate', function(gp) {
458 if (!gp.grid.rendered) {
471 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
473 // GridPanel (grid, cfg)
479 Roo.each(xitems, function(i) {
480 region = nb && i.region && !i.background ? i.region : false;
482 var add = ret.addxtype(i);
490 // make the last non-background panel active..
491 //if (nb) { Roo.log(nb); }
495 region = this.getRegion(r);
497 region.setActivePanel(nb[r]);
507 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
508 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
509 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
510 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
513 var CP = Roo.ContentPanel;
515 var layout = Roo.BorderLayout.create({
519 panels: [new CP("north", "North")]
528 panels: [new CP("west", {title: "West"})]
537 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
546 panels: [new CP("south", {title: "South", closable: true})]
553 preferredTabWidth: 150,
555 new CP("center1", {title: "Close Me", closable: true}),
556 new CP("center2", {title: "Center Panel", closable: false})
561 layout.getRegion("center").showPanel("center1");
566 Roo.BorderLayout.create = function(config, targetEl){
567 var layout = new Roo.BorderLayout(targetEl || document.body, config);
568 layout.beginUpdate();
569 var regions = Roo.BorderLayout.RegionFactory.validRegions;
570 for(var j = 0, jlen = regions.length; j < jlen; j++){
572 if(layout.regions[lr] && config[lr].panels){
573 var r = layout.regions[lr];
574 var ps = config[lr].panels;
575 layout.addTypedPanels(r, ps);
583 Roo.BorderLayout.RegionFactory = {
585 validRegions : ["north","south","east","west","center"],
588 create : function(target, mgr, config){
589 target = target.toLowerCase();
590 if(config.lightweight || config.basic){
591 return new Roo.BasicLayoutRegion(mgr, config, target);
595 return new Roo.NorthLayoutRegion(mgr, config);
597 return new Roo.SouthLayoutRegion(mgr, config);
599 return new Roo.EastLayoutRegion(mgr, config);
601 return new Roo.WestLayoutRegion(mgr, config);
603 return new Roo.CenterLayoutRegion(mgr, config);
605 throw 'Layout region "'+target+'" not supported.';