@guiexpert/table 1.1.94 → 1.1.96
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 +12 -0
- package/css/main.css +192 -0
- package/css/table-calc.css +7 -0
- package/css/table-color-vars.css +46 -0
- package/css/table-fill-batch.css +58 -0
- package/css/table-row-drag.css +81 -0
- package/index.cjs +39 -37
- package/index.d.ts +28 -0
- package/index.js +5501 -1934
- package/lib/table/action/action-id.type.d.ts +1 -1
- package/lib/table/aria/aria-texts.d.ts +11 -0
- package/lib/table/aria/aria-texts.if.d.ts +87 -0
- package/lib/table/batch-edit/batch-edit-options.d.ts +21 -0
- package/lib/table/batch-edit/batch-edit-options.if.d.ts +20 -0
- package/lib/table/batch-edit/batch-edit-service.d.ts +104 -0
- package/lib/table/batch-edit/cell-change.if.d.ts +39 -0
- package/lib/table/batch-edit/cell-value-change.if.d.ts +18 -0
- package/lib/table/batch-edit/pending-cell-changes.d.ts +104 -0
- package/lib/table/calc/column-values.d.ts +55 -0
- package/lib/table/calc/show-values-as-internals.d.ts +4 -0
- package/lib/table/calc/show-values-as.d.ts +87 -0
- package/lib/table/calc/show-values-as.type.d.ts +55 -0
- package/lib/table/calc/value-getter-context.if.d.ts +35 -0
- package/lib/table/calc/value-getter.type.d.ts +36 -0
- package/lib/table/data/common/event/ge-batch-edit-event.d.ts +46 -0
- package/lib/table/data/common/event/ge-model-change-event.d.ts +27 -1
- package/lib/table/data/common/event/ge-row-drag-event.d.ts +89 -0
- package/lib/table/data/options/table-options.d.ts +6 -0
- package/lib/table/data/options/table-options.if.d.ts +44 -0
- package/lib/table/data/tablemodel/areamodel/abstract-area-model.d.ts +66 -0
- package/lib/table/data/tablemodel/areamodel/area-model-aggregate-footer.d.ts +5 -0
- package/lib/table/data/tablemodel/areamodel/area-model-array-of-arrays.d.ts +24 -0
- package/lib/table/data/tablemodel/areamodel/area-model-object-array.d.ts +70 -0
- package/lib/table/data/tablemodel/areamodel/area-model-pivot.d.ts +31 -0
- package/lib/table/data/tablemodel/areamodel/area-model-row-groups.d.ts +23 -1
- package/lib/table/data/tablemodel/areamodel/area-model-tree.d.ts +83 -0
- package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +55 -0
- package/lib/table/data/tablemodel/column/column-def.d.ts +31 -1
- package/lib/table/data/tablemodel/column/column-def.if.d.ts +86 -0
- package/lib/table/event-adapter.d.ts +7 -0
- package/lib/table/event-listener.if.d.ts +32 -0
- package/lib/table/factory/table-factory.d.ts +11 -0
- package/lib/table/fill/compute-fill-changes.d.ts +67 -0
- package/lib/table/fill/fill-direction.type.d.ts +7 -0
- package/lib/table/fill/fill-handle-options.d.ts +29 -0
- package/lib/table/fill/fill-handle-options.if.d.ts +35 -0
- package/lib/table/fill/fill-handle-service.d.ts +55 -0
- package/lib/table/fill/fill-series.d.ts +60 -0
- package/lib/table/fill/fill-value-context.if.d.ts +36 -0
- package/lib/table/formula/compile-formula.d.ts +86 -0
- package/lib/table/formula/evaluator.d.ts +19 -0
- package/lib/table/formula/formula-ast.if.d.ts +42 -0
- package/lib/table/formula/formula-error.d.ts +59 -0
- package/lib/table/formula/formula-options.if.d.ts +41 -0
- package/lib/table/formula/formula-values.d.ts +13 -0
- package/lib/table/formula/functions.d.ts +18 -0
- package/lib/table/formula/parser.d.ts +10 -0
- package/lib/table/formula/tokenizer.d.ts +22 -0
- package/lib/table/pivot/pivot-value.type.d.ts +13 -0
- package/lib/table/render-scope.d.ts +81 -0
- package/lib/table/renderer/edit/input-cell-renderer.d.ts +1 -1
- package/lib/table/renderer/edit/select-cell-renderer.d.ts +1 -1
- package/lib/table/row-drag/move-rows.d.ts +157 -0
- package/lib/table/row-drag/row-drag-options.d.ts +28 -0
- package/lib/table/row-drag/row-drag-options.if.d.ts +36 -0
- package/lib/table/row-drag/row-drag-service.d.ts +130 -0
- package/lib/table/row-drag/row-drop-target.if.d.ts +29 -0
- package/lib/table/service/excel-service.d.ts +6 -0
- package/lib/table/service/excel-service.if.d.ts +35 -0
- package/lib/table/table-api.d.ts +277 -2
- package/lib/table/table-scope.d.ts +121 -0
- package/package.json +1 -1
|
@@ -6,6 +6,10 @@ import { FilterFunction } from '../../common/filter-function.js';
|
|
|
6
6
|
import { SorterService } from '../../../service/sorter.service.js';
|
|
7
7
|
import { SortItem } from '../../common/sort-item.js';
|
|
8
8
|
import { TreeRowIf } from '../../common/tree-row-if.js';
|
|
9
|
+
import { CellRendererIf } from '../../../renderer/cell-render.if.js';
|
|
10
|
+
import { DerivedValuesChangeIf } from './derived-values-change.if.js';
|
|
11
|
+
import { ShowValuesAsIf } from '../../../calc/show-values-as.type.js';
|
|
12
|
+
import { RowDropTargetIf } from '../../../row-drag/row-drop-target.if.js';
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* Represents a tree-based table model.
|
|
@@ -57,6 +61,8 @@ export declare class AreaModelTree<S> extends AbstractAreaModel<TreeRow<S>> {
|
|
|
57
61
|
private lastPredictFn?;
|
|
58
62
|
/** `row.keep` was set for the current filter (it depends on the filter and the data, not on expand/collapse). */
|
|
59
63
|
private keepMarked;
|
|
64
|
+
/** „Show values as“: shown value per row and property (cleared on filter, sorting and invalidation). */
|
|
65
|
+
private showValuesCache;
|
|
60
66
|
constructor(areaIdent: AreaIdent, rows: TreeRowIf<S>[], defaultRowHeight: number, columnDefs?: ColumnDefIf[]);
|
|
61
67
|
changeColumnOrder(sourceColumnIndex: number, targetColumnIndex: number): void;
|
|
62
68
|
/**
|
|
@@ -136,7 +142,84 @@ export declare class AreaModelTree<S> extends AbstractAreaModel<TreeRow<S>> {
|
|
|
136
142
|
* @since 1.1.92
|
|
137
143
|
*/
|
|
138
144
|
getUnfilteredRowCount(): number;
|
|
145
|
+
/**
|
|
146
|
+
* Row drag: true if the rows can be moved to the target – no filter hides a displayed row, and the target is none of
|
|
147
|
+
* the dragged rows and no descendant of them (no cycle). `"before"` / `"after"` = sibling of the target row,
|
|
148
|
+
* `"inside"` = last child.
|
|
149
|
+
*
|
|
150
|
+
* @param {number[]} rowIndices - display indices of the dragged rows
|
|
151
|
+
* @param {RowDropTargetIf} target - the drop target
|
|
152
|
+
* @returns {boolean} true if {@link moveRows} would move them
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* const treeModel = tableModel.getBodyModel() as AreaModelTree<OrderNode>;
|
|
156
|
+
* treeModel.canMoveRows([0], { rowIndex: 1, position: "inside" }); // false if row 1 is a child of row 0
|
|
157
|
+
*
|
|
158
|
+
* @since 1.1.95
|
|
159
|
+
*/
|
|
160
|
+
canMoveRows(rowIndices: number[], target: RowDropTargetIf): boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Row drag: moves tree rows (with their children) in front of / behind the target row (siblings) or into it
|
|
163
|
+
* (`"inside"`: last children, the target is expanded) – in place in {@link rows} and the `children` arrays;
|
|
164
|
+
* `parent` and `deep` follow. See {@link canMoveRows}.
|
|
165
|
+
*
|
|
166
|
+
* @param {number[]} rowIndices - display indices of the dragged rows
|
|
167
|
+
* @param {RowDropTargetIf} target - the drop target (display index before the move)
|
|
168
|
+
* @returns {boolean} true if moved
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* const treeModel = tableModel.getBodyModel() as AreaModelTree<OrderNode>;
|
|
172
|
+
* treeModel.moveRows([3], { rowIndex: 0, position: "inside" });
|
|
173
|
+
* tableApi.repaintHard(); // or simply tableApi.moveRows([3], { rowIndex: 0, position: "inside" })
|
|
174
|
+
*
|
|
175
|
+
* @since 1.1.95
|
|
176
|
+
*/
|
|
177
|
+
moveRows(rowIndices: number[], target: RowDropTargetIf): boolean;
|
|
178
|
+
/** The topmost tree rows of the display indices (children travel with their parent). */
|
|
179
|
+
private getDragRows;
|
|
139
180
|
getValueAt(rowIndex: number, columnIndex: number): any;
|
|
181
|
+
/**
|
|
182
|
+
* The value of a tree row for a property – before „Show values as“: the computed value of a calculated column,
|
|
183
|
+
* otherwise the property (path) of `row.data`. Subclasses (row groups) return their aggregates for group rows.
|
|
184
|
+
*
|
|
185
|
+
* @param {TreeRowIf<S>} row - the tree row
|
|
186
|
+
* @param {string} prop - the property of the column
|
|
187
|
+
* @returns {any} the raw value
|
|
188
|
+
* @since 1.1.95
|
|
189
|
+
*/
|
|
190
|
+
protected getRawValueOfRow(row: TreeRowIf<S>, prop: string): any;
|
|
191
|
+
/**
|
|
192
|
+
* The text of a cell: for a „Show values as“ column the formatted value (`"66.7%"`), for a formula error its code;
|
|
193
|
+
* otherwise like before (`'' + value`).
|
|
194
|
+
*
|
|
195
|
+
* @param {number} rowIndex - the row
|
|
196
|
+
* @param {number} columnIndex - the column
|
|
197
|
+
* @returns {string} the text
|
|
198
|
+
*/
|
|
199
|
+
getTextValueAt(rowIndex: number, columnIndex: number): string;
|
|
200
|
+
/** A „Show values as“ column without an own body renderer shows the formatted text. */
|
|
201
|
+
getCellRenderer(rowIndex: number, columnIndex: number): CellRendererIf | undefined;
|
|
202
|
+
/** The message of a formula error as tooltip. */
|
|
203
|
+
getTooltipAt(rowIndex: number, columnIndex: number): any;
|
|
204
|
+
/**
|
|
205
|
+
* Drops derived values: cached aggregates of formulas and „Show values as“ (called by the table on filter,
|
|
206
|
+
* sorting, editing, `updateCells` and `api.repaint()`).
|
|
207
|
+
*
|
|
208
|
+
* @param {DerivedValuesChangeIf} [_change] - the changed rows (not used here)
|
|
209
|
+
* @since 1.1.95
|
|
210
|
+
*/
|
|
211
|
+
invalidateDerivedValues(_change?: DerivedValuesChangeIf): void;
|
|
212
|
+
/**
|
|
213
|
+
* „Show values as“ of one tree row: percentages of the column total relate to the (filtered) leaf rows,
|
|
214
|
+
* `percentOfParentTotal`, `runningTotal`, `differenceFromPrevious` and `rank` to the displayed siblings.
|
|
215
|
+
*/
|
|
216
|
+
protected applyShowValuesAs(row: TreeRowIf<S>, property: string, value: unknown, options: ShowValuesAsIf): unknown;
|
|
217
|
+
protected readPropertyPath(t: any, property: string): unknown;
|
|
218
|
+
protected getAggregationSourceForValues(): {
|
|
219
|
+
signal: unknown;
|
|
220
|
+
length: number;
|
|
221
|
+
rows: () => ArrayLike<unknown>;
|
|
222
|
+
};
|
|
140
223
|
getRowHeight(_rowIndex: number): number;
|
|
141
224
|
/**
|
|
142
225
|
* All rows share `defaultRowHeight` – unless a subclass overrides `getRowHeight()`, then row heights may
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RowDropTargetIf } from '../../../row-drag/row-drop-target.if.js';
|
|
1
2
|
import { DerivedValuesChangeIf } from './derived-values-change.if.js';
|
|
2
3
|
import { CellRendererIf } from '../../../renderer/cell-render.if.js';
|
|
3
4
|
import { CheckedType } from '../../common/checked-type.js';
|
|
@@ -281,6 +282,40 @@ export interface AreaModelIf {
|
|
|
281
282
|
* @since 1.1.92
|
|
282
283
|
*/
|
|
283
284
|
getUnfilteredRowCount?(): number;
|
|
285
|
+
/**
|
|
286
|
+
* Optional (row drag, managed mode): true if the rows can be moved to the target – e.g. false for a node dropped
|
|
287
|
+
* into its own child, or while a filter hides rows. Without {@link moveRows} the table cannot move rows itself.
|
|
288
|
+
*
|
|
289
|
+
* @param {number[]} rowIndices - display indices of the dragged rows (ascending)
|
|
290
|
+
* @param {RowDropTargetIf} target - the drop target (display index before the move)
|
|
291
|
+
* @returns {boolean} true if {@link moveRows} would move them
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* class TasksBodyModel extends AreaModel {
|
|
295
|
+
* tasks: string[] = ["Write", "Test", "Ship"];
|
|
296
|
+
* override getRowCount(): number { return this.tasks.length; }
|
|
297
|
+
* override getValueAt(rowIndex: number): any { return this.tasks[rowIndex]; }
|
|
298
|
+
* canMoveRows(rowIndices: number[], target: RowDropTargetIf): boolean { return target.position !== "inside"; }
|
|
299
|
+
* moveRows(rowIndices: number[], target: RowDropTargetIf): boolean {
|
|
300
|
+
* return moveArrayItems(this.tasks, rowIndices, getInsertBeforeIndex(target)) > -1;
|
|
301
|
+
* }
|
|
302
|
+
* }
|
|
303
|
+
*
|
|
304
|
+
* @since 1.1.95
|
|
305
|
+
*/
|
|
306
|
+
canMoveRows?(rowIndices: number[], target: RowDropTargetIf): boolean;
|
|
307
|
+
/**
|
|
308
|
+
* Optional (row drag, managed mode): moves the rows to the target in the model – the table calls it on a drop and
|
|
309
|
+
* for `tableApi.moveRows()`, then repaints. Implemented by `AreaModelObjectArray`, `AreaModelArrayOfArrays` and
|
|
310
|
+
* `AreaModelTree` (in place in their row arrays). See {@link canMoveRows} for an example.
|
|
311
|
+
*
|
|
312
|
+
* @param {number[]} rowIndices - display indices of the dragged rows (ascending)
|
|
313
|
+
* @param {RowDropTargetIf} target - the drop target (display index before the move)
|
|
314
|
+
* @returns {boolean} true if the rows were moved
|
|
315
|
+
*
|
|
316
|
+
* @since 1.1.95
|
|
317
|
+
*/
|
|
318
|
+
moveRows?(rowIndices: number[], target: RowDropTargetIf): boolean;
|
|
284
319
|
/**
|
|
285
320
|
* Optional: drops cached, derived values (e.g. the totals of an {@link AreaModelAggregateFooter}). The table calls
|
|
286
321
|
* it for all three areas when data may have changed: filter, sorting, editing, `updateCells()` and the public
|
|
@@ -319,6 +354,26 @@ export interface AreaModelIf {
|
|
|
319
354
|
* @since 1.1.94
|
|
320
355
|
*/
|
|
321
356
|
isRowHeaderCell?(rowIndex: number, columnIndex: number): boolean;
|
|
357
|
+
/**
|
|
358
|
+
* Optional: true if the column with this property is calculated (`ColumnDefIf.valueGetter` / `formula`).
|
|
359
|
+
* Implemented by the object-array, tree, row-group and pivot models.
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* tableModel.getBodyModel().isCalculatedProperty?.("total"); // true
|
|
363
|
+
*
|
|
364
|
+
* @since 1.1.95
|
|
365
|
+
*/
|
|
366
|
+
isCalculatedProperty?(property: string): boolean;
|
|
367
|
+
/**
|
|
368
|
+
* Optional: the value of a column for a row object – computed for a calculated column, otherwise the property
|
|
369
|
+
* path ({@link TableApi.getRowValue}). Implemented by the object-array, tree, row-group and pivot models.
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* tableModel.getBodyModel().getRowValue?.({ price: 25, quantity: 10 }, "total"); // 250
|
|
373
|
+
*
|
|
374
|
+
* @since 1.1.95
|
|
375
|
+
*/
|
|
376
|
+
getRowValue?(row: any, property: string): unknown;
|
|
322
377
|
/**
|
|
323
378
|
* Returns the value of the cell at the specified row and column indices.
|
|
324
379
|
* This is one of the most important methods in the area model, as it provides
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SizeIf } from '../../common/size.if.js';
|
|
2
|
-
import { ColumnDefIf, ValueRowSortComparator } from './column-def.if.js';
|
|
2
|
+
import { CellValidator, ColumnDefIf, RowDragColumnOption, ValueRowSortComparator } from './column-def.if.js';
|
|
3
3
|
import { CellRendererIf } from '../../../renderer/cell-render.if.js';
|
|
4
4
|
import { AreaObjectMapType } from '../../common/area-map.type.js';
|
|
5
5
|
import { AreaObjectMap } from '../../common/area-map.js';
|
|
@@ -7,6 +7,9 @@ import { BooleanFunction } from '../../common/boolean-function.js';
|
|
|
7
7
|
import { SortState } from '../../common/sort-state.type.js';
|
|
8
8
|
import { GetEditRenderer } from '../../../renderer/edit/edit-cell-renderer.type.js';
|
|
9
9
|
import { editInputPipe } from '../../../renderer/edit/edit-input-pipe.if.js';
|
|
10
|
+
import { ValueGetter, ValueSetter } from '../../../calc/value-getter.type.js';
|
|
11
|
+
import { ShowValuesAsConfig } from '../../../calc/show-values-as.type.js';
|
|
12
|
+
import { FormulaOptionsIf } from '../../../formula/formula-options.if.js';
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* The column definition – see {@link ColumnDefIf} for all fields.
|
|
@@ -52,6 +55,17 @@ export declare class ColumnDef implements ColumnDefIf {
|
|
|
52
55
|
editInputPipe?: editInputPipe | undefined;
|
|
53
56
|
isVisible: BooleanFunction;
|
|
54
57
|
visible: boolean;
|
|
58
|
+
/** A calculated column, see {@link ColumnDefIf.valueGetter}. */
|
|
59
|
+
valueGetter?: ValueGetter;
|
|
60
|
+
/** Writes an edited calculated value back, see {@link ColumnDefIf.valueSetter}. */
|
|
61
|
+
valueSetter?: ValueSetter;
|
|
62
|
+
/** „Show values as“, see {@link ColumnDefIf.showValuesAs}. */
|
|
63
|
+
showValuesAs?: ShowValuesAsConfig;
|
|
64
|
+
/** The formula of a formula column, see {@link ColumnDefIf.formula}. */
|
|
65
|
+
formula?: string;
|
|
66
|
+
rowDrag?: RowDragColumnOption;
|
|
67
|
+
/** Checks edited values, see {@link ColumnDefIf.validate} (since 1.1.96). */
|
|
68
|
+
validate?: CellValidator;
|
|
55
69
|
constructor(property: string, headerLabel: string, width?: SizeIf, classes?: AreaObjectMapType<string[]>, rendererMap?: AreaObjectMapType<CellRendererIf>, minWidth?: SizeIf, maxWidth?: SizeIf, sortable?: BooleanFunction | undefined, sortComparator?: ValueRowSortComparator | undefined, sortState?: SortState | undefined, sortStatesOrder?: SortState[] | undefined, sortIconVisible?: BooleanFunction | undefined, editable?: BooleanFunction | undefined, getEditRenderer?: GetEditRenderer | undefined, editInputPipe?: editInputPipe | undefined, isVisible?: BooleanFunction);
|
|
56
70
|
static bodyRenderer(bodyRenderer: CellRendererIf): AreaObjectMap<CellRendererIf>;
|
|
57
71
|
/**
|
|
@@ -109,5 +123,21 @@ export declare class ColumnDef implements ColumnDefIf {
|
|
|
109
123
|
getEditRenderer?: GetEditRenderer;
|
|
110
124
|
/** Converts the editor text before it is stored, e.g. `editInputPipeForNumber`. */
|
|
111
125
|
editInputPipe?: editInputPipe;
|
|
126
|
+
/** A calculated column: `(row, context) => value` (since 1.1.95). */
|
|
127
|
+
valueGetter?: ValueGetter;
|
|
128
|
+
/** Makes a calculated column editable (since 1.1.95). */
|
|
129
|
+
valueSetter?: ValueSetter;
|
|
130
|
+
/** „Show values as“: `"percentOfColumnTotal"`, `"rank"` … (since 1.1.95). */
|
|
131
|
+
showValuesAs?: ShowValuesAsConfig;
|
|
132
|
+
/**
|
|
133
|
+
* A formula column, e.g. `"[price] * [quantity] * 1.19"` – compiled once into the `valueGetter` (since 1.1.95,
|
|
134
|
+
* see {@link compileFormula}). Takes precedence over `valueGetter`.
|
|
135
|
+
*/
|
|
136
|
+
formula?: string;
|
|
137
|
+
/** Own functions of the formula (since 1.1.95). */
|
|
138
|
+
formulaOptions?: FormulaOptionsIf;
|
|
139
|
+
rowDrag?: RowDragColumnOption;
|
|
140
|
+
/** Checks edited values: a message for an invalid value (since 1.1.96). */
|
|
141
|
+
validate?: CellValidator;
|
|
112
142
|
}): ColumnDefIf;
|
|
113
143
|
}
|
|
@@ -5,6 +5,8 @@ import { BooleanFunction } from '../../common/boolean-function.js';
|
|
|
5
5
|
import { SortState } from '../../common/sort-state.type.js';
|
|
6
6
|
import { GetEditRenderer } from '../../../renderer/edit/edit-cell-renderer.type.js';
|
|
7
7
|
import { editInputPipe } from '../../../renderer/edit/edit-input-pipe.if.js';
|
|
8
|
+
import { ValueGetter, ValueSetter } from '../../../calc/value-getter.type.js';
|
|
9
|
+
import { ShowValuesAsConfig } from '../../../calc/show-values-as.type.js';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Represents a function that compares two values for sorting purposes.
|
|
@@ -116,4 +118,88 @@ export interface ColumnDefIf {
|
|
|
116
118
|
getEditRenderer?: GetEditRenderer;
|
|
117
119
|
/** Converts the text of the editor before it is written into the model, e.g. {@link editInputPipeForNumber}. */
|
|
118
120
|
editInputPipe?: editInputPipe;
|
|
121
|
+
/**
|
|
122
|
+
* A calculated column: computes the value from the row instead of reading `property` (the data stays unchanged).
|
|
123
|
+
* Sorting, filter ({@link TableApi.getRowValue}), copy, Excel, totals (`footerAggregates`) and row groups use the
|
|
124
|
+
* computed value. `property` stays the id of the column (state, `footerAggregates`, other formulas).
|
|
125
|
+
* Without a {@link ColumnDefIf.valueSetter} the column cannot be edited.
|
|
126
|
+
*
|
|
127
|
+
* Supported by the models of `TableFactory.createTableModel({ rows })`, trees, row groups (not by array-of-arrays
|
|
128
|
+
* models; an own `AreaModel` calls it itself).
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ColumnDef.create({ property: "total", headerLabel: "Total", sortable: TrueFn,
|
|
132
|
+
* valueGetter: (o: Item) => o.price * o.quantity })
|
|
133
|
+
*
|
|
134
|
+
* @see Training: [Columns with ColumnDef](https://gui.expert/training/column-definitions/)
|
|
135
|
+
* @since 1.1.95
|
|
136
|
+
*/
|
|
137
|
+
valueGetter?: ValueGetter;
|
|
138
|
+
/**
|
|
139
|
+
* Makes a calculated column editable: writes the edited value back into the row (return `false` to reject).
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* valueSetter: (o: Item, v: unknown) => { o.price = Number(v) / o.quantity; }
|
|
143
|
+
*
|
|
144
|
+
* @since 1.1.95
|
|
145
|
+
*/
|
|
146
|
+
valueSetter?: ValueSetter;
|
|
147
|
+
/**
|
|
148
|
+
* Shows the numbers of the column differently without changing the data: share of the column total, running
|
|
149
|
+
* total, rank … (see {@link ShowValuesAs}). Change it at runtime with {@link TableApi.setShowValuesAs}.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ColumnDef.create({ property: "total", headerLabel: "Share", showValuesAs: "percentOfColumnTotal" })
|
|
153
|
+
*
|
|
154
|
+
* @since 1.1.95
|
|
155
|
+
*/
|
|
156
|
+
showValuesAs?: ShowValuesAsConfig;
|
|
157
|
+
/**
|
|
158
|
+
* The formula of a formula column (`ColumnDef.create({ formula })` compiles it into the `valueGetter`), e.g.
|
|
159
|
+
* `"[price] * [quantity] * 1.19"`. Informational – change it with {@link TableApi.setColumnFormula}.
|
|
160
|
+
*
|
|
161
|
+
* @since 1.1.95
|
|
162
|
+
*/
|
|
163
|
+
formula?: string;
|
|
164
|
+
/**
|
|
165
|
+
* Row drag: the body cells of this column get a drag handle (`true`, or a function that decides per row – e.g. no
|
|
166
|
+
* handle for locked rows). Dragging the handle moves the row (see {@link TableOptionsIf.rowDragOptions}); the keyboard
|
|
167
|
+
* alternative is Ctrl+Alt+↑/↓. `TableFactory.createTableModel({ rows, rowDrag: true })` sets it on the first data
|
|
168
|
+
* column.
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ColumnDef.create({ property: "title", headerLabel: "Task", rowDrag: (task: { locked: boolean }) => !task.locked })
|
|
172
|
+
*
|
|
173
|
+
* @since 1.1.95
|
|
174
|
+
*/
|
|
175
|
+
rowDrag?: RowDragColumnOption;
|
|
176
|
+
/**
|
|
177
|
+
* Checks an edited, filled or pasted value (after `editInputPipe`): return a message for an invalid value,
|
|
178
|
+
* `undefined` for a valid one. Batch edit: invalid values are marked (`ge-table-cell-invalid`, the message as
|
|
179
|
+
* tooltip) and block {@link TableApi.commitBatchEdit}; otherwise an invalid value is not written.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ColumnDef.create({
|
|
183
|
+
* property: "price", headerLabel: "Price", editable: TrueFn, editInputPipe: editInputPipeForNumber,
|
|
184
|
+
* validate: (value: unknown) => typeof value === "number" && value >= 0 ? undefined : "A price is a number ≥ 0",
|
|
185
|
+
* })
|
|
186
|
+
*
|
|
187
|
+
* @since 1.1.96
|
|
188
|
+
*/
|
|
189
|
+
validate?: CellValidator;
|
|
119
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* {@link ColumnDefIf.validate}: a message for an invalid value, `undefined` (or `null`, `""`) for a valid one.
|
|
193
|
+
*
|
|
194
|
+
* @category Fill handle & batch edit
|
|
195
|
+
* @since 1.1.96
|
|
196
|
+
*/
|
|
197
|
+
export type CellValidator<T = any> = (value: unknown, row: T) => string | undefined | null | void;
|
|
198
|
+
/**
|
|
199
|
+
* {@link ColumnDefIf.rowDrag}: `true` = every row has a drag handle in this column, a function decides per row
|
|
200
|
+
* (`row` = the row object, a `TreeRow` in a tree; `rowIndex` = display index).
|
|
201
|
+
*
|
|
202
|
+
* @category Row drag
|
|
203
|
+
* @since 1.1.95
|
|
204
|
+
*/
|
|
205
|
+
export type RowDragColumnOption = boolean | ((row: any, rowIndex: number) => boolean);
|
|
@@ -5,6 +5,8 @@ import { EventListenerIf } from './event-listener.if.js';
|
|
|
5
5
|
import { SelectionModelIf } from './selection/selection-model.if.js';
|
|
6
6
|
import { FocusModelIf } from './focus/focus-model.if.js';
|
|
7
7
|
import { GeStateChangeEvent } from './data/common/event/ge-state-change-event.js';
|
|
8
|
+
import { GeBatchEditEvent } from './data/common/event/ge-batch-edit-event.js';
|
|
9
|
+
import { GeRowDragEvent } from './data/common/event/ge-row-drag-event.js';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Empty implementation of {@link EventListenerIf} – extend it and override only the events you need.
|
|
@@ -33,4 +35,9 @@ export declare class EventAdapter implements EventListenerIf {
|
|
|
33
35
|
onFocusChanged(_model: FocusModelIf): void;
|
|
34
36
|
/** @since 1.1.92 */
|
|
35
37
|
onStateChanged(_evt: GeStateChangeEvent): void;
|
|
38
|
+
onRowDragStart(_evt: GeRowDragEvent): void;
|
|
39
|
+
onRowDragMove(_evt: GeRowDragEvent): void;
|
|
40
|
+
onRowDragEnd(_evt: GeRowDragEvent): void;
|
|
41
|
+
/** @since 1.1.96 */
|
|
42
|
+
onBatchEditChanged(_evt: GeBatchEditEvent): void;
|
|
36
43
|
}
|
|
@@ -2,6 +2,8 @@ import { GeMouseEvent } from './data/common/event/ge-mouse-event.js';
|
|
|
2
2
|
import { GeModelChangeEvent } from './data/common/event/ge-model-change-event.js';
|
|
3
3
|
import { GeScrollEvent } from './data/common/event/ge-scroll-event.js';
|
|
4
4
|
import { GeStateChangeEvent } from './data/common/event/ge-state-change-event.js';
|
|
5
|
+
import { GeRowDragEvent } from './data/common/event/ge-row-drag-event.js';
|
|
6
|
+
import { GeBatchEditEvent } from './data/common/event/ge-batch-edit-event.js';
|
|
5
7
|
import { SelectionModelIf } from './selection/selection-model.if.js';
|
|
6
8
|
import { FocusModelIf } from './focus/focus-model.if.js';
|
|
7
9
|
import { EventFocusChangedListenerIf } from './focus/event-focus-changed-listener.if.js';
|
|
@@ -63,4 +65,34 @@ export interface EventListenerIf extends EventFocusChangedListenerIf, EventSelec
|
|
|
63
65
|
* @since 1.1.92
|
|
64
66
|
*/
|
|
65
67
|
onStateChanged?(evt: GeStateChangeEvent): void;
|
|
68
|
+
/**
|
|
69
|
+
* Optional: a row drag started (drag handle moved past the threshold, or Ctrl+Alt+↑/↓). `evt.preventDefault()`
|
|
70
|
+
* cancels it. See {@link GeRowDragEvent}.
|
|
71
|
+
*
|
|
72
|
+
* @since 1.1.95
|
|
73
|
+
*/
|
|
74
|
+
onRowDragStart?(evt: GeRowDragEvent): void;
|
|
75
|
+
/**
|
|
76
|
+
* Optional: the drop target of a row drag changed (not on every pixel). `evt.preventDefault()` marks the target as
|
|
77
|
+
* invalid (no drop marker, no drop).
|
|
78
|
+
*
|
|
79
|
+
* @since 1.1.95
|
|
80
|
+
*/
|
|
81
|
+
onRowDragMove?(evt: GeRowDragEvent): void;
|
|
82
|
+
/**
|
|
83
|
+
* Optional: a row drag ended – `evt.type` is `"end"` (dropped; `evt.moved` = the table moved the rows) or `"cancel"`.
|
|
84
|
+
* Managed: called after the move (`evt.toIndex` = the real position). Save the new order here; to veto a drop, call
|
|
85
|
+
* `evt.preventDefault()` in {@link onRowDragMove}.
|
|
86
|
+
*
|
|
87
|
+
* @since 1.1.95
|
|
88
|
+
*/
|
|
89
|
+
onRowDragEnd?(evt: GeRowDragEvent): void;
|
|
90
|
+
/**
|
|
91
|
+
* The pending changes of a batch edit changed: values were marked, set back, written or discarded
|
|
92
|
+
* ({@link TableApi.startBatchEdit}, {@link TableOptionsIf.batchEdit}). Optional.
|
|
93
|
+
*
|
|
94
|
+
* @param {GeBatchEditEvent} evt - type, cells of this step, number of pending and invalid cells
|
|
95
|
+
* @since 1.1.96
|
|
96
|
+
*/
|
|
97
|
+
onBatchEditChanged?(evt: GeBatchEditEvent): void;
|
|
66
98
|
}
|
|
@@ -78,6 +78,17 @@ export interface CreateTableModelPara {
|
|
|
78
78
|
* @since 1.1.93
|
|
79
79
|
*/
|
|
80
80
|
rowNumbersVisible: boolean | Partial<RowNumberOptionsIf>;
|
|
81
|
+
/**
|
|
82
|
+
* Row drag: `true` puts a drag handle into the first data column (behind row numbers and checkboxes) –
|
|
83
|
+
* sets {@link ColumnDefIf.rowDrag} on that column definition. Options: {@link TableOptionsIf.rowDragOptions}.
|
|
84
|
+
* Default false.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* const tableModel = TableFactory.createTableModel({ rows: orders, rowDrag: true });
|
|
88
|
+
*
|
|
89
|
+
* @since 1.1.95
|
|
90
|
+
*/
|
|
91
|
+
rowDrag: boolean;
|
|
81
92
|
/** Row heights of header, body and footer in px. Default: `tableOptions.defaultRowHeights`, otherwise 34 / 34 / 34. */
|
|
82
93
|
defaultRowHeights: DefaultRowHeightsIf;
|
|
83
94
|
/** The columns: property, header label, width, classes, renderers, sorting, editing. See {@link ColumnDef}. */
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { CellRange } from '../data/common/cell-range.js';
|
|
2
|
+
import { CellValueChangeIf } from '../batch-edit/cell-value-change.if.js';
|
|
3
|
+
import { FillDirection } from './fill-direction.type.js';
|
|
4
|
+
import { FillValueContextIf } from './fill-value-context.if.js';
|
|
5
|
+
import { FillMode } from './fill-series.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Input of {@link computeFillChanges}.
|
|
9
|
+
*
|
|
10
|
+
* @category Fill handle & batch edit
|
|
11
|
+
* @since 1.1.96
|
|
12
|
+
*/
|
|
13
|
+
export interface FillRequestIf {
|
|
14
|
+
/** The selected source range (body display indices, `r1 <= r2`, `c1 <= c2`). */
|
|
15
|
+
source: CellRange;
|
|
16
|
+
/** Where the range is extended to. */
|
|
17
|
+
direction: FillDirection;
|
|
18
|
+
/** The number of rows (down/up) or columns (right/left) to fill. */
|
|
19
|
+
count: number;
|
|
20
|
+
/** Series or copy, see {@link FillMode}. */
|
|
21
|
+
mode?: FillMode;
|
|
22
|
+
/** The shown value of a cell (batch edit: the pending value). */
|
|
23
|
+
getValue: (rowIndex: number, columnIndex: number) => unknown;
|
|
24
|
+
/** `false` skips a target cell (not editable, hidden column …); the series keeps counting. */
|
|
25
|
+
isFillable?: (rowIndex: number, columnIndex: number) => boolean;
|
|
26
|
+
/** Own fill function, see {@link FillHandleOptionsIf.fillValue}. */
|
|
27
|
+
fillValue?: (ctx: FillValueContextIf) => unknown;
|
|
28
|
+
/** Row object and property of a cell – for `fillValue`. */
|
|
29
|
+
getCellInfo?: (rowIndex: number, columnIndex: number) => {
|
|
30
|
+
row: unknown;
|
|
31
|
+
property: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The cells a fill covers: the source range extended by `count` rows or columns in `direction`.
|
|
36
|
+
*
|
|
37
|
+
* @param {CellRange} source - the selected range
|
|
38
|
+
* @param {FillDirection} direction - the direction of the fill
|
|
39
|
+
* @param {number} count - rows or columns added
|
|
40
|
+
* @returns {CellRange} source and filled cells together
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* getFillRange(new CellRange(2, 1, 3, 1), "down", 3); // rows 2…6 of column 1
|
|
44
|
+
*
|
|
45
|
+
* @category Fill handle & batch edit
|
|
46
|
+
* @since 1.1.96
|
|
47
|
+
*/
|
|
48
|
+
export declare function getFillRange(source: CellRange, direction: FillDirection, count: number): CellRange;
|
|
49
|
+
/**
|
|
50
|
+
* The values a fill writes: per line of the source range (each column when filling down/up, each row when filling
|
|
51
|
+
* right/left) the continuation of its values ({@link computeFillValues}) – DOM-free, the table applies the result with
|
|
52
|
+
* {@link TableApi.applyCellChanges}.
|
|
53
|
+
*
|
|
54
|
+
* @param {FillRequestIf} request - source range, direction, count, value access
|
|
55
|
+
* @returns {CellValueChangeIf[]} one change per fillable target cell (column = model index)
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const values = [[1], [2]]; // a 2 × 1 source range
|
|
59
|
+
* computeFillChanges({
|
|
60
|
+
* source: new CellRange(0, 0, 1, 0), direction: "down", count: 2,
|
|
61
|
+
* getValue: (r, c) => values[r]?.[c],
|
|
62
|
+
* }); // [{ rowIndex: 2, column: 0, value: 3 }, { rowIndex: 3, column: 0, value: 4 }]
|
|
63
|
+
*
|
|
64
|
+
* @category Fill handle & batch edit
|
|
65
|
+
* @since 1.1.96
|
|
66
|
+
*/
|
|
67
|
+
export declare function computeFillChanges(request: FillRequestIf): CellValueChangeIf[];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FillHandleOptionsIf } from './fill-handle-options.if.js';
|
|
2
|
+
import { FillValueContextIf } from './fill-value-context.if.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The defaults of {@link FillHandleOptionsIf}.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const options = FillHandleOptions.create(true);
|
|
9
|
+
* options?.direction; // "both"
|
|
10
|
+
*
|
|
11
|
+
* @category Fill handle & batch edit
|
|
12
|
+
* @since 1.1.96
|
|
13
|
+
*/
|
|
14
|
+
export declare class FillHandleOptions implements FillHandleOptionsIf {
|
|
15
|
+
direction: "vertical" | "horizontal" | "both";
|
|
16
|
+
fillValue?: (ctx: FillValueContextIf) => unknown;
|
|
17
|
+
maxCells: number;
|
|
18
|
+
dragThresholdInPx: number;
|
|
19
|
+
autoScrollZoneInPx: number;
|
|
20
|
+
autoScrollMaxSpeedInPx: number;
|
|
21
|
+
/**
|
|
22
|
+
* The options of {@link TableOptionsIf.fillHandle}: `undefined`/`false` = no fill handle, `true` = the defaults, an
|
|
23
|
+
* object = the defaults overridden by its values (`undefined` keeps the default).
|
|
24
|
+
*
|
|
25
|
+
* @param {boolean | Partial<FillHandleOptionsIf>} [option] - `tableOptions.fillHandle`
|
|
26
|
+
* @returns {FillHandleOptionsIf | undefined} complete options, `undefined` if the fill handle is off
|
|
27
|
+
*/
|
|
28
|
+
static create(option?: boolean | Partial<FillHandleOptionsIf>): FillHandleOptionsIf | undefined;
|
|
29
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { FillValueContextIf } from './fill-value-context.if.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Options of the fill handle ({@link TableOptionsIf.fillHandle}): the small square at the bottom right corner of the
|
|
5
|
+
* selected range. Dragging it fills the neighbouring cells – copies values or continues series (1, 2, 3 …; dates;
|
|
6
|
+
* `Item 1` → `Item 2`). Needs a {@link SelectionModel} of the type `"range"`.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* const selectionModel = new SelectionModel("range", "multi"); // one model – not a new one per call
|
|
10
|
+
* const tableOptions: TableOptionsIf = {
|
|
11
|
+
* ...new TableOptions(),
|
|
12
|
+
* getSelectionModel: () => selectionModel,
|
|
13
|
+
* fillHandle: { direction: "vertical" },
|
|
14
|
+
* };
|
|
15
|
+
*
|
|
16
|
+
* @category Fill handle & batch edit
|
|
17
|
+
* @since 1.1.96
|
|
18
|
+
*/
|
|
19
|
+
export interface FillHandleOptionsIf {
|
|
20
|
+
/** Allowed directions: `"vertical"` (down/up), `"horizontal"` (right/left) or `"both"` (default). */
|
|
21
|
+
direction: "vertical" | "horizontal" | "both";
|
|
22
|
+
/**
|
|
23
|
+
* Own fill function, called for every filled cell. Return the value – or `undefined` for the default
|
|
24
|
+
* (`ctx.defaultValue`).
|
|
25
|
+
*/
|
|
26
|
+
fillValue?: (ctx: FillValueContextIf) => unknown;
|
|
27
|
+
/** At most this many cells are filled at once (default 100,000); a bigger fill is refused and announced. */
|
|
28
|
+
maxCells: number;
|
|
29
|
+
/** Distance in px the pointer has to move before a fill starts (default 3). */
|
|
30
|
+
dragThresholdInPx: number;
|
|
31
|
+
/** Width in px of the zone at the edges of the body that scrolls automatically (default 40). */
|
|
32
|
+
autoScrollZoneInPx: number;
|
|
33
|
+
/** Maximum auto-scroll speed in px per animation frame (default 24). */
|
|
34
|
+
autoScrollMaxSpeedInPx: number;
|
|
35
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { TableScope } from '../table-scope.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The fill handle of one table (`tableScope.fillHandleService`): the square at the bottom right corner of the selected
|
|
5
|
+
* range, the pointer drag with preview and auto-scroll, Escape. The values come from {@link TableScope.fillRange}.
|
|
6
|
+
* Use {@link TableApi.fillRange}, {@link TableApi.isFilling} and {@link TableApi.cancelFill} instead.
|
|
7
|
+
*
|
|
8
|
+
* Pointer Events (mouse, touch, pen) only on the handle; its `pointerdown` is prevented, so the mouse handler of the
|
|
9
|
+
* table (range selection, column drag) never sees it.
|
|
10
|
+
*
|
|
11
|
+
* @category Internals
|
|
12
|
+
* @since 1.1.96
|
|
13
|
+
*/
|
|
14
|
+
export declare class FillHandleService {
|
|
15
|
+
private readonly tableScope;
|
|
16
|
+
private handle?;
|
|
17
|
+
private preview?;
|
|
18
|
+
private pending?;
|
|
19
|
+
private session?;
|
|
20
|
+
private sessionAbortController?;
|
|
21
|
+
private autoScrollFrame;
|
|
22
|
+
private suppressClick;
|
|
23
|
+
private shortcutsSet;
|
|
24
|
+
constructor(tableScope: TableScope);
|
|
25
|
+
/** true while the handle is dragged. */
|
|
26
|
+
isFilling(): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Places the handle at the bottom right corner of the last selected range (called after every render pass) – or
|
|
29
|
+
* hides it: no fill handle option, no range, the corner scrolled out, an open editor, a blocking overlay.
|
|
30
|
+
*/
|
|
31
|
+
update(): void;
|
|
32
|
+
/** The handle's position (the corner of the range) in host coordinates – `undefined` if it is not visible. */
|
|
33
|
+
private getCornerOf;
|
|
34
|
+
private ensureHandle;
|
|
35
|
+
private removeHandle;
|
|
36
|
+
/** Keyboard alternative on the grid: Ctrl/⌘+D, Ctrl/⌘+R (only directions the options allow). */
|
|
37
|
+
private updateHostShortcuts;
|
|
38
|
+
private isHandle;
|
|
39
|
+
private onPointerDown;
|
|
40
|
+
private listenToDocument;
|
|
41
|
+
private onPointerMove;
|
|
42
|
+
private onPointerUp;
|
|
43
|
+
private suppressNextClick;
|
|
44
|
+
private onClickCapture;
|
|
45
|
+
/** Target cell under the pointer → direction and count; preview; auto-scroll. */
|
|
46
|
+
private updateTarget;
|
|
47
|
+
private renderPreview;
|
|
48
|
+
private updateAutoScroll;
|
|
49
|
+
private autoScrollStep;
|
|
50
|
+
/** Cancels a running fill (Escape, `pointercancel`, {@link TableApi.cancelFill}): nothing is changed. */
|
|
51
|
+
cancel(): void;
|
|
52
|
+
private stopListening;
|
|
53
|
+
/** Releases everything (TableScope.destroy). */
|
|
54
|
+
destroy(): void;
|
|
55
|
+
}
|