Web Inspector: REGRESSION (r248873): Debugger: pressing delete on a breakpoint will...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / SourcesNavigationSidebarPanel.js
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WI.SourcesNavigationSidebarPanel = class SourcesNavigationSidebarPanel extends WI.NavigationSidebarPanel
27 {
28     constructor()
29     {
30         const shouldAutoPruneStaleTopLevelResourceTreeElements = true;
31         super("sources", WI.UIString("Sources"), shouldAutoPruneStaleTopLevelResourceTreeElements);
32
33         this._workerTargetTreeElementMap = new Map;
34         this._mainFrameTreeElement = null;
35         this._extensionScriptsFolderTreeElement = null;
36         this._extraScriptsFolderTreeElement = null;
37         this._anonymousScriptsFolderTreeElement = null;
38
39         this._originTreeElementMap = new Map;
40
41         this._boundCompareTreeElements = this._compareTreeElements.bind(this);
42
43         this._debuggerNavigationBar = new WI.NavigationBar;
44         this.addSubview(this._debuggerNavigationBar);
45
46         let createActivateNavigationItem = ({identifier, defaultToolTip, activatedToolTip, image}) => {
47             let navigationItem = new WI.ActivateButtonNavigationItem(identifier, defaultToolTip, activatedToolTip, image, 15, 15);
48             this._debuggerNavigationBar.addNavigationItem(navigationItem);
49             return navigationItem;
50         };
51
52         let createToggleNavigationItem = ({identifier, defaultToolTip, alternateToolTip, defaultImage, alternateImage}) => {
53             let navigationItem = new WI.ToggleButtonNavigationItem(identifier, defaultToolTip, alternateToolTip, defaultImage, alternateImage, 15, 15);
54             this._debuggerNavigationBar.addNavigationItem(navigationItem);
55             return navigationItem;
56         };
57
58         let createButtonNavigationitem = ({identifier, toolTipOrLabel, image}) => {
59             let navigationItem = new WI.ButtonNavigationItem(identifier, toolTipOrLabel, image, 15, 15);
60             this._debuggerNavigationBar.addNavigationItem(navigationItem);
61             return navigationItem;
62         };
63
64         this._debuggerBreakpointsButtonItem = createActivateNavigationItem({
65             identifier: "debugger-breakpoints",
66             defaultToolTip: WI.UIString("Enable all breakpoints (%s)").format(WI.toggleBreakpointsKeyboardShortcut.displayName),
67             activatedToolTip: WI.UIString("Disable all breakpoints (%s)").format(WI.toggleBreakpointsKeyboardShortcut.displayName),
68             image: "Images/Breakpoints.svg",
69         });
70         this._debuggerBreakpointsButtonItem.activated = WI.debuggerManager.breakpointsEnabled;
71         this._debuggerBreakpointsButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerToggleBreakpoints, this);
72
73         this._debuggerPauseResumeButtonItem = createToggleNavigationItem({
74             identifier: "debugger-pause-resume",
75             defaultToolTip: WI.UIString("Pause script execution (%s or %s)").format(WI.pauseOrResumeKeyboardShortcut.displayName, WI.pauseOrResumeAlternateKeyboardShortcut.displayName),
76             alternateToolTip: WI.UIString("Continue script execution (%s or %s)").format(WI.pauseOrResumeKeyboardShortcut.displayName, WI.pauseOrResumeAlternateKeyboardShortcut.displayName),
77             defaultImage: "Images/Pause.svg",
78             alternateImage: "Images/Resume.svg",
79         });
80         this._debuggerPauseResumeButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerPauseResumeToggle, this);
81
82         this._debuggerStepOverButtonItem = createButtonNavigationitem({
83             identifier: "debugger-step-over",
84             toolTipOrLabel: WI.UIString("Step over (%s or %s)").format(WI.stepOverKeyboardShortcut.displayName, WI.stepOverAlternateKeyboardShortcut.displayName),
85             image: "Images/StepOver.svg",
86         });
87         this._debuggerStepOverButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerStepOver, this);
88         this._debuggerStepOverButtonItem.enabled = false;
89
90         this._debuggerStepIntoButtonItem = createButtonNavigationitem({
91             identifier: "debugger-step-into",
92             toolTipOrLabel: WI.UIString("Step into (%s or %s)").format(WI.stepIntoKeyboardShortcut.displayName, WI.stepIntoAlternateKeyboardShortcut.displayName),
93             image: "Images/StepInto.svg",
94         });
95         this._debuggerStepIntoButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerStepInto, this);
96         this._debuggerStepIntoButtonItem.enabled = false;
97
98         this._debuggerStepOutButtonItem = createButtonNavigationitem({
99             identifier: "debugger-step-out",
100             toolTipOrLabel: WI.UIString("Step out (%s or %s)").format(WI.stepOutKeyboardShortcut.displayName, WI.stepOutAlternateKeyboardShortcut.displayName),
101             image: "Images/StepOut.svg",
102         });
103         this._debuggerStepOutButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerStepOut, this);
104         this._debuggerStepOutButtonItem.enabled = false;
105
106         this._timelineRecordingWarningElement = null;
107         this._auditTestWarningElement = null;
108         this._breakpointsDisabledWarningElement = null;
109
110         this._pauseReasonTreeOutline = null;
111         this._pauseReasonLinkContainerElement = document.createElement("span");
112         this._pauseReasonTextRow = new WI.DetailsSectionTextRow;
113         this._pauseReasonGroup = new WI.DetailsSectionGroup([this._pauseReasonTextRow]);
114         this._pauseReasonSection = new WI.DetailsSection("paused-reason", WI.UIString("Pause Reason"), [this._pauseReasonGroup], this._pauseReasonLinkContainerElement);
115
116         this._pauseReasonContainer = document.createElement("div");
117         this._pauseReasonContainer.classList.add("pause-reason-container");
118         this._pauseReasonContainer.appendChild(this._pauseReasonSection.element);
119
120         this._callStackTreeOutline = this.createContentTreeOutline({suppressFiltering: true});
121         this._callStackTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._handleTreeSelectionDidChange, this);
122
123         let callStackRow = new WI.DetailsSectionRow;
124         callStackRow.element.appendChild(this._callStackTreeOutline.element);
125
126         let callStackGroup = new WI.DetailsSectionGroup([callStackRow]);
127         this._callStackSection = new WI.DetailsSection("call-stack", WI.UIString("Call Stack"), [callStackGroup]);
128
129         this._callStackContainer = document.createElement("div");
130         this._callStackContainer.classList.add("call-stack-container");
131         this._callStackContainer.appendChild(this._callStackSection.element);
132
133         this._mainTargetTreeElement = null;
134         this._activeCallFrameTreeElement = null;
135
136         // Prevent the breakpoints list from being used as the source of selection restoration (e.g. on reload or navigation).
137         this._breakpointsTreeOutline = this.createContentTreeOutline({ignoreCookieRestoration: true});
138         this._breakpointsTreeOutline.addEventListener(WI.TreeOutline.Event.ElementAdded, this._handleBreakpointElementAddedOrRemoved, this);
139         this._breakpointsTreeOutline.addEventListener(WI.TreeOutline.Event.ElementRemoved, this._handleBreakpointElementAddedOrRemoved, this);
140         this._breakpointsTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._handleTreeSelectionDidChange, this);
141         this._breakpointsTreeOutline.ondelete = (selectedTreeElement) => {
142             console.assert(selectedTreeElement.selected);
143
144             if (!WI.debuggerManager.isBreakpointRemovable(selectedTreeElement.representedObject)) {
145                 let treeElementToSelect = selectedTreeElement.nextSelectableSibling;
146                 if (treeElementToSelect) {
147                     const omitFocus = true;
148                     const selectedByUser = true;
149                     treeElementToSelect.select(omitFocus, selectedByUser);
150                 }
151             } else if (selectedTreeElement instanceof WI.ResourceTreeElement || selectedTreeElement instanceof WI.ScriptTreeElement) {
152                 let breakpoints = this._breakpointsBeneathTreeElement(selectedTreeElement);
153                 this._removeAllBreakpoints(breakpoints);
154             } else if (selectedTreeElement.representedObject === SourcesNavigationSidebarPanel.__windowEventTargetRepresentedObject) {
155                 let eventBreakpointsOnWindow = WI.domManager.eventListenerBreakpoints.filter((eventBreakpoint) => eventBreakpoint.eventListener.onWindow);
156                 for (let eventBreakpoint of eventBreakpointsOnWindow)
157                     WI.domManager.removeBreakpointForEventListener(eventBreakpoint.eventListener);
158             }
159
160             return true;
161         };
162         this._breakpointsTreeOutline.populateContextMenu = (contextMenu, event, treeElement) => {
163             // This check is necessary since the context menu is created by the TreeOutline, meaning
164             // that any child could be the target of the context menu event.
165             if (treeElement instanceof WI.ResourceTreeElement || treeElement instanceof WI.ScriptTreeElement) {
166                 let breakpoints = this._breakpointsBeneathTreeElement(treeElement);
167
168                 let shouldDisable = breakpoints.some((breakpoint) => !breakpoint.disabled);
169                 contextMenu.appendItem(shouldDisable ? WI.UIString("Disable Breakpoints") : WI.UIString("Enable Breakpoints"), () => {
170                     this._toggleAllBreakpoints(breakpoints, shouldDisable);
171                 });
172
173                 contextMenu.appendItem(WI.UIString("Delete Breakpoints"), () => {
174                     this._removeAllBreakpoints(breakpoints);
175                 });
176             }
177
178             WI.TreeOutline.prototype.populateContextMenu(contextMenu, event, treeElement);
179         };
180
181         let breakpointsRow = new WI.DetailsSectionRow;
182         breakpointsRow.element.appendChild(this._breakpointsTreeOutline.element);
183
184         let breakpointNavigationBarWrapper = document.createElement("div");
185
186         let breakpointNavigationBar = new WI.NavigationBar;
187         breakpointNavigationBarWrapper.appendChild(breakpointNavigationBar.element);
188
189         this._createBreakpointButton = new WI.ButtonNavigationItem("create-breakpoint", WI.UIString("Create Breakpoint"), "Images/Plus13.svg", 13, 13);
190         WI.addMouseDownContextMenuHandlers(this._createBreakpointButton.element, this._populateCreateBreakpointContextMenu.bind(this));
191         breakpointNavigationBar.addNavigationItem(this._createBreakpointButton);
192
193         let breakpointsGroup = new WI.DetailsSectionGroup([breakpointsRow]);
194         this._breakpointsSection = new WI.DetailsSection("breakpoints", WI.UIString("Breakpoints"), [breakpointsGroup], breakpointNavigationBarWrapper);
195
196         this._breakpointsContainer = document.createElement("div");
197         this._breakpointsContainer.classList.add("breakpoints-container");
198         this._breakpointsContainer.appendChild(this._breakpointsSection.element);
199
200         this.contentView.element.insertBefore(this._breakpointsContainer, this.contentView.element.firstChild);
201
202         this._resourcesNavigationBar = new WI.NavigationBar;
203         this.contentView.addSubview(this._resourcesNavigationBar);
204         this.contentView.element.insertBefore(this._resourcesNavigationBar.element, this._breakpointsContainer.nextSibling);
205
206         this._resourceGroupingModeScopeBarItems = {};
207         let createResourceGroupingModeScopeBarItem = (mode, label) => {
208             this._resourceGroupingModeScopeBarItems[mode] = new WI.ScopeBarItem("sources-resource-grouping-mode-" + mode, label, {exclusive: true});
209             this._resourceGroupingModeScopeBarItems[mode][SourcesNavigationSidebarPanel.ResourceGroupingModeSymbol] = mode;
210         };
211         createResourceGroupingModeScopeBarItem(WI.Resource.GroupingMode.Type, WI.UIString("By Type"));
212         createResourceGroupingModeScopeBarItem(WI.Resource.GroupingMode.Path, WI.UIString("By Path"));
213
214         this._resourceGroupingModeScopeBar = new WI.ScopeBar("sources-resource-grouping-mode-scope-bar", Object.values(this._resourceGroupingModeScopeBarItems), this._resourceGroupingModeScopeBarItems[WI.settings.resourceGroupingMode.value]);
215         this._resourceGroupingModeScopeBar.addEventListener(WI.ScopeBar.Event.SelectionChanged, this._handleResourceGroupingModeScopeBarSelectionChanged, this);
216         this._resourcesNavigationBar.addNavigationItem(this._resourceGroupingModeScopeBar);
217
218         let resourcesContainer = document.createElement("div");
219         resourcesContainer.classList.add("resources-container");
220         this.contentView.element.insertBefore(resourcesContainer, this._resourcesNavigationBar.element.nextSibling);
221
222         this._resourcesTreeOutline = this.contentTreeOutline;
223         this._resourcesTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._handleTreeSelectionDidChange, this);
224         this._resourcesTreeOutline.includeSourceMapResourceChildren = true;
225         resourcesContainer.appendChild(this._resourcesTreeOutline.element);
226
227         if (InspectorBackend.domains.CSS) {
228             let createResourceNavigationBar = new WI.NavigationBar;
229
230             let createResourceButtonNavigationItem = new WI.ButtonNavigationItem("create-resource", WI.UIString("Create Resource"), "Images/Plus15.svg", 15, 15);
231             WI.addMouseDownContextMenuHandlers(createResourceButtonNavigationItem.element, this._populateCreateResourceContextMenu.bind(this));
232             createResourceNavigationBar.addNavigationItem(createResourceButtonNavigationItem);
233
234             this.filterBar.element.insertBefore(createResourceNavigationBar.element, this.filterBar.element.firstChild);
235         }
236
237         const activatedByDefault = false;
238         this.filterBar.addFilterBarButton("sources-only-show-resources-with-issues", this._filterByResourcesWithIssues.bind(this), activatedByDefault, WI.UIString("Only show resources with issues"), WI.UIString("Show all resources"), "Images/Errors.svg", 15, 15);
239
240         const resourceTypeScopeItemPrefix = "sources-resource-type-";
241         let resourceTypeScopeBarItems = [];
242         resourceTypeScopeBarItems.push(new WI.ScopeBarItem(resourceTypeScopeItemPrefix + "all", WI.UIString("All")));
243         for (let value of Object.values(WI.Resource.Type)) {
244             let scopeBarItem = new WI.ScopeBarItem(resourceTypeScopeItemPrefix + value, WI.Resource.displayNameForType(value, true));
245             scopeBarItem[SourcesNavigationSidebarPanel.ResourceTypeSymbol] = value;
246             resourceTypeScopeBarItems.push(scopeBarItem);
247         }
248
249         const shouldGroupNonExclusiveItems = true;
250         this._resourceTypeScopeBar = new WI.ScopeBar("sources-resource-type-scope-bar", resourceTypeScopeBarItems, resourceTypeScopeBarItems[0], shouldGroupNonExclusiveItems);
251         this._resourceTypeScopeBar.addEventListener(WI.ScopeBar.Event.SelectionChanged, this._handleResourceTypeScopeBarSelectionChanged, this);
252         this.filterBar.addFilterNavigationItem(this._resourceTypeScopeBar);
253
254         WI.settings.resourceGroupingMode.addEventListener(WI.Setting.Event.Changed, this._handleResourceGroupingModeChanged, this);
255
256         WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._handleFrameMainResourceDidChange, this);
257         WI.Frame.addEventListener(WI.Frame.Event.ResourceWasAdded, this._handleResourceAdded, this);
258         WI.Target.addEventListener(WI.Target.Event.ResourceAdded, this._handleResourceAdded, this);
259
260         WI.networkManager.addEventListener(WI.NetworkManager.Event.FrameWasAdded, this._handleFrameWasAdded, this);
261
262         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointAdded, this._handleDebuggerBreakpointAdded, this);
263         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.DOMBreakpointAdded, this._handleDebuggerBreakpointAdded, this);
264         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.EventBreakpointAdded, this._handleDebuggerBreakpointAdded, this);
265         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.URLBreakpointAdded, this._handleDebuggerBreakpointAdded, this);
266
267         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointRemoved, this._handleDebuggerBreakpointRemoved, this);
268         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.DOMBreakpointRemoved, this._handleDebuggerBreakpointRemoved, this);
269         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, this._handleDebuggerBreakpointRemoved, this);
270         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.URLBreakpointRemoved, this._handleDebuggerBreakpointRemoved, this);
271
272         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointsEnabledDidChange, this._handleDebuggerBreakpointsEnabledDidChange, this);
273         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ScriptAdded, this._handleDebuggerScriptAdded, this);
274         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ScriptRemoved, this._handleDebuggerScriptRemoved, this);
275         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ScriptsCleared, this._handleDebuggerScriptsCleared, this);
276         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, this._handleDebuggerPaused, this);
277         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Resumed, this._handleDebuggerResumed, this);
278         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.CallFramesDidChange, this._handleDebuggerCallFramesDidChange, this);
279         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ActiveCallFrameDidChange, this._handleDebuggerActiveCallFrameDidChange, this);
280         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.WaitingToPause, this._handleDebuggerWaitingToPause, this);
281
282         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.DisplayLocationDidChange, this._handleDebuggerObjectDisplayLocationDidChange, this);
283         WI.IssueMessage.addEventListener(WI.IssueMessage.Event.DisplayLocationDidChange, this._handleDebuggerObjectDisplayLocationDidChange, this);
284
285         WI.DOMBreakpoint.addEventListener(WI.DOMBreakpoint.Event.DOMNodeChanged, this._handleDOMBreakpointDOMNodeChanged, this);
286
287         WI.consoleManager.addEventListener(WI.ConsoleManager.Event.IssueAdded, this._handleConsoleIssueAdded, this);
288         WI.consoleManager.addEventListener(WI.ConsoleManager.Event.Cleared, this._handleConsoleCleared, this);
289
290         WI.timelineManager.addEventListener(WI.TimelineManager.Event.CapturingStateChanged, this._handleTimelineCapturingStateChanged, this);
291
292         WI.auditManager.addEventListener(WI.AuditManager.Event.TestScheduled, this._handleAuditManagerTestScheduled, this);
293         WI.auditManager.addEventListener(WI.AuditManager.Event.TestCompleted, this._handleAuditManagerTestCompleted, this);
294
295         WI.cssManager.addEventListener(WI.CSSManager.Event.StyleSheetAdded, this._handleCSSStyleSheetAdded, this);
296
297         WI.targetManager.addEventListener(WI.TargetManager.Event.TargetAdded, this._handleTargetAdded, this);
298         WI.targetManager.addEventListener(WI.TargetManager.Event.TargetRemoved, this._handleTargetRemoved, this);
299
300         WI.notifications.addEventListener(WI.Notification.ExtraDomainsActivated, this._handleExtraDomainsActivated, this);
301
302         if (WI.SourcesNavigationSidebarPanel.shouldPlaceResourcesAtTopLevel()) {
303             this._resourcesTreeOutline.disclosureButtons = false;
304             WI.SourceCode.addEventListener(WI.SourceCode.Event.SourceMapAdded, () => {
305                 this._resourcesTreeOutline.disclosureButtons = true;
306             }, this);
307         }
308
309         WI.debuggerManager.addBreakpoint(WI.debuggerManager.allExceptionsBreakpoint);
310         WI.debuggerManager.addBreakpoint(WI.debuggerManager.uncaughtExceptionsBreakpoint);
311
312         // COMPATIBILITY (iOS 10): DebuggerAgent.setPauseOnAssertions did not exist yet.
313         if (InspectorBackend.domains.Debugger.setPauseOnAssertions && WI.settings.showAssertionFailuresBreakpoint.value)
314             WI.debuggerManager.addBreakpoint(WI.debuggerManager.assertionFailuresBreakpoint);
315
316         // COMPATIBILITY (iOS 13): DebuggerAgent.setPauseOnMicrotasks did not exist yet.
317         if (InspectorBackend.domains.Debugger.setPauseOnMicrotasks && WI.settings.showAllMicrotasksBreakpoint.value)
318             WI.debuggerManager.addBreakpoint(WI.debuggerManager.allMicrotasksBreakpoint);
319
320         for (let target of WI.targets)
321             this._addTarget(target);
322
323         this._updateCallStackTreeOutline();
324
325         this._handleResourceGroupingModeChanged();
326
327         if (WI.domDebuggerManager.supported) {
328             if (WI.settings.showAllAnimationFramesBreakpoint.value)
329                 WI.domDebuggerManager.addEventBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint);
330
331             if (WI.settings.showAllTimeoutsBreakpoint.value)
332                 WI.domDebuggerManager.addEventBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint);
333
334             if (WI.settings.showAllIntervalsBreakpoint.value)
335                 WI.domDebuggerManager.addEventBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint);
336
337             if (WI.settings.showAllListenersBreakpoint.value)
338                 WI.domDebuggerManager.addEventBreakpoint(WI.domDebuggerManager.allListenersBreakpoint);
339
340             for (let eventBreakpoint of WI.domDebuggerManager.listenerBreakpoints)
341                 this._addBreakpoint(eventBreakpoint);
342
343             for (let eventListenerBreakpoint of WI.domManager.eventListenerBreakpoints)
344                 this._addBreakpoint(eventListenerBreakpoint);
345
346             for (let domBreakpoint of WI.domDebuggerManager.domBreakpoints)
347                 this._addBreakpoint(domBreakpoint);
348
349             if (WI.settings.showAllRequestsBreakpoint.value)
350                 WI.domDebuggerManager.addURLBreakpoint(WI.domDebuggerManager.allRequestsBreakpoint);
351
352             for (let urlBreakpoints of WI.domDebuggerManager.urlBreakpoints)
353                 this._addBreakpoint(urlBreakpoints);
354         }
355
356         if (WI.debuggerManager.paused)
357             this._handleDebuggerPaused();
358
359         if (WI.debuggerManager.breakpointsDisabledTemporarily) {
360             this._handleTimelineCapturingStateChanged();
361
362             if (WI.auditManager.runningState === WI.AuditManager.RunningState.Active || WI.auditManager.runningState === WI.AuditManager.RunningState.Stopping)
363                 this._handleAuditManagerTestScheduled();
364         }
365
366         this._updateBreakpointsDisabledBanner();
367     }
368
369     // Static
370
371     static shouldPlaceResourcesAtTopLevel()
372     {
373         return (WI.sharedApp.debuggableType === WI.DebuggableType.JavaScript && !WI.sharedApp.hasExtraDomains)
374             || WI.sharedApp.debuggableType === WI.DebuggableType.ServiceWorker;
375     }
376
377     // Public
378
379     get minimumWidth()
380     {
381         return Math.max(this._debuggerNavigationBar.minimumWidth, this._resourcesNavigationBar.minimumWidth);
382     }
383
384     closed()
385     {
386         WI.settings.resourceGroupingMode.removeEventListener(null, null, this);
387         WI.Frame.removeEventListener(null, null, this);
388         WI.Target.removeEventListener(null, null, this);
389         WI.networkManager.removeEventListener(null, null, this);
390         WI.debuggerManager.removeEventListener(null, null, this);
391         WI.domDebuggerManager.removeEventListener(null, null, this);
392         WI.Breakpoint.removeEventListener(null, null, this);
393         WI.IssueMessage.removeEventListener(null, null, this);
394         WI.DOMBreakpoint.removeEventListener(null, null, this);
395         WI.consoleManager.removeEventListener(null, null, this);
396         WI.timelineManager.removeEventListener(null, null, this);
397         WI.auditManager.removeEventListener(null, null, this);
398         WI.cssManager.removeEventListener(null, null, this);
399         WI.targetManager.removeEventListener(null, null, this);
400         WI.notifications.removeEventListener(null, null, this);
401         WI.SourceCode.removeEventListener(null, null, this);
402
403         super.closed();
404     }
405
406     showDefaultContentView()
407     {
408         if (WI.networkManager.mainFrame) {
409             this.contentBrowser.showContentViewForRepresentedObject(WI.networkManager.mainFrame);
410             return;
411         }
412
413         let firstTreeElement = this._resourcesTreeOutline.children[0];
414         if (firstTreeElement)
415             this.showDefaultContentViewForTreeElement(firstTreeElement);
416     }
417
418     treeElementForRepresentedObject(representedObject)
419     {
420         // A custom implementation is needed for this since the frames are populated lazily.
421
422         if (!this._mainFrameTreeElement && (representedObject instanceof WI.Resource || representedObject instanceof WI.Frame || representedObject instanceof WI.Collection)) {
423             // All resources are under the main frame, so we need to return early if we don't have the main frame yet.
424             return null;
425         }
426
427         switch (WI.settings.resourceGroupingMode.value) {
428         case WI.Resource.GroupingMode.Path:
429             if (representedObject instanceof WI.Frame)
430                 representedObject = representedObject.mainResource;
431             break;
432
433         default:
434             WI.reportInternalError("Unknown resource grouping mode", {"Resource Grouping Mode": WI.settings.resourceGroupingMode.value});
435             // Fallthrough for default value.
436
437         case WI.Resource.GroupingMode.Type:
438             if (representedObject instanceof WI.Resource && representedObject.parentFrame && representedObject.parentFrame.mainResource === representedObject)
439                 representedObject = representedObject.parentFrame;
440             break;
441         }
442
443         function isAncestor(ancestor, resourceOrFrame) {
444             // SourceMapResources are descendants of another SourceCode object.
445             if (resourceOrFrame instanceof WI.SourceMapResource) {
446                 if (resourceOrFrame.sourceMap.originalSourceCode === ancestor)
447                     return true;
448
449                 // Not a direct ancestor, so check the ancestors of the parent SourceCode object.
450                 resourceOrFrame = resourceOrFrame.sourceMap.originalSourceCode;
451             }
452
453             let currentFrame = resourceOrFrame.parentFrame;
454             while (currentFrame) {
455                 if (currentFrame === ancestor)
456                     return true;
457                 currentFrame = currentFrame.parentFrame;
458             }
459             return false;
460         }
461
462         function getParent(resourceOrFrame) {
463             // SourceMapResources are descendants of another SourceCode object.
464             if (resourceOrFrame instanceof WI.SourceMapResource)
465                 return resourceOrFrame.sourceMap.originalSourceCode;
466             return resourceOrFrame.parentFrame;
467         }
468
469         function searchTreeOutline(treeOutline, forceSearch) {
470             if (!treeOutline || (!treeOutline.selectedTreeElement && !forceSearch))
471                 return null;
472             return treeOutline.findTreeElement(representedObject, isAncestor, getParent);
473         }
474         let treeElement = searchTreeOutline(this._pauseReasonTreeOutline) || searchTreeOutline(this._callStackTreeOutline) || searchTreeOutline(this._breakpointsTreeOutline) || searchTreeOutline(this._resourcesTreeOutline, true);
475         if (treeElement)
476             return treeElement;
477
478         // Only special case Script objects.
479         if (!(representedObject instanceof WI.Script)) {
480             console.error("Didn't find a TreeElement for representedObject", representedObject);
481             return null;
482         }
483
484         // If the Script has a URL we should have found it earlier.
485         if (representedObject.url) {
486             console.error("Didn't find a ScriptTreeElement for a Script with a URL.");
487             return null;
488         }
489
490         // Since the Script does not have a URL we consider it an 'anonymous' script. These scripts happen from calls to
491         // window.eval() or browser features like Auto Fill and Reader. They are not normally added to the sidebar, but since
492         // we have a ScriptContentView asking for the tree element we will make a ScriptTreeElement on demand and add it.
493
494         if (!this._anonymousScriptsFolderTreeElement)
495             this._anonymousScriptsFolderTreeElement = new WI.FolderTreeElement(WI.UIString("Anonymous Scripts"), new WI.ScriptCollection);
496
497         if (!this._anonymousScriptsFolderTreeElement.parent) {
498             let index = insertionIndexForObjectInListSortedByFunction(this._anonymousScriptsFolderTreeElement, this._resourcesTreeOutline.children, this._boundCompareTreeElements);
499             this._resourcesTreeOutline.insertChild(this._anonymousScriptsFolderTreeElement, index);
500         }
501
502         this._anonymousScriptsFolderTreeElement.representedObject.add(representedObject);
503
504         let scriptTreeElement = new WI.ScriptTreeElement(representedObject);
505         this._anonymousScriptsFolderTreeElement.appendChild(scriptTreeElement);
506         return scriptTreeElement;
507     }
508
509     // Protected
510
511     createContentTreeOutline(options = {})
512     {
513         let treeOutline = super.createContentTreeOutline(options);
514
515         treeOutline.addEventListener(WI.TreeOutline.Event.ElementRevealed, (event) => {
516             let treeElement = event.data.element;
517             let detailsSections = [this._pauseReasonSection, this._callStackSection, this._breakpointsSection];
518             let detailsSection = detailsSections.find((detailsSection) => detailsSection.element.contains(treeElement.listItemElement));
519             if (!detailsSection)
520                 return;
521
522             // Revealing a TreeElement at the scroll container's topmost edge with
523             // scrollIntoViewIfNeeded may result in the element being covered by the
524             // DetailsSection header, which uses sticky positioning. Detect this case,
525             // and adjust the sidebar content's scroll position to compensate.
526             let offset = detailsSection.headerElement.totalOffsetBottom - treeElement.listItemElement.totalOffsetTop;
527             if (offset > 0)
528                 this.scrollElement.scrollBy(0, -offset);
529         });
530
531         return treeOutline;
532     }
533
534     resetFilter()
535     {
536         this._resourceTypeScopeBar.resetToDefault();
537
538         super.resetFilter();
539     }
540
541     hasCustomFilters()
542     {
543         console.assert(this._resourceTypeScopeBar.selectedItems.length === 1);
544         let selectedScopeBarItem = this._resourceTypeScopeBar.selectedItems[0];
545         return selectedScopeBarItem && selectedScopeBarItem !== this._resourceTypeScopeBar.defaultItem;
546     }
547
548     matchTreeElementAgainstCustomFilters(treeElement, flags)
549     {
550         // Only apply the resource type filter to the resources list.
551         if (treeElement.treeOutline !== this._resourcesTreeOutline)
552             return true;
553
554         console.assert(this._resourceTypeScopeBar.selectedItems.length === 1);
555         let selectedScopeBarItem = this._resourceTypeScopeBar.selectedItems[0];
556
557         // Show everything if there is no selection or "All Resources" is selected (the default item).
558         if (!selectedScopeBarItem || selectedScopeBarItem === this._resourceTypeScopeBar.defaultItem)
559             return true;
560
561         // Folders are hidden on the first pass, but visible childen under the folder will force the folder visible again.
562         if (treeElement instanceof WI.FolderTreeElement || treeElement instanceof WI.OriginTreeElement)
563             return false;
564
565         if (treeElement instanceof WI.IssueTreeElement)
566             treeElement = treeElement.parent;
567
568         function match()
569         {
570             if (treeElement instanceof WI.FrameTreeElement)
571                 return selectedScopeBarItem[WI.SourcesNavigationSidebarPanel.ResourceTypeSymbol] === WI.Resource.Type.Document;
572
573             if (treeElement instanceof WI.ScriptTreeElement)
574                 return selectedScopeBarItem[WI.SourcesNavigationSidebarPanel.ResourceTypeSymbol] === WI.Resource.Type.Script;
575
576             if (treeElement instanceof WI.CSSStyleSheetTreeElement)
577                 return selectedScopeBarItem[WI.SourcesNavigationSidebarPanel.ResourceTypeSymbol] === WI.Resource.Type.StyleSheet;
578
579             console.assert(treeElement instanceof WI.ResourceTreeElement, "Unknown treeElement", treeElement);
580             if (!(treeElement instanceof WI.ResourceTreeElement))
581                 return false;
582
583             return treeElement.resource.type === selectedScopeBarItem[WI.SourcesNavigationSidebarPanel.ResourceTypeSymbol];
584         }
585
586         let matched = match();
587         if (matched)
588             flags.expandTreeElement = true;
589         return matched;
590     }
591
592     // Popover delegate
593
594     willDismissPopover(popover)
595     {
596         let breakpoint = popover.breakpoint;
597         if (!breakpoint)
598             return;
599
600         if (breakpoint instanceof WI.EventBreakpoint)
601             WI.domDebuggerManager.addEventBreakpoint(breakpoint);
602         else if (breakpoint instanceof WI.URLBreakpoint)
603             WI.domDebuggerManager.addURLBreakpoint(breakpoint);
604     }
605
606     // Private
607
608     _filterByResourcesWithIssues(treeElement)
609     {
610         if (treeElement.treeOutline !== this._resourcesTreeOutline)
611             return true;
612
613         if (treeElement instanceof WI.IssueTreeElement)
614             return true;
615
616         if (treeElement.hasChildren) {
617             for (let child of treeElement.children) {
618                 if (child instanceof WI.IssueTreeElement)
619                     return true;
620             }
621         }
622         return false;
623     }
624
625     _compareTreeElements(a, b)
626     {
627         const rankFunctions = [
628             (treeElement) => treeElement instanceof WI.CSSStyleSheetTreeElement && treeElement.representedObject.isInspectorStyleSheet(),
629             (treeElement) => treeElement === this._mainFrameTreeElement,
630             (treeElement) => treeElement instanceof WI.FrameTreeElement,
631             (treeElement) => treeElement instanceof WI.OriginTreeElement,
632             (treeElement) => {
633                 return treeElement !== this._extensionScriptsFolderTreeElement
634                     && treeElement !== this._extraScriptsFolderTreeElement
635                     && treeElement !== this._anonymousScriptsFolderTreeElement;
636             },
637             (treeElement) => treeElement === this._extensionScriptsFolderTreeElement,
638             (treeElement) => treeElement === this._extraScriptsFolderTreeElement,
639             (treeElement) => treeElement === this._anonymousScriptsFolderTreeElement,
640         ];
641
642         let aRank = rankFunctions.findIndex((rankFunction) => rankFunction(a));
643         let bRank = rankFunctions.findIndex((rankFunction) => rankFunction(b));
644         if ((aRank >= 0 && bRank < 0) || aRank < bRank)
645             return -1;
646         if ((bRank >= 0 && aRank < 0) || bRank < aRank)
647             return 1;
648
649         return a.mainTitle.extendedLocaleCompare(b.mainTitle) || a.subtitle.extendedLocaleCompare(b.subtitle);
650     }
651
652     _updateMainFrameTreeElement(mainFrame)
653     {
654         if (this.didInitialLayout)
655             this.contentBrowser.contentViewContainer.closeAllContentViews();
656
657         let oldMainFrameTreeElement = this._mainFrameTreeElement;
658         if (this._mainFrameTreeElement) {
659             this._resourcesTreeOutline.removeChild(this._mainFrameTreeElement);
660             this._mainFrameTreeElement = null;
661         }
662
663         if (!mainFrame)
664             return;
665
666         switch (WI.settings.resourceGroupingMode.value) {
667         case WI.Resource.GroupingMode.Path: {
668             for (let treeElement of this._originTreeElementMap.values()) {
669                 if (treeElement !== oldMainFrameTreeElement)
670                     this._resourcesTreeOutline.removeChild(treeElement);
671             }
672             this._originTreeElementMap.clear();
673
674             let origin = mainFrame.urlComponents.origin;
675             this._mainFrameTreeElement = new WI.OriginTreeElement(origin, mainFrame, {hasChildren: true});
676             this._originTreeElementMap.set(origin, this._mainFrameTreeElement);
677             break;
678         }
679
680         default:
681             WI.reportInternalError("Unknown resource grouping mode", {"Resource Grouping Mode": WI.settings.resourceGroupingMode.value});
682             // Fallthrough for default value.
683
684         case WI.Resource.GroupingMode.Type:
685             this._mainFrameTreeElement = new WI.FrameTreeElement(mainFrame);
686             break;
687         }
688
689         this._resourcesTreeOutline.insertChild(this._mainFrameTreeElement, 0);
690
691         // Cookie restoration will attempt to re-select the resource we were showing.
692         // Give it time to do that before selecting the main frame resource.
693         setTimeout(() => {
694             if (this._resourcesTreeOutline.selectedTreeElement)
695                 return;
696
697             let currentContentView = this.contentBrowser.currentContentView;
698             let treeElement = currentContentView ? this.treeElementForRepresentedObject(currentContentView.representedObject) : null;
699             if (!treeElement)
700                 treeElement = this.treeElementForRepresentedObject(WI.networkManager.mainFrame);
701             this.showDefaultContentViewForTreeElement(treeElement);
702         });
703     }
704
705     _addTarget(target)
706     {
707         let treeElement = new WI.ThreadTreeElement(target);
708         this._callStackTreeOutline.appendChild(treeElement);
709
710         // FIXME: When WI.mainTarget changes?
711         if (target === WI.mainTarget)
712             this._mainTargetTreeElement = treeElement;
713
714         this._updateCallStackTreeOutline();
715     }
716
717     _findCallStackTargetTreeElement(target)
718     {
719         for (let child of this._callStackTreeOutline.children) {
720             if (child.target === target)
721                 return child;
722         }
723         return null;
724     }
725
726     _updateCallStackTreeOutline()
727     {
728         let singleThreadShowing = WI.targets.length <= 1;
729         this._callStackTreeOutline.element.classList.toggle("single-thread", singleThreadShowing);
730         if (this._mainTargetTreeElement)
731             this._mainTargetTreeElement.selectable = !singleThreadShowing;
732     }
733
734     _addResource(resource)
735     {
736         if (WI.settings.resourceGroupingMode.value === WI.Resource.GroupingMode.Path) {
737             if (!this._mainFrameTreeElement || this._resourcesTreeOutline.findTreeElement(resource))
738                 return;
739
740             let parentTreeElement = null;
741
742             if (resource instanceof WI.CSSStyleSheet && resource.isInspectorStyleSheet())
743                 parentTreeElement = this._resourcesTreeOutline.findTreeElement(resource.parentFrame.mainResource);
744
745             if (!parentTreeElement) {
746                 let origin = resource.urlComponents.origin;
747                 if (origin) {
748                     let originTreeElement = this._originTreeElementMap.get(origin);
749                     if (!originTreeElement) {
750                         originTreeElement = new WI.OriginTreeElement(origin, resource.parentFrame, {hasChildren: true});
751                         this._originTreeElementMap.set(origin, originTreeElement);
752
753                         let index = insertionIndexForObjectInListSortedByFunction(originTreeElement, this._resourcesTreeOutline.children, this._boundCompareTreeElements);
754                         this._resourcesTreeOutline.insertChild(originTreeElement, index);
755                     }
756
757                     let subpath = resource.urlComponents.path;
758                     if (subpath && subpath[0] === "/")
759                         subpath = subpath.substring(1);
760
761                     parentTreeElement = originTreeElement.createFoldersAsNeededForSubpath(subpath, this._boundCompareTreeElements);
762                 } else
763                     parentTreeElement = this._resourcesTreeOutline;
764             }
765
766             let resourceTreeElement = null;
767             if (resource instanceof WI.CSSStyleSheet)
768                 resourceTreeElement = new WI.CSSStyleSheetTreeElement(resource);
769             else
770                 resourceTreeElement = new WI.ResourceTreeElement(resource, resource, {allowDirectoryAsName: true, hideOrigin: true});
771
772             let index = insertionIndexForObjectInListSortedByFunction(resourceTreeElement, parentTreeElement.children, this._boundCompareTreeElements);
773             parentTreeElement.insertChild(resourceTreeElement, index);
774         }
775
776         if (resource.type === WI.Resource.Type.Document || resource.type === WI.Resource.Type.Script) {
777             this._addBreakpointsForSourceCode(resource);
778             this._addIssuesForSourceCode(resource);
779         }
780     }
781
782     _addResourcesRecursivelyForFrame(frame)
783     {
784         this._addResource(frame.mainResource);
785
786         for (let resource of frame.resourceCollection)
787             this._addResource(resource);
788
789         for (let childFrame of frame.childFrameCollection)
790             this._addResourcesRecursivelyForFrame(childFrame);
791
792         if (WI.settings.resourceGroupingMode.value === WI.Resource.GroupingMode.Path) {
793             for (let styleSheet of WI.cssManager.inspectorStyleSheetsForFrame(frame))
794                 this._addResource(styleSheet);
795         }
796     }
797
798     _addScript(script)
799     {
800         // We don't add scripts without URLs here. Those scripts can quickly clutter the interface and
801         // are usually more transient. They will get added if/when they need to be shown in a content view.
802         if (!script.url && !script.sourceURL)
803             return;
804
805         // Target main resource.
806         if (WI.sharedApp.debuggableType !== WI.DebuggableType.JavaScript) {
807             if (script.target !== WI.pageTarget) {
808                 if (script.isMainResource()) {
809                     this._addWorkerTargetWithMainResource(script.target);
810                     this._addBreakpointsForSourceCode(script);
811                     this._addIssuesForSourceCode(script);
812                 }
813                 this._resourcesTreeOutline.disclosureButtons = true;
814                 return;
815             }
816         }
817
818         // If the script URL matches a resource we can assume it is part of that resource and does not need added.
819         if (script.resource || script.dynamicallyAddedScriptElement)
820             return;
821
822         let scriptTreeElement = new WI.ScriptTreeElement(script);
823
824         if (!script.injected && WI.SourcesNavigationSidebarPanel.shouldPlaceResourcesAtTopLevel()) {
825             let index = insertionIndexForObjectInListSortedByFunction(scriptTreeElement, this._resourcesTreeOutline.children, this._boundCompareTreeElements);
826             this._resourcesTreeOutline.insertChild(scriptTreeElement, index);
827         } else {
828             let parentFolderTreeElement = null;
829
830             if (script.injected) {
831                 if (!this._extensionScriptsFolderTreeElement) {
832                     let collection = new WI.ScriptCollection;
833                     this._extensionScriptsFolderTreeElement = new WI.FolderTreeElement(WI.UIString("Extension Scripts"), collection);
834                 }
835
836                 parentFolderTreeElement = this._extensionScriptsFolderTreeElement;
837             } else {
838                 if (!this._extraScriptsFolderTreeElement) {
839                     let collection = new WI.ScriptCollection;
840                     this._extraScriptsFolderTreeElement = new WI.FolderTreeElement(WI.UIString("Extra Scripts"), collection);
841                 }
842
843                 parentFolderTreeElement = this._extraScriptsFolderTreeElement;
844             }
845
846             if (parentFolderTreeElement)
847                 parentFolderTreeElement.representedObject.add(script);
848
849             if (!parentFolderTreeElement.parent) {
850                 let index = insertionIndexForObjectInListSortedByFunction(parentFolderTreeElement, this._resourcesTreeOutline.children, this._boundCompareTreeElements);
851                 this._resourcesTreeOutline.insertChild(parentFolderTreeElement, index);
852             }
853
854             parentFolderTreeElement.appendChild(scriptTreeElement);
855         }
856
857         this._addBreakpointsForSourceCode(script);
858         this._addIssuesForSourceCode(script);
859     }
860
861     _addWorkerTargetWithMainResource(target)
862     {
863         console.assert(target.type === WI.Target.Type.Worker || target.type === WI.Target.Type.ServiceWorker);
864
865         let targetTreeElement = new WI.WorkerTreeElement(target);
866         this._workerTargetTreeElementMap.set(target, targetTreeElement);
867
868         let index = insertionIndexForObjectInListSortedByFunction(targetTreeElement, this._resourcesTreeOutline.children, this._boundCompareTreeElements);
869         this._resourcesTreeOutline.insertChild(targetTreeElement, index);
870     }
871
872     _addDebuggerTreeElementForSourceCode(sourceCode)
873     {
874         let treeElement = this._breakpointsTreeOutline.findTreeElement(sourceCode);
875         if (!treeElement) {
876             if (sourceCode instanceof WI.SourceMapResource)
877                 treeElement = new WI.SourceMapResourceTreeElement(sourceCode);
878             else if (sourceCode instanceof WI.Resource)
879                 treeElement = new WI.ResourceTreeElement(sourceCode);
880             else if (sourceCode instanceof WI.Script)
881                 treeElement = new WI.ScriptTreeElement(sourceCode);
882         }
883
884         if (!treeElement) {
885             console.error("Unknown sourceCode instance", sourceCode);
886             return null;
887         }
888
889         if (!treeElement.parent) {
890             treeElement.hasChildren = false;
891             treeElement.expand();
892
893             this._insertDebuggerTreeElement(treeElement, this._breakpointsTreeOutline);
894         }
895
896         return treeElement;
897     }
898
899     _insertDebuggerTreeElement(treeElement, parentTreeElement)
900     {
901         let comparator = (a, b) => {
902             const rankFunctions = [
903                 (treeElement) => treeElement.representedObject === WI.debuggerManager.allExceptionsBreakpoint,
904                 (treeElement) => treeElement.representedObject === WI.debuggerManager.uncaughtExceptionsBreakpoint,
905                 (treeElement) => treeElement.representedObject === WI.debuggerManager.assertionFailuresBreakpoint,
906                 (treeElement) => treeElement instanceof WI.BreakpointTreeElement || treeElement instanceof WI.ResourceTreeElement || treeElement instanceof WI.ScriptTreeElement,
907                 (treeElement) => treeElement.representedObject === WI.debuggerManager.allMicrotasksBreakpoint,
908                 (treeElement) => treeElement.representedObject === WI.domDebuggerManager.allAnimationFramesBreakpoint,
909                 (treeElement) => treeElement.representedObject === WI.domDebuggerManager.allTimeoutsBreakpoint,
910                 (treeElement) => treeElement.representedObject === WI.domDebuggerManager.allIntervalsBreakpoint,
911                 (treeElement) => treeElement.representedObject === WI.domDebuggerManager.allListenersBreakpoint,
912                 (treeElement) => treeElement instanceof WI.EventBreakpointTreeElement,
913                 (treeElement) => treeElement instanceof WI.DOMNodeTreeElement,
914                 (treeElement) => treeElement.representedObject === SourcesNavigationSidebarPanel.__windowEventTargetRepresentedObject,
915                 (treeElement) => treeElement instanceof WI.DOMBreakpointTreeElement,
916                 (treeElement) => treeElement.representedObject === WI.domDebuggerManager.allRequestsBreakpoint,
917                 (treeElement) => treeElement instanceof WI.URLBreakpointTreeElement,
918             ];
919
920             let aRank = rankFunctions.findIndex((rankFunction) => rankFunction(a));
921             let bRank = rankFunctions.findIndex((rankFunction) => rankFunction(b));
922             if (aRank >= 0 && bRank >= 0) {
923                 if (aRank < bRank)
924                     return -1;
925                 if (bRank < aRank)
926                     return 1;
927             }
928
929             if (a instanceof WI.BreakpointTreeElement && b instanceof WI.BreakpointTreeElement)
930                 return this._compareBreakpointTreeElements(a, b);
931
932             return a.mainTitle.extendedLocaleCompare(b.mainTitle) || a.subtitle.extendedLocaleCompare(b.subtitle);
933         };
934
935         parentTreeElement.insertChild(treeElement, insertionIndexForObjectInListSortedByFunction(treeElement, parentTreeElement.children, comparator));
936     }
937
938     _compareBreakpointTreeElements(a, b)
939     {
940         if (!a.representedObject || !b.representedObject)
941             return 0;
942
943         let aLocation = a.representedObject.sourceCodeLocation;
944         let bLocation = b.representedObject.sourceCodeLocation;
945         if (!aLocation || !bLocation)
946             return 0;
947
948         return aLocation.displayLineNumber - bLocation.displayLineNumber || aLocation.displayColumnNumber - bLocation.displayColumnNumber;
949     }
950
951     _addBreakpoint(breakpoint)
952     {
953         if (this._breakpointsTreeOutline.findTreeElement(breakpoint))
954             return null;
955
956         let constructor = WI.BreakpointTreeElement;
957         let options = {};
958         let parentTreeElement = this._breakpointsTreeOutline;
959
960         let getDOMNodeTreeElement = (domNode) => {
961             console.assert(domNode, "Missing DOMNode for identifier", breakpoint.domNodeIdentifier);
962             if (!domNode)
963                 return null;
964
965             let domNodeTreeElement = this._breakpointsTreeOutline.findTreeElement(domNode);
966             if (!domNodeTreeElement) {
967                 domNodeTreeElement = new WI.DOMNodeTreeElement(domNode);
968                 this._insertDebuggerTreeElement(domNodeTreeElement, this._breakpointsTreeOutline);
969             }
970             return domNodeTreeElement;
971         };
972
973         if (breakpoint === WI.debuggerManager.allExceptionsBreakpoint) {
974             options.className = "breakpoint-exception-icon";
975             options.title = WI.repeatedUIString.allExceptions();
976         } else if (breakpoint === WI.debuggerManager.uncaughtExceptionsBreakpoint) {
977             options.className = "breakpoint-exception-icon";
978             options.title = WI.repeatedUIString.uncaughtExceptions();
979         } else if (breakpoint === WI.debuggerManager.assertionFailuresBreakpoint) {
980             options.className = "breakpoint-assertion-icon";
981             options.title = WI.repeatedUIString.assertionFailures();
982         } else if (breakpoint === WI.debuggerManager.allMicrotasksBreakpoint) {
983             options.className = "breakpoint-microtask-icon";
984             options.title = WI.UIString("All Microtasks");
985         } else if (breakpoint instanceof WI.DOMBreakpoint) {
986             if (!breakpoint.domNodeIdentifier)
987                 return null;
988
989             constructor = WI.DOMBreakpointTreeElement;
990
991             let domNode = WI.domManager.nodeForId(breakpoint.domNodeIdentifier);
992             parentTreeElement = getDOMNodeTreeElement(domNode);
993         } else if (breakpoint instanceof WI.EventBreakpoint) {
994             constructor = WI.EventBreakpointTreeElement;
995
996             if (breakpoint === WI.domDebuggerManager.allAnimationFramesBreakpoint)
997                 options.title = WI.UIString("All Animation Frames");
998             else if (breakpoint === WI.domDebuggerManager.allIntervalsBreakpoint)
999                 options.title = WI.UIString("All Intervals");
1000             else if (breakpoint === WI.domDebuggerManager.allListenersBreakpoint)
1001                 options.title = WI.UIString("All Events");
1002             else if (breakpoint === WI.domDebuggerManager.allTimeoutsBreakpoint)
1003                 options.title = WI.UIString("All Timeouts");
1004             else if (breakpoint.eventListener) {
1005                 let eventTargetTreeElement = null;
1006                 if (breakpoint.eventListener.onWindow) {
1007                     if (!SourcesNavigationSidebarPanel.__windowEventTargetRepresentedObject)
1008                         SourcesNavigationSidebarPanel.__windowEventTargetRepresentedObject = {__window: true};
1009
1010                     eventTargetTreeElement = this._breakpointsTreeOutline.findTreeElement(SourcesNavigationSidebarPanel.__windowEventTargetRepresentedObject);
1011                     if (!eventTargetTreeElement) {
1012                         const subtitle = null;
1013                         eventTargetTreeElement = new WI.GeneralTreeElement(["event-target-window"], WI.unlocalizedString("window"), subtitle, SourcesNavigationSidebarPanel.__windowEventTargetRepresentedObject);
1014                         this._insertDebuggerTreeElement(eventTargetTreeElement, this._breakpointsTreeOutline);
1015                     }
1016                 } else if (breakpoint.eventListener.node)
1017                     eventTargetTreeElement = getDOMNodeTreeElement(breakpoint.eventListener.node);
1018                 if (eventTargetTreeElement)
1019                     parentTreeElement = eventTargetTreeElement;
1020             }
1021         } else if (breakpoint instanceof WI.URLBreakpoint) {
1022             constructor = WI.URLBreakpointTreeElement;
1023
1024             if (breakpoint === WI.domDebuggerManager.allRequestsBreakpoint)
1025                 options.title = WI.repeatedUIString.allRequests();
1026         } else {
1027             let sourceCode = breakpoint.sourceCodeLocation && breakpoint.sourceCodeLocation.displaySourceCode;
1028             if (!sourceCode)
1029                 return null;
1030
1031             parentTreeElement = this._addDebuggerTreeElementForSourceCode(sourceCode);
1032
1033             // Mark disabled breakpoints as resolved if there is source code loaded with that URL.
1034             // This gives the illusion the breakpoint was resolved, but since we don't send disabled
1035             // breakpoints to the backend we don't know for sure. If the user enables the breakpoint
1036             // it will be resolved properly.
1037             if (breakpoint.disabled)
1038                 breakpoint.resolved = true;
1039         }
1040
1041         let breakpointTreeElement = new constructor(breakpoint, options);
1042         this._insertDebuggerTreeElement(breakpointTreeElement, parentTreeElement);
1043         if (parentTreeElement.children.length === 1)
1044             parentTreeElement.expand();
1045         return breakpointTreeElement;
1046     }
1047
1048     _removeBreakpoint(breakpoint)
1049     {
1050         if (this._pauseReasonTreeOutline) {
1051             let pauseReasonBreakpointTreeElement = this._pauseReasonTreeOutline.findTreeElement(breakpoint);
1052             if (pauseReasonBreakpointTreeElement)
1053                 pauseReasonBreakpointTreeElement.status = null;
1054         }
1055
1056         let breakpointTreeElement = this._breakpointsTreeOutline.findTreeElement(breakpoint);
1057         if (!breakpointTreeElement)
1058             return;
1059
1060         this._removeDebuggerTreeElement(breakpointTreeElement);
1061     }
1062
1063     _removeAllBreakpoints(breakpoints)
1064     {
1065         for (let breakpoint of breakpoints) {
1066             if (WI.debuggerManager.isBreakpointRemovable(breakpoint))
1067                 WI.debuggerManager.removeBreakpoint(breakpoint);
1068         }
1069     }
1070
1071     _toggleAllBreakpoints(breakpoints, disabled)
1072     {
1073         for (let breakpoint of breakpoints)
1074             breakpoint.disabled = disabled;
1075     }
1076
1077     _breakpointsBeneathTreeElement(treeElement)
1078     {
1079         console.assert(treeElement instanceof WI.ResourceTreeElement || treeElement instanceof WI.ScriptTreeElement);
1080         if (!(treeElement instanceof WI.ResourceTreeElement) && !(treeElement instanceof WI.ScriptTreeElement))
1081             return [];
1082
1083         let breakpoints = [];
1084         for (let child of treeElement.children) {
1085             console.assert(child instanceof WI.BreakpointTreeElement);
1086             let breakpoint = child.breakpoint;
1087             console.assert(breakpoint);
1088             if (breakpoint)
1089                 breakpoints.push(breakpoint);
1090         }
1091         return breakpoints;
1092     }
1093
1094     _addIssue(issueMessage, sourceCode)
1095     {
1096         let issueTreeElement = this._resourcesTreeOutline.findTreeElement(issueMessage);
1097         if (!issueTreeElement) {
1098             console.assert(sourceCode || (issueMessage.sourceCodeLocation && issueMessage.sourceCodeLocation.sourceCode));
1099             let parentTreeElement = this._resourcesTreeOutline.findTreeElement(sourceCode || issueMessage.sourceCodeLocation.sourceCode);
1100             if (!parentTreeElement)
1101                 return null;
1102
1103             issueTreeElement = new WI.IssueTreeElement(issueMessage);
1104
1105             parentTreeElement.insertChild(issueTreeElement, insertionIndexForObjectInListSortedByFunction(issueTreeElement, parentTreeElement.children, this._compareBreakpointTreeElements));
1106             if (parentTreeElement.children.length === 1)
1107                 parentTreeElement.expand();
1108         }
1109         return issueTreeElement;
1110     }
1111
1112     _removeDebuggerTreeElement(debuggerTreeElement)
1113     {
1114         // If this is a BreakpointTreeElement being deleted because of a cause
1115         // outside of the TreeOutline then deselect if it is selected to avoid
1116         // TreeOutline selection changes causing unexpected ContentView changes.
1117         if (!debuggerTreeElement.__deletedViaDeleteKeyboardShortcut)
1118             debuggerTreeElement.deselect();
1119
1120         let parentTreeElement = debuggerTreeElement.parent;
1121         parentTreeElement.removeChild(debuggerTreeElement);
1122
1123         if (parentTreeElement.children.length || parentTreeElement === this._breakpointsTreeOutline)
1124             return;
1125
1126         parentTreeElement.treeOutline.removeChild(parentTreeElement);
1127     }
1128
1129     _addBreakpointsForSourceCode(sourceCode)
1130     {
1131         for (let breakpoint of WI.debuggerManager.breakpointsForSourceCode(sourceCode))
1132             this._addBreakpoint(breakpoint);
1133     }
1134
1135     _addIssuesForSourceCode(sourceCode)
1136     {
1137         for (let issue of WI.consoleManager.issuesForSourceCode(sourceCode))
1138             this._addIssue(issue, sourceCode);
1139     }
1140
1141     _updateTemporarilyDisabledBreakpointsButtons()
1142     {
1143         let breakpointsDisabledTemporarily = WI.debuggerManager.breakpointsDisabledTemporarily;
1144         this._debuggerBreakpointsButtonItem.enabled = !breakpointsDisabledTemporarily;
1145         this._debuggerPauseResumeButtonItem.enabled = !breakpointsDisabledTemporarily;
1146     }
1147
1148     _updateBreakpointsDisabledBanner()
1149     {
1150         if (!WI.debuggerManager.breakpointsEnabled && !this._timelineRecordingWarningElement && !this._auditTestWarningElement) {
1151             if (!this._breakpointsDisabledWarningElement) {
1152                 let enableBreakpointsButton = document.createElement("button");
1153                 enableBreakpointsButton.textContent = WI.UIString("Enable Breakpoints");
1154                 enableBreakpointsButton.addEventListener("click", () => {
1155                     WI.debuggerToggleBreakpoints();
1156                 });
1157
1158                 this._breakpointsDisabledWarningElement = document.createElement("div");
1159                 this._breakpointsDisabledWarningElement.classList.add("warning-banner");
1160                 this._breakpointsDisabledWarningElement.append(WI.UIString("Breakpoints disabled"), document.createElement("br"), enableBreakpointsButton);
1161             }
1162
1163             this.contentView.element.insertBefore(this._breakpointsDisabledWarningElement, this.contentView.element.firstChild);
1164         } else if (this._breakpointsDisabledWarningElement) {
1165             this._breakpointsDisabledWarningElement.remove();
1166             this._breakpointsDisabledWarningElement = null;
1167         }
1168     }
1169
1170     _updatePauseReason()
1171     {
1172         this._pauseReasonTreeOutline = null;
1173
1174         this._updatePauseReasonGotoArrow();
1175         return this._updatePauseReasonSection();
1176     }
1177
1178     _updatePauseReasonGotoArrow()
1179     {
1180         this._pauseReasonLinkContainerElement.removeChildren();
1181
1182         let activeCallFrame = WI.debuggerManager.activeCallFrame;
1183         if (!activeCallFrame)
1184             return;
1185
1186         let sourceCodeLocation = activeCallFrame.sourceCodeLocation;
1187         if (!sourceCodeLocation)
1188             return;
1189
1190         const options = {
1191             useGoToArrowButton: true,
1192         };
1193         let linkElement = WI.createSourceCodeLocationLink(sourceCodeLocation, options);
1194         this._pauseReasonLinkContainerElement.appendChild(linkElement);
1195     }
1196
1197     _updatePauseReasonSection()
1198     {
1199         let target = WI.debuggerManager.activeCallFrame.target;
1200         let targetData = WI.debuggerManager.dataForTarget(target);
1201         let {pauseReason, pauseData} = targetData;
1202
1203         switch (pauseReason) {
1204         case WI.DebuggerManager.PauseReason.AnimationFrame: {
1205             this._pauseReasonTreeOutline = this.createContentTreeOutline({suppressFiltering: true});
1206
1207             let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(WI.domDebuggerManager.allAnimationFramesBreakpoint, {
1208                 className: "breakpoint-paused-icon",
1209                 title: WI.UIString("requestAnimationFrame Fired"),
1210             });
1211             this._pauseReasonTreeOutline.appendChild(eventBreakpointTreeElement);
1212
1213             let eventBreakpointRow = new WI.DetailsSectionRow;
1214             eventBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1215
1216             this._pauseReasonGroup.rows = [eventBreakpointRow];
1217             return true;
1218         }
1219
1220         case WI.DebuggerManager.PauseReason.Assertion:
1221             // FIXME: We should include the assertion condition string.
1222             console.assert(pauseData, "Expected data with an assertion, but found none.");
1223             if (pauseData && pauseData.message)
1224                 this._pauseReasonTextRow.text = WI.UIString("Assertion with message: %s").format(pauseData.message);
1225             else
1226                 this._pauseReasonTextRow.text = WI.UIString("Assertion Failed");
1227             this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1228             return true;
1229
1230         case WI.DebuggerManager.PauseReason.Breakpoint: {
1231             console.assert(pauseData, "Expected breakpoint identifier, but found none.");
1232             if (!pauseData || !pauseData.breakpointId)
1233                 break;
1234
1235             this._pauseReasonTreeOutline = this.createContentTreeOutline({suppressFiltering: true});
1236             this._pauseReasonTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._handleTreeSelectionDidChange, this);
1237
1238             let breakpoint = WI.debuggerManager.breakpointForIdentifier(pauseData.breakpointId);
1239             let breakpointTreeElement = new WI.BreakpointTreeElement(breakpoint, {
1240                 className: "breakpoint-paused-icon",
1241                 title: WI.UIString("Triggered Breakpoint"),
1242             });
1243             let breakpointDetailsSection = new WI.DetailsSectionRow;
1244             this._pauseReasonTreeOutline.appendChild(breakpointTreeElement);
1245             breakpointDetailsSection.element.appendChild(this._pauseReasonTreeOutline.element);
1246
1247             this._pauseReasonGroup.rows = [breakpointDetailsSection];
1248             return true;
1249         }
1250
1251         case WI.DebuggerManager.PauseReason.CSPViolation:
1252             console.assert(pauseData, "Expected data with a CSP Violation, but found none.");
1253             if (!pauseData)
1254                 break;
1255
1256             // COMPATIBILITY (iOS 8): 'directive' was 'directiveText'.
1257             this._pauseReasonTextRow.text = WI.UIString("Content Security Policy violation of directive: %s").format(pauseData.directive || pauseData.directiveText);
1258             this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1259             return true;
1260
1261         case WI.DebuggerManager.PauseReason.DebuggerStatement:
1262             this._pauseReasonTextRow.text = WI.UIString("Debugger Statement");
1263             this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1264             return true;
1265
1266         case WI.DebuggerManager.PauseReason.DOM: {
1267             console.assert(WI.domDebuggerManager.supported);
1268             console.assert(pauseData, "Expected DOM breakpoint data, but found none.");
1269             if (!pauseData || !pauseData.nodeId)
1270                 break;
1271
1272             let domNode = WI.domManager.nodeForId(pauseData.nodeId);
1273             let domBreakpoints = WI.domDebuggerManager.domBreakpointsForNode(domNode);
1274             let domBreakpoint;
1275             for (let breakpoint of domBreakpoints) {
1276                 if (breakpoint.type === pauseData.type) {
1277                     domBreakpoint = breakpoint;
1278                     break;
1279                 }
1280             }
1281
1282             console.assert(domBreakpoint, "Missing DOM breakpoint of type for node", pauseData.type, domNode);
1283             if (!domBreakpoint)
1284                 break;
1285
1286             this._pauseReasonTreeOutline = this.createContentTreeOutline({suppressFiltering: true});
1287
1288             let type = WI.DOMBreakpointTreeElement.displayNameForType(domBreakpoint.type);
1289             let domBreakpointTreeElement = new WI.DOMBreakpointTreeElement(domBreakpoint, {
1290                 className: "breakpoint-paused-icon",
1291                 title: type,
1292             });
1293             let domBreakpointRow = new WI.DetailsSectionRow;
1294             this._pauseReasonTreeOutline.appendChild(domBreakpointTreeElement);
1295             domBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1296
1297             let ownerElementRow = new WI.DetailsSectionSimpleRow(WI.UIString("Element"), WI.linkifyNodeReference(domNode));
1298             this._pauseReasonGroup.rows = [domBreakpointRow, ownerElementRow];
1299
1300             if (domBreakpoint.type !== WI.DOMBreakpoint.Type.SubtreeModified)
1301                 return true;
1302
1303             console.assert(pauseData.targetNode);
1304
1305             let remoteObject = WI.RemoteObject.fromPayload(pauseData.targetNode, target);
1306             remoteObject.pushNodeToFrontend((nodeId) => {
1307                 if (!nodeId)
1308                     return;
1309
1310                 let node = WI.domManager.nodeForId(nodeId);
1311                 console.assert(node, "Missing node for id.", nodeId);
1312                 if (!node)
1313                     return;
1314
1315                 let fragment = document.createDocumentFragment();
1316                 let description = pauseData.insertion ? WI.UIString("Child added to ") : WI.UIString("Removed descendant ");
1317                 fragment.append(description, WI.linkifyNodeReference(node));
1318
1319                 let targetDescriptionRow = new WI.DetailsSectionSimpleRow(WI.UIString("Details"), fragment);
1320                 targetDescriptionRow.element.classList.add("target-description");
1321
1322                 this._pauseReasonGroup.rows = this._pauseReasonGroup.rows.concat(targetDescriptionRow);
1323             });
1324
1325             return true;
1326         }
1327
1328         case WI.DebuggerManager.PauseReason.Listener:
1329         case WI.DebuggerManager.PauseReason.EventListener: {
1330             console.assert(pauseData, "Expected data with an event listener, but found none.");
1331             if (!pauseData)
1332                 break;
1333
1334             let eventBreakpoint = null;
1335             if (pauseData.eventListenerId)
1336                 eventBreakpoint = WI.domManager.breakpointForEventListenerId(pauseData.eventListenerId);
1337             if (!eventBreakpoint)
1338                 eventBreakpoint = WI.domDebuggerManager.listenerBreakpointForEventName(pauseData.eventName);
1339
1340             console.assert(eventBreakpoint, "Expected Event Listener breakpoint for event name.", pauseData.eventName);
1341             if (!eventBreakpoint)
1342                 break;
1343
1344             this._pauseReasonTreeOutline = this.createContentTreeOutline({suppressFiltering: true});
1345
1346             let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(eventBreakpoint, {
1347                 className: "breakpoint-paused-icon",
1348                 title: WI.UIString("\u201C%s\u201D Event Fired").format(pauseData.eventName),
1349             });
1350             this._pauseReasonTreeOutline.appendChild(eventBreakpointTreeElement);
1351
1352             let eventBreakpointRow = new WI.DetailsSectionRow;
1353             eventBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1354
1355             let rows = [eventBreakpointRow];
1356
1357             let eventListener = eventBreakpoint.eventListener;
1358             if (eventListener) {
1359                 console.assert(eventListener.eventListenerId === pauseData.eventListenerId);
1360
1361                 let value = null;
1362                 if (eventListener.onWindow)
1363                     value = WI.unlocalizedString("window");
1364                 else if (eventListener.node)
1365                     value = WI.linkifyNodeReference(eventListener.node);
1366                 if (value)
1367                     rows.push(new WI.DetailsSectionSimpleRow(WI.UIString("Target"), value));
1368             }
1369
1370             this._pauseReasonGroup.rows = rows;
1371             return true;
1372         }
1373
1374         case WI.DebuggerManager.PauseReason.Exception: {
1375             console.assert(pauseData, "Expected data with an exception, but found none.");
1376             if (!pauseData)
1377                 break;
1378
1379             // FIXME: We should improve the appearance of thrown objects. This works well for exception strings.
1380             let data = WI.RemoteObject.fromPayload(pauseData, target);
1381             this._pauseReasonTextRow.text = WI.UIString("Exception with thrown value: %s").format(data.description);
1382             this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1383             return true;
1384         }
1385
1386         case WI.DebuggerManager.PauseReason.Interval: {
1387             this._pauseReasonTreeOutline = this.createContentTreeOutline({suppressFiltering: true});
1388
1389             let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(WI.domDebuggerManager.allIntervalsBreakpoint, {
1390                 className: "breakpoint-paused-icon",
1391                 title: WI.UIString("setInterval Fired"),
1392             });
1393             this._pauseReasonTreeOutline.appendChild(eventBreakpointTreeElement);
1394
1395             let eventBreakpointRow = new WI.DetailsSectionRow;
1396             eventBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1397
1398             this._pauseReasonGroup.rows = [eventBreakpointRow];
1399             return true;
1400         }
1401
1402         case WI.DebuggerManager.PauseReason.Microtask:
1403             this._pauseReasonTextRow.text = WI.UIString("Microtask Fired");
1404             this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1405             return true;
1406
1407         case WI.DebuggerManager.PauseReason.PauseOnNextStatement:
1408             this._pauseReasonTextRow.text = WI.UIString("Immediate Pause Requested");
1409             this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1410             return true;
1411
1412         case WI.DebuggerManager.PauseReason.Timer: {
1413             console.assert(pauseData, "Expected data with a timer, but found none.");
1414             if (!pauseData)
1415                 break;
1416
1417             let eventBreakpoint = null;
1418             switch (pauseData.eventName) {
1419             case "setTimeout":
1420                 eventBreakpoint = WI.domDebuggerManager.allTimeoutsBreakpoint;
1421                 break;
1422
1423             case "setInterval":
1424                 eventBreakpoint = WI.domDebuggerManager.allIntervalsBreakpoint;
1425                 break;
1426             }
1427             console.assert(eventBreakpoint, "Expected Timer breakpoint for event name.", pauseData.eventName);
1428             if (!eventBreakpoint)
1429                 break;
1430
1431             this._pauseReasonTreeOutline = this.createContentTreeOutline({suppressFiltering: true});
1432
1433             let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(eventBreakpoint, {
1434                 className: "breakpoint-paused-icon",
1435                 title: WI.UIString("%s Fired").format(pauseData.eventName),
1436             });
1437             this._pauseReasonTreeOutline.appendChild(eventBreakpointTreeElement);
1438
1439             let eventBreakpointRow = new WI.DetailsSectionRow;
1440             eventBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1441
1442             this._pauseReasonGroup.rows = [eventBreakpointRow];
1443             return true;
1444         }
1445
1446         case WI.DebuggerManager.PauseReason.Timeout: {
1447             this._pauseReasonTreeOutline = this.createContentTreeOutline({suppressFiltering: true});
1448
1449             let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(WI.domDebuggerManager.allTimeoutsBreakpoint, {
1450                 className: "breakpoint-paused-icon",
1451                 title: WI.UIString("setTimeout Fired"),
1452             });
1453             this._pauseReasonTreeOutline.appendChild(eventBreakpointTreeElement);
1454
1455             let eventBreakpointRow = new WI.DetailsSectionRow;
1456             eventBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1457
1458             this._pauseReasonGroup.rows = [eventBreakpointRow];
1459             return true;
1460         }
1461
1462         case WI.DebuggerManager.PauseReason.Fetch:
1463         case WI.DebuggerManager.PauseReason.XHR: {
1464             console.assert(WI.domDebuggerManager.supported);
1465             console.assert(pauseData, "Expected URL breakpoint data, but found none.");
1466             if (!pauseData)
1467                 break;
1468
1469             if (pauseData.breakpointURL) {
1470                 let urlBreakpoint = WI.domDebuggerManager.urlBreakpointForURL(pauseData.breakpointURL);
1471                 console.assert(urlBreakpoint, "Expected URL breakpoint for URL.", pauseData.breakpointURL);
1472
1473                 this._pauseReasonTreeOutline = this.createContentTreeOutline({suppressFiltering: true});
1474
1475                 let urlBreakpointTreeElement = new WI.URLBreakpointTreeElement(urlBreakpoint, {
1476                     className: "breakpoint-paused-icon",
1477                     title: WI.UIString("Triggered URL Breakpoint"),
1478                 });
1479                 let urlBreakpointRow = new WI.DetailsSectionRow;
1480                 this._pauseReasonTreeOutline.appendChild(urlBreakpointTreeElement);
1481                 urlBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1482
1483                 this._pauseReasonTextRow.text = pauseData.url;
1484                 this._pauseReasonGroup.rows = [urlBreakpointRow, this._pauseReasonTextRow];
1485             } else {
1486                 console.assert(pauseData.breakpointURL === "", "Should be the All Requests breakpoint which has an empty URL");
1487                 this._pauseReasonTextRow.text = WI.UIString("Requesting: %s").format(pauseData.url);
1488                 this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1489             }
1490             this._pauseReasonTextRow.element.title = pauseData.url;
1491             return true;
1492         }
1493
1494         case WI.DebuggerManager.PauseReason.Other:
1495             console.error("Paused for unknown reason. We should always have a reason.");
1496             break;
1497         }
1498
1499         return false;
1500     }
1501
1502     _handleResourceGroupingModeScopeBarSelectionChanged(event)
1503     {
1504         console.assert(this._resourceGroupingModeScopeBar.selectedItems.length === 1);
1505         let selectedScopeBarItem = this._resourceGroupingModeScopeBar.selectedItems[0];
1506         WI.settings.resourceGroupingMode.value = selectedScopeBarItem[SourcesNavigationSidebarPanel.ResourceGroupingModeSymbol] || WI.Resource.GroupingMode.Type;
1507     }
1508
1509     _handleResourceTypeScopeBarSelectionChanged(event)
1510     {
1511         this.updateFilter();
1512     }
1513
1514     _handleTreeSelectionDidChange(event)
1515     {
1516         if (!this.selected)
1517             return;
1518
1519         let treeElement = event.target.selectedTreeElement;
1520         if (!treeElement)
1521             return;
1522
1523         if (treeElement instanceof WI.DOMNodeTreeElement
1524             || treeElement instanceof WI.DOMBreakpointTreeElement
1525             || treeElement instanceof WI.EventBreakpointTreeElement
1526             || treeElement instanceof WI.URLBreakpointTreeElement)
1527             return;
1528
1529         if (treeElement.representedObject === SourcesNavigationSidebarPanel.__windowEventTargetRepresentedObject)
1530             return;
1531
1532         if (treeElement instanceof WI.FolderTreeElement
1533             || treeElement instanceof WI.OriginTreeElement
1534             || treeElement instanceof WI.ResourceTreeElement
1535             || treeElement instanceof WI.ScriptTreeElement
1536             || treeElement instanceof WI.CSSStyleSheetTreeElement) {
1537             let representedObject = treeElement.representedObject;
1538             if (representedObject instanceof WI.Collection || representedObject instanceof WI.SourceCode || representedObject instanceof WI.Frame)
1539                 WI.showRepresentedObject(representedObject);
1540             return;
1541         }
1542
1543         if (treeElement instanceof WI.CallFrameTreeElement) {
1544             let callFrame = treeElement.callFrame;
1545             if (callFrame.id)
1546                 WI.debuggerManager.activeCallFrame = callFrame;
1547             if (callFrame.sourceCodeLocation)
1548                 WI.showSourceCodeLocation(callFrame.sourceCodeLocation);
1549             return;
1550         }
1551
1552         if (treeElement instanceof WI.IssueTreeElement) {
1553             WI.showSourceCodeLocation(treeElement.issueMessage.sourceCodeLocation);
1554             return;
1555         }
1556
1557         if (treeElement instanceof WI.BreakpointTreeElement) {
1558             let breakpoint = treeElement.breakpoint;
1559             if (WI.debuggerManager.isBreakpointSpecial(breakpoint))
1560                 return;
1561
1562             if (treeElement.treeOutline === this._pauseReasonTreeOutline) {
1563                 WI.showSourceCodeLocation(breakpoint.sourceCodeLocation);
1564                 return;
1565             }
1566
1567             if (treeElement.parent.representedObject) {
1568                 console.assert(treeElement.parent.representedObject instanceof WI.SourceCode);
1569                 if (treeElement.parent.representedObject instanceof WI.SourceCode) {
1570                     WI.showSourceCodeLocation(breakpoint.sourceCodeLocation);
1571                     return;
1572                 }
1573             }
1574         }
1575
1576         console.error("Unknown tree element", treeElement);
1577     }
1578
1579     _handleBreakpointElementAddedOrRemoved(event)
1580     {
1581         let treeElement = event.data.element;
1582
1583         let setting = null;
1584         switch (treeElement.representedObject) {
1585         case WI.debuggerManager.assertionFailuresBreakpoint:
1586             setting = WI.settings.showAssertionFailuresBreakpoint;
1587             break;
1588
1589         case WI.debuggerManager.allMicrotasksBreakpoint:
1590             setting = WI.settings.showAllMicrotasksBreakpoint;
1591             break;
1592
1593         case WI.domDebuggerManager.allAnimationFramesBreakpoint:
1594             setting = WI.settings.showAllAnimationFramesBreakpoint;
1595             break;
1596
1597         case WI.domDebuggerManager.allIntervalsBreakpoint:
1598             setting = WI.settings.showAllIntervalsBreakpoint;
1599             break;
1600
1601         case WI.domDebuggerManager.allListenersBreakpoint:
1602             setting = WI.settings.showAllListenersBreakpoint;
1603             break;
1604
1605         case WI.domDebuggerManager.allRequestsBreakpoint:
1606             setting = WI.settings.showAllRequestsBreakpoint;
1607             break;
1608
1609         case WI.domDebuggerManager.allTimeoutsBreakpoint:
1610             setting = WI.settings.showAllTimeoutsBreakpoint;
1611             break;
1612         }
1613
1614         if (setting)
1615             setting.value = !!treeElement.parent;
1616
1617         if (event.type === WI.TreeOutline.Event.ElementRemoved) {
1618             let selectedTreeElement = this._breakpointsTreeOutline.selectedTreeElement;
1619             console.assert(selectedTreeElement);
1620             if (selectedTreeElement.representedObject === WI.debuggerManager.assertionFailuresBreakpoint || !WI.debuggerManager.isBreakpointRemovable(selectedTreeElement.representedObject)) {
1621                 const skipUnrevealed = true;
1622                 const dontPopulate = true;
1623                 let treeElementToSelect = selectedTreeElement.traverseNextTreeElement(skipUnrevealed, dontPopulate);
1624                 if (treeElementToSelect) {
1625                     const omitFocus = true;
1626                     const selectedByUser = true;
1627                     treeElementToSelect.select(omitFocus, selectedByUser);
1628                 }
1629             }
1630         }
1631     }
1632
1633     _populateCreateBreakpointContextMenu(contextMenu)
1634     {
1635         // COMPATIBILITY (iOS 10): DebuggerAgent.setPauseOnAssertions did not exist yet.
1636         if (InspectorBackend.domains.Debugger.setPauseOnAssertions) {
1637             let assertionFailuresBreakpointShown = WI.settings.showAssertionFailuresBreakpoint.value;
1638
1639             contextMenu.appendCheckboxItem(WI.repeatedUIString.assertionFailures(), () => {
1640                 if (assertionFailuresBreakpointShown)
1641                     WI.debuggerManager.removeBreakpoint(WI.debuggerManager.assertionFailuresBreakpoint);
1642                 else {
1643                     WI.debuggerManager.assertionFailuresBreakpoint.disabled = false;
1644                     WI.debuggerManager.addBreakpoint(WI.debuggerManager.assertionFailuresBreakpoint);
1645                 }
1646             }, assertionFailuresBreakpointShown);
1647         }
1648
1649         contextMenu.appendSeparator();
1650
1651         // COMPATIBILITY (iOS 13): DebuggerAgent.setPauseOnMicrotasks did not exist yet.
1652         if (InspectorBackend.domains.Debugger.setPauseOnMicrotasks) {
1653             let allMicrotasksBreakpointShown = WI.settings.showAllMicrotasksBreakpoint.value;
1654
1655             contextMenu.appendCheckboxItem(WI.UIString("All Microtasks"), () => {
1656                 if (allMicrotasksBreakpointShown)
1657                     WI.debuggerManager.removeBreakpoint(WI.debuggerManager.allMicrotasksBreakpoint);
1658                 else {
1659                     WI.debuggerManager.allMicrotasksBreakpoint.disabled = false;
1660                     WI.debuggerManager.addBreakpoint(WI.debuggerManager.allMicrotasksBreakpoint);
1661                 }
1662             }, allMicrotasksBreakpointShown);
1663         }
1664
1665         if (WI.DOMDebuggerManager.supportsEventBreakpoints() || WI.DOMDebuggerManager.supportsEventListenerBreakpoints()) {
1666             function addToggleForSpecialEventBreakpoint(breakpoint, label, checked) {
1667                 contextMenu.appendCheckboxItem(label, () => {
1668                     if (checked)
1669                         WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
1670                     else {
1671                         breakpoint.disabled = false;
1672                         WI.domDebuggerManager.addEventBreakpoint(breakpoint);
1673                     }
1674                 }, checked);
1675             }
1676
1677             addToggleForSpecialEventBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint, WI.UIString("All Animation Frames"), WI.settings.showAllAnimationFramesBreakpoint.value);
1678             addToggleForSpecialEventBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint, WI.UIString("All Timeouts"), WI.settings.showAllTimeoutsBreakpoint.value);
1679             addToggleForSpecialEventBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint, WI.UIString("All Intervals"), WI.settings.showAllIntervalsBreakpoint.value);
1680
1681             contextMenu.appendSeparator();
1682
1683             if (WI.DOMDebuggerManager.supportsAllListenersBreakpoint())
1684                 addToggleForSpecialEventBreakpoint(WI.domDebuggerManager.allListenersBreakpoint, WI.UIString("All Events"), WI.settings.showAllListenersBreakpoint.value);
1685
1686             contextMenu.appendItem(WI.UIString("Event Breakpoint\u2026"), () => {
1687                 let popover = new WI.EventBreakpointPopover(this);
1688                 popover.show(this._createBreakpointButton.element, [WI.RectEdge.MAX_Y, WI.RectEdge.MIN_Y, WI.RectEdge.MAX_X]);
1689             });
1690         }
1691
1692         if (WI.DOMDebuggerManager.supportsURLBreakpoints() || WI.DOMDebuggerManager.supportsXHRBreakpoints()) {
1693             contextMenu.appendSeparator();
1694
1695             let allRequestsBreakpointShown = WI.settings.showAllRequestsBreakpoint.value;
1696             contextMenu.appendCheckboxItem(WI.repeatedUIString.allRequests(), () => {
1697                 if (allRequestsBreakpointShown)
1698                     WI.domDebuggerManager.removeURLBreakpoint(WI.domDebuggerManager.allRequestsBreakpoint);
1699                 else {
1700                     WI.domDebuggerManager.allRequestsBreakpoint.disabled = false;
1701                     WI.domDebuggerManager.addURLBreakpoint(WI.domDebuggerManager.allRequestsBreakpoint);
1702                 }
1703             }, allRequestsBreakpointShown);
1704
1705             contextMenu.appendItem(WI.DOMDebuggerManager.supportsURLBreakpoints() ? WI.UIString("URL Breakpoint\u2026") : WI.UIString("XHR Breakpoint\u2026"), () => {
1706                 let popover = new WI.URLBreakpointPopover(this);
1707                 popover.show(this._createBreakpointButton.element, [WI.RectEdge.MAX_Y, WI.RectEdge.MIN_Y, WI.RectEdge.MAX_X]);
1708             });
1709         }
1710     }
1711
1712     _populateCreateResourceContextMenu(contextMenu)
1713     {
1714         if (InspectorBackend.domains.CSS) {
1715             let addInspectorStyleSheetItem = (menu, frame) => {
1716                 menu.appendItem(WI.UIString("Inspector Style Sheet"), () => {
1717                     if (WI.settings.resourceGroupingMode.value === WI.Resource.GroupingMode.Path) {
1718                         // Force the parent to populate.
1719                         let parentFrameTreeElement = this._resourcesTreeOutline.findTreeElement(frame.mainResource);
1720                         parentFrameTreeElement.reveal();
1721                         parentFrameTreeElement.expand();
1722                     }
1723
1724                     WI.cssManager.preferredInspectorStyleSheetForFrame(frame, (styleSheet) => {
1725                         WI.showRepresentedObject(styleSheet);
1726                     });
1727                 });
1728             };
1729
1730             addInspectorStyleSheetItem(contextMenu, WI.networkManager.mainFrame);
1731
1732             let frames = WI.networkManager.frames;
1733             if (frames.length > 2) {
1734                 let framesSubMenu = contextMenu.appendSubMenuItem(WI.UIString("Frames"));
1735
1736                 for (let frame of frames) {
1737                     if (frame === WI.networkManager.mainFrame || frame.mainResource.type !== WI.Resource.Type.Document)
1738                         continue;
1739
1740                     let frameSubMenuItem = framesSubMenu.appendSubMenuItem(frame.name ? WI.UIString("%s (%s)").format(frame.name, frame.mainResource.displayName) : frame.mainResource.displayName);
1741
1742                     addInspectorStyleSheetItem(frameSubMenuItem, frame);
1743                 }
1744             }
1745         }
1746     }
1747
1748     _handleResourceGroupingModeChanged(event)
1749     {
1750         this._workerTargetTreeElementMap.clear();
1751         this._mainFrameTreeElement = null;
1752         this._extensionScriptsFolderTreeElement = null;
1753         this._extraScriptsFolderTreeElement = null;
1754         this._anonymousScriptsFolderTreeElement = null;
1755
1756         this._originTreeElementMap.clear();
1757
1758         let resourceGroupingModeScopeBarItem = this._resourceGroupingModeScopeBarItems[WI.settings.resourceGroupingMode.value];
1759         console.assert(resourceGroupingModeScopeBarItem);
1760         if (resourceGroupingModeScopeBarItem)
1761             resourceGroupingModeScopeBarItem.selected = true;
1762
1763         this._resourcesTreeOutline.removeChildren();
1764
1765         let mainFrame = WI.networkManager.mainFrame;
1766         if (mainFrame) {
1767             this._updateMainFrameTreeElement(mainFrame);
1768             this._addResourcesRecursivelyForFrame(mainFrame);
1769
1770             for (let frame of WI.networkManager.frames) {
1771                 if (frame !== mainFrame)
1772                     this._addResourcesRecursivelyForFrame(frame);
1773             }
1774         }
1775
1776         for (let script of WI.debuggerManager.knownNonResourceScripts) {
1777             this._addScript(script);
1778
1779             if (script.sourceMaps.length && WI.SourcesNavigationSidebarPanel.shouldPlaceResourcesAtTopLevel())
1780                 this._resourcesTreeOutline.disclosureButtons = true;
1781         }
1782     }
1783
1784     _handleFrameMainResourceDidChange(event)
1785     {
1786         let frame = event.target;
1787         if (frame.isMainFrame()) {
1788             this._updateMainFrameTreeElement(frame);
1789             this._addResourcesRecursivelyForFrame(frame);
1790
1791             for (let domBreakpoint of WI.domDebuggerManager.domBreakpoints)
1792                 this._removeBreakpoint(domBreakpoint);
1793         }
1794
1795         if (!event.data.oldMainResource) {
1796             let resource = event.target.mainResource;
1797             this._addBreakpointsForSourceCode(resource);
1798             this._addIssuesForSourceCode(resource);
1799         }
1800     }
1801
1802     _handleResourceAdded(event)
1803     {
1804         this._addResource(event.data.resource);
1805     }
1806
1807     _handleFrameWasAdded(event)
1808     {
1809         let {frame} = event.data;
1810
1811         if (frame.isMainFrame())
1812             this._updateMainFrameTreeElement(frame);
1813
1814         this._addResourcesRecursivelyForFrame(frame);
1815     }
1816
1817     _handleDebuggerBreakpointAdded(event)
1818     {
1819         this._addBreakpoint(event.data.breakpoint);
1820     }
1821
1822     _handleDebuggerBreakpointRemoved(event)
1823     {
1824         this._removeBreakpoint(event.data.breakpoint);
1825     }
1826
1827     _handleDebuggerBreakpointsEnabledDidChange(event)
1828     {
1829         this._debuggerBreakpointsButtonItem.activated = WI.debuggerManager.breakpointsEnabled;
1830
1831         this._updateBreakpointsDisabledBanner();
1832     }
1833
1834     _handleDebuggerScriptAdded(event)
1835     {
1836         this._addScript(event.data.script);
1837     }
1838
1839     _handleDebuggerScriptRemoved(event)
1840     {
1841         let script = event.data.script;
1842         let scriptTreeElement = this._resourcesTreeOutline.findTreeElement(script);
1843         if (!scriptTreeElement)
1844             return;
1845
1846         let parentTreeElement = scriptTreeElement.parent;
1847         parentTreeElement.removeChild(scriptTreeElement);
1848
1849         if (parentTreeElement instanceof WI.FolderTreeElement || parentTreeElement instanceof WI.OriginTreeElement) {
1850             parentTreeElement.representedObject.remove(script);
1851
1852             if (!parentTreeElement.children.length)
1853                 parentTreeElement.parent.removeChild(parentTreeElement);
1854         }
1855     }
1856
1857     _handleDebuggerScriptsCleared(event)
1858     {
1859         const suppressOnDeselect = true;
1860         const suppressSelectSibling = true;
1861
1862         for (let i = this._breakpointsTreeOutline.children.length - 1; i >= 0; --i) {
1863             let treeElement = this._breakpointsTreeOutline.children[i];
1864             if (!(treeElement instanceof WI.ScriptTreeElement))
1865                 continue;
1866
1867             this._breakpointsTreeOutline.removeChild(treeElement, suppressOnDeselect, suppressSelectSibling);
1868         }
1869
1870         if (this._extensionScriptsFolderTreeElement) {
1871             if (this._extensionScriptsFolderTreeElement.parent)
1872                 this._extensionScriptsFolderTreeElement.parent.removeChild(this._extensionScriptsFolderTreeElement, suppressOnDeselect, suppressSelectSibling);
1873
1874             this._extensionScriptsFolderTreeElement.representedObject.clear();
1875             this._extensionScriptsFolderTreeElement = null;
1876         }
1877
1878         if (this._extraScriptsFolderTreeElement) {
1879             if (this._extraScriptsFolderTreeElement.parent)
1880                 this._extraScriptsFolderTreeElement.parent.removeChild(this._extraScriptsFolderTreeElement, suppressOnDeselect, suppressSelectSibling);
1881
1882             this._extraScriptsFolderTreeElement.representedObject.clear();
1883             this._extraScriptsFolderTreeElement = null;
1884         }
1885
1886         if (this._anonymousScriptsFolderTreeElement) {
1887             if (this._anonymousScriptsFolderTreeElement.parent)
1888                 this._anonymousScriptsFolderTreeElement.parent.removeChild(this._anonymousScriptsFolderTreeElement, suppressOnDeselect, suppressSelectSibling);
1889
1890             this._anonymousScriptsFolderTreeElement.representedObject.clear();
1891             this._anonymousScriptsFolderTreeElement = null;
1892         }
1893
1894         if (this._workerTargetTreeElementMap.size) {
1895             for (let treeElement of this._workerTargetTreeElementMap.values())
1896                 treeElement.parent.removeChild(treeElement, suppressOnDeselect, suppressSelectSibling);
1897             this._workerTargetTreeElementMap.clear();
1898         }
1899
1900         this._addResourcesRecursivelyForFrame(WI.networkManager.mainFrame);
1901     }
1902
1903     _handleDebuggerPaused(event)
1904     {
1905         this.contentView.element.insertBefore(this._callStackContainer, this.contentView.element.firstChild);
1906
1907         if (this._updatePauseReason())
1908             this.contentView.element.insertBefore(this._pauseReasonContainer, this.contentView.element.firstChild);
1909
1910         this._debuggerPauseResumeButtonItem.enabled = true;
1911         this._debuggerPauseResumeButtonItem.toggled = true;
1912         this._debuggerStepOverButtonItem.enabled = true;
1913         this._debuggerStepIntoButtonItem.enabled = true;
1914         this._debuggerStepOutButtonItem.enabled = true;
1915
1916         this.element.classList.add("paused");
1917     }
1918
1919     _handleDebuggerResumed(event)
1920     {
1921         this._callStackContainer.remove();
1922
1923         this._pauseReasonContainer.remove();
1924
1925         this._debuggerPauseResumeButtonItem.enabled = true;
1926         this._debuggerPauseResumeButtonItem.toggled = false;
1927         this._debuggerStepOverButtonItem.enabled = false;
1928         this._debuggerStepIntoButtonItem.enabled = false;
1929         this._debuggerStepOutButtonItem.enabled = false;
1930
1931         this.element.classList.remove("paused");
1932     }
1933
1934     _handleDebuggerCallFramesDidChange(event)
1935     {
1936         let {target} = event.data;
1937         let treeElement = this._findCallStackTargetTreeElement(target);
1938         console.assert(treeElement);
1939         if (treeElement)
1940             treeElement.refresh();
1941
1942         let activeCallFrameTreeElement = this._callStackTreeOutline.findTreeElement(WI.debuggerManager.activeCallFrame);
1943         if (activeCallFrameTreeElement)
1944             activeCallFrameTreeElement.reveal();
1945     }
1946
1947     _handleDebuggerActiveCallFrameDidChange(event)
1948     {
1949         if (this._activeCallFrameTreeElement) {
1950             this._activeCallFrameTreeElement.isActiveCallFrame = false;
1951             this._activeCallFrameTreeElement = null;
1952         }
1953
1954         if (!WI.debuggerManager.activeCallFrame)
1955             return;
1956
1957         this._activeCallFrameTreeElement = this._callStackTreeOutline.findTreeElement(WI.debuggerManager.activeCallFrame);
1958         if (this._activeCallFrameTreeElement)
1959             this._activeCallFrameTreeElement.isActiveCallFrame = true;
1960     }
1961
1962     _handleDebuggerWaitingToPause(event)
1963     {
1964         this._debuggerPauseResumeButtonItem.enabled = false;
1965     }
1966
1967     _handleDebuggerObjectDisplayLocationDidChange(event)
1968     {
1969         let debuggerObject = event.target;
1970
1971         if (event.data.oldDisplaySourceCode === debuggerObject.sourceCodeLocation.displaySourceCode)
1972             return;
1973
1974         // A known debugger object (breakpoint, issueMessage, etc.) moved between resources. Remove
1975         // the old tree element and create a new tree element with the updated file.
1976
1977         let wasSelected = false;
1978         let oldDebuggerTreeElement = null;
1979         let newDebuggerTreeElement = null;
1980         if (debuggerObject instanceof WI.Breakpoint) {
1981             oldDebuggerTreeElement = this._breakpointsTreeOutline.findTreeElement(debuggerObject);
1982             if (oldDebuggerTreeElement)
1983                 wasSelected = oldDebuggerTreeElement.selected;
1984
1985             newDebuggerTreeElement = this._addBreakpoint(debuggerObject);
1986         } else if (debuggerObject instanceof WI.IssueMessage) {
1987             oldDebuggerTreeElement = this._resourcesTreeOutline.findTreeElement(debuggerObject);
1988             if (oldDebuggerTreeElement)
1989                 wasSelected = oldDebuggerTreeElement.selected;
1990
1991             newDebuggerTreeElement = this._addIssue(debuggerObject);
1992         }
1993
1994         if (!newDebuggerTreeElement)
1995             return;
1996
1997         if (oldDebuggerTreeElement)
1998             this._removeDebuggerTreeElement(oldDebuggerTreeElement);
1999
2000         if (wasSelected)
2001             newDebuggerTreeElement.revealAndSelect(true, false, true);
2002     }
2003
2004     _handleDOMBreakpointDOMNodeChanged(event)
2005     {
2006         let breakpoint = event.target;
2007         if (breakpoint.domNodeIdentifier)
2008             this._addBreakpoint(breakpoint);
2009         else
2010             this._removeBreakpoint(breakpoint);
2011     }
2012
2013     _handleConsoleIssueAdded(event)
2014     {
2015         let {issue} = event.data;
2016
2017         // We only want to show issues originating from JavaScript source code.
2018         if (!issue.sourceCodeLocation || !issue.sourceCodeLocation.sourceCode || (issue.source !== "javascript" && issue.source !== "console-api"))
2019             return;
2020
2021         this._addIssue(issue);
2022     }
2023
2024     _handleConsoleCleared(event)
2025     {
2026         let issueTreeElements = [];
2027         let currentTreeElement = this._resourcesTreeOutline.children[0];
2028         while (currentTreeElement && !currentTreeElement.root) {
2029             if (currentTreeElement instanceof WI.IssueTreeElement)
2030                 issueTreeElements.push(currentTreeElement);
2031
2032             const skipUnrevealed = false;
2033             const stayWithin = null;
2034             const dontPopulate = true;
2035             currentTreeElement = currentTreeElement.traverseNextTreeElement(skipUnrevealed, stayWithin, dontPopulate);
2036         }
2037
2038         issueTreeElements.forEach((treeElement) => treeElement.parent.removeChild(treeElement));
2039     }
2040
2041     _handleTimelineCapturingStateChanged(event)
2042     {
2043         this._updateTemporarilyDisabledBreakpointsButtons();
2044
2045         switch (WI.timelineManager.capturingState) {
2046         case WI.TimelineManager.CapturingState.Starting:
2047             if (!this._timelineRecordingWarningElement) {
2048                 let stopRecordingButton = document.createElement("button");
2049                 stopRecordingButton.textContent = WI.UIString("Stop recording");
2050                 stopRecordingButton.addEventListener("click", () => {
2051                     WI.timelineManager.stopCapturing();
2052                 });
2053
2054                 this._timelineRecordingWarningElement = document.createElement("div");
2055                 this._timelineRecordingWarningElement.classList.add("warning-banner");
2056                 this._timelineRecordingWarningElement.append(WI.UIString("Debugger disabled during Timeline recording"), document.createElement("br"), stopRecordingButton);
2057             }
2058
2059             this.contentView.element.insertBefore(this._timelineRecordingWarningElement, this.contentView.element.firstChild);
2060             break;
2061
2062         case WI.TimelineManager.CapturingState.Inactive:
2063             if (this._timelineRecordingWarningElement) {
2064                 this._timelineRecordingWarningElement.remove();
2065                 this._timelineRecordingWarningElement = null;
2066             }
2067             break;
2068         }
2069
2070         this._updateBreakpointsDisabledBanner();
2071     }
2072
2073     _handleAuditManagerTestScheduled(event)
2074     {
2075         this._updateTemporarilyDisabledBreakpointsButtons();
2076
2077         if (!this._auditTestWarningElement) {
2078             let stopAuditButton = document.createElement("button");
2079             stopAuditButton.textContent = WI.UIString("Stop Audit");
2080             stopAuditButton.addEventListener("click", (event) => {
2081                 WI.auditManager.stop();
2082             });
2083
2084             this._auditTestWarningElement = document.createElement("div");
2085             this._auditTestWarningElement.classList.add("warning-banner");
2086             this._auditTestWarningElement.append(WI.UIString("Debugger disabled during Audit"), document.createElement("br"), stopAuditButton);
2087         }
2088
2089         this.contentView.element.insertBefore(this._auditTestWarningElement, this.contentView.element.firstChild);
2090
2091         this._updateBreakpointsDisabledBanner();
2092     }
2093
2094     _handleAuditManagerTestCompleted(event)
2095     {
2096         this._updateTemporarilyDisabledBreakpointsButtons();
2097
2098         if (this._auditTestWarningElement) {
2099             this._auditTestWarningElement.remove();
2100             this._auditTestWarningElement = null;
2101         }
2102
2103         this._updateBreakpointsDisabledBanner();
2104     }
2105
2106     _handleCSSStyleSheetAdded(event)
2107     {
2108         let styleSheet = event.data.styleSheet;
2109         if (!styleSheet.isInspectorStyleSheet())
2110             return;
2111
2112         if (WI.settings.resourceGroupingMode.value === WI.Resource.GroupingMode.Type) {
2113             let frameTreeElement = this.treeElementForRepresentedObject(styleSheet.parentFrame);
2114             if (frameTreeElement) {
2115                 frameTreeElement.addRepresentedObjectToNewChildQueue(styleSheet);
2116                 return;
2117             }
2118         }
2119
2120         this._addResource(styleSheet);
2121     }
2122
2123     _handleTargetAdded(event)
2124     {
2125         this._addTarget(event.data.target);
2126     }
2127
2128     _handleTargetRemoved(event)
2129     {
2130         let {target} = event.data;
2131
2132         let workerTreeElement = this._workerTargetTreeElementMap.take(target);
2133         if (workerTreeElement)
2134             workerTreeElement.parent.removeChild(workerTreeElement);
2135
2136         let callStackTreeElement = this._findCallStackTargetTreeElement(target);
2137         console.assert(callStackTreeElement);
2138         if (callStackTreeElement)
2139             this._callStackTreeOutline.removeChild(callStackTreeElement);
2140
2141         this._updateCallStackTreeOutline();
2142     }
2143
2144     _handleExtraDomainsActivated()
2145     {
2146         if (WI.SourcesNavigationSidebarPanel.shouldPlaceResourcesAtTopLevel())
2147             this._resourcesTreeOutline.disclosureButtons = true;
2148     }
2149 };
2150
2151 WI.SourcesNavigationSidebarPanel.ResourceTypeSymbol = Symbol("resource-type");
2152 WI.SourcesNavigationSidebarPanel.ResourceGroupingModeSymbol = Symbol("resource-grouping-mode");