Web Inspector: REGRESSION (r248873): Debugger: pressing delete on a breakpoint will...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / DOMBreakpointTreeElement.js
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WI.DOMBreakpointTreeElement = class DOMBreakpointTreeElement extends WI.GeneralTreeElement
27 {
28     constructor(breakpoint, {className, title} = {})
29     {
30         console.assert(breakpoint instanceof WI.DOMBreakpoint);
31
32         let classNames = ["breakpoint", "dom", `breakpoint-for-${breakpoint.type}`];
33         if (className)
34             classNames.push(className);
35
36         if (!title)
37             title = WI.DOMBreakpointTreeElement.displayNameForType(breakpoint.type);
38
39         const subtitle = null;
40         super(classNames, title, subtitle, breakpoint);
41
42         this.status = WI.ImageUtilities.useSVGSymbol("Images/Breakpoint.svg");
43         this.status.className = WI.BreakpointTreeElement.StatusImageElementStyleClassName;
44
45         this.tooltipHandledSeparately = true;
46     }
47
48     // Static
49
50     static displayNameForType(type)
51     {
52         switch (type) {
53         case WI.DOMBreakpoint.Type.SubtreeModified:
54             return WI.UIString("Subtree Modified", "A submenu item of 'Break On' that breaks (pauses) before child DOM node is modified");
55         case WI.DOMBreakpoint.Type.AttributeModified:
56             return WI.UIString("Attribute Modified", "A submenu item of 'Break On' that breaks (pauses) before DOM attribute is modified");
57         case WI.DOMBreakpoint.Type.NodeRemoved:
58             return WI.UIString("Node Removed", "A submenu item of 'Break On' that breaks (pauses) before DOM node is removed");
59         default:
60             console.error("Unexpected DOM breakpoint type: " + type);
61             return null;
62         }
63     }
64
65     // Protected
66
67     onattach()
68     {
69         super.onattach();
70
71         this.representedObject.addEventListener(WI.DOMBreakpoint.Event.DisabledStateChanged, this._updateStatus, this);
72         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointsEnabledDidChange, this._updateStatus, this);
73
74         this._boundStatusImageElementClicked = this._statusImageElementClicked.bind(this);
75         this._boundStatusImageElementFocused = this._statusImageElementFocused.bind(this);
76         this._boundStatusImageElementMouseDown = this._statusImageElementMouseDown.bind(this);
77
78         this.status.addEventListener("click", this._boundStatusImageElementClicked);
79         this.status.addEventListener("focus", this._boundStatusImageElementFocused);
80         this.status.addEventListener("mousedown", this._boundStatusImageElementMouseDown);
81
82         this._updateStatus();
83     }
84
85     ondetach()
86     {
87         super.ondetach();
88
89         this.representedObject.removeEventListener(null, null, this);
90         WI.debuggerManager.removeEventListener(null, null, this);
91
92         this.status.removeEventListener("click", this._boundStatusImageElementClicked);
93         this.status.removeEventListener("focus", this._boundStatusImageElementFocused);
94         this.status.removeEventListener("mousedown", this._boundStatusImageElementMouseDown);
95
96         this._boundStatusImageElementClicked = null;
97         this._boundStatusImageElementFocused = null;
98         this._boundStatusImageElementMouseDown = null;
99     }
100
101     ondelete()
102     {
103         // We set this flag so that TreeOutlines that will remove this
104         // BreakpointTreeElement will know whether it was deleted from
105         // within the TreeOutline or from outside it (e.g. TextEditor).
106         this.__deletedViaDeleteKeyboardShortcut = true;
107
108         WI.domDebuggerManager.removeDOMBreakpoint(this.representedObject);
109
110         return true;
111     }
112
113     onenter()
114     {
115         this._toggleBreakpoint();
116         return true;
117     }
118
119     onspace()
120     {
121         this._toggleBreakpoint();
122         return true;
123     }
124
125     populateContextMenu(contextMenu, event)
126     {
127         let breakpoint = this.representedObject;
128         let label = breakpoint.disabled ? WI.UIString("Enable Breakpoint") : WI.UIString("Disable Breakpoint");
129         contextMenu.appendItem(label, this._toggleBreakpoint.bind(this));
130
131         contextMenu.appendItem(WI.UIString("Delete Breakpoint"), function() {
132             WI.domDebuggerManager.removeDOMBreakpoint(breakpoint);
133         });
134     }
135
136     // Private
137
138     _statusImageElementClicked(event)
139     {
140         this._toggleBreakpoint();
141     }
142
143     _statusImageElementFocused(event)
144     {
145         // Prevent tree outline focus.
146         event.stopPropagation();
147     }
148
149     _statusImageElementMouseDown(event)
150     {
151         // Prevent tree element selection.
152         event.stopPropagation();
153     }
154
155     _toggleBreakpoint()
156     {
157         this.representedObject.disabled = !this.representedObject.disabled;
158     }
159
160     _updateStatus()
161     {
162         if (!this.status)
163             return;
164
165         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageDisabledStyleClassName, this.representedObject.disabled);
166         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageResolvedStyleClassName, WI.debuggerManager.breakpointsEnabled);
167     }
168 };