macoslinuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskypefacebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-services
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
475 lines
14 KiB
475 lines
14 KiB
/** |
|
* Simple header class which is used for on {@link Ext.panel.Panel} and {@link Ext.window.Window}. |
|
*/ |
|
Ext.define('Ext.panel.Header', { |
|
extend: 'Ext.panel.Bar', |
|
requires: [ |
|
'Ext.panel.Title', |
|
'Ext.panel.Tool' |
|
], |
|
xtype: 'header', |
|
|
|
/** |
|
* @property {Boolean} isHeader |
|
* `true` in this class to identify an object as an instantiated Header, or subclass thereof. |
|
*/ |
|
isHeader: true, |
|
|
|
defaultType: 'tool', |
|
indicateDrag: false, |
|
weight: -1, |
|
shrinkWrap: 3, |
|
|
|
// For performance reasons we give the following configs their default values on |
|
// the class body. This prevents the updaters from running on initialization in the |
|
// default configuration scenario |
|
iconAlign: 'left', |
|
titleAlign: 'left', |
|
titlePosition: 0, |
|
titleRotation: 'default', |
|
|
|
beforeRenderConfig: { |
|
/** |
|
* @cfg {Number/String} glyph |
|
* A numeric unicode character code to use as the icon for the panel header. The |
|
* default font-family for glyphs can be set globally using |
|
* {@link Ext#setGlyphFontFamily Ext.setGlyphFontFamily()}. Alternatively, this |
|
* config option accepts a string with the charCode and font-family separated by the |
|
* `@` symbol. For example '65@My Font Family'. |
|
*/ |
|
glyph: null, |
|
|
|
/** |
|
* @cfg {String} icon |
|
* Path to image for an icon. |
|
* |
|
* There are no default icons that come with Ext JS. |
|
*/ |
|
icon: null, |
|
|
|
/** |
|
* @cfg {String} iconCls |
|
* CSS class for an icon. |
|
* |
|
* There are no default icon classes that come with Ext JS. |
|
*/ |
|
iconCls: null, |
|
|
|
/** |
|
* @cfg {'top'/'right'/'bottom'/'left'} [iconAlign='left'] |
|
* The side of the title to render the icon. |
|
*/ |
|
iconAlign: null, |
|
|
|
/** |
|
* @cfg {String/Ext.panel.Title} |
|
* The title text or config object for the {@link Ext.panel.Title Title} component. |
|
*/ |
|
title: { |
|
$value: { |
|
ariaRole: 'presentation', |
|
xtype: 'title', |
|
flex: 1 |
|
}, |
|
merge: function(newValue, oldValue) { |
|
if (typeof newValue === 'string') { |
|
newValue = { |
|
text: newValue |
|
}; |
|
} |
|
|
|
return Ext.merge(oldValue ? Ext.Object.chain(oldValue) : {}, newValue); |
|
} |
|
}, |
|
|
|
/** |
|
* @cfg {String} [titleAlign='left'] |
|
* The alignment of the title text. |
|
*/ |
|
titleAlign: null, |
|
|
|
/** |
|
* @cfg {Number} [titlePosition=0] |
|
* The ordinal position among the header items (tools and other components specified using the {@link #cfg-items} config) |
|
* at which the title component is inserted. See {@link Ext.panel.Panel#cfg-header Panel's header config}. |
|
* |
|
* If not specified, the title is inserted after any {@link #cfg-items}, but *before* any {@link Ext.panel.Panel#tools}. |
|
* |
|
* Note that if an {@link #icon} or {@link #iconCls} has been configured, then the icon component will be the |
|
* first item before all specified tools or {@link #cfg-items}. This configuration does not include the icon. |
|
*/ |
|
titlePosition: null, |
|
|
|
/** |
|
* @cfg {'default'/0/1/2} [titleRotation='default'] |
|
* The rotation of the header's title text. Can be one of the following values: |
|
* |
|
* - `'default'` - use the default rotation, depending on the dock position of the header |
|
* - `0` - no rotation |
|
* - `1` - rotate 90deg clockwise |
|
* - `2` - rotate 90deg counter-clockwise |
|
* |
|
* The default behavior of this config depends on the dock position of the header: |
|
* |
|
* - `'top'` or `'bottom'` - `0` |
|
* - `'right'` - `1` |
|
* - `'left'` - `1` |
|
*/ |
|
titleRotation: null |
|
}, |
|
|
|
// a class for styling that is shared between panel and window headers |
|
headerCls: Ext.baseCSSPrefix + 'header', |
|
|
|
/** |
|
* @event click |
|
* Fires when the header is clicked. This event will not be fired |
|
* if the click was on a {@link Ext.panel.Tool} |
|
* @param {Ext.panel.Header} this |
|
* @param {Ext.event.Event} e |
|
*/ |
|
|
|
/** |
|
* @event dblclick |
|
* Fires when the header is double clicked. This event will not |
|
* be fired if the click was on a {@link Ext.panel.Tool} |
|
* @param {Ext.panel.Header} this |
|
* @param {Ext.event.Event} e |
|
*/ |
|
|
|
/** |
|
* @cfg {Number} [itemPosition] |
|
* The index at which the any {@link #cfg-items} will be inserted into the Header's |
|
* items collection. By default this will effectively be the `1` position |
|
* placing the items following the panel {@link Ext.panel.Panel#title title}. |
|
* |
|
* Set to `0` to have the items {@link #insert inserted} before the panel title. |
|
* |
|
* Ext.create('Ext.panel.Panel', { |
|
* title: 'Hello', |
|
* width: 200, |
|
* html: '<p>World!</p>', |
|
* renderTo: Ext.getBody(), |
|
* tools: [{ |
|
* type: 'pin' |
|
* }], |
|
* header: { |
|
* //itemPosition: 0, // before panel title |
|
* //itemPosition: 1, // after panel title |
|
* //itemPosition: 2, // after pin tool |
|
* items: [{ |
|
* xtype: 'button', |
|
* text: 'Header Button' |
|
* }] |
|
* } |
|
* }); |
|
*/ |
|
|
|
initComponent: function() { |
|
var me = this, |
|
items = me.items, |
|
itemPosition = me.itemPosition, |
|
cls = [me.headerCls]; |
|
|
|
me.tools = me.tools || []; |
|
me.items = items = (items ? items.slice() : []); |
|
|
|
if (itemPosition !== undefined) { |
|
me._userItems = items.slice(); |
|
me.items = items = []; |
|
} |
|
|
|
me.indicateDragCls = me.headerCls + '-draggable'; |
|
if (me.indicateDrag) { |
|
cls.push(me.indicateDragCls); |
|
} |
|
|
|
me.addCls(cls); |
|
|
|
me.syncNoBorderCls(); |
|
|
|
// Add Tools |
|
Ext.Array.push(items, me.tools); |
|
// Clear the tools so we can have only the instances. Intentional mutation of passed in array |
|
// Owning code in Panel uses this array as its public tools property. |
|
me.tools.length = 0; |
|
me.callParent(); |
|
|
|
me.on({ |
|
dblclick: me.onDblClick, |
|
click: me.onClick, |
|
element: 'el', |
|
scope: me |
|
}); |
|
}, |
|
|
|
/** |
|
* Add a tool to the header |
|
* @param {Object} tool |
|
*/ |
|
addTool: function(tool) { |
|
// Even though the defaultType is tool, it may be changed, |
|
// so let's be safe and forcibly specify tool |
|
this.add(Ext.ComponentManager.create(tool, 'tool')); |
|
}, |
|
|
|
afterLayout: function() { |
|
var me = this, |
|
frameBR, frameTR, frameTL, xPos; |
|
|
|
if (me.vertical) { |
|
frameTR = me.frameTR; |
|
if (frameTR) { |
|
// The corners sprite currently requires knowledge of the vertical header's |
|
// width to correctly set the background position of the bottom right corner. |
|
// TODO: rearrange the sprite so that this can be done with pure css. |
|
frameBR = me.frameBR; |
|
frameTL = me.frameTL; |
|
xPos = (me.getWidth() - frameTR.getPadding('r') - |
|
((frameTL) ? frameTL.getPadding('l') : me.el.getBorderWidth('l'))) + 'px'; |
|
frameBR.setStyle('background-position-x', xPos); |
|
frameTR.setStyle('background-position-x', xPos); |
|
} |
|
} |
|
this.callParent(); |
|
}, |
|
|
|
applyTitle: function(title, oldTitle) { |
|
var me = this, |
|
isString, configHasRotation; |
|
|
|
title = title || ''; |
|
|
|
isString = typeof title === 'string'; |
|
if (isString) { |
|
title = { |
|
text: title |
|
}; |
|
} |
|
|
|
if (oldTitle) { |
|
// several title configs can trigger layouts, so suspend before setting |
|
// configs in bulk |
|
Ext.suspendLayouts(); |
|
oldTitle.setConfig(title); |
|
Ext.resumeLayouts(true); |
|
title = oldTitle; |
|
} else { |
|
if (isString) { |
|
title.xtype = 'title'; |
|
} |
|
title.ui = me.ui; |
|
title.headerRole = me.headerRole; |
|
configHasRotation = ('rotation' in title); |
|
|
|
title = Ext.create(title); |
|
|
|
// avoid calling the title's rotation updater on initial startup in the default scenario |
|
if (!configHasRotation && me.vertical && me.titleRotation === 'default') { |
|
title.rotation = 1; |
|
} |
|
} |
|
|
|
return title; |
|
}, |
|
|
|
applyTitlePosition: function(position) { |
|
var max = this.items.getCount(); |
|
|
|
if (this._titleInItems) { |
|
--max; |
|
} |
|
return Math.max(Math.min(position, max), 0); |
|
}, |
|
|
|
beforeLayout: function () { |
|
this.callParent(); |
|
this.syncBeforeAfterTitleClasses(); |
|
}, |
|
|
|
beforeRender: function() { |
|
var me = this, |
|
itemPosition = me.itemPosition; |
|
|
|
me.protoEl.unselectable(); |
|
me.callParent(); |
|
|
|
if (itemPosition !== undefined) { |
|
me.insert(itemPosition, me._userItems); |
|
} |
|
}, |
|
|
|
/** |
|
* Gets the tools for this header. |
|
* @return {Ext.panel.Tool[]} The tools |
|
*/ |
|
getTools: function(){ |
|
return this.tools.slice(); |
|
}, |
|
|
|
onAdd: function(component, index) { |
|
var tools = this.tools; |
|
this.callParent([component, index]); |
|
if (component.isTool) { |
|
tools.push(component); |
|
tools[component.type] = component; |
|
} |
|
}, |
|
|
|
onAdded: function(container, pos, instanced) { |
|
this.syncNoBorderCls(); |
|
this.callParent([container, pos, instanced]); |
|
}, |
|
|
|
onRemoved: function(container, pos, instanced) { |
|
this.syncNoBorderCls(); |
|
this.callParent([container, pos, instanced]); |
|
}, |
|
|
|
setDock: function(dock) { |
|
var me = this, |
|
title = me.getTitle(), |
|
rotation = me.getTitleRotation(), |
|
titleRotation = title.getRotation(); |
|
|
|
Ext.suspendLayouts(); |
|
|
|
me.callParent([dock]); |
|
|
|
if (rotation === 'default') { |
|
rotation = (me.vertical ? 1 : 0); |
|
|
|
if (rotation !== titleRotation) { |
|
title.setRotation(rotation); |
|
} |
|
|
|
if (me.rendered) { |
|
// remove margins set on items by box layout last time around. |
|
// TODO: this will no longer be needed when EXTJS-13359 is fixed |
|
me.resetItemMargins(); |
|
} |
|
} |
|
|
|
Ext.resumeLayouts(true); |
|
}, |
|
|
|
updateGlyph: function(glyph) { |
|
this.getTitle().setGlyph(glyph); |
|
}, |
|
|
|
updateIcon: function(icon) { |
|
this.getTitle().setIcon(icon); |
|
}, |
|
|
|
updateIconAlign: function(align, oldAlign) { |
|
this.getTitle().setIconAlign(align); |
|
}, |
|
|
|
updateIconCls: function(cls) { |
|
this.getTitle().setIconCls(cls); |
|
}, |
|
|
|
updateTitle: function(title, oldTitle) { |
|
if (!oldTitle) { |
|
this.insert(this.getTitlePosition(), title); |
|
this._titleInItems = true; |
|
} |
|
// for backward compat with 4.x, set titleCmp property |
|
this.titleCmp = title; |
|
}, |
|
|
|
updateTitleAlign: function(align, oldAlign) { |
|
this.getTitle().setTextAlign(align); |
|
}, |
|
|
|
updateTitlePosition: function(position) { |
|
this.insert(position, this.getTitle()); |
|
}, |
|
|
|
updateTitleRotation: function(rotation) { |
|
if (rotation === 'default') { |
|
rotation = (this.vertical ? 1 : 0); |
|
} |
|
this.getTitle().setRotation(rotation); |
|
}, |
|
|
|
privates: { |
|
fireClickEvent: function(type, e){ |
|
var toolCls = '.' + Ext.panel.Tool.prototype.baseCls; |
|
if (!e.getTarget(toolCls)) { |
|
this.fireEvent(type, this, e); |
|
} |
|
}, |
|
|
|
getFocusEl: function() { |
|
return this.el; |
|
}, |
|
|
|
getFramingInfoCls: function(){ |
|
var me = this, |
|
cls = me.callParent(), |
|
owner = me.ownerCt; |
|
|
|
if (!me.expanding && owner && (owner.collapsed || me.isCollapsedExpander)) { |
|
cls += '-' + owner.collapsedCls; |
|
} |
|
return cls + '-' + me.dock; |
|
}, |
|
|
|
onClick: function(e) { |
|
this.fireClickEvent('click', e); |
|
}, |
|
|
|
onDblClick: function(e){ |
|
this.fireClickEvent('dblclick', e); |
|
}, |
|
|
|
syncBeforeAfterTitleClasses: function(force) { |
|
var me = this, |
|
items = me.items, |
|
childItems = items.items, |
|
titlePosition = me.getTitlePosition(), |
|
itemCount = childItems.length, |
|
itemGeneration = items.generation, |
|
syncGen = me.syncBeforeAfterGen, |
|
afterCls, beforeCls, i, item; |
|
|
|
if (!force && (syncGen === itemGeneration)) { |
|
return; |
|
} |
|
me.syncBeforeAfterGen = itemGeneration; |
|
|
|
for (i = 0; i < itemCount; ++i) { |
|
item = childItems[i]; |
|
|
|
afterCls = item.afterTitleCls || (item.afterTitleCls = item.baseCls + '-after-title'); |
|
beforeCls = item.beforeTitleCls || (item.beforeTitleCls = item.baseCls + '-before-title'); |
|
|
|
if (!me.title || i < titlePosition) { |
|
if (syncGen) { |
|
item.removeCls(afterCls); |
|
} // else first time we won't need to remove anything... |
|
item.addCls(beforeCls); |
|
} else if (i > titlePosition) { |
|
if (syncGen) { |
|
item.removeCls(beforeCls); |
|
} |
|
item.addCls(afterCls); |
|
} |
|
} |
|
}, |
|
|
|
syncNoBorderCls: function() { |
|
var me = this, |
|
ownerCt = this.ownerCt, |
|
noBorderCls = me.headerCls + '-noborder'; |
|
|
|
// test for border === false is needed because undefined is the same as true |
|
if (ownerCt ? (ownerCt.border === false && !ownerCt.frame) : me.border === false) { |
|
me.addCls(noBorderCls); |
|
} else { |
|
me.removeCls(noBorderCls); |
|
} |
|
} |
|
} // private |
|
});
|
|
|