UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

519 lines (416 loc) • 17.7 kB
"use strict"; var Class = require("../../core/class"), grep = require("../../core/utils/common").grep, isDefined = require("../../core/utils/type").isDefined, extend = require("../../core/utils/extend").extend, each = require("../../core/utils/iterator").each, DataSourceModule = require("../../data/data_source/data_source"), deferredUtils = require("../../core/utils/deferred"), when = deferredUtils.when, Deferred = deferredUtils.Deferred, pivotGridUtils = require("./ui.pivot_grid.utils"), getFiltersByPath = pivotGridUtils.getFiltersByPath; function createGroupingOptions(dimensionOptions) { var groupingOptions = []; each(dimensionOptions, function (index, dimensionOption) { groupingOptions.push({ selector: dimensionOption.dataField, groupInterval: dimensionOption.groupInterval, isExpanded: index < dimensionOptions.length - 1 }); }); return groupingOptions; } function getFieldFilterSelector(field) { var selector = field.dataField, groupInterval = field.groupInterval; if (field.dataType === "date" && typeof groupInterval === "string") { if (groupInterval.toLowerCase() === "quarter") { groupInterval = "Month"; } selector = selector + "." + pivotGridUtils.capitalizeFirstLetter(groupInterval); } return selector; } function getIntervalFilterExpression(selector, numericInterval, numericValue, isExcludedFilterType) { var startFilterValue = [selector, isExcludedFilterType ? "<" : ">=", numericValue], endFilterValue = [selector, isExcludedFilterType ? ">=" : "<", numericValue + numericInterval]; return [startFilterValue, isExcludedFilterType ? "or" : "and", endFilterValue]; } function getFilterExpressionForFilterValue(field, filterValue) { var selector = getFieldFilterSelector(field), isExcludedFilterType = field.filterType === "exclude", expression = [selector, isExcludedFilterType ? "<>" : "=", filterValue]; if (isDefined(field.groupInterval)) { if (typeof field.groupInterval === "string" && field.groupInterval.toLowerCase() === "quarter") { expression = getIntervalFilterExpression(selector, 3, (filterValue - 1) * 3 + 1, isExcludedFilterType); } else if (typeof field.groupInterval === "number" && field.dataType !== "date") { expression = getIntervalFilterExpression(selector, field.groupInterval, filterValue, isExcludedFilterType); } } return expression; } function createFieldFilterExpressions(field, operation) { var fieldFilterExpressions = []; if (field.filterType === "exclude") { operation = operation || "and"; } else { operation = operation || "or"; } each(field.filterValues, function (index, filterValue) { var currentExpression = [], currentField = field.levels ? field.levels[index] : field; if (Array.isArray(filterValue)) { var parseLevelsRecursive = field.levels && field.levels.length; if (parseLevelsRecursive) { currentExpression = createFieldFilterExpressions({ filterValues: filterValue, filterType: currentField.filterType, levels: field.levels }, "and"); } } else { currentExpression = getFilterExpressionForFilterValue(currentField, filterValue); } if (!currentExpression.length) { return; } if (fieldFilterExpressions.length) { fieldFilterExpressions.push(operation); } fieldFilterExpressions.push(currentExpression); }); return fieldFilterExpressions; } function createFilterExpressions(fields) { var filterExpressions = []; each(fields, function (_, field) { var fieldExpressions = createFieldFilterExpressions(field); if (!fieldExpressions.length) { return []; } if (filterExpressions.length) { filterExpressions.push("and"); } filterExpressions.push(fieldExpressions); }); if (filterExpressions.length === 1) { filterExpressions = filterExpressions[0]; } return filterExpressions; } function mergeFilters(filter1, filter2) { var mergedFilter, notEmpty = function notEmpty(filter) { return filter && filter.length; }; if (notEmpty(filter1) && notEmpty(filter2)) { mergedFilter = [filter1, "and", filter2]; } else { mergedFilter = notEmpty(filter1) ? filter1 : filter2; } return mergedFilter; } function createLoadOptions(options, externalFilterExpr) { var filterExpressions = createFilterExpressions(options.filters), groupingOptions = createGroupingOptions(options.rows).concat(createGroupingOptions(options.columns)), loadOptions = { groupSummary: [], totalSummary: [], group: groupingOptions.length ? groupingOptions : undefined, take: groupingOptions.length ? undefined : 1 }; if (externalFilterExpr) { filterExpressions = mergeFilters(filterExpressions, externalFilterExpr); } if (filterExpressions.length) { loadOptions.filter = filterExpressions; } each(options.values, function (_, value) { var summaryOption = { selector: value.dataField, summaryType: value.summaryType || "count" }; loadOptions.groupSummary.push(summaryOption); options.includeTotalSummary && loadOptions.totalSummary.push(summaryOption); }); return loadOptions; } function forEachGroup(data, callback, level) { data = data || []; level = level || 0; each(data, function (_, group) { callback(group, level); if (group.items && group.items.length) { forEachGroup(group.items, callback, level + 1); } }); } function setValue(valuesArray, value, rowIndex, columnIndex, dataIndex) { valuesArray[rowIndex] = valuesArray[rowIndex] || []; valuesArray[rowIndex][columnIndex] = valuesArray[rowIndex][columnIndex] || []; if (!isDefined(valuesArray[rowIndex][columnIndex][dataIndex])) { valuesArray[rowIndex][columnIndex][dataIndex] = value; } } function parseResult(data, total, descriptions, result) { var rowPath = [], columnPath = [], rowHash = result.rowHash, columnHash = result.columnHash; if (total && total.summary) { each(total.summary, function (index, summary) { setValue(result.values, summary, result.grandTotalRowIndex, result.grandTotalColumnIndex, index); }); } function getItem(dataItem, dimensionName, path, level) { var dimensionHash = result[dimensionName + "Hash"], parentItem, parentItemChildren, item, pathValue = path.slice(0, level + 1).join("/"), parentPathValue; if (dimensionHash[pathValue] !== undefined) { item = dimensionHash[pathValue]; } else { item = { value: dataItem.key, index: result[dimensionName + "Index"]++ }; parentPathValue = path.slice(0, level).join("/"); if (level > 0 && dimensionHash[parentPathValue] !== undefined) { parentItem = dimensionHash[parentPathValue]; parentItemChildren = parentItem.children = parentItem.children || []; } else { parentItemChildren = result[dimensionName + "s"]; } parentItemChildren.push(item); dimensionHash[pathValue] = item; } return item; } forEachGroup(data, function (item, level) { var rowLevel = level >= descriptions.rows.length ? descriptions.rows.length : level, columnLevel = level >= descriptions.rows.length ? level - descriptions.rows.length : 0, columnItem, rowItem; if (level >= descriptions.rows.length && columnLevel >= descriptions.columns.length) { return; } if (level < descriptions.rows.length) { columnPath = []; } if (level >= descriptions.rows.length) { columnPath[columnLevel] = item.key + ""; columnItem = getItem(item, "column", columnPath, columnLevel); rowItem = rowHash[rowPath.slice(0, rowLevel + 1).join("/")]; } else { rowPath[rowLevel] = item.key + ""; rowItem = getItem(item, "row", rowPath, rowLevel); columnItem = columnHash[columnPath.slice(0, columnLevel + 1).join("/")]; } var currentRowIndex = rowItem && rowItem.index || result.grandTotalRowIndex, currentColumnIndex = columnItem && columnItem.index || result.grandTotalColumnIndex; each(item.summary || [], function (i, summary) { setValue(result.values, summary, currentRowIndex, currentColumnIndex, i); }); }); return result; } function getFiltersForDimension(dimensionOptions) { return grep(dimensionOptions || [], function (field) { return field.filterValues && field.filterValues.length; }); } function getExpandedIndex(options, axis) { if (axis === options.headerName) { return options.path.length; } return 0; } function getFiltersForExpandedDimension(options) { return getFiltersByPath(options[options.headerName], options.path); } function getExpandedPathSliceFilter(options, dimensionName, level, firstCollapsedFieldIndex) { var result = [], startSliceIndex = level > firstCollapsedFieldIndex ? 0 : firstCollapsedFieldIndex, fields = options.headerName !== dimensionName ? options[dimensionName].slice(startSliceIndex, level) : [], paths = dimensionName === "rows" ? options.rowExpandedPaths : options.columnExpandedPaths; each(fields, function (index, field) { var filterValues = []; each(paths, function (_, path) { path = path.slice(startSliceIndex, level); if (index < path.length) { filterValues.push(path[index]); } }); if (filterValues.length) { result.push(extend({}, field, { filterType: "include", filterValues: filterValues })); } }); return result; } function getGrandTotalRequest(options, dimensionName, expandedIndex, expandedLevel, commonFilters, firstCollapsedFieldIndex) { var expandedPaths = (dimensionName === "columns" ? options.columnExpandedPaths : options.rowExpandedPaths) || [], oppositeDimensionName = dimensionName === "columns" ? "rows" : "columns", fields = options[dimensionName], result = [], newOptions; if (expandedPaths.length) { for (var i = expandedIndex; i < expandedLevel + 1; i++) { newOptions = { filters: commonFilters.concat(getExpandedPathSliceFilter(options, dimensionName, i, firstCollapsedFieldIndex)) }; newOptions[dimensionName] = fields.slice(expandedIndex, i + 1); newOptions[oppositeDimensionName] = []; if (i === expandedLevel) { newOptions.includeTotalSummary = true; } result.push(extend({}, options, newOptions)); } } else { newOptions = { filters: commonFilters, includeTotalSummary: true }; newOptions[dimensionName] = fields.slice(expandedIndex, expandedLevel + 1); newOptions[oppositeDimensionName] = []; result.push(extend({}, options, newOptions)); } return result; } function getFirstCollapsedIndex(fields) { var firstCollapsedIndex = 0; each(fields, function (index, field) { if (!field.expanded) { firstCollapsedIndex = index; return false; } }); return firstCollapsedIndex; } function getRequestsData(options) { var rowExpandedLevel = pivotGridUtils.getExpandedLevel(options, "rows"), columnExpandedLevel = pivotGridUtils.getExpandedLevel(options, "columns"), columnTotalsOptions, filters = options.filters || [], columnExpandedIndex = getExpandedIndex(options, "columns"), firstCollapsedColumnIndex = getFirstCollapsedIndex(options.columns), firstCollapsedRowIndex = getFirstCollapsedIndex(options.rows), rowExpandedIndex = getExpandedIndex(options, "rows"), data = []; filters = filters.concat(getFiltersForDimension(options.rows)).concat(getFiltersForDimension(options.columns)).concat(getFiltersForExpandedDimension(options)); columnTotalsOptions = getGrandTotalRequest(options, "columns", columnExpandedIndex, columnExpandedLevel, filters, firstCollapsedColumnIndex); if (options.rows.length && options.columns.length) { data = data.concat(columnTotalsOptions); for (var i = rowExpandedIndex; i < rowExpandedLevel + 1; i++) { var rows = options.rows.slice(rowExpandedIndex, i + 1), rowFilterByExpandedPaths = getExpandedPathSliceFilter(options, "rows", i, firstCollapsedRowIndex); for (var j = columnExpandedIndex; j < columnExpandedLevel + 1; j++) { var preparedOptions = extend({}, options, { columns: options.columns.slice(columnExpandedIndex, j + 1), rows: rows, filters: filters.concat(getExpandedPathSliceFilter(options, "columns", j, firstCollapsedColumnIndex)).concat(rowFilterByExpandedPaths) }); data.push(preparedOptions); } } } else { data = options.columns.length ? columnTotalsOptions : getGrandTotalRequest(options, "rows", rowExpandedIndex, rowExpandedLevel, filters, firstCollapsedRowIndex); } return data; } function prepareFields(fields) { each(fields || [], function (_, field) { var levels = field.levels; if (levels) { prepareFields(levels); } pivotGridUtils.setDefaultFieldValueFormatting(field); }); } module.exports = Class.inherit(function () { return { ctor: function ctor(options) { this._dataSource = new DataSourceModule.DataSource(options); this._store = this._dataSource.store(); }, getFields: function getFields(fields) { var d = new Deferred(); this._store.load({ skip: 0, take: 20 }).done(function (data) { d.resolve(pivotGridUtils.discoverObjectFields(data, fields)); }).fail(d.reject); return d; }, key: function key() { return this._store.key(); }, load: function load(options) { var that = this, d = new Deferred(), result = { rows: [], columns: [], values: [[[]]], grandTotalRowIndex: 0, grandTotalColumnIndex: 0, rowHash: {}, columnHash: {}, rowIndex: 1, columnIndex: 1 }, requestsData = getRequestsData(options), deferreds = []; prepareFields(options.rows); prepareFields(options.columns); prepareFields(options.filters); each(requestsData, function (_, dataItem) { deferreds.push(that._store.load(createLoadOptions(dataItem, that.filter()))); }); when.apply(null, deferreds).done(function () { var args = deferreds.length > 1 ? arguments : [arguments]; each(args, function (index, argument) { parseResult(argument[0], argument[1], requestsData[index], result); }); d.resolve({ rows: result.rows, columns: result.columns, values: result.values, grandTotalRowIndex: result.grandTotalRowIndex, grandTotalColumnIndex: result.grandTotalColumnIndex }); }).fail(d.reject); return d; }, filter: function filter() { return this._dataSource.filter.apply(this._dataSource, arguments); }, supportSorting: function supportSorting() { return false; }, createDrillDownDataSource: function createDrillDownDataSource(loadOptions, params) { loadOptions = loadOptions || {}; params = params || {}; var store = this._store, filters = getFiltersByPath(loadOptions.rows, params.rowPath).concat(getFiltersByPath(loadOptions.columns, params.columnPath)).concat(getFiltersForDimension(loadOptions.rows)).concat(loadOptions.filters || []).concat(getFiltersForDimension(loadOptions.columns)), filterExp = createFilterExpressions(filters); return new DataSourceModule.DataSource({ load: function load(loadOptions) { return store.load(extend({}, loadOptions, { filter: mergeFilters(filterExp, loadOptions.filter), select: params.customColumns })); } }); } }; }()); ///#DEBUG module.exports.__forEachGroup = forEachGroup; ///#ENDDEBUG