DataPointSelections.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. 'use strict';
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. 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; }
  4. 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; }
  5. /**
  6. * Licensed Materials - Property of IBM
  7. * IBM Cognos Products: Dashboard
  8. * (C) Copyright IBM Corp. 2019, 2020
  9. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  10. */
  11. /**
  12. * @class DataPointSelections
  13. * @hideconstructor
  14. */
  15. define(['underscore', '../../../../lib/@waca/dashboard-common/dist/core/APIFactory', './api/DataPointSelectionsAPI', './api/deprecated/DataPointSelectionsAPI', './api/DataPointSelectionsAPISpec', '../../../../util/ContentUtil', '../../../../lib/@waca/dashboard-common/dist/utils/ContentUtil', './VisSelected', './PendingSelections'], function (_, APIFactory, DataPointSelectionsAPI, DeprecatedDataPointSelectionsAPI, DataPointSelectionsAPISpec, ContentUtil, CommonContentUtil, VisSelected, PendingSelections) {
  16. var DataPointSelections = function (_DataPointSelectionsA) {
  17. _inherits(DataPointSelections, _DataPointSelectionsA);
  18. function DataPointSelections(options) {
  19. _classCallCheck(this, DataPointSelections);
  20. var _this = _possibleConstructorReturn(this, _DataPointSelectionsA.call(this, options));
  21. _this.content = options.content;
  22. _this.dashboard = options.dashboardAPI;
  23. return _this;
  24. }
  25. DataPointSelections.prototype.getAPI = function getAPI(type) {
  26. if (type === 'deprecated') {
  27. if (!this._deprecatedApi) {
  28. this._deprecatedApi = APIFactory.createAPI(this, [DataPointSelectionsAPI, DeprecatedDataPointSelectionsAPI]);
  29. }
  30. return this._deprecatedApi;
  31. }
  32. if (type === 'pending') {
  33. if (!this._pending) {
  34. var pendingSelections = new PendingSelections();
  35. this._pending = APIFactory.createAPI(pendingSelections, [DataPointSelectionsAPI]);
  36. }
  37. return this._pending;
  38. }
  39. if (!this._api) {
  40. this._api = APIFactory.createAPI(this, [DataPointSelectionsAPI]);
  41. }
  42. return this._api;
  43. };
  44. DataPointSelections.prototype.select = function select(selections, transactionToken) {
  45. var legacySelection = this._getLegacySelection(selections);
  46. var multiTuple = selections && selections.length > 1;
  47. var controller = this._getController();
  48. controller.select({
  49. itemIds: legacySelection.columnIds,
  50. tuple: legacySelection.tuple,
  51. command: 'update',
  52. slotsToClear: [],
  53. pending: false,
  54. edgeSelect: legacySelection.edgeSelect,
  55. multiTuple: multiTuple
  56. }, transactionToken);
  57. };
  58. /**
  59. * deselect current selections.
  60. * @param {*} selections The selected items to deselect
  61. * @param {*} transactionToken the transaction Token
  62. * @param {*} forceClearSlots if true, clear all slots regardless if there is a selection
  63. */
  64. DataPointSelections.prototype.deselect = function deselect(selections, transactionToken) {
  65. var forceClearSlots = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  66. var legacySelection = this._getLegacySelection(selections);
  67. var multiTuple = selections && selections.length > 1;
  68. var visualization = this.content.getFeature('Visualization');
  69. var controller = this._getController();
  70. var _slotsToClear = forceClearSlots ? visualization.getSlots().getMappedSlotList() : this._getSlotsToClear(selections);
  71. return controller.select({
  72. itemIds: legacySelection.columnIds,
  73. tuple: legacySelection.tuple,
  74. command: 'remove',
  75. slotsToClear: _slotsToClear,
  76. pending: false,
  77. edgeSelect: legacySelection.edgeSelect,
  78. multiTuple: multiTuple
  79. }, transactionToken);
  80. };
  81. DataPointSelections.prototype._getSelectionValues = function _getSelectionValues(selections) {
  82. // Default. Use the current selections
  83. return _.chain(selections || this.getSelections()).map(function (selection) {
  84. return selection.categories;
  85. }).flatten().map(function (selection) {
  86. return selection.value;
  87. }).value();
  88. };
  89. DataPointSelections.prototype._getSlotsToClear = function _getSlotsToClear(selections) {
  90. var values = this._getSelectionValues(selections);
  91. var current = this._getSelectionValues();
  92. if (values.length === current.length && !_.difference(values, current).length) {
  93. var visualization = this.content.getFeature('Visualization');
  94. return visualization.getSlots().getMappedSlotList();
  95. }
  96. return [];
  97. };
  98. DataPointSelections.prototype.clearAll = function clearAll(transactionToken) {
  99. var selections = this._buildSelections( /*selectedDataItemList*/[], /*strictMatch*/false) || [];
  100. return this.deselect(selections, transactionToken, true);
  101. };
  102. DataPointSelections.prototype._getVisualization = function _getVisualization() {
  103. if (!this.visualization) {
  104. this.visualization = this.content.getFeature('Visualization');
  105. }
  106. return this.visualization;
  107. };
  108. DataPointSelections.prototype._getController = function _getController() {
  109. if (!this.controller) {
  110. this.controller = this.content.getFeature('SelectionController.deprecated');
  111. }
  112. return this.controller;
  113. };
  114. DataPointSelections.prototype._getLegacySelection = function _getLegacySelection(selections) {
  115. var legacySelection = {
  116. columnIds: [],
  117. tuple: [],
  118. edgeSelect: !!_.find(selections, function (selection) {
  119. return selection.edgeSelect;
  120. })
  121. };
  122. selections.forEach(function (selection) {
  123. var values = [];
  124. var addedValues = [];
  125. selection.categories.forEach(function (category) {
  126. if (!(legacySelection.columnIds.indexOf(category.columnId) !== -1)) {
  127. legacySelection.columnIds.push(category.columnId);
  128. }
  129. if (!(addedValues.indexOf(category.columnId + category.value) !== -1)) {
  130. values.push({ u: category.value, d: category.label });
  131. addedValues.push(category.columnId + category.value);
  132. }
  133. });
  134. if (values.length) {
  135. legacySelection.tuple.push(values);
  136. }
  137. });
  138. return legacySelection;
  139. };
  140. DataPointSelections.prototype.getSelections = function getSelections() {
  141. var selectedDataItemList = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  142. return this._buildSelections(selectedDataItemList);
  143. };
  144. DataPointSelections.prototype._getScope = function _getScope() {
  145. var type = this.dashboard.getAppConfig('pageContainerType');
  146. var page = CommonContentUtil.getPageContent(this.content, type);
  147. var scope = page && page.getId();
  148. return scope;
  149. };
  150. DataPointSelections.prototype._getEventGroupId = function _getEventGroupId() {
  151. var eventGroups = this.dashboard.getFeature('EventGroups');
  152. var eventGroupId = eventGroups.getGroupId(this.content.getId());
  153. return eventGroupId;
  154. };
  155. DataPointSelections.prototype._getPageContext = function _getPageContext() {
  156. if (!this._pageContext) {
  157. this._pageContext = ContentUtil.getPageContext(this.dashboard);
  158. }
  159. return this._pageContext;
  160. };
  161. DataPointSelections.prototype._buildSelections = function _buildSelections(selectedDataItemList) {
  162. var strictMatch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  163. var dataPointSelections = [];
  164. var dataSource = this._getVisualization().getDataSource();
  165. var sourceId = dataSource && dataSource.getId();
  166. if (sourceId) {
  167. var _dataPointSelections;
  168. var selectors = {
  169. scope: this._getScope(),
  170. eventGroupId: this._getEventGroupId(),
  171. sourceId: sourceId,
  172. origin: 'visualization',
  173. eventSourceId: this.content.getId(),
  174. _strictMatch: strictMatch
  175. };
  176. var slots = this._getVisualization().getSlots();
  177. var mappedDataItemList = slots.getDataItemList();
  178. /**
  179. * If there is either brushing or pending filters collect data points or edge values.
  180. * Note: pageContextEntry.getDataPoints() returns an array of array, i.e. an array of tuples,
  181. * while pageContextEntry.getValues() returns an array of values.
  182. */
  183. var netPageContext = this._getPageContext().getNetPageContextItems(selectors);
  184. (_dataPointSelections = dataPointSelections).push.apply(_dataPointSelections, this._getValues(netPageContext, selectedDataItemList, mappedDataItemList));
  185. if (dataPointSelections.length) {
  186. dataPointSelections = this._uniqueValues(dataPointSelections);
  187. }
  188. }
  189. return dataPointSelections;
  190. };
  191. DataPointSelections.prototype._getValues = function _getValues(pageContextEntries, selectedDataItemList, mappedDataItemList) {
  192. var _this2 = this;
  193. var payloadValueList = [];
  194. var payloadValue = null;
  195. var dataItem = null;
  196. if (pageContextEntries && pageContextEntries.length) {
  197. pageContextEntries.forEach(function (pEntry) {
  198. var columnIdList = pEntry.getItemIds();
  199. if (pEntry.isDataPointType()) {
  200. var payloadTupleList = [];
  201. var tupleList = pEntry.getDataPoints();
  202. tupleList.forEach(function (tuple) {
  203. var payloadTuple = [];
  204. tuple.forEach(function (value, valueIdx) {
  205. dataItem = _this2._getDataItem(columnIdList[valueIdx], selectedDataItemList, mappedDataItemList);
  206. if (dataItem && dataItem.getType() === 'attribute') {
  207. payloadValue = _this2._toPayLoadValue(value, columnIdList[valueIdx], dataItem.getId());
  208. payloadTuple.push(payloadValue);
  209. }
  210. });
  211. payloadTupleList.push({
  212. categories: payloadTuple
  213. });
  214. });
  215. payloadValueList.push.apply(payloadValueList, payloadTupleList);
  216. } else {
  217. var values = pEntry.getValues();
  218. values.forEach(function (value) {
  219. dataItem = _this2._getDataItem(columnIdList[0], selectedDataItemList, mappedDataItemList);
  220. if (dataItem && dataItem.getType() === 'attribute') {
  221. payloadValue = _this2._toPayLoadValue(value, columnIdList[0], dataItem.getId());
  222. payloadValueList.push({
  223. categories: [payloadValue]
  224. });
  225. }
  226. });
  227. }
  228. });
  229. }
  230. return payloadValueList;
  231. };
  232. DataPointSelections.prototype._getDataItem = function _getDataItem(columnId, selectedDataItemList, mappedDataItemList) {
  233. var dataItem = _.find(selectedDataItemList, function (dataItem) {
  234. return dataItem.getColumnId() === columnId;
  235. });
  236. if (!dataItem) {
  237. dataItem = _.find(mappedDataItemList, function (dataItem) {
  238. return dataItem.getColumnId() === columnId;
  239. });
  240. }
  241. return dataItem;
  242. };
  243. DataPointSelections.prototype._toPayLoadValue = function _toPayLoadValue(value, columnId, dataItemId) {
  244. var resultPayLoad = {
  245. dataItemId: dataItemId,
  246. columnId: columnId,
  247. value: value.u,
  248. label: value.d
  249. };
  250. if (value.p) {
  251. resultPayLoad.parentId = value.p.u;
  252. }
  253. return resultPayLoad;
  254. };
  255. DataPointSelections.prototype._uniqueValues = function _uniqueValues() {
  256. var dataPointSelections = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  257. var uniqueValues = [];
  258. var valuesMap = {};
  259. dataPointSelections.forEach(function (dataPoint) {
  260. var categoryKey = _.pluck(dataPoint.categories, 'value').join();
  261. if (!valuesMap[categoryKey]) {
  262. valuesMap[categoryKey] = 1;
  263. uniqueValues.push(dataPoint);
  264. }
  265. });
  266. return uniqueValues;
  267. };
  268. DataPointSelections.prototype.isSelected = function isSelected(selectionPayload) {
  269. var resolvedSelections = this._getLegacySelection(selectionPayload);
  270. return resolvedSelections.edgeSelect ? this._isEdgeSelected(selectionPayload) : this._isDataPointSelected(resolvedSelections);
  271. };
  272. /**
  273. * @return {boolean} true if the resolved items are identical to the current selection
  274. */
  275. DataPointSelections.prototype._isDataPointSelected = function _isDataPointSelected(resolvedSelections) {
  276. var selection = this.getSelection(resolvedSelections.columnIds);
  277. return selection ? selection.isSelected(_.flatten(resolvedSelections.tuple)) : false;
  278. };
  279. /**
  280. * @return {boolean} true if the resolved items are identical to the current selection
  281. */
  282. DataPointSelections.prototype._isEdgeSelected = function _isEdgeSelected(selections) {
  283. var _this3 = this;
  284. var getSelectedEdgeValues = function getSelectedEdgeValues(columnId) {
  285. return _this3._getController().getSelectedTuples([columnId]);
  286. };
  287. // The format of resolved and the result of visSelectionController.getSelectedTuples() do not match.
  288. // Perform a sequence of operations to transform the output of getSelectedTuples() into the same format as resolved.
  289. var selectionTuples = _.chain(_.map(this._getVisualization().getSlots().getDataItemList(), function (dataItem) {
  290. var columnId = dataItem.getColumnId();
  291. var values = getSelectedEdgeValues(columnId);
  292. return _.map(values, function (value) {
  293. value.label = _.isUndefined(value.label) ? value.d : value.label;
  294. value.value = _.isUndefined(value.value) ? value.u : value.value;
  295. return {
  296. columnId: columnId,
  297. tupleItem: value
  298. };
  299. });
  300. })).flatten().filter(function (itemTuplePair) {
  301. return !!itemTuplePair.tupleItem;
  302. }) // Remove items with empty tuples
  303. .value(); // End sequence of transformations - get final array
  304. // check if the resolved tuple is a subset of the selectionTuples
  305. var isSelected = true;
  306. var categorySelections = _.pluck(selections, 'categories');
  307. _.each(categorySelections, function (resolvedTuple) {
  308. _.each(resolvedTuple, function (tupleValue) {
  309. isSelected = isSelected ? !!_.find(selectionTuples, function (selectedTuple) {
  310. return selectedTuple.columnId === tupleValue.columnId && selectedTuple.tupleItem.u === tupleValue.value;
  311. }) : false;
  312. });
  313. });
  314. return isSelected;
  315. };
  316. /**
  317. * Get a selection object that corresponds to the supplied list of itemIds.
  318. * @param itemIds array of item ids to be considered part of the selection
  319. * If omitted, apply all dataitem
  320. * @param {object} options selection options to describe the selection
  321. * @param {boolean} options.includeParents[includeParents=false]- if includes parents; default to false
  322. * @param {boolean} options.ignoreEdgeSelections[ignoreEdgeSelections=false] - if includes parents; default to false
  323. * @return selection object
  324. */
  325. DataPointSelections.prototype.getSelection = function getSelection(itemIds, options) {
  326. if (!itemIds) {
  327. itemIds = ContentUtil.getColumnIdList(this._getVisualization().getSlots().getMappedSlotList(), 'attribute');
  328. }
  329. return this._getSelected(itemIds, options);
  330. };
  331. /**
  332. * Return a proxy object that returns the selected items/tuples as an object for fast lookup.
  333. * @param itemIds - the itemIds that form a tuple as an array ['Products', 'Years']
  334. * (also supports a single itemId)
  335. * @returns a proxy object that returns an isSelected interface about what is selected by the itemIds.
  336. * or null if no selections exist for any of the set of items.
  337. */
  338. DataPointSelections.prototype._getSelected = function _getSelected(itemIds, options) {
  339. if (!this._getVisualization().getDataSource()) {
  340. return null;
  341. }
  342. var visualization = this._getVisualization();
  343. var dataSource = visualization.getDataSource();
  344. var selected = new VisSelected({
  345. pageContextAPI: this._getPageContext(),
  346. itemIds: Array.isArray(itemIds) ? itemIds : [itemIds],
  347. scope: this._getScope(),
  348. eventGroupId: this._getEventGroupId(),
  349. sourceId: dataSource && dataSource.getId(),
  350. includeParents: options && options.includeParents === true ? true : false, //Default including parents to false (not applicable to charts)
  351. ignoreEdgeSelections: options && options.ignoreEdgeSelections === true ? true : false,
  352. synchronizeData: this._getController().synchronizeData // TODO will be replaced with synchronized feature soon
  353. });
  354. return selected.hasSelections() ? selected.getAPI() : null;
  355. };
  356. return DataPointSelections;
  357. }(DataPointSelectionsAPISpec);
  358. return DataPointSelections;
  359. });
  360. //# sourceMappingURL=DataPointSelections.js.map