devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,048 lines (1,025 loc) • 51 kB
JavaScript
/**
* DevExtreme (cjs/__internal/grids/pivot_grid/data_source/m_data_source.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.PivotGridDataSource = void 0;
var _utils = require("../../../../common/data/data_source/utils");
var _class = _interopRequireDefault(require("../../../../core/class"));
var _events_strategy = require("../../../../core/events_strategy");
var _array = require("../../../../core/utils/array");
var _deferred = require("../../../../core/utils/deferred");
var _extend = require("../../../../core/utils/extend");
var _iterator = require("../../../../core/utils/iterator");
var _type = require("../../../../core/utils/type");
var _abstract_store = _interopRequireDefault(require("../../../../data/abstract_store"));
var _m_common = _interopRequireDefault(require("../../../core/utils/m_common"));
var _m_inflector = _interopRequireDefault(require("../../../core/utils/m_inflector"));
var _m_local_store = require("../local_store/m_local_store");
var _m_widget_utils = require("../m_widget_utils");
var _m_remote_store = require("../remote_store/m_remote_store");
var _m_summary_display_modes = _interopRequireDefault(require("../summary_display_modes/m_summary_display_modes"));
var _m_xmla_store = _interopRequireDefault(require("../xmla_store/m_xmla_store"));
var _m_data_source_utils = require("./m_data_source_utils");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
const DESCRIPTION_NAME_BY_AREA = {
row: "rows",
column: "columns",
data: "values",
filter: "filters"
};
const STATE_PROPERTIES = ["area", "areaIndex", "sortOrder", "filterType", "filterValues", "sortBy", "sortBySummaryField", "sortBySummaryPath", "expanded", "summaryType", "summaryDisplayMode"];
const CALCULATED_PROPERTIES = ["format", "selector", "customizeText", "caption"];
const ALL_CALCULATED_PROPERTIES = CALCULATED_PROPERTIES.concat(["allowSorting", "allowSortingBySummary", "allowFiltering", "allowExpandAll"]);
function createCaption(field) {
let caption = field.dataField || field.groupName || "";
let summaryType = (field.summaryType || "").toLowerCase();
if ((0, _type.isString)(field.groupInterval)) {
caption += `_${field.groupInterval}`
}
if (summaryType && "custom" !== summaryType) {
summaryType = summaryType.replace(/^./, summaryType[0].toUpperCase());
if (caption.length) {
summaryType = ` (${summaryType})`
}
} else {
summaryType = ""
}
return _m_inflector.default.titleize(caption) + summaryType
}
function resetFieldState(field, properties) {
const initialProperties = field._initProperties || {};
(0, _iterator.each)(properties, ((_, prop) => {
if (Object.prototype.hasOwnProperty.call(initialProperties, prop)) {
field[prop] = initialProperties[prop]
}
}))
}
function updateCalculatedFieldProperties(field, calculatedProperties) {
resetFieldState(field, calculatedProperties);
if (!(0, _type.isDefined)(field.caption)) {
(0, _m_widget_utils.setFieldProperty)(field, "caption", createCaption(field))
}
}
function areExpressionsUsed(dataFields) {
return dataFields.some((field => field.summaryDisplayMode || field.calculateSummaryValue))
}
function isRunningTotalUsed(dataFields) {
return dataFields.some((field => !!field.runningTotal))
}
function isDataExists(data) {
return data.rows.length || data.columns.length || data.values.length
}
const PivotGridDataSource = exports.PivotGridDataSource = _class.default.inherit(function() {
const findHeaderItem = function(headerItems, path) {
if (headerItems._cacheByPath) {
return headerItems._cacheByPath[path.join(".")] || null
}
return
};
const getHeaderItemsLastIndex = function(headerItems, grandTotalIndex) {
let i;
let lastIndex = -1;
let headerItem;
if (headerItems) {
for (i = 0; i < headerItems.length; i += 1) {
headerItem = headerItems[i];
if (void 0 !== headerItem.index) {
lastIndex = Math.max(lastIndex, headerItem.index)
}
if (headerItem.children) {
lastIndex = Math.max(lastIndex, getHeaderItemsLastIndex(headerItem.children))
} else if (headerItem.collapsedChildren) {
lastIndex = Math.max(lastIndex, getHeaderItemsLastIndex(headerItem.collapsedChildren))
}
}
}
if ((0, _type.isDefined)(grandTotalIndex)) {
lastIndex = Math.max(lastIndex, grandTotalIndex)
}
return lastIndex
};
const updateHeaderItemChildren = function(headerItems, headerItem, children, grandTotalIndex) {
const applyingHeaderItemsCount = getHeaderItemsLastIndex(children) + 1;
let emptyIndex = getHeaderItemsLastIndex(headerItems, grandTotalIndex) + 1;
let index;
const applyingItemIndexesToCurrent = [];
let needIndexUpdate = false;
const d = new _deferred.Deferred;
if (headerItem.children && headerItem.children.length === children.length) {
for (let i = 0; i < children.length; i += 1) {
const child = children[i];
if (void 0 !== child.index) {
if (void 0 === headerItem.children[i].index) {
child.index = applyingItemIndexesToCurrent[child.index] = emptyIndex++;
headerItem.children[i] = child
} else {
applyingItemIndexesToCurrent[child.index] = headerItem.children[i].index
}
}
}
} else {
needIndexUpdate = true;
for (index = 0; index < applyingHeaderItemsCount; index += 1) {
applyingItemIndexesToCurrent[index] = emptyIndex++
}
headerItem.children = children
}(0, _deferred.when)((0, _m_widget_utils.foreachTreeAsync)(headerItem.children, (items => {
if (needIndexUpdate) {
items[0].index = applyingItemIndexesToCurrent[items[0].index]
}
}))).done((() => {
d.resolve(applyingItemIndexesToCurrent)
}));
return d
};
const updateHeaderItems = function(headerItems, newHeaderItems, grandTotalIndex) {
const d = new _deferred.Deferred;
let emptyIndex = grandTotalIndex >= 0 && getHeaderItemsLastIndex(headerItems, grandTotalIndex) + 1;
const applyingItemIndexesToCurrent = [];
(0, _deferred.when)((0, _m_widget_utils.foreachTreeAsync)(headerItems, (items => {
delete items[0].collapsedChildren
}))).done((() => {
(0, _deferred.when)((0, _m_widget_utils.foreachTreeAsync)(newHeaderItems, ((newItems, index) => {
const newItem = newItems[0];
if (newItem.index >= 0) {
let headerItem = findHeaderItem(headerItems, (0, _m_widget_utils.createPath)(newItems));
if (headerItem && headerItem.index >= 0) {
applyingItemIndexesToCurrent[newItem.index] = headerItem.index
} else if (emptyIndex) {
const path = (0, _m_widget_utils.createPath)(newItems.slice(1));
headerItem = findHeaderItem(headerItems, path);
const parentItems = path.length ? headerItem && headerItem.children : headerItems;
if (parentItems) {
parentItems[index] = newItem;
newItem.index = applyingItemIndexesToCurrent[newItem.index] = emptyIndex++
}
}
}
}))).done((() => {
d.resolve(applyingItemIndexesToCurrent)
}))
}));
return d
};
const updateDataSourceCells = function(dataSource, newDataSourceCells, newRowItemIndexesToCurrent, newColumnItemIndexesToCurrent) {
let newRowIndex;
let newColumnIndex;
let newRowCells;
let newCell;
let rowIndex;
let columnIndex;
const dataSourceCells = dataSource.values;
if (newDataSourceCells) {
for (newRowIndex = 0; newRowIndex < newDataSourceCells.length; newRowIndex += 1) {
newRowCells = newDataSourceCells[newRowIndex];
rowIndex = newRowItemIndexesToCurrent[newRowIndex];
if (!(0, _type.isDefined)(rowIndex)) {
rowIndex = dataSource.grandTotalRowIndex
}
if (newRowCells && (0, _type.isDefined)(rowIndex)) {
if (!dataSourceCells[rowIndex]) {
dataSourceCells[rowIndex] = []
}
for (newColumnIndex = 0; newColumnIndex < newRowCells.length; newColumnIndex += 1) {
newCell = newRowCells[newColumnIndex];
columnIndex = newColumnItemIndexesToCurrent[newColumnIndex];
if (!(0, _type.isDefined)(columnIndex)) {
columnIndex = dataSource.grandTotalColumnIndex
}
if ((0, _type.isDefined)(newCell) && (0, _type.isDefined)(columnIndex)) {
dataSourceCells[rowIndex][columnIndex] = newCell
}
}
}
}
}
};
function createLocalOrRemoteStore(dataSourceOptions, notifyProgress) {
const StoreConstructor = dataSourceOptions.remoteOperations || dataSourceOptions.paginate ? _m_remote_store.RemoteStore : _m_local_store.LocalStore;
return new StoreConstructor((0, _extend.extend)((0, _utils.normalizeDataSourceOptions)(dataSourceOptions), {
onChanged: null,
onLoadingChanged: null,
onProgressChanged: notifyProgress
}))
}
function getExpandedPaths(dataSource, loadOptions, dimensionName, prevLoadOptions) {
const result = [];
const fields = loadOptions && loadOptions[dimensionName] || [];
const prevFields = prevLoadOptions && prevLoadOptions[dimensionName] || [];
(0, _m_widget_utils.foreachTree)(dataSource[dimensionName], (items => {
const item = items[0];
const path = (0, _m_widget_utils.createPath)(items);
if (item.children && fields[path.length - 1] && !fields[path.length - 1].expanded) {
if (path.length < fields.length && (!prevLoadOptions || function(fields, prevFields, count) {
for (let i = 0; i < count; i += 1) {
if (!fields[i] || !prevFields[i] || fields[i].index !== prevFields[i].index) {
return false
}
}
return true
}(fields, prevFields, path.length))) {
result.push(path.slice())
}
}
}), true);
return result
}
function setFieldProperties(field, srcField, skipInitPropertySave, properties) {
if (srcField) {
(0, _iterator.each)(properties, ((_, name) => {
if (skipInitPropertySave) {
field[name] = srcField[name]
} else {
if (("summaryType" === name || "summaryDisplayMode" === name) && void 0 === srcField[name]) {
return
}(0, _m_widget_utils.setFieldProperty)(field, name, srcField[name])
}
}))
} else {
resetFieldState(field, properties)
}
return field
}
function getFieldsState(fields, properties) {
const result = [];
(0, _iterator.each)(fields, ((_, field) => {
result.push(setFieldProperties({
dataField: field.dataField,
name: field.name
}, field, true, properties))
}));
return result
}
function getFieldStateId(field) {
if (field.name) {
return field.name
}
return `${field.dataField}`
}
function getFieldsById(fields, id) {
const result = [];
(0, _iterator.each)(fields || [], ((_, field) => {
if (getFieldStateId(field) === id) {
result.push(field)
}
}));
return result
}
function setFieldsState(stateFields, fields) {
stateFields = stateFields || [];
const fieldsById = {};
let id;
(0, _iterator.each)(fields, ((_, field) => {
id = getFieldStateId(field);
if (!fieldsById[id]) {
fieldsById[id] = getFieldsById(fields, getFieldStateId(field))
}
}));
(0, _iterator.each)(fieldsById, ((id, fields) => {
! function(stateFields, fields) {
stateFields = stateFields || [];
(0, _iterator.each)(fields, ((index, field) => {
setFieldProperties(field, stateFields[index], false, STATE_PROPERTIES);
updateCalculatedFieldProperties(field, CALCULATED_PROPERTIES)
}));
return fields
}(getFieldsById(stateFields, id), fields)
}));
return fields
}
function sortFieldsByAreaIndex(fields) {
fields.sort(((field1, field2) => field1.areaIndex - field2.areaIndex || field1.groupIndex - field2.groupIndex))
}
function getFieldId(field, retrieveFieldsOptionValue) {
const groupName = field.groupName || "";
return (field.dataField || groupName) + (field.groupInterval ? groupName + field.groupInterval : "NOGROUP") + (retrieveFieldsOptionValue ? "" : groupName)
}
function mergeFields(fields, storeFields, retrieveFieldsOptionValue) {
let result = [];
const fieldsDictionary = {};
const removedFields = {};
const dataTypes = (0, _m_widget_utils.getFieldsDataType)(fields);
if (storeFields) {
(0, _iterator.each)(storeFields, ((_, field) => {
fieldsDictionary[getFieldId(field, retrieveFieldsOptionValue)] = field
}));
(0, _iterator.each)(fields, ((_, field) => {
const fieldKey = getFieldId(field, retrieveFieldsOptionValue);
const storeField = fieldsDictionary[fieldKey] || removedFields[fieldKey];
let mergedField;
if (storeField) {
if (storeField._initProperties) {
resetFieldState(storeField, ALL_CALCULATED_PROPERTIES)
}
mergedField = (0, _extend.extend)({}, storeField, field, {
_initProperties: null
})
} else {
fieldsDictionary[fieldKey] = mergedField = field
}
if (!mergedField.dataType && dataTypes[field.dataField]) {
mergedField.dataType = dataTypes[field.dataField]
}
delete fieldsDictionary[fieldKey];
removedFields[fieldKey] = storeField;
result.push(mergedField)
}));
if (retrieveFieldsOptionValue) {
(0, _iterator.each)(fieldsDictionary, ((_, field) => {
result.push(field)
}))
}
} else {
result = fields
}
result.push.apply(result, []);
! function(fields) {
fields.forEach((field => {
if (field.groupName && field.groupInterval && void 0 === field.groupIndex) {
const maxGroupIndex = fields.filter((f => f.groupName === field.groupName && (0, _type.isNumeric)(f.groupIndex))).map((f => f.groupIndex)).reduce(((prev, current) => Math.max(prev, current)), -1);
field.groupIndex = maxGroupIndex + 1
}
}))
}(result);
return result
}
function getFields(that) {
const result = new _deferred.Deferred;
const store = that._store;
const storeFields = store && store.getFields(that._fields);
let mergedFields;
(0, _deferred.when)(storeFields).done((storeFields => {
that._storeFields = storeFields;
mergedFields = mergeFields(that._fields, storeFields, that._retrieveFields);
result.resolve(mergedFields)
})).fail(result.reject);
return result
}
function formatHeaderItems(data, loadOptions, headerName) {
return (0, _m_widget_utils.foreachTreeAsync)(data[headerName], (items => {
const item = items[0];
item.text = item.text || (0, _m_widget_utils.formatValue)(item.value, loadOptions[headerName][(0, _m_widget_utils.createPath)(items).length - 1])
}))
}
function formatHeaders(loadOptions, data) {
return (0, _deferred.when)(formatHeaderItems(data, loadOptions, "columns"), formatHeaderItems(data, loadOptions, "rows"))
}
function updateCache(headerItems) {
const d = new _deferred.Deferred;
const cacheByPath = {};
(0, _deferred.when)((0, _m_widget_utils.foreachTreeAsync)(headerItems, (items => {
const path = (0, _m_widget_utils.createPath)(items).join(".");
cacheByPath[path] = items[0]
}))).done(d.resolve);
headerItems._cacheByPath = cacheByPath;
return d
}
function getAreaFields(fields, area) {
const areaFields = [];
(0, _iterator.each)(fields, (function() {
if (function(field, area) {
const canAddFieldInArea = "data" === area || false !== field.visible;
return field.area === area && !(0, _type.isDefined)(field.groupIndex) && canAddFieldInArea
}(this, area)) {
areaFields.push(this)
}
}));
return areaFields
}
return {
ctor(options) {
options = options || {};
this._eventsStrategy = new _events_strategy.EventsStrategy(this);
const that = this;
const store = function(dataSourceOptions, notifyProgress) {
let store;
let storeOptions;
if ((0, _type.isPlainObject)(dataSourceOptions) && dataSourceOptions.load) {
store = createLocalOrRemoteStore(dataSourceOptions, notifyProgress)
} else {
if (dataSourceOptions && !dataSourceOptions.store) {
dataSourceOptions = {
store: dataSourceOptions
}
}
storeOptions = dataSourceOptions.store;
if ("xmla" === storeOptions.type) {
store = new _m_xmla_store.default.XmlaStore(storeOptions)
} else if ((0, _type.isPlainObject)(storeOptions) && storeOptions.type || storeOptions instanceof _abstract_store.default || Array.isArray(storeOptions)) {
store = createLocalOrRemoteStore(dataSourceOptions, notifyProgress)
} else if (storeOptions instanceof _class.default) {
store = storeOptions
}
}
return store
}(options, (progress => {
that._eventsStrategy.fireEvent("progressChanged", [progress])
}));
that._store = store;
that._paginate = !!options.paginate;
that._pageSize = options.pageSize || 40;
that._data = {
rows: [],
columns: [],
values: []
};
that._loadingCount = 0;
that._isFieldsModified = false;
(0, _iterator.each)(["changed", "loadError", "loadingChanged", "progressChanged", "fieldsPrepared", "expandValueChanging"], ((_, eventName) => {
const optionName = `on${eventName[0].toUpperCase()}${eventName.slice(1)}`;
if (Object.prototype.hasOwnProperty.call(options, optionName)) {
this.on(eventName, options[optionName])
}
}));
that._retrieveFields = (0, _type.isDefined)(options.retrieveFields) ? options.retrieveFields : true;
that._fields = options.fields || [];
that._descriptions = options.descriptions ? (0, _extend.extend)(that._createDescriptions(), options.descriptions) : void 0;
if (!store) {
(0, _extend.extend)(true, that._data, options.store || options)
}
},
getData() {
return this._data
},
getAreaFields(area, collectGroups) {
let areaFields = [];
let descriptions;
if (collectGroups || "data" === area) {
areaFields = getAreaFields(this._fields, area);
sortFieldsByAreaIndex(areaFields)
} else {
descriptions = this._descriptions || {};
areaFields = descriptions[DESCRIPTION_NAME_BY_AREA[area]] || []
}
return areaFields
},
getSummaryFields() {
return this.getAreaFields("data").filter((field => (0, _type.isDefined)(field.summaryType)))
},
fields(fields) {
const that = this;
if (fields) {
that._fields = mergeFields(fields, that._storeFields, that._retrieveFields);
that._fieldsPrepared(that._fields)
}
return that._fields
},
field(id, options) {
const that = this;
const fields = that._fields;
const field = fields && fields[(0, _type.isNumeric)(id) ? id : (0, _m_widget_utils.findField)(fields, id)];
let levels;
if (field && options) {
(0, _iterator.each)(options, ((optionName, optionValue) => {
const isInitialization = !STATE_PROPERTIES.includes(optionName);
(0, _m_widget_utils.setFieldProperty)(field, optionName, optionValue, isInitialization);
if ("sortOrder" === optionName) {
levels = field.levels || [];
for (let i = 0; i < levels.length; i += 1) {
levels[i][optionName] = optionValue
}
}
}));
updateCalculatedFieldProperties(field, CALCULATED_PROPERTIES);
that._descriptions = that._createDescriptions(field);
that._isFieldsModified = true;
that._eventsStrategy.fireEvent("fieldChanged", [field])
}
return field
},
getFieldValues(index, applyFilters, options) {
const that = this;
const field = this._fields && this._fields[index];
const store = this.store();
const loadFields = [];
const loadOptions = {
columns: loadFields,
rows: [],
values: this.getAreaFields("data"),
filters: applyFilters ? this._fields.filter((f => f !== field && f.area && f.filterValues && f.filterValues.length)) : [],
skipValues: true
};
let searchValue;
const d = new _deferred.Deferred;
if (options) {
searchValue = options.searchValue;
loadOptions.columnSkip = options.skip;
loadOptions.columnTake = options.take
}
if (field && store) {
(0, _iterator.each)(field.levels || [field], (function() {
loadFields.push((0, _extend.extend)({}, this, {
expanded: true,
filterValues: null,
sortOrder: "asc",
sortBySummaryField: null,
searchValue: searchValue
}))
}));
store.load(loadOptions).done((data => {
if (loadOptions.columnSkip) {
data.columns = data.columns.slice(loadOptions.columnSkip)
}
if (loadOptions.columnTake) {
data.columns = data.columns.slice(0, loadOptions.columnTake)
}
formatHeaders(loadOptions, data);
if (!loadOptions.columnTake) {
that._sort(loadOptions, data)
}
d.resolve(data.columns)
})).fail(d)
} else {
d.reject()
}
return d
},
reload() {
return this.load({
reload: true
})
},
filter() {
const store = this._store;
return store.filter.apply(store, arguments)
},
load: function(options) {
const that = this;
const d = new _deferred.Deferred;
options = options || {};
that.beginLoading();
d.fail((e => {
that._eventsStrategy.fireEvent("loadError", [e])
})).always((() => {
that.endLoading()
}));
function loadTask() {
that._delayedLoadTask = void 0;
if (!that._descriptions) {
(0, _deferred.when)(getFields(that)).done((fields => {
that._fieldsPrepared(fields);
that._loadCore(options, d)
})).fail(d.reject).fail(that._loadErrorHandler)
} else {
that._loadCore(options, d)
}
}
if (that.store()) {
that._delayedLoadTask = _m_common.default.executeAsync(loadTask)
} else {
loadTask()
}
return d
},
createDrillDownDataSource(params) {
return this._store.createDrillDownDataSource(this._descriptions, params)
},
_createDescriptions(currentField) {
const fields = this.fields();
const descriptions = {
rows: [],
columns: [],
values: [],
filters: []
};
(0, _iterator.each)(["row", "column", "data", "filter"], ((_, areaName) => {
(0, _array.normalizeIndexes)(getAreaFields(fields, areaName), "areaIndex", currentField)
}));
(0, _iterator.each)(fields || [], ((_, field) => {
const descriptionName = DESCRIPTION_NAME_BY_AREA[field.area];
const dimension = descriptions[descriptionName];
const {
groupName: groupName
} = field;
if (groupName && !(0, _type.isNumeric)(field.groupIndex)) {
field.levels = function(fields, groupingField) {
return fields.filter((field => field.groupName === groupingField.groupName && (0, _type.isNumeric)(field.groupIndex) && false !== field.visible)).map((field => (0, _extend.extend)(field, {
areaIndex: groupingField.areaIndex,
area: groupingField.area,
expanded: (0, _type.isDefined)(field.expanded) ? field.expanded : groupingField.expanded,
dataField: field.dataField || groupingField.dataField,
dataType: field.dataType || groupingField.dataType,
sortBy: field.sortBy || groupingField.sortBy,
sortOrder: field.sortOrder || groupingField.sortOrder,
sortBySummaryField: field.sortBySummaryField || groupingField.sortBySummaryField,
sortBySummaryPath: field.sortBySummaryPath || groupingField.sortBySummaryPath,
visible: field.visible || groupingField.visible,
showTotals: (0, _type.isDefined)(field.showTotals) ? field.showTotals : groupingField.showTotals,
showGrandTotals: (0, _type.isDefined)(field.showGrandTotals) ? field.showGrandTotals : groupingField.showGrandTotals
}))).sort(((a, b) => a.groupIndex - b.groupIndex))
}(fields, field)
}
if (!dimension || groupName && (0, _type.isNumeric)(field.groupIndex) || false === field.visible && "data" !== field.area && "filter" !== field.area) {
return
}
if (field.levels && dimension !== descriptions.filters && dimension !== descriptions.values) {
dimension.push.apply(dimension, field.levels);
if (field.filterValues && field.filterValues.length) {
descriptions.filters.push(field)
}
} else {
dimension.push(field)
}
}));
(0, _iterator.each)(descriptions, ((_, fields) => {
sortFieldsByAreaIndex(fields)
}));
const indices = {};
(0, _iterator.each)(descriptions.values, ((_, field) => {
const expression = field.calculateSummaryValue;
if ((0, _type.isFunction)(expression)) {
const summaryCell = _m_summary_display_modes.default.createMockSummaryCell(descriptions, fields, indices);
expression(summaryCell)
}
}));
return descriptions
},
_fieldsPrepared(fields) {
this._fields = fields;
(0, _iterator.each)(fields, ((index, field) => {
field.index = index;
updateCalculatedFieldProperties(field, ALL_CALCULATED_PROPERTIES)
}));
const currentFieldState = getFieldsState(fields, ["caption"]);
this._eventsStrategy.fireEvent("fieldsPrepared", [fields]);
for (let i = 0; i < fields.length; i += 1) {
if (fields[i].caption !== currentFieldState[i].caption) {
(0, _m_widget_utils.setFieldProperty)(fields[i], "caption", fields[i].caption, true)
}
}
this._descriptions = this._createDescriptions()
},
isLoading() {
return this._loadingCount > 0
},
state(state, skipLoading) {
const that = this;
if (arguments.length) {
state = (0, _extend.extend)({
rowExpandedPaths: [],
columnExpandedPaths: []
}, state);
if (!that._descriptions) {
that.beginLoading();
(0, _deferred.when)(getFields(that)).done((fields => {
that._fields = setFieldsState(state.fields, fields);
that._fieldsPrepared(fields);
!skipLoading && that.load(state)
})).always((() => {
that.endLoading()
}))
} else {
that._fields = setFieldsState(state.fields, that._fields);
that._descriptions = that._createDescriptions();
!skipLoading && that.load(state)
}
return
}
return {
fields: getFieldsState(that._fields, STATE_PROPERTIES),
columnExpandedPaths: getExpandedPaths(that._data, that._descriptions, "columns", that._lastLoadOptions),
rowExpandedPaths: getExpandedPaths(that._data, that._descriptions, "rows", that._lastLoadOptions)
}
},
beginLoading() {
this._changeLoadingCount(1)
},
endLoading() {
this._changeLoadingCount(-1)
},
_changeLoadingCount(increment) {
const oldLoading = this.isLoading();
this._loadingCount += increment;
const newLoading = this.isLoading();
if (oldLoading ^ newLoading) {
this._eventsStrategy.fireEvent("loadingChanged", [newLoading])
}
},
_hasPagingValues(options, area, oppositeIndex) {
const takeField = `${area}Take`;
const skipField = `${area}Skip`;
const {
values: values
} = this._data;
let items = this._data[`${area}s`];
const oppositeArea = "row" === area ? "column" : "row";
const indices = [];
if (options.path && options.area === area) {
const headerItem = findHeaderItem(items, options.path);
items = headerItem && headerItem.children;
if (!items) {
return false
}
}
if (options.oppositePath && options.area === oppositeArea) {
const headerItem = findHeaderItem(items, options.oppositePath);
items = headerItem && headerItem.children;
if (!items) {
return false
}
}
for (let i = options[skipField]; i < options[skipField] + options[takeField]; i += 1) {
if (items[i]) {
indices.push(items[i].index)
}
}
return indices.every((index => {
if (void 0 !== index) {
if ("row" === area) {
return (values[index] || [])[oppositeIndex]
}
return (values[oppositeIndex] || [])[index]
}
return
}))
},
_processPagingCacheByArea(options, pageSize, area) {
const takeField = `${area}Take`;
const skipField = `${area}Skip`;
let items = this._data[`${area}s`];
const oppositeArea = "row" === area ? "column" : "row";
let item;
if (options[takeField]) {
if (options.path && options.area === area) {
const headerItem = findHeaderItem(items, options.path);
items = headerItem && headerItem.children || []
}
if (options.oppositePath && options.area === oppositeArea) {
const headerItem = findHeaderItem(items, options.oppositePath);
items = headerItem && headerItem.children || []
}
do {
item = items[options[skipField]];
if (item && void 0 !== item.index) {
if (this._hasPagingValues(options, oppositeArea, item.index)) {
options[skipField]++;
options[takeField]--
} else {
break
}
}
} while (item && void 0 !== item.index && options[takeField]);
if (options[takeField]) {
const start = Math.floor(options[skipField] / pageSize) * pageSize;
const end = Math.ceil((options[skipField] + options[takeField]) / pageSize) * pageSize;
options[skipField] = start;
options[takeField] = end - start
}
}
},
_processPagingCache(storeLoadOptions) {
const pageSize = this._pageSize;
if (pageSize < 0) {
return
}
for (let i = 0; i < storeLoadOptions.length; i += 1) {
this._processPagingCacheByArea(storeLoadOptions[i], pageSize, "row");
this._processPagingCacheByArea(storeLoadOptions[i], pageSize, "column")
}
},
_loadCore(options, deferred) {
const that = this;
const store = this._store;
const descriptions = this._descriptions;
const reload = options.reload || this.paginate() && that._isFieldsModified;
const paginate = this.paginate();
const headerName = DESCRIPTION_NAME_BY_AREA[options.area];
options = options || {};
if (store) {
(0, _extend.extend)(options, descriptions);
options.columnExpandedPaths = options.columnExpandedPaths || getExpandedPaths(this._data, options, "columns", that._lastLoadOptions);
options.rowExpandedPaths = options.rowExpandedPaths || getExpandedPaths(this._data, options, "rows", that._lastLoadOptions);
if (paginate) {
options.pageSize = this._pageSize
}
if (headerName) {
options.headerName = headerName
}
that.beginLoading();
deferred.always((() => {
that.endLoading()
}));
let storeLoadOptions = [options];
that._eventsStrategy.fireEvent("customizeStoreLoadOptions", [storeLoadOptions, reload]);
if (!reload) {
that._processPagingCache(storeLoadOptions)
}
storeLoadOptions = storeLoadOptions.filter((options => !(options.rows.length && 0 === options.rowTake) && !(options.columns.length && 0 === options.columnTake)));
if (!storeLoadOptions.length) {
that._update(deferred);
return
}
const results = storeLoadOptions.map((options => store.load(options)));
_deferred.when.apply(null, results).done((function() {
const results = arguments;
for (let i = 0; i < results.length; i += 1) {
const options = storeLoadOptions[i];
const data = results[i];
const isLast = i === results.length - 1;
if (options.path) {
that.applyPartialDataSource(options.area, options.path, data, isLast ? deferred : false, options.oppositePath)
} else if (paginate && !reload && isDataExists(that._data)) {
that.mergePartialDataSource(data, isLast ? deferred : false)
} else {
(0, _extend.extend)(that._data, data);
that._lastLoadOptions = options;
that._update(isLast ? deferred : false)
}
}
})).fail(deferred.reject)
} else {
that._update(deferred)
}
},
_sort(descriptions, data, getAscOrder) {
const store = this._store;
if (store && !this._paginate) {
(0, _m_data_source_utils.sort)(descriptions, data, getAscOrder)
}
},
sortLocal() {
this._sort(this._descriptions, this._data);
this._eventsStrategy.fireEvent("changed")
},
paginate() {
return this._paginate && this._store && this._store.supportPaging()
},
isEmpty() {
const dataFields = this.getAreaFields("data").filter((f => false !== f.visible));
const data = this.getData();
return !dataFields.length || !data.values.length
},
_update(deferred) {
const that = this;
const descriptions = that._descriptions;
const loadedData = that._data;
const dataFields = descriptions.values;
const expressionsUsed = areExpressionsUsed(dataFields);
(0, _deferred.when)(formatHeaders(descriptions, loadedData), updateCache(loadedData.rows), updateCache(loadedData.columns)).done((() => {
if (expressionsUsed) {
that._sort(descriptions, loadedData, expressionsUsed);
!that.isEmpty() && _m_summary_display_modes.default.applyDisplaySummaryMode(descriptions, loadedData)
}
that._sort(descriptions, loadedData);
!that.isEmpty() && isRunningTotalUsed(dataFields) && _m_summary_display_modes.default.applyRunningTotal(descriptions, loadedData);
that._data = loadedData;
false !== deferred && (0, _deferred.when)(deferred).done((() => {
that._isFieldsModified = false;
that._eventsStrategy.fireEvent("changed");
if ((0, _type.isDefined)(that._data.grandTotalRowIndex)) {
loadedData.grandTotalRowIndex = that._data.grandTotalRowIndex
}
if ((0, _type.isDefined)(that._data.grandTotalColumnIndex)) {
loadedData.grandTotalColumnIndex = that._data.grandTotalColumnIndex
}
}));
deferred && deferred.resolve(that._data)
}));
return deferred
},
store() {
return this._store
},
collapseHeaderItem(area, path) {
const that = this;
const headerItems = "column" === area ? that._data.columns : that._data.rows;
const headerItem = findHeaderItem(headerItems, path);
const field = that.getAreaFields(area)[path.length - 1];
if (headerItem && headerItem.children) {
that._eventsStrategy.fireEvent("expandValueChanging", [{
area: area,
path: path,
expanded: false
}]);
if (field) {
field.expanded = false
}
headerItem.collapsedChildren = headerItem.children;
delete headerItem.children;
that._update();
if (that.paginate()) {
that.load()
}
return true
}
return false
},
collapseAll(id) {
let dataChanged = false;
const field = this.field(id) || {};
let areaOffsets = [this.getAreaFields(field.area).indexOf(field)];
field.expanded = false;
if (field && field.levels) {
areaOffsets = [];
field.levels.forEach((f => {
areaOffsets.push(this.getAreaFields(field.area).indexOf(f));
f.expanded = false
}))
}(0, _m_widget_utils.foreachTree)(this._data[`${field.area}s`], (items => {
const item = items[0];
const path = (0, _m_widget_utils.createPath)(items);
if (item && item.children && areaOffsets.includes(path.length - 1)) {
item.collapsedChildren = item.children;
delete item.children;
dataChanged = true
}
}), true);
dataChanged && this._update()
},
expandAll(id) {
const field = this.field(id);
if (field && field.area) {
field.expanded = true;
if (field && field.levels) {
field.levels.forEach((f => {
f.expanded = true
}))
}
this.load()
}
},
expandHeaderItem(area, path) {
const that = this;
const headerItems = "column" === area ? that._data.columns : that._data.rows;
const headerItem = findHeaderItem(headerItems, path);
if (headerItem && !headerItem.children) {
const hasCache = !!headerItem.collapsedChildren;
const options = {
area: area,
path: path,
expanded: true,
needExpandData: !hasCache
};
that._eventsStrategy.fireEvent("expandValueChanging", [options]);
if (hasCache) {
headerItem.children = headerItem.collapsedChildren;
delete headerItem.collapsedChildren;
that._update()
} else if (this.store()) {
that.load(options)
}
return hasCache
}
return false
},
mergePartialDataSource(dataSource, deferred) {
const that = this;
const loadedData = that._data;
let newRowItemIndexesToCurrent;
let newColumnItemIndexesToCurrent;
if (dataSource && dataSource.values) {
dataSource.rows = dataSource.rows || [];
dataSource.columns = dataSource.columns || [];
newRowItemIndexesToCurrent = updateHeaderItems(loadedData.rows, dataSource.rows, loadedData.grandTotalColumnIndex);
newColumnItemIndexesToCurrent = updateHeaderItems(loadedData.columns, dataSource.columns, loadedData.grandTotalColumnIndex);
(0, _deferred.when)(newRowItemIndexesToCurrent, newColumnItemIndexesToCurrent).done(((newRowItemIndexesToCurrent, newColumnItemIndexesToCurrent) => {
if (newRowItemIndexesToCurrent.length || newColumnItemIndexesToCurrent.length) {
updateDataSourceCells(loadedData, dataSource.values, newRowItemIndexesToCurrent, newColumnItemIndexesToCurrent)
}
that._update(deferred)
}))
}
},
applyPartialDataSource(area, path, dataSource, deferred, oppositePath) {
const that = this;
const loadedData = that._data;
const headerItems = "column" === area ? loadedData.columns : loadedData.rows;
let headerItem;
const oppositeHeaderItems = "column" === area ? loadedData.rows : loadedData.columns;
let oppositeHeaderItem;
let newRowItemIndexesToCurrent;
let newColumnItemIndexesToCurrent;
if (dataSource && dataSource.values) {
dataSource.rows = dataSource.rows || [];
dataSource.columns = dataSource.columns || [];
headerItem = findHeaderItem(headerItems, path);
oppositeHeaderItem = oppositePath && findHeaderItem(oppositeHeaderItems, oppositePath);
if (headerItem) {
if ("column" === area) {
newColumnItemIndexesToCurrent = updateHeaderItemChildren(headerItems, headerItem, dataSource.columns, loadedData.grandTotalColumnIndex);
if (oppositeHeaderItem) {
newRowItemIndexesToCurrent = updateHeaderItemChildren(oppositeHeaderItems, oppositeHeaderItem, dataSource.rows, loadedData.grandTotalRowIndex)
} else {
newRowItemIndexesToCurrent = updateHeaderItems(loadedData.rows, dataSource.rows, loadedData.grandTotalRowIndex)
}
} else {
newRowItemIndexesToCurrent = updateHeaderItemChildren(headerItems, headerItem, dataSource.rows, loadedData.grandTotalRowIndex);
if (oppositeHeaderItem) {
newColumnItemIndexesToCurrent = updateHeaderItemChildren(oppositeHeaderItems, oppositeHeaderItem, dataSource.columns, loadedData.grandTotalColumnIndex)
} else {
newColumnItemIndexesToCurrent = updateHeaderItems(loadedData.columns, dataSource.columns, loadedData.grandTotalColumnIndex)
}
}(0, _deferred.when)(newRowItemIndexesToCurrent, newColumnItemIndexesToCurrent).done(((newRowItemIndexesToCurrent, newColumnItemIndexesToCurrent) => {
if ("row" === area && newRowItemIndexesToCurrent.length || "column" === area && newColumnItemIndexesToCurrent.len