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