Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / panel / Header.js
1 /**
2  * @class Ext.panel.Header
3  * @extends Ext.container.Container
4  * Simple header class which is used for on {@link Ext.panel.Panel} and {@link Ext.window.Window}
5  * @xtype header
6  */
7 Ext.define('Ext.panel.Header', {
8     extend: 'Ext.container.Container',
9     uses: ['Ext.panel.Tool', 'Ext.draw.Component', 'Ext.util.CSS'],
10     alias: 'widget.header',
11
12     isHeader       : true,
13     defaultType    : 'tool',
14     indicateDrag   : false,
15     weight         : -1,
16
17     renderTpl: ['<div class="{baseCls}-body<tpl if="bodyCls"> {bodyCls}</tpl><tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>></div>'],
18
19     initComponent: function() {
20         var me = this,
21             rule,
22             style,
23             titleTextEl,
24             ui;
25
26         me.indicateDragCls = me.baseCls + '-draggable';
27         me.title = me.title || '&#160;';
28         me.tools = me.tools || [];
29         me.items = me.items || [];
30         me.orientation = me.orientation || 'horizontal';
31         me.dock = (me.dock) ? me.dock : (me.orientation == 'horizontal') ? 'top' : 'left';
32
33         //add the dock as a ui
34         //this is so we support top/right/left/bottom headers
35         me.addClsWithUI(me.orientation);
36         me.addClsWithUI(me.dock);
37
38         Ext.applyIf(me.renderSelectors, {
39             body: '.' + me.baseCls + '-body'
40         });
41
42         // Add Icon
43         if (!Ext.isEmpty(me.iconCls)) {
44             me.initIconCmp();
45             me.items.push(me.iconCmp);
46         }
47
48         // Add Title
49         if (me.orientation == 'vertical') {
50             // Hack for IE6/7's inability to display an inline-block
51             if (Ext.isIE6 || Ext.isIE7) {
52                 me.width = this.width || 24;
53             } else if (Ext.isIEQuirks) {
54                 me.width = this.width || 25;
55             }
56
57             me.layout = {
58                 type : 'vbox',
59                 align: 'center',
60                 clearInnerCtOnLayout: true,
61                 bindToOwnerCtContainer: false
62             };
63             me.textConfig = {
64                 cls: me.baseCls + '-text',
65                 type: 'text',
66                 text: me.title,
67                 rotate: {
68                     degrees: 90
69                 }
70             };
71             ui = me.ui;
72             if (Ext.isArray(ui)) {
73                 ui = ui[0];
74             }
75             rule = Ext.util.CSS.getRule('.' + me.baseCls + '-text-' + ui);
76             if (rule) {
77                 style = rule.style;
78             }
79             if (style) {
80                 Ext.apply(me.textConfig, {
81                     'font-family': style.fontFamily,
82                     'font-weight': style.fontWeight,
83                     'font-size': style.fontSize,
84                     fill: style.color
85                 });
86             }
87             me.titleCmp = Ext.create('Ext.draw.Component', {
88                 ariaRole  : 'heading',
89                 focusable: false,
90                 viewBox: false,
91                 autoSize: true,
92                 margins: '5 0 0 0',
93                 items: [ me.textConfig ],
94                 renderSelectors: {
95                     textEl: '.' + me.baseCls + '-text'
96                 }
97             });
98         } else {
99             me.layout = {
100                 type : 'hbox',
101                 align: 'middle',
102                 clearInnerCtOnLayout: true,
103                 bindToOwnerCtContainer: false
104             };
105             me.titleCmp = Ext.create('Ext.Component', {
106                 xtype     : 'component',
107                 ariaRole  : 'heading',
108                 focusable: false,
109                 renderTpl : ['<span class="{cls}-text {cls}-text-{ui}">{title}</span>'],
110                 renderData: {
111                     title: me.title,
112                     cls  : me.baseCls,
113                     ui   : me.ui
114                 },
115                 renderSelectors: {
116                     textEl: '.' + me.baseCls + '-text'
117                 }
118             });
119         }
120         me.items.push(me.titleCmp);
121
122         // Spacer ->
123         me.items.push({
124             xtype: 'component',
125             html : '&nbsp;',
126             flex : 1,
127             focusable: false
128         });
129
130         // Add Tools
131         me.items = me.items.concat(me.tools);
132         this.callParent();
133     },
134
135     initIconCmp: function() {
136         this.iconCmp = Ext.create('Ext.Component', {
137             focusable: false,
138             renderTpl : ['<img alt="" src="{blank}" class="{cls}-icon {iconCls}"/>'],
139             renderData: {
140                 blank  : Ext.BLANK_IMAGE_URL,
141                 cls    : this.baseCls,
142                 iconCls: this.iconCls,
143                 orientation: this.orientation
144             },
145             renderSelectors: {
146                 iconEl: '.' + this.baseCls + '-icon'
147             },
148             iconCls: this.iconCls
149         });
150     },
151
152     afterRender: function() {
153         var me = this;
154
155         me.el.unselectable();
156         if (me.indicateDrag) {
157             me.el.addCls(me.indicateDragCls);
158         }
159         me.mon(me.el, {
160             click: me.onClick,
161             scope: me
162         });
163         me.callParent();
164     },
165
166     afterLayout: function() {
167         var me = this;
168         me.callParent(arguments);
169
170         // IE7 needs a forced repaint to make the top framing div expand to full width
171         if (Ext.isIE7) {
172             me.el.repaint();
173         }
174     },
175
176     // inherit docs
177     addUIClsToElement: function(cls, force) {
178         var me = this;
179
180         me.callParent(arguments);
181
182         if (!force && me.rendered) {
183             me.body.addCls(me.baseCls + '-body-' + cls);
184             me.body.addCls(me.baseCls + '-body-' + me.ui + '-' + cls);
185         }
186     },
187
188     // inherit docs
189     removeUIClsFromElement: function(cls, force) {
190         var me = this;
191
192         me.callParent(arguments);
193
194         if (!force && me.rendered) {
195             me.body.removeCls(me.baseCls + '-body-' + cls);
196             me.body.removeCls(me.baseCls + '-body-' + me.ui + '-' + cls);
197         }
198     },
199
200     // inherit docs
201     addUIToElement: function(force) {
202         var me = this;
203
204         me.callParent(arguments);
205
206         if (!force && me.rendered) {
207             me.body.addCls(me.baseCls + '-body-' + me.ui);
208         }
209
210         if (!force && me.titleCmp && me.titleCmp.rendered && me.titleCmp.textEl) {
211             me.titleCmp.textEl.addCls(me.baseCls + '-text-' + me.ui);
212         }
213     },
214
215     // inherit docs
216     removeUIFromElement: function() {
217         var me = this;
218
219         me.callParent(arguments);
220
221         if (me.rendered) {
222             me.body.removeCls(me.baseCls + '-body-' + me.ui);
223         }
224
225         if (me.titleCmp && me.titleCmp.rendered && me.titleCmp.textEl) {
226             me.titleCmp.textEl.removeCls(me.baseCls + '-text-' + me.ui);
227         }
228     },
229
230     onClick: function(e) {
231         if (!e.getTarget(Ext.baseCSSPrefix + 'tool')) {
232             this.fireEvent('click', e);
233         }
234     },
235
236     getTargetEl: function() {
237         return this.body || this.frameBody || this.el;
238     },
239
240     /**
241      * Sets the title of the header.
242      * @param {String} title The title to be set
243      */
244     setTitle: function(title) {
245         var me = this;
246         if (me.rendered) {
247             if (me.titleCmp.rendered) {
248                 if (me.titleCmp.surface) {
249                     me.title = title || '';
250                     var sprite = me.titleCmp.surface.items.items[0],
251                         surface = me.titleCmp.surface;
252
253                     surface.remove(sprite);
254                     me.textConfig.type = 'text';
255                     me.textConfig.text = title;
256                     sprite = surface.add(me.textConfig);
257                     sprite.setAttributes({
258                         rotate: {
259                             degrees: 90
260                         }
261                     }, true);
262                     me.titleCmp.autoSizeSurface();
263                 } else {
264                     me.title = title || '&#160;';
265                     me.titleCmp.textEl.update(me.title);
266                 }
267             } else {
268                 me.titleCmp.on({
269                     render: function() {
270                         me.setTitle(title);
271                     },
272                     single: true
273                 });
274             }
275         } else {
276             me.on({
277                 render: function() {
278                     me.layout.layout();
279                     me.setTitle(title);
280                 },
281                 single: true
282             });
283         }
284     },
285
286     /**
287      * Sets the CSS class that provides the icon image for this panel.  This method will replace any existing
288      * icon class if one has already been set and fire the {@link #iconchange} event after completion.
289      * @param {String} cls The new CSS class name
290      */
291     setIconCls: function(cls) {
292         this.iconCls = cls;
293         if (!this.iconCmp) {
294             this.initIconCmp();
295             this.insert(0, this.iconCmp);
296         }
297         else {
298             if (!cls || !cls.length) {
299                 this.iconCmp.destroy();
300             }
301             else {
302                 var iconCmp = this.iconCmp,
303                     el      = iconCmp.iconEl;
304
305                 el.removeCls(iconCmp.iconCls);
306                 el.addCls(cls);
307                 iconCmp.iconCls = cls;
308             }
309         }
310     },
311
312     /**
313      * Add a tool to the header
314      * @param {Object} tool
315      */
316     addTool: function(tool) {
317         this.tools.push(this.add(tool));
318     },
319
320     /**
321      * @private
322      * Set up the tools.&lt;tool type> link in the owning Panel.
323      * Bind the tool to its owning Panel.
324      * @param component
325      * @param index
326      */
327     onAdd: function(component, index) {
328         this.callParent([arguments]);
329         if (component instanceof Ext.panel.Tool) {
330             component.bindTo(this.ownerCt);
331             this.tools[component.type] = component;
332         }
333     }
334 });