SearchAndSelectPromptView.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. 'use strict';
  2. /**
  3. * Licensed Materials - Property of IBM
  4. * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2016, 2017
  5. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  6. */
  7. define(['../../lib/@waca/core-client/js/core-client/ui/AccessibleView', '../../widgets/livewidget/nls/StringResources', 'text!./templates/BasePromptView.html', 'text!./templates/SearchAndSelectContent.html', 'jquery', 'underscore', 'doT'], function (View, stringResources, BasePromptViewTemplate, SearchAndSelectContentTemplate, $, _, dot) {
  8. 'use strict';
  9. var SearchAndSelectPromptView = View.extend({
  10. events: {
  11. 'primaryaction .itemRow': '_selectItem',
  12. 'keydown .itemRow': '_moveFocus',
  13. 'primaryaction .searchWrapper .wfg_remove': '_clearSearch',
  14. 'keyup .search': 'searchTypeDelay'
  15. },
  16. _selectedPromptValues: null,
  17. _selectedTab: null,
  18. init: function init(options) {
  19. options.width = '400px';
  20. SearchAndSelectPromptView.inherited('init', this, arguments);
  21. _.extend(this, options);
  22. // Default specs
  23. this._selectedPromptValues = {
  24. refId: options.columnId,
  25. columnId: options.columnId,
  26. values: this.defaultValues ? this.defaultValues : [],
  27. ui: 'picklist'
  28. };
  29. },
  30. render: function render() {
  31. var sBasePromptViewHtml = dot.template(BasePromptViewTemplate)({
  32. promptModuleName: this.promptModuleName
  33. });
  34. this.$el.addClass('promptDialogContainer promptViewDialog').width(this.width).append(sBasePromptViewHtml);
  35. this.$('.content').html(SearchAndSelectContentTemplate);
  36. this.$el.attr('role', 'region');
  37. this.$el.attr('aria-label', this.viewTitle);
  38. // Search Field
  39. this.$('.search').attr('placeholder', stringResources.get('search')).attr('aria-label', stringResources.get('search'));
  40. this._populateRows();
  41. var axisLabelList = this.$('.selectItems');
  42. axisLabelList.attr('aria-label', this.$('.title').text());
  43. return this;
  44. },
  45. _moveFocus: function _moveFocus(evt) {
  46. var $target = $(evt.currentTarget);
  47. if (evt.keyCode === 37 || evt.keyCode === 38) {
  48. //left/up
  49. this._moveToItem($target, $target.prev());
  50. } else if (evt.keyCode === 39 || evt.keyCode === 40) {
  51. //right/down
  52. this._moveToItem($target, $target.next());
  53. }
  54. },
  55. _moveToItem: function _moveToItem($current, $next) {
  56. $current.attr('tabindex', '-1');
  57. $next.focus();
  58. $next.attr('tabindex', '0');
  59. },
  60. setFocus: function setFocus() {
  61. this.$('.search').focus();
  62. },
  63. _clearSearch: function _clearSearch() {
  64. this.$('.search').val('');
  65. return this.searchData();
  66. },
  67. _serverResponse: function _serverResponse(resultData) {
  68. this._collectDistinctValuesResponse(resultData);
  69. this._populateRows();
  70. },
  71. _collectDistinctValuesResponse: function _collectDistinctValuesResponse(resultData) {
  72. if (resultData) {
  73. var resultRowSize = resultData.getDatapointCount();
  74. var aResults = [];
  75. for (var rowIndex = 0; rowIndex < resultRowSize; rowIndex++) {
  76. // Only one column and one tuple part for singleItemQuery result.
  77. aResults.push(resultData.getCellValue(rowIndex, 0)[0]);
  78. }
  79. this.promptValues = aResults;
  80. } else {
  81. this.promptValues = [];
  82. }
  83. },
  84. _getRowValue: function _getRowValue($el) {
  85. var rowValue = JSON.parse(_.unescape($el.attr('data')));
  86. return rowValue === undefined ? null : rowValue;
  87. },
  88. _highlightSelected: function _highlightSelected() {
  89. var selectRows = this.$('.itemRow');
  90. var aExistingSelectionKeys = _.pluck(this._selectedPromptValues.values, 'u');
  91. _.each(selectRows, function (item) {
  92. var $item = $(item);
  93. var data = this._getRowValue($item);
  94. var bInclude = true;
  95. if (_.contains(aExistingSelectionKeys, data.u)) {
  96. $item.toggleClass('exclude', !bInclude).toggleClass('include', bInclude);
  97. $item.find('.check').toggleClass('wfg_checkmark', bInclude);
  98. $item.find('.text').toggleClass('bold', bInclude);
  99. $item.attr('aria-selected', 'true');
  100. } else {
  101. $item.removeClass('include exclude');
  102. $item.find('.check').toggleClass('wfg_checkmark', !bInclude);
  103. $item.find('.text').toggleClass('bold', !bInclude);
  104. $item.attr('aria-selected', 'false');
  105. }
  106. }.bind(this));
  107. },
  108. _populateRows: function _populateRows() {
  109. var items = this.$('.selectItems').empty();
  110. if (this.promptValues.length > 0) {
  111. _.each(this.promptValues, function (dataItem) {
  112. var sRowLabel = dataItem === null ? stringResources.get('nullValueLabel') : dataItem.d;
  113. var item = $('<div></div>').addClass('itemRow').attr('data', _.escape(JSON.stringify(dataItem)));
  114. $('<div></div>').addClass('check wfg_checkmark').appendTo(item);
  115. $('<div></div>').addClass('text').text(sRowLabel).appendTo(item);
  116. item.appendTo(items);
  117. }.bind(this));
  118. setTimeout(function () {
  119. if (!items[0].style.height && items.height()) {
  120. // set height to prevent shrinking lists when search.
  121. items.height(items.height());
  122. }
  123. }, 500);
  124. } else {
  125. $('<div></div>').addClass('itemNotAvailable').text(stringResources.get('textFilterItemsNotFound')).appendTo(items);
  126. }
  127. this._highlightSelected();
  128. var listItem = this.$('.itemRow');
  129. listItem.attr('role', 'option');
  130. listItem.attr('aria-selected', 'false');
  131. listItem.attr('tabindex', '-1');
  132. listItem.first().attr('tabindex', '0');
  133. },
  134. _selectItem: function _selectItem(evt) {
  135. evt.stopPropagation();
  136. var target = this._getRowValue($(evt.currentTarget));
  137. var aExistingSelectionKeys = _.pluck(this._selectedPromptValues.values, 'u');
  138. if (_.contains(aExistingSelectionKeys, target.u)) {
  139. this._selectedPromptValues.values = _.filter(this._selectedPromptValues.values, function (promptValue) {
  140. return promptValue.u !== target.u;
  141. }.bind(this));
  142. } else if (this.singleSelect && this._selectedPromptValues.values.length > 0) {
  143. this._selectedPromptValues.values = [target];
  144. } else {
  145. this._selectedPromptValues.values.push(target);
  146. }
  147. this._highlightSelected();
  148. this._enableOk();
  149. },
  150. /**
  151. * @public
  152. * Get prompt values from dialog.
  153. *
  154. */
  155. getPromptValues: function getPromptValues() {
  156. return this._selectedPromptValues.values;
  157. },
  158. searchData: function searchData() {
  159. var sSearchText = this.$('.search')[0].value;
  160. var result = void 0;
  161. if (this.whenSingleItemQueryReady) {
  162. result = this.whenSingleItemQueryReady({
  163. 'column': { 'columnId': this.columnId },
  164. 'nativeQuery': true,
  165. 'promptName': this.name
  166. }, {
  167. 'searchTerm': sSearchText
  168. }).then(this._serverResponse.bind(this));
  169. } else {
  170. result = Promise.resolve();
  171. }
  172. var sRemoveBtnVisibility = sSearchText.length > 0 ? 'visible' : 'hidden';
  173. this.$('.searchWrapper .wfg_remove').css('visibility', sRemoveBtnVisibility);
  174. return result;
  175. },
  176. /**
  177. * Performs search request on a delay. If a new request arrives before the
  178. * search is performed then the previous search is cancelled and the new
  179. * request is set up on a delay.
  180. * @protected
  181. */
  182. searchTypeDelay: function searchTypeDelay() {
  183. // already have search pending so clear
  184. if (this.iTypeDelayTimer) {
  185. window.clearTimeout(this.iTypeDelayTimer);
  186. }
  187. // set up a search for 250ms after a type event stops.
  188. // hard to set a value here, needs to be slow enough to collect multiple key presses
  189. // but not too slow that the delay after typing is noticeable to the end user.
  190. // according to the internets the average person types at 240 characters/minute
  191. this.iTypeDelayTimer = window.setTimeout(this.searchData.bind(this), 250);
  192. },
  193. _enableOk: function _enableOk() {
  194. if (this._selectedPromptValues.values.length > 0) {
  195. this.enableOk(true);
  196. } else {
  197. this.enableOk(false);
  198. }
  199. }
  200. });
  201. return SearchAndSelectPromptView;
  202. });
  203. //# sourceMappingURL=SearchAndSelectPromptView.js.map