CrosstabGrid.js 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963
  1. 'use strict';
  2. 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; };
  3. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4. /**
  5. * Licensed Materials - Property of IBM
  6. * IBM Cognos Products: Dashboard
  7. * (C) Copyright IBM Corp. 2016, 2020
  8. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  9. */
  10. define(['../../../widgets/livewidget/nls/StringResources', './Pivot', '../grid/GridDnDManager', 'underscore', '../grid/GridDataProvider', '../grid/GridDropTarget', '../grid/GridContentRenderer', 'react-dom', 'react', 'ca-ui-toolkit', 'react-draggable', 'jquery', '../../../util/DashboardFormatter'], function (StringResources, Pivot, GridDndManager, _, DataProvider, GridDropTarget, GridContentRenderer, ReactDOM, React, Toolkit, Draggable, $, Formatter) {
  11. 'use strict';
  12. var ROW_SLOT_ID = 'row_level1';
  13. var COLUMN_SLOT_ID = 'column_level1';
  14. var VALUES_SLOT_ID = 'values';
  15. var PROP_ID_SUPPRESSION = 'suppression';
  16. var PROP_ID_EXPANDCOLLAPSE = 'expandCollapse';
  17. var PROP_ID_HIDDEN_ROWS_AND_COLS = 'hiddenRowsAndColumns';
  18. var MEASURE_ROW_RESIZE_IDENTIFIER = 'Measures_Row';
  19. var DEFAULT_ROW_HEIGHT = 32;
  20. var DEFAULT_COLUMN_WIDTH = 120;
  21. var MIN_ROW_HEIGHT = 24;
  22. var MIN_COLUMN_WIDTH = 24;
  23. var SHAPE_WIDTH = 24;
  24. // hiddenRowHeight is set as a small float number that is close to 0 to prevent the react removing the dom with 0 height
  25. var HIDDEN_ROW_HEIGHT = 0.000001;
  26. // hiddenColumnWidth is set as a small float number that is close to 0 to prevent the react removing the dom with 0 width
  27. var HIDDEN_COL_WIDTH = 0.000001;
  28. var EXPAND_INDENTATION = 24;
  29. var AXIS_X = 'x';
  30. var AXIS_Y = 'y';
  31. var AREA_TYPE = {
  32. ROW: 'cell_edge_row',
  33. COLUMN: 'cell_edge_column',
  34. CELL: 'cell',
  35. MEASURE: 'values',
  36. SUMMARY: 'summary'
  37. };
  38. var DEFAULT_TEXT_STYLE = {
  39. FONT_SIZE: '10pt',
  40. FONT_FAMILY: 'IBM Plex Sans',
  41. PADDING_WIDTH: 18
  42. };
  43. return function () {
  44. function CrosstabGrid(options) {
  45. _classCallCheck(this, CrosstabGrid);
  46. options = options || {};
  47. this.$el = options.$el;
  48. this.visModel = options.visModel;
  49. this.dashboardApi = options.dashboardApi;
  50. this.crosstabView = options.crosstabView;
  51. this.content = this.crosstabView && this.crosstabView.content;
  52. this.colorsService = options.colorsService;
  53. this.conditionalFormatting = options.conditionalFormatting;
  54. this.dataProvider = new DataProvider();
  55. this.textStyleIndex = {
  56. cell: 'dataValueStyles',
  57. corner: 'valueHeadingStyles',
  58. row: 'rowHeadingStyles',
  59. column: 'columnHeadingStyles',
  60. summary: 'summaryStyles',
  61. selectedArea: 'selectedAreaStyles'
  62. };
  63. //crosstab dnd
  64. this._gridDnDManager = new GridDndManager({
  65. grid: this,
  66. dashboardApi: this.dashboardApi,
  67. content: this.content,
  68. gridEdgeMappedToId: { row: ROW_SLOT_ID, column: COLUMN_SLOT_ID, values: VALUES_SLOT_ID }
  69. });
  70. this._shapeCols = [];
  71. }
  72. CrosstabGrid.prototype.render = function render(resultData, resizing, renderingNewData, eventHandler) {
  73. this.eventHandler = eventHandler;
  74. // If the data has changed or we're not resizing (property change) then create the pivot table
  75. if (!resizing || renderingNewData || !this.data) {
  76. this._pivotTable = new Pivot({
  77. data: resultData,
  78. visModel: this.visModel,
  79. slots: this.content.getFeature('Visualization').getSlots(),
  80. dashboard: this.dashboardApi,
  81. conditionalFormatting: this.conditionalFormatting
  82. });
  83. this.data = this._pivotTable.create();
  84. // if the data has changed, cached cellWidthStatus needs to be reset
  85. this._cellWidthStatus = null;
  86. }
  87. this._alternateRowFlag = -1; // -1: not initialize, 1: alternate on odd number, 0: alternate on even number.
  88. this._cellStartRow = this._pivotTable.colEdgeNestingLevelWithMeasure ? this._pivotTable.colEdgeNestingLevelWithMeasure : this._pivotTable.colEdgeNestingLevel;
  89. if (this.gridRef && resizing && !renderingNewData) {
  90. //if only do resizing
  91. this.onResize();
  92. this.onSyncScrollBar();
  93. return Promise.resolve(true);
  94. } else {
  95. // dataChange will change the rowNum and colNum of the data, need to re-render the grid
  96. this.dataProvider.updateData(this.data);
  97. //reset summary indicator flag
  98. if (!this._errorWarningAdded) {
  99. this.crosstabView.clearInfoIndicator('error_summary_cell');
  100. } else {
  101. this._errorWarningAdded = false;
  102. }
  103. this.$el.addClass('dashboard-common-grid').addClass('xtab-grid');
  104. this._renderReactGrid();
  105. if (this.gridRef) {
  106. return Promise.resolve(true);
  107. } else {
  108. return Promise.resolve(false);
  109. }
  110. }
  111. };
  112. CrosstabGrid.prototype.onResize = function onResize() {
  113. this.maxColHeight = this._getMaxColHeight();
  114. this.gridRef && this.gridRef.recomputeGridSize();
  115. };
  116. CrosstabGrid.prototype._getMaxColHeight = function _getMaxColHeight() {
  117. return this.$el && this.$el.length && this.$el[0].offsetHeight || Infinity;
  118. };
  119. CrosstabGrid.prototype.onSyncScrollBar = function onSyncScrollBar() {
  120. // when parent dom is moved or updated the scrollLeft and scrollTop value reset to 0 for the bottom-right-grid
  121. // this is a bug in React MultiGrid Level
  122. // the fix here is to sync the scrollBar among the three grid before onResize is triggered
  123. var $domNode = $(this.$el[0]);
  124. var rightBottomGrid = $domNode.find('.ba-common-grid__bottom-right-grid');
  125. var rightTopGrid = $domNode.find('.ba-common-grid__top-right-grid');
  126. var leftBottomGrid = $domNode.find('.ba-common-grid__bottom-left-grid');
  127. $(rightBottomGrid).animate({
  128. scrollLeft: $(rightTopGrid).scrollLeft(),
  129. scrollTop: $(leftBottomGrid).scrollTop()
  130. }, 0);
  131. };
  132. CrosstabGrid.prototype.removeGridView = function removeGridView() {
  133. if (this.gridRef && this.$el) {
  134. ReactDOM.unmountComponentAtNode(this.$el[0]);
  135. this.gridRef = null;
  136. }
  137. };
  138. CrosstabGrid.prototype.remove = function remove() {
  139. this.columnWidths = null;
  140. this.rowHeights = null;
  141. this.fixedRowHeight = null;
  142. this.fixedColumnWidth = null;
  143. this.hiddenRowsAndColumns = null;
  144. this._cachedHiddenCol = null;
  145. this._cachedHiddenRow = null;
  146. this._cachedRowDataItemInfo = null;
  147. this._cachedLevelInfo = null;
  148. this._cachedColumnDataItemInfo = null;
  149. this.expandCollapseFeature = null;
  150. this.isExpandable = null;
  151. this.dataProvider = null;
  152. this.data = null;
  153. this._pivotTable = null;
  154. this.eventHandler = null;
  155. this._selections = null;
  156. this._measureHeaderDecorations = null;
  157. this._selectedMeasureNodes = null;
  158. this._isSummaryHighlighted = null;
  159. this._cellWidthStatus = null;
  160. this._canvas = null;
  161. this.removeGridView();
  162. this.$el = null;
  163. };
  164. CrosstabGrid.prototype._setSummaryColor = function _setSummaryColor(gridCellProps) {
  165. var summaryColor = this.conditionalFormatting && this.conditionalFormatting.getSummaryFillColor();
  166. if (summaryColor) {
  167. _.extend(gridCellProps.style, { 'background-color': summaryColor });
  168. }
  169. };
  170. CrosstabGrid.prototype._getConditionalFormatting = function _getConditionalFormatting(condValue, dataValue, measureIndex) {
  171. var style = void 0;
  172. if (this.conditionalFormatting) {
  173. var measure = measureIndex >= 0 && this._pivotTable._measuresInfo.length > measureIndex ? this._pivotTable._measuresInfo[measureIndex] : undefined;
  174. if (measure) {
  175. var dataItem = this.content.getFeature('Visualization').getSlots().getDataItem(measure.id);
  176. style = this.conditionalFormatting.getFormatting(dataValue.rawValue, condValue.value, dataItem.getColumnId());
  177. }
  178. } else {
  179. var conditionalPalette = this.visModel.getConditions() ? this.visModel.getConditions().palette : null;
  180. if (conditionalPalette) {
  181. var paletteStyle = conditionalPalette.getColorByValue(condValue.value);
  182. if (paletteStyle) {
  183. style = paletteStyle.getStyle();
  184. }
  185. }
  186. }
  187. return style;
  188. };
  189. CrosstabGrid.prototype._getDataCellValue = function _getDataCellValue(dataCellValue, valueType) {
  190. if (valueType === 'tuple') {
  191. dataCellValue = dataCellValue && dataCellValue.tuple;
  192. } else if (valueType === 'useValue') {
  193. dataCellValue = dataCellValue && dataCellValue.isMeasure ? this._getValue(dataCellValue) : this._getUseValue(dataCellValue);
  194. } else if (valueType === 'condValue') {
  195. dataCellValue = dataCellValue && dataCellValue.condValue;
  196. } else if (valueType === 'type') {
  197. dataCellValue = dataCellValue && dataCellValue.type;
  198. } else if (valueType === 'isMeasure') {
  199. dataCellValue = dataCellValue && dataCellValue.isMeasure;
  200. } else if (valueType === 'nestlevel') {
  201. dataCellValue = dataCellValue && dataCellValue.nestlevel;
  202. } else if (valueType === 'rowEdge') {
  203. dataCellValue = dataCellValue && dataCellValue.rowEdge;
  204. } else if (valueType === 'columnEdge') {
  205. dataCellValue = dataCellValue && dataCellValue.columnEdge;
  206. } else if (valueType === 'ancestor_or_self') {
  207. dataCellValue = dataCellValue && dataCellValue.ancestor_or_self;
  208. } else if (valueType === 'levelNumber') {
  209. dataCellValue = dataCellValue && dataCellValue.value && dataCellValue.value.ln;
  210. } else if (valueType === 'parentUseValue') {
  211. dataCellValue = dataCellValue && dataCellValue.value && dataCellValue.value.pu;
  212. } else {
  213. var value = this._getValue(dataCellValue);
  214. // Should preserve null and 0 values, except undefined. Should allow user format the 3 types of
  215. // cells respectively.
  216. dataCellValue = value === undefined ? '' : value;
  217. }
  218. return dataCellValue;
  219. };
  220. /**
  221. * Removes cell-is-focused classname if there's no selections
  222. *
  223. * @param aClassString
  224. * @return {*}
  225. * @private
  226. */
  227. CrosstabGrid.prototype._removeFocusedClassName = function _removeFocusedClassName(aClassString) {
  228. var SELECTED = 'cell-is-focused';
  229. if (!(this._selections && (this._selections.datapointSelection || this._selections.rowSelection || this._selections.colSelection))) {
  230. if (aClassString && aClassString.indexOf(SELECTED) !== -1) {
  231. return aClassString.replace(SELECTED, '').trim();
  232. }
  233. }
  234. return aClassString;
  235. };
  236. CrosstabGrid.prototype.restoreFormat = function restoreFormat() {
  237. this.fixedRowHeight = null;
  238. this.fixedColumnWidth = null;
  239. this.columnWidths = null;
  240. this.rowHeights = null;
  241. };
  242. CrosstabGrid.prototype.setFormat = function setFormat(format) {
  243. this.fixedRowHeight = format.fixedRowHeight;
  244. this.fixedColumnWidth = format.fixedColumnWidth;
  245. this.columnWidths = format.columnWidths;
  246. this.rowHeights = format.rowHeights;
  247. };
  248. CrosstabGrid.prototype.setHiddenRowsAndColumns = function setHiddenRowsAndColumns(hiddenRowsAndColumns) {
  249. this.hiddenRowsAndColumns = hiddenRowsAndColumns;
  250. };
  251. /**
  252. * Apply highlight decoration to the selected measure header cell
  253. * @param $node: the node has been selected
  254. */
  255. CrosstabGrid.prototype.setMeasureHeaderDecorations = function setMeasureHeaderDecorations(node) {
  256. var decorations = $(node).attr('usevalue');
  257. this._measureHeaderDecorations = this._measureHeaderDecorations || [];
  258. this._selectedMeasureNodes = this._selectedMeasureNodes || [];
  259. if (this._measureHeaderDecorations.indexOf(decorations) > -1 || $(node).hasClass('dashboard-grid-cell-selected')) {
  260. this.clearMeasureHeaderDecorations();
  261. } else {
  262. this._measureHeaderDecorations.push(decorations);
  263. this._selectedMeasureNodes.push(node);
  264. }
  265. };
  266. /**
  267. * Get selected measure header cell nodes list
  268. */
  269. CrosstabGrid.prototype.getSelectedMeasureNodes = function getSelectedMeasureNodes() {
  270. return this._selectedMeasureNodes;
  271. };
  272. /**
  273. * Clear selected measure header cell decoration.
  274. */
  275. CrosstabGrid.prototype.clearMeasureHeaderDecorations = function clearMeasureHeaderDecorations() {
  276. this._measureHeaderDecorations = null;
  277. this._selectedMeasureNodes = null;
  278. };
  279. CrosstabGrid.prototype.highlightSummary = function highlightSummary(node) {
  280. this._isSummaryHighlighted = !$(node).hasClass('dashboard-grid-cell-selected');
  281. };
  282. CrosstabGrid.prototype.resetSummaryHighlight = function resetSummaryHighlight() {
  283. this._isSummaryHighlighted = false;
  284. };
  285. CrosstabGrid.prototype.isSummaryHighlighted = function isSummaryHighlighted() {
  286. return this._isSummaryHighlighted;
  287. };
  288. /**
  289. * Build resize key for the resize map from ancestor_or_self info
  290. */
  291. CrosstabGrid.prototype._buildResizeKey = function _buildResizeKey(ancestor_or_self) {
  292. var resizeKey = '';
  293. _.each(ancestor_or_self, function (dataItem) {
  294. if (dataItem.value) {
  295. resizeKey += dataItem.value + ',';
  296. } else {
  297. resizeKey += dataItem + ',';
  298. }
  299. });
  300. return resizeKey.slice(0, -1);
  301. };
  302. /**
  303. * calculate colspan, rowspan, columnWidth and rowHeight of current data cell
  304. *
  305. * @param {integer} colIndex, column index of current cell
  306. * @param {integer} rowIndex, row index of current cell
  307. * @param {integer} colBound, numbers of columns
  308. * @param {integer} rowBound, numbers of rows
  309. * @param {object} dataProvider
  310. * @param {integer} fixedRows, numbers of fixed rows
  311. * @param {integer} fixedColumns, numbers of fixed columns
  312. * @param {any} dataCellValue
  313. * @param {object} gridCellProps
  314. * @param {integer} defaultColumnWidth, fixedColumnWidth value
  315. * @param {integer} defaultRowHeight, fixedRowHeight value
  316. * @return {object} colSpan, rowSpan, gridCellColumnWidth, gridCellRowHeight
  317. */
  318. CrosstabGrid.prototype._getSpanIndex = function _getSpanIndex(options) {
  319. var colIndex = options.colIndex,
  320. rowIndex = options.rowIndex,
  321. colBound = options.colBound,
  322. rowBound = options.rowBound,
  323. dataProvider = options.dataProvider,
  324. fixedRows = options.fixedRows,
  325. fixedColumns = options.fixedColumns,
  326. dataCellValue = options.dataCellValue,
  327. gridCellProps = options.gridCellProps,
  328. defaultColumnWidth = options.defaultColumnWidth,
  329. defaultRowHeight = options.defaultRowHeight,
  330. ignoreGrouping = options.ignoreGrouping;
  331. var colSpanIndex = colIndex + 1;
  332. var gridCellColumnWidth = parseInt(gridCellProps.style.width, 10);
  333. var siblingCellColumnWidth = void 0,
  334. siblingCellRowHeight = void 0;
  335. if (!ignoreGrouping.column) {
  336. while (colSpanIndex <= colBound && this._getDataCellValue(dataProvider.getValue(rowIndex, colSpanIndex)) === dataCellValue && this._getDataCellValue(dataProvider.getValue(0, colSpanIndex)) === this._getDataCellValue(dataProvider.getValue(0, colIndex))) {
  337. siblingCellColumnWidth = this._getColumnWidth(dataProvider, fixedRows - 1, colSpanIndex, defaultColumnWidth);
  338. gridCellColumnWidth = gridCellColumnWidth + siblingCellColumnWidth;
  339. colSpanIndex++;
  340. }
  341. }
  342. var colSpan = colSpanIndex - colIndex - 1;
  343. var rowSpanIndex = rowIndex + 1;
  344. var gridCellRowHeight = parseInt(gridCellProps.style.height, 10);
  345. if (!ignoreGrouping.row) {
  346. while (rowSpanIndex <= rowBound && this._getDataCellValue(dataProvider.getValue(rowSpanIndex, colIndex)) === dataCellValue && this._getDataCellValue(dataProvider.getValue(rowSpanIndex, 0)) === this._getDataCellValue(dataProvider.getValue(rowIndex, 0))) {
  347. siblingCellRowHeight = this._getRowHeight(dataProvider, rowSpanIndex, fixedColumns - 1, defaultRowHeight);
  348. gridCellRowHeight = gridCellRowHeight + siblingCellRowHeight;
  349. rowSpanIndex++;
  350. }
  351. }
  352. var rowSpan = rowSpanIndex - rowIndex - 1;
  353. return { colSpan: colSpan, rowSpan: rowSpan, gridCellColumnWidth: gridCellColumnWidth, gridCellRowHeight: gridCellRowHeight };
  354. };
  355. /**
  356. * calculate delta value bounded to minimal values
  357. *
  358. * @param {integer} delta
  359. * @param {integer} bound, MIN_COLUMN_WIDTH or MIN_ROW_HEIGHT
  360. * @param {integer} spanIndex
  361. * @param {integer} currentValue, gridCellColumnWidth/gridCellRowHeight value
  362. */
  363. CrosstabGrid.prototype._calculateDelta = function _calculateDelta(delta, bound, spanIndex, currentValue) {
  364. if (delta + currentValue < bound) {
  365. delta = bound - currentValue;
  366. } else if (spanIndex > 0) {
  367. var evenDelta = parseInt((delta + currentValue) / (spanIndex + 1));
  368. if (evenDelta < bound) {
  369. delta = delta + (bound - evenDelta) * (spanIndex + 1);
  370. }
  371. }
  372. return delta;
  373. };
  374. /**
  375. * resize the grid with draggable handler
  376. *
  377. * @param {object} dataProvider
  378. * @param {string} direction, 'x' for columnWidth and 'y' for rowHeight
  379. * @param {integer} delta
  380. * @param {integer} colIndex
  381. * @param {integer} rowIndex
  382. * @param {integer} colSpan
  383. * @param {integer} rowSpan
  384. * @param {integer} fixedRows, numbers of fixed rows
  385. * @param {integer} fixedColumns, numbers of fixed columns
  386. * @param {integer} defaultValue, fixedColumnWidth/fixedRowHeight value
  387. * @param {integer} currentValue, gridCellColumnWidth/gridCellRowHeight value
  388. * @param {boolean} skipBound, skip the bound check and grow the cell if skipBound is set to true
  389. */
  390. CrosstabGrid.prototype._onDraggableResize = function _onDraggableResize(options) {
  391. if (options.delta !== undefined && options.delta === 0) {
  392. return;
  393. }
  394. var dataProvider = options.dataProvider,
  395. direction = options.direction,
  396. delta = options.delta,
  397. rowIndex = options.rowIndex,
  398. colIndex = options.colIndex,
  399. colSpan = options.colSpan,
  400. rowSpan = options.rowSpan,
  401. fixedColumns = options.fixedColumns,
  402. fixedRows = options.fixedRows,
  403. defaultValue = options.defaultValue,
  404. currentValue = options.currentValue,
  405. skipBound = options.skipBound;
  406. var index = void 0,
  407. spanIndex = void 0,
  408. boundIndex = void 0,
  409. bound = void 0,
  410. formatMap = void 0,
  411. propertyName = void 0,
  412. rootCellValue = void 0,
  413. rootResizeKey = void 0,
  414. siblingCellValue = void 0,
  415. siblingResizeKey = void 0;
  416. var dataValue = dataProvider.getValue(rowIndex, colIndex);
  417. if (direction === AXIS_X) {
  418. formatMap = this.columnWidths || {};
  419. propertyName = 'columnWidths';
  420. index = colIndex;
  421. boundIndex = rowIndex;
  422. spanIndex = colSpan;
  423. bound = MIN_COLUMN_WIDTH;
  424. rootCellValue = dataProvider.getValue(fixedRows - 1, index);
  425. if (this._getDataCellValue(rootCellValue, 'type') === 'corner') {
  426. // when the cell is a corner cell, use the dataItem label as resize key
  427. rootResizeKey = this._getCachedDataItemInfoByIndex(this._cachedRowDataItemInfo, index, 'dataitemId');
  428. } else {
  429. rootResizeKey = this._buildResizeKey(this._getDataCellValue(rootCellValue, 'ancestor_or_self'));
  430. }
  431. siblingCellValue = dataProvider.getNumColumns() - 1 > index + 1 && dataProvider.getValue(fixedRows - 1, index + 1);
  432. if (siblingCellValue && this._getDataCellValue(siblingCellValue, 'type') === 'corner') {
  433. siblingResizeKey = this._getCachedDataItemInfoByIndex(this._cachedRowDataItemInfo, index + 1, 'dataitemId');
  434. } else {
  435. siblingResizeKey = this._buildResizeKey(this._getDataCellValue(siblingCellValue, 'ancestor_or_self'));
  436. }
  437. } else {
  438. formatMap = this.rowHeights || {};
  439. propertyName = 'rowHeights';
  440. index = rowIndex;
  441. boundIndex = colIndex;
  442. spanIndex = rowSpan;
  443. bound = MIN_ROW_HEIGHT;
  444. rootCellValue = dataProvider.getValue(index, fixedColumns - 1);
  445. if (this._getDataCellValue(rootCellValue, 'type') === 'corner') {
  446. // measure row is a special row since it does not have any dataItem mapped, use a constant as resize key
  447. rootResizeKey = this._getCachedDataItemInfoByIndex(this._cachedColumnDataItemInfo, index, 'dataitemId') || MEASURE_ROW_RESIZE_IDENTIFIER;
  448. } else {
  449. rootResizeKey = this._buildResizeKey(this._getDataCellValue(rootCellValue, 'ancestor_or_self'));
  450. }
  451. siblingCellValue = dataProvider.getNumRows() - 1 > index + 1 && dataProvider.getValue(index + 1, fixedColumns - 1);
  452. if (siblingCellValue && this._getDataCellValue(siblingResizeKey, 'type') === 'corner') {
  453. siblingResizeKey = this._getCachedDataItemInfoByIndex(this._cachedColumnDataItemInfo, index + 1, 'dataitemId') || MEASURE_ROW_RESIZE_IDENTIFIER;
  454. } else {
  455. siblingResizeKey = this._buildResizeKey(this._getDataCellValue(siblingResizeKey, 'ancestor_or_self'));
  456. }
  457. }
  458. var resizedValue = delta + currentValue;
  459. var resizeKey = this._buildResizeKey(this._getDataCellValue(dataValue, 'ancestor_or_self'));
  460. formatMap[resizeKey] = resizedValue;
  461. formatMap[rootResizeKey] = resizedValue;
  462. // child resize will resize the sibling and the children
  463. if (!skipBound && boundIndex > 0 && spanIndex <= 0 && siblingResizeKey) {
  464. formatMap[siblingResizeKey] = formatMap[siblingResizeKey] || defaultValue;
  465. formatMap[siblingResizeKey] = Math.max(formatMap[siblingResizeKey] - delta, bound);
  466. }
  467. // root resize will resize the parent and the children
  468. if (spanIndex > 0) {
  469. var evenDistribution = parseInt(resizedValue / (spanIndex + 1));
  470. var counter = spanIndex + 1;
  471. while (counter > 0) {
  472. if (direction === AXIS_X) {
  473. rootResizeKey = this._buildResizeKey(this._getDataCellValue(dataProvider.getValue(fixedRows - 1, index + counter - 1), 'ancestor_or_self'));
  474. } else {
  475. rootResizeKey = this._buildResizeKey(this._getDataCellValue(dataProvider.getValue(index + counter - 1, fixedColumns - 1), 'ancestor_or_self'));
  476. }
  477. if (rootResizeKey) {
  478. formatMap[rootResizeKey] = evenDistribution;
  479. }
  480. counter--;
  481. }
  482. }
  483. this.crosstabView.setPropertyValue(propertyName, formatMap);
  484. };
  485. /**
  486. * setup resize guideline and cell blocker for draggable resize handler
  487. */
  488. CrosstabGrid.prototype._onStartResizeGuideLine = function _onStartResizeGuideLine(event, direction, containerClassName, offSetParent) {
  489. var style = {};
  490. var guideLineClassName = void 0;
  491. if (direction === AXIS_X) {
  492. guideLineClassName = 'grid-column-resizer-guideLine';
  493. style.height = this.$el[0].clientHeight;
  494. } else {
  495. guideLineClassName = 'grid-row-resizer-guideLine';
  496. style.width = this.$el[0].clientWidth;
  497. }
  498. // add cell blocker to make sure hover does not leak through the drag handler
  499. var cells = $(this.$el[0]).find('.' + containerClassName);
  500. _.each(cells, function (cell) {
  501. $(cell).addClass(containerClassName + '-resizing');
  502. });
  503. // initialize the resize guideline styles
  504. var resizeGuideLine = $(this.$el[0]).find('.xtab-grid-guideLine');
  505. var offset = $(this.$el[0]).find('.' + offSetParent).offsetParent().offsetParent().offset();
  506. $(resizeGuideLine).addClass(guideLineClassName);
  507. style.top = event.clientY - offset.top - 1 + 'px';
  508. style.left = event.clientX - offset.left - 1 + 'px';
  509. $(resizeGuideLine).css(style);
  510. };
  511. /**
  512. * move resize guideline along with draggable resize handler
  513. */
  514. CrosstabGrid.prototype._onDragResizeGuideLine = function _onDragResizeGuideLine(event, direction, offSetParent) {
  515. var isResizingColumn = direction === AXIS_X;
  516. var guideLineClassName = isResizingColumn ? 'grid-column-resizer-guideLine' : 'grid-row-resizer-guideLine';
  517. // update guideLine position while dragging happens
  518. var resizeGuideLine = $(this.$el[0]).find('.' + guideLineClassName);
  519. var offset = $(this.$el[0]).find('.' + offSetParent).offsetParent().offsetParent().offset();
  520. if (isResizingColumn) {
  521. $(resizeGuideLine).css({
  522. left: event.clientX - offset.left - 1 + 'px'
  523. });
  524. } else {
  525. $(resizeGuideLine).css({
  526. top: event.clientY - offset.top - 1 + 'px'
  527. });
  528. }
  529. };
  530. /**
  531. * remove resize guideline and cell blocker for draggable resize handler
  532. */
  533. CrosstabGrid.prototype._onStopResizeGuideLine = function _onStopResizeGuideLine(event, direction, containerClassName) {
  534. var isResizingColumn = direction === AXIS_X;
  535. var guideLineClassName = isResizingColumn ? 'grid-column-resizer-guideLine' : 'grid-row-resizer-guideLine';
  536. var style = isResizingColumn ? { height: '', top: '', left: '' } : { width: '', top: '', left: '' };
  537. // remove the cell blocker
  538. var cells = $(this.$el[0]).find('.' + containerClassName);
  539. _.each(cells, function (cell) {
  540. $(cell).removeClass(containerClassName + '-resizing');
  541. });
  542. // reset the guideLine styles
  543. var resizeGuideLine = $(this.$el[0]).find('.' + guideLineClassName);
  544. $(resizeGuideLine).css(style);
  545. $(resizeGuideLine).removeClass(guideLineClassName);
  546. };
  547. /**
  548. * render the draggable resize handler
  549. * @param {object} options
  550. */
  551. CrosstabGrid.prototype._renderResizeHandler = function _renderResizeHandler(options) {
  552. var _this = this;
  553. var dataProvider = options.dataProvider,
  554. direction = options.direction,
  555. className = options.className,
  556. defaultValue = options.defaultValue,
  557. currentValue = options.currentValue,
  558. containerClassName = options.containerClassName,
  559. offSetParent = options.offSetParent,
  560. rowIndex = options.rowIndex,
  561. colIndex = options.colIndex,
  562. colSpan = options.colSpan,
  563. rowSpan = options.rowSpan,
  564. fixedColumns = options.fixedColumns,
  565. fixedRows = options.fixedRows,
  566. bound = options.bound,
  567. skipBound = options.skipBound;
  568. var spanIndex = direction === AXIS_X ? colSpan : rowSpan;
  569. var resizeHandler = React.createElement('div', {
  570. className: className,
  571. onDoubleClick: function onDoubleClick() {
  572. // double click to adjust the size fit the text
  573. var textWidth = direction === AXIS_X ? _this._cellWidthStatus && _this._cellWidthStatus[colIndex] && _this._cellWidthStatus[colIndex]['textWidth'] || defaultValue : defaultValue;
  574. var isShapeCol = _this._shapeCols.indexOf(colIndex) !== -1;
  575. if (isShapeCol) {
  576. textWidth += SHAPE_WIDTH;
  577. }
  578. var delta = textWidth - currentValue;
  579. if (spanIndex > 0) {
  580. delta = textWidth * spanIndex - currentValue;
  581. }
  582. if (delta > 0) {
  583. var draggableOptions = { dataProvider: dataProvider, direction: direction, delta: delta, rowIndex: rowIndex, colIndex: colIndex, colSpan: colSpan, rowSpan: rowSpan, fixedColumns: fixedColumns, fixedRows: fixedRows, defaultValue: defaultValue, currentValue: currentValue, skipBound: skipBound };
  584. _this._onDraggableResize(draggableOptions);
  585. }
  586. }
  587. }, '');
  588. return React.createElement(Draggable, {
  589. axis: direction,
  590. position: { x: 0, y: 0 },
  591. onStart: function onStart(event) {
  592. _this._onStartResizeGuideLine(event, direction, containerClassName, offSetParent);
  593. },
  594. onDrag: function onDrag(event) {
  595. _this._onDragResizeGuideLine(event, direction, offSetParent);
  596. },
  597. onStop: function onStop(event, data) {
  598. _this._onStopResizeGuideLine(event, direction, containerClassName);
  599. var rawDeltaData = direction === AXIS_X ? data.x : data.y;
  600. var delta = _this._calculateDelta(rawDeltaData, bound, spanIndex, currentValue);
  601. var draggableOptions = { dataProvider: dataProvider, direction: direction, delta: delta, rowIndex: rowIndex, colIndex: colIndex, colSpan: colSpan, rowSpan: rowSpan, fixedColumns: fixedColumns, fixedRows: fixedRows, defaultValue: defaultValue, currentValue: currentValue, skipBound: skipBound };
  602. _this._onDraggableResize(draggableOptions);
  603. }
  604. }, resizeHandler);
  605. };
  606. /**
  607. * render the hidden rows or columns handler
  608. * @param {string} useValue
  609. * @param {string} position
  610. */
  611. CrosstabGrid.prototype._renderHiddenRowsAndColumnsHandler = function _renderHiddenRowsAndColumnsHandler(useValue) {
  612. var _this2 = this;
  613. var position = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'bottom';
  614. return React.createElement('div', {
  615. class: 'grid-hidden-rowsAndColumns ' + position,
  616. onDoubleClick: function onDoubleClick() {
  617. _this2.crosstabView.setPropertyValue(PROP_ID_HIDDEN_ROWS_AND_COLS, _this2.hiddenRowsAndColumns.filter(function (hiddenRowOrColumn) {
  618. return hiddenRowOrColumn !== useValue;
  619. }));
  620. }
  621. }, '');
  622. };
  623. /**
  624. * render the expand button
  625. * @param {object} expandOptions
  626. */
  627. CrosstabGrid.prototype._renderExpandButton = function _renderExpandButton(expandOptions) {
  628. var _this3 = this;
  629. var dataItemInfo = expandOptions.dataItemInfo,
  630. parentUseValue = expandOptions.parentUseValue,
  631. currentUseValue = expandOptions.currentUseValue;
  632. return React.createElement(Toolkit.Button, {
  633. icon: 'visualizations-expand_16',
  634. iconSize: 'small',
  635. variant: 'icon',
  636. intent: 'primary',
  637. title: StringResources.get('expandBtnLabel'),
  638. onClick: function onClick(event) {
  639. _this3.expandCollapseFeature.expand(dataItemInfo.dataitemUniqueId, parentUseValue, currentUseValue);
  640. event.stopPropagation();
  641. }
  642. });
  643. };
  644. /**
  645. * render the collapse button
  646. * @param {object} expandOptions
  647. */
  648. CrosstabGrid.prototype._renderCollapseButton = function _renderCollapseButton(expandOptions) {
  649. var _this4 = this;
  650. var dataItemInfo = expandOptions.dataItemInfo,
  651. parentUseValue = expandOptions.parentUseValue,
  652. currentUseValue = expandOptions.currentUseValue,
  653. hasChildren = expandOptions.hasChildren;
  654. return React.createElement(Toolkit.Button, {
  655. icon: 'visualizations-collapse_16',
  656. iconSize: 'small',
  657. variant: 'icon',
  658. intent: 'primary',
  659. title: StringResources.get('collapseBtnLabel'),
  660. onClick: function onClick(event) {
  661. _this4.expandCollapseFeature.collapse(dataItemInfo.dataitemUniqueId, parentUseValue, currentUseValue);
  662. event.stopPropagation();
  663. },
  664. style: hasChildren ? {} : { visibility: 'hidden' }
  665. });
  666. };
  667. /**
  668. * render the text cell
  669. * @param {string} displayValue
  670. * @param {object} expandOptions
  671. */
  672. CrosstabGrid.prototype._renderTextCell = function _renderTextCell(displayValue, expandOptions) {
  673. var textCellChildren = [];
  674. var style = {};
  675. if (expandOptions.levelNumber !== undefined) {
  676. var expandCollapseHandler = expandOptions.isExpanded ? this._renderCollapseButton(expandOptions) : this._renderExpandButton(expandOptions);
  677. textCellChildren.push(expandCollapseHandler);
  678. var marginStyle = expandOptions.position === 'top' ? 'margin-top' : 'margin-left';
  679. style[marginStyle] = (expandOptions.levelNumber - expandOptions.rootLevel) * EXPAND_INDENTATION;
  680. }
  681. textCellChildren.push(displayValue);
  682. return React.createElement('div', {
  683. class: 'dashboard-text-cell',
  684. style: style
  685. }, textCellChildren);
  686. };
  687. CrosstabGrid.prototype._renderGridCellContent = function _renderGridCellContent(colIndex, style, fixedColumns, dataCellValue) {
  688. var shapeCol = colIndex + fixedColumns;
  689. var isShapeCol = this._shapeCols.indexOf(shapeCol) !== -1;
  690. if (!isShapeCol && style.shapeId) {
  691. isShapeCol = !!this._shapeCols.push(shapeCol);
  692. }
  693. var contentSpec = {
  694. displayValue: this._wrapDataCellValue(colIndex + fixedColumns, dataCellValue, style, true, isShapeCol)
  695. };
  696. if (isShapeCol) {
  697. contentSpec.shapeId = style.shapeId;
  698. }
  699. return React.createElement(GridContentRenderer, contentSpec);
  700. };
  701. /**
  702. * decorate edge cell with selection or implied selection style
  703. * @param {string} valueType, 'row' or 'column'
  704. * @param {object} dataValue, rawDataValue
  705. * @param {string} useValue
  706. * @param {array} classList, an array of class names
  707. */
  708. CrosstabGrid.prototype._renderEdgeSelection = function _renderEdgeSelection(valueType, dataValue, useValue, classList) {
  709. var sSlotID = this._getSlotIDByEdgeType(valueType);
  710. var ancestor_or_self = this._getDataCellValue(dataValue, 'ancestor_or_self');
  711. var edgeSelections = sSlotID === ROW_SLOT_ID ? this._selections.rowSelection : this._selections.colSelection;
  712. if (edgeSelections && edgeSelections.isSelected(ancestor_or_self)) {
  713. classList.push('dashboard-grid-cell-selected');
  714. } else {
  715. var selectedDataPoints = _.chain(_.pluck(this.crosstabView.getSelector().getSelections(), 'categories')).flatten().map(function (category) {
  716. return category.value;
  717. }).value();
  718. if (selectedDataPoints.indexOf(useValue) !== -1) {
  719. classList.push('dashboard-grid-cell-selected');
  720. }
  721. }
  722. };
  723. /**
  724. * decorate data cell with selection style
  725. * @param {object} dataValue, rawDataValue
  726. * @param {array} classList, an array of class names
  727. */
  728. CrosstabGrid.prototype._renderDatapointSelection = function _renderDatapointSelection(dataValue, classList) {
  729. var columnEdge = this._getDataCellValue(dataValue, 'columnEdge');
  730. var rowEdge = this._getDataCellValue(dataValue, 'rowEdge');
  731. if (columnEdge && rowEdge && _.isObject(rowEdge.value) && (columnEdge.isMeasure || _.isObject(columnEdge.value))) {
  732. var selections = this._selections.datapointSelection;
  733. if (selections) {
  734. var aColumnEdgeContext = !columnEdge.isMeasure ? this._getCurrentEdgeSelectionContext(columnEdge) : [];
  735. var aRowEdgeContext = this._getCurrentEdgeSelectionContext(rowEdge);
  736. var selected = selections.isSelected(aColumnEdgeContext.concat(aRowEdgeContext));
  737. if (selected) {
  738. classList.push('dashboard-grid-cell-selected');
  739. }
  740. }
  741. }
  742. };
  743. CrosstabGrid.prototype._getSelectionFormattingStyles = function _getSelectionFormattingStyles() {
  744. var _this5 = this;
  745. var useValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  746. var selectedAreaStyles = this.textStyle[this.textStyleIndex.selectedArea];
  747. var convertedStylesValue = {};
  748. var weight = '';
  749. _.each(selectedAreaStyles, function (val, key) {
  750. var formatKey = useValue;
  751. var propValue = val && val[formatKey];
  752. while (formatKey && formatKey.lastIndexOf(',') > 0) {
  753. formatKey = formatKey.slice(0, formatKey.lastIndexOf(','));
  754. var nextFormatValue = val && val[formatKey];
  755. if (propValue && nextFormatValue && propValue.weight < nextFormatValue.weight || !propValue && nextFormatValue) {
  756. propValue = val[formatKey];
  757. }
  758. }
  759. //color prop need to convert the color into hexValue
  760. if (propValue && key === 'color') {
  761. convertedStylesValue[key] = propValue.value && _this5.colorsService.getHexColorFromDashboardColorSet(propValue.value) || '';
  762. } else {
  763. convertedStylesValue[key] = propValue && propValue.value;
  764. }
  765. // keep the latest weight as reference
  766. var currentWeight = propValue && propValue.weight;
  767. if (currentWeight && currentWeight > weight) {
  768. weight = currentWeight;
  769. }
  770. });
  771. if (_.values(convertedStylesValue).join('') !== '') {
  772. return { convertedStylesValue: convertedStylesValue, weight: weight };
  773. }
  774. };
  775. CrosstabGrid.prototype._getSelectionFormattingStylesForTuple = function _getSelectionFormattingStylesForTuple(dataValue, tuple) {
  776. var _getEdgeUseValues2 = this._getEdgeUseValues(dataValue, tuple),
  777. columnEdgeUseValue = _getEdgeUseValues2.columnEdgeUseValue,
  778. rowEdgeUseValue = _getEdgeUseValues2.rowEdgeUseValue;
  779. var convertedStylesValueForColumnEdge = this._getSelectionFormattingStyles(columnEdgeUseValue);
  780. var convertedStylesValueForRowEdge = this._getSelectionFormattingStyles(rowEdgeUseValue);
  781. var convertedStyles = convertedStylesValueForColumnEdge || convertedStylesValueForRowEdge;
  782. if (convertedStylesValueForColumnEdge && convertedStylesValueForRowEdge) {
  783. convertedStyles = convertedStylesValueForColumnEdge.weight > convertedStylesValueForRowEdge.weight ? convertedStylesValueForColumnEdge : convertedStylesValueForRowEdge;
  784. }
  785. return convertedStyles;
  786. };
  787. /**
  788. * construct the edges useValues for dataPoint
  789. * @param {object} dataValue
  790. * @param {string} tuple value
  791. */
  792. CrosstabGrid.prototype._getEdgeUseValues = function _getEdgeUseValues(dataValue, tuple) {
  793. var columnEdgeDecendant = dataValue.columnEdge && dataValue.columnEdge.descendant_or_self_without_measures;
  794. var columnEdgeCount = columnEdgeDecendant && columnEdgeDecendant.length || 0;
  795. var tupleUseValueList = tuple && _.isString(tuple) ? tuple.split(',') : null;
  796. var columnEdgeUseValue = tupleUseValueList && tupleUseValueList.slice(0, columnEdgeCount).join(',');
  797. var rowEdgeUseValue = tupleUseValueList && tupleUseValueList.slice(columnEdgeCount, tupleUseValueList.length).join(',');
  798. return { columnEdgeUseValue: columnEdgeUseValue, rowEdgeUseValue: rowEdgeUseValue };
  799. };
  800. /**
  801. * determine if a measure cell should be hidden
  802. * measure does not have any useValue mapping, need to use the useValue of the parent row
  803. * @param {object} dataProvider
  804. * @param {integer} rowIndex
  805. * @param {integer} columnIndex
  806. */
  807. CrosstabGrid.prototype._isMeasureHidden = function _isMeasureHidden(dataProvider, rowIndex, columnIndex) {
  808. if (rowIndex < 1) {
  809. return false;
  810. }
  811. var dataValue = dataProvider.getValue(rowIndex - 1, columnIndex);
  812. var useValue = this._getDataCellValue(dataValue, 'useValue');
  813. return this._isRowOrColumnHidden(useValue);
  814. };
  815. /**
  816. * determine if a row or column should be hidden
  817. * @param {string} useValue
  818. */
  819. CrosstabGrid.prototype._isRowOrColumnHidden = function _isRowOrColumnHidden() {
  820. var useValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  821. if (this.hiddenRowsAndColumns.length < 1) {
  822. return false;
  823. }
  824. var isHidden = this.hiddenRowsAndColumns.indexOf(useValue) !== -1;
  825. while (useValue && useValue.lastIndexOf(',') > 0 && !isHidden) {
  826. useValue = useValue.slice(0, useValue.lastIndexOf(','));
  827. isHidden = this.hiddenRowsAndColumns.indexOf(useValue) !== -1;
  828. }
  829. return isHidden;
  830. };
  831. CrosstabGrid.prototype._getCanvasFont = function _getCanvasFont(style) {
  832. // take default style into consideration
  833. var font = {
  834. 'font-style': style['font-style'],
  835. 'font-weight': style['font-weight'],
  836. 'font-size': style['font-size'] || DEFAULT_TEXT_STYLE.FONT_SIZE,
  837. 'font-family': style['font-family'] || DEFAULT_TEXT_STYLE.FONT_FAMILY
  838. };
  839. return _.values(font).join(' ');
  840. };
  841. CrosstabGrid.prototype._getTextWidth = function _getTextWidth(text, font) {
  842. this._canvas = this._canvas || document.createElement('canvas');
  843. var context = this._canvas.getContext('2d');
  844. context.font = font;
  845. return parseInt(context.measureText(text).width);
  846. };
  847. CrosstabGrid.prototype._generateWrappedText = function _generateWrappedText(colIndex, font, width) {
  848. // cached the character counter that can fit a column, so we do not need to repeatly calculate for every cell in the same column
  849. var cachedCellWidthStatus = this._cellWidthStatus && this._cellWidthStatus[colIndex];
  850. var cachedCharCount = cachedCellWidthStatus && cachedCellWidthStatus['charCount'];
  851. var cachedCellWidth = cachedCellWidthStatus && cachedCellWidthStatus['cellWidth'];
  852. var wrappedText = '#';
  853. if (cachedCharCount && width === cachedCellWidth) {
  854. return wrappedText.repeat(cachedCharCount);
  855. } else {
  856. var singleCharWidth = this._getTextWidth(wrappedText, font);
  857. // take padding into consideration
  858. var charCount = parseInt((width - DEFAULT_TEXT_STYLE.PADDING_WIDTH) / singleCharWidth);
  859. // when the cell width is super small, wrap at least one char
  860. charCount = charCount <= 0 ? 1 : charCount;
  861. this._cellWidthStatus = this._cellWidthStatus || {};
  862. this._cellWidthStatus[colIndex] = this._cellWidthStatus[colIndex] || {};
  863. this._cellWidthStatus[colIndex]['charCount'] = charCount;
  864. this._cellWidthStatus[colIndex]['cellWidth'] = width;
  865. return wrappedText.repeat(charCount);
  866. }
  867. };
  868. CrosstabGrid.prototype._wrapDataCellValue = function _wrapDataCellValue(colIndex, dataCellValue, gridCellStyles, isTextWrapped, isShapeCol) {
  869. var font = this._getCanvasFont(gridCellStyles);
  870. // take padding into consideration
  871. var textWidth = this._getTextWidth(dataCellValue, font) + DEFAULT_TEXT_STYLE.PADDING_WIDTH;
  872. var cellWidth = parseInt(gridCellStyles.width);
  873. var cellContentWidth = textWidth;
  874. if (isShapeCol) {
  875. cellContentWidth += SHAPE_WIDTH;
  876. }
  877. if (cellContentWidth > cellWidth) {
  878. // cached the biggeset textWidth for resize to unwrap the text
  879. this._cellWidthStatus = this._cellWidthStatus || {};
  880. this._cellWidthStatus[colIndex] = this._cellWidthStatus[colIndex] || {};
  881. // we always keep track the biggest textWidth, so using colIndex as key is safe
  882. this._cellWidthStatus[colIndex]['textWidth'] = this._cellWidthStatus[colIndex]['textWidth'] < textWidth ? textWidth : this._cellWidthStatus[colIndex]['textWidth'] || textWidth;
  883. if (isTextWrapped) {
  884. // only wrapped text if the flag is on
  885. dataCellValue = this._generateWrappedText(colIndex, font, cellWidth);
  886. }
  887. }
  888. return dataCellValue;
  889. };
  890. CrosstabGrid.prototype._getWhiteListStyles = function _getWhiteListStyles(styles, blackList) {
  891. return _.omit(styles, blackList);
  892. };
  893. CrosstabGrid.prototype._isSuppressionOn = function _isSuppressionOn() {
  894. var suppressionValue = this.content && this.content.getPropertyValue(PROP_ID_SUPPRESSION);
  895. if (suppressionValue && suppressionValue === 'none') {
  896. return false;
  897. }
  898. return true;
  899. };
  900. CrosstabGrid.prototype._isExpandable = function _isExpandable() {
  901. var isExpandFeatureOn = !this.dashboardApi.getGlassCoreSvc('.FeatureChecker').checkValue('dashboard', 'expandCollapse', 'disabled');
  902. var supportsExpandCollapse = this.content && this.content.getPropertyValue(PROP_ID_EXPANDCOLLAPSE);
  903. return isExpandFeatureOn && supportsExpandCollapse;
  904. };
  905. /**
  906. * get expand options for current dataCell
  907. * @param {object} dataValue
  908. * @param {object} siblingDataValue
  909. * @param {object} dataItemInfo
  910. * @param {string} position - top/left
  911. * @returns {Object} expandOptions
  912. */
  913. CrosstabGrid.prototype._getExpandOptions = function _getExpandOptions(dataValue, siblingDataValue, dataItemInfo, levelInfo, position) {
  914. var useValues = this._getDataCellValue(dataValue, 'useValue').split(',');
  915. var siblingUseValues = siblingDataValue && this._getDataCellValue(siblingDataValue, 'useValue').split(',');
  916. // in nested scenario, the useValue of the cell will contain all the edge useValues, the last one will be the one we need
  917. var useValue = useValues[useValues.length - 1];
  918. var siblingUseValue = siblingUseValues && siblingUseValues[siblingUseValues.length - 1];
  919. return {
  920. dataItemInfo: dataItemInfo,
  921. parentUseValue: this._getDataCellValue(dataValue, 'parentUseValue'),
  922. currentUseValue: useValue,
  923. levelNumber: this._getDataCellValue(dataValue, 'levelNumber'),
  924. isExpanded: !!(dataItemInfo && dataItemInfo.expandMap && dataItemInfo.expandMap[useValue]),
  925. position: position,
  926. rootLevel: levelInfo && levelInfo.rootLevelnumber,
  927. hasChildren: !!(siblingDataValue && (useValue === this._getDataCellValue(siblingDataValue, 'parentUseValue') || useValue === siblingUseValue))
  928. };
  929. };
  930. /**
  931. * get expandInfo from the dataItem
  932. * @param {object} dataItem
  933. * @param {object} expandMap
  934. * @param {integer} maxDepth
  935. * @returns {Object} maxDepth and expandMap
  936. */
  937. CrosstabGrid.prototype._getExpandInfo = function _getExpandInfo(dataItem, expandMap, maxDepth) {
  938. var _this6 = this;
  939. var union = dataItem.getUnion();
  940. var dataItemList = union.getDataItemList();
  941. if (dataItemList.length > 0) {
  942. maxDepth++;
  943. dataItemList.forEach(function (newDataItem) {
  944. var nestedChildren = newDataItem.getDrillDownValue();
  945. expandMap[nestedChildren] = true;
  946. var nestedUnion = newDataItem.getUnion();
  947. var nestedDataItemList = nestedUnion.getDataItemList();
  948. if (nestedDataItemList.length > 0) {
  949. var tmpMaxDepth = _this6._getExpandInfo(newDataItem, expandMap, maxDepth).maxDepth;
  950. if (tmpMaxDepth > maxDepth) {
  951. maxDepth = tmpMaxDepth;
  952. }
  953. }
  954. });
  955. }
  956. return { maxDepth: maxDepth, expandMap: expandMap };
  957. };
  958. /**
  959. * get dataItemInfo by slotId
  960. * @param {string} slotId
  961. * @returns {Object} dataItemInfo
  962. */
  963. CrosstabGrid.prototype._getDataItemInfoBySlotId = function _getDataItemInfoBySlotId(slotId) {
  964. var _this7 = this;
  965. var visualization = this.content && this.content.getFeature('Visualization');
  966. var slots = visualization && visualization.getSlots();
  967. var slot = slots.getSlot(slotId);
  968. var dataItemInfo = {};
  969. if (slot) {
  970. _.each(slot.getDataItemList(), function (dataItem, index) {
  971. var expandInfo = _this7._getExpandInfo(dataItem, {}, 0);
  972. dataItemInfo[index] = {
  973. dataitemId: dataItem.getColumnId(),
  974. dataitemUniqueId: dataItem.getId(),
  975. expandMap: expandInfo.expandMap,
  976. maxDepth: expandInfo.maxDepth,
  977. isProperty: dataItem.getMetadataColumn().isProperty()
  978. };
  979. });
  980. }
  981. return dataItemInfo;
  982. };
  983. /**
  984. * get cached dataItemInfo by index
  985. * @param {Object} cachedDataItemInfo
  986. * @param {integer} row/column index
  987. * @param {string} propertyName
  988. * @returns {Object} dataItemInfo
  989. */
  990. CrosstabGrid.prototype._getCachedDataItemInfoByIndex = function _getCachedDataItemInfoByIndex(cachedDataItemInfoMap, index, propertyName) {
  991. var cachedDataItemInfo = cachedDataItemInfoMap && cachedDataItemInfoMap[index];
  992. return propertyName ? cachedDataItemInfo && cachedDataItemInfo[propertyName] : cachedDataItemInfo;
  993. };
  994. CrosstabGrid.prototype._getCellPropertyColors = function _getCellPropertyColors() {
  995. try {
  996. // if user customized a background color for current widget
  997. var fillColor = this.content && this.content.getPropertyValue('fillColor');
  998. var cellFillColor = fillColor && this.colorsService.getHexColorFromDashboardColorSet(fillColor);
  999. // TODO: have our own theme mapping for new grid
  1000. var foregroundColorProperties = this.colorsService.getForegroundColorPropertiesForUIElement(fillColor, 'tabs');
  1001. var cellTextColor = foregroundColorProperties && foregroundColorProperties.length && foregroundColorProperties[0].value;
  1002. return {
  1003. cellFillColor: cellFillColor,
  1004. cellTextColor: cellTextColor
  1005. };
  1006. } catch (err) {
  1007. return {};
  1008. }
  1009. };
  1010. CrosstabGrid.prototype._getIndentationDepth = function _getIndentationDepth(dataItemInfo, type, index) {
  1011. var maxDepth = this._getCachedDataItemInfoByIndex(dataItemInfo, index, 'maxDepth') || 0;
  1012. var levelInfo = this._cachedLevelInfo[type][index];
  1013. var maxLevelDepth = levelInfo && levelInfo.maxLevelDepth || 0;
  1014. return Math.max(maxDepth, maxLevelDepth);
  1015. };
  1016. /**
  1017. * calculate columnWidth for current column
  1018. * hiddenColumnWidth > customizedColumnWidth > fixedColumnWidth(default)
  1019. * hiddenColumnWidth is set as a small float number that is close to 0 to prevent the react removing the dom with 0 width
  1020. * @param {object} dataProvider
  1021. * @param {integer} rowIndex
  1022. * @param {integer} columnIndex
  1023. * @param {integer} fixedColumnWidth
  1024. */
  1025. CrosstabGrid.prototype._getColumnWidth = function _getColumnWidth(dataProvider, rowIndex, colIndex, fixedColumnWidth) {
  1026. // check from cached status first
  1027. if (this._cachedHiddenCol[colIndex]) {
  1028. return HIDDEN_COL_WIDTH;
  1029. }
  1030. var fixedRowCellValue = dataProvider.getValue(rowIndex, colIndex);
  1031. var isMeasure = this._getDataCellValue(fixedRowCellValue, 'isMeasure');
  1032. if (this._isRowOrColumnHidden(this._getDataCellValue(fixedRowCellValue, 'useValue')) || isMeasure && this._isMeasureHidden(dataProvider, rowIndex, colIndex)) {
  1033. this._cachedHiddenCol[colIndex] = true;
  1034. return HIDDEN_COL_WIDTH;
  1035. }
  1036. // when the cell is a corner cell, use the dataItem label as resize key
  1037. var rootResizeKey = this._getDataCellValue(fixedRowCellValue, 'type') === 'corner' ? this._getCachedDataItemInfoByIndex(this._cachedRowDataItemInfo, colIndex, 'dataitemId') : this._buildResizeKey(this._getDataCellValue(fixedRowCellValue, 'ancestor_or_self'));
  1038. if (this.columnWidths && this.columnWidths[rootResizeKey]) {
  1039. return this.columnWidths[rootResizeKey];
  1040. }
  1041. var isShapeCol = this._shapeCols.indexOf(colIndex) !== -1;
  1042. if (isShapeCol) {
  1043. fixedColumnWidth += SHAPE_WIDTH;
  1044. }
  1045. // increase columnWidth for the expand indentations
  1046. var indentationDepth = this._getIndentationDepth(this._cachedRowDataItemInfo, 'col', colIndex);
  1047. if (this.isExpandable && indentationDepth > 0) {
  1048. return parseInt(fixedColumnWidth, 10) + indentationDepth * EXPAND_INDENTATION;
  1049. }
  1050. return fixedColumnWidth;
  1051. };
  1052. /**
  1053. * calculate rowHeight for current row
  1054. * hiddenRowHeight > customizedRowHeight > fixedRowheight(default)
  1055. * hiddenRowHeight is set as a small float number that is close to 0 to prevent the react removing the dom with 0 height
  1056. * @param {object} dataProvider
  1057. * @param {integer} rowIndex
  1058. * @param {integer} columnIndex
  1059. * @param {integer} fixedRowHeight
  1060. */
  1061. CrosstabGrid.prototype._getRowHeight = function _getRowHeight(dataProvider, rowIndex, colIndex, fixedRowHeight) {
  1062. // check from cached status first
  1063. if (this._cachedHiddenRow[colIndex]) {
  1064. return HIDDEN_ROW_HEIGHT;
  1065. }
  1066. var fixedColumnCellValue = dataProvider.getValue(rowIndex, colIndex);
  1067. if (this._isRowOrColumnHidden(this._getDataCellValue(fixedColumnCellValue, 'useValue'))) {
  1068. this._cachedHiddenRow[rowIndex] = true;
  1069. return HIDDEN_ROW_HEIGHT;
  1070. }
  1071. // when the cell is a corner cell, use the dataItem label as resize key
  1072. // measure row is a special row since it does not have any dataItem mapped, use a constant as resize key
  1073. var rootResizeKey = this._getDataCellValue(fixedColumnCellValue, 'type') === 'corner' ? this._getCachedDataItemInfoByIndex(this._cachedColumnDataItemInfo, rowIndex, 'dataitemId') || MEASURE_ROW_RESIZE_IDENTIFIER : this._buildResizeKey(this._getDataCellValue(fixedColumnCellValue, 'ancestor_or_self'));
  1074. if (this.rowHeights && this.rowHeights[rootResizeKey]) {
  1075. return this.rowHeights[rootResizeKey];
  1076. }
  1077. // increase rowHeight for the expand indentations
  1078. var indentationDepth = this._getIndentationDepth(this._cachedColumnDataItemInfo, 'row', rowIndex);
  1079. if (this.isExpandable && indentationDepth > 0) {
  1080. return parseInt(fixedRowHeight, 10) + indentationDepth * EXPAND_INDENTATION;
  1081. }
  1082. return fixedRowHeight;
  1083. };
  1084. CrosstabGrid.prototype._renderReactGrid = function _renderReactGrid() {
  1085. var _this8 = this;
  1086. var _dataProvider = this.dataProvider;
  1087. _dataProvider.updateData.bind(this.dataProvider);
  1088. _dataProvider.getNumColumns.bind(this.dataProvider);
  1089. _dataProvider.getNumRows.bind(this.dataProvider);
  1090. _dataProvider.getValue.bind(this.dataProvider);
  1091. // in story, the first-time rendering from dashboard, the offsetHeight of the node is 0, need to check this
  1092. this.maxColHeight = this._getMaxColHeight();
  1093. var fixedColumns = this._pivotTable.getNestingLevels().rowNestingLevel;
  1094. var fixedRows = this._pivotTable.getNestingLevels().colNestingLevel;
  1095. _dataProvider.updateData(this.data);
  1096. var numColumns = _dataProvider.getNumColumns() - fixedColumns;
  1097. var numRows = _dataProvider.getNumRows() - fixedRows;
  1098. var TABINDEX = 0;
  1099. var fixedRowHeight = this.fixedRowHeight || DEFAULT_ROW_HEIGHT;
  1100. var fixedColumnWidth = this.fixedColumnWidth || DEFAULT_COLUMN_WIDTH;
  1101. if (numRows === 0) {
  1102. fixedRows = numRows;
  1103. }
  1104. if (numColumns === 0) {
  1105. fixedColumns = numColumns;
  1106. }
  1107. var _getCellPropertyColor = this._getCellPropertyColors(),
  1108. cellFillColor = _getCellPropertyColor.cellFillColor,
  1109. cellTextColor = _getCellPropertyColor.cellTextColor;
  1110. var isSuppressed = this._isSuppressionOn();
  1111. this.isExpandable = this._isExpandable();
  1112. // load expandCollapseFeature if the grid is expandable
  1113. if (this.isExpandable) {
  1114. this.expandCollapseFeature = this.content && this.content.getFeature('ExpandCollapse');
  1115. }
  1116. // cache the dataitemInfo
  1117. this._cachedRowDataItemInfo = this._getDataItemInfoBySlotId(ROW_SLOT_ID);
  1118. this._cachedColumnDataItemInfo = this._getDataItemInfoBySlotId(COLUMN_SLOT_ID);
  1119. // cache the levelInfo
  1120. this._cachedLevelInfo = this._pivotTable.getLevelInfo();
  1121. //reset cached hidden rows and columns info per render
  1122. this._cachedHiddenRow = {};
  1123. this._cachedHiddenCol = {};
  1124. var dataCellRenderer = function dataCellRenderer(rowIndex, colIndex, gridCellProps) {
  1125. var dataValue = _dataProvider.getValue(rowIndex + fixedRows, colIndex + fixedColumns);
  1126. var _isSummary = _this8._isSummary(dataValue);
  1127. var dataCellValue = _this8._getDataCellValue(dataValue);
  1128. var measureInfo = _this8._pivotTable._measuresInfo;
  1129. var measureIndex = measureInfo.length > 0 ? colIndex % measureInfo.length : null;
  1130. var formatSpec = Number.isInteger(measureIndex) ? measureInfo[measureIndex].formatSpec : null;
  1131. var content = _this8.crosstabView && _this8.crosstabView.content;
  1132. if (content) {
  1133. var visFormatSpec = content.getPropertyValue('format');
  1134. if (visFormatSpec) {
  1135. formatSpec = _.extend({}, formatSpec, visFormatSpec);
  1136. }
  1137. }
  1138. dataCellValue = Formatter.formatNull(dataCellValue, formatSpec);
  1139. var tuple = _this8._getDataCellValue(dataValue, 'tuple');
  1140. var blackListStyles = ['word-break', 'white-space'];
  1141. //populate the attributes we needed
  1142. _.extend(gridCellProps, {
  1143. tuple: tuple,
  1144. measure: _this8._getDataCellValue(dataValue, 'isMeasure'),
  1145. row: rowIndex + fixedRows,
  1146. col: colIndex + fixedColumns,
  1147. 'aria-label': dataCellValue,
  1148. tabindex: TABINDEX,
  1149. area: AREA_TYPE.CELL
  1150. });
  1151. gridCellProps.className = _this8._removeFocusedClassName(gridCellProps.className);
  1152. var classList = [gridCellProps.className];
  1153. classList.push('grid-data-cell', 'dashboard-grid-cell');
  1154. if (_this8._cachedHiddenRow[rowIndex + fixedRows] || _this8._cachedHiddenCol[colIndex + fixedColumns]) {
  1155. // if any of the edge is hidden, render an empty div
  1156. gridCellProps.className = classList.join(' ');
  1157. return React.createElement('div', gridCellProps, '');
  1158. }
  1159. // background color from Property
  1160. if (cellFillColor && !_isSummary) {
  1161. if ((rowIndex + fixedRows) % 2 === 0) {
  1162. gridCellProps.style = _.extend(gridCellProps.style, {
  1163. color: cellTextColor
  1164. });
  1165. classList.push('light');
  1166. } else {
  1167. gridCellProps.style = _.extend(gridCellProps.style, {
  1168. backgroundColor: cellFillColor,
  1169. color: cellTextColor
  1170. });
  1171. }
  1172. }
  1173. //Text toolbar style applied
  1174. var valueType = _this8._getDataCellValue(dataValue, 'type');
  1175. if (!valueType) {
  1176. // ignore text wrapping styles
  1177. var values = Object.assign({}, _this8.textStyle[_this8.textStyleIndex.cell]);
  1178. Object.keys(values).forEach(function (key) {
  1179. return values[key] === '' && delete values[key];
  1180. });
  1181. Object.assign(gridCellProps.style, _this8._getWhiteListStyles(values, blackListStyles));
  1182. }
  1183. //Selection formatting for text toolbar
  1184. var selectedAreaStyles = _this8._getSelectionFormattingStylesForTuple(dataValue, tuple);
  1185. if (selectedAreaStyles) {
  1186. // ignore text wrapping styles
  1187. var _values = selectedAreaStyles.convertedStylesValue;
  1188. Object.keys(_values).forEach(function (key) {
  1189. return _values[key] === '' && delete _values[key];
  1190. });
  1191. Object.assign(gridCellProps.style, _this8._getWhiteListStyles(_values, blackListStyles));
  1192. }
  1193. //Alternative row background
  1194. if ((rowIndex + fixedRows) % 2 === 0) {
  1195. classList.push('alternate');
  1196. }
  1197. //Conditional Formatting
  1198. var condValue = _this8._getDataCellValue(dataValue, 'condValue');
  1199. if (condValue) {
  1200. var _style = _this8._getConditionalFormatting(condValue, dataValue, measureIndex);
  1201. _.extend(gridCellProps.style, _style);
  1202. }
  1203. //render selection highlight
  1204. _this8._renderDatapointSelection(dataValue, classList);
  1205. var children = [];
  1206. // styles overwritten for summary cell
  1207. if (_isSummary) {
  1208. classList.push('summary');
  1209. if (dataValue.rowEdge.isSummary) {
  1210. children.push(React.createElement('div', { className: 'grid-summary-decorator' }, ''));
  1211. }
  1212. gridCellProps.area = AREA_TYPE.SUMMARY;
  1213. // ignore text wrapping styles
  1214. _.extend(gridCellProps.style, _this8._getWhiteListStyles(_this8.textStyle[_this8.textStyleIndex.summary], blackListStyles));
  1215. // summary text is always bold
  1216. _.extend(gridCellProps.style, { 'font-weight': 'bold' });
  1217. if (_this8._isSummaryHighlighted) {
  1218. classList.push('dashboard-grid-cell-selected');
  1219. }
  1220. _this8._setSummaryColor(gridCellProps);
  1221. }
  1222. children.push(_this8._renderGridCellContent(colIndex, gridCellProps.style, fixedColumns, dataCellValue));
  1223. gridCellProps.className = classList.join(' ');
  1224. return React.createElement('div', gridCellProps, children);
  1225. };
  1226. var fixedRowCellRenderer = function fixedRowCellRenderer(rowIndex, colIndex, gridCellProps) {
  1227. var dataValue = _dataProvider.getValue(rowIndex, colIndex + fixedColumns);
  1228. var _isSummary = _this8._isSummary(dataValue);
  1229. var useValue = _this8._getDataCellValue(dataValue, 'useValue');
  1230. var dataCellValue = _this8._getDataCellValue(dataValue);
  1231. var isMeasure = _this8._getDataCellValue(dataValue, 'isMeasure');
  1232. //populate the attributes we needed
  1233. _.extend(gridCellProps, {
  1234. useValue: useValue,
  1235. nestlevel: _this8._getDataCellValue(dataValue, 'nestlevel'),
  1236. row: rowIndex,
  1237. col: colIndex + fixedColumns,
  1238. scope: 'col',
  1239. 'aria-label': dataCellValue,
  1240. tabindex: TABINDEX,
  1241. area: AREA_TYPE.COLUMN
  1242. });
  1243. var classList = gridCellProps.className ? [gridCellProps.className] : [];
  1244. classList.push('grid-fixed-row-cell', 'dashboard-grid-cell');
  1245. if (_this8._cachedHiddenCol[colIndex + fixedColumns]) {
  1246. // if column is hidden, render a hidden column handler on the left
  1247. gridCellProps.className = classList.join(' ');
  1248. gridCellProps.style.zIndex = numColumns - colIndex;
  1249. delete gridCellProps.style.width;
  1250. return React.createElement('div', gridCellProps, _this8._renderHiddenRowsAndColumnsHandler(useValue, 'left'));
  1251. }
  1252. //Text toolbar style applied
  1253. var valueType = _this8._getDataCellValue(dataValue, 'type');
  1254. valueType = valueType && valueType === 'column' && isMeasure ? 'corner' : valueType;
  1255. if (valueType) {
  1256. var styleIndexForValueType = _this8.textStyleIndex[valueType];
  1257. _.extend(gridCellProps.style, _this8.textStyle[styleIndexForValueType]);
  1258. // overwrite the area type if the column is actually a measure label
  1259. if (valueType === 'corner') {
  1260. _.extend(gridCellProps, {
  1261. area: AREA_TYPE.MEASURE,
  1262. measure: 'true'
  1263. });
  1264. // highlight the measure header cell if multiselected for calculation
  1265. if (_this8._measureHeaderDecorations && _this8._measureHeaderDecorations.indexOf(useValue) > -1) {
  1266. classList.push('dashboard-grid-cell-selected');
  1267. }
  1268. }
  1269. }
  1270. //Selection formatting for text toolbar
  1271. var selectedAreaStyles = _this8._getSelectionFormattingStyles(useValue);
  1272. if (selectedAreaStyles) {
  1273. _.extend(gridCellProps.style, selectedAreaStyles.convertedStylesValue);
  1274. }
  1275. // colspan/rowspan
  1276. var spanIndexOptions = {
  1277. colIndex: colIndex + fixedColumns,
  1278. rowIndex: rowIndex,
  1279. colBound: numColumns + 1,
  1280. rowBound: fixedRows,
  1281. dataProvider: _dataProvider,
  1282. fixedRows: fixedRows,
  1283. fixedColumns: fixedColumns,
  1284. dataCellValue: dataCellValue,
  1285. gridCellProps: gridCellProps,
  1286. defaultColumnWidth: fixedColumnWidth,
  1287. defaultRowHeight: fixedRowHeight,
  1288. ignoreGrouping: {
  1289. row: !_isSummary
  1290. }
  1291. };
  1292. var _getSpanIndex2 = _this8._getSpanIndex(spanIndexOptions),
  1293. colSpan = _getSpanIndex2.colSpan,
  1294. rowSpan = _getSpanIndex2.rowSpan,
  1295. gridCellColumnWidth = _getSpanIndex2.gridCellColumnWidth,
  1296. gridCellRowHeight = _getSpanIndex2.gridCellRowHeight;
  1297. _.extend(gridCellProps.style, {
  1298. width: gridCellColumnWidth + 'px',
  1299. zIndex: numColumns - colIndex + (colSpan > rowSpan ? colSpan : rowSpan)
  1300. });
  1301. var columnInfo = _this8._pivotTable._columnInfo;
  1302. var index = colIndex % columnInfo.length;
  1303. var formatSpec = columnInfo[index] && columnInfo[index].formatSpec;
  1304. var content = _this8.crosstabView && _this8.crosstabView.content;
  1305. if (content) {
  1306. var visFormatSpec = content.getPropertyValue('format');
  1307. if (visFormatSpec) {
  1308. formatSpec = _.extend({}, formatSpec, visFormatSpec);
  1309. }
  1310. }
  1311. if (_isSummary) {
  1312. formatSpec = null;
  1313. }
  1314. var formattedDisplayValue = isSuppressed ? Formatter.format(dataCellValue, formatSpec) : Formatter.formatNull(dataCellValue);
  1315. // check if cell is expandable
  1316. var siblingDataValue = colIndex + fixedColumns < numColumns ? _dataProvider.getValue(rowIndex, colIndex + fixedColumns + 1) : null;
  1317. // defect 298869: Disable expand/collapse on crosstab if property/attribute data item on edges
  1318. var _cachedDataItemInfoByIndex = _this8._getCachedDataItemInfoByIndex(_this8._cachedColumnDataItemInfo, rowIndex);
  1319. var isProperty = _cachedDataItemInfoByIndex && _cachedDataItemInfoByIndex.isProperty;
  1320. var expandOptions = _this8.isExpandable && !isProperty ? _this8._getExpandOptions(dataValue, siblingDataValue, _cachedDataItemInfoByIndex, _this8._cachedLevelInfo.row[rowIndex], 'top') : {};
  1321. var children = [_this8._renderTextCell(formattedDisplayValue, expandOptions)];
  1322. // styles overwritten for summary cell
  1323. if (_isSummary) {
  1324. classList.push('summary');
  1325. children.push(React.createElement('div', { class: 'grid-summary-decorator' }, ''));
  1326. gridCellProps.area = AREA_TYPE.SUMMARY;
  1327. _.extend(gridCellProps.style, _this8.textStyle[_this8.textStyleIndex.summary]);
  1328. // summary text is always bold
  1329. _.extend(gridCellProps.style, { 'font-weight': 'bold' });
  1330. if (_this8._isSummaryHighlighted) {
  1331. classList.push('dashboard-grid-cell-selected');
  1332. }
  1333. _this8._setSummaryColor(gridCellProps);
  1334. } else {
  1335. gridCellProps.style.height = Math.min(gridCellRowHeight, _this8.maxColHeight) + 'px';
  1336. //render selection and implied Selection
  1337. _this8._renderEdgeSelection(valueType, dataValue, useValue, classList);
  1338. if (isMeasure) {
  1339. children.push(React.createElement('div', { class: 'grid-drop-zone left' }, ''));
  1340. children.push(React.createElement('div', { class: 'grid-drop-zone right' }, ''));
  1341. } else {
  1342. children.push(React.createElement('div', { class: 'grid-drop-zone top' }, ''));
  1343. children.push(React.createElement('div', { class: 'grid-drop-zone bottom' }, ''));
  1344. }
  1345. children.push(React.createElement('div', { class: 'grid-drop-zone replace' }, ''));
  1346. }
  1347. gridCellProps.className = classList.join(' ');
  1348. // common resize props
  1349. var commonResizeHandlerOptions = {
  1350. dataProvider: _dataProvider,
  1351. containerClassName: 'grid-fixed-row-cell',
  1352. offSetParent: 'ba-common-grid__top-right-grid',
  1353. rowIndex: rowIndex,
  1354. colIndex: colIndex + fixedColumns,
  1355. colSpan: colSpan,
  1356. rowSpan: rowSpan,
  1357. fixedColumns: fixedColumns,
  1358. fixedRows: fixedRows
  1359. };
  1360. // column resize handlers
  1361. children.push(_this8._renderResizeHandler(_.extend(commonResizeHandlerOptions, {
  1362. direction: AXIS_X,
  1363. className: 'grid-column-resizer',
  1364. defaultValue: fixedColumnWidth,
  1365. currentValue: gridCellColumnWidth,
  1366. bound: MIN_COLUMN_WIDTH,
  1367. skipBound: false
  1368. })));
  1369. // row resize handlers
  1370. children.push(_this8._renderResizeHandler(_.extend(commonResizeHandlerOptions, {
  1371. direction: AXIS_Y,
  1372. className: 'grid-row-resizer',
  1373. defaultValue: fixedRowHeight,
  1374. currentValue: gridCellRowHeight,
  1375. bound: MIN_ROW_HEIGHT,
  1376. skipBound: true
  1377. })));
  1378. return React.createElement(GridDropTarget, _extends({ dndManager: _this8._gridDnDManager, cellType: 'row', isMeasure: isMeasure }, gridCellProps), children);
  1379. };
  1380. var fixedColumnCellRenderer = function fixedColumnCellRenderer(rowIndex, colIndex, gridCellProps) {
  1381. var dataValue = _dataProvider.getValue(rowIndex + fixedRows, colIndex);
  1382. var _isSummary = _this8._isSummary(dataValue);
  1383. var useValue = _this8._getDataCellValue(dataValue, 'useValue');
  1384. var dataCellValue = _this8._getDataCellValue(dataValue);
  1385. //populate the attributes we needed
  1386. _.extend(gridCellProps, {
  1387. useValue: useValue,
  1388. nestlevel: _this8._getDataCellValue(dataValue, 'nestlevel'),
  1389. row: rowIndex + fixedRows,
  1390. col: colIndex,
  1391. scope: 'row',
  1392. 'aria-label': dataCellValue,
  1393. tabindex: TABINDEX,
  1394. area: AREA_TYPE.ROW
  1395. });
  1396. var classList = gridCellProps.className ? [gridCellProps.className] : [];
  1397. classList.push('grid-fixed-column-cell', 'dashboard-grid-cell');
  1398. if (_this8._cachedHiddenRow[rowIndex + fixedRows]) {
  1399. // if row is hidden, render a hidden row handler on the bottom
  1400. gridCellProps.className = classList.join(' ');
  1401. gridCellProps.style.zIndex = numRows - rowIndex;
  1402. delete gridCellProps.style.height;
  1403. return React.createElement('div', gridCellProps, _this8._renderHiddenRowsAndColumnsHandler(useValue, 'bottom'));
  1404. }
  1405. //Text toolbar style applied
  1406. var valueType = _this8._getDataCellValue(dataValue, 'type');
  1407. if (valueType) {
  1408. var styleIndexForValueType = _this8.textStyleIndex[valueType];
  1409. _.extend(gridCellProps.style, _this8.textStyle[styleIndexForValueType]);
  1410. }
  1411. //Selection formatting for text toolbar
  1412. var selectedAreaStyles = _this8._getSelectionFormattingStyles(useValue);
  1413. if (selectedAreaStyles) {
  1414. _.extend(gridCellProps.style, selectedAreaStyles.convertedStylesValue);
  1415. }
  1416. // colspan/rowspan
  1417. var spanIndexOptions = {
  1418. colIndex: colIndex,
  1419. rowIndex: rowIndex + fixedRows,
  1420. colBound: fixedColumns,
  1421. rowBound: numRows + fixedRows - 1,
  1422. dataProvider: _dataProvider,
  1423. fixedRows: fixedRows,
  1424. fixedColumns: fixedColumns,
  1425. dataCellValue: dataCellValue,
  1426. gridCellProps: gridCellProps,
  1427. defaultColumnWidth: fixedColumnWidth,
  1428. defaultRowHeight: fixedRowHeight,
  1429. ignoreGrouping: {
  1430. column: !_isSummary
  1431. }
  1432. };
  1433. var _getSpanIndex3 = _this8._getSpanIndex(spanIndexOptions),
  1434. colSpan = _getSpanIndex3.colSpan,
  1435. rowSpan = _getSpanIndex3.rowSpan,
  1436. gridCellColumnWidth = _getSpanIndex3.gridCellColumnWidth,
  1437. gridCellRowHeight = _getSpanIndex3.gridCellRowHeight;
  1438. _.extend(gridCellProps.style, {
  1439. width: gridCellColumnWidth + 'px',
  1440. zIndex: numRows - rowIndex + (colSpan > rowSpan ? colSpan : rowSpan)
  1441. });
  1442. var rowInfo = _this8._pivotTable._rowInfo;
  1443. var index = colIndex % rowInfo.length;
  1444. var formatSpec = rowInfo[index] && rowInfo[index].formatSpec;
  1445. var content = _this8.crosstabView && _this8.crosstabView.content;
  1446. if (content) {
  1447. var visFormatSpec = content.getPropertyValue('format');
  1448. if (visFormatSpec) {
  1449. formatSpec = _.extend({}, formatSpec, visFormatSpec);
  1450. }
  1451. }
  1452. if (_isSummary) {
  1453. formatSpec = null;
  1454. }
  1455. var formattedDisplayValue = isSuppressed ? Formatter.format(dataCellValue, formatSpec) : Formatter.formatNull(dataCellValue);
  1456. // check if cell is expandable
  1457. var siblingDataValue = rowIndex < numRows - 1 ? _dataProvider.getValue(rowIndex + fixedRows + 1, colIndex) : null;
  1458. // defect 298869: Disable expand/collapse on crosstab if property/attribute data item on edges
  1459. var _cachedDataItemInfoByIndex = _this8._getCachedDataItemInfoByIndex(_this8._cachedRowDataItemInfo, colIndex);
  1460. var isProperty = _cachedDataItemInfoByIndex && _cachedDataItemInfoByIndex.isProperty;
  1461. var expandOptions = _this8.isExpandable && !isProperty ? _this8._getExpandOptions(dataValue, siblingDataValue, _cachedDataItemInfoByIndex, _this8._cachedLevelInfo.col[colIndex], 'left') : {};
  1462. var children = [_this8._renderTextCell(formattedDisplayValue, expandOptions)];
  1463. // styles overwritten for summary cell
  1464. if (_isSummary) {
  1465. classList.push('summary');
  1466. children.push(React.createElement('div', { class: 'grid-summary-decorator' }, ''));
  1467. gridCellProps.area = AREA_TYPE.SUMMARY;
  1468. _.extend(gridCellProps.style, _this8.textStyle[_this8.textStyleIndex.summary]);
  1469. // summary text is always bold
  1470. _.extend(gridCellProps.style, { 'font-weight': 'bold' });
  1471. if (_this8._isSummaryHighlighted) {
  1472. classList.push('dashboard-grid-cell-selected');
  1473. }
  1474. _this8._setSummaryColor(gridCellProps);
  1475. } else {
  1476. gridCellProps.style.height = Math.min(gridCellRowHeight, _this8.maxColHeight) + 'px';
  1477. //render selection and implied Selection
  1478. _this8._renderEdgeSelection(valueType, dataValue, useValue, classList);
  1479. children.push(React.createElement('div', { class: 'grid-drop-zone left' }, ''));
  1480. children.push(React.createElement('div', { class: 'grid-drop-zone replace' }, ''));
  1481. children.push(React.createElement('div', { class: 'grid-drop-zone right' }, ''));
  1482. }
  1483. gridCellProps.className = classList.join(' ');
  1484. // generate the size map for double-click on fixedColumn cell to expand the wrapped value
  1485. _this8._wrapDataCellValue(colIndex, dataCellValue, gridCellProps.style, false);
  1486. // common resize props
  1487. var commonResizeHandlerOptions = {
  1488. dataProvider: _dataProvider,
  1489. containerClassName: 'grid-fixed-column-cell',
  1490. offSetParent: 'ba-common-grid__bottom-left-grid',
  1491. rowIndex: rowIndex + fixedRows,
  1492. colIndex: colIndex,
  1493. colSpan: colSpan,
  1494. rowSpan: rowSpan,
  1495. fixedColumns: fixedColumns,
  1496. fixedRows: fixedRows
  1497. };
  1498. // column resize handlers
  1499. children.push(_this8._renderResizeHandler(_.extend(commonResizeHandlerOptions, {
  1500. direction: AXIS_X,
  1501. className: 'grid-column-resizer',
  1502. defaultValue: fixedColumnWidth,
  1503. currentValue: gridCellColumnWidth,
  1504. bound: MIN_COLUMN_WIDTH,
  1505. skipBound: true
  1506. })));
  1507. // row resize handlers
  1508. children.push(_this8._renderResizeHandler(_.extend(commonResizeHandlerOptions, {
  1509. direction: AXIS_Y,
  1510. className: 'grid-row-resizer',
  1511. defaultValue: fixedRowHeight,
  1512. currentValue: gridCellRowHeight,
  1513. bound: MIN_ROW_HEIGHT,
  1514. skipBound: false
  1515. })));
  1516. return React.createElement(GridDropTarget, _extends({ dndManager: _this8._gridDnDManager, cellType: 'column' }, gridCellProps), children);
  1517. };
  1518. var fixedCornerCellRenderer = function fixedCornerCellRenderer(rowIndex, colIndex, gridCellProps) {
  1519. var dataValue = _dataProvider.getValue(rowIndex, colIndex);
  1520. var dataCellValue = _this8._getDataCellValue(dataValue);
  1521. //populate the attributes we needed
  1522. _.extend(gridCellProps, {
  1523. row: rowIndex,
  1524. col: colIndex,
  1525. tabindex: TABINDEX,
  1526. area: AREA_TYPE.MEASURE,
  1527. measure: 'true',
  1528. 'aria-label': dataCellValue
  1529. });
  1530. var classList = gridCellProps.className ? [gridCellProps.className] : [];
  1531. classList.push('grid-corner-cell', 'dashboard-grid-cell');
  1532. //Text toolbar style applied
  1533. var valueType = _this8._getDataCellValue(dataValue, 'type');
  1534. if (valueType) {
  1535. var styleIndexForValueType = _this8.textStyleIndex[valueType];
  1536. _.extend(gridCellProps.style, _this8.textStyle[styleIndexForValueType]);
  1537. }
  1538. // colspan/rowspan
  1539. var spanIndexOptions = {
  1540. colIndex: colIndex,
  1541. rowIndex: rowIndex,
  1542. colBound: fixedColumns,
  1543. rowBound: fixedRows,
  1544. dataProvider: _dataProvider,
  1545. fixedRows: fixedRows,
  1546. fixedColumns: fixedColumns,
  1547. dataCellValue: dataCellValue,
  1548. gridCellProps: gridCellProps,
  1549. defaultColumnWidth: fixedColumnWidth,
  1550. defaultRowHeight: fixedRowHeight,
  1551. ignoreGrouping: {}
  1552. };
  1553. var _getSpanIndex4 = _this8._getSpanIndex(spanIndexOptions),
  1554. colSpan = _getSpanIndex4.colSpan,
  1555. rowSpan = _getSpanIndex4.rowSpan,
  1556. gridCellColumnWidth = _getSpanIndex4.gridCellColumnWidth,
  1557. gridCellRowHeight = _getSpanIndex4.gridCellRowHeight;
  1558. _.extend(gridCellProps.style, {
  1559. width: gridCellColumnWidth + 'px',
  1560. height: Math.min(gridCellRowHeight, _this8.maxColHeight) + 'px',
  1561. zIndex: fixedColumns - colIndex + (fixedRows - rowIndex) + (colSpan > rowSpan ? colSpan : rowSpan)
  1562. });
  1563. var children = [React.createElement('div', { class: 'dashboard-text-cell' }, dataCellValue)];
  1564. if (dataCellValue) {
  1565. children.push(React.createElement('div', { class: 'grid-drop-zone left' }, ''));
  1566. children.push(React.createElement('div', { class: 'grid-drop-zone replace' }, ''));
  1567. children.push(React.createElement('div', { class: 'grid-drop-zone right' }, ''));
  1568. }
  1569. gridCellProps.className = classList.join(' ');
  1570. return React.createElement(GridDropTarget, _extends({ dndManager: _this8._gridDnDManager, isMeasure: true, cellType: 'corner' }, gridCellProps), children);
  1571. };
  1572. var rowHeight = function rowHeight(index) {
  1573. return _this8._getRowHeight(_dataProvider, index, fixedColumns - 1, fixedRowHeight);
  1574. };
  1575. var columnWidth = function columnWidth(index) {
  1576. return _this8._getColumnWidth(_dataProvider, fixedRows - 1, index, fixedColumnWidth);
  1577. };
  1578. // RTC #290279 - Crosstab and Grid will sometimes show blank cells when row span is active
  1579. var overscanRowCount = fixedColumns > 1 ? 2 : 20;
  1580. var overscanColumnCount = fixedRows > 1 ? 2 : 10;
  1581. var style = {};
  1582. var grid = React.createElement(Toolkit.Grid, {
  1583. rowHeight: rowHeight,
  1584. columnWidth: columnWidth,
  1585. numColumns: numColumns,
  1586. numRows: numRows,
  1587. fixedRows: fixedRows,
  1588. fixedColumns: fixedColumns,
  1589. dataCellRenderer: dataCellRenderer,
  1590. fixedRowCellRenderer: fixedRowCellRenderer,
  1591. fixedColumnCellRenderer: fixedColumnCellRenderer,
  1592. fixedCornerCellRenderer: fixedCornerCellRenderer,
  1593. overscanRowCount: overscanRowCount,
  1594. overscanColumnCount: overscanColumnCount,
  1595. style: style,
  1596. ref: function ref(node) {
  1597. _this8.gridRef = node;
  1598. },
  1599. maxColumnWidth: Infinity
  1600. });
  1601. var gridGuideLine = React.createElement('div', { class: 'xtab-grid-guideLine' }, '');
  1602. var crosstabGrid = React.createElement('div', { class: 'xtab-grid-view' }, [grid, gridGuideLine]);
  1603. ReactDOM.render(crosstabGrid, this.$el[0]);
  1604. this.gridRef && this.gridRef.recomputeGridSize();
  1605. };
  1606. CrosstabGrid.prototype._isSummary = function _isSummary(dataValue) {
  1607. if (dataValue) {
  1608. if (dataValue.rowEdge && dataValue.columnEdge) {
  1609. return dataValue.columnEdge.isSummary || dataValue.rowEdge.isSummary;
  1610. } else {
  1611. return dataValue.isSummary;
  1612. }
  1613. }
  1614. return false;
  1615. };
  1616. /**
  1617. * Set selections context which contains row edge selection, column edge selection
  1618. * and datapoint selection
  1619. **/
  1620. CrosstabGrid.prototype.setSelections = function setSelections(selections, options) {
  1621. if (options && options.clearSelectionCaches) {
  1622. this.resetSummaryHighlight();
  1623. this.clearMeasureHeaderDecorations();
  1624. }
  1625. this._selections = selections;
  1626. };
  1627. CrosstabGrid.prototype._getSlotIDByEdgeType = function _getSlotIDByEdgeType(edgeType) {
  1628. if (edgeType === 'row') {
  1629. return ROW_SLOT_ID;
  1630. } else if (edgeType === 'column') {
  1631. return COLUMN_SLOT_ID;
  1632. }
  1633. return null;
  1634. };
  1635. CrosstabGrid.prototype.setStyles = function setStyles(styleObj) {
  1636. this.textStyle = styleObj;
  1637. };
  1638. CrosstabGrid.prototype._getCurrentEdgeSelectionContext = function _getCurrentEdgeSelectionContext(edge) {
  1639. var aEdgeContextAncestor = _.clone(edge.ancestor_or_self);
  1640. var aEdgeContextDescendant = _.clone(edge.descendant_or_self);
  1641. aEdgeContextAncestor = _.filter(aEdgeContextAncestor, function (entry) {
  1642. return entry.value;
  1643. });
  1644. aEdgeContextAncestor.pop();
  1645. aEdgeContextDescendant = _.filter(aEdgeContextDescendant, function (entry) {
  1646. return entry.value;
  1647. });
  1648. return (aEdgeContextAncestor || []).concat(aEdgeContextDescendant || []);
  1649. };
  1650. CrosstabGrid.prototype.onEnterContainer = function onEnterContainer() {
  1651. var firstCellNode = $(this.$el[0]).find('.grid-corner-cell[row="0"][col="0"]');
  1652. if (firstCellNode.length) {
  1653. firstCellNode.focus();
  1654. }
  1655. };
  1656. CrosstabGrid.prototype._getValue = function _getValue(value) {
  1657. if (value === null || value === undefined) {
  1658. return;
  1659. }
  1660. return value.value && typeof value.value.label !== 'undefined' ? value.value.label : value.value;
  1661. };
  1662. CrosstabGrid.prototype._getUseValue = function _getUseValue(value) {
  1663. if (value.type === 'column' || value.type === 'row') {
  1664. var aTuples = value.ancestor_or_self;
  1665. if (aTuples) {
  1666. return _.pluck(aTuples, 'value') + '';
  1667. }
  1668. }
  1669. return null;
  1670. };
  1671. CrosstabGrid.prototype.showDropZone = function showDropZone(selector) {
  1672. this.hideDropZones();
  1673. var cells = this.$el.find(selector);
  1674. cells.css({ 'display': 'block' });
  1675. this.$el.find('.grid-column-resizer, .grid-row-resizer').css({ 'display': 'none' }); // Hide resizer handles
  1676. };
  1677. CrosstabGrid.prototype.hideDropZones = function hideDropZones() {
  1678. this.$el.find('.grid-drop-zone').css({ 'display': 'none' });
  1679. this.$el.find('.grid-column-resizer, .grid-row-resizer').css({ 'display': 'block' }); // Show resizer handles
  1680. };
  1681. CrosstabGrid.prototype.showReplaceDropZone = function showReplaceDropZone(idx, type, useValue) {
  1682. if (idx === 'corner') {
  1683. this.showDropZone('.grid-corner-cell > .grid-drop-zone');
  1684. } else {
  1685. if (type === 'row') {
  1686. if (useValue) {
  1687. this.showDropZone('.grid-fixed-row-cell[row="' + idx + '"][useValue="' + useValue + '"] > .grid-drop-zone');
  1688. } else {
  1689. this.showDropZone('.grid-fixed-row-cell[row="' + idx + '"] > .grid-drop-zone');
  1690. }
  1691. } else if (type === 'col') {
  1692. this.showDropZone('.grid-fixed-column-cell[col="' + idx + '"] > .grid-drop-zone');
  1693. }
  1694. }
  1695. };
  1696. CrosstabGrid.prototype.showLeftDropZone = function showLeftDropZone(col) {
  1697. if (col === 'corner') {
  1698. this.showDropZone('.grid-corner-cell > .grid-drop-zone.left');
  1699. } else {
  1700. this.showDropZone('.grid-fixed-column-cell[col="' + col + '"] > .grid-drop-zone.left, .grid-fixed-row-cell[col="' + col + '"] > .grid-drop-zone.left');
  1701. }
  1702. };
  1703. CrosstabGrid.prototype.showRightDropZone = function showRightDropZone(col) {
  1704. if (col === 'corner') {
  1705. this.showDropZone('.grid-corner-cell > .grid-drop-zone.right');
  1706. } else {
  1707. this.showDropZone('.grid-fixed-column-cell[col="' + col + '"] > .grid-drop-zone.right, .grid-fixed-row-cell[col="' + col + '"] > .grid-drop-zone.right');
  1708. }
  1709. };
  1710. CrosstabGrid.prototype.showTopDropZone = function showTopDropZone(row) {
  1711. this.showDropZone('.grid-fixed-row-cell[row="' + row + '"] > .grid-drop-zone.top');
  1712. };
  1713. CrosstabGrid.prototype.showBottomDropZone = function showBottomDropZone(row) {
  1714. this.showDropZone('.grid-fixed-row-cell[row="' + row + '"] > .grid-drop-zone.bottom');
  1715. };
  1716. return CrosstabGrid;
  1717. }();
  1718. });
  1719. //# sourceMappingURL=CrosstabGrid.js.map