DrillThroughDefinitionView.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. 'use strict';
  2. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  3. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4. 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; }
  5. 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; }
  6. /**
  7. * Licensed Materials - Property of IBM
  8. *
  9. * IBM Cognos Products: BI UI Commons
  10. *
  11. * Copyright IBM Corp. 2018, 2019
  12. *
  13. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  14. */
  15. //jshint maxparams:9
  16. define(['../../lib/@waca/core-client/js/core-client/ui/core/View', 'jquery', 'doT', 'underscore', 'react', 'react-dom', 'ca-ui-toolkit', 'prop-types', 'text!../templates/DrillThroughDefinitionView.html', 'text!../templates/SelectMenu.html', 'text!../templates/NoPromptContent.html', '../../widgets/livewidget/nls/StringResources', '../../lib/@waca/loading-indicator/src/js/LoadingIndicatorView'], function (BaseView, $, doT, _, React, ReactDOM, UI_Toolkit, PropTypes, template, selectMenuTemplate, noPromptContentTemplate, StringResources, LoadingIndicator) {
  17. var KEY_CODES = {
  18. ENTER: 13,
  19. UP: 38,
  20. DOWN: 40,
  21. TAB: 9,
  22. SPACE: 32
  23. };
  24. var NO_MAPPING_TEXT = '---';
  25. /**
  26. * This class renders a view with a parameters list and a corresponding drop down list to show the mapped parameters
  27. * and metadata items from the dashboard, also allows picking a metadata item for the mapped or unmapped
  28. * parameter by user preferences
  29. */
  30. var DrillThroughDefinitionView = BaseView.extend({
  31. events: {
  32. 'primaryaction .dtColDropdown': 'toggleSelectMenu',
  33. 'primaryaction .dtCloseBtnIcon': '_closeDialog',
  34. 'primaryaction .dtBackIcon': '_goBack',
  35. 'primaryaction .dtSelectListItem': '_onSelectValue'
  36. },
  37. templateString: template,
  38. selectMenuTemplate: selectMenuTemplate,
  39. noPromptContentTemplate: noPromptContentTemplate,
  40. init: function init(options) {
  41. DrillThroughDefinitionView.inherited('init', this, arguments);
  42. this.selectMenuTemplateFunc = doT.template(selectMenuTemplate);
  43. this.noPromptContentTemplateFunc = doT.template(noPromptContentTemplate);
  44. this.name = options.name || options.targetName;
  45. this.applicationName = options.applicationName;
  46. this.boardName = options.boardName;
  47. this.targetName = options.targetName;
  48. this.handlers = options.handlers;
  49. this.rowSize = options.rowSize;
  50. this.scope = options.scope;
  51. this.isLoading = options.isLoading;
  52. this.sourceName = options.sourceName;
  53. this.type = options.type;
  54. this.perspective = options.perspective;
  55. this.iconsFeature = options.iconsFeature;
  56. },
  57. /**
  58. * Render the dialog
  59. */
  60. render: function render() {
  61. this.$el.empty();
  62. if (this.isLoading) {
  63. this.rowSize = 0;
  64. }
  65. var previousIcon = this.iconsFeature.getIcon('common-previous');
  66. var reportIcon = this.iconsFeature.getIcon('reportIcon');
  67. var dashboardIcon = this.iconsFeature.getIcon('dashboardIcon');
  68. var chevronLeftIcon = this.iconsFeature.getIcon('common-chevron_left');
  69. var sHtml = this.dotTemplate({
  70. getRow: this.handlers.getRow,
  71. metadataTitle: StringResources.get('drillThroughMetadataColumnTitle', {
  72. boardName: this.boardName
  73. }),
  74. rowSize: this.rowSize,
  75. noMappingText: NO_MAPPING_TEXT,
  76. subTitle: this._getSubTitleText(),
  77. title: StringResources.get('drillthrough_jumpTo', {
  78. name: this.name
  79. }),
  80. drillDefinitionName: this.name,
  81. parametersTitle: StringResources.get('drillThroughParametersColumnTitle', {
  82. targetName: this.targetName
  83. }),
  84. editTitle: StringResources.get('edit'),
  85. StringResources: StringResources,
  86. isReportPerspective: this._isReportPerspective(),
  87. previousIcon: previousIcon.id,
  88. reportIcon: reportIcon.id,
  89. dashboardIcon: dashboardIcon.id,
  90. chevronLeftIcon: chevronLeftIcon.id
  91. });
  92. this.$el.append(sHtml);
  93. this._createTitleInput(this.$el.find('.dtTitleInput')[0]);
  94. this._createScopeRadio(this.$el.find('.dtEditFooter')[0]);
  95. if (this.isLoading) {
  96. var loadingIndicator = new LoadingIndicator();
  97. loadingIndicator.render().then(function ($el) {
  98. this.$el.find('.dtEditTable').empty().addClass('dtLoading').append($el);
  99. }.bind(this));
  100. } else {
  101. if (!this.rowSize && this._isReportPerspective()) {
  102. this._showNoTargetParamIcon();
  103. }
  104. }
  105. },
  106. _createTitleInput: function _createTitleInput(parent) {
  107. var _this = this;
  108. var titleInput = React.createElement(
  109. React.Fragment,
  110. null,
  111. React.createElement(UI_Toolkit.Label, { id: 'dtTitleInputLabel', type: 'caption', label: StringResources.get('drillthrough_titleLabel') }),
  112. React.createElement(UI_Toolkit.TextInput, {
  113. id: 'dtTitleInput',
  114. value: this.name,
  115. onChange: function onChange(value) {
  116. return _this.handlers.onNameChange(value);
  117. }
  118. })
  119. );
  120. ReactDOM.render(titleInput, parent);
  121. },
  122. _createScopeRadio: function _createScopeRadio(parent) {
  123. var options = [{
  124. label: StringResources.get('drillthroughScopeRadioOptionVisualization'),
  125. value: 'visualization'
  126. }, {
  127. label: StringResources.get('drillthroughScopeRadioOptionConnection'),
  128. value: 'connection'
  129. }, {
  130. label: StringResources.get('drillthroughScopeRadioOptionDashboard', {
  131. perspective: this.applicationName
  132. }),
  133. value: 'dashboard'
  134. }];
  135. var ScopeRadio = function (_React$Component) {
  136. _inherits(ScopeRadio, _React$Component);
  137. _createClass(ScopeRadio, null, [{
  138. key: 'propTypes',
  139. get: function get() {
  140. return {
  141. checked: PropTypes.string,
  142. onChange: PropTypes.func,
  143. options: PropTypes.object
  144. };
  145. }
  146. }]);
  147. function ScopeRadio(props) {
  148. _classCallCheck(this, ScopeRadio);
  149. var _this2 = _possibleConstructorReturn(this, _React$Component.call(this, props));
  150. _this2.state = {
  151. checked: props.checked
  152. };
  153. return _this2;
  154. }
  155. ScopeRadio.prototype.render = function render() {
  156. var _this3 = this;
  157. return React.createElement(
  158. React.Fragment,
  159. null,
  160. React.createElement(UI_Toolkit.Label, { id: 'dtScopeRadioLabel', label: StringResources.get('drillthroughScopeRadioLabel') }),
  161. React.createElement(UI_Toolkit.RadioGroup, {
  162. direction: 'vertical',
  163. options: this.props.options,
  164. 'aria-labelledby': 'dtScopeRadioLabel',
  165. checked: this.state.checked,
  166. onChange: function onChange(value) {
  167. _this3._onScopeChange(value);
  168. }
  169. })
  170. );
  171. };
  172. ScopeRadio.prototype._onScopeChange = function _onScopeChange(value) {
  173. this.setState({ checked: value });
  174. this.props.onChange(value);
  175. };
  176. return ScopeRadio;
  177. }(React.Component);
  178. ReactDOM.render(React.createElement(ScopeRadio, { options: options, checked: this.scope, onChange: this.handlers.onScopeChange }), parent);
  179. },
  180. _showNoTargetParamIcon: function _showNoTargetParamIcon() {
  181. var sHtml = this.noPromptContentTemplateFunc({
  182. 'noPromptHeading': StringResources.get('noPrompt'),
  183. 'noPromptDetails': StringResources.get('drillThroughDefinitionNoParameter')
  184. });
  185. this.$el.find('.dtEditTable').addClass('dtNoPromptTable').empty().html(sHtml);
  186. },
  187. _isReportPerspective: function _isReportPerspective() {
  188. return this.type !== 'exploration';
  189. },
  190. _getSubTitleText: function _getSubTitleText() {
  191. if (this.isLoading) {
  192. return '';
  193. } else if (this._isReportPerspective()) {
  194. return this.rowSize ? StringResources.get('drillThroughMappingViewLabel') : StringResources.get('drillThroughDefinitionNoParameterSubTitle');
  195. } else {
  196. return StringResources.get('drillthrough_subTitle', { perspective: this.perspective });
  197. }
  198. },
  199. /*
  200. * Toggle the select menu drop down
  201. */
  202. toggleSelectMenu: function toggleSelectMenu(event) {
  203. var $currentTarget = $(event.currentTarget);
  204. if ($currentTarget.hasClass('dtColDropdown') && this.$el.find('.dtSelectList').length) {
  205. this._closeSelectMenu();
  206. } else if ($currentTarget.hasClass('dtColDropdown')) {
  207. this._openSelectMenu(event);
  208. }
  209. },
  210. /*
  211. * Close the select menu dropdown
  212. */
  213. _closeSelectMenu: function _closeSelectMenu() {
  214. var $list = this.$el.find('.dtSelectList');
  215. if ($list.length) {
  216. var $dropDownNode = $list.siblings('.dtColDropdown');
  217. $dropDownNode.find('.dtDropDownIcon').removeClass('open');
  218. $list.hide();
  219. $list.remove();
  220. // $list .unbind('keydown', this._onDropDownKeydown_bind);
  221. if (this._closeSelectMenu_bind) {
  222. $(document.body).off('click', this._closeSelectMenu_bind);
  223. }
  224. $dropDownNode.attr('aria-expanded', false);
  225. }
  226. },
  227. /*
  228. * Open the select menu dropdown
  229. */
  230. _openSelectMenu: function _openSelectMenu(event) {
  231. event.preventDefault();
  232. event.stopPropagation();
  233. var $dropDownNode = $(event.currentTarget);
  234. var $selectNode = $dropDownNode.parent();
  235. var $dtDropDownIcon = $dropDownNode.find('.dtDropDownIcon');
  236. var rowId = event.currentTarget.dataset.rowid;
  237. var sHtml = this.selectMenuTemplateFunc({
  238. rowId: rowId,
  239. getRow: this.handlers.getRow,
  240. noMappingText: NO_MAPPING_TEXT
  241. });
  242. var $node = $(sHtml);
  243. $selectNode.append($node);
  244. $dtDropDownIcon.addClass('open');
  245. $dropDownNode.attr('aria-expanded', true);
  246. this._closeSelectMenu_bind = this._closeSelectMenu.bind(this, { body: true });
  247. $(document.body).on('click', this._closeSelectMenu_bind);
  248. $node.on('mouseover mousemove mousein mouseout', function (event) {
  249. $node.find('span').removeClass('noPsuedoHover psuedoHover');
  250. $(event.target).addClass('psuedoHover');
  251. });
  252. $node.show();
  253. var $list = $selectNode.find('.dtSelectList');
  254. var $selected = $list.find('span.dtSelected').addClass('psuedoHover');
  255. if ($selected.length) {
  256. if (!this._iswithinVerticalBounds($selected, $list)) {
  257. $selected.get(0).scrollIntoView();
  258. }
  259. }
  260. $list.get(0).focus();
  261. this._onDropDownKeydown_bind = this._onDropDownKeydown.bind(this, $list);
  262. $list.keydown(this._onDropDownKeydown_bind);
  263. },
  264. /**
  265. * Select value callback
  266. */
  267. _onSelectValue: function _onSelectValue(event) {
  268. this._selectValue(event.currentTarget);
  269. this._closeSelectMenu();
  270. },
  271. /**
  272. * Select value callback helper
  273. */
  274. _selectValue: function _selectValue(target) {
  275. var $currentTarget = $(target);
  276. var $dropDownNode = $currentTarget.closest('.dtSelect').find('.dtColDropdown');
  277. var $list = $currentTarget.parent('.dtSelectList');
  278. var rowId = $list.data('rowid');
  279. $list.find('.dtSelected').removeClass('dtSelected');
  280. this.handlers.onValueSelected(rowId, $currentTarget.data('optid'));
  281. var update = this.handlers.getRow(rowId);
  282. var text = null;
  283. var checkmarkSelector = '.row_checkIcon_' + rowId + ' .dt-checked';
  284. this.$checkmark = this.$el.find(checkmarkSelector);
  285. this.$tableRow = this.$checkmark.closest('.dtEditTableRowsItem');
  286. if (update.state.selectedIndex >= 0) {
  287. text = update.state.values[update.state.selectedIndex];
  288. this.$checkmark.removeClass('hidden');
  289. this.$tableRow.addClass('mapped');
  290. } else {
  291. text = NO_MAPPING_TEXT;
  292. this.$checkmark.addClass('hidden');
  293. this.$tableRow.removeClass('mapped');
  294. }
  295. $dropDownNode.find('.dtColDropdownLabel').text(text);
  296. $dropDownNode.find('.dtColDropdownLabel').attr('aria-label', text);
  297. },
  298. /**
  299. * Keydown handler when select drop down is focus
  300. */
  301. _onDropDownKeydown: function _onDropDownKeydown($node, event) {
  302. var $current = $node.find('span.psuedoHover');
  303. var next,
  304. prev = null;
  305. var isUpArrow = event.which === KEY_CODES.UP || event.keyCode === KEY_CODES.UP;
  306. var isDownArrow = event.which === KEY_CODES.DOWN || event.keyCode === KEY_CODES.DOWN;
  307. var isDirectionAllowed = isUpArrow || isDownArrow;
  308. var isEnter = event.which === KEY_CODES.ENTER || event.keyCode === KEY_CODES.ENTER;
  309. var isTab = event.which === KEY_CODES.TAB || event.keyCode === KEY_CODES.TAB;
  310. if (isTab) {
  311. this._closeSelectMenu();
  312. }
  313. if ($current.length) {
  314. next = $current.next();
  315. prev = $current.prev();
  316. if (isDirectionAllowed) {
  317. //Check for hover due to mouse
  318. $current = $current.is(':hover') ? $current.addClass('noPsuedoHover') : $current;
  319. //Remove psuedo Hover
  320. $current = $current.removeClass('psuedoHover');
  321. $current.attr('id', '');
  322. }
  323. }
  324. if ($current.length) {
  325. if (isEnter) {
  326. this._selectValue($current);
  327. this._closeSelectMenu();
  328. } else if (isDirectionAllowed) {
  329. if (isUpArrow) {
  330. if (prev && prev.length) {
  331. prev.addClass('psuedoHover').removeClass('noPsuedoHover');
  332. } else {
  333. $node.find('span').last().addClass('psuedoHover').removeClass('noPsuedoHover');
  334. }
  335. } else if (isDownArrow) {
  336. if (next && next.length) {
  337. next.addClass('psuedoHover').removeClass('noPsuedoHover');
  338. } else {
  339. $node.find('span').first().addClass('psuedoHover').removeClass('noPsuedoHover');
  340. }
  341. }
  342. event.preventDefault();
  343. event.stopPropagation();
  344. }
  345. } else if (isDirectionAllowed) {
  346. if (isUpArrow) {
  347. $node.find('span').last().addClass('psuedoHover').removeClass('noPsuedoHover');
  348. } else if (isDownArrow) {
  349. $node.find('span').first().addClass('psuedoHover').removeClass('noPsuedoHover');
  350. }
  351. event.preventDefault();
  352. event.stopPropagation();
  353. }
  354. $current = $node.find('span.psuedoHover');
  355. $current.attr('id', 'dt-activedescendant');
  356. $current.focus();
  357. if ($current.length && !this._iswithinVerticalBounds($current, $node)) {
  358. $current.get(0).scrollIntoView();
  359. }
  360. },
  361. /**
  362. * Check is an element is within the bound of another
  363. */
  364. _iswithinVerticalBounds: function _iswithinVerticalBounds($childElement, $containerElem) {
  365. var containerRect = $containerElem.get(0).getBoundingClientRect();
  366. var childRect = $childElement.get(0).getBoundingClientRect();
  367. return childRect.top >= containerRect.top && childRect.bottom <= containerRect.bottom;
  368. },
  369. /**
  370. * close dialog callback
  371. */
  372. _closeDialog: function _closeDialog() {
  373. this.handlers.onCloseDialog();
  374. },
  375. /**
  376. * back callback
  377. */
  378. _goBack: function _goBack() {
  379. this.handlers.onBack();
  380. },
  381. update: function update(options) {
  382. this.rowSize = options.rowSize || this.rowSize;
  383. this.isLoading = options.isLoading;
  384. this.targetName = options.targetName || this.targetName;
  385. this.render();
  386. },
  387. remove: function remove() {
  388. DrillThroughDefinitionView.inherited('remove', this, arguments);
  389. }
  390. });
  391. return DrillThroughDefinitionView;
  392. });
  393. //# sourceMappingURL=DrillThroughDefinitionView.js.map