@alaarab/ogrid-js 2.0.23 → 2.1.1
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/esm/OGrid.js +189 -503
- package/dist/esm/OGridEventWiring.js +178 -0
- package/dist/esm/OGridRendering.js +269 -0
- package/dist/esm/components/ColumnChooser.js +26 -3
- package/dist/esm/components/InlineCellEditor.js +18 -36
- package/dist/esm/index.js +2 -0
- package/dist/esm/renderer/TableRenderer.js +102 -61
- package/dist/esm/state/ClipboardState.js +8 -54
- package/dist/esm/state/ColumnPinningState.js +1 -2
- package/dist/esm/state/ColumnReorderState.js +8 -1
- package/dist/esm/state/EventEmitter.js +3 -2
- package/dist/esm/state/FillHandleState.js +27 -41
- package/dist/esm/state/GridState.js +36 -10
- package/dist/esm/state/HeaderFilterState.js +19 -11
- package/dist/esm/state/KeyboardNavState.js +19 -132
- package/dist/esm/state/RowSelectionState.js +6 -15
- package/dist/esm/state/SideBarState.js +1 -1
- package/dist/esm/state/TableLayoutState.js +6 -4
- package/dist/esm/utils/getCellCoordinates.js +15 -0
- package/dist/esm/utils/index.js +1 -0
- package/dist/types/OGrid.d.ts +97 -9
- package/dist/types/OGridEventWiring.d.ts +60 -0
- package/dist/types/OGridRendering.d.ts +93 -0
- package/dist/types/components/ColumnChooser.d.ts +5 -0
- package/dist/types/components/InlineCellEditor.d.ts +5 -0
- package/dist/types/index.d.ts +6 -1
- package/dist/types/renderer/TableRenderer.d.ts +12 -5
- package/dist/types/state/EventEmitter.d.ts +1 -1
- package/dist/types/state/FillHandleState.d.ts +1 -1
- package/dist/types/state/GridState.d.ts +7 -1
- package/dist/types/state/HeaderFilterState.d.ts +2 -0
- package/dist/types/types/gridTypes.d.ts +15 -0
- package/dist/types/utils/getCellCoordinates.d.ts +8 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/package.json +11 -4
package/dist/esm/OGrid.js
CHANGED
|
@@ -7,24 +7,22 @@ import { SideBarState } from './state/SideBarState';
|
|
|
7
7
|
import { SideBar } from './components/SideBar';
|
|
8
8
|
import { HeaderFilterState } from './state/HeaderFilterState';
|
|
9
9
|
import { HeaderFilter } from './components/HeaderFilter';
|
|
10
|
-
import { SelectionState } from './state/SelectionState';
|
|
11
|
-
import { KeyboardNavState } from './state/KeyboardNavState';
|
|
12
|
-
import { ClipboardState } from './state/ClipboardState';
|
|
13
|
-
import { UndoRedoState } from './state/UndoRedoState';
|
|
14
|
-
import { ColumnResizeState } from './state/ColumnResizeState';
|
|
15
10
|
import { TableLayoutState } from './state/TableLayoutState';
|
|
16
|
-
import { FillHandleState } from './state/FillHandleState';
|
|
17
11
|
import { RowSelectionState } from './state/RowSelectionState';
|
|
18
12
|
import { ColumnPinningState } from './state/ColumnPinningState';
|
|
19
|
-
import { ColumnReorderState } from './state/ColumnReorderState';
|
|
20
13
|
import { VirtualScrollState } from './state/VirtualScrollState';
|
|
21
|
-
import { MarchingAntsOverlay } from './components/MarchingAntsOverlay';
|
|
22
|
-
import { InlineCellEditor } from './components/InlineCellEditor';
|
|
23
|
-
import { ContextMenu } from './components/ContextMenu';
|
|
24
14
|
import { EventEmitter } from './state/EventEmitter';
|
|
25
|
-
import {
|
|
26
|
-
|
|
15
|
+
import { flattenColumns, injectGlobalStyles } from '@alaarab/ogrid-core';
|
|
16
|
+
import { OGridEventWiring } from './OGridEventWiring';
|
|
17
|
+
import { OGridRendering } from './OGridRendering';
|
|
18
|
+
/**
|
|
19
|
+
* CSS variable definitions for light and dark themes (injected once per page).
|
|
20
|
+
* NOTE: The dark theme variable block appears twice — once for [data-theme='dark'] and once
|
|
21
|
+
* for @media (prefers-color-scheme: dark). Both blocks must be kept in sync. If you change a
|
|
22
|
+
* dark-theme variable in one block, update the other block too.
|
|
23
|
+
*/
|
|
27
24
|
const OGRID_THEME_CSS = `
|
|
25
|
+
.ogrid-drag-target { box-shadow: inset 0 0 0 1px var(--ogrid-accent, #0078d4); }
|
|
28
26
|
:root {
|
|
29
27
|
--ogrid-bg: #ffffff;
|
|
30
28
|
--ogrid-fg: rgba(0, 0, 0, 0.87);
|
|
@@ -133,10 +131,10 @@ export class OGrid {
|
|
|
133
131
|
this.contextMenu = null;
|
|
134
132
|
this.events = new EventEmitter();
|
|
135
133
|
this.unsubscribes = [];
|
|
136
|
-
this.layoutVersion = 0; // Incremented when items, columns, sizing, or order change
|
|
137
134
|
this.options = options;
|
|
138
135
|
this.state = new GridState(options);
|
|
139
136
|
this.api = this.state.getApi();
|
|
137
|
+
this.eventWiringHelper = new OGridEventWiring();
|
|
140
138
|
// Inject theme CSS variables (light + dark) once per page
|
|
141
139
|
injectGlobalStyles('ogrid-theme-vars', OGRID_THEME_CSS);
|
|
142
140
|
// Build layout
|
|
@@ -186,343 +184,165 @@ export class OGrid {
|
|
|
186
184
|
});
|
|
187
185
|
this.headerFilterComponent = new HeaderFilter(this.headerFilterState);
|
|
188
186
|
this.buildFilterConfigs();
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
this.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.bodyArea
|
|
187
|
+
try {
|
|
188
|
+
// Pass filter config to renderer for filter icons in headers
|
|
189
|
+
this.renderer.setHeaderFilterState(this.headerFilterState, this.filterConfigs);
|
|
190
|
+
this.renderer.setOnFilterIconClick((columnId, headerEl) => {
|
|
191
|
+
this.handleFilterIconClick(columnId, headerEl);
|
|
192
|
+
});
|
|
193
|
+
// Initialize sidebar if configured
|
|
194
|
+
if (options.sideBar) {
|
|
195
|
+
this.sideBarState = new SideBarState(options.sideBar);
|
|
196
|
+
this.sideBarContainer = document.createElement('div');
|
|
197
|
+
this.sideBarContainer.className = 'ogrid-sidebar-container';
|
|
198
|
+
this.sideBarComponent = new SideBar(this.sideBarContainer, this.sideBarState);
|
|
199
|
+
if (this.bodyArea) {
|
|
200
|
+
if (this.sideBarState.position === 'left') {
|
|
201
|
+
this.bodyArea.insertBefore(this.sideBarContainer, this.tableContainer);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
this.bodyArea.appendChild(this.sideBarContainer);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
this.unsubscribes.push(this.sideBarState.onChange(() => {
|
|
208
|
+
this.renderingHelper.renderSideBar();
|
|
209
|
+
}));
|
|
202
210
|
}
|
|
203
|
-
|
|
204
|
-
|
|
211
|
+
// Initialize column pinning (always active, even without interaction)
|
|
212
|
+
const flatCols = flattenColumns(options.columns);
|
|
213
|
+
this.pinningState = new ColumnPinningState(options.pinnedColumns, flatCols);
|
|
214
|
+
// Initialize row selection (always active if rowSelection is set)
|
|
215
|
+
if (options.rowSelection && options.rowSelection !== 'none') {
|
|
216
|
+
this.rowSelectionState = new RowSelectionState(options.rowSelection, options.getRowId);
|
|
217
|
+
// Wire row selection API methods
|
|
218
|
+
this.api.getSelectedRows = () => {
|
|
219
|
+
return Array.from(this.rowSelectionState?.selectedRowIds ?? []);
|
|
220
|
+
};
|
|
221
|
+
this.api.selectAll = () => {
|
|
222
|
+
const { items } = this.state.getProcessedItems();
|
|
223
|
+
this.rowSelectionState?.handleSelectAll(true, items);
|
|
224
|
+
};
|
|
225
|
+
this.api.deselectAll = () => {
|
|
226
|
+
const { items } = this.state.getProcessedItems();
|
|
227
|
+
this.rowSelectionState?.handleSelectAll(false, items);
|
|
228
|
+
};
|
|
229
|
+
this.api.setSelectedRows = (rowIds) => {
|
|
230
|
+
const { items } = this.state.getProcessedItems();
|
|
231
|
+
this.rowSelectionState?.updateSelection(new Set(rowIds), items);
|
|
232
|
+
};
|
|
233
|
+
this.unsubscribes.push(this.rowSelectionState.onRowSelectionChange(() => {
|
|
234
|
+
this.renderingHelper.updateRendererInteractionState();
|
|
235
|
+
}));
|
|
205
236
|
}
|
|
206
|
-
|
|
207
|
-
|
|
237
|
+
// Create rendering helper (uses lazy context — state objects populated after interaction init)
|
|
238
|
+
this.renderingHelper = this.createRenderingHelper();
|
|
239
|
+
// Initial render (must happen before interaction init so wrapper DOM exists)
|
|
240
|
+
this.renderer.render();
|
|
241
|
+
// Initialize interaction features if enabled (default: true for cellSelection)
|
|
242
|
+
const shouldEnableInteraction = options.cellSelection !== false || options.editable === true;
|
|
243
|
+
if (shouldEnableInteraction) {
|
|
244
|
+
const result = this.eventWiringHelper.initializeInteraction(options, this.state, this.renderer, this.tableContainer, this.layoutState, this.rowSelectionState, this.pinningState, {
|
|
245
|
+
updateRendererInteractionState: () => this.renderingHelper.updateRendererInteractionState(),
|
|
246
|
+
updateDragAttributes: () => this.renderingHelper.updateDragAttributes(),
|
|
247
|
+
clearCachedDragCells: () => this.renderingHelper.clearCachedDragCells(),
|
|
248
|
+
showContextMenu: (x, y) => this.showContextMenu(x, y),
|
|
249
|
+
startCellEdit: (rowId, columnId) => this.startCellEdit(rowId, columnId),
|
|
250
|
+
});
|
|
251
|
+
// Store all created state objects
|
|
252
|
+
this.selectionState = result.selectionState;
|
|
253
|
+
this.keyboardNavState = result.keyboardNavState;
|
|
254
|
+
this.clipboardState = result.clipboardState;
|
|
255
|
+
this.undoRedoState = result.undoRedoState;
|
|
256
|
+
this.resizeState = result.resizeState;
|
|
257
|
+
this.fillHandleState = result.fillHandleState;
|
|
258
|
+
this.reorderState = result.reorderState;
|
|
259
|
+
this.marchingAnts = result.marchingAnts;
|
|
260
|
+
this.cellEditor = result.cellEditor;
|
|
261
|
+
this.contextMenu = result.contextMenu;
|
|
262
|
+
this.unsubscribes.push(...result.unsubscribes);
|
|
263
|
+
}
|
|
264
|
+
// Subscribe to state changes
|
|
265
|
+
this.unsubscribes.push(this.state.onStateChange(() => {
|
|
266
|
+
this.renderingHelper.renderAll();
|
|
208
267
|
}));
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
this.pinningState = new ColumnPinningState(options.pinnedColumns, flatCols);
|
|
213
|
-
// Initialize row selection (always active if rowSelection is set)
|
|
214
|
-
if (options.rowSelection && options.rowSelection !== 'none') {
|
|
215
|
-
this.rowSelectionState = new RowSelectionState(options.rowSelection, options.getRowId);
|
|
216
|
-
// Wire row selection API methods
|
|
217
|
-
this.api.getSelectedRows = () => {
|
|
218
|
-
return Array.from(this.rowSelectionState?.selectedRowIds ?? []);
|
|
219
|
-
};
|
|
220
|
-
this.api.selectAll = () => {
|
|
221
|
-
const { items } = this.state.getProcessedItems();
|
|
222
|
-
this.rowSelectionState?.handleSelectAll(true, items);
|
|
223
|
-
};
|
|
224
|
-
this.api.deselectAll = () => {
|
|
225
|
-
const { items } = this.state.getProcessedItems();
|
|
226
|
-
this.rowSelectionState?.handleSelectAll(false, items);
|
|
227
|
-
};
|
|
228
|
-
this.api.setSelectedRows = (rowIds) => {
|
|
229
|
-
const { items } = this.state.getProcessedItems();
|
|
230
|
-
this.rowSelectionState?.updateSelection(new Set(rowIds), items);
|
|
231
|
-
};
|
|
232
|
-
this.unsubscribes.push(this.rowSelectionState.onRowSelectionChange(() => {
|
|
233
|
-
this.updateRendererInteractionState();
|
|
268
|
+
// Subscribe to pinning changes
|
|
269
|
+
this.unsubscribes.push(this.pinningState.onPinningChange(() => {
|
|
270
|
+
this.renderingHelper.updateRendererInteractionState();
|
|
234
271
|
}));
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// Initialize interaction features if enabled (default: true for cellSelection)
|
|
239
|
-
const shouldEnableInteraction = options.cellSelection !== false || options.editable === true;
|
|
240
|
-
if (shouldEnableInteraction) {
|
|
241
|
-
this.initializeInteraction();
|
|
242
|
-
}
|
|
243
|
-
// Subscribe to state changes
|
|
244
|
-
this.unsubscribes.push(this.state.onStateChange(() => {
|
|
245
|
-
this.renderAll();
|
|
246
|
-
}));
|
|
247
|
-
// Subscribe to pinning changes
|
|
248
|
-
this.unsubscribes.push(this.pinningState.onPinningChange(() => {
|
|
249
|
-
this.updateRendererInteractionState();
|
|
250
|
-
}));
|
|
251
|
-
// Subscribe to header filter state changes
|
|
252
|
-
this.unsubscribes.push(this.headerFilterState.onChange(() => {
|
|
253
|
-
this.renderHeaderFilterPopover();
|
|
254
|
-
}));
|
|
255
|
-
// Initialize virtual scrolling if configured
|
|
256
|
-
if (options.virtualScroll?.enabled) {
|
|
257
|
-
this.virtualScrollState = new VirtualScrollState(options.virtualScroll);
|
|
258
|
-
this.virtualScrollState.observeContainer(this.tableContainer);
|
|
259
|
-
this.renderer.setVirtualScrollState(this.virtualScrollState);
|
|
260
|
-
// Wire scroll event on the table container
|
|
261
|
-
const handleScroll = () => {
|
|
262
|
-
this.virtualScrollState?.handleScroll(this.tableContainer.scrollTop);
|
|
263
|
-
};
|
|
264
|
-
this.tableContainer.addEventListener('scroll', handleScroll, { passive: true });
|
|
265
|
-
this.unsubscribes.push(() => {
|
|
266
|
-
this.tableContainer.removeEventListener('scroll', handleScroll);
|
|
267
|
-
});
|
|
268
|
-
// Re-render when visible range changes
|
|
269
|
-
this.unsubscribes.push(this.virtualScrollState.onRangeChanged(() => {
|
|
270
|
-
this.updateRendererInteractionState();
|
|
272
|
+
// Subscribe to header filter state changes
|
|
273
|
+
this.unsubscribes.push(this.headerFilterState.onChange(() => {
|
|
274
|
+
this.renderingHelper.renderHeaderFilterPopover();
|
|
271
275
|
}));
|
|
272
|
-
//
|
|
273
|
-
|
|
274
|
-
this.virtualScrollState
|
|
275
|
-
|
|
276
|
+
// Initialize virtual scrolling if configured
|
|
277
|
+
if (options.virtualScroll?.enabled) {
|
|
278
|
+
this.virtualScrollState = new VirtualScrollState(options.virtualScroll);
|
|
279
|
+
this.virtualScrollState.observeContainer(this.tableContainer);
|
|
280
|
+
this.renderer.setVirtualScrollState(this.virtualScrollState);
|
|
281
|
+
// Wire scroll event on the table container
|
|
282
|
+
const handleScroll = () => {
|
|
283
|
+
this.virtualScrollState?.handleScroll(this.tableContainer.scrollTop);
|
|
284
|
+
};
|
|
285
|
+
this.tableContainer.addEventListener('scroll', handleScroll, { passive: true });
|
|
286
|
+
this.unsubscribes.push(() => {
|
|
287
|
+
this.tableContainer.removeEventListener('scroll', handleScroll);
|
|
288
|
+
});
|
|
289
|
+
// Re-render when visible range changes
|
|
290
|
+
this.unsubscribes.push(this.virtualScrollState.onRangeChanged(() => {
|
|
291
|
+
this.renderingHelper.updateRendererInteractionState();
|
|
292
|
+
}));
|
|
293
|
+
// Wire scrollToRow API method
|
|
294
|
+
this.api.scrollToRow = (index, opts) => {
|
|
295
|
+
this.virtualScrollState?.scrollToRow(index, this.tableContainer, opts?.align);
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
// Complete initial render (pagination, status bar, column chooser, sidebar, loading)
|
|
299
|
+
this.renderingHelper.renderAll();
|
|
276
300
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
initializeInteraction() {
|
|
281
|
-
const { editable } = this.options;
|
|
282
|
-
const colOffset = this.rowSelectionState ? 1 : 0;
|
|
283
|
-
// Create interaction states
|
|
284
|
-
this.selectionState = new SelectionState();
|
|
285
|
-
this.resizeState = new ColumnResizeState();
|
|
286
|
-
this.contextMenu = new ContextMenu();
|
|
287
|
-
this.cellEditor = new InlineCellEditor(this.tableContainer);
|
|
288
|
-
// Undo/Redo (wraps onCellValueChanged if editable)
|
|
289
|
-
const onCellValueChanged = this.options.onCellValueChanged;
|
|
290
|
-
this.undoRedoState = new UndoRedoState(onCellValueChanged);
|
|
291
|
-
// Clipboard
|
|
292
|
-
this.clipboardState = new ClipboardState({
|
|
293
|
-
items: [],
|
|
294
|
-
visibleCols: [],
|
|
295
|
-
colOffset,
|
|
296
|
-
editable,
|
|
297
|
-
onCellValueChanged: this.undoRedoState.getWrappedCallback(),
|
|
298
|
-
}, () => this.selectionState?.activeCell ?? null, () => this.selectionState?.selectionRange ?? null);
|
|
299
|
-
// Fill handle
|
|
300
|
-
this.fillHandleState = new FillHandleState({
|
|
301
|
-
items: [],
|
|
302
|
-
visibleCols: [],
|
|
303
|
-
editable,
|
|
304
|
-
onCellValueChanged: this.undoRedoState.getWrappedCallback(),
|
|
305
|
-
colOffset,
|
|
306
|
-
beginBatch: () => this.undoRedoState?.beginBatch(),
|
|
307
|
-
endBatch: () => this.undoRedoState?.endBatch(),
|
|
308
|
-
}, () => this.selectionState?.selectionRange ?? null, (range) => {
|
|
309
|
-
this.selectionState?.setSelectionRange(range);
|
|
310
|
-
this.updateRendererInteractionState();
|
|
311
|
-
}, (cell) => {
|
|
312
|
-
this.selectionState?.setActiveCell(cell);
|
|
313
|
-
});
|
|
314
|
-
// Keyboard navigation
|
|
315
|
-
this.keyboardNavState = new KeyboardNavState({
|
|
316
|
-
items: [],
|
|
317
|
-
visibleCols: [],
|
|
318
|
-
colOffset,
|
|
319
|
-
getRowId: this.state.getRowId,
|
|
320
|
-
editable,
|
|
321
|
-
onCellValueChanged: this.undoRedoState.getWrappedCallback(),
|
|
322
|
-
onCopy: () => this.clipboardState?.handleCopy(),
|
|
323
|
-
onCut: () => this.clipboardState?.handleCut(),
|
|
324
|
-
onPaste: async () => { await this.clipboardState?.handlePaste(); },
|
|
325
|
-
onUndo: () => this.undoRedoState?.undo(),
|
|
326
|
-
onRedo: () => this.undoRedoState?.redo(),
|
|
327
|
-
onContextMenu: (x, y) => this.showContextMenu(x, y),
|
|
328
|
-
onStartEdit: (rowId, columnId) => this.startCellEdit(rowId, columnId),
|
|
329
|
-
clearClipboardRanges: () => this.clipboardState?.clearClipboardRanges(),
|
|
330
|
-
}, () => this.selectionState?.activeCell ?? null, () => this.selectionState?.selectionRange ?? null, (cell) => this.selectionState?.setActiveCell(cell), (range) => this.selectionState?.setSelectionRange(range));
|
|
331
|
-
// Subscribe to selection changes
|
|
332
|
-
this.unsubscribes.push(this.selectionState.onSelectionChange(() => {
|
|
333
|
-
this.updateRendererInteractionState();
|
|
334
|
-
}));
|
|
335
|
-
// Subscribe to clipboard range changes
|
|
336
|
-
this.unsubscribes.push(this.clipboardState.onRangesChange(() => {
|
|
337
|
-
this.updateRendererInteractionState();
|
|
338
|
-
}));
|
|
339
|
-
// Subscribe to column resize changes
|
|
340
|
-
this.unsubscribes.push(this.resizeState.onColumnWidthChange(() => {
|
|
341
|
-
this.updateRendererInteractionState();
|
|
342
|
-
}));
|
|
343
|
-
// Column reorder
|
|
344
|
-
this.reorderState = new ColumnReorderState();
|
|
345
|
-
this.unsubscribes.push(this.reorderState.onStateChange(({ isDragging, dropIndicatorX }) => {
|
|
346
|
-
this.renderer.updateDropIndicator(dropIndicatorX, isDragging);
|
|
347
|
-
}));
|
|
348
|
-
this.unsubscribes.push(this.reorderState.onReorder(({ columnOrder }) => {
|
|
349
|
-
this.state.setColumnOrder(columnOrder);
|
|
350
|
-
}));
|
|
351
|
-
// Attach keyboard handler to wrapper
|
|
352
|
-
const wrapper = this.renderer.getWrapperElement();
|
|
353
|
-
if (wrapper) {
|
|
354
|
-
wrapper.addEventListener('keydown', this.keyboardNavState.handleKeyDown);
|
|
355
|
-
this.keyboardNavState.setWrapperRef(wrapper);
|
|
356
|
-
this.fillHandleState.setWrapperRef(wrapper);
|
|
357
|
-
// Initialize marching ants overlay
|
|
358
|
-
this.marchingAnts = new MarchingAntsOverlay(wrapper, colOffset);
|
|
301
|
+
catch (e) {
|
|
302
|
+
this.destroy();
|
|
303
|
+
throw e;
|
|
359
304
|
}
|
|
360
|
-
// Attach global mouse handlers for resize and drag
|
|
361
|
-
this.attachGlobalHandlers();
|
|
362
|
-
// Set initial interaction state on renderer
|
|
363
|
-
this.updateRendererInteractionState();
|
|
364
305
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
const handleMouseUp = (e) => {
|
|
387
|
-
if (resizing && this.resizeState) {
|
|
388
|
-
const colId = this.resizeState.resizingColumnId;
|
|
389
|
-
this.resizeState.endResize(e.clientX);
|
|
390
|
-
if (colId) {
|
|
391
|
-
const width = this.resizeState.getColumnWidth(colId);
|
|
392
|
-
if (width)
|
|
393
|
-
this.layoutState.setColumnOverride(colId, width);
|
|
394
|
-
}
|
|
395
|
-
resizing = false;
|
|
396
|
-
document.body.style.cursor = '';
|
|
397
|
-
this.updateRendererInteractionState();
|
|
398
|
-
}
|
|
399
|
-
if (this.selectionState?.isDragging) {
|
|
400
|
-
this.selectionState.endDrag();
|
|
401
|
-
}
|
|
402
|
-
};
|
|
403
|
-
const handleResizeStart = (columnId, clientX, currentWidth) => {
|
|
404
|
-
resizing = true;
|
|
405
|
-
document.body.style.cursor = 'col-resize';
|
|
406
|
-
this.resizeState?.startResize(columnId, clientX, currentWidth);
|
|
306
|
+
/** Creates the OGridRenderingContext that bridges OGrid state to the rendering helper. */
|
|
307
|
+
createRenderingHelper() {
|
|
308
|
+
const liveGetter = (getter) => ({ get: getter, enumerable: true, configurable: true });
|
|
309
|
+
const ctx = {
|
|
310
|
+
options: this.options,
|
|
311
|
+
state: this.state,
|
|
312
|
+
renderer: this.renderer,
|
|
313
|
+
pagination: this.pagination,
|
|
314
|
+
statusBar: this.statusBar,
|
|
315
|
+
columnChooser: this.columnChooser,
|
|
316
|
+
layoutState: this.layoutState,
|
|
317
|
+
tableContainer: this.tableContainer,
|
|
318
|
+
headerFilterState: this.headerFilterState,
|
|
319
|
+
headerFilterComponent: this.headerFilterComponent,
|
|
320
|
+
filterConfigs: this.filterConfigs,
|
|
321
|
+
setLoadingOverlay: (el) => { this.loadingOverlay = el; },
|
|
322
|
+
handleCellClick: (rowIndex, colIndex) => this.handleCellClick(rowIndex, colIndex),
|
|
323
|
+
handleCellMouseDown: (rowIndex, colIndex, e) => this.handleCellMouseDown(rowIndex, colIndex, e),
|
|
324
|
+
handleCellContextMenu: (rowIndex, colIndex, e) => this.handleCellContextMenu(rowIndex, colIndex, e),
|
|
325
|
+
startCellEdit: (rowId, columnId) => this.startCellEdit(rowId, columnId),
|
|
326
|
+
showContextMenu: (x, y) => this.showContextMenu(x, y),
|
|
407
327
|
};
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
328
|
+
Object.defineProperties(ctx, {
|
|
329
|
+
selectionState: liveGetter(() => this.selectionState),
|
|
330
|
+
keyboardNavState: liveGetter(() => this.keyboardNavState),
|
|
331
|
+
clipboardState: liveGetter(() => this.clipboardState),
|
|
332
|
+
undoRedoState: liveGetter(() => this.undoRedoState),
|
|
333
|
+
resizeState: liveGetter(() => this.resizeState),
|
|
334
|
+
fillHandleState: liveGetter(() => this.fillHandleState),
|
|
335
|
+
rowSelectionState: liveGetter(() => this.rowSelectionState),
|
|
336
|
+
pinningState: liveGetter(() => this.pinningState),
|
|
337
|
+
reorderState: liveGetter(() => this.reorderState),
|
|
338
|
+
virtualScrollState: liveGetter(() => this.virtualScrollState),
|
|
339
|
+
marchingAnts: liveGetter(() => this.marchingAnts),
|
|
340
|
+
cellEditor: liveGetter(() => this.cellEditor),
|
|
341
|
+
sideBarState: liveGetter(() => this.sideBarState),
|
|
342
|
+
sideBarComponent: liveGetter(() => this.sideBarComponent),
|
|
343
|
+
loadingOverlay: liveGetter(() => this.loadingOverlay),
|
|
424
344
|
});
|
|
425
|
-
|
|
426
|
-
updateRendererInteractionState() {
|
|
427
|
-
if (!this.selectionState || !this.clipboardState || !this.resizeState)
|
|
428
|
-
return;
|
|
429
|
-
const { items } = this.state.getProcessedItems();
|
|
430
|
-
const visibleCols = this.state.visibleColumnDefs;
|
|
431
|
-
// Compute pinning offsets
|
|
432
|
-
const columnWidths = this.layoutState.getAllColumnWidths();
|
|
433
|
-
const leftOffsets = this.pinningState?.computeLeftOffsets(visibleCols, columnWidths, 120, !!this.rowSelectionState, 40, !!this.options.showRowNumbers) ?? {};
|
|
434
|
-
const rightOffsets = this.pinningState?.computeRightOffsets(visibleCols, columnWidths, 120) ?? {};
|
|
435
|
-
this.renderer.setInteractionState({
|
|
436
|
-
activeCell: this.selectionState.activeCell,
|
|
437
|
-
selectionRange: this.selectionState.selectionRange,
|
|
438
|
-
copyRange: this.clipboardState.copyRange,
|
|
439
|
-
cutRange: this.clipboardState.cutRange,
|
|
440
|
-
editingCell: this.cellEditor?.getEditingCell() ?? null,
|
|
441
|
-
columnWidths,
|
|
442
|
-
onCellClick: (rowIndex, colIndex) => this.handleCellClick(rowIndex, colIndex),
|
|
443
|
-
onCellMouseDown: (rowIndex, colIndex, e) => this.handleCellMouseDown(rowIndex, colIndex, e),
|
|
444
|
-
onCellDoubleClick: (rowIndex, colIndex, rowId, columnId) => this.startCellEdit(rowId, columnId),
|
|
445
|
-
onCellContextMenu: (rowIndex, colIndex, e) => this.handleCellContextMenu(rowIndex, colIndex, e),
|
|
446
|
-
onResizeStart: this.renderer['interactionState']?.onResizeStart,
|
|
447
|
-
// Fill handle
|
|
448
|
-
onFillHandleMouseDown: this.options.editable !== false ? (e) => this.fillHandleState?.startFillDrag(e) : undefined,
|
|
449
|
-
// Row selection
|
|
450
|
-
rowSelectionMode: this.rowSelectionState?.rowSelection ?? 'none',
|
|
451
|
-
selectedRowIds: this.rowSelectionState?.selectedRowIds,
|
|
452
|
-
onRowCheckboxChange: (rowId, checked, rowIndex, shiftKey) => {
|
|
453
|
-
this.rowSelectionState?.handleRowCheckboxChange(rowId, checked, rowIndex, shiftKey, items);
|
|
454
|
-
},
|
|
455
|
-
onSelectAll: (checked) => {
|
|
456
|
-
this.rowSelectionState?.handleSelectAll(checked, items);
|
|
457
|
-
},
|
|
458
|
-
allSelected: this.rowSelectionState?.isAllSelected(items),
|
|
459
|
-
someSelected: this.rowSelectionState?.isSomeSelected(items),
|
|
460
|
-
// Row numbers
|
|
461
|
-
showRowNumbers: this.options.showRowNumbers,
|
|
462
|
-
// Column pinning
|
|
463
|
-
pinnedColumns: this.pinningState?.pinnedColumns,
|
|
464
|
-
leftOffsets,
|
|
465
|
-
rightOffsets,
|
|
466
|
-
// Column reorder
|
|
467
|
-
onColumnReorderStart: this.reorderState ? (columnId, event) => {
|
|
468
|
-
const tableEl = this.renderer.getTableElement();
|
|
469
|
-
if (!tableEl)
|
|
470
|
-
return;
|
|
471
|
-
this.reorderState?.startDrag(columnId, event, visibleCols, this.state.columnOrder, this.pinningState?.pinnedColumns, tableEl);
|
|
472
|
-
} : undefined,
|
|
473
|
-
});
|
|
474
|
-
this.renderer.update();
|
|
475
|
-
// Update marching ants overlay
|
|
476
|
-
this.marchingAnts?.update(this.selectionState.selectionRange, this.clipboardState.copyRange, this.clipboardState.cutRange, this.layoutVersion);
|
|
477
|
-
}
|
|
478
|
-
updateDragAttributes() {
|
|
479
|
-
const wrapper = this.renderer.getWrapperElement();
|
|
480
|
-
if (!wrapper || !this.selectionState)
|
|
481
|
-
return;
|
|
482
|
-
const range = this.selectionState.getDragRange();
|
|
483
|
-
if (!range)
|
|
484
|
-
return;
|
|
485
|
-
const norm = normalizeSelectionRange(range);
|
|
486
|
-
const anchor = this.selectionState.dragAnchor;
|
|
487
|
-
const minR = norm.startRow;
|
|
488
|
-
const maxR = norm.endRow;
|
|
489
|
-
const minC = norm.startCol;
|
|
490
|
-
const maxC = norm.endCol;
|
|
491
|
-
const cells = wrapper.querySelectorAll('td[data-row-index][data-col-index]');
|
|
492
|
-
for (let _i = 0; _i < cells.length; _i++) {
|
|
493
|
-
const cell = cells[_i];
|
|
494
|
-
const el = cell;
|
|
495
|
-
const rowIndex = parseInt(el.getAttribute('data-row-index') ?? '-1', 10);
|
|
496
|
-
const colIndex = parseInt(el.getAttribute('data-col-index') ?? '-1', 10);
|
|
497
|
-
if (isInSelectionRange(norm, rowIndex, colIndex)) {
|
|
498
|
-
el.setAttribute('data-drag-range', 'true');
|
|
499
|
-
// Anchor cell (white background)
|
|
500
|
-
const isAnchor = anchor && rowIndex === anchor.rowIndex && colIndex === anchor.columnIndex;
|
|
501
|
-
if (isAnchor) {
|
|
502
|
-
el.setAttribute('data-drag-anchor', '');
|
|
503
|
-
}
|
|
504
|
-
else {
|
|
505
|
-
el.removeAttribute('data-drag-anchor');
|
|
506
|
-
}
|
|
507
|
-
// Edge borders via inset box-shadow
|
|
508
|
-
const shadows = [];
|
|
509
|
-
if (rowIndex === minR)
|
|
510
|
-
shadows.push('inset 0 2px 0 0 var(--ogrid-selection, #217346)');
|
|
511
|
-
if (rowIndex === maxR)
|
|
512
|
-
shadows.push('inset 0 -2px 0 0 var(--ogrid-selection, #217346)');
|
|
513
|
-
if (colIndex === minC)
|
|
514
|
-
shadows.push('inset 2px 0 0 0 var(--ogrid-selection, #217346)');
|
|
515
|
-
if (colIndex === maxC)
|
|
516
|
-
shadows.push('inset -2px 0 0 0 var(--ogrid-selection, #217346)');
|
|
517
|
-
el.style.boxShadow = shadows.length > 0 ? shadows.join(', ') : '';
|
|
518
|
-
}
|
|
519
|
-
else {
|
|
520
|
-
el.removeAttribute('data-drag-range');
|
|
521
|
-
el.removeAttribute('data-drag-anchor');
|
|
522
|
-
if (el.style.boxShadow)
|
|
523
|
-
el.style.boxShadow = '';
|
|
524
|
-
}
|
|
525
|
-
}
|
|
345
|
+
return new OGridRendering(ctx);
|
|
526
346
|
}
|
|
527
347
|
handleCellClick(rowIndex, colIndex) {
|
|
528
348
|
if (!this.selectionState)
|
|
@@ -537,7 +357,7 @@ export class OGrid {
|
|
|
537
357
|
e.preventDefault();
|
|
538
358
|
this.selectionState.startDrag(rowIndex, colIndex);
|
|
539
359
|
// Apply drag attributes immediately for instant visual feedback on the initial cell
|
|
540
|
-
setTimeout(() => this.updateDragAttributes(), 0);
|
|
360
|
+
setTimeout(() => this.renderingHelper.updateDragAttributes(), 0);
|
|
541
361
|
}
|
|
542
362
|
handleCellContextMenu(rowIndex, colIndex, e) {
|
|
543
363
|
e.preventDefault();
|
|
@@ -546,7 +366,7 @@ export class OGrid {
|
|
|
546
366
|
// Set active cell if not already set
|
|
547
367
|
if (!this.selectionState.activeCell || this.selectionState.activeCell.rowIndex !== rowIndex || this.selectionState.activeCell.columnIndex !== colIndex) {
|
|
548
368
|
this.selectionState.setActiveCell({ rowIndex, columnIndex: colIndex });
|
|
549
|
-
this.updateRendererInteractionState();
|
|
369
|
+
this.renderingHelper.updateRendererInteractionState();
|
|
550
370
|
}
|
|
551
371
|
this.showContextMenu(e.clientX, e.clientY);
|
|
552
372
|
}
|
|
@@ -554,24 +374,24 @@ export class OGrid {
|
|
|
554
374
|
if (!this.contextMenu || !this.clipboardState || !this.undoRedoState || !this.keyboardNavState || !this.selectionState)
|
|
555
375
|
return;
|
|
556
376
|
this.contextMenu.show(x, y, {
|
|
557
|
-
onCopy: () => this.clipboardState
|
|
558
|
-
onCut: () => this.clipboardState
|
|
559
|
-
onPaste: () => void this.clipboardState
|
|
377
|
+
onCopy: () => this.clipboardState?.handleCopy(),
|
|
378
|
+
onCut: () => this.clipboardState?.handleCut(),
|
|
379
|
+
onPaste: () => void this.clipboardState?.handlePaste(),
|
|
560
380
|
onSelectAll: () => {
|
|
561
381
|
const { items } = this.state.getProcessedItems();
|
|
562
382
|
const visibleCols = this.state.visibleColumnDefs;
|
|
563
383
|
if (items.length > 0 && visibleCols.length > 0) {
|
|
564
|
-
this.selectionState
|
|
384
|
+
this.selectionState?.setSelectionRange({
|
|
565
385
|
startRow: 0,
|
|
566
386
|
startCol: 0,
|
|
567
387
|
endRow: items.length - 1,
|
|
568
388
|
endCol: visibleCols.length - 1,
|
|
569
389
|
});
|
|
570
|
-
this.updateRendererInteractionState();
|
|
390
|
+
this.renderingHelper.updateRendererInteractionState();
|
|
571
391
|
}
|
|
572
392
|
},
|
|
573
|
-
onUndo: () => this.undoRedoState
|
|
574
|
-
onRedo: () => this.undoRedoState
|
|
393
|
+
onUndo: () => this.undoRedoState?.undo(),
|
|
394
|
+
onRedo: () => this.undoRedoState?.redo(),
|
|
575
395
|
}, this.undoRedoState.canUndo, this.undoRedoState.canRedo, this.selectionState.selectionRange);
|
|
576
396
|
}
|
|
577
397
|
startCellEdit(rowId, columnId) {
|
|
@@ -593,27 +413,30 @@ export class OGrid {
|
|
|
593
413
|
const cell = row.querySelector(`td[data-column-id="${columnId}"]`);
|
|
594
414
|
if (!cell)
|
|
595
415
|
return;
|
|
596
|
-
const
|
|
597
|
-
|
|
416
|
+
const rowIndex = items.indexOf(item);
|
|
417
|
+
const onCommit = (_rid, cid, value) => {
|
|
418
|
+
// Use the already-resolved item and look up the committed column
|
|
598
419
|
const col = visibleCols.find((c) => c.columnId === cid);
|
|
599
|
-
if (!
|
|
420
|
+
if (!col)
|
|
600
421
|
return;
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
const
|
|
422
|
+
// NOTE: Direct mutation on the item reference. This updates the in-memory data
|
|
423
|
+
// so subsequent renders reflect the new value before the consumer calls setRowData.
|
|
424
|
+
const oldValue = item[cid];
|
|
425
|
+
item[cid] = value;
|
|
426
|
+
const wrapped = this.undoRedoState?.getWrappedCallback();
|
|
604
427
|
if (wrapped) {
|
|
605
428
|
wrapped({
|
|
606
|
-
item
|
|
429
|
+
item,
|
|
607
430
|
columnId: cid,
|
|
608
431
|
oldValue,
|
|
609
432
|
newValue: value,
|
|
610
|
-
rowIndex
|
|
433
|
+
rowIndex,
|
|
611
434
|
});
|
|
612
435
|
}
|
|
613
|
-
this.updateRendererInteractionState();
|
|
436
|
+
this.renderingHelper.updateRendererInteractionState();
|
|
614
437
|
};
|
|
615
438
|
const onCancel = () => {
|
|
616
|
-
this.updateRendererInteractionState();
|
|
439
|
+
this.renderingHelper.updateRendererInteractionState();
|
|
617
440
|
};
|
|
618
441
|
const onAfterCommit = () => {
|
|
619
442
|
// After Enter-commit, move the active cell down one row (Excel-style behavior)
|
|
@@ -666,150 +489,13 @@ export class OGrid {
|
|
|
666
489
|
this.headerFilterState.setFilterOptions(this.state.filterOptions);
|
|
667
490
|
this.headerFilterState.open(columnId, config, headerEl, tempPopover);
|
|
668
491
|
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
if (!config)
|
|
677
|
-
return;
|
|
678
|
-
this.headerFilterComponent.render(config);
|
|
679
|
-
// Update the popover element reference for click-outside detection
|
|
680
|
-
const popoverEl = document.querySelector('.ogrid-header-filter-popover');
|
|
681
|
-
if (popoverEl) {
|
|
682
|
-
this.headerFilterState._popoverEl = popoverEl;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
renderSideBar() {
|
|
686
|
-
if (!this.sideBarComponent || !this.sideBarState)
|
|
687
|
-
return;
|
|
688
|
-
const columns = this.state.columns.map(c => ({
|
|
689
|
-
columnId: c.columnId,
|
|
690
|
-
name: c.name,
|
|
691
|
-
required: c.required === true,
|
|
692
|
-
}));
|
|
693
|
-
const filterableColumns = this.state.columns
|
|
694
|
-
.filter(c => c.filterable && typeof c.filterable === 'object' && c.filterable.type)
|
|
695
|
-
.map(c => ({
|
|
696
|
-
columnId: c.columnId,
|
|
697
|
-
name: c.name,
|
|
698
|
-
filterField: c.filterable.filterField ?? c.columnId,
|
|
699
|
-
filterType: c.filterable.type,
|
|
700
|
-
}));
|
|
701
|
-
this.sideBarComponent.setConfig({
|
|
702
|
-
columns,
|
|
703
|
-
visibleColumns: this.state.visibleColumns,
|
|
704
|
-
onVisibilityChange: (columnKey, visible) => {
|
|
705
|
-
const next = new Set(this.state.visibleColumns);
|
|
706
|
-
if (visible)
|
|
707
|
-
next.add(columnKey);
|
|
708
|
-
else
|
|
709
|
-
next.delete(columnKey);
|
|
710
|
-
this.state.setVisibleColumns(next);
|
|
711
|
-
},
|
|
712
|
-
onSetVisibleColumns: (cols) => this.state.setVisibleColumns(cols),
|
|
713
|
-
filterableColumns,
|
|
714
|
-
filters: this.state.filters,
|
|
715
|
-
onFilterChange: (key, value) => this.state.setFilter(key, value),
|
|
716
|
-
filterOptions: this.state.filterOptions,
|
|
717
|
-
});
|
|
718
|
-
this.sideBarComponent.render();
|
|
719
|
-
}
|
|
720
|
-
renderLoadingOverlay() {
|
|
721
|
-
if (this.state.isLoading) {
|
|
722
|
-
// Ensure the container has minimum height during loading so overlay is visible
|
|
723
|
-
const { items } = this.state.getProcessedItems();
|
|
724
|
-
this.tableContainer.style.minHeight = (!items || items.length === 0) ? '200px' : '';
|
|
725
|
-
if (!this.loadingOverlay) {
|
|
726
|
-
this.loadingOverlay = document.createElement('div');
|
|
727
|
-
this.loadingOverlay.className = 'ogrid-loading-overlay';
|
|
728
|
-
this.loadingOverlay.style.position = 'absolute';
|
|
729
|
-
this.loadingOverlay.style.top = '0';
|
|
730
|
-
this.loadingOverlay.style.left = '0';
|
|
731
|
-
this.loadingOverlay.style.right = '0';
|
|
732
|
-
this.loadingOverlay.style.bottom = '0';
|
|
733
|
-
this.loadingOverlay.style.display = 'flex';
|
|
734
|
-
this.loadingOverlay.style.alignItems = 'center';
|
|
735
|
-
this.loadingOverlay.style.justifyContent = 'center';
|
|
736
|
-
this.loadingOverlay.style.background = 'var(--ogrid-loading-overlay, rgba(255, 255, 255, 0.7))';
|
|
737
|
-
this.loadingOverlay.style.zIndex = '100';
|
|
738
|
-
const spinner = document.createElement('div');
|
|
739
|
-
spinner.className = 'ogrid-loading-spinner';
|
|
740
|
-
spinner.textContent = 'Loading...';
|
|
741
|
-
this.loadingOverlay.appendChild(spinner);
|
|
742
|
-
}
|
|
743
|
-
if (!this.tableContainer.contains(this.loadingOverlay)) {
|
|
744
|
-
this.tableContainer.appendChild(this.loadingOverlay);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
else {
|
|
748
|
-
this.tableContainer.style.minHeight = '';
|
|
749
|
-
if (this.loadingOverlay && this.tableContainer.contains(this.loadingOverlay)) {
|
|
750
|
-
this.loadingOverlay.remove();
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
renderAll() {
|
|
755
|
-
// Increment layout version to trigger marching ants re-measurement
|
|
756
|
-
this.layoutVersion++;
|
|
757
|
-
const colOffset = this.rowSelectionState ? 1 : 0;
|
|
758
|
-
// Update header filter state with current filters and options
|
|
759
|
-
this.headerFilterState.setFilters(this.state.filters);
|
|
760
|
-
this.headerFilterState.setFilterOptions(this.state.filterOptions);
|
|
761
|
-
// Update interaction states with current data
|
|
762
|
-
if (this.keyboardNavState && this.clipboardState) {
|
|
763
|
-
const { items } = this.state.getProcessedItems();
|
|
764
|
-
const visibleCols = this.state.visibleColumnDefs;
|
|
765
|
-
this.keyboardNavState.updateParams({
|
|
766
|
-
items,
|
|
767
|
-
visibleCols: visibleCols,
|
|
768
|
-
colOffset,
|
|
769
|
-
getRowId: this.state.getRowId,
|
|
770
|
-
editable: this.options.editable,
|
|
771
|
-
onCellValueChanged: this.undoRedoState?.getWrappedCallback(),
|
|
772
|
-
onCopy: () => this.clipboardState?.handleCopy(),
|
|
773
|
-
onCut: () => this.clipboardState?.handleCut(),
|
|
774
|
-
onPaste: async () => { await this.clipboardState?.handlePaste(); },
|
|
775
|
-
onUndo: () => this.undoRedoState?.undo(),
|
|
776
|
-
onRedo: () => this.undoRedoState?.redo(),
|
|
777
|
-
onContextMenu: (x, y) => this.showContextMenu(x, y),
|
|
778
|
-
onStartEdit: (rowId, columnId) => this.startCellEdit(rowId, columnId),
|
|
779
|
-
clearClipboardRanges: () => this.clipboardState?.clearClipboardRanges(),
|
|
780
|
-
});
|
|
781
|
-
this.clipboardState.updateParams({
|
|
782
|
-
items,
|
|
783
|
-
visibleCols: visibleCols,
|
|
784
|
-
colOffset,
|
|
785
|
-
editable: this.options.editable,
|
|
786
|
-
onCellValueChanged: this.undoRedoState?.getWrappedCallback(),
|
|
787
|
-
});
|
|
788
|
-
// Update fill handle params
|
|
789
|
-
this.fillHandleState?.updateParams({
|
|
790
|
-
items,
|
|
791
|
-
visibleCols: visibleCols,
|
|
792
|
-
editable: this.options.editable,
|
|
793
|
-
onCellValueChanged: this.undoRedoState?.getWrappedCallback(),
|
|
794
|
-
colOffset,
|
|
795
|
-
beginBatch: () => this.undoRedoState?.beginBatch(),
|
|
796
|
-
endBatch: () => this.undoRedoState?.endBatch(),
|
|
797
|
-
});
|
|
798
|
-
// Update renderer interaction state before rendering
|
|
799
|
-
this.updateRendererInteractionState();
|
|
800
|
-
}
|
|
801
|
-
else {
|
|
802
|
-
this.renderer.update();
|
|
803
|
-
}
|
|
804
|
-
const { totalCount } = this.state.getProcessedItems();
|
|
805
|
-
// Update virtual scroll with current total row count
|
|
806
|
-
this.virtualScrollState?.setTotalRows(totalCount);
|
|
807
|
-
this.pagination.render(totalCount, this.options.pageSizeOptions);
|
|
808
|
-
this.statusBar.render({ totalCount });
|
|
809
|
-
this.columnChooser.render();
|
|
810
|
-
this.renderSideBar();
|
|
811
|
-
this.renderLoadingOverlay();
|
|
812
|
-
}
|
|
492
|
+
// Rendering methods delegated to OGridRendering helper:
|
|
493
|
+
// - updateRendererInteractionState() -> this.renderingHelper.updateRendererInteractionState()
|
|
494
|
+
// - updateDragAttributes() -> this.renderingHelper.updateDragAttributes()
|
|
495
|
+
// - renderAll() -> this.renderingHelper.renderAll()
|
|
496
|
+
// - renderHeaderFilterPopover() -> this.renderingHelper.renderHeaderFilterPopover()
|
|
497
|
+
// - renderSideBar() -> this.renderingHelper.renderSideBar()
|
|
498
|
+
// - renderLoadingOverlay() -> this.renderingHelper.renderLoadingOverlay()
|
|
813
499
|
/** Subscribe to grid events. */
|
|
814
500
|
on(event, handler) {
|
|
815
501
|
this.events.on(event, handler);
|