chrome-devtools-frontend 1.0.944903 → 1.0.945884
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/config/gni/devtools_grd_files.gni +1 -0
- package/config/gni/devtools_image_files.gni +1 -0
- package/front_end/Images/src/circled_exclamation_icon.svg +3 -0
- package/front_end/core/host/InspectorFrontendHostAPI.ts +5 -5
- package/front_end/core/host/UserMetrics.ts +3 -1
- package/front_end/core/i18n/i18nImpl.ts +7 -4
- package/front_end/core/i18n/locales/en-US.json +9 -45
- package/front_end/core/i18n/locales/en-XL.json +9 -45
- package/front_end/core/sdk/CSSMetadata.ts +0 -1
- package/front_end/core/sdk/sdk-meta.ts +20 -8
- package/front_end/entrypoints/main/MainImpl.ts +6 -0
- package/front_end/generated/protocol.d.ts +0 -4
- package/front_end/models/emulation/EmulatedDevices.ts +2 -4
- package/front_end/models/persistence/IsolatedFileSystemManager.ts +6 -10
- package/front_end/models/timeline_model/TimelineJSProfile.ts +16 -3
- package/front_end/models/timeline_model/TimelineModel.ts +1 -0
- package/front_end/models/workspace_diff/WorkspaceDiff.ts +20 -6
- package/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/application/BackForwardCacheStrings.ts +15 -75
- package/front_end/panels/application/BackForwardCacheView.ts +8 -1
- package/front_end/panels/changes/ChangesView.ts +8 -7
- package/front_end/panels/elements/StyleEditorWidget.ts +7 -7
- package/front_end/panels/elements/StylePropertyTreeElement.ts +8 -15
- package/front_end/panels/elements/StylesSidebarPane.ts +35 -9
- package/front_end/panels/emulation/DeviceModeView.ts +3 -0
- package/front_end/panels/help/ReleaseNoteText.ts +3 -1
- package/front_end/panels/network/NetworkItemView.ts +7 -1
- package/front_end/panels/profiler/heapProfiler.css +2 -5
- package/front_end/panels/timeline/TimelineController.ts +3 -0
- package/front_end/panels/webauthn/WebauthnPane.ts +31 -32
- package/front_end/third_party/acorn/README.chromium +2 -2
- package/front_end/third_party/acorn/acorn.ts +1 -1
- package/front_end/third_party/acorn/package/CHANGELOG.md +31 -1
- package/front_end/third_party/acorn/package/README.md +1 -1
- package/front_end/third_party/acorn/package/dist/acorn.d.ts +3 -0
- package/front_end/third_party/acorn/package/dist/acorn.js +772 -708
- package/front_end/third_party/acorn/package/dist/acorn.mjs +767 -703
- package/front_end/third_party/acorn/package/dist/bin.js +47 -21
- package/front_end/third_party/acorn/package/package.json +1 -1
- package/front_end/third_party/acorn-loose/README.chromium +2 -2
- package/front_end/third_party/acorn-loose/package/CHANGELOG.md +12 -0
- package/front_end/third_party/acorn-loose/package/dist/acorn-loose.js +27 -7
- package/front_end/third_party/acorn-loose/package/dist/acorn-loose.mjs +28 -8
- package/front_end/third_party/acorn-loose/package/package.json +2 -2
- package/front_end/third_party/i18n/i18n-impl.ts +1 -1
- package/front_end/ui/components/adorners/Adorner.ts +14 -14
- package/front_end/ui/components/buttons/Button.ts +133 -42
- package/front_end/ui/components/buttons/button.css +31 -0
- package/front_end/ui/components/data_grid/DataGrid.ts +131 -122
- package/front_end/ui/components/data_grid/DataGridController.ts +42 -42
- package/front_end/ui/components/diff_view/DiffView.ts +4 -4
- package/front_end/ui/components/docs/button/basic.html +3 -0
- package/front_end/ui/components/docs/button/basic.ts +58 -0
- package/front_end/ui/components/expandable_list/ExpandableList.ts +11 -11
- package/front_end/ui/components/icon_button/Icon.ts +24 -21
- package/front_end/ui/components/icon_button/IconButton.ts +31 -31
- package/front_end/ui/components/issue_counter/IssueCounter.ts +52 -52
- package/front_end/ui/components/issue_counter/IssueLinkIcon.ts +42 -42
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspector.ts +67 -67
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspectorController.ts +22 -22
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspectorPane.ts +36 -36
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryNavigator.ts +19 -19
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryValueInterpreter.ts +24 -32
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryViewer.ts +52 -52
- package/front_end/ui/components/linear_memory_inspector/ValueInterpreterDisplay.ts +21 -21
- package/front_end/ui/components/linear_memory_inspector/ValueInterpreterSettings.ts +6 -6
- package/front_end/ui/components/markdown_view/MarkdownImage.ts +14 -14
- package/front_end/ui/components/markdown_view/MarkdownLink.ts +8 -8
- package/front_end/ui/components/markdown_view/MarkdownView.ts +6 -6
- package/front_end/ui/components/render_coordinator/RenderCoordinator.ts +33 -33
- package/front_end/ui/components/report_view/ReportView.ts +18 -18
- package/front_end/ui/components/request_link_icon/RequestLinkIcon.ts +53 -53
- package/front_end/ui/components/settings/SettingCheckbox.ts +15 -15
- package/front_end/ui/components/survey_link/SurveyLink.ts +28 -28
- package/front_end/ui/components/text_editor/TextEditor.ts +55 -52
- package/front_end/ui/components/text_editor/javascript.ts +6 -6
- package/front_end/ui/components/text_prompt/TextPrompt.ts +19 -19
- package/front_end/ui/components/tree_outline/TreeOutline.ts +56 -56
- package/front_end/ui/legacy/Infobar.ts +9 -0
- package/front_end/ui/legacy/InspectorView.ts +1 -1
- package/front_end/ui/legacy/ListWidget.ts +2 -2
- package/front_end/ui/legacy/tabbedPane.css +1 -1
- package/inspector_overlay/main.ts +3 -0
- package/package.json +1 -1
- package/scripts/eslint_rules/lib/l10n_filename_matches.js +17 -4
- package/scripts/eslint_rules/tests/l10n_filename_matches_test.js +21 -0
|
@@ -61,14 +61,14 @@ const PADDING_ROWS_COUNT = 10;
|
|
|
61
61
|
export class DataGrid extends HTMLElement {
|
|
62
62
|
static readonly litTagName = LitHtml.literal`devtools-data-grid`;
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
readonly #shadow = this.attachShadow({mode: 'open'});
|
|
65
|
+
#columns: readonly Column[] = [];
|
|
66
|
+
#rows: readonly Row[] = [];
|
|
67
|
+
#sortState: Readonly<SortState>|null = null;
|
|
68
|
+
#isRendering = false;
|
|
69
|
+
#userScrollState: UserScrollState = UserScrollState.NOT_SCROLLED;
|
|
70
|
+
#contextMenus?: DataGridContextMenusConfiguration = undefined;
|
|
71
|
+
#currentResize: {
|
|
72
72
|
rightCellCol: HTMLTableColElement,
|
|
73
73
|
leftCellCol: HTMLTableColElement,
|
|
74
74
|
leftCellColInitialPercentageWidth: number,
|
|
@@ -83,16 +83,16 @@ export class DataGrid extends HTMLElement {
|
|
|
83
83
|
// actual row index from the original dataset. We could use this.rows[index]
|
|
84
84
|
// but that's O(n) and will slow as the dataset grows. A weakmap makes the
|
|
85
85
|
// lookup constant.
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
readonly #rowIndexMap = new WeakMap<Row, number>();
|
|
87
|
+
readonly #resizeObserver = new ResizeObserver(() => {
|
|
88
88
|
this.alignScrollHandlers();
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
// These have to be bound as they are put onto the global document, not onto
|
|
92
92
|
// this element, so LitHtml does not bind them for us.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
#boundOnResizePointerUp = this.onResizePointerUp.bind(this);
|
|
94
|
+
#boundOnResizePointerMove = this.onResizePointerMove.bind(this);
|
|
95
|
+
#boundOnResizePointerDown = this.onResizePointerDown.bind(this);
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
98
|
* Following guidance from
|
|
@@ -108,35 +108,35 @@ export class DataGrid extends HTMLElement {
|
|
|
108
108
|
* first render if any of the columns are sortable we'll set the active cell
|
|
109
109
|
* to [0, 0].
|
|
110
110
|
*/
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
#cellToFocusIfUserTabsIn: CellPosition = [0, 1];
|
|
112
|
+
#cellUserHasFocused: CellPosition|null = null;
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
#hasRenderedAtLeastOnce = false;
|
|
115
|
+
#userHasFocusInDataGrid = false;
|
|
116
|
+
#scheduleRender = false;
|
|
117
117
|
|
|
118
118
|
connectedCallback(): void {
|
|
119
|
-
this
|
|
119
|
+
this.#shadow.adoptedStyleSheets = [dataGridStyles];
|
|
120
120
|
ComponentHelpers.SetCSSProperty.set(this, '--table-row-height', `${ROW_HEIGHT_PIXELS}px`);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
get data(): DataGridData {
|
|
124
124
|
return {
|
|
125
|
-
columns: this
|
|
126
|
-
rows: this
|
|
127
|
-
activeSort: this
|
|
128
|
-
contextMenus: this
|
|
125
|
+
columns: this.#columns as Column[],
|
|
126
|
+
rows: this.#rows as Row[],
|
|
127
|
+
activeSort: this.#sortState,
|
|
128
|
+
contextMenus: this.#contextMenus,
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
set data(data: DataGridData) {
|
|
133
|
-
this
|
|
134
|
-
this
|
|
135
|
-
this
|
|
136
|
-
this
|
|
133
|
+
this.#columns = data.columns;
|
|
134
|
+
this.#rows = data.rows;
|
|
135
|
+
this.#rows.forEach((row, index) => {
|
|
136
|
+
this.#rowIndexMap.set(row, index);
|
|
137
137
|
});
|
|
138
|
-
this
|
|
139
|
-
this
|
|
138
|
+
this.#sortState = data.activeSort;
|
|
139
|
+
this.#contextMenus = data.contextMenus;
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
142
|
* On first render, now we have data, we can figure out which cell is the
|
|
@@ -153,22 +153,22 @@ export class DataGrid extends HTMLElement {
|
|
|
153
153
|
* We only do this on the first render; otherwise if we re-render and the
|
|
154
154
|
* user has focused a cell, this logic will reset it.
|
|
155
155
|
*/
|
|
156
|
-
if (!this
|
|
157
|
-
this
|
|
156
|
+
if (!this.#hasRenderedAtLeastOnce) {
|
|
157
|
+
this.#cellToFocusIfUserTabsIn = calculateFirstFocusableCell({columns: this.#columns, rows: this.#rows});
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
if (this
|
|
160
|
+
if (this.#hasRenderedAtLeastOnce && this.userHasCellFocused()) {
|
|
161
161
|
const [selectedColIndex, selectedRowIndex] = this.tabbableCell();
|
|
162
|
-
const columnOutOfBounds = selectedColIndex > this
|
|
163
|
-
const rowOutOfBounds = selectedRowIndex > this
|
|
162
|
+
const columnOutOfBounds = selectedColIndex > this.#columns.length;
|
|
163
|
+
const rowOutOfBounds = selectedRowIndex > this.#rows.length;
|
|
164
164
|
|
|
165
165
|
/** If the row or column was removed, so the user is out of bounds, we
|
|
166
166
|
* move them to the last focusable cell, which should be close to where
|
|
167
167
|
* they were. */
|
|
168
168
|
if (columnOutOfBounds || rowOutOfBounds) {
|
|
169
|
-
this
|
|
170
|
-
columnOutOfBounds ? this
|
|
171
|
-
rowOutOfBounds ? this
|
|
169
|
+
this.#cellUserHasFocused = [
|
|
170
|
+
columnOutOfBounds ? this.#columns.length : selectedColIndex,
|
|
171
|
+
rowOutOfBounds ? this.#rows.length : selectedRowIndex,
|
|
172
172
|
];
|
|
173
173
|
}
|
|
174
174
|
}
|
|
@@ -181,7 +181,7 @@ export class DataGrid extends HTMLElement {
|
|
|
181
181
|
* If the user's last scroll took them to the bottom, then we assume they
|
|
182
182
|
* want to automatically scroll.
|
|
183
183
|
*/
|
|
184
|
-
if (this
|
|
184
|
+
if (this.#userScrollState === UserScrollState.SCROLLED_TO_BOTTOM) {
|
|
185
185
|
return true;
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -190,7 +190,7 @@ export class DataGrid extends HTMLElement {
|
|
|
190
190
|
* selected a cell), we automatically scroll, as long as the user hasn't
|
|
191
191
|
* manually scrolled the data-grid to somewhere that isn't the bottom.
|
|
192
192
|
*/
|
|
193
|
-
if (!this
|
|
193
|
+
if (!this.#userHasFocusInDataGrid && this.#userScrollState !== UserScrollState.MANUAL_SCROLL_NOT_BOTTOM) {
|
|
194
194
|
return true;
|
|
195
195
|
}
|
|
196
196
|
|
|
@@ -202,12 +202,12 @@ export class DataGrid extends HTMLElement {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
private scrollToBottomIfRequired(): void {
|
|
205
|
-
if (this
|
|
205
|
+
if (this.#hasRenderedAtLeastOnce === false || !this.shouldAutoScrollToBottom()) {
|
|
206
206
|
return;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
coordinator.read(() => {
|
|
210
|
-
const wrapper = this
|
|
210
|
+
const wrapper = this.#shadow.querySelector('.wrapping-container');
|
|
211
211
|
if (!wrapper) {
|
|
212
212
|
return;
|
|
213
213
|
}
|
|
@@ -219,21 +219,21 @@ export class DataGrid extends HTMLElement {
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
private engageResizeObserver(): void {
|
|
222
|
-
if (!this
|
|
223
|
-
this
|
|
222
|
+
if (!this.#hasRenderedAtLeastOnce) {
|
|
223
|
+
this.#resizeObserver.observe(this.#shadow.host);
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
private userHasCellFocused(): boolean {
|
|
228
|
-
return this
|
|
228
|
+
return this.#cellUserHasFocused !== null;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
private getTableElementForCellUserHasFocused(): HTMLTableCellElement|null {
|
|
232
|
-
if (!this
|
|
232
|
+
if (!this.#cellUserHasFocused) {
|
|
233
233
|
return null;
|
|
234
234
|
}
|
|
235
|
-
const [columnIndex, rowIndex] = this
|
|
236
|
-
const cell = this
|
|
235
|
+
const [columnIndex, rowIndex] = this.#cellUserHasFocused;
|
|
236
|
+
const cell = this.#shadow.querySelector<HTMLTableCellElement>(
|
|
237
237
|
`[data-row-index="${rowIndex}"][data-col-index="${columnIndex}"]`);
|
|
238
238
|
return cell;
|
|
239
239
|
}
|
|
@@ -245,15 +245,15 @@ export class DataGrid extends HTMLElement {
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
private focusCellIfRequired([newColumnIndex, newRowIndex]: CellPosition): void {
|
|
248
|
-
this
|
|
248
|
+
this.#userHasFocusInDataGrid = true;
|
|
249
249
|
|
|
250
|
-
if (this
|
|
251
|
-
this
|
|
250
|
+
if (this.#cellUserHasFocused && this.#cellUserHasFocused[0] === newColumnIndex &&
|
|
251
|
+
this.#cellUserHasFocused[1] === newRowIndex) {
|
|
252
252
|
// The cell is already active and focused so we don't need to do anything.
|
|
253
253
|
return;
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
this
|
|
256
|
+
this.#cellUserHasFocused = [newColumnIndex, newRowIndex];
|
|
257
257
|
this.render();
|
|
258
258
|
const tableCell = this.getTableElementForCellUserHasFocused();
|
|
259
259
|
if (!tableCell) {
|
|
@@ -270,13 +270,13 @@ export class DataGrid extends HTMLElement {
|
|
|
270
270
|
private onTableKeyDown(event: KeyboardEvent): void {
|
|
271
271
|
const key = event.key;
|
|
272
272
|
|
|
273
|
-
if (!this
|
|
273
|
+
if (!this.#cellUserHasFocused) {
|
|
274
274
|
return;
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
if (KEYS_TREATED_AS_CLICKS.has(key)) {
|
|
278
|
-
const [focusedColumnIndex, focusedRowIndex] = this
|
|
279
|
-
const activeColumn = this
|
|
278
|
+
const [focusedColumnIndex, focusedRowIndex] = this.#cellUserHasFocused;
|
|
279
|
+
const activeColumn = this.#columns[focusedColumnIndex];
|
|
280
280
|
if (focusedRowIndex === 0 && activeColumn && activeColumn.sortable) {
|
|
281
281
|
this.onColumnHeaderClick(activeColumn, focusedColumnIndex);
|
|
282
282
|
}
|
|
@@ -288,9 +288,9 @@ export class DataGrid extends HTMLElement {
|
|
|
288
288
|
|
|
289
289
|
const nextFocusedCell = handleArrowKeyNavigation({
|
|
290
290
|
key: key,
|
|
291
|
-
currentFocusedCell: this
|
|
292
|
-
columns: this
|
|
293
|
-
rows: this
|
|
291
|
+
currentFocusedCell: this.#cellUserHasFocused,
|
|
292
|
+
columns: this.#columns,
|
|
293
|
+
rows: this.#rows,
|
|
294
294
|
});
|
|
295
295
|
event.preventDefault();
|
|
296
296
|
this.focusCellIfRequired(nextFocusedCell);
|
|
@@ -306,13 +306,13 @@ export class DataGrid extends HTMLElement {
|
|
|
306
306
|
* https://www.w3.org/TR/wai-aria-practices/examples/grid/dataGrids.html.
|
|
307
307
|
*/
|
|
308
308
|
private ariaSortForHeader(col: Column): string|undefined {
|
|
309
|
-
if (col.sortable && (!this
|
|
309
|
+
if (col.sortable && (!this.#sortState || this.#sortState.columnId !== col.id)) {
|
|
310
310
|
// Column is sortable but is not currently sorted
|
|
311
311
|
return 'none';
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
-
if (this
|
|
315
|
-
return this
|
|
314
|
+
if (this.#sortState && this.#sortState.columnId === col.id) {
|
|
315
|
+
return this.#sortState.direction === SortDirection.ASC ? 'ascending' : 'descending';
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
// Column is not sortable, so don't apply any label
|
|
@@ -320,7 +320,7 @@ export class DataGrid extends HTMLElement {
|
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
private renderEmptyFillerRow(numberOfVisibleRows: number): LitHtml.TemplateResult {
|
|
323
|
-
const emptyCells = this
|
|
323
|
+
const emptyCells = this.#columns.map((col, colIndex) => {
|
|
324
324
|
if (!col.visible) {
|
|
325
325
|
return LitHtml.nothing;
|
|
326
326
|
}
|
|
@@ -338,11 +338,11 @@ export class DataGrid extends HTMLElement {
|
|
|
338
338
|
}
|
|
339
339
|
|
|
340
340
|
private cleanUpAfterResizeColumnComplete(): void {
|
|
341
|
-
if (!this
|
|
341
|
+
if (!this.#currentResize) {
|
|
342
342
|
return;
|
|
343
343
|
}
|
|
344
|
-
this
|
|
345
|
-
this
|
|
344
|
+
this.#currentResize.documentForCursorChange.body.style.cursor = this.#currentResize.cursorToRestore;
|
|
345
|
+
this.#currentResize = null;
|
|
346
346
|
// Realign the scroll handlers now the table columns have been resized.
|
|
347
347
|
this.alignScrollHandlers();
|
|
348
348
|
}
|
|
@@ -366,20 +366,20 @@ export class DataGrid extends HTMLElement {
|
|
|
366
366
|
/* To find the cell to the right we can't just go +1 as it might be hidden,
|
|
367
367
|
* so find the next index that is visible.
|
|
368
368
|
*/
|
|
369
|
-
const rightColumnIndexAsNumber = this
|
|
369
|
+
const rightColumnIndexAsNumber = this.#columns.findIndex((column, index) => {
|
|
370
370
|
return index > leftColumnIndexAsNumber && column.visible === true;
|
|
371
371
|
});
|
|
372
372
|
|
|
373
|
-
const leftCell = this
|
|
374
|
-
const rightCell = this
|
|
373
|
+
const leftCell = this.#shadow.querySelector(`td[data-filler-row-column-index="${leftColumnIndexAsNumber}"]`);
|
|
374
|
+
const rightCell = this.#shadow.querySelector(`td[data-filler-row-column-index="${rightColumnIndexAsNumber}"]`);
|
|
375
375
|
if (!leftCell || !rightCell) {
|
|
376
376
|
return;
|
|
377
377
|
}
|
|
378
378
|
// We query for the <col> elements as they are the elements that we put the actual width on.
|
|
379
379
|
const leftCellCol =
|
|
380
|
-
this
|
|
380
|
+
this.#shadow.querySelector<HTMLTableColElement>(`col[data-col-column-index="${leftColumnIndexAsNumber}"]`);
|
|
381
381
|
const rightCellCol =
|
|
382
|
-
this
|
|
382
|
+
this.#shadow.querySelector<HTMLTableColElement>(`col[data-col-column-index="${rightColumnIndexAsNumber}"]`);
|
|
383
383
|
if (!leftCellCol || !rightCellCol) {
|
|
384
384
|
return;
|
|
385
385
|
}
|
|
@@ -389,7 +389,7 @@ export class DataGrid extends HTMLElement {
|
|
|
389
389
|
return;
|
|
390
390
|
}
|
|
391
391
|
// We now store values that we'll make use of in the mousemouse event to calculate how much to resize the table by.
|
|
392
|
-
this
|
|
392
|
+
this.#currentResize = {
|
|
393
393
|
leftCellCol,
|
|
394
394
|
rightCellCol,
|
|
395
395
|
leftCellColInitialPercentageWidth: globalThis.parseInt(leftCellCol.style.width, 10),
|
|
@@ -403,23 +403,23 @@ export class DataGrid extends HTMLElement {
|
|
|
403
403
|
|
|
404
404
|
targetDocumentForCursorChange.body.style.cursor = 'col-resize';
|
|
405
405
|
resizerElement.setPointerCapture(event.pointerId);
|
|
406
|
-
resizerElement.addEventListener('pointermove', this
|
|
406
|
+
resizerElement.addEventListener('pointermove', this.#boundOnResizePointerMove);
|
|
407
407
|
}
|
|
408
408
|
|
|
409
409
|
private onResizePointerMove(event: PointerEvent): void {
|
|
410
410
|
event.preventDefault();
|
|
411
|
-
if (!this
|
|
411
|
+
if (!this.#currentResize) {
|
|
412
412
|
return;
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
const MIN_CELL_WIDTH_PERCENTAGE = 10;
|
|
416
|
-
const MAX_CELL_WIDTH_PERCENTAGE =
|
|
417
|
-
|
|
416
|
+
const MAX_CELL_WIDTH_PERCENTAGE = (this.#currentResize.leftCellColInitialPercentageWidth +
|
|
417
|
+
this.#currentResize.rightCellColInitialPercentageWidth) -
|
|
418
418
|
MIN_CELL_WIDTH_PERCENTAGE;
|
|
419
|
-
const deltaOfMouseMove = event.x - this
|
|
419
|
+
const deltaOfMouseMove = event.x - this.#currentResize.initialMouseX;
|
|
420
420
|
const absoluteDelta = Math.abs(deltaOfMouseMove);
|
|
421
421
|
const percentageDelta =
|
|
422
|
-
(absoluteDelta / (this
|
|
422
|
+
(absoluteDelta / (this.#currentResize.initialLeftCellWidth + this.#currentResize.initialRightCellWidth)) * 100;
|
|
423
423
|
|
|
424
424
|
let newLeftColumnPercentage;
|
|
425
425
|
let newRightColumnPercentage;
|
|
@@ -429,10 +429,10 @@ export class DataGrid extends HTMLElement {
|
|
|
429
429
|
* want to make the right column smaller, and the left column larger.
|
|
430
430
|
*/
|
|
431
431
|
newLeftColumnPercentage = Platform.NumberUtilities.clamp(
|
|
432
|
-
this
|
|
432
|
+
this.#currentResize.leftCellColInitialPercentageWidth + percentageDelta, MIN_CELL_WIDTH_PERCENTAGE,
|
|
433
433
|
MAX_CELL_WIDTH_PERCENTAGE);
|
|
434
434
|
newRightColumnPercentage = Platform.NumberUtilities.clamp(
|
|
435
|
-
this
|
|
435
|
+
this.#currentResize.rightCellColInitialPercentageWidth - percentageDelta, MIN_CELL_WIDTH_PERCENTAGE,
|
|
436
436
|
MAX_CELL_WIDTH_PERCENTAGE);
|
|
437
437
|
} else if (deltaOfMouseMove < 0) {
|
|
438
438
|
/**
|
|
@@ -441,10 +441,10 @@ export class DataGrid extends HTMLElement {
|
|
|
441
441
|
* smaller.
|
|
442
442
|
*/
|
|
443
443
|
newLeftColumnPercentage = Platform.NumberUtilities.clamp(
|
|
444
|
-
this
|
|
444
|
+
this.#currentResize.leftCellColInitialPercentageWidth - percentageDelta, MIN_CELL_WIDTH_PERCENTAGE,
|
|
445
445
|
MAX_CELL_WIDTH_PERCENTAGE);
|
|
446
446
|
newRightColumnPercentage = Platform.NumberUtilities.clamp(
|
|
447
|
-
this
|
|
447
|
+
this.#currentResize.rightCellColInitialPercentageWidth + percentageDelta, MIN_CELL_WIDTH_PERCENTAGE,
|
|
448
448
|
MAX_CELL_WIDTH_PERCENTAGE);
|
|
449
449
|
}
|
|
450
450
|
|
|
@@ -456,8 +456,8 @@ export class DataGrid extends HTMLElement {
|
|
|
456
456
|
// We limit the values to two decimal places to not work with huge decimals.
|
|
457
457
|
// It also prevents stuttering if the user barely moves the mouse, as the
|
|
458
458
|
// browser won't try to move the column by 0.0000001% or similar.
|
|
459
|
-
this
|
|
460
|
-
this
|
|
459
|
+
this.#currentResize.leftCellCol.style.width = newLeftColumnPercentage.toFixed(2) + '%';
|
|
460
|
+
this.#currentResize.rightCellCol.style.width = newRightColumnPercentage.toFixed(2) + '%';
|
|
461
461
|
}
|
|
462
462
|
|
|
463
463
|
private onResizePointerUp(event: PointerEvent): void {
|
|
@@ -467,7 +467,7 @@ export class DataGrid extends HTMLElement {
|
|
|
467
467
|
return;
|
|
468
468
|
}
|
|
469
469
|
resizer.releasePointerCapture(event.pointerId);
|
|
470
|
-
resizer.removeEventListener('pointermove', this
|
|
470
|
+
resizer.removeEventListener('pointermove', this.#boundOnResizePointerMove);
|
|
471
471
|
this.cleanUpAfterResizeColumnComplete();
|
|
472
472
|
}
|
|
473
473
|
|
|
@@ -487,16 +487,16 @@ export class DataGrid extends HTMLElement {
|
|
|
487
487
|
}
|
|
488
488
|
|
|
489
489
|
return LitHtml.html`<span class="cell-resize-handle"
|
|
490
|
-
@pointerdown=${this
|
|
491
|
-
@pointerup=${this
|
|
490
|
+
@pointerdown=${this.#boundOnResizePointerDown}
|
|
491
|
+
@pointerup=${this.#boundOnResizePointerUp}
|
|
492
492
|
data-column-index=${columnIndex}
|
|
493
493
|
></span>`;
|
|
494
494
|
}
|
|
495
495
|
|
|
496
496
|
private getIndexOfLastVisibleColumn(): number {
|
|
497
|
-
let index = this
|
|
497
|
+
let index = this.#columns.length - 1;
|
|
498
498
|
for (; index > -1; index--) {
|
|
499
|
-
const col = this
|
|
499
|
+
const col = this.#columns[index];
|
|
500
500
|
if (col.visible) {
|
|
501
501
|
break;
|
|
502
502
|
}
|
|
@@ -524,9 +524,9 @@ export class DataGrid extends HTMLElement {
|
|
|
524
524
|
this.dispatchEvent(new ContextMenuHeaderResetClickEvent());
|
|
525
525
|
});
|
|
526
526
|
|
|
527
|
-
if (this
|
|
527
|
+
if (this.#contextMenus && this.#contextMenus.headerRow) {
|
|
528
528
|
// Let the user append things to the menu
|
|
529
|
-
this
|
|
529
|
+
this.#contextMenus.headerRow(menu, this.#columns);
|
|
530
530
|
}
|
|
531
531
|
menu.show();
|
|
532
532
|
}
|
|
@@ -551,7 +551,7 @@ export class DataGrid extends HTMLElement {
|
|
|
551
551
|
|
|
552
552
|
const rowIndex = parseInt(rowIndexAttribute, 10);
|
|
553
553
|
// rowIndex - 1 here because in the UI the 0th row is the column headers.
|
|
554
|
-
const rowThatWasClicked = this
|
|
554
|
+
const rowThatWasClicked = this.#rows[rowIndex - 1];
|
|
555
555
|
|
|
556
556
|
const menu = new UI.ContextMenu.ContextMenu(event);
|
|
557
557
|
const sortMenu = menu.defaultSection().appendSubMenuItem(i18nString(UIStrings.sortBy));
|
|
@@ -563,8 +563,8 @@ export class DataGrid extends HTMLElement {
|
|
|
563
563
|
this.dispatchEvent(new ContextMenuHeaderResetClickEvent());
|
|
564
564
|
});
|
|
565
565
|
|
|
566
|
-
if (this
|
|
567
|
-
this
|
|
566
|
+
if (this.#contextMenus && this.#contextMenus.bodyRow) {
|
|
567
|
+
this.#contextMenus.bodyRow(menu, this.#columns, rowThatWasClicked);
|
|
568
568
|
}
|
|
569
569
|
menu.show();
|
|
570
570
|
}
|
|
@@ -578,7 +578,7 @@ export class DataGrid extends HTMLElement {
|
|
|
578
578
|
// Need to Math.round because on high res screens we can end up with decimal
|
|
579
579
|
// point numbers for scroll positions.
|
|
580
580
|
const userIsAtBottom = Math.round(wrapper.scrollTop + wrapper.clientHeight) === Math.round(wrapper.scrollHeight);
|
|
581
|
-
this
|
|
581
|
+
this.#userScrollState =
|
|
582
582
|
userIsAtBottom ? UserScrollState.SCROLLED_TO_BOTTOM : UserScrollState.MANUAL_SCROLL_NOT_BOTTOM;
|
|
583
583
|
|
|
584
584
|
this.render();
|
|
@@ -586,9 +586,9 @@ export class DataGrid extends HTMLElement {
|
|
|
586
586
|
|
|
587
587
|
private alignScrollHandlers(): Promise<void> {
|
|
588
588
|
return coordinator.read(() => {
|
|
589
|
-
const columnHeaders = this
|
|
590
|
-
const handlers = this
|
|
591
|
-
const table = this
|
|
589
|
+
const columnHeaders = this.#shadow.querySelectorAll<HTMLElement>('th:not(.hidden)');
|
|
590
|
+
const handlers = this.#shadow.querySelectorAll<HTMLElement>('.cell-resize-handle');
|
|
591
|
+
const table = this.#shadow.querySelector<HTMLTableElement>('table');
|
|
592
592
|
if (!table) {
|
|
593
593
|
return;
|
|
594
594
|
}
|
|
@@ -616,7 +616,7 @@ export class DataGrid extends HTMLElement {
|
|
|
616
616
|
*/
|
|
617
617
|
private calculateTopAndBottomRowIndexes(): Promise<{topVisibleRow: number, bottomVisibleRow: number}> {
|
|
618
618
|
return coordinator.read(() => {
|
|
619
|
-
const wrapper = this
|
|
619
|
+
const wrapper = this.#shadow.querySelector('.wrapping-container');
|
|
620
620
|
|
|
621
621
|
// On first render we don't have a wrapper, so we can't get at its
|
|
622
622
|
// scroll/height values. So we default to the inner height of the window as
|
|
@@ -633,7 +633,7 @@ export class DataGrid extends HTMLElement {
|
|
|
633
633
|
let bottomVisibleRow = Math.ceil((scrollTop + clientHeight + padding) / ROW_HEIGHT_PIXELS);
|
|
634
634
|
|
|
635
635
|
topVisibleRow = Math.max(0, topVisibleRow);
|
|
636
|
-
bottomVisibleRow = Math.min(this
|
|
636
|
+
bottomVisibleRow = Math.min(this.#rows.filter(r => !r.hidden).length, bottomVisibleRow);
|
|
637
637
|
|
|
638
638
|
return {
|
|
639
639
|
topVisibleRow,
|
|
@@ -652,7 +652,7 @@ export class DataGrid extends HTMLElement {
|
|
|
652
652
|
* we can steal focus away from the user if they are typing into an input
|
|
653
653
|
* box to filter the data-grid, for example.
|
|
654
654
|
*/
|
|
655
|
-
this
|
|
655
|
+
this.#userHasFocusInDataGrid = false;
|
|
656
656
|
}
|
|
657
657
|
|
|
658
658
|
private tabbableCell(): CellPosition {
|
|
@@ -662,7 +662,7 @@ export class DataGrid extends HTMLElement {
|
|
|
662
662
|
* hasn't selected a cell, we fallback to the default cell that we set as
|
|
663
663
|
* tabbable when we render.
|
|
664
664
|
*/
|
|
665
|
-
return this
|
|
665
|
+
return this.#cellUserHasFocused || this.#cellToFocusIfUserTabsIn;
|
|
666
666
|
}
|
|
667
667
|
|
|
668
668
|
/**
|
|
@@ -673,27 +673,27 @@ export class DataGrid extends HTMLElement {
|
|
|
673
673
|
* padding).
|
|
674
674
|
*/
|
|
675
675
|
private async render(): Promise<void> {
|
|
676
|
-
if (this
|
|
676
|
+
if (this.#isRendering) {
|
|
677
677
|
// If we receive a request to render during a previous render call, we block
|
|
678
678
|
// the newly requested render (since we could receive a lot of them in quick
|
|
679
679
|
// succession), but we do ensure that at the end of the current render we
|
|
680
680
|
// go again with the latest data.
|
|
681
|
-
this
|
|
681
|
+
this.#scheduleRender = true;
|
|
682
682
|
return;
|
|
683
683
|
}
|
|
684
|
-
this
|
|
684
|
+
this.#isRendering = true;
|
|
685
685
|
|
|
686
686
|
const {topVisibleRow, bottomVisibleRow} = await this.calculateTopAndBottomRowIndexes();
|
|
687
|
-
const nonHiddenRows = this
|
|
687
|
+
const nonHiddenRows = this.#rows.filter(row => !row.hidden);
|
|
688
688
|
const renderableRows = nonHiddenRows.filter((_, idx) => idx >= topVisibleRow && idx <= bottomVisibleRow);
|
|
689
|
-
const indexOfFirstVisibleColumn = this
|
|
690
|
-
const anyColumnsSortable = this
|
|
689
|
+
const indexOfFirstVisibleColumn = this.#columns.findIndex(col => col.visible);
|
|
690
|
+
const anyColumnsSortable = this.#columns.some(col => col.sortable === true);
|
|
691
691
|
|
|
692
692
|
await coordinator.write(() => {
|
|
693
693
|
// Disabled until https://crbug.com/1079231 is fixed.
|
|
694
694
|
// clang-format off
|
|
695
695
|
LitHtml.render(LitHtml.html`
|
|
696
|
-
${this
|
|
696
|
+
${this.#columns.map((col, columnIndex) => {
|
|
697
697
|
/**
|
|
698
698
|
* We render the resizers outside of the table. One is rendered for each
|
|
699
699
|
* column, and they are positioned absolutely at the right position. They
|
|
@@ -704,13 +704,13 @@ export class DataGrid extends HTMLElement {
|
|
|
704
704
|
})}
|
|
705
705
|
<div class="wrapping-container" @scroll=${this.onScroll} @focusout=${this.onFocusOut}>
|
|
706
706
|
<table
|
|
707
|
-
aria-rowcount=${this
|
|
708
|
-
aria-colcount=${this
|
|
707
|
+
aria-rowcount=${this.#rows.length}
|
|
708
|
+
aria-colcount=${this.#columns.length}
|
|
709
709
|
@keydown=${this.onTableKeyDown}
|
|
710
710
|
>
|
|
711
711
|
<colgroup>
|
|
712
|
-
${this
|
|
713
|
-
const width = calculateColumnWidthPercentageFromWeighting(this
|
|
712
|
+
${this.#columns.map((col, colIndex) => {
|
|
713
|
+
const width = calculateColumnWidthPercentageFromWeighting(this.#columns, col.id);
|
|
714
714
|
const style = `width: ${width}%`;
|
|
715
715
|
if (!col.visible) {
|
|
716
716
|
return LitHtml.nothing;
|
|
@@ -720,7 +720,7 @@ export class DataGrid extends HTMLElement {
|
|
|
720
720
|
</colgroup>
|
|
721
721
|
<thead>
|
|
722
722
|
<tr @contextmenu=${this.onHeaderContextMenu}>
|
|
723
|
-
${this
|
|
723
|
+
${this.#columns.map((col, columnIndex) => {
|
|
724
724
|
const thClasses = LitHtml.Directives.classMap({
|
|
725
725
|
hidden: !col.visible,
|
|
726
726
|
firstVisibleColumn: columnIndex === indexOfFirstVisibleColumn,
|
|
@@ -758,8 +758,8 @@ export class DataGrid extends HTMLElement {
|
|
|
758
758
|
<tr class="filler-row-top padding-row" style=${LitHtml.Directives.styleMap({
|
|
759
759
|
height: `${topVisibleRow * ROW_HEIGHT_PIXELS}px`,
|
|
760
760
|
})}></tr>
|
|
761
|
-
${LitHtml.Directives.repeat(renderableRows, row => this
|
|
762
|
-
const rowIndex = this
|
|
761
|
+
${LitHtml.Directives.repeat(renderableRows, row => this.#rowIndexMap.get(row), (row): LitHtml.TemplateResult => {
|
|
762
|
+
const rowIndex = this.#rowIndexMap.get(row);
|
|
763
763
|
if (rowIndex === undefined) {
|
|
764
764
|
throw new Error('Trying to render a row that has no index in the rowIndexMap');
|
|
765
765
|
}
|
|
@@ -769,7 +769,7 @@ export class DataGrid extends HTMLElement {
|
|
|
769
769
|
|
|
770
770
|
// Check for cellUserHasFocused instead of tabbableCell so that we
|
|
771
771
|
// don't highlight the active cell before they've even clicked it.
|
|
772
|
-
const rowIsSelected = this
|
|
772
|
+
const rowIsSelected = this.#cellUserHasFocused ? tableRowIndex === this.#cellUserHasFocused[1] : false;
|
|
773
773
|
|
|
774
774
|
const rowClasses = LitHtml.Directives.classMap({
|
|
775
775
|
selected: rowIsSelected,
|
|
@@ -781,7 +781,7 @@ export class DataGrid extends HTMLElement {
|
|
|
781
781
|
class=${rowClasses}
|
|
782
782
|
style=${LitHtml.Directives.ifDefined(row.styles ? LitHtml.Directives.styleMap(row.styles) : undefined)}
|
|
783
783
|
@contextmenu=${this.onBodyRowContextMenu}
|
|
784
|
-
>${this
|
|
784
|
+
>${this.#columns.map((col, columnIndex) => {
|
|
785
785
|
const cell = getRowEntryForColumnId(row, col.id);
|
|
786
786
|
const cellClasses = LitHtml.Directives.classMap({
|
|
787
787
|
hidden: !col.visible,
|
|
@@ -813,7 +813,7 @@ export class DataGrid extends HTMLElement {
|
|
|
813
813
|
</tbody>
|
|
814
814
|
</table>
|
|
815
815
|
</div>
|
|
816
|
-
`, this
|
|
816
|
+
`, this.#shadow, {
|
|
817
817
|
host: this,
|
|
818
818
|
});
|
|
819
819
|
});
|
|
@@ -827,18 +827,27 @@ export class DataGrid extends HTMLElement {
|
|
|
827
827
|
const tabbableCell = this.tabbableCell();
|
|
828
828
|
const currentlyFocusedRowIndex = tabbableCell[1];
|
|
829
829
|
const tabbableCellElement = this.getTableElementForCellUserHasFocused();
|
|
830
|
-
if (this
|
|
830
|
+
if (this.#userHasFocusInDataGrid && currentlyFocusedRowIndex > 0 && tabbableCellElement) {
|
|
831
831
|
this.focusTableCellInDOM(tabbableCellElement);
|
|
832
832
|
}
|
|
833
833
|
this.scrollToBottomIfRequired();
|
|
834
834
|
this.engageResizeObserver();
|
|
835
|
-
this
|
|
836
|
-
|
|
835
|
+
if (this.#hasRenderedAtLeastOnce) {
|
|
836
|
+
// We may have had a cell's width change on a re-render, or it may have
|
|
837
|
+
// been hidden entirely, so we need to ensure that the resize handlers are
|
|
838
|
+
// re-positioned correctly if so.
|
|
839
|
+
|
|
840
|
+
// We don't have to do this on first render as it will fire when the resize observer is engaged.
|
|
841
|
+
this.alignScrollHandlers();
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
this.#isRendering = false;
|
|
845
|
+
this.#hasRenderedAtLeastOnce = true;
|
|
837
846
|
|
|
838
847
|
// If we've received more data mid-render we will do one extra render at
|
|
839
848
|
// the end with the most recent data.
|
|
840
|
-
if (this
|
|
841
|
-
this
|
|
849
|
+
if (this.#scheduleRender) {
|
|
850
|
+
this.#scheduleRender = false;
|
|
842
851
|
this.render();
|
|
843
852
|
}
|
|
844
853
|
}
|