UNPKG

ag-grid

Version:

Advanced Data Grid / Data Table supporting Javascript / React / AngularJS / Web Components

623 lines (622 loc) 27.3 kB
/** * ag-grid - Advanced Data Grid / Data Table supporting Javascript / React / AngularJS / Web Components * @version v18.1.2 * @link http://www.ag-grid.com/ * @license MIT */ "use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); var eventService_1 = require("../eventService"); var events_1 = require("../events"); var gridOptionsWrapper_1 = require("../gridOptionsWrapper"); var selectionController_1 = require("../selectionController"); var valueService_1 = require("../valueService/valueService"); var columnController_1 = require("../columnController/columnController"); var columnApi_1 = require("../columnController/columnApi"); var context_1 = require("../context/context"); var constants_1 = require("../constants"); var utils_1 = require("../utils"); var valueCache_1 = require("../valueService/valueCache"); var gridApi_1 = require("../gridApi"); var RowNode = (function () { function RowNode() { /** Children mapped by the pivot columns */ this.childrenMapped = {}; /** True by default - can be overridden via gridOptions.isRowSelectable(rowNode) */ this.selectable = true; this.selected = false; } RowNode.prototype.setData = function (data) { var oldData = this.data; this.data = data; this.valueCache.onDataChanged(); this.updateDataOnDetailNode(); this.checkRowSelectable(); var event = this.createDataChangedEvent(data, oldData, false); this.dispatchLocalEvent(event); }; // when we are doing master / detail, the detail node is lazy created, but then kept around. // so if we show / hide the detail, the same detail rowNode is used. so we need to keep the data // in sync, otherwise expand/collapse of the detail would still show the old values. RowNode.prototype.updateDataOnDetailNode = function () { if (this.detailNode) { this.detailNode.data = this.data; } }; RowNode.prototype.createDataChangedEvent = function (newData, oldData, update) { return { type: RowNode.EVENT_DATA_CHANGED, node: this, oldData: oldData, newData: newData, update: update }; }; RowNode.prototype.createLocalRowEvent = function (type) { return { type: type, node: this }; }; // similar to setRowData, however it is expected that the data is the same data item. this // is intended to be used with Redux type stores, where the whole data can be changed. we are // guaranteed that the data is the same entity (so grid doesn't need to worry about the id of the // underlying data changing, hence doesn't need to worry about selection). the grid, upon receiving // dataChanged event, will refresh the cells rather than rip them all out (so user can show transitions). RowNode.prototype.updateData = function (data) { var oldData = this.data; this.data = data; this.updateDataOnDetailNode(); this.checkRowSelectable(); this.updateDataOnDetailNode(); var event = this.createDataChangedEvent(data, oldData, true); this.dispatchLocalEvent(event); }; RowNode.prototype.getRowIndexString = function () { if (this.rowPinned === constants_1.Constants.PINNED_TOP) { return 't-' + this.rowIndex; } else if (this.rowPinned === constants_1.Constants.PINNED_BOTTOM) { return 'b-' + this.rowIndex; } else { return this.rowIndex.toString(); } }; RowNode.prototype.createDaemonNode = function () { var oldNode = new RowNode(); this.context.wireBean(oldNode); // just copy the id and data, this is enough for the node to be used // in the selection controller (the selection controller is the only // place where daemon nodes can live). oldNode.id = this.id; oldNode.data = this.data; oldNode.daemon = true; oldNode.selected = this.selected; oldNode.level = this.level; return oldNode; }; RowNode.prototype.setDataAndId = function (data, id) { var oldNode = utils_1.Utils.exists(this.id) ? this.createDaemonNode() : null; var oldData = this.data; this.data = data; this.updateDataOnDetailNode(); this.setId(id); this.selectionController.syncInRowNode(this, oldNode); this.checkRowSelectable(); var event = this.createDataChangedEvent(data, oldData, false); this.dispatchLocalEvent(event); }; RowNode.prototype.checkRowSelectable = function () { var isRowSelectableFunc = this.gridOptionsWrapper.getIsRowSelectableFunc(); var shouldInvokeIsRowSelectable = isRowSelectableFunc && utils_1.Utils.exists(this); this.setRowSelectable(shouldInvokeIsRowSelectable ? isRowSelectableFunc(this) : true); }; RowNode.prototype.setRowSelectable = function (newVal) { if (this.selectable !== newVal) { this.selectable = newVal; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_SELECTABLE_CHANGED)); } } }; RowNode.prototype.setId = function (id) { // see if user is providing the id's var getRowNodeId = this.gridOptionsWrapper.getRowNodeIdFunc(); if (getRowNodeId) { // if user is providing the id's, then we set the id only after the data has been set. // this is important for virtual pagination and viewport, where empty rows exist. if (this.data) { this.id = getRowNodeId(this.data); } else { // this can happen if user has set blank into the rowNode after the row previously // having data. this happens in virtual page row model, when data is delete and // the page is refreshed. this.id = undefined; } } else { this.id = id; } }; RowNode.prototype.isPixelInRange = function (pixel) { return pixel >= this.rowTop && pixel < (this.rowTop + this.rowHeight); }; RowNode.prototype.clearRowTop = function () { this.oldRowTop = this.rowTop; this.setRowTop(null); }; RowNode.prototype.setFirstChild = function (firstChild) { if (this.firstChild === firstChild) { return; } this.firstChild = firstChild; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_FIRST_CHILD_CHANGED)); } }; RowNode.prototype.setLastChild = function (lastChild) { if (this.lastChild === lastChild) { return; } this.lastChild = lastChild; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_LAST_CHILD_CHANGED)); } }; RowNode.prototype.setChildIndex = function (childIndex) { if (this.childIndex === childIndex) { return; } this.childIndex = childIndex; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_CHILD_INDEX_CHANGED)); } }; RowNode.prototype.setRowTop = function (rowTop) { if (this.rowTop === rowTop) { return; } this.rowTop = rowTop; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_TOP_CHANGED)); } }; RowNode.prototype.setDragging = function (dragging) { if (this.dragging === dragging) { return; } this.dragging = dragging; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_DRAGGING_CHANGED)); } }; RowNode.prototype.setAllChildrenCount = function (allChildrenCount) { if (this.allChildrenCount === allChildrenCount) { return; } this.allChildrenCount = allChildrenCount; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_ALL_CHILDREN_COUNT_CHANGED)); } }; RowNode.prototype.setRowHeight = function (rowHeight) { this.rowHeight = rowHeight; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_HEIGHT_CHANGED)); } }; RowNode.prototype.setRowIndex = function (rowIndex) { this.rowIndex = rowIndex; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_ROW_INDEX_CHANGED)); } }; RowNode.prototype.setUiLevel = function (uiLevel) { if (this.uiLevel === uiLevel) { return; } this.uiLevel = uiLevel; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_UI_LEVEL_CHANGED)); } }; RowNode.prototype.setExpanded = function (expanded) { if (this.expanded === expanded) { return; } this.expanded = expanded; if (this.eventService) { this.eventService.dispatchEvent(this.createLocalRowEvent(RowNode.EVENT_EXPANDED_CHANGED)); } var event = this.createGlobalRowEvent(events_1.Events.EVENT_ROW_GROUP_OPENED); this.mainEventService.dispatchEvent(event); if (this.gridOptionsWrapper.isGroupIncludeFooter()) { this.gridApi.redrawRows({ rowNodes: [this] }); } }; RowNode.prototype.createGlobalRowEvent = function (type) { var event = { type: type, node: this, data: this.data, rowIndex: this.rowIndex, rowPinned: this.rowPinned, context: this.gridOptionsWrapper.getContext(), api: this.gridOptionsWrapper.getApi(), columnApi: this.gridOptionsWrapper.getColumnApi() }; return event; }; RowNode.prototype.dispatchLocalEvent = function (event) { if (this.eventService) { this.eventService.dispatchEvent(event); } }; // we also allow editing the value via the editors. when it is done via // the editors, no 'cell changed' event gets fired, as it's assumed that // the cell knows about the change given it's in charge of the editing. // this method is for the client to call, so the cell listens for the change // event, and also flashes the cell when the change occurs. RowNode.prototype.setDataValue = function (colKey, newValue) { var column = this.columnController.getPrimaryColumn(colKey); this.valueService.setValue(this, column, newValue); this.dispatchCellChangedEvent(column, newValue); }; RowNode.prototype.setGroupValue = function (colKey, newValue) { var column = this.columnController.getGridColumn(colKey); if (utils_1.Utils.missing(this.groupData)) { this.groupData = {}; } this.groupData[column.getColId()] = newValue; this.dispatchCellChangedEvent(column, newValue); }; // sets the data for an aggregation RowNode.prototype.setAggData = function (newAggData) { var _this = this; // find out all keys that could potentially change var colIds = utils_1.Utils.getAllKeysInObjects([this.aggData, newAggData]); this.aggData = newAggData; // if no event service, nobody has registered for events, so no need fire event if (this.eventService) { colIds.forEach(function (colId) { var column = _this.columnController.getGridColumn(colId); var value = _this.aggData ? _this.aggData[colId] : undefined; _this.dispatchCellChangedEvent(column, value); }); } }; RowNode.prototype.hasChildren = function () { // we need to return true when this.group=true, as this is used by server side row model // (as children are lazy loaded and stored in a cache anyway). otherwise we return true // if children exist. return this.group || (this.childrenAfterGroup && this.childrenAfterGroup.length > 0); }; RowNode.prototype.isEmptyFillerNode = function () { return this.group && utils_1.Utils.missingOrEmpty(this.childrenAfterGroup); }; RowNode.prototype.dispatchCellChangedEvent = function (column, newValue) { var cellChangedEvent = { type: RowNode.EVENT_CELL_CHANGED, node: this, column: column, newValue: newValue }; this.dispatchLocalEvent(cellChangedEvent); }; RowNode.prototype.resetQuickFilterAggregateText = function () { this.quickFilterAggregateText = null; }; RowNode.prototype.isExpandable = function () { return this.hasChildren() || this.master; }; RowNode.prototype.isSelected = function () { // for footers, we just return what our sibling selected state is, as cannot select a footer if (this.footer) { return this.sibling.isSelected(); } return this.selected; }; RowNode.prototype.depthFirstSearch = function (callback) { if (this.childrenAfterGroup) { this.childrenAfterGroup.forEach(function (child) { return child.depthFirstSearch(callback); }); } callback(this); }; // + rowController.updateGroupsInSelection() // + selectionController.calculatedSelectedForAllGroupNodes() RowNode.prototype.calculateSelectedFromChildren = function () { var atLeastOneSelected = false; var atLeastOneDeSelected = false; var atLeastOneMixed = false; var newSelectedValue; if (this.childrenAfterGroup) { for (var i = 0; i < this.childrenAfterGroup.length; i++) { var child = this.childrenAfterGroup[i]; // skip non-selectable nodes to prevent inconsistent selection values if (!child.selectable) continue; var childState = child.isSelected(); switch (childState) { case true: atLeastOneSelected = true; break; case false: atLeastOneDeSelected = true; break; default: atLeastOneMixed = true; break; } } } if (atLeastOneMixed) { newSelectedValue = undefined; } else if (atLeastOneSelected && !atLeastOneDeSelected) { newSelectedValue = true; } else if (!atLeastOneSelected && atLeastOneDeSelected) { newSelectedValue = false; } else { newSelectedValue = undefined; } this.selectThisNode(newSelectedValue); }; RowNode.prototype.setSelectedInitialValue = function (selected) { this.selected = selected; }; RowNode.prototype.setSelected = function (newValue, clearSelection, suppressFinishActions) { if (clearSelection === void 0) { clearSelection = false; } if (suppressFinishActions === void 0) { suppressFinishActions = false; } this.setSelectedParams({ newValue: newValue, clearSelection: clearSelection, suppressFinishActions: suppressFinishActions, rangeSelect: false }); }; RowNode.prototype.isRowPinned = function () { return this.rowPinned === constants_1.Constants.PINNED_TOP || this.rowPinned === constants_1.Constants.PINNED_BOTTOM; }; // to make calling code more readable, this is the same method as setSelected except it takes names parameters RowNode.prototype.setSelectedParams = function (params) { var groupSelectsChildren = this.gridOptionsWrapper.isGroupSelectsChildren(); var newValue = params.newValue === true; var clearSelection = params.clearSelection === true; var suppressFinishActions = params.suppressFinishActions === true; var rangeSelect = params.rangeSelect === true; // groupSelectsFiltered only makes sense when group selects children var groupSelectsFiltered = groupSelectsChildren && (params.groupSelectsFiltered === true); if (this.id === undefined) { console.warn('ag-Grid: cannot select node until id for node is known'); return 0; } if (this.rowPinned) { console.log('ag-Grid: cannot select pinned rows'); return 0; } // if we are a footer, we don't do selection, just pass the info // to the sibling (the parent of the group) if (this.footer) { var count = this.sibling.setSelectedParams(params); return count; } if (rangeSelect) { var newRowClicked = this.selectionController.getLastSelectedNode() !== this; var allowMultiSelect = this.gridOptionsWrapper.isRowSelectionMulti(); if (newRowClicked && allowMultiSelect) { return this.doRowRangeSelection(); } } var updatedCount = 0; // when groupSelectsFiltered, then this node may end up intermediate despite // trying to set it to true / false. this group will be calculated further on // down when we call calculatedSelectedForAllGroupNodes(). we need to skip it // here, otherwise the updatedCount would include it. var skipThisNode = groupSelectsFiltered && this.group; if (!skipThisNode) { var thisNodeWasSelected = this.selectThisNode(newValue); if (thisNodeWasSelected) { updatedCount++; } } if (groupSelectsChildren && this.group) { updatedCount += this.selectChildNodes(newValue, groupSelectsFiltered); } // clear other nodes if not doing multi select if (!suppressFinishActions) { var clearOtherNodes = newValue && (clearSelection || !this.gridOptionsWrapper.isRowSelectionMulti()); if (clearOtherNodes) { updatedCount += this.selectionController.clearOtherNodes(this); } // only if we selected something, then update groups and fire events if (updatedCount > 0) { this.selectionController.updateGroupsFromChildrenSelections(); // this is the very end of the 'action node', so we are finished all the updates, // include any parent / child changes that this method caused var event_1 = { type: events_1.Events.EVENT_SELECTION_CHANGED, api: this.gridApi, columnApi: this.columnApi }; this.mainEventService.dispatchEvent(event_1); } // so if user next does shift-select, we know where to start the selection from if (newValue) { this.selectionController.setLastSelectedNode(this); } } return updatedCount; }; // selects all rows between this node and the last selected node (or the top if this is the first selection). // not to be mixed up with 'cell range selection' where you drag the mouse, this is row range selection, by // holding down 'shift'. RowNode.prototype.doRowRangeSelection = function () { var updatedCount = 0; var groupsSelectChildren = this.gridOptionsWrapper.isGroupSelectsChildren(); var lastSelectedNode = this.selectionController.getLastSelectedNode(); var nodesToSelect = this.rowModel.getNodesInRangeForSelection(this, lastSelectedNode); nodesToSelect.forEach(function (rowNode) { if (rowNode.group && groupsSelectChildren) { return; } var nodeWasSelected = rowNode.selectThisNode(true); if (nodeWasSelected) { updatedCount++; } }); this.selectionController.updateGroupsFromChildrenSelections(); var event = { type: events_1.Events.EVENT_SELECTION_CHANGED, api: this.gridApi, columnApi: this.columnApi }; this.mainEventService.dispatchEvent(event); return updatedCount; }; RowNode.prototype.isParentOfNode = function (potentialParent) { var parentNode = this.parent; while (parentNode) { if (parentNode === potentialParent) { return true; } parentNode = parentNode.parent; } return false; }; RowNode.prototype.selectThisNode = function (newValue) { if (!this.selectable || this.selected === newValue) return false; this.selected = newValue; if (this.eventService) { this.dispatchLocalEvent(this.createLocalRowEvent(RowNode.EVENT_ROW_SELECTED)); } var event = this.createGlobalRowEvent(events_1.Events.EVENT_ROW_SELECTED); this.mainEventService.dispatchEvent(event); return true; }; RowNode.prototype.selectChildNodes = function (newValue, groupSelectsFiltered) { var children = groupSelectsFiltered ? this.childrenAfterFilter : this.childrenAfterGroup; var updatedCount = 0; if (utils_1.Utils.missing(children)) { return; } for (var i = 0; i < children.length; i++) { updatedCount += children[i].setSelectedParams({ newValue: newValue, clearSelection: false, suppressFinishActions: true, groupSelectsFiltered: groupSelectsFiltered }); } return updatedCount; }; RowNode.prototype.addEventListener = function (eventType, listener) { if (!this.eventService) { this.eventService = new eventService_1.EventService(); } this.eventService.addEventListener(eventType, listener); }; RowNode.prototype.removeEventListener = function (eventType, listener) { this.eventService.removeEventListener(eventType, listener); }; RowNode.prototype.onMouseEnter = function () { this.dispatchLocalEvent(this.createLocalRowEvent(RowNode.EVENT_MOUSE_ENTER)); }; RowNode.prototype.onMouseLeave = function () { this.dispatchLocalEvent(this.createLocalRowEvent(RowNode.EVENT_MOUSE_LEAVE)); }; RowNode.prototype.getFirstChildOfFirstChild = function (rowGroupColumn) { var currentRowNode = this; // if we are hiding groups, then if we are the first child, of the first child, // all the way up to the column we are interested in, then we show the group cell. var isCandidate = true; var foundFirstChildPath = false; var nodeToSwapIn; while (isCandidate && !foundFirstChildPath) { var parentRowNode = currentRowNode.parent; var firstChild = utils_1.Utils.exists(parentRowNode) && currentRowNode.firstChild; if (firstChild) { if (parentRowNode.rowGroupColumn === rowGroupColumn) { foundFirstChildPath = true; nodeToSwapIn = parentRowNode; } } else { isCandidate = false; } currentRowNode = parentRowNode; } return foundFirstChildPath ? nodeToSwapIn : null; }; RowNode.EVENT_ROW_SELECTED = 'rowSelected'; RowNode.EVENT_DATA_CHANGED = 'dataChanged'; RowNode.EVENT_CELL_CHANGED = 'cellChanged'; RowNode.EVENT_ALL_CHILDREN_COUNT_CHANGED = 'allChildrenCountChanged'; RowNode.EVENT_MOUSE_ENTER = 'mouseEnter'; RowNode.EVENT_MOUSE_LEAVE = 'mouseLeave'; RowNode.EVENT_HEIGHT_CHANGED = 'heightChanged'; RowNode.EVENT_TOP_CHANGED = 'topChanged'; RowNode.EVENT_FIRST_CHILD_CHANGED = 'firstChildChanged'; RowNode.EVENT_LAST_CHILD_CHANGED = 'lastChildChanged'; RowNode.EVENT_CHILD_INDEX_CHANGED = 'childIndexChanged'; RowNode.EVENT_ROW_INDEX_CHANGED = 'rowIndexChanged'; RowNode.EVENT_EXPANDED_CHANGED = 'expandedChanged'; RowNode.EVENT_SELECTABLE_CHANGED = 'selectableChanged'; RowNode.EVENT_UI_LEVEL_CHANGED = 'uiLevelChanged'; RowNode.EVENT_DRAGGING_CHANGED = 'draggingChanged'; __decorate([ context_1.Autowired('eventService'), __metadata("design:type", eventService_1.EventService) ], RowNode.prototype, "mainEventService", void 0); __decorate([ context_1.Autowired('gridOptionsWrapper'), __metadata("design:type", gridOptionsWrapper_1.GridOptionsWrapper) ], RowNode.prototype, "gridOptionsWrapper", void 0); __decorate([ context_1.Autowired('selectionController'), __metadata("design:type", selectionController_1.SelectionController) ], RowNode.prototype, "selectionController", void 0); __decorate([ context_1.Autowired('columnController'), __metadata("design:type", columnController_1.ColumnController) ], RowNode.prototype, "columnController", void 0); __decorate([ context_1.Autowired('valueService'), __metadata("design:type", valueService_1.ValueService) ], RowNode.prototype, "valueService", void 0); __decorate([ context_1.Autowired('rowModel'), __metadata("design:type", Object) ], RowNode.prototype, "rowModel", void 0); __decorate([ context_1.Autowired('context'), __metadata("design:type", context_1.Context) ], RowNode.prototype, "context", void 0); __decorate([ context_1.Autowired('valueCache'), __metadata("design:type", valueCache_1.ValueCache) ], RowNode.prototype, "valueCache", void 0); __decorate([ context_1.Autowired('columnApi'), __metadata("design:type", columnApi_1.ColumnApi) ], RowNode.prototype, "columnApi", void 0); __decorate([ context_1.Autowired('gridApi'), __metadata("design:type", gridApi_1.GridApi) ], RowNode.prototype, "gridApi", void 0); return RowNode; }()); exports.RowNode = RowNode;