source: trunk/web/addons/job_monarch/lib/extjs/source/widgets/Container.js @ 619

Last change on this file since 619 was 619, checked in by ramonb, 15 years ago

lib/:

  • added new AJAX dependancies: ExtJS, pChart, Lightbox2
File size: 27.2 KB
Line 
1/*
2 * Ext JS Library 2.2.1
3 * Copyright(c) 2006-2009, Ext JS, LLC.
4 * licensing@extjs.com
5 *
6 * http://extjs.com/license
7 */
8
9/**
10 * @class Ext.Container
11 * @extends Ext.BoxComponent
12 * <p>Base class for any {@link Ext.BoxComponent} that can contain other components. The most commonly
13 * used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}, but you can
14 * create a lightweight Container to encapsulate an HTML element that is created to your
15 * specifications at render time by using the {@link Ext.Component#autoEl autoEl} config option
16 * which takes the form of a {@link Ext.DomHelper DomHelper} specification. If you do not need
17 * the capabilities offered by the above mentioned classes, for instance embedded
18 * {@link Ext.layout.ColumnLayout column} layouts inside FormPanels, then this is a useful technique.</p>
19 * <p>The code below illustrates both how to explicitly <i>create</i> a Container, and how to implicitly
20 * create one using the <b><tt>'container'</tt></b> xtype:<pre><code>
21var embeddedColumns = new Ext.Container({
22    autoEl: {},
23    layout: 'column',
24    defaults: {
25        xtype: 'container',
26        autoEl: {},
27        layout: 'form',
28        columnWidth: 0.5,
29        style: {
30            padding: '10px'
31        }
32    },
33    items: [{
34        items: {
35            xtype: 'datefield',
36            name: 'startDate',
37            fieldLabel: 'Start date'
38        }
39    }, {
40        items: {
41            xtype: 'datefield',
42            name: 'endDate',
43            fieldLabel: 'End date'
44        }
45    }]
46});</code></pre></p>
47 * Containers handle the basic behavior of containing items, namely adding, inserting and removing them.
48 * The specific layout logic required to visually render contained items is delegated to any one of the different
49 * {@link #layout} classes available.</p>
50 * <p>When either specifying child {@link #items} of a Container, or dynamically adding components to a Container,
51 * remember to consider how you wish the Container to arrange those child elements, and whether those child elements
52 * need to be sized using one of Ext's built-in layout schemes.</p>
53 * <p>By default, Containers use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders
54 * child components, appending them one after the other inside the Container, and does not apply any sizing at all.
55 * This is a common source of confusion when widgets like GridPanels or TreePanels are added to Containers for
56 * which no layout has been specified. If a Container is left to use the ContainerLayout scheme, none of its child
57 * components will be resized, or changed in any way when the Container is resized.</p>
58 * <p>A very common example of this is where a developer will attempt to add a GridPanel to a TabPanel by wrapping
59 * the GridPanel <i>inside</i> a wrapping Panel and add that wrapping Panel to the TabPanel. This misses the point that
60 * Ext's inheritance means that a GridPanel <b>is</b> a Component which can be added unadorned into a Container. If
61 * that wrapping Panel has no layout configuration, then the GridPanel will not be sized as expected.<p>
62 * <p>Below is an example of adding a newly created GridPanel to a TabPanel. A TabPanel uses {@link Ext.layout.CardLayout}
63 * as its layout manager which means all its child items are sized to fit exactly into its client area. The following
64 * code requires prior knowledge of how to create GridPanels. See {@link Ext.grid.GridPanel}, {@link Ext.data.Store}
65 * and {@link Ext.data.JsonReader} as well as the grid examples in the Ext installation's <tt>examples/grid</tt>
66 * directory.</p><pre><code>
67//  Create the GridPanel.
68myGrid = new Ext.grid.GridPanel({
69    store: myStore,
70    columns: myColumnModel,
71    title: 'Results',
72});
73
74myTabPanel.add(myGrid);
75myTabPanel.setActiveTab(myGrid);
76</code></pre>
77 */
78Ext.Container = Ext.extend(Ext.BoxComponent, {
79    /** @cfg {Boolean} monitorResize
80     * True to automatically monitor window resize events to handle anything that is sensitive to the current size
81     * of the viewport.  This value is typically managed by the chosen {@link #layout} and should not need to be set manually.
82     */
83    /**
84     * @cfg {String} layout
85     * The layout type to be used in this container.  If not specified, a default {@link Ext.layout.ContainerLayout}
86     * will be created and used. Specific config values for the chosen layout type can be specified using
87     * {@link #layoutConfig}. Valid values are:<ul class="mdetail-params">
88     * <li>absolute</li>
89     * <li>accordion</li>
90     * <li>anchor</li>
91     * <li>border</li>
92     * <li>card</li>
93     * <li>column</li>
94     * <li>fit</li>
95     * <li>form</li>
96     * <li>table</li></ul>
97     */
98    /**
99     * @cfg {Object} layoutConfig
100     * This is a config object containing properties specific to the chosen layout (to be used in conjunction with
101     * the {@link #layout} config value).  For complete details regarding the valid config options for each layout
102     * type, see the layout class corresponding to the type specified:<ul class="mdetail-params">
103     * <li>{@link Ext.layout.Absolute}</li>
104     * <li>{@link Ext.layout.Accordion}</li>
105     * <li>{@link Ext.layout.AnchorLayout}</li>
106     * <li>{@link Ext.layout.BorderLayout}</li>
107     * <li>{@link Ext.layout.CardLayout}</li>
108     * <li>{@link Ext.layout.ColumnLayout}</li>
109     * <li>{@link Ext.layout.FitLayout}</li>
110     * <li>{@link Ext.layout.FormLayout}</li>
111     * <li>{@link Ext.layout.TableLayout}</li></ul>
112     */
113    /**
114     * @cfg {Boolean/Number} bufferResize
115     * When set to true (100 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer
116     * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers
117     * with a large quantity of sub-components for which frequent layout calls would be expensive.
118     */
119    /**
120     * @cfg {String/Number} activeItem
121     * A string component id or the numeric index of the component that should be initially activated within the
122     * container's layout on render.  For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
123     * item in the container's collection).  activeItem only applies to layout styles that can display
124     * items one at a time (like {@link Ext.layout.Accordion}, {@link Ext.layout.CardLayout} and
125     * {@link Ext.layout.FitLayout}).  Related to {@link Ext.layout.ContainerLayout#activeItem}.
126     */
127    /**
128     * @cfg {Mixed} items
129     * A single item, or an array of child Components to be added to this container.
130     * Each item can be any type of object based on {@link Ext.Component}.<br><br>
131     * Component config objects may also be specified in order to avoid the overhead
132     * of constructing a real Component object if lazy rendering might mean that the
133     * added Component will not be rendered immediately. To take advantage of this
134     * "lazy instantiation", set the {@link Ext.Component#xtype} config property to
135     * the registered type of the Component wanted.<br><br>
136     * For a list of all available xtypes, see {@link Ext.Component}.
137     * If a single item is being passed, it should be passed directly as an object
138     * reference (e.g., items: {...}).  Multiple items should be passed as an array
139     * of objects (e.g., items: [{...}, {...}]).
140     */
141    /**
142     * @cfg {Object} defaults
143     * A config object that will be applied to all components added to this container either via the {@link #items}
144     * config or via the {@link #add} or {@link #insert} methods.  The defaults config can contain any number of
145     * name/value property pairs to be added to each item, and should be valid for the types of items
146     * being added to the container.  For example, to automatically apply padding to the body of each of a set of
147     * contained {@link Ext.Panel} items, you could pass: defaults: {bodyStyle:'padding:15px'}.
148     */
149
150    /** @cfg {Boolean} autoDestroy
151     * If true the container will automatically destroy any contained component that is removed from it, else
152     * destruction must be handled manually (defaults to true).
153     */
154    autoDestroy: true,
155    /** @cfg {Boolean} hideBorders
156     * True to hide the borders of each contained component, false to defer to the component's existing
157     * border settings (defaults to false).
158     */
159    /** @cfg {String} defaultType
160     * <p>The default {@link Ext.Component xtype} of child Components to create in this Container when
161     * a child item is specified as a raw configuration object, rather than as an instantiated Component.</p>
162     * <p>Defaults to 'panel'.</p>
163     */
164    defaultType: 'panel',
165
166    // private
167    initComponent : function(){
168        Ext.Container.superclass.initComponent.call(this);
169
170        this.addEvents(
171            /**
172             * @event afterlayout
173             * Fires when the components in this container are arranged by the associated layout manager.
174             * @param {Ext.Container} this
175             * @param {ContainerLayout} layout The ContainerLayout implementation for this container
176             */
177            'afterlayout',
178            /**
179             * @event beforeadd
180             * Fires before any {@link Ext.Component} is added or inserted into the container.
181             * A handler can return false to cancel the add.
182             * @param {Ext.Container} this
183             * @param {Ext.Component} component The component being added
184             * @param {Number} index The index at which the component will be added to the container's items collection
185             */
186            'beforeadd',
187            /**
188             * @event beforeremove
189             * Fires before any {@link Ext.Component} is removed from the container.  A handler can return
190             * false to cancel the remove.
191             * @param {Ext.Container} this
192             * @param {Ext.Component} component The component being removed
193             */
194            'beforeremove',
195            /**
196             * @event add
197             * Fires after any {@link Ext.Component} is added or inserted into the container.
198             * @param {Ext.Container} this
199             * @param {Ext.Component} component The component that was added
200             * @param {Number} index The index at which the component was added to the container's items collection
201             */
202            'add',
203            /**
204             * @event remove
205             * Fires after any {@link Ext.Component} is removed from the container.
206             * @param {Ext.Container} this
207             * @param {Ext.Component} component The component that was removed
208             */
209            'remove'
210        );
211
212        /**
213         * The collection of components in this container as a {@link Ext.util.MixedCollection}
214         * @type MixedCollection
215         * @property items
216         */
217        var items = this.items;
218        if(items){
219            delete this.items;
220            if(Ext.isArray(items) && items.length > 0){
221                this.add.apply(this, items);
222            }else{
223                this.add(items);
224            }
225        }
226    },
227
228    // private
229    initItems : function(){
230        if(!this.items){
231            this.items = new Ext.util.MixedCollection(false, this.getComponentId);
232            this.getLayout(); // initialize the layout
233        }
234    },
235
236    // private
237    setLayout : function(layout){
238        if(this.layout && this.layout != layout){
239            this.layout.setContainer(null);
240        }
241        this.initItems();
242        this.layout = layout;
243        layout.setContainer(this);
244    },
245
246    // private
247    render : function(){
248        Ext.Container.superclass.render.apply(this, arguments);
249        if(this.layout){
250            if(typeof this.layout == 'string'){
251                this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
252            }
253            this.setLayout(this.layout);
254
255            if(this.activeItem !== undefined){
256                var item = this.activeItem;
257                delete this.activeItem;
258                this.layout.setActiveItem(item);
259                return;
260            }
261        }
262        if(!this.ownerCt){
263            this.doLayout();
264        }
265        if(this.monitorResize === true){
266            Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
267        }
268    },
269
270    /**
271     * <p>Returns the Element to be used to contain the child Components of this Container.</p>
272     * <p>An implementation is provided which returns the Container's {@link #getEl Element}, but
273     * if there is a more complex structure to a Container, this may be overridden to return
274     * the element into which the {@link #layout layout} renders child Components.</p>
275     * @return {Ext.Element} The Element to render child Components into.
276     */
277    getLayoutTarget : function(){
278        return this.el;
279    },
280
281    // private - used as the key lookup function for the items collection
282    getComponentId : function(comp){
283        return comp.itemId || comp.id;
284    },
285
286    /**
287     * <p>Adds a {@link Ext.Component Component} to this Container. Fires the {@link #beforeadd} event before
288     * adding, then fires the {@link #add} event after the component has been added.</p>
289     * <p>You will never call the render method of a child Component when using a Container.
290     * Child Components are rendered by this Container's {@link #layout} manager when
291     * this Container is first rendered.</p>
292     * <p>Certain layout managers allow dynamic addition of child components. Those that do
293     * include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout},
294     * {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.</p>
295     * <p>If the Container is already rendered when add is called, you may need to call
296     * {@link #doLayout} to refresh the view which causes any unrendered child Components
297     * to be rendered. This is required so that you can add multiple child components if needed
298     * while only refreshing the layout once.</p>
299     * <p>When creating complex UIs, it is important to remember that sizing and positioning
300     * of child items is the responsibility of the Container's {@link #layout} manager. If
301     * you expect child items to be sized in response to user interactions, you must
302     * specify a layout manager which creates and manages the type of layout you have in mind.</p>
303     * <p><b>Omitting the {@link #layout} config means that a basic layout manager is
304     * used which does nothnig but render child components sequentially into the Container.
305     * No sizing or positioning will be performed in this situation.</b></p>
306     * @param {Ext.Component/Object} component The Component to add.<br><br>
307     * Ext uses lazy rendering, and will only render the added Component should
308     * it become necessary, that is: when the Container is layed out either on first render
309     * or in response to a {@link #doLayout} call.<br><br>
310     * A Component config object may be passed instead of an instantiated Component object.
311     * The type of Component created from a config object is determined by the {@link Ext.Component#xtype xtype}
312     * config property. If no xtype is configured, the Container's {@link #defaultType}
313     * is used.<br><br>
314     * For a list of all available xtypes, see {@link Ext.Component}.
315     * @return {Ext.Component} component The Component (or config object) that was
316     * added with the Container's default config values applied.
317     * <p>example:</p><pre><code>
318var myNewGrid = new Ext.grid.GridPanel({
319    store: myStore,
320    colModel: myColModel
321});
322myTabPanel.add(myNewGrid);
323myTabPanel.setActiveTab(myNewGrid);
324</code></pre>
325     */
326    add : function(comp){
327        if(!this.items){
328            this.initItems();
329        }
330        var a = arguments, len = a.length;
331        if(len > 1){
332            for(var i = 0; i < len; i++) {
333                this.add(a[i]);
334            }
335            return;
336        }
337        var c = this.lookupComponent(this.applyDefaults(comp));
338        var pos = this.items.length;
339        if(this.fireEvent('beforeadd', this, c, pos) !== false && this.onBeforeAdd(c) !== false){
340            this.items.add(c);
341            c.ownerCt = this;
342            this.fireEvent('add', this, c, pos);
343        }
344        return c;
345    },
346
347    /**
348     * Inserts a Component into this Container at a specified index. Fires the
349     * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the
350     * Component has been inserted.
351     * @param {Number} index The index at which the Component will be inserted
352     * into the Container's items collection
353     * @param {Ext.Component} component The child Component to insert.<br><br>
354     * Ext uses lazy rendering, and will only render the inserted Component should
355     * it become necessary.<br><br>
356     * A Component config object may be passed in order to avoid the overhead of
357     * constructing a real Component object if lazy rendering might mean that the
358     * inserted Component will not be rendered immediately. To take advantage of
359     * this "lazy instantiation", set the {@link Ext.Component#xtype} config
360     * property to the registered type of the Component wanted.<br><br>
361     * For a list of all available xtypes, see {@link Ext.Component}.
362     * @return {Ext.Component} component The Component (or config object) that was
363     * inserted with the Container's default config values applied.
364     */
365    insert : function(index, comp){
366        if(!this.items){
367            this.initItems();
368        }
369        var a = arguments, len = a.length;
370        if(len > 2){
371            for(var i = len-1; i >= 1; --i) {
372                this.insert(index, a[i]);
373            }
374            return;
375        }
376        var c = this.lookupComponent(this.applyDefaults(comp));
377
378        if(c.ownerCt == this && this.items.indexOf(c) < index){
379            --index;
380        }
381
382        if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
383            this.items.insert(index, c);
384            c.ownerCt = this;
385            this.fireEvent('add', this, c, index);
386        }
387        return c;
388    },
389
390    // private
391    applyDefaults : function(c){
392        if(this.defaults){
393            if(typeof c == 'string'){
394                c = Ext.ComponentMgr.get(c);
395                Ext.apply(c, this.defaults);
396            }else if(!c.events){
397                Ext.applyIf(c, this.defaults);
398            }else{
399                Ext.apply(c, this.defaults);
400            }
401        }
402        return c;
403    },
404
405    // private
406    onBeforeAdd : function(item){
407        if(item.ownerCt){
408            item.ownerCt.remove(item, false);
409        }
410        if(this.hideBorders === true){
411            item.border = (item.border === true);
412        }
413    },
414
415    /**
416     * Removes a component from this container.  Fires the {@link #beforeremove} event before removing, then fires
417     * the {@link #remove} event after the component has been removed.
418     * @param {Component/String} component The component reference or id to remove.
419     * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
420     * Defaults to the value of this Container's {@link #autoDestroy} config.
421     * @return {Ext.Component} component The Component that was removed.
422     */
423    remove : function(comp, autoDestroy){
424        var c = this.getComponent(comp);
425        if(c && this.fireEvent('beforeremove', this, c) !== false){
426            this.items.remove(c);
427            delete c.ownerCt;
428            if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
429                c.destroy();
430            }
431            if(this.layout && this.layout.activeItem == c){
432                delete this.layout.activeItem;
433            }
434            this.fireEvent('remove', this, c);
435        }
436        return c;
437    },
438   
439    /**
440     * Removes all components from this container.
441     * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
442     * Defaults to the value of this Container's {@link #autoDestroy} config.
443     * @return {Array} Array of the destroyed components
444     */
445    removeAll: function(autoDestroy){
446        var item, items = [];
447        while((item = this.items.last())){
448            items.unshift(this.remove(item, autoDestroy));
449        }
450        return items;
451    },
452
453    /**
454     * Gets a direct child Component by id, or by index.
455     * @param {String/Number} id or index of child Component to return.
456     * @return Ext.Component
457     */
458    getComponent : function(comp){
459        if(typeof comp == 'object'){
460            return comp;
461        }
462        return this.items.get(comp);
463    },
464
465    // private
466    lookupComponent : function(comp){
467        if(typeof comp == 'string'){
468            return Ext.ComponentMgr.get(comp);
469        }else if(!comp.events){
470            return this.createComponent(comp);
471        }
472        return comp;
473    },
474
475    // private
476    createComponent : function(config){
477        return Ext.ComponentMgr.create(config, this.defaultType);
478    },
479
480    /**
481     * Force this container's layout to be recalculated. A call to this function is required after adding a new component
482     * to an already rendered container, or possibly after changing sizing/position properties of child components.
483     * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto
484     * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer)
485     */
486    doLayout : function(shallow){
487        if(this.rendered && this.layout){
488            this.layout.layout();
489        }
490        if(shallow !== false && this.items){
491            var cs = this.items.items;
492            for(var i = 0, len = cs.length; i < len; i++) {
493                var c  = cs[i];
494                if(c.doLayout){
495                    c.doLayout();
496                }
497            }
498        }
499    },
500
501    /**
502     * Returns the layout currently in use by the container.  If the container does not currently have a layout
503     * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout.
504     * @return {ContainerLayout} layout The container's layout
505     */
506    getLayout : function(){
507        if(!this.layout){
508            var layout = new Ext.layout.ContainerLayout(this.layoutConfig);
509            this.setLayout(layout);
510        }
511        return this.layout;
512    },
513
514    // private
515    beforeDestroy : function(){
516        if(this.items){
517            Ext.destroy.apply(Ext, this.items.items);
518        }
519        if(this.monitorResize){
520            Ext.EventManager.removeResizeListener(this.doLayout, this);
521        }
522        if (this.layout && this.layout.destroy) {
523            this.layout.destroy();
524        }
525        Ext.Container.superclass.beforeDestroy.call(this);
526    },
527
528    /**
529     * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
530     * function call will be the scope provided or the current component. The arguments to the function
531     * will be the args provided or the current component. If the function returns false at any point,
532     * the bubble is stopped.
533     * @param {Function} fn The function to call
534     * @param {Object} scope (optional) The scope of the function (defaults to current node)
535     * @param {Array} args (optional) The args to call the function with (default to passing the current component)
536     */
537    bubble : function(fn, scope, args){
538        var p = this;
539        while(p){
540            if(fn.apply(scope || p, args || [p]) === false){
541                break;
542            }
543            p = p.ownerCt;
544        }
545    },
546
547    /**
548     * Cascades down the component/container heirarchy from this component (called first), calling the specified function with
549     * each component. The scope (<i>this</i>) of
550     * function call will be the scope provided or the current component. The arguments to the function
551     * will be the args provided or the current component. If the function returns false at any point,
552     * the cascade is stopped on that branch.
553     * @param {Function} fn The function to call
554     * @param {Object} scope (optional) The scope of the function (defaults to current component)
555     * @param {Array} args (optional) The args to call the function with (defaults to passing the current component)
556     */
557    cascade : function(fn, scope, args){
558        if(fn.apply(scope || this, args || [this]) !== false){
559            if(this.items){
560                var cs = this.items.items;
561                for(var i = 0, len = cs.length; i < len; i++){
562                    if(cs[i].cascade){
563                        cs[i].cascade(fn, scope, args);
564                    }else{
565                        fn.apply(scope || cs[i], args || [cs[i]]);
566                    }
567                }
568            }
569        }
570    },
571
572    /**
573     * Find a component under this container at any level by id
574     * @param {String} id
575     * @return Ext.Component
576     */
577    findById : function(id){
578        var m, ct = this;
579        this.cascade(function(c){
580            if(ct != c && c.id === id){
581                m = c;
582                return false;
583            }
584        });
585        return m || null;
586    },
587
588    /**
589     * Find a component under this container at any level by xtype or class
590     * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
591     * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
592     * the default), or true to check whether this Component is directly of the specified xtype.
593     * @return {Array} Array of Ext.Components
594     */
595    findByType : function(xtype, shallow){
596        return this.findBy(function(c){
597            return c.isXType(xtype, shallow);
598        });
599    },
600
601    /**
602     * Find a component under this container at any level by property
603     * @param {String} prop
604     * @param {String} value
605     * @return {Array} Array of Ext.Components
606     */
607    find : function(prop, value){
608        return this.findBy(function(c){
609            return c[prop] === value;
610        });
611    },
612
613    /**
614     * Find a component under this container at any level by a custom function. If the passed function returns
615     * true, the component will be included in the results. The passed function is called with the arguments (component, this container).
616     * @param {Function} fcn
617     * @param {Object} scope (optional)
618     * @return {Array} Array of Ext.Components
619     */
620    findBy : function(fn, scope){
621        var m = [], ct = this;
622        this.cascade(function(c){
623            if(ct != c && fn.call(scope || c, c, ct) === true){
624                m.push(c);
625            }
626        });
627        return m;
628    }
629});
630
631Ext.Container.LAYOUTS = {};
632Ext.reg('container', Ext.Container);
Note: See TracBrowser for help on using the repository browser.