Web Inspector: Move sidebar-specific styles to a separate file.
[WebKit-https.git] / Source / WebCore / inspector / front-end / BreakpointsSidebarPane.js
1 /*
2  * Copyright (C) 2008 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 /**
27  * @constructor
28  * @param {WebInspector.BreakpointManager} breakpointManager
29  * @extends {WebInspector.SidebarPane}
30  */
31 WebInspector.JavaScriptBreakpointsSidebarPane = function(breakpointManager, showSourceLineDelegate)
32 {
33     WebInspector.SidebarPane.call(this, WebInspector.UIString("Breakpoints"));
34     this.registerRequiredCSS("breakpointsList.css");
35
36     this._breakpointManager = breakpointManager;
37     this._showSourceLineDelegate = showSourceLineDelegate;
38
39     this.listElement = document.createElement("ol");
40     this.listElement.className = "breakpoint-list";
41
42     this.emptyElement = document.createElement("div");
43     this.emptyElement.className = "info";
44     this.emptyElement.textContent = WebInspector.UIString("No Breakpoints");
45
46     this.bodyElement.appendChild(this.emptyElement);
47
48     this._items = new Map();
49     
50     var breakpointLocations = this._breakpointManager.allBreakpointLocations();
51     for (var i = 0; i < breakpointLocations.length; ++i)
52         this._addBreakpoint(breakpointLocations[i].breakpoint, breakpointLocations[i].uiLocation);
53
54     this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointAdded, this._breakpointAdded, this);
55     this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointRemoved, this._breakpointRemoved, this);
56
57     this.emptyElement.addEventListener("contextmenu", this._emptyElementContextMenu.bind(this), true);
58 }
59
60 WebInspector.JavaScriptBreakpointsSidebarPane.prototype = {
61     _emptyElementContextMenu: function(event)
62     {
63         var contextMenu = new WebInspector.ContextMenu(event);
64         var breakpointActive = WebInspector.debuggerModel.breakpointsActive();
65         var breakpointActiveTitle = WebInspector.UIString(breakpointActive ? "Deactivate Breakpoints" : "Activate Breakpoints");
66         contextMenu.appendItem(breakpointActiveTitle, WebInspector.debuggerModel.setBreakpointsActive.bind(WebInspector.debuggerModel, !breakpointActive));
67         contextMenu.show();
68     },
69
70     /**
71      * @param {WebInspector.Event} event
72      */
73     _breakpointAdded: function(event)
74     {
75         this._breakpointRemoved(event);
76
77         var breakpoint = /** @type {WebInspector.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
78         var uiLocation = /** @type {WebInspector.UILocation} */ (event.data.uiLocation);
79         this._addBreakpoint(breakpoint, uiLocation);
80     },
81
82     /**
83      * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
84      * @param {WebInspector.UILocation} uiLocation
85      */
86     _addBreakpoint: function(breakpoint, uiLocation)
87     {
88         var element = document.createElement("li");
89         element.addStyleClass("cursor-pointer");
90         element.addEventListener("contextmenu", this._breakpointContextMenu.bind(this, breakpoint), true);
91         element.addEventListener("click", this._breakpointClicked.bind(this, uiLocation), false);
92
93         var checkbox = document.createElement("input");
94         checkbox.className = "checkbox-elem";
95         checkbox.type = "checkbox";
96         checkbox.checked = breakpoint.enabled();
97         checkbox.addEventListener("click", this._breakpointCheckboxClicked.bind(this, breakpoint), false);
98         element.appendChild(checkbox);
99
100         var labelElement = document.createTextNode(WebInspector.formatLinkText(uiLocation.uiSourceCode.originURL(), uiLocation.lineNumber));
101         element.appendChild(labelElement);
102
103         var snippetElement = document.createElement("div");
104         snippetElement.className = "source-text monospace";
105         element.appendChild(snippetElement);
106
107         /**
108          * @param {?string} content
109          * @param {boolean} contentEncoded
110          * @param {string} mimeType
111          */
112         function didRequestContent(content, contentEncoded, mimeType)
113         {
114             var lineEndings = content.lineEndings();
115             if (uiLocation.lineNumber < lineEndings.length)
116                 snippetElement.textContent = content.substring(lineEndings[uiLocation.lineNumber - 1], lineEndings[uiLocation.lineNumber]);
117         }
118         uiLocation.uiSourceCode.requestContent(didRequestContent.bind(this));
119
120         element._data = uiLocation;
121         var currentElement = this.listElement.firstChild;
122         while (currentElement) {
123             if (currentElement._data && this._compareBreakpoints(currentElement._data, element._data) > 0)
124                 break;
125             currentElement = currentElement.nextSibling;
126         }
127         this._addListElement(element, currentElement);
128
129         var breakpointItem = {};
130         breakpointItem.element = element;
131         breakpointItem.checkbox = checkbox;
132         this._items.put(breakpoint, breakpointItem);
133
134         this.expand();
135     },
136
137     /**
138      * @param {WebInspector.Event} event
139      */
140     _breakpointRemoved: function(event)
141     {
142         var breakpoint = /** @type {WebInspector.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
143         var uiLocation = /** @type {WebInspector.UILocation} */ (event.data.uiLocation);
144         var breakpointItem = this._items.get(breakpoint);
145         if (!breakpointItem)
146             return;
147         this._items.remove(breakpoint);
148         this._removeListElement(breakpointItem.element);
149     },
150
151     /**
152      * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
153      */
154     highlightBreakpoint: function(breakpoint)
155     {
156         var breakpointItem = this._items.get(breakpoint);
157         if (!breakpointItem)
158             return;
159         breakpointItem.element.addStyleClass("breakpoint-hit");
160         this._highlightedBreakpointItem = breakpointItem;
161     },
162
163     clearBreakpointHighlight: function()
164     {
165         if (this._highlightedBreakpointItem) {
166             this._highlightedBreakpointItem.element.removeStyleClass("breakpoint-hit");
167             delete this._highlightedBreakpointItem;
168         }
169     },
170
171     _breakpointClicked: function(uiLocation, event)
172     {
173         this._showSourceLineDelegate(uiLocation.uiSourceCode, uiLocation.lineNumber);
174     },
175
176     /**
177      * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
178      */
179     _breakpointCheckboxClicked: function(breakpoint, event)
180     {
181         // Breakpoint element has it's own click handler.
182         event.consume();
183         breakpoint.setEnabled(event.target.checked);
184     },
185
186     /**
187      * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
188      */
189     _breakpointContextMenu: function(breakpoint, event)
190     {
191         var breakpoints = this._items.values();
192         var contextMenu = new WebInspector.ContextMenu(event);
193         contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), breakpoint.remove.bind(breakpoint));
194         if (breakpoints.length > 1) {
195             var removeAllTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove all breakpoints" : "Remove All Breakpoints");
196             contextMenu.appendItem(removeAllTitle, this._breakpointManager.removeAllBreakpoints.bind(this._breakpointManager));
197         }
198
199         contextMenu.appendSeparator();
200         var breakpointActive = WebInspector.debuggerModel.breakpointsActive();
201         var breakpointActiveTitle = WebInspector.UIString(breakpointActive ? "Deactivate Breakpoints" : "Activate Breakpoints");
202         contextMenu.appendItem(breakpointActiveTitle, WebInspector.debuggerModel.setBreakpointsActive.bind(WebInspector.debuggerModel, !breakpointActive));
203
204         function enabledBreakpointCount(breakpoints)
205         {
206             var count = 0;
207             for (var i = 0; i < breakpoints.length; ++i) {
208                 if (breakpoints[i].checkbox.checked)
209                     count++;
210             }
211             return count;
212         }
213         if (breakpoints.length > 1) {
214             var enableBreakpointCount = enabledBreakpointCount(breakpoints);
215             var enableTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Enable all breakpoints" : "Enable All Breakpoints");
216             var disableTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Disable all breakpoints" : "Disable All Breakpoints");
217
218             contextMenu.appendSeparator();
219
220             contextMenu.appendItem(enableTitle, this._breakpointManager.toggleAllBreakpoints.bind(this._breakpointManager, true), !(enableBreakpointCount != breakpoints.length));
221             contextMenu.appendItem(disableTitle, this._breakpointManager.toggleAllBreakpoints.bind(this._breakpointManager, false), !(enableBreakpointCount > 1));
222         }
223
224         contextMenu.show();
225     },
226
227     _addListElement: function(element, beforeElement)
228     {
229         if (beforeElement)
230             this.listElement.insertBefore(element, beforeElement);
231         else {
232             if (!this.listElement.firstChild) {
233                 this.bodyElement.removeChild(this.emptyElement);
234                 this.bodyElement.appendChild(this.listElement);
235             }
236             this.listElement.appendChild(element);
237         }
238     },
239
240     _removeListElement: function(element)
241     {
242         this.listElement.removeChild(element);
243         if (!this.listElement.firstChild) {
244             this.bodyElement.removeChild(this.listElement);
245             this.bodyElement.appendChild(this.emptyElement);
246         }
247     },
248
249     _compare: function(x, y)
250     {
251         if (x !== y)
252             return x < y ? -1 : 1;
253         return 0;
254     },
255
256     _compareBreakpoints: function(b1, b2)
257     {
258         return this._compare(b1.uiSourceCode.originURL(), b2.uiSourceCode.originURL()) || this._compare(b1.lineNumber, b2.lineNumber);
259     },
260
261     reset: function()
262     {
263         this.listElement.removeChildren();
264         if (this.listElement.parentElement) {
265             this.bodyElement.removeChild(this.listElement);
266             this.bodyElement.appendChild(this.emptyElement);
267         }
268         this._items.clear();
269     },
270
271     __proto__: WebInspector.SidebarPane.prototype
272 }
273
274 /**
275  * @constructor
276  * @extends {WebInspector.NativeBreakpointsSidebarPane}
277  */
278 WebInspector.XHRBreakpointsSidebarPane = function()
279 {
280     WebInspector.NativeBreakpointsSidebarPane.call(this, WebInspector.UIString("XHR Breakpoints"));
281
282     this._breakpointElements = {};
283
284     var addButton = document.createElement("button");
285     addButton.className = "pane-title-button add";
286     addButton.addEventListener("click", this._addButtonClicked.bind(this), false);
287     addButton.title = WebInspector.UIString("Add XHR breakpoint");
288     this.titleElement.appendChild(addButton);
289
290     this.emptyElement.addEventListener("contextmenu", this._emptyElementContextMenu.bind(this), true);
291
292     this._restoreBreakpoints();
293 }
294
295 WebInspector.XHRBreakpointsSidebarPane.prototype = {
296     _emptyElementContextMenu: function(event)
297     {
298         var contextMenu = new WebInspector.ContextMenu(event);
299         contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._addButtonClicked.bind(this));
300         contextMenu.show();
301     },
302
303     _addButtonClicked: function(event)
304     {
305         if (event)
306             event.consume();
307
308         this.expand();
309
310         var inputElementContainer = document.createElement("p");
311         inputElementContainer.className = "breakpoint-condition";
312         var inputElement = document.createElement("span");
313         inputElementContainer.textContent = WebInspector.UIString("Break when URL contains:");
314         inputElement.className = "editing";
315         inputElement.id = "breakpoint-condition-input";
316         inputElementContainer.appendChild(inputElement);
317         this._addListElement(inputElementContainer, this.listElement.firstChild);
318
319         function finishEditing(accept, e, text)
320         {
321             this._removeListElement(inputElementContainer);
322             if (accept) {
323                 this._setBreakpoint(text, true);
324                 this._saveBreakpoints();
325             }
326         }
327
328         var config = new WebInspector.EditingConfig(finishEditing.bind(this, true), finishEditing.bind(this, false));
329         WebInspector.startEditing(inputElement, config);
330     },
331
332     _setBreakpoint: function(url, enabled)
333     {
334         if (url in this._breakpointElements)
335             return;
336
337         var element = document.createElement("li");
338         element._url = url;
339         element.addEventListener("contextmenu", this._contextMenu.bind(this, url), true);
340
341         var checkboxElement = document.createElement("input");
342         checkboxElement.className = "checkbox-elem";
343         checkboxElement.type = "checkbox";
344         checkboxElement.checked = enabled;
345         checkboxElement.addEventListener("click", this._checkboxClicked.bind(this, url), false);
346         element._checkboxElement = checkboxElement;
347         element.appendChild(checkboxElement);
348
349         var labelElement = document.createElement("span");
350         if (!url)
351             labelElement.textContent = WebInspector.UIString("Any XHR");
352         else
353             labelElement.textContent = WebInspector.UIString("URL contains \"%s\"", url);
354         labelElement.addStyleClass("cursor-auto");
355         labelElement.addEventListener("dblclick", this._labelClicked.bind(this, url), false);
356         element.appendChild(labelElement);
357
358         var currentElement = this.listElement.firstChild;
359         while (currentElement) {
360             if (currentElement._url && currentElement._url < element._url)
361                 break;
362             currentElement = currentElement.nextSibling;
363         }
364         this._addListElement(element, currentElement);
365         this._breakpointElements[url] = element;
366         if (enabled)
367             DOMDebuggerAgent.setXHRBreakpoint(url);
368     },
369
370     _removeBreakpoint: function(url)
371     {
372         var element = this._breakpointElements[url];
373         if (!element)
374             return;
375
376         this._removeListElement(element);
377         delete this._breakpointElements[url];
378         if (element._checkboxElement.checked)
379             DOMDebuggerAgent.removeXHRBreakpoint(url);
380     },
381
382     _contextMenu: function(url, event)
383     {
384         var contextMenu = new WebInspector.ContextMenu(event);
385         function removeBreakpoint()
386         {
387             this._removeBreakpoint(url);
388             this._saveBreakpoints();
389         }
390         function removeAllBreakpoints()
391         {
392             for (var url in this._breakpointElements)
393                 this._removeBreakpoint(url);
394             this._saveBreakpoints();
395         }
396         var removeAllTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove all breakpoints" : "Remove All Breakpoints");
397
398         contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._addButtonClicked.bind(this));
399         contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), removeBreakpoint.bind(this));
400         contextMenu.appendItem(removeAllTitle, removeAllBreakpoints.bind(this));
401         contextMenu.show();
402     },
403
404     _checkboxClicked: function(url, event)
405     {
406         if (event.target.checked)
407             DOMDebuggerAgent.setXHRBreakpoint(url);
408         else
409             DOMDebuggerAgent.removeXHRBreakpoint(url);
410         this._saveBreakpoints();
411     },
412
413     _labelClicked: function(url)
414     {
415         var element = this._breakpointElements[url];
416         var inputElement = document.createElement("span");
417         inputElement.className = "breakpoint-condition editing";
418         inputElement.textContent = url;
419         this.listElement.insertBefore(inputElement, element);
420         element.addStyleClass("hidden");
421
422         function finishEditing(accept, e, text)
423         {
424             this._removeListElement(inputElement);
425             if (accept) {
426                 this._removeBreakpoint(url);
427                 this._setBreakpoint(text, element._checkboxElement.checked);
428                 this._saveBreakpoints();
429             } else
430                 element.removeStyleClass("hidden");
431         }
432
433         WebInspector.startEditing(inputElement, new WebInspector.EditingConfig(finishEditing.bind(this, true), finishEditing.bind(this, false)));
434     },
435
436     highlightBreakpoint: function(url)
437     {
438         var element = this._breakpointElements[url];
439         if (!element)
440             return;
441         this.expand();
442         element.addStyleClass("breakpoint-hit");
443         this._highlightedElement = element;
444     },
445
446     clearBreakpointHighlight: function()
447     {
448         if (this._highlightedElement) {
449             this._highlightedElement.removeStyleClass("breakpoint-hit");
450             delete this._highlightedElement;
451         }
452     },
453
454     _saveBreakpoints: function()
455     {
456         var breakpoints = [];
457         for (var url in this._breakpointElements)
458             breakpoints.push({ url: url, enabled: this._breakpointElements[url]._checkboxElement.checked });
459         WebInspector.settings.xhrBreakpoints.set(breakpoints);
460     },
461
462     _restoreBreakpoints: function()
463     {
464         var breakpoints = WebInspector.settings.xhrBreakpoints.get();
465         for (var i = 0; i < breakpoints.length; ++i) {
466             var breakpoint = breakpoints[i];
467             if (breakpoint && typeof breakpoint.url === "string")
468                 this._setBreakpoint(breakpoint.url, breakpoint.enabled);
469         }
470     },
471
472     __proto__: WebInspector.NativeBreakpointsSidebarPane.prototype
473 }
474
475 /**
476  * @constructor
477  * @extends {WebInspector.SidebarPane}
478  */
479 WebInspector.EventListenerBreakpointsSidebarPane = function()
480 {
481     WebInspector.SidebarPane.call(this, WebInspector.UIString("Event Listener Breakpoints"));
482     this.registerRequiredCSS("breakpointsList.css");
483
484     this.categoriesElement = document.createElement("ol");
485     this.categoriesElement.tabIndex = 0;
486     this.categoriesElement.addStyleClass("properties-tree");
487     this.categoriesElement.addStyleClass("event-listener-breakpoints");
488     this.categoriesTreeOutline = new TreeOutline(this.categoriesElement);
489     this.bodyElement.appendChild(this.categoriesElement);
490
491     this._breakpointItems = {};
492     // FIXME: uncomment following once inspector stops being drop targer in major ports.
493     // Otherwise, inspector page reacts on drop event and tries to load the event data.
494     // this._createCategory(WebInspector.UIString("Drag"), true, ["drag", "drop", "dragstart", "dragend", "dragenter", "dragleave", "dragover"]);
495     this._createCategory(WebInspector.UIString("Animation"), false, ["requestAnimationFrame", "cancelAnimationFrame", "animationFrameFired"]);
496     this._createCategory(WebInspector.UIString("Control"), true, ["resize", "scroll", "zoom", "focus", "blur", "select", "change", "submit", "reset"]);
497     this._createCategory(WebInspector.UIString("Clipboard"), true, ["copy", "cut", "paste", "beforecopy", "beforecut", "beforepaste"]);
498     this._createCategory(WebInspector.UIString("DOM Mutation"), true, ["DOMActivate", "DOMFocusIn", "DOMFocusOut", "DOMAttrModified", "DOMCharacterDataModified", "DOMNodeInserted", "DOMNodeInsertedIntoDocument", "DOMNodeRemoved", "DOMNodeRemovedFromDocument", "DOMSubtreeModified", "DOMContentLoaded"]);
499     this._createCategory(WebInspector.UIString("Device"), true, ["deviceorientation", "devicemotion"]);
500     this._createCategory(WebInspector.UIString("Keyboard"), true, ["keydown", "keyup", "keypress", "input"]);
501     this._createCategory(WebInspector.UIString("Load"), true, ["load", "unload", "abort", "error"]);
502     this._createCategory(WebInspector.UIString("Mouse"), true, ["click", "dblclick", "mousedown", "mouseup", "mouseover", "mousemove", "mouseout", "mousewheel"]);
503     this._createCategory(WebInspector.UIString("Timer"), false, ["setTimer", "clearTimer", "timerFired"]);
504     this._createCategory(WebInspector.UIString("Touch"), true, ["touchstart", "touchmove", "touchend", "touchcancel"]);
505
506     this._restoreBreakpoints();
507 }
508
509 WebInspector.EventListenerBreakpointsSidebarPane.categotyListener = "listener:";
510 WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation = "instrumentation:";
511
512 WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI = function(eventName)
513 {
514     if (!WebInspector.EventListenerBreakpointsSidebarPane._eventNamesForUI) {
515         WebInspector.EventListenerBreakpointsSidebarPane._eventNamesForUI = {
516             "instrumentation:setTimer": WebInspector.UIString("Set Timer"),
517             "instrumentation:clearTimer": WebInspector.UIString("Clear Timer"),
518             "instrumentation:timerFired": WebInspector.UIString("Timer Fired"),
519             "instrumentation:requestAnimationFrame": WebInspector.UIString("Request Animation Frame"),
520             "instrumentation:cancelAnimationFrame": WebInspector.UIString("Cancel Animation Frame"),
521             "instrumentation:animationFrameFired": WebInspector.UIString("Animation Frame Fired")
522         };
523     }
524     return WebInspector.EventListenerBreakpointsSidebarPane._eventNamesForUI[eventName] || eventName.substring(eventName.indexOf(":") + 1);
525 }
526
527 WebInspector.EventListenerBreakpointsSidebarPane.prototype = {
528     _createCategory: function(name, isDOMEvent, eventNames)
529     {
530         var categoryItem = {};
531         categoryItem.element = new TreeElement(name);
532         this.categoriesTreeOutline.appendChild(categoryItem.element);
533         categoryItem.element.listItemElement.addStyleClass("event-category");
534         categoryItem.element.selectable = true;
535
536         categoryItem.checkbox = this._createCheckbox(categoryItem.element);
537         categoryItem.checkbox.addEventListener("click", this._categoryCheckboxClicked.bind(this, categoryItem), true);
538
539         categoryItem.children = {};
540         for (var i = 0; i < eventNames.length; ++i) {
541             var eventName = (isDOMEvent ? WebInspector.EventListenerBreakpointsSidebarPane.categotyListener :  WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation) + eventNames[i];
542
543             var breakpointItem = {};
544             var title = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName);
545             breakpointItem.element = new TreeElement(title);
546             categoryItem.element.appendChild(breakpointItem.element);
547             var hitMarker = document.createElement("div");
548             hitMarker.className = "breakpoint-hit-marker";
549             breakpointItem.element.listItemElement.appendChild(hitMarker);
550             breakpointItem.element.listItemElement.addStyleClass("source-code");
551             breakpointItem.element.selectable = true;
552
553             breakpointItem.checkbox = this._createCheckbox(breakpointItem.element);
554             breakpointItem.checkbox.addEventListener("click", this._breakpointCheckboxClicked.bind(this, eventName), true);
555             breakpointItem.parent = categoryItem;
556
557             this._breakpointItems[eventName] = breakpointItem;
558             categoryItem.children[eventName] = breakpointItem;
559         }
560     },
561
562     _createCheckbox: function(treeElement)
563     {
564         var checkbox = document.createElement("input");
565         checkbox.className = "checkbox-elem";
566         checkbox.type = "checkbox";
567         treeElement.listItemElement.insertBefore(checkbox, treeElement.listItemElement.firstChild);
568         return checkbox;
569     },
570
571     _categoryCheckboxClicked: function(categoryItem)
572     {
573         var checked = categoryItem.checkbox.checked;
574         for (var eventName in categoryItem.children) {
575             var breakpointItem = categoryItem.children[eventName];
576             if (breakpointItem.checkbox.checked === checked)
577                 continue;
578             if (checked)
579                 this._setBreakpoint(eventName);
580             else
581                 this._removeBreakpoint(eventName);
582         }
583         this._saveBreakpoints();
584     },
585
586     _breakpointCheckboxClicked: function(eventName, event)
587     {
588         if (event.target.checked)
589             this._setBreakpoint(eventName);
590         else
591             this._removeBreakpoint(eventName);
592         this._saveBreakpoints();
593     },
594
595     _setBreakpoint: function(eventName)
596     {
597         var breakpointItem = this._breakpointItems[eventName];
598         if (!breakpointItem)
599             return;
600         breakpointItem.checkbox.checked = true;
601         if (eventName.startsWith(WebInspector.EventListenerBreakpointsSidebarPane.categotyListener))
602             DOMDebuggerAgent.setEventListenerBreakpoint(eventName.substring(WebInspector.EventListenerBreakpointsSidebarPane.categotyListener.length));
603         else if (eventName.startsWith(WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation))
604             DOMDebuggerAgent.setInstrumentationBreakpoint(eventName.substring(WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation.length));
605         this._updateCategoryCheckbox(breakpointItem.parent);
606     },
607
608     _removeBreakpoint: function(eventName)
609     {
610         var breakpointItem = this._breakpointItems[eventName];
611         if (!breakpointItem)
612             return;
613         breakpointItem.checkbox.checked = false;
614         if (eventName.startsWith(WebInspector.EventListenerBreakpointsSidebarPane.categotyListener))
615             DOMDebuggerAgent.removeEventListenerBreakpoint(eventName.substring(WebInspector.EventListenerBreakpointsSidebarPane.categotyListener.length));
616         else if (eventName.startsWith(WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation))
617             DOMDebuggerAgent.removeInstrumentationBreakpoint(eventName.substring(WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation.length));
618         this._updateCategoryCheckbox(breakpointItem.parent);
619     },
620
621     _updateCategoryCheckbox: function(categoryItem)
622     {
623         var hasEnabled = false, hasDisabled = false;
624         for (var eventName in categoryItem.children) {
625             var breakpointItem = categoryItem.children[eventName];
626             if (breakpointItem.checkbox.checked)
627                 hasEnabled = true;
628             else
629                 hasDisabled = true;
630         }
631         categoryItem.checkbox.checked = hasEnabled;
632         categoryItem.checkbox.indeterminate = hasEnabled && hasDisabled;
633     },
634
635     highlightBreakpoint: function(eventName)
636     {
637         var breakpointItem = this._breakpointItems[eventName];
638         if (!breakpointItem)
639             return;
640         this.expand();
641         breakpointItem.parent.element.expand();
642         breakpointItem.element.listItemElement.addStyleClass("breakpoint-hit");
643         this._highlightedElement = breakpointItem.element.listItemElement;
644     },
645
646     clearBreakpointHighlight: function()
647     {
648         if (this._highlightedElement) {
649             this._highlightedElement.removeStyleClass("breakpoint-hit");
650             delete this._highlightedElement;
651         }
652     },
653
654     _saveBreakpoints: function()
655     {
656         var breakpoints = [];
657         for (var eventName in this._breakpointItems) {
658             if (this._breakpointItems[eventName].checkbox.checked)
659                 breakpoints.push({ eventName: eventName });
660         }
661         WebInspector.settings.eventListenerBreakpoints.set(breakpoints);
662     },
663
664     _restoreBreakpoints: function()
665     {
666         var breakpoints = WebInspector.settings.eventListenerBreakpoints.get();
667         for (var i = 0; i < breakpoints.length; ++i) {
668             var breakpoint = breakpoints[i];
669             if (breakpoint && typeof breakpoint.eventName === "string")
670                 this._setBreakpoint(breakpoint.eventName);
671         }
672     },
673
674     __proto__: WebInspector.SidebarPane.prototype
675 }