chrome-devtools-frontend 1.0.1700561 → 1.0.1701636
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/root/Runtime.ts +5 -0
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +16 -11
- package/front_end/core/sdk/NetworkManager.ts +7 -0
- package/front_end/core/sdk/SecurityOrigin.ts +1 -0
- package/front_end/core/sdk/SourceMap.ts +12 -1
- package/front_end/core/sdk/SourceMapCache.ts +12 -0
- package/front_end/core/sdk/SourceMapManager.ts +17 -8
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +2 -19
- package/front_end/core/sdk/SourceMapScopesInfo.ts +21 -0
- package/front_end/entrypoints/formatter_worker/ScopeParser.ts +7 -3
- package/front_end/entrypoints/formatter_worker/Substitute.ts +90 -26
- package/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.ts +1 -1
- package/front_end/entrypoints/main/ExecutionContextSelector.ts +17 -4
- package/front_end/generated/InspectorBackendCommands.ts +1 -3
- package/front_end/generated/protocol-mapping.d.ts +0 -8
- package/front_end/generated/protocol-proxy-api.d.ts +0 -6
- package/front_end/generated/protocol.ts +4 -22
- package/front_end/models/ai_assistance/debug.ts +10 -2
- package/front_end/models/comment_manager/CD4ABridge.ts +2 -2
- package/front_end/models/comment_manager/CommentManager.ts +3 -0
- package/front_end/models/formatter/FormatterWorkerPool.ts +2 -2
- package/front_end/models/javascript_metadata/NativeFunctions.ts +7 -2
- package/front_end/models/source_map_scopes/NamesResolver.ts +42 -39
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +70 -1
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +1 -1
- package/front_end/panels/common/CommentsOverlayWidget.ts +29 -2
- package/front_end/panels/common/ExtensionServer.ts +18 -8
- package/front_end/panels/console/ConsolePrompt.ts +1 -1
- package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
- package/front_end/panels/elements/ClassesPaneWidget.ts +2 -1
- package/front_end/panels/elements/DOMTreeContextMenu.ts +1 -1
- package/front_end/panels/elements/{ElementsTreeOutline.ts → DOMTreeWidget.ts} +34 -24
- package/front_end/panels/elements/ElementsPanel.ts +1 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +1 -1
- package/front_end/panels/elements/ShortcutTreeElement.ts +1 -1
- package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +4 -6
- package/front_end/panels/elements/TopLayerContainer.ts +1 -1
- package/front_end/panels/elements/elements.ts +4 -3
- package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +1 -1
- package/front_end/panels/profiler/HeapProfileView.ts +8 -6
- package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +8 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +6 -4
- package/front_end/panels/security/SecurityPanel.ts +87 -99
- package/front_end/panels/sensors/SensorsView.ts +87 -0
- package/front_end/panels/sensors/sensors-meta.ts +69 -1
- package/front_end/panels/settings/keybindsSettingsTab.css +1 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/legacy/Treeoutline.ts +2 -1
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +1 -1
- package/front_end/ui/legacy/treeoutline.css +2 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
- package/package.json +1 -1
|
@@ -18532,24 +18532,6 @@ export namespace Storage {
|
|
|
18532
18532
|
durability: StorageBucketsDurability;
|
|
18533
18533
|
}
|
|
18534
18534
|
|
|
18535
|
-
/**
|
|
18536
|
-
* A single Related Website Set object.
|
|
18537
|
-
*/
|
|
18538
|
-
export interface RelatedWebsiteSet {
|
|
18539
|
-
/**
|
|
18540
|
-
* The primary site of this set, along with the ccTLDs if there is any.
|
|
18541
|
-
*/
|
|
18542
|
-
primarySites: string[];
|
|
18543
|
-
/**
|
|
18544
|
-
* The associated sites of this set, along with the ccTLDs if there is any.
|
|
18545
|
-
*/
|
|
18546
|
-
associatedSites: string[];
|
|
18547
|
-
/**
|
|
18548
|
-
* The service sites of this set, along with the ccTLDs if there is any.
|
|
18549
|
-
*/
|
|
18550
|
-
serviceSites: string[];
|
|
18551
|
-
}
|
|
18552
|
-
|
|
18553
18535
|
export interface GetStorageKeyForFrameRequest {
|
|
18554
18536
|
frameId: Page.FrameId;
|
|
18555
18537
|
}
|
|
@@ -18763,10 +18745,6 @@ export namespace Storage {
|
|
|
18763
18745
|
deletedSites: string[];
|
|
18764
18746
|
}
|
|
18765
18747
|
|
|
18766
|
-
export interface GetRelatedWebsiteSetsResponse extends ProtocolResponseWithError {
|
|
18767
|
-
sets: RelatedWebsiteSet[];
|
|
18768
|
-
}
|
|
18769
|
-
|
|
18770
18748
|
/**
|
|
18771
18749
|
* A cache's contents have been modified.
|
|
18772
18750
|
*/
|
|
@@ -20429,6 +20407,10 @@ export namespace WebMCP {
|
|
|
20429
20407
|
* A hint indicating that executing the tool will result in consequential actions, ex: booking a flight, transferring money.
|
|
20430
20408
|
*/
|
|
20431
20409
|
consequential?: boolean;
|
|
20410
|
+
/**
|
|
20411
|
+
* If true, indicates that the tool is intended for debugging and developer tooling rather than end-user interactions.
|
|
20412
|
+
*/
|
|
20413
|
+
debugging?: boolean;
|
|
20432
20414
|
/**
|
|
20433
20415
|
* If the declarative tool was declared with the autosubmit attribute.
|
|
20434
20416
|
*/
|
|
@@ -7,11 +7,19 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
export function isDebugMode(): boolean {
|
|
10
|
-
|
|
10
|
+
try {
|
|
11
|
+
return Boolean(localStorage.getItem('debugAiAssistancePanelEnabled'));
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
export function isStructuredLogEnabled(): boolean {
|
|
14
|
-
|
|
18
|
+
try {
|
|
19
|
+
return Boolean(localStorage.getItem('aiAssistanceStructuredLogEnabled'));
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
export function debugLog(...log: unknown[]): void {
|
|
@@ -72,7 +72,7 @@ export class CD4ABridge extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
|
72
72
|
if (!this.#targetManager) {
|
|
73
73
|
return undefined;
|
|
74
74
|
}
|
|
75
|
-
const target = this.#targetManager.targetById(nodeSignature.targetId)
|
|
75
|
+
const target = this.#targetManager.targetById(nodeSignature.targetId);
|
|
76
76
|
const domModel = target?.model(SDK.DOMModel.DOMModel);
|
|
77
77
|
if (!domModel) {
|
|
78
78
|
return undefined;
|
|
@@ -156,7 +156,7 @@ export class CD4ABridge extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
if (target?.node && this.#targetManager) {
|
|
159
|
-
const sdkTarget = this.#targetManager.targetById(target.node.targetId)
|
|
159
|
+
const sdkTarget = this.#targetManager.targetById(target.node.targetId);
|
|
160
160
|
const domModel = sdkTarget?.model(SDK.DOMModel.DOMModel);
|
|
161
161
|
if (domModel) {
|
|
162
162
|
const cdpNodeId = target.node.backendNodeId as Protocol.DOM.BackendNodeId;
|
|
@@ -134,8 +134,8 @@ export class FormatterWorkerPool {
|
|
|
134
134
|
return this.runTask(FormatterActions.FormatterActions.FORMAT, parameters) as Promise<FormatterActions.FormatResult>;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
javaScriptSubstitute(expression: string, mapping: Map<string, string|null
|
|
138
|
-
if (mapping.size === 0) {
|
|
137
|
+
javaScriptSubstitute(expression: string, mapping: Array<Map<string, string|null>>): Promise<string> {
|
|
138
|
+
if (mapping.every(m => m.size === 0)) {
|
|
139
139
|
return Promise.resolve(expression);
|
|
140
140
|
}
|
|
141
141
|
return this.runTask(FormatterActions.FormatterActions.JAVASCRIPT_SUBSTITUTE, {content: expression, mapping})
|
|
@@ -1367,6 +1367,11 @@ export const NativeFunctions: readonly NativeFunctionValue[] = [
|
|
|
1367
1367
|
signatures: [["message","?options"],["message","transfer"],["message","targetOrigin","?transfer"]],
|
|
1368
1368
|
receivers: ["Window"]
|
|
1369
1369
|
},
|
|
1370
|
+
{
|
|
1371
|
+
name: "postMessage",
|
|
1372
|
+
signatures: [["message","targetOrigin"],["message","?options"]],
|
|
1373
|
+
receivers: ["HTMLPersistentWidgetElement","PersistentWidgetOpener"]
|
|
1374
|
+
},
|
|
1370
1375
|
{
|
|
1371
1376
|
name: "deleteRule",
|
|
1372
1377
|
signatures: [["index"]],
|
|
@@ -2050,7 +2055,7 @@ export const NativeFunctions: readonly NativeFunctionValue[] = [
|
|
|
2050
2055
|
},
|
|
2051
2056
|
{
|
|
2052
2057
|
name: "write",
|
|
2053
|
-
signatures: [["...text"]
|
|
2058
|
+
signatures: [["...text"]],
|
|
2054
2059
|
receivers: ["Document"]
|
|
2055
2060
|
},
|
|
2056
2061
|
{
|
|
@@ -2489,7 +2494,7 @@ export const NativeFunctions: readonly NativeFunctionValue[] = [
|
|
|
2489
2494
|
},
|
|
2490
2495
|
{
|
|
2491
2496
|
name: "writeln",
|
|
2492
|
-
signatures: [["...text"]
|
|
2497
|
+
signatures: [["...text"]]
|
|
2493
2498
|
},
|
|
2494
2499
|
{
|
|
2495
2500
|
name: "elementFromPoint",
|
|
@@ -15,7 +15,7 @@ interface CachedScopeMap {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const scopeToCachedIdentifiersMap = new WeakMap<Formatter.FormatterWorkerPool.ScopeTreeNode, CachedScopeMap>();
|
|
18
|
-
const cachedMapByCallFrame = new WeakMap<SDK.DebuggerModel.CallFrame, Map<string, string|null
|
|
18
|
+
const cachedMapByCallFrame = new WeakMap<SDK.DebuggerModel.CallFrame, Array<Map<string, string|null>>>();
|
|
19
19
|
|
|
20
20
|
export async function getTextFor(contentProvider: TextUtils.ContentProvider.ContentProvider):
|
|
21
21
|
Promise<TextUtils.Text.Text|null> {
|
|
@@ -401,56 +401,61 @@ export const resolveScopeChain =
|
|
|
401
401
|
return scopes.map(scope => new ScopeWithSourceMappedVariables(scope, thisObject, debuggerWorkspaceBinding));
|
|
402
402
|
};
|
|
403
403
|
|
|
404
|
+
function reverseScopeMapping(variableMapping: Map<string, string>): Map<string, string|null> {
|
|
405
|
+
const result = new Map<string, string|null>();
|
|
406
|
+
for (const [compiledName, originalName] of variableMapping) {
|
|
407
|
+
if (originalName && !result.has(originalName)) {
|
|
408
|
+
result.set(originalName, compiledName);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return result;
|
|
412
|
+
}
|
|
413
|
+
|
|
404
414
|
/**
|
|
405
|
-
* @returns
|
|
406
|
-
* shadowed) we set it to `null`.
|
|
415
|
+
* @returns An array of mappings (from inner-most to outer-most scope) of original name -> compiled name or binding expression.
|
|
407
416
|
*/
|
|
408
417
|
export const allVariablesInCallFrame = async(
|
|
409
418
|
callFrame: SDK.DebuggerModel.CallFrame,
|
|
410
419
|
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding):
|
|
411
|
-
Promise<Map<string, string|null
|
|
420
|
+
Promise<Array<Map<string, string|null>>> => {
|
|
412
421
|
if (!callFrame.debuggerModel.target()
|
|
413
422
|
.targetManager()
|
|
414
423
|
.settings.resolve(SDK.SDKSettings.jsSourceMapsEnabledSettingDescriptor)
|
|
415
424
|
.get()) {
|
|
416
|
-
return
|
|
425
|
+
return [];
|
|
417
426
|
}
|
|
418
|
-
const
|
|
419
|
-
if (
|
|
420
|
-
return
|
|
427
|
+
const cached = cachedMapByCallFrame.get(callFrame);
|
|
428
|
+
if (cached) {
|
|
429
|
+
return cached;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (Root.Runtime.hostConfig.devToolsSourceMapScopesInSourcesPanel?.enabled) {
|
|
433
|
+
const sourceMap = callFrame.script.sourceMap() ??
|
|
434
|
+
await callFrame.debuggerModel.sourceMapManager().sourceMapForClientPromise(callFrame.script);
|
|
435
|
+
const mappedVariables =
|
|
436
|
+
sourceMap?.resolveMappedVariablesAtPosition(callFrame.location(), callFrame.returnValue() !== null);
|
|
437
|
+
if (mappedVariables) {
|
|
438
|
+
cachedMapByCallFrame.set(callFrame, mappedVariables);
|
|
439
|
+
return mappedVariables;
|
|
440
|
+
}
|
|
421
441
|
}
|
|
422
442
|
|
|
423
443
|
const scopeChain = callFrame.scopeChain().filter(scope => !scope.empty());
|
|
424
444
|
const nameMappings =
|
|
425
445
|
await Promise.all(scopeChain.map(scope => resolveDebuggerScope(scope, debuggerWorkspaceBinding)));
|
|
426
|
-
const reverseMapping =
|
|
427
|
-
const compiledNames = new Set<string>();
|
|
428
|
-
for (const {variableMapping} of nameMappings) {
|
|
429
|
-
for (const [compiledName, originalName] of variableMapping) {
|
|
430
|
-
if (!originalName) {
|
|
431
|
-
continue;
|
|
432
|
-
}
|
|
433
|
-
if (!reverseMapping.has(originalName)) {
|
|
434
|
-
// An inner scope might have shadowed {compiledName}. Mark it as "unavailable" in that case.
|
|
435
|
-
const compiledNameOrNull = compiledNames.has(compiledName) ? null : compiledName;
|
|
436
|
-
reverseMapping.set(originalName, compiledNameOrNull);
|
|
437
|
-
}
|
|
438
|
-
compiledNames.add(compiledName);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
446
|
+
const reverseMapping = nameMappings.map(({variableMapping}) => reverseScopeMapping(variableMapping));
|
|
441
447
|
cachedMapByCallFrame.set(callFrame, reverseMapping);
|
|
442
448
|
return reverseMapping;
|
|
443
449
|
};
|
|
444
450
|
|
|
445
451
|
/**
|
|
446
|
-
* @returns
|
|
447
|
-
* shadowed) we set it to `null`.
|
|
452
|
+
* @returns An array of mappings (from inner-most to outer-most scope) of original name -> compiled name or binding expression.
|
|
448
453
|
*/
|
|
449
454
|
export const allVariablesAtPosition =
|
|
450
455
|
async(location: SDK.DebuggerModel.Location,
|
|
451
456
|
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding):
|
|
452
|
-
Promise<Map<string, string|null
|
|
453
|
-
const reverseMapping
|
|
457
|
+
Promise<Array<Map<string, string|null>>> => {
|
|
458
|
+
const reverseMapping: Array<Map<string, string|null>> = [];
|
|
454
459
|
const script = location.script();
|
|
455
460
|
if (!script) {
|
|
456
461
|
return reverseMapping;
|
|
@@ -462,6 +467,15 @@ export const allVariablesAtPosition =
|
|
|
462
467
|
return reverseMapping;
|
|
463
468
|
}
|
|
464
469
|
|
|
470
|
+
if (Root.Runtime.hostConfig.devToolsSourceMapScopesInSourcesPanel?.enabled) {
|
|
471
|
+
const sourceMap =
|
|
472
|
+
script.sourceMap() ?? await script.debuggerModel.sourceMapManager().sourceMapForClientPromise(script);
|
|
473
|
+
const mappedVariables = sourceMap?.resolveMappedVariablesAtPosition(location);
|
|
474
|
+
if (mappedVariables) {
|
|
475
|
+
return mappedVariables;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
465
479
|
const scopeTreeAndText = await computeScopeTree(script);
|
|
466
480
|
if (!scopeTreeAndText) {
|
|
467
481
|
return reverseMapping;
|
|
@@ -470,21 +484,10 @@ export const allVariablesAtPosition =
|
|
|
470
484
|
const {scopeTree, text} = scopeTreeAndText;
|
|
471
485
|
const locationOffset = text.offsetFromPosition(location.lineNumber, location.columnNumber);
|
|
472
486
|
const scopeChain = findScopeChain(scopeTree, {start: locationOffset, end: locationOffset});
|
|
473
|
-
const compiledNames = new Set<string>();
|
|
474
487
|
|
|
475
488
|
while (scopeChain.length > 0) {
|
|
476
489
|
const {variableMapping} = await resolveScope(script, scopeChain, debuggerWorkspaceBinding);
|
|
477
|
-
|
|
478
|
-
if (!originalName) {
|
|
479
|
-
continue;
|
|
480
|
-
}
|
|
481
|
-
if (!reverseMapping.has(originalName)) {
|
|
482
|
-
// An inner scope might have shadowed {compiledName}. Mark it as "unavailable" in that case.
|
|
483
|
-
const compiledNameOrNull = compiledNames.has(compiledName) ? null : compiledName;
|
|
484
|
-
reverseMapping.set(originalName, compiledNameOrNull);
|
|
485
|
-
}
|
|
486
|
-
compiledNames.add(compiledName);
|
|
487
|
-
}
|
|
490
|
+
reverseMapping.push(reverseScopeMapping(variableMapping));
|
|
488
491
|
scopeChain.pop();
|
|
489
492
|
}
|
|
490
493
|
return reverseMapping;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type * as Common from '../../core/common/common.js';
|
|
6
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
7
|
+
import * as Platform from '../../core/platform/platform.js';
|
|
7
8
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
8
9
|
import type * as Protocol from '../../generated/protocol.js';
|
|
9
10
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
@@ -35,6 +36,10 @@ const UIStrings = {
|
|
|
35
36
|
* @description Tooltip for the clear announcements button in the announcements tool.
|
|
36
37
|
*/
|
|
37
38
|
clearAnnouncements: 'Clear announcements',
|
|
39
|
+
/**
|
|
40
|
+
* @description Tooltip for the export to CSV button in the announcements tool.
|
|
41
|
+
*/
|
|
42
|
+
exportCsv: 'Export to CSV',
|
|
38
43
|
/**
|
|
39
44
|
* @description Label/title for the dropdown filter to select which announcement types to record.
|
|
40
45
|
*/
|
|
@@ -108,6 +113,8 @@ export interface ViewInput {
|
|
|
108
113
|
isRecording: boolean;
|
|
109
114
|
onToggleRecording: () => void;
|
|
110
115
|
onClear: () => void;
|
|
116
|
+
onExportCsv: () => void;
|
|
117
|
+
canExport: boolean;
|
|
111
118
|
recordTypeFilter: RecordTypeFilter;
|
|
112
119
|
onRecordTypeFilterChange: (type: RecordTypeFilter) => void;
|
|
113
120
|
textFilter: string;
|
|
@@ -144,6 +151,14 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
144
151
|
.variant=${Buttons.Button.Variant.TOOLBAR}
|
|
145
152
|
.jslogContext=${'accessibility.clear-announcements'}>
|
|
146
153
|
</devtools-button>
|
|
154
|
+
<devtools-button
|
|
155
|
+
title=${i18nString(UIStrings.exportCsv)}
|
|
156
|
+
.iconName=${'download'}
|
|
157
|
+
.disabled=${!input.canExport}
|
|
158
|
+
@click=${input.onExportCsv}
|
|
159
|
+
.variant=${Buttons.Button.Variant.TOOLBAR}
|
|
160
|
+
.jslogContext=${'accessibility.export-csv'}>
|
|
161
|
+
</devtools-button>
|
|
147
162
|
<div class="toolbar-divider" role="separator"></div>
|
|
148
163
|
<select
|
|
149
164
|
title=${i18nString(UIStrings.filterByType)}
|
|
@@ -729,6 +744,32 @@ export function validateAndSanitizeAnnouncement(payload: unknown): A11yAnnouncem
|
|
|
729
744
|
};
|
|
730
745
|
}
|
|
731
746
|
|
|
747
|
+
export function escapeCsvValue(val: string): string {
|
|
748
|
+
const escaped = val.replace(/"/g, '""');
|
|
749
|
+
if (escaped.includes(',') || escaped.includes('\n') || escaped.includes('\r') || escaped.includes('"')) {
|
|
750
|
+
return `"${escaped}"`;
|
|
751
|
+
}
|
|
752
|
+
return escaped;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
export function buildCsvContent(announcements: readonly A11yAnnouncement[]): string {
|
|
756
|
+
const csvRows: string[] = [];
|
|
757
|
+
csvRows.push(['Time', 'API', 'Politeness', 'Message'].join(','));
|
|
758
|
+
|
|
759
|
+
for (const item of announcements) {
|
|
760
|
+
const timeString = new Date(item.time).toISOString();
|
|
761
|
+
const row = [
|
|
762
|
+
escapeCsvValue(timeString),
|
|
763
|
+
escapeCsvValue(item.api),
|
|
764
|
+
escapeCsvValue(item.politeness),
|
|
765
|
+
escapeCsvValue(item.message),
|
|
766
|
+
];
|
|
767
|
+
csvRows.push(row.join(','));
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return csvRows.join('\r\n');
|
|
771
|
+
}
|
|
772
|
+
|
|
732
773
|
export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane implements SDK.TargetManager.Observer {
|
|
733
774
|
#announcements: A11yAnnouncement[] = [];
|
|
734
775
|
#filteredAnnouncements: readonly A11yAnnouncement[]|null = null;
|
|
@@ -984,6 +1025,29 @@ export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane
|
|
|
984
1025
|
this.requestUpdate();
|
|
985
1026
|
}
|
|
986
1027
|
|
|
1028
|
+
#exportCsv(): void {
|
|
1029
|
+
const csvContent = this.#buildCsvContent();
|
|
1030
|
+
const blob = new Blob(['\ufeff', csvContent], {type: 'text/csv;charset=utf-8'});
|
|
1031
|
+
const url = URL.createObjectURL(blob);
|
|
1032
|
+
/* eslint-disable-next-line @devtools/no-imperative-dom-api */
|
|
1033
|
+
const link = document.createElement('a');
|
|
1034
|
+
link.setAttribute('href', url);
|
|
1035
|
+
link.setAttribute('download', `aria-live-announcements-${Platform.DateUtilities.toISO8601Compact(new Date())}.csv`);
|
|
1036
|
+
link.style.visibility = 'hidden';
|
|
1037
|
+
document.body.appendChild(link);
|
|
1038
|
+
link.click();
|
|
1039
|
+
document.body.removeChild(link);
|
|
1040
|
+
URL.revokeObjectURL(url);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
#buildCsvContent(): string {
|
|
1044
|
+
return buildCsvContent(this.filteredAnnouncements);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
exportCsvForTest(): string {
|
|
1048
|
+
return this.#buildCsvContent();
|
|
1049
|
+
}
|
|
1050
|
+
|
|
987
1051
|
override performUpdate(): void {
|
|
988
1052
|
const blockedTargets: BlockedTargetInfo[] = [];
|
|
989
1053
|
for (const [target, reason] of this.#blockedTargets) {
|
|
@@ -991,6 +1055,7 @@ export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane
|
|
|
991
1055
|
blockedTargets.push({targetName, reason});
|
|
992
1056
|
}
|
|
993
1057
|
|
|
1058
|
+
const filteredAnnouncements = this.filteredAnnouncements;
|
|
994
1059
|
const input: ViewInput = {
|
|
995
1060
|
isRecording: this.#isRecording,
|
|
996
1061
|
onToggleRecording: () => {
|
|
@@ -1003,6 +1068,10 @@ export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane
|
|
|
1003
1068
|
onClear: () => {
|
|
1004
1069
|
this.clearAnnouncements();
|
|
1005
1070
|
},
|
|
1071
|
+
onExportCsv: () => {
|
|
1072
|
+
this.#exportCsv();
|
|
1073
|
+
},
|
|
1074
|
+
canExport: filteredAnnouncements.length > 0,
|
|
1006
1075
|
recordTypeFilter: this.#recordTypeFilter,
|
|
1007
1076
|
onRecordTypeFilterChange: (type: RecordTypeFilter) => {
|
|
1008
1077
|
this.setRecordTypeFilter(type);
|
|
@@ -1012,7 +1081,7 @@ export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane
|
|
|
1012
1081
|
this.setTextFilter(text);
|
|
1013
1082
|
},
|
|
1014
1083
|
blockedTargets,
|
|
1015
|
-
announcements:
|
|
1084
|
+
announcements: filteredAnnouncements,
|
|
1016
1085
|
};
|
|
1017
1086
|
this.#view(input, undefined, this.contentElement);
|
|
1018
1087
|
}
|
|
@@ -1636,7 +1636,7 @@ async function makeDomTreeWidget(widgetData: AiAssistanceModel.AiAgent.DomTreeAi
|
|
|
1636
1636
|
// clang-format off
|
|
1637
1637
|
const renderedWidget = html`
|
|
1638
1638
|
${networkRequest ? renderNetworkRequestPreview(networkRequest) : Lit.nothing}
|
|
1639
|
-
<devtools-widget class="dom-tree-widget" ${widget(Elements.
|
|
1639
|
+
<devtools-widget class="dom-tree-widget" ${widget(Elements.DOMTreeWidget.DOMTreeWidget, {
|
|
1640
1640
|
maxTreeDepth: 2,
|
|
1641
1641
|
enableContextMenu: false,
|
|
1642
1642
|
showComments: false,
|
|
@@ -43,6 +43,7 @@ const POPUP_MARGIN = 8;
|
|
|
43
43
|
const PIN_HEIGHT = 30;
|
|
44
44
|
const POPUP_WIDTH = 288;
|
|
45
45
|
const POPUP_HEIGHT = 220;
|
|
46
|
+
const AUTO_CLOSE_DELAY_MS = 2000;
|
|
46
47
|
|
|
47
48
|
const DEFAULT_VIEW: View = (input: ViewInput, _output: undefined, target: HTMLElement): void => {
|
|
48
49
|
// clang-format off
|
|
@@ -119,6 +120,7 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
119
120
|
readonly #commentManager: CommentManager.CommentManager.CommentManager;
|
|
120
121
|
#commentOverlayManager: Comments.CommentOverlayManager.CommentOverlayManager;
|
|
121
122
|
#activeThreadId: string|null = null;
|
|
123
|
+
#closeTimeoutId: number|null = null;
|
|
122
124
|
#cachedTitle: Title = {text: ''};
|
|
123
125
|
#cachedTitleAnchor: CommentManager.CommentManager.CommentAnchorSignature|null = null;
|
|
124
126
|
|
|
@@ -173,6 +175,7 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
override willHide(): void {
|
|
178
|
+
this.#clearCloseTimeout();
|
|
176
179
|
this.#commentOverlayManager.stop();
|
|
177
180
|
this.#commentOverlayManager.removeEventListener(
|
|
178
181
|
Comments.CommentOverlayManager.Events.POSITIONS_UPDATED,
|
|
@@ -204,6 +207,13 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
204
207
|
super.willHide();
|
|
205
208
|
}
|
|
206
209
|
|
|
210
|
+
#clearCloseTimeout(): void {
|
|
211
|
+
if (this.#closeTimeoutId !== null) {
|
|
212
|
+
window.clearTimeout(this.#closeTimeoutId);
|
|
213
|
+
this.#closeTimeoutId = null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
207
217
|
#onAgentAttachedChanged(
|
|
208
218
|
event: Common.EventTarget.EventTargetEvent<
|
|
209
219
|
CommentManager.CommentManager.EventTypes[CommentManager.CommentManager.Events.AGENT_ATTACHED_CHANGED]>,
|
|
@@ -329,7 +339,18 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
329
339
|
activePin,
|
|
330
340
|
title,
|
|
331
341
|
onAddComment: (text: string) => {
|
|
332
|
-
activeThread
|
|
342
|
+
if (!activeThread) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
activeThread.save(text);
|
|
346
|
+
const threadId = activeThread.id;
|
|
347
|
+
this.#closeTimeoutId = window.setTimeout(() => {
|
|
348
|
+
this.#closeTimeoutId = null;
|
|
349
|
+
if (this.#activeThreadId === threadId) {
|
|
350
|
+
this.#activeThreadId = null;
|
|
351
|
+
this.requestUpdate();
|
|
352
|
+
}
|
|
353
|
+
}, AUTO_CLOSE_DELAY_MS);
|
|
333
354
|
},
|
|
334
355
|
};
|
|
335
356
|
this.#view(viewInput, undefined, this.contentElement);
|
|
@@ -350,6 +371,9 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
|
|
|
350
371
|
|
|
351
372
|
handleAction(_context: UI.Context.Context, actionId: string): boolean {
|
|
352
373
|
if (actionId === 'comments.toggle-comment-mode') {
|
|
374
|
+
if (!this.#commentManager.isAgentAttached()) {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
353
377
|
if (!widgetInstance) {
|
|
354
378
|
widgetInstance = new CommentsOverlayWidget(
|
|
355
379
|
undefined,
|
|
@@ -383,11 +407,14 @@ export class ButtonProvider implements UI.Toolbar.Provider {
|
|
|
383
407
|
Root.DevToolsContext.globalInstance().get(
|
|
384
408
|
CommentManager.CommentManager.CommentManager,
|
|
385
409
|
);
|
|
386
|
-
|
|
410
|
+
const action = UI.ActionRegistry.ActionRegistry.instance().getAction('comments.toggle-comment-mode');
|
|
411
|
+
action.setEnabled(this.#commentManager.isAgentAttached());
|
|
412
|
+
this.#button = UI.Toolbar.Toolbar.createActionButton(action);
|
|
387
413
|
this.#button.setVisible(this.#commentManager.isAgentAttached());
|
|
388
414
|
this.#commentManager.addEventListener(
|
|
389
415
|
CommentManager.CommentManager.Events.AGENT_ATTACHED_CHANGED,
|
|
390
416
|
event => {
|
|
417
|
+
action.setEnabled(event.data);
|
|
391
418
|
this.#button.setVisible(event.data);
|
|
392
419
|
},
|
|
393
420
|
);
|
|
@@ -34,6 +34,7 @@ const kForbiddenSchemes = [
|
|
|
34
34
|
'chrome-error:',
|
|
35
35
|
'chrome-search:',
|
|
36
36
|
'devtools:',
|
|
37
|
+
'isolated-app:',
|
|
37
38
|
];
|
|
38
39
|
|
|
39
40
|
declare global {
|
|
@@ -44,6 +45,18 @@ declare global {
|
|
|
44
45
|
|
|
45
46
|
let extensionServerInstance: ExtensionServer|null;
|
|
46
47
|
|
|
48
|
+
function parseCanonicalURL(url: Platform.DevToolsPath.UrlString): URL|null {
|
|
49
|
+
try {
|
|
50
|
+
let parsedURL = new URL(url);
|
|
51
|
+
while (parsedURL.protocol === 'blob:' || parsedURL.protocol === 'filesystem:') {
|
|
52
|
+
parsedURL = new URL(parsedURL.href.slice(parsedURL.protocol.length));
|
|
53
|
+
}
|
|
54
|
+
return parsedURL;
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
export class HostsPolicy {
|
|
48
61
|
static create(policy?: Host.InspectorFrontendHostAPI.ExtensionHostsPolicy): HostsPolicy|null {
|
|
49
62
|
const runtimeAllowedHosts = [];
|
|
@@ -98,12 +111,11 @@ class RegisteredExtension {
|
|
|
98
111
|
return false;
|
|
99
112
|
}
|
|
100
113
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
parsedURL = new URL(inspectedURL);
|
|
104
|
-
} catch {
|
|
114
|
+
const parsedURL = parseCanonicalURL(inspectedURL);
|
|
115
|
+
if (!parsedURL) {
|
|
105
116
|
return false;
|
|
106
117
|
}
|
|
118
|
+
inspectedURL = parsedURL.href as Platform.DevToolsPath.UrlString;
|
|
107
119
|
|
|
108
120
|
if (parsedURL.protocol === 'chrome-extension:') {
|
|
109
121
|
if (parsedURL.origin !== this.origin) {
|
|
@@ -1827,12 +1839,10 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
1827
1839
|
}
|
|
1828
1840
|
|
|
1829
1841
|
static canInspectURL(url: Platform.DevToolsPath.UrlString): boolean {
|
|
1830
|
-
let parsedURL;
|
|
1831
1842
|
// This is only to work around invalid URLs we're occasionally getting from some tests.
|
|
1832
1843
|
// TODO(caseq): make sure tests supply valid URLs or we specifically handle invalid ones.
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
} catch {
|
|
1844
|
+
const parsedURL = parseCanonicalURL(url);
|
|
1845
|
+
if (!parsedURL) {
|
|
1836
1846
|
return false;
|
|
1837
1847
|
}
|
|
1838
1848
|
|
|
@@ -459,7 +459,7 @@ export class ConsolePrompt extends ConsolePromptBase {
|
|
|
459
459
|
?.evaluateCommandInConsole(executionContext, message, expression, useCommandLineAPI);
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
-
private async substituteNames(expression: string, mapping: Map<string, string|null
|
|
462
|
+
private async substituteNames(expression: string, mapping: Array<Map<string, string|null>>): Promise<string> {
|
|
463
463
|
try {
|
|
464
464
|
return await Formatter.FormatterWorkerPool.formatterWorkerPool().javaScriptSubstitute(expression, mapping);
|
|
465
465
|
} catch {
|
|
@@ -1030,7 +1030,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
|
|
|
1030
1030
|
result.appendChild(this.formatParameterAsObject(remoteObject, false));
|
|
1031
1031
|
return;
|
|
1032
1032
|
}
|
|
1033
|
-
const treeOutline = new Elements.
|
|
1033
|
+
const treeOutline = new Elements.DOMTreeWidget.ElementsTreeOutline(
|
|
1034
1034
|
/* omitRootDOMNode: */ false, /* selectEnabled: */ true, /* hideGutter: */ true);
|
|
1035
1035
|
treeOutline.rootDOMNode = node;
|
|
1036
1036
|
treeOutline.deindentSingleNode();
|
|
@@ -359,7 +359,8 @@ export class ClassNamePrompt extends UI.TextPrompt.TextPrompt {
|
|
|
359
359
|
|
|
360
360
|
let completions: string[] = await this.classNamesPromise;
|
|
361
361
|
const classesMap = this.nodeClasses((selectedNode));
|
|
362
|
-
|
|
362
|
+
const existingClasses = new Set(expression.split(/[,\s]/).map(className => className.trim()).filter(Boolean));
|
|
363
|
+
completions = completions.filter(value => !classesMap.get(value) && !existingClasses.has(value));
|
|
363
364
|
|
|
364
365
|
if (prefix[0] === '.') {
|
|
365
366
|
completions = completions.map(value => '.' + value);
|
|
@@ -9,9 +9,9 @@ import * as UI from '../../ui/legacy/legacy.js';
|
|
|
9
9
|
import * as Emulation from '../emulation/emulation.js';
|
|
10
10
|
|
|
11
11
|
import {canGetJSPath} from './DOMPath.js';
|
|
12
|
+
import type {DOMTreeWidget} from './DOMTreeWidget.js';
|
|
12
13
|
import {ElementsPanel} from './ElementsPanel.js';
|
|
13
14
|
import {ElementsTreeElement} from './ElementsTreeElement.js';
|
|
14
|
-
import type {DOMTreeWidget} from './ElementsTreeOutline.js';
|
|
15
15
|
|
|
16
16
|
const UIStrings = {
|
|
17
17
|
/**
|