169b473c6db70d5e4476afd79ce60e501a9a18f1
[WebKit-https.git] / Source / WebCore / inspector / front-end / BreakpointManager.js
1 /*
2  * Copyright (C) 2010 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.BreakpointManager = function()
32 {
33     this._stickyBreakpoints = {};
34     var breakpoints = WebInspector.settings.findSettingForAllProjects("nativeBreakpoints");
35     for (var projectId in breakpoints)
36         this._stickyBreakpoints[projectId] = this._validateBreakpoints(breakpoints[projectId]);
37
38     this._breakpoints = {};
39     this._domBreakpointsRestored = false;
40     this._scriptBreakpoints = {};
41
42     WebInspector.settings.addEventListener(WebInspector.Settings.Events.ProjectChanged, this._projectChanged, this);
43     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._scriptBreakpointAdded, this);
44     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._scriptBreakpointRemoved, this);
45     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
46     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this);
47 }
48
49 WebInspector.BreakpointManager.BreakpointTypes = {
50     DOM: "DOM",
51     JS: "JS",
52     EventListener: "EventListener",
53     XHR: "XHR"
54 }
55
56 WebInspector.BreakpointManager.Events = {
57     DOMBreakpointAdded: "dom-breakpoint-added",
58     EventListenerBreakpointAdded: "event-listener-breakpoint-added",
59     XHRBreakpointAdded: "xhr-breakpoint-added",
60     ProjectChanged: "project-changed"
61 }
62
63 WebInspector.BreakpointManager.prototype = {
64     createDOMBreakpoint: function(nodeId, type)
65     {
66         this._createDOMBreakpoint(nodeId, type, true, false);
67     },
68
69     _createDOMBreakpoint: function(nodeId, type, enabled, restored)
70     {
71         var node = WebInspector.domAgent.nodeForId(nodeId);
72         if (!node)
73             return;
74
75         var breakpointId = this._createDOMBreakpointId(nodeId, type);
76         if (breakpointId in this._breakpoints)
77             return;
78
79         var breakpoint = new WebInspector.DOMBreakpoint(node, type);
80         this._setBreakpoint(breakpointId, breakpoint, enabled, restored);
81         if (enabled && restored)
82             breakpoint._enable();
83
84         breakpoint.view = new WebInspector.DOMBreakpointView(this, breakpointId, enabled, node, type);
85         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.DOMBreakpointAdded, breakpoint.view);
86     },
87
88     createEventListenerBreakpoint: function(eventName)
89     {
90         this._createEventListenerBreakpoint(eventName, true, false);
91     },
92
93     _createEventListenerBreakpoint: function(eventName, enabled, restored)
94     {
95         var breakpointId = this._createEventListenerBreakpointId(eventName);
96         if (breakpointId in this._breakpoints)
97             return;
98
99         var breakpoint = new WebInspector.EventListenerBreakpoint(eventName);
100         this._setBreakpoint(breakpointId, breakpoint, enabled, restored);
101
102         breakpoint.view = new WebInspector.EventListenerBreakpointView(this, breakpointId, enabled, eventName);
103         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.EventListenerBreakpointAdded, breakpoint.view);
104     },
105
106     _createJavaScriptBreakpoint: function(url, lineNumber, condition, enabled, restored)
107     {
108         var breakpointId = this._createJavaScriptBreakpointId(url, lineNumber);
109         if (breakpointId in this._breakpoints)
110             return;
111
112         var breakpoint = new WebInspector.JavaScriptBreakpoint(url, lineNumber, condition);
113         this._setBreakpoint(breakpointId, breakpoint, enabled, restored);
114     },
115
116     _scriptBreakpointAdded: function(event)
117     {
118         var scriptBreakpoint = event.data;
119
120         if (!scriptBreakpoint.url)
121             return;
122
123         if (!scriptBreakpoint.restored)
124             this._createJavaScriptBreakpoint(scriptBreakpoint.url, scriptBreakpoint.originalLineNumber, scriptBreakpoint.condition, scriptBreakpoint.enabled, false);
125         var breakpointId = this._createJavaScriptBreakpointId(scriptBreakpoint.url, scriptBreakpoint.originalLineNumber);
126         this._scriptBreakpoints[scriptBreakpoint.id] = breakpointId;
127     },
128
129     _scriptBreakpointRemoved: function(event)
130     {
131         var scriptBreakpointId = event.data;
132         var breakpointId = this._scriptBreakpoints[scriptBreakpointId];
133         delete this._scriptBreakpoints[scriptBreakpointId];
134         if (breakpointId in this._breakpoints)
135             this._removeBreakpoint(breakpointId);
136     },
137
138     createXHRBreakpoint: function(url)
139     {
140         this._createXHRBreakpoint(url, true, false);
141     },
142
143     _createXHRBreakpoint: function(url, enabled, restored)
144     {
145         var breakpointId = this._createXHRBreakpointId(url);
146         if (breakpointId in this._breakpoints)
147             return;
148
149         var breakpoint = new WebInspector.XHRBreakpoint(url);
150         this._setBreakpoint(breakpointId, breakpoint, enabled, restored);
151
152         breakpoint.view = new WebInspector.XHRBreakpointView(this, breakpointId, enabled, url);
153         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.XHRBreakpointAdded, breakpoint.view);
154     },
155
156     _setBreakpoint: function(breakpointId, breakpoint, enabled, restored)
157     {
158         this._breakpoints[breakpointId] = breakpoint;
159         breakpoint.enabled = enabled;
160         if (restored)
161             return;
162         if (enabled)
163             breakpoint._enable();
164         this._saveBreakpoints();
165     },
166
167     _setBreakpointEnabled: function(breakpointId, enabled)
168     {
169         var breakpoint = this._breakpoints[breakpointId];
170         if (breakpoint.enabled === enabled)
171             return;
172         if (enabled)
173             breakpoint._enable();
174         else
175             breakpoint._disable();
176         breakpoint.enabled = enabled;
177         this._saveBreakpoints();
178     },
179
180     _removeBreakpoint: function(breakpointId)
181     {
182         var breakpoint = this._breakpoints[breakpointId];
183         if (breakpoint.enabled)
184             breakpoint._disable();
185         delete this._breakpoints[breakpointId];
186         this._saveBreakpoints();
187     },
188
189     breakpointViewForEventData: function(eventData)
190     {
191         var breakpointId;
192         if (eventData.breakpointType === WebInspector.BreakpointManager.BreakpointTypes.DOM)
193             breakpointId = this._createDOMBreakpointId(eventData.nodeId, eventData.type);
194         else if (eventData.breakpointType === WebInspector.BreakpointManager.BreakpointTypes.EventListener)
195             breakpointId = this._createEventListenerBreakpointId(eventData.eventName);
196         else if (eventData.breakpointType === WebInspector.BreakpointManager.BreakpointTypes.XHR)
197             breakpointId = this._createXHRBreakpointId(eventData.breakpointURL);
198         else
199             return;
200
201         var breakpoint = this._breakpoints[breakpointId];
202         if (breakpoint)
203             return breakpoint.view;
204     },
205
206     _debuggerPaused: function(event)
207     {
208         var eventType = event.data.eventType;
209         var eventData = event.data.eventData;
210
211         if (eventType !== WebInspector.DebuggerEventTypes.NativeBreakpoint)
212             return;
213
214         var breakpointView = this.breakpointViewForEventData(eventData);
215         if (!breakpointView)
216             return;
217
218         breakpointView.hit = true;
219         this._lastHitBreakpointView = breakpointView;
220     },
221
222     _debuggerResumed: function(event)
223     {
224         if (!this._lastHitBreakpointView)
225             return;
226         this._lastHitBreakpointView.hit = false;
227         delete this._lastHitBreakpointView;
228     },
229
230     _projectChanged: function(event)
231     {
232         this._breakpoints = {};
233         this._domBreakpointsRestored = false;
234         this._scriptBreakpoints = {};
235         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.ProjectChanged);
236
237         var breakpoints = this._stickyBreakpoints[WebInspector.settings.projectId] || [];
238         for (var i = 0; i < breakpoints.length; ++i) {
239             var breakpoint = breakpoints[i];
240             if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.EventListener)
241                 this._createEventListenerBreakpoint(breakpoint.condition.eventName, breakpoint.enabled, true);
242             else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.JS)
243                 this._createJavaScriptBreakpoint(breakpoint.condition.url, breakpoint.condition.lineNumber, breakpoint.condition.condition, breakpoint.enabled, true);
244             else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.XHR)
245                 this._createXHRBreakpoint(breakpoint.condition.url, breakpoint.enabled, true);
246         }
247
248         if (!this._breakpointsPushedToFrontend) {
249             this._pushBreakpointsToBackend();
250             this._breakpointsPushedToFrontend = true;
251         }
252     },
253
254     restoreDOMBreakpoints: function()
255     {
256         function didPushNodeByPathToFrontend(path, nodeId)
257         {
258             pathToNodeId[path] = nodeId;
259             pendingCalls -= 1;
260             if (pendingCalls)
261                 return;
262             for (var i = 0; i < breakpoints.length; ++i) {
263                 var breakpoint = breakpoints[i];
264                 if (breakpoint.type !== WebInspector.BreakpointManager.BreakpointTypes.DOM)
265                     continue;
266                 var nodeId = pathToNodeId[breakpoint.condition.path];
267                 if (nodeId)
268                     this._createDOMBreakpoint(nodeId, breakpoint.condition.type, breakpoint.enabled, true);
269             }
270             this._domBreakpointsRestored = true;
271             this._saveBreakpoints();
272         }
273
274         var breakpoints = this._stickyBreakpoints[WebInspector.settings.projectId] || [];
275         var pathToNodeId = {};
276         var pendingCalls = 0;
277         for (var i = 0; i < breakpoints.length; ++i) {
278             if (breakpoints[i].type !== WebInspector.BreakpointManager.BreakpointTypes.DOM)
279                 continue;
280             var path = breakpoints[i].condition.path;
281             if (path in pathToNodeId)
282                 continue;
283             pathToNodeId[path] = 0;
284             pendingCalls += 1;
285             InspectorBackend.pushNodeByPathToFrontend(path, didPushNodeByPathToFrontend.bind(this, path));
286         }
287         if (!pendingCalls)
288             this._domBreakpointsRestored = true;
289     },
290
291     _saveBreakpoints: function()
292     {
293         var breakpoints = [];
294         for (var breakpointId in this._breakpoints) {
295             var breakpoint = this._breakpoints[breakpointId];
296             var persistentBreakpoint = breakpoint._serializeToJSON();
297             persistentBreakpoint.enabled = breakpoint.enabled;
298             breakpoints.push(persistentBreakpoint);
299         }
300         if (!this._domBreakpointsRestored) {
301             var stickyBreakpoints = this._stickyBreakpoints[WebInspector.settings.projectId] || [];
302             for (var i = 0; i < stickyBreakpoints.length; ++i) {
303                 if (stickyBreakpoints[i].type === WebInspector.BreakpointManager.BreakpointTypes.DOM)
304                     breakpoints.push(stickyBreakpoints[i]);
305             }
306         }
307         WebInspector.settings.nativeBreakpoints = breakpoints;
308
309         this._stickyBreakpoints[WebInspector.settings.projectId] = breakpoints;
310         this._pushBreakpointsToBackend();
311     },
312
313     _pushBreakpointsToBackend: function()
314     {
315         var allJavaScriptBreakpoints = {};
316         var allBrowserBreakpoints = {};
317         for (var projectId in this._stickyBreakpoints) {
318             var breakpoints = this._stickyBreakpoints[projectId];
319             var javaScriptBreakpoints = [];
320             var browserBreakpoints = [];
321             for (var i = 0; i < breakpoints.length; ++i) {
322                 if (breakpoints[i].type == WebInspector.BreakpointManager.BreakpointTypes.JS) {
323                     var data = {};
324                     data.enabled = breakpoints[i].enabled;
325                     for (var p in breakpoints[i].condition)
326                         data[p] = breakpoints[i].condition[p];
327                     javaScriptBreakpoints.push(data);
328                 } else
329                     browserBreakpoints.push(breakpoints[i]);
330             }
331             if (javaScriptBreakpoints.length)
332                 allJavaScriptBreakpoints[projectId] = javaScriptBreakpoints;
333             if (browserBreakpoints.length)
334                 allBrowserBreakpoints[projectId] = browserBreakpoints;
335         }
336         InspectorBackend.setAllJavaScriptBreakpoints(allJavaScriptBreakpoints);
337         InspectorBackend.setAllBrowserBreakpoints(allBrowserBreakpoints);
338     },
339
340     _validateBreakpoints: function(persistentBreakpoints)
341     {
342         var breakpoints = [];
343         var breakpointsSet = {};
344         for (var i = 0; i < persistentBreakpoints.length; ++i) {
345             var breakpoint = persistentBreakpoints[i];
346             if (!("type" in breakpoint && "enabled" in breakpoint && "condition" in breakpoint))
347                 continue;
348             var id = breakpoint.type + ":";
349             var condition = breakpoint.condition;
350             if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.DOM) {
351                 if (typeof condition.path !== "string" || typeof condition.type !== "number")
352                     continue;
353                 id += condition.path + ":" + condition.type;
354             } else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.EventListener) {
355                 if (typeof condition.eventName !== "string")
356                     continue;
357                 id += condition.eventName;
358             } else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.JS) {
359                 if (typeof condition.url !== "string" || typeof condition.lineNumber !== "number" || typeof condition.condition !== "string")
360                     continue;
361                 id += condition.url + ":" + condition.lineNumber;
362             } else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.XHR) {
363                 if (typeof condition.url !== "string")
364                     continue;
365                 id += condition.url;
366             }
367             if (id in breakpointsSet)
368                 continue;
369             breakpointsSet[id] = true;
370             breakpoints.push(breakpoint);
371         }
372         return breakpoints;
373     },
374
375     _createDOMBreakpointId: function(nodeId, type)
376     {
377         return "dom:" + nodeId + ":" + type;
378     },
379
380     _createJavaScriptBreakpointId: function(url, lineNumber)
381     {
382         return "js:" + url + ":" + lineNumber;
383     },
384
385     _createEventListenerBreakpointId: function(eventName)
386     {
387         return "eventListner:" + eventName;
388     },
389
390     _createXHRBreakpointId: function(url)
391     {
392         return "xhr:" + url;
393     }
394 }
395
396 WebInspector.BreakpointManager.prototype.__proto__ = WebInspector.Object.prototype;
397
398 WebInspector.DOMBreakpoint = function(node, type)
399 {
400     this._nodeId = node.id;
401     this._path = node.path();
402     this._type = type;
403 }
404
405 WebInspector.DOMBreakpoint.prototype = {
406     _enable: function()
407     {
408         InspectorBackend.setDOMBreakpoint(this._nodeId, this._type);
409     },
410
411     _disable: function()
412     {
413         InspectorBackend.removeDOMBreakpoint(this._nodeId, this._type);
414     },
415
416     _serializeToJSON: function()
417     {
418         var type = WebInspector.BreakpointManager.BreakpointTypes.DOM;
419         return { type: type, condition: { path: this._path, type: this._type } };
420     }
421 }
422
423 WebInspector.JavaScriptBreakpoint = function(url, lineNumber, condition)
424 {
425     this._url = url;
426     this._lineNumber = lineNumber;
427     this._condition = condition;
428 }
429
430 WebInspector.JavaScriptBreakpoint.prototype = {
431     _enable: function()
432     {
433     },
434
435     _disable: function()
436     {
437     },
438
439     _serializeToJSON: function()
440     {
441         var type = WebInspector.BreakpointManager.BreakpointTypes.JS;
442         return { type: type, condition: { url: this._url, lineNumber: this._lineNumber, columnNumber: 1, condition: this._condition } };
443     }
444 }
445
446 WebInspector.EventListenerBreakpoint = function(eventName)
447 {
448     this._eventName = eventName;
449 }
450
451 WebInspector.EventListenerBreakpoint.prototype = {
452     _enable: function()
453     {
454         InspectorBackend.setEventListenerBreakpoint(this._eventName);
455     },
456
457     _disable: function()
458     {
459         InspectorBackend.removeEventListenerBreakpoint(this._eventName);
460     },
461
462     _serializeToJSON: function()
463     {
464         var type = WebInspector.BreakpointManager.BreakpointTypes.EventListener;
465         return { type: type, condition: { eventName: this._eventName } };
466     }
467 }
468
469 WebInspector.XHRBreakpoint = function(url)
470 {
471     this._url = url;
472 }
473
474 WebInspector.XHRBreakpoint.prototype = {
475     _enable: function()
476     {
477         InspectorBackend.setXHRBreakpoint(this._url);
478     },
479
480     _disable: function()
481     {
482         InspectorBackend.removeXHRBreakpoint(this._url);
483     },
484
485     _serializeToJSON: function()
486     {
487         var type = WebInspector.BreakpointManager.BreakpointTypes.XHR;
488         return { type: type, condition: { url: this._url } };
489     }
490 }
491
492
493
494 WebInspector.NativeBreakpointView = function(manager, id, enabled)
495 {
496     this._manager = manager;
497     this._id = id;
498     this._enabled = enabled;
499     this._hit = false;
500 }
501
502 WebInspector.NativeBreakpointView.prototype = {
503     get enabled()
504     {
505         return this._enabled;
506     },
507
508     set enabled(enabled)
509     {
510         this._manager._setBreakpointEnabled(this._id, enabled);
511         this._enabled = enabled;
512         this.dispatchEventToListeners("enable-changed");
513     },
514
515     get hit()
516     {
517         return this._hit;
518     },
519
520     set hit(hit)
521     {
522         this._hit = hit;
523         this.dispatchEventToListeners("hit-state-changed");
524     },
525
526     remove: function()
527     {
528         this._manager._removeBreakpoint(this._id);
529         this._onRemove();
530         this.dispatchEventToListeners("removed");
531     },
532
533     _compare: function(x, y)
534     {
535         if (x !== y)
536             return x < y ? -1 : 1;
537         return 0;
538     },
539
540     _onRemove: function()
541     {
542     }
543 }
544
545 WebInspector.NativeBreakpointView.prototype.__proto__ = WebInspector.Object.prototype;
546
547 WebInspector.DOMBreakpointView = function(manager, id, enabled, node, type)
548 {
549     WebInspector.NativeBreakpointView.call(this, manager, id, enabled);
550     this._node = node;
551     this._nodeId = node.id;
552     this._type = type;
553     node.breakpoints[this._type] = this;
554 }
555
556 WebInspector.DOMBreakpointView.prototype = {
557     compareTo: function(other)
558     {
559         return this._compare(this._type, other._type);
560     },
561
562     populateLabelElement: function(element)
563     {
564         // FIXME: this should belong to the view, not the manager.
565         var linkifiedNode = WebInspector.panels.elements.linkifyNodeById(this._nodeId);
566         linkifiedNode.addStyleClass("monospace");
567         element.appendChild(linkifiedNode);
568         var description = document.createElement("div");
569         description.className = "source-text";
570         description.textContent = WebInspector.domBreakpointTypeLabel(this._type);
571         element.appendChild(description);
572     },
573
574     populateStatusMessageElement: function(element, eventData)
575     {
576         var substitutions = [WebInspector.domBreakpointTypeLabel(this._type), WebInspector.panels.elements.linkifyNodeById(this._nodeId)];
577         var formatters = {
578             s: function(substitution)
579             {
580                 return substitution;
581             }
582         };
583         function append(a, b)
584         {
585             if (typeof b === "string")
586                 b = document.createTextNode(b);
587             element.appendChild(b);
588         }
589         if (this._type === WebInspector.DOMBreakpointTypes.SubtreeModified) {
590             var targetNode = WebInspector.panels.elements.linkifyNodeById(eventData.targetNodeId);
591             if (eventData.insertion) {
592                 if (eventData.targetNodeId !== this._nodeId)
593                     WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s.", substitutions.concat(targetNode), formatters, "", append);
594                 else
595                     WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node.", substitutions, formatters, "", append);
596             } else
597                 WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed.", substitutions.concat(targetNode), formatters, "", append);
598         } else
599             WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s.", substitutions, formatters, "", append);
600     },
601
602     _onRemove: function()
603     {
604         delete this._node.breakpoints[this._type];
605     }
606 }
607
608 WebInspector.DOMBreakpointView.prototype.__proto__ = WebInspector.NativeBreakpointView.prototype;
609
610 WebInspector.EventListenerBreakpointView = function(manager, id, enabled, eventName)
611 {
612     WebInspector.NativeBreakpointView.call(this, manager, id, enabled);
613     this._eventName = eventName;
614 }
615
616 WebInspector.EventListenerBreakpointView.eventNameForUI = function(eventName)
617 {
618     if (!WebInspector.EventListenerBreakpointView._eventNamesForUI) {
619         WebInspector.EventListenerBreakpointView._eventNamesForUI = {
620             "instrumentation:setTimer": WebInspector.UIString("Set Timer"),
621             "instrumentation:clearTimer": WebInspector.UIString("Clear Timer"),
622             "instrumentation:timerFired": WebInspector.UIString("Timer Fired")
623         };
624     }
625     return WebInspector.EventListenerBreakpointView._eventNamesForUI[eventName] || eventName.substring(eventName.indexOf(":") + 1);
626 }
627
628 WebInspector.EventListenerBreakpointView.prototype = {
629     get eventName()
630     {
631         return this._eventName;
632     },
633
634     compareTo: function(other)
635     {
636         return this._compare(this._eventName, other._eventName);
637     },
638
639     populateLabelElement: function(element)
640     {
641         element.appendChild(document.createTextNode(this._uiEventName()));
642     },
643
644     populateStatusMessageElement: function(element, eventData)
645     {
646         var status = WebInspector.UIString("Paused on a \"%s\" Event Listener.", this._uiEventName());
647         element.appendChild(document.createTextNode(status));
648     },
649
650     _uiEventName: function()
651     {
652         return WebInspector.EventListenerBreakpointView.eventNameForUI(this._eventName);
653     }
654 }
655
656 WebInspector.EventListenerBreakpointView.prototype.__proto__ = WebInspector.NativeBreakpointView.prototype;
657
658 WebInspector.XHRBreakpointView = function(manager, id, enabled, url)
659 {
660     WebInspector.NativeBreakpointView.call(this, manager, id, enabled);
661     this._url = url;
662 }
663
664 WebInspector.XHRBreakpointView.prototype = {
665     compareTo: function(other)
666     {
667         return this._compare(this._url, other._url);
668     },
669
670     populateEditElement: function(element)
671     {
672         element.textContent = this._url;
673     },
674
675     populateLabelElement: function(element)
676     {
677         var label;
678         if (!this._url.length)
679             label = WebInspector.UIString("Any XHR");
680         else
681             label = WebInspector.UIString("URL contains \"%s\"", this._url);
682         element.appendChild(document.createTextNode(label));
683         element.addStyleClass("cursor-auto");
684     },
685
686     populateStatusMessageElement: function(element)
687     {
688         var status = WebInspector.UIString("Paused on a XMLHttpRequest.");
689         element.appendChild(document.createTextNode(status));
690     }
691 }
692
693 WebInspector.XHRBreakpointView.prototype.__proto__ = WebInspector.NativeBreakpointView.prototype;
694
695 WebInspector.DOMBreakpointTypes = {
696     SubtreeModified: 0,
697     AttributeModified: 1,
698     NodeRemoved: 2
699 };
700
701 WebInspector.domBreakpointTypeLabel = function(type)
702 {
703     if (!WebInspector._DOMBreakpointTypeLabels) {
704         WebInspector._DOMBreakpointTypeLabels = {};
705         WebInspector._DOMBreakpointTypeLabels[WebInspector.DOMBreakpointTypes.SubtreeModified] = WebInspector.UIString("Subtree Modified");
706         WebInspector._DOMBreakpointTypeLabels[WebInspector.DOMBreakpointTypes.AttributeModified] = WebInspector.UIString("Attribute Modified");
707         WebInspector._DOMBreakpointTypeLabels[WebInspector.DOMBreakpointTypes.NodeRemoved] = WebInspector.UIString("Node Removed");
708     }
709     return WebInspector._DOMBreakpointTypeLabels[type];
710 }
711
712 WebInspector.domBreakpointTypeContextMenuLabel = function(type)
713 {
714     if (!WebInspector._DOMBreakpointTypeContextMenuLabels) {
715         WebInspector._DOMBreakpointTypeContextMenuLabels = {};
716         WebInspector._DOMBreakpointTypeContextMenuLabels[WebInspector.DOMBreakpointTypes.SubtreeModified] = WebInspector.UIString("Break on Subtree Modifications");
717         WebInspector._DOMBreakpointTypeContextMenuLabels[WebInspector.DOMBreakpointTypes.AttributeModified] = WebInspector.UIString("Break on Attributes Modifications");
718         WebInspector._DOMBreakpointTypeContextMenuLabels[WebInspector.DOMBreakpointTypes.NodeRemoved] = WebInspector.UIString("Break on Node Removal");
719     }
720     return WebInspector._DOMBreakpointTypeContextMenuLabels[type];
721 }