devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
544 lines (537 loc) • 22.6 kB
JavaScript
/**
* DevExtreme (cjs/__internal/grids/pivot_grid/field_chooser/m_field_chooser.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 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.FieldChooser = void 0;
require("../data_source/m_data_source");
var _message = _interopRequireDefault(require("../../../../common/core/localization/message"));
var _component_registrator = _interopRequireDefault(require("../../../../core/component_registrator"));
var _renderer = _interopRequireDefault(require("../../../../core/renderer"));
var _extend = require("../../../../core/utils/extend");
var _icon = require("../../../../core/utils/icon");
var _iterator = require("../../../../core/utils/iterator");
var _type = require("../../../../core/utils/type");
var _window = require("../../../../core/utils/window");
var _context_menu = _interopRequireDefault(require("../../../../ui/context_menu"));
var _tree_view = _interopRequireDefault(require("../../../../ui/tree_view"));
var _m_widget_utils = require("../m_widget_utils");
var _const = require("./const");
var _m_field_chooser_base = require("./m_field_chooser_base");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
function _extends() {
return _extends = Object.assign ? Object.assign.bind() : function(n) {
for (var e = 1; e < arguments.length; e++) {
var t = arguments[e];
for (var r in t) {
({}).hasOwnProperty.call(t, r) && (n[r] = t[r])
}
}
return n
}, _extends.apply(null, arguments)
}
const DIV = "<div>";
const hasWindow = (0, _window.hasWindow)();
function getDimensionFields(item, fields) {
const result = [];
if (item.items) {
for (let i = 0; i < item.items.length; i += 1) {
result.push.apply(result, getDimensionFields(item.items[i], fields))
}
} else if ((0, _type.isDefined)(item.index)) {
result.push(fields[item.index])
}
return result
}
function getFirstItem(item, condition) {
if (item.items) {
for (let i = 0; i < item.items.length; i += 1) {
const childrenItem = getFirstItem(item.items[i], condition);
if (childrenItem) {
return childrenItem
}
}
}
if (condition(item)) {
return item
}
return
}
const compareOrder = [function(a, b) {
const aValue = -!!a.isMeasure;
const bValue = +!!b.isMeasure;
return aValue + bValue
}, function(a, b) {
const aValue = -!!(a.items && a.items.length);
const bValue = +!!(b.items && b.items.length);
return aValue + bValue
}, function(a, b) {
const aValue = +!!(false === a.isMeasure && a.field && a.field.levels && a.field.levels.length);
const bValue = -!!(false === b.isMeasure && b.field && b.field.levels && b.field.levels.length);
return aValue + bValue
}, (0, _m_widget_utils.getCompareFunction)((item => item.text))];
function compareItems(a, b) {
let result = 0;
let i = 0;
while (!result && compareOrder[i]) {
result = compareOrder[i++](a, b)
}
return result
}
function getScrollable(container) {
return container.find(`.${_const.CLASSES.scrollable.self}`).dxScrollable("instance")
}
class FieldChooser extends _m_field_chooser_base.FieldChooserBase {
_getDefaultOptions() {
return _extends({}, super._getDefaultOptions(), {
height: 400,
layout: 0,
dataSource: null,
encodeHtml: true,
onContextMenuPreparing: null,
allowSearch: false,
searchTimeout: 500,
texts: {
columnFields: _message.default.format("dxPivotGrid-columnFields"),
rowFields: _message.default.format("dxPivotGrid-rowFields"),
dataFields: _message.default.format("dxPivotGrid-dataFields"),
filterFields: _message.default.format("dxPivotGrid-filterFields"),
allFields: _message.default.format("dxPivotGrid-allFields")
}
})
}
_refreshDataSource() {
const that = this;
that._expandedPaths = [];
that._changedHandler = that._changedHandler || function() {
(0, _iterator.each)(that._dataChangedHandlers, ((_, func) => {
func()
}));
that._fireContentReadyAction();
that._skipStateChange = true;
that.option("state", that._dataSource.state());
that._skipStateChange = false
};
that._disposeDataSource();
super._refreshDataSource();
that._dataSource && that._dataSource.on("changed", that._changedHandler)
}
_disposeDataSource() {
const that = this;
const dataSource = that._dataSource;
if (dataSource) {
dataSource.off("changed", that._changedHandler);
that._dataSource = void 0
}
}
_dispose() {
this._disposeDataSource();
super._dispose.apply(this, arguments)
}
_init() {
super._init();
this._refreshDataSource();
this._dataChangedHandlers = [];
this._initActions()
}
_initActions() {
this._actions = {
onContextMenuPreparing: this._createActionByOption("onContextMenuPreparing")
}
}
_trigger(eventName, eventArg) {
this._actions[eventName](eventArg)
}
_setOptionsByReference() {
super._setOptionsByReference();
(0, _extend.extend)(this._optionsByReference, {
dataSource: true
})
}
_optionChanged(args) {
const that = this;
switch (args.name) {
case "dataSource":
that._refreshDataSource();
that._invalidate();
break;
case "layout":
case "texts":
case "allowSearch":
case "searchTimeout":
case "encodeHtml":
that._invalidate();
break;
case "onContextMenuPreparing":
that._actions[args.name] = that._createActionByOption(args.name);
break;
default:
super._optionChanged(args)
}
}
_clean(skipStateSetting) {
!skipStateSetting && this._dataSource && this.option("state", this._dataSource.state());
this.$element().children(`.${_const.CLASSES.fieldChooser.container}`).remove()
}
_renderLayout0($container) {
$container.addClass(_const.CLASSES.layout.zero);
const $row1 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.row).appendTo($container);
const $row2 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.row).appendTo($container);
const $col1 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.col).appendTo($row1);
const $col2 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.col).appendTo($row1);
const $col3 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.col).appendTo($row2);
const $col4 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.col).appendTo($row2);
this._renderArea($col1, "all");
this._renderArea($col2, "row");
this._renderArea($col2, "column");
this._renderArea($col3, "filter");
this._renderArea($col4, "data")
}
_renderLayout1($container) {
const $col1 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.col).appendTo($container);
const $col2 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.col).appendTo($container);
this._renderArea($col1, "all");
this._renderArea($col2, "filter");
this._renderArea($col2, "row");
this._renderArea($col2, "column");
this._renderArea($col2, "data")
}
_renderLayout2($container) {
$container.addClass(_const.CLASSES.layout.second);
const $row1 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.row).appendTo($container);
this._renderArea($row1, "all");
const $row2 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.row).appendTo($container);
const $col1 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.col).appendTo($row2);
const $col2 = (0, _renderer.default)(DIV).addClass(_const.CLASSES.col).appendTo($row2);
this._renderArea($col1, "filter");
this._renderArea($col1, "row");
this._renderArea($col2, "column");
this._renderArea($col2, "data")
}
_initMarkup() {
const that = this;
const $element = this.$element();
const $container = (0, _renderer.default)(DIV).addClass(_const.CLASSES.fieldChooser.container).appendTo($element);
const layout = that.option("layout");
super._initMarkup();
$element.addClass(_const.CLASSES.fieldChooser.self).addClass(_const.CLASSES.pivotGrid.fieldsContainer);
that._dataChangedHandlers = [];
const dataSource = this._dataSource;
const currentState = "instantly" !== that.option("applyChangesMode") && dataSource && dataSource.state();
currentState && that.option("state") && dataSource.state(that.option("state"), true);
if (0 === layout) {
that._renderLayout0($container)
} else if (1 === layout) {
that._renderLayout1($container)
} else {
that._renderLayout2($container)
}
currentState && dataSource.state(currentState, true)
}
_renderContentImpl() {
super._renderContentImpl();
this.renderSortable();
this._renderContextMenu();
this.updateDimensions()
}
_fireContentReadyAction() {
if (!this._dataSource || !this._dataSource.isLoading()) {
super._fireContentReadyAction()
}
}
_getContextMenuArgs(dxEvent) {
const targetFieldElement = (0, _renderer.default)(dxEvent.target).closest(`.${_const.CLASSES.area.field}`);
const targetGroupElement = (0, _renderer.default)(dxEvent.target).closest(`.${_const.CLASSES.area.fieldList}`);
let field;
let area;
if (targetFieldElement.length) {
const fieldCopy = targetFieldElement.data("field");
if (fieldCopy) {
field = this.getDataSource().field(fieldCopy.index) || fieldCopy
}
}
if (targetGroupElement.length) {
area = targetGroupElement.attr("group")
}
return {
event: dxEvent,
field: field,
area: area,
items: []
}
}
_renderContextMenu() {
const that = this;
const $container = that.$element();
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;
if (!event) {
return
}
const args = that._getContextMenuArgs(event);
that._trigger("onContextMenuPreparing", args);
if (args.items && args.items.length) {
actionArgs.component.option("items", args.items)
} else {
actionArgs.cancel = true
}
},
target: $container,
onItemClick(params) {
params.itemData.onItemClick && params.itemData.onItemClick(params)
},
cssClass: _const.CLASSES.fieldChooser.contextMenu
})
}
_createTreeItems(fields, groupFieldNames, path) {
const that = this;
let isMeasure;
let resultItems = [];
const groupedItems = [];
const groupFieldName = groupFieldNames[0];
const fieldsByGroup = {};
if (!groupFieldName) {
(0, _iterator.each)(fields, ((_, field) => {
let icon;
if (true === field.isMeasure) {
icon = _const.ICONS.measure
}
if (false === field.isMeasure) {
icon = field.groupName ? _const.ICONS.hierarchy : _const.ICONS.dimension
}
resultItems.push({
index: field.index,
field: field,
key: field.dataField,
selected: (0, _type.isDefined)(field.area),
text: field.caption || field.dataField,
icon: icon,
isMeasure: field.isMeasure,
isDefault: field.isDefault
})
}))
} else {
(0, _iterator.each)(fields, ((_, field) => {
const groupName = field[groupFieldName] || "";
fieldsByGroup[groupName] = fieldsByGroup[groupName] || [];
fieldsByGroup[groupName].push(field);
if (void 0 === isMeasure) {
isMeasure = true
}
isMeasure = isMeasure && true === field.isMeasure
}));
(0, _iterator.each)(fieldsByGroup, ((groupName, fields) => {
const currentPath = path ? `${path}.${groupName}` : groupName;
const items = that._createTreeItems(fields, groupFieldNames.slice(1), currentPath);
if (groupName) {
groupedItems.push({
key: groupName,
text: groupName,
path: currentPath,
isMeasure: items.isMeasure,
expanded: that._expandedPaths.includes(currentPath),
items: items
})
} else {
resultItems = items
}
}));
resultItems = groupedItems.concat(resultItems);
resultItems.isMeasure = isMeasure
}
return resultItems
}
_createFieldsDataSource(dataSource) {
let fields = dataSource && dataSource.fields() || [];
fields = fields.filter((field => false !== field.visible && !(0, _type.isDefined)(field.groupIndex)));
const treeItems = this._createTreeItems(fields, ["dimension", "displayFolder"]);
(0, _m_widget_utils.foreachDataLevel)(treeItems, (items => {
items.sort(compareItems)
}), 0, "items");
return treeItems
}
_renderFieldsTreeView(container) {
const that = this;
const dataSource = that._dataSource;
const treeView = that._createComponent(container, _tree_view.default, {
dataSource: that._createFieldsDataSource(dataSource),
showCheckBoxesMode: "normal",
expandNodesRecursive: false,
searchEnabled: that.option("allowSearch"),
searchTimeout: that.option("searchTimeout"),
useNativeScrolling: false,
itemTemplate(itemData, itemIndex, itemElement) {
const $item = (0, _renderer.default)("<div>").toggleClass(_const.CLASSES.area.field, !itemData.items).attr(_const.ATTRIBUTES.treeViewItem, true).data("field", itemData.field).appendTo(itemElement);
if (itemData.icon) {
var _getImageContainer;
null === (_getImageContainer = (0, _icon.getImageContainer)(itemData.icon)) || void 0 === _getImageContainer || _getImageContainer.appendTo($item)
}(0, _renderer.default)("<span>").text(itemData.text).appendTo($item)
},
onItemCollapsed(e) {
const index = that._expandedPaths.indexOf(e.itemData.path);
if (index >= 0) {
that._expandedPaths.splice(index, 1)
}
},
onItemExpanded(e) {
const index = that._expandedPaths.indexOf(e.itemData.path);
if (index < 0) {
that._expandedPaths.push(e.itemData.path)
}
},
onItemSelectionChanged(e) {
const data = e.itemData;
let field;
let fields;
let needSelectDefaultItem = true;
let area;
if (data.items) {
if (data.selected) {
treeView.unselectItem(data);
return
}
that._processDemandState((() => {
fields = getDimensionFields(data, dataSource.fields());
for (let i = 0; i < fields.length; i += 1) {
if (fields[i].area) {
needSelectDefaultItem = false;
break
}
}
}));
if (needSelectDefaultItem) {
const item = getFirstItem(data, (item => item.isDefault)) || getFirstItem(data, (item => (0, _type.isDefined)(item.index)));
item && treeView.selectItem(item);
return
}
} else {
field = dataSource.fields()[data.index];
if (data.selected) {
area = field.isMeasure ? "data" : "column"
}
if (field) {
fields = [field]
}
}
that._applyChanges(fields, {
area: area,
areaIndex: void 0
})
}
});
that._dataChangedHandlers.push((function() {
let scrollable = getScrollable(container);
const scrollTop = scrollable ? scrollable.scrollTop() : 0;
treeView.option({
dataSource: that._createFieldsDataSource(dataSource)
});
scrollable = getScrollable(container);
if (scrollable) {
scrollable.scrollTo({
y: scrollTop
});
scrollable.update()
}
}))
}
_renderAreaFields($container, area) {
const that = this;
const dataSource = that._dataSource;
const fields = dataSource ? (0, _extend.extend)(true, [], dataSource.getAreaFields(area, true)) : [];
$container.empty();
(0, _iterator.each)(fields, ((_, field) => {
if (false !== field.visible) {
that.renderField(field, true).appendTo($container)
}
}))
}
_renderArea(container, area) {
const that = this;
const $areaContainer = (0, _renderer.default)(DIV).addClass(_const.CLASSES.area.self).appendTo(container);
const $fieldsHeaderContainer = (0, _renderer.default)(DIV).addClass(_const.CLASSES.area.fieldListHeader).appendTo($areaContainer);
const caption = that.option(`texts.${area}Fields`);
let $fieldsContent;
let render;
(0, _renderer.default)("<span>").addClass(_const.CLASSES.area.icon).addClass(`dx-icon-${_const.ICONS[area]}`).appendTo($fieldsHeaderContainer);
(0, _renderer.default)("<span>").html(" ").appendTo($fieldsHeaderContainer);
(0, _renderer.default)("<span>").addClass(_const.CLASSES.area.caption).text(caption).appendTo($fieldsHeaderContainer);
const $fieldsContainer = (0, _renderer.default)(DIV).addClass(_const.CLASSES.area.fieldList).addClass(_const.CLASSES.pivotGrid.dragAction).appendTo($areaContainer);
if ("all" !== area) {
$fieldsContainer.attr("group", area).attr(_const.ATTRIBUTES.allowScrolling, true);
$fieldsContent = (0, _renderer.default)(DIV).addClass(_const.CLASSES.area.fieldContainer).appendTo($fieldsContainer);
render = function() {
that._renderAreaFields($fieldsContent, area)
};
that._dataChangedHandlers.push(render);
render();
$fieldsContainer.dxScrollable({
useNative: false
})
} else {
$areaContainer.addClass(_const.CLASSES.allFields);
$fieldsContainer.addClass(_const.CLASSES.treeView.borderVisible);
that._renderFieldsTreeView($fieldsContainer)
}
}
_getSortableOptions() {
return {
direction: ""
}
}
_adjustSortableOnChangedArgs() {}
resetTreeView() {
const treeView = this.$element().find(`.${_const.CLASSES.treeView.self}`).dxTreeView("instance");
if (treeView) {
treeView.option("searchValue", "");
treeView.collapseAll()
}
}
applyChanges() {
const state = this.option("state");
if ((0, _type.isDefined)(state)) {
this._dataSource.state(state)
}
}
cancelChanges() {
const dataSource = this._dataSource;
if (!dataSource.isLoading()) {
this.option("state", dataSource.state());
return true
}
return false
}
getDataSource() {
return this._dataSource
}
updateDimensions() {
const $scrollableElements = this.$element().find(`.${_const.CLASSES.area.self} .${_const.CLASSES.scrollable.self}`);
$scrollableElements.dxScrollable("update")
}
_visibilityChanged(visible) {
if (visible && hasWindow) {
this.updateDimensions()
}
}
}
exports.FieldChooser = FieldChooser;
(0, _component_registrator.default)("dxPivotGridFieldChooser", FieldChooser);
var _default = exports.default = {
FieldChooser: FieldChooser
};