fix #7318 - rename upload cropbox and panel tree
[roojs1] / Roo / BorderLayout.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.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>
19  * Example:
20  <pre><code>
21  var layout = new Roo.BorderLayout(document.body, {
22     north: {
23         initialSize: 25,
24         titlebar: false
25     },
26     west: {
27         split:true,
28         initialSize: 200,
29         minSize: 175,
30         maxSize: 400,
31         titlebar: true,
32         collapsible: true
33     },
34     east: {
35         split:true,
36         initialSize: 202,
37         minSize: 175,
38         maxSize: 400,
39         titlebar: true,
40         collapsible: true
41     },
42     south: {
43         split:true,
44         initialSize: 100,
45         minSize: 100,
46         maxSize: 200,
47         titlebar: true,
48         collapsible: true
49     },
50     center: {
51         titlebar: true,
52         autoScroll:true,
53         resizeTabs: true,
54         minTabWidth: 50,
55         preferredTabWidth: 150
56     }
57 });
58
59 // shorthand
60 var CP = Roo.panel.Content;
61
62 layout.beginUpdate();
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");
70 layout.endUpdate();
71 </code></pre>
72
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>
77
78 * @constructor
79 * Create a new BorderLayout
80 * @param {String/HTMLElement/Element} container The container this layout is bound to
81 * @param {Object} config Configuration options
82  */
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];
89         if(config[target]){
90             this.addRegion(target, config[target]);
91         }
92     }
93 };
94
95 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
96         
97         /**
98          * @cfg {Roo.LayoutRegion} east
99          */
100         /**
101          * @cfg {Roo.LayoutRegion} west
102          */
103         /**
104          * @cfg {Roo.LayoutRegion} north
105          */
106         /**
107          * @cfg {Roo.LayoutRegion} south
108          */
109         /**
110          * @cfg {Roo.LayoutRegion} center
111          */
112     /**
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
117      */
118     addRegion : function(target, config){
119         if(!this.regions[target]){
120             var r = this.factory.create(target, this, config);
121             this.bindRegion(target, r);
122         }
123         return this.regions[target];
124     },
125
126     // private (kinda)
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);
136     },
137
138     /**
139      * Performs a layout update.
140      */
141     layout : function(){
142         if(this.updating) {
143             return;
144         }
145         var size = this.getViewSize();
146         var w = size.width;
147         var h = size.height;
148         var centerW = w;
149         var centerH = h;
150         var centerY = 0;
151         var centerX = 0;
152         //var x = 0, y = 0;
153
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");
162         //}
163         if(north && north.isVisible()){
164             var b = north.getBox();
165             var m = north.getMargins();
166             b.width = w - (m.left+m.right);
167             b.x = m.left;
168             b.y = m.top;
169             centerY = b.height + b.y + m.bottom;
170             centerH -= centerY;
171             north.updateBox(this.safeBox(b));
172         }
173         if(south && south.isVisible()){
174             var b = south.getBox();
175             var m = south.getMargins();
176             b.width = w - (m.left+m.right);
177             b.x = m.left;
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));
182         }
183         if(west && west.isVisible()){
184             var b = west.getBox();
185             var m = west.getMargins();
186             b.height = centerH - (m.top+m.bottom);
187             b.x = m.left;
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));
193         }
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));
203         }
204         if(center){
205             var m = center.getMargins();
206             var centerBox = {
207                 x: centerX + m.left,
208                 y: centerY + m.top,
209                 width: centerW - (m.left+m.right),
210                 height: centerH - (m.top+m.bottom)
211             };
212             //if(this.hideOnLayout){
213                 //center.el.setStyle("display", "block");
214             //}
215             center.updateBox(this.safeBox(centerBox));
216         }
217         this.el.repaint();
218         this.fireEvent("layout", this);
219     },
220
221     // private
222     safeBox : function(box){
223         box.width = Math.max(0, box.width);
224         box.height = Math.max(0, box.height);
225         return box;
226     },
227
228     /**
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
233      */
234     add : function(target, panel){
235          
236         target = target.toLowerCase();
237         return this.regions[target].add(panel);
238     },
239
240     /**
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
245      */
246     remove : function(target, panel){
247         target = target.toLowerCase();
248         return this.regions[target].remove(panel);
249     },
250
251     /**
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
255      */
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);
261                 if(p){
262                     return p;
263                 }
264             }
265         }
266         return null;
267     },
268
269     /**
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
273      */
274     showPanel : function(panelId) {
275       var rs = this.regions;
276       for(var target in rs){
277          var r = rs[target];
278          if(typeof r != "function"){
279             if(r.hasPanel(panelId)){
280                return r.showPanel(panelId);
281             }
282          }
283       }
284       return null;
285    },
286
287    /**
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
290      */
291     restoreState : function(provider){
292         if(!provider){
293             provider = Roo.state.Manager;
294         }
295         var sm = new Roo.LayoutStateManager();
296         sm.init(this, provider);
297     },
298
299     /**
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:
303      * <pre><code>
304 // Create the main layout
305 var layout = new Roo.BorderLayout('main-ct', {
306     west: {
307         split:true,
308         minSize: 175,
309         titlebar: true
310     },
311     center: {
312         title:'Components'
313     }
314 }, 'main-ct');
315
316 // Create and add multiple ContentPanels at once via configs
317 layout.batchAdd({
318    west: {
319        id: 'source-files',
320        autoCreate:true,
321        title:'Ext Source Files',
322        autoScroll:true,
323        fitToFrame:true
324    },
325    center : {
326        el: cview,
327        autoScroll:true,
328        fitToFrame:true,
329        toolbar: tb,
330        resizeEl:'cbody'
331    }
332 });
333 </code></pre>
334      * @param {Object} regions An object containing ContentPanel configs by region name
335      */
336     batchAdd : function(regions){
337         this.beginUpdate();
338         for(var rname in regions){
339             var lr = this.regions[rname];
340             if(lr){
341                 this.addTypedPanels(lr, regions[rname]);
342             }
343         }
344         this.endUpdate();
345     },
346
347     // private
348     addTypedPanels : function(lr, ps){
349         if(typeof ps == 'string'){
350             lr.add(new Roo.panel.Content(ps));
351         }
352         else if(ps instanceof Array){
353             for(var i =0, len = ps.length; i < len; i++){
354                 this.addTypedPanels(lr, ps[i]);
355             }
356         }
357         else if(!ps.events){ // raw config?
358             var el = ps.el;
359             delete ps.el; // prevent conflict
360             lr.add(new Roo.panel.Content(el || Roo.id(), ps));
361         }
362         else {  // panel object assumed!
363             lr.add(ps);
364         }
365     },
366     /**
367      * Adds a xtype elements to the layout.
368      * <pre><code>
369
370 layout.addxtype({
371        xtype : 'ContentPanel',
372        region: 'west',
373        items: [ .... ]
374    }
375 );
376
377 layout.addxtype({
378         xtype : 'NestedLayoutPanel',
379         region: 'west',
380         layout: {
381            center: { },
382            west: { }   
383         },
384         items : [ ... list of content panels or nested layout panels.. ]
385    }
386 );
387 </code></pre>
388      * @param {Object} cfg Xtype definition of item to add.
389      */
390     addxtype : function(cfg)
391     {
392         // basically accepts a pannel...
393         // can accept a layout region..!?!?
394         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
395         
396         // if (!cfg.xtype.match(/Panel$/)) {
397         //     return false;
398         // }
399         var ret = false;
400
401         if (typeof(cfg.region) == 'undefined') {
402             Roo.log("Failed to add Panel, region was not set");
403             Roo.log(cfg);
404             return false;
405         }
406         var region = cfg.region;
407         delete cfg.region;
408         
409           
410         var xitems = [];
411         if (cfg.items) {
412             xitems = cfg.items;
413             delete cfg.items;
414         }
415         var nb = false;
416         
417         switch(cfg.xtype) 
418         {
419             case 'Content':
420                 if(cfg.autoCreate) {
421                     ret = new Roo.panel[cfg.xtype](cfg); // new panel!!!!!
422                 } else {
423                     var el = this.el.createChild();
424                     ret = new Roo.panel[cfg.xtype](el, cfg); // new panel!!!!!
425                 }
426                 
427                 this.add(region, ret);
428                 break;
429             case 'Grid':
430                 // needs grid and region
431                 
432                 //var el = this.getRegion(region).el.createChild();
433                 var el = this.el.createChild();
434                 // create the grid first...
435                 
436                 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
437                 delete cfg.grid;
438                 if (region == 'center' && this.active ) {
439                     cfg.background = false;
440                 }
441                 ret = new Roo.panel[cfg.xtype](grid, cfg); // new panel!!!!!
442                 
443                 this.add(region, ret);
444                 if (cfg.background) {
445                     ret.on('activate', function(gp) {
446                         if (!gp.grid.rendered) {
447                             gp.grid.render();
448                         }
449                     });
450                 } else {
451                     grid.render();
452                 }
453                 break;
454             case 'NestedLayout': 
455                 // create a new Layout (which is  a Border Layout...
456                 var el = this.el.createChild();
457                 var clayout = cfg.layout;
458                 delete cfg.layout;
459                 clayout.items   = clayout.items  || [];
460                 // replace this exitems with the clayout ones..
461                 xitems = clayout.items;
462                  
463                 
464                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
465                     cfg.background = false;
466                 }
467                 var layout = new Roo.BorderLayout(el, clayout);
468                 
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...
473                 break;
474                 
475             case 'Calendar':
476                 ret = new Roo.panel[cfg.xtype](cfg); // new panel!!!!!
477                 this.add(region, ret);
478                 break;
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);
483                 break;
484             case 'ContentPanel':
485             case 'ScrollPanel':  // ContentPanel (el, cfg)
486             case 'ViewPanel': 
487                 if(cfg.autoCreate) {
488                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
489                 } else {
490                     var el = this.el.createChild();
491                     ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
492                 }
493                 
494                 this.add(region, ret);
495                 break;
496             
497             
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);
502                 break;
503             
504             case 'NestedLayoutPanel': 
505                 // create a new Layout (which is  a Border Layout...
506                 var el = this.el.createChild();
507                 var clayout = cfg.layout;
508                 delete cfg.layout;
509                 clayout.items   = clayout.items  || [];
510                 // replace this exitems with the clayout ones..
511                 xitems = clayout.items;
512                  
513                 
514                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
515                     cfg.background = false;
516                 }
517                 var layout = new Roo.BorderLayout(el, clayout);
518                 
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...
523                 break;
524                 
525             case 'GridPanel': 
526             
527                 // needs grid and region
528                 
529                 //var el = this.getRegion(region).el.createChild();
530                 var el = this.el.createChild();
531                 // create the grid first...
532                 
533                 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
534                 delete cfg.grid;
535                 if (region == 'center' && this.active ) {
536                     cfg.background = false;
537                 }
538                 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
539                 
540                 this.add(region, ret);
541                 if (cfg.background) {
542                     ret.on('activate', function(gp) {
543                         if (!gp.grid.rendered) {
544                             gp.grid.render();
545                         }
546                     });
547                 } else {
548                     grid.render();
549                 }
550                 break;
551            
552            
553            
554                 
555                 
556                 
557             default:
558                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
559                     
560                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
561                     this.add(region, ret);
562                 } else {
563                 
564                     alert("Can not add '" + cfg.xtype + "' to BorderLayout");
565                     return null;
566                 }
567                 
568              // GridPanel (grid, cfg)
569             
570         }
571         this.beginUpdate();
572         // add children..
573         var region = '';
574         var abn = {};
575         Roo.each(xitems, function(i)  {
576             region = nb && i.region ? i.region : false;
577             
578             var add = ret.addxtype(i);
579            
580             if (region) {
581                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
582                 if (!i.background) {
583                     abn[region] = nb[region] ;
584                 }
585             }
586             
587         });
588         this.endUpdate();
589
590         // make the last non-background panel active..
591         //if (nb) { Roo.log(abn); }
592         if (nb) {
593             
594             for(var r in abn) {
595                 region = this.getRegion(r);
596                 if (region) {
597                     // tried using nb[r], but it does not work..
598                      
599                     region.showPanel(abn[r]);
600                    
601                 }
602             }
603         }
604         return ret;
605         
606     }
607 });
608
609 /**
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:
614  * <pre><code>
615 // shorthand
616 var CP = Roo.ContentPanel;
617
618 var layout = Roo.BorderLayout.create({
619     north: {
620         initialSize: 25,
621         titlebar: false,
622         panels: [new CP("north", "North")]
623     },
624     west: {
625         split:true,
626         initialSize: 200,
627         minSize: 175,
628         maxSize: 400,
629         titlebar: true,
630         collapsible: true,
631         panels: [new CP("west", {title: "West"})]
632     },
633     east: {
634         split:true,
635         initialSize: 202,
636         minSize: 175,
637         maxSize: 400,
638         titlebar: true,
639         collapsible: true,
640         panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
641     },
642     south: {
643         split:true,
644         initialSize: 100,
645         minSize: 100,
646         maxSize: 200,
647         titlebar: true,
648         collapsible: true,
649         panels: [new CP("south", {title: "South", closable: true})]
650     },
651     center: {
652         titlebar: true,
653         autoScroll:true,
654         resizeTabs: true,
655         minTabWidth: 50,
656         preferredTabWidth: 150,
657         panels: [
658             new CP("center1", {title: "Close Me", closable: true}),
659             new CP("center2", {title: "Center Panel", closable: false})
660         ]
661     }
662 }, document.body);
663
664 layout.getRegion("center").showPanel("center1");
665 </code></pre>
666  * @param config
667  * @param targetEl
668  */
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++){
674         var lr = regions[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);
679         }
680     }
681     layout.endUpdate();
682     return layout;
683 };
684
685 // private
686 Roo.BorderLayout.RegionFactory = {
687     // private
688     validRegions : ["north","south","east","west","center"],
689
690     // private
691     create : function(target, mgr, config){
692         target = target.toLowerCase();
693         if(config.lightweight || config.basic){
694             return new Roo.BasicLayoutRegion(mgr, config, target);
695         }
696         switch(target){
697             case "north":
698                 return new Roo.NorthLayoutRegion(mgr, config);
699             case "south":
700                 return new Roo.SouthLayoutRegion(mgr, config);
701             case "east":
702                 return new Roo.EastLayoutRegion(mgr, config);
703             case "west":
704                 return new Roo.WestLayoutRegion(mgr, config);
705             case "center":
706                 return new Roo.CenterLayoutRegion(mgr, config);
707         }
708         throw 'Layout region "'+target+'" not supported.';
709     }
710 };