Форк Rambox
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

/**
* 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
});