'use strict'; 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; }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Licensed Materials - Property of IBM * IBM Cognos Products: Dashboard * (C) Copyright IBM Corp. 2014, 2020 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. * * JQuery datatables grid control (JQGrid). * @module com/ibm/ui/render/grid/control/JQGrid */ define(['underscore', 'jquery', '../../../../util/DashboardFormatter', '../../../../widgets/livewidget/nls/StringResources', '../GridDataProcessor', '../GridDropTarget', '../GridDnDManager', '../../../../dataSources/metadata/MetadataColumn', '../RankProcessor', '../GridDataProvider', '../GridContentRenderer', 'react-dom', 'react', 'ca-ui-toolkit'], function (_, $, Formatter, StringResources, GridDataProcessor, GridDropTarget, GridDnDManager, MetadataColumn, RankProcessor, DataProvider, GridContentRenderer, ReactDOM, React, Toolkit) { var SLOT_ID = 'grid_cols'; var SUMMARY_COLS_THRESHOLD = 12; var ROW_HEADER_INDEX = 0; var LABEL = 'label'; var VALUE = 'value'; var DEFAULT_ROW_HEIGHT = 32; var PROP_ID_SUPPRESSION = 'suppression'; var SUMMARY_ID = StringResources.get('summaryCaption'); return function () { function JQGrid() { _classCallCheck(this, JQGrid); this.init(arguments.length <= 0 ? undefined : arguments[0]); } JQGrid.prototype.init = function init() { var _this = this; var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; this.domNode = options.domNode; this.gridView = options.gridView; this.colorsService = options.dashboardApi.getFeature('Colors'); this.tabNavigation = options.tabNavigation; this.conditionalFormatting = options.conditionalFormatting; this.cellRenderer = options.cellRenderer; this._dataRows = null; //Data used by the grid in row form. this._focusNode = null; this._heatByIndex = -1; this._heatIndice = []; this._colorAllColumns = false; this._bGroupingEnabled = true; this._filterableSlots = []; this._selectedCellCache = {}; this._slotFormatCache = {}; this._rankDataItems = []; this._columnDataItems = []; this._visModel = options.visModel; this._hideSummaries = false; this._hasTopBottomLimit = null; this._columnsInfo = { groupedIndices: [], factIndices: [] }; var content = this.gridView && this.gridView.content; this.summaryFeature = options.summaryFeature; this.visualization = content.getFeature('Visualization'); this._gridDnDManager = new GridDnDManager({ grid: this, dashboardApi: options.dashboardApi, content: content, gridEdgeMappedToId: { row: SLOT_ID } }); this._setSummaryColor = function (gridCellProps) { var summaryColor = _this.conditionalFormatting && _this.conditionalFormatting.getSummaryFillColor(); if (summaryColor) { _.extend(gridCellProps.style, { 'background-color': summaryColor }); } }; }; /** * Resets the table - should be called before the first call to setData. * @param {object} visModel */ JQGrid.prototype.reset = function reset(visModel) { this._visModel = visModel; this._heatIndice = []; this._heatByIndex = -1; this._colorAllColumns = false; this._columnSlot = this.visualization.getSlots().getSlot('grid_cols'); this._heatSlot = this.visualization.getSlots().getSlot('heat'); this._slots = [this._columnSlot, this._heatSlot]; this._rankDataItems = []; this._columnDataItems = []; this._dataRows = []; this._hasTopBottomLimit = null; this._columnsInfo = { groupedIndices: [], factIndices: [] }; }; // These configurations need the rank to be processed before being set JQGrid.prototype._whenRankProcessed = function _whenRankProcessed() { this._columnDataItems = this._rankDataItems.concat(this._columnSlot && this._columnSlot.getDataItemList() || []); this._filterHeatBySlot(this.visualization.getSlots().getSlotList()); this._setColumnsInfo(); this._doGrouping = this._columnsInfo && !(this._columnsInfo.disableGrouping || this._hasTopBottomLimit); this._setDoSummaryInfo(); }; JQGrid.prototype._setDoSummaryInfo = function _setDoSummaryInfo() { this._hideSummaries = this._visModel.getPropertyValue('hideSummaries'); if (this._hideSummaries === undefined && (this._columnDataItems ? this._columnDataItems.length : 0) > SUMMARY_COLS_THRESHOLD) { // only override the default of hideSummaries on the first time Through // sanity check for defect 247618 to mitigate risk of crash on initial rendering of very large tables // user can change at own risk after first render this._hideSummaries = true; this.gridView.ownerWidget.updateVisProperties({ id: 'hideSummaries', value: true }, { silent: true }); } var hasFactInColumn = this._columnsInfo.factIndices.length; var hasGroup = this._columnsInfo.groupedIndices.length; this._doSummary = hasFactInColumn && hasGroup && !this._hideSummaries && this._doGrouping; }; JQGrid.prototype._setColumnsInfo = function _setColumnsInfo() { if (this._columnDataItems && this._columnDataItems.length) { var numberOfColumns = this._columnDataItems.length; var groupedIndices = []; var factIndices = []; this._columnsInfo = {}; this._setLeftMostFactSlotIndex(); // const bPreviousColumnHasUserSort = true; // const bCheckForDisableGrouping = true; this._columnsInfo.disableGrouping = false; for (var columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { var dataItem = this._columnDataItems[columnIndex]; //TODO: Add Top-N support here // const mapping = slot.getMapping(); // if (!this._hasTopBottomLimit) { // const limit = mapping.getLimit ? mapping.getLimit() : undefined; // this._hasTopBottomLimit = (limit !== undefined); // } //TODO: Rewrite this logic to use new model if (this._columnCanBeGrouped(columnIndex)) { groupedIndices.push(columnIndex); } if (this._isFactOrAggregationSet(dataItem) || this.isRank(columnIndex)) { factIndices.push(columnIndex); } } this._columnsInfo.factIndices = factIndices; this._columnsInfo.groupedIndices = groupedIndices; } }; JQGrid.prototype._setLeftMostFactSlotIndex = function _setLeftMostFactSlotIndex() { delete this._columnsInfo.leftMostFactSlotIndex; for (var i = 0; i < this._columnDataItems.length; i++) { if (this._isFactOrAggregationSet(this._columnDataItems[i]) || this.isRank(i)) { this._columnsInfo.leftMostFactSlotIndex = i; break; } } }; /** * A slot can be grouped (i.e. only one value displayed if there is muliple ) * IF it is an attribute OR it has an attribute concept (like cAge, cWeek, cDate) attatched to it OR slot definition indicates group = true. * Otherwise, it should not be grouped (as in the case of measures like Quantity or Units Sold). See RTC 73968 for details. * @param colIndex - index of the column in question * @returns true if the slot should be grouped...false if each value should be rendered even if it is the same as the previous row. * */ JQGrid.prototype._columnCanBeGrouped = function _columnCanBeGrouped(colIndex) { var leftMostCol = this._columnsInfo.leftMostFactSlotIndex; if (!_.isUndefined(leftMostCol) && colIndex >= leftMostCol) { return false; } return this._columnDataItems[colIndex].getType() === 'attribute'; //TODO: Put in equivalent for this condition: //|| (slot.getDefinition() && slot.getDefinition().group) }; JQGrid.prototype._filterHeatBySlot = function _filterHeatBySlot(dataSlots) { var _this2 = this; if (!this._hasDataMappings()) { return; } var index = this.getRankDataItemCount(); var heatDataItemList = this._heatSlot.getDataItemList(); var heatByColumnId = this._heatSlot && heatDataItemList.length > 0 ? heatDataItemList[0].getColumnId() : null; //return an array containing all of the non-heat slots and //locate what column index in the data that the heat slot will be located var newSlots = _.filter(dataSlots, function (slot) { var dataItemList = slot.getDataItemList(); if (dataItemList.length == 0) { return false; } if (slot.getId() === 'heat') { _this2._heatByIndex = index++; // ignore heat slot return false; } else { index += dataItemList.length; return true; } }); // Collect the slots indice that matches the heatby column id if (heatByColumnId) { index = this.getRankDataItemCount(); _.each(newSlots, function (slot) { var dataItemList = slot.getDataItemList(); //slots now contain more than 1 data item so have to iterate over the data items inside if (dataItemList.length > 0) { var itemIds = _.map(dataItemList, function (dataItem) { return dataItem.getColumnId(); }); _.each(itemIds, function (dataItemId) { if (dataItemId === heatByColumnId) { _this2._heatIndice.push(index); } index++; }); } }); // format the entire row. -1 in the array indicates that heat slot // is populated but the column is not displayed in the grid if (this._heatIndice.length === 0) { this._colorAllColumns = true; } } return newSlots; }; JQGrid.prototype.setData = function setData(queryResult) { this._queryResult = queryResult; this._processRank(); }; JQGrid.prototype.hasData = function hasData() { return !!this._queryResult; }; JQGrid.prototype.setStyles = function setStyles(styleObj) { if (styleObj) { this.headerStyles = styleObj.headerStyles; this.cellStyles = styleObj.cellStyles; } }; JQGrid.prototype.resetOnRender = function resetOnRender() { if (this._groupedConditionalColor) { delete this._groupedConditionalColor; } this._setDoSummaryInfo(); }; // Modifies original data, should not be called more than once per data set JQGrid.prototype._processRank = function _processRank() { var rankProcessor = new RankProcessor(this._queryResult, this.findSlotDetailsByRealColumnIndex.bind(this)); this._rankDataItems = rankProcessor.processData(); this._whenRankProcessed(); }; JQGrid.prototype._generateDataRows = function _generateDataRows() { var _this3 = this; // rank processor is only called once upon setData for new query result // client side format change will no longer trigger a new query, but the model change will trigger a reset on visModel // need to make sure that the columnInfo is set in this scenario if (this._columnDataItems.length === 0) { this._whenRankProcessed(); } this._resetOnGetDataRows(); var dataProcessor = new GridDataProcessor({ 'queryResult': this._queryResult, 'numberOfColumns': this._columnDataItems ? this._columnDataItems.length : 0, 'exceedsColumnThreshold': (this._columnDataItems ? this._columnDataItems.length : 0) > SUMMARY_COLS_THRESHOLD, 'columnSlot': this._columnSlot, 'rankDataItems': this._rankDataItems, 'columnDataItems': this._columnDataItems, 'lastGroupedColumnIndex': this._columnsInfo ? this._columnsInfo.leftMostFactSlotIndex : 0, 'visModel': this._visModel, 'factColumnIndices': this._columnsInfo ? this._columnsInfo.factIndices : 0, 'doSummary': this._doSummary, 'onCellDataChange': this._onCellDataChange.bind(this), 'getRankFormat': this._getRankFormat, 'getRealColumnIndex': this.getRealColumnIndex.bind(this), 'summaryFeature': this.summaryFeature }); return dataProcessor.getData().then(function (dataRows) { _this3._dataRows = dataRows; if (_this3._columnDataItems.length > 0) { _this3._headers = _this3._columnDataItems.map(function (dataItem, index) { var label = dataItem.getLabel(); if (_this3.isRank(index)) { label = StringResources.get('topBottomRankLabel', { label: label }); } return label; }); } _this3._dataRows.unshift(_this3._headers); _this3._WhenDataRowsAreReady(); //TODO: clean-up is to remove the unnecessary creation of summary value promises; // this can definitely be done when we have only one request but also without this: as discussed, we could wait for the summary promises to be resolved only dataProcessor.whenAllSummaryValuesAreReady().then(_this3.onResize.bind(_this3)); }); }; JQGrid.prototype.onResize = function onResize() { this.maxColHeight = this._getMaxColHeight(); this.gridRef && this.gridRef.recomputeGridSize(); }; JQGrid.prototype.render = function render(resizing, renderingNewData) { var _this4 = this; if (this.gridRef && resizing && !renderingNewData) { //if only do resizing this.onResize(); this.onSyncScrollBar(); return Promise.resolve(true); } else { // dataChange will change the rowNum and colNum of the data, need to re-render the grid //reset summary indicator flag if (!this._errorWarningAdded) { this.gridView && this.gridView.clearInfoIndicator('error_summary_cell'); } else { this._errorWarningAdded = false; } this.resetOnRender(); return this._generateDataRows().then(this._renderReactGrid.bind(this)).then(function () { return !!_this4.gridRef; }); } }; JQGrid.prototype.onSyncScrollBar = function onSyncScrollBar() { // when parent dom is moved or updated the scrollLeft and scrollTop value reset to 0 for the bottom-right-grid // this is a bug in React MultiGrid Level // the fix here is to sync the scrollBar among the three grid before onResize is triggered var $domNode = $(this.domNode); var rightBottomGrid = $domNode.find('.ba-common-grid__bottom-right-grid'); var rightTopGrid = $domNode.find('.ba-common-grid__top-right-grid'); var visibleChildrenCells = $(rightBottomGrid).find('.bottom-right-grid-cell'); var firstVisibleChild = visibleChildrenCells && visibleChildrenCells[0]; $(rightBottomGrid).animate({ scrollLeft: $(rightTopGrid).scrollLeft(), scrollTop: firstVisibleChild && firstVisibleChild.offsetTop || 1 }, 0); }; /** * Set selections context which contains row edge selection, column edge selection * and datapoint selection **/ JQGrid.prototype.setSelections = function setSelections(selections) { var _this5 = this; this._selections = selections; this._selectionValues = []; this._selectedCellCache = {}; this._selections.forEach(function (selection) { var _tempSelection = []; Object.values(selection).forEach(function (s) { _tempSelection.push(s.u); }); _this5._selectionValues.push(_tempSelection); }); }; JQGrid.prototype._getDataCellValue = function _getDataCellValue(dataCellValue, valueType) { if (dataCellValue === null || dataCellValue === undefined) { return; } if (valueType === 'useValue') { dataCellValue = this._getValue(dataCellValue, VALUE); } else if (valueType === 'type') { dataCellValue = dataCellValue.type; } else if (valueType === 'isSummary') { dataCellValue = dataCellValue.isSummary; } else if (valueType === 'summaryOf') { dataCellValue = dataCellValue.summaryOf; } else if (valueType === 'tuple') { dataCellValue = dataCellValue.key; } else if (valueType === 'rank') { dataCellValue = dataCellValue.value && (dataCellValue.value.deco && dataCellValue.value.deco.rank || dataCellValue.value.value) || dataCellValue.value; } else { if (dataCellValue.isSummary && this._getValue(dataCellValue, VALUE) === dataCellValue.summaryOf) { dataCellValue = SUMMARY_ID; } else { dataCellValue = this._getValue(dataCellValue, LABEL); } } return dataCellValue; }; /** * Removes cell-is-focused classname if there's no selections * * @param aClassString * @return {*} * @private */ JQGrid.prototype._removeFocusedClassName = function _removeFocusedClassName(aClassString) { var SELECTED = 'cell-is-focused'; if (Array.isArray(this._selections) && this._selections.length === 0) { if (aClassString.indexOf(SELECTED) !== -1) { return aClassString.replace(SELECTED, '').trim(); } } return aClassString; }; JQGrid.prototype._getValueForRowAtIndex = function _getValueForRowAtIndex(row, colIndex) { var cell = row[colIndex]; if (cell.value && cell.value.value) { return cell.value.value; } else if (cell[0]) { return cell[0].value; } else { return null; } }; JQGrid.prototype._calculateSelectionForFact = function _calculateSelectionForFact(rowIndex) { var row = this._dataRows[rowIndex + 1]; var isSelected = false; var attributeValues = []; for (var i = 0; i < row.length; i++) { if (!(this._columnsInfo.factIndices.indexOf(i) !== -1)) { var cellValue = this._getValueForRowAtIndex(row, i); attributeValues.push(cellValue); } } this._selectionValues.forEach(function (selection) { if (_.difference(selection, attributeValues).length === 0) { isSelected = true; } }); return isSelected; }; JQGrid.prototype._calculateSelectionForAttribute = function _calculateSelectionForAttribute(rowIndex, colIndex) { var row = this._dataRows[rowIndex + 1]; for (var i = 0; i < colIndex + 1; i++) { if (!(this._columnsInfo.factIndices.indexOf(i) !== -1)) { var cellValue = this._getValueForRowAtIndex(row, i); if (!(_.flatten(this._selectionValues).indexOf(cellValue) !== -1)) { return false; } } } return true; }; /** * Determine if a cell should be selected based on the selection info * * @param {object} dataValue * @param {number} colIndex * @return {boolean} * @private */ JQGrid.prototype._isCellSelected = function _isCellSelected(rowIndex, colIndex) { var cacheKey = rowIndex + '-' + colIndex; if (this._selectedCellCache[cacheKey] !== undefined) { return this._selectedCellCache[cacheKey]; } var isSelected = false; if (this._selectionValues.length > 0) { if (this._columnsInfo.factIndices.indexOf(colIndex) !== -1) { isSelected = this._calculateSelectionForFact(rowIndex); } else { isSelected = this._calculateSelectionForAttribute(rowIndex, colIndex); } } this._selectedCellCache[cacheKey] = isSelected; return isSelected; }; JQGrid.prototype._getCellPropertyColors = function _getCellPropertyColors() { try { // if user customized a background color for current widget var fillColor = this.gridView && this.gridView.content && this.gridView.content.getPropertyValue('fillColor'); var cellFillColor = fillColor && this.colorsService.getHexColorFromDashboardColorSet(fillColor); // TODO: have our own theme mapping for new grid var foregroundColorProperties = fillColor && this.colorsService.getForegroundColorPropertiesForUIElement(fillColor, 'tabs'); var cellTextColor = foregroundColorProperties && foregroundColorProperties.length && foregroundColorProperties[0].value; return { cellFillColor: cellFillColor, cellTextColor: cellTextColor }; } catch (err) { return {}; } }; JQGrid.prototype._prepFormatCache = function _prepFormatCache(numColumns) { this._slotFormatCache = {}; for (var i = 0; i < numColumns; i++) { var _findSlotDetails = this.findSlotDetails(i), slot = _findSlotDetails.slot, mapIndex = _findSlotDetails.mapIndex; this._slotFormatCache[i] = slot.getDataItemList()[mapIndex].getFormat(mapIndex); // this call is expensive! } }; JQGrid.prototype._renderReactGrid = function _renderReactGrid() { var _this6 = this; var _dataProvider = new DataProvider(this._dataRows); var fixedRows = 1; var numColumns = _dataProvider.getNumColumns(); var numRows = _dataProvider.getNumRows() - fixedRows; var dataRows = _dataProvider.getNumRows() - (_dataProvider.getNumRows() - this._queryResult.getRowCount()); this._prepFormatCache(numColumns); // in story, the first-time rendering from dashboard, the offsetHeight of the node is 0, need to check this this.maxColHeight = this._getMaxColHeight(); var TABINDEX = 0; var summaryRowIdxs = []; var isSuppressed = this._isSuppressionOn(); var _getCellPropertyColor = this._getCellPropertyColors(), cellFillColor = _getCellPropertyColor.cellFillColor, cellTextColor = _getCellPropertyColor.cellTextColor; var _shapeCols = []; // find heat dataItem position so it is associated with its fact column var heatColumnPosition = this._determineHeatColumnPosition(); var dataCellRenderer = function dataCellRenderer(rowIndex, colIndex, gridCellProps) { try { var dataValue = _dataProvider.getValue(rowIndex + fixedRows, colIndex); var isSummary = _this6._getDataCellValue(dataValue, 'isSummary'); var isRank = _this6.isRank(colIndex); var isMeasure = colIndex < _this6._columnDataItems.length && _this6._isFactOrAggregationSet(_this6._columnDataItems[colIndex]); //Summary values are already formatted so only format non-summary values var rawDataCellValue = _this6._getDataCellValue(dataValue); var dataCellValue = isSummary ? rawDataCellValue : isRank ? _this6._getDataCellValue(dataValue, 'rank') : _this6._formatValue(rawDataCellValue, colIndex, isSummary, isSuppressed); //populate the attributes we needed gridCellProps['row'] = rowIndex + fixedRows; gridCellProps['col'] = colIndex; gridCellProps['aria-label'] = dataCellValue; gridCellProps['tabindex'] = TABINDEX; gridCellProps.className = _this6._removeFocusedClassName(gridCellProps.className); var classList = [gridCellProps.className]; classList.push('grid-data-cell', 'dashboard-grid-cell'); gridCellProps.style = _.extend(gridCellProps.style, {}); // background color from Property if (cellFillColor && !isSummary) { gridCellProps.style = _.extend(gridCellProps.style, { backgroundColor: cellFillColor, color: cellTextColor }); } //Text toolbar style applied var values = Object.assign({}, _this6.cellStyles); Object.keys(values).forEach(function (key) { return values[key] === '' && delete values[key]; }); gridCellProps.style = Object.assign(gridCellProps.style, values); //summary row background var summaryCnt = 0; if (isSummary) { classList.push('summary'); var found = summaryRowIdxs.find(function (ele) { return rowIndex === ele; }); if (!found) { summaryRowIdxs.push(rowIndex); } } // determine summary row cnt for conditional formatting summaryRowIdxs.forEach(function (idx) { if (rowIndex > idx) { summaryCnt++; } }); //Conditional Formatting if (!isSummary && rowIndex < dataRows + summaryCnt && !dataValue.hasLeafNode) { var conditionalColor = _this6._getConditionalColor(rowIndex - summaryCnt, colIndex, dataValue, heatColumnPosition); if (conditionalColor) { if (!_this6.conditionalFormatting) { _.extend(gridCellProps.style, conditionalColor.getStyle()); } else { _.extend(gridCellProps.style, conditionalColor); } } } // colspan/rowspan var rowSpan = 0; var colSpan = 0; var isTransparent = false; if (_this6.isGroupedColumn(colIndex) && !isSummary) { if (cellFillColor === 'transparent' && _this6._getDataCellValue(_dataProvider.getValue(rowIndex + fixedRows - 1, colIndex)) === dataCellValue) { isTransparent = true; } var rowSpanIndex = rowIndex + fixedRows + 1; //iterate over the rows in this row until we find one that is different while (rowSpanIndex <= numRows + fixedRows - 1 && _this6._getDataCellValue(_dataProvider.getValue(rowSpanIndex, colIndex)) === rawDataCellValue && _this6._getDataCellValue(_dataProvider.getValue(rowSpanIndex, 0)) === _this6._getDataCellValue(_dataProvider.getValue(rowIndex + fixedRows, 0))) { rowSpanIndex++; } rowSpan = rowSpanIndex - (rowIndex + fixedRows); var _height = parseInt(gridCellProps.style.height, 10) * rowSpan; gridCellProps.style.height = Math.min(_height, _this6.maxColHeight) + 'px'; } if (isSummary && !isMeasure) { var colSpanIndex = colIndex + 1; while (colSpanIndex <= numColumns + 1 && _this6._getDataCellValue(_dataProvider.getValue(rowIndex + fixedRows, colSpanIndex)) === dataCellValue) { colSpanIndex++; } colSpan = colSpanIndex - colIndex; gridCellProps.style.width = parseInt(gridCellProps.style.width, 10) * colSpan + 'px'; } if (rowSpan || colSpan) { gridCellProps.style.zIndex = colSpan > rowSpan ? colSpan : rowSpan; } //render selection highlight and implied_selection for fact column if (!isSummary && _this6._isCellSelected(rowIndex, colIndex)) { classList.push('dashboard-grid-cell-selected'); } if (isMeasure) { classList.push('measure'); } gridCellProps.className = classList.join(' '); var value = isTransparent ? '' : dataCellValue; var contentSpec = { displayValue: value }; var isShapeCol = _shapeCols.indexOf(colIndex) !== -1; if (isShapeCol || gridCellProps.style.shapeId) { if (!isShapeCol) { _shapeCols.push(colIndex); } contentSpec.shapeId = gridCellProps.style.shapeId; } var children = void 0; if (_this6.cellRenderer && _this6.cellRenderer.canRender()) { // This code is currently not used. It is only here to provide an extension point for rendering cell content var _value = void 0; // The summary values are inconsistent with the rest values // A better way is to fix the root cause and make things consistent.. // but for now, we adjust things here to make the value format consistent before we call the extension if (dataValue.isSummary) { _value = {}; if (_typeof(dataValue.value) === 'object') { _value.label = dataValue.value.label; _value.value = dataValue.value.value; } else { _value.label = dataValue.value; _value.value = dataValue.rawValue || dataValue.value; } } else { _value = dataValue.value; } var _isRank = _this6.isRank(colIndex); var dataItemIndex = _this6.isRank(colIndex) ? _this6.getRefIndex(colIndex) + _this6.getRankDataItemCount() : colIndex; var state = { dataItem: _this6._columnDataItems[dataItemIndex], dataValue: _value, rowIndex: rowIndex, colIndex: colIndex }; if (_isRank) { state.isRank = true; } if (dataValue.isSummary) { state.isSummary = true; } children = _this6.cellRenderer.getComponentList(state); } else { children = []; } if (children.length === 0) { children.push(React.createElement(GridContentRenderer, _extends({}, contentSpec, { key: colIndex }))); } if (isSummary) { children.push(React.createElement('div', { className: 'grid-summary-decorator' }, '')); _this6._setSummaryColor(gridCellProps); } else { children.push(React.createElement('div', { class: 'grid-drop-zone left' }, '')); children.push(React.createElement('div', { class: 'grid-drop-zone replace' }, '')); children.push(React.createElement('div', { class: 'grid-drop-zone right' }, '')); } return React.createElement(GridDropTarget, _extends({ dndManager: _this6._gridDnDManager, cellType: 'column' }, gridCellProps), children); } catch (err) { // livewidget_cleanup // An error might occure because this function seems to access destroyed objects. // This happens when the grid is being re-rendered, and for some reason this function // gets called before the re-render and since it references destroyed obbect (i.e. deleted dataitems) // we will get an exception // No need to do anything and the re-render will occur and things should be fine // But we need to understand more why this is happening. } }; var fixedRowCellRenderer = function fixedRowCellRenderer(rowIndex, colIndex, gridCellProps) { var dataValue = _dataProvider.getValue(rowIndex, colIndex); var isSummary = _this6._getDataCellValue(dataValue, 'isSummary'); var dataCellValue = _this6._getDataCellValue(dataValue); //populate the attributes we needed gridCellProps['row'] = rowIndex; gridCellProps['col'] = colIndex; gridCellProps['scope'] = 'col'; gridCellProps['aria-label'] = dataCellValue; gridCellProps['tabindex'] = TABINDEX; gridCellProps.className = _this6._removeFocusedClassName(gridCellProps.className); var classList = [gridCellProps.className]; classList.push('grid-fixed-row-cell', 'dashboard-grid-cell'); gridCellProps.style = _.extend(gridCellProps.style, {}); //Text toolbar style applied gridCellProps.style = _.extend(gridCellProps.style, _this6.headerStyles); gridCellProps.className = classList.join(' '); var textCellChildren = [dataCellValue]; //Add sorting indicator if any exists var sortType = _this6._getSortType(colIndex); if (sortType) { var orderClass = sortType === 'asc' ? 'wfg_sorted_asc' : 'wfg_sorted_desc'; var sortingIndicator = React.createElement('span', { className: orderClass }, ''); textCellChildren.push(sortingIndicator); } var children = [React.createElement('div', { className: 'dashboard-text-cell' }, textCellChildren)]; if (isSummary) { children.push(React.createElement('div', { className: 'grid-summary-decorator' }, '')); } else { children.push(React.createElement('div', { class: 'grid-drop-zone left' }, '')); children.push(React.createElement('div', { class: 'grid-drop-zone replace' }, '')); children.push(React.createElement('div', { class: 'grid-drop-zone right' }, '')); } return React.createElement(GridDropTarget, _extends({ dndManager: _this6._gridDnDManager, cellType: 'column' }, gridCellProps), children); }; var rowHeight = function rowHeight() { return DEFAULT_ROW_HEIGHT; }; var columnWidth = function columnWidth() { var minCellWidth = 100; var viewPortWidth = _this6.domNode.clientWidth; if (_this6.domNode.clientHeight / DEFAULT_ROW_HEIGHT < numRows) { // when vertical scrollbar is visible, it takes up the width space of current view port, which is 17px among all types of browsers and increase 1px for windows machine var scrollBarWidth = 18; viewPortWidth = viewPortWidth - scrollBarWidth; } else { // IE has around 1px differences than the other browsers var calWidthDiff = 1; viewPortWidth = viewPortWidth - calWidthDiff; } var adjustedCellWidth = parseInt(viewPortWidth / numColumns); return Math.max(adjustedCellWidth, minCellWidth); }; var overscanRowCount = 2; if ((this._columnDataItems ? this._columnDataItems.length : 0) > SUMMARY_COLS_THRESHOLD) { // We know we won't have groups in this scenario, so its safe to overscan more rows. // RTC #290279 - Crosstab and Grid will sometimes show blank cells when row span is active overscanRowCount = 20; } var style = {}; var props = { rowHeight: rowHeight, columnWidth: columnWidth, numColumns: numColumns, numRows: numRows, fixedRows: fixedRows, overscanRowCount: overscanRowCount, dataCellRenderer: dataCellRenderer, fixedRowCellRenderer: fixedRowCellRenderer, style: style, ref: function ref(node) { _this6.gridRef = node; }, maxColumnWidth: Infinity }; var contextualGrid = React.createElement(Toolkit.Grid, props); this.$el = $(this.domNode).addClass('dashboard-common-grid').addClass('table-grid'); ReactDOM.render(contextualGrid, this.domNode); this.gridRef && this.gridRef.recomputeGridSize(); }; JQGrid.prototype._getMaxColHeight = function _getMaxColHeight() { return this.domNode.offsetHeight || Infinity; }; /** * Callback for handling when data dynamically changes from the pivot * @param {number} row - row index of the pivot data * @param {number} column - column index of the pivot data * @param {string} value - formatted value of the changed data */ JQGrid.prototype._onCellDataChange = function _onCellDataChange(row, column, value, rawValue) { if (!this._dataRowsIsReady) { this._delayedCellUpdate.push({ row: row, column: column, value: value, rawValue: rawValue }); } // When the value is error, add warning icon only once if (value && value.error) { if (!this._errorWarningAdded) { this.gridView.onSummaryDataCellError(); this._errorWarningAdded = true; } value = StringResources.get('value_is_not_available'); } if (this._dataRows && row < this._dataRows.length && column < this._dataRows[row].length && this._dataRows[row][column].value !== value) { this._dataRows[row][column].value = value; this._dataRows[row][column].rawValue = rawValue; } }; /** * For scenario that summaryValue is ready before dataRows are ready, we need to delay the cell update once the dataRows are resolved */ JQGrid.prototype._WhenDataRowsAreReady = function _WhenDataRowsAreReady() { var _this7 = this; this._dataRowsIsReady = true; this._delayedCellUpdate.forEach(function (cell) { return _this7._onCellDataChange(cell.row, cell.column, cell.value, cell.rawValue); }); }; /** * Reset the dataRowsIsReady flag and delayedCellUpdates when dataRows are regenerated */ JQGrid.prototype._resetOnGetDataRows = function _resetOnGetDataRows() { this._dataRowsIsReady = false; this._delayedCellUpdate = []; }; /** * * @param {*} value could be an object, an array or a string * @param {String} type either displayValue or useValue */ JQGrid.prototype._getValue = function _getValue(value, type) { if (value === null || value === undefined) { return; } // Since the query result value is also in the form of {value: 'aaa', label: 'AAA'} // Need to differentiate query result value vs. internal generated value from EdgeIterator if (value.value !== undefined && value.descendant_or_self !== undefined) { value = value.value; } if (value !== null && value !== undefined) { if (value[type] !== undefined) { // Get the either display or use value return value[type]; } // When value has a nested value object if (value.value && _typeof(value.value) === 'object') { return this._getValue(value.value, type); } // If label is missing, return use value if (type === LABEL && value.value !== undefined) { return value.value; } } // When value is an array if (_.isArray(value) && value[0]) { return this._getValue(value[0], type); } return value; }; JQGrid.prototype.setValue = function setValue($td, value, rowIndex, colIndex) { var cellValue = this._getValue(value, LABEL); var bIsSummary = (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && 'isSummary' in value ? value.isSummary : this._dataRows[rowIndex][colIndex].isSummary; //Fixup the label for summary row so it gets rendered properly if (bIsSummary) { if (this._getValue(value, VALUE) === value.summaryOf) { cellValue = SUMMARY_ID; } } else if (rowIndex !== ROW_HEADER_INDEX) { //Summary values are already formatted so only format non-summary values cellValue = this._formatValue(cellValue, colIndex, bIsSummary); } $td.attr('aria-label', cellValue); $td.text(cellValue); }; JQGrid.prototype._getSortType = function _getSortType(colIndex) { // Find the correct slot and index of data item in it var _findSlotDetails2 = this.findSlotDetails(colIndex), slot = _findSlotDetails2.slot, mapIndex = _findSlotDetails2.mapIndex; // If not sorted by rank hide sort icon for rank column, if sorted by rank hide sort icon for the non-rank column var dataItem = slot.getDataItemList()[mapIndex]; var dataItemSort = dataItem && dataItem.getSort(); if (dataItemSort) { if (this.isRank(colIndex) && !dataItemSort.rankSort || !this.isRank(colIndex) && dataItemSort.rankSort) { return null; } } return dataItemSort && !dataItem.hasDefaultSort() && dataItemSort.type; }; // Rank columns should always be formatted as number JQGrid.prototype._getRankFormat = function _getRankFormat() { return { formatSpec: { 'selectedFormat': 'none', 'maximumFractionDigits': 0, 'formatLength': 'short', 'type': 'number', 'locale': this._columnSlot.locale }, validFormatSpec: { 'selectedFormat': 'none', 'maximumFractionDigits': 0, 'formatLength': 'short', 'type': 'number', 'locale': this._columnSlot.locale } }; }; JQGrid.prototype._formatValue = function _formatValue(cellValue, colIndex, bIsSummary, isSuppressed) { var format = void 0; if (this.isRank(colIndex)) { format = this._rankFormat; } else { format = this._slotFormatCache[colIndex]; } if (!bIsSummary) { return isSuppressed ? Formatter.format(cellValue, format) : Formatter.formatNull(cellValue, format); } else { // only format the summary row for number var dataItem = this._columnDataItems[colIndex]; if (dataItem && this._isFactOrAggregationSet(dataItem)) { return isSuppressed ? Formatter.format(cellValue, format) : Formatter.formatNull(cellValue, format); } return cellValue; } }; JQGrid.prototype._isSuppressionOn = function _isSuppressionOn() { var content = this.gridView && this.gridView.content; var suppressionValue = content && content.getPropertyValue(PROP_ID_SUPPRESSION); if (suppressionValue && suppressionValue === 'none') { return false; } return true; }; /** * Callback for handling when data dynamically changes from the pivot * * @param {number} iRow - row index of the pivot data * @param {number} iCol - column index of the pivot data * @param {number} dataValue - value of the data * @param {Array} heatColumnPosition - an array of the column position against the heat slot */ JQGrid.prototype._getConditionalColor = function _getConditionalColor(iRow, iCol, dataValue, heatColumnPosition) { /* * A grid can be colored if there is a heat slot populated. _heatIndice contains the index of the heat column that is displayed in * the grid, which causes only that column to be colored. If the first value is -1, that means the heat slot is populated but the column * is not displayed in the grid; thus, all columns are colored. */ // If this is a rank column, look at the referenced table column var colIndex = this.isRank(iCol) ? this.getRefIndex(iCol) + this.getRankDataItemCount() : iCol; if (!this.conditionalFormatting) { var conditionalPalette = this._visModel.getConditions() ? this._visModel.getConditions().palette : null; if (conditionalPalette && (this._heatIndice.indexOf(colIndex) > -1 || colIndex == this._heatByIndex || this._colorAllColumns)) { //return conditionalPalette.getColorByValue(this._heatByDataRows[iRow]); var oValue = this._queryResult.getValue(iRow, this._heatByIndex); var conditionalColor = conditionalPalette.getColorByValue(this._getValue(oValue, VALUE)); if (conditionalColor && this.cellStyles && this.cellStyles.color) { delete conditionalColor.color; } return conditionalColor; } } else { if (this._heatByIndex !== -1 && heatColumnPosition.length) { var heatOffset = heatColumnPosition.indexOf(colIndex); if (heatOffset !== -1) { var condValue = this._queryResult.getValue(iRow, this._heatByIndex + heatOffset); var dataItem = this._columnDataItems[colIndex]; var baseValue = dataValue.value.value ? dataValue.value.value : dataValue.value; return this.conditionalFormatting.getFormatting(baseValue, condValue.value, dataItem.getColumnId()); } } } return null; }; /** * Gets a list of the nodes that have been selected * @return {Array.node} - an array of nodes */ JQGrid.prototype.getSelectedColumnHeaderNodes = function getSelectedColumnHeaderNodes() { return $(this.domNode).find('.header-cell.implied_selection'); }; /** * highlight the column header */ JQGrid.prototype.hilightColumn = function hilightColumn(selectedNode, bSingleSelect, bDeselect, bRightClick) { var $node = $(selectedNode); if (bDeselect && bRightClick) { return; } if (bSingleSelect) { this.clearColumnHighlight(); } if (bDeselect) { $node.removeClass('implied_selection'); } else { $node.addClass('implied_selection'); } }; JQGrid.prototype.clearColumnHighlight = function clearColumnHighlight() { $(this.domNode).find('.header-cell.implied_selection').removeClass('implied_selection'); }; /** * @returns true if the current node includes the 'selected' or 'selected_secondary' or 'implied_selection' class. */ JQGrid.prototype.isCellSelected = function isCellSelected(node) { var $node = $(node); return $node.hasClass('dashboard-grid-cell-selected') || $node.hasClass('implied_selection'); }; JQGrid.prototype.isGroupedColumn = function isGroupedColumn(columnNodeOrColumnIndex) { var columnIndex = columnNodeOrColumnIndex; if ((typeof columnNodeOrColumnIndex === 'undefined' ? 'undefined' : _typeof(columnNodeOrColumnIndex)) === 'object') { columnIndex = this.getColumnIndex(columnNodeOrColumnIndex); } return this._columnsInfo.groupedIndices && this._columnsInfo.groupedIndices.indexOf(parseInt(columnIndex)) !== -1; }; JQGrid.prototype._isFactColumn = function _isFactColumn(columnIndex) { return this._columnsInfo.factIndices.indexOf(parseInt(columnIndex)) !== -1; }; JQGrid.prototype.getRowIndexFromSelectedNode = function getRowIndexFromSelectedNode(selectedNode) { return parseInt($(selectedNode).attr('row'), 10); }; JQGrid.prototype.getColumnIndex = function getColumnIndex(cellNode) { return parseInt($(cellNode).attr('col'), 10); }; JQGrid.prototype._hasDataMappings = function _hasDataMappings() { return this.visualization.getSlots().getMappedSlotList().length > 0; }; JQGrid.prototype.getColumnCount = function getColumnCount() { return this._columnDataItems.length; }; /** * Find the slot, index of slot in JQGrid._slots and item's mapIndex in that slot * @param colIndex Column index in the table */ JQGrid.prototype.findSlotDetails = function findSlotDetails(colIndex) { var realColumnIndex = this.getRealColumnIndex(colIndex); return this.findSlotDetailsByRealColumnIndex(realColumnIndex); }; /** * The rank value can depend on a value which exists in either column slot or heat slot * When we need to fetch information from the slot, we should detect which slot we should use. * Function returns the correct slot, its index in JQGrid._slots and data item's mapIndex in the slot. * * @param columnIndex Data item index in the original data */ JQGrid.prototype.findSlotDetailsByRealColumnIndex = function findSlotDetailsByRealColumnIndex(columnIndex) { var prevItemCount = 0; var slot = null; var mapIndex = null; // index of item in slot var slotIndex = 0; // index of the slot for (var i = 0; i < this._slots.length; i++) { slot = this._slots[i]; var slotItemCount = slot.getDataItemList().length; if (columnIndex < slotItemCount + prevItemCount) { mapIndex = columnIndex - prevItemCount; slotIndex = i; break; } else { prevItemCount += slotItemCount; } } return { slot: slot, slotIndex: slotIndex, mapIndex: mapIndex }; }; /** * Returns the real index of data item in the original query result data * given the column's index on the table. * * @param {*} colIndex column index on the table */ JQGrid.prototype.getRealColumnIndex = function getRealColumnIndex(colIndex) { return this.isRank(colIndex) ? this.getRefIndex(colIndex) : colIndex - this.getRankDataItemCount(); }; JQGrid.prototype.getRankDataItemCount = function getRankDataItemCount() { return this._rankDataItems && this._rankDataItems.length || 0; }; /** * Determines whether the given column mapping is a rank column * @param columIndex: index of the column in the table */ JQGrid.prototype.isRank = function isRank(columIndex) { return !!(this._columnDataItems[columIndex] && this._columnDataItems[columIndex].isRank) || false; }; /** * Returns the 'original' index of a data column that is being referenced by a rank column. * This is the index of the referenced column BEFORE the Rank Processor modified the data. * In order to get to the visible (rendered) column index, we should add the _rankDataItems.length to this. * * @param colIndex index of the rank */ JQGrid.prototype.getRefIndex = function getRefIndex(colIndex) { return this._columnDataItems[colIndex].getRefColumnIndex && this._columnDataItems[colIndex].getRefColumnIndex(); }; /** * Set focusNode and clear existing user selection (focus) */ JQGrid.prototype.updateFocusNode = function updateFocusNode(focusNode) { var bDeselect = $(focusNode).hasClass('focused') || this.isCellSelected(focusNode); if (this._focusNode) { this._focusNode.removeClass('focused'); } if (bDeselect) { return; } this._focusNode = $(focusNode); this._focusNode.addClass('focused'); }; JQGrid.prototype.remove = function remove() { this.gridView = null; this.tabNavigation = null; this._rankDataItems = null; this._dataRows = null; this._headers = null; this._dataRowsIsReady = null; this._delayedCellUpdate = null; this.removeGridView(); this.domNode = null; }; JQGrid.prototype.removeGridView = function removeGridView() { if (this.gridRef && this.domNode) { ReactDOM.unmountComponentAtNode(this.domNode); this.gridRef = null; } }; JQGrid.prototype.onEnterContainer = function onEnterContainer() { var firstCellNode = $(this.domNode).find('.top-right-grid-cell[row="0"][col="0"]'); if (firstCellNode.length) { firstCellNode.focus(); } }; JQGrid.prototype.handleSelectColumnHeader = function handleSelectColumnHeader(selectedNode, bSingleSelect, bRightClick) { //Existing column header will still be highlighted if the ctrl key is held var bDeselect = this.isCellSelected(selectedNode); this.hilightColumn(selectedNode, bSingleSelect, bDeselect, bRightClick); }; JQGrid.prototype._isFactOrAggregationSet = function _isFactOrAggregationSet(dataItem) { if (!dataItem) { return false; } if (dataItem.getType() === 'fact') { return true; } else { if (dataItem.getAggregation() !== MetadataColumn.AGGREGATION_TYPE_MAP.none) { return true; } return false; } }; JQGrid.prototype.showDropZone = function showDropZone(selector) { this.hideDropZones(); this.$el.find(selector).css({ 'display': 'block' }); }; JQGrid.prototype.hideDropZones = function hideDropZones() { this.$el.find('.grid-drop-zone').css({ 'display': 'none' }); }; JQGrid.prototype.showReplaceDropZone = function showReplaceDropZone(idx) { var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'col'; this.showDropZone('[' + type + '=' + idx + '] > .grid-drop-zone'); }; JQGrid.prototype.showLeftDropZone = function showLeftDropZone(col) { this.showDropZone('[col=' + col + '] > .grid-drop-zone.left'); }; JQGrid.prototype.showRightDropZone = function showRightDropZone(col) { this.showDropZone('[col=' + col + '] > .grid-drop-zone.right'); }; /** * Determine the column position relative to the heat slot */ JQGrid.prototype._determineHeatColumnPosition = function _determineHeatColumnPosition() { var _this8 = this; var heatPos = []; var condFormats = this.conditionalFormatting && this.conditionalFormatting.getConditionalFormatting(); if (condFormats) { this._heatSlot.getDataItemList().forEach(function (dataItem) { var condFormat = condFormats.conditionalFormats.find(function (cf) { return cf.heatId === dataItem.getId(); }); if (condFormat) { heatPos.push(_this8._columnsInfo.factIndices.find(function (factIndex) { return !_this8.isRank(factIndex) && condFormat.dataItemId === _this8._columnDataItems[factIndex].getColumnId(); })); } }); } return heatPos; }; return JQGrid; }(); }); //# sourceMappingURL=JQGrid.js.map