OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
11 * copyright notice, this list of conditions and the following disclaimer | 11 * copyright notice, this list of conditions and the following disclaimer |
12 * in the documentation and/or other materials provided with the | 12 * in the documentation and/or other materials provided with the |
13 * distribution. | 13 * distribution. |
14 * * Neither the name of Google Inc. nor the names of its | 14 * * Neither the name of Google Inc. nor the names of its |
15 * contributors may be used to endorse or promote products derived from | 15 * contributors may be used to endorse or promote products derived from |
16 * this software without specific prior written permission. | 16 * this software without specific prior written permission. |
17 * | 17 * |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | |
31 /** | 30 /** |
32 * @constructor | |
33 * @extends {WebInspector.BreakpointsSidebarPaneBase} | |
34 * @implements {WebInspector.ContextFlavorListener} | 31 * @implements {WebInspector.ContextFlavorListener} |
| 32 * @unrestricted |
35 */ | 33 */ |
36 WebInspector.DOMBreakpointsSidebarPane = function() | 34 WebInspector.DOMBreakpointsSidebarPane = class extends WebInspector.BreakpointsS
idebarPaneBase { |
37 { | 35 constructor() { |
38 WebInspector.BreakpointsSidebarPaneBase.call(this); | 36 super(); |
39 this._domBreakpointsSetting = WebInspector.settings.createLocalSetting("domB
reakpoints", []); | 37 this._domBreakpointsSetting = WebInspector.settings.createLocalSetting('domB
reakpoints', []); |
40 this.listElement.classList.add("dom-breakpoints-list"); | 38 this.listElement.classList.add('dom-breakpoints-list'); |
41 | 39 |
42 /** @type {!Map<string, !Element>} */ | 40 /** @type {!Map<string, !Element>} */ |
43 this._breakpointElements = new Map(); | 41 this._breakpointElements = new Map(); |
44 | 42 |
45 WebInspector.targetManager.addModelListener(WebInspector.DOMModel, WebInspec
tor.DOMModel.Events.NodeRemoved, this._nodeRemoved, this); | 43 WebInspector.targetManager.addModelListener( |
| 44 WebInspector.DOMModel, WebInspector.DOMModel.Events.NodeRemoved, this._n
odeRemoved, this); |
46 this._update(); | 45 this._update(); |
47 }; | 46 } |
48 | 47 |
49 WebInspector.DOMBreakpointsSidebarPane.BreakpointTypes = { | 48 /** |
50 SubtreeModified: "subtree-modified", | 49 * @param {!WebInspector.DebuggerPausedDetails} details |
51 AttributeModified: "attribute-modified", | 50 * @return {!Element} |
52 NodeRemoved: "node-removed" | 51 */ |
53 }; | 52 static createBreakpointHitMessage(details) { |
54 | 53 var messageWrapper = createElement('span'); |
55 WebInspector.DOMBreakpointsSidebarPane.BreakpointTypeLabels = { | 54 var mainElement = messageWrapper.createChild('div', 'status-main'); |
56 "subtree-modified": WebInspector.UIString("Subtree Modified"), | |
57 "attribute-modified": WebInspector.UIString("Attribute Modified"), | |
58 "node-removed": WebInspector.UIString("Node Removed") | |
59 }; | |
60 | |
61 WebInspector.DOMBreakpointsSidebarPane.BreakpointTypeNouns = { | |
62 "subtree-modified": WebInspector.UIString("subtree modifications"), | |
63 "attribute-modified": WebInspector.UIString("attribute modifications"), | |
64 "node-removed": WebInspector.UIString("node removal") | |
65 }; | |
66 | |
67 WebInspector.DOMBreakpointsSidebarPane.Marker = "breakpoint-marker"; | |
68 | |
69 WebInspector.DOMBreakpointsSidebarPane.prototype = { | |
70 /** | |
71 * @param {!WebInspector.DOMNode} node | |
72 * @param {!WebInspector.ContextMenu} contextMenu | |
73 * @param {boolean} createSubMenu | |
74 */ | |
75 populateNodeContextMenu: function(node, contextMenu, createSubMenu) | |
76 { | |
77 if (node.pseudoType()) | |
78 return; | |
79 | |
80 var nodeBreakpoints = this._nodeBreakpoints(node); | |
81 | |
82 /** | |
83 * @param {!DOMDebuggerAgent.DOMBreakpointType} type | |
84 * @this {WebInspector.DOMBreakpointsSidebarPane} | |
85 */ | |
86 function toggleBreakpoint(type) | |
87 { | |
88 if (!nodeBreakpoints.has(type)) | |
89 this._setBreakpoint(node, type, true); | |
90 else | |
91 this._removeBreakpoint(node, type); | |
92 this._saveBreakpoints(); | |
93 } | |
94 | |
95 var breakpointsMenu = createSubMenu ? contextMenu.appendSubMenuItem(WebI
nspector.UIString("Break on...")) : contextMenu; | |
96 for (var key in WebInspector.DOMBreakpointsSidebarPane.BreakpointTypes)
{ | |
97 var type = WebInspector.DOMBreakpointsSidebarPane.BreakpointTypes[ke
y]; | |
98 var label = WebInspector.DOMBreakpointsSidebarPane.BreakpointTypeNou
ns[type]; | |
99 breakpointsMenu.appendCheckboxItem(label, toggleBreakpoint.bind(this
, type), nodeBreakpoints.has(type)); | |
100 } | |
101 }, | |
102 | |
103 /** | |
104 * @param {!WebInspector.DOMNode} node | |
105 * @return {!Set<!DOMDebuggerAgent.DOMBreakpointType>} | |
106 */ | |
107 _nodeBreakpoints: function(node) | |
108 { | |
109 /** @type {!Set<!DOMDebuggerAgent.DOMBreakpointType>} */ | |
110 var nodeBreakpoints = new Set(); | |
111 for (var element of this._breakpointElements.values()) { | |
112 if (element._node === node && element._checkboxElement.checked) | |
113 nodeBreakpoints.add(element._type); | |
114 } | |
115 return nodeBreakpoints; | |
116 }, | |
117 | |
118 /** | |
119 * @param {!WebInspector.DOMNode} node | |
120 * @return {boolean} | |
121 */ | |
122 hasBreakpoints: function(node) | |
123 { | |
124 for (var element of this._breakpointElements.values()) { | |
125 if (element._node === node && element._checkboxElement.checked) | |
126 return true; | |
127 } | |
128 return false; | |
129 }, | |
130 | |
131 _nodeRemoved: function(event) | |
132 { | |
133 var node = event.data.node; | |
134 this._removeBreakpointsForNode(event.data.node); | |
135 var children = node.children(); | |
136 if (!children) | |
137 return; | |
138 for (var i = 0; i < children.length; ++i) | |
139 this._removeBreakpointsForNode(children[i]); | |
140 this._saveBreakpoints(); | |
141 }, | |
142 | |
143 /** | |
144 * @param {!WebInspector.DOMNode} node | |
145 */ | |
146 _removeBreakpointsForNode: function(node) | |
147 { | |
148 for (var element of this._breakpointElements.values()) { | |
149 if (element._node === node) | |
150 this._removeBreakpoint(element._node, element._type); | |
151 } | |
152 }, | |
153 | |
154 /** | |
155 * @param {!WebInspector.DOMNode} node | |
156 * @param {!DOMDebuggerAgent.DOMBreakpointType} type | |
157 * @param {boolean} enabled | |
158 */ | |
159 _setBreakpoint: function(node, type, enabled) | |
160 { | |
161 var breakpointId = this._createBreakpointId(node.id, type); | |
162 var breakpointElement = this._breakpointElements.get(breakpointId); | |
163 if (!breakpointElement) { | |
164 breakpointElement = this._createBreakpointElement(node, type, enable
d); | |
165 this._breakpointElements.set(breakpointId, breakpointElement); | |
166 } else { | |
167 breakpointElement._checkboxElement.checked = enabled; | |
168 } | |
169 if (enabled) | |
170 node.target().domdebuggerAgent().setDOMBreakpoint(node.id, type); | |
171 node.setMarker(WebInspector.DOMBreakpointsSidebarPane.Marker, true); | |
172 }, | |
173 | |
174 /** | |
175 * @param {!WebInspector.DOMNode} node | |
176 * @param {!DOMDebuggerAgent.DOMBreakpointType} type | |
177 * @param {boolean} enabled | |
178 */ | |
179 _createBreakpointElement: function(node, type, enabled) | |
180 { | |
181 var element = createElement("li"); | |
182 element._node = node; | |
183 element._type = type; | |
184 element.addEventListener("contextmenu", this._contextMenu.bind(this, nod
e, type), true); | |
185 | |
186 var checkboxLabel = createCheckboxLabel("", enabled); | |
187 var checkboxElement = checkboxLabel.checkboxElement; | |
188 checkboxElement.addEventListener("click", this._checkboxClicked.bind(thi
s, node, type), false); | |
189 element._checkboxElement = checkboxElement; | |
190 element.appendChild(checkboxLabel); | |
191 | |
192 var labelElement = createElementWithClass("div", "dom-breakpoint"); | |
193 element.appendChild(labelElement); | |
194 | |
195 var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeReferen
ce(node); | |
196 linkifiedNode.classList.add("monospace"); | |
197 linkifiedNode.style.display = "block"; | |
198 labelElement.appendChild(linkifiedNode); | |
199 | |
200 var description = createElement("div"); | |
201 description.textContent = WebInspector.DOMBreakpointsSidebarPane.Breakpo
intTypeLabels[type]; | |
202 labelElement.appendChild(description); | |
203 | |
204 var currentElement = this.listElement.firstChild; | |
205 while (currentElement) { | |
206 if (currentElement._type && currentElement._type < element._type) | |
207 break; | |
208 currentElement = currentElement.nextSibling; | |
209 } | |
210 this.addListElement(element, currentElement); | |
211 return element; | |
212 }, | |
213 | |
214 _removeAllBreakpoints: function() | |
215 { | |
216 for (var element of this._breakpointElements.values()) | |
217 this._removeBreakpoint(element._node, element._type); | |
218 this._saveBreakpoints(); | |
219 }, | |
220 | |
221 /** | |
222 * @param {!WebInspector.DOMNode} node | |
223 * @param {!DOMDebuggerAgent.DOMBreakpointType} type | |
224 */ | |
225 _removeBreakpoint: function(node, type) | |
226 { | |
227 var breakpointId = this._createBreakpointId(node.id, type); | |
228 var element = this._breakpointElements.get(breakpointId); | |
229 if (!element) | |
230 return; | |
231 | |
232 this.removeListElement(element); | |
233 this._breakpointElements.delete(breakpointId); | |
234 if (element._checkboxElement.checked) | |
235 node.target().domdebuggerAgent().removeDOMBreakpoint(node.id, type); | |
236 node.setMarker(WebInspector.DOMBreakpointsSidebarPane.Marker, this.hasBr
eakpoints(node) ? true : null); | |
237 }, | |
238 | |
239 /** | |
240 * @param {!WebInspector.DOMNode} node | |
241 * @param {!DOMDebuggerAgent.DOMBreakpointType} type | |
242 * @param {!Event} event | |
243 */ | |
244 _contextMenu: function(node, type, event) | |
245 { | |
246 var contextMenu = new WebInspector.ContextMenu(event); | |
247 | |
248 /** | |
249 * @this {WebInspector.DOMBreakpointsSidebarPane} | |
250 */ | |
251 function removeBreakpoint() | |
252 { | |
253 this._removeBreakpoint(node, type); | |
254 this._saveBreakpoints(); | |
255 } | |
256 contextMenu.appendItem(WebInspector.UIString.capitalize("Remove ^breakpo
int"), removeBreakpoint.bind(this)); | |
257 contextMenu.appendItem(WebInspector.UIString.capitalize("Remove ^all DOM
breakpoints"), this._removeAllBreakpoints.bind(this)); | |
258 contextMenu.show(); | |
259 }, | |
260 | |
261 /** | |
262 * @param {!WebInspector.DOMNode} node | |
263 * @param {!DOMDebuggerAgent.DOMBreakpointType} type | |
264 * @param {!Event} event | |
265 */ | |
266 _checkboxClicked: function(node, type, event) | |
267 { | |
268 if (event.target.checked) | |
269 node.target().domdebuggerAgent().setDOMBreakpoint(node.id, type); | |
270 else | |
271 node.target().domdebuggerAgent().removeDOMBreakpoint(node.id, type); | |
272 this._saveBreakpoints(); | |
273 }, | |
274 | |
275 /** | |
276 * @override | |
277 * @param {?Object} object | |
278 */ | |
279 flavorChanged: function(object) | |
280 { | |
281 this._update(); | |
282 }, | |
283 | |
284 _update: function() | |
285 { | |
286 var details = WebInspector.context.flavor(WebInspector.DebuggerPausedDet
ails); | |
287 if (!details || details.reason !== WebInspector.DebuggerModel.BreakReaso
n.DOM) { | |
288 if (this._highlightedElement) { | |
289 this._highlightedElement.classList.remove("breakpoint-hit"); | |
290 delete this._highlightedElement; | |
291 } | |
292 return; | |
293 } | |
294 var auxData = details.auxData; | |
295 var breakpointId = this._createBreakpointId(auxData.nodeId, auxData.type
); | |
296 var element = this._breakpointElements.get(breakpointId); | |
297 if (!element) | |
298 return; | |
299 WebInspector.viewManager.showView("sources.domBreakpoints"); | |
300 element.classList.add("breakpoint-hit"); | |
301 this._highlightedElement = element; | |
302 }, | |
303 | |
304 /** | |
305 * @param {number} nodeId | |
306 * @param {!DOMDebuggerAgent.DOMBreakpointType} type | |
307 */ | |
308 _createBreakpointId: function(nodeId, type) | |
309 { | |
310 return nodeId + ":" + type; | |
311 }, | |
312 | |
313 _saveBreakpoints: function() | |
314 { | |
315 var breakpoints = []; | |
316 var storedBreakpoints = this._domBreakpointsSetting.get(); | |
317 for (var i = 0; i < storedBreakpoints.length; ++i) { | |
318 var breakpoint = storedBreakpoints[i]; | |
319 if (breakpoint.url !== this._inspectedURL) | |
320 breakpoints.push(breakpoint); | |
321 } | |
322 for (var element of this._breakpointElements.values()) | |
323 breakpoints.push({ url: this._inspectedURL, path: element._node.path
(), type: element._type, enabled: element._checkboxElement.checked }); | |
324 this._domBreakpointsSetting.set(breakpoints); | |
325 }, | |
326 | |
327 /** | |
328 * @param {!WebInspector.DOMDocument} domDocument | |
329 */ | |
330 restoreBreakpoints: function(domDocument) | |
331 { | |
332 this._breakpointElements.clear(); | |
333 this.reset(); | |
334 this._inspectedURL = domDocument.documentURL; | |
335 var domModel = domDocument.domModel(); | |
336 /** @type {!Map<string, !Array<!Object>>} */ | |
337 var pathToBreakpoints = new Map(); | |
338 | |
339 /** | |
340 * @param {string} path | |
341 * @param {?DOMAgent.NodeId} nodeId | |
342 * @this {WebInspector.DOMBreakpointsSidebarPane} | |
343 */ | |
344 function didPushNodeByPathToFrontend(path, nodeId) | |
345 { | |
346 var node = nodeId ? domModel.nodeForId(nodeId) : null; | |
347 if (!node) | |
348 return; | |
349 | |
350 var breakpoints = pathToBreakpoints.get(path); | |
351 for (var i = 0; i < breakpoints.length; ++i) | |
352 this._setBreakpoint(node, breakpoints[i].type, breakpoints[i].en
abled); | |
353 } | |
354 | |
355 var breakpoints = this._domBreakpointsSetting.get(); | |
356 for (var i = 0; i < breakpoints.length; ++i) { | |
357 var breakpoint = breakpoints[i]; | |
358 if (breakpoint.url !== this._inspectedURL) | |
359 continue; | |
360 var path = breakpoint.path; | |
361 if (!pathToBreakpoints.has(path)) { | |
362 pathToBreakpoints.set(path, []); | |
363 domModel.pushNodeByPathToFrontend(path, didPushNodeByPathToFront
end.bind(this, path)); | |
364 } | |
365 pathToBreakpoints.get(path).push(breakpoint); | |
366 } | |
367 }, | |
368 | |
369 __proto__: WebInspector.BreakpointsSidebarPaneBase.prototype | |
370 }; | |
371 | |
372 /** | |
373 * @param {!WebInspector.DebuggerPausedDetails} details | |
374 * @return {!Element} | |
375 */ | |
376 WebInspector.DOMBreakpointsSidebarPane.createBreakpointHitMessage = function(det
ails) | |
377 { | |
378 var messageWrapper = createElement("span"); | |
379 var mainElement = messageWrapper.createChild("div", "status-main"); | |
380 var auxData = /** @type {!Object} */ (details.auxData); | 55 var auxData = /** @type {!Object} */ (details.auxData); |
381 mainElement.textContent = String.sprintf("Paused on %s", WebInspector.DOMBre
akpointsSidebarPane.BreakpointTypeNouns[auxData["type"]]); | 56 mainElement.textContent = |
| 57 String.sprintf('Paused on %s', WebInspector.DOMBreakpointsSidebarPane.Br
eakpointTypeNouns[auxData['type']]); |
382 | 58 |
383 var domModel = WebInspector.DOMModel.fromTarget(details.target()); | 59 var domModel = WebInspector.DOMModel.fromTarget(details.target()); |
384 if (domModel) { | 60 if (domModel) { |
385 var subElement = messageWrapper.createChild("div", "status-sub monospace
"); | 61 var subElement = messageWrapper.createChild('div', 'status-sub monospace')
; |
386 var node = domModel.nodeForId(auxData["nodeId"]); | 62 var node = domModel.nodeForId(auxData['nodeId']); |
387 var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeReferen
ce(node); | 63 var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeReference
(node); |
388 subElement.appendChild(linkifiedNode); | 64 subElement.appendChild(linkifiedNode); |
389 | 65 |
390 var targetNode = auxData["targetNodeId"] ? domModel.nodeForId(auxData["t
argetNodeId"]) : null; | 66 var targetNode = auxData['targetNodeId'] ? domModel.nodeForId(auxData['tar
getNodeId']) : null; |
391 var targetNodeLink = targetNode ? WebInspector.DOMPresentationUtils.link
ifyNodeReference(targetNode) : ""; | 67 var targetNodeLink = targetNode ? WebInspector.DOMPresentationUtils.linkif
yNodeReference(targetNode) : ''; |
392 var message; | 68 var message; |
393 if (auxData.type === WebInspector.DOMBreakpointsSidebarPane.BreakpointTy
pes.SubtreeModified) { | 69 if (auxData.type === WebInspector.DOMBreakpointsSidebarPane.BreakpointType
s.SubtreeModified) { |
394 if (auxData["insertion"]) | 70 if (auxData['insertion']) |
395 message = targetNode === node ? "Child %s added" : "Descendant %
s added"; | 71 message = targetNode === node ? 'Child %s added' : 'Descendant %s adde
d'; |
396 else | 72 else |
397 message = "Descendant %s removed"; | 73 message = 'Descendant %s removed'; |
398 subElement.appendChild(createElement("br")); | 74 subElement.appendChild(createElement('br')); |
399 subElement.appendChild(WebInspector.formatLocalized(message, [target
NodeLink])); | 75 subElement.appendChild(WebInspector.formatLocalized(message, [targetNode
Link])); |
400 } | 76 } |
401 } | 77 } |
402 return messageWrapper; | 78 return messageWrapper; |
403 }; | 79 } |
| 80 |
| 81 /** |
| 82 * @param {!WebInspector.DOMNode} node |
| 83 * @param {!WebInspector.ContextMenu} contextMenu |
| 84 * @param {boolean} createSubMenu |
| 85 */ |
| 86 populateNodeContextMenu(node, contextMenu, createSubMenu) { |
| 87 if (node.pseudoType()) |
| 88 return; |
| 89 |
| 90 var nodeBreakpoints = this._nodeBreakpoints(node); |
| 91 |
| 92 /** |
| 93 * @param {!DOMDebuggerAgent.DOMBreakpointType} type |
| 94 * @this {WebInspector.DOMBreakpointsSidebarPane} |
| 95 */ |
| 96 function toggleBreakpoint(type) { |
| 97 if (!nodeBreakpoints.has(type)) |
| 98 this._setBreakpoint(node, type, true); |
| 99 else |
| 100 this._removeBreakpoint(node, type); |
| 101 this._saveBreakpoints(); |
| 102 } |
| 103 |
| 104 var breakpointsMenu = |
| 105 createSubMenu ? contextMenu.appendSubMenuItem(WebInspector.UIString('Bre
ak on...')) : contextMenu; |
| 106 for (var key in WebInspector.DOMBreakpointsSidebarPane.BreakpointTypes) { |
| 107 var type = WebInspector.DOMBreakpointsSidebarPane.BreakpointTypes[key]; |
| 108 var label = WebInspector.DOMBreakpointsSidebarPane.BreakpointTypeNouns[typ
e]; |
| 109 breakpointsMenu.appendCheckboxItem(label, toggleBreakpoint.bind(this, type
), nodeBreakpoints.has(type)); |
| 110 } |
| 111 } |
| 112 |
| 113 /** |
| 114 * @param {!WebInspector.DOMNode} node |
| 115 * @return {!Set<!DOMDebuggerAgent.DOMBreakpointType>} |
| 116 */ |
| 117 _nodeBreakpoints(node) { |
| 118 /** @type {!Set<!DOMDebuggerAgent.DOMBreakpointType>} */ |
| 119 var nodeBreakpoints = new Set(); |
| 120 for (var element of this._breakpointElements.values()) { |
| 121 if (element._node === node && element._checkboxElement.checked) |
| 122 nodeBreakpoints.add(element._type); |
| 123 } |
| 124 return nodeBreakpoints; |
| 125 } |
| 126 |
| 127 /** |
| 128 * @param {!WebInspector.DOMNode} node |
| 129 * @return {boolean} |
| 130 */ |
| 131 hasBreakpoints(node) { |
| 132 for (var element of this._breakpointElements.values()) { |
| 133 if (element._node === node && element._checkboxElement.checked) |
| 134 return true; |
| 135 } |
| 136 return false; |
| 137 } |
| 138 |
| 139 _nodeRemoved(event) { |
| 140 var node = event.data.node; |
| 141 this._removeBreakpointsForNode(event.data.node); |
| 142 var children = node.children(); |
| 143 if (!children) |
| 144 return; |
| 145 for (var i = 0; i < children.length; ++i) |
| 146 this._removeBreakpointsForNode(children[i]); |
| 147 this._saveBreakpoints(); |
| 148 } |
| 149 |
| 150 /** |
| 151 * @param {!WebInspector.DOMNode} node |
| 152 */ |
| 153 _removeBreakpointsForNode(node) { |
| 154 for (var element of this._breakpointElements.values()) { |
| 155 if (element._node === node) |
| 156 this._removeBreakpoint(element._node, element._type); |
| 157 } |
| 158 } |
| 159 |
| 160 /** |
| 161 * @param {!WebInspector.DOMNode} node |
| 162 * @param {!DOMDebuggerAgent.DOMBreakpointType} type |
| 163 * @param {boolean} enabled |
| 164 */ |
| 165 _setBreakpoint(node, type, enabled) { |
| 166 var breakpointId = this._createBreakpointId(node.id, type); |
| 167 var breakpointElement = this._breakpointElements.get(breakpointId); |
| 168 if (!breakpointElement) { |
| 169 breakpointElement = this._createBreakpointElement(node, type, enabled); |
| 170 this._breakpointElements.set(breakpointId, breakpointElement); |
| 171 } else { |
| 172 breakpointElement._checkboxElement.checked = enabled; |
| 173 } |
| 174 if (enabled) |
| 175 node.target().domdebuggerAgent().setDOMBreakpoint(node.id, type); |
| 176 node.setMarker(WebInspector.DOMBreakpointsSidebarPane.Marker, true); |
| 177 } |
| 178 |
| 179 /** |
| 180 * @param {!WebInspector.DOMNode} node |
| 181 * @param {!DOMDebuggerAgent.DOMBreakpointType} type |
| 182 * @param {boolean} enabled |
| 183 */ |
| 184 _createBreakpointElement(node, type, enabled) { |
| 185 var element = createElement('li'); |
| 186 element._node = node; |
| 187 element._type = type; |
| 188 element.addEventListener('contextmenu', this._contextMenu.bind(this, node, t
ype), true); |
| 189 |
| 190 var checkboxLabel = createCheckboxLabel('', enabled); |
| 191 var checkboxElement = checkboxLabel.checkboxElement; |
| 192 checkboxElement.addEventListener('click', this._checkboxClicked.bind(this, n
ode, type), false); |
| 193 element._checkboxElement = checkboxElement; |
| 194 element.appendChild(checkboxLabel); |
| 195 |
| 196 var labelElement = createElementWithClass('div', 'dom-breakpoint'); |
| 197 element.appendChild(labelElement); |
| 198 |
| 199 var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeReference(n
ode); |
| 200 linkifiedNode.classList.add('monospace'); |
| 201 linkifiedNode.style.display = 'block'; |
| 202 labelElement.appendChild(linkifiedNode); |
| 203 |
| 204 var description = createElement('div'); |
| 205 description.textContent = WebInspector.DOMBreakpointsSidebarPane.BreakpointT
ypeLabels[type]; |
| 206 labelElement.appendChild(description); |
| 207 |
| 208 var currentElement = this.listElement.firstChild; |
| 209 while (currentElement) { |
| 210 if (currentElement._type && currentElement._type < element._type) |
| 211 break; |
| 212 currentElement = currentElement.nextSibling; |
| 213 } |
| 214 this.addListElement(element, currentElement); |
| 215 return element; |
| 216 } |
| 217 |
| 218 _removeAllBreakpoints() { |
| 219 for (var element of this._breakpointElements.values()) |
| 220 this._removeBreakpoint(element._node, element._type); |
| 221 this._saveBreakpoints(); |
| 222 } |
| 223 |
| 224 /** |
| 225 * @param {!WebInspector.DOMNode} node |
| 226 * @param {!DOMDebuggerAgent.DOMBreakpointType} type |
| 227 */ |
| 228 _removeBreakpoint(node, type) { |
| 229 var breakpointId = this._createBreakpointId(node.id, type); |
| 230 var element = this._breakpointElements.get(breakpointId); |
| 231 if (!element) |
| 232 return; |
| 233 |
| 234 this.removeListElement(element); |
| 235 this._breakpointElements.delete(breakpointId); |
| 236 if (element._checkboxElement.checked) |
| 237 node.target().domdebuggerAgent().removeDOMBreakpoint(node.id, type); |
| 238 node.setMarker(WebInspector.DOMBreakpointsSidebarPane.Marker, this.hasBreakp
oints(node) ? true : null); |
| 239 } |
| 240 |
| 241 /** |
| 242 * @param {!WebInspector.DOMNode} node |
| 243 * @param {!DOMDebuggerAgent.DOMBreakpointType} type |
| 244 * @param {!Event} event |
| 245 */ |
| 246 _contextMenu(node, type, event) { |
| 247 var contextMenu = new WebInspector.ContextMenu(event); |
| 248 |
| 249 /** |
| 250 * @this {WebInspector.DOMBreakpointsSidebarPane} |
| 251 */ |
| 252 function removeBreakpoint() { |
| 253 this._removeBreakpoint(node, type); |
| 254 this._saveBreakpoints(); |
| 255 } |
| 256 contextMenu.appendItem(WebInspector.UIString.capitalize('Remove ^breakpoint'
), removeBreakpoint.bind(this)); |
| 257 contextMenu.appendItem( |
| 258 WebInspector.UIString.capitalize('Remove ^all DOM breakpoints'), this._r
emoveAllBreakpoints.bind(this)); |
| 259 contextMenu.show(); |
| 260 } |
| 261 |
| 262 /** |
| 263 * @param {!WebInspector.DOMNode} node |
| 264 * @param {!DOMDebuggerAgent.DOMBreakpointType} type |
| 265 * @param {!Event} event |
| 266 */ |
| 267 _checkboxClicked(node, type, event) { |
| 268 if (event.target.checked) |
| 269 node.target().domdebuggerAgent().setDOMBreakpoint(node.id, type); |
| 270 else |
| 271 node.target().domdebuggerAgent().removeDOMBreakpoint(node.id, type); |
| 272 this._saveBreakpoints(); |
| 273 } |
| 274 |
| 275 /** |
| 276 * @override |
| 277 * @param {?Object} object |
| 278 */ |
| 279 flavorChanged(object) { |
| 280 this._update(); |
| 281 } |
| 282 |
| 283 _update() { |
| 284 var details = WebInspector.context.flavor(WebInspector.DebuggerPausedDetails
); |
| 285 if (!details || details.reason !== WebInspector.DebuggerModel.BreakReason.DO
M) { |
| 286 if (this._highlightedElement) { |
| 287 this._highlightedElement.classList.remove('breakpoint-hit'); |
| 288 delete this._highlightedElement; |
| 289 } |
| 290 return; |
| 291 } |
| 292 var auxData = details.auxData; |
| 293 var breakpointId = this._createBreakpointId(auxData.nodeId, auxData.type); |
| 294 var element = this._breakpointElements.get(breakpointId); |
| 295 if (!element) |
| 296 return; |
| 297 WebInspector.viewManager.showView('sources.domBreakpoints'); |
| 298 element.classList.add('breakpoint-hit'); |
| 299 this._highlightedElement = element; |
| 300 } |
| 301 |
| 302 /** |
| 303 * @param {number} nodeId |
| 304 * @param {!DOMDebuggerAgent.DOMBreakpointType} type |
| 305 */ |
| 306 _createBreakpointId(nodeId, type) { |
| 307 return nodeId + ':' + type; |
| 308 } |
| 309 |
| 310 _saveBreakpoints() { |
| 311 var breakpoints = []; |
| 312 var storedBreakpoints = this._domBreakpointsSetting.get(); |
| 313 for (var i = 0; i < storedBreakpoints.length; ++i) { |
| 314 var breakpoint = storedBreakpoints[i]; |
| 315 if (breakpoint.url !== this._inspectedURL) |
| 316 breakpoints.push(breakpoint); |
| 317 } |
| 318 for (var element of this._breakpointElements.values()) |
| 319 breakpoints.push({ |
| 320 url: this._inspectedURL, |
| 321 path: element._node.path(), |
| 322 type: element._type, |
| 323 enabled: element._checkboxElement.checked |
| 324 }); |
| 325 this._domBreakpointsSetting.set(breakpoints); |
| 326 } |
| 327 |
| 328 /** |
| 329 * @param {!WebInspector.DOMDocument} domDocument |
| 330 */ |
| 331 restoreBreakpoints(domDocument) { |
| 332 this._breakpointElements.clear(); |
| 333 this.reset(); |
| 334 this._inspectedURL = domDocument.documentURL; |
| 335 var domModel = domDocument.domModel(); |
| 336 /** @type {!Map<string, !Array<!Object>>} */ |
| 337 var pathToBreakpoints = new Map(); |
| 338 |
| 339 /** |
| 340 * @param {string} path |
| 341 * @param {?DOMAgent.NodeId} nodeId |
| 342 * @this {WebInspector.DOMBreakpointsSidebarPane} |
| 343 */ |
| 344 function didPushNodeByPathToFrontend(path, nodeId) { |
| 345 var node = nodeId ? domModel.nodeForId(nodeId) : null; |
| 346 if (!node) |
| 347 return; |
| 348 |
| 349 var breakpoints = pathToBreakpoints.get(path); |
| 350 for (var i = 0; i < breakpoints.length; ++i) |
| 351 this._setBreakpoint(node, breakpoints[i].type, breakpoints[i].enabled); |
| 352 } |
| 353 |
| 354 var breakpoints = this._domBreakpointsSetting.get(); |
| 355 for (var i = 0; i < breakpoints.length; ++i) { |
| 356 var breakpoint = breakpoints[i]; |
| 357 if (breakpoint.url !== this._inspectedURL) |
| 358 continue; |
| 359 var path = breakpoint.path; |
| 360 if (!pathToBreakpoints.has(path)) { |
| 361 pathToBreakpoints.set(path, []); |
| 362 domModel.pushNodeByPathToFrontend(path, didPushNodeByPathToFrontend.bind
(this, path)); |
| 363 } |
| 364 pathToBreakpoints.get(path).push(breakpoint); |
| 365 } |
| 366 } |
| 367 }; |
| 368 |
| 369 WebInspector.DOMBreakpointsSidebarPane.BreakpointTypes = { |
| 370 SubtreeModified: 'subtree-modified', |
| 371 AttributeModified: 'attribute-modified', |
| 372 NodeRemoved: 'node-removed' |
| 373 }; |
| 374 |
| 375 WebInspector.DOMBreakpointsSidebarPane.BreakpointTypeLabels = { |
| 376 'subtree-modified': WebInspector.UIString('Subtree Modified'), |
| 377 'attribute-modified': WebInspector.UIString('Attribute Modified'), |
| 378 'node-removed': WebInspector.UIString('Node Removed') |
| 379 }; |
| 380 |
| 381 WebInspector.DOMBreakpointsSidebarPane.BreakpointTypeNouns = { |
| 382 'subtree-modified': WebInspector.UIString('subtree modifications'), |
| 383 'attribute-modified': WebInspector.UIString('attribute modifications'), |
| 384 'node-removed': WebInspector.UIString('node removal') |
| 385 }; |
| 386 |
| 387 WebInspector.DOMBreakpointsSidebarPane.Marker = 'breakpoint-marker'; |
| 388 |
404 | 389 |
405 /** | 390 /** |
406 * @constructor | 391 * @unrestricted |
407 * @extends {WebInspector.VBox} | |
408 */ | 392 */ |
409 WebInspector.DOMBreakpointsSidebarPane.Proxy = function() | 393 WebInspector.DOMBreakpointsSidebarPane.Proxy = class extends WebInspector.VBox { |
410 { | 394 constructor() { |
411 WebInspector.VBox.call(this); | 395 super(); |
412 this.registerRequiredCSS("components/breakpointsList.css"); | 396 this.registerRequiredCSS('components/breakpointsList.css'); |
413 }; | 397 } |
414 | 398 |
415 WebInspector.DOMBreakpointsSidebarPane.Proxy.prototype = { | 399 /** |
416 wasShown: function() | 400 * @override |
417 { | 401 */ |
418 WebInspector.SimpleView.prototype.wasShown.call(this); | 402 wasShown() { |
419 var pane = WebInspector.domBreakpointsSidebarPane; | 403 super.wasShown(); |
420 if (pane.element.parentNode !== this.element) | 404 var pane = WebInspector.domBreakpointsSidebarPane; |
421 pane.show(this.element); | 405 if (pane.element.parentNode !== this.element) |
422 }, | 406 pane.show(this.element); |
423 | 407 } |
424 __proto__: WebInspector.VBox.prototype | |
425 }; | 408 }; |
426 | 409 |
427 /** | 410 /** |
428 * @type {!WebInspector.DOMBreakpointsSidebarPane} | 411 * @type {!WebInspector.DOMBreakpointsSidebarPane} |
429 */ | 412 */ |
430 WebInspector.domBreakpointsSidebarPane; | 413 WebInspector.domBreakpointsSidebarPane; |
OLD | NEW |