chrome-devtools-frontend 1.0.1518653 → 1.0.1520139
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/owner/COMMON_OWNERS +1 -2
- package/config/typescript/tsconfig.eslint.json +12 -1
- package/docs/ui_engineering.md +1011 -0
- package/eslint.config.mjs +1 -0
- package/front_end/core/host/GdpClient.ts +12 -3
- package/front_end/core/sdk/EnhancedTracesParser.ts +5 -5
- package/front_end/core/sdk/NetworkManager.ts +1 -0
- package/front_end/core/sdk/NetworkRequest.ts +10 -0
- package/front_end/core/sdk/RehydratingConnection.snapshot.txt +211 -0
- package/front_end/core/sdk/TargetManager.ts +4 -0
- package/front_end/entrypoints/main/MainImpl.ts +6 -1
- package/front_end/entrypoints/main/main-meta.ts +3 -3
- package/front_end/generated/SupportedCSSProperties.js +19 -4
- package/front_end/models/ai_assistance/agents/AiAgent.ts +57 -10
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +64 -87
- package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +4 -4
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +0 -31
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +127 -29
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +106 -55
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +317 -640
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +23 -19
- package/front_end/models/ai_assistance/performance/AICallTree.snapshot.txt +75 -0
- package/front_end/models/ai_assistance/performance/AICallTree.ts +14 -6
- package/front_end/models/ai_assistance/performance/AIContext.ts +63 -8
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +5 -0
- package/front_end/models/badges/AiExplorerBadge.ts +19 -3
- package/front_end/models/badges/Badge.ts +8 -1
- package/front_end/models/badges/CodeWhispererBadge.ts +1 -0
- package/front_end/models/badges/DOMDetectiveBadge.ts +1 -0
- package/front_end/models/badges/SpeedsterBadge.ts +1 -0
- package/front_end/models/badges/StarterBadge.ts +6 -0
- package/front_end/models/badges/badges.ts +1 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +4 -0
- package/front_end/models/trace/EventsSerializer.ts +4 -3
- package/front_end/models/trace/handlers/UserInteractionsHandler.ts +101 -73
- package/front_end/models/trace/helpers/Timing.ts +1 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +18 -8
- package/front_end/panels/ai_assistance/PatchWidget.ts +17 -55
- package/front_end/panels/ai_assistance/components/ChatView.ts +44 -68
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +63 -15
- package/front_end/panels/ai_assistance/components/chatView.css +12 -0
- package/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/animation/animationTimeline.css +4 -0
- package/front_end/panels/application/components/BounceTrackingMitigationsView.ts +2 -2
- package/front_end/panels/application/preloading/components/PreloadingString.ts +2 -5
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +5 -0
- package/front_end/panels/common/BadgeNotification.ts +3 -3
- package/front_end/panels/common/GdpSignUpDialog.ts +3 -4
- package/front_end/panels/common/aiCodeCompletionTeaser.css +6 -1
- package/front_end/panels/console/ConsolePrompt.ts +6 -0
- package/front_end/panels/console/ConsoleView.ts +4 -2
- package/front_end/panels/coverage/CoverageListView.ts +133 -158
- package/front_end/panels/coverage/CoverageView.ts +39 -16
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +5 -5
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +2 -0
- package/front_end/panels/network/NetworkDataGridNode.ts +22 -0
- package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
- package/front_end/panels/recorder/components/CreateRecordingView.ts +2 -0
- package/front_end/panels/recorder/components/RecordingView.ts +2 -2
- package/front_end/panels/search/SearchResultsPane.ts +186 -134
- package/front_end/panels/search/SearchView.ts +42 -36
- package/front_end/panels/search/searchResultsPane.css +9 -0
- package/front_end/panels/search/searchView.css +0 -2
- package/front_end/panels/security/CookieControlsView.ts +2 -1
- package/front_end/panels/settings/AISettingsTab.ts +6 -3
- package/front_end/panels/settings/components/SyncSection.ts +26 -12
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +1 -1
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +4 -4
- package/front_end/panels/sources/DebuggerPlugin.ts +4 -0
- package/front_end/panels/sources/SourcesPanel.ts +1 -1
- package/front_end/panels/sources/sourcesView.css +6 -1
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +0 -8
- package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -5
- package/front_end/panels/timeline/TimelinePanel.ts +2 -0
- package/front_end/panels/timeline/TimelineTreeView.ts +1 -1
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +1 -1
- package/front_end/panels/timeline/components/NetworkRequestDetails.ts +1 -1
- package/front_end/panels/timeline/components/RelatedInsightChips.ts +1 -1
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js +16 -25
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +19 -28
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js +16 -25
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/package.json +12 -4
- package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +1 -0
- package/front_end/third_party/puppeteer/package/src/node/PipeTransport.ts +15 -17
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/Function.ts +22 -30
- package/front_end/tsconfig.json +12 -1
- package/front_end/ui/components/dialogs/Dialog.ts +1 -1
- package/front_end/ui/components/markdown_view/MarkdownImage.ts +4 -5
- package/front_end/ui/components/switch/SwitchImpl.ts +12 -1
- package/front_end/ui/components/text_editor/config.ts +16 -2
- package/front_end/ui/legacy/InspectorView.ts +86 -13
- package/front_end/ui/legacy/TabbedPane.ts +2 -1
- package/front_end/ui/legacy/Treeoutline.ts +3 -1
- package/front_end/ui/legacy/components/source_frame/XMLView.ts +12 -11
- package/front_end/ui/lit/i18n-template.ts +5 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +15 -5
- package/front_end/ui/visual_logging/LoggingEvents.ts +1 -1
- package/package.json +1 -1
@@ -771,6 +771,24 @@ export class NetworkRequestNode extends NetworkNode {
|
|
771
771
|
return aScore - bScore || aRequest.identityCompare(bRequest);
|
772
772
|
}
|
773
773
|
|
774
|
+
static IsAdRelatedComparator(a: NetworkNode, b: NetworkNode): number {
|
775
|
+
// TODO(allada) Handle this properly for group nodes.
|
776
|
+
const aRequest = a.requestOrFirstKnownChildRequest();
|
777
|
+
const bRequest = b.requestOrFirstKnownChildRequest();
|
778
|
+
if (!aRequest || !bRequest) {
|
779
|
+
return !aRequest ? -1 : 1;
|
780
|
+
}
|
781
|
+
const aIsAdRelated = aRequest.isAdRelated();
|
782
|
+
const bIsAdRelated = bRequest.isAdRelated();
|
783
|
+
if (aIsAdRelated > bIsAdRelated) {
|
784
|
+
return 1;
|
785
|
+
}
|
786
|
+
if (bIsAdRelated > aIsAdRelated) {
|
787
|
+
return -1;
|
788
|
+
}
|
789
|
+
return aRequest.identityCompare(bRequest);
|
790
|
+
}
|
791
|
+
|
774
792
|
static RequestPropertyComparator(propertyName: string, a: NetworkNode, b: NetworkNode): number {
|
775
793
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
776
794
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
@@ -1038,6 +1056,10 @@ export class NetworkRequestNode extends NetworkNode {
|
|
1038
1056
|
this.renderAddressSpaceCell(cell, this.requestInternal.remoteAddressSpace());
|
1039
1057
|
break;
|
1040
1058
|
}
|
1059
|
+
case 'is-ad-related': {
|
1060
|
+
this.setTextAndTitle(cell, this.requestInternal.isAdRelated().toLocaleString());
|
1061
|
+
break;
|
1062
|
+
}
|
1041
1063
|
case 'cookies': {
|
1042
1064
|
this.setTextAndTitle(cell, this.arrayLength(this.requestInternal.includedRequestCookies()));
|
1043
1065
|
break;
|
@@ -148,6 +148,10 @@ const UIStrings = {
|
|
148
148
|
* @description Text in Network Log View Columns of the Network panel
|
149
149
|
*/
|
150
150
|
remoteAddressSpace: 'Remote Address Space',
|
151
|
+
/**
|
152
|
+
* @description Text to show whether a request is ad-related
|
153
|
+
*/
|
154
|
+
isAdRelated: 'Is Ad-Related',
|
151
155
|
} as const;
|
152
156
|
const str_ = i18n.i18n.registerUIStrings('panels/network/NetworkLogViewColumns.ts', UIStrings);
|
153
157
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
@@ -1183,6 +1187,11 @@ const DEFAULT_COLUMNS = [
|
|
1183
1187
|
title: i18n.i18n.lockedLazyString('User-Agent'),
|
1184
1188
|
sortingFunction: NetworkRequestNode.RequestHeaderStringComparator.bind(null, 'user-agent'),
|
1185
1189
|
},
|
1190
|
+
{
|
1191
|
+
id: 'is-ad-related',
|
1192
|
+
title: i18nLazyString(UIStrings.isAdRelated),
|
1193
|
+
sortingFunction: NetworkRequestNode.IsAdRelatedComparator,
|
1194
|
+
},
|
1186
1195
|
// This header is a placeholder to let datagrid know that it can be sorted by this column, but never shown.
|
1187
1196
|
{
|
1188
1197
|
id: 'waterfall',
|
@@ -8,6 +8,7 @@ import '../../../ui/components/icon_button/icon_button.js';
|
|
8
8
|
import './ControlButton.js';
|
9
9
|
|
10
10
|
import * as i18n from '../../../core/i18n/i18n.js';
|
11
|
+
import * as Badges from '../../../models/badges/badges.js';
|
11
12
|
import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
12
13
|
import * as Input from '../../../ui/components/input/input.js';
|
13
14
|
import * as Lit from '../../../ui/lit/lit.js';
|
@@ -231,6 +232,7 @@ export class CreateRecordingView extends HTMLElement {
|
|
231
232
|
selectorAttribute,
|
232
233
|
),
|
233
234
|
);
|
235
|
+
Badges.UserBadges.instance().recordAction(Badges.BadgeAction.RECORDER_RECORDING_STARTED);
|
234
236
|
}
|
235
237
|
|
236
238
|
#dispatchRecordingCancelled(): void {
|
@@ -220,9 +220,9 @@ function renderSettings({
|
|
220
220
|
replayState,
|
221
221
|
onReplaySettingsKeydown,
|
222
222
|
onToggleReplaySettings
|
223
|
-
}: ViewInput): Lit.
|
223
|
+
}: ViewInput): Lit.LitTemplate {
|
224
224
|
if (!settings) {
|
225
|
-
return
|
225
|
+
return Lit.nothing;
|
226
226
|
}
|
227
227
|
const environmentFragments = [];
|
228
228
|
if (settings.viewportSettings) {
|
@@ -1,16 +1,13 @@
|
|
1
1
|
// Copyright 2014 The Chromium Authors
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
3
3
|
// found in the LICENSE file.
|
4
|
-
/* eslint-disable rulesdir/no-imperative-dom-api */
|
5
|
-
/* eslint-disable rulesdir/no-lit-render-outside-of-view */
|
6
|
-
|
7
4
|
import * as Common from '../../core/common/common.js';
|
8
5
|
import * as i18n from '../../core/i18n/i18n.js';
|
9
6
|
import * as Platform from '../../core/platform/platform.js';
|
10
7
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
11
8
|
import type * as Workspace from '../../models/workspace/workspace.js';
|
12
9
|
import * as UI from '../../ui/legacy/legacy.js';
|
13
|
-
import {html, render} from '../../ui/lit/lit.js';
|
10
|
+
import {html, render, type TemplateResult} from '../../ui/lit/lit.js';
|
14
11
|
|
15
12
|
import searchResultsPaneStyles from './searchResultsPane.css.js';
|
16
13
|
import type {SearchResult} from './SearchScope.js';
|
@@ -41,143 +38,185 @@ interface SearchMatch {
|
|
41
38
|
resultLabel: string|number;
|
42
39
|
}
|
43
40
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
41
|
+
interface ViewInput {
|
42
|
+
results: SearchResult[];
|
43
|
+
matches: WeakMap<SearchResult, SearchMatch[]>;
|
44
|
+
expandedResults: WeakSet<SearchResult>;
|
45
|
+
onSelectMatch: (searchResult: SearchResult, matchIndex: number) => void;
|
46
|
+
onExpandSearchResult: (searchResult: SearchResult) => void;
|
47
|
+
onShowMoreMatches: (searchResult: SearchResult) => void;
|
48
|
+
}
|
49
|
+
|
50
|
+
export type View = (input: ViewInput, output: unknown, target: HTMLElement) => void;
|
51
|
+
|
52
|
+
export const DEFAULT_VIEW: View = (input, _output, target) => {
|
53
|
+
const {results, matches, expandedResults, onSelectMatch, onExpandSearchResult, onShowMoreMatches} = input;
|
54
|
+
|
55
|
+
const onExpand = ({detail: {expanded, target}}: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
|
56
|
+
const searchResultIndex = Number(target.dataset.searchResultIndex);
|
57
|
+
const searchResult = results[searchResultIndex];
|
58
|
+
if (expanded) {
|
59
|
+
expandedResults.add(searchResult);
|
60
|
+
onExpandSearchResult(searchResult);
|
61
|
+
} else {
|
62
|
+
expandedResults.delete(searchResult);
|
59
63
|
}
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
64
|
+
};
|
65
|
+
|
66
|
+
// clang-format off
|
67
|
+
render(html`
|
68
|
+
<devtools-tree hide-overflow @expand=${onExpand} .template=${html`
|
69
|
+
<ul role="tree">
|
70
|
+
${results.map((searchResult, i) => html`
|
71
|
+
<li role="treeitem" data-search-result-index=${i} class="search-result">
|
72
|
+
<style>${searchResultsPaneStyles}</style>
|
73
|
+
${renderSearchResult(searchResult)}
|
74
|
+
<ul role="group" ?hidden=${!expandedResults.has(searchResult)}>
|
75
|
+
${renderSearchMatches(searchResult, matches, onSelectMatch, onShowMoreMatches)}
|
76
|
+
</ul>
|
77
|
+
</li>`)}
|
78
|
+
</ul>
|
79
|
+
`}></devtools-tree>`,
|
80
|
+
target,
|
81
|
+
);
|
82
|
+
// clang-format on
|
83
|
+
};
|
84
|
+
|
85
|
+
const renderSearchResult = (searchResult: SearchResult): TemplateResult => {
|
86
|
+
// clang-format off
|
87
|
+
return html`
|
88
|
+
<span class="search-result-file-name">${searchResult.label()}
|
89
|
+
<span class="search-result-dash">${'\u2014'}</span>
|
90
|
+
<span class="search-result-qualifier">${searchResult.description()}</span>
|
91
|
+
</span>
|
92
|
+
<span class="search-result-matches-count"
|
93
|
+
aria-label=${i18nString(UIStrings.matchesCountS, {PH1: searchResult.matchesCount()})}>
|
94
|
+
${searchResult.matchesCount()}
|
95
|
+
</span>`;
|
96
|
+
// clang-format on
|
97
|
+
};
|
98
|
+
|
99
|
+
const renderSearchMatches =
|
100
|
+
(searchResult: SearchResult, matches: WeakMap<SearchResult, SearchMatch[]>,
|
101
|
+
onSelectMatch: (searchResult: SearchResult, matchIndex: number) => void,
|
102
|
+
onShowMoreMatches: (searchResult: SearchResult) => void): TemplateResult => {
|
103
|
+
const visibleMatches = matches.get(searchResult) ?? [];
|
104
|
+
const matchesLeftCount = searchResult.matchesCount() - visibleMatches.length;
|
105
|
+
// clang-format off
|
106
|
+
return html`
|
107
|
+
${visibleMatches.map(({lineContent, matchRanges, resultLabel}, i) => html`
|
108
|
+
<li role="treeitem" class="search-match" @click=${() => onSelectMatch(searchResult, i)}
|
109
|
+
${UI.TreeOutline.TreeSearch.highlight(matchRanges.map(range =>
|
110
|
+
({offset: range.offset + `${resultLabel}`.length, length: range.length})), undefined)}
|
111
|
+
@keydown=${(event: KeyboardEvent) => {
|
112
|
+
if (event.key === 'Enter') {
|
113
|
+
onSelectMatch(searchResult, i);
|
114
|
+
}
|
115
|
+
}}
|
116
|
+
>
|
117
|
+
<button class="devtools-link text-button link-style search-match-link"
|
118
|
+
jslog="Link; context: search-match; track: click" role="link" tabindex="0"
|
119
|
+
@click=${() => void Common.Revealer.reveal(searchResult.matchRevealable(i))}>
|
120
|
+
<span class="search-match-line-number"
|
121
|
+
aria-label=${typeof resultLabel === 'number' && !isNaN(resultLabel)
|
122
|
+
? i18nString(UIStrings.lineS, {PH1: resultLabel}) : resultLabel}>
|
123
|
+
${resultLabel}
|
124
|
+
</span>
|
125
|
+
<span class="search-match-content" aria-label="${lineContent} line">
|
126
|
+
${lineContent}
|
127
|
+
</span>
|
128
|
+
</button>
|
129
|
+
</li>`)}
|
130
|
+
${
|
131
|
+
matchesLeftCount > 0 ? html`
|
132
|
+
<li role="treeitem" class="show-more-matches" @click=${() => onShowMoreMatches(searchResult)}>
|
133
|
+
${i18nString(UIStrings.showDMore, { PH1: matchesLeftCount })}
|
134
|
+
</li>` : ''}`;
|
135
|
+
// clang-format on
|
136
|
+
};
|
137
|
+
|
138
|
+
export class SearchResultsPane extends UI.Widget.VBox {
|
139
|
+
#searchConfig: Workspace.SearchConfig.SearchConfig|null = null;
|
140
|
+
#searchResults: SearchResult[] = [];
|
141
|
+
#resultsUpdated = false;
|
142
|
+
#expandedResults = new WeakSet<SearchResult>();
|
143
|
+
readonly #searchMatches = new WeakMap<SearchResult, SearchMatch[]>();
|
144
|
+
#view: View;
|
145
|
+
|
146
|
+
constructor(element: HTMLElement|undefined, view: View = DEFAULT_VIEW) {
|
147
|
+
super(element, {useShadowDom: true});
|
148
|
+
this.#view = view;
|
74
149
|
}
|
75
150
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
151
|
+
get searchResults(): SearchResult[] {
|
152
|
+
return this.#searchResults;
|
153
|
+
}
|
154
|
+
|
155
|
+
set searchResults(searchResults: SearchResult[]) {
|
156
|
+
if (this.#searchResults === searchResults) {
|
80
157
|
return;
|
81
158
|
}
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
? i18nString(UIStrings.lineS, {PH1: resultLabel}) : resultLabel}>
|
92
|
-
${resultLabel}
|
93
|
-
</span>
|
94
|
-
<span class="search-match-content" aria-label="${lineContent} line">
|
95
|
-
${lineContent}
|
96
|
-
</span>
|
97
|
-
</button>`,
|
98
|
-
searchMatchElement.listItemElement);
|
99
|
-
// clang-format on
|
100
|
-
const contentSpan = searchMatchElement.listItemElement.querySelector('.search-match-content') as HTMLElement;
|
101
|
-
UI.UIUtils.highlightRangesWithStyleClass(contentSpan, matchRanges, 'highlighted-search-result');
|
102
|
-
searchMatchElement.listItemElement.className = 'search-match';
|
103
|
-
searchMatchElement.listItemElement.addEventListener('keydown', event => {
|
104
|
-
if (event.key === 'Enter') {
|
105
|
-
event.consume(true);
|
106
|
-
void Common.Revealer.reveal(searchResult.matchRevealable(i));
|
159
|
+
if (this.#searchResults.length !== searchResults.length) {
|
160
|
+
this.#resultsUpdated = true;
|
161
|
+
} else if (this.#searchResults.length === searchResults.length) {
|
162
|
+
for (let i = 0; i < this.#searchResults.length; ++i) {
|
163
|
+
if (this.#searchResults[i] === searchResults[i]) {
|
164
|
+
continue;
|
165
|
+
}
|
166
|
+
this.#resultsUpdated = true;
|
167
|
+
break;
|
107
168
|
}
|
108
|
-
}
|
109
|
-
|
169
|
+
}
|
170
|
+
if (!this.#resultsUpdated) {
|
171
|
+
return;
|
172
|
+
}
|
173
|
+
this.#searchResults = searchResults;
|
174
|
+
this.requestUpdate();
|
110
175
|
}
|
111
176
|
|
112
|
-
|
113
|
-
|
114
|
-
this.searchConfig = searchConfig;
|
115
|
-
this.treeOutline = new UI.TreeOutline.TreeOutlineInShadow();
|
116
|
-
this.treeOutline.registerRequiredCSS(searchResultsPaneStyles);
|
117
|
-
this.treeOutline.setHideOverflow(true);
|
118
|
-
this.treeOutline.addEventListener(
|
119
|
-
UI.TreeOutline.Events.ElementExpanded,
|
120
|
-
(event: Common.EventTarget.EventTargetEvent<UI.TreeOutline.TreeElement>) => {
|
121
|
-
const searchResult = this.searchResults.entries().find(entry => entry[1] === event.data)?.[0];
|
122
|
-
if (!searchResult) {
|
123
|
-
return;
|
124
|
-
}
|
125
|
-
this.expandSearchResult(searchResult);
|
126
|
-
});
|
127
|
-
|
128
|
-
this.contentElement.appendChild(this.treeOutline.element);
|
129
|
-
|
130
|
-
this.matchesExpandedCount = 0;
|
177
|
+
get searchConfig(): Workspace.SearchConfig.SearchConfig|null {
|
178
|
+
return this.#searchConfig;
|
131
179
|
}
|
132
180
|
|
133
|
-
|
134
|
-
this
|
135
|
-
|
136
|
-
if (this.matchesExpandedCount < matchesExpandedByDefault) {
|
137
|
-
this.searchResults.get(searchResult)?.expand();
|
138
|
-
}
|
181
|
+
set searchConfig(searchConfig: Workspace.SearchConfig.SearchConfig|null) {
|
182
|
+
this.#searchConfig = searchConfig;
|
183
|
+
this.requestUpdate();
|
139
184
|
}
|
140
185
|
|
141
186
|
showAllMatches(): void {
|
142
|
-
for (const searchResult of this
|
143
|
-
const startMatchIndex = this
|
144
|
-
this
|
187
|
+
for (const searchResult of this.#searchResults) {
|
188
|
+
const startMatchIndex = this.#searchMatches.get(searchResult)?.length ?? 0;
|
189
|
+
this.#appendSearchMatches(searchResult, startMatchIndex, searchResult.matchesCount());
|
190
|
+
this.#expandedResults.add(searchResult);
|
145
191
|
}
|
192
|
+
this.requestUpdate();
|
146
193
|
}
|
147
194
|
|
148
195
|
collapseAllResults(): void {
|
149
|
-
|
150
|
-
|
151
|
-
}
|
196
|
+
this.#expandedResults = new WeakSet<SearchResult>();
|
197
|
+
this.requestUpdate();
|
152
198
|
}
|
153
199
|
|
154
|
-
|
200
|
+
#onExpandSearchResult(searchResult: SearchResult): void {
|
155
201
|
const toIndex = Math.min(searchResult.matchesCount(), matchesShownAtOnce);
|
156
|
-
|
157
|
-
this.appendSearchMatches(searchResult, 0, toIndex - 1);
|
158
|
-
this.appendShowMoreMatchesElement(searchResult, toIndex - 1);
|
159
|
-
} else {
|
160
|
-
this.appendSearchMatches(searchResult, 0, toIndex);
|
161
|
-
}
|
162
|
-
this.matchesExpandedCount += toIndex;
|
202
|
+
this.#appendSearchMatches(searchResult, 0, toIndex);
|
163
203
|
this.requestUpdate();
|
164
204
|
}
|
165
205
|
|
166
|
-
|
167
|
-
this
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
const queries = this.searchConfig.queries();
|
206
|
+
#appendSearchMatches(searchResult: SearchResult, fromIndex: number, toIndex: number): void {
|
207
|
+
if (!this.#searchConfig) {
|
208
|
+
return;
|
209
|
+
}
|
210
|
+
const queries = this.#searchConfig.queries();
|
172
211
|
const regexes = [];
|
173
212
|
for (let i = 0; i < queries.length; ++i) {
|
174
213
|
regexes.push(Platform.StringUtilities.createSearchRegex(
|
175
|
-
queries[i], !this
|
214
|
+
queries[i], !this.#searchConfig.ignoreCase(), this.#searchConfig.isRegex()));
|
176
215
|
}
|
177
216
|
|
178
|
-
const searchMatches = this
|
179
|
-
this
|
180
|
-
if (searchMatches.length
|
217
|
+
const searchMatches = this.#searchMatches.get(searchResult) ?? [];
|
218
|
+
this.#searchMatches.set(searchResult, searchMatches);
|
219
|
+
if (searchMatches.length >= toIndex) {
|
181
220
|
return;
|
182
221
|
}
|
183
222
|
|
@@ -197,32 +236,48 @@ export class SearchResultsPane extends UI.Widget.VBox {
|
|
197
236
|
} else {
|
198
237
|
lineContent = lineContent.trim();
|
199
238
|
for (let j = 0; j < regexes.length; ++j) {
|
200
|
-
matchRanges = matchRanges.concat(this
|
239
|
+
matchRanges = matchRanges.concat(this.#regexMatchRanges(lineContent, regexes[j]));
|
201
240
|
}
|
202
241
|
({lineSegment: lineContent, matchRanges} = lineSegmentForMultipleMatches(lineContent, matchRanges));
|
203
242
|
}
|
204
243
|
|
205
244
|
const resultLabel = searchResult.matchLabel(i);
|
206
245
|
searchMatches.push({lineContent, matchRanges, resultLabel});
|
207
|
-
this.appendSearchMatchElement(searchResult, searchMatches[i], i);
|
208
246
|
}
|
209
247
|
}
|
210
248
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
249
|
+
override performUpdate(): void {
|
250
|
+
if (this.#resultsUpdated) {
|
251
|
+
let matchesExpandedCount = 0;
|
252
|
+
for (const searchResult of this.#searchResults) {
|
253
|
+
if (this.#expandedResults.has(searchResult)) {
|
254
|
+
matchesExpandedCount += this.#searchMatches.get(searchResult)?.length ?? 0;
|
255
|
+
}
|
256
|
+
}
|
257
|
+
for (const searchResult of this.#searchResults) {
|
258
|
+
if (matchesExpandedCount < matchesExpandedByDefault && !this.#expandedResults.has(searchResult)) {
|
259
|
+
this.#expandedResults.add(searchResult);
|
260
|
+
this.#onExpandSearchResult(searchResult);
|
261
|
+
matchesExpandedCount += this.#searchMatches.get(searchResult)?.length ?? 0;
|
262
|
+
}
|
263
|
+
}
|
264
|
+
this.#resultsUpdated = false;
|
215
265
|
}
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
266
|
+
this.#view(
|
267
|
+
{
|
268
|
+
results: this.#searchResults,
|
269
|
+
matches: this.#searchMatches,
|
270
|
+
expandedResults: this.#expandedResults,
|
271
|
+
onSelectMatch: (searchResult, matchIndex) => {
|
272
|
+
void Common.Revealer.reveal(searchResult.matchRevealable(matchIndex));
|
273
|
+
},
|
274
|
+
onExpandSearchResult: this.#onExpandSearchResult.bind(this),
|
275
|
+
onShowMoreMatches: this.#onShowMoreMatches.bind(this),
|
276
|
+
},
|
277
|
+
{}, this.contentElement);
|
223
278
|
}
|
224
279
|
|
225
|
-
|
280
|
+
#regexMatchRanges(lineContent: string, regex: RegExp): TextUtils.TextRange.SourceRange[] {
|
226
281
|
regex.lastIndex = 0;
|
227
282
|
let match;
|
228
283
|
const matchRanges = [];
|
@@ -233,13 +288,10 @@ export class SearchResultsPane extends UI.Widget.VBox {
|
|
233
288
|
return matchRanges;
|
234
289
|
}
|
235
290
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
parentElement?.removeChild(showMoreMatchesTreeElement);
|
241
|
-
this.appendSearchMatches(searchResult, startMatchIndex, searchResult.matchesCount());
|
242
|
-
return true;
|
291
|
+
#onShowMoreMatches(searchResult: SearchResult): void {
|
292
|
+
const startMatchIndex = this.#searchMatches.get(searchResult)?.length ?? 0;
|
293
|
+
this.#appendSearchMatches(searchResult, startMatchIndex, searchResult.matchesCount());
|
294
|
+
this.requestUpdate();
|
243
295
|
}
|
244
296
|
}
|
245
297
|
|