'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** * Licensed Materials - Property of IBM * IBM Cognos Products: Dashboard * (C) Copyright IBM Corp. 2018, 2020 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['./DataItem', '../../api/DataItemAPI', '../../visualizations/interactions/BinningActionsUtils', '../../util/TransactionUtil', '../../apiHelpers/SlotAPIHelper'], function (DataItem, DataItemAPI, BinningActionsUtils, TransactionUtil, SlotAPIHelper) { var MappedDataItem = function (_DataItem) { _inherits(MappedDataItem, _DataItem); function MappedDataItem(filterSupport, dataItemModel, slot, dataSource, transaction, locale, visualizationImpl, slotsImpl) { _classCallCheck(this, MappedDataItem); var _this = _possibleConstructorReturn(this, _DataItem.call(this, dataItemModel, dataSource, transaction, locale)); _this.visualizationImpl = visualizationImpl; _this.slotsImpl = slotsImpl; _this.localFilters = filterSupport.getLocalFilters(); _this.filterSupport = filterSupport; _this.slot = slot; /* The originalCustomGroupItemId (ie group sourceColumn) is required for driling so it needs to be persisted for module load consumption Since the public DataItem API no longer supports this method, we set it for now via the oldDataItemAPI TODO: ReEnvision custom groups architecture so this interim solution is no longer necessary. TODO: persist the original columnIds as part of the data source spec instead. This does not belong in the dataitem. TODO: AVOID calling getFeature('DataSources.moser') */ var shaping = _this.visualizationImpl.dashboardAPI.getFeature('DataSources.moser'); if (shaping && shaping.isConsumerGroupColumn) { var sourceId = _this.dataSourceAPI.getId(); var columnId = _this.getColumnId(); if (shaping.isConsumerGroupColumn(sourceId, columnId)) { var customGroup = shaping.getCustomGroupData(sourceId, columnId); if (customGroup && customGroup.basedOnMoserObjectId) { _this.dataItemModel.originalCustomGroupItemId = customGroup.basedOnMoserObjectId; } } } return _this; } MappedDataItem.prototype.getSlot = function getSlot() { return this.slot; }; MappedDataItem.prototype.destroy = function destroy() { _DataItem.prototype.destroy.call(this); this.visualizationImpl = null; this.slotsImpl = null; this.localFilters = null; this.filterSupport = null; }; MappedDataItem.prototype.setSlot = function setSlot(slot, transactionToken) { this.slot = slot; if (slot && this.getBinning()) { var canApplyBinning = this.visualizationImpl.getDefinition().getProperty('canApplyBinning'); if (!canApplyBinning || !SlotAPIHelper.doesDataItemSupportBinning(slot, this.getAPI())) { this.getAPI().setBinning(null, transactionToken); } } }; MappedDataItem.prototype.getType = function getType() { var slotType = void 0; if (this.slot) { var def = this.slot.getDefinition(); if (def.getSubType() === 'latitude' || def.getSubType() === 'longitude') { slotType = 'category'; } else if (def.getType() === 'any') { if (SlotAPIHelper.isMultiMeasuresSeriesSlot(this.slot)) { slotType = 'category'; } else if (this.getBinning()) { slotType = 'category'; } else { var metadata = this.getMetadataColumn(); if (metadata && metadata.getType() === 'attribute') { if (this.getAggregation() === DataItemAPI.AGGREGATION_TYPE.none) { slotType = 'category'; } else { slotType = 'ordinal'; } } else if (metadata && metadata.getType() === 'fact') { /** * - If one of the items in an 'any' slot is a measure, and we have more than one items, * then simply consider slot type to be category. * This prevents issues described in defect #255087 */ if (this.slot.getDataItemList().length > 1 && !this.slot.getDefinition().getProperty('repeats')) { slotType = 'category'; } else { slotType = 'ordinal'; } } } } if (!slotType) { slotType = def.getType(); } } return slotType && (slotType === 'ordinal' ? 'fact' : 'attribute'); }; MappedDataItem.prototype.setAggregation = function setAggregation(aggregationType, transactionToken) { if (!this.slot) { _DataItem.prototype.setAggregation.call(this, aggregationType, transactionToken); } else { var subTransaction = this.transaction.startTransaction(transactionToken); if (this.getType() === 'fact') { var currentAggregationType = this.getAggregation(); var localFilters = this.localFilters; var rangeFilterOnOldAggregationType = localFilters.getFilterEntry(localFilters.getOrdinalFilterKey(this.getColumnId(), currentAggregationType)); if (rangeFilterOnOldAggregationType) { var itemContext = { uniqueId: this.getId(), itemId: this.getColumnId(), itemName: this.getLabel(), dataType: this.getDataType(), sourceId: this.visualizationImpl.getDataSource().getId(), aggregationType: currentAggregationType }; this.visualizationImpl.getLocalFilters().removeFilter(itemContext, subTransaction); } } _DataItem.prototype.setAggregation.call(this, aggregationType, subTransaction); this.transaction.endTransaction(subTransaction); } }; MappedDataItem.prototype.getAggregation = function getAggregation() { if (!this.slot) { return _DataItem.prototype.getAggregation.call(this); } var mdColumn = this.getMetadataColumn(); if (!mdColumn) { return null; } var type = this.dataItemModel.aggregate; if (!type) { // TODO -- livewidget_cleanup --- apply this old code in here (used to be in visDataSlotsManager) // Basically if the category is in both measure and category slot, set the default aggregation to Count.. instead of var mappedSlots = this.slotsImpl.getMappedSlotList(); // Check to see if we have the same column in both the aggregations and dimensions, if so, default to aggType of 'count' if (this.slot.getDefinition().getType() === 'ordinal' && this.getMetadataColumn().getType() === 'attribute') { var itemId = this.getColumnId(); for (var i = 0; i < mappedSlots.length; i++) { var slotAPI = mappedSlots[i]; var slotDef = slotAPI.getDefinition(); if (slotDef.getType() === 'category' || slotDef.getType() === 'any') { var dataItemAPIs = slotAPI.getDataItemList(); for (var j = 0; j < dataItemAPIs.length; j++) { if (dataItemAPIs[j].getColumnId() === itemId) { type = 'count'; break; } } } // Stop once aggType is set. if (type) { break; } } } if (!type) { var _mdColumn = this.getMetadataColumn(); type = _mdColumn ? _mdColumn.getDefaultAggregation() : null; } } var def = this.slot.getDefinition(); if (def.getType() === 'any') { if (_DataItem.prototype.getType.call(this) === 'attribute') { if (!_DataItem.prototype.hasDefaultAggregation.call(this)) { return type; } else { type = DataItemAPI.AGGREGATION_TYPE.none; } } // fact assigned to a category slot should not aggregate } else if (def.getType() === 'category') { type = DataItemAPI.AGGREGATION_TYPE.none; // when an attribute is used in an ordinal slot, aggregation none doesn't make sense...consider it a count } else if (def.getType() === 'ordinal' && _DataItem.prototype.getType.call(this) === 'attribute' && type === DataItemAPI.AGGREGATION_TYPE.none) { var defaultAggrType = _DataItem.prototype.getMetadataColumn.call(this).getDefaultAggregation(); type = defaultAggrType === DataItemAPI.AGGREGATION_TYPE.none ? DataItemAPI.AGGREGATION_TYPE.countDistinct : defaultAggrType; } return type; }; /** * @function MappedDataItem#getFormat * @description Retrieve the format for the mapped data item. * @return {Object} An object containing format related properties. */ MappedDataItem.prototype.getFormat = function getFormat() { if (!this.slot) { return _DataItem.prototype.getFormat.call(this); } var widgetModel = this.visualizationImpl.widgetModel; // this comes from an upgraded dashboard where we want to change the KPI format. see SummaryKPIUpgrade.js var useSlotDefinitionFormat = widgetModel.enableSlotDefinitionFormat === false ? false : true; var slotDefinitionFormat = this._getDefinitionFormat(); var format = _DataItem.prototype.getFormat.call(this); if (useSlotDefinitionFormat && !format) { format = slotDefinitionFormat; } if (!format && (this.getMetadataColumn().getType() !== 'attribute' || _DataItem.prototype.isDateOrTimeType.call(this))) { // Default format format = { 'selectedFormat': 'none', // This property does not appear to be used anymore, it may be replaced with dateStyle 'maximumFractionDigits': 2, 'formatLength': 'short' // This property is only applicable for dates }; if (_DataItem.prototype.isDateOrTimeType.call(this)) { format.type = this.getMetadataColumn().getDataType(); } } // resolve the proper format when have an invalid format var metadataColumn = this.getMetadataColumn(); if (format && metadataColumn) { var dataType = metadataColumn.getDataType(); var isDateOrTimeType = dataType === 'date' || dataType === 'datetime' || dataType === 'time' || dataType === 'year' ? true : false; if (isDateOrTimeType) { isDateOrTimeType = this.getType() !== 'ordinal'; } var formatType = format && format.type; var invalidDateFormatting = isDateOrTimeType && metadataColumn.getType() !== 'attribute' && ['date', 'time', 'datetime'].indexOf(formatType) === -1; var invalidBinningFormatting = this.getBinning() && (formatType === 'currency' || formatType === 'percent'); if (invalidDateFormatting || invalidBinningFormatting || !isDateOrTimeType && ['date', 'time', 'datetime'].indexOf(formatType) > -1) { format = { 'selectedFormat': 'none', 'maximumFractionDigits': 2, 'formatLength': 'short', 'locale': this.locale }; if (invalidDateFormatting || invalidBinningFormatting) { format.type = metadataColumn.getDataType(); } } } // Overwrite the format type to be number if the dataItem is fact and doesn't already have a number format spec set if (this.getType() === 'fact') { if (_DataItem.prototype.isDateOrTimeType.call(this) && format && format.type !== 'number') { // Default format return { 'selectedFormat': 'none', 'maximumFractionDigits': 2, 'formatLength': 'short', 'type': 'number', 'locale': this.locale }; } else if (!format && (_DataItem.prototype.getAggregation.call(this) === 'count' || _DataItem.prototype.getAggregation.call(this) === 'countdistinct')) { //If the item is assigned to an ordinal slot and it has aggregation type count or countdistinct and no format specified, //return a default (1 decimal number) //this should be changed back to 0 when implementation of VIDA story for using tickInterval is finished. See story 228160 return { 'selectedFormat': 'none', 'maximumFractionDigits': 1, 'formatLength': 'short', 'type': 'number', 'locale': this.locale }; } } // TODO -- livewidget_cleanup - we should not add .selectedFormat to set the ui to auto. We should simply call the hasDefaultFormat() API // ensure use auto if using default format if (format && _DataItem.prototype.hasDefaultFormat.call(this)) { format.selectedFormat = 'none'; } if (format && !format.locale) { format.locale = this.locale; } return format; }; MappedDataItem.prototype._getDefinitionFormat = function _getDefinitionFormat() { var definitionFormat = null; var format = this.slot.getDefinition().getFormat(); if (format) { definitionFormat = Object.assign({ locale: this.locale }, format); } return definitionFormat; }; /** * Updates the priority field on any sort entries on all slots, such that they enforce priority order as implied by the slot definition order. * This is done before a new sort is added, and the events are silent, as the sort addition will send a non-silent event to trigger render. * @param {string} slotId - the id of the slot having sort added * @param {string} dataItemId - the id of the data item having sort added * @param {number} explicitPriority (optional) - the priority explicitly given to the data item. * If omitted, the priority will be assigned automatically based on the existing data item sorts * @param {object} options */ MappedDataItem.prototype._setSortPriorities = function _setSortPriorities(slotId, dataItemId, explicitPriority) { var _this2 = this; var isExplicitPriority = typeof explicitPriority !== 'undefined' && explicitPriority !== null; var priority = 0, newPriority = void 0; var mappedSlotList = this.slotsImpl.getMappedSlotList(); mappedSlotList.forEach(function (slot) { var currentSlotId = slot.getId(); var dataItemList = slot.getDataItemList(); dataItemList.forEach(function (dataItem) { if (slotId === currentSlotId && dataItem.getId() === dataItemId) { //This is the item which will have its sort set - record the priority it's at newPriority = isExplicitPriority ? explicitPriority : priority++; } else if (dataItem.getSort()) { //Existing item - adjust its priority var shift = isExplicitPriority && priority >= explicitPriority; if (!dataItem.hasDefaultSort()) { var sort = dataItem.getSort(); sort.priority = shift ? ++priority : priority++; _this2.slotsImpl.getDataItemImpl(dataItem.getId())._setSortWithoutAdjustingPriority(sort); } } }); }); return newPriority; }; MappedDataItem.prototype._setSortWithoutAdjustingPriority = function _setSortWithoutAdjustingPriority(params, transactionToken) { return _DataItem.prototype.setSort.call(this, params, transactionToken); }; MappedDataItem.prototype.setSort = function setSort(params, transactionToken) { var sortSpec = params ? JSON.parse(JSON.stringify(params)) : {}; if (!this.slot) { return _DataItem.prototype.setSort.call(this, sortSpec, transactionToken); } if (sortSpec) { // TODO - make the the setSortPriorities is abble to reset to previous prioroties if the sortSpec is not defined (i.e. clearing the sort) //Adjust priority setting on existing sorts prior to setting actual sort sortSpec.priority = this._setSortPriorities(this.slot.getId(), this.getId(), sortSpec.priority); } return _DataItem.prototype.setSort.call(this, sortSpec, transactionToken); }; MappedDataItem.prototype.hasModelSort = function hasModelSort() { return !!this._getDefaultSort(); }; MappedDataItem.prototype._getDefaultSort = function _getDefaultSort() { var _this3 = this; var mdColumn = this.getMetadataColumn(); var sortType = mdColumn ? mdColumn.getDefaultSortType() : null; if (sortType) { // model sort found. // Calculate sort priority for model sort. var dataItemSortPriority = 0; var modelSortItemIdx = 0; var modelSortItemFound = false; this.slotsImpl.getDataItemImplList().forEach(function (dataItem) { var sortObj = dataItem._getUserSort(); if (sortObj) { // User defined sort is set/saved with dataitems with highest priority. // Priorty numbers are in ascending order with 0 been the highest priority. // Find the lowest priority for user defined sort. if (dataItemSortPriority < sortObj.priority) { dataItemSortPriority = sortObj.priority; } } else if (!modelSortItemFound) { // Find the index of the model sort data item over all dataitems with model sort but without user defned sort. var currentItemId = dataItem.getColumnId(); var currentItemMdColumn = dataItem.getMetadataColumn(); var modelSortType = currentItemMdColumn ? currentItemMdColumn.getDefaultSortType() : null; if (modelSortType) { modelSortItemIdx++; modelSortItemFound = currentItemId === _this3.getColumnId(); } } }); return { type: sortType, by: 'caption', // The current model sort priority should be the highest user defined sort priorty number plus // the index of the model sort data item over all dataitems with model sort but without user defned sort. priority: dataItemSortPriority + modelSortItemIdx }; } return null; }; MappedDataItem.prototype.getSort = function getSort() { if (!this.slot) { return _DataItem.prototype.getSort.call(this); } var dataItemSort = _DataItem.prototype.getSort.call(this); if (!dataItemSort) { dataItemSort = this._getDefaultSort(); } if (!dataItemSort || !dataItemSort.type) { var metadataColumn = this.getMetadataColumn(); var defaultSort = metadataColumn && !metadataColumn.isOlapColumn() && !metadataColumn.isNamedSet() && this.slot.getDefinition().getSort(); if (defaultSort) { dataItemSort = dataItemSort && dataItemSort.custom ? _extends({}, dataItemSort, { type: defaultSort }) : { type: defaultSort }; } } if (dataItemSort && dataItemSort.rankSort) { delete dataItemSort.rankSort; } return dataItemSort; }; //Crurrently AutobinDialog listens on BA-UI-TOOLKIT NumberInput's onChange event //However, there are cases that it is not the change of the number input's value that //caused the onChange event but just a blur or focus on number input //Currently onChange event that executs auto bin action, therefore, to avoid unecssary //auto bin action, we compare the incoming state's value with the dataitem's existing //binning state, we only execute auto bin action for new values MappedDataItem.prototype._isSameNumberOfBins = function _isSameNumberOfBins(binningSpec) { if (!binningSpec) { return false; } var binningInfo = this.getBinning(); if (!binningInfo) { return false; } if (binningInfo.bins !== binningSpec.bins) { return false; } return true; }; MappedDataItem.prototype.setBinning = function setBinning(binningSpec, transactionToken) { if (!this.slot) { _DataItem.prototype.setBinning.call(this, binningSpec, transactionToken); } else if (!this._isSameNumberOfBins(binningSpec)) { var options = TransactionUtil.transactionTokenToOptions(transactionToken); this.filterSupport.clearSelectionsByDataItemIds([this.getColumnId()]); BinningActionsUtils.removeCompoundFilters(this.slot, this.localFilters, options); var binningFilters = BinningActionsUtils.getBinningFilters(this.localFilters, this); if (binningFilters) { BinningActionsUtils.removeLocalBinnedFilterEntries(this.localFilters, binningFilters, options); } _DataItem.prototype.setBinning.call(this, binningSpec, transactionToken); } }; MappedDataItem.prototype.setFormat = function setFormat(spec, transactionToken) { var formatSpec = JSON.parse(JSON.stringify(spec)); if (!this.slot) { return _DataItem.prototype.setFormat.call(this, formatSpec, transactionToken); } var binningFilters = void 0; var options = TransactionUtil.transactionTokenToOptions(transactionToken); if (_DataItem.prototype.getBinning.call(this)) { //for any changes in binning we need clear all selection filters, it will not be part of undo/redo this.filterSupport.clearSelectionsByDataItemIds([_DataItem.prototype.getColumnId.call(this)]); BinningActionsUtils.removeCompoundFilters(this.slot, this.localFilters, options); binningFilters = formatSpec ? BinningActionsUtils.getBinningFilterForFormatedItem(formatSpec, this.localFilters, this) : null; } var clientSideDataFormatting = binningFilters ? false : true; if (binningFilters) { BinningActionsUtils.removeLocalBinnedFilterEntries(this.localFilters, binningFilters, options); } if (clientSideDataFormatting) { //Only re-send the query if needed since formatting is done on the client side so set dataIfQueryChanged to true. //Reasons why binned has to be formatted on the server side due to how the values are returned. Examples of binned values returned from DSS: //'less than 202.309000, '202.309000 to < 404.608000', '404.608000 to < 606.907000' //So the client side cannot format such values if (!options.payloadData) { options.payloadData = {}; } options.payloadData.dataIfQueryChanged = true; } // TODO livewidget_cleanup --- should be passing a transction token and not options !! _DataItem.prototype.setFormat.call(this, formatSpec, options); }; return MappedDataItem; }(DataItem); return MappedDataItem; }); //# sourceMappingURL=MappedDataItem.js.map