| Differences between
and this patch
- a/Source/WebCore/ChangeLog +12 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2018-03-13  Devin Rousso  <webkit@devinrousso.com>
2
3
        Web Inspector: support breakpoints for arbitrary event names
4
        https://bugs.webkit.org/show_bug.cgi?id=183118
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Test: inspector/dom-debugger/event-listener-breakpoints.html
9
10
        * inspector/agents/InspectorDOMDebuggerAgent.cpp:
11
        (WebCore::InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded):
12
1
2018-03-13  Chris Dumez  <cdumez@apple.com>
13
2018-03-13  Chris Dumez  <cdumez@apple.com>
2
14
3
        fast/loader/javascript-url-iframe-remove-on-navigate.html is a flaky crash on iOS with async delegates
15
        fast/loader/javascript-url-iframe-remove-on-navigate.html is a flaky crash on iOS with async delegates
- a/Source/WebInspectorUI/ChangeLog +91 lines
Lines 1-3 a/Source/WebInspectorUI/ChangeLog_sec1
1
2018-03-13  Devin Rousso  <webkit@devinrousso.com>
2
3
        Web Inspector: support breakpoints for arbitrary event names
4
        https://bugs.webkit.org/show_bug.cgi?id=183118
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Create UI for setting breakpoints on event names. Ties into existing DOMDebugger commands,
9
        specifically `setEventListenerBreakpoint` and `removeEventListenerBreakpoint`, that will
10
        pause execution if any DOM event is fired that matches any previously registered breakpoints.
11
12
        Event listener breakpoints are distinguished by name, and they currently apply globally,
13
        meaning that only one breakpoint per event name can be registered.
14
15
        Event listener breakpoints are created in the Debugger tab in a new "Event Listener Breakpoints"
16
        section in the Navigation sidebar. A new type of popover, EventListenerBreakpointPopover, is
17
        used, but right now all it contains is a basic text input for the event name. Similarly, a
18
        new TreeElement subclass, EventListenerBreakpointTreeElement, is used when showing the list
19
        of event listener breakpoints, but all it shows now is the event name.
20
21
        The majority of the logic in this patch was derived from XHR breakpoints.
22
23
        * Localizations/en.lproj/localizedStrings.js:
24
        * UserInterface/Main.html:
25
        * UserInterface/Test.html:
26
27
        * UserInterface/Models/EventListenerBreakpoint.js: Added.
28
        (WI.EventListenerBreakpoint):
29
        (WI.EventListenerBreakpoint.prototype.get eventName):
30
        (WI.EventListenerBreakpoint.prototype.get disabled):
31
        (WI.EventListenerBreakpoint.prototype.set disabled):
32
        (WI.EventListenerBreakpoint.prototype.get serializableInfo):
33
        (WI.EventListenerBreakpoint.prototype.saveIdentityToCookie):
34
35
        * UserInterface/Controllers/DOMDebuggerManager.js:
36
        (WI.DOMDebuggerManager):
37
        (WI.DOMDebuggerManager.prototype.get eventListenerBreakpoints):
38
        (WI.DOMDebuggerManager.prototype.eventListenerBreakpointForEventName):
39
        (WI.DOMDebuggerManager.prototype.addEventListenerBreakpoint):
40
        (WI.DOMDebuggerManager.prototype.removeEventListenerBreakpoint):
41
        (WI.DOMDebuggerManager.prototype._speculativelyResolveBreakpoints):
42
        (WI.DOMDebuggerManager.prototype._updateEventListenerBreakpoint.breakpointUpdated):
43
        (WI.DOMDebuggerManager.prototype._updateEventListenerBreakpoint):
44
        (WI.DOMDebuggerManager.prototype._resolveEventListenerBreakpoint):
45
        (WI.DOMDebuggerManager.prototype._saveEventListenerBreakpoints):
46
        (WI.DOMDebuggerManager.prototype._eventListenerBreakpointDisabledStateDidChange):
47
48
        * UserInterface/Controllers/DebuggerManager.js:
49
        (WI.DebuggerManager.prototype._pauseReasonFromPayload):
50
51
        * UserInterface/Controllers/EventListenerBreakpointTreeController.js: Added.
52
        (WI.EventListenerBreakpointTreeController):
53
        (WI.EventListenerBreakpointTreeController.prototype.revealAndSelect):
54
        (WI.EventListenerBreakpointTreeController.prototype._eventListenerBreakpointAdded):
55
        (WI.EventListenerBreakpointTreeController.prototype._eventListenerBreakpointRemoved):
56
        (WI.EventListenerBreakpointTreeController.prototype._addTreeElement):
57
58
        * UserInterface/Views/DebuggerSidebarPanel.js:
59
        (WI.DebuggerSidebarPanel):
60
        (WI.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
61
        (WI.DebuggerSidebarPanel.prototype._eventListenerBreakpointAddedOrRemoved):
62
        (WI.DebuggerSidebarPanel.prototype._addEventListenerBreakpointButtonClicked):
63
        (WI.DebuggerSidebarPanel.prototype.willDismissPopover):
64
65
        * UserInterface/Views/EventListenerBreakpointTreeElement.js: Added.
66
        (WI.EventListenerBreakpointTreeElement):
67
        (WI.EventListenerBreakpointTreeElement.prototype.onattach):
68
        (WI.EventListenerBreakpointTreeElement.prototype.ondetach):
69
        (WI.EventListenerBreakpointTreeElement.prototype.ondelete):
70
        (WI.EventListenerBreakpointTreeElement.prototype.onenter):
71
        (WI.EventListenerBreakpointTreeElement.prototype.onspace):
72
        (WI.EventListenerBreakpointTreeElement.prototype.populateContextMenu):
73
        (WI.EventListenerBreakpointTreeElement.prototype._statusImageElementClicked):
74
        (WI.EventListenerBreakpointTreeElement.prototype._statusImageElementFocused):
75
        (WI.EventListenerBreakpointTreeElement.prototype._statusImageElementMouseDown):
76
        (WI.EventListenerBreakpointTreeElement.prototype._toggleBreakpoint):
77
        (WI.EventListenerBreakpointTreeElement.prototype._updateStatus):
78
79
        * UserInterface/Views/EventListenerBreakpointPopover.js: Added.
80
        (WI.EventListenerBreakpointPopover):
81
        (WI.EventListenerBreakpointPopover.prototype.get result):
82
        (WI.EventListenerBreakpointPopover.prototype.get value):
83
        (WI.EventListenerBreakpointPopover.prototype.show):
84
        (WI.EventListenerBreakpointPopover.prototype._presentOverTargetElement):
85
        * UserInterface/Views/EventListenerBreakpointPopover.css: Added.
86
        (.popover .event-listener-breakpoint-content):
87
        (.popover .event-listener-breakpoint-content > input):
88
89
        * UserInterface/Views/NavigationSidebarPanel.js:
90
        (WI.NavigationSidebarPanel.prototype._isTreeElementWithoutRepresentedObject):
91
1
2018-03-12  Jon Davis  <jond@apple.com>
92
2018-03-12  Jon Davis  <jond@apple.com>
2
93
3
        Web Inspector: Remove redundant tooltips
94
        Web Inspector: Remove redundant tooltips
- a/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp -1 / +1 lines
Lines 367-373 void InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded(bool isDOMEvent, cons a/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp_sec1
367
        return;
367
        return;
368
368
369
    Ref<JSON::Object> eventData = JSON::Object::create();
369
    Ref<JSON::Object> eventData = JSON::Object::create();
370
    eventData->setString(ASCIILiteral("eventName"), fullEventName);
370
    eventData->setString(ASCIILiteral("eventName"), eventName);
371
371
372
    if (synchronous)
372
    if (synchronous)
373
        m_debuggerAgent->breakProgram(Inspector::DebuggerFrontendDispatcher::Reason::EventListener, WTFMove(eventData));
373
        m_debuggerAgent->breakProgram(Inspector::DebuggerFrontendDispatcher::Reason::EventListener, WTFMove(eventData));
- a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js +4 lines
Lines 71-76 localizedStrings["Add"] = "Add"; a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js_sec1
71
localizedStrings["Add %s Rule"] = "Add %s Rule";
71
localizedStrings["Add %s Rule"] = "Add %s Rule";
72
localizedStrings["Add Action"] = "Add Action";
72
localizedStrings["Add Action"] = "Add Action";
73
localizedStrings["Add Breakpoint"] = "Add Breakpoint";
73
localizedStrings["Add Breakpoint"] = "Add Breakpoint";
74
localizedStrings["Add Event Listener Breakpoint"] = "Add Event Listener Breakpoint";
74
localizedStrings["Add New"] = "Add New";
75
localizedStrings["Add New"] = "Add New";
75
localizedStrings["Add New Class"] = "Add New Class";
76
localizedStrings["Add New Class"] = "Add New Class";
76
localizedStrings["Add New Probe Expression"] = "Add New Probe Expression";
77
localizedStrings["Add New Probe Expression"] = "Add New Probe Expression";
Lines 143-148 localizedStrings["Bottom"] = "Bottom"; a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js_sec2
143
localizedStrings["Boundary"] = "Boundary";
144
localizedStrings["Boundary"] = "Boundary";
144
localizedStrings["Box Model"] = "Box Model";
145
localizedStrings["Box Model"] = "Box Model";
145
localizedStrings["Box Shadow"] = "Box Shadow";
146
localizedStrings["Box Shadow"] = "Box Shadow";
147
localizedStrings["Break on listeners for event with name:"] = "Break on listeners for event with name:";
146
localizedStrings["Break on request with URL:"] = "Break on request with URL:";
148
localizedStrings["Break on request with URL:"] = "Break on request with URL:";
147
localizedStrings["Break on…"] = "Break on…";
149
localizedStrings["Break on…"] = "Break on…";
148
localizedStrings["Breakdown"] = "Breakdown";
150
localizedStrings["Breakdown"] = "Breakdown";
Lines 392-397 localizedStrings["Eval Code"] = "Eval Code"; a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js_sec3
392
localizedStrings["Evaluate JavaScript"] = "Evaluate JavaScript";
394
localizedStrings["Evaluate JavaScript"] = "Evaluate JavaScript";
393
localizedStrings["Event"] = "Event";
395
localizedStrings["Event"] = "Event";
394
localizedStrings["Event Dispatched"] = "Event Dispatched";
396
localizedStrings["Event Dispatched"] = "Event Dispatched";
397
localizedStrings["Event Listener Breakpoints"] = "Event Listener Breakpoints";
395
localizedStrings["Event Listeners"] = "Event Listeners";
398
localizedStrings["Event Listeners"] = "Event Listeners";
396
localizedStrings["Events"] = "Events";
399
localizedStrings["Events"] = "Events";
397
localizedStrings["Exception with thrown value: %s"] = "Exception with thrown value: %s";
400
localizedStrings["Exception with thrown value: %s"] = "Exception with thrown value: %s";
Lines 1084-1089 localizedStrings["times before stopping"] = "times before stopping"; a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js_sec4
1084
localizedStrings["toggle"] = "toggle";
1087
localizedStrings["toggle"] = "toggle";
1085
localizedStrings["unsupported version."] = "unsupported version.";
1088
localizedStrings["unsupported version."] = "unsupported version.";
1086
localizedStrings["value"] = "value";
1089
localizedStrings["value"] = "value";
1090
localizedStrings["“%s“ Event Fired"] = "“%s“ Event Fired";
1087
localizedStrings["“%s” Profile Recorded"] = "“%s” Profile Recorded";
1091
localizedStrings["“%s” Profile Recorded"] = "“%s” Profile Recorded";
1088
localizedStrings["“%s” is invalid."] = "“%s” is invalid.";
1092
localizedStrings["“%s” is invalid."] = "“%s” is invalid.";
1089
localizedStrings["“%s” threw an error."] = "“%s” threw an error.";
1093
localizedStrings["“%s” threw an error."] = "“%s” threw an error.";
- a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js +106 lines
Lines 33-38 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec1
33
        this._domBreakpointURLMap = new Map;
33
        this._domBreakpointURLMap = new Map;
34
        this._domBreakpointFrameIdentifierMap = new Map;
34
        this._domBreakpointFrameIdentifierMap = new Map;
35
35
36
        this._eventListenerBreakpointSetting = new WI.Setting("event-listener-breakpoint", []);
37
        this._eventListenerBreakpoints = [];
38
36
        this._xhrBreakpointsSetting = new WI.Setting("xhr-breakpoints", []);
39
        this._xhrBreakpointsSetting = new WI.Setting("xhr-breakpoints", []);
37
        this._xhrBreakpoints = [];
40
        this._xhrBreakpoints = [];
38
        this._allRequestsBreakpointEnabledSetting = new WI.Setting("break-on-all-requests", false);
41
        this._allRequestsBreakpointEnabledSetting = new WI.Setting("break-on-all-requests", false);
Lines 40-45 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec2
40
        this._allRequestsBreakpoint = new WI.XHRBreakpoint(null, null, !this._allRequestsBreakpointEnabledSetting.value);
43
        this._allRequestsBreakpoint = new WI.XHRBreakpoint(null, null, !this._allRequestsBreakpointEnabledSetting.value);
41
44
42
        WI.DOMBreakpoint.addEventListener(WI.DOMBreakpoint.Event.DisabledStateDidChange, this._domBreakpointDisabledStateDidChange, this);
45
        WI.DOMBreakpoint.addEventListener(WI.DOMBreakpoint.Event.DisabledStateDidChange, this._domBreakpointDisabledStateDidChange, this);
46
        WI.EventListenerBreakpoint.addEventListener(WI.EventListenerBreakpoint.Event.DisabledStateDidChange, this._eventListenerBreakpointDisabledStateDidChange, this);
43
        WI.XHRBreakpoint.addEventListener(WI.XHRBreakpoint.Event.DisabledStateDidChange, this._xhrBreakpointDisabledStateDidChange, this);
47
        WI.XHRBreakpoint.addEventListener(WI.XHRBreakpoint.Event.DisabledStateDidChange, this._xhrBreakpointDisabledStateDidChange, this);
44
48
45
        WI.domTreeManager.addEventListener(WI.DOMTreeManager.Event.NodeRemoved, this._nodeRemoved, this);
49
        WI.domTreeManager.addEventListener(WI.DOMTreeManager.Event.NodeRemoved, this._nodeRemoved, this);
Lines 58-63 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec3
58
                this.addDOMBreakpoint(breakpoint);
62
                this.addDOMBreakpoint(breakpoint);
59
            }
63
            }
60
64
65
            for (let cookie of this._eventListenerBreakpointSetting.value) {
66
                let breakpoint = new WI.EventListenerBreakpoint(cookie.eventName, cookie.disabled);
67
                this.addEventListenerBreakpoint(breakpoint);
68
            }
69
61
            for (let cookie of this._xhrBreakpointsSetting.value) {
70
            for (let cookie of this._xhrBreakpointsSetting.value) {
62
                let breakpoint = new WI.XHRBreakpoint(cookie.type, cookie.url, cookie.disabled);
71
                let breakpoint = new WI.XHRBreakpoint(cookie.type, cookie.url, cookie.disabled);
63
                this.addXHRBreakpoint(breakpoint);
72
                this.addXHRBreakpoint(breakpoint);
Lines 102-107 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec4
102
        return resolvedBreakpoints;
111
        return resolvedBreakpoints;
103
    }
112
    }
104
113
114
    get eventListenerBreakpoints() { return this._eventListenerBreakpoints; }
115
105
    get xhrBreakpoints() { return this._xhrBreakpoints; }
116
    get xhrBreakpoints() { return this._xhrBreakpoints; }
106
117
107
    isBreakpointRemovable(breakpoint)
118
    isBreakpointRemovable(breakpoint)
Lines 184-189 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec5
184
        this._saveDOMBreakpoints();
195
        this._saveDOMBreakpoints();
185
    }
196
    }
186
197
198
    eventListenerBreakpointForEventName(eventName)
199
    {
200
        return this._eventListenerBreakpoints.find((breakpoint) => breakpoint.eventName === eventName) || null;
201
    }
202
203
    addEventListenerBreakpoint(breakpoint)
204
    {
205
        console.assert(breakpoint instanceof WI.EventListenerBreakpoint);
206
        if (!breakpoint)
207
            return;
208
209
        if (this._eventListenerBreakpoints.includes(breakpoint))
210
            return;
211
212
        if (this._eventListenerBreakpoints.some((item) => item.eventName === breakpoint.eventName))
213
            return;
214
215
        this._eventListenerBreakpoints.push(breakpoint);
216
217
        this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventListenerBreakpointAdded, {breakpoint});
218
219
        this._resolveEventListenerBreakpoint(breakpoint);
220
        this._saveEventListenerBreakpoints();
221
    }
222
223
    removeEventListenerBreakpoint(breakpoint)
224
    {
225
        console.assert(breakpoint instanceof WI.EventListenerBreakpoint);
226
        if (!breakpoint)
227
            return;
228
229
        if (!this._eventListenerBreakpoints.includes(breakpoint))
230
            return;
231
232
        this._eventListenerBreakpoints.remove(breakpoint);
233
234
        this._saveEventListenerBreakpoints();
235
        this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventListenerBreakpointRemoved, {breakpoint});
236
237
        if (breakpoint.disabled)
238
            return;
239
240
        DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName, (error) => {
241
            if (error)
242
                console.error(error);
243
        });
244
    }
245
187
    xhrBreakpointForURL(url)
246
    xhrBreakpointForURL(url)
188
    {
247
    {
189
        return this._xhrBreakpoints.find((breakpoint) => breakpoint.url === url) || null;
248
        return this._xhrBreakpoints.find((breakpoint) => breakpoint.url === url) || null;
Lines 300-305 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec6
300
            }
359
            }
301
        }
360
        }
302
361
362
        for (let breakpoint of this._eventListenerBreakpoints)
363
            this._resolveEventListenerBreakpoint(breakpoint);
364
303
        for (let breakpoint of this._xhrBreakpoints)
365
        for (let breakpoint of this._xhrBreakpoints)
304
            this._resolveXHRBreakpoint(breakpoint);
366
            this._resolveXHRBreakpoint(breakpoint);
305
    }
367
    }
Lines 347-352 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec7
347
            DOMDebuggerAgent.setDOMBreakpoint(nodeIdentifier, breakpoint.type, breakpointUpdated);
409
            DOMDebuggerAgent.setDOMBreakpoint(nodeIdentifier, breakpoint.type, breakpointUpdated);
348
    }
410
    }
349
411
412
    _updateEventListenerBreakpoint(breakpoint, callback)
413
    {
414
        function breakpointUpdated(error)
415
        {
416
            if (error)
417
                console.error(error);
418
419
            if (callback)
420
                callback(error);
421
        }
422
423
        if (breakpoint.disabled)
424
            DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName, breakpointUpdated);
425
        else
426
            DOMDebuggerAgent.setEventListenerBreakpoint(breakpoint.eventName, breakpointUpdated);
427
    }
428
350
    _updateXHRBreakpoint(breakpoint, callback)
429
    _updateXHRBreakpoint(breakpoint, callback)
351
    {
430
    {
352
        function breakpointUpdated(error)
431
        function breakpointUpdated(error)
Lines 366-371 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec8
366
        }
445
        }
367
    }
446
    }
368
447
448
    _resolveEventListenerBreakpoint(breakpoint)
449
    {
450
        if (breakpoint.disabled)
451
            return;
452
453
        this._updateEventListenerBreakpoint(breakpoint, () => {
454
            breakpoint.dispatchEventToListeners(WI.EventListenerBreakpoint.Event.ResolvedStateDidChange);
455
        });
456
    }
457
369
    _resolveXHRBreakpoint(breakpoint)
458
    _resolveXHRBreakpoint(breakpoint)
370
    {
459
    {
371
        if (breakpoint.disabled)
460
        if (breakpoint.disabled)
Lines 388-393 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec9
388
        this._domBreakpointsSetting.value = breakpointsToSave.map((breakpoint) => breakpoint.serializableInfo);
477
        this._domBreakpointsSetting.value = breakpointsToSave.map((breakpoint) => breakpoint.serializableInfo);
389
    }
478
    }
390
479
480
    _saveEventListenerBreakpoints()
481
    {
482
        if (this._restoringBreakpoints)
483
            return;
484
485
        this._eventListenerBreakpointSetting.value = this._eventListenerBreakpoints.map((breakpoint) => breakpoint.serializableInfo);
486
    }
487
391
    _saveXHRBreakpoints()
488
    _saveXHRBreakpoints()
392
    {
489
    {
393
        if (this._restoringBreakpoints)
490
        if (this._restoringBreakpoints)
Lines 403-408 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec10
403
        this._saveDOMBreakpoints();
500
        this._saveDOMBreakpoints();
404
    }
501
    }
405
502
503
    _eventListenerBreakpointDisabledStateDidChange(event)
504
    {
505
        let breakpoint = event.target;
506
        this._updateEventListenerBreakpoint(breakpoint);
507
        this._saveEventListenerBreakpoints();
508
    }
509
406
    _xhrBreakpointDisabledStateDidChange(event)
510
    _xhrBreakpointDisabledStateDidChange(event)
407
    {
511
    {
408
        let breakpoint = event.target;
512
        let breakpoint = event.target;
Lines 488-493 WI.DOMDebuggerManager = class DOMDebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js_sec11
488
WI.DOMDebuggerManager.Event = {
592
WI.DOMDebuggerManager.Event = {
489
    DOMBreakpointAdded: "dom-debugger-manager-dom-breakpoint-added",
593
    DOMBreakpointAdded: "dom-debugger-manager-dom-breakpoint-added",
490
    DOMBreakpointRemoved: "dom-debugger-manager-dom-breakpoint-removed",
594
    DOMBreakpointRemoved: "dom-debugger-manager-dom-breakpoint-removed",
595
    EventListenerBreakpointAdded: "dom-debugger-manager-event-listener-breakpoint-added",
596
    EventListenerBreakpointRemoved: "dom-debugger-manager-event-listener-breakpoint-removed",
491
    XHRBreakpointAdded: "dom-debugger-manager-xhr-breakpoint-added",
597
    XHRBreakpointAdded: "dom-debugger-manager-xhr-breakpoint-added",
492
    XHRBreakpointRemoved: "dom-debugger-manager-xhr-breakpoint-removed",
598
    XHRBreakpointRemoved: "dom-debugger-manager-xhr-breakpoint-removed",
493
};
599
};
- a/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js +3 lines
Lines 820-825 WI.DebuggerManager = class DebuggerManager extends WI.Object a/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js_sec1
820
            return WI.DebuggerManager.PauseReason.DOM;
820
            return WI.DebuggerManager.PauseReason.DOM;
821
        case DebuggerAgent.PausedReason.DebuggerStatement:
821
        case DebuggerAgent.PausedReason.DebuggerStatement:
822
            return WI.DebuggerManager.PauseReason.DebuggerStatement;
822
            return WI.DebuggerManager.PauseReason.DebuggerStatement;
823
        case DebuggerAgent.PausedReason.EventListener:
824
            return WI.DebuggerManager.PauseReason.EventListener;
823
        case DebuggerAgent.PausedReason.Exception:
825
        case DebuggerAgent.PausedReason.Exception:
824
            return WI.DebuggerManager.PauseReason.Exception;
826
            return WI.DebuggerManager.PauseReason.Exception;
825
        case DebuggerAgent.PausedReason.PauseOnNextStatement:
827
        case DebuggerAgent.PausedReason.PauseOnNextStatement:
Lines 1228-1233 WI.DebuggerManager.PauseReason = { a/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js_sec2
1228
    CSPViolation: "CSP-violation",
1230
    CSPViolation: "CSP-violation",
1229
    DebuggerStatement: "debugger-statement",
1231
    DebuggerStatement: "debugger-statement",
1230
    DOM: "DOM",
1232
    DOM: "DOM",
1233
    EventListener: "EventListener",
1231
    Exception: "exception",
1234
    Exception: "exception",
1232
    PauseOnNextStatement: "pause-on-next-statement",
1235
    PauseOnNextStatement: "pause-on-next-statement",
1233
    XHR: "xhr",
1236
    XHR: "xhr",
- a/Source/WebInspectorUI/UserInterface/Controllers/EventListenerBreakpointTreeController.js +78 lines
Line 0 a/Source/WebInspectorUI/UserInterface/Controllers/EventListenerBreakpointTreeController.js_sec1
1
/*
2
 * Copyright (C) 2018 Devin Rousso <webkit@devinrousso.com>. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23
 * THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
WI.EventListenerBreakpointTreeController = class EventListenerBreakpointTreeController extends WI.Object
27
{
28
    constructor(treeOutline)
29
    {
30
        super();
31
32
        this._treeOutline = treeOutline;
33
34
        WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.EventListenerBreakpointAdded, this._eventListenerBreakpointAdded, this);
35
        WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.EventListenerBreakpointRemoved, this._eventListenerBreakpointRemoved, this);
36
37
        for (let breakpoint of WI.domDebuggerManager.eventListenerBreakpoints)
38
            this._addTreeElement(breakpoint);
39
    }
40
41
    // Public
42
43
    revealAndSelect(breakpoint)
44
    {
45
        let treeElement = this._treeOutline.findTreeElement(breakpoint);
46
        if (!treeElement)
47
            return;
48
49
        treeElement.revealAndSelect();
50
    }
51
52
    // Private
53
54
    _eventListenerBreakpointAdded(event)
55
    {
56
        this._addTreeElement(event.data.breakpoint);
57
    }
58
59
    _eventListenerBreakpointRemoved(event)
60
    {
61
        let breakpoint = event.data.breakpoint;
62
        let treeElement = this._treeOutline.findTreeElement(breakpoint);
63
        if (!treeElement)
64
            return;
65
66
        this._treeOutline.removeChild(treeElement);
67
    }
68
69
    _addTreeElement(breakpoint)
70
    {
71
        let treeElement = this._treeOutline.findTreeElement(breakpoint);
72
        console.assert(!treeElement);
73
        if (treeElement)
74
            return;
75
76
        this._treeOutline.appendChild(new WI.EventListenerBreakpointTreeElement(breakpoint));
77
    }
78
};
- a/Source/WebInspectorUI/UserInterface/Main.html +5 lines
Lines 83-88 a/Source/WebInspectorUI/UserInterface/Main.html_sec1
83
    <link rel="stylesheet" href="Views/DetailsSection.css">
83
    <link rel="stylesheet" href="Views/DetailsSection.css">
84
    <link rel="stylesheet" href="Views/DividerNavigationItem.css">
84
    <link rel="stylesheet" href="Views/DividerNavigationItem.css">
85
    <link rel="stylesheet" href="Views/Editing.css">
85
    <link rel="stylesheet" href="Views/Editing.css">
86
    <link rel="stylesheet" href="Views/EventListenerBreakpointPopover.css">
86
    <link rel="stylesheet" href="Views/EventListenerSectionGroup.css">
87
    <link rel="stylesheet" href="Views/EventListenerSectionGroup.css">
87
    <link rel="stylesheet" href="Views/ErrorObjectView.css">
88
    <link rel="stylesheet" href="Views/ErrorObjectView.css">
88
    <link rel="stylesheet" href="Views/FilterBar.css">
89
    <link rel="stylesheet" href="Views/FilterBar.css">
Lines 372-377 a/Source/WebInspectorUI/UserInterface/Main.html_sec2
372
    <script src="Models/DebuggerDashboard.js"></script>
373
    <script src="Models/DebuggerDashboard.js"></script>
373
    <script src="Models/DebuggerData.js"></script>
374
    <script src="Models/DebuggerData.js"></script>
374
    <script src="Models/DefaultDashboard.js"></script>
375
    <script src="Models/DefaultDashboard.js"></script>
376
    <script src="Models/EventListenerBreakpoint.js"></script>
375
    <script src="Models/ExecutionContext.js"></script>
377
    <script src="Models/ExecutionContext.js"></script>
376
    <script src="Models/ExecutionContextList.js"></script>
378
    <script src="Models/ExecutionContextList.js"></script>
377
    <script src="Models/FPSInstrument.js"></script>
379
    <script src="Models/FPSInstrument.js"></script>
Lines 613-618 a/Source/WebInspectorUI/UserInterface/Main.html_sec3
613
    <script src="Views/EditableDataGridNode.js"></script>
615
    <script src="Views/EditableDataGridNode.js"></script>
614
    <script src="Views/EditingSupport.js"></script>
616
    <script src="Views/EditingSupport.js"></script>
615
    <script src="Views/ErrorObjectView.js"></script>
617
    <script src="Views/ErrorObjectView.js"></script>
618
    <script src="Views/EventListenerBreakpointPopover.js"></script>
619
    <script src="Views/EventListenerBreakpointTreeElement.js"></script>
616
    <script src="Views/EventListenerSectionGroup.js"></script>
620
    <script src="Views/EventListenerSectionGroup.js"></script>
617
    <script src="Views/FilterBar.js"></script>
621
    <script src="Views/FilterBar.js"></script>
618
    <script src="Views/FilterBarButton.js"></script>
622
    <script src="Views/FilterBarButton.js"></script>
Lines 833-838 a/Source/WebInspectorUI/UserInterface/Main.html_sec4
833
    <script src="Controllers/DebuggerManager.js"></script>
837
    <script src="Controllers/DebuggerManager.js"></script>
834
    <script src="Controllers/DOMBreakpointTreeController.js"></script>
838
    <script src="Controllers/DOMBreakpointTreeController.js"></script>
835
    <script src="Controllers/DragToAdjustController.js"></script>
839
    <script src="Controllers/DragToAdjustController.js"></script>
840
    <script src="Controllers/EventListenerBreakpointTreeController.js"></script>
836
    <script src="Controllers/Formatter.js"></script>
841
    <script src="Controllers/Formatter.js"></script>
837
    <script src="Controllers/FormatterSourceMap.js"></script>
842
    <script src="Controllers/FormatterSourceMap.js"></script>
838
    <script src="Controllers/FrameResourceManager.js"></script>
843
    <script src="Controllers/FrameResourceManager.js"></script>
- a/Source/WebInspectorUI/UserInterface/Models/EventListenerBreakpoint.js +77 lines
Line 0 a/Source/WebInspectorUI/UserInterface/Models/EventListenerBreakpoint.js_sec1
1
/*
2
 * Copyright (C) 2018 Devin Rousso <webkit@devinrousso.com>. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23
 * THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
WI.EventListenerBreakpoint = class EventListenerBreakpoint extends WI.Object
27
{
28
    constructor(eventName, disabled)
29
    {
30
        super();
31
32
        this._eventName = eventName;
33
        this._disabled = disabled || false;
34
    }
35
36
    // Public
37
38
    get eventName() { return this._eventName; }
39
40
    get disabled()
41
    {
42
        return this._disabled;
43
    }
44
45
    set disabled(disabled)
46
    {
47
        if (this._disabled === disabled)
48
            return;
49
50
        this._disabled = disabled;
51
52
        this.dispatchEventToListeners(WI.EventListenerBreakpoint.Event.DisabledStateDidChange);
53
    }
54
55
    get serializableInfo()
56
    {
57
        let info = {
58
            eventName: this._eventName,
59
        };
60
        if (this._disabled)
61
            info.disabled = true;
62
63
        return info;
64
    }
65
66
    saveIdentityToCookie(cookie)
67
    {
68
        cookie[WI.EventListenerBreakpoint.EventNameCookieKey] = this._eventName;
69
    }
70
};
71
72
WI.EventListenerBreakpoint.EventNameCookieKey = "event-listener-breakpoint-event-name";
73
74
WI.EventListenerBreakpoint.Event = {
75
    DisabledStateDidChange: "event-listener-breakpoint-disabled-state-did-change",
76
    ResolvedStateDidChange: "event-listener-breakpoint-resolved-state-did-change",
77
};
- a/Source/WebInspectorUI/UserInterface/Test.html +1 lines
Lines 132-137 a/Source/WebInspectorUI/UserInterface/Test.html_sec1
132
    <script src="Models/DOMStorageObject.js"></script>
132
    <script src="Models/DOMStorageObject.js"></script>
133
    <script src="Models/DOMTree.js"></script>
133
    <script src="Models/DOMTree.js"></script>
134
    <script src="Models/DebuggerData.js"></script>
134
    <script src="Models/DebuggerData.js"></script>
135
    <script src="Models/EventListenerBreakpoint.js"></script>
135
    <script src="Models/ExecutionContext.js"></script>
136
    <script src="Models/ExecutionContext.js"></script>
136
    <script src="Models/ExecutionContextList.js"></script>
137
    <script src="Models/ExecutionContextList.js"></script>
137
    <script src="Models/FPSInstrument.js"></script>
138
    <script src="Models/FPSInstrument.js"></script>
- a/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js -8 / +78 lines
Lines 176-197 WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba a/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js_sec1
176
            this._domBreakpointsSection = new WI.DetailsSection("dom-breakpoints", WI.UIString("DOM Breakpoints"), [domBreakpointsGroup], null, defaultCollapsed);
176
            this._domBreakpointsSection = new WI.DetailsSection("dom-breakpoints", WI.UIString("DOM Breakpoints"), [domBreakpointsGroup], null, defaultCollapsed);
177
            this.contentView.element.appendChild(this._domBreakpointsSection.element);
177
            this.contentView.element.appendChild(this._domBreakpointsSection.element);
178
178
179
            this._eventListenerBreakpointsContentTreeOutline = this.createContentTreeOutline(true);
180
            this._eventListenerBreakpointsContentTreeOutline.addEventListener(WI.TreeOutline.Event.ElementAdded, this._eventListenerBreakpointAddedOrRemoved, this);
181
            this._eventListenerBreakpointsContentTreeOutline.addEventListener(WI.TreeOutline.Event.ElementRemoved, this._eventListenerBreakpointAddedOrRemoved, this);
182
183
            this._eventListenerBreakpointsRow = new WI.DetailsSectionRow(WI.UIString("No Breakpoints"));
184
            this._eventListenerBreakpointsRow.element.appendChild(this._eventListenerBreakpointsContentTreeOutline.element);
185
            this._eventListenerBreakpointsRow.showEmptyMessage();
186
187
            let eventListenerBreakpointNavigationBar = new WI.NavigationBar;
188
            let eventListenerBreakpointNavigationBarWrapper = document.createElement("div");
189
            eventListenerBreakpointNavigationBarWrapper.appendChild(eventListenerBreakpointNavigationBar.element);
190
191
            let addEventListenerBreakpointButton = new WI.ButtonNavigationItem("add-event-listener-breakpoint", WI.UIString("Add Event Listener Breakpoint"), "Images/Plus13.svg", 13, 13);
192
            addEventListenerBreakpointButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._addEventListenerBreakpointButtonClicked, this);
193
            eventListenerBreakpointNavigationBar.addNavigationItem(addEventListenerBreakpointButton);
194
195
            let eventListenerBreakpointsGroup = new WI.DetailsSectionGroup([this._eventListenerBreakpointsRow]);
196
            this._eventListenerBreakpointsSection = new WI.DetailsSection("event-listener-breakpoints", WI.UIString("Event Listener Breakpoints"), [eventListenerBreakpointsGroup], eventListenerBreakpointNavigationBarWrapper, defaultCollapsed);
197
            this.contentView.element.appendChild(this._eventListenerBreakpointsSection.element);
198
199
            this._eventListenerBreakpointTreeController = new WI.EventListenerBreakpointTreeController(this._eventListenerBreakpointsContentTreeOutline);
200
179
            this._xhrBreakpointsContentTreeOutline = this.createContentTreeOutline(true);
201
            this._xhrBreakpointsContentTreeOutline = this.createContentTreeOutline(true);
180
            this._xhrBreakpointTreeController = new WI.XHRBreakpointTreeController(this._xhrBreakpointsContentTreeOutline);
202
            this._xhrBreakpointTreeController = new WI.XHRBreakpointTreeController(this._xhrBreakpointsContentTreeOutline);
181
203
182
            this._xhrBreakpointsRow = new WI.DetailsSectionRow;
204
            this._xhrBreakpointsRow = new WI.DetailsSectionRow;
183
            this._xhrBreakpointsRow.element.appendChild(this._xhrBreakpointsContentTreeOutline.element);
205
            this._xhrBreakpointsRow.element.appendChild(this._xhrBreakpointsContentTreeOutline.element);
184
206
185
            let navigationBar = new WI.NavigationBar;
207
            let xhrBreakpointNavigationBar = new WI.NavigationBar;
186
            let navigationBarWrapper = document.createElement("div");
208
            let xhrBreakpointNavigationBarWrapper = document.createElement("div");
187
            navigationBarWrapper.appendChild(navigationBar.element);
209
            xhrBreakpointNavigationBarWrapper.appendChild(xhrBreakpointNavigationBar.element);
188
210
189
            let addXHRBreakpointButton = new WI.ButtonNavigationItem("add-xhr-breakpoint", WI.UIString("Add XHR Breakpoint"), "Images/Plus13.svg", 13, 13);
211
            let addXHRBreakpointButton = new WI.ButtonNavigationItem("add-xhr-breakpoint", WI.UIString("Add XHR Breakpoint"), "Images/Plus13.svg", 13, 13);
190
            addXHRBreakpointButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._addXHRBreakpointButtonClicked, this);
212
            addXHRBreakpointButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._addXHRBreakpointButtonClicked, this);
191
            navigationBar.addNavigationItem(addXHRBreakpointButton);
213
            xhrBreakpointNavigationBar.addNavigationItem(addXHRBreakpointButton);
192
214
193
            let xhrBreakpointsGroup = new WI.DetailsSectionGroup([this._xhrBreakpointsRow]);
215
            let xhrBreakpointsGroup = new WI.DetailsSectionGroup([this._xhrBreakpointsRow]);
194
            let xhrBreakpointsSection = new WI.DetailsSection("xhr-breakpoints", WI.UIString("XHR Breakpoints"), [xhrBreakpointsGroup], navigationBarWrapper, defaultCollapsed);
216
            let xhrBreakpointsSection = new WI.DetailsSection("xhr-breakpoints", WI.UIString("XHR Breakpoints"), [xhrBreakpointsGroup], xhrBreakpointNavigationBarWrapper, defaultCollapsed);
195
            this.contentView.element.appendChild(xhrBreakpointsSection.element);
217
            this.contentView.element.appendChild(xhrBreakpointsSection.element);
196
        }
218
        }
197
219
Lines 1032-1037 WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba a/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js_sec2
1032
            }
1054
            }
1033
            break;
1055
            break;
1034
1056
1057
        case WI.DebuggerManager.PauseReason.EventListener:
1058
            console.assert(pauseData, "Expected data with an event listener, but found none.");
1059
            if (pauseData) {
1060
                let eventListenerBreakpoint = WI.domDebuggerManager.eventListenerBreakpointForEventName(pauseData.eventName);
1061
                console.assert(eventListenerBreakpoint, "Expected Event Listener breakpoint for event name.", pauseData.eventName);
1062
1063
                this._pauseReasonTreeOutline = this.createContentTreeOutline(true);
1064
1065
                let eventListenerBreakpointTreeElement = new WI.EventListenerBreakpointTreeElement(eventListenerBreakpoint, WI.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName, WI.UIString("“%s“ Event Fired").format(pauseData.eventName));
1066
                this._pauseReasonTreeOutline.appendChild(eventListenerBreakpointTreeElement);
1067
1068
                let eventListenerBreakpointRow = new WI.DetailsSectionRow;
1069
                eventListenerBreakpointRow.element.appendChild(this._pauseReasonTreeOutline.element);
1070
1071
                this._pauseReasonGroup.rows = [eventListenerBreakpointRow];
1072
            }
1073
            return true;
1074
1035
        case WI.DebuggerManager.PauseReason.Exception:
1075
        case WI.DebuggerManager.PauseReason.Exception:
1036
            console.assert(pauseData, "Expected data with an exception, but found none.");
1076
            console.assert(pauseData, "Expected data with an exception, but found none.");
1037
            if (pauseData) {
1077
            if (pauseData) {
Lines 1175-1180 WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba a/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js_sec3
1175
        this._domBreakpointsSection.collapsed = false;
1215
        this._domBreakpointsSection.collapsed = false;
1176
    }
1216
    }
1177
1217
1218
    _eventListenerBreakpointAddedOrRemoved(event)
1219
    {
1220
        if (!this._eventListenerBreakpointsContentTreeOutline.children.length) {
1221
            this._eventListenerBreakpointsRow.showEmptyMessage();
1222
            return;
1223
        }
1224
1225
        if (this._eventListenerBreakpointsContentTreeOutline.element.parent)
1226
            return;
1227
1228
        this._eventListenerBreakpointsRow.hideEmptyMessage();
1229
        this._eventListenerBreakpointsRow.element.append(this._eventListenerBreakpointsContentTreeOutline.element);
1230
1231
        this._eventListenerBreakpointsSection.collapsed = false;
1232
    }
1233
1234
    _addEventListenerBreakpointButtonClicked(event)
1235
    {
1236
        let popover = new WI.EventListenerBreakpointPopover(this);
1237
        popover.show(event.target.element, [WI.RectEdge.MAX_Y, WI.RectEdge.MIN_Y, WI.RectEdge.MAX_X]);
1238
    }
1239
1178
    _addXHRBreakpointButtonClicked(event)
1240
    _addXHRBreakpointButtonClicked(event)
1179
    {
1241
    {
1180
        let popover = new WI.XHRBreakpointPopover(this);
1242
        let popover = new WI.XHRBreakpointPopover(this);
Lines 1188-1198 WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba a/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js_sec4
1188
        if (popover.result !== WI.InputPopover.Result.Committed)
1250
        if (popover.result !== WI.InputPopover.Result.Committed)
1189
            return;
1251
            return;
1190
1252
1191
        let url = popover.value;
1253
        if (popover instanceof WI.EventListenerBreakpointPopover) {
1192
        if (!url)
1254
            let eventName = popover.value;
1255
            if (eventName)
1256
                WI.domDebuggerManager.addEventListenerBreakpoint(new WI.EventListenerBreakpoint(eventName));
1193
            return;
1257
            return;
1258
        }
1194
1259
1195
        WI.domDebuggerManager.addXHRBreakpoint(new WI.XHRBreakpoint(popover.type, url));
1260
        if (popover instanceof WI.XHRBreakpointPopover) {
1261
            let url = popover.value;
1262
            if (url)
1263
                WI.domDebuggerManager.addXHRBreakpoint(new WI.XHRBreakpoint(popover.type, url));
1264
            return;
1265
        }
1196
    }
1266
    }
1197
};
1267
};
1198
1268
- a/Source/WebInspectorUI/UserInterface/Views/EventListenerBreakpointPopover.css +34 lines
Line 0 a/Source/WebInspectorUI/UserInterface/Views/EventListenerBreakpointPopover.css_sec1
1
/*
2
 * Copyright (C) 2018 Devin Rousso <webkit@devinrousso.com>. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23
 * THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
.popover .event-listener-breakpoint-content {
27
    padding: 5px;
28
    margin: 2px;
29
}
30
31
.popover .event-listener-breakpoint-content > input {
32
    width: 100%;
33
    outline: none;
34
}
- a/Source/WebInspectorUI/UserInterface/Views/EventListenerBreakpointPopover.js +87 lines
Line 0 a/Source/WebInspectorUI/UserInterface/Views/EventListenerBreakpointPopover.js_sec1
1
/*
2
 * Copyright (C) 2018 Devin Rousso <webkit@devinrousso.com>. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23
 * THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
WI.EventListenerBreakpointPopover = class EventListenerBreakpointPopover extends WI.Popover
27
{
28
    constructor(delegate)
29
    {
30
        super(delegate);
31
32
        this._result = WI.InputPopover.Result.None;
33
        this._value = null;
34
35
        this._codeMirror = null;
36
        this._targetElement = null;
37
        this._preferredEdges = null;
38
39
        this.windowResizeHandler = this._presentOverTargetElement.bind(this);
40
    }
41
42
    // Public
43
44
    get result() { return this._result; }
45
    get value() { return this._value; }
46
47
    show(targetElement, preferredEdges)
48
    {
49
        this._targetElement = targetElement;
50
        this._preferredEdges = preferredEdges;
51
52
        let contentElement = document.createElement("div");
53
        contentElement.classList.add("event-listener-breakpoint-content");
54
55
        let label = contentElement.appendChild(document.createElement("div"));
56
        label.classList.add("label");
57
        label.textContent = WI.UIString("Break on listeners for event with name:");
58
59
        this._inputElement = contentElement.appendChild(document.createElement("input"));
60
        this._inputElement.addEventListener("keydown", (event) => {
61
            if (!isEnterKey(event))
62
                return;
63
64
            this._result = WI.InputPopover.Result.Committed;
65
            this._value = event.target.value.trim();
66
67
            this.dismiss();
68
        });
69
70
        this.content = contentElement;
71
72
        this._presentOverTargetElement();
73
    }
74
75
    // Private
76
77
    _presentOverTargetElement()
78
    {
79
        if (!this._targetElement)
80
            return;
81
82
        let targetFrame = WI.Rect.rectFromClientRect(this._targetElement.getBoundingClientRect());
83
        this.present(targetFrame, this._preferredEdges);
84
85
        this._inputElement.select();
86
    }
87
};
- a/Source/WebInspectorUI/UserInterface/Views/EventListenerBreakpointTreeElement.js +138 lines
Line 0 a/Source/WebInspectorUI/UserInterface/Views/EventListenerBreakpointTreeElement.js_sec1
1
/*
2
 * Copyright (C) 2018 Devin Rousso <webkit@devinrousso.com>. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23
 * THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
WI.EventListenerBreakpointTreeElement = class EventListenerBreakpointTreeElement extends WI.GeneralTreeElement
27
{
28
    constructor(breakpoint, className, title)
29
    {
30
        console.assert(breakpoint instanceof WI.EventListenerBreakpoint);
31
32
        if (!className)
33
            className = WI.BreakpointTreeElement.GenericLineIconStyleClassName;
34
35
        if (!title)
36
            title = breakpoint.eventName;
37
38
        const subtitle = null;
39
        super(["breakpoint", className], title, subtitle, breakpoint);
40
41
        this._statusImageElement = document.createElement("img");
42
        this._statusImageElement.classList.add("status-image", "resolved");
43
        this.status = this._statusImageElement;
44
45
        breakpoint.addEventListener(WI.EventListenerBreakpoint.Event.DisabledStateDidChange, this._updateStatus, this);
46
47
        this._updateStatus();
48
    }
49
50
    // Protected
51
52
    onattach()
53
    {
54
        super.onattach();
55
56
        this._boundStatusImageElementClicked = this._statusImageElementClicked.bind(this);
57
        this._boundStatusImageElementFocused = this._statusImageElementFocused.bind(this);
58
        this._boundStatusImageElementMouseDown = this._statusImageElementMouseDown.bind(this);
59
60
        this._statusImageElement.addEventListener("click", this._boundStatusImageElementClicked);
61
        this._statusImageElement.addEventListener("focus", this._boundStatusImageElementFocused);
62
        this._statusImageElement.addEventListener("mousedown", this._boundStatusImageElementMouseDown);
63
    }
64
65
    ondetach()
66
    {
67
        super.ondetach();
68
69
        this._statusImageElement.removeEventListener("click", this._boundStatusImageElementClicked);
70
        this._statusImageElement.removeEventListener("focus", this._boundStatusImageElementFocused);
71
        this._statusImageElement.removeEventListener("mousedown", this._boundStatusImageElementMouseDown);
72
73
        this._boundStatusImageElementClicked = null;
74
        this._boundStatusImageElementFocused = null;
75
        this._boundStatusImageElementMouseDown = null;
76
    }
77
78
    ondelete()
79
    {
80
        WI.domDebuggerManager.removeEventListenerBreakpoint(this.representedObject);
81
        return true;
82
    }
83
84
    onenter()
85
    {
86
        this._toggleBreakpoint();
87
        return true;
88
    }
89
90
    onspace()
91
    {
92
        this._toggleBreakpoint();
93
        return true;
94
    }
95
96
    populateContextMenu(contextMenu, event)
97
    {
98
        let breakpoint = this.representedObject;
99
        let label = breakpoint.disabled ? WI.UIString("Enable Breakpoint") : WI.UIString("Disable Breakpoint");
100
        contextMenu.appendItem(label, this._toggleBreakpoint.bind(this));
101
102
        if (WI.domDebuggerManager.isBreakpointRemovable(breakpoint)) {
103
            contextMenu.appendSeparator();
104
            contextMenu.appendItem(WI.UIString("Delete Breakpoint"), () => {
105
                WI.domDebuggerManager.removeEventListenerBreakpoint(breakpoint);
106
            });
107
        }
108
    }
109
110
    // Private
111
112
    _statusImageElementClicked(event)
113
    {
114
        this._toggleBreakpoint();
115
    }
116
117
    _statusImageElementFocused(event)
118
    {
119
        // Prevent tree outline focus.
120
        event.stopPropagation();
121
    }
122
123
    _statusImageElementMouseDown(event)
124
    {
125
        // Prevent tree element selection.
126
        event.stopPropagation();
127
    }
128
129
    _toggleBreakpoint()
130
    {
131
        this.representedObject.disabled = !this.representedObject.disabled;
132
    }
133
134
    _updateStatus()
135
    {
136
        this._statusImageElement.classList.toggle("disabled", this.representedObject.disabled);
137
    }
138
};
- a/Source/WebInspectorUI/UserInterface/Views/NavigationSidebarPanel.js +1 lines
Lines 640-645 WI.NavigationSidebarPanel = class NavigationSidebarPanel extends WI.SidebarPanel a/Source/WebInspectorUI/UserInterface/Views/NavigationSidebarPanel.js_sec1
640
            || treeElement instanceof WI.ThreadTreeElement
640
            || treeElement instanceof WI.ThreadTreeElement
641
            || treeElement instanceof WI.IdleTreeElement
641
            || treeElement instanceof WI.IdleTreeElement
642
            || treeElement instanceof WI.DOMBreakpointTreeElement
642
            || treeElement instanceof WI.DOMBreakpointTreeElement
643
            || treeElement instanceof WI.EventListenerBreakpointTreeElement
643
            || treeElement instanceof WI.XHRBreakpointTreeElement
644
            || treeElement instanceof WI.XHRBreakpointTreeElement
644
            || treeElement instanceof WI.CSSStyleSheetTreeElement
645
            || treeElement instanceof WI.CSSStyleSheetTreeElement
645
            || typeof treeElement.representedObject === "string"
646
            || typeof treeElement.representedObject === "string"
- a/LayoutTests/ChangeLog +10 lines
Lines 1-3 a/LayoutTests/ChangeLog_sec1
1
2018-03-13  Devin Rousso  <webkit@devinrousso.com>
2
3
        Web Inspector: support breakpoints for arbitrary event names
4
        https://bugs.webkit.org/show_bug.cgi?id=183118
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        * inspector/dom-debugger/event-listener-breakpoints-expected.txt: Added.
9
        * inspector/dom-debugger/event-listener-breakpoints.html: Added.
10
1
2018-03-13  Youenn Fablet  <youenn@apple.com>
11
2018-03-13  Youenn Fablet  <youenn@apple.com>
2
12
3
        Layout Test imported/w3c/web-platform-tests/service-workers/service-worker/register-closed-window.https.html is flaky
13
        Layout Test imported/w3c/web-platform-tests/service-workers/service-worker/register-closed-window.https.html is flaky
- a/LayoutTests/inspector/dom-debugger/event-listener-breakpoints-expected.txt +36 lines
Line 0 a/LayoutTests/inspector/dom-debugger/event-listener-breakpoints-expected.txt_sec1
1
Tests for Event Listener breakpoints.
2
3
4
== Running test suite: DOMDebugger.EventListener
5
-- Running test case: DOMDebugger.EventListener.AddBreakpoint
6
Adding Breakpoint...
7
Clicking body...
8
PASS: Should pause before event handler is run.
9
CALL STACK:
10
0: [F] handleBodyClick
11
1: [F] clickBody
12
2: [P] Global Code
13
-- Running test teardown.
14
15
-- Running test case: DOMDebugger.EventListener.AddDisabledBreakpoint
16
Adding Breakpoint...
17
Disabling Breakpoint...
18
Clicking body...
19
PASS: Should not pause for disabled breakpoint.
20
-- Running test teardown.
21
22
-- Running test case: DOMDebugger.EventListener.RemoveBreakpoint
23
Adding Breakpoint...
24
Removing Breakpoint...
25
Clicking body...
26
PASS: Should not pause for removed breakpoint.
27
-- Running test teardown.
28
29
-- Running test case: DOMDebugger.EventListener.RemoveDisabledBreakpoint
30
Adding Breakpoint...
31
Disabling Breakpoint...
32
Removing Breakpoint...
33
Clicking body...
34
PASS: Should not pause for removed disabled breakpoint.
35
-- Running test teardown.
36
- a/LayoutTests/inspector/dom-debugger/event-listener-breakpoints.html +189 lines
Line 0 a/LayoutTests/inspector/dom-debugger/event-listener-breakpoints.html_sec1
1
<!doctype html>
2
<html>
3
<head>
4
<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
5
<script src="../debugger/resources/log-active-stack-trace.js"></script>
6
<script>
7
function handleBodyClick(event) {
8
    TestPage.dispatchEventToFrontend("TestPageBodyClick");
9
}
10
11
function clickBody() {
12
    document.body.click();
13
}
14
15
function test() {
16
    let suite = InspectorTest.createAsyncSuite("DOMDebugger.EventListener");
17
18
    function teardown(resolve, reject) {
19
        let breakpoints = WI.domDebuggerManager.eventListenerBreakpoints;
20
        for (let breakpoint of breakpoints)
21
            WI.domDebuggerManager.removeEventListenerBreakpoint(breakpoint);
22
23
        resolve();
24
    }
25
26
    function awaitClickBody() {
27
        InspectorTest.log("Clicking body...");
28
29
        return new Promise((resolve, reject) => {
30
            InspectorTest.evaluateInPage(`clickBody()`, (error) => {
31
                if (error)
32
                    reject(error);
33
                else
34
                    resolve();
35
            });
36
        });
37
    }
38
39
    function failOnPause(resolve, message) {
40
        let paused = false;
41
42
        let listener = WI.debuggerManager.singleFireEventListener(WI.DebuggerManager.Event.Paused, (event) => {
43
            paused = true;
44
45
            let targetData = WI.debuggerManager.dataForTarget(WI.debuggerManager.activeCallFrame.target);
46
            InspectorTest.assert(targetData.pauseReason === WI.DebuggerManager.PauseReason.EventListener, "Pause reason should be EventListener.");
47
            InspectorTest.assert(targetData.pauseData.eventName === "click", "Pause data eventName should be \"click\".");
48
49
            InspectorTest.fail(message);
50
            logActiveStackTrace();
51
52
            WI.debuggerManager.resume();
53
        });
54
55
        InspectorTest.singleFireEventListener("TestPageBodyClick", (event) => {
56
            if (!paused) {
57
                WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
58
59
                InspectorTest.pass(message);
60
            }
61
62
            resolve();
63
        });
64
    }
65
66
    function addBreakpoint(eventName) {
67
        InspectorTest.log("Adding Breakpoint...");
68
        return new Promise((resolve, reject) => {
69
            let breakpoint = new WI.EventListenerBreakpoint(eventName);
70
71
            WI.domDebuggerManager.awaitEvent(WI.DOMDebuggerManager.Event.EventListenerBreakpointAdded)
72
            .then((event) => {
73
                InspectorTest.assert(event.data.breakpoint.eventName === eventName, "Breakpoint should be for expected event name.");
74
                InspectorTest.assert(!breakpoint.disabled, "Breakpoint should not be disabled initially.");
75
                resolve(breakpoint);
76
            });
77
78
            WI.domDebuggerManager.addEventListenerBreakpoint(breakpoint);
79
        });
80
    }
81
82
    function removeBreakpoint(breakpoint) {
83
        InspectorTest.log("Removing Breakpoint...");
84
        return new Promise((resolve, reject) => {
85
            WI.domDebuggerManager.awaitEvent(WI.DOMDebuggerManager.Event.EventListenerBreakpointRemoved)
86
            .then((event) => {
87
                InspectorTest.assert(event.data.breakpoint === breakpoint, "Removed Breakpoint should be expected object.");
88
                InspectorTest.assert(!WI.domDebuggerManager.eventListenerBreakpoints.includes(breakpoint), "Breakpoint should not be in the list of breakpoints.");
89
                resolve(breakpoint);
90
            });
91
92
            WI.domDebuggerManager.removeEventListenerBreakpoint(breakpoint);
93
        });
94
    }
95
96
    suite.addTestCase({
97
        name: "DOMDebugger.EventListener.AddBreakpoint",
98
        description: "Check that the debugger pauses for enabled breakpoints.",
99
        teardown,
100
        test(resolve, reject) {
101
            let paused = false;
102
103
            let listener = WI.debuggerManager.singleFireEventListener(WI.DebuggerManager.Event.Paused, (event) => {
104
                paused = true;
105
106
                InspectorTest.pass("Should pause before event handler is run.");
107
                logActiveStackTrace();
108
109
                WI.debuggerManager.resume();
110
            });
111
112
            InspectorTest.singleFireEventListener("TestPageBodyClick", (event) => {
113
                if (!paused) {
114
                    WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
115
116
                    InspectorTest.fail("Should pause before event handler is run.");
117
                }
118
119
                resolve();
120
            });
121
122
            addBreakpoint("click")
123
            .then((breakpoint) => awaitClickBody())
124
            .catch(reject);
125
        }
126
    });
127
128
    suite.addTestCase({
129
        name: "DOMDebugger.EventListener.AddDisabledBreakpoint",
130
        description: "Check that debugger does the not pause for disabled breakpoints.",
131
        teardown,
132
        test(resolve, reject) {
133
            failOnPause(resolve, "Should not pause for disabled breakpoint.");
134
135
            addBreakpoint("click")
136
            .then((breakpoint) => {
137
                InspectorTest.log("Disabling Breakpoint...");
138
                breakpoint.disabled = true;
139
                return breakpoint;
140
            })
141
            .then((breakpoint) => awaitClickBody())
142
            .catch(reject);
143
        }
144
    });
145
146
    suite.addTestCase({
147
        name: "DOMDebugger.EventListener.RemoveBreakpoint",
148
        description: "Check that debugger does not pause for removed breakpoint.",
149
        teardown,
150
        test(resolve, reject) {
151
            failOnPause(resolve, "Should not pause for removed breakpoint.");
152
153
            addBreakpoint("click")
154
            .then((breakpoint) => removeBreakpoint(breakpoint))
155
            .then((breakpoint) => awaitClickBody())
156
            .catch(reject);
157
        }
158
    });
159
160
    suite.addTestCase({
161
        name: "DOMDebugger.EventListener.RemoveDisabledBreakpoint",
162
        description: "Check that a disabled breakpoint can be removed.",
163
        teardown,
164
        test(resolve, reject) {
165
            failOnPause(resolve, "Should not pause for removed disabled breakpoint.");
166
167
            addBreakpoint("click")
168
            .then((breakpoint) => {
169
                InspectorTest.log("Disabling Breakpoint...");
170
                breakpoint.disabled = true;
171
                return breakpoint;
172
            })
173
            .then((breakpoint) => removeBreakpoint(breakpoint))
174
            .then((breakpoint) => awaitClickBody())
175
            .catch(reject);
176
        }
177
    });
178
179
    suite.runTestCasesAndFinish();
180
}
181
</script>
182
</head>
183
<body onload="runTest()">
184
    <p>Tests for Event Listener breakpoints.</p>
185
    <script>
186
        document.body.addEventListener("click", handleBodyClick);
187
    </script>
188
</body>
189
</html>

Return to Bug 183118