UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

1,139 lines (1,131 loc) • 64.9 kB
/** * DevExtreme (cjs/__internal/grids/pivot_grid/m_widget.js) * Version: 26.1.4 * Build date: Fri Jul 24 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.PivotGrid = void 0; var _click = require("../../../common/core/events/click"); var _events_engine = _interopRequireDefault(require("../../../common/core/events/core/events_engine")); var _index = require("../../../common/core/events/utils/index"); var _message = _interopRequireDefault(require("../../../common/core/localization/message")); var _component_registrator = _interopRequireDefault(require("../../../core/component_registrator")); var _element = require("../../../core/element"); var _renderer = _interopRequireDefault(require("../../../core/renderer")); var _common = require("../../../core/utils/common"); var _deferred = require("../../../core/utils/deferred"); var _extend = require("../../../core/utils/extend"); var _iterator = require("../../../core/utils/iterator"); var _size = require("../../../core/utils/size"); var _string = require("../../../core/utils/string"); var _type = require("../../../core/utils/type"); var _window = require("../../../core/utils/window"); var _button = _interopRequireDefault(require("../../../ui/button")); var _context_menu = _interopRequireDefault(require("../../../ui/context_menu")); var _ui = _interopRequireDefault(require("../../../ui/popup/ui.popup")); var _accessibility = require("../../../ui/shared/accessibility"); var _themes = require("../../../ui/themes"); var _widget = _interopRequireDefault(require("../../core/widget/widget")); var _m_utils = _interopRequireDefault(require("../../grids/grid_core/m_utils")); var _m_chart_integration = require("./chart_integration/m_chart_integration"); var _m_data_area = _interopRequireDefault(require("./data_area/m_data_area")); var _m_data_controller = _interopRequireDefault(require("./data_controller/m_data_controller")); var _m_export = require("./export/m_export"); var _m_field_chooser = require("./field_chooser/m_field_chooser"); var _m_field_chooser_base = require("./field_chooser/m_field_chooser_base"); var _m_fields_area = require("./fields_area/m_fields_area"); var _m_headers_area = _interopRequireDefault(require("./headers_area/m_headers_area")); var _const = require("./keyboard_navigation/const"); var _roving_tab_index = require("./keyboard_navigation/roving_tab_index"); var _table_cell_navigation = require("./keyboard_navigation/table_cell_navigation"); var _m_widget_utils = require("./m_widget_utils"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } const window = (0, _window.getWindow)(); const DATA_AREA_CELL_CLASS = "dx-area-data-cell"; const ROW_AREA_CELL_CLASS = "dx-area-row-cell"; const COLUMN_AREA_CELL_CLASS = "dx-area-column-cell"; const DESCRIPTION_AREA_CELL_CLASS = "dx-area-description-cell"; const BORDERS_CLASS = "dx-pivotgrid-border"; const PIVOTGRID_CLASS = "dx-pivotgrid"; const ROW_LINES_CLASS = "dx-row-lines"; const BOTTOM_ROW_CLASS = "dx-bottom-row"; const BOTTOM_BORDER_CLASS = "dx-bottom-border"; const FIELDS_CONTAINER_CLASS = "dx-pivotgrid-fields-container"; const FIELDS_CLASS = "dx-area-fields"; const FIELD_CHOOSER_POPUP_CLASS = "dx-fieldchooser-popup"; const INCOMPRESSIBLE_FIELDS_CLASS = "dx-incompressible-fields"; const OVERFLOW_HIDDEN_CLASS = "dx-overflow-hidden"; const TR = "<tr>"; const TD = "<td>"; const DIV = "<div>"; const TEST_HEIGHT = 66666; const FIELD_CALCULATED_OPTIONS = ["allowSorting", "allowSortingBySummary", "allowFiltering", "allowExpandAll"]; const ARROW_KEY_DIRECTIONS = { ArrowUp: "up", ArrowDown: "down", ArrowLeft: "left", ArrowRight: "right" }; function getArraySum(array) { let sum = 0; (0, _iterator.each)(array, (_, value) => { sum += value || 0 }); return sum } function adjustSizeArray(sizeArray, space) { const delta = space / sizeArray.length; for (let i = 0; i < sizeArray.length; i += 1) { sizeArray[i] -= delta } } function unsubscribeScrollEvents(area) { area.off("scroll").off("stop") } function subscribeToScrollEvent(area, handler) { unsubscribeScrollEvents(area); area.on("scroll", handler).on("stop", handler) } function getCommonBorderWidth(elements, direction) { const borderStyleNames = "width" === direction ? ["borderLeftWidth", "borderRightWidth"] : ["borderTopWidth", "borderBottomWidth"]; let width = 0; (0, _iterator.each)(elements, (_, elem) => { const computedStyle = window.getComputedStyle(elem.get(0)); borderStyleNames.forEach(borderStyleName => { width += parseFloat(computedStyle[borderStyleName]) || 0 }) }); return width } function clickedOnFieldsArea($targetElement) { return $targetElement.closest(`.${FIELDS_CLASS}`).length || $targetElement.find(`.${FIELDS_CLASS}`).length } class PivotGrid extends _widget.default { _getDefaultOptions() { return (0, _extend.extend)(super._getDefaultOptions(), { scrolling: { timeout: 300, renderingThreshold: 150, minTimeout: 10, mode: "standard", useNative: "auto", removeInvisiblePages: true, virtualRowHeight: 50, virtualColumnWidth: 100, loadTwoPagesOnStart: true }, encodeHtml: true, dataSource: null, activeStateEnabled: false, fieldChooser: { minWidth: 250, minHeight: 250, enabled: true, allowSearch: false, searchTimeout: 500, layout: 0, title: _message.default.format("dxPivotGrid-fieldChooserTitle"), width: 600, height: 600, applyChangesMode: "instantly" }, onContextMenuPreparing: void 0, allowSorting: false, allowSortingBySummary: false, allowFiltering: false, allowExpandAll: false, wordWrapEnabled: true, fieldPanel: { showColumnFields: true, showFilterFields: true, showDataFields: true, showRowFields: true, allowFieldDragging: true, visible: false, texts: { columnFieldArea: _message.default.format("dxPivotGrid-columnFieldArea"), rowFieldArea: _message.default.format("dxPivotGrid-rowFieldArea"), filterFieldArea: _message.default.format("dxPivotGrid-filterFieldArea"), dataFieldArea: _message.default.format("dxPivotGrid-dataFieldArea") } }, dataFieldArea: "column", export: { enabled: false, fileName: "PivotGrid" }, showRowTotals: true, showRowGrandTotals: true, showColumnTotals: true, showColumnGrandTotals: true, hideEmptySummaryCells: true, showTotalsPrior: "none", rowHeaderLayout: "standard", loadPanel: { enabled: true, text: _message.default.format("Loading"), width: 200, height: 70, showIndicator: true, showPane: true }, texts: { grandTotal: _message.default.format("dxPivotGrid-grandTotal"), total: _message.default.getFormatter("dxPivotGrid-total"), noData: _message.default.format("dxDataGrid-noDataText"), showFieldChooser: _message.default.format("dxPivotGrid-showFieldChooser"), expandAll: _message.default.format("dxPivotGrid-expandAll"), collapseAll: _message.default.format("dxPivotGrid-collapseAll"), sortColumnBySummary: _message.default.getFormatter("dxPivotGrid-sortColumnBySummary"), sortRowBySummary: _message.default.getFormatter("dxPivotGrid-sortRowBySummary"), removeAllSorting: _message.default.format("dxPivotGrid-removeAllSorting"), exportToExcel: _message.default.format("dxDataGrid-exportToExcel"), dataNotAvailable: _message.default.format("dxPivotGrid-dataNotAvailable") }, onCellClick: void 0, onCellPrepared: void 0, showBorders: false, stateStoring: { enabled: false, storageKey: void 0, type: "localStorage", customLoad: null, customSave: null, savingTimeout: 2e3 }, onExpandValueChanging: null, renderCellCountLimit: 2e4, onExporting: void 0, headerFilter: { width: 252, height: 325, allowSelectAll: true, showRelevantValues: false, search: { enabled: false, timeout: 500, editorOptions: {}, mode: "contains" }, texts: { emptyValue: _message.default.format("dxDataGrid-headerFilterEmptyValue"), ok: _message.default.format("dxDataGrid-headerFilterOK"), cancel: _message.default.format("dxDataGrid-headerFilterCancel") } } }) } _setDeprecatedOptions() { super._setDeprecatedOptions(); this._deprecatedOptions = Object.assign({}, this._deprecatedOptions, { "loadPanel.indicatorSrc": { since: "25.2", alias: "loadPanel.indicatorOptions.src" } }) } _updateCalculatedOptions(fields) { const that = this; (0, _iterator.each)(fields, (_, field) => { (0, _iterator.each)(FIELD_CALCULATED_OPTIONS, (_, optionName) => { const isCalculated = field._initProperties && optionName in field._initProperties && void 0 === field._initProperties[optionName]; const needUpdate = void 0 === field[optionName] || isCalculated; if (needUpdate) { (0, _m_widget_utils.setFieldProperty)(field, optionName, that.option(optionName)) } }) }) } _getDataControllerOptions() { const that = this; return { component: that, dataSource: that.option("dataSource"), texts: that.option("texts"), showRowTotals: that.option("showRowTotals"), showRowGrandTotals: that.option("showRowGrandTotals"), showColumnTotals: that.option("showColumnTotals"), showTotalsPrior: that.option("showTotalsPrior"), showColumnGrandTotals: that.option("showColumnGrandTotals"), dataFieldArea: that.option("dataFieldArea"), rowHeaderLayout: that.option("rowHeaderLayout"), hideEmptySummaryCells: that.option("hideEmptySummaryCells"), onFieldsPrepared(fields) { that._updateCalculatedOptions(fields) } } } _initDataController() { const that = this; that._dataController && that._dataController.dispose(); that._dataController = new _m_data_controller.default.DataController(that._getDataControllerOptions()); if ((0, _window.hasWindow)()) { that._dataController.changed.add(() => { that._render() }) } that._dataController.scrollChanged.add(options => { that._scrollLeft = options.left; that._scrollTop = options.top }); that._dataController.loadingChanged.add(() => { that._updateLoading() }); that._dataController.progressChanged.add(that._updateLoading.bind(that)); that._dataController.dataSourceChanged.add(() => { that._trigger("onChanged", void 0) }); const expandValueChanging = that.option("onExpandValueChanging"); if (expandValueChanging) { that._dataController.expandValueChanging.add(e => { expandValueChanging(e) }) } } _init() { super._init(); this._initDataController(); _m_utils.default.logHeaderFilterDeprecatedWarningIfNeed(this); this._scrollLeft = this._scrollTop = null; this._initActions() } _initActions() { this._actions = { onChanged: this._createActionByOption("onChanged"), onContextMenuPreparing: this._createActionByOption("onContextMenuPreparing"), onCellClick: this._createActionByOption("onCellClick"), onExporting: this._createActionByOption("onExporting"), onCellPrepared: this._createActionByOption("onCellPrepared") } } _trigger(eventName, eventArg) { this._actions[eventName](eventArg) } _optionChanged(args) { const that = this; if (FIELD_CALCULATED_OPTIONS.includes(args.name)) { const fields = this.getDataSource().fields(); this._updateCalculatedOptions(fields) } switch (args.name) { case "dataSource": case "allowSorting": case "allowFiltering": case "allowExpandAll": case "allowSortingBySummary": case "scrolling": case "stateStoring": that._initDataController(); that.getFieldChooserPopup().hide(); that._renderFieldChooser(); that._invalidate(); break; case "texts": case "showTotalsPrior": case "showRowTotals": case "showRowGrandTotals": case "showColumnTotals": case "showColumnGrandTotals": case "hideEmptySummaryCells": case "dataFieldArea": that._dataController.updateViewOptions(that._getDataControllerOptions()); break; case "useNativeScrolling": case "encodeHtml": case "renderCellCountLimit": case "onExpandValueChanging": break; case "rtlEnabled": super._optionChanged(args); that._renderFieldChooser(); that._renderContextMenu(); (0, _window.hasWindow)() && that._renderLoadPanel(that._dataArea.groupElement(), that.$element()); that._invalidate(); break; case "export": that._renderDescriptionArea(); break; case "onCellClick": case "onContextMenuPreparing": case "onExporting": case "onExported": case "onFileSaving": case "onCellPrepared": that._actions[args.name] = that._createActionByOption(args.name); break; case "fieldChooser": that._renderFieldChooser(); that._renderDescriptionArea(); break; case "loadPanel": if ((0, _window.hasWindow)()) { if ("loadPanel.enabled" === args.fullName) { clearTimeout(this._hideLoadingTimeoutID); that._renderLoadPanel(that._dataArea.groupElement(), that.$element()) } else { that._renderLoadPanel(that._dataArea.groupElement(), that.$element()); that._invalidate() } } break; case "fieldPanel": that._renderDescriptionArea(); that._invalidate(); break; case "headerFilter": that._renderFieldChooser(); that._invalidate(); break; case "showBorders": that._tableElement().toggleClass(BORDERS_CLASS, !!args.value); that.updateDimensions(); break; case "wordWrapEnabled": that._tableElement().toggleClass("dx-word-wrap", !!args.value); that.updateDimensions(); break; case "rowHeaderLayout": that._tableElement().find(".dx-area-row-cell").toggleClass("dx-area-tree-view", "tree" === args.value); that._dataController.updateViewOptions(that._getDataControllerOptions()); break; case "height": case "width": that._hasHeight = null; super._optionChanged(args); that.resize(); break; default: super._optionChanged(args) } } _updateScrollPosition(columnsArea, rowsArea, dataArea) { let force = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : false; const that = this; let scrollTop; let scrollLeft; const scrolled = that._scrollTop || that._scrollLeft; if (that._scrollUpdating) { return } that._scrollUpdating = true; if (rowsArea && !rowsArea.hasScroll() && that._hasHeight) { that._scrollTop = null } if (columnsArea && !columnsArea.hasScroll()) { that._scrollLeft = null } if (null !== that._scrollTop || null !== that._scrollLeft || scrolled || that.option("rtlEnabled")) { scrollTop = that._scrollTop || 0; scrollLeft = that._scrollLeft || 0; dataArea.scrollTo({ left: scrollLeft, top: scrollTop }, force); columnsArea.scrollTo({ left: scrollLeft }, force); rowsArea.scrollTo({ top: scrollTop }, force); that._dataController.updateWindowScrollPosition(that._scrollTop) } that._scrollUpdating = false } _subscribeToEvents(columnsArea, rowsArea, dataArea) { const that = this; (0, _iterator.each)([columnsArea, rowsArea, dataArea], (_, area) => { subscribeToScrollEvent(area, e => function(e, area) { const { scrollOffset: scrollOffset } = e; const scrollable = area._getScrollable(); const leftOffset = "vertical" !== scrollable.option("direction") ? scrollOffset.left : that._scrollLeft; const topOffset = "horizontal" !== scrollable.option("direction") && that._hasHeight ? scrollOffset.top : that._scrollTop; if ((that._scrollLeft || 0) !== (leftOffset || 0) || (that._scrollTop || 0) !== (topOffset || 0)) { that._scrollLeft = leftOffset; that._scrollTop = topOffset; that._updateScrollPosition(columnsArea, rowsArea, dataArea); if ("virtual" === that.option("scrolling.mode")) { that._dataController.setViewportPosition(that._scrollLeft, that._scrollTop) } } }(e, area)) }); !that._hasHeight && that._dataController.subscribeToWindowScrollEvents(dataArea.groupElement()) } _clean() { (0, _common.noop)() } _needDelayResizing(cellsInfo) { const cellsCount = cellsInfo.length * (cellsInfo.length ? cellsInfo[0].length : 0); return cellsCount > Number(this.option("renderCellCountLimit")) } _renderFieldChooser() { const that = this; const container = that._pivotGridContainer; const fieldChooserOptions = that.option("fieldChooser") || {}; const toolbarItems = "onDemand" === fieldChooserOptions.applyChangesMode ? [{ toolbar: "bottom", location: "after", widget: "dxButton", options: { text: _message.default.format("OK"), onClick() { that.getFieldChooserPopup().$content().dxPivotGridFieldChooser("applyChanges"); that.getFieldChooserPopup().hide() } } }, { toolbar: "bottom", location: "after", widget: "dxButton", options: { text: _message.default.format("Cancel"), onClick() { that.getFieldChooserPopup().hide() } } }] : []; const fieldChooserComponentOptions = { layout: fieldChooserOptions.layout, texts: fieldChooserOptions.texts || {}, dataSource: that.getDataSource(), allowSearch: fieldChooserOptions.allowSearch, searchTimeout: fieldChooserOptions.searchTimeout, width: void 0, height: void 0, headerFilter: that.option("headerFilter"), encodeHtml: that.option("fieldChooser.encodeHtml") ?? that.option("encodeHtml"), applyChangesMode: fieldChooserOptions.applyChangesMode, rtlEnabled: that.option("rtlEnabled"), onContextMenuPreparing(e) { that._trigger("onContextMenuPreparing", e) } }; const popupOptions = { shading: false, title: fieldChooserOptions.title, width: fieldChooserOptions.width, height: fieldChooserOptions.height, showCloseButton: true, resizeEnabled: true, minWidth: fieldChooserOptions.minWidth, minHeight: fieldChooserOptions.minHeight, toolbarItems: toolbarItems, onResize(e) { e.component.$content().dxPivotGridFieldChooser("updateDimensions") }, onShown(e) { that._createComponent(e.component.content(), _m_field_chooser.FieldChooser, fieldChooserComponentOptions) }, onHidden(e) { const fieldChooser = e.component.$content().dxPivotGridFieldChooser("instance"); fieldChooser.resetTreeView(); fieldChooser.cancelChanges(); if (that.$fieldChooserButton) { that.$fieldChooserButton.get(0).focus() } } }; if (that.getFieldChooserPopup()) { that._fieldChooserPopup.option(popupOptions); that._fieldChooserPopup.$content().dxPivotGridFieldChooser(fieldChooserComponentOptions) } else { that._fieldChooserPopup = that._createComponent((0, _renderer.default)(DIV).addClass("dx-fieldchooser-popup").appendTo(container), _ui.default, popupOptions) } } _renderContextMenu() { const that = this; const $container = that._pivotGridContainer; if (that._contextMenu) { that._contextMenu.$element().remove() } that._contextMenu = that._createComponent((0, _renderer.default)(DIV).appendTo($container), _context_menu.default, { onPositioning(actionArgs) { const { event: event } = actionArgs; actionArgs.cancel = true; if (!event) { return } const targetElement = event.target.cellIndex >= 0 ? event.target : (0, _renderer.default)(event.target).closest("td").get(0); if (!targetElement) { return } const args = that._createEventArgs(targetElement, event); const items = that._getContextMenuItems(args); if (items) { actionArgs.component.option("items", items); if ("keydown" === event.type) { if (actionArgs.position) { actionArgs.position.of = (0, _renderer.default)(targetElement) } } else { that._contextMenuOwnerNavigation = void 0 } actionArgs.cancel = false } }, onHidden() { var _that$_contextMenuOwn; null === (_that$_contextMenuOwn = that._contextMenuOwnerNavigation) || void 0 === _that$_contextMenuOwn || _that$_contextMenuOwn.refocusFocusedItem(); that._contextMenuOwnerNavigation = void 0 }, onItemClick(params) { params.itemData.onItemClick && params.itemData.onItemClick(params) }, cssClass: "dx-pivotgrid", target: that.$element() }) } _getContextMenuItems(e) { const that = this; let items = []; const texts = that.option("texts"); if ("row" === e.area || "column" === e.area) { const areaFields = e[`${e.area}Fields`]; const oppositeAreaFields = e["column" === e.area ? "rowFields" : "columnFields"]; const field = e.cell.path && areaFields[e.cell.path.length - 1]; const dataSource = that.getDataSource(); if (field && field.allowExpandAll && e.cell.path.length < e[`${e.area}Fields`].length && !dataSource.paginate()) { items.push({ beginGroup: true, icon: "none", text: texts.expandAll, onItemClick() { dataSource.expandAll(field.index) } }); items.push({ text: texts.collapseAll, icon: "none", onItemClick() { dataSource.collapseAll(field.index) } }) } if (e.cell.isLast && !dataSource.paginate()) { let sortingBySummaryItemCount = 0; (0, _iterator.each)(oppositeAreaFields, (_, field) => { if (!field.allowSortingBySummary) { return }(0, _iterator.each)(e.dataFields, (dataIndex, dataField) => { if ((0, _type.isDefined)(e.cell.dataIndex) && e.cell.dataIndex !== dataIndex) { return } const showDataFieldCaption = !(0, _type.isDefined)(e.cell.dataIndex) && e.dataFields.length > 1; const textFormat = "column" === e.area ? texts.sortColumnBySummary : texts.sortRowBySummary; const checked = (0, _m_widget_utils.findField)(e.dataFields, field.sortBySummaryField) === dataIndex && (e.cell.path || []).join("/") === (field.sortBySummaryPath || []).join("/"); const text = (0, _string.format)(textFormat, showDataFieldCaption ? `${field.caption} - ${dataField.caption}` : field.caption); items.push({ beginGroup: 0 === sortingBySummaryItemCount, icon: checked ? "desc" === field.sortOrder ? "sortdowntext" : "sortuptext" : "none", text: text, onItemClick() { dataSource.field(field.index, { sortBySummaryField: dataField.name || dataField.caption || dataField.dataField, sortBySummaryPath: e.cell.path, sortOrder: "desc" === field.sortOrder ? "asc" : "desc" }); dataSource.load() } }); sortingBySummaryItemCount += 1 }) }); (0, _iterator.each)(oppositeAreaFields, (_, field) => { if (!field.allowSortingBySummary || !(0, _type.isDefined)(field.sortBySummaryField)) { return } items.push({ beginGroup: 0 === sortingBySummaryItemCount, icon: "none", text: texts.removeAllSorting, onItemClick() { (0, _iterator.each)(oppositeAreaFields, (_, field) => { dataSource.field(field.index, { sortBySummaryField: void 0, sortBySummaryPath: void 0, sortOrder: void 0 }) }); dataSource.load() } }); return false }) } } if (that.option("fieldChooser.enabled")) { items.push({ beginGroup: true, icon: "columnchooser", text: texts.showFieldChooser, onItemClick() { that.getFieldChooserPopup().show() } }) } if (that.option("export.enabled")) { items.push({ beginGroup: true, icon: "xlsxfile", text: texts.exportToExcel, onItemClick() { that.exportTo() } }) } e.items = items; that._trigger("onContextMenuPreparing", e); items = e.items; if (items && items.length) { return items } return } _createEventArgs(targetElement, dxEvent) { const that = this; const dataSource = that.getDataSource(); const args = { rowFields: dataSource.getAreaFields("row"), columnFields: dataSource.getAreaFields("column"), dataFields: dataSource.getAreaFields("data"), event: dxEvent }; if (clickedOnFieldsArea((0, _renderer.default)(targetElement))) { return (0, _extend.extend)(that._createFieldArgs(targetElement), args) } return (0, _extend.extend)(that._createCellArgs(targetElement), args) } _createFieldArgs(targetElement) { const field = (0, _renderer.default)(targetElement).children().data("field"); const args = { field: field }; return (0, _type.isDefined)(field) ? args : {} } _createCellArgs(cellElement) { const $cellElement = (0, _renderer.default)(cellElement); const columnIndex = cellElement.cellIndex; const { rowIndex: rowIndex } = cellElement.parentElement; const $table = $cellElement.closest("table"); const data = $table.data("data"); const cell = data && data[rowIndex] && data[rowIndex][columnIndex]; const args = { area: $table.data("area"), rowIndex: rowIndex, columnIndex: columnIndex, cellElement: (0, _element.getPublicElement)($cellElement), cell: cell }; return args } _handleCellClick(e) { const that = this; const args = that._createEventArgs(e.currentTarget, e); const { cell: cell } = args; if (!cell || !args.area && (args.rowIndex || args.columnIndex)) { return } that._trigger("onCellClick", args); cell && !args.cancel && (0, _type.isDefined)(cell.expanded) && setTimeout(() => { that._dataController[cell.expanded ? "collapseHeaderItem" : "expandHeaderItem"](args.area, cell.path) }) } _getColumnsAreaNavigation() { this._columnsAreaNavigation = this._columnsAreaNavigation ?? new _roving_tab_index.RovingTabIndex({ component: this, getItems: () => this._getColumnHeaderCells(), scrollToItem: item => this._columnsArea.scrollToElement(item), getItemId: item => this._getHeaderCellId(item) }); return this._columnsAreaNavigation } _getHeaderCellId(cell) { const columnIndex = cell.getAttribute("aria-colindex"); const row = cell.parentElement; if (!columnIndex || !row) { return } return `${row.sectionRowIndex}:${columnIndex}` } _getRowsAreaNavigation() { this._rowsAreaNavigation = this._rowsAreaNavigation ?? new _roving_tab_index.RovingTabIndex({ component: this, getItems: () => this._getRowHeaderCells(), scrollToItem: item => this._rowsArea.scrollToElement(item), getItemId: item => this._getRowHeaderCellId(item) }); return this._rowsAreaNavigation } _getRowHeaderCellId(cell) { const rowIndex = cell.getAttribute("aria-rowindex"); const { cellIndex: cellIndex } = cell; if (!rowIndex || cellIndex < 0) { return } return `${cellIndex}:${rowIndex}` } _getHeaderAreaCells(cellSelector) { const element = this.$element().get(0); if (!element) { return [] } const cells = Array.from(element.querySelectorAll(cellSelector)); return cells.filter(cell => !cell.closest(`.${_const.FAKE_TABLE_CLASS}`)) } _getColumnHeaderCells() { return this._getHeaderAreaCells(`thead.${_const.HORIZONTAL_HEADERS_AREA_CLASS} td[tabindex]`) } _getRowHeaderCells() { return this._getHeaderAreaCells(`tbody.${_const.VERTICAL_HEADERS_AREA_CLASS} td[tabindex]`) } _getCellAreaNavigation(cell) { var _cell$closest, _cell$closest2, _cell$closest3; if (null !== (_cell$closest = cell.closest) && void 0 !== _cell$closest && _cell$closest.call(cell, `.${_const.FAKE_TABLE_CLASS}`)) { return } if (null !== (_cell$closest2 = cell.closest) && void 0 !== _cell$closest2 && _cell$closest2.call(cell, `thead.${_const.HORIZONTAL_HEADERS_AREA_CLASS}`)) { return this._getColumnsAreaNavigation() } if (null !== (_cell$closest3 = cell.closest) && void 0 !== _cell$closest3 && _cell$closest3.call(cell, `tbody.${_const.VERTICAL_HEADERS_AREA_CLASS}`)) { return this._getRowsAreaNavigation() } return } _normalizeCellNavigationDirection(direction) { if (!this.option("rtlEnabled")) { return direction } if ("left" === direction) { return "right" } if ("right" === direction) { return "left" } return direction } _handleCellArrowKeyDown(e, direction) { const cell = e.currentTarget; const navigation = this._getCellAreaNavigation(cell); if (!navigation) { return } e.preventDefault(); const section = cell.closest("thead, tbody"); const normalizedDirection = this._normalizeCellNavigationDirection(direction); let target = (0, _table_cell_navigation.getAdjacentCell)(section, cell, normalizedDirection); while (target && !target.hasAttribute("tabindex")) { target = (0, _table_cell_navigation.getAdjacentCell)(section, target, normalizedDirection) } if (target) { navigation.focusItem(target) } } _handleCellFocusIn(e) { var _this$_getCellAreaNav; null === (_this$_getCellAreaNav = this._getCellAreaNavigation(e.currentTarget)) || void 0 === _this$_getCellAreaNav || _this$_getCellAreaNav.handleFocusIn(e.currentTarget) } _handleCellContextMenuKeyDown(e) { const cell = e.currentTarget; const navigation = this._getCellAreaNavigation(cell); if (!navigation || !this._contextMenu) { return } this._contextMenu._show(e); if (this._contextMenu.option("visible")) { this._contextMenuOwnerNavigation = navigation } } _handleCellKeyDown(e) { const direction = ARROW_KEY_DIRECTIONS[e.key]; if (direction) { this._handleCellArrowKeyDown(e, direction); return } if (e.repeat) { return } if ("ContextMenu" === e.key || e.shiftKey && "F10" === e.key) { this._handleCellContextMenuKeyDown(e); return } if ("Enter" !== e.key && " " !== e.key) { return } const args = this._createEventArgs(e.currentTarget, e); const { cell: cell } = args; if (!cell || !(0, _type.isDefined)(cell.expanded)) { return } e.preventDefault(); this._trigger("onCellClick", args); if (args.cancel) { return } const $control = (0, _renderer.default)(e.currentTarget).find(".dx-expand-icon-container"); (0, _accessibility.saveFocusedElementInfo)($control.get(0), this); const onReady = () => { this.off("contentReady", onReady); (0, _accessibility.restoreFocus)(this) }; this.on("contentReady", onReady); setTimeout(() => { this._dataController[cell.expanded ? "collapseHeaderItem" : "expandHeaderItem"](args.area, cell.path) }) } _getNoDataText() { return this.option("texts.noData") } _renderNoDataText(element) { return _m_utils.default.renderNoDataText.call(this, element) } _renderLoadPanel(element, container) { return _m_utils.default.renderLoadPanel.call(this, element, container, void 0) } _updateLoading(progress) { const that = this; const isLoading = that._dataController.isLoading(); if (!that._loadPanel) { return } const loadPanelVisible = that._loadPanel.option("visible"); if (!loadPanelVisible) { that._startLoadingTime = new Date } if (isLoading) { if (progress) { if (new Date - that._startLoadingTime >= 1e3) { that._loadPanel.option("message", `${Math.floor(100*progress)}%`) } } else { that._loadPanel.option("message", that.option("loadPanel.text")) } } clearTimeout(that._hideLoadingTimeoutID); if (loadPanelVisible && !isLoading) { that._hideLoadingTimeoutID = setTimeout(() => { that._loadPanel.option("visible", false); that.$element().removeClass("dx-overflow-hidden") }) } else { const visibilityOptions = { visible: isLoading }; if (isLoading) { visibilityOptions.position = _m_utils.default.calculateLoadPanelPosition(that._dataArea.groupElement()) } that._loadPanel.option(visibilityOptions); that.$element().toggleClass("dx-overflow-hidden", !isLoading) } } _renderDescriptionArea() { const $element = this.$element(); const $descriptionCell = $element.find(".dx-area-description-cell"); const $toolbarContainer = (0, _renderer.default)(DIV).addClass("dx-pivotgrid-toolbar"); const fieldPanel = this.option("fieldPanel"); const $filterHeader = $element.find(".dx-filter-header"); const $columnHeader = $element.find(".dx-column-header"); let $targetContainer; let buttonStylingMode = (0, _themes.isGeneric)((0, _themes.current)()) ? "contained" : "text"; if (fieldPanel.visible && fieldPanel.showFilterFields) { $targetContainer = $filterHeader } else if (fieldPanel.visible && (fieldPanel.showDataFields || fieldPanel.showColumnFields)) { $targetContainer = $columnHeader } else { $targetContainer = $descriptionCell; buttonStylingMode = "text" } $columnHeader.toggleClass("dx-bottom-border", !!(fieldPanel.visible && (fieldPanel.showDataFields || fieldPanel.showColumnFields))); $filterHeader.toggleClass("dx-bottom-border", !!(fieldPanel.visible && fieldPanel.showFilterFields)); $descriptionCell.toggleClass("dx-pivotgrid-background", fieldPanel.visible && (fieldPanel.showDataFields || fieldPanel.showColumnFields || fieldPanel.showRowFields)); this.$element().find(".dx-pivotgrid-toolbar").remove(); $toolbarContainer.prependTo($targetContainer); if (this.option("fieldChooser.enabled")) { this.$fieldChooserButton = (0, _renderer.default)(DIV).appendTo($toolbarContainer).addClass("dx-pivotgrid-field-chooser-button"); const buttonOptions = { icon: "columnchooser", hint: this.option("texts.showFieldChooser"), elementAttr: { "aria-label": this.option("texts.showFieldChooser"), "aria-haspopup": "dialog" }, stylingMode: buttonStylingMode, onClick: () => { this.getFieldChooserPopup().show() } }; this._createComponent(this.$fieldChooserButton, _button.default, buttonOptions) } if (this.option("export.enabled")) { const $buttonElement = (0, _renderer.default)(DIV).appendTo($toolbarContainer).addClass("dx-pivotgrid-export-button"); const buttonOptions = { icon: "xlsxfile", hint: this.option("texts.exportToExcel"), stylingMode: buttonStylingMode, onClick: () => { this.exportTo() } }; this._createComponent($buttonElement, _button.default, buttonOptions) } } _detectHasContainerHeight() { const that = this; const element = that.$element(); if ((0, _type.isDefined)(that._hasHeight)) { const height = that.option("height") || that.$element().get(0).style.height; if (height && that._hasHeight ^ "auto" !== height) { that._hasHeight = null } } if ((0, _type.isDefined)(that._hasHeight) || element.is(":hidden")) { return } that._pivotGridContainer.addClass("dx-hidden"); const testElement = (0, _renderer.default)(DIV); (0, _size.setHeight)(testElement, 66666); element.append(testElement); that._hasHeight = 66666 !== (0, _size.getHeight)(element); that._pivotGridContainer.removeClass("dx-hidden"); testElement.remove() } _renderHeaders(rowHeaderContainer, columnHeaderContainer, filterHeaderContainer, dataHeaderContainer) { const dataSource = this.getDataSource(); this._rowFields = this._rowFields || new _m_fields_area.FieldsArea(this, "row"); this._rowFields.render(rowHeaderContainer, dataSource.getAreaFields("row")); this._columnFields = this._columnFields || new _m_fields_area.FieldsArea(this, "column"); this._columnFields.render(columnHeaderContainer, dataSource.getAreaFields("column")); this._filterFields = this._filterFields || new _m_fields_area.FieldsArea(this, "filter"); this._filterFields.render(filterHeaderContainer, dataSource.getAreaFields("filter")); this._dataFields = this._dataFields || new _m_fields_area.FieldsArea(this, "data"); this._dataFields.render(dataHeaderContainer, dataSource.getAreaFields("data")); const fieldChooser = this.$element().dxPivotGridFieldChooserBase("instance"); fieldChooser.renderSortable(); fieldChooser.restoreFieldFocus() } _createTableElement() { const $table = (0, _renderer.default)("<table>").attr("role", "presentation").css({ width: "100%" }).toggleClass(BORDERS_CLASS, !!this.option("showBorders")).toggleClass("dx-word-wrap", !!this.option("wordWrapEnabled")); _events_engine.default.on($table, (0, _index.addNamespace)(_click.name, "dxPivotGrid"), "td", this._handleCellClick.bind(this)); _events_engine.default.on($table, (0, _index.addNamespace)("keydown", "dxPivotGrid"), "td", this._handleCellKeyDown.bind(this)); _events_engine.default.on($table, (0, _index.addNamespace)("focusin", "dxPivotGrid"), "td", this._handleCellFocusIn.bind(this)); return $table } _renderDataArea(dataAreaElement) { const dataArea = this._dataArea || new _m_data_area.default.DataArea(this); this._dataArea = dataArea; dataArea.render(dataAreaElement, this._dataController.getCellsInfo()); return dataArea } _renderRowsArea(rowsAreaElement) { const that = this; const rowsArea = that._rowsArea || new _m_headers_area.default.VerticalHeadersArea(that); that._rowsArea = rowsArea; const navigation = that._getRowsAreaNavigation(); const needRestoreFocus = navigation.containsActiveElement(); rowsArea.render(rowsAreaElement, that._dataController.getRowsInfo()); navigation.updateTabIndexes(); if (needRestoreFocus) { navigation.refocusFocusedItem(); that._scheduleNavigationFocusRestore(navigation) } return rowsArea } _scheduleNavigationFocusRestore(navigation) { const onReady = () => { this.off("contentReady", onReady); if (!navigation.containsActiveElement()) { navigation.refocusFocusedItem() } }; this.on("contentReady", onReady) } _renderColumnsArea(columnsAreaElement) { const that = this; const columnsArea = that._columnsArea || new _m_headers_area.default.HorizontalHeadersArea(that); that._columnsArea = columnsArea; const navigation = that._getColumnsAreaNavigation(); const needRestoreFocus = navigation.containsActiveElement(); columnsArea.render(columnsAreaElement, that._dataController.getColumnsInfo()); navigation.updateTabIndexes(); if (needRestoreFocus) { navigation.refocusFocusedItem(); that._scheduleNavigationFocusRestore(navigation) } return columnsArea } _initMarkup() { super._initMarkup(); this.$element().addClass("dx-pivotgrid").attr("role", "group").attr("aria-label", _message.default.format("dxPivotGrid-ariaLabel")) } _renderContentImpl() { const that = this; let columnsAreaElement; let rowsAreaElement; let dataAreaElement; let tableElement; const isFirstDrawing = !that._pivotGridContainer; let rowHeaderContainer; let columnHeaderContainer; let filterHeaderContainer; let dataHeaderContainer; tableElement = !isFirstDrawing && that._tableElement(); if (!tableElement) { that.$element().addClass("dx-row-lines").addClass(FIELDS_CONTAINER_CLASS); that._pivotGridContainer = (0, _renderer.default)(DIV).addClass("dx-pivotgrid-container"); that._renderFieldChooser(); that._renderContextMenu(); columnsAreaElement = (0, _renderer.default)(TD).addClass("dx-area-column-cell"); rowsAreaElement = (0, _renderer.default)(TD).addClass("dx-area-row-cell"); dataAreaElement = (0, _renderer.default)(TD).addClass("dx-area-data-cell"); tableElement = that._createTableElement(); dataHeaderContainer = (0, _renderer.default)(TD).addClass("dx-data-header"); filterHeaderContainer = (0, _renderer.default)("<td>").attr("colspan", "2").addClass("dx-filter-header"); columnHeaderContainer = (0, _renderer.default)(TD).addClass("dx-column-header"); rowHeaderContainer = (0, _renderer.default)(TD).addClass("dx-area-description-cell"); (0, _renderer.default)(TR).append(filterHeaderContainer).appendTo(tableElement); (0, _renderer.default)(TR).append(dataHeaderContainer).append(columnHeaderContainer).appendTo(tableElement); (0, _renderer.default)(TR).append(rowHeaderContainer).append(columnsAreaElement).appendTo(tableElement); (0, _renderer.default)(TR).addClass("dx-bottom-row").append(rowsAreaElement).append(dataAreaElement).appendTo(tableElement); that._pivotGridContainer.append(tableElement); that.$element().append(that._pivotGridContainer); if ("tree" === that.option("rowHeaderLayout")) { rowsAreaElement.addClass("dx-area-tree-view") } } that.$element().addClass("dx-overflow-hidden"); const fieldChooserBaseConfig = { dataSource: that.getDataSource(), encodeHtml: that.option("encodeHtml"), allowFieldDragging: that.option("fieldPanel.allowFieldDragging"), headerFilter: that.option("headerFilter"), visible: that.option("visible"), remoteSort: "virtual" === that.option("scrolling.mode") }; if (that._fieldChooserBase) { that._fieldChooserBase.option(fieldChooserBaseConfig) } else { that._fieldChooserBase = that._createComponent(that.$element(), _m_field_chooser_base.FieldChooserBase, fieldChooserBaseConfig) }