CrosstabView.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. 'use strict';
  2. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  3. /**
  4. * Licensed Materials - Property of IBM
  5. * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2016, 2020
  6. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  7. */
  8. define(['../VisView', './CrosstabGrid', '../../../widgets/livewidget/nls/StringResources', 'text!./Crosstab.html', '../../../DynamicFileLoader', 'jquery', 'underscore', '../VisEventHandler', './CrosstabEventTarget', '../../../util/ContentUtil'], function (VisView, CrosstabGrid, StringResources, CrosstabTemplate, DynamicFileLoader, $, _, VisEventHandler, CrosstabEventTarget, ContentUtil) {
  9. 'use strict';
  10. var ROW_SLOT_ID = 'row_level1';
  11. var COLUMN_SLOT_ID = 'column_level1';
  12. var CrosstabView = VisView.extend({
  13. className: 'dataview crosstab-widget',
  14. templateString: CrosstabTemplate,
  15. alwaysRenderOnResize: true,
  16. /**
  17. * Initialize the view and its handlers, then render.
  18. */
  19. init: function init() {
  20. CrosstabView.inherited('init', this, arguments);
  21. this.visModel.on('change:theme', this.onChangeTheme, this);
  22. this.isMobilePannable = true;
  23. this.visProperties = this.visModel.getProperties();
  24. this.styleProxy = this.visModel.getVisPropertiesCSSProxy();
  25. this.rowHeadingProperties = this._getPropertiesForPrefix('rowHeading');
  26. this.columnHeadingProperties = this._getPropertiesForPrefix('columnHeading');
  27. this.dataValueProperties = this._getPropertiesForPrefix('values');
  28. this.valueHeadingProperties = this._getPropertiesForPrefix('valueHeading');
  29. this.summaryProperties = this._getPropertiesForPrefix('summary');
  30. this.selectedAreaProperties = this._getPropertiesForPrefix('selectedArea');
  31. this.content = this.content || this.dashboardApi.getCanvas().getContent(this.ownerWidget.getId());
  32. if (this._isNewConditionalFormatFeature()) {
  33. this._conditionalFormatting = this.content.getFeature('ConditionalFormatting');
  34. } else {
  35. // deregister here since the new component do not have access to the dashboardAPI to check whether the feature flag is turned on or off
  36. // Instead when the new feature gets loaded it always register itself with the 'Properties' and 'CustomColor' feature
  37. // Remove this code when the new feature get turn on by default
  38. var newCondFeature = this.content.getFeature('ConditionalFormatting');
  39. if (newCondFeature) {
  40. var properties = this.content.getFeature('Properties');
  41. var customColor = this.dashboardApi.getFeature('CustomColor');
  42. properties.deregisterProvider(newCondFeature);
  43. customColor.deregisterProvider(newCondFeature);
  44. }
  45. }
  46. this._crosstabGrid = new CrosstabGrid({
  47. $el: this.$el.find('.crosstab-widget'),
  48. visModel: this.visModel,
  49. dashboardApi: this.dashboardApi,
  50. colorsService: this.dashboardApi.getFeature('Colors'),
  51. crosstabView: this,
  52. conditionalFormatting: this._conditionalFormatting
  53. });
  54. },
  55. onChangeTheme: function onChangeTheme() {
  56. this.visModel.getRenderSequence().reRender();
  57. },
  58. getGrid: function getGrid() {
  59. return this._crosstabGrid;
  60. },
  61. getDescription: function getDescription() {
  62. // Append the F12 key instruction to the description
  63. var description = CrosstabView.inherited('getDescription', this, arguments);
  64. return StringResources.get('WidgetLabelWithDescripion', {
  65. label: description,
  66. description: StringResources.get('f12KeyDescription')
  67. });
  68. },
  69. /**
  70. * Handle the on container entered event
  71. * Sets up keyboard navigation inside the list
  72. * @return undefined
  73. */
  74. onEnterContainer: function onEnterContainer() {
  75. this._crosstabGrid.onEnterContainer();
  76. },
  77. /**
  78. * @Override VisView.getCurrentViewSelector()
  79. */
  80. //TODO: This might need to be abstracted at higher level
  81. getCurrentViewSelector: function getCurrentViewSelector() {
  82. return this.eventHandler;
  83. },
  84. /**
  85. * render the results.
  86. * @param {Object} renderInfo - renderInfo passed to all render methods from the render sequence.
  87. * @returns a promise which is resolved when rendering has completed.
  88. */
  89. render: function render(renderInfo) {
  90. var _this = this,
  91. _arguments = arguments;
  92. return this._initializeConditionalFormatting().then(function () {
  93. if (!_this.isMappingComplete() || _this.hasMissingFilters() || _this.hasUnavailableMetadataColumns()) {
  94. _this.removeGridView();
  95. _this.resizeToWidget(renderInfo);
  96. _this.renderIconView();
  97. _this.updateSubViews();
  98. return Promise.resolve(_this);
  99. }
  100. _this.removeIconView();
  101. var dataQueryResult = renderInfo.data.getResult();
  102. _this.setStyles();
  103. _this.setSelections();
  104. _this.setFormat();
  105. _this.setHiddenRowsAndColumns();
  106. return _this._crosstabGrid.render(dataQueryResult, _this.resizing, _this.getRenderingNewData(), _this.eventHandler).then(function (isRenderValid) {
  107. if (!isRenderValid) {
  108. return { reRenderNeeded: true };
  109. } else {
  110. _this.resizeToWidget(renderInfo);
  111. _this.visControl.resetData(_this.visModel);
  112. _this.visControl.setGridData(_this._crosstabGrid);
  113. //Note: renderComplete is called from VisView.
  114. return CrosstabView.inherited('render', _this, _arguments);
  115. }
  116. });
  117. });
  118. },
  119. removeGridView: function removeGridView() {
  120. this._crosstabGrid && this._crosstabGrid.removeGridView();
  121. },
  122. remove: function remove() {
  123. if (this._crosstabGrid) {
  124. this._crosstabGrid.remove();
  125. }
  126. if (this.eventHandler) {
  127. this.eventHandler.remove();
  128. }
  129. this.visControl = null;
  130. // The super.destroy will clear all members of this class.
  131. CrosstabView.inherited('remove', this, arguments);
  132. },
  133. _isNewConditionalFormatFeature: function _isNewConditionalFormatFeature() {
  134. return !this.dashboardApi.getGlassCoreSvc('.FeatureChecker').checkValue('dashboard', 'xtabcondFormat', 'disabled');
  135. },
  136. _initializeConditionalFormatting: function _initializeConditionalFormatting() {
  137. // This is temporary until features have a proper way of initializing themselves
  138. return this._conditionalFormatting ? this._conditionalFormatting.initializeFeature() : Promise.resolve();
  139. },
  140. _getPropertiesForPrefix: function _getPropertiesForPrefix(prefix) {
  141. var propertiesForPrefix = this.visProperties.filter(function (property) {
  142. return property.prefix === prefix;
  143. });
  144. return propertiesForPrefix;
  145. },
  146. /**
  147. * Construct a CSS style map for the properties changed
  148. * @returns {object} in the form of {<styleName>: <propertyValue>}
  149. */
  150. _constructTextStyles: function _constructTextStyles(properties) {
  151. var stylesMap = {};
  152. var visModel = this.visModel;
  153. var styleProxy = this.styleProxy;
  154. var styleToValue = styleProxy.styleToValue;
  155. _.each(properties, function (property) {
  156. // one property may control multiple styles
  157. var styleNames = styleProxy.getPropertyStyle(property.id);
  158. styleNames = Array.isArray(styleNames) ? styleNames : [styleNames];
  159. var propertyValue = visModel.getPropertyValue(property.id);
  160. _.each(styleNames, function (styleName) {
  161. if (propertyValue) {
  162. if (styleToValue && styleToValue[styleName]) {
  163. if ((typeof propertyValue === 'undefined' ? 'undefined' : _typeof(propertyValue)) === 'object') {
  164. var result = {};
  165. _.each(propertyValue, function (val, key) {
  166. result[key] = {
  167. value: val.value ? styleToValue[styleName] : '',
  168. weight: val.weight
  169. };
  170. });
  171. propertyValue = result;
  172. } else {
  173. propertyValue = styleToValue[styleName];
  174. }
  175. }
  176. stylesMap[styleName] = propertyValue;
  177. } else {
  178. stylesMap[styleName] = '';
  179. }
  180. });
  181. });
  182. return stylesMap;
  183. },
  184. setStyles: function setStyles() {
  185. var styleObj = {
  186. rowHeadingStyles: this._constructTextStyles(this.rowHeadingProperties),
  187. columnHeadingStyles: this._constructTextStyles(this.columnHeadingProperties),
  188. dataValueStyles: this._constructTextStyles(this.dataValueProperties),
  189. valueHeadingStyles: this._constructTextStyles(this.valueHeadingProperties),
  190. summaryStyles: this._constructTextStyles(this.summaryProperties),
  191. selectedAreaStyles: this._constructTextStyles(this.selectedAreaProperties)
  192. };
  193. this._crosstabGrid.setStyles(styleObj);
  194. },
  195. /**
  196. * Loads and creates the control. Returns a promise which is resolved when the control
  197. * is created and ready to render
  198. */
  199. whenVisControlReady: function whenVisControlReady() {
  200. var _this2 = this;
  201. //Load the control class defined in the item definition (eg JQGrid).
  202. this.$el.addClass('dataview crosstab-widget');
  203. return DynamicFileLoader.load(['dashboard-analytics/visualizations/renderer/crosstab/CrosstabControl']).then(function (modules) {
  204. var CrosstabControl = modules[0];
  205. var visControl = new CrosstabControl({
  206. domNode: _this2.$el.find('.crosstab-widget')[0],
  207. visualization: _this2.visualization
  208. });
  209. _this2.visControl = visControl;
  210. _this2.visControl.resetData(_this2.visModel);
  211. _this2.eventHandler = new VisEventHandler({
  212. target: new CrosstabEventTarget({
  213. $el: _this2.$el,
  214. view: _this2,
  215. visAPI: _this2.visModel.ownerWidget.visAPI,
  216. content: _this2.content,
  217. visualization: _this2.visualization
  218. }),
  219. transaction: _this2.transactionApi,
  220. ownerWidget: _this2.ownerWidget,
  221. visAPI: _this2.ownerWidget.visAPI
  222. });
  223. return _this2.visControl;
  224. });
  225. },
  226. /**
  227. * Update the selection tuple of the crosstabGrid
  228. */
  229. setSelections: function setSelections() {
  230. var aRowItems = ContentUtil.getColumnIdList([this.visualization.getSlots().getSlot(ROW_SLOT_ID)], 'attribute');
  231. var aColItems = ContentUtil.getColumnIdList([this.visualization.getSlots().getSlot(COLUMN_SLOT_ID)], 'attribute');
  232. var aRowSelection = this.getSelector().getSelection(aRowItems, {
  233. includeParents: true
  234. });
  235. var aColSelection = this.getSelector().getSelection(aColItems, {
  236. includeParents: true
  237. });
  238. var aDatapointSelection = this.getSelector().getSelection(aColItems.concat(aRowItems));
  239. //only clear the selection caches if we've just made a selection and we currently have items in the caches;
  240. var options = {
  241. clearSelectionCaches: (aRowSelection || aColSelection || aDatapointSelection) && (this._crosstabGrid.isSummaryHighlighted() || this._crosstabGrid.getSelectedMeasureNodes())
  242. };
  243. this._crosstabGrid.setSelections({
  244. rowSelection: aRowSelection,
  245. colSelection: aColSelection,
  246. datapointSelection: aDatapointSelection
  247. }, options);
  248. },
  249. /**
  250. * set property value with contentAPI
  251. */
  252. setPropertyValue: function setPropertyValue(property, value, options) {
  253. this.content.setPropertyValue(property, value, options);
  254. },
  255. /**
  256. * Update the selection tuple of the crosstabGrid and update the view
  257. * this will be called from visView once grid view is ready
  258. * should never be called before view is ready
  259. */
  260. renderSelected: function renderSelected() {
  261. this.setSelections();
  262. // force a re-render so selections are handled properly
  263. if (this._crosstabGrid) {
  264. this._crosstabGrid.onResize();
  265. }
  266. },
  267. /**
  268. * get property value with contentAPI
  269. */
  270. getPropertyValue: function getPropertyValue(property) {
  271. return this.content && this.content.getPropertyValue(property);
  272. },
  273. /**
  274. * Update the format info of the crosstab
  275. */
  276. setFormat: function setFormat() {
  277. var format = {
  278. fixedRowHeight: this.getPropertyValue('fixedRowHeight'),
  279. fixedColumnWidth: this.getPropertyValue('fixedColumnWidth'),
  280. columnWidths: this.getPropertyValue('columnWidths'),
  281. rowHeights: this.getPropertyValue('rowHeights')
  282. };
  283. this._crosstabGrid.setFormat(format);
  284. },
  285. /**
  286. * Update the hidden rows and columns info of the crosstab
  287. */
  288. setHiddenRowsAndColumns: function setHiddenRowsAndColumns() {
  289. var hiddenRowsAndColumns = this.getPropertyValue('hiddenRowsAndColumns') || [];
  290. this._crosstabGrid.setHiddenRowsAndColumns(hiddenRowsAndColumns);
  291. },
  292. /**
  293. * build validation response
  294. * @param {boolean} isValid
  295. * @param {string} message
  296. * @returns {object}
  297. */
  298. _buildValidateResponse: function _buildValidateResponse(isValid, message) {
  299. return { isValid: isValid, message: message };
  300. },
  301. /**
  302. * validate the input for property input
  303. * @param {number} propertyValue
  304. * @param {number} range
  305. */
  306. _checkValidInput: function _checkValidInput(propertyValue, range) {
  307. if (!$.isNumeric(propertyValue)) {
  308. return this._buildValidateResponse(false, StringResources.get('prop_sizeInputNonNumericValue'));
  309. }
  310. if (parseInt(propertyValue) < range) {
  311. return this._buildValidateResponse(false, StringResources.get('prop_sizeValueShouldBeHigher', {
  312. value: range
  313. }));
  314. }
  315. return this._buildValidateResponse(true);
  316. },
  317. /**
  318. * Property Provider for crosstabView
  319. */
  320. getPropertyList: function getPropertyList() {
  321. // TODO livewidget_cleanup - remove this line after making sure it is not used
  322. throw new Error('should not be called');
  323. },
  324. /**
  325. * Property Provider for crosstabView
  326. */
  327. getPropertyLayoutList: function getPropertyLayoutList() {
  328. // TODO livewidget_cleanup - remove this line after making sure it is not used
  329. throw new Error('should not be called');
  330. },
  331. /**
  332. * Override the animate to avoid the fade in/out when we resize or apply filters
  333. */
  334. animate: function animate() {
  335. if (this.resizing) {
  336. this.visModel.renderCompleteBeforeAnimation(); // Rendering is complete, no animation
  337. } else {
  338. CrosstabView.inherited('animate', this, arguments);
  339. }
  340. }
  341. });
  342. return CrosstabView;
  343. });
  344. //# sourceMappingURL=CrosstabView.js.map