Title: [235288] releases/WebKitGTK/webkit-2.22
Revision
235288
Author
[email protected]
Date
2018-08-24 01:07:22 -0700 (Fri, 24 Aug 2018)

Log Message

Merge r235103 - Web Inspector: allow breakpoints to be set for specific event listeners
https://bugs.webkit.org/show_bug.cgi?id=183138

Reviewed by Joseph Pecoraro.

Source/_javascript_Core:

* inspector/protocol/DOM.json:
Add `setBreakpointForEventListener` and `removeBreakpointForEventListener`, each of which
takes an `eventListenerId` and toggles whether that specific usage of that event listener
should have a breakpoint and pause before running.

Source/WebCore:

Test: inspector/dom/breakpoint-for-event-listener.html

* inspector/agents/InspectorDOMAgent.h:
* inspector/agents/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::getEventListenersForNode):
(WebCore::InspectorDOMAgent::setEventListenerDisabled):
(WebCore::InspectorDOMAgent::setBreakpointForEventListener): Added.
(WebCore::InspectorDOMAgent::removeBreakpointForEventListener): Added.
(WebCore::InspectorDOMAgent::buildObjectForEventListener):
(WebCore::InspectorDOMAgent::willRemoveEventListener):
(WebCore::InspectorDOMAgent::isEventListenerDisabled):
(WebCore::InspectorDOMAgent::hasBreakpointForEventListener): Added.
(WebCore::InspectorDOMAgent::idForEventListener): Added.
Rework the event listener data structure to be based on ID instead of `EventListener`, since
it is possible to have the same `EventListener` be used for multiple events.

* inspector/agents/InspectorDOMDebuggerAgent.h:
* inspector/agents/InspectorDOMDebuggerAgent.cpp:
(WebCore::InspectorDOMDebuggerAgent::setEventListenerBreakpoint):
(WebCore::InspectorDOMDebuggerAgent::setInstrumentationBreakpoint):
(WebCore::InspectorDOMDebuggerAgent::removeEventListenerBreakpoint):
(WebCore::InspectorDOMDebuggerAgent::removeInstrumentationBreakpoint):
(WebCore::InspectorDOMDebuggerAgent::willHandleEvent): Added.
(WebCore::InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded):
For DOM events, also check to see if there is a matching event listener specific breakpoint
set via the DOMAgent, and break on it if one is found.

* inspector/InspectorInstrumentation.h:
* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::didInstallTimerImpl):
(WebCore::InspectorInstrumentation::didRemoveTimerImpl):
(WebCore::InspectorInstrumentation::willHandleEventImpl):
(WebCore::InspectorInstrumentation::willFireTimerImpl):
(WebCore::InspectorInstrumentation::pauseOnNativeEventIfNeeded):
(WebCore::InspectorInstrumentation::didRequestAnimationFrameImpl):
(WebCore::InspectorInstrumentation::didCancelAnimationFrameImpl):
(WebCore::InspectorInstrumentation::willFireAnimationFrameImpl):
Split off `pauseOnNativeEventIfNeeded` to only handle non-DOM events, since all DOM events
would already only go through `willHandleEvent`.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:

* UserInterface/Models/EventBreakpoint.js:
(WI.EventBreakpoint):
(WI.EventBreakpoint.fromPayload): Added.
(WI.EventBreakpoint.prototype.get eventListener): Added.

* UserInterface/Controllers/DOMDebuggerManager.js:
(WI.DOMDebuggerManager):

* UserInterface/Controllers/DOMTreeManager.js:
(WI.DOMTreeManager):
(WI.DOMTreeManager.prototype.get eventBreakpoints): Added.
(WI.DOMTreeManager.prototype._setDocument):
(WI.DOMTreeManager.prototype.setEventListenerDisabled):
(WI.DOMTreeManager.prototype.setBreakpointForEventListener): Added.
(WI.DOMTreeManager.prototype.removeBreakpointForEventListener): Added.
(WI.DOMTreeManager.prototype.breakpointForEventListenerId): Added.

* UserInterface/Controllers/EventBreakpointTreeController.js:
(WI.EventBreakpointTreeController):

* UserInterface/Views/DebuggerSidebarPanel.js:
(WI.DebuggerSidebarPanel.prototype._updatePauseReasonSection):

* UserInterface/Views/EventListenerSectionGroup.js:
(WI.EventListenerSectionGroup):
(WI.EventListenerSectionGroup.prototype._createDisabledToggleRow):
(WI.EventListenerSectionGroup.prototype._createBreakpointToggleRow): Added.

* UserInterface/Views/EventBreakpointTreeElement.js:
(WI.EventBreakpointTreeElement):
(WI.EventBreakpointTreeElement.prototype.ondelete):
(WI.EventBreakpointTreeElement.prototype.populateContextMenu):
(WI.EventBreakpointTreeElement.prototype._toggleBreakpoint):

LayoutTests:

* inspector/dom/breakpoint-for-event-listener-expected.txt: Added.
* inspector/dom/breakpoint-for-event-listener.html: Added.

Modified Paths

Added Paths

Diff

Modified: releases/WebKitGTK/webkit-2.22/LayoutTests/ChangeLog (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/LayoutTests/ChangeLog	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/LayoutTests/ChangeLog	2018-08-24 08:07:22 UTC (rev 235288)
@@ -1,3 +1,13 @@
+2018-08-20  Devin Rousso  <[email protected]>
+
+        Web Inspector: allow breakpoints to be set for specific event listeners
+        https://bugs.webkit.org/show_bug.cgi?id=183138
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/dom/breakpoint-for-event-listener-expected.txt: Added.
+        * inspector/dom/breakpoint-for-event-listener.html: Added.
+
 2018-08-20  Rob Buis  <[email protected]>
 
         Throw an exception if window.open() gets passed a URL that cannot be parsed

Added: releases/WebKitGTK/webkit-2.22/LayoutTests/inspector/dom/breakpoint-for-event-listener-expected.txt (0 => 235288)


--- releases/WebKitGTK/webkit-2.22/LayoutTests/inspector/dom/breakpoint-for-event-listener-expected.txt	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.22/LayoutTests/inspector/dom/breakpoint-for-event-listener-expected.txt	2018-08-24 08:07:22 UTC (rev 235288)
@@ -0,0 +1,29 @@
+Testing DOMAgent.setBreakpointForEventListener and DOMAgent.removeBreakpointForEventListener.
+
+  
+
+== Running test suite: DOM.BreakpointForEventListener
+-- Running test case: DOM.setBreakpointForEventListener
+Adding breakpoint for event listener...
+Clicking button2...
+PASS: Should not pause before button2 event handler is run.
+Clicking button1...
+PASS: Should pause before button1 event handler is run.
+PASS: Pause reason should be EventListener.
+PASS: Pause data eventName should be "click".
+
+-- Running test case: DOM.removeBreakpointForEventListener
+Removing breakpoint for event listener...
+Clicking button2...
+PASS: Should not pause before button2 event handler is run.
+Clicking button1...
+PASS: Should not pause before button1 event handler is run.
+
+-- Running test case: DOM.setBreakpointForEventListener.Invalid
+PASS: Should produce an error.
+Error: No event listener for given identifier.
+
+-- Running test case: DOM.removeBreakpointForEventListener.Invalid
+PASS: Should produce an error.
+Error: No event listener for given identifier.
+

Added: releases/WebKitGTK/webkit-2.22/LayoutTests/inspector/dom/breakpoint-for-event-listener.html (0 => 235288)


--- releases/WebKitGTK/webkit-2.22/LayoutTests/inspector/dom/breakpoint-for-event-listener.html	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.22/LayoutTests/inspector/dom/breakpoint-for-event-listener.html	2018-08-24 08:07:22 UTC (rev 235288)
@@ -0,0 +1,211 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function handleButton1Click(event) {
+    TestPage.dispatchEventToFrontend("TestPageButton1Click");
+}
+
+function handleButton2Click(event) {
+    TestPage.dispatchEventToFrontend("TestPageButton2Click");
+}
+
+function clickButton1() {
+    document.getElementById("button1").click();
+}
+
+function clickButton2() {
+    document.getElementById("button2").click();
+}
+
+function test() {
+    let button1Node = null;
+    let button2Node = null;
+
+    function awaitGetClickEventListener(nodeId) {
+        return DOMAgent.getEventListenersForNode(nodeId)
+        .then(({listeners}) => listeners.find((eventListener) => eventListener.type === "click"));
+    }
+
+    let suite = InspectorTest.createAsyncSuite("DOM.BreakpointForEventListener");
+
+    suite.addTestCase({
+        name: "DOM.setBreakpointForEventListener",
+        description: "Check that the debugger pauses for this event.",
+        test(resolve, reject) {
+            let paused = false;
+            let clickingButton1 = false;
+
+            let listener = WI.debuggerManager.singleFireEventListener(WI.DebuggerManager.Event.Paused, (event) => {
+                if (clickingButton1)
+                    InspectorTest.pass("Should pause before button1 event handler is run.");
+                else
+                    InspectorTest.fail("Should not pause before button2 event handler is run.");
+
+                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, "click", `Pause data eventName should be "click".`);
+
+                awaitGetClickEventListener(button1Node.id)
+                .then((clickEventListener) => {
+                    InspectorTest.assert(targetData.pauseData.eventListenerId === clickEventListener.eventListenerId, `Pause data eventListenerId should be "${clickEventListener.eventListenerId}".`);
+                    InspectorTest.assert(clickEventListener.hasBreakpoint, "Click event listener for button1 should have a breakpoint.");
+
+                    WI.debuggerManager.resume();
+                });
+            });
+
+            InspectorTest.singleFireEventListener("TestPageButton1Click", (event) => {
+                if (!paused) {
+                    WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
+
+                    InspectorTest.fail("Should pause before button1 event handler is run.");
+                }
+
+                resolve();
+            });
+
+            InspectorTest.singleFireEventListener("TestPageButton2Click", (event) => {
+                if (!paused)
+                    InspectorTest.pass("Should not pause before button2 event handler is run.");
+
+                InspectorTest.log("Clicking button1...");
+                clickingButton1 = true;
+                InspectorTest.evaluateInPage(`clickButton1()`);
+            });
+
+            awaitGetClickEventListener(button1Node.id)
+            .then((clickEventListener) => {
+                InspectorTest.assert(!clickEventListener.hasBreakpoint, "Click event listener for button1 should not have a breakpoint.");
+
+                InspectorTest.log("Adding breakpoint for event listener...");
+                return DOMAgent.setBreakpointForEventListener(clickEventListener.eventListenerId);
+            })
+            .then(() => {
+                InspectorTest.log("Clicking button2...");
+                return InspectorTest.evaluateInPage(`clickButton2()`);
+            })
+            .catch(reject);
+        }
+    });
+
+    suite.addTestCase({
+        name: "DOM.removeBreakpointForEventListener",
+        description: "Check that the debugger does the not pause for this event.",
+        test(resolve, reject) {
+            let paused = false;
+            let clickingButton1 = false;
+
+            let listener = WI.debuggerManager.singleFireEventListener(WI.DebuggerManager.Event.Paused, (event) => {
+                if (clickingButton1)
+                    InspectorTest.fail("Should not pause before button1 event handler is run.");
+                else
+                    InspectorTest.fail("Should not pause before button2 event handler is run.");
+
+                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, "click", `Pause data eventName should be "click".`);
+
+                awaitGetClickEventListener(button1Node.id)
+                .then((clickEventListener) => {
+                    InspectorTest.assert(targetData.pauseData.eventListenerId === clickEventListener.eventListenerId, `Pause data eventListenerId should be "${clickEventListener.eventListenerId}".`);
+                    InspectorTest.assert(clickEventListener.hasBreakpoint, "Click event listener for button1 should have a breakpoint.");
+
+                    WI.debuggerManager.resume();
+                });
+            });
+
+            InspectorTest.singleFireEventListener("TestPageButton1Click", (event) => {
+                if (!paused) {
+                    WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
+
+                    InspectorTest.pass("Should not pause before button1 event handler is run.");
+                }
+
+                resolve();
+            });
+
+            InspectorTest.singleFireEventListener("TestPageButton2Click", (event) => {
+                if (!paused)
+                    InspectorTest.pass("Should not pause before button2 event handler is run.");
+
+                InspectorTest.log("Clicking button1...");
+                clickingButton1 = true;
+                InspectorTest.evaluateInPage(`clickButton1()`);
+            });
+
+            awaitGetClickEventListener(button1Node.id)
+            .then((clickEventListener) => {
+                InspectorTest.assert(clickEventListener.hasBreakpoint, "Click event listener for button1 should have a breakpoint.");
+
+                InspectorTest.log("Removing breakpoint for event listener...");
+                return DOMAgent.removeBreakpointForEventListener(clickEventListener.eventListenerId);
+            })
+            .then(() => {
+                InspectorTest.log("Clicking button2...");
+                return InspectorTest.evaluateInPage(`clickButton2()`);
+            })
+            .catch(reject);
+        }
+    });
+
+    suite.addTestCase({
+        name: "DOM.setBreakpointForEventListener.Invalid",
+        description: "Invalid event listener identifiers should cause an error.",
+        test(resolve, reject) {
+            const invalidEventListenerId = 9999999;
+            DOMAgent.setBreakpointForEventListener(invalidEventListenerId, (error) => {
+                InspectorTest.expectThat(error, "Should produce an error.");
+                InspectorTest.log("Error: " + error);
+                resolve();
+            });
+        }
+    });
+
+    suite.addTestCase({
+        name: "DOM.removeBreakpointForEventListener.Invalid",
+        description: "Invalid event listener identifiers should cause an error.",
+        test(resolve, reject) {
+            const invalidEventListenerId = 9999999;
+            DOMAgent.removeBreakpointForEventListener(invalidEventListenerId, (error) => {
+                InspectorTest.expectThat(error, "Should produce an error.");
+                InspectorTest.log("Error: " + error);
+                resolve();
+            });
+        }
+    });
+
+    WI.domTreeManager.requestDocument((documentNode) => {
+        Promise.all([
+            WI.domTreeManager.querySelector(documentNode.id, "#button1"),
+            WI.domTreeManager.querySelector(documentNode.id, "#button2"),
+        ])
+        .then(([button1Id, button2Id]) => {
+            button1Node = WI.domTreeManager.nodeForId(button1Id);
+            button2Node = WI.domTreeManager.nodeForId(button2Id);
+
+            suite.runTestCasesAndFinish();
+        })
+        .catch(() => {
+            InspectorTest.fail("Unable to retrieve nodes.");
+            InspectorTest.completeTest();
+        });
+    });
+}
+</script>
+</head>
+<body _onload_="runTest()">
+    <p>Testing DOMAgent.setBreakpointForEventListener and DOMAgent.removeBreakpointForEventListener.</p>
+    <button id="button1"></button>
+    <button id="button2"></button>
+    <script>
+        document.getElementById("button1").addEventListener("click", handleButton1Click);
+        document.getElementById("button2").addEventListener("click", handleButton2Click);
+    </script>
+</body>
+</html>

Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/ChangeLog (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/ChangeLog	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/ChangeLog	2018-08-24 08:07:22 UTC (rev 235288)
@@ -1,3 +1,15 @@
+2018-08-20  Devin Rousso  <[email protected]>
+
+        Web Inspector: allow breakpoints to be set for specific event listeners
+        https://bugs.webkit.org/show_bug.cgi?id=183138
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/protocol/DOM.json:
+        Add `setBreakpointForEventListener` and `removeBreakpointForEventListener`, each of which
+        takes an `eventListenerId` and toggles whether that specific usage of that event listener
+        should have a breakpoint and pause before running.
+
 2018-08-20  Mark Lam  <[email protected]>
 
         Fix the LLInt so that btjs shows vmEntryToJavaScript instead of llintPCRangeStart for the entry frame.

Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/inspector/protocol/DOM.json (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/inspector/protocol/DOM.json	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/inspector/protocol/DOM.json	2018-08-24 08:07:22 UTC (rev 235288)
@@ -90,7 +90,8 @@
                 { "name": "handler", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Event handler function value." },
                 { "name": "passive", "type": "boolean", "optional": true, "description": "<code>EventListener</code>'s passive." },
                 { "name": "once", "type": "boolean", "optional": true, "description": "<code>EventListener</code>'s once." },
-                { "name": "disabled", "type": "boolean", "optional": true }
+                { "name": "disabled", "type": "boolean", "optional": true },
+                { "name": "hasBreakpoint", "type": "boolean", "optional": true }
             ]
         },
         {
@@ -274,6 +275,20 @@
             ]
         },
         {
+            "name": "setBreakpointForEventListener",
+            "description": "Set a breakpoint on the given event listener.",
+            "parameters": [
+                { "name": "eventListenerId", "$ref": "EventListenerId" }
+            ]
+        },
+        {
+            "name": "removeBreakpointForEventListener",
+            "description": "Remove any breakpoints on the given event listener.",
+            "parameters": [
+                { "name": "eventListenerId", "$ref": "EventListenerId" }
+            ]
+        },
+        {
             "name": "getAccessibilityPropertiesForNode",
             "description": "Returns a dictionary of accessibility properties for the node.",
             "parameters": [

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/ChangeLog (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/ChangeLog	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/ChangeLog	2018-08-24 08:07:22 UTC (rev 235288)
@@ -1,3 +1,50 @@
+2018-08-20  Devin Rousso  <[email protected]>
+
+        Web Inspector: allow breakpoints to be set for specific event listeners
+        https://bugs.webkit.org/show_bug.cgi?id=183138
+
+        Reviewed by Joseph Pecoraro.
+
+        Test: inspector/dom/breakpoint-for-event-listener.html
+
+        * inspector/agents/InspectorDOMAgent.h:
+        * inspector/agents/InspectorDOMAgent.cpp:
+        (WebCore::InspectorDOMAgent::getEventListenersForNode):
+        (WebCore::InspectorDOMAgent::setEventListenerDisabled):
+        (WebCore::InspectorDOMAgent::setBreakpointForEventListener): Added.
+        (WebCore::InspectorDOMAgent::removeBreakpointForEventListener): Added.
+        (WebCore::InspectorDOMAgent::buildObjectForEventListener):
+        (WebCore::InspectorDOMAgent::willRemoveEventListener):
+        (WebCore::InspectorDOMAgent::isEventListenerDisabled):
+        (WebCore::InspectorDOMAgent::hasBreakpointForEventListener): Added.
+        (WebCore::InspectorDOMAgent::idForEventListener): Added.
+        Rework the event listener data structure to be based on ID instead of `EventListener`, since
+        it is possible to have the same `EventListener` be used for multiple events.
+
+        * inspector/agents/InspectorDOMDebuggerAgent.h:
+        * inspector/agents/InspectorDOMDebuggerAgent.cpp:
+        (WebCore::InspectorDOMDebuggerAgent::setEventListenerBreakpoint):
+        (WebCore::InspectorDOMDebuggerAgent::setInstrumentationBreakpoint):
+        (WebCore::InspectorDOMDebuggerAgent::removeEventListenerBreakpoint):
+        (WebCore::InspectorDOMDebuggerAgent::removeInstrumentationBreakpoint):
+        (WebCore::InspectorDOMDebuggerAgent::willHandleEvent): Added.
+        (WebCore::InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded):
+        For DOM events, also check to see if there is a matching event listener specific breakpoint
+        set via the DOMAgent, and break on it if one is found.
+
+        * inspector/InspectorInstrumentation.h:
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::didInstallTimerImpl):
+        (WebCore::InspectorInstrumentation::didRemoveTimerImpl):
+        (WebCore::InspectorInstrumentation::willHandleEventImpl):
+        (WebCore::InspectorInstrumentation::willFireTimerImpl):
+        (WebCore::InspectorInstrumentation::pauseOnNativeEventIfNeeded):
+        (WebCore::InspectorInstrumentation::didRequestAnimationFrameImpl):
+        (WebCore::InspectorInstrumentation::didCancelAnimationFrameImpl):
+        (WebCore::InspectorInstrumentation::willFireAnimationFrameImpl):
+        Split off `pauseOnNativeEventIfNeeded` to only handle non-DOM events, since all DOM events
+        would already only go through `willHandleEvent`.
+
 2018-08-20  Michael Catanzaro  <[email protected]>
 
         [CMake] Sync unified build with Cocoa ports

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/InspectorInstrumentation.cpp (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/InspectorInstrumentation.cpp	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/InspectorInstrumentation.cpp	2018-08-24 08:07:22 UTC (rev 235288)
@@ -294,7 +294,7 @@
 
 void InspectorInstrumentation::didInstallTimerImpl(InstrumentingAgents& instrumentingAgents, int timerId, Seconds timeout, bool singleShot, ScriptExecutionContext& context)
 {
-    pauseOnNativeEventIfNeeded(instrumentingAgents, false, setTimerEventName, true);
+    pauseOnNativeEventIfNeeded(instrumentingAgents, setTimerEventName, true);
 
     if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent())
         debuggerAgent->didScheduleAsyncCall(context.execState(), InspectorDebuggerAgent::AsyncCallType::DOMTimer, timerId, singleShot);
@@ -305,7 +305,7 @@
 
 void InspectorInstrumentation::didRemoveTimerImpl(InstrumentingAgents& instrumentingAgents, int timerId, ScriptExecutionContext& context)
 {
-    pauseOnNativeEventIfNeeded(instrumentingAgents, false, clearTimerEventName, true);
+    pauseOnNativeEventIfNeeded(instrumentingAgents, clearTimerEventName, true);
 
     if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent())
         debuggerAgent->didCancelAsyncCall(InspectorDebuggerAgent::AsyncCallType::DOMTimer, timerId);
@@ -393,7 +393,8 @@
     if (PageDebuggerAgent* pageDebuggerAgent = instrumentingAgents.pageDebuggerAgent())
         pageDebuggerAgent->willHandleEvent(listener);
 
-    pauseOnNativeEventIfNeeded(instrumentingAgents, true, event.type(), false);
+    if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents.inspectorDOMDebuggerAgent())
+        domDebuggerAgent->willHandleEvent(event, listener);
 }
 
 void InspectorInstrumentation::didHandleEventImpl(InstrumentingAgents& instrumentingAgents)
@@ -444,7 +445,7 @@
 
 InspectorInstrumentationCookie InspectorInstrumentation::willFireTimerImpl(InstrumentingAgents& instrumentingAgents, int timerId, ScriptExecutionContext& context)
 {
-    pauseOnNativeEventIfNeeded(instrumentingAgents, false, timerFiredEventName, false);
+    pauseOnNativeEventIfNeeded(instrumentingAgents, timerFiredEventName, false);
 
     if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent())
         debuggerAgent->willDispatchAsyncCall(InspectorDebuggerAgent::AsyncCallType::DOMTimer, timerId);
@@ -1043,15 +1044,15 @@
     return instrumentingAgents && instrumentingAgents->inspectorTimelineAgent();
 }
 
-void InspectorInstrumentation::pauseOnNativeEventIfNeeded(InstrumentingAgents& instrumentingAgents, bool isDOMEvent, const String& eventName, bool synchronous)
+void InspectorInstrumentation::pauseOnNativeEventIfNeeded(InstrumentingAgents& instrumentingAgents, const String& eventName, bool synchronous)
 {
     if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents.inspectorDOMDebuggerAgent())
-        domDebuggerAgent->pauseOnNativeEventIfNeeded(isDOMEvent, eventName, synchronous);
+        domDebuggerAgent->pauseOnNativeEventIfNeeded(eventName, synchronous);
 }
 
 void InspectorInstrumentation::didRequestAnimationFrameImpl(InstrumentingAgents& instrumentingAgents, int callbackId, Document& document)
 {
-    pauseOnNativeEventIfNeeded(instrumentingAgents, false, requestAnimationFrameEventName, true);
+    pauseOnNativeEventIfNeeded(instrumentingAgents, requestAnimationFrameEventName, true);
 
     if (PageDebuggerAgent* pageDebuggerAgent = instrumentingAgents.pageDebuggerAgent())
         pageDebuggerAgent->didRequestAnimationFrame(callbackId, document);
@@ -1061,7 +1062,7 @@
 
 void InspectorInstrumentation::didCancelAnimationFrameImpl(InstrumentingAgents& instrumentingAgents, int callbackId, Document& document)
 {
-    pauseOnNativeEventIfNeeded(instrumentingAgents, false, cancelAnimationFrameEventName, true);
+    pauseOnNativeEventIfNeeded(instrumentingAgents, cancelAnimationFrameEventName, true);
 
     if (PageDebuggerAgent* pageDebuggerAgent = instrumentingAgents.pageDebuggerAgent())
         pageDebuggerAgent->didCancelAnimationFrame(callbackId);
@@ -1071,7 +1072,7 @@
 
 InspectorInstrumentationCookie InspectorInstrumentation::willFireAnimationFrameImpl(InstrumentingAgents& instrumentingAgents, int callbackId, Document& document)
 {
-    pauseOnNativeEventIfNeeded(instrumentingAgents, false, animationFrameFiredEventName, false);
+    pauseOnNativeEventIfNeeded(instrumentingAgents, animationFrameFiredEventName, false);
 
     if (PageDebuggerAgent* pageDebuggerAgent = instrumentingAgents.pageDebuggerAgent())
         pageDebuggerAgent->willFireAnimationFrame(callbackId);

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/InspectorInstrumentation.h (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/InspectorInstrumentation.h	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/InspectorInstrumentation.h	2018-08-24 08:07:22 UTC (rev 235288)
@@ -453,7 +453,7 @@
 
     static InspectorTimelineAgent* retrieveTimelineAgent(const InspectorInstrumentationCookie&);
 
-    static void pauseOnNativeEventIfNeeded(InstrumentingAgents&, bool isDOMEvent, const String& eventName, bool synchronous);
+    static void pauseOnNativeEventIfNeeded(InstrumentingAgents&, const String& eventName, bool synchronous);
 
     WEBCORE_EXPORT static int s_frontendCounter;
 };

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp	2018-08-24 08:07:22 UTC (rev 235288)
@@ -841,20 +841,28 @@
     auto addListener = [&] (RegisteredEventListener& listener, const EventListenerInfo& info) {
         int identifier = 0;
         bool disabled = false;
+        bool hasBreakpoint = false;
 
-        auto it = m_eventListenerEntries.find(&listener.callback());
-        if (it == m_eventListenerEntries.end()) {
-            InspectorEventListener inspectorEventListener(m_lastEventListenerId++, *info.node, info.eventType, listener.useCapture());
-            m_eventListenerEntries.add(&listener.callback(), inspectorEventListener);
+        for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
+            if (inspectorEventListener.matches(*info.node, info.eventType, listener.callback(), listener.useCapture())) {
+                identifier = inspectorEventListener.identifier;
+                disabled = inspectorEventListener.disabled;
+                hasBreakpoint = inspectorEventListener.hasBreakpoint;
+                break;
+            }
+        }
 
+        if (!identifier) {
+            InspectorEventListener inspectorEventListener(m_lastEventListenerId++, *info.node, info.eventType, listener.callback(), listener.useCapture());
+
             identifier = inspectorEventListener.identifier;
             disabled = inspectorEventListener.disabled;
-        } else {
-            identifier = it->value.identifier;
-            disabled = it->value.disabled;
+            hasBreakpoint = inspectorEventListener.hasBreakpoint;
+
+            m_eventListenerEntries.add(identifier, inspectorEventListener);
         }
 
-        listenersArray->addItem(buildObjectForEventListener(listener, identifier, info.eventType, info.node, objectGroup, disabled));
+        listenersArray->addItem(buildObjectForEventListener(listener, identifier, info.eventType, info.node, objectGroup, disabled, hasBreakpoint));
     };
 
     // Get Capturing Listeners (in this order)
@@ -910,16 +918,37 @@
 
 void InspectorDOMAgent::setEventListenerDisabled(ErrorString& errorString, int eventListenerId, bool disabled)
 {
-    for (InspectorEventListener& inspectorEventListener : m_eventListenerEntries.values()) {
-        if (inspectorEventListener.identifier == eventListenerId) {
-            inspectorEventListener.disabled = disabled;
-            return;
-        }
+    auto it = m_eventListenerEntries.find(eventListenerId);
+    if (it == m_eventListenerEntries.end()) {
+        errorString = "No event listener for given identifier."_s;
+        return;
     }
 
-    errorString = "No event listener for given identifier."_s;
+    it->value.disabled = disabled;
 }
 
+void InspectorDOMAgent::setBreakpointForEventListener(ErrorString& errorString, int eventListenerId)
+{
+    auto it = m_eventListenerEntries.find(eventListenerId);
+    if (it == m_eventListenerEntries.end()) {
+        errorString = "No event listener for given identifier."_s;
+        return;
+    }
+
+    it->value.hasBreakpoint = true;
+}
+
+void InspectorDOMAgent::removeBreakpointForEventListener(ErrorString& errorString, int eventListenerId)
+{
+    auto it = m_eventListenerEntries.find(eventListenerId);
+    if (it == m_eventListenerEntries.end()) {
+        errorString = "No event listener for given identifier."_s;
+        return;
+    }
+
+    it->value.hasBreakpoint = false;
+}
+
 void InspectorDOMAgent::getAccessibilityPropertiesForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::DOM::AccessibilityProperties>& axProperties)
 {
     Node* node = assertNode(errorString, nodeId);
@@ -1593,7 +1622,7 @@
     return WTFMove(pseudoElements);
 }
 
-Ref<Inspector::Protocol::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, int identifier, const AtomicString& eventType, Node* node, const String* objectGroupId, bool disabled)
+Ref<Inspector::Protocol::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, int identifier, const AtomicString& eventType, Node* node, const String* objectGroupId, bool disabled, bool hasBreakpoint)
 {
     Ref<EventListener> eventListener = registeredEventListener.callback();
 
@@ -1653,6 +1682,8 @@
         value->setOnce(true);
     if (disabled)
         value->setDisabled(disabled);
+    if (hasBreakpoint)
+        value->setHasBreakpoint(hasBreakpoint);
     return value;
 }
     
@@ -2271,7 +2302,9 @@
     if (!listenerExists)
         return;
 
-    m_eventListenerEntries.remove(&listener);
+    m_eventListenerEntries.removeIf([&] (auto& entry) {
+        return entry.value.matches(target, eventType, listener, capture);
+    });
 
     m_frontendDispatcher->willRemoveEventListener(nodeId);
 }
@@ -2278,14 +2311,29 @@
 
 bool InspectorDOMAgent::isEventListenerDisabled(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture)
 {
-    auto it = m_eventListenerEntries.find(&listener);
-    if (it == m_eventListenerEntries.end())
-        return false;
+    for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
+        if (inspectorEventListener.matches(target, eventType, listener, capture))
+            return inspectorEventListener.disabled;
+    }
+    return false;
+}
 
-    if (!it->value.disabled)
-        return false;
+bool InspectorDOMAgent::hasBreakpointForEventListener(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture)
+{
+    for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
+        if (inspectorEventListener.matches(target, eventType, listener, capture))
+            return inspectorEventListener.hasBreakpoint;
+    }
+    return false;
+}
 
-    return it->value.eventTarget.get() == &target && it->value.eventType == eventType && it->value.useCapture == capture;
+int InspectorDOMAgent::idForEventListener(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture)
+{
+    for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
+        if (inspectorEventListener.matches(target, eventType, listener, capture))
+            return inspectorEventListener.identifier;
+    }
+    return 0;
 }
 
 Node* InspectorDOMAgent::nodeForPath(const String& path)

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMAgent.h (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMAgent.h	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMAgent.h	2018-08-24 08:07:22 UTC (rev 235288)
@@ -125,6 +125,8 @@
     void setNodeValue(ErrorString&, int nodeId, const String& value) override;
     void getEventListenersForNode(ErrorString&, int nodeId, const WTF::String* objectGroup, RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::EventListener>>& listenersArray) override;
     void setEventListenerDisabled(ErrorString&, int eventListenerId, bool disabled) override;
+    void setBreakpointForEventListener(ErrorString&, int eventListenerId) override;
+    void removeBreakpointForEventListener(ErrorString&, int eventListenerId) override;
     void getAccessibilityPropertiesForNode(ErrorString&, int nodeId, RefPtr<Inspector::Protocol::DOM::AccessibilityProperties>& axProperties) override;
     void performSearch(ErrorString&, const String& whitespaceTrimmedQuery, const JSON::Array* nodeIds, String* searchId, int* resultCount) override;
     void getSearchResults(ErrorString&, const String& searchId, int fromIndex, int toIndex, RefPtr<JSON::ArrayOf<int>>&) override;
@@ -213,6 +215,9 @@
     // Methods called from other agents.
     InspectorPageAgent* pageAgent() { return m_pageAgent; }
 
+    bool hasBreakpointForEventListener(EventTarget&, const AtomicString& eventType, EventListener&, bool capture);
+    int idForEventListener(EventTarget&, const AtomicString& eventType, EventListener&, bool capture);
+
 private:
     void highlightMousedOverNode();
     void setSearchingForNode(ErrorString&, bool enabled, const JSON::Object* highlightConfig);
@@ -233,7 +238,7 @@
     Ref<JSON::ArrayOf<String>> buildArrayForElementAttributes(Element*);
     Ref<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap);
     RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForPseudoElements(const Element&, NodeToIdMap* nodesMap);
-    Ref<Inspector::Protocol::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, int identifier, const AtomicString& eventType, Node*, const String* objectGroupId, bool disabled = false);
+    Ref<Inspector::Protocol::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, int identifier, const AtomicString& eventType, Node*, const String* objectGroupId, bool disabled, bool hasBreakpoint);
     RefPtr<Inspector::Protocol::DOM::AccessibilityProperties> buildObjectForAccessibilityProperties(Node*);
     void processAccessibilityChildren(RefPtr<AccessibilityObject>&&, RefPtr<JSON::ArrayOf<int>>&&);
     
@@ -278,22 +283,38 @@
     struct InspectorEventListener {
         int identifier { 1 };
         RefPtr<EventTarget> eventTarget;
+        RefPtr<EventListener> eventListener;
         AtomicString eventType;
         bool useCapture { false };
         bool disabled { false };
+        bool hasBreakpoint { false };
 
         InspectorEventListener() { }
 
-        InspectorEventListener(int identifier, EventTarget& eventTarget, const AtomicString& eventType, bool useCapture)
+        InspectorEventListener(int identifier, EventTarget& target, const AtomicString& type, EventListener& listener, bool capture)
             : identifier(identifier)
-            , eventTarget(&eventTarget)
-            , eventType(eventType)
-            , useCapture(useCapture)
+            , eventTarget(&target)
+            , eventListener(&listener)
+            , eventType(type)
+            , useCapture(capture)
         {
         }
+
+        bool matches(EventTarget& target, const AtomicString& type, EventListener& listener, bool capture)
+        {
+            if (eventTarget.get() != &target)
+                return false;
+            if (eventListener.get() != &listener)
+                return false;
+            if (eventType != type)
+                return false;
+            if (useCapture != capture)
+                return false;
+            return true;
+        }
     };
 
-    HashMap<EventListener*, InspectorEventListener> m_eventListenerEntries;
+    HashMap<int, InspectorEventListener> m_eventListenerEntries;
     int m_lastEventListenerId { 1 };
 };
 

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp	2018-08-24 08:07:22 UTC (rev 235288)
@@ -32,10 +32,12 @@
 #include "config.h"
 #include "InspectorDOMDebuggerAgent.h"
 
+#include "Event.h"
 #include "Frame.h"
 #include "HTMLElement.h"
 #include "InspectorDOMAgent.h"
 #include "InstrumentingAgents.h"
+#include "RegisteredEventListener.h"
 #include <_javascript_Core/ContentSearchUtilities.h>
 #include <_javascript_Core/InspectorFrontendDispatchers.h>
 #include <_javascript_Core/RegularExpression.h>
@@ -50,8 +52,8 @@
     DOMBreakpointTypesCount
 };
 
-static const char listenerEventCategoryType[] = "listener:";
-static const char instrumentationEventCategoryType[] = "instrumentation:";
+static const char eventNameCategoryType[] = "event-name:";
+static const char instrumentationCategoryType[] = "instrumentation:";
 
 const uint32_t inheritableDOMBreakpointTypesMask = (1 << SubtreeModified);
 const int domBreakpointDerivedTypeShift = 16;
@@ -126,12 +128,12 @@
 
 void InspectorDOMDebuggerAgent::setEventListenerBreakpoint(ErrorString& error, const String& eventName)
 {
-    setBreakpoint(error, listenerEventCategoryType + eventName);
+    setBreakpoint(error, eventNameCategoryType + eventName);
 }
 
 void InspectorDOMDebuggerAgent::setInstrumentationBreakpoint(ErrorString& error, const String& eventName)
 {
-    setBreakpoint(error, instrumentationEventCategoryType + eventName);
+    setBreakpoint(error, instrumentationCategoryType + eventName);
 }
 
 void InspectorDOMDebuggerAgent::setBreakpoint(ErrorString& error, const String& eventName)
@@ -146,12 +148,12 @@
 
 void InspectorDOMDebuggerAgent::removeEventListenerBreakpoint(ErrorString& error, const String& eventName)
 {
-    removeBreakpoint(error, listenerEventCategoryType + eventName);
+    removeBreakpoint(error, eventNameCategoryType + eventName);
 }
 
 void InspectorDOMDebuggerAgent::removeInstrumentationBreakpoint(ErrorString& error, const String& eventName)
 {
-    removeBreakpoint(error, instrumentationEventCategoryType + eventName);
+    removeBreakpoint(error, instrumentationCategoryType + eventName);
 }
 
 void InspectorDOMDebuggerAgent::removeBreakpoint(ErrorString& error, const String& eventName)
@@ -362,15 +364,34 @@
         updateSubtreeBreakpoints(child, newRootMask, set);
 }
 
-void InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded(bool isDOMEvent, const String& eventName, bool synchronous)
+void InspectorDOMDebuggerAgent::willHandleEvent(const Event& event, const RegisteredEventListener& registeredEventListener)
 {
-    String fullEventName = (isDOMEvent ? listenerEventCategoryType : instrumentationEventCategoryType) + eventName;
+    bool shouldPause = m_debuggerAgent->pauseOnNextStatementEnabled() || m_eventListenerBreakpoints.contains(eventNameCategoryType + event.type());
 
-    bool shouldPause = m_debuggerAgent->pauseOnNextStatementEnabled() || m_eventListenerBreakpoints.contains(fullEventName);
+    if (!shouldPause && m_domAgent)
+        shouldPause = m_domAgent->hasBreakpointForEventListener(*event.currentTarget(), event.type(), registeredEventListener.callback(), registeredEventListener.useCapture());
+
     if (!shouldPause)
         return;
 
     Ref<JSON::Object> eventData = JSON::Object::create();
+    eventData->setString("eventName"_s, event.type());
+    if (m_domAgent) {
+        int eventListenerId = m_domAgent->idForEventListener(*event.currentTarget(), event.type(), registeredEventListener.callback(), registeredEventListener.useCapture());
+        if (eventListenerId)
+            eventData->setInteger("eventListenerId"_s, eventListenerId);
+    }
+
+    m_debuggerAgent->schedulePauseOnNextStatement(Inspector::DebuggerFrontendDispatcher::Reason::EventListener, WTFMove(eventData));
+}
+
+void InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded(const String& eventName, bool synchronous)
+{
+    bool shouldPause = m_debuggerAgent->pauseOnNextStatementEnabled() || m_eventListenerBreakpoints.contains(instrumentationCategoryType + eventName);
+    if (!shouldPause)
+        return;
+
+    Ref<JSON::Object> eventData = JSON::Object::create();
     eventData->setString("eventName"_s, eventName);
 
     if (synchronous)

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.h (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.h	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.h	2018-08-24 08:07:22 UTC (rev 235288)
@@ -41,9 +41,11 @@
 namespace WebCore {
 
 class Element;
+class Event;
 class Frame;
 class InspectorDOMAgent;
 class Node;
+class RegisteredEventListener;
 
 typedef String ErrorString;
 
@@ -72,8 +74,10 @@
     void didRemoveDOMNode(Node&);
     void willModifyDOMAttr(Element&);
     void willSendXMLHttpRequest(const String& url);
-    void pauseOnNativeEventIfNeeded(bool isDOMEvent, const String& eventName, bool synchronous);
     void frameDocumentUpdated(Frame&);
+    void willHandleEvent(const Event&, const RegisteredEventListener&);
+    void pauseOnNativeEventIfNeeded(const String& eventName, bool synchronous);
+    void mainFrameDOMContentLoaded();
 
     void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) final;
     void willDestroyFrontendAndBackend(Inspector::DisconnectReason) final;

Modified: releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/ChangeLog (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/ChangeLog	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/ChangeLog	2018-08-24 08:07:22 UTC (rev 235288)
@@ -1,3 +1,46 @@
+2018-08-20  Devin Rousso  <[email protected]>
+
+        Web Inspector: allow breakpoints to be set for specific event listeners
+        https://bugs.webkit.org/show_bug.cgi?id=183138
+
+        Reviewed by Joseph Pecoraro.
+
+        * Localizations/en.lproj/localizedStrings.js:
+
+        * UserInterface/Models/EventBreakpoint.js:
+        (WI.EventBreakpoint):
+        (WI.EventBreakpoint.fromPayload): Added.
+        (WI.EventBreakpoint.prototype.get eventListener): Added.
+
+        * UserInterface/Controllers/DOMDebuggerManager.js:
+        (WI.DOMDebuggerManager):
+
+        * UserInterface/Controllers/DOMTreeManager.js:
+        (WI.DOMTreeManager):
+        (WI.DOMTreeManager.prototype.get eventBreakpoints): Added.
+        (WI.DOMTreeManager.prototype._setDocument):
+        (WI.DOMTreeManager.prototype.setEventListenerDisabled):
+        (WI.DOMTreeManager.prototype.setBreakpointForEventListener): Added.
+        (WI.DOMTreeManager.prototype.removeBreakpointForEventListener): Added.
+        (WI.DOMTreeManager.prototype.breakpointForEventListenerId): Added.
+
+        * UserInterface/Controllers/EventBreakpointTreeController.js:
+        (WI.EventBreakpointTreeController):
+
+        * UserInterface/Views/DebuggerSidebarPanel.js:
+        (WI.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
+
+        * UserInterface/Views/EventListenerSectionGroup.js:
+        (WI.EventListenerSectionGroup):
+        (WI.EventListenerSectionGroup.prototype._createDisabledToggleRow):
+        (WI.EventListenerSectionGroup.prototype._createBreakpointToggleRow): Added.
+
+        * UserInterface/Views/EventBreakpointTreeElement.js:
+        (WI.EventBreakpointTreeElement):
+        (WI.EventBreakpointTreeElement.prototype.ondelete):
+        (WI.EventBreakpointTreeElement.prototype.populateContextMenu):
+        (WI.EventBreakpointTreeElement.prototype._toggleBreakpoint):
+
 2018-08-16  Devin Rousso  <[email protected]>
 
         Web Inspector: support breakpoints for arbitrary event names

Modified: releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2018-08-24 08:07:22 UTC (rev 235288)
@@ -146,10 +146,12 @@
 localizedStrings["Box Model"] = "Box Model";
 localizedStrings["Box Shadow"] = "Box Shadow";
 localizedStrings["Break on events with name:"] = "Break on events with name:";
+localizedStrings["Break on listeners for event with name:"] = "Break on listeners for event with name:";
 localizedStrings["Break on request with URL:"] = "Break on request with URL:";
 localizedStrings["Break on…"] = "Break on…";
 localizedStrings["Breakdown"] = "Breakdown";
 localizedStrings["Breakdown of each memory category at the end of the selected time range"] = "Breakdown of each memory category at the end of the selected time range";
+localizedStrings["Breakpoint"] = "Breakpoint";
 localizedStrings["Breakpoints"] = "Breakpoints";
 localizedStrings["Breakpoints disabled"] = "Breakpoints disabled";
 localizedStrings["Bubbling"] = "Bubbling";

Modified: releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js	2018-08-24 08:07:22 UTC (rev 235288)
@@ -62,10 +62,8 @@
                 this.addDOMBreakpoint(breakpoint);
             }
 
-            for (let cookie of this._eventBreakpointSetting.value) {
-                let breakpoint = new WI.EventBreakpoint(cookie.eventName, cookie.disabled);
-                this.addEventBreakpoint(breakpoint);
-            }
+            for (let payload of this._eventBreakpointSetting.value)
+                this.addEventBreakpoint(WI.EventBreakpoint.fromPayload(payload));
 
             for (let cookie of this._xhrBreakpointsSetting.value) {
                 let breakpoint = new WI.XHRBreakpoint(cookie.type, cookie.url, cookie.disabled);

Modified: releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Controllers/DOMTreeManager.js (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Controllers/DOMTreeManager.js	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Controllers/DOMTreeManager.js	2018-08-24 08:07:22 UTC (rev 235288)
@@ -43,11 +43,18 @@
         this._loadNodeAttributesTimeout = 0;
         this._inspectedNode = null;
 
+        this._breakpointsForEventListeners = new Map;
+
         WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
     }
 
     // Public
 
+    get eventListenerBreakpoints()
+    {
+        return Array.from(this._breakpointsForEventListeners.values());
+    }
+
     requestDocument(callback)
     {
         if (this._document) {
@@ -219,6 +226,7 @@
     _setDocument(payload)
     {
         this._idToDOMNode = {};
+        this._breakpointsForEventListeners.clear();
 
         let newDocument = null;
         if (payload && "nodeId" in payload)
@@ -538,11 +546,52 @@
         DOMAgent.setInspectedNode(node.id, callback);
     }
 
-    setEventListenerDisabled(eventListenerId, disabled)
+    setEventListenerDisabled(eventListener, disabled)
     {
-        DOMAgent.setEventListenerDisabled(eventListenerId, disabled);
+        DOMAgent.setEventListenerDisabled(eventListener.eventListenerId, disabled, (error) => {
+            if (error)
+                console.error(error);
+        });
     }
 
+    setBreakpointForEventListener(eventListener)
+    {
+        let breakpoint = new WI.EventBreakpoint(eventListener.type, {eventListener});
+        this._breakpointsForEventListeners.set(eventListener.eventListenerId, breakpoint);
+
+        DOMAgent.setBreakpointForEventListener(eventListener.eventListenerId, (error) => {
+            if (error) {
+                console.error(error);
+                return;
+            }
+
+            WI.domDebuggerManager.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointAdded, {breakpoint});
+        });
+    }
+
+    removeBreakpointForEventListener(eventListener)
+    {
+        let breakpoint = this._breakpointsForEventListeners.get(eventListener.eventListenerId);
+        console.assert(breakpoint);
+
+        this._breakpointsForEventListeners.delete(eventListener.eventListenerId);
+
+        DOMAgent.removeBreakpointForEventListener(eventListener.eventListenerId, (error) => {
+            if (error) {
+                console.error(error);
+                return;
+            }
+
+            if (breakpoint)
+                WI.domDebuggerManager.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, {breakpoint});
+        });
+    }
+
+    breakpointForEventListenerId(eventListenerId)
+    {
+        return this._breakpointsForEventListeners.get(eventListenerId) || null;
+    }
+
     _buildHighlightConfig(mode = "all")
     {
         let highlightConfig = {showInfo: mode === "all"};

Modified: releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Controllers/EventBreakpointTreeController.js (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Controllers/EventBreakpointTreeController.js	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Controllers/EventBreakpointTreeController.js	2018-08-24 08:07:22 UTC (rev 235288)
@@ -32,6 +32,9 @@
         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.domTreeManager.eventListenerBreakpoints)
+            this._addTreeElement(breakpoint);
+
         for (let breakpoint of WI.domDebuggerManager.eventBreakpoints)
             this._addTreeElement(breakpoint);
     }
@@ -71,6 +74,8 @@
         if (treeElement)
             return;
 
-        this._treeOutline.appendChild(new WI.EventBreakpointTreeElement(breakpoint));
+        this._treeOutline.appendChild(new WI.EventBreakpointTreeElement(breakpoint, {
+            linkifyNode: true,
+        }));
     }
 };

Modified: releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Models/EventBreakpoint.js (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Models/EventBreakpoint.js	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Models/EventBreakpoint.js	2018-08-24 08:07:22 UTC (rev 235288)
@@ -25,7 +25,7 @@
 
 WI.EventBreakpoint = class EventBreakpoint extends WI.Object
 {
-    constructor(eventName, disabled)
+    constructor(eventName, {disabled, eventListener} = {})
     {
         super();
 
@@ -32,12 +32,24 @@
         console.assert(typeof eventName === "string");
 
         this._eventName = eventName;
+
         this._disabled = disabled || false;
+        this._eventListener = eventListener || null;
     }
 
+    // Static
+
+    static fromPayload(payload)
+    {
+        return new WI.EventBreakpoint(payload.eventName, {
+            disabled: !!payload.disabled,
+        });
+    }
+
     // Public
 
     get eventName() { return this._eventName; }
+    get eventListener() { return this._eventListener; }
 
     get disabled()
     {

Modified: releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js	2018-08-24 08:07:22 UTC (rev 235288)
@@ -1057,18 +1057,35 @@
         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);
+                let eventBreakpoint = null;
+                if (pauseData.eventListenerId)
+                    eventBreakpoint = WI.domTreeManager.breakpointForEventListenerId(pauseData.eventListenerId);
+                if (!eventBreakpoint)
+                    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));
+                let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(eventBreakpoint, {
+                    className: WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName,
+                    title: 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];
+                let rows = [eventBreakpointRow];
+
+                let eventListener = eventBreakpoint.eventListener;
+                if (eventListener) {
+                    console.assert(eventListener.eventListenerId === pauseData.eventListenerId);
+
+                    let ownerElementRow = new WI.DetailsSectionSimpleRow(WI.UIString("Element"), WI.linkifyNodeReference(eventListener.node));
+                    rows.push(ownerElementRow);
+                }
+
+                this._pauseReasonGroup.rows = rows;
             }
             return true;
 

Modified: releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.js (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.js	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.js	2018-08-24 08:07:22 UTC (rev 235288)
@@ -25,7 +25,7 @@
 
 WI.EventBreakpointTreeElement = class EventBreakpointTreeElement extends WI.GeneralTreeElement
 {
-    constructor(breakpoint, className, title)
+    constructor(breakpoint, {className, title, linkifyNode} = {})
     {
         console.assert(breakpoint instanceof WI.EventBreakpoint);
 
@@ -36,7 +36,10 @@
         if (!title)
             title = breakpoint.eventName;
 
-        const subtitle = null;
+        let subtitle = null;
+        if (linkifyNode && breakpoint.eventListener)
+            subtitle = WI.linkifyNodeReference(breakpoint.eventListener.node);
+
         super(classNames, title, subtitle, breakpoint);
 
         this._statusImageElement = document.createElement("img");
@@ -78,7 +81,10 @@
 
     ondelete()
     {
-        WI.domDebuggerManager.removeEventBreakpoint(this.representedObject);
+        if (this.representedObject.eventListener)
+            WI.domTreeManager.removeBreakpointForEventListener(this.representedObject.eventListener);
+        else
+            WI.domDebuggerManager.removeEventBreakpoint(this.representedObject);
         return true;
     }
 
@@ -97,13 +103,18 @@
     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 (!breakpoint.eventListener) {
+            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);
+                if (breakpoint.eventListener)
+                    WI.domTreeManager.removeBreakpointForEventListener(breakpoint.eventListener);
+                else
+                    WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
             });
         }
     }
@@ -129,6 +140,11 @@
 
     _toggleBreakpoint()
     {
+        if (this.representedObject.eventListener) {
+            WI.domTreeManager.removeBreakpointForEventListener(this.representedObject.eventListener);
+            return;
+        }
+
         this.representedObject.disabled = !this.representedObject.disabled;
     }
 

Modified: releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Views/EventListenerSectionGroup.js (235287 => 235288)


--- releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Views/EventListenerSectionGroup.js	2018-08-24 08:07:05 UTC (rev 235287)
+++ releases/WebKitGTK/webkit-2.22/Source/WebInspectorUI/UserInterface/Views/EventListenerSectionGroup.js	2018-08-24 08:07:22 UTC (rev 235288)
@@ -52,9 +52,14 @@
         if (this._eventListener.once)
             rows.push(new WI.DetailsSectionSimpleRow(WI.UIString("Once"), WI.UIString("Yes")));
 
-        if (DOMAgent.setEventListenerDisabled && this._eventListener.eventListenerId)
-            rows.push(this._createDisabledToggleRow());
+        if (this._eventListener.eventListenerId) {
+            if (DOMAgent.setEventListenerDisabled)
+                rows.push(this._createDisabledToggleRow());
 
+            if (DOMAgent.setBreakpointForEventListener && DOMAgent.removeBreakpointForEventListener)
+                rows.push(this._createBreakpointToggleRow());
+        }
+
         this.rows = rows;
     }
 
@@ -125,7 +130,7 @@
 
         toggleElement.addEventListener("change", (event) => {
             this._eventListener.disabled = !toggleElement.checked;
-            WI.domTreeManager.setEventListenerDisabled(this._eventListener.eventListenerId, this._eventListener.disabled);
+            WI.domTreeManager.setEventListenerDisabled(this._eventListener, this._eventListener.disabled);
             updateTitle();
         });
 
@@ -137,4 +142,38 @@
 
         return new WI.DetailsSectionSimpleRow(toggleLabel, toggleElement);
     }
+
+    _createBreakpointToggleRow()
+    {
+        let checkboxElement = document.createElement("input");
+        checkboxElement.type = "checkbox";
+        checkboxElement.checked = !!this._eventListener.hasBreakpoint;
+
+        let updateTitle = () => {
+            if (this._eventListener.hasBreakpoint)
+                checkboxElement.title = WI.UIString("Delete Breakpoint");
+            else
+                checkboxElement.title = WI.UIString("Add Breakpoint");
+        };
+
+        updateTitle();
+
+        checkboxElement.addEventListener("change", (event) => {
+            this._eventListener.hasBreakpoint = !!checkboxElement.checked;
+            if (this._eventListener.hasBreakpoint)
+                WI.domTreeManager.setBreakpointForEventListener(this._eventListener);
+            else
+                WI.domTreeManager.removeBreakpointForEventListener(this._eventListener);
+
+            updateTitle();
+        });
+
+        let labelElement = document.createElement("span");
+        labelElement.textContent = WI.UIString("Breakpoint");
+        labelElement.addEventListener("click", (event) => {
+            checkboxElement.click();
+        });
+
+        return new WI.DetailsSectionSimpleRow(labelElement, checkboxElement);
+    }
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to