@deephaven/iris-grid 1.28.1 → 1.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ColumnStatistics.js +1 -1
- package/dist/ColumnStatistics.js.map +1 -1
- package/dist/IrisGrid.d.ts +28 -4
- package/dist/IrisGrid.d.ts.map +1 -1
- package/dist/IrisGrid.js +185 -113
- package/dist/IrisGrid.js.map +1 -1
- package/dist/IrisGridCopyHandler.d.ts +5 -4
- package/dist/IrisGridCopyHandler.d.ts.map +1 -1
- package/dist/IrisGridCopyHandler.js +36 -29
- package/dist/IrisGridCopyHandler.js.map +1 -1
- package/dist/IrisGridModel.d.ts +2 -2
- package/dist/IrisGridModel.d.ts.map +1 -1
- package/dist/IrisGridModel.js +2 -2
- package/dist/IrisGridModel.js.map +1 -1
- package/dist/IrisGridSelectionUtils.d.ts +26 -0
- package/dist/IrisGridSelectionUtils.d.ts.map +1 -0
- package/dist/IrisGridSelectionUtils.js +84 -0
- package/dist/IrisGridSelectionUtils.js.map +1 -0
- package/dist/IrisGridTableModel.d.ts +4 -4
- package/dist/IrisGridTableModel.d.ts.map +1 -1
- package/dist/IrisGridTableModel.js +8 -8
- package/dist/IrisGridTableModel.js.map +1 -1
- package/dist/IrisGridTableModelTemplate.d.ts +25 -3
- package/dist/IrisGridTableModelTemplate.d.ts.map +1 -1
- package/dist/IrisGridTableModelTemplate.js +283 -79
- package/dist/IrisGridTableModelTemplate.js.map +1 -1
- package/dist/IrisGridTreeTableModel.d.ts +2 -0
- package/dist/IrisGridTreeTableModel.d.ts.map +1 -1
- package/dist/IrisGridTreeTableModel.js +11 -0
- package/dist/IrisGridTreeTableModel.js.map +1 -1
- package/dist/KeyedGridModel.d.ts +63 -0
- package/dist/KeyedGridModel.d.ts.map +1 -0
- package/dist/KeyedGridModel.js +12 -0
- package/dist/KeyedGridModel.js.map +1 -0
- package/dist/KeyedSelection.d.ts +194 -0
- package/dist/KeyedSelection.d.ts.map +1 -0
- package/dist/KeyedSelection.js +699 -0
- package/dist/KeyedSelection.js.map +1 -0
- package/dist/LazyIrisGrid.d.ts +1 -0
- package/dist/LazyIrisGrid.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/key-handlers/CopyKeyHandler.d.ts.map +1 -1
- package/dist/key-handlers/CopyKeyHandler.js +8 -6
- package/dist/key-handlers/CopyKeyHandler.js.map +1 -1
- package/dist/mousehandlers/IrisGridContextMenuHandler.d.ts +1 -1
- package/dist/mousehandlers/IrisGridContextMenuHandler.d.ts.map +1 -1
- package/dist/mousehandlers/IrisGridContextMenuHandler.js +94 -69
- package/dist/mousehandlers/IrisGridContextMenuHandler.js.map +1 -1
- package/dist/sidebar/TableCsvExporter.d.ts +7 -4
- package/dist/sidebar/TableCsvExporter.d.ts.map +1 -1
- package/dist/sidebar/TableCsvExporter.js +86 -38
- package/dist/sidebar/TableCsvExporter.js.map +1 -1
- package/package.json +9 -9
|
@@ -0,0 +1,699 @@
|
|
|
1
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
2
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
3
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
4
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
5
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
6
|
+
import { EMPTY_ARRAY, EMPTY_MAP } from '@deephaven/utils';
|
|
7
|
+
import { computeGestureExtend, cursorLandingCellForRanges, nextCursorInRanges, withCommittedCursor } from '@deephaven/grid';
|
|
8
|
+
/**
|
|
9
|
+
* Serializes key-column values to a stable string for use as a Map/Set key.
|
|
10
|
+
* JSON.stringify encodes NaN, Infinity, and -Infinity as null, so we
|
|
11
|
+
* substitute sentinel strings to preserve their distinct identities.
|
|
12
|
+
*/
|
|
13
|
+
export function serializeKeyValues(values) {
|
|
14
|
+
return JSON.stringify(values, (_key, value) => {
|
|
15
|
+
if (typeof value === 'number') {
|
|
16
|
+
if (Number.isNaN(value)) return '__NaN__';
|
|
17
|
+
if (value === Infinity) return '__Infinity__';
|
|
18
|
+
if (value === -Infinity) return '__-Infinity__';
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Configuration for a `KeyedSelection`. `getModel` is required; every
|
|
26
|
+
* other field defaults to an "empty" value (`null`, an empty set/map, or
|
|
27
|
+
* `false` where appropriate).
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Immutable `Selection` for keyed tables: identifies rows by their
|
|
32
|
+
* serialized key-column values rather than raw row indices, so the
|
|
33
|
+
* selection survives ticks that shuffle row positions.
|
|
34
|
+
*
|
|
35
|
+
* Rows sharing the same key highlight together (see `isRowSelected`).
|
|
36
|
+
* When `invertedSelection` is true, `selectedKeys` is treated as an
|
|
37
|
+
* exclusion set (all rows selected except those keys).
|
|
38
|
+
*/
|
|
39
|
+
export class KeyedSelection {
|
|
40
|
+
static empty(getModel) {
|
|
41
|
+
return new KeyedSelection({
|
|
42
|
+
getModel
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
constructor(options) {
|
|
46
|
+
var _options$selectedKeys, _options$overlayRange, _options$invertedSele, _options$selectedKeyV, _options$maxRows, _options$pendingRange, _options$anchorKey, _options$anchorRow, _options$cursorKey, _options$cursorRowHin, _options$cursorColumn, _options$selectionEnd, _options$selectionEnd2, _options$selectionEnd3;
|
|
47
|
+
_defineProperty(this, "getModel", void 0);
|
|
48
|
+
_defineProperty(this, "selectedKeys", void 0);
|
|
49
|
+
_defineProperty(this, "overlayRanges", void 0);
|
|
50
|
+
_defineProperty(this, "invertedSelection", void 0);
|
|
51
|
+
_defineProperty(this, "selectedKeyValues", void 0);
|
|
52
|
+
_defineProperty(this, "maxRows", void 0);
|
|
53
|
+
_defineProperty(this, "pendingRanges", void 0);
|
|
54
|
+
_defineProperty(this, "anchorKey", void 0);
|
|
55
|
+
_defineProperty(this, "anchorRow", void 0);
|
|
56
|
+
_defineProperty(this, "cursorKey", void 0);
|
|
57
|
+
_defineProperty(this, "cursorRowHint", void 0);
|
|
58
|
+
_defineProperty(this, "cursorColumn", void 0);
|
|
59
|
+
_defineProperty(this, "selectionEndKey", void 0);
|
|
60
|
+
_defineProperty(this, "selectionEndRowHint", void 0);
|
|
61
|
+
_defineProperty(this, "selectionEndColumn", void 0);
|
|
62
|
+
/** Keys derived from the current overlay range's viewport-visible rows. */
|
|
63
|
+
_defineProperty(this, "gestureKeys", void 0);
|
|
64
|
+
this.getModel = options.getModel;
|
|
65
|
+
this.selectedKeys = (_options$selectedKeys = options.selectedKeys) !== null && _options$selectedKeys !== void 0 ? _options$selectedKeys : new Set();
|
|
66
|
+
this.overlayRanges = (_options$overlayRange = options.overlayRanges) !== null && _options$overlayRange !== void 0 ? _options$overlayRange : EMPTY_ARRAY;
|
|
67
|
+
this.invertedSelection = (_options$invertedSele = options.invertedSelection) !== null && _options$invertedSele !== void 0 ? _options$invertedSele : false;
|
|
68
|
+
this.selectedKeyValues = (_options$selectedKeyV = options.selectedKeyValues) !== null && _options$selectedKeyV !== void 0 ? _options$selectedKeyV : EMPTY_MAP;
|
|
69
|
+
this.maxRows = (_options$maxRows = options.maxRows) !== null && _options$maxRows !== void 0 ? _options$maxRows : null;
|
|
70
|
+
this.pendingRanges = (_options$pendingRange = options.pendingRanges) !== null && _options$pendingRange !== void 0 ? _options$pendingRange : EMPTY_ARRAY;
|
|
71
|
+
this.anchorKey = (_options$anchorKey = options.anchorKey) !== null && _options$anchorKey !== void 0 ? _options$anchorKey : null;
|
|
72
|
+
this.anchorRow = (_options$anchorRow = options.anchorRow) !== null && _options$anchorRow !== void 0 ? _options$anchorRow : null;
|
|
73
|
+
this.cursorKey = (_options$cursorKey = options.cursorKey) !== null && _options$cursorKey !== void 0 ? _options$cursorKey : null;
|
|
74
|
+
this.cursorRowHint = (_options$cursorRowHin = options.cursorRowHint) !== null && _options$cursorRowHin !== void 0 ? _options$cursorRowHin : null;
|
|
75
|
+
this.cursorColumn = (_options$cursorColumn = options.cursorColumn) !== null && _options$cursorColumn !== void 0 ? _options$cursorColumn : null;
|
|
76
|
+
this.selectionEndKey = (_options$selectionEnd = options.selectionEndKey) !== null && _options$selectionEnd !== void 0 ? _options$selectionEnd : null;
|
|
77
|
+
this.selectionEndRowHint = (_options$selectionEnd2 = options.selectionEndRowHint) !== null && _options$selectionEnd2 !== void 0 ? _options$selectionEnd2 : null;
|
|
78
|
+
this.selectionEndColumn = (_options$selectionEnd3 = options.selectionEndColumn) !== null && _options$selectionEnd3 !== void 0 ? _options$selectionEnd3 : null;
|
|
79
|
+
|
|
80
|
+
// Enumerate only viewport-visible rows so gesture key lookup stays O(1)
|
|
81
|
+
// and construction is O(viewport) regardless of total table size.
|
|
82
|
+
if (this.overlayRanges.length === 0) {
|
|
83
|
+
this.gestureKeys = new Set();
|
|
84
|
+
} else {
|
|
85
|
+
var _model$viewport$top, _model$viewport, _model$viewport$botto, _model$viewport2;
|
|
86
|
+
var model = this.getModel();
|
|
87
|
+
var viewTop = (_model$viewport$top = (_model$viewport = model.viewport) === null || _model$viewport === void 0 ? void 0 : _model$viewport.top) !== null && _model$viewport$top !== void 0 ? _model$viewport$top : 0;
|
|
88
|
+
var viewBottom = (_model$viewport$botto = (_model$viewport2 = model.viewport) === null || _model$viewport2 === void 0 ? void 0 : _model$viewport2.bottom) !== null && _model$viewport$botto !== void 0 ? _model$viewport$botto : 0;
|
|
89
|
+
var keys = new Set();
|
|
90
|
+
for (var i = 0; i < this.overlayRanges.length; i += 1) {
|
|
91
|
+
var _this$overlayRanges$i = this.overlayRanges[i],
|
|
92
|
+
startRow = _this$overlayRanges$i.startRow,
|
|
93
|
+
endRow = _this$overlayRanges$i.endRow;
|
|
94
|
+
if (startRow == null) continue; // eslint-disable-line no-continue
|
|
95
|
+
var last = endRow !== null && endRow !== void 0 ? endRow : startRow;
|
|
96
|
+
var clampedStart = Math.max(startRow, viewTop);
|
|
97
|
+
var clampedEnd = Math.min(last, viewBottom);
|
|
98
|
+
for (var r = clampedStart; r <= clampedEnd; r += 1) {
|
|
99
|
+
var data = this.getRowKeyData(r);
|
|
100
|
+
if (data != null) keys.add(data.key);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
this.gestureKeys = keys;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Returns a copy of this selection with the given fields overridden.
|
|
109
|
+
* Unspecified fields carry through; pass `null` (or an empty
|
|
110
|
+
* set/map/false) to explicitly clear a field.
|
|
111
|
+
*/
|
|
112
|
+
copyWith(overrides) {
|
|
113
|
+
return new KeyedSelection(_objectSpread({
|
|
114
|
+
getModel: this.getModel,
|
|
115
|
+
selectedKeys: this.selectedKeys,
|
|
116
|
+
overlayRanges: this.overlayRanges,
|
|
117
|
+
invertedSelection: this.invertedSelection,
|
|
118
|
+
selectedKeyValues: this.selectedKeyValues,
|
|
119
|
+
maxRows: this.maxRows,
|
|
120
|
+
pendingRanges: this.pendingRanges,
|
|
121
|
+
anchorKey: this.anchorKey,
|
|
122
|
+
anchorRow: this.anchorRow,
|
|
123
|
+
cursorKey: this.cursorKey,
|
|
124
|
+
cursorRowHint: this.cursorRowHint,
|
|
125
|
+
cursorColumn: this.cursorColumn,
|
|
126
|
+
selectionEndKey: this.selectionEndKey,
|
|
127
|
+
selectionEndRowHint: this.selectionEndRowHint,
|
|
128
|
+
selectionEndColumn: this.selectionEndColumn
|
|
129
|
+
}, overrides));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Returns both the serialized key and the raw values for a visible row, or
|
|
134
|
+
* `null` when the row is not keyable (e.g. totals / aggregation floating
|
|
135
|
+
* rows whose column values are aggregates, not real row keys).
|
|
136
|
+
*/
|
|
137
|
+
getRowKeyData(row) {
|
|
138
|
+
var model = this.getModel();
|
|
139
|
+
if (model.isKeyableRow(row) !== true) return null;
|
|
140
|
+
var values = model.selectionKeyColumnIndices.map(col => model.valueForCell(col, row));
|
|
141
|
+
return {
|
|
142
|
+
key: serializeKeyValues(values),
|
|
143
|
+
values
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
isEmpty() {
|
|
147
|
+
// Inverted selection means all rows are selected — never empty.
|
|
148
|
+
if (this.invertedSelection) return false;
|
|
149
|
+
// Pending resolution means a selection is in progress — not empty.
|
|
150
|
+
if (this.pendingRanges.length > 0) return false;
|
|
151
|
+
return this.selectedKeys.size === 0 && this.gestureKeys.size === 0;
|
|
152
|
+
}
|
|
153
|
+
describe() {
|
|
154
|
+
if (this.pendingRanges.length > 0) return 'Selection loading.';
|
|
155
|
+
// Non-unique key columns can map one key to many rows; report the
|
|
156
|
+
// truthful count (keys) rather than lying about row counts.
|
|
157
|
+
var unit = this.getModel().hasUniqueSelectionKeys ? 'row' : 'key';
|
|
158
|
+
var n = this.selectedKeys.size;
|
|
159
|
+
if (this.invertedSelection) {
|
|
160
|
+
if (n === 0) return 'Everything selected.';
|
|
161
|
+
return unit === 'row' ? "All rows except ".concat(n, " selected.") : "All rows except ".concat(n, " ").concat(n === 1 ? 'key' : 'keys', " selected.");
|
|
162
|
+
}
|
|
163
|
+
if (n === 0) return 'No selection.';
|
|
164
|
+
if (n === 1) return unit === 'row' ? '1 row selected.' : '1 key selected.';
|
|
165
|
+
return unit === 'row' ? "".concat(n, " rows selected.") : "".concat(n, " keys selected.");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Keyed selection is always full-row; column is irrelevant
|
|
169
|
+
isCellSelected(_column, row) {
|
|
170
|
+
return this.isRowSelected(row);
|
|
171
|
+
}
|
|
172
|
+
isRowSelected(row) {
|
|
173
|
+
var data = this.getRowKeyData(row);
|
|
174
|
+
if (data == null) return false;
|
|
175
|
+
var key = data.key;
|
|
176
|
+
if (this.invertedSelection) return !this.selectedKeys.has(key);
|
|
177
|
+
// Include gesture preview keys so key-siblings highlight on mousedown without waiting for commit.
|
|
178
|
+
return this.selectedKeys.has(key) || this.gestureKeys.has(key);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Only fully selected when the inversion covers every row (i.e. select-all).
|
|
182
|
+
isColumnSelected(_column) {
|
|
183
|
+
return this.invertedSelection && this.selectedKeys.size === 0;
|
|
184
|
+
}
|
|
185
|
+
getNextCursorInDirection(current, direction) {
|
|
186
|
+
var _this$getModel = this.getModel(),
|
|
187
|
+
columnCount = _this$getModel.columnCount,
|
|
188
|
+
rowCount = _this$getModel.rowCount;
|
|
189
|
+
return nextCursorInRanges(this.overlayRanges, current, direction, {
|
|
190
|
+
columnCount,
|
|
191
|
+
rowCount
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
getCursorLandingCell() {
|
|
195
|
+
var _this$getModel2 = this.getModel(),
|
|
196
|
+
columnCount = _this$getModel2.columnCount,
|
|
197
|
+
rowCount = _this$getModel2.rowCount;
|
|
198
|
+
return cursorLandingCellForRanges(this.overlayRanges, {
|
|
199
|
+
columnCount,
|
|
200
|
+
rowCount
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Cursor / endpoint tracking. Rows are stored as `(key, rowHint)` pairs so
|
|
205
|
+
// ticks that shuffle row indices resolve to the live row via
|
|
206
|
+
// `findKeyInViewport`; columns don't drift and are kept as raw indices.
|
|
207
|
+
withCursor(row, column) {
|
|
208
|
+
var _this$getRowKeyData$k, _this$getRowKeyData;
|
|
209
|
+
if (row === this.cursorRow && column === this.cursorColumn) return this;
|
|
210
|
+
var nextKey = row != null ? (_this$getRowKeyData$k = (_this$getRowKeyData = this.getRowKeyData(row)) === null || _this$getRowKeyData === void 0 ? void 0 : _this$getRowKeyData.key) !== null && _this$getRowKeyData$k !== void 0 ? _this$getRowKeyData$k : null : null;
|
|
211
|
+
return this.copyWith({
|
|
212
|
+
cursorKey: nextKey,
|
|
213
|
+
cursorRowHint: row,
|
|
214
|
+
cursorColumn: column
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
withSelectionEnd(row, column) {
|
|
218
|
+
var _this$getRowKeyData$k2, _this$getRowKeyData2;
|
|
219
|
+
if (row === this.selectionEndRow && column === this.selectionEndColumn) {
|
|
220
|
+
return this;
|
|
221
|
+
}
|
|
222
|
+
var nextKey = row != null ? (_this$getRowKeyData$k2 = (_this$getRowKeyData2 = this.getRowKeyData(row)) === null || _this$getRowKeyData2 === void 0 ? void 0 : _this$getRowKeyData2.key) !== null && _this$getRowKeyData$k2 !== void 0 ? _this$getRowKeyData$k2 : null : null;
|
|
223
|
+
return this.copyWith({
|
|
224
|
+
selectionEndKey: nextKey,
|
|
225
|
+
selectionEndRowHint: row,
|
|
226
|
+
selectionEndColumn: column
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Replaces the transient overlay ranges (mid-gesture preview) with the
|
|
232
|
+
* given ranges. Preserves the gesture anchor so mid-drag range updates
|
|
233
|
+
* don't clobber the shift-click origin.
|
|
234
|
+
*
|
|
235
|
+
* When `isReplacing` is true the caller intends the overlay to replace
|
|
236
|
+
* the current committed selection (drag / shift+click); previously
|
|
237
|
+
* committed keys are dropped so the commit uses the overlay as a fresh
|
|
238
|
+
* selection. Otherwise the committed keys are kept, letting a subsequent
|
|
239
|
+
* `commitGesture` fold the overlay into the existing set.
|
|
240
|
+
*/
|
|
241
|
+
withMouseGestureRanges(ranges) {
|
|
242
|
+
var isReplacing = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
243
|
+
if (isReplacing) {
|
|
244
|
+
return this.copyWith({
|
|
245
|
+
selectedKeys: new Set(),
|
|
246
|
+
overlayRanges: ranges,
|
|
247
|
+
invertedSelection: false,
|
|
248
|
+
selectedKeyValues: EMPTY_MAP,
|
|
249
|
+
pendingRanges: EMPTY_ARRAY
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return this.copyWith({
|
|
253
|
+
overlayRanges: ranges,
|
|
254
|
+
pendingRanges: EMPTY_ARRAY
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Sets the gesture anchor (extend-from position for shift-click and
|
|
260
|
+
* keyboard extend) to the row's key. Passing `null` clears the anchor.
|
|
261
|
+
*/
|
|
262
|
+
withGestureAnchor(row) {
|
|
263
|
+
var _this$getRowKeyData$k3, _this$getRowKeyData3;
|
|
264
|
+
var nextKey = row != null ? (_this$getRowKeyData$k3 = (_this$getRowKeyData3 = this.getRowKeyData(row)) === null || _this$getRowKeyData3 === void 0 ? void 0 : _this$getRowKeyData3.key) !== null && _this$getRowKeyData$k3 !== void 0 ? _this$getRowKeyData$k3 : null : null;
|
|
265
|
+
if (nextKey === this.anchorKey && row === this.anchorRow) return this;
|
|
266
|
+
return this.copyWith({
|
|
267
|
+
anchorKey: nextKey,
|
|
268
|
+
anchorRow: row
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* The current `{row, column}` of the gesture anchor, or `null` if none is
|
|
274
|
+
* set. Because `KeyedSelection` tracks the anchor by serialized key, the
|
|
275
|
+
* anchor's visible row may drift as the viewport scrolls. Resolves the
|
|
276
|
+
* key against the current viewport when possible; falls back to the
|
|
277
|
+
* click-time row hint (`anchorRow`) when the key has scrolled out. Returns
|
|
278
|
+
* `null` only when neither is set.
|
|
279
|
+
*/
|
|
280
|
+
getGestureAnchor() {
|
|
281
|
+
if (this.anchorKey == null && this.anchorRow == null) return null;
|
|
282
|
+
if (this.anchorKey != null) {
|
|
283
|
+
var viewportRow = this.findKeyInViewport(this.anchorKey, this.anchorRow);
|
|
284
|
+
if (viewportRow != null) return {
|
|
285
|
+
row: viewportRow,
|
|
286
|
+
column: null
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
// Anchor key is not in the viewport; fall back to the click-time row hint.
|
|
290
|
+
return {
|
|
291
|
+
row: this.anchorRow,
|
|
292
|
+
column: null
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Returns the visible row of `key`, or `null` if it's not in the viewport.
|
|
298
|
+
* When multiple rows share the key (non-unique key columns), prefers the one
|
|
299
|
+
* closest to `hint` so we track the row the caller last saw the key at.
|
|
300
|
+
*/
|
|
301
|
+
findKeyInViewport(key, hint) {
|
|
302
|
+
var _model$viewport$top2, _model$viewport3, _model$viewport$botto2, _model$viewport4;
|
|
303
|
+
var model = this.getModel();
|
|
304
|
+
var viewTop = (_model$viewport$top2 = (_model$viewport3 = model.viewport) === null || _model$viewport3 === void 0 ? void 0 : _model$viewport3.top) !== null && _model$viewport$top2 !== void 0 ? _model$viewport$top2 : 0;
|
|
305
|
+
var viewBottom = (_model$viewport$botto2 = (_model$viewport4 = model.viewport) === null || _model$viewport4 === void 0 ? void 0 : _model$viewport4.bottom) !== null && _model$viewport$botto2 !== void 0 ? _model$viewport$botto2 : 0;
|
|
306
|
+
var best = null;
|
|
307
|
+
var bestDist = Infinity;
|
|
308
|
+
for (var r = viewTop; r <= viewBottom; r += 1) {
|
|
309
|
+
var data = this.getRowKeyData(r);
|
|
310
|
+
if (data == null || data.key !== key) continue; // eslint-disable-line no-continue
|
|
311
|
+
if (hint == null) return r;
|
|
312
|
+
var dist = Math.abs(r - hint);
|
|
313
|
+
if (dist < bestDist) {
|
|
314
|
+
best = r;
|
|
315
|
+
bestDist = dist;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return best;
|
|
319
|
+
}
|
|
320
|
+
get cursorRow() {
|
|
321
|
+
var _this$findKeyInViewpo;
|
|
322
|
+
if (this.cursorKey == null) return this.cursorRowHint;
|
|
323
|
+
return (_this$findKeyInViewpo = this.findKeyInViewport(this.cursorKey, this.cursorRowHint)) !== null && _this$findKeyInViewpo !== void 0 ? _this$findKeyInViewpo : this.cursorRowHint;
|
|
324
|
+
}
|
|
325
|
+
get selectionEndRow() {
|
|
326
|
+
var _this$findKeyInViewpo2;
|
|
327
|
+
if (this.selectionEndKey == null) return this.selectionEndRowHint;
|
|
328
|
+
return (_this$findKeyInViewpo2 = this.findKeyInViewport(this.selectionEndKey, this.selectionEndRowHint)) !== null && _this$findKeyInViewpo2 !== void 0 ? _this$findKeyInViewpo2 : this.selectionEndRowHint;
|
|
329
|
+
}
|
|
330
|
+
withGestureExtend(cursor, opts) {
|
|
331
|
+
var _computeGestureExtend = computeGestureExtend(this.overlayRanges, this.getGestureAnchor(), cursor, opts),
|
|
332
|
+
newRanges = _computeGestureExtend.newRanges,
|
|
333
|
+
isReplacing = _computeGestureExtend.isReplacing,
|
|
334
|
+
trimBefore = _computeGestureExtend.trimBefore,
|
|
335
|
+
resetAnchor = _computeGestureExtend.resetAnchor;
|
|
336
|
+
var base = trimBefore ? this.trimmed() : this;
|
|
337
|
+
var result = base.withMouseGestureRanges(newRanges, isReplacing);
|
|
338
|
+
if (resetAnchor) {
|
|
339
|
+
// Keyed selection is row based, so column is not used in the anchor.
|
|
340
|
+
result = result.withGestureAnchor(cursor.row);
|
|
341
|
+
}
|
|
342
|
+
return result;
|
|
343
|
+
}
|
|
344
|
+
commitGesture(lastCommitted, opts) {
|
|
345
|
+
if (this.overlayRanges.length === 0) return this;
|
|
346
|
+
if (opts.settle === false) {
|
|
347
|
+
// Mouse-down: keep overlayRanges pending. The overlay-to-committed
|
|
348
|
+
// merge (add / toggle-off / consolidation) runs on mouse-up so a drag
|
|
349
|
+
// can grow the overlay without prematurely folding it into selectedKeys.
|
|
350
|
+
return withCommittedCursor(this, this.getCursorLandingCell(), opts);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Scan ranges for endpoints and total row count
|
|
354
|
+
var first = null;
|
|
355
|
+
var lastRow = 0;
|
|
356
|
+
var rowCount = 0;
|
|
357
|
+
for (var i = 0; i < this.overlayRanges.length; i += 1) {
|
|
358
|
+
var _this$overlayRanges$i2 = this.overlayRanges[i],
|
|
359
|
+
startRow = _this$overlayRanges$i2.startRow,
|
|
360
|
+
endRow = _this$overlayRanges$i2.endRow;
|
|
361
|
+
if (startRow == null) continue; // eslint-disable-line no-continue
|
|
362
|
+
var rEnd = endRow !== null && endRow !== void 0 ? endRow : startRow;
|
|
363
|
+
if (first === null) first = startRow;
|
|
364
|
+
lastRow = rEnd;
|
|
365
|
+
rowCount += rEnd - startRow + 1;
|
|
366
|
+
}
|
|
367
|
+
if (first === null || rowCount === 0) return this;
|
|
368
|
+
var next = new Set(this.selectedKeys);
|
|
369
|
+
if (this.selectedKeys.size > 0 || this.invertedSelection) {
|
|
370
|
+
// Ctrl+click / ctrl+drag path: clearSelectedRanges was not called, so
|
|
371
|
+
// selectedKeys still holds the previous committed keys. Toggle off when
|
|
372
|
+
// every row in the overlay was already committed (single-row ctrl+click
|
|
373
|
+
// on a selected row, or ctrl+drag over an all-selected range); otherwise
|
|
374
|
+
// add all rows to the selection without unioning them off.
|
|
375
|
+
var shouldToggle = true;
|
|
376
|
+
for (var _i = 0; _i < this.overlayRanges.length && shouldToggle; _i += 1) {
|
|
377
|
+
var _this$overlayRanges$_ = this.overlayRanges[_i],
|
|
378
|
+
_startRow = _this$overlayRanges$_.startRow,
|
|
379
|
+
_endRow = _this$overlayRanges$_.endRow;
|
|
380
|
+
if (_startRow == null) continue; // eslint-disable-line no-continue
|
|
381
|
+
var _rEnd = _endRow !== null && _endRow !== void 0 ? _endRow : _startRow;
|
|
382
|
+
for (var r = _startRow; r <= _rEnd; r += 1) {
|
|
383
|
+
if (!lastCommitted.isRowSelected(r)) {
|
|
384
|
+
shouldToggle = false;
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Multi-row ctrl+shift add that spans out-of-viewport should defer
|
|
391
|
+
// to async resolution while preserving the already-committed keys.
|
|
392
|
+
if (!shouldToggle && !this.invertedSelection) {
|
|
393
|
+
var _model$viewport$top3, _model$viewport5, _model$viewport$botto3, _model$viewport6;
|
|
394
|
+
var model = this.getModel();
|
|
395
|
+
var viewTop = (_model$viewport$top3 = (_model$viewport5 = model.viewport) === null || _model$viewport5 === void 0 ? void 0 : _model$viewport5.top) !== null && _model$viewport$top3 !== void 0 ? _model$viewport$top3 : 0;
|
|
396
|
+
var viewBottom = (_model$viewport$botto3 = (_model$viewport6 = model.viewport) === null || _model$viewport6 === void 0 ? void 0 : _model$viewport6.bottom) !== null && _model$viewport$botto3 !== void 0 ? _model$viewport$botto3 : 0;
|
|
397
|
+
if (first < viewTop || lastRow > viewBottom) {
|
|
398
|
+
return withCommittedCursor(this.copyWith({
|
|
399
|
+
overlayRanges: EMPTY_ARRAY,
|
|
400
|
+
pendingRanges: this.overlayRanges
|
|
401
|
+
}), this.getCursorLandingCell(), opts);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
var _nextKeyValues = new Map(this.selectedKeyValues);
|
|
405
|
+
for (var _i2 = 0; _i2 < this.overlayRanges.length; _i2 += 1) {
|
|
406
|
+
var _this$overlayRanges$_2 = this.overlayRanges[_i2],
|
|
407
|
+
_startRow2 = _this$overlayRanges$_2.startRow,
|
|
408
|
+
_endRow2 = _this$overlayRanges$_2.endRow;
|
|
409
|
+
if (_startRow2 == null) continue; // eslint-disable-line no-continue
|
|
410
|
+
var _rEnd2 = _endRow2 !== null && _endRow2 !== void 0 ? _endRow2 : _startRow2;
|
|
411
|
+
for (var _r = _startRow2; _r <= _rEnd2; _r += 1) {
|
|
412
|
+
var _data = this.getRowKeyData(_r);
|
|
413
|
+
if (_data == null) continue; // eslint-disable-line no-continue
|
|
414
|
+
var _k = _data.key,
|
|
415
|
+
_values = _data.values;
|
|
416
|
+
if (shouldToggle) {
|
|
417
|
+
// Toggle off: every overlay row was already in lastCommitted, so
|
|
418
|
+
// ctrl+click / ctrl+drag flips them off.
|
|
419
|
+
if (this.invertedSelection) {
|
|
420
|
+
next.add(_k);
|
|
421
|
+
_nextKeyValues.set(_k, _values);
|
|
422
|
+
} else {
|
|
423
|
+
next.delete(_k);
|
|
424
|
+
_nextKeyValues.delete(_k);
|
|
425
|
+
}
|
|
426
|
+
} else if (this.invertedSelection) {
|
|
427
|
+
next.delete(_k);
|
|
428
|
+
_nextKeyValues.delete(_k);
|
|
429
|
+
} else {
|
|
430
|
+
next.add(_k);
|
|
431
|
+
_nextKeyValues.set(_k, _values);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return withCommittedCursor(this.copyWith({
|
|
436
|
+
selectedKeys: next,
|
|
437
|
+
overlayRanges: EMPTY_ARRAY,
|
|
438
|
+
selectedKeyValues: _nextKeyValues,
|
|
439
|
+
pendingRanges: EMPTY_ARRAY
|
|
440
|
+
}), this.getCursorLandingCell(), opts);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Regular click path: clearSelectedRanges emptied selectedKeys first.
|
|
444
|
+
// Multi-row shift selections may span out-of-viewport rows where valueForCell
|
|
445
|
+
// returns null. Defer those to async resolution in IrisGrid.
|
|
446
|
+
// Assumes shift+click/drag emits one contiguous overlay range; `first`/`lastRow`
|
|
447
|
+
// are that range's endpoints and drive the anchor/target endpoint capture below.
|
|
448
|
+
if (rowCount > 1) {
|
|
449
|
+
var _model$viewport$top4, _model$viewport7, _model$viewport$botto4, _model$viewport8;
|
|
450
|
+
var _model = this.getModel();
|
|
451
|
+
var _viewTop = (_model$viewport$top4 = (_model$viewport7 = _model.viewport) === null || _model$viewport7 === void 0 ? void 0 : _model$viewport7.top) !== null && _model$viewport$top4 !== void 0 ? _model$viewport$top4 : 0;
|
|
452
|
+
var _viewBottom = (_model$viewport$botto4 = (_model$viewport8 = _model.viewport) === null || _model$viewport8 === void 0 ? void 0 : _model$viewport8.bottom) !== null && _model$viewport$botto4 !== void 0 ? _model$viewport$botto4 : 0;
|
|
453
|
+
|
|
454
|
+
// Fast path: entire range is in the viewport, so we can enumerate keys
|
|
455
|
+
// synchronously and skip the async fetch race entirely.
|
|
456
|
+
if (first >= _viewTop && lastRow <= _viewBottom) {
|
|
457
|
+
var _nextKeyValues2 = new Map();
|
|
458
|
+
for (var _r2 = first; _r2 <= lastRow; _r2 += 1) {
|
|
459
|
+
var _data2 = this.getRowKeyData(_r2);
|
|
460
|
+
if (_data2 == null) continue; // eslint-disable-line no-continue
|
|
461
|
+
_nextKeyValues2.set(_data2.key, _data2.values);
|
|
462
|
+
}
|
|
463
|
+
return withCommittedCursor(this.copyWith({
|
|
464
|
+
selectedKeys: new Set(_nextKeyValues2.keys()),
|
|
465
|
+
overlayRanges: EMPTY_ARRAY,
|
|
466
|
+
invertedSelection: false,
|
|
467
|
+
selectedKeyValues: _nextKeyValues2,
|
|
468
|
+
pendingRanges: EMPTY_ARRAY
|
|
469
|
+
}), this.getCursorLandingCell(), opts);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Slow path: same async-fetch mechanism as `withCommittedRanges`.
|
|
473
|
+
// `IrisGrid.resolveKeyedSelection` fetches keys for the overlay ranges;
|
|
474
|
+
// rows that scroll away during the fetch are dropped from the result.
|
|
475
|
+
return withCommittedCursor(this.copyWith({
|
|
476
|
+
selectedKeys: new Set(),
|
|
477
|
+
invertedSelection: false,
|
|
478
|
+
selectedKeyValues: EMPTY_MAP,
|
|
479
|
+
pendingRanges: this.overlayRanges
|
|
480
|
+
}), this.getCursorLandingCell(), opts);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Single-row path (rowCount === 1): first === lastRow.
|
|
484
|
+
var row = first;
|
|
485
|
+
var data = this.getRowKeyData(row);
|
|
486
|
+
if (data == null) {
|
|
487
|
+
// Row is not keyable (totals / aggregation row); commit clears the
|
|
488
|
+
// overlay without touching the keyed set.
|
|
489
|
+
return withCommittedCursor(this.copyWith({
|
|
490
|
+
overlayRanges: EMPTY_ARRAY
|
|
491
|
+
}), this.getCursorLandingCell(), opts);
|
|
492
|
+
}
|
|
493
|
+
var k = data.key,
|
|
494
|
+
values = data.values;
|
|
495
|
+
var nextKeyValues = new Map(this.selectedKeyValues);
|
|
496
|
+
// Deselect only when the clicked row was the entire previous committed selection.
|
|
497
|
+
var wasEntireSelection = opts.allowDeselect !== false && lastCommitted instanceof KeyedSelection && !lastCommitted.invertedSelection && lastCommitted.selectedKeys.size === 1 && lastCommitted.selectedKeys.has(k);
|
|
498
|
+
if (wasEntireSelection) {
|
|
499
|
+
next.delete(k);
|
|
500
|
+
nextKeyValues.delete(k);
|
|
501
|
+
} else {
|
|
502
|
+
next.add(k);
|
|
503
|
+
nextKeyValues.set(k, values);
|
|
504
|
+
}
|
|
505
|
+
return withCommittedCursor(this.copyWith({
|
|
506
|
+
selectedKeys: next,
|
|
507
|
+
overlayRanges: EMPTY_ARRAY,
|
|
508
|
+
invertedSelection: false,
|
|
509
|
+
selectedKeyValues: nextKeyValues,
|
|
510
|
+
pendingRanges: EMPTY_ARRAY
|
|
511
|
+
}), this.getCursorLandingCell(), opts);
|
|
512
|
+
}
|
|
513
|
+
clear() {
|
|
514
|
+
// Fresh empty carrying cursor forward (Escape semantics). Endpoint is
|
|
515
|
+
// transient gesture state and drops as part of the reset.
|
|
516
|
+
return KeyedSelection.empty(this.getModel).copyWith({
|
|
517
|
+
cursorKey: this.cursorKey,
|
|
518
|
+
cursorRowHint: this.cursorRowHint,
|
|
519
|
+
cursorColumn: this.cursorColumn
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Shift+click needs a clean slate so the range replaces rather than extends the old keys.
|
|
524
|
+
// Anchor is preserved so shift+click's extend reads it after the trim.
|
|
525
|
+
trimmed() {
|
|
526
|
+
return this.copyWith({
|
|
527
|
+
selectedKeys: new Set(),
|
|
528
|
+
overlayRanges: EMPTY_ARRAY,
|
|
529
|
+
invertedSelection: false,
|
|
530
|
+
selectedKeyValues: EMPTY_MAP,
|
|
531
|
+
maxRows: null,
|
|
532
|
+
pendingRanges: EMPTY_ARRAY
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Always returns non-inverted; switching to a new selection exits inverted mode.
|
|
537
|
+
withCommittedRanges(ranges, anchor) {
|
|
538
|
+
var result = this.installCommittedRanges(ranges);
|
|
539
|
+
if (anchor === undefined) return result;
|
|
540
|
+
// Keyed selection is row based, so column is not used in the anchor.
|
|
541
|
+
return result.withGestureAnchor(anchor.row);
|
|
542
|
+
}
|
|
543
|
+
installCommittedRanges(ranges) {
|
|
544
|
+
var _model$viewport$top5, _model$viewport9, _model$viewport$botto5, _model$viewport0;
|
|
545
|
+
// Fields threaded through every fresh install so cursor / endpoint state
|
|
546
|
+
// survive programmatic range replacement (matches Escape semantics).
|
|
547
|
+
var carry = {
|
|
548
|
+
cursorKey: this.cursorKey,
|
|
549
|
+
cursorRowHint: this.cursorRowHint,
|
|
550
|
+
cursorColumn: this.cursorColumn,
|
|
551
|
+
selectionEndKey: this.selectionEndKey,
|
|
552
|
+
selectionEndRowHint: this.selectionEndRowHint,
|
|
553
|
+
selectionEndColumn: this.selectionEndColumn
|
|
554
|
+
};
|
|
555
|
+
// Replacement semantics: discard previous selection and select exactly these rows.
|
|
556
|
+
if (ranges.length === 0) {
|
|
557
|
+
return new KeyedSelection(_objectSpread({
|
|
558
|
+
getModel: this.getModel
|
|
559
|
+
}, carry));
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Compute the true min/max across every range so the viewport check is
|
|
563
|
+
// correct even when input ranges arrive out of order or non-contiguous
|
|
564
|
+
// (e.g. plugin-driven programmatic selection).
|
|
565
|
+
var minRow = null;
|
|
566
|
+
var maxRow = null;
|
|
567
|
+
for (var i = 0; i < ranges.length; i += 1) {
|
|
568
|
+
var _ranges$i = ranges[i],
|
|
569
|
+
startRow = _ranges$i.startRow,
|
|
570
|
+
endRow = _ranges$i.endRow;
|
|
571
|
+
if (startRow == null) continue; // eslint-disable-line no-continue
|
|
572
|
+
var rEnd = endRow !== null && endRow !== void 0 ? endRow : startRow;
|
|
573
|
+
var low = Math.min(startRow, rEnd);
|
|
574
|
+
var high = Math.max(startRow, rEnd);
|
|
575
|
+
if (minRow === null || low < minRow) minRow = low;
|
|
576
|
+
if (maxRow === null || high > maxRow) maxRow = high;
|
|
577
|
+
}
|
|
578
|
+
if (minRow === null || maxRow === null) {
|
|
579
|
+
return new KeyedSelection(_objectSpread({
|
|
580
|
+
getModel: this.getModel
|
|
581
|
+
}, carry));
|
|
582
|
+
}
|
|
583
|
+
var model = this.getModel();
|
|
584
|
+
var viewTop = (_model$viewport$top5 = (_model$viewport9 = model.viewport) === null || _model$viewport9 === void 0 ? void 0 : _model$viewport9.top) !== null && _model$viewport$top5 !== void 0 ? _model$viewport$top5 : 0;
|
|
585
|
+
var viewBottom = (_model$viewport$botto5 = (_model$viewport0 = model.viewport) === null || _model$viewport0 === void 0 ? void 0 : _model$viewport0.bottom) !== null && _model$viewport$botto5 !== void 0 ? _model$viewport$botto5 : 0;
|
|
586
|
+
|
|
587
|
+
// Fast path: every range fits in the viewport, so valueForCell answers
|
|
588
|
+
// synchronously with real values.
|
|
589
|
+
if (minRow >= viewTop && maxRow <= viewBottom) {
|
|
590
|
+
var next = new Set();
|
|
591
|
+
var nextKeyValues = new Map();
|
|
592
|
+
for (var _i3 = 0; _i3 < ranges.length; _i3 += 1) {
|
|
593
|
+
var _ranges$_i = ranges[_i3],
|
|
594
|
+
_startRow3 = _ranges$_i.startRow,
|
|
595
|
+
_endRow3 = _ranges$_i.endRow;
|
|
596
|
+
if (_startRow3 == null) continue; // eslint-disable-line no-continue
|
|
597
|
+
var _rEnd3 = _endRow3 !== null && _endRow3 !== void 0 ? _endRow3 : _startRow3;
|
|
598
|
+
var _low = Math.min(_startRow3, _rEnd3);
|
|
599
|
+
var _high = Math.max(_startRow3, _rEnd3);
|
|
600
|
+
for (var r = _low; r <= _high; r += 1) {
|
|
601
|
+
var data = this.getRowKeyData(r);
|
|
602
|
+
if (data == null) continue; // eslint-disable-line no-continue
|
|
603
|
+
next.add(data.key);
|
|
604
|
+
nextKeyValues.set(data.key, data.values);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return new KeyedSelection(_objectSpread({
|
|
608
|
+
getModel: this.getModel,
|
|
609
|
+
selectedKeys: next,
|
|
610
|
+
selectedKeyValues: nextKeyValues
|
|
611
|
+
}, carry));
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Slow path: any row outside the viewport would resolve to a phantom
|
|
615
|
+
// all-null key via undefined valueForCell reads. Defer to async key fetch;
|
|
616
|
+
// IrisGrid's onSelectionChange handler picks up pendingRanges.
|
|
617
|
+
return new KeyedSelection(_objectSpread({
|
|
618
|
+
getModel: this.getModel,
|
|
619
|
+
pendingRanges: ranges
|
|
620
|
+
}, carry));
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Sets invertedSelection=true with an empty exclusion set (all rows selected).
|
|
624
|
+
selectAll() {
|
|
625
|
+
// Fresh inverted-all carrying cursor forward.
|
|
626
|
+
return KeyedSelection.empty(this.getModel).copyWith({
|
|
627
|
+
invertedSelection: true,
|
|
628
|
+
cursorKey: this.cursorKey,
|
|
629
|
+
cursorRowHint: this.cursorRowHint,
|
|
630
|
+
cursorColumn: this.cursorColumn
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
truncate(maxRows) {
|
|
634
|
+
if (maxRows === this.maxRows) return this;
|
|
635
|
+
return this.copyWith({
|
|
636
|
+
maxRows
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Builds a fully-resolved selection from async-fetched key values merged with the current selection, clearing pendingRanges.
|
|
642
|
+
*/
|
|
643
|
+
resolve(keyValues) {
|
|
644
|
+
var mergedKeys = new Set(this.selectedKeys);
|
|
645
|
+
var mergedKeyValues = new Map(this.selectedKeyValues);
|
|
646
|
+
keyValues.forEach((values, key) => {
|
|
647
|
+
mergedKeys.add(key);
|
|
648
|
+
mergedKeyValues.set(key, values);
|
|
649
|
+
});
|
|
650
|
+
return this.copyWith({
|
|
651
|
+
selectedKeys: mergedKeys,
|
|
652
|
+
overlayRanges: EMPTY_ARRAY,
|
|
653
|
+
invertedSelection: false,
|
|
654
|
+
selectedKeyValues: mergedKeyValues,
|
|
655
|
+
maxRows: null,
|
|
656
|
+
pendingRanges: EMPTY_ARRAY
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Returns the exact committed row count when each key maps to one row,
|
|
662
|
+
* or null when the count is unknown (non-unique keys or pending resolution).
|
|
663
|
+
* For inverted selections the count is approximate on ticking tables.
|
|
664
|
+
*/
|
|
665
|
+
getUniqueRowCount() {
|
|
666
|
+
if (this.pendingRanges.length > 0 || !this.getModel().hasUniqueSelectionKeys) {
|
|
667
|
+
return null;
|
|
668
|
+
}
|
|
669
|
+
if (this.invertedSelection) {
|
|
670
|
+
return this.getModel().rowCount - this.selectedKeys.size;
|
|
671
|
+
}
|
|
672
|
+
return this.selectedKeys.size;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/** Returns a new selection with the given row's key toggled. */
|
|
676
|
+
withToggledRow(row) {
|
|
677
|
+
var data = this.getRowKeyData(row);
|
|
678
|
+
if (data == null) return this;
|
|
679
|
+
var key = data.key,
|
|
680
|
+
values = data.values;
|
|
681
|
+
var next = new Set(this.selectedKeys);
|
|
682
|
+
var nextKeyValues = new Map(this.selectedKeyValues);
|
|
683
|
+
if (next.has(key)) {
|
|
684
|
+
next.delete(key);
|
|
685
|
+
nextKeyValues.delete(key);
|
|
686
|
+
} else {
|
|
687
|
+
next.add(key);
|
|
688
|
+
nextKeyValues.set(key, values);
|
|
689
|
+
}
|
|
690
|
+
return this.copyWith({
|
|
691
|
+
selectedKeys: next,
|
|
692
|
+
overlayRanges: EMPTY_ARRAY,
|
|
693
|
+
selectedKeyValues: nextKeyValues,
|
|
694
|
+
pendingRanges: EMPTY_ARRAY
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
export default KeyedSelection;
|
|
699
|
+
//# sourceMappingURL=KeyedSelection.js.map
|