OSDN Git Service

Merge WebKit at r84325: Initial merge by git.
[android-x86/external-webkit.git] / Source / WebCore / inspector / front-end / DOMBreakpointsSidebarPane.js
1 /*
2  * Copyright (C) 2011 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 WebInspector.DOMBreakpointsSidebarPane = function()
32 {
33     WebInspector.NativeBreakpointsSidebarPane.call(this, WebInspector.UIString("DOM Breakpoints"));
34
35     this._breakpointElements = {};
36
37     this._breakpointTypes = {
38         SubtreeModified: 0,
39         AttributeModified: 1,
40         NodeRemoved: 2
41     };
42     this._breakpointTypeLabels = [
43         WebInspector.UIString("Subtree Modified"),
44         WebInspector.UIString("Attribute Modified"),
45         WebInspector.UIString("Node Removed")
46     ];
47     this._contextMenuLabels = [
48         WebInspector.UIString("Break on Subtree Modifications"),
49         WebInspector.UIString("Break on Attributes Modifications"),
50         WebInspector.UIString("Break on Node Removal")
51     ];
52 }
53
54 WebInspector.DOMBreakpointsSidebarPane.prototype = {
55     setInspectedURL: function(url)
56     {
57         this._reset();
58         this._inspectedURL = url.removeURLFragment();
59     },
60
61     populateNodeContextMenu: function(node, contextMenu)
62     {
63         var nodeBreakpoints = {};
64         for (var id in this._breakpointElements) {
65             var element = this._breakpointElements[id];
66             if (element._node === node)
67                 nodeBreakpoints[element._type] = true;
68         }
69
70         function toggleBreakpoint(type)
71         {
72             if (!nodeBreakpoints[type])
73                 this._setBreakpoint(node, type, true);
74             else
75                 this._removeBreakpoint(node, type);
76             this._saveBreakpoints();
77         }
78
79         for (var type = 0; type < 3; ++type) {
80             var label = this._contextMenuLabels[type];
81             contextMenu.appendCheckboxItem(label, toggleBreakpoint.bind(this, type), nodeBreakpoints[type]);
82         }
83     },
84
85     createBreakpointHitStatusMessage: function(eventData, callback)
86     {
87         if (eventData.type === this._breakpointTypes.SubtreeModified) {
88             var targetNodeObject = WebInspector.RemoteObject.fromPayload(eventData.targetNode);
89             function didPushNodeToFrontend(targetNodeId)
90             {
91                 if (targetNodeId)
92                     targetNodeObject.release();
93                 this._doCreateBreakpointHitStatusMessage(eventData, targetNodeId, callback);
94             }
95             targetNodeObject.pushNodeToFrontend(didPushNodeToFrontend.bind(this));
96         } else
97             this._doCreateBreakpointHitStatusMessage(eventData, null, callback);
98     },
99
100     _doCreateBreakpointHitStatusMessage: function (eventData, targetNodeId, callback)
101     {
102         var message;
103         var typeLabel = this._breakpointTypeLabels[eventData.type];
104         var linkifiedNode = WebInspector.panels.elements.linkifyNodeById(eventData.nodeId);
105         var substitutions = [typeLabel, linkifiedNode];
106         var targetNode = "";
107         if (targetNodeId)
108             targetNode = WebInspector.panels.elements.linkifyNodeById(targetNodeId);
109
110         if (eventData.type === this._breakpointTypes.SubtreeModified) {
111             if (eventData.insertion) {
112                 if (targetNodeId !== eventData.nodeId) {
113                     message = "Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s.";
114                     substitutions.push(targetNode);
115                 } else
116                     message = "Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node.";
117             } else {
118                 message = "Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed.";
119                 substitutions.push(targetNode);
120             }
121         } else
122             message = "Paused on a \"%s\" breakpoint set on %s.";
123
124         var element = document.createElement("span");
125         var formatters = {
126             s: function(substitution)
127             {
128                 return substitution;
129             }
130         };
131         function append(a, b)
132         {
133             if (typeof b === "string")
134                 b = document.createTextNode(b);
135             element.appendChild(b);
136         }
137         WebInspector.formatLocalized(message, substitutions, formatters, "", append);
138
139         callback(element);
140     },
141
142     nodeRemoved: function(node)
143     {
144         this._removeBreakpointsForNode(node);
145         if (!node.children)
146             return;
147         for (var i = 0; i < node.children.length; ++i)
148             this._removeBreakpointsForNode(node.children[i]);
149         this._saveBreakpoints();
150     },
151
152     _removeBreakpointsForNode: function(node)
153     {
154         for (var id in this._breakpointElements) {
155             var element = this._breakpointElements[id];
156             if (element._node === node)
157                 this._removeBreakpoint(element._node, element._type);
158         }
159     },
160
161     _setBreakpoint: function(node, type, enabled)
162     {
163         var breakpointId = this._createBreakpointId(node.id, type);
164         if (breakpointId in this._breakpointElements)
165             return;
166
167         var element = document.createElement("li");
168         element._node = node;
169         element._type = type;
170         element.addEventListener("contextmenu", this._contextMenu.bind(this, node, type), true);
171
172         var checkboxElement = document.createElement("input");
173         checkboxElement.className = "checkbox-elem";
174         checkboxElement.type = "checkbox";
175         checkboxElement.checked = enabled;
176         checkboxElement.addEventListener("click", this._checkboxClicked.bind(this, node, type), false);
177         element._checkboxElement = checkboxElement;
178         element.appendChild(checkboxElement);
179
180         var labelElement = document.createElement("span");
181         element.appendChild(labelElement);
182
183         var linkifiedNode = WebInspector.panels.elements.linkifyNodeById(node.id);
184         linkifiedNode.addStyleClass("monospace");
185         labelElement.appendChild(linkifiedNode);
186
187         var description = document.createElement("div");
188         description.className = "source-text";
189         description.textContent = this._breakpointTypeLabels[type];
190         labelElement.appendChild(description);
191
192         var currentElement = this.listElement.firstChild;
193         while (currentElement) {
194             if (currentElement._type && currentElement._type < element._type)
195                 break;
196             currentElement = currentElement.nextSibling;
197         }
198         this._addListElement(element, currentElement);
199         this._breakpointElements[breakpointId] = element;
200         if (enabled)
201             BrowserDebuggerAgent.setDOMBreakpoint(node.id, type);
202     },
203
204     _removeBreakpoint: function(node, type)
205     {
206         var breakpointId = this._createBreakpointId(node.id, type);
207         var element = this._breakpointElements[breakpointId];
208         if (!element)
209             return;
210
211         this._removeListElement(element);
212         delete this._breakpointElements[breakpointId];
213         if (element._checkboxElement.checked)
214             BrowserDebuggerAgent.removeDOMBreakpoint(node.id, type);
215     },
216
217     _contextMenu: function(node, type, event)
218     {
219         var contextMenu = new WebInspector.ContextMenu();
220         function removeBreakpoint()
221         {
222             this._removeBreakpoint(node, type);
223             this._saveBreakpoints();
224         }
225         contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), removeBreakpoint.bind(this));
226         contextMenu.show(event);
227     },
228
229     _checkboxClicked: function(node, type, event)
230     {
231         if (event.target.checked)
232             BrowserDebuggerAgent.setDOMBreakpoint(node.id, type);
233         else
234             BrowserDebuggerAgent.removeDOMBreakpoint(node.id, type);
235         this._saveBreakpoints();
236     },
237
238     highlightBreakpoint: function(eventData)
239     {
240         var breakpointId = this._createBreakpointId(eventData.nodeId, eventData.type);
241         var element = this._breakpointElements[breakpointId];
242         if (!element)
243             return;
244         this.expanded = true;
245         element.addStyleClass("breakpoint-hit");
246         this._highlightedElement = element;
247     },
248
249     clearBreakpointHighlight: function()
250     {
251         if (this._highlightedElement) {
252             this._highlightedElement.removeStyleClass("breakpoint-hit");
253             delete this._highlightedElement;
254         }
255     },
256
257     _createBreakpointId: function(nodeId, type)
258     {
259         return nodeId + ":" + type;
260     },
261
262     _saveBreakpoints: function()
263     {
264         var breakpoints = [];
265         var storedBreakpoints = WebInspector.settings.domBreakpoints;
266         for (var i = 0; i < storedBreakpoints.length; ++i) {
267             var breakpoint = storedBreakpoints[i];
268             if (breakpoint.url !== this._inspectedURL)
269                 breakpoints.push(breakpoint);
270         }
271         for (var id in this._breakpointElements) {
272             var element = this._breakpointElements[id];
273             breakpoints.push({ url: this._inspectedURL, path: element._node.path(), type: element._type, enabled: element._checkboxElement.checked });
274         }
275         WebInspector.settings.domBreakpoints = breakpoints;
276     },
277
278     restoreBreakpoints: function()
279     {
280         var pathToBreakpoints = {};
281
282         function didPushNodeByPathToFrontend(path, nodeId)
283         {
284             var node = WebInspector.domAgent.nodeForId(nodeId);
285             if (!node)
286                 return;
287
288             var breakpoints = pathToBreakpoints[path];
289             for (var i = 0; i < breakpoints.length; ++i)
290                 this._setBreakpoint(node, breakpoints[i].type, breakpoints[i].enabled);
291         }
292
293         var breakpoints = WebInspector.settings.domBreakpoints;
294         for (var i = 0; i < breakpoints.length; ++i) {
295             var breakpoint = breakpoints[i];
296             if (breakpoint.url !== this._inspectedURL)
297                 continue;
298             var path = breakpoint.path;
299             if (!pathToBreakpoints[path]) {
300                 pathToBreakpoints[path] = [];
301                 WebInspector.domAgent.pushNodeByPathToFrontend(path, didPushNodeByPathToFrontend.bind(this, path));
302             }
303             pathToBreakpoints[path].push(breakpoint);
304         }
305     }
306 }
307
308 WebInspector.DOMBreakpointsSidebarPane.prototype.__proto__ = WebInspector.NativeBreakpointsSidebarPane.prototype;