@svgrid/grid 3.0.4 → 3.0.5
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/README.md +4 -4
- package/dist/SvGrid.controller.svelte.d.ts +12 -2
- package/dist/SvGrid.controller.svelte.js +192 -8
- package/dist/SvGrid.css +73 -0
- package/dist/SvGrid.svelte +128 -3
- package/dist/SvGrid.types.d.ts +356 -3
- package/dist/build-api.js +11 -6
- package/dist/cdn/{GridMenus-BL7ZgQvU.js → GridMenus-CID62rlI.js} +11 -11
- package/dist/cdn/{GridMenus-7kbpnnBW.js → GridMenus-DLL-qZeu.js} +11 -11
- package/dist/cdn/server-block-cache-CGoWz-87.js +237 -0
- package/dist/cdn/{src-BKhZ6eXd.js → src-Bklofsad.js} +8818 -8798
- package/dist/cdn/{src-V1uu8iE9.js → src-jcFMkBnN.js} +4282 -4262
- package/dist/cdn/svgrid.js +27 -26
- package/dist/cdn/svgrid.svelte-external.js +27 -26
- package/dist/cdn/validate-C7Rn_Bns.js +76 -0
- package/dist/core.js +36 -13
- package/dist/editing.js +10 -0
- package/dist/gantt-view.svelte.d.ts +24 -0
- package/dist/gantt-view.svelte.js +13 -0
- package/dist/grid-icons.d.ts +2 -2
- package/dist/grid-icons.js +2 -2
- package/dist/grid-messages.d.ts +6 -0
- package/dist/grid-messages.js +5 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -3
- package/dist/row-model.d.ts +133 -0
- package/dist/row-model.js +16 -0
- package/dist/selection.d.ts +2 -1
- package/dist/selection.js +30 -2
- package/dist/server-block-cache.d.ts +214 -0
- package/dist/server-block-cache.js +531 -0
- package/dist/server-data-source.d.ts +240 -6
- package/dist/server-data-source.js +220 -20
- package/dist/server.d.ts +13 -0
- package/dist/server.js +13 -0
- package/dist/validate.d.ts +4 -0
- package/dist/validate.js +21 -3
- package/package.json +6 -1
- package/src/SvGrid.controller.svelte.ts +191 -8
- package/src/SvGrid.css +73 -0
- package/src/SvGrid.svelte +128 -3
- package/src/SvGrid.types.ts +376 -3
- package/src/build-api.ts +11 -4
- package/src/core.rowmodel-cache.test.ts +51 -0
- package/src/core.ts +33 -12
- package/src/editing.ts +8 -0
- package/src/gantt-stub.test.svelte +38 -0
- package/src/gantt-view.svelte.ts +35 -0
- package/src/grid-icons.ts +2 -2
- package/src/grid-messages.ts +12 -0
- package/src/icon-seam.test.ts +2 -4
- package/src/index.ts +36 -10
- package/src/row-model.ts +146 -0
- package/src/selection.test.ts +3 -0
- package/src/selection.ts +32 -2
- package/src/server-block-cache.test.ts +645 -0
- package/src/server-block-cache.ts +677 -0
- package/src/server-data-source.infinite.test.ts +343 -0
- package/src/server-data-source.ts +450 -27
- package/src/server.ts +47 -0
- package/src/svgrid.gantt-seam.test.ts +199 -0
- package/src/svgrid.row-model-prop.svelte.test.ts +352 -0
- package/src/svgrid.row-model-seam.svelte.test.ts +289 -0
- package/src/svgrid.upsell-license.test.ts +7 -4
- package/src/validate.test.ts +29 -0
- package/src/validate.ts +28 -3
- package/dist/SvGroupCell.svelte +0 -141
- package/dist/SvGroupCell.svelte.d.ts +0 -49
- package/dist/SvRowGroupPanel.svelte +0 -186
- package/dist/SvRowGroupPanel.svelte.d.ts +0 -25
- package/dist/cdn/validate-_CDJzgIo.js +0 -75
- package/dist/server-group-model.d.ts +0 -98
- package/dist/server-group-model.js +0 -263
- package/src/SvGroupCell.svelte +0 -141
- package/src/SvRowGroupPanel.svelte +0 -186
- package/src/server-group-model.test.ts +0 -294
- package/src/server-group-model.ts +0 -370
package/src/grid-messages.ts
CHANGED
|
@@ -106,9 +106,16 @@ export type GridChromeMessages = {
|
|
|
106
106
|
bulkEditCancel: string
|
|
107
107
|
bulkEditNoFields: string
|
|
108
108
|
chartRange: string
|
|
109
|
+
// Rows whose data has not arrived (server-side / infinite loading)
|
|
110
|
+
rowLoadFailed: string
|
|
111
|
+
rowLoadRetry: string
|
|
109
112
|
// Upsell notes (enterprise views not installed)
|
|
110
113
|
pivotUpsellTitle: string
|
|
111
114
|
pivotUpsellBody: string
|
|
115
|
+
ganttUpsellTitle: string
|
|
116
|
+
ganttUpsellBody: string
|
|
117
|
+
/** Placeholder in the Gantt view's search box. */
|
|
118
|
+
ganttSearchPlaceholder: string
|
|
112
119
|
/** Shared licensing line under every Enterprise upsell note. */
|
|
113
120
|
upsellLicense: string
|
|
114
121
|
upsellLicenseLink: string
|
|
@@ -185,8 +192,13 @@ export const defaultGridMessages: GridChromeMessages = {
|
|
|
185
192
|
opBefore: 'Before',
|
|
186
193
|
opAfter: 'After',
|
|
187
194
|
chartRange: 'Chart selected range',
|
|
195
|
+
rowLoadFailed: 'Could not load these rows.',
|
|
196
|
+
rowLoadRetry: 'Retry',
|
|
188
197
|
pivotUpsellTitle: 'Pivot mode',
|
|
189
198
|
pivotUpsellBody: 'Pivot mode is an Enterprise feature. Install @svgrid/enterprise and call enablePivot() to use it.',
|
|
199
|
+
ganttUpsellTitle: 'Gantt view',
|
|
200
|
+
ganttUpsellBody: 'The Gantt view is an Enterprise feature. Install @svgrid/enterprise and call enableGanttView() to render it.',
|
|
201
|
+
ganttSearchPlaceholder: 'Search tasks...',
|
|
190
202
|
upsellLicense:
|
|
191
203
|
'A license key is required for production use. Without one the feature still works, but the grid renders an unlicensed watermark.',
|
|
192
204
|
upsellLicenseLink: 'View licensing',
|
package/src/icon-seam.test.ts
CHANGED
|
@@ -20,18 +20,16 @@ const SRC = join(process.cwd(), 'src')
|
|
|
20
20
|
const read = (f: string) => readFileSync(join(SRC, f), 'utf8')
|
|
21
21
|
|
|
22
22
|
/** Files that render grid chrome and therefore must go through the seam. */
|
|
23
|
-
const CHROME = ['SvGrid.svelte', 'GridMenus.svelte', 'GridFooter.svelte'
|
|
23
|
+
const CHROME = ['SvGrid.svelte', 'GridMenus.svelte', 'GridFooter.svelte']
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Drop the regions allowed to contain raw icon markup: the `icon` snippet's own
|
|
27
|
-
* body (which IS the built-in set)
|
|
28
|
-
* every `<script>` block.
|
|
27
|
+
* body (which IS the built-in set) and every `<script>` block.
|
|
29
28
|
*/
|
|
30
29
|
function stripAllowedRegions(src: string): string {
|
|
31
30
|
let out = src.replace(/<script[\s\S]*?<\/script>/g, '')
|
|
32
31
|
// The built-in catalogue: from the snippet header to its closing tag.
|
|
33
32
|
out = out.replace(/\{#snippet icon\(name: GridIconName\)\}[\s\S]*?\n\{\/snippet\}/g, '')
|
|
34
|
-
out = out.replace(/\{#snippet ic\(name: GridIconName\)\}[\s\S]*?\{\/snippet\}/g, '')
|
|
35
33
|
return out
|
|
36
34
|
}
|
|
37
35
|
|
package/src/index.ts
CHANGED
|
@@ -121,6 +121,23 @@ export type {
|
|
|
121
121
|
SchedulerOccurrenceChangeEvent,
|
|
122
122
|
} from './SvGrid.types'
|
|
123
123
|
export { registerSchedulerView, getSchedulerView, hasSchedulerView } from './scheduler-view.svelte'
|
|
124
|
+
// Gantt view. Same split as the scheduler: the `gantt` prop and its config
|
|
125
|
+
// types live in the free grid, the RENDERER ships in @svgrid/enterprise and
|
|
126
|
+
// registers itself through this seam (see gantt-view.svelte.ts). Unlike the
|
|
127
|
+
// scheduler, the Gantt's layout model lives in enterprise too - only the
|
|
128
|
+
// renderer reads it.
|
|
129
|
+
export type {
|
|
130
|
+
GanttConfig,
|
|
131
|
+
GanttDrawerConfig,
|
|
132
|
+
GanttTaskMoveEvent,
|
|
133
|
+
GanttTaskResizeEvent,
|
|
134
|
+
GanttProgressChangeEvent,
|
|
135
|
+
GanttTaskCommitEvent,
|
|
136
|
+
GanttDependency,
|
|
137
|
+
GanttDependencyType,
|
|
138
|
+
GanttZoom,
|
|
139
|
+
} from './SvGrid.types'
|
|
140
|
+
export { registerGanttView, getGanttView, hasGanttView } from './gantt-view.svelte'
|
|
124
141
|
// Bulk-action bar over the row selection. Prop + types free, renderer Pro.
|
|
125
142
|
export { registerSelectionBarView, getSelectionBarView, hasSelectionBarView } from './selection-bar-view.svelte'
|
|
126
143
|
// Chart view. The `chart` prop + its config live in the free grid AND so does the
|
|
@@ -754,9 +771,11 @@ export {
|
|
|
754
771
|
export {
|
|
755
772
|
createServerDataSource,
|
|
756
773
|
type ServerDataSource,
|
|
774
|
+
type ServerSelectionRule,
|
|
757
775
|
type ServerRequest,
|
|
758
776
|
type ServerResult,
|
|
759
777
|
type ServerController,
|
|
778
|
+
type ServerControllerOptions,
|
|
760
779
|
type ServerState,
|
|
761
780
|
type ServerSortModel,
|
|
762
781
|
type ServerFilterModel,
|
|
@@ -766,19 +785,26 @@ export {
|
|
|
766
785
|
type ServerMoreRow,
|
|
767
786
|
type ServerFooterRow,
|
|
768
787
|
type ServerSkeletonRow,
|
|
788
|
+
type ServerGrandTotalRow,
|
|
789
|
+
type ServerPlaceholderRow,
|
|
769
790
|
type ServerDisplayRow,
|
|
770
791
|
} from './server-data-source'
|
|
771
792
|
export {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
type
|
|
776
|
-
type
|
|
777
|
-
type
|
|
778
|
-
type
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
export {
|
|
793
|
+
createBlockCache,
|
|
794
|
+
createRowPlaceholder,
|
|
795
|
+
rowPlaceholderState,
|
|
796
|
+
type BlockCache,
|
|
797
|
+
type BlockCacheOptions,
|
|
798
|
+
type BlockCacheState,
|
|
799
|
+
type BlockFetchResult,
|
|
800
|
+
type BlockState,
|
|
801
|
+
} from './server-block-cache'
|
|
802
|
+
export {
|
|
803
|
+
toServerFilterColumns,
|
|
804
|
+
type GridRowModel,
|
|
805
|
+
type GridFilterState,
|
|
806
|
+
type GridRowModelSort,
|
|
807
|
+
} from './row-model'
|
|
782
808
|
export {
|
|
783
809
|
createNamedViews,
|
|
784
810
|
memoryViews,
|
package/src/row-model.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GridRowModel` - one prop instead of eleven.
|
|
3
|
+
*
|
|
4
|
+
* A grid backed by a server needs the same wiring every time: hand it the
|
|
5
|
+
* rows, tell it not to sort or filter locally, forward the sort and the filter
|
|
6
|
+
* to the backend, report which rows are on screen, say which rows have not
|
|
7
|
+
* loaded, and delegate selection. Written out by hand that is a dozen props
|
|
8
|
+
* and a filter-shape conversion that every app gets slightly differently:
|
|
9
|
+
*
|
|
10
|
+
* ```svelte
|
|
11
|
+
* <SvGrid data={s.rows} externalSort externalFilter loading={s.loading}
|
|
12
|
+
* onSortingChange={(x) => ctl.setSort(x)}
|
|
13
|
+
* onFiltersChange={(f) => ctl.setFilter({ global: f.global,
|
|
14
|
+
* columns: Object.fromEntries(f.columns.map((c) => [c.id, { ... }])) })}
|
|
15
|
+
* onVisibleRangeChange={(r) => ctl.setViewport(r.startIndex, r.endIndex)}
|
|
16
|
+
* ... />
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* An object that implements this interface carries all of it, so the same grid
|
|
20
|
+
* becomes:
|
|
21
|
+
*
|
|
22
|
+
* ```svelte
|
|
23
|
+
* <SvGrid rowModel={ctl} {columns} />
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* `createServerDataSource` returns one, and so does the Enterprise server row
|
|
27
|
+
* model - which is the point of the interface rather than a concrete type: the
|
|
28
|
+
* grid depends on the SHAPE, never on either implementation, and an app with
|
|
29
|
+
* its own fetching can satisfy it too.
|
|
30
|
+
*
|
|
31
|
+
* Every member except `subscribe` / `getRows` / `isLoading` is optional, and a
|
|
32
|
+
* prop written explicitly on `<SvGrid>` always wins over the model's answer -
|
|
33
|
+
* so adopting this is never all-or-nothing.
|
|
34
|
+
*/
|
|
35
|
+
import type { FilterOperator } from './SvGrid.types'
|
|
36
|
+
|
|
37
|
+
/** The filter state as the grid reports it, straight from `onFiltersChange`. */
|
|
38
|
+
export type GridFilterState = {
|
|
39
|
+
global: string
|
|
40
|
+
columns: Array<{
|
|
41
|
+
id: string
|
|
42
|
+
operator: FilterOperator
|
|
43
|
+
value: string
|
|
44
|
+
valueTo?: string
|
|
45
|
+
selectedValues?: Array<string>
|
|
46
|
+
}>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The sort the grid hands a row model: column id and direction, in priority order. */
|
|
50
|
+
export type GridRowModelSort = Array<{ id: string; desc: boolean }>
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* What `<SvGrid rowModel>` consumes: rows, a loading flag, a change
|
|
54
|
+
* subscription, and whichever optional parts the model implements - sort,
|
|
55
|
+
* filter, viewport, placeholders, group accessors, selection, filter
|
|
56
|
+
* values, paging, pinned rows and pivot columns. `createServerDataSource`
|
|
57
|
+
* and the Enterprise `createServerRowModel` both satisfy it.
|
|
58
|
+
*/
|
|
59
|
+
export type GridRowModel<TData> = {
|
|
60
|
+
/**
|
|
61
|
+
* Register a callback for "something changed, re-read me". Returns an
|
|
62
|
+
* unsubscribe function, which the grid calls on unmount.
|
|
63
|
+
*/
|
|
64
|
+
subscribe(onChange: () => void): () => void
|
|
65
|
+
/** The rows to render, including any placeholders for unloaded ones. */
|
|
66
|
+
getRows(): ReadonlyArray<TData>
|
|
67
|
+
/** True while a fetch is in flight, for the loading overlay. */
|
|
68
|
+
isLoading(): boolean
|
|
69
|
+
/** Stable row id. Required once selection or editing is involved. */
|
|
70
|
+
getRowId?(row: TData, index: number): string
|
|
71
|
+
/** Sort on the server. Present means "do not sort locally". */
|
|
72
|
+
setSort?(sort: GridRowModelSort): void
|
|
73
|
+
/** Filter on the server. Present means "do not filter locally". */
|
|
74
|
+
setFilter?(filters: GridFilterState): void
|
|
75
|
+
/** Which rows are on screen, so a block-loading model knows what to fetch. */
|
|
76
|
+
setViewport?(startIndex: number, endIndex: number): void
|
|
77
|
+
/** Why a row has no data yet, or null when it does. */
|
|
78
|
+
rowPlaceholder?(row: TData, rowIndex: number): 'loading' | 'failed' | null
|
|
79
|
+
/** Retry the failed block a placeholder row belongs to. */
|
|
80
|
+
retryRow?(row: TData, rowIndex: number): void
|
|
81
|
+
/** Group / tree accessors, for the grid's treegrid keyboard and ARIA. */
|
|
82
|
+
group?: {
|
|
83
|
+
isGroup: (row: TData) => boolean
|
|
84
|
+
level: (row: TData) => number
|
|
85
|
+
expanded?: (row: TData) => boolean
|
|
86
|
+
onToggle: (row: TData) => void
|
|
87
|
+
}
|
|
88
|
+
/** Selection the grid does not own - see the `rowSelectionModel` prop. */
|
|
89
|
+
selection?: {
|
|
90
|
+
isSelected: (rowId: string, row: TData) => boolean
|
|
91
|
+
headerState: () => 'none' | 'some' | 'all'
|
|
92
|
+
toggle: (rowId: string, row: TData, next: boolean) => void
|
|
93
|
+
toggleAll: (next: boolean) => void
|
|
94
|
+
selectedCount?: () => number | null
|
|
95
|
+
bulkUpdate?: (patch: Record<string, unknown>) => Promise<number>
|
|
96
|
+
}
|
|
97
|
+
/** Distinct values for a column's set filter, fetched from the server. */
|
|
98
|
+
filterValues?(columnId: string): Promise<Array<string>>
|
|
99
|
+
/** Server-side paging. Omit it for infinite scrolling. */
|
|
100
|
+
pagination?: {
|
|
101
|
+
pageIndex: number
|
|
102
|
+
pageSize: number
|
|
103
|
+
rowCount: number
|
|
104
|
+
setPage(pageIndex: number): void
|
|
105
|
+
setPageSize(pageSize: number): void
|
|
106
|
+
/** Choices for the footer's page-size selector. */
|
|
107
|
+
pageSizes?: number[]
|
|
108
|
+
/**
|
|
109
|
+
* Ask the grid for as many rows as its body fits: it measures and calls
|
|
110
|
+
* `setPageSize` whenever the fit changes.
|
|
111
|
+
*/
|
|
112
|
+
autoPageSize?: boolean
|
|
113
|
+
}
|
|
114
|
+
/** Rows to pin above / below the scrolling body - a grand total, say. */
|
|
115
|
+
readonly pinnedTopRows?: ReadonlyArray<TData>
|
|
116
|
+
readonly pinnedBottomRows?: ReadonlyArray<TData>
|
|
117
|
+
/**
|
|
118
|
+
* Columns that replace the grid's `columns` while the model is in pivot
|
|
119
|
+
* mode, or null. Read after every change notification.
|
|
120
|
+
*/
|
|
121
|
+
readonly pivotResultColumns?: ReadonlyArray<unknown> | null
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Turn the grid's filter payload into the column-keyed map a `ServerRequest`
|
|
126
|
+
* carries. Exported because a hand-written `GridRowModel` needs exactly this
|
|
127
|
+
* conversion, and copying it is how the two shapes drift apart.
|
|
128
|
+
*/
|
|
129
|
+
export function toServerFilterColumns(
|
|
130
|
+
filters: GridFilterState,
|
|
131
|
+
): Record<
|
|
132
|
+
string,
|
|
133
|
+
{ operator: string; value: string; valueTo?: string; selectedValues?: Array<string> }
|
|
134
|
+
> {
|
|
135
|
+
return Object.fromEntries(
|
|
136
|
+
filters.columns.map((c) => [
|
|
137
|
+
c.id,
|
|
138
|
+
{
|
|
139
|
+
operator: c.operator,
|
|
140
|
+
value: c.value,
|
|
141
|
+
...(c.valueTo !== undefined ? { valueTo: c.valueTo } : {}),
|
|
142
|
+
...(c.selectedValues !== undefined ? { selectedValues: c.selectedValues } : {}),
|
|
143
|
+
},
|
|
144
|
+
]),
|
|
145
|
+
)
|
|
146
|
+
}
|
package/src/selection.test.ts
CHANGED
|
@@ -39,6 +39,9 @@ function makeCtx(overrides: any = {}) {
|
|
|
39
39
|
allRows: [],
|
|
40
40
|
allColumns: [],
|
|
41
41
|
headerSelectionState: 'none',
|
|
42
|
+
// The real controller always supplies this; a fake that omits it would
|
|
43
|
+
// make every select-all path throw rather than assert.
|
|
44
|
+
placeholderStateOf: () => null,
|
|
42
45
|
userHasActivatedCell: false,
|
|
43
46
|
enableCellSelectionEffective: true,
|
|
44
47
|
selectionRange: { anchor: null, focus: null },
|
package/src/selection.ts
CHANGED
|
@@ -21,16 +21,45 @@ export function createSelection<
|
|
|
21
21
|
TData extends RowData = RowData,
|
|
22
22
|
>(ctx: any) {
|
|
23
23
|
function isRowSelected(rowId: string) {
|
|
24
|
+
const model = ctx.props.rowSelectionModel;
|
|
25
|
+
if (model) {
|
|
26
|
+
const row = ctx.allRows.find((r: any) => r.id === rowId);
|
|
27
|
+
return row ? model.isSelected(rowId, row.original) : false;
|
|
28
|
+
}
|
|
24
29
|
return Boolean(ctx.rowSelectionState[rowId]);
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
function toggleRowSelectionById(rowId: string) {
|
|
33
|
+
const model = ctx.props.rowSelectionModel;
|
|
34
|
+
if (model) {
|
|
35
|
+
const row = ctx.allRows.find((r: any) => r.id === rowId);
|
|
36
|
+
if (!row) return;
|
|
37
|
+
model.toggle(rowId, row.original, !model.isSelected(rowId, row.original));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
28
40
|
ctx.grid.setRowSelection((prev: any) => ({ ...prev, [rowId]: !prev[rowId] }));
|
|
29
41
|
}
|
|
30
42
|
|
|
31
43
|
function toggleSelectAllRows() {
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
setSelectAllRows(ctx.headerSelectionState !== "all");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Select or clear every row, for the header checkbox and for
|
|
49
|
+
* `api.selectAllRows()`.
|
|
50
|
+
*/
|
|
51
|
+
function setSelectAllRows(select: boolean) {
|
|
52
|
+
// An external model decides what "all" means - possibly a million rows
|
|
53
|
+
// the grid has never seen - so it gets the intent, not a row list.
|
|
54
|
+
if (ctx.props.rowSelectionModel) {
|
|
55
|
+
ctx.props.rowSelectionModel.toggleAll(select);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Placeholder rows are excluded: there is no row there to select yet,
|
|
59
|
+
// and ticking one would leave a selected id that never resolves.
|
|
60
|
+
const selectable = ctx.allRows.filter(
|
|
61
|
+
(row: any) => !isGroupRow(row) && !ctx.placeholderStateOf(row),
|
|
62
|
+
);
|
|
34
63
|
ctx.grid.setRowSelection((prev: any) => {
|
|
35
64
|
const next = { ...prev };
|
|
36
65
|
for (const row of selectable) {
|
|
@@ -687,6 +716,7 @@ export function createSelection<
|
|
|
687
716
|
isRowSelected,
|
|
688
717
|
toggleRowSelectionById,
|
|
689
718
|
toggleSelectAllRows,
|
|
719
|
+
setSelectAllRows,
|
|
690
720
|
setActiveCell,
|
|
691
721
|
scrollActiveCellIntoView,
|
|
692
722
|
setSelection,
|