OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 /** | |
5 * @implements {UI.ContextFlavorListener} | |
6 * @unrestricted | |
7 */ | |
8 Sources.JavaScriptBreakpointsSidebarPane = class extends UI.ThrottledWidget { | |
9 constructor() { | |
10 super(true); | |
11 this.registerRequiredCSS('components/breakpointsList.css'); | |
12 | |
13 this._breakpointManager = Bindings.breakpointManager; | |
14 this._breakpointManager.addEventListener(Bindings.BreakpointManager.Events.B
reakpointAdded, this.update, this); | |
15 this._breakpointManager.addEventListener(Bindings.BreakpointManager.Events.B
reakpointRemoved, this.update, this); | |
16 this._breakpointManager.addEventListener( | |
17 Bindings.BreakpointManager.Events.BreakpointsActiveStateChanged, this.up
date, this); | |
18 | |
19 /** @type {?Element} */ | |
20 this._listElement = null; | |
21 this.update(); | |
22 } | |
23 | |
24 /** | |
25 * @override | |
26 * @return {!Promise<?>} | |
27 */ | |
28 doUpdate() { | |
29 var breakpointLocations = this._breakpointManager.allBreakpointLocations(); | |
30 if (!breakpointLocations.length) { | |
31 this._listElement = null; | |
32 this.contentElement.removeChildren(); | |
33 var emptyElement = this.contentElement.createChild('div', 'gray-info-messa
ge'); | |
34 emptyElement.textContent = Common.UIString('No Breakpoints'); | |
35 this.contentElement.appendChild(emptyElement); | |
36 this._didUpdateForTest(); | |
37 return Promise.resolve(); | |
38 } | |
39 | |
40 if (!this._listElement) { | |
41 this.contentElement.removeChildren(); | |
42 this._listElement = this.contentElement.createChild('div'); | |
43 this.contentElement.appendChild(this._listElement); | |
44 } | |
45 | |
46 breakpointLocations.sort((item1, item2) => item1.uiLocation.compareTo(item2.
uiLocation)); | |
47 | |
48 /** @type {!Multimap<string, !{breakpoint: !Bindings.BreakpointManager.Break
point, uiLocation: !Workspace.UILocation}>} */ | |
49 var locationForEntry = new Multimap(); | |
50 for (var breakpointLocation of breakpointLocations) { | |
51 var uiLocation = breakpointLocation.uiLocation; | |
52 var entryDescriptor = uiLocation.uiSourceCode.url() + ':' + uiLocation.lin
eNumber; | |
53 locationForEntry.set(entryDescriptor, breakpointLocation); | |
54 } | |
55 | |
56 var details = UI.context.flavor(SDK.DebuggerPausedDetails); | |
57 var selectedUILocation = details && details.callFrames.length ? | |
58 Bindings.debuggerWorkspaceBinding.rawLocationToUILocation(details.callFr
ames[0].location()) : | |
59 null; | |
60 | |
61 var shouldShowView = false; | |
62 var entry = this._listElement.firstChild; | |
63 var promises = []; | |
64 for (var descriptor of locationForEntry.keysArray()) { | |
65 if (!entry) { | |
66 entry = this._listElement.createChild('div', 'breakpoint-entry'); | |
67 entry.addEventListener('contextmenu', this._breakpointContextMenu.bind(t
his), true); | |
68 entry.addEventListener('click', this._revealLocation.bind(this), false); | |
69 var checkboxLabel = UI.CheckboxLabel.create(''); | |
70 checkboxLabel.addEventListener('click', this._breakpointCheckboxClicked.
bind(this), false); | |
71 entry.appendChild(checkboxLabel); | |
72 entry[Sources.JavaScriptBreakpointsSidebarPane._checkboxLabelSymbol] = c
heckboxLabel; | |
73 var snippetElement = entry.createChild('div', 'source-text monospace'); | |
74 entry[Sources.JavaScriptBreakpointsSidebarPane._snippetElementSymbol] =
snippetElement; | |
75 } | |
76 | |
77 var locations = Array.from(locationForEntry.get(descriptor)); | |
78 var uiLocation = locations[0].uiLocation; | |
79 var isSelected = | |
80 !!selectedUILocation && locations.some(location => location.uiLocation
.id() === selectedUILocation.id()); | |
81 var hasEnabled = locations.some(location => location.breakpoint.enabled())
; | |
82 var hasDisabled = locations.some(location => !location.breakpoint.enabled(
)); | |
83 promises.push(this._resetEntry(/** @type {!Element}*/ (entry), uiLocation,
isSelected, hasEnabled, hasDisabled)); | |
84 | |
85 if (isSelected) | |
86 shouldShowView = true; | |
87 entry = entry.nextSibling; | |
88 } | |
89 while (entry) { | |
90 var next = entry.nextSibling; | |
91 entry.remove(); | |
92 entry = next; | |
93 } | |
94 if (shouldShowView) | |
95 UI.viewManager.showView('sources.jsBreakpoints'); | |
96 this._listElement.classList.toggle('breakpoints-list-deactivated', !this._br
eakpointManager.breakpointsActive()); | |
97 Promise.all(promises).then(() => this._didUpdateForTest()); | |
98 return Promise.resolve(); | |
99 } | |
100 | |
101 /** | |
102 * @param {!Element} element | |
103 * @param {!Workspace.UILocation} uiLocation | |
104 * @param {boolean} isSelected | |
105 * @param {boolean} hasEnabled | |
106 * @param {boolean} hasDisabled | |
107 * @return {!Promise<undefined>} | |
108 */ | |
109 _resetEntry(element, uiLocation, isSelected, hasEnabled, hasDisabled) { | |
110 element[Sources.JavaScriptBreakpointsSidebarPane._locationSymbol] = uiLocati
on; | |
111 element.classList.toggle('breakpoint-hit', isSelected); | |
112 | |
113 var checkboxLabel = element[Sources.JavaScriptBreakpointsSidebarPane._checkb
oxLabelSymbol]; | |
114 checkboxLabel.textElement.textContent = uiLocation.linkText(); | |
115 checkboxLabel.checkboxElement.checked = hasEnabled; | |
116 checkboxLabel.checkboxElement.indeterminate = hasEnabled && hasDisabled; | |
117 | |
118 var snippetElement = element[Sources.JavaScriptBreakpointsSidebarPane._snipp
etElementSymbol]; | |
119 return uiLocation.uiSourceCode.requestContent().then(fillSnippetElement.bind
(null, snippetElement)); | |
120 | |
121 /** | |
122 * @param {!Element} snippetElement | |
123 * @param {?string} content | |
124 */ | |
125 function fillSnippetElement(snippetElement, content) { | |
126 var lineNumber = uiLocation.lineNumber; | |
127 var text = new TextUtils.Text(content || ''); | |
128 if (lineNumber < text.lineCount()) { | |
129 var lineText = text.lineAt(lineNumber); | |
130 var maxSnippetLength = 200; | |
131 snippetElement.textContent = lineText.trimEnd(maxSnippetLength); | |
132 } | |
133 } | |
134 } | |
135 | |
136 /** | |
137 * @param {!Event} event | |
138 * @return {?Workspace.UILocation} | |
139 */ | |
140 _uiLocationFromEvent(event) { | |
141 var node = event.target.enclosingNodeOrSelfWithClass('breakpoint-entry'); | |
142 if (!node) | |
143 return null; | |
144 return node[Sources.JavaScriptBreakpointsSidebarPane._locationSymbol] || nul
l; | |
145 } | |
146 | |
147 /** | |
148 * @param {!Event} event | |
149 */ | |
150 _breakpointCheckboxClicked(event) { | |
151 var uiLocation = this._uiLocationFromEvent(event); | |
152 if (!uiLocation) | |
153 return; | |
154 | |
155 var breakpoints = this._breakpointManager.findBreakpoints(uiLocation.uiSourc
eCode, uiLocation.lineNumber); | |
156 var newState = event.target.checkboxElement.checked; | |
157 for (var breakpoint of breakpoints) | |
158 breakpoint.setEnabled(newState); | |
159 event.consume(); | |
160 } | |
161 | |
162 /** | |
163 * @param {!Event} event | |
164 */ | |
165 _revealLocation(event) { | |
166 var uiLocation = this._uiLocationFromEvent(event); | |
167 if (uiLocation) | |
168 Common.Revealer.reveal(uiLocation); | |
169 } | |
170 | |
171 /** | |
172 * @param {!Event} event | |
173 */ | |
174 _breakpointContextMenu(event) { | |
175 var uiLocation = this._uiLocationFromEvent(event); | |
176 if (!uiLocation) | |
177 return; | |
178 | |
179 var breakpoints = this._breakpointManager.findBreakpoints(uiLocation.uiSourc
eCode, uiLocation.lineNumber); | |
180 | |
181 var contextMenu = new UI.ContextMenu(event); | |
182 var removeEntryTitle = breakpoints.length > 1 ? Common.UIString('Remove all
breakpoints in line') : | |
183 Common.UIString('Remove brea
kpoint'); | |
184 contextMenu.appendItem(removeEntryTitle, () => breakpoints.map(breakpoint =>
breakpoint.remove())); | |
185 | |
186 contextMenu.appendSeparator(); | |
187 var breakpointActive = this._breakpointManager.breakpointsActive(); | |
188 var breakpointActiveTitle = | |
189 breakpointActive ? Common.UIString('Deactivate breakpoints') : Common.UI
String('Activate breakpoints'); | |
190 contextMenu.appendItem( | |
191 breakpointActiveTitle, | |
192 this._breakpointManager.setBreakpointsActive.bind(this._breakpointManage
r, !breakpointActive)); | |
193 | |
194 contextMenu.appendSeparator(); | |
195 if (breakpoints.some(breakpoint => !breakpoint.enabled())) { | |
196 var enableTitle = Common.UIString('Enable all breakpoints'); | |
197 contextMenu.appendItem( | |
198 enableTitle, this._breakpointManager.toggleAllBreakpoints.bind(this._b
reakpointManager, true)); | |
199 } | |
200 if (breakpoints.some(breakpoint => breakpoint.enabled())) { | |
201 var disableTitle = Common.UIString('Disable all breakpoints'); | |
202 contextMenu.appendItem( | |
203 disableTitle, this._breakpointManager.toggleAllBreakpoints.bind(this._
breakpointManager, false)); | |
204 } | |
205 var removeAllTitle = Common.UIString('Remove all breakpoints'); | |
206 contextMenu.appendItem(removeAllTitle, this._breakpointManager.removeAllBrea
kpoints.bind(this._breakpointManager)); | |
207 var removeOtherTitle = Common.UIString('Remove other breakpoints'); | |
208 contextMenu.appendItem( | |
209 removeOtherTitle, | |
210 this._breakpointManager.removeOtherBreakpoints.bind(this._breakpointMana
ger, new Set(breakpoints))); | |
211 contextMenu.show(); | |
212 } | |
213 | |
214 /** | |
215 * @override | |
216 * @param {?Object} object | |
217 */ | |
218 flavorChanged(object) { | |
219 this.update(); | |
220 } | |
221 | |
222 _didUpdateForTest() { | |
223 } | |
224 }; | |
225 | |
226 Sources.JavaScriptBreakpointsSidebarPane._locationSymbol = Symbol('location'); | |
227 Sources.JavaScriptBreakpointsSidebarPane._checkboxLabelSymbol = Symbol('checkbox
-label'); | |
228 Sources.JavaScriptBreakpointsSidebarPane._snippetElementSymbol = Symbol('snippet
-element'); | |
OLD | NEW |