devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
456 lines (454 loc) • 24.4 kB
JavaScript
/**
* DevExtreme (esm/ui/grid_core/ui.grid_core.column_headers.js)
* Version: 21.1.4
* Build date: Mon Jun 21 2021
*
* Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
import $ from "../../core/renderer";
import eventsEngine from "../../events/core/events_engine";
import {
ColumnsView
} from "./ui.grid_core.columns_view";
import messageLocalization from "../../localization/message";
import {
isDefined
} from "../../core/utils/type";
import {
each
} from "../../core/utils/iterator";
import {
extend
} from "../../core/utils/extend";
import {
registerKeyboardAction
} from "./ui.grid_core.accessibility";
var CELL_CONTENT_CLASS = "text-content";
var HEADERS_CLASS = "headers";
var NOWRAP_CLASS = "nowrap";
var ROW_CLASS_SELECTOR = ".dx-row";
var HEADER_ROW_CLASS = "dx-header-row";
var COLUMN_LINES_CLASS = "dx-column-lines";
var CONTEXT_MENU_SORT_ASC_ICON = "context-menu-sort-asc";
var CONTEXT_MENU_SORT_DESC_ICON = "context-menu-sort-desc";
var CONTEXT_MENU_SORT_NONE_ICON = "context-menu-sort-none";
var CELL_FOCUS_DISABLED_CLASS = "dx-cell-focus-disabled";
var VISIBILITY_HIDDEN_CLASS = "dx-visibility-hidden";
var TEXT_CONTENT_ALIGNMENT_CLASS_PREFIX = "dx-text-content-alignment-";
var SORT_INDICATOR_CLASS = "dx-sort-indicator";
var SORT_INDEX_INDICATOR_CLASS = "dx-sort-index-indicator";
var HEADER_FILTER_CLASS_SELECTOR = ".dx-header-filter";
var HEADER_FILTER_INDICATOR_CLASS = "dx-header-filter-indicator";
var MULTI_ROW_HEADER_CLASS = "dx-header-multi-row";
export var columnHeadersModule = {
defaultOptions: function() {
return {
showColumnHeaders: true,
cellHintEnabled: true
}
},
views: {
columnHeadersView: ColumnsView.inherit(function() {
var createCellContent = function(that, $cell, options) {
var $cellContent = $("<div>").addClass(that.addWidgetPrefix(CELL_CONTENT_CLASS));
that.setAria("role", "presentation", $cellContent);
addCssClassesToCellContent(that, $cell, options.column, $cellContent);
var showColumnLines = that.option("showColumnLines");
var contentAlignment = that.getController("columns").getHeaderContentAlignment(options.column.alignment);
return $cellContent[showColumnLines || "right" === contentAlignment ? "appendTo" : "prependTo"]($cell)
};
function addCssClassesToCellContent(that, $cell, column, $cellContent) {
var $indicatorElements = that._getIndicatorElements($cell, true);
var $visibleIndicatorElements = that._getIndicatorElements($cell);
var indicatorCount = $indicatorElements && $indicatorElements.length;
var columnAlignment = that._getColumnAlignment(column.alignment);
var sortIndicatorClassName = ".".concat(that._getIndicatorClassName("sort"));
var sortIndexIndicatorClassName = ".".concat(that._getIndicatorClassName("sortIndex"));
var $sortIndicator = $visibleIndicatorElements.filter(sortIndicatorClassName);
var $sortIndexIndicator = $visibleIndicatorElements.children().filter(sortIndexIndicatorClassName);
$cellContent = $cellContent || $cell.children("." + that.addWidgetPrefix(CELL_CONTENT_CLASS));
$cellContent.toggleClass(TEXT_CONTENT_ALIGNMENT_CLASS_PREFIX + columnAlignment, indicatorCount > 0).toggleClass(TEXT_CONTENT_ALIGNMENT_CLASS_PREFIX + ("left" === columnAlignment ? "right" : "left"), indicatorCount > 0 && "center" === column.alignment).toggleClass(SORT_INDICATOR_CLASS, !!$sortIndicator.length).toggleClass(SORT_INDEX_INDICATOR_CLASS, !!$sortIndexIndicator.length).toggleClass(HEADER_FILTER_INDICATOR_CLASS, !!$visibleIndicatorElements.filter("." + that._getIndicatorClassName("headerFilter")).length)
}
return {
_createTable: function() {
var $table = this.callBase.apply(this, arguments);
eventsEngine.on($table, "mousedown selectstart", this.createAction((function(e) {
var event = e.event;
if (event.shiftKey) {
event.preventDefault()
}
})));
return $table
},
_isLegacyKeyboardNavigation() {
return this.option("useLegacyKeyboardNavigation")
},
_getDefaultTemplate: function(column) {
var that = this;
return function($container, options) {
var $content = column.command ? $container : createCellContent(that, $container, options);
var caption = "expand" !== column.command && column.caption;
if (caption) {
$content.text(caption)
} else if (column.command) {
$container.html(" ")
}
}
},
_getHeaderTemplate: function(column) {
return column.headerCellTemplate || {
allowRenderToDetachedContainer: true,
render: this._getDefaultTemplate(column)
}
},
_processTemplate: function(template, options) {
var that = this;
var resultTemplate;
var column = options.column;
var renderingTemplate = that.callBase(template);
if ("header" === options.rowType && renderingTemplate && column.headerCellTemplate && !column.command) {
resultTemplate = {
render: function(options) {
var $content = createCellContent(that, options.container, options.model);
renderingTemplate.render(extend({}, options, {
container: $content
}))
}
}
} else {
resultTemplate = renderingTemplate
}
return resultTemplate
},
_handleDataChanged: function(e) {
if ("refresh" !== e.changeType) {
return
}
if (this._isGroupingChanged || this._requireReady) {
this._isGroupingChanged = false;
this.render()
}
},
_renderCell: function($row, options) {
var $cell = this.callBase($row, options);
if ("header" === options.row.rowType) {
$cell.addClass(CELL_FOCUS_DISABLED_CLASS);
if (!this._isLegacyKeyboardNavigation()) {
if (options.column && !options.column.type) {
$cell.attr("tabindex", this.option("tabindex") || 0)
}
}
}
return $cell
},
_setCellAriaAttributes: function($cell, cellOptions) {
this.callBase($cell, cellOptions);
if ("header" === cellOptions.rowType) {
this.setAria("role", "columnheader", $cell);
if (cellOptions.column && !cellOptions.column.command && !cellOptions.column.isBand) {
$cell.attr("id", cellOptions.column.headerId);
this.setAria("label", messageLocalization.format("dxDataGrid-ariaColumn") + " " + cellOptions.column.caption, $cell)
}
}
},
_createRow: function(row) {
var $row = this.callBase(row).toggleClass(COLUMN_LINES_CLASS, this.option("showColumnLines"));
if ("header" === row.rowType) {
$row.addClass(HEADER_ROW_CLASS);
if (!this._isLegacyKeyboardNavigation()) {
registerKeyboardAction("columnHeaders", this, $row, "td", this._handleActionKeyDown.bind(this))
}
}
return $row
},
_handleActionKeyDown: function(args) {
var event = args.event;
var $target = $(event.target);
this._lastActionElement = event.target;
if ($target.is(HEADER_FILTER_CLASS_SELECTOR)) {
var headerFilterController = this.getController("headerFilter");
var $column = $target.closest("td");
var columnIndex = this.getColumnIndexByElement($column);
if (columnIndex >= 0) {
headerFilterController.showHeaderFilterMenu(columnIndex, false)
}
} else {
var $row = $target.closest(ROW_CLASS_SELECTOR);
this._processHeaderAction(event, $row)
}
event.preventDefault()
},
_renderCore: function() {
var that = this;
var $container = that.element();
if (that._tableElement && !that._dataController.isLoaded() && !that._hasRowElements) {
return
}
$container.addClass(that.addWidgetPrefix(HEADERS_CLASS)).toggleClass(that.addWidgetPrefix(NOWRAP_CLASS), !that.option("wordWrapEnabled")).empty();
that.setAria("role", "presentation", $container);
that._updateContent(that._renderTable());
if (that.getRowCount() > 1) {
$container.addClass(MULTI_ROW_HEADER_CLASS)
}
that.callBase.apply(that, arguments)
},
_renderRows: function() {
var that = this;
if (that._dataController.isLoaded() || that._hasRowElements) {
that.callBase.apply(that, arguments);
that._hasRowElements = true
}
},
_getRowVisibleColumns: function(rowIndex) {
return this._columnsController.getVisibleColumns(rowIndex)
},
_renderRow: function($table, options) {
options.columns = this._getRowVisibleColumns(options.row.rowIndex);
this.callBase($table, options)
},
_createCell: function(options) {
var column = options.column;
var $cellElement = this.callBase.apply(this, arguments);
column.rowspan > 1 && "header" === options.rowType && $cellElement.attr("rowSpan", column.rowspan);
return $cellElement
},
_getRows: function() {
var result = [];
var rowCount = this.getRowCount();
if (this.option("showColumnHeaders")) {
for (var i = 0; i < rowCount; i++) {
result.push({
rowType: "header",
rowIndex: i
})
}
}
return result
},
_getCellTemplate: function(options) {
if ("header" === options.rowType) {
return this._getHeaderTemplate(options.column)
}
},
_columnOptionChanged: function(e) {
var changeTypes = e.changeTypes;
var optionNames = e.optionNames;
if (changeTypes.grouping) {
this._isGroupingChanged = true;
return
}
this.callBase(e);
if (optionNames.width || optionNames.visible) {
this.resizeCompleted.fire()
}
},
_isElementVisible: function(elementOptions) {
return elementOptions && elementOptions.visible
},
_alignCaptionByCenter: function($cell) {
var $indicatorsContainer = this._getIndicatorContainer($cell, true);
if ($indicatorsContainer && $indicatorsContainer.length) {
$indicatorsContainer.filter("." + VISIBILITY_HIDDEN_CLASS).remove();
$indicatorsContainer = this._getIndicatorContainer($cell);
$indicatorsContainer.clone().addClass(VISIBILITY_HIDDEN_CLASS).css("float", "").insertBefore($cell.children("." + this.addWidgetPrefix(CELL_CONTENT_CLASS)))
}
},
_updateCell: function($cell, options) {
if ("header" === options.rowType && "center" === options.column.alignment) {
this._alignCaptionByCenter($cell)
}
this.callBase.apply(this, arguments)
},
_updateIndicator: function($cell, column, indicatorName) {
var $indicatorElement = this.callBase.apply(this, arguments);
if ("center" === column.alignment) {
this._alignCaptionByCenter($cell)
}
addCssClassesToCellContent(this, $cell, column);
return $indicatorElement
},
_getIndicatorContainer: function($cell, returnAll) {
var $indicatorsContainer = this.callBase($cell);
return returnAll ? $indicatorsContainer : $indicatorsContainer.filter(":not(." + VISIBILITY_HIDDEN_CLASS + ")")
},
_isSortableElement: function() {
return true
},
getHeadersRowHeight: function() {
var $tableElement = this.getTableElement();
var $headerRows = $tableElement && $tableElement.find("." + HEADER_ROW_CLASS);
return $headerRows && $headerRows.toArray().reduce((function(sum, headerRow) {
return sum + $(headerRow).height()
}), 0) || 0
},
getHeaderElement: function(index) {
var columnElements = this.getColumnElements();
return columnElements && columnElements.eq(index)
},
getColumnElements: function(index, bandColumnIndex) {
var that = this;
var $cellElement;
var columnsController = that._columnsController;
var rowCount = that.getRowCount();
if (that.option("showColumnHeaders")) {
if (rowCount > 1 && (!isDefined(index) || isDefined(bandColumnIndex))) {
var result = [];
var visibleColumns = isDefined(bandColumnIndex) ? columnsController.getChildrenByBandColumn(bandColumnIndex, true) : columnsController.getVisibleColumns();
each(visibleColumns, (function(_, column) {
var rowIndex = isDefined(index) ? index : columnsController.getRowIndex(column.index);
$cellElement = that._getCellElement(rowIndex, columnsController.getVisibleIndex(column.index, rowIndex));
$cellElement && result.push($cellElement.get(0))
}));
return $(result)
} else if (!index || index < rowCount) {
return that.getCellElements(index || 0)
}
}
},
getColumnIndexByElement: function($cell) {
var cellIndex = this.getCellIndex($cell);
var $row = $cell.closest(".dx-row");
var rowIndex = $row[0].rowIndex;
var column = this.getColumns(rowIndex)[cellIndex];
return column ? column.index : -1
},
getVisibleColumnIndex: function(columnIndex, rowIndex) {
var column = this.getColumns()[columnIndex];
return column ? this._columnsController.getVisibleIndex(column.index, rowIndex) : -1
},
getColumnWidths: function() {
var $columnElements = this.getColumnElements();
if ($columnElements && $columnElements.length) {
return this._getWidths($columnElements)
}
return this.callBase.apply(this, arguments)
},
allowDragging: function(column, sourceLocation, draggingPanels) {
var i;
var draggableColumnCount = 0;
var rowIndex = column && this._columnsController.getRowIndex(column.index);
var columns = this.getColumns(0 === rowIndex ? 0 : null);
var canHideColumn = (null === column || void 0 === column ? void 0 : column.allowHiding) && columns.length > 1;
var allowDrag = function(column) {
return column.allowReordering || column.allowGrouping || column.allowHiding
};
for (i = 0; i < columns.length; i++) {
if (allowDrag(columns[i])) {
draggableColumnCount++
}
}
if (draggableColumnCount <= 1 && !canHideColumn) {
return false
} else if (!draggingPanels) {
return (this.option("allowColumnReordering") || this._columnsController.isColumnOptionUsed("allowReordering")) && column && column.allowReordering
}
for (i = 0; i < draggingPanels.length; i++) {
var draggingPanel = draggingPanels[i];
if (draggingPanel && draggingPanel.allowDragging(column, sourceLocation)) {
return true
}
}
return false
},
getBoundingRect: function() {
var $columnElements = this.getColumnElements();
if ($columnElements && $columnElements.length) {
var offset = this.getTableElement().offset();
return {
top: offset.top
}
}
return null
},
getName: function() {
return "headers"
},
getColumnCount: function() {
var $columnElements = this.getColumnElements();
return $columnElements ? $columnElements.length : 0
},
isVisible: function() {
return this.option("showColumnHeaders")
},
optionChanged: function(args) {
switch (args.name) {
case "showColumnHeaders":
case "wordWrapEnabled":
case "showColumnLines":
this._invalidate(true, true);
args.handled = true;
break;
default:
this.callBase(args)
}
},
getHeight: function() {
return this.getElementHeight()
},
getContextMenuItems: function(options) {
var that = this;
var column = options.column;
if (options.row && ("header" === options.row.rowType || "detailAdaptive" === options.row.rowType)) {
var sortingOptions = that.option("sorting");
if (sortingOptions && "none" !== sortingOptions.mode && column && column.allowSorting) {
var onItemClick = function(params) {
setTimeout((function() {
that._columnsController.changeSortOrder(column.index, params.itemData.value)
}))
};
return [{
text: sortingOptions.ascendingText,
value: "asc",
disabled: "asc" === column.sortOrder,
icon: CONTEXT_MENU_SORT_ASC_ICON,
onItemClick: onItemClick
}, {
text: sortingOptions.descendingText,
value: "desc",
disabled: "desc" === column.sortOrder,
icon: CONTEXT_MENU_SORT_DESC_ICON,
onItemClick: onItemClick
}, {
text: sortingOptions.clearText,
value: "none",
disabled: !column.sortOrder,
icon: CONTEXT_MENU_SORT_NONE_ICON,
onItemClick: onItemClick
}]
}
}
},
getRowCount: function() {
return this._columnsController && this._columnsController.getRowCount()
},
setRowsOpacity: function(columnIndex, value, rowIndex) {
var that = this;
var i;
var columnElements;
var rowCount = that.getRowCount();
var columns = that._columnsController.getColumns();
var column = columns && columns[columnIndex];
var columnID = column && column.isBand && column.index;
var setColumnOpacity = function(index, column) {
if (column.ownerBand === columnID) {
columnElements.eq(index).css({
opacity: value
});
if (column.isBand) {
that.setRowsOpacity(column.index, value, i + 1)
}
}
};
if (isDefined(columnID)) {
rowIndex = rowIndex || 0;
for (i = rowIndex; i < rowCount; i++) {
columnElements = that.getCellElements(i);
each(that.getColumns(i), setColumnOpacity)
}
}
}
}
}())
}
};