| 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 |