UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

1,651 lines (1,650 loc) 185 kB
const require_kendo_licensing = require('./kendo.licensing-DQkab2ZD.js'); const require_loaderContainer = require('./loaderContainer-DBvhSdyB.js'); let _progress_kendo_pivotgrid_common = require("@progress/kendo-pivotgrid-common"); //#region ../src/kendo.pivotgrid.js const __meta__ = { id: "pivotgrid", name: "PivotGrid", category: "web", description: "The PivotGrid widget is a data summarization tool.", depends: [ "dom", "data", "data.xml", "sortable", "icons", "loader", "html.loadercontainer" ], features: [ { id: "pivotgrid-configurator", name: "Configurator", description: "The PivotConfigurator widget allows the user to select data slices displayed in PivotGrid", depends: ["pivot.configurator"] }, { id: "pivotgrid-filtering", name: "Filtering", description: "Support for filtering", depends: ["pivot.fieldmenu"] }, { id: "pivotgrid-excel-export", name: "Excel export", description: "Export pivot grid data as Excel spreadsheet", depends: ["ooxml"] }, { id: "pivotgrid-pdf-export", name: "PDF export", description: "Export pivot grid data as PDF", depends: ["pdf", "drawing"] }, { id: "mobile-scroller", name: "Mobile scroller", description: "Support for kinetic scrolling in mobile device", depends: ["mobile.scroller"] } ] }; (function($, undefined) { var kendo = window.kendo, ui = kendo.ui, encode = kendo.htmlEncode, Class = kendo.Class, Comparer = kendo.data.Comparer, Widget = ui.Widget, DataSource = kendo.data.DataSource, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, normalizeFilter = kendo.data.Query.normalizeFilter, normalizeSort = kendo.data.Query.normalizeSort, toString = {}.toString, identity = function(o) { return o; }, map = $.map, extend = $.extend, keys = kendo.keys, isFunction = kendo.isFunction, RESIZE = "resize", READ = "read", CHANGE = "change", ERROR = "error", REQUESTSTART = "requestStart", PROGRESS = "progress", REQUESTEND = "requestEnd", MEASURES = "Measures", STATERESET = "stateReset", AUTO = "auto", DIV = "<div></div>", NS = ".kendoPivotGrid", ROW_TOTAL_KEY = "__row_total__", DATABINDING = "dataBinding", DATABOUND = "dataBound", EXPANDMEMBER = "expandMember", HEADERTEMPLATE = ({ id, key, headerClass, colspan, rowspan, expandable, iconClass, role, expanded }) => `<th id="${id}" role="${role}" ${expandable ? `aria-expanded="${expanded}"` : ""} data-key="${encode(key)}" class="${encode(headerClass)}" ${colspan ? "colspan=\"" + encode(colspan) + "\"" : ""} ${rowspan ? "rowspan=\"" + encode(rowspan) + "\"" : ""}>` + `${expandable ? kendo.ui.icon($("<span role=\"presentation\" class=\"k-pivotgrid-toggle\"></span>"), { icon: `chevron-${encode(iconClass)}` }) : ""}` + "</th>", COLLAPSEMEMBER = "collapseMember", STATE_EXPANDED_ICONNAME = "caret-alt-down", STATE_EXPANDED_SELECTOR = `.k-i-${STATE_EXPANDED_ICONNAME},.k-svg-i-${STATE_EXPANDED_ICONNAME}`, STATE_COLLAPSED_ICONNAME = "caret-alt-right", HEADER_TEMPLATE = ({ member }) => `<span>${encode(member.caption || member.name)}</span>`, PIVOTGRID_TREND_ICONS_MAP = { "kpi-trend-decrease": "caret-alt-down", "kpi-trend-increase": "caret-alt-up", "kpi-trend-equal": "minus" }, KPISTATUS_TEMPLATE = ({ dataItem }) => kendo.ui.icon($(`<span title="${encode(dataItem.value)}"></span>`), { icon: `kpi-status-${dataItem.value > 0 ? "open" : dataItem.value < 0 ? "deny" : "hold"}` }), KPITREND_TEMPLATE = ({ dataItem }) => kendo.ui.icon($(`<span title="${encode(dataItem.value)}"></span>`), { icon: PIVOTGRID_TREND_ICONS_MAP[`kpi-trend-${dataItem.value > 0 ? "increase" : dataItem.value < 0 ? "decrease" : "equal"}`] }), DATACELL_TEMPLATE = ({ dataItem }) => dataItem ? dataItem.fmtValue || dataItem.value ? `<span class="k-pivotgrid-content">${encode(dataItem.fmtValue || dataItem.value)}</span>` : "&nbsp;" : "&nbsp;", LAYOUT_TABLE = "<table class=\"k-pivot-layout\">" + "<tr>" + "<td>" + "<div class=\"k-pivot-rowheaders\"></div>" + "</td>" + "<td>" + "<div class=\"k-pivot-table\"></div>" + "</td>" + "</tr>" + "</table>"; var AXIS_ROWS = "rows"; var AXIS_COLUMNS = "columns"; const SEPARATOR = "&"; var tableStyles = { tableRow: "k-table-row", header: "k-header k-table-th", headerTable: "k-grid-header-table k-table", table: "k-table", contentTable: "k-grid-table k-table", tbody: "k-table-tbody", tableCell: "k-table-td" }; function normalizeMeasures(measure) { var descriptor = typeof measure === "string" ? [{ name: measure }] : measure; var descriptors = toString.call(descriptor) === "[object Array]" ? descriptor : descriptor !== undefined ? [descriptor] : []; return map(descriptors, function(d) { if (typeof d === "string") { return { name: d }; } return $.extend(true, d, { name: d.name, type: d.type }); }); } function normalizeMembers(member) { var descriptor = typeof member === "string" ? [{ name: [member], expand: false }] : member; var descriptors = toString.call(descriptor) === "[object Array]" ? descriptor : descriptor !== undefined ? [descriptor] : []; return map(descriptors, function(d) { if (typeof d === "string") { return { name: [d], expand: false }; } return { name: toString.call(d.name) === "[object Array]" ? d.name.slice() : [d.name], expand: d.expand }; }); } function normalizeName(name) { if (name.indexOf(" ") !== -1) { name = "[\"" + name + "\"]"; } return name; } function accumulateMembers(accumulator, rootTuple, tuple, level) { var idx, length; var children; var member; if (!tuple) { tuple = rootTuple; } if (!level) { level = 0; } member = tuple.members[level]; if (!member || member.measure) { return; } children = member.children; length = children.length; if (tuple === rootTuple) { accumulator[kendo.stringify([member.name])] = !!length; } else if (length) { accumulator[kendo.stringify(buildPath(tuple, level))] = true; } if (length) { for (idx = 0; idx < length; idx++) { accumulateMembers(accumulator, rootTuple, children[idx], level); } } accumulateMembers(accumulator, rootTuple, tuple, level + 1); } function descriptorsForAxes(tuples) { var result = {}; if (tuples.length) { accumulateMembers(result, tuples[0]); } var descriptors = []; for (var k in result) { descriptors.push({ name: JSON.parse(k), expand: result[k] }); } return descriptors; } function addMissingPathMembers(members, axis) { var tuples = axis.tuples || []; var firstTuple = tuples[0]; if (firstTuple && members.length < firstTuple.members.length) { var tupleMembers = firstTuple.members; for (var idx = 0; idx < tupleMembers.length; idx++) { if (tupleMembers[idx].measure) { continue; } var found = false; for (var j = 0; j < members.length; j++) { if (getName(members[j]).indexOf(tupleMembers[idx].hierarchy) === 0) { found = true; break; } } if (!found) { members.push({ name: [tupleMembers[idx].name], expand: false }); } } } } function tupleToDescriptors(tuple) { var result = []; var members = tuple.members; for (var idx = 0; idx < members.length; idx++) { if (members[idx].measure) { continue; } result.push({ name: [members[idx].name], expand: members[idx].children.length > 0 }); } return result; } function descriptorsForMembers(axis, members, measures) { axis = axis || {}; addMissingPathMembers(members, axis); if (measures.length > 1) { members.push({ name: MEASURES, measure: true, children: normalizeMembers(measures) }); } var tupletoSearch = { members }; if (axis.tuples) { var result = findExistingTuple(axis.tuples, tupletoSearch); if (result.tuple) { members = tupleToDescriptors(result.tuple); } } return members; } function createAggregateGetter(m) { var measureGetter = kendo.getter(m.field, true); return function(aggregatorContext, state) { return m.aggregate(measureGetter(aggregatorContext.dataItem), state, aggregatorContext); }; } function isNumber(val) { return typeof val === "number" && !isNaN(val); } function isDate(val) { return val && val.getTime; } function getScollWidth() { var scrollbar = 0; var div; if (document && document.createElement) { div = document.createElement("div"); div.style.cssText = "overflow:scroll;overflow-x:hidden;zoom:1;clear:both;display:block"; div.innerHTML = "&nbsp;"; document.body.appendChild(div); scrollbar = div.offsetWidth - div.scrollWidth; document.body.removeChild(div); } return scrollbar; } function loadLocalData(data, params, deferred) { const that = this; const originalData = (that.reader.data(data) || []).slice(0); if (originalData && !that._pristineData) { that._pristineData = originalData; } const columnSettings = that._createSettings(params.columnAxes); const rowSettings = that._createSettings(params.rowAxes); const measures = that.measures(); const dataTree = (0, _progress_kendo_pivotgrid_common.createDataTree)(originalData, rowSettings, columnSettings, measures, { dataField: "aggregate", columnsData: "columns" }, that.filter() || []); const stateArgs = { dataTree, columnSettings, rowSettings, columnAxes: params.columnAxes, rowAxes: params.rowAxes, measures: measures.map(function(item) { return item; }), fields: { dataField: "aggregate", columnsData: "columns" }, sort: flattenSortDescriptors(params.sort || []) }; that._saveState((0, _progress_kendo_pivotgrid_common.createLocalDataState)(stateArgs)); that.trigger(CHANGE); deferred.resolve(); } function flattenSortDescriptors(descriptors) { var result = []; for (var i = 0; i < descriptors.length; i++) { result.push({ dir: descriptors[i].dir, field: descriptors[i].field.split(".").pop() }); } return result; } function createLocalMeasure(field, key, format, aggregate) { var formatFunc = function(value) { return kendo.format(this.format, value); }; var measureMap = { "sum": _progress_kendo_pivotgrid_common.sumAggregate, "average": _progress_kendo_pivotgrid_common.averageAggregate, "min": _progress_kendo_pivotgrid_common.minAggregate, "max": _progress_kendo_pivotgrid_common.maxAggregate, "count": _progress_kendo_pivotgrid_common.countAggregate }; var valueFunc = function(item) { return item[this.field]; }; var measure = { value: valueFunc.bind({ field }), aggregate: measureMap[aggregate], caption: key, uniqueName: key, type: 2, name: [key] }; if (format) { measure.aggregate.format = formatFunc.bind({ format }); } return measure; } function getIcons(sortIcon, options, pivotOptions) { var sortable = options.sortable, filterable = options.filterable, reorderable = pivotOptions.reorderable, result = ""; if (sortable) { result += sortIcon ? `<span class="k-chip-action">${kendo.ui.icon(sortIcon + "-sm")}</span>` : ""; } if (filterable || sortable) { result += `<span class="k-setting-fieldmenu k-chip-action">${kendo.ui.icon("more-vertical")}</span>`; } if (reorderable) { result += `<span class="k-setting-delete k-chip-action">${kendo.ui.icon("x")}</span>`; } return result; } var functions = { sum: function(value, state) { var accumulator = state.accumulator; if (!isNumber(accumulator)) { accumulator = value; } else if (isNumber(value)) { accumulator += value; } return accumulator; }, count: function(value, state) { return (state.accumulator || 0) + 1; }, average: { aggregate: function(value, state) { var accumulator = state.accumulator; if (state.count === undefined) { state.count = 0; } if (!isNumber(accumulator)) { accumulator = value; } else if (isNumber(value)) { accumulator += value; } if (isNumber(value)) { state.count++; } return accumulator; }, result: function(state) { var accumulator = state.accumulator; if (isNumber(accumulator)) { accumulator = accumulator / state.count; } return accumulator; } }, max: function(value, state) { var accumulator = state.accumulator; if (!isNumber(accumulator) && !isDate(accumulator)) { accumulator = value; } if (accumulator < value && (isNumber(value) || isDate(value))) { accumulator = value; } return accumulator; }, min: function(value, state) { var accumulator = state.accumulator; if (!isNumber(accumulator) && !isDate(accumulator)) { accumulator = value; } if (accumulator > value && (isNumber(value) || isDate(value))) { accumulator = value; } return accumulator; } }; var PivotCubeBuilder = Class.extend({ init: function(options) { this.options = extend({}, this.options, options); this.dimensions = this._normalizeDescriptors("field", this.options.dimensions); this.measures = this._normalizeDescriptors("name", this.options.measures); }, _normalizeDescriptors: function(keyField, descriptors) { descriptors = descriptors || {}; var fields = {}; var field; if (toString.call(descriptors) === "[object Array]") { for (var idx = 0, length = descriptors.length; idx < length; idx++) { field = descriptors[idx]; if (typeof field === "string") { fields[field] = {}; } else if (field[keyField]) { fields[field[keyField]] = field; } } descriptors = fields; } return descriptors; }, _rootTuples: function(rootNames, measureAggregators) { var aggregatorsLength = measureAggregators.length || 1; var dimensionsSchema = this.dimensions || []; var root, name, parts; var measureIdx = 0; var idx; var rootNamesLength = rootNames.length; var result = []; var keys = []; if (rootNamesLength || measureAggregators.length) { for (measureIdx = 0; measureIdx < aggregatorsLength; measureIdx++) { root = { members: [] }; for (idx = 0; idx < rootNamesLength; idx++) { name = rootNames[idx]; parts = name.split("&"); root.members[root.members.length] = { children: [], caption: (dimensionsSchema[name] || {}).caption || "All", name, levelName: name, levelNum: "0", hasChildren: true, parentName: parts.length > 1 ? parts[0] : undefined, hierarchy: name }; } if (aggregatorsLength > 1) { root.members[root.members.length] = { children: [], caption: measureAggregators[measureIdx].caption, name: measureAggregators[measureIdx].descriptor.name, levelName: "MEASURES", levelNum: "0", hasChildren: false, parentName: undefined, hierarchy: "MEASURES" }; } result[result.length] = root; } keys.push(ROW_TOTAL_KEY); } return { keys, tuples: result }; }, _sortMap: function(map, sortDescriptors) { var sortedMaps = []; var sortTree = []; var flattenTree = []; var mapItem; var key; for (key in map) { if (!map[key].directParentName) { sortTree.push($.extend({}, { name: key, parentName: map[key].parentName })); } } if (!sortTree.length) { for (key in map) { sortTree.push($.extend({}, { name: key, parentName: map[key].parentName })); } } fillSortTree(sortTree, map); for (var i = 0; i < sortDescriptors.length; i++) { sortItemsTree(sortDescriptors[i].field.split(".").pop(), sortTree, Comparer.create({ field: "name", dir: sortDescriptors[i].dir })); } flattenTree = flatColumns(sortTree); for (var j = 0; j < flattenTree.length; j++) { mapItem = map[flattenTree[j].name]; mapItem.index = j; sortedMaps[j] = mapItem; } return sortedMaps; }, _expandedTuples: function(map, expanded, measureAggregators, sortDescriptors) { var aggregatorsLength = measureAggregators.length || 1; var dimensionsSchema = this.dimensions || []; var measureIdx; var tuple; var key; var mapItem; var current; var currentKeys; var accumulator = []; var accumulatorKeys = []; var memberInfo; var expandedNames; var parts; var name; var idx; if (sortDescriptors && sortDescriptors.length && !$.isEmptyObject(map)) { map = this._sortMap(map, sortDescriptors); } for (key in map) { mapItem = map[key]; memberInfo = this._findExpandedMember(expanded, mapItem.uniquePath); current = accumulator[memberInfo.index] || []; currentKeys = accumulatorKeys[memberInfo.index] || []; expandedNames = memberInfo.member.names; for (measureIdx = 0; measureIdx < aggregatorsLength; measureIdx++) { tuple = { members: [] }; for (idx = 0; idx < expandedNames.length; idx++) { if (idx === memberInfo.member.expandedIdx) { tuple.members[tuple.members.length] = { children: [], caption: mapItem.value, name: mapItem.name, hasChildren: false, levelNum: 1, levelName: mapItem.parentName + mapItem.name, parentName: mapItem.parentName, hierarchy: mapItem.parentName + mapItem.name }; if (measureIdx === 0) { currentKeys.push(buildPath(tuple, idx).join("")); } } else { name = expandedNames[idx]; parts = name.split("&"); tuple.members[tuple.members.length] = { children: [], caption: (dimensionsSchema[name] || {}).caption || "All", name, levelName: name, levelNum: "0", hasChildren: true, parentName: parts.length > 1 ? parts[0] : undefined, hierarchy: name }; } } if (aggregatorsLength > 1) { tuple.members[tuple.members.length] = { children: [], caption: measureAggregators[measureIdx].caption, name: measureAggregators[measureIdx].descriptor.name, levelName: "MEASURES", levelNum: "0", hasChildren: true, parentName: undefined, hierarchy: "MEASURES" }; } current[current.length] = tuple; } accumulator[memberInfo.index] = current; accumulatorKeys[memberInfo.index] = currentKeys; } return { keys: accumulatorKeys, tuples: accumulator }; }, _findExpandedMember: function(members, parentName) { for (var idx = 0; idx < members.length; idx++) { if (members[idx].uniquePath === parentName) { return { member: members[idx], index: idx }; } } }, _asTuples: function(map, descriptor, measureAggregators, sortDescriptors) { measureAggregators = measureAggregators || []; var rootInfo = this._rootTuples(descriptor.root, measureAggregators); var expandedInfo = this._expandedTuples(map, descriptor.expanded, measureAggregators, sortDescriptors); return { keys: [].concat.apply(rootInfo.keys, expandedInfo.keys), tuples: [].concat.apply(rootInfo.tuples, expandedInfo.tuples) }; }, _measuresInfo: function(measures, rowAxis) { var idx = 0; var length = measures && measures.length; var aggregateNames = []; var resultFuncs = {}; var formats = {}; var descriptors = this.measures || {}; var measure; var name; for (; idx < length; idx++) { name = measures[idx].descriptor.name; measure = descriptors[name] || {}; aggregateNames.push(name); if (measure.result) { resultFuncs[name] = measure.result; } if (measure.format) { formats[name] = measure.format; } } return { names: aggregateNames, formats, resultFuncs, rowAxis }; }, _toDataArray: function(map, measuresInfo, rowKeys, columnKeys) { var result = []; var aggregates; var name, i, j, k, n; var row, column, columnKey; var rowMeasureNamesLength = 1; var rowMeasureNames = []; var columnMeasureNames; var rowLength = rowKeys.length || 1; var columnLength = columnKeys.length || 1; if (measuresInfo.rowAxis) { rowMeasureNames = measuresInfo.names; rowMeasureNamesLength = rowMeasureNames.length; } else { columnMeasureNames = measuresInfo.names; } for (i = 0; i < rowLength; i++) { row = map[rowKeys[i] || ROW_TOTAL_KEY]; for (n = 0; n < rowMeasureNamesLength; n++) { if (measuresInfo.rowAxis) { columnMeasureNames = [rowMeasureNames[n]]; } for (j = 0; j < columnLength; j++) { columnKey = columnKeys[j] || ROW_TOTAL_KEY; column = row.items[columnKey]; if (columnKey === ROW_TOTAL_KEY) { aggregates = row.aggregates; } else { aggregates = column ? column.aggregates : {}; } for (k = 0; k < columnMeasureNames.length; k++) { name = columnMeasureNames[k]; this._addData(result, aggregates[name], measuresInfo.formats[name], measuresInfo.resultFuncs[name]); } } } } return result; }, _addData: function(result, value, format, resultFunc) { var fmtValue = ""; var ordinal; if (value) { value = resultFunc ? resultFunc(value) : value.accumulator; fmtValue = format ? kendo.format(format, value) : value; } ordinal = result.length; result[ordinal] = { ordinal, value: value || "", fmtValue }; }, _matchDescriptors: function(dataItem, descriptor, getters) { var parts; var parentField; var expectedValue; var names = descriptor.names; var idx = descriptor.expandedIdx; var value; while (idx > 0) { parts = names[--idx].split("&"); if (parts.length > 1) { parentField = parts[0]; expectedValue = parts[1]; value = getters[parentField](dataItem); value = value !== undefined && value !== null ? value.toString() : value; if (value != expectedValue) { return false; } } } return true; }, _calculateAggregate: function(measureAggregators, aggregatorContext, totalItem) { var result = {}; var state; var name; for (var measureIdx = 0; measureIdx < measureAggregators.length; measureIdx++) { name = measureAggregators[measureIdx].descriptor.name; state = totalItem.aggregates[name] || {}; state.accumulator = measureAggregators[measureIdx].aggregator(aggregatorContext, state); result[name] = state; } return result; }, _processColumns: function(measureAggregators, descriptors, getters, columns, aggregatorContext, rowTotal, state, updateColumn) { var value; var descriptor; var column; var totalItem; var key, name, parentName, path; var dataItem = aggregatorContext.dataItem; var idx = 0; for (; idx < descriptors.length; idx++) { descriptor = descriptors[idx]; if (!this._matchDescriptors(dataItem, descriptor, getters)) { continue; } path = descriptor.names.slice(0, descriptor.expandedIdx).join(""); name = descriptor.names[descriptor.expandedIdx]; value = getters[name](dataItem); value = value !== undefined && value !== null ? value.toString() : value; parentName = name; name = name + "&" + value; key = path + name; column = columns[key] || { index: state.columnIndex, parentName, name, directParentName: path.indexOf("&") !== -1 ? path : "", uniquePath: path + parentName, childrenMap: {}, value }; if (path && columns[path] && !columns[path].childrenMap[path + parentName + "&" + value]) { columns[path].childrenMap[path + parentName + "&" + value] = true; } totalItem = rowTotal.items[key] || { aggregates: {} }; rowTotal.items[key] = { index: column.index, aggregates: this._calculateAggregate(measureAggregators, aggregatorContext, totalItem) }; if (updateColumn) { if (!columns[key]) { state.columnIndex++; } columns[key] = column; } } }, _measureAggregators: function(options) { var measureDescriptors = options.measures || []; var measures = this.measures || {}; var aggregators = []; var descriptor, measure, idx, length; var defaultAggregate, aggregate; if (measureDescriptors.length) { for (idx = 0, length = measureDescriptors.length; idx < length; idx++) { descriptor = measureDescriptors[idx]; measure = measures[descriptor.name]; defaultAggregate = null; if (measure) { aggregate = measure.aggregate; if (typeof aggregate === "string") { defaultAggregate = functions[aggregate.toLowerCase()]; if (!defaultAggregate) { throw new Error("There is no such aggregate function"); } measure.aggregate = defaultAggregate.aggregate || defaultAggregate; measure.result = defaultAggregate.result; } aggregators.push({ descriptor, caption: measure.caption, result: measure.result, aggregator: createAggregateGetter(measure) }); } } } else { aggregators.push({ descriptor: { name: "default" }, caption: "default", aggregator: function() { return 1; } }); } return aggregators; }, _buildGetters: function(names) { var result = {}; var parts; var name; for (var idx = 0; idx < names.length; idx++) { name = names[idx]; parts = name.split("&"); if (parts.length > 1) { result[parts[0]] = kendo.getter(parts[0], true); } else { result[name] = kendo.getter(normalizeName(name), true); } } return result; }, _parseDescriptors: function(descriptors) { var parsedDescriptors = parseDescriptors(descriptors); var rootNames = getRootNames(parsedDescriptors.root); var expanded = parsedDescriptors.expanded; var result = []; for (var idx = 0; idx < expanded.length; idx++) { result.push(mapNames(expanded[idx].name, rootNames)); } return { root: rootNames, expanded: result }; }, _filter: function(data, filter) { if (!filter) { return data; } var expr; var idx = 0; var filters = filter.filters; for (; idx < filters.length; idx++) { expr = filters[idx]; if (expr.operator === "in") { filters[idx] = this._normalizeFilter(expr); } } return new kendo.data.Query(data).filter(filter).data; }, _normalizeFilter: function(filter) { var value = filter.value.split(","); var result = []; if (!value.length) { return value; } for (var idx = 0; idx < value.length; idx++) { result.push({ field: filter.field, operator: "eq", value: value[idx] }); } return { logic: "or", filters: result }; }, process: function(data, options) { data = data || []; options = options || {}; data = this._filter(data, options.filter); var measures = options.measures || []; var measuresRowAxis = options.measuresAxis === "rows"; var columnDescriptors = options.columns || []; var rowDescriptors = options.rows || []; if (!columnDescriptors.length && rowDescriptors.length && (!measures.length || measures.length && measuresRowAxis)) { columnDescriptors = rowDescriptors; rowDescriptors = []; measuresRowAxis = false; } if (!columnDescriptors.length && !rowDescriptors.length) { measuresRowAxis = false; } if (!columnDescriptors.length && measures.length) { columnDescriptors = normalizeMembers(options.measures); } columnDescriptors = this._parseDescriptors(columnDescriptors); rowDescriptors = this._parseDescriptors(rowDescriptors); var aggregatedData = {}; var columns = {}; var rows = {}; var rowValue; var state = { columnIndex: 0 }; var measureAggregators = this._measureAggregators(options); var columnGetters = this._buildGetters(columnDescriptors.root); var rowGetters = this._buildGetters(rowDescriptors.root); var processed = false; var expandedColumns = columnDescriptors.expanded; var expandedRows = rowDescriptors.expanded; var dataItem; var aggregatorContext; var hasExpandedRows = expandedRows.length !== 0; var rowIdx, rowDescriptor, rowName, rowTotal; var key, path, parentName, value; var columnsInfo, rowsInfo; var length = data.length; var idx = 0; if (columnDescriptors.root.length || rowDescriptors.root.length) { processed = true; for (idx = 0; idx < length; idx++) { dataItem = data[idx]; aggregatorContext = { dataItem, index: idx }; rowTotal = aggregatedData[ROW_TOTAL_KEY] || { items: {}, aggregates: {} }; this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, rowTotal, state, !hasExpandedRows); rowTotal.aggregates = this._calculateAggregate(measureAggregators, aggregatorContext, rowTotal); aggregatedData[ROW_TOTAL_KEY] = rowTotal; for (rowIdx = 0; rowIdx < expandedRows.length; rowIdx++) { rowDescriptor = expandedRows[rowIdx]; if (!this._matchDescriptors(dataItem, rowDescriptor, rowGetters)) { this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, { items: {}, aggregates: {} }, state, true); continue; } path = rowDescriptor.names.slice(0, rowDescriptor.expandedIdx).join(""); rowName = rowDescriptor.names[rowDescriptor.expandedIdx]; parentName = rowName; rowValue = rowGetters[rowName](dataItem); rowValue = rowValue !== undefined ? rowValue.toString() : rowValue; rowName = rowName + "&" + rowValue; key = path + rowName; rows[key] = { uniquePath: path + parentName, parentName, name: rowName, value: rowValue }; value = aggregatedData[key] || { items: {}, aggregates: {} }; this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, value, state, true); value.aggregates = this._calculateAggregate(measureAggregators, aggregatorContext, value); aggregatedData[key] = value; } } } if (processed && length) { if (measureAggregators.length > 1 && (!options.columns || !options.columns.length)) { columnDescriptors = { root: [], expanded: [] }; } columnsInfo = this._asTuples(columns, columnDescriptors, measuresRowAxis ? [] : measureAggregators, options.sort ? options.sort : []); rowsInfo = this._asTuples(rows, rowDescriptors, measuresRowAxis ? measureAggregators : [], options.sort ? options.sort : []); columns = columnsInfo.tuples; rows = rowsInfo.tuples; aggregatedData = this._toDataArray(aggregatedData, this._measuresInfo(measureAggregators, measuresRowAxis), rowsInfo.keys, columnsInfo.keys); } else { aggregatedData = columns = rows = []; } return { axes: { columns: { tuples: columns }, rows: { tuples: rows } }, data: aggregatedData }; } }); var PivotTransport = Class.extend({ init: function(options, transport) { this.transport = transport; this.options = transport.options || {}; if (!this.transport.discover) { if (isFunction(options.discover)) { this.discover = options.discover; } } }, read: function(options) { return this.transport.read(options); }, update: function(options) { return this.transport.update(options); }, create: function(options) { return this.transport.create(options); }, destroy: function(options) { return this.transport.destroy(options); }, discover: function(options) { if (this.transport.discover) { return this.transport.discover(options); } options.success({}); }, catalog: function(val) { var options = this.options || {}; if (val === undefined) { return (options.connection || {}).catalog; } var connection = options.connection || {}; connection.catalog = val; this.options.connection = connection; $.extend(this.transport.options, { connection }); }, cube: function(val) { var options = this.options || {}; if (val === undefined) { return (options.connection || {}).cube; } var connection = options.connection || {}; connection.cube = val; this.options.connection = connection; extend(true, this.transport.options, { connection }); } }); var PivotDataSourceV2 = DataSource.extend({ init: function(options) { var cube = ((options || {}).schema || {}).cube; var schema = { axes: identity, cubes: identity, catalogs: identity, measures: identity, dimensions: identity, hierarchies: identity, levels: identity, members: identity }; if (cube) { this.cubeSchema = $.extend(schema, this._cubeSchema(cube)); } DataSource.fn.init.call(this, extend(true, {}, { schema: this.cubeSchema }, options)); var transportOptions = this.options.transport || {}; if ((this.options.type || "xmla").toLowerCase() === "xmla") { this._online = true; this.transport = new XmlaTransportV2(transportOptions); } else { this.transport = new PivotTransport(this.options.transport || {}, this.transport); } this._columns = normalizeMembers(this.options.columns); this._rows = normalizeMembers(this.options.rows); var measures = this.cubeSchema ? this.cubeSchema.measures() : this.options.measures || []; if (toString.call(measures) === "[object Object]") { this._measuresAxis = measures.axis || "columns"; measures = measures.values || []; } this._measures = normalizeMeasures(measures); }, options: { serverSorting: true, serverPaging: true, serverFiltering: true, serverGrouping: true, serverAggregates: true }, axes: function() { return { columns: normalizeAxis(this.columns()), rows: normalizeAxis(this.rows()) }; }, catalog: function(val) { if (val === undefined) { return this.transport.catalog(); } this.transport.catalog(val); this._mergeState({}); this.read(); }, cube: function(val) { if (val === undefined) { return this.transport.cube(); } this.transport.cube(val); this._mergeState({}); this.read(); }, measuresAxis: function() { return this._measuresAxis || "columns"; }, fetch: function(callback) { var that = this; if (this._data === undefined || this._data.length === 0) { var fn = function() { if (isFunction(callback)) { callback.call(that); } }; return this._query().done(fn); } }, _createSettings: function(axes) { var settings = []; var key; var dimensions = this.cubeSchema.dimensionsSettings(); var displayValueFunc = function(item) { return item[this.key]; }; var sortValueFunc = function(value) { return value; }; for (var i = 0; i < axes.length; i++) { key = axes[i].name[0]; if (key.indexOf(SEPARATOR) > -1) { continue; } settings.push({ key, displayValue: displayValueFunc.bind({ key }), sortValue: sortValueFunc, caption: (dimensions[key] || {}).caption || key }); } return settings; }, _cubeSchema: function(cube) { return { dimensionsSettings: function() { return cube.dimensions; }, dimensions: function() { var result = []; var dimensions = cube.dimensions; for (var key in dimensions) { result.push({ name: key, caption: dimensions[key].caption || key, uniqueName: key, defaultHierarchy: key, type: 1 }); } if (cube.measures) { result.push({ name: MEASURES, caption: MEASURES, uniqueName: MEASURES, type: 2 }); } return result; }, restoreMeasure: function(measures, measure) { for (var i = 0; i < measures.length; i++) { if (!measures[i].aggregate) { measures[i].aggregate = measure.aggregate; measures[i].value = measure.value; measures[i].caption = measure.caption; measures[i].uniqueName = measure.uniqueName; measures[i].type = 2; } } }, measures: function() { var result = []; var measures = cube.measures; for (var key in measures) { result.push(createLocalMeasure(measures[key].field, key, measures[key].format, measures[key].aggregate)); } return result; }, memberType: function(name) { var getter = kendo.getter(normalizeName(name), true); var data = this.options.data || this._pristineData || []; if (!data.length) { return null; } return typeof getter(data[0]); }.bind(this), members: function(name) { var data = this.options.data || this._pristineData || []; var result = []; var distinct = {}; var getter; var value; var idx = 0; if (name.indexOf("[(ALL)]") !== -1) { return [{ caption: cube.dimensions[name.split(".")[0]].caption || name, levelUniqueName: name, name, childrenCardinality: 1, uniqueName: name }]; } getter = kendo.getter(normalizeName(name), true); for (; idx < data.length; idx++) { value = getter(data[idx]); if ((value || value === 0 || value === false) && !distinct[value]) { distinct[value] = true; result.push({ caption: value + "", name: value + "", childrenCardinality: 0, uniqueName: value }); } } return result; }.bind(this) }; }, read: function(data) { const that = this; const isPrevented = that.trigger(REQUESTSTART, { type: READ }); const params = that._params(data); const deferred = $.Deferred(); if (!isPrevented) { that.trigger(PROGRESS); if (that.options.data) { loadLocalData.call(that, that.options.data, params, deferred); } else if ((this.options.type || "xmla").toLowerCase() === "xmla") { that.transport.read({ data: params, success: function(newDataState) { that._saveState(newDataState); that.trigger(REQUESTEND, { response: newDataState, type: READ }); that.trigger(CHANGE); if (that._preventRefresh) { that._preventRefresh = false; } deferred.resolve(); }, error: function(err) { that.trigger(ERROR, { error: err }); } }); } else { that.transport.read({ success: function(data) { loadLocalData.call(that, data, params, deferred); }, error: function(err) { that.trigger(ERROR, { error: err }); } }); } } return deferred.promise(); }, _params: function(data) { var that = this; var options = DataSource.fn._params.call(that, data); options = extend({ columnAxes: JSON.parse(JSON.stringify(that._columns)), rowAxes: JSON.parse(JSON.stringify(that._rows)), measuresAxis: that.measuresAxis(), measureAxes: that._measures }, options); if ((this.options.type || "").toLowerCase() === "xmla") { options.connection = that.options.transport.connection; } if (options.filter) { options.filter = normalizeFilter(options.filter); options.filter = (options.filter || {}).filters; } if (options.sort) { options.sort = normalizeSort(options.sort); } return options; }, discover: function(options) { const that = this; const transport = that.transport; const isOdata = that.options.type === "odata"; const converters = { "schemaMeasures": that.reader.measures, "schemaKPIs": that.reader.kpis, "schemaDimensions": that.reader.dimensions, "schemaHierarchies": that.reader.hierarchies, "schemaLevels": that.reader.levels, "schemaCubes": that.reader.cubes, "schemaCatalogs": that.reader.catalogs, "schemaMembers": that.reader.members }; if (transport.discover && !isOdata) { return transport.discover(options); } return $.Deferred(function(deferred) { transport.discover(extend({ success: function(response) { response = that.reader.parse(response); if (that._handleCustomErrors(response)) { return; } if (converters[options.command]) { response = converters[options.command](response); } deferred.resolve(response); }, error: function(response, status, error) { deferred.reject(response); that.error(response, status, error); } }, options)); }).promise().done(function() { that.trigger("schemaChange"); }); }, schemaMeasures: function() { const that = this; return that.discover({ command: "schemaMeasures", restrictions: { catalogName: that.transport.catalog(), cubeName: that.transport.cube() } }); }, schemaKPIs: function() { const that = this; return that.discover({ command: "schemaKPIs", restrictions: { catalogName: that.transport.catalog(), cubeName: that.transport.cube() } }); }, schemaDimensions: function() { const that = this; return that.discover({ command: "schemaDimensions", restrictions: { catalogName: that.transport.catalog(), cubeName: that.transport.cube() } }); }, schemaHierarchies: function(dimensionName) { const that = this; return that.discover({ command: "schemaHierarchies", restrictions: { catalogName: that.transport.catalog(), cubeName: that.transport.cube(), dimensionUniqueName: dimensionName } }); }, schemaLevels: function(hierarchyName) { const that = this; return that.discover({ command: "schemaLevels", restrictions: { catalogName: that.transport.catalog(), cubeName: that.transport.cube(), hierarchyUniqueName: hierarchyName } }); }, schemaCubes: function() { const that = this; return that.discover({ command: "schemaCubes", restrictions: { catalogName: that.transport.catalog() } }); }, schemaCatalogs: function() { const that = this; return that.discover({ command: "schemaCatalogs" }); }, schemaMembers: function(restrictions) { const that = this; return that.discover({ command: "schemaMembers", restrictions: extend({ catalogName: that.transport.catalog(), cubeName: that.transport.cube() }, restrictions) }); }, _saveState: function(state) { var that = this; that._columnTuples = state.columns; that._rowTuples = state.rows; that._view = that._data = state.data; }, columns: function(val) { if (val === undefined) { return this._columns; } this._columns = normalizeMembers(val); this.read(); }, rows: function(val) { if (val === undefined) { return this._rows; } this._rows = normalizeMembers(val); this.read(); }, measures: function(val) { if (val === undefined) { return this._measures; } this._measures = normalizeMeasures(val); this.read(); }, _mergeState: function(options) { options = DataSource.fn._mergeState.call(this, options); return options; }, _query: function(options) { var that = this; var params = extend({}, { sort: that.sort(), measuresAxis: that.measuresAxis(), filter: that.filter() }, options); this._mergeState(params); return this.read(); } }); var PivotDataSource = DataSource.extend({ init: function(options) { var cube = ((options || {}).schema || {}).cube; var measuresAxis = "columns"; var measures; var schema = { axes: identity, cubes: identity, catalogs: identity, measures: identity, dimensions: identity, hierarchies: identity, levels: identity, members: identity }; if (cube) { schema = $.extend(schema, this._cubeSchema(cube)); this.cubeBuilder = new PivotCubeBuilder(cube); } DataSource.fn.init.call(this, extend(true, {}, { schema }, options)); this.transport = new PivotTransport(this.options.transport || {}, this.transport); this._columns = normalizeMembers(this.options.columns); this._rows = normalizeMembers(this.options.rows); measures = this.options.measures || []; if (toString.call(measures) === "[object Object]") { measuresAxis = measures.axis || "columns"; measures = measures.values || []; } this._measures = normalizeMeasures(measures); this._measuresAxis = measuresAxis; this._skipNormalize = 0; this._axes = {}; }, _cubeSchema: function(cube) { return { dimensions: function() { var result = []; var dimensions = cube.dimensions; for (var key in dimensions) { result.push({ name: key, caption: dimensions[key].caption || key, uniqueName: key, defaultHierarchy: key, type: 1 }); } if (cube.measures) { result.push({ name: MEASURES, caption: MEASURES, uniqueName: MEASURES, type: 2 }); } return result; }, hierarchies: function() { return []; }, measures: function() { var result = []; var measures = cube.measures; for (var key in measures) { result.push({ name: key, caption: key, uniqueName: key, aggregator: key }); } return result; }, members: function(response, restrictions) { var name = restrictions.levelUniqueName || restrictions.memberUniqueName; var schemaData = this.options.schema.data; var dataGetter = isFunction(schemaData) ? schemaData : kendo.getter(schemaData, true); var data = this.options.data && dataGetter(this.options.data) || this._rawData || []; var result = []; var getter; var value; var idx = 0; var distinct = {}; if (name) { name = name.split(".")[0]; } if (!restrictions.treeOp) { result.push({ caption: cube.dimensions[name].caption || name, childrenCardinality: "1", dimensionUniqueName: name, hierarchyUniqueName: name, levelUniqueName: name, name, uniqueName: name }); return result; } getter = kendo.getter(normalizeName(name), true); for (; idx < data.length; idx++) { value = getter(data[idx]); if ((value || value === 0) && !distinct[value]) { distinct[value] = true; result.push({ caption: value, childrenCardinality: "0", dimensionUniqueName: name, hierarchyUniqueName: name, levelUniqueName: name, name: value, uniqueName: value }); } } return result; }.bind(this) }; }, options: { serverSorting: true, serverPaging: true, serverFiltering: true, serverGrouping: true, serverAggregates: true }, catalog: function(val) { if (val === undefined) { return this.transport.catalog(); } this.transport.catalog(val); this._mergeState({}); this._axes = {}; this.data([]); }, cube: function(val) { if (val === undefined) { return this.transport.cube(); } this.transport.cube(val); this._axes = {}; this._mergeState({}); this.data([]); }, axes: function() { return this._axes; }, columns: function(val) { if (val === undefined) { return this._columns; } this._skipNormalize += 1; this._clearAxesData = true; this._columns = normalizeMembers(val); this.query({ columns: val, rows: this.rowsAxisDescriptors(), measures: this.measures(), sort: this.sort(), filter: this.filter() }); }, rows: function(val) { if (val === undefined) { return this._rows; } this._skipNormalize += 1; this._clearAxesData = true; this._rows = normalizeMembers(val); this.query({ columns: this.columnsAxisDescriptors(), rows: val, measures: this.measures(), sort: this.sort(), filter: this.filter() }); }, measures: function(val) { if (val === undefined) { return this._measures; } this._skipNormalize += 1; this._clearAxesData = true; this.query({ columns: this.columnsAxisDescriptors(), rows: this.rowsAxisDescriptors(), measures: normalizeMeasures(val), sort: this.sort(), filter: this.filter() }); }, measuresAxis: function() { return this._measuresAxis || "columns"; }, _expandPath: function(path, axis) { var origin = axis === "columns" ? "columns" : "rows"; var other = axis === "columns" ? "rows" : "columns"; var members = normalizeMembers(path); var memberToExpand = getName(members[members.length - 1]); this._lastExpanded = origin; members = descriptorsForMembers(this.axes()[origin], members, this.measures()); for (var idx = 0; idx < members.length; idx++) { var memberName = getName(members[idx]); if (memberName === memberToExpand) { if (members[idx].expand) { return; } members[idx].expand = true; } else { members[idx].expand = false; } } var descriptors = {}; descriptors[origin] = members; descriptors[other] = this._descriptorsForAxis(other); this._query(descriptors); }, _descriptorsForAxis: function(axis) { var axes = this.axes(); var descriptors = this[axis]() || []; if (axes && axes[axis] && axes[axis].tuples && axes[axis].tuples[0]) { descriptors = descriptorsForAxes(axes[axis].tuples || []); } return descriptors; }, columnsAxisDescriptors: function() { return this._descriptorsForAxis("columns"); }, rowsAxisDescriptors: function() { return this._descriptorsForAxis("rows"); }, _process: function(data, e) { this._view = data; e = e || {}; e.items = e.items || this._view; this.trigger(CHANGE, e); }, _query: function(options) { var that = this; if (!options) { this._skipNormalize += 1; this._clearAxesData = true; } return that.query(extend({}, { page: that.page(), pageSize: that.pageSize(), sort: that.sort(), filter: that.filter(), group: that.group(), aggregate: that.aggregate(), columns: this.columnsAx