chrome-devtools-frontend 1.0.1587572 → 1.0.1587905
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/front_end/core/sdk/ScopeTreeCache.ts +4 -0
- package/front_end/generated/Deprecation.ts +21 -0
- package/front_end/models/ai_assistance/AiConversation.ts +5 -1
- package/front_end/models/ai_assistance/agents/AiAgent.ts +16 -4
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +7 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +0 -2
- package/front_end/panels/ai_assistance/components/ChatInput.ts +36 -31
- package/front_end/panels/ai_assistance/components/chatInput.css +6 -9
- package/front_end/panels/application/ServiceWorkerCacheViews.ts +3 -5
- package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +11 -3
- package/front_end/panels/common/DOMLinkifier.ts +6 -1
- package/front_end/panels/elements/ComputedStyleWidget.ts +25 -2
- package/front_end/panels/elements/PropertiesWidget.ts +40 -2
- package/front_end/panels/elements/StylesSidebarPane.ts +26 -3
- package/front_end/panels/network/NetworkDataGridNode.ts +4 -0
- package/front_end/panels/network/NetworkItemView.ts +6 -45
- package/front_end/panels/network/RequestHeadersView.ts +236 -302
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/legacy/Toolbar.ts +37 -5
- package/front_end/ui/legacy/UIUtils.ts +35 -5
- package/package.json +1 -1
|
@@ -25,6 +25,10 @@ const scopeTrees = new WeakMap<Script, Promise<{scopeTree: ScopeTreeNode, text:
|
|
|
25
25
|
* and the text allows conversion from/to line/column numbers.
|
|
26
26
|
*/
|
|
27
27
|
export function scopeTreeForScript(script: Script): Promise<{scopeTree: ScopeTreeNode, text: Text}|null> {
|
|
28
|
+
if (script.isWasm()) {
|
|
29
|
+
return Promise.resolve(null);
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
let promise = scopeTrees.get(script);
|
|
29
33
|
if (promise === undefined) {
|
|
30
34
|
promise = script.requestContentData().then(content => {
|
|
@@ -94,6 +94,18 @@ export const UIStrings = {
|
|
|
94
94
|
* @description Warning displayed to developers that instead of calling the `Intl.v8BreakIterator` constructor, which is not a standard JavaScript API, use ECMA402 standard API Intl.Segmenter shipped in end of 2020 instead.
|
|
95
95
|
*/
|
|
96
96
|
IntlV8BreakIterator: "`Intl.v8BreakIterator` is deprecated. Please use `Intl.Segmenter` instead.",
|
|
97
|
+
/**
|
|
98
|
+
* @description Warning for using deprecated 'inputQuota' attribute.
|
|
99
|
+
*/
|
|
100
|
+
LanguageModel_InputQuota: "LanguageModel.inputQuota is deprecated. Please use LanguageModel.contextWindow instead. This alias is only available in extensions.",
|
|
101
|
+
/**
|
|
102
|
+
* @description Warning for using deprecated 'inputUsage' attribute.
|
|
103
|
+
*/
|
|
104
|
+
LanguageModel_InputUsage: "LanguageModel.inputUsage is deprecated. Please use LanguageModel.contextUsage instead. This alias is only available in extensions.",
|
|
105
|
+
/**
|
|
106
|
+
* @description Warning for using deprecated 'measureInputUsage' method.
|
|
107
|
+
*/
|
|
108
|
+
LanguageModel_MeasureInputUsage: "LanguageModel.measureInputUsage() is deprecated. Please use LanguageModel.measureContextUsage() instead. This alias is only available in extensions.",
|
|
97
109
|
/**
|
|
98
110
|
* @description Warning message for web developers when they call the deprecated LanguageModel.params() method.
|
|
99
111
|
*/
|
|
@@ -313,6 +325,15 @@ export const DEPRECATIONS_METADATA: Partial<Record<string, DeprecationDescriptor
|
|
|
313
325
|
"LanguageModelTopK": {
|
|
314
326
|
"chromeStatusFeature": 5134603979063296
|
|
315
327
|
},
|
|
328
|
+
"LanguageModel_InputQuota": {
|
|
329
|
+
"chromeStatusFeature": 5134603979063296
|
|
330
|
+
},
|
|
331
|
+
"LanguageModel_InputUsage": {
|
|
332
|
+
"chromeStatusFeature": 5134603979063296
|
|
333
|
+
},
|
|
334
|
+
"LanguageModel_MeasureInputUsage": {
|
|
335
|
+
"chromeStatusFeature": 5134603979063296
|
|
336
|
+
},
|
|
316
337
|
"LocalCSSFileExtensionRejected": {
|
|
317
338
|
"milestone": 64
|
|
318
339
|
},
|
|
@@ -425,6 +425,10 @@ Time: ${micros(time)}`;
|
|
|
425
425
|
yield* this.#runAgent(initialQuery, options);
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
+
#getQueryAfterSelection(initialQuery: string, selection: string): string {
|
|
429
|
+
return `${selection}\nOriginal user query: ${initialQuery}`;
|
|
430
|
+
}
|
|
431
|
+
|
|
428
432
|
async *
|
|
429
433
|
#runAgent(
|
|
430
434
|
initialQuery: string,
|
|
@@ -467,7 +471,7 @@ Time: ${micros(time)}`;
|
|
|
467
471
|
// requery with the specialized agent.
|
|
468
472
|
if (data.type === ResponseType.CONTEXT_CHANGE) {
|
|
469
473
|
this.setContext(data.context);
|
|
470
|
-
yield* this.#runAgent(initialQuery, options);
|
|
474
|
+
yield* this.#runAgent(this.#getQueryAfterSelection(initialQuery, data.description), options);
|
|
471
475
|
return;
|
|
472
476
|
}
|
|
473
477
|
}
|
|
@@ -88,6 +88,12 @@ export interface SideEffectResponse {
|
|
|
88
88
|
}
|
|
89
89
|
export interface ContextChangeResponse {
|
|
90
90
|
type: ResponseType.CONTEXT_CHANGE;
|
|
91
|
+
/**
|
|
92
|
+
* Information to pass down what was selected
|
|
93
|
+
* Use to make the LLM understand the the user
|
|
94
|
+
* already selected something.
|
|
95
|
+
*/
|
|
96
|
+
description: string;
|
|
91
97
|
context: ConversationContext<unknown>;
|
|
92
98
|
}
|
|
93
99
|
|
|
@@ -212,7 +218,8 @@ export type FunctionCallHandlerResult<Result> = {
|
|
|
212
218
|
}|{
|
|
213
219
|
result: Result,
|
|
214
220
|
}|{
|
|
215
|
-
context: unknown
|
|
221
|
+
context: ConversationContext<unknown>,
|
|
222
|
+
description: string,
|
|
216
223
|
}|{
|
|
217
224
|
error: string,
|
|
218
225
|
};
|
|
@@ -484,7 +491,9 @@ export abstract class AiAgent<T> {
|
|
|
484
491
|
* called with one object with `foo` and `bar` keys.
|
|
485
492
|
*/
|
|
486
493
|
protected declareFunction<Args extends Record<string, unknown>, ReturnType = unknown>(
|
|
487
|
-
name: string,
|
|
494
|
+
name: string,
|
|
495
|
+
declaration: FunctionDeclaration<Args, ReturnType>,
|
|
496
|
+
): void {
|
|
488
497
|
if (this.#functionDeclarations.has(name)) {
|
|
489
498
|
throw new Error(`Duplicate function declaration ${name}`);
|
|
490
499
|
}
|
|
@@ -609,6 +618,7 @@ export abstract class AiAgent<T> {
|
|
|
609
618
|
if ('context' in result) {
|
|
610
619
|
yield {
|
|
611
620
|
type: ResponseType.CONTEXT_CHANGE,
|
|
621
|
+
description: result.description,
|
|
612
622
|
context: result.context,
|
|
613
623
|
};
|
|
614
624
|
|
|
@@ -643,7 +653,9 @@ export abstract class AiAgent<T> {
|
|
|
643
653
|
name: string,
|
|
644
654
|
args: Record<string, unknown>,
|
|
645
655
|
options?: FunctionHandlerOptions&{explanation?: string},
|
|
646
|
-
): AsyncGenerator<FunctionCallResponseData, {
|
|
656
|
+
): AsyncGenerator<FunctionCallResponseData, {
|
|
657
|
+
result: unknown,
|
|
658
|
+
}|{context: ConversationContext<unknown>, description: string}> {
|
|
647
659
|
const call = this.#functionDeclarations.get(name);
|
|
648
660
|
if (!call) {
|
|
649
661
|
throw new Error(`Function ${name} is not found.`);
|
|
@@ -755,7 +767,7 @@ export abstract class AiAgent<T> {
|
|
|
755
767
|
}
|
|
756
768
|
|
|
757
769
|
if ('context' in result) {
|
|
758
|
-
return result
|
|
770
|
+
return result;
|
|
759
771
|
}
|
|
760
772
|
|
|
761
773
|
return result as {result: unknown};
|
|
@@ -169,6 +169,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
169
169
|
const calculator = this.#networkTimeCalculator ?? new NetworkTimeCalculator.NetworkTransferTimeCalculator();
|
|
170
170
|
return {
|
|
171
171
|
context: new RequestContext(request, calculator),
|
|
172
|
+
description: 'User selected a network request',
|
|
172
173
|
};
|
|
173
174
|
}
|
|
174
175
|
|
|
@@ -231,11 +232,14 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
231
232
|
if (file.fullDisplayName() === params.name) {
|
|
232
233
|
return {
|
|
233
234
|
context: new FileContext(file),
|
|
235
|
+
description: 'User selected a source file',
|
|
234
236
|
};
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
239
|
|
|
238
|
-
return {
|
|
240
|
+
return {
|
|
241
|
+
error: 'Unable to find file.',
|
|
242
|
+
};
|
|
239
243
|
},
|
|
240
244
|
});
|
|
241
245
|
|
|
@@ -264,6 +268,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
264
268
|
|
|
265
269
|
return {
|
|
266
270
|
context: PerformanceTraceContext.fromParsedTrace(result),
|
|
271
|
+
description: 'User recorded a performance trace',
|
|
267
272
|
};
|
|
268
273
|
}
|
|
269
274
|
});
|
|
@@ -292,6 +297,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
292
297
|
if (node) {
|
|
293
298
|
return {
|
|
294
299
|
context: new NodeContext(node),
|
|
300
|
+
description: 'User selected an element',
|
|
295
301
|
};
|
|
296
302
|
}
|
|
297
303
|
return {
|
|
@@ -1426,8 +1426,6 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1426
1426
|
// Cancel any previous in-flight conversation.
|
|
1427
1427
|
this.#cancel();
|
|
1428
1428
|
const signal = this.#runAbortController.signal;
|
|
1429
|
-
const context = this.#getConversationContext(this.#conversation.type);
|
|
1430
|
-
this.#conversation.setContext(context);
|
|
1431
1429
|
|
|
1432
1430
|
// If a different context is provided, it must be from the same origin.
|
|
1433
1431
|
if (this.#conversation.isBlockedByOrigin) {
|
|
@@ -202,7 +202,8 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
|
|
|
202
202
|
jslog=${VisualLogging.link('open-ai-settings').track({
|
|
203
203
|
click: true,
|
|
204
204
|
})}
|
|
205
|
-
@click=${() => {
|
|
205
|
+
@click=${(ev: Event) => {
|
|
206
|
+
ev.preventDefault();
|
|
206
207
|
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
|
|
207
208
|
}}
|
|
208
209
|
>${lockedString('Relevant data')}</button> ${lockedString('is sent to Google')}
|
|
@@ -320,42 +321,46 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
|
|
|
320
321
|
></devtools-button>`
|
|
321
322
|
: Lit.nothing}
|
|
322
323
|
<div
|
|
323
|
-
role=button
|
|
324
324
|
class=${Lit.Directives.classMap({
|
|
325
325
|
'resource-link': true,
|
|
326
326
|
'has-picker-behavior': input.conversationType === AiAssistanceModel.AiHistoryStorage.ConversationType.STYLING,
|
|
327
|
-
disabled: input.isTextInputDisabled,
|
|
328
327
|
})}
|
|
329
|
-
tabindex=${(input.conversationType === AiAssistanceModel.AiHistoryStorage.ConversationType.STYLING || input.isTextInputDisabled) ? '-1' : '0'}
|
|
330
|
-
@click=${input.onContextClick}
|
|
331
|
-
@keydown=${(ev: KeyboardEvent) => {
|
|
332
|
-
if (ev.key === 'Enter' || ev.key === ' ') {
|
|
333
|
-
void input.onContextClick();
|
|
334
|
-
}
|
|
335
|
-
}}
|
|
336
|
-
aria-description=${i18nString(UIStrings.revealContextDescription)}
|
|
337
328
|
>
|
|
338
|
-
${
|
|
339
|
-
|
|
340
|
-
input.selectedContext instanceof AiAssistanceModel.FileAgent.FileContext ?
|
|
341
|
-
PanelUtils.PanelUtils.getIconForSourceFile(input.selectedContext.getItem()) :
|
|
342
|
-
input.selectedContext instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext ?
|
|
343
|
-
html`<devtools-icon name="performance" title="Performance"></devtools-icon>` :
|
|
344
|
-
Lit.nothing}
|
|
345
|
-
<span class="title">
|
|
346
|
-
${input.selectedContext instanceof AiAssistanceModel.StylingAgent.NodeContext ?
|
|
329
|
+
${
|
|
330
|
+
input.selectedContext instanceof AiAssistanceModel.StylingAgent.NodeContext ?
|
|
347
331
|
html`
|
|
348
|
-
<devtools-widget
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
332
|
+
<devtools-widget
|
|
333
|
+
class="title"
|
|
334
|
+
.widgetConfig=${UI.Widget.widgetConfig(PanelsCommon.DOMLinkifier.DOMNodeLink, {
|
|
335
|
+
node: input.selectedContext.getItem(),
|
|
336
|
+
options: {
|
|
337
|
+
hiddenClassList: input.selectedContext.getItem().classNames().filter(
|
|
338
|
+
className => className.startsWith(AiAssistanceModel.Injected.AI_ASSISTANCE_CSS_CLASS_NAME)),
|
|
339
|
+
ariaDescription: i18nString(UIStrings.revealContextDescription),
|
|
340
|
+
},
|
|
341
|
+
})}
|
|
342
|
+
></devtools-widget>` :
|
|
343
|
+
html`
|
|
344
|
+
${input.selectedContext instanceof AiAssistanceModel.NetworkAgent.RequestContext ?
|
|
345
|
+
PanelUtils.PanelUtils.getIconForNetworkRequest(input.selectedContext.getItem()) :
|
|
346
|
+
input.selectedContext instanceof AiAssistanceModel.FileAgent.FileContext ?
|
|
347
|
+
PanelUtils.PanelUtils.getIconForSourceFile(input.selectedContext.getItem()) :
|
|
348
|
+
input.selectedContext instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext ?
|
|
349
|
+
html`<devtools-icon name="performance" title="Performance"></devtools-icon>` :
|
|
350
|
+
Lit.nothing}
|
|
351
|
+
<span
|
|
352
|
+
role="button"
|
|
353
|
+
class="title"
|
|
354
|
+
tabindex="0"
|
|
355
|
+
@click=${input.onContextClick}
|
|
356
|
+
@keydown=${(ev: KeyboardEvent) => {
|
|
357
|
+
if (ev.key === 'Enter' || ev.key === ' ') {
|
|
358
|
+
void input.onContextClick();
|
|
359
|
+
}
|
|
360
|
+
}}
|
|
361
|
+
aria-description=${i18nString(UIStrings.revealContextDescription)}
|
|
362
|
+
>${input.selectedContext.getTitle()}</span>`
|
|
363
|
+
}
|
|
359
364
|
${input.onContextRemoved ? html`
|
|
360
365
|
<devtools-button
|
|
361
366
|
title=${getContextRemoveLabel(input.selectedContext)}
|
|
@@ -218,9 +218,9 @@
|
|
|
218
218
|
gap: var(--sys-size-3);
|
|
219
219
|
align-items: center;
|
|
220
220
|
|
|
221
|
-
.resource-link
|
|
222
|
-
.resource-task {
|
|
221
|
+
.resource-link {
|
|
223
222
|
display: flex;
|
|
223
|
+
background-color: var(--sys-color-cdt-base-container);
|
|
224
224
|
align-items: center;
|
|
225
225
|
cursor: pointer;
|
|
226
226
|
padding: var(--sys-size-2) var(--sys-size-3);
|
|
@@ -250,6 +250,10 @@
|
|
|
250
250
|
|
|
251
251
|
&.has-picker-behavior {
|
|
252
252
|
overflow: visible;
|
|
253
|
+
|
|
254
|
+
.title {
|
|
255
|
+
overflow: visible;
|
|
256
|
+
}
|
|
253
257
|
}
|
|
254
258
|
|
|
255
259
|
&:focus-visible {
|
|
@@ -301,13 +305,6 @@
|
|
|
301
305
|
}
|
|
302
306
|
}
|
|
303
307
|
}
|
|
304
|
-
|
|
305
|
-
.resource-link.disabled,
|
|
306
|
-
.resource-task.disabled {
|
|
307
|
-
color: var(--sys-color-state-disabled);
|
|
308
|
-
border-color: var(--sys-color-neutral-outline);
|
|
309
|
-
pointer-events: none;
|
|
310
|
-
}
|
|
311
308
|
}
|
|
312
309
|
|
|
313
310
|
.link {
|
|
@@ -11,7 +11,6 @@ import * as Platform from '../../core/platform/platform.js';
|
|
|
11
11
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
12
12
|
import type * as Protocol from '../../generated/protocol.js';
|
|
13
13
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
|
14
|
-
import * as LegacyWrapper from '../../ui/components/legacy_wrapper/legacy_wrapper.js';
|
|
15
14
|
import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
|
|
16
15
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
17
16
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
@@ -541,10 +540,9 @@ export class RequestView extends UI.Widget.VBox {
|
|
|
541
540
|
this.resourceViewTabSetting =
|
|
542
541
|
Common.Settings.Settings.instance().createSetting('cache-storage-view-tab', 'preview');
|
|
543
542
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
UI.Widget.VBox, new Network.RequestHeadersView.RequestHeadersView(request)));
|
|
543
|
+
const requestHeadersView = new Network.RequestHeadersView.RequestHeadersView();
|
|
544
|
+
requestHeadersView.request = request;
|
|
545
|
+
this.tabbedPane.appendTab('headers', i18nString(UIStrings.headers), requestHeadersView);
|
|
548
546
|
this.tabbedPane.appendTab(
|
|
549
547
|
'preview', i18nString(UIStrings.preview), new Network.RequestPreviewView.RequestPreviewView(request));
|
|
550
548
|
this.tabbedPane.show(this.element);
|
|
@@ -150,12 +150,20 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
150
150
|
const shouldExpandCategory = (breakpoints: SDK.CategorizedBreakpoint.CategorizedBreakpoint[]): boolean =>
|
|
151
151
|
Boolean(input.filterText) || (input.highlightedItem && breakpoints.includes(input.highlightedItem)) ||
|
|
152
152
|
breakpoints.some(breakpoint => breakpoint.enabled());
|
|
153
|
-
const
|
|
154
|
-
|
|
153
|
+
const filterRegex =
|
|
154
|
+
input.filterText ? new RegExp(Platform.StringUtilities.escapeForRegExp(input.filterText), 'i') : null;
|
|
155
|
+
const filter = (breakpoint: SDK.CategorizedBreakpoint.CategorizedBreakpoint): boolean => !filterRegex ||
|
|
156
|
+
Boolean(Sources.CategorizedBreakpointL10n.getLocalizedBreakpointName(breakpoint.name).match(filterRegex)) ||
|
|
155
157
|
breakpoint === input.highlightedItem;
|
|
156
158
|
const filteredCategories =
|
|
157
159
|
input.sortedCategoryNames.values()
|
|
158
|
-
.map(category =>
|
|
160
|
+
.map(category => {
|
|
161
|
+
const breakpoints = input.categories.get(category);
|
|
162
|
+
if (filterRegex && getLocalizedCategory(category).match(filterRegex)) {
|
|
163
|
+
return [category, breakpoints];
|
|
164
|
+
}
|
|
165
|
+
return [category, breakpoints?.filter(filter)];
|
|
166
|
+
})
|
|
159
167
|
.filter(
|
|
160
168
|
(filteredCategory): filteredCategory is
|
|
161
169
|
[SDK.CategorizedBreakpoint.Category, SDK.CategorizedBreakpoint.CategorizedBreakpoint[]] =>
|
|
@@ -12,7 +12,7 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
|
12
12
|
|
|
13
13
|
import domLinkifierStyles from './domLinkifier.css.js';
|
|
14
14
|
|
|
15
|
-
const {classMap} = Directives;
|
|
15
|
+
const {classMap, ifDefined} = Directives;
|
|
16
16
|
|
|
17
17
|
const UIStrings = {
|
|
18
18
|
/**
|
|
@@ -33,6 +33,7 @@ export interface Options {
|
|
|
33
33
|
isDynamicLink?: boolean;
|
|
34
34
|
hiddenClassList?: string[];
|
|
35
35
|
disabled?: boolean;
|
|
36
|
+
ariaDescription?: string;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
interface ViewInput {
|
|
@@ -43,6 +44,7 @@ interface ViewInput {
|
|
|
43
44
|
id?: string;
|
|
44
45
|
classes: string[];
|
|
45
46
|
pseudo?: string;
|
|
47
|
+
ariaDescription?: string;
|
|
46
48
|
onClick: () => void;
|
|
47
49
|
onMouseOver: () => void;
|
|
48
50
|
onMouseLeave: () => void;
|
|
@@ -59,6 +61,7 @@ const DEFAULT_VIEW: View = (input, _output, target: HTMLElement) => {
|
|
|
59
61
|
'dynamic-link': Boolean(input.dynamic),
|
|
60
62
|
disabled: Boolean(input.disabled)
|
|
61
63
|
})}"
|
|
64
|
+
aria-description=${ifDefined(input.ariaDescription)}
|
|
62
65
|
jslog=${VisualLogging.link('node').track({click: true, keydown: 'Enter'})}
|
|
63
66
|
tabindex=${input.preventKeyboardFocus ? -1 : 0}
|
|
64
67
|
@click=${input.onClick}
|
|
@@ -112,6 +115,7 @@ export class DOMNodeLink extends UI.Widget.Widget {
|
|
|
112
115
|
textContent: undefined,
|
|
113
116
|
isDynamicLink: false,
|
|
114
117
|
disabled: false,
|
|
118
|
+
ariaDescription: undefined,
|
|
115
119
|
};
|
|
116
120
|
const viewInput: ViewInput = {
|
|
117
121
|
dynamic: options.isDynamicLink,
|
|
@@ -129,6 +133,7 @@ export class DOMNodeLink extends UI.Widget.Widget {
|
|
|
129
133
|
onMouseLeave: () => {
|
|
130
134
|
SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight();
|
|
131
135
|
},
|
|
136
|
+
ariaDescription: options.ariaDescription,
|
|
132
137
|
};
|
|
133
138
|
if (!this.#node) {
|
|
134
139
|
this.#view(viewInput, {}, this.contentElement);
|
|
@@ -270,6 +270,7 @@ interface ComputedStyleWidgetInput {
|
|
|
270
270
|
groupComputedStylesSetting: Common.Settings.Setting<boolean>;
|
|
271
271
|
onFilterChanged: (event: CustomEvent<string>) => void;
|
|
272
272
|
filterText: string;
|
|
273
|
+
onRegexToggled: () => void;
|
|
273
274
|
}
|
|
274
275
|
|
|
275
276
|
type View = (input: ComputedStyleWidgetInput, output: null, target: HTMLElement) => void;
|
|
@@ -283,8 +284,10 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
283
284
|
<devtools-toolbar-input
|
|
284
285
|
type="filter"
|
|
285
286
|
autofocus
|
|
287
|
+
?regex=${true}
|
|
286
288
|
value=${input.filterText}
|
|
287
289
|
@change=${input.onFilterChanged}
|
|
290
|
+
@regextoggle=${input.onRegexToggled}
|
|
288
291
|
></devtools-toolbar-input>
|
|
289
292
|
<devtools-checkbox
|
|
290
293
|
title=${i18nString(UIStrings.showAll)}
|
|
@@ -317,6 +320,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
317
320
|
#treeData?: TreeOutline.TreeOutline.TreeOutlineData<ComputedStyleData>;
|
|
318
321
|
readonly #view: View;
|
|
319
322
|
#filterText = '';
|
|
323
|
+
#isRegex = false;
|
|
320
324
|
|
|
321
325
|
constructor() {
|
|
322
326
|
super({useShadowDom: true});
|
|
@@ -374,6 +378,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
374
378
|
groupComputedStylesSetting: this.groupComputedStylesSetting,
|
|
375
379
|
onFilterChanged: this.onFilterChanged.bind(this),
|
|
376
380
|
filterText: this.#filterText,
|
|
381
|
+
onRegexToggled: this.onRegexToggled.bind(this),
|
|
377
382
|
},
|
|
378
383
|
null, this.contentElement);
|
|
379
384
|
}
|
|
@@ -654,10 +659,28 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
654
659
|
return result;
|
|
655
660
|
}
|
|
656
661
|
|
|
662
|
+
#buildFilterRegex(text: string): RegExp|null {
|
|
663
|
+
if (!text) {
|
|
664
|
+
return null;
|
|
665
|
+
}
|
|
666
|
+
if (this.#isRegex) {
|
|
667
|
+
try {
|
|
668
|
+
return new RegExp(text, 'i');
|
|
669
|
+
} catch {
|
|
670
|
+
// Invalid regex: fall through to plain-text matching.
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return new RegExp(Platform.StringUtilities.escapeForRegExp(text), 'i');
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
private async onRegexToggled(): Promise<void> {
|
|
677
|
+
this.#isRegex = !this.#isRegex;
|
|
678
|
+
await this.filterComputedStyles(this.#buildFilterRegex(this.#filterText));
|
|
679
|
+
}
|
|
680
|
+
|
|
657
681
|
private async onFilterChanged(event: CustomEvent<string>): Promise<void> {
|
|
658
682
|
this.#filterText = event.detail;
|
|
659
|
-
await this.filterComputedStyles(
|
|
660
|
-
event.detail ? new RegExp(Platform.StringUtilities.escapeForRegExp(event.detail), 'i') : null);
|
|
683
|
+
await this.filterComputedStyles(this.#buildFilterRegex(event.detail));
|
|
661
684
|
|
|
662
685
|
if (event.detail && this.#computedStylesTree.data && this.#computedStylesTree.data.tree) {
|
|
663
686
|
UI.ARIAUtils.LiveAnnouncer.alert(i18nString(
|
|
@@ -73,6 +73,8 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
|
73
73
|
|
|
74
74
|
interface PropertiesWidgetInput {
|
|
75
75
|
onFilterChanged: (e: CustomEvent<string>) => void;
|
|
76
|
+
onRegexToggled: () => void;
|
|
77
|
+
isRegex: boolean;
|
|
76
78
|
treeOutlineElement: HTMLElement;
|
|
77
79
|
displayNoMatchingPropertyMessage: boolean;
|
|
78
80
|
}
|
|
@@ -85,7 +87,13 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
85
87
|
<div jslog=${VisualLogging.pane('element-properties').track({resize: true})}>
|
|
86
88
|
<div class="hbox properties-widget-toolbar">
|
|
87
89
|
<devtools-toolbar class="styles-pane-toolbar" role="presentation">
|
|
88
|
-
<devtools-toolbar-input
|
|
90
|
+
<devtools-toolbar-input
|
|
91
|
+
type="filter"
|
|
92
|
+
?regex=${true}
|
|
93
|
+
@change=${input.onFilterChanged}
|
|
94
|
+
@regextoggle=${input.onRegexToggled}
|
|
95
|
+
style="flex-grow:1; flex-shrink:1"
|
|
96
|
+
></devtools-toolbar-input>
|
|
89
97
|
<devtools-checkbox title=${i18nString(UIStrings.showAllTooltip)} ${bindToSetting(getShowAllPropertiesSetting())}>
|
|
90
98
|
${i18nString(UIStrings.showAll)}
|
|
91
99
|
</devtools-checkbox>
|
|
@@ -110,6 +118,8 @@ export class PropertiesWidget extends UI.Widget.VBox {
|
|
|
110
118
|
private lastRequestedNode?: SDK.DOMModel.DOMNode;
|
|
111
119
|
readonly #view: View;
|
|
112
120
|
#displayNoMatchingPropertyMessage = false;
|
|
121
|
+
#isRegex = false;
|
|
122
|
+
#filterText = '';
|
|
113
123
|
|
|
114
124
|
constructor(view: View = DEFAULT_VIEW) {
|
|
115
125
|
super({useShadowDom: true});
|
|
@@ -140,11 +150,33 @@ export class PropertiesWidget extends UI.Widget.VBox {
|
|
|
140
150
|
void this.performUpdate();
|
|
141
151
|
}
|
|
142
152
|
|
|
153
|
+
#buildFilterRegex(text: string): RegExp|null {
|
|
154
|
+
if (!text) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
if (this.#isRegex) {
|
|
158
|
+
try {
|
|
159
|
+
return new RegExp(text, 'i');
|
|
160
|
+
} catch {
|
|
161
|
+
// Invalid regex: fall through to plain-text matching.
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return new RegExp(Platform.StringUtilities.escapeForRegExp(text), 'i');
|
|
165
|
+
}
|
|
166
|
+
|
|
143
167
|
private onFilterChanged(event: CustomEvent<string>): void {
|
|
144
|
-
this
|
|
168
|
+
this.#filterText = event.detail;
|
|
169
|
+
this.filterRegex = this.#buildFilterRegex(event.detail);
|
|
145
170
|
this.filterAndScheduleUpdate();
|
|
146
171
|
}
|
|
147
172
|
|
|
173
|
+
private onRegexToggled(): void {
|
|
174
|
+
this.#isRegex = !this.#isRegex;
|
|
175
|
+
this.filterRegex = this.#buildFilterRegex(this.#filterText);
|
|
176
|
+
this.internalFilterProperties();
|
|
177
|
+
this.#renderView();
|
|
178
|
+
}
|
|
179
|
+
|
|
148
180
|
private filterAndScheduleUpdate(): void {
|
|
149
181
|
const previousDisplay = this.#displayNoMatchingPropertyMessage;
|
|
150
182
|
this.internalFilterProperties();
|
|
@@ -195,9 +227,15 @@ export class PropertiesWidget extends UI.Widget.VBox {
|
|
|
195
227
|
treeElement, await root.populateChildrenIfNeeded(), true /* skipProto */, true /* skipGettersAndSetters */);
|
|
196
228
|
this.internalFilterProperties();
|
|
197
229
|
}
|
|
230
|
+
this.#renderView();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
#renderView(): void {
|
|
198
234
|
this.#view(
|
|
199
235
|
{
|
|
200
236
|
onFilterChanged: this.onFilterChanged.bind(this),
|
|
237
|
+
onRegexToggled: this.onRegexToggled.bind(this),
|
|
238
|
+
isRegex: this.#isRegex,
|
|
201
239
|
treeOutlineElement: this.treeOutline.element,
|
|
202
240
|
displayNoMatchingPropertyMessage: this.#displayNoMatchingPropertyMessage,
|
|
203
241
|
},
|
|
@@ -184,6 +184,8 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
184
184
|
private userOperation = false;
|
|
185
185
|
isEditingStyle = false;
|
|
186
186
|
#filterRegex: RegExp|null = null;
|
|
187
|
+
#isRegex = false;
|
|
188
|
+
#filterText = '';
|
|
187
189
|
private isActivePropertyHighlighted = false;
|
|
188
190
|
private initialUpdateCompleted = false;
|
|
189
191
|
hasMatchedStyles = false;
|
|
@@ -486,9 +488,28 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
486
488
|
}
|
|
487
489
|
}
|
|
488
490
|
|
|
491
|
+
#buildFilterRegex(text: string): RegExp|null {
|
|
492
|
+
if (!text) {
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
if (this.#isRegex) {
|
|
496
|
+
try {
|
|
497
|
+
return new RegExp(text, 'i');
|
|
498
|
+
} catch {
|
|
499
|
+
// Invalid regex: fall through to plain-text matching.
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return new RegExp(Platform.StringUtilities.escapeForRegExp(text), 'i');
|
|
503
|
+
}
|
|
504
|
+
|
|
489
505
|
private onFilterChanged(event: Common.EventTarget.EventTargetEvent<string>): void {
|
|
490
|
-
|
|
491
|
-
this.setFilter(
|
|
506
|
+
this.#filterText = event.data;
|
|
507
|
+
this.setFilter(this.#buildFilterRegex(event.data));
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
private onRegexToggled(): void {
|
|
511
|
+
this.#isRegex = !this.#isRegex;
|
|
512
|
+
this.setFilter(this.#buildFilterRegex(this.#filterText));
|
|
492
513
|
}
|
|
493
514
|
|
|
494
515
|
setFilter(regex: RegExp|null): void {
|
|
@@ -1392,7 +1413,9 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1392
1413
|
const hbox = container.createChild('div', 'hbox styles-sidebar-pane-toolbar');
|
|
1393
1414
|
const toolbar = hbox.createChild('devtools-toolbar', 'styles-pane-toolbar');
|
|
1394
1415
|
toolbar.role = 'presentation';
|
|
1395
|
-
const filterInput = new UI.Toolbar.ToolbarFilter(
|
|
1416
|
+
const filterInput = new UI.Toolbar.ToolbarFilter(
|
|
1417
|
+
undefined, 1, 1, undefined, undefined, false, undefined, undefined, /* showRegexToggle=*/ true,
|
|
1418
|
+
this.onRegexToggled.bind(this));
|
|
1396
1419
|
filterInput.addEventListener(UI.Toolbar.ToolbarInput.Event.TEXT_CHANGED, this.onFilterChanged, this);
|
|
1397
1420
|
toolbar.appendToolbarItem(filterInput);
|
|
1398
1421
|
void toolbar.appendItemsAtLocation('styles-sidebarpane-toolbar');
|
|
@@ -1621,6 +1621,10 @@ export class NetworkRequestNode extends NetworkNode {
|
|
|
1621
1621
|
this.select();
|
|
1622
1622
|
void action.execute();
|
|
1623
1623
|
}, {capture: true});
|
|
1624
|
+
// We need this as else the images get open under it.
|
|
1625
|
+
floatingButton.addEventListener('dblclick', ev => {
|
|
1626
|
+
ev.stopPropagation();
|
|
1627
|
+
}, {capture: true});
|
|
1624
1628
|
floatingButton.addEventListener('mousedown', ev => {
|
|
1625
1629
|
ev.stopPropagation();
|
|
1626
1630
|
}, {capture: true});
|