Web Inspector: Remove parameters from TreeOutline SelectionDidChange event
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / DebuggerSidebarPanel.js
1 /*
2  * Copyright (C) 2013, 2015 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.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSidebarPanel
27 {
28     constructor()
29     {
30         super("debugger", WI.UIString("Debugger"), true);
31
32         WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
33         WI.Frame.addEventListener(WI.Frame.Event.ResourceWasAdded, this._resourceAdded, this);
34         WI.Target.addEventListener(WI.Target.Event.ResourceAdded, this._resourceAdded, this);
35
36         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointAdded, this._breakpointAdded, this);
37         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.DOMBreakpointAdded, this._breakpointAdded, this);
38         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.EventBreakpointAdded, this._breakpointAdded, this);
39         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.XHRBreakpointAdded, this._breakpointAdded, this);
40
41         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointRemoved, this._breakpointRemoved, this);
42         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.DOMBreakpointRemoved, this._breakpointRemoved, this);
43         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, this._breakpointRemoved, this);
44         WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.XHRBreakpointRemoved, this._breakpointRemoved, this);
45
46         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointsEnabledDidChange, this._breakpointsEnabledDidChange, this);
47         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ScriptAdded, this._scriptAdded, this);
48         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ScriptRemoved, this._scriptRemoved, this);
49         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ScriptsCleared, this._scriptsCleared, this);
50         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, this._debuggerDidPause, this);
51         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Resumed, this._debuggerDidResume, this);
52         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.CallFramesDidChange, this._debuggerCallFramesDidChange, this);
53         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ActiveCallFrameDidChange, this._debuggerActiveCallFrameDidChange, this);
54         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.WaitingToPause, this._debuggerWaitingToPause, this);
55
56         WI.DOMBreakpoint.addEventListener(WI.DOMBreakpoint.Event.ResolvedStateDidChange, this._domBreakpointResolvedStateDidChange, this);
57
58         WI.timelineManager.addEventListener(WI.TimelineManager.Event.CapturingWillStart, this._timelineCapturingWillStart, this);
59         WI.timelineManager.addEventListener(WI.TimelineManager.Event.CapturingStopped, this._timelineCapturingStopped, this);
60
61         WI.targetManager.addEventListener(WI.TargetManager.Event.TargetAdded, this._targetAdded, this);
62         WI.targetManager.addEventListener(WI.TargetManager.Event.TargetRemoved, this._targetRemoved, this);
63
64         this._timelineRecordingWarningElement = document.createElement("div");
65         this._timelineRecordingWarningElement.classList.add("warning-banner");
66         this._timelineRecordingWarningElement.append(WI.UIString("Debugger disabled during Timeline recording"), " ");
67         let stopRecordingLink = this._timelineRecordingWarningElement.appendChild(document.createElement("a"));
68         stopRecordingLink.textContent = WI.UIString("Stop recording");
69         stopRecordingLink.addEventListener("click", () => { WI.timelineManager.stopCapturing(); });
70
71         this._breakpointsDisabledWarningElement = document.createElement("div");
72         this._breakpointsDisabledWarningElement.classList.add("warning-banner");
73         this._breakpointsDisabledWarningElement.append(WI.UIString("Breakpoints disabled"), document.createElement("br"));
74         let enableBreakpointsLink = this._breakpointsDisabledWarningElement.appendChild(document.createElement("a"));
75         enableBreakpointsLink.textContent = WI.UIString("Enable breakpoints");
76         enableBreakpointsLink.addEventListener("click", () => { WI.debuggerToggleBreakpoints(); });
77
78         this._navigationBar = new WI.NavigationBar;
79         this.addSubview(this._navigationBar);
80
81         var breakpointsImage = {src: "Images/Breakpoints.svg", width: 15, height: 15};
82         var pauseImage = {src: "Images/Pause.svg", width: 15, height: 15};
83         var resumeImage = {src: "Images/Resume.svg", width: 15, height: 15};
84         var stepOverImage = {src: "Images/StepOver.svg", width: 15, height: 15};
85         var stepIntoImage = {src: "Images/StepInto.svg", width: 15, height: 15};
86         var stepOutImage = {src: "Images/StepOut.svg", width: 15, height: 15};
87
88         var toolTip = WI.UIString("Enable all breakpoints (%s)").format(WI.toggleBreakpointsKeyboardShortcut.displayName);
89         var altToolTip = WI.UIString("Disable all breakpoints (%s)").format(WI.toggleBreakpointsKeyboardShortcut.displayName);
90
91         this._debuggerBreakpointsButtonItem = new WI.ActivateButtonNavigationItem("debugger-breakpoints", toolTip, altToolTip, breakpointsImage.src, breakpointsImage.width, breakpointsImage.height);
92         this._debuggerBreakpointsButtonItem.activated = WI.debuggerManager.breakpointsEnabled;
93         this._debuggerBreakpointsButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerToggleBreakpoints, this);
94         this._navigationBar.addNavigationItem(this._debuggerBreakpointsButtonItem);
95
96         toolTip = WI.UIString("Pause script execution (%s or %s)").format(WI.pauseOrResumeKeyboardShortcut.displayName, WI.pauseOrResumeAlternateKeyboardShortcut.displayName);
97         altToolTip = WI.UIString("Continue script execution (%s or %s)").format(WI.pauseOrResumeKeyboardShortcut.displayName, WI.pauseOrResumeAlternateKeyboardShortcut.displayName);
98
99         this._debuggerPauseResumeButtonItem = new WI.ToggleButtonNavigationItem("debugger-pause-resume", toolTip, altToolTip, pauseImage.src, resumeImage.src, pauseImage.width, pauseImage.height);
100         this._debuggerPauseResumeButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerPauseResumeToggle, this);
101         this._navigationBar.addNavigationItem(this._debuggerPauseResumeButtonItem);
102
103         this._debuggerStepOverButtonItem = new WI.ButtonNavigationItem("debugger-step-over", WI.UIString("Step over (%s or %s)").format(WI.stepOverKeyboardShortcut.displayName, WI.stepOverAlternateKeyboardShortcut.displayName), stepOverImage.src, stepOverImage.width, stepOverImage.height);
104         this._debuggerStepOverButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerStepOver, this);
105         this._debuggerStepOverButtonItem.enabled = false;
106         this._navigationBar.addNavigationItem(this._debuggerStepOverButtonItem);
107
108         this._debuggerStepIntoButtonItem = new WI.ButtonNavigationItem("debugger-step-into", WI.UIString("Step into (%s or %s)").format(WI.stepIntoKeyboardShortcut.displayName, WI.stepIntoAlternateKeyboardShortcut.displayName), stepIntoImage.src, stepIntoImage.width, stepIntoImage.height);
109         this._debuggerStepIntoButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerStepInto, this);
110         this._debuggerStepIntoButtonItem.enabled = false;
111         this._navigationBar.addNavigationItem(this._debuggerStepIntoButtonItem);
112
113         this._debuggerStepOutButtonItem = new WI.ButtonNavigationItem("debugger-step-out", WI.UIString("Step out (%s or %s)").format(WI.stepOutKeyboardShortcut.displayName, WI.stepOutAlternateKeyboardShortcut.displayName), stepOutImage.src, stepOutImage.width, stepOutImage.height);
114         this._debuggerStepOutButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.debuggerStepOut, this);
115         this._debuggerStepOutButtonItem.enabled = false;
116         this._navigationBar.addNavigationItem(this._debuggerStepOutButtonItem);
117
118         // Add this offset-sections class name so the sticky headers don't overlap the navigation bar.
119         this.element.classList.add(WI.DebuggerSidebarPanel.OffsetSectionsStyleClassName);
120
121         function showResourcesWithIssuesOnlyFilterFunction(treeElement)
122         {
123             // Issues are only shown in the scripts tree outline.
124             if (treeElement.treeOutline !== this._scriptsContentTreeOutline)
125                 return true;
126
127             // Keep issues.
128             if (treeElement instanceof WI.IssueTreeElement)
129                 return true;
130
131             // Keep resources with issues.
132             if (treeElement.hasChildren) {
133                 for (let child of treeElement.children) {
134                     if (child instanceof WI.IssueTreeElement)
135                         return true;
136                 }
137             }
138             return false;
139         }
140
141         this.filterBar.addFilterBarButton("debugger-show-resources-with-issues-only", showResourcesWithIssuesOnlyFilterFunction.bind(this), false, WI.UIString("Only show resources with issues"), WI.UIString("Show all resources"), "Images/Errors.svg", 15, 15);
142
143         this._breakpointsContentTreeOutline = this.contentTreeOutline;
144
145         let breakpointsRow = new WI.DetailsSectionRow;
146         breakpointsRow.element.appendChild(this._breakpointsContentTreeOutline.element);
147
148         let breakpointNavigationBarWrapper = document.createElement("div");
149
150         let breakpointNavigationBar = new WI.NavigationBar;
151         breakpointNavigationBarWrapper.appendChild(breakpointNavigationBar.element);
152
153         let createBreakpointButton = new WI.ButtonNavigationItem("create-breakpoint", WI.UIString("Create Breakpoint"), "Images/Plus13.svg", 13, 13);
154         createBreakpointButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._handleCreateBreakpointClicked, this);
155         breakpointNavigationBar.addNavigationItem(createBreakpointButton);
156
157         let breakpointsGroup = new WI.DetailsSectionGroup([breakpointsRow]);
158         let breakpointsSection = new WI.DetailsSection("breakpoints", WI.UIString("Breakpoints"), [breakpointsGroup], breakpointNavigationBarWrapper);
159         this.contentView.element.appendChild(breakpointsSection.element);
160
161         this._breakpointsContentTreeOutline.addEventListener(WI.TreeOutline.Event.ElementAdded, this._handleBreakpointElementAddedOrRemoved, this);
162         this._breakpointsContentTreeOutline.addEventListener(WI.TreeOutline.Event.ElementRemoved, this._handleBreakpointElementAddedOrRemoved, this);
163         this._breakpointsContentTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._treeSelectionDidChange, this);
164         this._breakpointsContentTreeOutline.ondelete = this._breakpointTreeOutlineDeleteTreeElement.bind(this);
165         this._breakpointsContentTreeOutline.populateContextMenu = function(contextMenu, event, treeElement) {
166             this._breakpointTreeOutlineContextMenuTreeElement(contextMenu, event, treeElement);
167
168             WI.TreeOutline.prototype.populateContextMenu(contextMenu, event, treeElement);
169         }.bind(this);
170
171         this._scriptsContentTreeOutline = this.createContentTreeOutline();
172         this._scriptsContentTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._treeSelectionDidChange, this);
173         this._scriptsContentTreeOutline.includeSourceMapResourceChildren = true;
174
175         let scriptsRow = new WI.DetailsSectionRow;
176         scriptsRow.element.appendChild(this._scriptsContentTreeOutline.element);
177
178         let scriptsGroup = new WI.DetailsSectionGroup([scriptsRow]);
179         this._scriptsSection = new WI.DetailsSection("scripts", WI.UIString("Sources"), [scriptsGroup]);
180         this.contentView.element.appendChild(this._scriptsSection.element);
181
182         const suppressFiltering = true;
183         this._callStackTreeOutline = this.createContentTreeOutline(suppressFiltering);
184         this._callStackTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._treeSelectionDidChange, this);
185
186         this._callStackRow = new WI.DetailsSectionRow;
187         this._callStackRow.element.appendChild(this._callStackTreeOutline.element);
188
189         this._callStackGroup = new WI.DetailsSectionGroup([this._callStackRow]);
190         this._callStackSection = new WI.DetailsSection("call-stack", WI.UIString("Call Stack"), [this._callStackGroup]);
191
192         this._mainTargetTreeElement = null;
193         this._activeCallFrameTreeElement = null;
194
195         this._pauseReasonTreeOutline = null;
196
197         this._pauseReasonLinkContainerElement = document.createElement("span");
198         this._pauseReasonTextRow = new WI.DetailsSectionTextRow;
199         this._pauseReasonGroup = new WI.DetailsSectionGroup([this._pauseReasonTextRow]);
200         this._pauseReasonSection = new WI.DetailsSection("paused-reason", WI.UIString("Pause Reason"), [this._pauseReasonGroup], this._pauseReasonLinkContainerElement);
201
202         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.DisplayLocationDidChange, this._handleDebuggerObjectDisplayLocationDidChange, this);
203         WI.IssueMessage.addEventListener(WI.IssueMessage.Event.DisplayLocationDidChange, this._handleDebuggerObjectDisplayLocationDidChange, this);
204         WI.consoleManager.addEventListener(WI.ConsoleManager.Event.IssueAdded, this._handleIssueAdded, this);
205         WI.consoleManager.addEventListener(WI.ConsoleManager.Event.Cleared, this._handleIssuesCleared, this);
206
207         WI.debuggerManager.addBreakpoint(WI.debuggerManager.allExceptionsBreakpoint);
208         WI.debuggerManager.addBreakpoint(WI.debuggerManager.uncaughtExceptionsBreakpoint);
209
210         // COMPATIBILITY (iOS 10): DebuggerAgent.setPauseOnAssertions did not exist yet.
211         if (InspectorBackend.domains.Debugger.setPauseOnAssertions && WI.settings.showAssertionFailuresBreakpoint.value)
212             WI.debuggerManager.addBreakpoint(WI.debuggerManager.assertionFailuresBreakpoint);
213
214         for (let target of WI.targets)
215             this._addTarget(target);
216         this._updateCallStackTreeOutline();
217
218         if (WI.networkManager.mainFrame)
219             this._addResourcesRecursivelyForFrame(WI.networkManager.mainFrame);
220
221         for (let script of WI.debuggerManager.knownNonResourceScripts)
222             this._addScript(script);
223
224         if (WI.domDebuggerManager.supported) {
225             if (WI.settings.showAllRequestsBreakpoint.value)
226                 WI.domDebuggerManager.addXHRBreakpoint(WI.domDebuggerManager.allRequestsBreakpoint);
227
228             for (let eventBreakpoint of WI.domDebuggerManager.eventBreakpoints)
229                 this._addBreakpoint(eventBreakpoint);
230
231             for (let domBreakpoint of WI.domDebuggerManager.domBreakpoints)
232                 this._addBreakpoint(domBreakpoint);
233
234             for (let eventListenerBreakpoint of WI.domManager.eventListenerBreakpoints)
235                 this._addBreakpoint(eventListenerBreakpoint);
236
237             for (let xhrBreakpoints of WI.domDebuggerManager.xhrBreakpoints)
238                 this._addBreakpoint(xhrBreakpoints);
239         }
240
241         if (WI.debuggerManager.paused)
242             this._debuggerDidPause(null);
243
244         if (WI.timelineManager.isCapturing() && WI.debuggerManager.breakpointsDisabledTemporarily)
245             this._timelineCapturingWillStart(null);
246
247         this._updateBreakpointsDisabledBanner();
248     }
249
250     // Public
251
252     get minimumWidth()
253     {
254         return this._navigationBar.minimumWidth;
255     }
256
257     closed()
258     {
259         super.closed();
260
261         WI.Frame.removeEventListener(null, null, this);
262         WI.Target.removeEventListener(null, null, this);
263         WI.debuggerManager.removeEventListener(null, null, this);
264         WI.domDebuggerManager.removeEventListener(null, null, this);
265         WI.DOMBreakpoint.removeEventListener(null, null, this);
266         WI.timelineManager.removeEventListener(null, null, this);
267         WI.targetManager.removeEventListener(null, null, this);
268         WI.Breakpoint.removeEventListener(null, null, this);
269         WI.IssueMessage.removeEventListener(null, null, this);
270     }
271
272     showDefaultContentView()
273     {
274         if (WI.networkManager.mainFrame) {
275             let mainTreeElement = this._scriptsContentTreeOutline.findTreeElement(WI.networkManager.mainFrame.mainResource);
276             if (mainTreeElement && this.showDefaultContentViewForTreeElement(mainTreeElement))
277                 return;
278         }
279
280         let currentTreeElement = this._scriptsContentTreeOutline.children[0];
281         while (currentTreeElement && !currentTreeElement.root) {
282             if (currentTreeElement instanceof WI.ResourceTreeElement || currentTreeElement instanceof WI.ScriptTreeElement) {
283                 if (this.showDefaultContentViewForTreeElement(currentTreeElement))
284                     return;
285             }
286
287             currentTreeElement = currentTreeElement.traverseNextTreeElement(false, null, true);
288         }
289     }
290
291     treeElementForRepresentedObject(representedObject)
292     {
293         // The main resource is used as the representedObject instead of Frame in our tree.
294         if (representedObject instanceof WI.Frame)
295             representedObject = representedObject.mainResource;
296
297         let treeElement = this._breakpointsContentTreeOutline.findTreeElement(representedObject);
298         if (!treeElement)
299             treeElement = this._scriptsContentTreeOutline.findTreeElement(representedObject);
300
301         if (treeElement)
302             return treeElement;
303
304         // Only special case Script objects.
305         if (!(representedObject instanceof WI.Script)) {
306             console.error("Didn't find a TreeElement for representedObject", representedObject);
307             return null;
308         }
309
310         // If the Script has a URL we should have found it earlier.
311         if (representedObject.url) {
312             console.error("Didn't find a ScriptTreeElement for a Script with a URL.");
313             return null;
314         }
315
316         // Since the Script does not have a URL we consider it an 'anonymous' script. These scripts happen from calls to
317         // window.eval() or browser features like Auto Fill and Reader. They are not normally added to the sidebar, but since
318         // we have a ScriptContentView asking for the tree element we will make a ScriptTreeElement on demand and add it.
319
320         return this._addScript(representedObject);
321     }
322
323     // Protected
324
325     saveStateToCookie(cookie)
326     {
327         console.assert(cookie);
328
329         var selectedTreeElement = this._breakpointsContentTreeOutline.selectedTreeElement;
330         if (!selectedTreeElement) {
331             super.saveStateToCookie(cookie);
332             return;
333         }
334
335         var representedObject = selectedTreeElement.representedObject;
336
337         if (representedObject === WI.debuggerManager.allExceptionsBreakpoint) {
338             cookie[WI.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey] = true;
339             return;
340         }
341
342         if (representedObject === WI.debuggerManager.uncaughtExceptionsBreakpoint) {
343             cookie[WI.DebuggerSidebarPanel.SelectedUncaughtExceptionsCookieKey] = true;
344             return;
345         }
346
347         if (representedObject === WI.debuggerManager.assertionFailuresBreakpoint) {
348             cookie[WI.DebuggerSidebarPanel.SelectedAssertionFailuresCookieKey] = true;
349             return;
350         }
351
352         if (representedObject === WI.domDebuggerManager.allRequestsBreakpoint) {
353             cookie[WI.DebuggerSidebarPanel.SelectedAllRequestsCookieKey] = true;
354             return;
355         }
356
357         super.saveStateToCookie(cookie);
358     }
359
360     restoreStateFromCookie(cookie, relaxedMatchDelay)
361     {
362         console.assert(cookie);
363
364         function revealAndSelect(treeOutline, breakpoint) {
365             let treeElement = treeOutline.findTreeElement(breakpoint);
366             if (!treeElement)
367                 return;
368
369             treeElement.revealAndSelect();
370         }
371
372         // Eagerly resolve the special breakpoints; otherwise, use the default behavior.
373         if (cookie[WI.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey])
374             revealAndSelect(this._breakpointsContentTreeOutline, WI.debuggerManager.allExceptionsBreakpoint);
375         else if (cookie[WI.DebuggerSidebarPanel.SelectedUncaughtExceptionsCookieKey])
376             revealAndSelect(this._breakpointsContentTreeOutline, WI.debuggerManager.uncaughtExceptionsBreakpoint);
377         else if (cookie[WI.DebuggerSidebarPanel.SelectedAssertionFailuresCookieKey])
378             revealAndSelect(this._breakpointsContentTreeOutline, WI.debuggerManager.assertionFailuresBreakpoint);
379         else if (cookie[WI.DebuggerSidebarPanel.SelectedAllRequestsCookieKey])
380             revealAndSelect(this._breakpointsContentTreeOutline, WI.domDebuggerManager.allRequestsBreakpoint);
381         else
382             super.restoreStateFromCookie(cookie, relaxedMatchDelay);
383     }
384
385     // Popover delegate
386
387     willDismissPopover(popover)
388     {
389         let breakpoint = popover.breakpoint;
390         if (!breakpoint)
391             return;
392
393         if (breakpoint instanceof WI.EventBreakpoint)
394             WI.domDebuggerManager.addEventBreakpoint(breakpoint);
395         else if (breakpoint instanceof WI.XHRBreakpoint)
396             WI.domDebuggerManager.addXHRBreakpoint(breakpoint);
397     }
398
399     // Private
400
401     _debuggerWaitingToPause(event)
402     {
403         this._debuggerPauseResumeButtonItem.enabled = false;
404     }
405
406     _debuggerDidPause(event)
407     {
408         this.contentView.element.insertBefore(this._callStackSection.element, this.contentView.element.firstChild);
409
410         if (this._updatePauseReason())
411             this.contentView.element.insertBefore(this._pauseReasonSection.element, this.contentView.element.firstChild);
412
413         this._debuggerPauseResumeButtonItem.enabled = true;
414         this._debuggerPauseResumeButtonItem.toggled = true;
415         this._debuggerStepOverButtonItem.enabled = true;
416         this._debuggerStepIntoButtonItem.enabled = true;
417         this._debuggerStepOutButtonItem.enabled = true;
418
419         this.element.classList.add(WI.DebuggerSidebarPanel.DebuggerPausedStyleClassName);
420     }
421
422     _debuggerDidResume(event)
423     {
424         this._callStackSection.element.remove();
425
426         this._pauseReasonSection.element.remove();
427
428         this._debuggerPauseResumeButtonItem.enabled = true;
429         this._debuggerPauseResumeButtonItem.toggled = false;
430         this._debuggerStepOverButtonItem.enabled = false;
431         this._debuggerStepIntoButtonItem.enabled = false;
432         this._debuggerStepOutButtonItem.enabled = false;
433
434         this.element.classList.remove(WI.DebuggerSidebarPanel.DebuggerPausedStyleClassName);
435     }
436
437     _breakpointsEnabledDidChange(event)
438     {
439         this._debuggerBreakpointsButtonItem.activated = WI.debuggerManager.breakpointsEnabled;
440
441         this._updateBreakpointsDisabledBanner();
442     }
443
444     _addBreakpoint(breakpoint)
445     {
446         let constructor = WI.BreakpointTreeElement;
447         let options = {};
448         let parentTreeElement = this._breakpointsContentTreeOutline;
449
450         let getDOMNodeTreeElement = (domNode) => {
451             console.assert(domNode, "Missing DOMNode for identifier", breakpoint.domNodeIdentifier);
452             if (!domNode)
453                 return null;
454
455             let domNodeTreeElement = this._breakpointsContentTreeOutline.findTreeElement(domNode);
456             if (!domNodeTreeElement) {
457                 domNodeTreeElement = new WI.DOMNodeTreeElement(domNode);
458                 this._addTreeElement(domNodeTreeElement, parentTreeElement);
459             }
460             return domNodeTreeElement;
461         };
462
463         if (breakpoint === WI.debuggerManager.allExceptionsBreakpoint) {
464             options.className = WI.DebuggerSidebarPanel.ExceptionIconStyleClassName;
465             options.title = WI.UIString("All Exceptions");
466         } else if (breakpoint === WI.debuggerManager.uncaughtExceptionsBreakpoint) {
467             options.className = WI.DebuggerSidebarPanel.ExceptionIconStyleClassName;
468             options.title = WI.UIString("Uncaught Exceptions");
469         } else if (breakpoint === WI.debuggerManager.assertionFailuresBreakpoint) {
470             options.className = WI.DebuggerSidebarPanel.AssertionIconStyleClassName;
471             options.title = WI.UIString("Assertion Failures");
472         } else if (breakpoint instanceof WI.DOMBreakpoint) {
473             if (!breakpoint.domNodeIdentifier)
474                 return null;
475
476             constructor = WI.DOMBreakpointTreeElement;
477
478             let domNode = WI.domManager.nodeForId(breakpoint.domNodeIdentifier);
479             parentTreeElement = getDOMNodeTreeElement(domNode);
480         } else if (breakpoint instanceof WI.EventBreakpoint) {
481             constructor = WI.EventBreakpointTreeElement;
482
483             if (breakpoint.eventListener)
484                 parentTreeElement = getDOMNodeTreeElement(breakpoint.eventListener.node);
485         } else if (breakpoint instanceof WI.XHRBreakpoint) {
486             constructor = WI.XHRBreakpointTreeElement;
487
488             if (breakpoint === WI.domDebuggerManager.allRequestsBreakpoint) {
489                 options.className = WI.DebuggerSidebarPanel.AssertionIconStyleClassName;
490                 options.title = WI.UIString("All Requests");
491             }
492         } else {
493             let sourceCode = breakpoint.sourceCodeLocation && breakpoint.sourceCodeLocation.displaySourceCode;
494             if (!sourceCode)
495                 return null;
496
497             if (this._breakpointsContentTreeOutline.findTreeElement(breakpoint))
498                 return null;
499
500             parentTreeElement = this._addTreeElementForSourceCodeToTreeOutline(sourceCode, this._breakpointsContentTreeOutline);
501
502             // Mark disabled breakpoints as resolved if there is source code loaded with that URL.
503             // This gives the illusion the breakpoint was resolved, but since we don't send disabled
504             // breakpoints to the backend we don't know for sure. If the user enables the breakpoint
505             // it will be resolved properly.
506             if (breakpoint.disabled)
507                 breakpoint.resolved = true;
508         }
509
510         let breakpointTreeElement = new constructor(breakpoint, options);
511         this._addTreeElement(breakpointTreeElement, parentTreeElement);
512         if (parentTreeElement.children.length === 1)
513             parentTreeElement.expand();
514         return breakpointTreeElement;
515     }
516
517     _removeBreakpoint(breakpoint)
518     {
519         if (this._pauseReasonTreeOutline) {
520             let pauseReasonBreakpointTreeElement = this._pauseReasonTreeOutline.getCachedTreeElement(breakpoint);
521             if (pauseReasonBreakpointTreeElement)
522                 pauseReasonBreakpointTreeElement.status = null;
523         }
524
525         let breakpointTreeElement = this._breakpointsContentTreeOutline.getCachedTreeElement(breakpoint);
526         if (!breakpointTreeElement)
527             return;
528
529         this._removeDebuggerTreeElement(breakpointTreeElement);
530     }
531
532     _addBreakpointsForSourceCode(sourceCode)
533     {
534         var breakpoints = WI.debuggerManager.breakpointsForSourceCode(sourceCode);
535         for (var i = 0; i < breakpoints.length; ++i)
536             this._addBreakpoint(breakpoints[i], sourceCode);
537     }
538
539     _addIssuesForSourceCode(sourceCode)
540     {
541         var issues = WI.consoleManager.issuesForSourceCode(sourceCode);
542         for (var issue of issues)
543             this._addIssue(issue);
544     }
545
546     _addTreeElementForSourceCodeToTreeOutline(sourceCode, treeOutline)
547     {
548         let treeElement = treeOutline.getCachedTreeElement(sourceCode);
549         if (!treeElement) {
550             if (sourceCode instanceof WI.SourceMapResource)
551                 treeElement = new WI.SourceMapResourceTreeElement(sourceCode);
552             else if (sourceCode instanceof WI.Resource)
553                 treeElement = new WI.ResourceTreeElement(sourceCode);
554             else if (sourceCode instanceof WI.Script)
555                 treeElement = new WI.ScriptTreeElement(sourceCode);
556         }
557
558         if (!treeElement) {
559             console.error("Unknown sourceCode instance", sourceCode);
560             return null;
561         }
562
563         if (!treeElement.parent) {
564             treeElement.hasChildren = false;
565             treeElement.expand();
566
567             this._addTreeElement(treeElement, treeOutline);
568         }
569
570         return treeElement;
571     }
572
573     _addResourcesRecursivelyForFrame(frame)
574     {
575         this._addResource(frame.mainResource);
576
577         for (let resource of frame.resourceCollection)
578             this._addResource(resource);
579
580         for (let childFrame of frame.childFrameCollection)
581             this._addResourcesRecursivelyForFrame(childFrame);
582     }
583
584     _resourceAdded(event)
585     {
586         this._addResource(event.data.resource);
587     }
588
589     _addResource(resource)
590     {
591         if (![WI.Resource.Type.Document, WI.Resource.Type.Script].includes(resource.type))
592             return;
593
594         let treeElement = this._addTreeElementForSourceCodeToTreeOutline(resource, this._scriptsContentTreeOutline);
595         this._addBreakpointsForSourceCode(resource);
596         this._addIssuesForSourceCode(resource);
597
598         if (this.parentSidebar && !this.contentBrowser.currentContentView)
599             this.showDefaultContentViewForTreeElement(treeElement);
600     }
601
602     _mainResourceDidChange(event)
603     {
604         if (event.target.isMainFrame()) {
605             // Aggressively prune resources now so the old resources are removed before
606             // the new main resource is added below. This avoids a visual flash when the
607             // prune normally happens on a later event loop cycle.
608             this.pruneStaleResourceTreeElements();
609             this.contentBrowser.contentViewContainer.closeAllContentViews();
610
611             for (let domBreakpoint of WI.domDebuggerManager.domBreakpoints)
612                 this._removeBreakpoint(domBreakpoint);
613         }
614
615         if (!event.data.oldMainResource) {
616             var resource = event.target.mainResource;
617             this._addTreeElementForSourceCodeToTreeOutline(resource, this._scriptsContentTreeOutline);
618             this._addBreakpointsForSourceCode(resource);
619             this._addIssuesForSourceCode(resource);
620         }
621     }
622
623     _timelineCapturingWillStart(event)
624     {
625         this._debuggerBreakpointsButtonItem.enabled = false;
626         this._debuggerPauseResumeButtonItem.enabled = false;
627
628         this.contentView.element.insertBefore(this._timelineRecordingWarningElement, this.contentView.element.firstChild);
629         this._updateBreakpointsDisabledBanner();
630     }
631
632     _timelineCapturingStopped(event)
633     {
634         this._debuggerBreakpointsButtonItem.enabled = true;
635         this._debuggerPauseResumeButtonItem.enabled = true;
636
637         this._timelineRecordingWarningElement.remove();
638         this._updateBreakpointsDisabledBanner();
639     }
640
641     _updateBreakpointsDisabledBanner()
642     {
643         let breakpointsEnabled = WI.debuggerManager.breakpointsEnabled;
644         let timelineWarningShowing = !!this._timelineRecordingWarningElement.parentElement;
645
646         if (!breakpointsEnabled && !timelineWarningShowing)
647             this.contentView.element.insertBefore(this._breakpointsDisabledWarningElement, this.contentView.element.firstChild);
648         else
649             this._breakpointsDisabledWarningElement.remove();
650     }
651
652     _scriptAdded(event)
653     {
654         this._addScript(event.data.script);
655     }
656
657     _addScript(script)
658     {
659         // COMPATIBILITY(iOS 9): Backends could send the frontend built-in code, filter out JSC internals.
660         if (!script.url && !script.sourceURL)
661             return null;
662
663         // In general, do not show dynamically added script elements.
664         if (script.dynamicallyAddedScriptElement && !script.sourceURL)
665             return null;
666
667         // Don't add breakpoints if the script is represented by a Resource. They were
668         // already added by _resourceAdded.
669         if (script.resource)
670             return null;
671
672         let treeElement = this._addTreeElementForSourceCodeToTreeOutline(script, this._scriptsContentTreeOutline);
673         this._addBreakpointsForSourceCode(script);
674         this._addIssuesForSourceCode(script);
675
676         if (this.parentSidebar && !this.contentBrowser.currentContentView)
677             this.showDefaultContentViewForTreeElement(treeElement);
678
679         return treeElement;
680     }
681
682     _scriptRemoved(event)
683     {
684         function removeScript(script, treeOutline)
685         {
686             let scriptTreeElement = treeOutline.getCachedTreeElement(script);
687             if (scriptTreeElement)
688                 scriptTreeElement.parent.removeChild(scriptTreeElement);
689         }
690
691         let script = event.data.script;
692         removeScript(script, this._breakpointsContentTreeOutline);
693         removeScript(script, this._scriptsContentTreeOutline);
694     }
695
696     _scriptsCleared(event)
697     {
698         for (var i = this._breakpointsContentTreeOutline.children.length - 1; i >= 0; --i) {
699             var treeElement = this._breakpointsContentTreeOutline.children[i];
700             if (!(treeElement instanceof WI.ScriptTreeElement))
701                 continue;
702
703             this._breakpointsContentTreeOutline.removeChildAtIndex(i, true, true);
704         }
705
706         this._scriptsContentTreeOutline.removeChildren();
707
708         this._addResourcesRecursivelyForFrame(WI.networkManager.mainFrame);
709     }
710
711     _breakpointAdded(event)
712     {
713         var breakpoint = event.data.breakpoint;
714         this._addBreakpoint(breakpoint);
715     }
716
717     _breakpointRemoved(event)
718     {
719         var breakpoint = event.data.breakpoint;
720         this._removeBreakpoint(breakpoint);
721     }
722
723     _findThreadTreeElementForTarget(target)
724     {
725         for (let child of this._callStackTreeOutline.children) {
726             if (child.target === target)
727                 return child;
728         }
729
730         return null;
731     }
732
733     _targetAdded(event)
734     {
735         this._addTarget(event.data.target);
736     }
737
738     _addTarget(target)
739     {
740         let treeElement = new WI.ThreadTreeElement(target);
741         this._callStackTreeOutline.appendChild(treeElement);
742
743         // FIXME: When WI.mainTarget changes?
744         if (target === WI.mainTarget)
745             this._mainTargetTreeElement = treeElement;
746
747         this._updateCallStackTreeOutline();
748     }
749
750     _targetRemoved(event)
751     {
752         let target = event.data.target;
753         let treeElement = this._findThreadTreeElementForTarget(target);
754         this._callStackTreeOutline.removeChild(treeElement);
755
756         this._updateCallStackTreeOutline();
757     }
758
759     _updateCallStackTreeOutline()
760     {
761         let singleThreadShowing = WI.targets.length <= 1;
762         this._callStackTreeOutline.element.classList.toggle("single-thread", singleThreadShowing);
763         if (this._mainTargetTreeElement)
764             this._mainTargetTreeElement.selectable = !singleThreadShowing;
765     }
766
767     _handleDebuggerObjectDisplayLocationDidChange(event)
768     {
769         var debuggerObject = event.target;
770
771         if (event.data.oldDisplaySourceCode === debuggerObject.sourceCodeLocation.displaySourceCode)
772             return;
773
774         var debuggerTreeElement = this._breakpointsContentTreeOutline.getCachedTreeElement(debuggerObject);
775         if (!debuggerTreeElement)
776             return;
777
778         // A known debugger object (breakpoint, issueMessage, etc.) moved between resources, remove the old tree element
779         // and create a new tree element with the updated file.
780
781         var wasSelected = debuggerTreeElement.selected;
782
783         this._removeDebuggerTreeElement(debuggerTreeElement);
784         var newDebuggerTreeElement = this._addDebuggerObject(debuggerObject);
785
786         if (newDebuggerTreeElement && wasSelected)
787             newDebuggerTreeElement.revealAndSelect(true, false, true, true);
788     }
789
790     _removeDebuggerTreeElement(debuggerTreeElement)
791     {
792         // If this is a BreakpointTreeElement being deleted because of a cause
793         // outside of the TreeOutline then deselect if it is selected to avoid
794         // TreeOutline selection changes causing unexpected ContentView changes.
795         if (!debuggerTreeElement.__deletedViaDeleteKeyboardShortcut)
796             debuggerTreeElement.deselect();
797
798         let parentTreeElement = debuggerTreeElement.parent;
799         parentTreeElement.removeChild(debuggerTreeElement);
800
801         if (parentTreeElement.children.length || parentTreeElement === this._breakpointsContentTreeOutline)
802             return;
803
804         parentTreeElement.treeOutline.removeChild(parentTreeElement);
805     }
806
807     _debuggerCallFramesDidChange(event)
808     {
809         let target = event.data.target;
810         let treeElement = this._findThreadTreeElementForTarget(target);
811         treeElement.refresh();
812     }
813
814     _debuggerActiveCallFrameDidChange()
815     {
816         if (this._activeCallFrameTreeElement) {
817             this._activeCallFrameTreeElement.isActiveCallFrame = false;
818             this._activeCallFrameTreeElement = null;
819         }
820
821         if (!WI.debuggerManager.activeCallFrame)
822             return;
823
824         this._activeCallFrameTreeElement = this._callStackTreeOutline.findTreeElement(WI.debuggerManager.activeCallFrame);
825         if (this._activeCallFrameTreeElement)
826             this._activeCallFrameTreeElement.isActiveCallFrame = true;
827     }
828
829     _breakpointsBeneathTreeElement(treeElement)
830     {
831         console.assert(treeElement instanceof WI.ResourceTreeElement || treeElement instanceof WI.ScriptTreeElement);
832         if (!(treeElement instanceof WI.ResourceTreeElement) && !(treeElement instanceof WI.ScriptTreeElement))
833             return [];
834
835         var breakpoints = [];
836         var breakpointTreeElements = treeElement.children;
837         for (var i = 0; i < breakpointTreeElements.length; ++i) {
838             console.assert(breakpointTreeElements[i] instanceof WI.BreakpointTreeElement);
839             console.assert(breakpointTreeElements[i].breakpoint);
840             var breakpoint = breakpointTreeElements[i].breakpoint;
841             if (breakpoint)
842                 breakpoints.push(breakpoint);
843         }
844
845         return breakpoints;
846     }
847
848     _removeAllBreakpoints(breakpoints)
849     {
850         for (var i = 0; i < breakpoints.length; ++i) {
851             var breakpoint = breakpoints[i];
852             if (WI.debuggerManager.isBreakpointRemovable(breakpoint))
853                 WI.debuggerManager.removeBreakpoint(breakpoint);
854         }
855     }
856
857     _toggleAllBreakpoints(breakpoints, disabled)
858     {
859         for (var i = 0; i < breakpoints.length; ++i)
860             breakpoints[i].disabled = disabled;
861     }
862
863     _breakpointTreeOutlineDeleteTreeElement(treeElement)
864     {
865         console.assert(treeElement.selected);
866         console.assert(treeElement instanceof WI.ResourceTreeElement || treeElement instanceof WI.ScriptTreeElement);
867         if (!(treeElement instanceof WI.ResourceTreeElement) && !(treeElement instanceof WI.ScriptTreeElement))
868             return false;
869
870         var wasTopResourceTreeElement = treeElement.previousSibling === this._assertionsBreakpointTreeElement || treeElement.previousSibling === this._allUncaughtExceptionsBreakpointTreeElement;
871         var nextSibling = treeElement.nextSibling;
872
873         var breakpoints = this._breakpointsBeneathTreeElement(treeElement);
874         this._removeAllBreakpoints(breakpoints);
875
876         if (wasTopResourceTreeElement && nextSibling)
877             nextSibling.select(true, true);
878
879         return true;
880     }
881
882     _breakpointTreeOutlineContextMenuTreeElement(contextMenu, event, treeElement)
883     {
884         // This check is necessary since the context menu is created by the TreeOutline, meaning
885         // that any child could be the target of the context menu event.
886         if (!(treeElement instanceof WI.ResourceTreeElement) && !(treeElement instanceof WI.ScriptTreeElement))
887             return;
888
889         let breakpoints = this._breakpointsBeneathTreeElement(treeElement);
890         let shouldDisable = breakpoints.some((breakpoint) => !breakpoint.disabled);
891
892         let removeAllResourceBreakpoints = () => {
893             this._removeAllBreakpoints(breakpoints);
894         };
895
896         let toggleAllResourceBreakpoints = () => {
897             this._toggleAllBreakpoints(breakpoints, shouldDisable);
898         };
899
900         if (shouldDisable)
901             contextMenu.appendItem(WI.UIString("Disable Breakpoints"), toggleAllResourceBreakpoints);
902         else
903             contextMenu.appendItem(WI.UIString("Enable Breakpoints"), toggleAllResourceBreakpoints);
904         contextMenu.appendItem(WI.UIString("Delete Breakpoints"), removeAllResourceBreakpoints);
905     }
906
907     _treeSelectionDidChange(event)
908     {
909         if (!this.selected)
910             return;
911
912         let treeElement = event.target.selectedTreeElement;
913         if (!treeElement)
914             return;
915
916         if (treeElement instanceof WI.DOMNodeTreeElement
917             || treeElement instanceof WI.DOMBreakpointTreeElement
918             || treeElement instanceof WI.EventBreakpointTreeElement
919             || treeElement instanceof WI.XHRBreakpointTreeElement)
920             return;
921
922         const options = {
923             ignoreNetworkTab: true,
924             ignoreSearchTab: true,
925         };
926
927         if (treeElement instanceof WI.ResourceTreeElement || treeElement instanceof WI.ScriptTreeElement) {
928             WI.showSourceCode(treeElement.representedObject, options);
929             return;
930         }
931
932         if (treeElement instanceof WI.CallFrameTreeElement) {
933             let callFrame = treeElement.callFrame;
934             if (callFrame.id)
935                 WI.debuggerManager.activeCallFrame = callFrame;
936
937             if (callFrame.sourceCodeLocation)
938                 WI.showSourceCodeLocation(callFrame.sourceCodeLocation, options);
939
940             return;
941         }
942
943         if (treeElement instanceof WI.IssueTreeElement) {
944             WI.showSourceCodeLocation(treeElement.issueMessage.sourceCodeLocation, options);
945             return;
946         }
947
948         if (!(treeElement instanceof WI.BreakpointTreeElement))
949             return;
950
951         let breakpoint = treeElement.breakpoint;
952         if (treeElement.treeOutline === this._pauseReasonTreeOutline) {
953             WI.showSourceCodeLocation(breakpoint.sourceCodeLocation, options);
954             return;
955         }
956
957         if (!treeElement.parent.representedObject)
958             return;
959
960         console.assert(treeElement.parent.representedObject instanceof WI.SourceCode);
961         if (!(treeElement.parent.representedObject instanceof WI.SourceCode))
962             return;
963
964         WI.showSourceCodeLocation(breakpoint.sourceCodeLocation, options);
965     }
966
967     _addTreeElement(treeElement, parentTreeElement)
968     {
969         if (!parentTreeElement)
970             parentTreeElement = this._breakpointsContentTreeOutline;
971
972         let comparator = (a, b) => {
973             const rankFunctions = [
974                 (treeElement) => treeElement.representedObject === WI.debuggerManager.allExceptionsBreakpoint,
975                 (treeElement) => treeElement.representedObject === WI.debuggerManager.uncaughtExceptionsBreakpoint,
976                 (treeElement) => treeElement.representedObject === WI.debuggerManager.assertionFailuresBreakpoint,
977                 (treeElement) => treeElement.representedObject === WI.domDebuggerManager.allRequestsBreakpoint,
978                 (treeElement) => treeElement instanceof WI.BreakpointTreeElement || treeElement instanceof WI.ResourceTreeElement || treeElement instanceof WI.ScriptTreeElement,
979                 (treeElement) => treeElement instanceof WI.EventBreakpointTreeElement,
980                 (treeElement) => treeElement instanceof WI.DOMNodeTreeElement,
981                 (treeElement) => treeElement instanceof WI.DOMBreakpointTreeElement,
982                 (treeElement) => treeElement instanceof WI.XHRBreakpointTreeElement,
983             ];
984
985             let aRank = rankFunctions.findIndex((rankFunction) => rankFunction(a));
986             let bRank = rankFunctions.findIndex((rankFunction) => rankFunction(b));
987             if (aRank >= 0 && bRank >= 0) {
988                 if (aRank < bRank)
989                     return -1;
990                 if (bRank < aRank)
991                     return 1;
992             }
993
994             if (a instanceof WI.BreakpointTreeElement && b instanceof WI.BreakpointTreeElement)
995                 return this._compareBreakpointTreeElements(a, b);
996
997             return a.mainTitle.extendedLocaleCompare(b.mainTitle) || a.subtitle.extendedLocaleCompare(b.subtitle);
998         };
999
1000         parentTreeElement.insertChild(treeElement, insertionIndexForObjectInListSortedByFunction(treeElement, parentTreeElement.children, comparator));
1001     }
1002
1003     _compareBreakpointTreeElements(a, b)
1004     {
1005         if (!a.representedObject || !b.representedObject)
1006             return 0;
1007
1008         let aLocation = a.representedObject.sourceCodeLocation;
1009         let bLocation = b.representedObject.sourceCodeLocation;
1010         if (!aLocation || !bLocation)
1011             return 0;
1012
1013         var comparisonResult = aLocation.displayLineNumber - bLocation.displayLineNumber;
1014         if (comparisonResult !== 0)
1015             return comparisonResult;
1016
1017         return aLocation.displayColumnNumber - bLocation.displayColumnNumber;
1018     }
1019
1020     _updatePauseReason()
1021     {
1022         this._pauseReasonTreeOutline = null;
1023
1024         this._updatePauseReasonGotoArrow();
1025         return this._updatePauseReasonSection();
1026     }
1027
1028     _updatePauseReasonSection()
1029     {
1030         let target = WI.debuggerManager.activeCallFrame.target;
1031         let targetData = WI.debuggerManager.dataForTarget(target);
1032         let {pauseReason, pauseData} = targetData;
1033
1034         switch (pauseReason) {
1035         case WI.DebuggerManager.PauseReason.AnimationFrame:
1036             console.assert(pauseData, "Expected data with an animation frame, but found none.");
1037             if (!pauseData)
1038                 return false;
1039
1040             var eventBreakpoint = WI.domDebuggerManager.eventBreakpointForTypeAndEventName(WI.EventBreakpoint.Type.AnimationFrame, pauseData.eventName);
1041             console.assert(eventBreakpoint, "Expected AnimationFrame breakpoint for event name.", pauseData.eventName);
1042             if (!eventBreakpoint)
1043                 return false;
1044
1045             var suppressFiltering = true;
1046             this._pauseReasonTreeOutline = this.createContentTreeOutline(suppressFiltering);
1047
1048             var eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(eventBreakpoint, {
1049                 className: WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName,
1050                 title: WI.UIString("%s Fired").format(pauseData.eventName),
1051             });
1052             this._pauseReasonTreeOutline.appendChild(eventBreakpointTreeElement);
1053
1054             var eventBreakpointRow = new WI.DetailsSectionRow;
1055             eventBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1056
1057             this._pauseReasonGroup.rows = [eventBreakpointRow];
1058             return true;
1059
1060         case WI.DebuggerManager.PauseReason.Assertion:
1061             // FIXME: We should include the assertion condition string.
1062             console.assert(pauseData, "Expected data with an assertion, but found none.");
1063             if (pauseData && pauseData.message) {
1064                 this._pauseReasonTextRow.text = WI.UIString("Assertion with message: %s").format(pauseData.message);
1065                 return true;
1066             }
1067
1068             this._pauseReasonTextRow.text = WI.UIString("Assertion Failed");
1069             this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1070             return true;
1071
1072         case WI.DebuggerManager.PauseReason.Breakpoint:
1073             console.assert(pauseData, "Expected breakpoint identifier, but found none.");
1074             if (pauseData && pauseData.breakpointId) {
1075                 const suppressFiltering = true;
1076                 this._pauseReasonTreeOutline = this.createContentTreeOutline(suppressFiltering);
1077                 this._pauseReasonTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._treeSelectionDidChange, this);
1078
1079                 let breakpoint = WI.debuggerManager.breakpointForIdentifier(pauseData.breakpointId);
1080                 let breakpointTreeElement = new WI.BreakpointTreeElement(breakpoint, {
1081                     className: WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName,
1082                     title: WI.UIString("Triggered Breakpoint"),
1083                 });
1084                 let breakpointDetailsSection = new WI.DetailsSectionRow;
1085                 this._pauseReasonTreeOutline.appendChild(breakpointTreeElement);
1086                 breakpointDetailsSection.element.appendChild(this._pauseReasonTreeOutline.element);
1087
1088                 this._pauseReasonGroup.rows = [breakpointDetailsSection];
1089                 return true;
1090             }
1091             break;
1092
1093         case WI.DebuggerManager.PauseReason.CSPViolation:
1094             console.assert(pauseData, "Expected data with a CSP Violation, but found none.");
1095             if (pauseData) {
1096                 // COMPATIBILITY (iOS 8): 'directive' was 'directiveText'.
1097                 this._pauseReasonTextRow.text = WI.UIString("Content Security Policy violation of directive: %s").format(pauseData.directive || pauseData.directiveText);
1098                 this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1099                 return true;
1100             }
1101             break;
1102
1103         case WI.DebuggerManager.PauseReason.DebuggerStatement:
1104             this._pauseReasonTextRow.text = WI.UIString("Debugger Statement");
1105             this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1106             return true;
1107
1108         case WI.DebuggerManager.PauseReason.DOM:
1109             console.assert(WI.domDebuggerManager.supported);
1110             console.assert(pauseData, "Expected DOM breakpoint data, but found none.");
1111             if (pauseData && pauseData.nodeId) {
1112                 let domNode = WI.domManager.nodeForId(pauseData.nodeId);
1113                 let domBreakpoints = WI.domDebuggerManager.domBreakpointsForNode(domNode);
1114                 let domBreakpoint;
1115                 for (let breakpoint of domBreakpoints) {
1116                     if (breakpoint.type === pauseData.type) {
1117                         domBreakpoint = breakpoint;
1118                         break;
1119                     }
1120                 }
1121
1122                 if (!domBreakpoint)
1123                     return;
1124
1125                 const suppressFiltering = true;
1126                 this._pauseReasonTreeOutline = this.createContentTreeOutline(suppressFiltering);
1127
1128                 let type = WI.DOMBreakpointTreeElement.displayNameForType(domBreakpoint.type);
1129                 let domBreakpointTreeElement = new WI.DOMBreakpointTreeElement(domBreakpoint, {
1130                     className: WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName,
1131                     title: type,
1132                 });
1133                 let domBreakpointRow = new WI.DetailsSectionRow;
1134                 this._pauseReasonTreeOutline.appendChild(domBreakpointTreeElement);
1135                 domBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1136
1137                 let ownerElementRow = new WI.DetailsSectionSimpleRow(WI.UIString("Element"), WI.linkifyNodeReference(domNode));
1138                 this._pauseReasonGroup.rows = [domBreakpointRow, ownerElementRow];
1139
1140                 if (domBreakpoint.type !== WI.DOMBreakpoint.Type.SubtreeModified)
1141                     return true;
1142
1143                 console.assert(pauseData.targetNode);
1144
1145                 let remoteObject = WI.RemoteObject.fromPayload(pauseData.targetNode, target);
1146                 remoteObject.pushNodeToFrontend((nodeId) => {
1147                     if (!nodeId)
1148                         return;
1149
1150                     let node = WI.domManager.nodeForId(nodeId);
1151                     console.assert(node, "Missing node for id.", nodeId);
1152                     if (!node)
1153                         return;
1154
1155                     let fragment = document.createDocumentFragment();
1156                     let description = pauseData.insertion ? WI.UIString("Child added to ") : WI.UIString("Removed descendant ");
1157                     fragment.append(description, WI.linkifyNodeReference(node));
1158
1159                     let targetDescriptionRow = new WI.DetailsSectionSimpleRow(WI.UIString("Details"), fragment);
1160                     targetDescriptionRow.element.classList.add("target-description");
1161
1162                     this._pauseReasonGroup.rows = this._pauseReasonGroup.rows.concat(targetDescriptionRow);
1163                 });
1164
1165                 return true;
1166             }
1167             break;
1168
1169         case WI.DebuggerManager.PauseReason.EventListener:
1170             console.assert(pauseData, "Expected data with an event listener, but found none.");
1171             if (!pauseData)
1172                 return false;
1173
1174             var eventBreakpoint = null;
1175             if (pauseData.eventListenerId)
1176                 eventBreakpoint = WI.domManager.breakpointForEventListenerId(pauseData.eventListenerId);
1177             if (!eventBreakpoint)
1178                 eventBreakpoint = WI.domDebuggerManager.eventBreakpointForTypeAndEventName(WI.EventBreakpoint.Type.Listener, pauseData.eventName);
1179
1180             console.assert(eventBreakpoint, "Expected Event Listener breakpoint for event name.", pauseData.eventName);
1181             if (!eventBreakpoint)
1182                 return false;
1183
1184             var suppressFiltering = true;
1185             this._pauseReasonTreeOutline = this.createContentTreeOutline(suppressFiltering);
1186
1187             var eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(eventBreakpoint, {
1188                 className: WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName,
1189                 title: WI.UIString("ā€œ%sā€œ Event Fired").format(pauseData.eventName),
1190             });
1191             this._pauseReasonTreeOutline.appendChild(eventBreakpointTreeElement);
1192
1193             var eventBreakpointRow = new WI.DetailsSectionRow;
1194             eventBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1195
1196             var rows = [eventBreakpointRow];
1197
1198             var eventListener = eventBreakpoint.eventListener;
1199             if (eventListener) {
1200                 console.assert(eventListener.eventListenerId === pauseData.eventListenerId);
1201
1202                 let ownerElementRow = new WI.DetailsSectionSimpleRow(WI.UIString("Element"), WI.linkifyNodeReference(eventListener.node));
1203                 rows.push(ownerElementRow);
1204             }
1205
1206             this._pauseReasonGroup.rows = rows;
1207             return true;
1208
1209         case WI.DebuggerManager.PauseReason.Exception:
1210             console.assert(pauseData, "Expected data with an exception, but found none.");
1211             if (pauseData) {
1212                 // FIXME: We should improve the appearance of thrown objects. This works well for exception strings.
1213                 var data = WI.RemoteObject.fromPayload(pauseData, target);
1214                 this._pauseReasonTextRow.text = WI.UIString("Exception with thrown value: %s").format(data.description);
1215                 this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1216                 return true;
1217             }
1218             break;
1219
1220         case WI.DebuggerManager.PauseReason.PauseOnNextStatement:
1221             this._pauseReasonTextRow.text = WI.UIString("Immediate Pause Requested");
1222             this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1223             return true;
1224
1225         case WI.DebuggerManager.PauseReason.Timer:
1226             console.assert(pauseData, "Expected data with a timer, but found none.");
1227             if (!pauseData)
1228                 return false;
1229
1230             var eventBreakpoint = WI.domDebuggerManager.eventBreakpointForTypeAndEventName(WI.EventBreakpoint.Type.Timer, pauseData.eventName);
1231             console.assert(eventBreakpoint, "Expected Timer breakpoint for event name.", pauseData.eventName);
1232             if (!eventBreakpoint)
1233                 return false;
1234
1235             var suppressFiltering = true;
1236             this._pauseReasonTreeOutline = this.createContentTreeOutline(suppressFiltering);
1237
1238             var eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(eventBreakpoint, {
1239                 className: WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName,
1240                 title: WI.UIString("%s Fired").format(pauseData.eventName),
1241             });
1242             this._pauseReasonTreeOutline.appendChild(eventBreakpointTreeElement);
1243
1244             var eventBreakpointRow = new WI.DetailsSectionRow;
1245             eventBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1246
1247             this._pauseReasonGroup.rows = [eventBreakpointRow];
1248             return true;
1249
1250         case WI.DebuggerManager.PauseReason.XHR:
1251             console.assert(WI.domDebuggerManager.supported);
1252             console.assert(pauseData, "Expected XHR breakpoint data, but found none.");
1253             if (pauseData) {
1254                 if (pauseData.breakpointURL) {
1255                     let xhrBreakpoint = WI.domDebuggerManager.xhrBreakpointForURL(pauseData.breakpointURL);
1256                     console.assert(xhrBreakpoint, "Expected XHR breakpoint for URL.", pauseData.breakpointURL);
1257
1258                     this._pauseReasonTreeOutline = this.createContentTreeOutline(true);
1259
1260                     let xhrBreakpointTreeElement = new WI.XHRBreakpointTreeElement(xhrBreakpoint, {
1261                         className: WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName,
1262                         title: WI.UIString("Triggered XHR Breakpoint"),
1263                     });
1264                     let xhrBreakpointRow = new WI.DetailsSectionRow;
1265                     this._pauseReasonTreeOutline.appendChild(xhrBreakpointTreeElement);
1266                     xhrBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1267
1268                     this._pauseReasonTextRow.text = pauseData.url;
1269                     this._pauseReasonGroup.rows = [xhrBreakpointRow, this._pauseReasonTextRow];
1270                 } else {
1271                     console.assert(pauseData.breakpointURL === "", "Should be the All Requests breakpoint which has an empty URL");
1272                     this._pauseReasonTextRow.text = WI.UIString("Requesting: %s").format(pauseData.url);
1273                     this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
1274                 }
1275                 this._pauseReasonTextRow.element.title = pauseData.url;
1276                 return true;
1277             }
1278             break;
1279
1280         case WI.DebuggerManager.PauseReason.Other:
1281             console.error("Paused for unknown reason. We should always have a reason.");
1282             break;
1283         }
1284
1285         return false;
1286     }
1287
1288     _updatePauseReasonGotoArrow()
1289     {
1290         this._pauseReasonLinkContainerElement.removeChildren();
1291
1292         var activeCallFrame = WI.debuggerManager.activeCallFrame;
1293         if (!activeCallFrame)
1294             return;
1295
1296         var sourceCodeLocation = activeCallFrame.sourceCodeLocation;
1297         if (!sourceCodeLocation)
1298             return;
1299
1300         const options = {
1301             useGoToArrowButton: true,
1302             ignoreNetworkTab: true,
1303             ignoreSearchTab: true,
1304         };
1305         let linkElement = WI.createSourceCodeLocationLink(sourceCodeLocation, options);
1306         this._pauseReasonLinkContainerElement.appendChild(linkElement);
1307     }
1308
1309     _addDebuggerObject(debuggerObject)
1310     {
1311         if (debuggerObject instanceof WI.Breakpoint)
1312             return this._addBreakpoint(debuggerObject);
1313
1314         if (debuggerObject instanceof WI.IssueMessage)
1315             return this._addIssue(debuggerObject);
1316
1317         return null;
1318     }
1319
1320     _addIssue(issueMessage)
1321     {
1322         let issueTreeElement = this._scriptsContentTreeOutline.findTreeElement(issueMessage);
1323         if (issueTreeElement)
1324             return issueTreeElement;
1325
1326         let parentTreeElement = this._addTreeElementForSourceCodeToTreeOutline(issueMessage.sourceCodeLocation.sourceCode, this._scriptsContentTreeOutline);
1327         if (!parentTreeElement)
1328             return null;
1329
1330         issueTreeElement = new WI.IssueTreeElement(issueMessage);
1331
1332         parentTreeElement.insertChild(issueTreeElement, insertionIndexForObjectInListSortedByFunction(issueTreeElement, parentTreeElement.children, this._compareBreakpointTreeElements));
1333         if (parentTreeElement.children.length === 1)
1334             parentTreeElement.expand();
1335
1336         return issueTreeElement;
1337     }
1338
1339     _domBreakpointResolvedStateDidChange(event)
1340     {
1341         let breakpoint = event.target;
1342         if (breakpoint.domNodeIdentifier)
1343             this._addBreakpoint(breakpoint);
1344         else
1345             this._removeBreakpoint(breakpoint);
1346     }
1347
1348     _handleIssueAdded(event)
1349     {
1350         var issue = event.data.issue;
1351
1352         // We only want to show issues originating from JavaScript source code.
1353         if (!issue.sourceCodeLocation || !issue.sourceCodeLocation.sourceCode || (issue.source !== "javascript" && issue.source !== "console-api"))
1354             return;
1355
1356         this._addIssue(issue);
1357     }
1358
1359     _handleIssuesCleared(event)
1360     {
1361         let currentTreeElement = this._scriptsContentTreeOutline.children[0];
1362         let issueTreeElements = [];
1363
1364         while (currentTreeElement && !currentTreeElement.root) {
1365             if (currentTreeElement instanceof WI.IssueTreeElement)
1366                 issueTreeElements.push(currentTreeElement);
1367             currentTreeElement = currentTreeElement.traverseNextTreeElement(false, null, true);
1368         }
1369
1370         issueTreeElements.forEach((treeElement) => treeElement.parent.removeChild(treeElement));
1371     }
1372
1373     _handleBreakpointElementAddedOrRemoved(event)
1374     {
1375         let treeElement = event.data.element;
1376
1377         let setting = null;
1378         if (treeElement.breakpoint === WI.debuggerManager.assertionFailuresBreakpoint)
1379             setting = WI.settings.showAssertionFailuresBreakpoint;
1380         else if (treeElement.representedObject === WI.domDebuggerManager.allRequestsBreakpoint)
1381             setting = WI.settings.showAllRequestsBreakpoint;
1382
1383         if (setting)
1384             setting.value = !!treeElement.parent;
1385     }
1386
1387     _handleCreateBreakpointClicked(event)
1388     {
1389         let contextMenu = WI.ContextMenu.createFromEvent(event.data.nativeEvent);
1390
1391         // COMPATIBILITY (iOS 10): DebuggerAgent.setPauseOnAssertions did not exist yet.
1392         if (InspectorBackend.domains.Debugger.setPauseOnAssertions) {
1393             let assertionFailuresBreakpointShown = WI.settings.showAssertionFailuresBreakpoint.value;
1394
1395             contextMenu.appendCheckboxItem(WI.UIString("Assertion Failures"), () => {
1396                 if (assertionFailuresBreakpointShown)
1397                     WI.debuggerManager.removeBreakpoint(WI.debuggerManager.assertionFailuresBreakpoint);
1398                 else {
1399                     WI.debuggerManager.assertionFailuresBreakpoint.disabled = false;
1400                     WI.debuggerManager.addBreakpoint(WI.debuggerManager.assertionFailuresBreakpoint);
1401                 }
1402             }, assertionFailuresBreakpointShown);
1403         }
1404
1405         if (WI.domDebuggerManager.supported) {
1406             contextMenu.appendSeparator();
1407
1408             contextMenu.appendItem(WI.UIString("Event Breakpoint\u2026"), () => {
1409                 let popover = new WI.EventBreakpointPopover(this);
1410                 popover.show(event.target.element, [WI.RectEdge.MAX_Y, WI.RectEdge.MIN_Y, WI.RectEdge.MAX_X]);
1411             });
1412
1413             contextMenu.appendSeparator();
1414
1415             let allRequestsBreakpointShown = WI.settings.showAllRequestsBreakpoint.value;
1416
1417             contextMenu.appendCheckboxItem(WI.UIString("All Requests"), () => {
1418                 if (allRequestsBreakpointShown)
1419                     WI.domDebuggerManager.removeXHRBreakpoint(WI.domDebuggerManager.allRequestsBreakpoint);
1420                 else {
1421                     WI.domDebuggerManager.allRequestsBreakpoint.disabled = false;
1422                     WI.domDebuggerManager.addXHRBreakpoint(WI.domDebuggerManager.allRequestsBreakpoint);
1423                 }
1424             }, allRequestsBreakpointShown);
1425
1426             contextMenu.appendItem(WI.UIString("XHR Breakpoint\u2026"), () => {
1427                 let popover = new WI.XHRBreakpointPopover(this);
1428                 popover.show(event.target.element, [WI.RectEdge.MAX_Y, WI.RectEdge.MIN_Y, WI.RectEdge.MAX_X]);
1429             });
1430         }
1431
1432         contextMenu.show();
1433     }
1434 };
1435
1436 WI.DebuggerSidebarPanel.DebuggerPausedStyleClassName = "paused";
1437 WI.DebuggerSidebarPanel.ExceptionIconStyleClassName = "breakpoint-exception-icon";
1438 WI.DebuggerSidebarPanel.AssertionIconStyleClassName = "breakpoint-assertion-icon";
1439 WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName = "breakpoint-paused-icon";
1440
1441 WI.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey = "debugger-sidebar-panel-all-exceptions-breakpoint";
1442 WI.DebuggerSidebarPanel.SelectedUncaughtExceptionsCookieKey = "debugger-sidebar-panel-uncaught-exceptions-breakpoint";
1443 WI.DebuggerSidebarPanel.SelectedAssertionFailuresCookieKey = "debugger-sidebar-panel-assertion-failures-breakpoint";
1444 WI.DebuggerSidebarPanel.SelectedAllRequestsCookieKey = "debugger-sidebar-panel-all-requests-breakpoint";