devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
742 lines (659 loc) • 29.5 kB
JavaScript
"use strict";
var $ = require("../../core/renderer"),
gridCore = require("./ui.data_grid.core"),
ExpandedGroupingHelper = require("./ui.data_grid.grouping.expanded").GroupingHelper,
CollapsedGroupingHelper = require("./ui.data_grid.grouping.collapsed").GroupingHelper,
messageLocalization = require("../../localization/message"),
dataSourceAdapter = require("./ui.data_grid.data_source_adapter"),
typeUtils = require("../../core/utils/type"),
each = require("../../core/utils/iterator").each,
devices = require("../../core/devices"),
deferredUtils = require("../../core/utils/deferred"),
when = deferredUtils.when,
Deferred = deferredUtils.Deferred;
var DATAGRID_GROUP_PANEL_CLASS = "dx-datagrid-group-panel",
DATAGRID_GROUP_PANEL_MESSAGE_CLASS = "dx-group-panel-message",
DATAGRID_GROUP_PANEL_ITEM_CLASS = "dx-group-panel-item",
DATAGRID_GROUP_PANEL_LABEL_CLASS = "dx-toolbar-label",
DATAGRID_EXPAND_CLASS = "dx-datagrid-expand",
DATAGRID_GROUP_ROW_CLASS = "dx-group-row";
var GroupingDataSourceAdapterExtender = function () {
return {
init: function init() {
this.callBase.apply(this, arguments);
this._initGroupingHelper();
},
_initGroupingHelper: function _initGroupingHelper(options) {
var grouping = this._grouping,
remoteOperations = options ? options.remoteOperations : this.remoteOperations();
if (remoteOperations.filtering && remoteOperations.sorting && remoteOperations.paging && !remoteOperations.grouping) {
if (!grouping || grouping instanceof CollapsedGroupingHelper) {
this._grouping = new ExpandedGroupingHelper(this);
}
} else {
if (!grouping || grouping instanceof ExpandedGroupingHelper) {
this._grouping = new CollapsedGroupingHelper(this);
}
}
},
totalItemsCount: function totalItemsCount() {
var that = this,
totalCount = that.callBase();
return totalCount > 0 && that._dataSource.group() && that._dataSource.requireTotalCount() ? totalCount + that._grouping.totalCountCorrection() : totalCount;
},
itemsCount: function itemsCount() {
return this._dataSource.group() ? this._grouping.itemsCount() || 0 : this.callBase();
},
allowCollapseAll: function allowCollapseAll() {
return this._grouping.allowCollapseAll();
},
isRowExpanded: function isRowExpanded(key) {
var groupInfo = this._grouping.findGroupInfo(key);
return groupInfo ? groupInfo.isExpanded : !this._grouping.allowCollapseAll();
},
collapseAll: function collapseAll(groupIndex) {
return this._collapseExpandAll(groupIndex, false);
},
expandAll: function expandAll(groupIndex) {
return this._collapseExpandAll(groupIndex, true);
},
_collapseExpandAll: function _collapseExpandAll(groupIndex, isExpand) {
var that = this,
dataSource = that._dataSource,
group = dataSource.group(),
groups = gridCore.normalizeSortingInfo(group || []),
i;
if (groups.length) {
for (i = 0; i < groups.length; i++) {
if (groupIndex === undefined || groupIndex === i) {
groups[i].isExpanded = isExpand;
} else if (group && group[i]) {
groups[i].isExpanded = group[i].isExpanded;
}
}
dataSource.group(groups);
that._grouping.foreachGroups(function (groupInfo, parents) {
if (groupIndex === undefined || groupIndex === parents.length - 1) {
groupInfo.isExpanded = isExpand;
}
}, false, true);
}
return true;
},
refresh: function refresh() {
this.callBase.apply(this, arguments);
return this._grouping.refresh.apply(this._grouping, arguments);
},
changeRowExpand: function changeRowExpand(path) {
var that = this,
dataSource = that._dataSource;
if (dataSource.group()) {
dataSource.beginLoading();
return that._changeRowExpandCore(path).always(function () {
dataSource.endLoading();
});
}
},
_changeRowExpandCore: function _changeRowExpandCore(path) {
return this._grouping.changeRowExpand(path);
},
///#DEBUG
getGroupsInfo: function getGroupsInfo() {
return this._grouping._groupsInfo;
},
///#ENDDEBUG
_hasGroupLevelsExpandState: function _hasGroupLevelsExpandState(group, isExpanded) {
if (group && Array.isArray(group)) {
for (var i = 0; i < group.length; i++) {
if (group[i].isExpanded === isExpanded) {
return true;
}
}
}
},
_customizeRemoteOperations: function _customizeRemoteOperations(options, isReload, operationTypes) {
var remoteOperations = options.remoteOperations;
if (options.storeLoadOptions.group) {
if (remoteOperations.grouping && !options.isCustomLoading) {
if (!remoteOperations.groupPaging || this._hasGroupLevelsExpandState(options.storeLoadOptions.group, true)) {
remoteOperations.paging = false;
}
}
if (!remoteOperations.grouping && (!remoteOperations.sorting || !remoteOperations.filtering || options.isCustomLoading || this._hasGroupLevelsExpandState(options.storeLoadOptions.group, false))) {
remoteOperations.paging = false;
}
} else if (!options.isCustomLoading && remoteOperations.paging && operationTypes.grouping) {
this.resetCache();
}
this.callBase.apply(this, arguments);
},
_handleDataLoading: function _handleDataLoading(options) {
this.callBase(options);
this._initGroupingHelper(options);
return this._grouping.handleDataLoading(options);
},
_handleDataLoaded: function _handleDataLoaded(options) {
return this._grouping.handleDataLoaded(options, this.callBase.bind(this));
},
_handleDataLoadedCore: function _handleDataLoadedCore(options) {
return this._grouping.handleDataLoadedCore(options, this.callBase.bind(this));
}
};
}();
dataSourceAdapter.extend(GroupingDataSourceAdapterExtender);
var GroupingDataControllerExtender = function () {
return {
init: function init() {
var that = this;
that.callBase();
that.createAction("onRowExpanding");
that.createAction("onRowExpanded");
that.createAction("onRowCollapsing");
that.createAction("onRowCollapsed");
},
_beforeProcessItems: function _beforeProcessItems(items) {
var groupColumns = this._columnsController.getGroupColumns();
items = this.callBase(items);
if (items.length && groupColumns.length) {
items = this._processGroupItems(items, groupColumns.length);
}
return items;
},
_processItem: function _processItem(item, options) {
if (typeUtils.isDefined(item.groupIndex) && typeUtils.isString(item.rowType) && item.rowType.indexOf("group") === 0) {
item = this._processGroupItem(item, options);
options.dataIndex = 0;
} else {
item = this.callBase.apply(this, arguments);
}
return item;
},
_processGroupItem: function _processGroupItem(item) {
return item;
},
_processGroupItems: function _processGroupItems(items, groupsCount, options) {
var that = this,
groupedColumns = that._columnsController.getGroupColumns(),
column = groupedColumns[groupedColumns.length - groupsCount],
scrollingMode,
i,
item,
resultItems;
if (!options) {
scrollingMode = that.option("scrolling.mode");
options = {
collectContinuationItems: scrollingMode !== "virtual" && scrollingMode !== "infinite",
resultItems: [],
path: [],
values: []
};
}
resultItems = options.resultItems;
if (options.data) {
if (options.collectContinuationItems || !options.data.isContinuation) {
resultItems.push({
rowType: "group",
data: options.data,
groupIndex: options.path.length - 1,
isExpanded: !!options.data.items,
key: options.path.slice(0),
values: options.values.slice(0)
});
}
}
if (items) {
if (groupsCount === 0) {
resultItems.push.apply(resultItems, items);
} else {
for (i = 0; i < items.length; i++) {
item = items[i];
if (item && "items" in item) {
options.data = item;
options.path.push(item.key);
options.values.push(column && column.deserializeValue ? column.deserializeValue(item.key) : item.key);
that._processGroupItems(item.items, groupsCount - 1, options);
options.data = undefined;
options.path.pop();
options.values.pop();
} else {
resultItems.push(item);
}
}
}
}
return resultItems;
},
publicMethods: function publicMethods() {
return this.callBase().concat(["collapseAll", "expandAll", "isRowExpanded", "expandRow", "collapseRow"]);
},
/**
* @name dxDataGridMethods.collapseAll
* @publicName collapseAll(groupIndex)
* @param1 groupIndex:number | undefined
*/
collapseAll: function collapseAll(groupIndex) {
var dataSource = this._dataSource;
if (dataSource && dataSource.collapseAll(groupIndex)) {
dataSource.pageIndex(0);
dataSource.reload();
}
},
/**
* @name dxDataGridMethods.expandAll
* @publicName expandAll(groupIndex)
* @param1 groupIndex:number | undefined
*/
expandAll: function expandAll(groupIndex) {
var dataSource = this._dataSource;
if (dataSource && dataSource.expandAll(groupIndex)) {
dataSource.pageIndex(0);
dataSource.reload();
}
},
changeRowExpand: function changeRowExpand(key) {
var that = this,
expanded = that.isRowExpanded(key),
args = {
key: key,
expanded: expanded
};
that.executeAction(expanded ? "onRowCollapsing" : "onRowExpanding", args);
if (!args.cancel) {
return when(that._changeRowExpandCore(key)).done(function () {
args.expanded = !expanded;
that.executeAction(expanded ? "onRowCollapsed" : "onRowExpanded", args);
});
}
return new Deferred().resolve();
},
_changeRowExpandCore: function _changeRowExpandCore(key) {
var that = this,
dataSource = this._dataSource,
d;
if (!dataSource) return;
d = new Deferred();
when(dataSource.changeRowExpand(key)).done(function () {
that.load().done(d.resolve).fail(d.reject);
}).fail(d.reject);
return d;
},
/**
* @name dxDataGridMethods.isRowExpanded
* @publicName isRowExpanded(key)
* @param1 key:any
* @return boolean
*/
isRowExpanded: function isRowExpanded(key) {
var dataSource = this._dataSource;
return dataSource && dataSource.isRowExpanded(key);
},
/**
* @name dxDataGridMethods.expandRow
* @publicName expandRow(key)
* @param1 key:any
* @return Promise<void>
*/
expandRow: function expandRow(key) {
if (!this.isRowExpanded(key)) {
return this.changeRowExpand(key);
}
return new Deferred().resolve();
},
/**
* @name dxDataGridMethods.collapseRow
* @publicName collapseRow(key)
* @param1 key:any
* @return Promise<void>
*/
collapseRow: function collapseRow(key) {
if (this.isRowExpanded(key)) {
return this.changeRowExpand(key);
}
return new Deferred().resolve();
},
optionChanged: function optionChanged(args) {
if (args.name === "grouping" /* autoExpandAll */) {
args.name = "dataSource";
}
this.callBase(args);
}
};
}();
var onGroupingMenuItemClick = function onGroupingMenuItemClick(column, params) {
var columnsController = this._columnsController;
switch (params.itemData.value) {
case "group":
var groups = columnsController._dataSource.group() || [];
columnsController.columnOption(column.dataField, "groupIndex", groups.length);
break;
case "ungroup":
columnsController.columnOption(column.dataField, "groupIndex", -1);
break;
case "ungroupAll":
this.component.clearGrouping();
break;
}
};
var GroupingHeaderPanelExtender = function () {
return {
_getToolbarItems: function _getToolbarItems() {
var items = this.callBase();
return this._appendGroupingItem(items);
},
_appendGroupingItem: function _appendGroupingItem(items) {
var that = this,
isRendered = false,
groupPanelRenderedCallback = function groupPanelRenderedCallback(e) {
that._updateGroupPanelContent($(e.itemElement).find("." + DATAGRID_GROUP_PANEL_CLASS));
isRendered && that.renderCompleted.fire();
isRendered = true;
};
if (that._isGroupPanelVisible()) {
var toolbarItem = {
html: "<div class='" + DATAGRID_GROUP_PANEL_CLASS + "'></div>",
name: "groupPanel",
onItemRendered: groupPanelRenderedCallback,
location: "before",
locateInMenu: "never",
sortIndex: 1
};
items.push(toolbarItem);
}
return items;
},
_isGroupPanelVisible: function _isGroupPanelVisible() {
var groupPanelOptions = this.option("groupPanel"),
isVisible;
if (groupPanelOptions) {
isVisible = groupPanelOptions.visible;
if (isVisible === "auto") {
isVisible = devices.current().deviceType === "desktop" ? true : false;
}
}
return isVisible;
},
_renderGroupPanelItems: function _renderGroupPanelItems($groupPanel, groupColumns) {
var that = this;
$groupPanel.empty();
each(groupColumns, function (index, groupColumn) {
that._createGroupPanelItem($groupPanel, groupColumn);
});
},
_createGroupPanelItem: function _createGroupPanelItem($rootElement, groupColumn) {
return $("<div>").addClass(groupColumn.cssClass).addClass(DATAGRID_GROUP_PANEL_ITEM_CLASS).data("columnData", groupColumn).appendTo($rootElement).text(groupColumn.caption);
},
_columnOptionChanged: function _columnOptionChanged(e) {
if (!this._requireReady && !gridCore.checkChanges(e.optionNames, ["width", "visibleWidth"])) {
var $toolbarElement = this.element(),
$groupPanel = $toolbarElement && $toolbarElement.find("." + DATAGRID_GROUP_PANEL_CLASS);
if ($groupPanel && $groupPanel.length) {
this._updateGroupPanelContent($groupPanel);
this.renderCompleted.fire();
}
}
this.callBase();
},
_updateGroupPanelContent: function _updateGroupPanelContent($groupPanel) {
var that = this,
groupColumns = that.getController("columns").getGroupColumns(),
groupPanelOptions = that.option("groupPanel");
that._renderGroupPanelItems($groupPanel, groupColumns);
if (groupPanelOptions.allowColumnDragging && !groupColumns.length) {
$("<div>").addClass(DATAGRID_GROUP_PANEL_MESSAGE_CLASS).text(groupPanelOptions.emptyPanelText).appendTo($groupPanel);
$groupPanel.closest("." + DATAGRID_GROUP_PANEL_LABEL_CLASS).css("maxWidth", "none");
that.updateToolbarDimensions();
}
},
allowDragging: function allowDragging(column) {
var groupPanelOptions = this.option("groupPanel");
return this._isGroupPanelVisible() && groupPanelOptions.allowColumnDragging && column && column.allowGrouping;
},
getColumnElements: function getColumnElements() {
var $element = this.element();
return $element && $element.find("." + DATAGRID_GROUP_PANEL_ITEM_CLASS);
},
getColumns: function getColumns() {
return this.getController("columns").getGroupColumns();
},
getBoundingRect: function getBoundingRect() {
var that = this,
$element = that.element(),
offset;
if ($element && $element.find("." + DATAGRID_GROUP_PANEL_CLASS).length) {
offset = $element.offset();
return {
top: offset.top,
bottom: offset.top + $element.height()
};
}
return null;
},
getName: function getName() {
return "group";
},
getContextMenuItems: function getContextMenuItems(options) {
var that = this,
contextMenuEnabled = that.option("grouping.contextMenuEnabled"),
$groupedColumnElement = $(options.targetElement).closest("." + DATAGRID_GROUP_PANEL_ITEM_CLASS),
items;
if ($groupedColumnElement.length) {
options.column = $groupedColumnElement.data("columnData");
}
if (contextMenuEnabled && options.column) {
var column = options.column,
isGroupingAllowed = typeUtils.isDefined(column.allowGrouping) ? column.allowGrouping : true;
if (isGroupingAllowed) {
var isColumnGrouped = typeUtils.isDefined(column.groupIndex) && column.groupIndex > -1,
groupingTexts = that.option("grouping.texts"),
onItemClick = onGroupingMenuItemClick.bind(that, column);
items = [{ text: groupingTexts.ungroup, value: "ungroup", disabled: !isColumnGrouped, onItemClick: onItemClick }, { text: groupingTexts.ungroupAll, value: "ungroupAll", onItemClick: onItemClick }];
}
}
return items;
},
isVisible: function isVisible() {
return this.callBase() || this._isGroupPanelVisible();
},
optionChanged: function optionChanged(args) {
if (args.name === "groupPanel") {
this._invalidate();
args.handled = true;
} else {
this.callBase(args);
}
}
};
}();
exports.GroupingHeaderPanelExtender = GroupingHeaderPanelExtender;
var GroupingRowsViewExtender = function () {
return {
getContextMenuItems: function getContextMenuItems(options) {
var that = this,
contextMenuEnabled = that.option("grouping.contextMenuEnabled"),
items;
if (contextMenuEnabled && options.row && options.row.rowType === "group") {
var columnsController = that._columnsController,
column = columnsController.columnOption("groupIndex:" + options.row.groupIndex);
if (column && column.allowGrouping) {
var groupingTexts = that.option("grouping.texts"),
onItemClick = onGroupingMenuItemClick.bind(that, column);
items = [];
items.push({ text: groupingTexts.ungroup, value: "ungroup", onItemClick: onItemClick }, { text: groupingTexts.ungroupAll, value: "ungroupAll", onItemClick: onItemClick });
}
}
return items;
},
_rowClick: function _rowClick(e) {
var that = this,
expandMode = that.option("grouping.expandMode"),
scrollingMode = that.option("scrolling.mode"),
isGroupRowStateChanged = scrollingMode !== "infinite" && expandMode === "rowClick" && $(e.event.target).closest("." + DATAGRID_GROUP_ROW_CLASS).length,
isExpandButtonClicked = $(e.event.target).closest("." + DATAGRID_EXPAND_CLASS).length;
if (isGroupRowStateChanged || isExpandButtonClicked) {
that._changeGroupRowState(e);
}
that.callBase(e);
},
_changeGroupRowState: function _changeGroupRowState(e) {
var dataController = this.getController("data"),
row = dataController.items()[e.rowIndex];
if (row.rowType !== "detail") {
dataController.changeRowExpand(row.key);
e.event.preventDefault();
e.handled = true;
}
}
};
}();
var columnHeadersViewExtender = function () {
return {
getContextMenuItems: function getContextMenuItems(options) {
var that = this,
contextMenuEnabled = that.option("grouping.contextMenuEnabled"),
items = that.callBase(options);
if (contextMenuEnabled && options.row && (options.row.rowType === "header" || options.row.rowType === "detailAdaptive")) {
var column = options.column;
if (!column.command && (!typeUtils.isDefined(column.allowGrouping) || column.allowGrouping)) {
var groupingTexts = that.option("grouping.texts"),
isColumnGrouped = typeUtils.isDefined(column.groupIndex) && column.groupIndex > -1,
onItemClick = onGroupingMenuItemClick.bind(that, column);
items = items || [];
items.push({ text: groupingTexts.groupByThisColumn, value: "group", beginGroup: true, disabled: isColumnGrouped, onItemClick: onItemClick });
if (column.showWhenGrouped) {
items.push({ text: groupingTexts.ungroup, value: "ungroup", disabled: !isColumnGrouped, onItemClick: onItemClick });
}
items.push({ text: groupingTexts.ungroupAll, value: "ungroupAll", onItemClick: onItemClick });
}
}
return items;
}
};
}();
gridCore.registerModule("grouping", {
defaultOptions: function defaultOptions() {
return {
/**
* @name dxDataGridOptions.grouping
* @publicName grouping
* @type object
*/
grouping: {
/**
* @name dxDataGridOptions.grouping.autoExpandAll
* @publicName autoExpandAll
* @type boolean
* @default true
*/
autoExpandAll: true,
/**
* @name dxDataGridOptions.grouping.allowCollapsing
* @publicName allowCollapsing
* @type boolean
* @default true
*/
allowCollapsing: true,
/**
* @name dxDataGridOptions.grouping.contextMenuEnabled
* @publicName contextMenuEnabled
* @type boolean
* @default false
*/
contextMenuEnabled: false,
/**
* @name dxDataGridOptions.grouping.expandMode
* @publicName expandMode
* @type Enums.GridGroupingExpandMode
* @default "buttonClick"
*/
expandMode: "buttonClick",
/**
* @name dxDataGridOptions.grouping.texts
* @publicName texts
* @type object
*/
texts: {
/**
* @name dxDataGridOptions.grouping.texts.groupContinuesMessage
* @publicName groupContinuesMessage
* @type string
* @default "Continues on the next page"
*/
groupContinuesMessage: messageLocalization.format("dxDataGrid-groupContinuesMessage"),
/**
* @name dxDataGridOptions.grouping.texts.groupContinuedMessage
* @publicName groupContinuedMessage
* @type string
* @default "Continued from the previous page"
*/
groupContinuedMessage: messageLocalization.format("dxDataGrid-groupContinuedMessage"),
/**
* @name dxDataGridOptions.grouping.texts.groupByThisColumn
* @publicName groupByThisColumn
* @type string
* @default "Group by This Column"
*/
groupByThisColumn: messageLocalization.format("dxDataGrid-groupHeaderText"),
/**
* @name dxDataGridOptions.grouping.texts.ungroup
* @publicName ungroup
* @type string
* @default "Ungroup"
*/
ungroup: messageLocalization.format("dxDataGrid-ungroupHeaderText"),
/**
* @name dxDataGridOptions.grouping.texts.ungroupAll
* @publicName ungroupAll
* @type string
* @default "Ungroup All"
*/
ungroupAll: messageLocalization.format("dxDataGrid-ungroupAllText")
}
},
/**
* @name dxDataGridOptions.groupPanel
* @publicName groupPanel
* @type object
*/
groupPanel: {
/**
* @name dxDataGridOptions.groupPanel.visible
* @publicName visible
* @type boolean|Enums.Mode
* @default false
*/
visible: false,
/**
* @name dxDataGridOptions.groupPanel.emptyPanelText
* @publicName emptyPanelText
* @type string
* @default "Drag a column header here to group by that column"
*/
emptyPanelText: messageLocalization.format("dxDataGrid-groupPanelEmptyText"),
/**
* @name dxDataGridOptions.groupPanel.allowColumnDragging
* @publicName allowColumnDragging
* @type boolean
* @default true
*/
allowColumnDragging: true
}
};
},
extenders: {
controllers: {
data: GroupingDataControllerExtender,
columns: {
_getExpandColumnOptions: function _getExpandColumnOptions() {
var options = this.callBase.apply(this, arguments);
options.cellTemplate = gridCore.getExpandCellTemplate();
return options;
}
}
},
views: {
headerPanel: GroupingHeaderPanelExtender,
rowsView: GroupingRowsViewExtender,
columnHeadersView: columnHeadersViewExtender
}
}
});