Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / layout / Layout.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.layout.Layout
17  * @extends Object
18  * Base Layout class - extended by ComponentLayout and ContainerLayout
19  */
20 Ext.define('Ext.layout.Layout', {
21
22     /* Begin Definitions */
23
24     /* End Definitions */
25
26     isLayout: true,
27     initialized: false,
28
29     statics: {
30         create: function(layout, defaultType) {
31             var type;
32             if (layout instanceof Ext.layout.Layout) {
33                 return Ext.createByAlias('layout.' + layout);
34             } else {
35                 if (!layout || typeof layout === 'string') {
36                     type = layout || defaultType;
37                     layout = {};                    
38                 }
39                 else {
40                     type = layout.type;
41                 }
42                 return Ext.createByAlias('layout.' + type, layout || {});
43             }
44         }
45     },
46
47     constructor : function(config) {
48         this.id = Ext.id(null, this.type + '-');
49         Ext.apply(this, config);
50     },
51
52     /**
53      * @private
54      */
55     layout : function() {
56         var me = this;
57         me.layoutBusy = true;
58         me.initLayout();
59
60         if (me.beforeLayout.apply(me, arguments) !== false) {
61             me.layoutCancelled = false;
62             me.onLayout.apply(me, arguments);
63             me.childrenChanged = false;
64             me.owner.needsLayout = false;
65             me.layoutBusy = false;
66             me.afterLayout.apply(me, arguments);
67         }
68         else {
69             me.layoutCancelled = true;
70         }
71         me.layoutBusy = false;
72         me.doOwnerCtLayouts();
73     },
74
75     beforeLayout : function() {
76         this.renderItems(this.getLayoutItems(), this.getRenderTarget());
77         return true;
78     },
79
80     /**
81      * @private
82      * Iterates over all passed items, ensuring they are rendered.  If the items are already rendered,
83      * also determines if the items are in the proper place dom.
84      */
85     renderItems : function(items, target) {
86         var ln = items.length,
87             i = 0,
88             item;
89
90         for (; i < ln; i++) {
91             item = items[i];
92             if (item && !item.rendered) {
93                 this.renderItem(item, target, i);
94             }
95             else if (!this.isValidParent(item, target, i)) {
96                 this.moveItem(item, target, i);
97             }
98         }
99     },
100
101     // @private - Validates item is in the proper place in the dom.
102     isValidParent : function(item, target, position) {
103         var dom = item.el ? item.el.dom : Ext.getDom(item);
104         if (dom && target && target.dom) {
105             if (Ext.isNumber(position) && dom !== target.dom.childNodes[position]) {
106                 return false;
107             }
108             return (dom.parentNode == (target.dom || target));
109         }
110         return false;
111     },
112
113     /**
114      * @private
115      * Renders the given Component into the target Element.
116      * @param {Ext.Component} item The Component to render
117      * @param {Ext.core.Element} target The target Element
118      * @param {Number} position The position within the target to render the item to
119      */
120     renderItem : function(item, target, position) {
121         var me = this;
122         if (!item.rendered) {
123             if (me.itemCls) {
124                 item.addCls(me.itemCls);
125             }
126             if (me.owner.itemCls) {
127                 item.addCls(me.owner.itemCls);
128             }
129             item.render(target, position);
130             me.configureItem(item);
131             me.childrenChanged = true;
132         }
133     },
134
135     /**
136      * @private
137      * Moved Component to the provided target instead.
138      */
139     moveItem : function(item, target, position) {
140         // Make sure target is a dom element
141         target = target.dom || target;
142         if (typeof position == 'number') {
143             position = target.childNodes[position];
144         }
145         target.insertBefore(item.el.dom, position || null);
146         item.container = Ext.get(target);
147         this.configureItem(item);
148         this.childrenChanged = true;
149     },
150
151     /**
152      * @private
153      * Adds the layout's targetCls if necessary and sets
154      * initialized flag when complete.
155      */
156     initLayout : function() {
157         if (!this.initialized && !Ext.isEmpty(this.targetCls)) {
158             this.getTarget().addCls(this.targetCls);
159         }
160         this.initialized = true;
161     },
162
163     // @private Sets the layout owner
164     setOwner : function(owner) {
165         this.owner = owner;
166     },
167
168     // @private - Returns empty array
169     getLayoutItems : function() {
170         return [];
171     },
172
173     /**
174      * @private
175      * Applies itemCls
176      * Empty template method
177      */
178     configureItem: Ext.emptyFn,
179     
180     // Placeholder empty functions for subclasses to extend
181     onLayout : Ext.emptyFn,
182     afterLayout : Ext.emptyFn,
183     onRemove : Ext.emptyFn,
184     onDestroy : Ext.emptyFn,
185     doOwnerCtLayouts : Ext.emptyFn,
186
187     /**
188      * @private
189      * Removes itemCls
190      */
191     afterRemove : function(item) {
192         var me = this,
193             el = item.el,
194             owner = me.owner;
195             
196         // Clear managed dimensions flag when removed from the layout.
197         if (item.rendered) {
198             if (me.itemCls) {
199                 el.removeCls(me.itemCls);
200             }
201             if (owner.itemCls) {
202                 el.removeCls(owner.itemCls);
203             }
204         }
205
206         // These flags are set at the time a child item is added to a layout.
207         // The layout must decide if it is managing the item's width, or its height, or both.
208         // See AbstractComponent for docs on these properties.
209         delete item.layoutManagedWidth;
210         delete item.layoutManagedHeight;
211     },
212
213     /*
214      * Destroys this layout. This is a template method that is empty by default, but should be implemented
215      * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
216      * @protected
217      */
218     destroy : function() {
219         if (!Ext.isEmpty(this.targetCls)) {
220             var target = this.getTarget();
221             if (target) {
222                 target.removeCls(this.targetCls);
223             }
224         }
225         this.onDestroy();
226     }
227 });