@guiexpert/table 1.1.96 → 1.1.98
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 +7 -0
- package/css/main.css +192 -27
- package/css/table-classes.css +33 -9
- package/css/table-color-vars.css +12 -0
- package/css/table-fill-batch.css +9 -2
- package/css/table-master-detail.css +115 -0
- package/css/table-tree.css +23 -16
- package/index.cjs +50 -50
- package/index.d.ts +12 -0
- package/index.js +3996 -2631
- package/lib/table/aria/aria-ids.d.ts +7 -0
- package/lib/table/aria/aria-texts.d.ts +2 -0
- package/lib/table/aria/aria-texts.if.d.ts +14 -0
- package/lib/table/crud/crud-object-edit.d.ts +2 -0
- package/lib/table/crud/crud-object-view.d.ts +2 -0
- package/lib/table/crud/crud-table-model-factory.d.ts +2 -0
- package/lib/table/data/common/event/ge-detail-event.d.ts +40 -0
- package/lib/table/data/options/auto-restore-options.d.ts +2 -0
- package/lib/table/data/options/auto-restore-options.if.d.ts +6 -0
- package/lib/table/data/options/table-options.d.ts +8 -0
- package/lib/table/data/options/table-options.if.d.ts +35 -0
- package/lib/table/ele-scope.d.ts +51 -0
- package/lib/table/event-adapter.d.ts +3 -0
- package/lib/table/event-listener.if.d.ts +7 -0
- package/lib/table/master-detail/detail-renderer.if.d.ts +99 -0
- package/lib/table/master-detail/master-detail-options.d.ts +30 -0
- package/lib/table/master-detail/master-detail-options.if.d.ts +60 -0
- package/lib/table/master-detail/master-detail-service.d.ts +223 -0
- package/lib/table/render-scope.d.ts +73 -0
- package/lib/table/row-layout/row-layout.d.ts +120 -0
- package/lib/table/rtl/rtl-util.d.ts +126 -0
- package/lib/table/rtl/table-direction.type.d.ts +23 -0
- package/lib/table/service/convenience-dom.service.d.ts +49 -1
- package/lib/table/service/excel-export-options.if.d.ts +17 -0
- package/lib/table/service/excel-service.d.ts +8 -2
- package/lib/table/service/excel-service.if.d.ts +3 -1
- package/lib/table/state/table-state.if.d.ts +4 -1
- package/lib/table/state/table-state.service.d.ts +4 -0
- package/lib/table/table-api.d.ts +123 -2
- package/lib/table/table-scope.d.ts +69 -0
- package/package.json +1 -1
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { TableScope } from '../table-scope.js';
|
|
2
|
+
import { TableApi } from '../table-api.js';
|
|
3
|
+
import { TableModelIf } from '../data/tablemodel/table-model.if.js';
|
|
4
|
+
import { TableOptionsIf } from '../data/options/table-options.if.js';
|
|
5
|
+
import { EventListenerIf } from '../event-listener.if.js';
|
|
6
|
+
import { GeDetailEventSource } from '../data/common/event/ge-detail-event.js';
|
|
7
|
+
import { MasterDetailOptionsIf } from './master-detail-options.if.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The part of a nested table the master/detail service needs (a {@link TableScope}).
|
|
11
|
+
*
|
|
12
|
+
* @category Internals
|
|
13
|
+
* @since 1.1.97
|
|
14
|
+
*/
|
|
15
|
+
export interface NestedTableScopeIf {
|
|
16
|
+
firstInit(): unknown;
|
|
17
|
+
getApi(): TableApi;
|
|
18
|
+
destroy(): void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates the {@link TableScope} of a nested table (given by `TableScope` – no import cycle).
|
|
22
|
+
*
|
|
23
|
+
* @category Internals
|
|
24
|
+
* @since 1.1.97
|
|
25
|
+
*/
|
|
26
|
+
export type NestedTableScopeFactory = (host: HTMLDivElement, tableModel: TableModelIf, tableOptions: TableOptionsIf | undefined, eventListener: EventListenerIf | undefined) => NestedTableScopeIf;
|
|
27
|
+
/**
|
|
28
|
+
* Master/detail of a table ({@link TableOptionsIf.masterDetail}): the expanded master rows, the detail layer and the
|
|
29
|
+
* life cycle of the detail contents. Created by {@link TableScope} (`tableScope.masterDetailService`); use the
|
|
30
|
+
* {@link TableApi} (`setDetailExpanded`, `toggleDetail` …).
|
|
31
|
+
*
|
|
32
|
+
* - **Layer**: one div `ge-table-detail-layer` in the host, over the body (full width, fixed columns included, without
|
|
33
|
+
* the scroll bars). It is never cleared by the virtual rendering and does not scroll horizontally.
|
|
34
|
+
* - **Positions**: the heights of the detail rows are extras of the body {@link RowLayout} (behind their master row);
|
|
35
|
+
* `RenderScope` reports the detail rows in view after every render pass ({@link layoutVisible}).
|
|
36
|
+
* - **Life cycle**: the content is created when the detail row becomes visible, hidden (not destroyed) when it scrolls
|
|
37
|
+
* out of view, destroyed when it is collapsed, beyond `maxRenderedDetails` or when the table is destroyed.
|
|
38
|
+
* - **Events**: mouse, keyboard and pointer events from a detail row are ignored by the outer table
|
|
39
|
+
* ({@link isInLayer}); the mouse wheel over a detail row scrolls the outer table when nothing in the detail scrolls.
|
|
40
|
+
*
|
|
41
|
+
* @category Internals
|
|
42
|
+
* @since 1.1.97
|
|
43
|
+
*/
|
|
44
|
+
export declare class MasterDetailService {
|
|
45
|
+
private readonly scope;
|
|
46
|
+
private readonly createNestedScope;
|
|
47
|
+
/** The complete options (defaults + `tableOptions.masterDetail`). */
|
|
48
|
+
readonly options: MasterDetailOptionsIf;
|
|
49
|
+
private readonly active;
|
|
50
|
+
private layer?;
|
|
51
|
+
private readonly entries;
|
|
52
|
+
private byIndex;
|
|
53
|
+
private visibleNow;
|
|
54
|
+
private renderPass;
|
|
55
|
+
private renderedCount;
|
|
56
|
+
private toggleColumnIndex;
|
|
57
|
+
private resizeFrame;
|
|
58
|
+
private destroyed;
|
|
59
|
+
constructor(scope: TableScope, createNestedScope: NestedTableScopeFactory);
|
|
60
|
+
/** True if master/detail is configured (and the body is flat). */
|
|
61
|
+
isActive(): boolean;
|
|
62
|
+
/** True if at least one master row is expanded. */
|
|
63
|
+
hasExpanded(): boolean;
|
|
64
|
+
/** The detail layer (`undefined` without master/detail). */
|
|
65
|
+
getLayer(): HTMLDivElement | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* True if an event comes from a detail row (or a nested table in it) – the outer table ignores it.
|
|
68
|
+
*
|
|
69
|
+
* @param {Event} evt - a DOM event while it is dispatched
|
|
70
|
+
* @returns {boolean} whether its path contains the detail layer
|
|
71
|
+
*/
|
|
72
|
+
isInLayer(evt: Event): boolean;
|
|
73
|
+
/** The id of a master row: `options.getRowId`, `autoRestoreOptions.getRowId`, the row object or its index. */
|
|
74
|
+
keyOf(row: unknown, rowIndex: number): unknown;
|
|
75
|
+
/**
|
|
76
|
+
* True if the row at a display index can be expanded ({@link MasterDetailOptionsIf.isMaster}).
|
|
77
|
+
*
|
|
78
|
+
* @param {number} rowIndex - display index
|
|
79
|
+
* @returns {boolean} whether it is a master row
|
|
80
|
+
*/
|
|
81
|
+
isMasterAt(rowIndex: number): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* True if the master row at a display index is expanded.
|
|
84
|
+
*
|
|
85
|
+
* @param {number} rowIndex - display index
|
|
86
|
+
* @returns {boolean} whether its detail row is open
|
|
87
|
+
*/
|
|
88
|
+
isExpandedAt(rowIndex: number): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* True if a row (display index or row object) is expanded.
|
|
91
|
+
*
|
|
92
|
+
* @param {number | object} rowOrIndex - display index or row object
|
|
93
|
+
* @returns {boolean} whether its detail row is open
|
|
94
|
+
*/
|
|
95
|
+
isExpanded(rowOrIndex: unknown): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Expands or collapses a master row. The table repaints and reports the change ({@link TableScope}).
|
|
98
|
+
*
|
|
99
|
+
* @param {number | object} rowOrIndex - display index or row object
|
|
100
|
+
* @param {boolean} expanded - the new state
|
|
101
|
+
* @param {GeDetailEventSource} [source] - what changed it (for the event)
|
|
102
|
+
* @returns {boolean} false if nothing changed (no master row, already in that state, no master/detail)
|
|
103
|
+
*/
|
|
104
|
+
setExpanded(rowOrIndex: unknown, expanded: boolean, source?: GeDetailEventSource): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Expands all master rows that are shown (their contents are created only when they scroll into view).
|
|
107
|
+
* No event per row.
|
|
108
|
+
*
|
|
109
|
+
* @returns {number} the number of rows that were expanded
|
|
110
|
+
*/
|
|
111
|
+
expandAll(): number;
|
|
112
|
+
/**
|
|
113
|
+
* Collapses all detail rows (their contents are destroyed). No event per row.
|
|
114
|
+
*
|
|
115
|
+
* @returns {number} the number of rows that were collapsed
|
|
116
|
+
*/
|
|
117
|
+
collapseAll(): number;
|
|
118
|
+
/** The expanded master rows (row objects; for models without row objects: `undefined`). */
|
|
119
|
+
getExpandedRows(): unknown[];
|
|
120
|
+
/**
|
|
121
|
+
* Expands exactly these rows and collapses all others – the restore of the table state. Rows that are no master
|
|
122
|
+
* rows are skipped. No event per row.
|
|
123
|
+
*
|
|
124
|
+
* @param {unknown[]} rows - row objects of the body model
|
|
125
|
+
* @param {GeDetailEventSource} [source] - what changed it
|
|
126
|
+
* @returns {boolean} true if something changed
|
|
127
|
+
*/
|
|
128
|
+
setExpandedRows(rows: readonly unknown[], source?: GeDetailEventSource): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Destroys the content of a detail row and creates it again (e.g. after the row's data changed).
|
|
131
|
+
*
|
|
132
|
+
* @param {number | object} rowOrIndex - display index or row object
|
|
133
|
+
* @returns {boolean} false if the row is not expanded
|
|
134
|
+
*/
|
|
135
|
+
refresh(rowOrIndex: unknown): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* The container of a detail row (the element `detailRenderer` renders into) – only while its content exists.
|
|
138
|
+
*
|
|
139
|
+
* @param {number | object} rowOrIndex - display index or row object
|
|
140
|
+
* @returns {HTMLDivElement | undefined} the container
|
|
141
|
+
*/
|
|
142
|
+
getDetailElement(rowOrIndex: unknown): HTMLDivElement | undefined;
|
|
143
|
+
/**
|
|
144
|
+
* The display index of the master row a DOM node belongs to (a detail row or something in it).
|
|
145
|
+
*
|
|
146
|
+
* @param {Node} node - a node in the detail layer
|
|
147
|
+
* @returns {number} the display index, -1 if none
|
|
148
|
+
*/
|
|
149
|
+
getMasterRowIndexOf(node: Node | null): number;
|
|
150
|
+
/**
|
|
151
|
+
* The display indices and heights of the expanded master rows that are shown – the extras of the body row layout.
|
|
152
|
+
* Called by `RenderScope` when the row layout is built (after filtering, sorting, editing, a detail toggle …): one
|
|
153
|
+
* pass over the shown rows. Removes expanded rows that no longer exist in the model (`getAllRows()`).
|
|
154
|
+
*
|
|
155
|
+
* @returns {{ rowIndices: number[], heights: number[] } | undefined} the extras, `undefined` without expanded rows
|
|
156
|
+
*/
|
|
157
|
+
computeExtras(): {
|
|
158
|
+
rowIndices: number[];
|
|
159
|
+
heights: number[];
|
|
160
|
+
} | undefined;
|
|
161
|
+
/**
|
|
162
|
+
* Called at the start of the body render pass: the column of the expand icon.
|
|
163
|
+
*/
|
|
164
|
+
startRenderPass(): void;
|
|
165
|
+
/**
|
|
166
|
+
* Shows the detail rows in view (called by `RenderScope` after the body rows were rendered): creates missing
|
|
167
|
+
* contents, sets their positions, hides the ones that left the view and destroys the oldest hidden contents beyond
|
|
168
|
+
* {@link MasterDetailOptionsIf.maxRenderedDetails}.
|
|
169
|
+
*
|
|
170
|
+
* @param {number[]} triples - `rowIndex, top, height` of each detail row in view; `top` relative to the body top
|
|
171
|
+
*/
|
|
172
|
+
layoutVisible(triples: number[]): void;
|
|
173
|
+
/**
|
|
174
|
+
* Position and size of the layer: the visible body including the fixed columns, without the scroll bars.
|
|
175
|
+
*
|
|
176
|
+
* @param {number} left - px in the host
|
|
177
|
+
* @param {number} top - px in the host (below the header)
|
|
178
|
+
* @param {number} width - px
|
|
179
|
+
* @param {number} height - px
|
|
180
|
+
*/
|
|
181
|
+
setBounds(left: number, top: number, width: number, height: number): void;
|
|
182
|
+
/**
|
|
183
|
+
* Decorates a body cell of the toggle column of a master row with the expand icon (`ge-table-detail-toggle`).
|
|
184
|
+
*
|
|
185
|
+
* @param {HTMLDivElement} cell - the rendered cell
|
|
186
|
+
* @param {number} rowIndex - display index
|
|
187
|
+
* @param {number} columnIndex - model column index
|
|
188
|
+
*/
|
|
189
|
+
decorateCell(cell: HTMLDivElement, rowIndex: number, columnIndex: number): void;
|
|
190
|
+
/**
|
|
191
|
+
* Called when the table is destroyed: destroys all detail contents and removes the layer.
|
|
192
|
+
*/
|
|
193
|
+
destroy(): void;
|
|
194
|
+
private getBody;
|
|
195
|
+
private getAllRows;
|
|
196
|
+
/** isMaster for a row that is not shown (filtered out) – the index is unknown (-1). */
|
|
197
|
+
private isMasterRow;
|
|
198
|
+
/** `[row, rowIndex]` of a display index or a row object (index -1 if the row is not shown). */
|
|
199
|
+
private resolve;
|
|
200
|
+
private heightOf;
|
|
201
|
+
private detailHeightOf;
|
|
202
|
+
private computeToggleColumnIndex;
|
|
203
|
+
private pruneRemovedRows;
|
|
204
|
+
private createLayer;
|
|
205
|
+
private createContent;
|
|
206
|
+
private createNestedTable;
|
|
207
|
+
private place;
|
|
208
|
+
private park;
|
|
209
|
+
/** The focus is inside a detail row that is hidden or removed: the master table (row) takes it. */
|
|
210
|
+
private releaseFocus;
|
|
211
|
+
private onResize;
|
|
212
|
+
private enforceLimit;
|
|
213
|
+
private destroyContent;
|
|
214
|
+
private clearAll;
|
|
215
|
+
/** The mouse wheel over a detail row: scrolls the outer table if nothing in the detail row takes the movement. */
|
|
216
|
+
private onWheel;
|
|
217
|
+
private canScrollInside;
|
|
218
|
+
/** Tab on a master row with an open detail row: the focus moves to the first focusable element in it. */
|
|
219
|
+
private onHostKeyDown;
|
|
220
|
+
/** The host got the focus back from a detail row (Shift+Tab): its master row gets the focus. */
|
|
221
|
+
private onHostFocus;
|
|
222
|
+
private findFocusable;
|
|
223
|
+
}
|
|
@@ -26,6 +26,8 @@ import { AreaObjectMapType } from './data/common/area-map.type.js';
|
|
|
26
26
|
import { TableCellUpdateEventIf } from './data/common/event/input/table-cell-update-event.if.js';
|
|
27
27
|
import { AriaGridInfo } from './aria/aria-grid-info.js';
|
|
28
28
|
import { AriaTextsIf } from './aria/aria-texts.if.js';
|
|
29
|
+
import { RowLayout } from './row-layout/row-layout.js';
|
|
30
|
+
import { MasterDetailService } from './master-detail/master-detail-service.js';
|
|
29
31
|
|
|
30
32
|
/** @category Internals */
|
|
31
33
|
export declare class RenderScope extends EleScope {
|
|
@@ -103,6 +105,16 @@ export declare class RenderScope extends EleScope {
|
|
|
103
105
|
* @since 1.1.96
|
|
104
106
|
*/
|
|
105
107
|
fillHandleService?: FillHandleService;
|
|
108
|
+
/**
|
|
109
|
+
* Master/detail of this table (detail rows below master rows) – created by {@link TableScope} with
|
|
110
|
+
* `tableOptions.masterDetail`.
|
|
111
|
+
* @since 1.1.97
|
|
112
|
+
*/
|
|
113
|
+
masterDetailService?: MasterDetailService;
|
|
114
|
+
/** Positions of the body rows (prefix sums of the heights + detail rows), see {@link getBodyRowLayout}. */
|
|
115
|
+
private readonly bodyRowLayout;
|
|
116
|
+
private bodyRowLayoutDirty;
|
|
117
|
+
private bodyRowLayoutModel?;
|
|
106
118
|
constructor(hostElement: HTMLDivElement, tableModel: TableModelIf, dom: ConvenienceDomService, tableOptions: TableOptionsIf);
|
|
107
119
|
/**
|
|
108
120
|
* The DOM service of this table (all DOM access of the table goes through it).
|
|
@@ -155,6 +167,52 @@ export declare class RenderScope extends EleScope {
|
|
|
155
167
|
* @since 1.1.96
|
|
156
168
|
*/
|
|
157
169
|
getBodyCellAtHostPoint(x: number, y: number): [number, number];
|
|
170
|
+
/**
|
|
171
|
+
* The positions of the body rows: prefix sums of the row heights (O(log n) lookups also for variable heights) plus
|
|
172
|
+
* the heights of open detail rows. Built lazily – again after {@link invalidateRowLayout}, a new body model or
|
|
173
|
+
* another row count.
|
|
174
|
+
*
|
|
175
|
+
* @returns {RowLayout} the layout of the body rows
|
|
176
|
+
* @since 1.1.97
|
|
177
|
+
*/
|
|
178
|
+
getBodyRowLayout(): RowLayout;
|
|
179
|
+
/**
|
|
180
|
+
* Marks the positions of the body rows as outdated (rows filtered, sorted, edited, added or removed, a detail row
|
|
181
|
+
* opened or closed) – they are computed again on the next access.
|
|
182
|
+
*
|
|
183
|
+
* @since 1.1.97
|
|
184
|
+
*/
|
|
185
|
+
invalidateRowLayout(): void;
|
|
186
|
+
/**
|
|
187
|
+
* Sets the height of the detail row behind one body row in the current row layout without building it again
|
|
188
|
+
* (a detail row was expanded or collapsed). Does nothing if the layout is outdated anyway.
|
|
189
|
+
*
|
|
190
|
+
* @param {number} rowIndex - display index of the master row
|
|
191
|
+
* @param {number} height - the detail height, 0 = none
|
|
192
|
+
* @returns {boolean} true if the layout was updated, false if it is outdated (it is built again on the next access)
|
|
193
|
+
* @since 1.1.97
|
|
194
|
+
*/
|
|
195
|
+
setBodyRowExtra(rowIndex: number, height: number): boolean;
|
|
196
|
+
/** True if open detail rows take space between the body rows. */
|
|
197
|
+
protected hasBodyRowExtras(): boolean;
|
|
198
|
+
/**
|
|
199
|
+
* The top of a body row in content pixels: {@link AreaModelIf.getYPosByRowIndex} plus the heights of the open detail
|
|
200
|
+
* rows above it (master/detail).
|
|
201
|
+
*
|
|
202
|
+
* @param {number} rowIndex - display index
|
|
203
|
+
* @returns {number} px from the top of the first body row
|
|
204
|
+
* @since 1.1.97
|
|
205
|
+
*/
|
|
206
|
+
getBodyRowTop(rowIndex: number): number;
|
|
207
|
+
/**
|
|
208
|
+
* The body row at a content position (a position in an open detail row belongs to its master row). Above the rows:
|
|
209
|
+
* 0, below: the last row, without rows: -1.
|
|
210
|
+
*
|
|
211
|
+
* @param {number} contentY - px from the top of the first body row
|
|
212
|
+
* @returns {number} display index
|
|
213
|
+
* @since 1.1.97
|
|
214
|
+
*/
|
|
215
|
+
getBodyRowIndexAtY(contentY: number): number;
|
|
158
216
|
/**
|
|
159
217
|
* Scroll bar pixels per content pixel: 1, below 1 for a capped scroll height ({@link isScrollHeightCapped}).
|
|
160
218
|
*
|
|
@@ -338,6 +396,15 @@ export declare class RenderScope extends EleScope {
|
|
|
338
396
|
* scaled and scrollTop is no longer a content pixel position.
|
|
339
397
|
*/
|
|
340
398
|
isScrollHeightCapped(): boolean;
|
|
399
|
+
/**
|
|
400
|
+
* The model's content height plus the heights of open detail rows (master/detail).
|
|
401
|
+
*
|
|
402
|
+
* @returns {number} px
|
|
403
|
+
* @since 1.1.97
|
|
404
|
+
*/
|
|
405
|
+
/** The detail layer (master/detail) covers the visible body. @since 1.1.97 */
|
|
406
|
+
protected adjustDetailLayerBounds(left: number, top: number, width: number, height: number): void;
|
|
407
|
+
protected getBodyContentHeight(): number;
|
|
341
408
|
/** Scrollable range of the content in content pixels (content height minus visible body height). */
|
|
342
409
|
protected getContentScrollRangeY(): number;
|
|
343
410
|
/** Scrollable range of the scroll viewport in scroll bar pixels. */
|
|
@@ -550,6 +617,12 @@ export declare class RenderScope extends EleScope {
|
|
|
550
617
|
*
|
|
551
618
|
* @returns {void}
|
|
552
619
|
*/
|
|
620
|
+
/**
|
|
621
|
+
* Hides the hover row and column – e.g. while the pointer is over a detail row (master/detail).
|
|
622
|
+
*
|
|
623
|
+
* @since 1.1.97
|
|
624
|
+
*/
|
|
625
|
+
hideHover(): void;
|
|
553
626
|
protected hideHoverRow(): void;
|
|
554
627
|
/**
|
|
555
628
|
* Adjusts the position and size of the hover column based on the mouse move event.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vertical positions of the body rows: the row heights as prefix sums plus optional extra heights behind single rows
|
|
3
|
+
* (the detail rows of master/detail). DOM-free; the table keeps one instance for its body
|
|
4
|
+
* ({@link RenderScope.getBodyRowTop}, {@link RenderScope.getBodyRowIndexAtY}).
|
|
5
|
+
*
|
|
6
|
+
* - Constant row height: positions are computed (`i * h`), no array.
|
|
7
|
+
* - Variable row heights: a `Float64Array` of `rowCount + 1` prefix sums, built lazily on the first access after
|
|
8
|
+
* {@link setRows} – then {@link getTop} is O(1) and {@link findIndexAt} O(log n) (before 1.1.97 the table summed the
|
|
9
|
+
* heights of all rows above the viewport in every scroll frame).
|
|
10
|
+
* - Extras: sorted row indices with their extra heights and the prefix sums of the extras (O(log k) per lookup,
|
|
11
|
+
* k = number of extras). Changing one extra height ({@link setExtraHeight}) costs O(k), not O(n).
|
|
12
|
+
*
|
|
13
|
+
* The slot of a row is the row plus its extra height below it: `getTop(i + 1) = getTop(i) + getRowHeight(i) +
|
|
14
|
+
* getExtraHeight(i)`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const layout = new RowLayout();
|
|
18
|
+
* layout.setRows(1000, i => i % 2 ? 30 : 50); // variable heights
|
|
19
|
+
* layout.setExtras([12, 40], [180, 240]); // details behind rows 12 and 40
|
|
20
|
+
* const top = layout.getTop(41); // top of row 41 below both details
|
|
21
|
+
* const row = layout.findIndexAt(5000); // the row whose slot contains y = 5000
|
|
22
|
+
*
|
|
23
|
+
* @category Internals
|
|
24
|
+
* @since 1.1.97
|
|
25
|
+
*/
|
|
26
|
+
export declare class RowLayout {
|
|
27
|
+
private rowCount;
|
|
28
|
+
private constantHeight?;
|
|
29
|
+
private heightOf;
|
|
30
|
+
private prefix?;
|
|
31
|
+
private extraIndices;
|
|
32
|
+
private extraHeights;
|
|
33
|
+
private extraPrefix;
|
|
34
|
+
/**
|
|
35
|
+
* Sets the rows. Prefix sums of variable heights are built lazily on the first access.
|
|
36
|
+
* Extras behind rows that no longer exist are dropped.
|
|
37
|
+
*
|
|
38
|
+
* @param {number} rowCount - number of rows
|
|
39
|
+
* @param {(rowIndex: number) => number} heightOf - height of a row (called only for variable heights)
|
|
40
|
+
* @param {number} [constantHeight] - the height of every row, if they are all equal (`AreaModelIf.getConstantRowHeight`)
|
|
41
|
+
*/
|
|
42
|
+
setRows(rowCount: number, heightOf: (rowIndex: number) => number, constantHeight?: number): void;
|
|
43
|
+
/**
|
|
44
|
+
* Sets the extra heights (e.g. detail rows) behind rows. Unsorted input is fine; heights of the same row add up;
|
|
45
|
+
* indices outside the rows and heights ≤ 0 are ignored. Replaces all previous extras.
|
|
46
|
+
*
|
|
47
|
+
* @param {ArrayLike<number>} rowIndices - the rows with an extra height below them
|
|
48
|
+
* @param {ArrayLike<number>} heights - the extra heights (same order as `rowIndices`)
|
|
49
|
+
*/
|
|
50
|
+
setExtras(rowIndices: ArrayLike<number>, heights: ArrayLike<number>): void;
|
|
51
|
+
/**
|
|
52
|
+
* Changes the extra height behind one row that already has one (see {@link setExtras}).
|
|
53
|
+
*
|
|
54
|
+
* @param {number} rowIndex - the row
|
|
55
|
+
* @param {number} height - the new extra height (> 0)
|
|
56
|
+
* @returns {boolean} false if the row has no extra or the height did not change
|
|
57
|
+
*/
|
|
58
|
+
setExtraHeight(rowIndex: number, height: number): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Sets, changes or (height ≤ 0) removes the extra height behind one row – O(k), the other extras stay.
|
|
61
|
+
*
|
|
62
|
+
* @param {number} rowIndex - the row (ignored outside the rows)
|
|
63
|
+
* @param {number} height - the extra height, ≤ 0 removes it
|
|
64
|
+
* @returns {boolean} true if something changed
|
|
65
|
+
*/
|
|
66
|
+
setExtra(rowIndex: number, height: number): boolean;
|
|
67
|
+
/** The number of rows. */
|
|
68
|
+
getRowCount(): number;
|
|
69
|
+
/** The number of rows with an extra height. */
|
|
70
|
+
getExtraCount(): number;
|
|
71
|
+
/** True after the prefix sums of variable heights were built (never for constant heights). */
|
|
72
|
+
hasPrefixSums(): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* The height of a row (without its extra).
|
|
75
|
+
*
|
|
76
|
+
* @param {number} rowIndex - the row
|
|
77
|
+
* @returns {number} the height in px
|
|
78
|
+
*/
|
|
79
|
+
getRowHeight(rowIndex: number): number;
|
|
80
|
+
/**
|
|
81
|
+
* The extra height below a row (0 = none).
|
|
82
|
+
*
|
|
83
|
+
* @param {number} rowIndex - the row
|
|
84
|
+
* @returns {number} the extra height in px
|
|
85
|
+
*/
|
|
86
|
+
getExtraHeight(rowIndex: number): number;
|
|
87
|
+
/**
|
|
88
|
+
* The sum of the extra heights of the rows above a row.
|
|
89
|
+
*
|
|
90
|
+
* @param {number} rowIndex - the row (`rowCount` = all extras)
|
|
91
|
+
* @returns {number} px
|
|
92
|
+
*/
|
|
93
|
+
getExtraBefore(rowIndex: number): number;
|
|
94
|
+
/** The sum of all extra heights. */
|
|
95
|
+
getExtraTotal(): number;
|
|
96
|
+
/**
|
|
97
|
+
* The top of a row: heights and extras of all rows above it. `getTop(rowCount)` = total height. The index is
|
|
98
|
+
* clamped to `0 … rowCount`.
|
|
99
|
+
*
|
|
100
|
+
* @param {number} rowIndex - the row
|
|
101
|
+
* @returns {number} px from the top of the first row
|
|
102
|
+
*/
|
|
103
|
+
getTop(rowIndex: number): number;
|
|
104
|
+
/** The height of all rows and extras. */
|
|
105
|
+
getTotalHeight(): number;
|
|
106
|
+
/**
|
|
107
|
+
* The row whose slot (row + extra) contains `y`; rows of height 0 are skipped. Above the first row: 0, below the
|
|
108
|
+
* last: the last row, without rows: -1. O(1) for constant heights without extras, otherwise O(log n).
|
|
109
|
+
*
|
|
110
|
+
* @param {number} y - px from the top of the first row
|
|
111
|
+
* @returns {number} the row index
|
|
112
|
+
*/
|
|
113
|
+
findIndexAt(y: number): number;
|
|
114
|
+
private getBaseTop;
|
|
115
|
+
private ensurePrefix;
|
|
116
|
+
private rebuildExtraPrefix;
|
|
117
|
+
/** The number of extras behind rows with an index < rowIndex (lower bound). */
|
|
118
|
+
private countExtrasBelow;
|
|
119
|
+
private findExtra;
|
|
120
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ResolvedTableDirection, TableDirection } from './table-direction.type.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Decides the direction of a table: `"rtl"` and `"ltr"` as given, `"auto"` from the computed `direction` of the host
|
|
5
|
+
* (inherited from `<html dir="rtl">` or any parent) – for a host that is not in the document yet from the nearest
|
|
6
|
+
* `dir` attribute of the host or a parent. Missing (`undefined`) = `"ltr"`.
|
|
7
|
+
*
|
|
8
|
+
* Must be called before the table sets the `dir` attribute of the host.
|
|
9
|
+
*
|
|
10
|
+
* @param {TableDirection | undefined} direction - the option ({@link TableOptionsIf.direction})
|
|
11
|
+
* @param {HTMLElement} [host] - the host element of the table (needed for `"auto"`)
|
|
12
|
+
* @returns {ResolvedTableDirection} `"ltr"` or `"rtl"`
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* resolveTableDirection("auto", document.getElementById("table")!); // "rtl" on a page with <html dir="rtl">
|
|
16
|
+
*
|
|
17
|
+
* @since 1.1.98
|
|
18
|
+
* @category Utilities
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveTableDirection(direction: TableDirection | undefined, host?: HTMLElement): ResolvedTableDirection;
|
|
21
|
+
/**
|
|
22
|
+
* The horizontal scroll position of an element as distance from the **start** (≥ 0): in left-to-right `scrollLeft`,
|
|
23
|
+
* in right-to-left `-scrollLeft` (browsers report 0 at the right start and negative values when scrolled to the left,
|
|
24
|
+
* CSSOM View).
|
|
25
|
+
*
|
|
26
|
+
* @param {{ scrollLeft: number }} element - a scroll container
|
|
27
|
+
* @param {boolean} rtl - the container is right-to-left
|
|
28
|
+
* @returns {number} px from the start
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* const fromStart = getLogicalScrollLeft(tableApi.getTableScope().scrollViewport, tableApi.getDirection() === "rtl");
|
|
32
|
+
*
|
|
33
|
+
* @since 1.1.98
|
|
34
|
+
* @category Utilities
|
|
35
|
+
*/
|
|
36
|
+
export declare function getLogicalScrollLeft(element: {
|
|
37
|
+
scrollLeft: number;
|
|
38
|
+
}, rtl: boolean): number;
|
|
39
|
+
/**
|
|
40
|
+
* Sets the horizontal scroll position of an element as distance from the **start** (see {@link getLogicalScrollLeft}).
|
|
41
|
+
*
|
|
42
|
+
* @param {{ scrollLeft: number }} element - a scroll container
|
|
43
|
+
* @param {number} x - px from the start
|
|
44
|
+
* @param {boolean} rtl - the container is right-to-left
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* setLogicalScrollLeft(tableApi.getTableScope().scrollViewport, 0, true); // back to the (right) start
|
|
48
|
+
*
|
|
49
|
+
* @since 1.1.98
|
|
50
|
+
* @category Utilities
|
|
51
|
+
*/
|
|
52
|
+
export declare function setLogicalScrollLeft(element: {
|
|
53
|
+
scrollLeft: number;
|
|
54
|
+
}, x: number, rtl: boolean): void;
|
|
55
|
+
/**
|
|
56
|
+
* The horizontal scroll position for `element.scrollTo(…)` – physical, i.e. negative in right-to-left.
|
|
57
|
+
*
|
|
58
|
+
* @param {number} x - px from the start
|
|
59
|
+
* @param {boolean} rtl - right-to-left
|
|
60
|
+
* @returns {number} the value for `scrollLeft` / `scrollTo()`
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* tableApi.getTableScope().scrollViewport.scrollTo(toPhysicalScrollLeft(200, true), 0); // 200 px from the right start
|
|
64
|
+
*
|
|
65
|
+
* @since 1.1.98
|
|
66
|
+
* @category Utilities
|
|
67
|
+
*/
|
|
68
|
+
export declare function toPhysicalScrollLeft(x: number, rtl: boolean): number;
|
|
69
|
+
/**
|
|
70
|
+
* Whether a scroll container can still scroll horizontally by `dx` (physical: `dx > 0` = to the right) – for
|
|
71
|
+
* left-to-right and right-to-left containers alike.
|
|
72
|
+
*
|
|
73
|
+
* @param {{ scrollLeft: number, scrollWidth: number, clientWidth: number }} element - a scroll container
|
|
74
|
+
* @param {number} dx - physical delta (e.g. `WheelEvent.deltaX`)
|
|
75
|
+
* @param {boolean} rtl - the container is right-to-left
|
|
76
|
+
* @returns {boolean} true if a scroll by `dx` would move the content
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* host.addEventListener("wheel", e => {
|
|
80
|
+
* const takesIt = canScrollHorizontally(host, e.deltaX, getComputedStyle(host).direction === "rtl");
|
|
81
|
+
* console.info(takesIt ? "the element scrolls itself" : "pass it on");
|
|
82
|
+
* });
|
|
83
|
+
*
|
|
84
|
+
* @since 1.1.98
|
|
85
|
+
* @category Utilities
|
|
86
|
+
*/
|
|
87
|
+
export declare function canScrollHorizontally(element: {
|
|
88
|
+
scrollLeft: number;
|
|
89
|
+
scrollWidth: number;
|
|
90
|
+
clientWidth: number;
|
|
91
|
+
}, dx: number, rtl: boolean): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* A client x coordinate (e.g. `PointerEvent.clientX`) as position in a box measured from the box's **start**:
|
|
94
|
+
* left-to-right from its left edge, right-to-left from its right edge.
|
|
95
|
+
*
|
|
96
|
+
* @param {number} clientX - x in client (viewport) coordinates
|
|
97
|
+
* @param {number} boxLeft - the left edge of the box in client coordinates
|
|
98
|
+
* @param {number} boxWidth - the width of the box
|
|
99
|
+
* @param {boolean} rtl - right-to-left
|
|
100
|
+
* @returns {number} px from the start of the box
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* host.addEventListener("pointerdown", e => {
|
|
104
|
+
* const r = host.getBoundingClientRect();
|
|
105
|
+
* console.info(toLogicalX(e.clientX, r.left + host.clientLeft, host.clientWidth, true)); // px from the right edge
|
|
106
|
+
* });
|
|
107
|
+
*
|
|
108
|
+
* @since 1.1.98
|
|
109
|
+
* @category Utilities
|
|
110
|
+
*/
|
|
111
|
+
export declare function toLogicalX(clientX: number, boxLeft: number, boxWidth: number, rtl: boolean): number;
|
|
112
|
+
/**
|
|
113
|
+
* Swaps the arrow keys "left" and "right" in a harmonized shortcut (e.g. `"cmd left"` → `"cmd right"`) – the
|
|
114
|
+
* keyboard handling of a right-to-left table, so that → moves backwards in reading direction.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} shortcut - a harmonized shortcut (`harmonizeShortcut`)
|
|
117
|
+
* @returns {string} the shortcut with swapped arrow keys
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* mirrorArrowKeys("left"); // "right"
|
|
121
|
+
* mirrorArrowKeys("cmd right"); // "cmd left"
|
|
122
|
+
*
|
|
123
|
+
* @since 1.1.98
|
|
124
|
+
* @category Keyboard
|
|
125
|
+
*/
|
|
126
|
+
export declare function mirrorArrowKeys(shortcut: string): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The writing direction of a table ({@link TableOptionsIf.direction}):
|
|
3
|
+
*
|
|
4
|
+
* - `"ltr"` (default): left to right – the first column on the left.
|
|
5
|
+
* - `"rtl"`: right to left (Arabic, Hebrew, Persian, Urdu …) – the first column on the right, horizontal scrolling,
|
|
6
|
+
* fixed columns, tree indent, resize handles and arrow keys mirrored.
|
|
7
|
+
* - `"auto"`: the direction of the page where the table is created (`dir="rtl"` on `<html>`, a parent element or the
|
|
8
|
+
* host itself → `"rtl"`).
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const tableOptions: TableOptionsIf = { ...new TableOptions(), direction: "rtl" };
|
|
12
|
+
*
|
|
13
|
+
* @since 1.1.98
|
|
14
|
+
* @category Options
|
|
15
|
+
*/
|
|
16
|
+
export type TableDirection = "ltr" | "rtl" | "auto";
|
|
17
|
+
/**
|
|
18
|
+
* A resolved writing direction – what {@link TableApi.getDirection} returns (`"auto"` is already decided).
|
|
19
|
+
*
|
|
20
|
+
* @since 1.1.98
|
|
21
|
+
* @category Options
|
|
22
|
+
*/
|
|
23
|
+
export type ResolvedTableDirection = "ltr" | "rtl";
|
|
@@ -10,6 +10,7 @@ import { SideIdent } from '../data/side-ident.type.js';
|
|
|
10
10
|
import { SortState } from '../data/common/sort-state.type.js';
|
|
11
11
|
import { SortedOptionsIf } from '../data/options/sorted-options.if.js';
|
|
12
12
|
import { HtmlStyle } from './data/html-style.type.js';
|
|
13
|
+
import { ResolvedTableDirection } from '../rtl/table-direction.type.js';
|
|
13
14
|
|
|
14
15
|
/** @category DOM */
|
|
15
16
|
export interface AddColumnDivPara {
|
|
@@ -37,7 +38,54 @@ export declare class ConvenienceDomService {
|
|
|
37
38
|
readonly domService: DomServiceIf;
|
|
38
39
|
/** Width of the focus frame of a cell in px (WCAG 2.4.7: visible focus, not only a color). @since 1.1.91 */
|
|
39
40
|
static focusBorderWidthInPx: number;
|
|
41
|
+
/** Right-to-left: `left` is written as `right` and vice versa (see {@link setDirection}). */
|
|
42
|
+
private rtl;
|
|
43
|
+
/** The physical CSS property of the inline start (`left`, right-to-left `right`). */
|
|
44
|
+
private startKey;
|
|
45
|
+
/** The physical CSS property of the inline end (`right`, right-to-left `left`). */
|
|
46
|
+
private endKey;
|
|
40
47
|
constructor(domService: DomServiceIf);
|
|
48
|
+
/**
|
|
49
|
+
* Sets the writing direction of the table. All positions of the table are computed from the **start** of a row
|
|
50
|
+
* (x = 0 is the first column); in right-to-left this service writes them as `right` instead of `left` – in
|
|
51
|
+
* {@link setStyle}, {@link applyStyle}, {@link applyStyleInPx} and all `add…` methods – so that the whole table is
|
|
52
|
+
* mirrored. Called once by the table before anything is positioned.
|
|
53
|
+
*
|
|
54
|
+
* @param {ResolvedTableDirection} direction - `"ltr"` or `"rtl"`
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const dom = new ConvenienceDomService(new SimpleDomService());
|
|
58
|
+
* dom.setDirection("rtl");
|
|
59
|
+
* const div = document.createElement("div");
|
|
60
|
+
* dom.setStyle(div, "left", "20px"); // div.style.right = "20px"
|
|
61
|
+
*
|
|
62
|
+
* @since 1.1.98
|
|
63
|
+
*/
|
|
64
|
+
setDirection(direction: ResolvedTableDirection): void;
|
|
65
|
+
/**
|
|
66
|
+
* The writing direction set with {@link setDirection} (default `"ltr"`).
|
|
67
|
+
*
|
|
68
|
+
* @returns {ResolvedTableDirection} `"ltr"` or `"rtl"`
|
|
69
|
+
* @since 1.1.98
|
|
70
|
+
*/
|
|
71
|
+
getDirection(): ResolvedTableDirection;
|
|
72
|
+
/**
|
|
73
|
+
* The physical CSS property for a logical position key: in right-to-left `left` ↔ `right`, everything else as is.
|
|
74
|
+
*
|
|
75
|
+
* @param {string} key - a CSS property
|
|
76
|
+
* @returns {string} the property to write
|
|
77
|
+
* @since 1.1.98
|
|
78
|
+
*/
|
|
79
|
+
toPhysicalStyleKey(key: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* The position of an element from the inline start in px, as written by this service (`style.left`, right-to-left
|
|
82
|
+
* `style.right`); 0 if it has none.
|
|
83
|
+
*
|
|
84
|
+
* @param {HTMLElement} ele - an element positioned by this service
|
|
85
|
+
* @returns {number} px
|
|
86
|
+
* @since 1.1.98
|
|
87
|
+
*/
|
|
88
|
+
getInlineStart(ele: HTMLElement): number;
|
|
41
89
|
setStyle(el: any, style: string, value: any): any;
|
|
42
90
|
applyStyle(ele: HTMLDivElement, style: HtmlStyle): HTMLDivElement;
|
|
43
91
|
applyDisplayNoneStyle(ele: HTMLDivElement): HTMLDivElement;
|
|
@@ -46,7 +94,7 @@ export declare class ConvenienceDomService {
|
|
|
46
94
|
applyStylePosistionRelative(ele: HTMLDivElement): HTMLDivElement;
|
|
47
95
|
applyStylePosistionAbsolute(ele: HTMLDivElement): HTMLDivElement;
|
|
48
96
|
applyStyleFullSize(ele: HTMLDivElement): HTMLDivElement;
|
|
49
|
-
applyStyleOverflowAuto(overflowX: "
|
|
97
|
+
applyStyleOverflowAuto(overflowX: "auto" | "scroll" | undefined, overflowY: "auto" | "scroll" | undefined, ele: HTMLDivElement): HTMLDivElement;
|
|
50
98
|
applyStyleNoPadding(ele: HTMLDivElement): HTMLDivElement;
|
|
51
99
|
appendRelativeChildDiv(parent: HTMLDivElement): DivScope;
|
|
52
100
|
appendText(parent: HTMLDivElement, text: string): HTMLElement;
|