<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[234974] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/234974">234974</a></dd>
<dt>Author</dt> <dd>drousso@apple.com</dd>
<dt>Date</dt> <dd>2018-08-16 19:37:46 -0700 (Thu, 16 Aug 2018)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: support breakpoints for arbitrary event names
https://bugs.webkit.org/show_bug.cgi?id=183118

Reviewed by Joseph Pecoraro.

Source/WebCore:

Tests: inspector/dom-debugger/event-breakpoints.html
       inspector/dom-debugger/event-breakpoints-with-navigation.html

* inspector/agents/InspectorDOMDebuggerAgent.cpp:
(WebCore::InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded):

Source/WebInspectorUI:

Create UI for setting breakpoints on event names. Ties into renamed DOMDebugger commands,
specifically `setEventBreakpoint` and `removeEventBreakpoint`, that will pause execution if
any DOM event is fired that matches any previously registered breakpoints.

Event breakpoints are distinguished by name, and they currently apply globally, meaning
that only one breakpoint per event name can be registered.

Event breakpoints are created in the Debugger tab in a new "Event Breakpoints" section in
the Navigation sidebar. A new type of popover, EventBreakpointPopover, is used, but right
now all it contains is a basic text input for the event name. Similarly, a new TreeElement
subclass, EventBreakpointTreeElement, is used when showing the list of event listener
breakpoints, but all it shows now is the event name.

The majority of the logic in this patch was derived from XHR breakpoints.

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Main.html:
* UserInterface/Test.html:
* UserInterface/Images/EventBreakpoint.svg: Added.

* UserInterface/Models/EventBreakpoint.js: Added.
(WI.EventBreakpoint):
(WI.EventBreakpoint.prototype.get eventName):
(WI.EventBreakpoint.prototype.get disabled):
(WI.EventBreakpoint.prototype.set disabled):
(WI.EventBreakpoint.prototype.get serializableInfo):
(WI.EventBreakpoint.prototype.saveIdentityToCookie):

* UserInterface/Controllers/DOMDebuggerManager.js:
(WI.DOMDebuggerManager):
(WI.DOMDebuggerManager.prototype.get eventBreakpoints): Added.
(WI.DOMDebuggerManager.prototype.eventBreakpointForEventName): Added.
(WI.DOMDebuggerManager.prototype.addEventBreakpoint): Added.
(WI.DOMDebuggerManager.prototype.removeEventBreakpoint): Added.
(WI.DOMDebuggerManager.prototype._speculativelyResolveBreakpoints):
(WI.DOMDebuggerManager.prototype._updateEventBreakpoint.breakpointUpdated): Added.
(WI.DOMDebuggerManager.prototype._updateEventBreakpoint): Added.
(WI.DOMDebuggerManager.prototype._resolveEventBreakpoint): Added.
(WI.DOMDebuggerManager.prototype._saveEventBreakpoints): Added.
(WI.DOMDebuggerManager.prototype._eventBreakpointDisabledStateDidChange): Added.

* UserInterface/Controllers/DebuggerManager.js:
(WI.DebuggerManager.prototype._pauseReasonFromPayload):

* UserInterface/Controllers/EventBreakpointTreeController.js: Added.
(WI.EventBreakpointTreeController):
(WI.EventBreakpointTreeController.prototype.revealAndSelect):
(WI.EventBreakpointTreeController.prototype._eventBreakpointAdded):
(WI.EventBreakpointTreeController.prototype._eventBreakpointRemoved):
(WI.EventBreakpointTreeController.prototype._addTreeElement):

* UserInterface/Views/DebuggerSidebarPanel.js:
(WI.DebuggerSidebarPanel):
(WI.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
(WI.DebuggerSidebarPanel.prototype._eventBreakpointAddedOrRemoved): Added.
(WI.DebuggerSidebarPanel.prototype._addEventBreakpointButtonClicked): Added.
(WI.DebuggerSidebarPanel.prototype.willDismissPopover):

* UserInterface/Views/EventBreakpointTreeElement.js: Added.
(WI.EventBreakpointTreeElement):
(WI.EventBreakpointTreeElement.prototype.onattach):
(WI.EventBreakpointTreeElement.prototype.ondetach):
(WI.EventBreakpointTreeElement.prototype.ondelete):
(WI.EventBreakpointTreeElement.prototype.onenter):
(WI.EventBreakpointTreeElement.prototype.onspace):
(WI.EventBreakpointTreeElement.prototype.populateContextMenu):
(WI.EventBreakpointTreeElement.prototype._statusImageElementClicked):
(WI.EventBreakpointTreeElement.prototype._statusImageElementFocused):
(WI.EventBreakpointTreeElement.prototype._statusImageElementMouseDown):
(WI.EventBreakpointTreeElement.prototype._toggleBreakpoint):
(WI.EventBreakpointTreeElement.prototype._updateStatus):
* UserInterface/Views/EventBreakpointTreeElement.css: Added.
(.breakpoint.event-listener:not(.breakpoint-paused-icon) .icon):

* UserInterface/Views/EventBreakpointPopover.js: Added.
(WI.EventBreakpointPopover):
(WI.EventBreakpointPopover.prototype.get result):
(WI.EventBreakpointPopover.prototype.get value):
(WI.EventBreakpointPopover.prototype.show):
(WI.EventBreakpointPopover.prototype._presentOverTargetElement):
* UserInterface/Views/EventBreakpointPopover.css: Added.
(.popover .event-listener-breakpoint-content):
(.popover .event-listener-breakpoint-content > input):

* UserInterface/Views/NavigationSidebarPanel.js:
(WI.NavigationSidebarPanel.prototype._isTreeElementWithoutRepresentedObject):

LayoutTests:

* inspector/dom-debugger/event-breakpoints-expected.txt: Added.
* inspector/dom-debugger/event-breakpoints.html: Added.

* inspector/dom-debugger/event-breakpoints-with-navigation-expected.txt: Added.
* inspector/dom-debugger/event-breakpoints-with-navigation.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreinspectoragentsInspectorDOMDebuggerAgentcpp">trunk/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp</a></li>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs">trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersDOMDebuggerManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersDebuggerManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceMainhtml">trunk/Source/WebInspectorUI/UserInterface/Main.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceTesthtml">trunk/Source/WebInspectorUI/UserInterface/Test.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsDebuggerSidebarPaneljs">trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNavigationSidebarPaneljs">trunk/Source/WebInspectorUI/UserInterface/Views/NavigationSidebarPanel.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsinspectordomdebuggereventbreakpointwithnavigationexpectedtxt">trunk/LayoutTests/inspector/dom-debugger/event-breakpoint-with-navigation-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectordomdebuggereventbreakpointwithnavigationhtml">trunk/LayoutTests/inspector/dom-debugger/event-breakpoint-with-navigation.html</a></li>
<li><a href="#trunkLayoutTestsinspectordomdebuggereventbreakpointsexpectedtxt">trunk/LayoutTests/inspector/dom-debugger/event-breakpoints-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectordomdebuggereventbreakpointshtml">trunk/LayoutTests/inspector/dom-debugger/event-breakpoints.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersEventBreakpointTreeControllerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/EventBreakpointTreeController.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceImagesEventBreakpointsvg">trunk/Source/WebInspectorUI/UserInterface/Images/EventBreakpoint.svg</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsEventBreakpointjs">trunk/Source/WebInspectorUI/UserInterface/Models/EventBreakpoint.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsEventBreakpointPopovercss">trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointPopover.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsEventBreakpointPopoverjs">trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointPopover.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsEventBreakpointTreeElementcss">trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsEventBreakpointTreeElementjs">trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/LayoutTests/ChangeLog 2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2018-08-16  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: support breakpoints for arbitrary event names
+        https://bugs.webkit.org/show_bug.cgi?id=183118
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/dom-debugger/event-breakpoints-expected.txt: Added.
+        * inspector/dom-debugger/event-breakpoints.html: Added.
+
+        * inspector/dom-debugger/event-breakpoints-with-navigation-expected.txt: Added.
+        * inspector/dom-debugger/event-breakpoints-with-navigation.html: Added.
+
</ins><span class="cx"> 2018-08-16  Basuke Suzuki  <Basuke.Suzuki@sony.com>
</span><span class="cx"> 
</span><span class="cx">         [Curl] Bug fix on deleting cookies when Max-Age is set to zero.
</span></span></pre></div>
<a id="trunkLayoutTestsinspectordomdebuggereventbreakpointwithnavigationexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/dom-debugger/event-breakpoint-with-navigation-expected.txt (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/dom-debugger/event-breakpoint-with-navigation-expected.txt                           (rev 0)
+++ trunk/LayoutTests/inspector/dom-debugger/event-breakpoint-with-navigation-expected.txt      2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+Tests for Event Listener breakpoints.
+
+
+== Running test suite: DOMDebugger.EventWithNavigation
+-- Running test case: DOMDebugger.EventWithNavigation.AddBreakpoint
+Adding "load" Event Breakpoint...
+Reloading WebInspector...
+PASS: Pause reason should be EventListener.
+PASS: Pause data eventName should be "load".
+-- Running test teardown.
+
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectordomdebuggereventbreakpointwithnavigationhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/dom-debugger/event-breakpoint-with-navigation.html (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/dom-debugger/event-breakpoint-with-navigation.html                           (rev 0)
+++ trunk/LayoutTests/inspector/dom-debugger/event-breakpoint-with-navigation.html      2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,80 @@
</span><ins>+<!doctype html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script>
+function handleLoad(event) {
+    TestPage.dispatchEventToFrontend("TestPageLoad");
+
+    runTest();
+}
+
+function test() {
+    let suite = InspectorTest.createAsyncSuite("DOMDebugger.EventWithNavigation");
+
+    suite.addTestCase({
+        name: `DOMDebugger.EventWithNavigation.AddBreakpoint`,
+        description: "Check that a breakpoint is preserved over navigation.",
+        test(resolve, reject) {
+            let paused = false;
+
+            let listener = WI.debuggerManager.singleFireEventListener(WI.DebuggerManager.Event.Paused, (event) => {
+                paused = true;
+
+                let targetData = WI.debuggerManager.dataForTarget(WI.debuggerManager.activeCallFrame.target);
+                InspectorTest.expectEqual(targetData.pauseReason, WI.DebuggerManager.PauseReason.EventListener, "Pause reason should be EventListener.");
+                InspectorTest.expectEqual(targetData.pauseData.eventName, "load", "Pause data eventName should be \"load\".");
+
+                WI.debuggerManager.resume()
+                .catch((reason) => {
+                    InspectorTest.fail(reason);
+                    resolve();
+                });
+            });
+
+            InspectorTest.singleFireEventListener("TestPageLoad", (event) => {
+                if (!paused) {
+                    WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
+
+                    InspectorTest.fail("Should pause before \"load\" event handler is run");
+                }
+
+                resolve();
+            });
+
+            InspectorTest.log("Adding \"load\" Event Breakpoint...");
+
+            let breakpoint = new WI.EventBreakpoint("load");
+
+            WI.domDebuggerManager.awaitEvent(WI.DOMDebuggerManager.Event.EventBreakpointAdded)
+            .then((event) => {
+                InspectorTest.assert(event.data.breakpoint.eventName, "load", "Breakpoint should be for expected event name.");
+
+                InspectorTest.log("Reloading WebInspector...");
+                return InspectorTest.reloadPage();
+            })
+            .catch(reject);
+
+            WI.domDebuggerManager.addEventBreakpoint(breakpoint);
+        },
+        teardown(resolve, reject) {
+            let breakpoints = WI.domDebuggerManager.eventBreakpoints;
+            for (let breakpoint of breakpoints)
+                WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
+
+            resolve();
+        },
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body>
+    <p>Tests for Event Listener breakpoints.</p>
+    <div id="x"></div>
+    <script>
+        window.addEventListener("load", handleLoad);
+    </script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectordomdebuggereventbreakpointsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/dom-debugger/event-breakpoints-expected.txt (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/dom-debugger/event-breakpoints-expected.txt                          (rev 0)
+++ trunk/LayoutTests/inspector/dom-debugger/event-breakpoints-expected.txt     2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,83 @@
</span><ins>+Tests for Event Listener breakpoints.
+
+
+== Running test suite: DOMDebugger.Event
+-- Running test case: DOMDebugger.Event.AddBreakpoint "click"
+Adding "click" Event Breakpoint...
+Firing "click" on body...
+PASS: Should pause before event handler is run.
+CALL STACK:
+0: [F] handleBody_click
+1: [F] bodyFire_click
+2: [P] Global Code
+-- Running test teardown.
+
+-- Running test case: DOMDebugger.Event.AddDisabledBreakpoint "click"
+Adding "click" Event Breakpoint...
+Disabling "click" Event Breakpoint...
+Firing "click" on body...
+PASS: Should not pause for disabled breakpoint.
+-- Running test teardown.
+
+-- Running test case: DOMDebugger.Event.RemoveBreakpoint "click"
+Adding "click" Event Breakpoint...
+Removing "click" Event Breakpoint...
+Firing "click" on body...
+PASS: Should not pause for removed breakpoint.
+-- Running test teardown.
+
+-- Running test case: DOMDebugger.Event.RemoveDisabledBreakpoint "click"
+Adding "click" Event Breakpoint...
+Disabling "click" Event Breakpoint...
+Removing "click" Event Breakpoint...
+Firing "click" on body...
+PASS: Should not pause for removed disabled breakpoint.
+-- Running test teardown.
+
+-- Running test case: DOMDebugger.Event.AddBreakpoint "custom"
+Adding "custom" Event Breakpoint...
+Firing "custom" on body...
+PASS: Should pause before event handler is run.
+CALL STACK:
+0: [F] handleBody_custom
+1: [F] bodyFire_custom
+2: [P] Global Code
+-- Running test teardown.
+
+-- Running test case: DOMDebugger.Event.AddDisabledBreakpoint "custom"
+Adding "custom" Event Breakpoint...
+Disabling "custom" Event Breakpoint...
+Firing "custom" on body...
+PASS: Should not pause for disabled breakpoint.
+-- Running test teardown.
+
+-- Running test case: DOMDebugger.Event.RemoveBreakpoint "custom"
+Adding "custom" Event Breakpoint...
+Removing "custom" Event Breakpoint...
+Firing "custom" on body...
+PASS: Should not pause for removed breakpoint.
+-- Running test teardown.
+
+-- Running test case: DOMDebugger.Event.RemoveDisabledBreakpoint "custom"
+Adding "custom" Event Breakpoint...
+Disabling "custom" Event Breakpoint...
+Removing "custom" Event Breakpoint...
+Firing "custom" on body...
+PASS: Should not pause for removed disabled breakpoint.
+-- Running test teardown.
+
+-- Running test case: DOMDebugger.Event.AddMultipleBreakpoints
+Adding "click" Event Breakpoint...
+Firing "click" on div#x...
+PASS: Should pause before event handler is run.
+CALL STACK:
+0: [F] handleX_click
+1: [F] xFire_click
+2: [P] Global Code
+PASS: Should pause before event handler is run.
+CALL STACK:
+0: [F] handleBody_click
+1: [F] xFire_click
+2: [P] Global Code
+-- Running test teardown.
+
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectordomdebuggereventbreakpointshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/dom-debugger/event-breakpoints.html (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/dom-debugger/event-breakpoints.html                          (rev 0)
+++ trunk/LayoutTests/inspector/dom-debugger/event-breakpoints.html     2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,249 @@
</span><ins>+<!doctype html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script src="../debugger/resources/log-active-stack-trace.js"></script>
+<script>
+function handleBody_click(event) {
+    TestPage.dispatchEventToFrontend("TestPageBody-click");
+}
+
+function handleBody_custom(event) {
+    TestPage.dispatchEventToFrontend("TestPageBody-custom");
+}
+
+function handleX_click(event) {
+    TestPage.dispatchEventToFrontend("TestPageX-click");
+}
+
+function bodyFire_click() {
+    document.body.click();
+}
+
+function bodyFire_custom() {
+    document.body.dispatchEvent(new Event("custom"));
+}
+
+function xFire_click() {
+    document.getElementById("x").click();
+}
+
+function test() {
+    let suite = InspectorTest.createAsyncSuite("DOMDebugger.Event");
+
+    function teardown(resolve, reject) {
+        let breakpoints = WI.domDebuggerManager.eventBreakpoints;
+        for (let breakpoint of breakpoints)
+            WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
+
+        resolve();
+    }
+
+    function awaitBodyEvent(eventName) {
+        return function() {
+            InspectorTest.log(`Firing "${eventName}" on body...`);
+            return InspectorTest.evaluateInPage(`bodyFire_${eventName}()`);
+        };
+    }
+
+    function failOnPause(resolve, eventName, message) {
+        let paused = false;
+
+        let listener = WI.debuggerManager.singleFireEventListener(WI.DebuggerManager.Event.Paused, (event) => {
+            paused = true;
+
+            let targetData = WI.debuggerManager.dataForTarget(WI.debuggerManager.activeCallFrame.target);
+            InspectorTest.assert(targetData.pauseReason === WI.DebuggerManager.PauseReason.EventListener, "Pause reason should be EventListener.");
+            InspectorTest.assert(targetData.pauseData.eventName === eventName, `Pause data eventName should be "${eventName}".`);
+
+            InspectorTest.fail(message);
+            logActiveStackTrace();
+
+            WI.debuggerManager.resume()
+            .catch((reason) => {
+                InspectorTest.fail(reason);
+                resolve();
+            });
+        });
+
+        InspectorTest.singleFireEventListener("TestPageBody-" + eventName, (event) => {
+            if (!paused) {
+                WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
+
+                InspectorTest.pass(message);
+            }
+
+            resolve();
+        });
+    }
+
+    function addBreakpoint(eventName) {
+        InspectorTest.log(`Adding "${eventName}" Event Breakpoint...`);
+
+        return new Promise((resolve, reject) => {
+            let breakpoint = new WI.EventBreakpoint(eventName);
+
+            WI.domDebuggerManager.awaitEvent(WI.DOMDebuggerManager.Event.EventBreakpointAdded)
+            .then((event) => {
+                InspectorTest.assert(event.data.breakpoint.eventName === eventName, "Breakpoint should be for expected event name.");
+                InspectorTest.assert(!breakpoint.disabled, "Breakpoint should not be disabled initially.");
+                resolve(breakpoint);
+            });
+
+            WI.domDebuggerManager.addEventBreakpoint(breakpoint);
+        });
+    }
+
+    function removeBreakpoint(breakpoint) {
+        InspectorTest.log(`Removing "${breakpoint.eventName}" Event Breakpoint...`);
+
+        return new Promise((resolve, reject) => {
+            WI.domDebuggerManager.awaitEvent(WI.DOMDebuggerManager.Event.EventBreakpointRemoved)
+            .then((event) => {
+                InspectorTest.assert(event.data.breakpoint === breakpoint, "Removed Breakpoint should be expected object.");
+                InspectorTest.assert(!WI.domDebuggerManager.eventBreakpoints.includes(breakpoint), "Breakpoint should not be in the list of breakpoints.");
+                resolve(breakpoint);
+            });
+
+            WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
+        });
+    }
+
+    function disableBreakpoint(breakpoint) {
+        InspectorTest.log(`Disabling "${breakpoint.eventName}" Event Breakpoint...`);
+
+        breakpoint.disabled = true;
+        return breakpoint;
+    }
+
+    function addTestCasesForEventName(eventName) {
+        suite.addTestCase({
+            name: `DOMDebugger.Event.AddBreakpoint "${eventName}"`,
+            description: "Check that the debugger pauses for enabled breakpoints.",
+            teardown,
+            test(resolve, reject) {
+                let paused = false;
+
+                let listener = WI.debuggerManager.singleFireEventListener(WI.DebuggerManager.Event.Paused, (event) => {
+                    paused = true;
+
+                    InspectorTest.pass("Should pause before event handler is run.");
+                    logActiveStackTrace();
+
+                    WI.debuggerManager.resume();
+                });
+
+                InspectorTest.singleFireEventListener(`TestPageBody-${eventName}`, (event) => {
+                    if (!paused) {
+                        WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
+
+                        InspectorTest.fail("Should pause before event handler is run.");
+                    }
+
+                    resolve();
+                });
+
+                addBreakpoint(eventName)
+                .then(awaitBodyEvent(eventName))
+                .catch(reject);
+            },
+        });
+
+        suite.addTestCase({
+            name: `DOMDebugger.Event.AddDisabledBreakpoint "${eventName}"`,
+            description: "Check that debugger does the not pause for disabled breakpoints.",
+            teardown,
+            test(resolve, reject) {
+                failOnPause(resolve, eventName, "Should not pause for disabled breakpoint.");
+
+                addBreakpoint(eventName)
+                .then(disableBreakpoint)
+                .then(awaitBodyEvent(eventName))
+                .catch(reject);
+            },
+        });
+
+        suite.addTestCase({
+            name: `DOMDebugger.Event.RemoveBreakpoint "${eventName}"`,
+            description: "Check that debugger does not pause for removed breakpoint.",
+            teardown,
+            test(resolve, reject) {
+                failOnPause(resolve, eventName, "Should not pause for removed breakpoint.");
+
+                addBreakpoint(eventName)
+                .then(removeBreakpoint)
+                .then(awaitBodyEvent(eventName))
+                .catch(reject);
+            },
+        });
+
+        suite.addTestCase({
+            name: `DOMDebugger.Event.RemoveDisabledBreakpoint "${eventName}"`,
+            description: "Check that a disabled breakpoint can be removed.",
+            teardown,
+            test(resolve, reject) {
+                failOnPause(resolve, eventName, "Should not pause for removed disabled breakpoint.");
+
+                addBreakpoint(eventName)
+                .then(disableBreakpoint)
+                .then(removeBreakpoint)
+                .then(awaitBodyEvent(eventName))
+                .catch(reject);
+            },
+        });
+
+    }
+
+    addTestCasesForEventName("click");
+    addTestCasesForEventName("custom");
+
+    suite.addTestCase({
+        name: `DOMDebugger.Event.AddMultipleBreakpoints`,
+        description: "Check that a single breakpoint pauses for every event of that type.",
+        teardown,
+        test(resolve, reject) {
+            let pauseCount = 0;
+
+            let listener = WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, (event) => {
+                ++pauseCount;
+
+                InspectorTest.pass("Should pause before event handler is run.");
+                logActiveStackTrace();
+
+                WI.debuggerManager.resume()
+                .catch((reason) => {
+                    InspectorTest.fail(reason);
+                    resolve();
+                });
+
+                if (pauseCount >= 2) {
+                    WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
+
+                    resolve();
+                }
+            });
+
+            addBreakpoint("click")
+            .then(() => {
+                InspectorTest.log("Firing \"click\" on div#x...");
+                return InspectorTest.evaluateInPage(`xFire_click()`);
+            })
+            .catch(reject);
+        },
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Tests for Event Listener breakpoints.</p>
+    <div id="x"></div>
+    <script>
+        document.body.addEventListener("click", handleBody_click);
+        document.body.addEventListener("custom", handleBody_custom);
+
+        document.getElementById("x").addEventListener("click", handleX_click);
+    </script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebCore/ChangeLog      2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2018-08-16  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: support breakpoints for arbitrary event names
+        https://bugs.webkit.org/show_bug.cgi?id=183118
+
+        Reviewed by Joseph Pecoraro.
+
+        Tests: inspector/dom-debugger/event-breakpoints.html
+               inspector/dom-debugger/event-breakpoints-with-navigation.html
+
+        * inspector/agents/InspectorDOMDebuggerAgent.cpp:
+        (WebCore::InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded):
+
</ins><span class="cx"> 2018-08-16  Basuke Suzuki  <Basuke.Suzuki@sony.com>
</span><span class="cx"> 
</span><span class="cx">         [Curl] Bug fix on deleting cookies when Max-Age is set to zero.
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectoragentsInspectorDOMDebuggerAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp      2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp 2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -371,7 +371,7 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     Ref<JSON::Object> eventData = JSON::Object::create();
</span><del>-    eventData->setString("eventName"_s, fullEventName);
</del><ins>+    eventData->setString("eventName"_s, eventName);
</ins><span class="cx"> 
</span><span class="cx">     if (synchronous)
</span><span class="cx">         m_debuggerAgent->breakProgram(Inspector::DebuggerFrontendDispatcher::Reason::EventListener, WTFMove(eventData));
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog    2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebInspectorUI/ChangeLog       2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -1,3 +1,97 @@
</span><ins>+2018-08-16  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: support breakpoints for arbitrary event names
+        https://bugs.webkit.org/show_bug.cgi?id=183118
+
+        Reviewed by Joseph Pecoraro.
+
+        Create UI for setting breakpoints on event names. Ties into renamed DOMDebugger commands,
+        specifically `setEventBreakpoint` and `removeEventBreakpoint`, that will pause execution if
+        any DOM event is fired that matches any previously registered breakpoints.
+
+        Event breakpoints are distinguished by name, and they currently apply globally, meaning
+        that only one breakpoint per event name can be registered.
+
+        Event breakpoints are created in the Debugger tab in a new "Event Breakpoints" section in
+        the Navigation sidebar. A new type of popover, EventBreakpointPopover, is used, but right
+        now all it contains is a basic text input for the event name. Similarly, a new TreeElement
+        subclass, EventBreakpointTreeElement, is used when showing the list of event listener
+        breakpoints, but all it shows now is the event name.
+
+        The majority of the logic in this patch was derived from XHR breakpoints.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Main.html:
+        * UserInterface/Test.html:
+        * UserInterface/Images/EventBreakpoint.svg: Added.
+
+        * UserInterface/Models/EventBreakpoint.js: Added.
+        (WI.EventBreakpoint):
+        (WI.EventBreakpoint.prototype.get eventName):
+        (WI.EventBreakpoint.prototype.get disabled):
+        (WI.EventBreakpoint.prototype.set disabled):
+        (WI.EventBreakpoint.prototype.get serializableInfo):
+        (WI.EventBreakpoint.prototype.saveIdentityToCookie):
+
+        * UserInterface/Controllers/DOMDebuggerManager.js:
+        (WI.DOMDebuggerManager):
+        (WI.DOMDebuggerManager.prototype.get eventBreakpoints): Added.
+        (WI.DOMDebuggerManager.prototype.eventBreakpointForEventName): Added.
+        (WI.DOMDebuggerManager.prototype.addEventBreakpoint): Added.
+        (WI.DOMDebuggerManager.prototype.removeEventBreakpoint): Added.
+        (WI.DOMDebuggerManager.prototype._speculativelyResolveBreakpoints):
+        (WI.DOMDebuggerManager.prototype._updateEventBreakpoint.breakpointUpdated): Added.
+        (WI.DOMDebuggerManager.prototype._updateEventBreakpoint): Added.
+        (WI.DOMDebuggerManager.prototype._resolveEventBreakpoint): Added.
+        (WI.DOMDebuggerManager.prototype._saveEventBreakpoints): Added.
+        (WI.DOMDebuggerManager.prototype._eventBreakpointDisabledStateDidChange): Added.
+
+        * UserInterface/Controllers/DebuggerManager.js:
+        (WI.DebuggerManager.prototype._pauseReasonFromPayload):
+
+        * UserInterface/Controllers/EventBreakpointTreeController.js: Added.
+        (WI.EventBreakpointTreeController):
+        (WI.EventBreakpointTreeController.prototype.revealAndSelect):
+        (WI.EventBreakpointTreeController.prototype._eventBreakpointAdded):
+        (WI.EventBreakpointTreeController.prototype._eventBreakpointRemoved):
+        (WI.EventBreakpointTreeController.prototype._addTreeElement):
+
+        * UserInterface/Views/DebuggerSidebarPanel.js:
+        (WI.DebuggerSidebarPanel):
+        (WI.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
+        (WI.DebuggerSidebarPanel.prototype._eventBreakpointAddedOrRemoved): Added.
+        (WI.DebuggerSidebarPanel.prototype._addEventBreakpointButtonClicked): Added.
+        (WI.DebuggerSidebarPanel.prototype.willDismissPopover):
+
+        * UserInterface/Views/EventBreakpointTreeElement.js: Added.
+        (WI.EventBreakpointTreeElement):
+        (WI.EventBreakpointTreeElement.prototype.onattach):
+        (WI.EventBreakpointTreeElement.prototype.ondetach):
+        (WI.EventBreakpointTreeElement.prototype.ondelete):
+        (WI.EventBreakpointTreeElement.prototype.onenter):
+        (WI.EventBreakpointTreeElement.prototype.onspace):
+        (WI.EventBreakpointTreeElement.prototype.populateContextMenu):
+        (WI.EventBreakpointTreeElement.prototype._statusImageElementClicked):
+        (WI.EventBreakpointTreeElement.prototype._statusImageElementFocused):
+        (WI.EventBreakpointTreeElement.prototype._statusImageElementMouseDown):
+        (WI.EventBreakpointTreeElement.prototype._toggleBreakpoint):
+        (WI.EventBreakpointTreeElement.prototype._updateStatus):
+        * UserInterface/Views/EventBreakpointTreeElement.css: Added.
+        (.breakpoint.event-listener:not(.breakpoint-paused-icon) .icon):
+
+        * UserInterface/Views/EventBreakpointPopover.js: Added.
+        (WI.EventBreakpointPopover):
+        (WI.EventBreakpointPopover.prototype.get result):
+        (WI.EventBreakpointPopover.prototype.get value):
+        (WI.EventBreakpointPopover.prototype.show):
+        (WI.EventBreakpointPopover.prototype._presentOverTargetElement):
+        * UserInterface/Views/EventBreakpointPopover.css: Added.
+        (.popover .event-listener-breakpoint-content):
+        (.popover .event-listener-breakpoint-content > input):
+
+        * UserInterface/Views/NavigationSidebarPanel.js:
+        (WI.NavigationSidebarPanel.prototype._isTreeElementWithoutRepresentedObject):
+
</ins><span class="cx"> 2018-08-16  Joseph Pecoraro  <pecoraro@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Show Initiator information in Network Table
</span></span></pre></div>
<a id="trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js   2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js      2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -72,6 +72,7 @@
</span><span class="cx"> localizedStrings["Add %s Rule"] = "Add %s Rule";
</span><span class="cx"> localizedStrings["Add Action"] = "Add Action";
</span><span class="cx"> localizedStrings["Add Breakpoint"] = "Add Breakpoint";
</span><ins>+localizedStrings["Add Event Breakpoint"] = "Add Event Breakpoint";
</ins><span class="cx"> localizedStrings["Add New"] = "Add New";
</span><span class="cx"> localizedStrings["Add New Class"] = "Add New Class";
</span><span class="cx"> localizedStrings["Add New Probe Expression"] = "Add New Probe Expression";
</span><span class="lines">@@ -144,6 +145,7 @@
</span><span class="cx"> localizedStrings["Boundary"] = "Boundary";
</span><span class="cx"> localizedStrings["Box Model"] = "Box Model";
</span><span class="cx"> localizedStrings["Box Shadow"] = "Box Shadow";
</span><ins>+localizedStrings["Break on events with name:"] = "Break on events with name:";
</ins><span class="cx"> localizedStrings["Break on request with URL:"] = "Break on request with URL:";
</span><span class="cx"> localizedStrings["Break on…"] = "Break on…";
</span><span class="cx"> localizedStrings["Breakdown"] = "Breakdown";
</span><span class="lines">@@ -395,6 +397,7 @@
</span><span class="cx"> localizedStrings["Eval Code"] = "Eval Code";
</span><span class="cx"> localizedStrings["Evaluate JavaScript"] = "Evaluate JavaScript";
</span><span class="cx"> localizedStrings["Event"] = "Event";
</span><ins>+localizedStrings["Event Breakpoints"] = "Event Breakpoints";
</ins><span class="cx"> localizedStrings["Event Dispatched"] = "Event Dispatched";
</span><span class="cx"> localizedStrings["Event Listeners"] = "Event Listeners";
</span><span class="cx"> localizedStrings["Events"] = "Events";
</span><span class="lines">@@ -1093,6 +1096,7 @@
</span><span class="cx"> localizedStrings["toggle"] = "toggle";
</span><span class="cx"> localizedStrings["unsupported version."] = "unsupported version.";
</span><span class="cx"> localizedStrings["value"] = "value";
</span><ins>+localizedStrings["“%s“ Event Fired"] = "“%s“ Event Fired";
</ins><span class="cx"> localizedStrings["“%s” Profile Recorded"] = "“%s” Profile Recorded";
</span><span class="cx"> localizedStrings["“%s” is invalid."] = "“%s” is invalid.";
</span><span class="cx"> localizedStrings["“%s” threw an error."] = "“%s” threw an error.";
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersDOMDebuggerManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js      2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js 2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -33,6 +33,9 @@
</span><span class="cx">         this._domBreakpointURLMap = new Map;
</span><span class="cx">         this._domBreakpointFrameIdentifierMap = new Map;
</span><span class="cx"> 
</span><ins>+        this._eventBreakpointSetting = new WI.Setting("event-breakpoints", []);
+        this._eventBreakpoints = [];
+
</ins><span class="cx">         this._xhrBreakpointsSetting = new WI.Setting("xhr-breakpoints", []);
</span><span class="cx">         this._xhrBreakpoints = [];
</span><span class="cx">         this._allRequestsBreakpointEnabledSetting = new WI.Setting("break-on-all-requests", false);
</span><span class="lines">@@ -40,6 +43,7 @@
</span><span class="cx">         this._allRequestsBreakpoint = new WI.XHRBreakpoint(null, null, !this._allRequestsBreakpointEnabledSetting.value);
</span><span class="cx"> 
</span><span class="cx">         WI.DOMBreakpoint.addEventListener(WI.DOMBreakpoint.Event.DisabledStateDidChange, this._domBreakpointDisabledStateDidChange, this);
</span><ins>+        WI.EventBreakpoint.addEventListener(WI.EventBreakpoint.Event.DisabledStateDidChange, this._eventBreakpointDisabledStateDidChange, this);
</ins><span class="cx">         WI.XHRBreakpoint.addEventListener(WI.XHRBreakpoint.Event.DisabledStateDidChange, this._xhrBreakpointDisabledStateDidChange, this);
</span><span class="cx"> 
</span><span class="cx">         WI.domTreeManager.addEventListener(WI.DOMTreeManager.Event.NodeRemoved, this._nodeRemoved, this);
</span><span class="lines">@@ -58,6 +62,11 @@
</span><span class="cx">                 this.addDOMBreakpoint(breakpoint);
</span><span class="cx">             }
</span><span class="cx"> 
</span><ins>+            for (let cookie of this._eventBreakpointSetting.value) {
+                let breakpoint = new WI.EventBreakpoint(cookie.eventName, cookie.disabled);
+                this.addEventBreakpoint(breakpoint);
+            }
+
</ins><span class="cx">             for (let cookie of this._xhrBreakpointsSetting.value) {
</span><span class="cx">                 let breakpoint = new WI.XHRBreakpoint(cookie.type, cookie.url, cookie.disabled);
</span><span class="cx">                 this.addXHRBreakpoint(breakpoint);
</span><span class="lines">@@ -102,6 +111,8 @@
</span><span class="cx">         return resolvedBreakpoints;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    get eventBreakpoints() { return this._eventBreakpoints; }
+
</ins><span class="cx">     get xhrBreakpoints() { return this._xhrBreakpoints; }
</span><span class="cx"> 
</span><span class="cx">     isBreakpointRemovable(breakpoint)
</span><span class="lines">@@ -184,6 +195,51 @@
</span><span class="cx">         this._saveDOMBreakpoints();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    eventBreakpointForEventName(eventName)
+    {
+        return this._eventBreakpoints.find((breakpoint) => breakpoint.eventName === eventName) || null;
+    }
+
+    addEventBreakpoint(breakpoint)
+    {
+        console.assert(breakpoint instanceof WI.EventBreakpoint);
+        if (!breakpoint)
+            return;
+
+        if (this._eventBreakpoints.some((item) => item.eventName === breakpoint.eventName))
+            return;
+
+        this._eventBreakpoints.push(breakpoint);
+
+        this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointAdded, {breakpoint});
+
+        this._resolveEventBreakpoint(breakpoint);
+        this._saveEventBreakpoints();
+    }
+
+    removeEventBreakpoint(breakpoint)
+    {
+        console.assert(breakpoint instanceof WI.EventBreakpoint);
+        if (!breakpoint)
+            return;
+
+        if (!this._eventBreakpoints.includes(breakpoint))
+            return;
+
+        this._eventBreakpoints.remove(breakpoint);
+
+        this._saveEventBreakpoints();
+        this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, {breakpoint});
+
+        if (breakpoint.disabled)
+            return;
+
+        DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName, (error) => {
+            if (error)
+                console.error(error);
+        });
+    }
+
</ins><span class="cx">     xhrBreakpointForURL(url)
</span><span class="cx">     {
</span><span class="cx">         return this._xhrBreakpoints.find((breakpoint) => breakpoint.url === url) || null;
</span><span class="lines">@@ -300,6 +356,9 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        for (let breakpoint of this._eventBreakpoints)
+            this._resolveEventBreakpoint(breakpoint);
+
</ins><span class="cx">         for (let breakpoint of this._xhrBreakpoints)
</span><span class="cx">             this._resolveXHRBreakpoint(breakpoint);
</span><span class="cx">     }
</span><span class="lines">@@ -347,6 +406,23 @@
</span><span class="cx">             DOMDebuggerAgent.setDOMBreakpoint(nodeIdentifier, breakpoint.type, breakpointUpdated);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _updateEventBreakpoint(breakpoint, callback)
+    {
+        function breakpointUpdated(error)
+        {
+            if (error)
+                console.error(error);
+
+            if (callback)
+                callback(error);
+        }
+
+        if (breakpoint.disabled)
+            DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName, breakpointUpdated);
+        else
+            DOMDebuggerAgent.setEventListenerBreakpoint(breakpoint.eventName, breakpointUpdated);
+    }
+
</ins><span class="cx">     _updateXHRBreakpoint(breakpoint, callback)
</span><span class="cx">     {
</span><span class="cx">         function breakpointUpdated(error)
</span><span class="lines">@@ -366,6 +442,16 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _resolveEventBreakpoint(breakpoint)
+    {
+        if (breakpoint.disabled)
+            return;
+
+        this._updateEventBreakpoint(breakpoint, () => {
+            breakpoint.dispatchEventToListeners(WI.EventBreakpoint.Event.ResolvedStateDidChange);
+        });
+    }
+
</ins><span class="cx">     _resolveXHRBreakpoint(breakpoint)
</span><span class="cx">     {
</span><span class="cx">         if (breakpoint.disabled)
</span><span class="lines">@@ -388,6 +474,14 @@
</span><span class="cx">         this._domBreakpointsSetting.value = breakpointsToSave.map((breakpoint) => breakpoint.serializableInfo);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _saveEventBreakpoints()
+    {
+        if (this._restoringBreakpoints)
+            return;
+
+        this._eventBreakpointSetting.value = this._eventBreakpoints.map((breakpoint) => breakpoint.serializableInfo);
+    }
+
</ins><span class="cx">     _saveXHRBreakpoints()
</span><span class="cx">     {
</span><span class="cx">         if (this._restoringBreakpoints)
</span><span class="lines">@@ -403,6 +497,13 @@
</span><span class="cx">         this._saveDOMBreakpoints();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _eventBreakpointDisabledStateDidChange(event)
+    {
+        let breakpoint = event.target;
+        this._updateEventBreakpoint(breakpoint);
+        this._saveEventBreakpoints();
+    }
+
</ins><span class="cx">     _xhrBreakpointDisabledStateDidChange(event)
</span><span class="cx">     {
</span><span class="cx">         let breakpoint = event.target;
</span><span class="lines">@@ -488,6 +589,8 @@
</span><span class="cx"> WI.DOMDebuggerManager.Event = {
</span><span class="cx">     DOMBreakpointAdded: "dom-debugger-manager-dom-breakpoint-added",
</span><span class="cx">     DOMBreakpointRemoved: "dom-debugger-manager-dom-breakpoint-removed",
</span><ins>+    EventBreakpointAdded: "dom-debugger-manager-event-breakpoint-added",
+    EventBreakpointRemoved: "dom-debugger-manager-event-breakpoint-removed",
</ins><span class="cx">     XHRBreakpointAdded: "dom-debugger-manager-xhr-breakpoint-added",
</span><span class="cx">     XHRBreakpointRemoved: "dom-debugger-manager-xhr-breakpoint-removed",
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersDebuggerManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js 2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js    2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -828,6 +828,8 @@
</span><span class="cx">             return WI.DebuggerManager.PauseReason.DOM;
</span><span class="cx">         case DebuggerAgent.PausedReason.DebuggerStatement:
</span><span class="cx">             return WI.DebuggerManager.PauseReason.DebuggerStatement;
</span><ins>+        case DebuggerAgent.PausedReason.EventListener:
+            return WI.DebuggerManager.PauseReason.EventListener;
</ins><span class="cx">         case DebuggerAgent.PausedReason.Exception:
</span><span class="cx">             return WI.DebuggerManager.PauseReason.Exception;
</span><span class="cx">         case DebuggerAgent.PausedReason.PauseOnNextStatement:
</span><span class="lines">@@ -1236,6 +1238,7 @@
</span><span class="cx">     CSPViolation: "CSP-violation",
</span><span class="cx">     DebuggerStatement: "debugger-statement",
</span><span class="cx">     DOM: "DOM",
</span><ins>+    EventListener: "event-listener",
</ins><span class="cx">     Exception: "exception",
</span><span class="cx">     PauseOnNextStatement: "pause-on-next-statement",
</span><span class="cx">     XHR: "xhr",
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersEventBreakpointTreeControllerjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Controllers/EventBreakpointTreeController.js (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/EventBreakpointTreeController.js                           (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/EventBreakpointTreeController.js      2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,76 @@
</span><ins>+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.EventBreakpointTreeController = class EventBreakpointTreeController
+{
+    constructor(treeOutline)
+    {
+        this._treeOutline = treeOutline;
+
+        WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.EventBreakpointAdded, this._eventBreakpointAdded, this);
+        WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, this._eventBreakpointRemoved, this);
+
+        for (let breakpoint of WI.domDebuggerManager.eventBreakpoints)
+            this._addTreeElement(breakpoint);
+    }
+
+    // Public
+
+    revealAndSelect(breakpoint)
+    {
+        let treeElement = this._treeOutline.findTreeElement(breakpoint);
+        if (!treeElement)
+            return;
+
+        treeElement.revealAndSelect();
+    }
+
+    // Private
+
+    _eventBreakpointAdded(event)
+    {
+        this._addTreeElement(event.data.breakpoint);
+    }
+
+    _eventBreakpointRemoved(event)
+    {
+        let breakpoint = event.data.breakpoint;
+        let treeElement = this._treeOutline.findTreeElement(breakpoint);
+        if (!treeElement)
+            return;
+
+        this._treeOutline.removeChild(treeElement);
+    }
+
+    _addTreeElement(breakpoint)
+    {
+        let treeElement = this._treeOutline.findTreeElement(breakpoint);
+        console.assert(!treeElement);
+        if (treeElement)
+            return;
+
+        this._treeOutline.appendChild(new WI.EventBreakpointTreeElement(breakpoint));
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceImagesEventBreakpointsvg"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Images/EventBreakpoint.svg (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Images/EventBreakpoint.svg                             (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Images/EventBreakpoint.svg        2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2018 Apple Inc. All rights reserved. -->
+<svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 16">
+    <path fill="rgb(148, 183, 219)" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 13 C 1 14.101562 1.898438 15 3 15 L 13 15 C 14.101562 15 15 14.101562 15 13 L 15 3 C 15 1.898438 14.101562 1 13 1 Z"/>
+    <path fill="rgb(106, 136, 170)" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 13 C 1 14.101562 1.898438 15 3 15 L 13 15 C 14.101562 15 15 14.101562 15 13 L 15 3 C 15 1.898438 14.101562 1 13 1 M 13 2 C 13.550781 2 14 2.449219 14 3 L 14 13 C 14 13.550781 13.550781 14 13 14 L 3 14 C 2.449219 14 2 13.550781 2 13 L 2 3 C 2 2.449219 2.449219 2 3 2 L 13 2"/>
+    <path fill="rgb(113, 146, 184)" d="M 5.503906 12.742188 C 4.949219 12.742188 4.503906 12.292969 4.503906 11.742188 L 4.503906 3.792969 C 4.503906 3.242188 4.949219 2.792969 5.503906 2.792969 L 10.472656 2.792969 C 11.023438 2.792969 11.472656 3.242188 11.472656 3.792969 L 11.472656 4.882812 C 11.472656 5.4375 11.023438 5.882812 10.472656 5.882812 C 10.472656 5.882812 9.132812 5.882812 8.15625 5.882812 C 8.15625 5.992188 8.15625 5.996094 8.15625 6.101562 C 8.957031 6.101562 9.875 6.101562 9.875 6.101562 C 10.425781 6.101562 10.875 6.550781 10.875 7.101562 L 10.875 8.164062 C 10.875 8.71875 10.425781 9.164062 9.875 9.164062 C 9.875 9.164062 8.957031 9.164062 8.15625 9.164062 C 8.15625 9.382812 8.15625 9.398438 8.15625 9.613281 C 9.191406 9.613281 10.722656 9.613281 10.722656 9.613281 C 11.277344 9.613281 11.722656 10.0625 11.722656 10.613281 L 11.722656 11.742188 C 11.722656 12.292969 11.277344 12.742188 10.722656 12.742188 L 5.503906 12.742188"/>
+    <path fill="white" d="M 5.503906 11.742188 L 5.503906 3.792969 L 10.46875 3.792969 L 10.46875 4.882812 L 7.15625 4.882812 L 7.15625 7.101562 L 9.875 7.101562 L 9.875 8.164062 L 7.15625 8.164062 L 7.15625 10.613281 L 10.722656 10.613281 L 10.722656 11.742188 Z"/>
+</svg>
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceMainhtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Main.html      2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -83,6 +83,8 @@
</span><span class="cx">     <link rel="stylesheet" href="Views/DetailsSection.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/DividerNavigationItem.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/Editing.css">
</span><ins>+    <link rel="stylesheet" href="Views/EventBreakpointPopover.css">
+    <link rel="stylesheet" href="Views/EventBreakpointTreeElement.css">
</ins><span class="cx">     <link rel="stylesheet" href="Views/EventListenerSectionGroup.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/ErrorObjectView.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/FilterBar.css">
</span><span class="lines">@@ -376,6 +378,7 @@
</span><span class="cx">     <script src="Models/DebuggerDashboard.js"></script>
</span><span class="cx">     <script src="Models/DebuggerData.js"></script>
</span><span class="cx">     <script src="Models/DefaultDashboard.js"></script>
</span><ins>+    <script src="Models/EventBreakpoint.js"></script>
</ins><span class="cx">     <script src="Models/ExecutionContext.js"></script>
</span><span class="cx">     <script src="Models/ExecutionContextList.js"></script>
</span><span class="cx">     <script src="Models/FPSInstrument.js"></script>
</span><span class="lines">@@ -622,6 +625,8 @@
</span><span class="cx">     <script src="Views/EditableDataGridNode.js"></script>
</span><span class="cx">     <script src="Views/EditingSupport.js"></script>
</span><span class="cx">     <script src="Views/ErrorObjectView.js"></script>
</span><ins>+    <script src="Views/EventBreakpointPopover.js"></script>
+    <script src="Views/EventBreakpointTreeElement.js"></script>
</ins><span class="cx">     <script src="Views/EventListenerSectionGroup.js"></script>
</span><span class="cx">     <script src="Views/FilterBar.js"></script>
</span><span class="cx">     <script src="Views/FilterBarButton.js"></script>
</span><span class="lines">@@ -843,6 +848,7 @@
</span><span class="cx">     <script src="Controllers/DebuggerManager.js"></script>
</span><span class="cx">     <script src="Controllers/DOMBreakpointTreeController.js"></script>
</span><span class="cx">     <script src="Controllers/DragToAdjustController.js"></script>
</span><ins>+    <script src="Controllers/EventBreakpointTreeController.js"></script>
</ins><span class="cx">     <script src="Controllers/Formatter.js"></script>
</span><span class="cx">     <script src="Controllers/FormatterSourceMap.js"></script>
</span><span class="cx">     <script src="Controllers/FrameResourceManager.js"></script>
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsEventBreakpointjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Models/EventBreakpoint.js (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/EventBreakpoint.js                              (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/EventBreakpoint.js 2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,79 @@
</span><ins>+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.EventBreakpoint = class EventBreakpoint extends WI.Object
+{
+    constructor(eventName, disabled)
+    {
+        super();
+
+        console.assert(typeof eventName === "string");
+
+        this._eventName = eventName;
+        this._disabled = disabled || false;
+    }
+
+    // Public
+
+    get eventName() { return this._eventName; }
+
+    get disabled()
+    {
+        return this._disabled;
+    }
+
+    set disabled(disabled)
+    {
+        if (this._disabled === disabled)
+            return;
+
+        this._disabled = disabled;
+
+        this.dispatchEventToListeners(WI.EventBreakpoint.Event.DisabledStateDidChange);
+    }
+
+    get serializableInfo()
+    {
+        let info = {
+            eventName: this._eventName,
+        };
+        if (this._disabled)
+            info.disabled = true;
+
+        return info;
+    }
+
+    saveIdentityToCookie(cookie)
+    {
+        cookie[WI.EventBreakpoint.EventNameCookieKey] = this._eventName;
+    }
+};
+
+WI.EventBreakpoint.EventNameCookieKey = "event-breakpoint-event-name";
+
+WI.EventBreakpoint.Event = {
+    DisabledStateDidChange: "event-breakpoint-disabled-state-did-change",
+    ResolvedStateDidChange: "event-breakpoint-resolved-state-did-change",
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceTesthtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Test.html (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Test.html      2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebInspectorUI/UserInterface/Test.html 2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -133,6 +133,7 @@
</span><span class="cx">     <script src="Models/DOMStorageObject.js"></script>
</span><span class="cx">     <script src="Models/DOMTree.js"></script>
</span><span class="cx">     <script src="Models/DebuggerData.js"></script>
</span><ins>+    <script src="Models/EventBreakpoint.js"></script>
</ins><span class="cx">     <script src="Models/ExecutionContext.js"></script>
</span><span class="cx">     <script src="Models/ExecutionContextList.js"></script>
</span><span class="cx">     <script src="Models/FPSInstrument.js"></script>
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsDebuggerSidebarPaneljs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js  2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js     2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -176,6 +176,28 @@
</span><span class="cx">             this._domBreakpointsSection = new WI.DetailsSection("dom-breakpoints", WI.UIString("DOM Breakpoints"), [domBreakpointsGroup], null, defaultCollapsed);
</span><span class="cx">             this.contentView.element.appendChild(this._domBreakpointsSection.element);
</span><span class="cx"> 
</span><ins>+            this._eventBreakpointsContentTreeOutline = this.createContentTreeOutline(true);
+            this._eventBreakpointsContentTreeOutline.addEventListener(WI.TreeOutline.Event.ElementAdded, this._eventBreakpointAddedOrRemoved, this);
+            this._eventBreakpointsContentTreeOutline.addEventListener(WI.TreeOutline.Event.ElementRemoved, this._eventBreakpointAddedOrRemoved, this);
+
+            this._eventBreakpointsRow = new WI.DetailsSectionRow(WI.UIString("No Breakpoints"));
+            this._eventBreakpointsRow.element.appendChild(this._eventBreakpointsContentTreeOutline.element);
+            this._eventBreakpointsRow.showEmptyMessage();
+
+            let eventBreakpointNavigationBar = new WI.NavigationBar;
+            let eventBreakpointNavigationBarWrapper = document.createElement("div");
+            eventBreakpointNavigationBarWrapper.appendChild(eventBreakpointNavigationBar.element);
+
+            let addEventBreakpointButton = new WI.ButtonNavigationItem("add-event-breakpoint", WI.UIString("Add Event Breakpoint"), "Images/Plus13.svg", 13, 13);
+            addEventBreakpointButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._addEventBreakpointButtonClicked, this);
+            eventBreakpointNavigationBar.addNavigationItem(addEventBreakpointButton);
+
+            let eventBreakpointsGroup = new WI.DetailsSectionGroup([this._eventBreakpointsRow]);
+            this._eventBreakpointsSection = new WI.DetailsSection("event-breakpoints", WI.UIString("Event Breakpoints"), [eventBreakpointsGroup], eventBreakpointNavigationBarWrapper, defaultCollapsed);
+            this.contentView.element.appendChild(this._eventBreakpointsSection.element);
+
+            this._eventBreakpointTreeController = new WI.EventBreakpointTreeController(this._eventBreakpointsContentTreeOutline);
+
</ins><span class="cx">             this._xhrBreakpointsContentTreeOutline = this.createContentTreeOutline(true);
</span><span class="cx">             this._xhrBreakpointTreeController = new WI.XHRBreakpointTreeController(this._xhrBreakpointsContentTreeOutline);
</span><span class="cx"> 
</span><span class="lines">@@ -182,16 +204,16 @@
</span><span class="cx">             this._xhrBreakpointsRow = new WI.DetailsSectionRow;
</span><span class="cx">             this._xhrBreakpointsRow.element.appendChild(this._xhrBreakpointsContentTreeOutline.element);
</span><span class="cx"> 
</span><del>-            let navigationBar = new WI.NavigationBar;
-            let navigationBarWrapper = document.createElement("div");
-            navigationBarWrapper.appendChild(navigationBar.element);
</del><ins>+            let xhrBreakpointNavigationBar = new WI.NavigationBar;
+            let xhrBreakpointNavigationBarWrapper = document.createElement("div");
+            xhrBreakpointNavigationBarWrapper.appendChild(xhrBreakpointNavigationBar.element);
</ins><span class="cx"> 
</span><span class="cx">             let addXHRBreakpointButton = new WI.ButtonNavigationItem("add-xhr-breakpoint", WI.UIString("Add XHR Breakpoint"), "Images/Plus13.svg", 13, 13);
</span><span class="cx">             addXHRBreakpointButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._addXHRBreakpointButtonClicked, this);
</span><del>-            navigationBar.addNavigationItem(addXHRBreakpointButton);
</del><ins>+            xhrBreakpointNavigationBar.addNavigationItem(addXHRBreakpointButton);
</ins><span class="cx"> 
</span><span class="cx">             let xhrBreakpointsGroup = new WI.DetailsSectionGroup([this._xhrBreakpointsRow]);
</span><del>-            let xhrBreakpointsSection = new WI.DetailsSection("xhr-breakpoints", WI.UIString("XHR Breakpoints"), [xhrBreakpointsGroup], navigationBarWrapper, defaultCollapsed);
</del><ins>+            let xhrBreakpointsSection = new WI.DetailsSection("xhr-breakpoints", WI.UIString("XHR Breakpoints"), [xhrBreakpointsGroup], xhrBreakpointNavigationBarWrapper, defaultCollapsed);
</ins><span class="cx">             this.contentView.element.appendChild(xhrBreakpointsSection.element);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -1032,6 +1054,24 @@
</span><span class="cx">             }
</span><span class="cx">             break;
</span><span class="cx"> 
</span><ins>+        case WI.DebuggerManager.PauseReason.EventListener:
+            console.assert(pauseData, "Expected data with an event listener, but found none.");
+            if (pauseData) {
+                let eventBreakpoint = WI.domDebuggerManager.eventBreakpointForEventName(pauseData.eventName);
+                console.assert(eventBreakpoint, "Expected Event Listener breakpoint for event name.", pauseData.eventName);
+
+                this._pauseReasonTreeOutline = this.createContentTreeOutline(true);
+
+                let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(eventBreakpoint, WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName, WI.UIString("“%s“ Event Fired").format(pauseData.eventName));
+                this._pauseReasonTreeOutline.appendChild(eventBreakpointTreeElement);
+
+                let eventBreakpointRow = new WI.DetailsSectionRow;
+                eventBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
+
+                this._pauseReasonGroup.rows = [eventBreakpointRow];
+            }
+            return true;
+
</ins><span class="cx">         case WI.DebuggerManager.PauseReason.Exception:
</span><span class="cx">             console.assert(pauseData, "Expected data with an exception, but found none.");
</span><span class="cx">             if (pauseData) {
</span><span class="lines">@@ -1175,6 +1215,28 @@
</span><span class="cx">         this._domBreakpointsSection.collapsed = false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _eventBreakpointAddedOrRemoved(event)
+    {
+        if (!this._eventBreakpointsContentTreeOutline.children.length) {
+            this._eventBreakpointsRow.showEmptyMessage();
+            return;
+        }
+
+        if (this._eventBreakpointsContentTreeOutline.element.parent)
+            return;
+
+        this._eventBreakpointsRow.hideEmptyMessage();
+        this._eventBreakpointsRow.element.append(this._eventBreakpointsContentTreeOutline.element);
+
+        this._eventBreakpointsSection.collapsed = false;
+    }
+
+    _addEventBreakpointButtonClicked(event)
+    {
+        let popover = new WI.EventBreakpointPopover(this);
+        popover.show(event.target.element, [WI.RectEdge.MAX_Y, WI.RectEdge.MIN_Y, WI.RectEdge.MAX_X]);
+    }
+
</ins><span class="cx">     _addXHRBreakpointButtonClicked(event)
</span><span class="cx">     {
</span><span class="cx">         let popover = new WI.XHRBreakpointPopover(this);
</span><span class="lines">@@ -1188,11 +1250,19 @@
</span><span class="cx">         if (popover.result !== WI.InputPopover.Result.Committed)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        let url = popover.value;
-        if (!url)
</del><ins>+        if (popover instanceof WI.EventBreakpointPopover) {
+            let eventName = popover.value;
+            if (eventName)
+                WI.domDebuggerManager.addEventBreakpoint(new WI.EventBreakpoint(eventName));
</ins><span class="cx">             return;
</span><ins>+        }
</ins><span class="cx"> 
</span><del>-        WI.domDebuggerManager.addXHRBreakpoint(new WI.XHRBreakpoint(popover.type, url));
</del><ins>+        if (popover instanceof WI.XHRBreakpointPopover) {
+            let url = popover.value;
+            if (url)
+                WI.domDebuggerManager.addXHRBreakpoint(new WI.XHRBreakpoint(popover.type, url));
+            return;
+        }
</ins><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsEventBreakpointPopovercss"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointPopover.css (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointPopover.css                               (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointPopover.css  2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.popover .event-breakpoint-content {
+    margin: 2px;
+    padding: 5px;
+}
+
+.popover .event-breakpoint-content > input {
+    width: 100%;
+    margin-top: 4px;
+    padding: 4px 0 2px 0;
+    outline: none;
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsEventBreakpointPopoverjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointPopover.js (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointPopover.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointPopover.js   2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,89 @@
</span><ins>+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.EventBreakpointPopover = class EventBreakpointPopover extends WI.Popover
+{
+    constructor(delegate)
+    {
+        super(delegate);
+
+        this._result = WI.InputPopover.Result.None;
+        this._value = null;
+
+        this._codeMirror = null;
+        this._targetElement = null;
+        this._preferredEdges = null;
+
+        this.windowResizeHandler = this._presentOverTargetElement.bind(this);
+    }
+
+    // Public
+
+    get result() { return this._result; }
+    get value() { return this._value; }
+
+    show(targetElement, preferredEdges)
+    {
+        this._targetElement = targetElement;
+        this._preferredEdges = preferredEdges;
+
+        let contentElement = document.createElement("div");
+        contentElement.classList.add("event-breakpoint-content");
+
+        let label = contentElement.appendChild(document.createElement("div"));
+        label.classList.add("label");
+        label.textContent = WI.UIString("Break on events with name:");
+
+        this._inputElement = contentElement.appendChild(document.createElement("input"));
+        this._inputElement.placeholder = "click";
+        this._inputElement.spellcheck = false;
+        this._inputElement.addEventListener("keydown", (event) => {
+            if (!isEnterKey(event))
+                return;
+
+            this._result = WI.InputPopover.Result.Committed;
+            this._value = event.target.value.trim();
+
+            this.dismiss();
+        });
+
+        this.content = contentElement;
+
+        this._presentOverTargetElement();
+    }
+
+    // Private
+
+    _presentOverTargetElement()
+    {
+        if (!this._targetElement)
+            return;
+
+        let targetFrame = WI.Rect.rectFromClientRect(this._targetElement.getBoundingClientRect());
+        this.present(targetFrame, this._preferredEdges);
+
+        this._inputElement.select();
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsEventBreakpointTreeElementcss"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.css (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.css                           (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.css      2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.breakpoint.event:not(.breakpoint-paused-icon) .icon {
+    content: url(../Images/EventBreakpoint.svg);
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsEventBreakpointTreeElementjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.js (0 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.js                            (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.js       2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -0,0 +1,139 @@
</span><ins>+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.EventBreakpointTreeElement = class EventBreakpointTreeElement extends WI.GeneralTreeElement
+{
+    constructor(breakpoint, className, title)
+    {
+        console.assert(breakpoint instanceof WI.EventBreakpoint);
+
+        let classNames = ["breakpoint", "event"];
+        if (className)
+            classNames.push(className);
+
+        if (!title)
+            title = breakpoint.eventName;
+
+        const subtitle = null;
+        super(classNames, title, subtitle, breakpoint);
+
+        this._statusImageElement = document.createElement("img");
+        this._statusImageElement.classList.add("status-image", "resolved");
+        this.status = this._statusImageElement;
+
+        breakpoint.addEventListener(WI.EventBreakpoint.Event.DisabledStateDidChange, this._updateStatus, this);
+
+        this._updateStatus();
+    }
+
+    // Protected
+
+    onattach()
+    {
+        super.onattach();
+
+        this._boundStatusImageElementClicked = this._statusImageElementClicked.bind(this);
+        this._boundStatusImageElementFocused = this._statusImageElementFocused.bind(this);
+        this._boundStatusImageElementMouseDown = this._statusImageElementMouseDown.bind(this);
+
+        this._statusImageElement.addEventListener("click", this._boundStatusImageElementClicked);
+        this._statusImageElement.addEventListener("focus", this._boundStatusImageElementFocused);
+        this._statusImageElement.addEventListener("mousedown", this._boundStatusImageElementMouseDown);
+    }
+
+    ondetach()
+    {
+        super.ondetach();
+
+        this._statusImageElement.removeEventListener("click", this._boundStatusImageElementClicked);
+        this._statusImageElement.removeEventListener("focus", this._boundStatusImageElementFocused);
+        this._statusImageElement.removeEventListener("mousedown", this._boundStatusImageElementMouseDown);
+
+        this._boundStatusImageElementClicked = null;
+        this._boundStatusImageElementFocused = null;
+        this._boundStatusImageElementMouseDown = null;
+    }
+
+    ondelete()
+    {
+        WI.domDebuggerManager.removeEventBreakpoint(this.representedObject);
+        return true;
+    }
+
+    onenter()
+    {
+        this._toggleBreakpoint();
+        return true;
+    }
+
+    onspace()
+    {
+        this._toggleBreakpoint();
+        return true;
+    }
+
+    populateContextMenu(contextMenu, event)
+    {
+        let breakpoint = this.representedObject;
+        let label = breakpoint.disabled ? WI.UIString("Enable Breakpoint") : WI.UIString("Disable Breakpoint");
+        contextMenu.appendItem(label, this._toggleBreakpoint.bind(this));
+
+        if (WI.domDebuggerManager.isBreakpointRemovable(breakpoint)) {
+            contextMenu.appendSeparator();
+            contextMenu.appendItem(WI.UIString("Delete Breakpoint"), () => {
+                WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
+            });
+        }
+    }
+
+    // Private
+
+    _statusImageElementClicked(event)
+    {
+        this._toggleBreakpoint();
+    }
+
+    _statusImageElementFocused(event)
+    {
+        // Prevent tree outline focus.
+        event.stopPropagation();
+    }
+
+    _statusImageElementMouseDown(event)
+    {
+        // Prevent tree element selection.
+        event.stopPropagation();
+    }
+
+    _toggleBreakpoint()
+    {
+        this.representedObject.disabled = !this.representedObject.disabled;
+    }
+
+    _updateStatus()
+    {
+        this._statusImageElement.classList.toggle("disabled", this.representedObject.disabled);
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNavigationSidebarPaneljs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NavigationSidebarPanel.js (234973 => 234974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NavigationSidebarPanel.js        2018-08-17 00:50:15 UTC (rev 234973)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NavigationSidebarPanel.js   2018-08-17 02:37:46 UTC (rev 234974)
</span><span class="lines">@@ -633,6 +633,7 @@
</span><span class="cx">             || treeElement instanceof WI.ThreadTreeElement
</span><span class="cx">             || treeElement instanceof WI.IdleTreeElement
</span><span class="cx">             || treeElement instanceof WI.DOMBreakpointTreeElement
</span><ins>+            || treeElement instanceof WI.EventBreakpointTreeElement
</ins><span class="cx">             || treeElement instanceof WI.XHRBreakpointTreeElement
</span><span class="cx">             || treeElement instanceof WI.CSSStyleSheetTreeElement
</span><span class="cx">             || typeof treeElement.representedObject === "string"
</span></span></pre>
</div>
</div>

</body>
</html>