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