]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/src/panel/Title.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / panel / Title.js
CommitLineData
6527f429
DM
1/**\r
2 * A basic title component for a Panel Header\r
3 */\r
4Ext.define('Ext.panel.Title', {\r
5 extend: 'Ext.Component',\r
6 xtype: 'title',\r
7\r
8 isTitle: true,\r
9 \r
10 // layout system optimization. Allows autocomponent layout to measure height without\r
11 // having to first know the width.\r
12 noWrap: true,\r
13\r
14 // For performance reasons we give the following configs their default values on\r
15 // the class body. This prevents the updaters from running on initialization in the\r
16 // default configuration scenario\r
17 textAlign: 'left',\r
18 iconAlign: 'left',\r
19 rotation: 0,\r
20 text: ' ',\r
21\r
22 beforeRenderConfig: {\r
23 /**\r
24 * @cfg [textAlign='left']\r
25 * @inheritdoc Ext.panel.Header#cfg-titleAlign\r
26 * @accessor\r
27 */\r
28 textAlign: null,\r
29\r
30 /**\r
31 * @cfg {String}\r
32 * The title's text (can contain html tags/entities)\r
33 * @accessor\r
34 */\r
35 text: null,\r
36\r
37 /**\r
38 * @cfg glyph\r
39 * @inheritdoc Ext.panel.Header#cfg-glyph\r
40 * @accessor\r
41 */\r
42 glyph: null,\r
43\r
44 /**\r
45 * @cfg icon\r
46 * @inheritdoc Ext.panel.Header#cfg-icon\r
47 * @accessor\r
48 */\r
49 icon: null,\r
50\r
51 /**\r
52 * @cfg {'top'/'right'/'bottom'/'left'} [iconAlign='left']\r
53 * alignment of the icon\r
54 * @accessor\r
55 */\r
56 iconAlign: null,\r
57\r
58 /**\r
59 * @cfg iconCls\r
60 * @inheritdoc Ext.panel.Header#cfg-iconCls\r
61 * @accessor\r
62 */\r
63 iconCls: null,\r
64 \r
65 /**\r
66 * @cfg rotation\r
67 * @inheritdoc Ext.panel.Header#cfg-titleRotation\r
68 * @accessor\r
69 */\r
70 rotation: null\r
71 },\r
72\r
73 autoEl: {\r
74 role: 'presentation',\r
75 // Required for Opera\r
76 unselectable: 'on'\r
77 },\r
78 \r
79 // In most cases the panel header title is purely presentational\r
80 // and does not have any structural significance wrt Assistive Technologies.\r
81 // The only exception is when the panel participates in Accordion layout;\r
82 // in that case the title component has the role of 'tab' and its textEl\r
83 // should not have any role to expose the text as the tab's accessible name.\r
84 // Header component is aware of this participation and will reset textElRole.\r
85 textElRole: 'presentation',\r
86 \r
87 // By default, panel title is not focusable; this only happens in Accordion layout.\r
88 // This config option is overridable, and it will prime tabIndex to be used\r
89 // without hardcoding it.\r
90 tabIndex: 0,\r
91\r
92 childEls: [\r
93 'textEl',\r
94 'iconEl',\r
95 'iconWrapEl'\r
96 ],\r
97\r
98 renderTpl:\r
99 '<tpl if="iconMarkup && iconBeforeTitle">{iconMarkup}</tpl>' +\r
100 // unselectable="on" is required for Opera, other browsers\r
101 // inherit unselectability from the header\r
102 '<div id="{id}-textEl" data-ref="textEl"' +\r
103 ' class="{textCls} {textCls}-{ui} {itemCls}{childElCls}" unselectable="on"' +\r
104 '<tpl if="textElRole"> role="{textElRole}"</tpl>' +\r
105 '>' +\r
106 '{text}' +\r
107 '</div>' +\r
108 '<tpl if="iconMarkup && !iconBeforeTitle">{iconMarkup}</tpl>',\r
109\r
110 iconTpl:\r
111 '<div id="{id}-iconWrapEl" data-ref="iconWrapEl" role="presentation" ' +\r
112 'class="{iconWrapCls} {iconWrapCls}-{ui} {iconAlignCls} {itemCls}{childElCls}"' +\r
113 '<tpl if="iconWrapStyle"> style="{iconWrapStyle}"</tpl>>' +\r
114 '<div id="{id}-iconEl" data-ref="iconEl" role="presentation" unselectable="on" ' +\r
115 'class="{baseIconCls} {baseIconCls}-{ui} {iconCls} {glyphCls}" style="' +\r
116 '<tpl if="iconUrl">background-image:url({iconUrl});</tpl>' +\r
117 '<tpl if="glyph && glyphFontFamily">font-family:{glyphFontFamily};</tpl>">' +\r
118 '<tpl if="glyph">&#{glyph};</tpl>' +\r
119 '</div>' +\r
120 '</div>',\r
121\r
122 _textAlignClasses: {\r
123 left: Ext.baseCSSPrefix + 'title-align-left',\r
124 center: Ext.baseCSSPrefix + 'title-align-center',\r
125 right: Ext.baseCSSPrefix + 'title-align-right'\r
126 },\r
127\r
128 _iconAlignClasses: {\r
129 top: Ext.baseCSSPrefix + 'title-icon-top',\r
130 right: Ext.baseCSSPrefix + 'title-icon-right',\r
131 bottom: Ext.baseCSSPrefix + 'title-icon-bottom',\r
132 left: Ext.baseCSSPrefix + 'title-icon-left'\r
133 },\r
134\r
135 _rotationClasses: {\r
136 0: Ext.baseCSSPrefix + 'title-rotate-none',\r
137 1: Ext.baseCSSPrefix + 'title-rotate-right',\r
138 2: Ext.baseCSSPrefix + 'title-rotate-left'\r
139 },\r
140\r
141 _rotationAngles: {\r
142 1: 90,\r
143 2: 270\r
144 },\r
145\r
146 baseCls: Ext.baseCSSPrefix + 'title',\r
147 _titleSuffix: '-title',\r
148 _glyphCls: Ext.baseCSSPrefix + 'title-glyph',\r
149 _iconWrapCls: Ext.baseCSSPrefix + 'title-icon-wrap',\r
150 _baseIconCls: Ext.baseCSSPrefix + 'title-icon',\r
151 _itemCls: Ext.baseCSSPrefix + 'title-item',\r
152 _textCls: Ext.baseCSSPrefix + 'title-text',\r
153\r
154 afterComponentLayout: function() {\r
155 var me = this,\r
156 rotation = me.getRotation(),\r
157 lastBox, lastX, el;\r
158\r
159 if (rotation && !Ext.isIE8) {\r
160 // In IE8 we use a BasicImage filter to rotate the title\r
161 // element 90 degrees. The result is that what was the bottom left\r
162 // corner is positioned exactly where the top left corner was\r
163 // originally. Since this is the desired result, no additional\r
164 // positioning is needed in IE8. In browsers that support CSS3 transform,\r
165 // however, we use transform: rotate(90deg) to rotate the element.\r
166 // CSS3 also provides a way to specify the position the rotated element\r
167 // by changing the axis on which it is rotated using the transform-origin\r
168 // property, but the required transform origin varies based on the\r
169 // elements size, and would require some complex math to calculate.\r
170 // To achieve the desired rotated position in modern browsers we use\r
171 // a transform-origin of "0, 0" which means the top left corner of\r
172 // the element is the rotation axis. After rotating 90 degrees we\r
173 // simply move the element to the right by the same number of pixels\r
174 // as its width.\r
175 el = me.el;\r
176 lastBox = me.lastBox;\r
177 lastX = lastBox.x;\r
178 el.setStyle(\r
179 me._getVerticalAdjustDirection(),\r
180 (lastX + ((rotation === 1) ? lastBox.width : -lastBox.height)) + 'px'\r
181 );\r
182 }\r
183 this.callParent();\r
184 },\r
185\r
186 onRender: function() {\r
187 var me = this,\r
188 rotation = me.getRotation(),\r
189 el = me.el;\r
190 \r
191 me.callParent();\r
192 \r
193 if (rotation) {\r
194 el.setVertical(me._rotationAngles[rotation]);\r
195 }\r
196\r
197 if (Ext.supports.FixedTableWidthBug) {\r
198 // Workaround for https://bugs.webkit.org/show_bug.cgi?id=130239 and\r
199 // https://code.google.com/p/chromium/issues/detail?id=377190\r
200 // See styleHooks for more details\r
201 el._needsTableWidthFix = true;\r
202 }\r
203 },\r
204\r
205 applyText: function(text) {\r
206 if (!text) {\r
207 text = '&#160;';\r
208 }\r
209 return text;\r
210 },\r
211 \r
212 beforeRender: function() {\r
213 var me = this;\r
214 \r
215 me.callParent();\r
216 \r
217 me.addCls(me._rotationClasses[me.getRotation()]);\r
218 me.addCls(me._textAlignClasses[me.getTextAlign()]);\r
219 },\r
220\r
221 getIconMarkup: function() {\r
222 return this.getTpl('iconTpl').apply(this.getIconRenderData());\r
223 },\r
224\r
225 getIconRenderData: function() {\r
226 var me = this,\r
227 icon = me.getIcon(),\r
228 iconCls = me.getIconCls(),\r
229 glyph = me.getGlyph(),\r
230 glyphFontFamily = Ext._glyphFontFamily,\r
231 iconAlign = me.getIconAlign(),\r
232 glyphParts;\r
233\r
234\r
235 if (typeof glyph === 'string') {\r
236 glyphParts = glyph.split('@');\r
237 glyph = glyphParts[0];\r
238 glyphFontFamily = glyphParts[1];\r
239 }\r
240\r
241 return {\r
242 id: me.id,\r
243 ui: me.ui,\r
244 itemCls: me._itemCls,\r
245 iconUrl: icon,\r
246 iconCls: iconCls,\r
247 iconWrapCls: me._iconWrapCls,\r
248 baseIconCls: me._baseIconCls,\r
249 iconAlignCls: me._iconAlignClasses[iconAlign],\r
250 glyph: glyph,\r
251 glyphCls: glyph ? me._glyphCls : '',\r
252 glyphFontFamily: glyphFontFamily\r
253 };\r
254 },\r
255\r
256 initRenderData: function() {\r
257 var me = this,\r
258 iconAlign, renderData;\r
259\r
260 renderData = Ext.apply({\r
261 text: me.getText(),\r
262 textElRole: me.textElRole,\r
263 id: me.id,\r
264 ui: me.ui,\r
265 itemCls: me._itemCls,\r
266 textCls: me._textCls,\r
267 iconMarkup: null,\r
268 iconBeforeTitle: null\r
269 }, me.callParent());\r
270\r
271 if (me._hasIcon()) {\r
272 iconAlign = me.getIconAlign();\r
273 renderData.iconMarkup = me.getIconMarkup();\r
274 renderData.iconBeforeTitle = (iconAlign === 'top' || iconAlign === 'left');\r
275 }\r
276 \r
277 return renderData;\r
278 },\r
279 \r
280 onAdded: function(container, pos, instanced) {\r
281 var me = this,\r
282 suffix = me._titleSuffix,\r
283 baseCls = container.baseCls;\r
284\r
285 me.addCls([\r
286 baseCls + suffix,\r
287 baseCls + suffix + '-' + container.ui\r
288 ]);\r
289 \r
290 me.callParent([container, pos, instanced]);\r
291 },\r
292\r
293 updateGlyph: function(glyph, oldGlyph) {\r
294 glyph = glyph || 0;\r
295 var me = this,\r
296 glyphCls = me._glyphCls,\r
297 iconEl, fontFamily, glyphParts;\r
298\r
299 me.glyph = glyph;\r
300\r
301 if (me.rendered) {\r
302 me._syncIconVisibility();\r
303 iconEl = me.iconEl;\r
304 \r
305 if (typeof glyph === 'string') {\r
306 glyphParts = glyph.split('@');\r
307 glyph = glyphParts[0];\r
308 fontFamily = glyphParts[1] || Ext._glyphFontFamily;\r
309 }\r
310\r
311 if (!glyph) {\r
312 iconEl.dom.innerHTML = '';\r
313 iconEl.removeCls(glyphCls);\r
314 } else if (oldGlyph !== glyph) {\r
315 iconEl.dom.innerHTML = '&#' + glyph + ';';\r
316 iconEl.addCls(glyphCls);\r
317 }\r
318\r
319 if (fontFamily) {\r
320 iconEl.setStyle('font-family', fontFamily);\r
321 }\r
322 if (me._didIconStateChange(oldGlyph, glyph)) {\r
323 me.updateLayout();\r
324 }\r
325 }\r
326 },\r
327\r
328 updateIcon: function(icon, oldIcon) {\r
329 icon = icon || '';\r
330 var me = this,\r
331 iconEl;\r
332\r
333 if (me.rendered && icon !== oldIcon) {\r
334 me._syncIconVisibility();\r
335 iconEl = me.iconEl;\r
336 \r
337 iconEl.setStyle('background-image', icon ? 'url(' + icon + ')': '');\r
338 if (me._didIconStateChange(oldIcon, icon)) {\r
339 me.updateLayout();\r
340 }\r
341 }\r
342 },\r
343\r
344 updateIconAlign: function(align, oldAlign) {\r
345 var me = this,\r
346 iconWrapEl = me.iconWrapEl,\r
347 el, iconAlignClasses;\r
348\r
349 if (me.iconWrapEl) {\r
350 el = me.el;\r
351 iconAlignClasses = me._iconAlignClasses;\r
352\r
353 if (oldAlign) {\r
354 iconWrapEl.removeCls(iconAlignClasses[oldAlign]);\r
355 }\r
356 iconWrapEl.addCls(iconAlignClasses[align]);\r
357\r
358 // here we move the iconWrap to the correct position in the dom - before the\r
359 // title el for top/left alignments, and after the title el for right/bottom\r
360 if (align === 'top' || align === 'left') {\r
361 el.insertFirst(iconWrapEl);\r
362 } else {\r
363 el.appendChild(iconWrapEl);\r
364 }\r
365 \r
366 me.updateLayout();\r
367 }\r
368 },\r
369\r
370 updateIconCls: function(cls, oldCls) {\r
371 cls = cls || '';\r
372 var me = this,\r
373 iconEl;\r
374\r
375 if (me.rendered && oldCls !== cls) {\r
376 me._syncIconVisibility();\r
377 iconEl = me.iconEl;\r
378 \r
379 if (oldCls) {\r
380 iconEl.removeCls(oldCls);\r
381 }\r
382 iconEl.addCls(cls);\r
383 if (me._didIconStateChange(oldCls, cls)) {\r
384 me.updateLayout();\r
385 }\r
386 }\r
387 },\r
388\r
389 updateRotation: function(rotation, oldRotation) {\r
390 var me = this,\r
391 el, rotationClasses;\r
392 \r
393 if (me.rendered) {\r
394 el = me.el;\r
395 rotationClasses = me._rotationClasses;\r
396 \r
397 me.removeCls(rotationClasses[oldRotation]);\r
398 me.addCls(rotationClasses[rotation]);\r
399\r
400 el.setHorizontal();\r
401 if (rotation) {\r
402 el.setVertical(me._rotationAngles[rotation]);\r
403 }\r
404 \r
405 // reset styles set by adjustTitlePosition (handles both rtl/ltr), and sizing\r
406 // set by last layout run (this prevents parallel size from becoming perpendicular\r
407 // size after rotation)\r
408 el.setStyle({\r
409 right: '',\r
410 left: '',\r
411 top: '',\r
412 height: '',\r
413 width: ''\r
414 });\r
415 \r
416 me.lastBox = null;\r
417\r
418 me.updateLayout();\r
419 }\r
420 },\r
421\r
422 updateText: function(text) {\r
423 if (this.rendered) {\r
424 this.textEl.setHtml(text);\r
425 this.updateLayout();\r
426 }\r
427 },\r
428\r
429 updateTextAlign: function(align, oldAlign) {\r
430 var me = this,\r
431 textAlignClasses = me._textAlignClasses;\r
432 \r
433 if (me.rendered) {\r
434 if (oldAlign) {\r
435 me.removeCls(textAlignClasses[oldAlign]);\r
436 }\r
437 me.addCls(textAlignClasses[align]);\r
438\r
439 me.updateLayout();\r
440 }\r
441 },\r
442\r
443 privates: {\r
444 // rtl hook\r
445 _getVerticalAdjustDirection: function() {\r
446 return 'left';\r
447 },\r
448\r
449 _didIconStateChange: function(old, current) {\r
450 var currentEmpty = Ext.isEmpty(current);\r
451 return Ext.isEmpty(old) ? !currentEmpty : currentEmpty;\r
452 },\r
453\r
454 _hasIcon: function() {\r
455 return !!(this.getIcon() || this.getIconCls() || this.getGlyph());\r
456 },\r
457\r
458 _syncIconVisibility: function() {\r
459 var me = this,\r
460 el = me.el,\r
461 hasIcon = me._hasIcon(),\r
462 iconWrapEl = me.iconWrapEl,\r
463 isBefore, iconAlign;\r
464 \r
465 if (hasIcon && !iconWrapEl) {\r
466 // if an icon was configured, but we have not yet rendered an icon\r
467 // element, we need to render it now.\r
468 iconAlign = me.iconAlign;\r
469 isBefore = (iconAlign === 'left' || iconAlign === 'top');\r
470 \r
471 el.dom.insertAdjacentHTML(\r
472 isBefore ? 'afterbegin' : 'beforeend',\r
473 me.getIconMarkup()\r
474 );\r
475 \r
476 iconWrapEl = me.iconWrapEl = el[isBefore ? 'first' : 'last']();\r
477 me.iconEl = iconWrapEl.first();\r
478 }\r
479\r
480 if (iconWrapEl) {\r
481 iconWrapEl.setDisplayed(hasIcon);\r
482 }\r
483 }\r
484 }\r
485});\r