/**
* The grouping panel used by {@link Ext.grid.plugin.GroupingPanel}
*/
Ext.define('Ext.grid.plugin.grouping.Panel', {
extend: 'Ext.panel.Panel',
alias: 'widget.groupingpanel',
requires: [
'Ext.grid.plugin.grouping.Column',
'Ext.grid.plugin.grouping.DragZone',
'Ext.grid.plugin.grouping.DropZone',
'Ext.layout.container.Column'
],
mixins: [
'Ext.mixin.FocusableContainer'
],
isGroupingPanel: true,
position: 'top',
border: false,
enableFocusableContainer: true,
// the column header container has a weight of 100 so we want to dock it before that.
weight: 50,
height: 'auto',
layout: 'column',
childEls: ['innerCt', 'targetEl'],
cls: Ext.baseCSSPrefix + 'grid-group-panel-body',
hintTextCls: Ext.baseCSSPrefix + 'grid-group-panel-hint',
config: {
grid: null,
store: null,
columnConfig: {
xtype: 'groupingpanelcolumn'
}
},
keyEventRe: /^key/,
groupingPanelText: 'Drag a column header here to group by that column',
showGroupingPanelText: 'Show Group By Panel',
hideGroupingPanelText: 'Hide Group By Panel',
clearGroupText: 'Clear Group',
sortAscText: 'Sort Ascending',
sortDescText: 'Sort Descending',
moveLeftText: 'Move left',
moveRightText: 'Move right',
moveBeginText: 'Move to beginning',
moveEndText: 'Move to end',
removeText: 'Remove',
ascSortIconCls: Ext.baseCSSPrefix + 'grid-group-column-sort-icon-asc',
descSortIconCls: Ext.baseCSSPrefix + 'grid-group-column-sort-icon-desc',
groupingPanelIconCls: Ext.baseCSSPrefix + 'grid-group-panel-icon',
clearGroupIconCls: Ext.baseCSSPrefix + 'grid-group-panel-clear-icon',
initComponent: function() {
var me = this;
Ext.apply(me, {
header: {
dock: 'left',
title: {
hidden: true
},
padding: 0,
tools: [{
type: 'gear',
handler: me.showPanelMenu,
scope: me
}]
}
});
me.callParent(arguments);
},
doDestroy: function() {
var me = this;
// eslint-disable-next-line max-len
Ext.destroyMembers(me, 'infoEl', 'dragZone', 'dropZone', 'contextMenu', 'panelListeners', 'columnListeners', 'storeListeners', 'columnMenu', 'panelMenu');
me.setGrid(null);
me.callParent();
},
afterRender: function() {
var me = this,
el = me.getEl();
me.callParent();
me.dragZone = new Ext.grid.plugin.grouping.DragZone(me);
me.dropZone = new Ext.grid.plugin.grouping.DropZone(me);
me.panelListeners = me.mon(el, {
contextmenu: me.showPanelMenu,
scope: me,
destroyable: true
});
me.columnListeners = me.mon(el, {
delegate: '.' + Ext.baseCSSPrefix + 'grid-group-column',
click: me.handleColumnEvent,
keypress: me.handleColumnEvent,
scope: me,
destroyable: true
});
me.infoEl = me.innerCt.createChild({
cls: me.hintTextCls + ' ' + Ext.baseCSSPrefix + 'unselectable',
html: me.groupingPanelText
});
me.setInfoElVisibility();
me.initGroupingColumns();
},
show: function() {
var me = this,
dragZone = me.dragZone,
dropZone = me.dropZone,
grid = me.getGrid();
if (dragZone) {
dragZone.enable();
}
if (dropZone) {
dropZone.enable();
}
me.callParent();
grid.fireEvent('showgroupingpanel', me);
},
hide: function() {
var me = this,
dragZone = me.dragZone,
dropZone = me.dropZone,
grid = me.getGrid();
if (dragZone) {
dragZone.disable();
}
if (dropZone) {
dropZone.disable();
}
me.callParent();
grid.fireEvent('hidegroupingpanel', me);
},
updateGrid: function(grid) {
var me = this,
store = null;
Ext.destroy(me.gridListeners);
if (grid) {
// catch this event to refresh the grouping columns in case one of them changed its name
me.gridListeners = grid.on({
reconfigure: me.onGridReconfigure,
scope: me,
destroyable: true
});
store = grid.getStore();
}
me.setStore(store);
},
updateStore: function(store) {
var me = this;
Ext.destroy(me.storeListeners);
if (store) {
me.storeListeners = store.on({
groupchange: me.initGroupingColumns,
groupschange: me.initGroupingColumns,
scope: me,
destroyable: true
});
me.initGroupingColumns();
}
},
onAdd: function() {
this.setInfoElVisibility();
},
onRemove: function() {
this.setInfoElVisibility();
},
/**
* The container has an info text displayed inside. This function makes it visible or hidden.
*
* @private
*/
setInfoElVisibility: function() {
var el = this.infoEl;
if (!el) {
return;
}
if (!this.items.length) {
el.show();
}
else {
el.hide();
}
},
handleColumnEvent: function(e) {
var isKeyEvent = this.keyEventRe.test(e.type),
fly, cmp;
if ((isKeyEvent && e.getKey() === e.SPACE) || (e.button === 0)) {
fly = Ext.fly(e.target);
if (fly && (cmp = fly.component) && cmp.isGroupingPanelColumn) {
this.showColumnMenu(e, cmp);
}
}
},
showColumnMenu: function(e, target) {
var me = this,
grid = me.getGrid(),
menu, options;
Ext.destroy(me.columnMenu);
menu = me.columnMenu = Ext.menu.Manager.get(me.getColumnMenu(target));
options = {
menu: menu,
column: target
};
if (grid.fireEvent('beforeshowgroupingcolumnmenu', me, options) !== false) {
menu.showBy(target);
menu.focus();
grid.fireEvent('showgroupingcolumnmenu', me, options);
}
else {
Ext.destroy(menu);
}
e.stopEvent();
},
getColumnMenu: function(target) {
var me = this,
items = [],
owner = target.ownerCt,
sibling;
items.push({
text: me.sortAscText,
direction: 'ASC',
iconCls: me.ascSortIconCls,
column: target,
handler: me.sortColumn
}, {
text: me.sortDescText,
direction: 'DESC',
iconCls: me.descSortIconCls,
column: target,
handler: me.sortColumn
}, {
xtype: 'menuseparator'
}, {
text: me.removeText,
handler: Ext.bind(me.removeColumn, me, [target])
}, {
text: me.moveLeftText,
disabled: !(sibling = target.previousSibling()),
handler: Ext.bind(me.moveColumn, me, [target, sibling, 'before'])
}, {
text: me.moveRightText,
disabled: !(sibling = target.nextSibling()),
handler: Ext.bind(me.moveColumn, me, [target, sibling, 'after'])
}, {
text: me.moveBeginText,
disabled: !(sibling = target.previousSibling()),
handler: Ext.bind(me.moveColumn, me, [target, owner.items.first(), 'before'])
}, {
text: me.moveEndText,
disabled: !(sibling = target.nextSibling()),
handler: Ext.bind(me.moveColumn, me, [target, owner.items.last(), 'after'])
});
return {
defaults: {
scope: me
},
items: items
};
},
showPanelMenu: function(e, target) {
var me = this,
grid = me.getGrid(),
isKeyEvent = me.keyEventRe.test(e.type),
menu, options;
Ext.destroy(me.panelMenu);
target.focus();
menu = me.panelMenu = Ext.menu.Manager.get(me.getPanelMenu());
options = {
menu: menu
};
if (grid.fireEvent('beforeshowgroupingpanelmenu', me, options) !== false) {
if (isKeyEvent) {
menu.showBy(target);
}
else {
menu.show();
menu.setPosition(e.getX(), e.getY());
}
menu.focus();
grid.fireEvent('showgroupingpanelmenu', me, options);
}
else {
Ext.destroy(menu);
}
e.stopEvent();
},
getPanelMenu: function() {
var me = this,
items = [],
groupers = me.getStore().getGroupers();
items.push({
iconCls: me.groupingPanelIconCls,
text: me.hideGroupingPanelText,
handler: me.hide
}, {
iconCls: me.clearGroupIconCls,
text: me.clearGroupText,
disabled: !groupers || !groupers.length,
handler: me.clearGrouping
});
return {
defaults: {
scope: me
},
items: items
};
},
clearGrouping: function() {
var me = this,
items = me.items.items,
length = items.length,
i, item, column;
Ext.suspendLayouts();
// make column headers visible in the grid
for (i = 0; i < length; i++) {
item = items[i];
column = item.getColumn();
if (column) {
column.show();
}
}
me.getStore().group(null);
me.getHeader().focus();
Ext.resumeLayouts(true);
},
sortColumn: function(target) {
var grouper = target.column.getGrouper();
if (grouper) {
grouper.setDirection(target.direction);
}
},
/**
* Check if the specified grid column is already added to the panel
*
* @param {Ext.grid.column.Column} col
*/
isNewColumn: function(col) {
return this.items.findIndex('idColumn', col.id) < 0;
},
addColumn: function(config, pos, notify) {
var me = this,
colConfig = Ext.apply({}, me.getColumnConfig()),
newCol;
Ext.suspendLayouts();
newCol = Ext.create(Ext.apply(colConfig, config));
if (pos !== -1) {
me.insert(pos, newCol);
}
else {
me.add(newCol);
}
if (notify === true) {
newCol.focus();
me.notifyGroupChange();
}
Ext.resumeLayouts(true);
},
getColumnPosition: function(column, position) {
var me = this,
pos;
if (column.isGroupingPanelColumn) {
// we have to insert before or after this column
pos = me.items.indexOf(column);
pos = (position === 'before') ? pos : pos + 1;
}
else {
pos = -1;
}
return pos;
},
moveColumn: function(from, to, position) {
var me = this;
Ext.suspendLayouts();
if (from !== to) {
if (position === 'before') {
me.moveBefore(from, to);
}
else {
me.moveAfter(from, to);
}
me.notifyGroupChange();
}
Ext.resumeLayouts(true);
},
removeColumn: function(column) {
var me = this,
col = column.getColumn(),
sibling = column.nextSibling() || column.previousSibling() || me.getHeader();
Ext.suspendLayouts();
if (col) {
col.show();
}
if (sibling) {
sibling.focus();
}
me.remove(column, true);
me.notifyGroupChange();
Ext.resumeLayouts(true);
},
showGridColumn: function(col) {
col.show();
},
hideGridColumn: function(col) {
col.hide();
},
notifyGroupChange: function() {
var me = this,
store = me.getStore(),
items = me.items.items,
length = items.length,
groupers = [],
i, column, grouper;
for (i = 0; i < length; i++) {
column = items[i];
grouper = column.getGrouper();
if (grouper) {
groupers.push(grouper);
}
}
if (!groupers.length) {
store.group(null);
}
else {
store.setGroupers(groupers);
}
},
onGridReconfigure: function(grid, store) {
if (store) {
this.setStore(store);
}
},
/**
* Check if the grid store has groupers and add them to the grouping panel
*/
initGroupingColumns: function() {
var me = this,
grid = me.getGrid(),
store = me.getStore(),
groupers = store.getGroupers(),
length = groupers.length,
columns = Ext.Array.toValueMap(grid.headerCt.getGridColumns(), 'dataIndex'),
i, column, grouper;
Ext.suspendLayouts();
// remove all previously created columns
me.removeAll(true);
for (i = 0; i < length; i++) {
grouper = groupers.items[i];
column = columns[grouper.getProperty()];
if (column) {
me.addColumn({
header: column.text,
idColumn: column.id,
grouper: grouper,
column: column
}, -1);
}
}
Ext.resumeLayouts(true);
}
});