chrome-devtools-frontend 1.0.1679704 → 1.0.1681091

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.
Files changed (54) hide show
  1. package/AUTHORS +1 -0
  2. package/front_end/core/platform/TypescriptUtilities.ts +0 -9
  3. package/front_end/core/platform/platform.ts +1 -1
  4. package/front_end/core/sdk/ConsoleModel.ts +6 -3
  5. package/front_end/core/sdk/DOMModel.ts +102 -0
  6. package/front_end/core/sdk/EmulationModel.ts +4 -2
  7. package/front_end/core/sdk/NetworkManager.ts +7 -6
  8. package/front_end/core/sdk/PageResourceLoader.ts +4 -3
  9. package/front_end/core/sdk/RuntimeModel.ts +5 -3
  10. package/front_end/core/sdk/SDKSettings.ts +47 -0
  11. package/front_end/core/sdk/sdk-meta.ts +0 -138
  12. package/front_end/entrypoints/inspector_main/RenderingOptions.ts +4 -2
  13. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +32 -0
  14. package/front_end/entrypoints/main/MainImpl.ts +1 -1
  15. package/front_end/generated/InspectorBackendCommands.ts +3 -1
  16. package/front_end/generated/SupportedCSSProperties.ts +20 -0
  17. package/front_end/generated/protocol-mapping.d.ts +7 -0
  18. package/front_end/generated/protocol-proxy-api.d.ts +5 -0
  19. package/front_end/generated/protocol.ts +15 -3
  20. package/front_end/panels/console/ConsoleView.ts +2 -1
  21. package/front_end/panels/console/console-meta.ts +10 -5
  22. package/front_end/panels/elements/DOMTreeContextMenu.ts +541 -0
  23. package/front_end/panels/elements/ElementsTreeElement.ts +27 -494
  24. package/front_end/panels/elements/ElementsTreeOutline.ts +173 -287
  25. package/front_end/panels/elements/StylesSidebarPane.ts +2 -1
  26. package/front_end/panels/elements/elements.ts +3 -0
  27. package/front_end/panels/issues/CorsIssueDetailsView.ts +13 -9
  28. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +3 -1
  29. package/front_end/panels/network/NetworkConfigView.ts +2 -1
  30. package/front_end/panels/network/NetworkPanel.ts +1 -1
  31. package/front_end/panels/network/network-meta.ts +60 -0
  32. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +2 -1
  33. package/front_end/panels/profiler/ProfileLauncherView.ts +19 -16
  34. package/front_end/panels/profiler/ProfileSidebarTreeElement.ts +1 -1
  35. package/front_end/panels/security/security.ts +6 -0
  36. package/front_end/panels/sources/SourcesView.ts +8 -107
  37. package/front_end/panels/sources/TabbedEditorContainer.ts +110 -7
  38. package/front_end/panels/sources/sources-meta.ts +16 -0
  39. package/front_end/panels/timeline/TimelineLoader.ts +1 -1
  40. package/front_end/panels/timeline/TimelineUIUtils.ts +6 -0
  41. package/front_end/panels/timeline/components/LayoutShiftDetails.ts +4 -3
  42. package/front_end/panels/timeline/components/LiveMetricsView.ts +1 -1
  43. package/front_end/panels/timeline/components/MetricCard.ts +4 -3
  44. package/front_end/panels/timeline/components/NetworkRequestDetails.ts +5 -2
  45. package/front_end/panels/timeline/components/TimelineRangeSummaryView.ts +1 -1
  46. package/front_end/panels/timeline/components/TimelineSummary.ts +8 -5
  47. package/front_end/third_party/chromium/README.chromium +1 -1
  48. package/front_end/ui/legacy/TabbedPane.ts +34 -2
  49. package/front_end/ui/legacy/components/quick_open/CommandMenu.ts +5 -5
  50. package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +7 -7
  51. package/front_end/ui/legacy/components/quick_open/QuickOpen.ts +1 -1
  52. package/front_end/ui/legacy/components/quick_open/quick_open-meta.ts +2 -2
  53. package/front_end/ui/visual_logging/KnownContextValues.ts +29 -0
  54. package/package.json +1 -1
@@ -5,6 +5,7 @@
5
5
  import './InspectElementModeController.js';
6
6
  import './ColorSwatchPopoverIcon.js';
7
7
  import './DOMPath.js';
8
+ import './DOMTreeContextMenu.js';
8
9
  import './ElementsSidebarPane.js';
9
10
  import './ElementsTreeElement.js';
10
11
  import './AdoptedStyleSheetTreeElement.js';
@@ -40,6 +41,7 @@ import * as CSSRuleValidator from './CSSRuleValidator.js';
40
41
  import * as CSSSpecificityBreakdown from './CSSSpecificityBreakdown.js';
41
42
  import * as CSSValueTraceView from './CSSValueTraceView.js';
42
43
  import * as DOMPath from './DOMPath.js';
44
+ import * as DOMTreeContextMenu from './DOMTreeContextMenu.js';
43
45
  import * as ElementsPanel from './ElementsPanel.js';
44
46
  import * as ElementsSidebarPane from './ElementsSidebarPane.js';
45
47
  import * as ElementStatePaneWidget from './ElementStatePaneWidget.js';
@@ -77,6 +79,7 @@ export {
77
79
  CSSSpecificityBreakdown,
78
80
  CSSValueTraceView,
79
81
  DOMPath,
82
+ DOMTreeContextMenu,
80
83
  ElementsPanel,
81
84
  ElementsSidebarPane,
82
85
  ElementStatePaneWidget,
@@ -204,11 +204,14 @@ export class CorsIssueDetailsView extends AffectedResourcesView {
204
204
  case IssuesManager.CorsIssue.IssueCode.NO_CORS_REDIRECT_MODE_NOT_FOLLOW:
205
205
  this.appendColumnTitle(header, i18nString(UIStrings.sourceLocation));
206
206
  break;
207
+ case IssuesManager.CorsIssue.IssueCode.PREFLIGHT_MISSING_ALLOW_EXTERNAL:
208
+ case IssuesManager.CorsIssue.IssueCode.PREFLIGHT_INVALID_ALLOW_EXTERNAL:
209
+ case IssuesManager.CorsIssue.IssueCode.INVALID_LOCAL_NETWORK_ACCESS:
210
+ case IssuesManager.CorsIssue.IssueCode.LOCAL_NETWORK_ACCESS_PERMISSION_DENIED:
211
+ // The default columns suffice.
212
+ break;
207
213
  default:
208
- Platform.assertUnhandled<IssuesManager.CorsIssue.IssueCode.PREFLIGHT_MISSING_ALLOW_EXTERNAL|
209
- IssuesManager.CorsIssue.IssueCode.PREFLIGHT_INVALID_ALLOW_EXTERNAL|
210
- IssuesManager.CorsIssue.IssueCode.INVALID_LOCAL_NETWORK_ACCESS|
211
- IssuesManager.CorsIssue.IssueCode.LOCAL_NETWORK_ACCESS_PERMISSION_DENIED>(issueCode);
214
+ Platform.assertNever(issueCode, 'Unknow issue code ' + issueCode);
212
215
  }
213
216
 
214
217
  this.affectedResources.appendChild(header);
@@ -428,14 +431,15 @@ export class CorsIssueDetailsView extends AffectedResourcesView {
428
431
  this.#appendStatus(element, details.isWarning);
429
432
  this.appendSourceLocation(element, details.location, issue.model()?.getTargetIfNotDisposed());
430
433
  break;
431
- default:
434
+ case IssuesManager.CorsIssue.IssueCode.PREFLIGHT_MISSING_ALLOW_EXTERNAL:
435
+ case IssuesManager.CorsIssue.IssueCode.PREFLIGHT_INVALID_ALLOW_EXTERNAL:
436
+ case IssuesManager.CorsIssue.IssueCode.INVALID_LOCAL_NETWORK_ACCESS:
437
+ case IssuesManager.CorsIssue.IssueCode.LOCAL_NETWORK_ACCESS_PERMISSION_DENIED:
432
438
  element.appendChild(this.createRequestCell(details.request, opts));
433
439
  this.#appendStatus(element, details.isWarning);
434
- Platform.assertUnhandled<IssuesManager.CorsIssue.IssueCode.PREFLIGHT_MISSING_ALLOW_EXTERNAL|
435
- IssuesManager.CorsIssue.IssueCode.PREFLIGHT_INVALID_ALLOW_EXTERNAL|
436
- IssuesManager.CorsIssue.IssueCode.INVALID_LOCAL_NETWORK_ACCESS|
437
- IssuesManager.CorsIssue.IssueCode.LOCAL_NETWORK_ACCESS_PERMISSION_DENIED>(issueCode);
438
440
  break;
441
+ default:
442
+ Platform.assertNever(issueCode, 'Unknown issue code: ' + issueCode);
439
443
  }
440
444
 
441
445
  this.affectedResources.appendChild(element);
@@ -36,7 +36,9 @@ export class NetworkPanelIndicator {
36
36
  SDK.NetworkManager.MultitargetNetworkManager.Events.BLOCKED_PATTERNS_CHANGED, updateVisibility);
37
37
  manager.addEventListener(
38
38
  SDK.NetworkManager.MultitargetNetworkManager.Events.INTERCEPTORS_CHANGED, updateVisibility);
39
- Common.Settings.Settings.instance().moduleSetting('cache-disabled').addChangeListener(updateVisibility, this);
39
+ Common.Settings.Settings.instance()
40
+ .resolve(SDK.SDKSettings.cacheDisabledSettingDescriptor)
41
+ .addChangeListener(updateVisibility, this);
40
42
 
41
43
  updateVisibility();
42
44
 
@@ -203,7 +203,8 @@ export class NetworkConfigView extends UI.Widget.VBox {
203
203
  private createCacheSection(): void {
204
204
  const section = this.createSection(i18nString(UIStrings.caching), 'network-config-disable-cache');
205
205
  section.appendChild(SettingsUI.SettingsUI.createSettingCheckbox(
206
- i18nString(UIStrings.disableCache), Common.Settings.Settings.instance().moduleSetting('cache-disabled')));
206
+ i18nString(UIStrings.disableCache),
207
+ Common.Settings.Settings.instance().resolve(SDK.SDKSettings.cacheDisabledSettingDescriptor)));
207
208
  }
208
209
 
209
210
  private createNetworkThrottlingSection(): void {
@@ -462,7 +462,7 @@ export class NetworkPanel extends UI.Panel.Panel implements
462
462
 
463
463
  this.panelToolbar.appendSeparator();
464
464
  const disableCacheCheckbox = new UI.Toolbar.ToolbarSettingCheckbox(
465
- Common.Settings.Settings.instance().moduleSetting('cache-disabled'),
465
+ Common.Settings.Settings.instance().resolve(SDK.SDKSettings.cacheDisabledSettingDescriptor),
466
466
  i18nString(UIStrings.disableCacheWhileDevtoolsIsOpen), i18nString(UIStrings.disableCache));
467
467
  this.panelToolbar.appendToolbarItem(disableCacheCheckbox);
468
468
 
@@ -10,11 +10,37 @@ import * as SDK from '../../core/sdk/sdk.js';
10
10
  import * as Workspace from '../../models/workspace/workspace.js';
11
11
  import * as PanelCommon from '../../panels/common/common.js';
12
12
  import * as UI from '../../ui/legacy/legacy.js';
13
+ import * as SettingsUI from '../../ui/settings/settings.js';
13
14
 
14
15
  import * as NetworkForward from './forward/forward.js';
15
16
  import type * as Network from './network.js';
16
17
 
17
18
  const UIStrings = {
19
+ /**
20
+ * @description Title of a setting under the Network category that can be invoked through the Command Menu.
21
+ */
22
+ enableCache: 'Enable cache',
23
+ /**
24
+ * @description Title of a setting under the Network category that can be invoked through the Command Menu.
25
+ */
26
+ disableCache: 'Disable cache while DevTools is open',
27
+ /**
28
+ * @description Tooltip text for a setting that controls the network cache. Disabling the network cache can simulate the network connections of users that are visiting a page for the first time.
29
+ */
30
+ networkCacheExplanation:
31
+ 'Disabling the network cache will simulate a network experience similar to a first time visitor.',
32
+ /**
33
+ * @description Title of a setting under the Network category.
34
+ */
35
+ networkRequestBlocking: 'Network request blocking',
36
+ /**
37
+ * @description Title of a setting under the Network category that can be invoked through the Command Menu.
38
+ */
39
+ enableNetworkRequestBlocking: 'Enable network request blocking',
40
+ /**
41
+ * @description Title of a setting under the Network category that can be invoked through the Command Menu.
42
+ */
43
+ disableNetworkRequestBlocking: 'Disable network request blocking',
18
44
  /**
19
45
  * @description Command for showing the 'Network' tool
20
46
  */
@@ -428,6 +454,40 @@ Common.Settings.registerSettingExtension({
428
454
  ],
429
455
  });
430
456
 
457
+ SettingsUI.SettingUIRegistration.register(SDK.SDKSettings.requestBlockingEnabledSettingDescriptor, {
458
+ category: Common.Settings.SettingCategory.NETWORK,
459
+ title: i18nLazyString(UIStrings.networkRequestBlocking),
460
+ options: [
461
+ {
462
+ value: true,
463
+ title: i18nLazyString(UIStrings.enableNetworkRequestBlocking),
464
+ },
465
+ {
466
+ value: false,
467
+ title: i18nLazyString(UIStrings.disableNetworkRequestBlocking),
468
+ },
469
+ ],
470
+ });
471
+
472
+ SettingsUI.SettingUIRegistration.register(SDK.SDKSettings.cacheDisabledSettingDescriptor, {
473
+ category: Common.Settings.SettingCategory.NETWORK,
474
+ title: i18nLazyString(UIStrings.disableCache),
475
+ order: 0,
476
+ options: [
477
+ {
478
+ value: true,
479
+ title: i18nLazyString(UIStrings.disableCache),
480
+ },
481
+ {
482
+ value: false,
483
+ title: i18nLazyString(UIStrings.enableCache),
484
+ },
485
+ ],
486
+ learnMore: {
487
+ tooltip: i18nLazyString(UIStrings.networkCacheExplanation),
488
+ },
489
+ });
490
+
431
491
  UI.ViewManager.registerLocationResolver({
432
492
  name: UI.ViewManager.ViewLocationValues.NETWORK_SIDEBAR,
433
493
  category: UI.ViewManager.ViewLocationCategory.NETWORK,
@@ -8,6 +8,7 @@ import * as SDK from '../../core/sdk/sdk.js';
8
8
  import type * as Protocol from '../../generated/protocol.js';
9
9
  import * as UI from '../../ui/legacy/legacy.js';
10
10
  import * as Lit from '../../ui/lit/lit.js';
11
+ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
11
12
  import * as Elements from '../elements/elements.js';
12
13
 
13
14
  import heapDetachedElementsDataGridStyles from './heapDetachedElementsDataGrid.css.js';
@@ -60,7 +61,7 @@ const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement|
60
61
  <th id="detached-node-count">${i18nString(UIStrings.nodeSize)}</th>
61
62
  </tr>
62
63
  ${input.parsedElements.map(parsed => html`
63
- <tr>
64
+ <tr jslog=${VisualLogging.tableRow('detached-element')}>
64
65
  <td>
65
66
  <devtools-widget
66
67
  ${widget(Elements.ElementsTreeOutline.DOMTreeWidget, {
@@ -4,6 +4,7 @@
4
4
 
5
5
  import * 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 Buttons from '../../ui/components/buttons/buttons.js';
8
9
  import * as UI from '../../ui/legacy/legacy.js';
9
10
  import {html, nothing, render} from '../../ui/lit/lit.js';
@@ -73,7 +74,7 @@ export type View = (input: ViewInput, output: ViewOutput, target: HTMLElement) =
73
74
  export const DEFAULT_VIEW: View = (input, output, target) => {
74
75
  render(html`
75
76
  <style>${profileLauncherViewStyles}</style>
76
- <div class="profile-launcher-view-content vbox">
77
+ <div class="profile-launcher-view-content vbox" jslog=${VisualLogging.section('profiler.launcher')}>
77
78
  <div class="vbox">
78
79
  <h1>${input.headerText}</h1>
79
80
  <form role="radiogroup" aria-label=${input.headerText}>
@@ -81,21 +82,23 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
81
82
  const radioId = `profile-type-${entry.profileType.id}`;
82
83
  const customContent = entry.customContent;
83
84
  return html`
84
- <input id=${radioId} type="radio" name="profile-type"
85
- .checked=${entry.selected}
86
- ?disabled=${input.isProfiling}
87
- @change=${() => input.onProfileTypeChange(entry.profileType)}
88
- jslog=${VisualLogging.toggle().track({change: true}).context('profiler.profile-type')}
89
- />
90
- <label for=${radioId}>${entry.profileType.name}</label>
91
- <p>${entry.profileType.description}</p>
92
- ${customContent ? html`
93
- <p>
94
- <span role="group" aria-labelledby=${radioId}>
95
- ${customContent}
96
- </span>
97
- </p>
98
- ` : nothing}
85
+ <div class="profile-type-option" jslog=${VisualLogging.item(Platform.StringUtilities.toKebabCase(entry.profileType.id))}>
86
+ <input id=${radioId} type="radio" name="profile-type"
87
+ .checked=${entry.selected}
88
+ ?disabled=${input.isProfiling}
89
+ @change=${() => input.onProfileTypeChange(entry.profileType)}
90
+ jslog=${VisualLogging.toggle().track({change: true}).context('profiler.profile-type')}
91
+ />
92
+ <label for=${radioId}>${entry.profileType.name}</label>
93
+ <p>${entry.profileType.description}</p>
94
+ ${customContent ? html`
95
+ <p>
96
+ <span role="group" aria-labelledby=${radioId}>
97
+ ${customContent}
98
+ </span>
99
+ </p>
100
+ ` : nothing}
101
+ </div>
99
102
  `;
100
103
  })}
101
104
  </form>
@@ -38,7 +38,7 @@ export class ProfileSidebarTreeElement extends UI.TreeOutline.TreeElement {
38
38
  profile: ProfileHeader;
39
39
  editing: UI.InplaceEditor.Controller|null;
40
40
  constructor(dataDisplayDelegate: DataDisplayDelegate, profile: ProfileHeader, className: string) {
41
- super('', false);
41
+ super('', false, 'profile-item');
42
42
  this.iconElement = document.createElement('div');
43
43
  this.iconElement.classList.add('icon');
44
44
  this.titlesElement = document.createElement('div');
@@ -2,10 +2,16 @@
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
4
 
5
+ import * as OriginTreeElement from './OriginTreeElement.js';
5
6
  import * as SecurityModel from './SecurityModel.js';
6
7
  import * as SecurityPanel from './SecurityPanel.js';
8
+ import * as SecurityPanelSidebar from './SecurityPanelSidebar.js';
9
+ import * as SecurityPanelSidebarTreeElement from './SecurityPanelSidebarTreeElement.js';
7
10
 
8
11
  export {
12
+ OriginTreeElement,
9
13
  SecurityModel,
10
14
  SecurityPanel,
15
+ SecurityPanelSidebar,
16
+ SecurityPanelSidebarTreeElement,
11
17
  };
@@ -14,12 +14,11 @@ import * as Bindings from '../../models/bindings/bindings.js';
14
14
  import * as Persistence from '../../models/persistence/persistence.js';
15
15
  import * as Workspace from '../../models/workspace/workspace.js';
16
16
  import * as QuickOpen from '../../ui/legacy/components/quick_open/quick_open.js';
17
- import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
17
+ import type * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
18
18
  import * as UI from '../../ui/legacy/legacy.js';
19
19
  import {Directives, html, render} from '../../ui/lit/lit.js';
20
20
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
21
21
 
22
- import * as Components from './components/components.js';
23
22
  import {EditingLocationHistoryManager} from './EditingLocationHistoryManager.js';
24
23
  import sourcesViewStyles from './sourcesView.css.js';
25
24
  import {
@@ -27,7 +26,6 @@ import {
27
26
  Events as TabbedEditorContainerEvents,
28
27
  type SerializedHistoryItem,
29
28
  TabbedEditorContainer,
30
- type TabbedEditorContainerDelegate,
31
29
  } from './TabbedEditorContainer.js';
32
30
  import {Events as UISourceCodeFrameEvents, UISourceCodeFrame} from './UISourceCodeFrame.js';
33
31
 
@@ -80,7 +78,7 @@ export interface ViewInput {
80
78
  searchableViewId: string;
81
79
  scriptViewToolbarItems: UI.Toolbar.ToolbarItem[];
82
80
  bottomToolbarItems: UI.Toolbar.ToolbarItem[];
83
- delegate: TabbedEditorContainerDelegate;
81
+ historyManager: EditingLocationHistoryManager;
84
82
  previouslyViewedFilesSetting: Common.Settings.Setting<SerializedHistoryItem[]>;
85
83
  }
86
84
 
@@ -104,7 +102,7 @@ export const DEFAULT_VIEW: View = (input, output, target): void => {
104
102
  ${widgetRef(UI.SearchableView.SearchableView, e => { output.searchableView = e; })}
105
103
  >
106
104
  <devtools-widget class="vbox flex-auto"
107
- ${widget(TabbedEditorContainer, {delegate: input.delegate, previouslyViewedFilesSetting: input.previouslyViewedFilesSetting})}
105
+ ${widget(TabbedEditorContainer, {historyManager: input.historyManager, previouslyViewedFilesSetting: input.previouslyViewedFilesSetting})}
108
106
  ${widgetRef(TabbedEditorContainer, e => { output.editorContainer = e; })}>
109
107
  </devtools-widget>
110
108
  </devtools-widget>
@@ -120,9 +118,8 @@ export const DEFAULT_VIEW: View = (input, output, target): void => {
120
118
  };
121
119
 
122
120
  export class SourcesView extends Common.ObjectWrapper.eventMixin<EventTypes, typeof UI.Widget.VBox>(UI.Widget.VBox)
123
- implements TabbedEditorContainerDelegate, UI.SearchableView.Searchable, UI.SearchableView.Replaceable {
121
+ implements UI.SearchableView.Searchable, UI.SearchableView.Replaceable {
124
122
  #searchableView!: UI.SearchableView.SearchableView;
125
- private readonly sourceViewByUISourceCode: Map<Workspace.UISourceCode.UISourceCode, UI.Widget.Widget>;
126
123
  editorContainer?: TabbedEditorContainer;
127
124
  #uiSourceCodes = new Set<Workspace.UISourceCode.UISourceCode>();
128
125
  private readonly historyManager: EditingLocationHistoryManager;
@@ -162,8 +159,6 @@ export class SourcesView extends Common.ObjectWrapper.eventMixin<EventTypes, typ
162
159
 
163
160
  const workspace = Workspace.Workspace.WorkspaceImpl.instance();
164
161
 
165
- this.sourceViewByUISourceCode = new Map();
166
-
167
162
  this.historyManager = new EditingLocationHistoryManager(this);
168
163
 
169
164
  this.toolbarChangedListener = null;
@@ -236,7 +231,7 @@ export class SourcesView extends Common.ObjectWrapper.eventMixin<EventTypes, typ
236
231
  searchableViewId: 'sources-view-search-config',
237
232
  scriptViewToolbarItems: this.#scriptViewToolbarItems,
238
233
  bottomToolbarItems: this.#bottomToolbarItems,
239
- delegate: this,
234
+ historyManager: this.historyManager,
240
235
  previouslyViewedFilesSetting: this.previouslyViewedFilesSetting,
241
236
  };
242
237
 
@@ -512,7 +507,6 @@ export class SourcesView extends Common.ObjectWrapper.eventMixin<EventTypes, typ
512
507
  uiSourceCodes.forEach(ui => this.#uiSourceCodes.delete(ui));
513
508
  this.editorContainer?.removeUISourceCodes(uiSourceCodes);
514
509
  for (let i = 0; i < uiSourceCodes.length; ++i) {
515
- this.removeSourceFrame(uiSourceCodes[i]);
516
510
  this.historyManager.removeHistoryForSourceCode(uiSourceCodes[i]);
517
511
  }
518
512
  }
@@ -563,96 +557,12 @@ export class SourcesView extends Common.ObjectWrapper.eventMixin<EventTypes, typ
563
557
  }
564
558
  }
565
559
 
566
- private createSourceView(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget {
567
- let sourceView;
568
- const contentType = uiSourceCode.contentType();
569
-
570
- if (contentType === Common.ResourceType.resourceTypes.Image || uiSourceCode.mimeType().startsWith('image/')) {
571
- sourceView = new SourceFrame.ImageView.ImageView(uiSourceCode.mimeType(), uiSourceCode);
572
- } else if (contentType === Common.ResourceType.resourceTypes.Font || uiSourceCode.mimeType().includes('font')) {
573
- sourceView = new SourceFrame.FontView.FontView(uiSourceCode.mimeType(), uiSourceCode);
574
- } else if (uiSourceCode.name() === HEADER_OVERRIDES_FILENAME) {
575
- sourceView = new Components.HeadersView.HeadersView(uiSourceCode);
576
- } else {
577
- sourceView = new UISourceCodeFrame(uiSourceCode);
578
- this.historyManager.trackSourceFrameCursorJumps(sourceView);
579
- }
580
-
581
- uiSourceCode.addEventListener(Workspace.UISourceCode.Events.TitleChanged, this.#uiSourceCodeTitleChanged, this);
582
-
583
- this.sourceViewByUISourceCode.set(uiSourceCode, sourceView);
584
- return sourceView;
585
- }
586
-
587
- #sourceViewTypeForWidget(widget: UI.Widget.Widget): SourceViewType {
588
- if (widget instanceof SourceFrame.ImageView.ImageView) {
589
- return SourceViewType.IMAGE_VIEW;
590
- }
591
- if (widget instanceof SourceFrame.FontView.FontView) {
592
- return SourceViewType.FONT_VIEW;
593
- }
594
- if (widget instanceof Components.HeadersView.HeadersView) {
595
- return SourceViewType.HEADERS_VIEW;
596
- }
597
- return SourceViewType.SOURCE_VIEW;
598
- }
599
-
600
- #sourceViewTypeForUISourceCode(uiSourceCode: Workspace.UISourceCode.UISourceCode): SourceViewType {
601
- if (uiSourceCode.name() === HEADER_OVERRIDES_FILENAME) {
602
- return SourceViewType.HEADERS_VIEW;
603
- }
604
- const contentType = uiSourceCode.contentType();
605
- switch (contentType) {
606
- case Common.ResourceType.resourceTypes.Image:
607
- return SourceViewType.IMAGE_VIEW;
608
- case Common.ResourceType.resourceTypes.Font:
609
- return SourceViewType.FONT_VIEW;
610
- default:
611
- return SourceViewType.SOURCE_VIEW;
612
- }
613
- }
614
-
615
- #uiSourceCodeTitleChanged(event: Common.EventTarget.EventTargetEvent<Workspace.UISourceCode.UISourceCode>): void {
616
- const uiSourceCode = event.data;
617
- const widget = this.sourceViewByUISourceCode.get(uiSourceCode);
618
- if (widget) {
619
- if (this.#sourceViewTypeForWidget(widget) !== this.#sourceViewTypeForUISourceCode(uiSourceCode)) {
620
- // Remove the existing editor tab and create a new one of the correct type.
621
- this.removeUISourceCodes([uiSourceCode]);
622
- this.#uiSourceCodes.add(uiSourceCode);
623
- void this.showSourceLocation(uiSourceCode);
624
- }
625
- }
560
+ viewForFile(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget|undefined {
561
+ return this.editorContainer?.viewForFile(uiSourceCode);
626
562
  }
627
563
 
628
564
  getSourceView(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget|undefined {
629
- return this.sourceViewByUISourceCode.get(uiSourceCode);
630
- }
631
-
632
- private getOrCreateSourceView(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget {
633
- return this.sourceViewByUISourceCode.get(uiSourceCode) || this.createSourceView(uiSourceCode);
634
- }
635
-
636
- recycleUISourceCodeFrame(sourceFrame: UISourceCodeFrame, uiSourceCode: Workspace.UISourceCode.UISourceCode): void {
637
- sourceFrame.uiSourceCode().removeEventListener(Workspace.UISourceCode.Events.TitleChanged,
638
- this.#uiSourceCodeTitleChanged, this);
639
- this.sourceViewByUISourceCode.delete(sourceFrame.uiSourceCode());
640
- sourceFrame.setUISourceCode(uiSourceCode);
641
- this.sourceViewByUISourceCode.set(uiSourceCode, sourceFrame);
642
- uiSourceCode.addEventListener(Workspace.UISourceCode.Events.TitleChanged, this.#uiSourceCodeTitleChanged, this);
643
- }
644
-
645
- viewForFile(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget {
646
- return this.getOrCreateSourceView(uiSourceCode);
647
- }
648
-
649
- private removeSourceFrame(uiSourceCode: Workspace.UISourceCode.UISourceCode): void {
650
- const sourceView = this.sourceViewByUISourceCode.get(uiSourceCode);
651
- this.sourceViewByUISourceCode.delete(uiSourceCode);
652
- if (sourceView && sourceView instanceof UISourceCodeFrame) {
653
- (sourceView).dispose();
654
- }
655
- uiSourceCode.removeEventListener(Workspace.UISourceCode.Events.TitleChanged, this.#uiSourceCodeTitleChanged, this);
565
+ return this.editorContainer?.getCreatedSourceView(uiSourceCode);
656
566
  }
657
567
 
658
568
  private editorClosed(event: Common.EventTarget.EventTargetEvent<Workspace.UISourceCode.UISourceCode>): void {
@@ -933,12 +843,3 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
933
843
  return false;
934
844
  }
935
845
  }
936
-
937
- const HEADER_OVERRIDES_FILENAME = '.headers';
938
-
939
- const enum SourceViewType {
940
- IMAGE_VIEW = 'ImageView',
941
- FONT_VIEW = 'FontView',
942
- HEADERS_VIEW = 'HeadersView',
943
- SOURCE_VIEW = 'SourceView',
944
- }
@@ -20,6 +20,8 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
20
20
  import * as PanelCommon from '../common/common.js';
21
21
  import * as Snippets from '../snippets/snippets.js';
22
22
 
23
+ import * as Components from './components/components.js';
24
+ import type {EditingLocationHistoryManager} from './EditingLocationHistoryManager.js';
23
25
  import {SourcesView} from './SourcesView.js';
24
26
  import {UISourceCodeFrame} from './UISourceCodeFrame.js';
25
27
 
@@ -73,17 +75,24 @@ const UIStrings = {
73
75
  } as const;
74
76
  const str_ = i18n.i18n.registerUIStrings('panels/sources/TabbedEditorContainer.ts', UIStrings);
75
77
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
76
- export interface TabbedEditorContainerDelegate {
77
- viewForFile(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget;
78
78
 
79
- recycleUISourceCodeFrame(sourceFrame: UISourceCodeFrame, uiSourceCode: Workspace.UISourceCode.UISourceCode): void;
79
+ const enum SourceViewType {
80
+ IMAGE_VIEW = 'ImageView',
81
+ FONT_VIEW = 'FontView',
82
+ HEADERS_VIEW = 'HeadersView',
83
+ SOURCE_VIEW = 'SourceView',
80
84
  }
85
+ const HEADER_OVERRIDES_FILENAME = '.headers';
81
86
 
82
87
  let tabId = 0;
83
88
 
84
89
  export class TabbedEditorContainer extends Common.ObjectWrapper.eventMixin<EventTypes, typeof UI.Widget.VBox>(
85
90
  UI.Widget.VBox) {
86
- delegate!: TabbedEditorContainerDelegate;
91
+ #historyManager!: EditingLocationHistoryManager;
92
+ set historyManager(historyManager: EditingLocationHistoryManager) {
93
+ this.#historyManager = historyManager;
94
+ }
95
+ private readonly sourceViewByUISourceCode = new Map<Workspace.UISourceCode.UISourceCode, UI.Widget.Widget>();
87
96
  private readonly tabbedPane: UI.TabbedPane.TabbedPane;
88
97
  private tabIds: Map<Workspace.UISourceCode.UISourceCode, string>;
89
98
  private readonly files: Map<string, Workspace.UISourceCode.UISourceCode>;
@@ -167,7 +176,7 @@ export class TabbedEditorContainer extends Common.ObjectWrapper.eventMixin<Event
167
176
  const networkView = this.tabbedPane.tabView(networkTabId);
168
177
  const tabIndex = this.tabbedPane.tabIndex(networkTabId);
169
178
  if (networkView instanceof UISourceCodeFrame) {
170
- this.delegate.recycleUISourceCodeFrame(networkView, binding.fileSystem);
179
+ this.recycleUISourceCodeFrame(networkView, binding.fileSystem);
171
180
  fileSystemTabId = this.appendFileTab(binding.fileSystem, false, tabIndex, networkView);
172
181
  } else {
173
182
  fileSystemTabId = this.appendFileTab(binding.fileSystem, false, tabIndex);
@@ -348,7 +357,7 @@ export class TabbedEditorContainer extends Common.ObjectWrapper.eventMixin<Event
348
357
  // We are showing a different UISourceCode in the same tab (because it has the same URL). This
349
358
  // commonly happens when switching between workers or iframes containing the same code, and while the
350
359
  // contents are usually identical they may not be and it is important to show users when they aren't.
351
- this.delegate.recycleUISourceCodeFrame(this.currentView, uiSourceCode);
360
+ this.recycleUISourceCodeFrame(this.currentView, uiSourceCode);
352
361
  if (uiSourceCode.project().type() !== Workspace.Workspace.projectTypes.FileSystem) {
353
362
  // Disable editing, because it may confuse users that only one of the copies of this code changes.
354
363
  uiSourceCode.disableEdit();
@@ -494,6 +503,7 @@ export class TabbedEditorContainer extends Common.ObjectWrapper.eventMixin<Event
494
503
  if (this.idToUISourceCode.get(uiSourceCode.canonicalScriptId()) === uiSourceCode) {
495
504
  this.idToUISourceCode.delete(uiSourceCode.canonicalScriptId());
496
505
  }
506
+ this.removeSourceFrame(uiSourceCode);
497
507
  }
498
508
  this.tabbedPane.closeTabs(tabIds);
499
509
  }
@@ -527,7 +537,7 @@ export class TabbedEditorContainer extends Common.ObjectWrapper.eventMixin<Event
527
537
  private appendFileTab(
528
538
  uiSourceCode: Workspace.UISourceCode.UISourceCode, userGesture?: boolean, index?: number,
529
539
  replaceView?: UI.Widget.Widget): string {
530
- const view = replaceView || this.delegate.viewForFile(uiSourceCode);
540
+ const view = replaceView || this.viewForFile(uiSourceCode);
531
541
  const title = this.titleForFile(uiSourceCode);
532
542
  const tooltip = this.tooltipForFile(uiSourceCode);
533
543
 
@@ -597,6 +607,7 @@ export class TabbedEditorContainer extends Common.ObjectWrapper.eventMixin<Event
597
607
 
598
608
  if (uiSourceCode) {
599
609
  this.removeUISourceCodeListeners(uiSourceCode);
610
+ this.removeSourceFrame(uiSourceCode);
600
611
 
601
612
  this.dispatchEventToListeners(Events.EDITOR_CLOSED, uiSourceCode);
602
613
 
@@ -687,6 +698,18 @@ export class TabbedEditorContainer extends Common.ObjectWrapper.eventMixin<Event
687
698
  private uiSourceCodeTitleChanged(event: Common.EventTarget.EventTargetEvent<Workspace.UISourceCode.UISourceCode>):
688
699
  void {
689
700
  const uiSourceCode = event.data;
701
+
702
+ const widget = this.sourceViewByUISourceCode.get(uiSourceCode);
703
+ if (widget) {
704
+ if (this.#sourceViewTypeForWidget(widget) !== this.#sourceViewTypeForUISourceCode(uiSourceCode)) {
705
+ // Remove the existing editor tab and create a new one of the correct type.
706
+ this.removeUISourceCodes([uiSourceCode]);
707
+ this.addUISourceCode(uiSourceCode);
708
+ this.showFile(uiSourceCode);
709
+ return;
710
+ }
711
+ }
712
+
690
713
  this.updateFileTitle(uiSourceCode);
691
714
  this.updateHistory();
692
715
 
@@ -785,6 +808,86 @@ export class TabbedEditorContainer extends Common.ObjectWrapper.eventMixin<Event
785
808
  void UI.ViewManager.ViewManager.instance().showView('navigator-files');
786
809
  }
787
810
 
811
+ getCreatedSourceView(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget|undefined {
812
+ return this.sourceViewByUISourceCode.get(uiSourceCode);
813
+ }
814
+
815
+ viewForFile(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget {
816
+ return this.getOrCreateSourceView(uiSourceCode);
817
+ }
818
+
819
+ private getOrCreateSourceView(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget {
820
+ return this.sourceViewByUISourceCode.get(uiSourceCode) || this.createSourceView(uiSourceCode);
821
+ }
822
+
823
+ private createSourceView(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Widget.Widget {
824
+ let sourceView;
825
+ const contentType = uiSourceCode.contentType();
826
+
827
+ if (contentType === Common.ResourceType.resourceTypes.Image || uiSourceCode.mimeType().startsWith('image/')) {
828
+ sourceView = new SourceFrame.ImageView.ImageView(uiSourceCode.mimeType(), uiSourceCode);
829
+ } else if (contentType === Common.ResourceType.resourceTypes.Font || uiSourceCode.mimeType().includes('font')) {
830
+ sourceView = new SourceFrame.FontView.FontView(uiSourceCode.mimeType(), uiSourceCode);
831
+ } else if (uiSourceCode.name() === HEADER_OVERRIDES_FILENAME) {
832
+ sourceView = new Components.HeadersView.HeadersView(uiSourceCode);
833
+ } else {
834
+ sourceView = new UISourceCodeFrame(uiSourceCode);
835
+ this.#historyManager.trackSourceFrameCursorJumps(sourceView);
836
+ }
837
+
838
+ this.sourceViewByUISourceCode.set(uiSourceCode, sourceView);
839
+ uiSourceCode.addEventListener(Workspace.UISourceCode.Events.TitleChanged, this.uiSourceCodeTitleChanged, this);
840
+ return sourceView;
841
+ }
842
+
843
+ recycleUISourceCodeFrame(sourceFrame: UISourceCodeFrame, uiSourceCode: Workspace.UISourceCode.UISourceCode): void {
844
+ sourceFrame.uiSourceCode().removeEventListener(Workspace.UISourceCode.Events.TitleChanged,
845
+ this.uiSourceCodeTitleChanged, this);
846
+ this.sourceViewByUISourceCode.delete(sourceFrame.uiSourceCode());
847
+ sourceFrame.setUISourceCode(uiSourceCode);
848
+ this.sourceViewByUISourceCode.set(uiSourceCode, sourceFrame);
849
+ uiSourceCode.addEventListener(Workspace.UISourceCode.Events.TitleChanged, this.uiSourceCodeTitleChanged, this);
850
+ }
851
+
852
+ private removeSourceFrame(uiSourceCode: Workspace.UISourceCode.UISourceCode): void {
853
+ const sourceView = this.sourceViewByUISourceCode.get(uiSourceCode);
854
+ this.sourceViewByUISourceCode.delete(uiSourceCode);
855
+ if (sourceView) {
856
+ uiSourceCode.removeEventListener(Workspace.UISourceCode.Events.TitleChanged, this.uiSourceCodeTitleChanged, this);
857
+ }
858
+ if (sourceView && sourceView instanceof UISourceCodeFrame) {
859
+ (sourceView).dispose();
860
+ }
861
+ }
862
+
863
+ #sourceViewTypeForWidget(widget: UI.Widget.Widget): SourceViewType {
864
+ if (widget instanceof SourceFrame.ImageView.ImageView) {
865
+ return SourceViewType.IMAGE_VIEW;
866
+ }
867
+ if (widget instanceof SourceFrame.FontView.FontView) {
868
+ return SourceViewType.FONT_VIEW;
869
+ }
870
+ if (widget instanceof Components.HeadersView.HeadersView) {
871
+ return SourceViewType.HEADERS_VIEW;
872
+ }
873
+ return SourceViewType.SOURCE_VIEW;
874
+ }
875
+
876
+ #sourceViewTypeForUISourceCode(uiSourceCode: Workspace.UISourceCode.UISourceCode): SourceViewType {
877
+ if (uiSourceCode.name() === HEADER_OVERRIDES_FILENAME) {
878
+ return SourceViewType.HEADERS_VIEW;
879
+ }
880
+ const contentType = uiSourceCode.contentType();
881
+ switch (contentType) {
882
+ case Common.ResourceType.resourceTypes.Image:
883
+ return SourceViewType.IMAGE_VIEW;
884
+ case Common.ResourceType.resourceTypes.Font:
885
+ return SourceViewType.FONT_VIEW;
886
+ default:
887
+ return SourceViewType.SOURCE_VIEW;
888
+ }
889
+ }
890
+
788
891
  currentFile(): Workspace.UISourceCode.UISourceCode|null {
789
892
  return this.#currentFile || null;
790
893
  }