UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,371 lines (1,209 loc) • 56 kB
"use strict"; var DataSourceModule = require("../../data/data_source/data_source"), Store = require("../../data/abstract_store"), commonUtils = require("../../core/utils/common"), typeUtils = require("../../core/utils/type"), extend = require("../../core/utils/extend").extend, inArray = require("../../core/utils/array").inArray, iteratorUtils = require("../../core/utils/iterator"), isDefined = typeUtils.isDefined, each = iteratorUtils.each, deferredUtils = require("../../core/utils/deferred"), when = deferredUtils.when, Deferred = deferredUtils.Deferred, Class = require("../../core/class"), EventsMixin = require("../../core/events_mixin"), inflector = require("../../core/utils/inflector"), normalizeIndexes = require("../../core/utils/array").normalizeIndexes, localStore = require("./local_store"), RemoteStore = require("./remote_store"), xmlaStore = require("./xmla_store/xmla_store"), summaryDisplayModes = require("./ui.pivot_grid.summary_display_modes"), pivotGridUtils = require("./ui.pivot_grid.utils"), foreachTree = pivotGridUtils.foreachTree, foreachTreeAsync = pivotGridUtils.foreachTreeAsync, findField = pivotGridUtils.findField, formatValue = pivotGridUtils.formatValue, getCompareFunction = pivotGridUtils.getCompareFunction, createPath = pivotGridUtils.createPath, foreachDataLevel = pivotGridUtils.foreachDataLevel, setFieldProperty = pivotGridUtils.setFieldProperty, DESCRIPTION_NAME_BY_AREA = { row: "rows", column: "columns", data: "values", filter: "filters" }, STATE_PROPERTIES = ["area", "areaIndex", "sortOrder", "filterType", "filterValues", "sortBy", "sortBySummaryField", "sortBySummaryPath", "expanded", "summaryType", "summaryDisplayMode"], CALCULATED_PROPERTIES = ["format", "selector", "customizeText", "caption"], ALL_CALCULATED_PROPERTIES = CALCULATED_PROPERTIES.concat(["allowSorting", "allowSortingBySummary", "allowFiltering", "allowExpandAll"]); function createCaption(field) { var caption = field.dataField || field.groupName || "", summaryType = (field.summaryType || "").toLowerCase(); if (typeUtils.isString(field.groupInterval)) { caption += "_" + field.groupInterval; } if (summaryType && summaryType !== "custom") { summaryType = summaryType.replace(/^./, summaryType[0].toUpperCase()); if (caption.length) { summaryType = " (" + summaryType + ")"; } } else { summaryType = ""; } return inflector.titleize(caption) + summaryType; } function resetFieldState(field, properties) { var initialProperties = field._initProperties || {}; iteratorUtils.each(properties, function (_, prop) { if (initialProperties.hasOwnProperty(prop)) { field[prop] = initialProperties[prop]; } }); } function updateCalculatedFieldProperties(field, calculatedProperties) { resetFieldState(field, calculatedProperties); if (!isDefined(field.caption)) { setFieldProperty(field, "caption", createCaption(field)); } } function areExpressionsUsed(dataFields) { return dataFields.some(function (field) { return field.summaryDisplayMode || field.calculateSummaryValue; }); } function isRunningTotalUsed(dataFields) { return dataFields.some(function (field) { return !!field.runningTotal; }); } module.exports = Class.inherit(function () { var findHeaderItem = function findHeaderItem(headerItems, path) { if (headerItems._cacheByPath) { return headerItems._cacheByPath[path.join(".")] || null; } }; var getHeaderItemsLastIndex = function getHeaderItemsLastIndex(headerItems, grandTotalIndex) { var i, lastIndex = -1, headerItem; if (headerItems) { for (i = 0; i < headerItems.length; i++) { headerItem = headerItems[i]; lastIndex = Math.max(lastIndex, headerItem.index); if (headerItem.children) { lastIndex = Math.max(lastIndex, getHeaderItemsLastIndex(headerItem.children)); } else if (headerItem.collapsedChildren) { // B232736 lastIndex = Math.max(lastIndex, getHeaderItemsLastIndex(headerItem.collapsedChildren)); } } } if (isDefined(grandTotalIndex)) { lastIndex = Math.max(lastIndex, grandTotalIndex); } return lastIndex; }; var updateHeaderItemChildren = function updateHeaderItemChildren(headerItems, headerItem, children, grandTotalIndex) { var applyingHeaderItemsCount = getHeaderItemsLastIndex(children) + 1, emptyIndex = getHeaderItemsLastIndex(headerItems, grandTotalIndex) + 1, index, applyingItemIndexesToCurrent = [], d = new Deferred(); for (index = 0; index < applyingHeaderItemsCount; index++) { applyingItemIndexesToCurrent[index] = emptyIndex++; } headerItem.children = children; when(foreachTreeAsync(headerItem.children, function (items) { items[0].index = applyingItemIndexesToCurrent[items[0].index]; })).done(function () { d.resolve(applyingItemIndexesToCurrent); }); return d; }; var updateHeaderItems = function updateHeaderItems(headerItems, newHeaderItems) { var d = new Deferred(); var applyingItemIndexesToCurrent = []; // reset cache when(foreachTreeAsync(headerItems, function (items) { delete items[0].collapsedChildren; })).done(function () { when(foreachTreeAsync(newHeaderItems, function (items) { var headerItem = findHeaderItem(headerItems, createPath(items)); if (headerItem) { applyingItemIndexesToCurrent[items[0].index] = headerItem.index; } })).done(function () { d.resolve(applyingItemIndexesToCurrent); }); }); return d; }; var updateDataSourceCells = function updateDataSourceCells(dataSource, newDataSourceCells, newRowItemIndexesToCurrent, newColumnItemIndexesToCurrent) { var newRowIndex, newColumnIndex, newRowCells, newCell, rowIndex, columnIndex, dataSourceCells = dataSource.values, isNewDataSourceNotEmpty = newRowItemIndexesToCurrent.length + newColumnItemIndexesToCurrent.length; if (newDataSourceCells && isNewDataSourceNotEmpty) { for (newRowIndex = 0; newRowIndex <= newDataSourceCells.length; newRowIndex++) { newRowCells = newDataSourceCells[newRowIndex]; rowIndex = newRowItemIndexesToCurrent[newRowIndex]; if (!isDefined(rowIndex)) { rowIndex = dataSource.grandTotalRowIndex; } if (newRowCells && isDefined(rowIndex)) { if (!dataSourceCells[rowIndex]) { dataSourceCells[rowIndex] = []; } for (newColumnIndex = 0; newColumnIndex <= newRowCells.length; newColumnIndex++) { newCell = newRowCells[newColumnIndex]; columnIndex = newColumnItemIndexesToCurrent[newColumnIndex]; if (!isDefined(columnIndex)) { columnIndex = dataSource.grandTotalColumnIndex; } if (isDefined(newCell) && isDefined(columnIndex)) { dataSourceCells[rowIndex][columnIndex] = newCell; } } } } } }; function createLocalOrRemoteStore(dataSourceOptions, notifyProgress) { var StoreConstructor = dataSourceOptions.remoteOperations ? RemoteStore : localStore.LocalStore; return new StoreConstructor(extend(DataSourceModule.normalizeDataSourceOptions(dataSourceOptions), { onChanged: null, onLoadingChanged: null, onProgressChanged: notifyProgress })); } function createStore(dataSourceOptions, notifyProgress) { var store, storeOptions; if (typeUtils.isPlainObject(dataSourceOptions) && dataSourceOptions.load) { store = createLocalOrRemoteStore(dataSourceOptions, notifyProgress); } else { // TODO remove if (dataSourceOptions && !dataSourceOptions.store) { dataSourceOptions = { store: dataSourceOptions }; } storeOptions = dataSourceOptions.store; if (storeOptions.type === "xmla") { store = new xmlaStore.XmlaStore(storeOptions); } else if (typeUtils.isPlainObject(storeOptions) && storeOptions.type || storeOptions instanceof Store || Array.isArray(storeOptions)) { store = createLocalOrRemoteStore(dataSourceOptions, notifyProgress); } else if (storeOptions instanceof Class) { store = storeOptions; } } return store; } function equalFields(fields, prevFields, count) { for (var i = 0; i < count; i++) { if (!fields[i] || !prevFields[i] || fields[i].index !== prevFields[i].index) { return false; } } return true; } function getExpandedPaths(dataSource, loadOptions, dimensionName, prevLoadOptions) { var result = [], fields = loadOptions && loadOptions[dimensionName] || [], prevFields = prevLoadOptions && prevLoadOptions[dimensionName] || []; foreachTree(dataSource[dimensionName], function (items) { var item = items[0], path = createPath(items); if (item.children && fields[path.length - 1] && !fields[path.length - 1].expanded) { if (path.length < fields.length && (!prevLoadOptions || equalFields(fields, prevFields, path.length))) { result.push(path.slice()); } } }, true); return result; } function setFieldProperties(field, srcField, skipInitPropertySave, properties) { if (srcField) { each(properties, function (_, name) { if (skipInitPropertySave) { field[name] = srcField[name]; } else { if ((name === "summaryType" || name === "summaryDisplayMode") && srcField[name] === undefined) { // T399271 return; } setFieldProperty(field, name, srcField[name]); } }); } else { resetFieldState(field, properties); } return field; } function getFieldsState(fields, properties) { var result = []; each(fields, function (_, 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) { var result = []; each(fields || [], function (_, field) { if (getFieldStateId(field) === id) { result.push(field); } }); return result; } function setFieldsStateCore(stateFields, fields) { stateFields = stateFields || []; each(fields, function (index, field) { setFieldProperties(field, stateFields[index], false, STATE_PROPERTIES); updateCalculatedFieldProperties(field, CALCULATED_PROPERTIES); }); return fields; } function setFieldsState(stateFields, fields) { stateFields = stateFields || []; var fieldsById = {}, id; each(fields, function (_, field) { id = getFieldStateId(field); if (!fieldsById[id]) { fieldsById[id] = getFieldsById(fields, getFieldStateId(field)); } }); each(fieldsById, function (id, fields) { setFieldsStateCore(getFieldsById(stateFields, id), fields); }); return fields; } function getFieldsByGroup(fields, groupingField) { return iteratorUtils.map(fields, function (field) { if (field.groupName === groupingField.groupName && typeUtils.isNumeric(field.groupIndex) && field.visible !== false) { return extend(field, { areaIndex: groupingField.areaIndex, area: groupingField.area, expanded: 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: isDefined(field.showTotals) ? field.showTotals : groupingField.showTotals, showGrandTotals: isDefined(field.showGrandTotals) ? field.showGrandTotals : groupingField.showGrandTotals }); } return null; }).sort(function (a, b) { return a.groupIndex - b.groupIndex; }); } function sortFieldsByAreaIndex(fields) { fields.sort(function (field1, field2) { return field1.areaIndex - field2.areaIndex || field1.groupIndex - field2.groupIndex; }); } function isAreaField(field, area) { var canAddFieldInArea = area === "data" || field.visible !== false; return field.area === area && !isDefined(field.groupIndex) && canAddFieldInArea; } function getFieldId(field, retrieveFieldsOptionValue) { var groupName = field.groupName || ""; return (field.dataField || groupName) + (field.groupInterval ? groupName + field.groupInterval : "NOGROUP") + (retrieveFieldsOptionValue ? "" : groupName); } function mergeFields(fields, storeFields, retrieveFieldsOptionValue) { var result = [], fieldsDictionary = {}, removedFields = {}, mergedGroups = [], dataTypes = pivotGridUtils.getFieldsDataType(fields); if (storeFields) { each(storeFields, function (_, field) { fieldsDictionary[getFieldId(field, retrieveFieldsOptionValue)] = field; }); each(fields, function (_, field) { var fieldKey = getFieldId(field, retrieveFieldsOptionValue), storeField = fieldsDictionary[fieldKey] || removedFields[fieldKey], mergedField; if (storeField) { if (storeField._initProperties) { resetFieldState(storeField, ALL_CALCULATED_PROPERTIES); } mergedField = extend({}, storeField, field, { _initProperties: null }); } else { fieldsDictionary[fieldKey] = mergedField = field; } extend(mergedField, { dataType: dataTypes[field.dataField] }); delete fieldsDictionary[fieldKey]; removedFields[fieldKey] = storeField; result.push(mergedField); }); if (retrieveFieldsOptionValue) { each(fieldsDictionary, function (_, field) { result.push(field); }); } } else { result = fields; } result.push.apply(result, mergedGroups); return result; } function getFields(that) { var result = new Deferred(), store = that._store, storeFields = store && store.getFields(that._fields), mergedFields; when(storeFields).done(function (storeFields) { that._storeFields = storeFields; mergedFields = mergeFields(that._fields, storeFields, that._retrieveFields); result.resolve(mergedFields); }).fail(function () { result.resolve(that._fields); }); return result; } function getSliceIndex(items, path) { var index = null, pathValue = (path || []).join("."); if (pathValue.length) { foreachTree(items, function (items) { var item = items[0], itemPath = createPath(items).join("."), textPath = iteratorUtils.map(items, function (item) { return item.text; }).reverse().join("."); if (pathValue === itemPath || item.key && textPath === pathValue) { index = items[0].index; return false; } }); } return index; } function getFieldSummaryValueSelector(field, dataSource, loadOptions, dimensionName) { var values = dataSource.values, sortBySummaryFieldIndex = findField(loadOptions.values, field.sortBySummaryField), areRows = dimensionName === "rows", sortByDimension = areRows ? dataSource.columns : dataSource.rows, grandTotalIndex = areRows ? dataSource.grandTotalRowIndex : dataSource.grandTotalColumnIndex, sortBySummaryPath = field.sortBySummaryPath || [], sliceIndex = sortBySummaryPath.length ? getSliceIndex(sortByDimension, sortBySummaryPath) : grandTotalIndex; if (values && values.length && sortBySummaryFieldIndex >= 0 && isDefined(sliceIndex)) { return function (field) { var rowIndex = areRows ? field.index : sliceIndex, columnIndex = areRows ? sliceIndex : field.index, value = ((values[rowIndex] || [[]])[columnIndex] || [])[sortBySummaryFieldIndex]; return isDefined(value) ? value : null; }; } } function getMemberForSortBy(sortBy, getAscOrder) { var member = "text"; if (sortBy === "none") { member = "index"; } else if (getAscOrder || sortBy !== "displayText") { member = "value"; } return member; } function getSortingMethod(field, dataSource, loadOptions, dimensionName, getAscOrder) { var sortOrder = getAscOrder ? "asc" : field.sortOrder, sortBy = getMemberForSortBy(field.sortBy, getAscOrder), defaultCompare = field.sortingMethod ? function (a, b) { return field.sortingMethod(a, b); } : getCompareFunction(function (item) { return item[sortBy]; }), summaryValueSelector = !getAscOrder && getFieldSummaryValueSelector(field, dataSource, loadOptions, dimensionName), summaryCompare = summaryValueSelector && getCompareFunction(summaryValueSelector), sortingMethod = function sortingMethod(a, b) { var result = summaryCompare && summaryCompare(a, b) || defaultCompare(a, b); return sortOrder === "desc" ? -result : result; }; return sortingMethod; } function sortDimension(dataSource, loadOptions, dimensionName, getAscOrder) { var fields = loadOptions[dimensionName] || [], baseIndex = loadOptions.headerName === dimensionName ? loadOptions.path.length : 0, sortingMethodByLevel = []; foreachDataLevel(dataSource[dimensionName], function (item, index) { var field = fields[index] || {}, sortingMethod = sortingMethodByLevel[index] = sortingMethodByLevel[index] || getSortingMethod(field, dataSource, loadOptions, dimensionName, getAscOrder); item.sort(sortingMethod); }, baseIndex); } function sort(loadOptions, dataSource, getAscOrder) { sortDimension(dataSource, loadOptions, "rows", getAscOrder); sortDimension(dataSource, loadOptions, "columns", getAscOrder); } function formatHeaderItems(data, loadOptions, headerName) { return foreachTreeAsync(data[headerName], function (items) { var item = items[0]; item.text = item.text || formatValue(item.value, loadOptions[headerName][createPath(items).length - 1]); }); } function formatHeaders(loadOptions, data) { return when(formatHeaderItems(data, loadOptions, "columns"), formatHeaderItems(data, loadOptions, "rows")); } function updateCache(headerItems) { var d = new Deferred(); var cacheByPath = {}; when(foreachTreeAsync(headerItems, function (items) { var path = createPath(items).join("."); cacheByPath[path] = items[0]; })).done(d.resolve); headerItems._cacheByPath = cacheByPath; return d; } function _getAreaFields(fields, area) { var areaFields = []; each(fields, function () { if (isAreaField(this, area)) { areaFields.push(this); } }); return areaFields; } ///#DEBUG exports.sort = sort; ///#ENDDEBUG /** * @name PivotGridDataSource * @publicName PivotGridDataSource * @type object * @inherits EventsMixin * @namespace DevExpress.data * @module ui/pivot_grid/data_source * @export default */ return { ctor: function ctor(options) { options = options || {}; var that = this, store = createStore(options, function (progress) { that.fireEvent("progressChanged", [progress]); }); /** * @name PivotGridDataSourceOptions.store * @publicName store * @type Store|StoreOptions|XmlaStore|XmlaStoreOptions|Array<Object>|Object */ /** * @name PivotGridDataSourceOptions.store.type * @publicName type * @type Enums.PivotGridStoreType */ that._store = store; that._data = { rows: [], columns: [], values: [] }; that._loadingCount = 0; /** * @name PivotGridDataSourceOptions.onChanged * @publicName onChanged * @type function * @action */ /** * @name PivotGridDataSourceOptions.onLoadingChanged * @publicName onLoadingChanged * @type function(isLoading) * @type_function_param1 isLoading:boolean * @action */ /** * @name PivotGridDataSourceOptions.onLoadError * @publicName onLoadError * @type function(error) * @type_function_param1 error:Object * @action */ /** * @name PivotGridDataSourceOptions.onFieldsPrepared * @publicName onFieldsPrepared * @type function(fields) * @type_function_param1 fields:Array<PivotGridDataSourceOptions.fields> * @action */ each(["changed", "loadError", "loadingChanged", "progressChanged", "fieldsPrepared", "expandValueChanging"], function (_, eventName) { var optionName = "on" + eventName[0].toUpperCase() + eventName.slice(1); if (options.hasOwnProperty(optionName)) { this.on(eventName, options[optionName]); } }.bind(this)); /** * @name PivotGridDataSourceOptions.retrieveFields * @publicName retrieveFields * @type boolean * @default true */ that._retrieveFields = isDefined(options.retrieveFields) ? options.retrieveFields : true; /** * @name PivotGridDataSourceOptions.filter * @publicName filter * @type Filter expression */ /** * @name PivotGridDataSourceOptions.remoteOperations * @publicName remoteOperations * @type boolean * @default false */ /** * @name PivotGridDataSourceOptions.fields * @publicName fields * @namespace DevExpress.data * @type Array<Object> * @default undefined */ that._fields = options.fields || []; /** * @name PivotGridDataSourceOptions.fields.index * @publicName index * @type number * @default undefined * @hidden */ /** * @name PivotGridDataSourceOptions.fields.dataField * @publicName dataField * @type string * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.caption * @publicName caption * @type string * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.dataType * @publicName dataType * @type Enums.PivotGridDataType * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.groupInterval * @publicName groupInterval * @type Enums.PivotGridGroupInterval|number * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.summaryType * @publicName summaryType * @type Enums.SummaryType * @default 'count' */ /** * @name PivotGridDataSourceOptions.fields.calculateCustomSummary * @publicName calculateCustomSummary * @type function(options) * @type_function_param1 options:object * @type_function_param1_field1 summaryProcess:string * @type_function_param1_field2 value:any * @type_function_param1_field3 totalValue:any */ /** * @name PivotGridDataSourceOptions.fields.selector * @publicName selector * @type function(data) * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.area * @publicName area * @type Enums.PivotGridArea * @default undefined * @acceptValues undefined */ /** * @name PivotGridDataSourceOptions.fields.areaIndex * @publicName areaIndex * @type number * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.visible * @publicName visible * @type boolean * @default true */ /** * @name PivotGridDataSourceOptions.fields.displayFolder * @publicName displayFolder * @type string * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.groupName * @publicName groupName * @type string * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.groupIndex * @publicName groupIndex * @type number * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.sortOrder * @publicName sortOrder * @type Enums.SortOrder * @default 'asc' */ /** * @name PivotGridDataSourceOptions.fields.sortBy * @publicName sortBy * @type Enums.PivotGridSortBy * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.sortingMethod * @publicName sortingMethod * @type function(a, b) * @type_function_param1 a:object * @type_function_param1_field1 value:string|number * @type_function_param1_field2 children:Array<any> * @type_function_param2 b:object * @type_function_param2_field1 value:string|number * @type_function_param2_field2 children:Array<any> * @type_function_return number * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.sortBySummaryField * @publicName sortBySummaryField * @type string * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.sortBySummaryPath * @publicName sortBySummaryPath * @type Array<number,string> * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.filterValues * @publicName filterValues * @type Array<any> * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.filterType * @publicName filterType * @type Enums.FilterType * @default 'include' */ /** * @name PivotGridDataSourceOptions.fields.expanded * @publicName expanded * @type boolean * @default false */ /** * @name PivotGridDataSourceOptions.fields.isMeasure * @publicName isMeasure * @type boolean * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.format * @publicName format * @type format * @default '' */ /** * @name PivotGridDataSourceOptions.fields.customizeText * @publicName customizeText * @type function(cellInfo) * @type_function_param1 cellInfo:object * @type_function_param1_field1 value:string|number|date * @type_function_param1_field2 valueText:string * @type_function_return string */ /** * @name PivotGridDataSourceOptions.fields.precision * @publicName precision * @type number * @default undefined * @deprecated */ /** * @name PivotGridDataSourceOptions.fields.allowSorting * @publicName allowSorting * @type boolean * @default false */ /** * @name PivotGridDataSourceOptions.fields.allowSortingBySummary * @publicName allowSortingBySummary * @type boolean * @default false */ /** * @name PivotGridDataSourceOptions.fields.allowFiltering * @publicName allowFiltering * @type boolean * @default false */ /** * @name PivotGridDataSourceOptions.fields.allowExpandAll * @publicName allowExpandAll * @type boolean * @default false */ /** * @name PivotGridDataSourceOptions.fields.width * @publicName width * @type number * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.summaryDisplayMode * @publicName summaryDisplayMode * @type Enums.PivotGridSummaryDisplayMode * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.runningTotal * @publicName runningTotal * @type Enums.PivotGridRunningTotalMode * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.wordWrapEnabled * @publicName wordWrapEnabled * @type boolean * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.allowCrossGroupCalculation * @publicName allowCrossGroupCalculation * @type boolean * @default false */ /** * @name PivotGridDataSourceOptions.fields.calculateSummaryValue * @publicName calculateSummaryValue * @type function(e) * @type_function_param1 e:dxPivotGridSummaryCell * @type_function_return number * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.showTotals * @publicName showTotals * @type boolean * @default true */ /** * @name PivotGridDataSourceOptions.fields.showGrandTotals * @publicName showGrandTotals * @type boolean * @default true */ /** * @name PivotGridDataSourceOptions.fields.showValues * @publicName showValues * @type boolean * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.headerFilter * @publicName headerFilter * @type object */ /** * @name PivotGridDataSourceOptions.fields.headerFilter.width * @publicName width * @type number * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.headerFilter.height * @publicName height * @type number * @default undefined */ /** * @name PivotGridDataSourceOptions.fields.headerFilter.allowSearch * @publicName allowSearch * @type boolean * @default undefined */ that._descriptions = options.descriptions ? extend(that._createDescriptions(), options.descriptions) : undefined; if (!store) { // TODO create dashboard store extend(true, that._data, options.store || options); } }, /** * @name PivotGridDataSourceMethods.getData * @publicName getData() * @return object */ getData: function getData() { return this._data; }, /** * @name PivotGridDataSourceMethods.getAreaFields * @publicName getAreaFields(area, collectGroups) * @param1 area:string * @param2 collectGroups:boolean * @return Array<PivotGridDataSourceOptions.fields> */ getAreaFields: function getAreaFields(area, collectGroups) { var areaFields = [], descriptions; if (collectGroups || area === "data") { areaFields = _getAreaFields(this._fields, area); sortFieldsByAreaIndex(areaFields); } else { descriptions = this._descriptions || {}; areaFields = descriptions[DESCRIPTION_NAME_BY_AREA[area]] || []; } return areaFields; }, /** * @name PivotGridDataSourceMethods.fields * @publicName fields() * @return Array<PivotGridDataSourceOptions.fields> */ /** * @name PivotGridDataSourceMethods.fields * @publicName fields(fields) * @param1 fields:Array<PivotGridDataSourceOptions.fields> */ fields: function fields(_fields) { var that = this; if (_fields) { that._fields = mergeFields(_fields, that._storeFields, that._retrieveFields); that._fieldsPrepared(that._fields); } return that._fields; }, /** * @name PivotGridDataSourceMethods.field * @publicName field(id) * @param1 id:number|string * @return object */ /** * @name PivotGridDataSourceMethods.field * @publicName field(id, options) * @param1 id:number|string * @param2 options:object */ field: function field(id, options) { var that = this, fields = that._fields, field = fields && fields[typeUtils.isNumeric(id) ? id : findField(fields, id)], levels; if (field && options) { each(options, function (optionName, optionValue) { var isInitialization = inArray(optionName, STATE_PROPERTIES) < 0; setFieldProperty(field, optionName, optionValue, isInitialization); if (optionName === "sortOrder") { levels = field.levels || []; for (var i = 0; i < levels.length; i++) { levels[i][optionName] = optionValue; } } }); updateCalculatedFieldProperties(field, CALCULATED_PROPERTIES); that._descriptions = that._createDescriptions(field); } return field; }, getFieldValues: function getFieldValues(index) { var that = this, field = this._fields && this._fields[index], store = this.store(), loadFields = [], loadOptions = { columns: loadFields, rows: [], values: this.getAreaFields("data"), filters: [], skipValues: true }, d = new Deferred(); if (field && store) { each(field.levels || [field], function () { loadFields.push(extend({}, this, { expanded: true, filterValues: null, sortOrder: 'asc', sortBySummaryField: null })); }); store.load(loadOptions).done(function (data) { formatHeaders(loadOptions, data); that._sort(loadOptions, data); d.resolve(data.columns); }).fail(d); } else { d.reject(); } return d; }, /** * @name PivotGridDataSourceMethods.reload * @publicName reload() * @return Promise<any> */ reload: function reload() { return this.load({ reload: true }); }, /** * @name PivotGridDataSourceMethods.filter * @publicName filter() * @return object */ /** * @name PivotGridDataSourceMethods.filter * @publicName filter(filterExpr) * @param1 filterExpr:object */ filter: function filter() { var store = this._store; return store.filter.apply(store, arguments); }, /** * @name PivotGridDataSourceMethods.load * @publicName load() * @return Promise<any> */ load: function load(options) { var that = this, d = new Deferred(); options = options || {}; that.beginLoading(); d.fail(function (e) { that.fireEvent("loadError", [e]); }).always(function () { that.endLoading(); }); function loadTask() { that._delayedLoadTask = undefined; if (!that._descriptions) { when(getFields(that)).done(function (fields) { that._fieldsPrepared(fields); that._loadCore(options, d); }).fail(d.reject).fail(that._loadErrorHandler); } else { that._loadCore(options, d); } } if (that.store()) { that._delayedLoadTask = commonUtils.executeAsync(loadTask); } else { loadTask(); } return d; }, /** * @name PivotGridDataSourceMethods.createDrillDownDataSource * @publicName createDrillDownDataSource(options) * @param1 options:object * @param1_field1 columnPath:Array<string, number, Date> * @param1_field2 rowPath:Array<string, number, Date> * @param1_field3 dataIndex:number * @param1_field4 maxRowCount:number * @param1_field5 customColumns:Array<string> * @return DataSource */ createDrillDownDataSource: function createDrillDownDataSource(params) { return this._store.createDrillDownDataSource(this._descriptions, params); }, _createDescriptions: function _createDescriptions(currentField) { var that = this, fields = that.fields(), descriptions = { rows: [], columns: [], values: [], filters: [] }; each(["row", "column", "data", "filter"], function (_, areaName) { normalizeIndexes(_getAreaFields(fields, areaName), 'areaIndex', currentField); }); each(fields || [], function (_, field) { var descriptionName = DESCRIPTION_NAME_BY_AREA[field.area], dimension = descriptions[descriptionName], groupName = field.groupName; if (groupName && !typeUtils.isNumeric(field.groupIndex)) { field.levels = getFieldsByGroup(fields, field); } if (!dimension || groupName && typeUtils.isNumeric(field.groupIndex) || field.visible === false && field.area !== "data" && field.area !== "filter") { 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); } }); each(descriptions, function (_, fields) { sortFieldsByAreaIndex(fields); }); var indices = {}; each(descriptions.values, function (_, field) { var expression = field.calculateSummaryValue; if (typeUtils.isFunction(expression)) { var summaryCell = summaryDisplayModes.createMockSummaryCell(descriptions, fields, indices); expression(summaryCell); } }); return descriptions; }, _fieldsPrepared: function _fieldsPrepared(fields) { var that = this; that._fields = fields; each(fields, function (index, field) { field.index = index; updateCalculatedFieldProperties(field, ALL_CALCULATED_PROPERTIES); }); var currentFieldState = getFieldsState(fields, ["caption"]); that.fireEvent("fieldsPrepared", [fields]); for (var i = 0; i < fields.length; i++) { if (fields[i].caption !== currentFieldState[i].caption) { setFieldProperty(fields[i], "caption", fields[i].caption, true); } } that._descriptions = that._createDescriptions(); }, /** * @name PivotGridDataSourceMethods.isLoading * @publicName isLoading() * @return boolean */ isLoading: function isLoading() { return this._loadingCount > 0; }, /** * @name PivotGridDataSourceMethods.state * @publicName state() * @return object */ /** * @name PivotGridDataSourceMethods.state * @publicName state(state) * @param1 state:object */ state: function state(_state, skipLoading) { var that = this; if (arguments.length) { _state = extend({ rowExpandedPaths: [], columnExpandedPaths: [] }, _state); if (!that._descriptions) { that.beginLoading(); when(getFields(that)).done(function (fields) { that._fields = setFieldsState(_state.fields, fields); that._fieldsPrepared(fields); !skipLoading && that.load(_state); }).always(function () { that.endLoading(); }); } else { that._fields = setFieldsState(_state.fields, that._fields); that._descriptions = that._createDescriptions(); !skipLoading && that.load(_state); } } else { return { fields: getFieldsState(that._fields, STATE_PROPERTIES), columnExpandedPaths: getExpandedPaths(that._data, that._descriptions, "columns"), rowExpandedPaths: getExpandedPaths(that._data, that._descriptions, "rows") }; } }, beginLoading: function beginLoading() { this._changeLoadingCount(1); }, endLoading: function endLoading() { this._changeLoadingCount(-1); }, _changeLoadingCount: function _changeLoadingCount(increment) { var oldLoading = this.isLoading(), newLoading; this._loadingCount += increment; newLoading = this.isLoading(); if (oldLoading ^ newLoading) { this.fireEvent("loadingChanged", [newLoading]); } }, _loadCore: function _loadCore(options, deferred) { var that = this, store = this._store, descriptions = this._descriptions, headerName = DESCRIPTION_NAME_BY_AREA[options.area]; options = options || {}; if (store) { 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 (headerName) { options.headerName = headerName; } that.beginLoading(); deferred.always(function () { that.endLoading(); }); when(store.load(options)).done(function (data) { if (options.path) { that.applyPartialDataSource(options.area, options.path, data, deferred); } else { extend(that._data, data); that._lastLoadOptions = options; that._update(deferred); } }).fail(deferred.reject); } else { that._update(deferred); } }, _sort: function _sort(descriptions, data, getAscOrder) { var store = this._store; if (store) { sort(descriptions, data, getAscOrder); } }, _update: function _update(deferred) { var that = this, descriptions = that._descriptions, loadedData = that._data, dataFields = descriptions.values, expressionsUsed = areExpressionsUsed(dataFields); when(formatHeaders(descriptions, loadedData), updateCache(loadedData.rows), updateCache(loadedData.columns)).done(function () { if (expressionsUsed) { that._sort(descriptions, loadedData, expressionsUsed); summaryDisplayModes.applyDisplaySummaryMode(descriptions, loadedData); } that._sort(descriptions, loadedData); isRunningTotalUsed(dataFields) && summaryDisplayModes.applyRunningTotal(descriptions, loadedData); that._data = loadedData; when(deferred).done(function () { that.fireEvent("changed"); if (isDefined(that._data.grandTotalRowIndex)) { loadedData.grandTotalRowIndex = that._data.grandTotalRowIndex; } if (isDefined(that._data.grandTotalColumnIndex)) { loadedData.grandTotalColumnIndex = that._data.grandTotalColumnIndex; } });