@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
1,404 lines (1,155 loc) • 250 kB
JavaScript
import './kendo.dom.js';
import './kendo.data.js';
import './kendo.icons.js';
import './kendo.loader.js';
import './kendo.html.loadercontainer.js';
import './kendo.sortable.js';
import { fetchDiscover, fetchData, createDataState, PivotGridNavigation, headersReducer, toData, toTree, toColumns, toRows, sumAggregate, setSort, setFilter, rootFields, readData, parseResponse, minAggregate, mergeTrees, maxAggregate, discoverCommands, createTuples, createRequestBody, createLocalDataState, createFlatSchemaDimensions, createDiscoverBody, createDataTree, createAxisDescriptors, configuratorReducer, compareAxes, cloneDataTree, buildKPIMeasures, averageAggregate, addMultipleMeasures, addKPI, countAggregate } from '@progress/kendo-pivotgrid-common';
import { u as useLoaderContainer } from './loaderContainer-CKYFB4vJ.js';
import './kendo.core.js';
import './kendo.licensing.js';
import '@progress/kendo-licensing';
import './kendo.data.odata.js';
import './kendo.data.xml.js';
import './kendo.html.icon.js';
import './kendo.html.base.js';
import '@progress/kendo-svg-icons';
import './kendo.draganddrop.js';
import './kendo.userevents.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$1) {
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>` : " " : " "),
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";
var tableStyles = {
tableRow: "k-table-row",
header: "k-header k-table-th",
headerTable: "k-grid-header-table k-table k-table-md",
table: "k-table k-table-md",
contentTable: "k-grid-table k-table k-table-md",
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$1 ? [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$1 ? [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 if no member or 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 }); //calling normalize here to make name from string to array
}
}
}
}
function tupleToDescriptors(tuple) {
var result = [];
var members = tuple.members;
for (var idx = 0; idx < members.length; idx++) {
if (members[idx].measure) {
continue;
}
//make tuple name an array
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: 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 = ' ';
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 = createDataTree(originalData, rowSettings, columnSettings, measures, { dataField: "aggregate", columnsData: "columns" }, that.filter() || []);
const stateArgs = {
dataTree: dataTree,
columnSettings: columnSettings,
rowSettings: 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(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": sumAggregate,
"average": averageAggregate,
"min": minAggregate,
"max": maxAggregate,
"count": countAggregate,
};
var valueFunc = function(item) { return item[this.field]; };
var measure = {
value: valueFunc.bind({ field: field }),
aggregate: measureMap[aggregate],
caption: key,
uniqueName: key,
type: 2,
name: [key]
};
if (format) {
measure.aggregate.format = formatFunc.bind({ format: 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$1) {
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: name,
levelName: name,
levelNum: "0",
hasChildren: true,
parentName: parts.length > 1 ? parts[0] : undefined$1,
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$1,
hierarchy: "MEASURES"
};
}
result[result.length] = root;
}
keys.push(ROW_TOTAL_KEY);
}
return {
keys: 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 there are no root this means that something is expanding
//and we should only sort that part of the tree
if (!sortTree.length) {
for (key in map) {
sortTree.push($.extend({}, { name: key, parentName: map[key].parentName }));
}
}
fillSortTree(sortTree, map);
// fill tree recursive
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);
//we need to flatten the structure so the tuples can build correctly
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: name,
levelName: name,
levelNum: "0",
hasChildren: true,
parentName: parts.length > 1 ? parts[0] : undefined$1,
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$1,
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: formats,
resultFuncs: resultFuncs,
rowAxis: 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: ordinal,
value: value || "",
fmtValue: 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$1 && 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];
//checks whether the dataItem is relevant to the descriptors
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$1 && value !== null) ? value.toString() : value;
parentName = name;
name = name + "&" + value;
key = path + name;
column = columns[key] || {
index: state.columnIndex,
parentName: parentName,
name: name,
directParentName: path.indexOf("&") !== -1 ? path : "",
uniquePath: path + parentName,
childrenMap: {},
value: 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: 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: 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$1 ? rowValue.toString() : rowValue;
rowName = rowName + "&" + rowValue;
key = path + rowName;
rows[key] = {
uniquePath: path + parentName,
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$1) {
return (options.connection || {}).catalog;
}
var connection = options.connection || {};
connection.catalog = val;
this.options.connection = connection;
$.extend(this.transport.options, { connection: connection });
},
cube: function(val) {
var options = this.options || {};
if (val === undefined$1) {
return (options.connection || {}).cube;
}
var connection = options.connection || {};
connection.cube = val;
this.options.connection = connection;
extend(true, this.transport.options, { connection: 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$1) {
return this.transport.catalog();
}
this.transport.catalog(val);
this._mergeState({});// clears current state
this.read();
},
cube: function(val) {
if (val === undefined$1) {
return this.transport.cube();
}
this.transport.cube(val);
this._mergeState({});// clears current state
this.read();
},
measuresAxis: function() {
return this._measuresAxis || "columns";
},
fetch: function(callback) {
var that = this;
if (this._data === undefined$1 || 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];
settings.push({
key: key,
displayValue: displayValueFunc.bind({ key: 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));
}
retu