OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. |
3 * Copyright (C) 2009 Joseph Pecoraro | 3 * Copyright (C) 2009 Joseph Pecoraro |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
7 * met: | 7 * met: |
8 * | 8 * |
9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 10 matching lines...) Expand all Loading... |
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 */ | 30 */ |
31 | |
32 /** | 31 /** |
33 * @constructor | 32 * @unrestricted |
34 * @extends {WebInspector.SDKObject} | |
35 * @param {!WebInspector.DOMModel} domModel | |
36 */ | 33 */ |
37 WebInspector.DOMNode = function(domModel) | 34 WebInspector.DOMNode = class extends WebInspector.SDKObject { |
38 { | 35 /** |
39 WebInspector.SDKObject.call(this, domModel.target()); | 36 * @param {!WebInspector.DOMModel} domModel |
| 37 */ |
| 38 constructor(domModel) { |
| 39 super(domModel.target()); |
40 this._domModel = domModel; | 40 this._domModel = domModel; |
41 }; | 41 } |
42 | 42 |
43 /** | 43 /** |
44 * @param {!WebInspector.DOMModel} domModel | 44 * @param {!WebInspector.DOMModel} domModel |
45 * @param {?WebInspector.DOMDocument} doc | 45 * @param {?WebInspector.DOMDocument} doc |
46 * @param {boolean} isInShadowTree | 46 * @param {boolean} isInShadowTree |
47 * @param {!DOMAgent.Node} payload | 47 * @param {!DOMAgent.Node} payload |
48 * @return {!WebInspector.DOMNode} | 48 * @return {!WebInspector.DOMNode} |
49 */ | 49 */ |
50 WebInspector.DOMNode.create = function(domModel, doc, isInShadowTree, payload) | 50 static create(domModel, doc, isInShadowTree, payload) { |
51 { | |
52 var node = new WebInspector.DOMNode(domModel); | 51 var node = new WebInspector.DOMNode(domModel); |
53 node._init(doc, isInShadowTree, payload); | 52 node._init(doc, isInShadowTree, payload); |
54 return node; | 53 return node; |
55 } | 54 } |
| 55 |
| 56 /** |
| 57 * @param {?WebInspector.DOMDocument} doc |
| 58 * @param {boolean} isInShadowTree |
| 59 * @param {!DOMAgent.Node} payload |
| 60 */ |
| 61 _init(doc, isInShadowTree, payload) { |
| 62 this._agent = this._domModel._agent; |
| 63 this.ownerDocument = doc; |
| 64 this._isInShadowTree = isInShadowTree; |
| 65 |
| 66 this.id = payload.nodeId; |
| 67 this._domModel._idToDOMNode[this.id] = this; |
| 68 this._nodeType = payload.nodeType; |
| 69 this._nodeName = payload.nodeName; |
| 70 this._localName = payload.localName; |
| 71 this._nodeValue = payload.nodeValue; |
| 72 this._pseudoType = payload.pseudoType; |
| 73 this._shadowRootType = payload.shadowRootType; |
| 74 this._frameOwnerFrameId = payload.frameId || null; |
| 75 this._xmlVersion = payload.xmlVersion; |
| 76 |
| 77 this._shadowRoots = []; |
| 78 |
| 79 this._attributes = []; |
| 80 this._attributesMap = {}; |
| 81 if (payload.attributes) |
| 82 this._setAttributesPayload(payload.attributes); |
| 83 |
| 84 /** @type {!Map<string, ?>} */ |
| 85 this._markers = new Map(); |
| 86 this._subtreeMarkerCount = 0; |
| 87 |
| 88 this._childNodeCount = payload.childNodeCount || 0; |
| 89 this._children = null; |
| 90 |
| 91 this.nextSibling = null; |
| 92 this.previousSibling = null; |
| 93 this.firstChild = null; |
| 94 this.lastChild = null; |
| 95 this.parentNode = null; |
| 96 |
| 97 if (payload.shadowRoots) { |
| 98 for (var i = 0; i < payload.shadowRoots.length; ++i) { |
| 99 var root = payload.shadowRoots[i]; |
| 100 var node = WebInspector.DOMNode.create(this._domModel, this.ownerDocumen
t, true, root); |
| 101 this._shadowRoots.push(node); |
| 102 node.parentNode = this; |
| 103 } |
| 104 } |
| 105 |
| 106 if (payload.templateContent) { |
| 107 this._templateContent = |
| 108 WebInspector.DOMNode.create(this._domModel, this.ownerDocument, true,
payload.templateContent); |
| 109 this._templateContent.parentNode = this; |
| 110 } |
| 111 |
| 112 if (payload.importedDocument) { |
| 113 this._importedDocument = |
| 114 WebInspector.DOMNode.create(this._domModel, this.ownerDocument, true,
payload.importedDocument); |
| 115 this._importedDocument.parentNode = this; |
| 116 } |
| 117 |
| 118 if (payload.distributedNodes) |
| 119 this._setDistributedNodePayloads(payload.distributedNodes); |
| 120 |
| 121 if (payload.children) |
| 122 this._setChildrenPayload(payload.children); |
| 123 |
| 124 this._setPseudoElements(payload.pseudoElements); |
| 125 |
| 126 if (payload.contentDocument) { |
| 127 this._contentDocument = new WebInspector.DOMDocument(this._domModel, paylo
ad.contentDocument); |
| 128 this._children = [this._contentDocument]; |
| 129 this._renumber(); |
| 130 } |
| 131 |
| 132 if (this._nodeType === Node.ELEMENT_NODE) { |
| 133 // HTML and BODY from internal iframes should not overwrite top-level ones
. |
| 134 if (this.ownerDocument && !this.ownerDocument.documentElement && this._nod
eName === 'HTML') |
| 135 this.ownerDocument.documentElement = this; |
| 136 if (this.ownerDocument && !this.ownerDocument.body && this._nodeName === '
BODY') |
| 137 this.ownerDocument.body = this; |
| 138 } else if (this._nodeType === Node.DOCUMENT_TYPE_NODE) { |
| 139 this.publicId = payload.publicId; |
| 140 this.systemId = payload.systemId; |
| 141 this.internalSubset = payload.internalSubset; |
| 142 } else if (this._nodeType === Node.ATTRIBUTE_NODE) { |
| 143 this.name = payload.name; |
| 144 this.value = payload.value; |
| 145 } |
| 146 } |
| 147 |
| 148 /** |
| 149 * @return {!WebInspector.DOMModel} |
| 150 */ |
| 151 domModel() { |
| 152 return this._domModel; |
| 153 } |
| 154 |
| 155 /** |
| 156 * @return {?Array.<!WebInspector.DOMNode>} |
| 157 */ |
| 158 children() { |
| 159 return this._children ? this._children.slice() : null; |
| 160 } |
| 161 |
| 162 /** |
| 163 * @return {boolean} |
| 164 */ |
| 165 hasAttributes() { |
| 166 return this._attributes.length > 0; |
| 167 } |
| 168 |
| 169 /** |
| 170 * @return {number} |
| 171 */ |
| 172 childNodeCount() { |
| 173 return this._childNodeCount; |
| 174 } |
| 175 |
| 176 /** |
| 177 * @return {boolean} |
| 178 */ |
| 179 hasShadowRoots() { |
| 180 return !!this._shadowRoots.length; |
| 181 } |
| 182 |
| 183 /** |
| 184 * @return {!Array.<!WebInspector.DOMNode>} |
| 185 */ |
| 186 shadowRoots() { |
| 187 return this._shadowRoots.slice(); |
| 188 } |
| 189 |
| 190 /** |
| 191 * @return {?WebInspector.DOMNode} |
| 192 */ |
| 193 templateContent() { |
| 194 return this._templateContent || null; |
| 195 } |
| 196 |
| 197 /** |
| 198 * @return {?WebInspector.DOMNode} |
| 199 */ |
| 200 importedDocument() { |
| 201 return this._importedDocument || null; |
| 202 } |
| 203 |
| 204 /** |
| 205 * @return {number} |
| 206 */ |
| 207 nodeType() { |
| 208 return this._nodeType; |
| 209 } |
| 210 |
| 211 /** |
| 212 * @return {string} |
| 213 */ |
| 214 nodeName() { |
| 215 return this._nodeName; |
| 216 } |
| 217 |
| 218 /** |
| 219 * @return {string|undefined} |
| 220 */ |
| 221 pseudoType() { |
| 222 return this._pseudoType; |
| 223 } |
| 224 |
| 225 /** |
| 226 * @return {boolean} |
| 227 */ |
| 228 hasPseudoElements() { |
| 229 return this._pseudoElements.size > 0; |
| 230 } |
| 231 |
| 232 /** |
| 233 * @return {!Map<string, !WebInspector.DOMNode>} |
| 234 */ |
| 235 pseudoElements() { |
| 236 return this._pseudoElements; |
| 237 } |
| 238 |
| 239 /** |
| 240 * @return {?WebInspector.DOMNode} |
| 241 */ |
| 242 beforePseudoElement() { |
| 243 if (!this._pseudoElements) |
| 244 return null; |
| 245 return this._pseudoElements.get(WebInspector.DOMNode.PseudoElementNames.Befo
re); |
| 246 } |
| 247 |
| 248 /** |
| 249 * @return {?WebInspector.DOMNode} |
| 250 */ |
| 251 afterPseudoElement() { |
| 252 if (!this._pseudoElements) |
| 253 return null; |
| 254 return this._pseudoElements.get(WebInspector.DOMNode.PseudoElementNames.Afte
r); |
| 255 } |
| 256 |
| 257 /** |
| 258 * @return {boolean} |
| 259 */ |
| 260 isInsertionPoint() { |
| 261 return !this.isXMLNode() && |
| 262 (this._nodeName === 'SHADOW' || this._nodeName === 'CONTENT' || this._no
deName === 'SLOT'); |
| 263 } |
| 264 |
| 265 /** |
| 266 * @return {!Array.<!WebInspector.DOMNodeShortcut>} |
| 267 */ |
| 268 distributedNodes() { |
| 269 return this._distributedNodes || []; |
| 270 } |
| 271 |
| 272 /** |
| 273 * @return {boolean} |
| 274 */ |
| 275 isInShadowTree() { |
| 276 return this._isInShadowTree; |
| 277 } |
| 278 |
| 279 /** |
| 280 * @return {?WebInspector.DOMNode} |
| 281 */ |
| 282 ancestorShadowHost() { |
| 283 var ancestorShadowRoot = this.ancestorShadowRoot(); |
| 284 return ancestorShadowRoot ? ancestorShadowRoot.parentNode : null; |
| 285 } |
| 286 |
| 287 /** |
| 288 * @return {?WebInspector.DOMNode} |
| 289 */ |
| 290 ancestorShadowRoot() { |
| 291 if (!this._isInShadowTree) |
| 292 return null; |
| 293 |
| 294 var current = this; |
| 295 while (current && !current.isShadowRoot()) |
| 296 current = current.parentNode; |
| 297 return current; |
| 298 } |
| 299 |
| 300 /** |
| 301 * @return {?WebInspector.DOMNode} |
| 302 */ |
| 303 ancestorUserAgentShadowRoot() { |
| 304 var ancestorShadowRoot = this.ancestorShadowRoot(); |
| 305 if (!ancestorShadowRoot) |
| 306 return null; |
| 307 return ancestorShadowRoot.shadowRootType() === WebInspector.DOMNode.ShadowRo
otTypes.UserAgent ? ancestorShadowRoot : |
| 308
null; |
| 309 } |
| 310 |
| 311 /** |
| 312 * @return {boolean} |
| 313 */ |
| 314 isShadowRoot() { |
| 315 return !!this._shadowRootType; |
| 316 } |
| 317 |
| 318 /** |
| 319 * @return {?string} |
| 320 */ |
| 321 shadowRootType() { |
| 322 return this._shadowRootType || null; |
| 323 } |
| 324 |
| 325 /** |
| 326 * @return {string} |
| 327 */ |
| 328 nodeNameInCorrectCase() { |
| 329 var shadowRootType = this.shadowRootType(); |
| 330 if (shadowRootType) |
| 331 return '#shadow-root (' + shadowRootType + ')'; |
| 332 |
| 333 // If there is no local name, it's case sensitive |
| 334 if (!this.localName()) |
| 335 return this.nodeName(); |
| 336 |
| 337 // If the names are different lengths, there is a prefix and it's case sensi
tive |
| 338 if (this.localName().length !== this.nodeName().length) |
| 339 return this.nodeName(); |
| 340 |
| 341 // Return the localname, which will be case insensitive if its an html node |
| 342 return this.localName(); |
| 343 } |
| 344 |
| 345 /** |
| 346 * @param {string} name |
| 347 * @param {function(?Protocol.Error, number)=} callback |
| 348 */ |
| 349 setNodeName(name, callback) { |
| 350 this._agent.setNodeName(this.id, name, this._domModel._markRevision(this, ca
llback)); |
| 351 } |
| 352 |
| 353 /** |
| 354 * @return {string} |
| 355 */ |
| 356 localName() { |
| 357 return this._localName; |
| 358 } |
| 359 |
| 360 /** |
| 361 * @return {string} |
| 362 */ |
| 363 nodeValue() { |
| 364 return this._nodeValue; |
| 365 } |
| 366 |
| 367 /** |
| 368 * @param {string} value |
| 369 * @param {function(?Protocol.Error)=} callback |
| 370 */ |
| 371 setNodeValue(value, callback) { |
| 372 this._agent.setNodeValue(this.id, value, this._domModel._markRevision(this,
callback)); |
| 373 } |
| 374 |
| 375 /** |
| 376 * @param {string} name |
| 377 * @return {string} |
| 378 */ |
| 379 getAttribute(name) { |
| 380 var attr = this._attributesMap[name]; |
| 381 return attr ? attr.value : undefined; |
| 382 } |
| 383 |
| 384 /** |
| 385 * @param {string} name |
| 386 * @param {string} text |
| 387 * @param {function(?Protocol.Error)=} callback |
| 388 */ |
| 389 setAttribute(name, text, callback) { |
| 390 this._agent.setAttributesAsText(this.id, text, name, this._domModel._markRev
ision(this, callback)); |
| 391 } |
| 392 |
| 393 /** |
| 394 * @param {string} name |
| 395 * @param {string} value |
| 396 * @param {function(?Protocol.Error)=} callback |
| 397 */ |
| 398 setAttributeValue(name, value, callback) { |
| 399 this._agent.setAttributeValue(this.id, name, value, this._domModel._markRevi
sion(this, callback)); |
| 400 } |
| 401 |
| 402 /** |
| 403 * @return {!Array<!WebInspector.DOMNode.Attribute>} |
| 404 */ |
| 405 attributes() { |
| 406 return this._attributes; |
| 407 } |
| 408 |
| 409 /** |
| 410 * @param {string} name |
| 411 * @param {function(?Protocol.Error)=} callback |
| 412 */ |
| 413 removeAttribute(name, callback) { |
| 414 /** |
| 415 * @param {?Protocol.Error} error |
| 416 * @this {WebInspector.DOMNode} |
| 417 */ |
| 418 function mycallback(error) { |
| 419 if (!error) { |
| 420 delete this._attributesMap[name]; |
| 421 for (var i = 0; i < this._attributes.length; ++i) { |
| 422 if (this._attributes[i].name === name) { |
| 423 this._attributes.splice(i, 1); |
| 424 break; |
| 425 } |
| 426 } |
| 427 } |
| 428 |
| 429 this._domModel._markRevision(this, callback)(error); |
| 430 } |
| 431 this._agent.removeAttribute(this.id, name, mycallback.bind(this)); |
| 432 } |
| 433 |
| 434 /** |
| 435 * @param {function(?Array.<!WebInspector.DOMNode>)=} callback |
| 436 */ |
| 437 getChildNodes(callback) { |
| 438 if (this._children) { |
| 439 if (callback) |
| 440 callback(this.children()); |
| 441 return; |
| 442 } |
| 443 |
| 444 /** |
| 445 * @this {WebInspector.DOMNode} |
| 446 * @param {?Protocol.Error} error |
| 447 */ |
| 448 function mycallback(error) { |
| 449 if (callback) |
| 450 callback(error ? null : this.children()); |
| 451 } |
| 452 |
| 453 this._agent.requestChildNodes(this.id, undefined, mycallback.bind(this)); |
| 454 } |
| 455 |
| 456 /** |
| 457 * @param {number} depth |
| 458 * @param {function(?Array.<!WebInspector.DOMNode>)=} callback |
| 459 */ |
| 460 getSubtree(depth, callback) { |
| 461 /** |
| 462 * @this {WebInspector.DOMNode} |
| 463 * @param {?Protocol.Error} error |
| 464 */ |
| 465 function mycallback(error) { |
| 466 if (callback) |
| 467 callback(error ? null : this._children); |
| 468 } |
| 469 |
| 470 this._agent.requestChildNodes(this.id, depth, mycallback.bind(this)); |
| 471 } |
| 472 |
| 473 /** |
| 474 * @param {function(?Protocol.Error, string)=} callback |
| 475 */ |
| 476 getOuterHTML(callback) { |
| 477 this._agent.getOuterHTML(this.id, callback); |
| 478 } |
| 479 |
| 480 /** |
| 481 * @param {string} html |
| 482 * @param {function(?Protocol.Error)=} callback |
| 483 */ |
| 484 setOuterHTML(html, callback) { |
| 485 this._agent.setOuterHTML(this.id, html, this._domModel._markRevision(this, c
allback)); |
| 486 } |
| 487 |
| 488 /** |
| 489 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback |
| 490 */ |
| 491 removeNode(callback) { |
| 492 this._agent.removeNode(this.id, this._domModel._markRevision(this, callback)
); |
| 493 } |
| 494 |
| 495 /** |
| 496 * @param {function(?string)=} callback |
| 497 */ |
| 498 copyNode(callback) { |
| 499 function copy(error, text) { |
| 500 if (!error) |
| 501 InspectorFrontendHost.copyText(text); |
| 502 if (callback) |
| 503 callback(error ? null : text); |
| 504 } |
| 505 this._agent.getOuterHTML(this.id, copy); |
| 506 } |
| 507 |
| 508 /** |
| 509 * @return {string} |
| 510 */ |
| 511 path() { |
| 512 /** |
| 513 * @param {?WebInspector.DOMNode} node |
| 514 */ |
| 515 function canPush(node) { |
| 516 return node && ('index' in node || (node.isShadowRoot() && node.parentNode
)) && node._nodeName.length; |
| 517 } |
| 518 |
| 519 var path = []; |
| 520 var node = this; |
| 521 while (canPush(node)) { |
| 522 var index = typeof node.index === 'number' ? |
| 523 node.index : |
| 524 (node.shadowRootType() === WebInspector.DOMNode.ShadowRootTypes.UserAg
ent ? 'u' : 'a'); |
| 525 path.push([index, node._nodeName]); |
| 526 node = node.parentNode; |
| 527 } |
| 528 path.reverse(); |
| 529 return path.join(','); |
| 530 } |
| 531 |
| 532 /** |
| 533 * @param {!WebInspector.DOMNode} node |
| 534 * @return {boolean} |
| 535 */ |
| 536 isAncestor(node) { |
| 537 if (!node) |
| 538 return false; |
| 539 |
| 540 var currentNode = node.parentNode; |
| 541 while (currentNode) { |
| 542 if (this === currentNode) |
| 543 return true; |
| 544 currentNode = currentNode.parentNode; |
| 545 } |
| 546 return false; |
| 547 } |
| 548 |
| 549 /** |
| 550 * @param {!WebInspector.DOMNode} descendant |
| 551 * @return {boolean} |
| 552 */ |
| 553 isDescendant(descendant) { |
| 554 return descendant !== null && descendant.isAncestor(this); |
| 555 } |
| 556 |
| 557 /** |
| 558 * @return {?PageAgent.FrameId} |
| 559 */ |
| 560 frameId() { |
| 561 var node = this.parentNode || this; |
| 562 while (!node._frameOwnerFrameId && node.parentNode) |
| 563 node = node.parentNode; |
| 564 return node._frameOwnerFrameId; |
| 565 } |
| 566 |
| 567 /** |
| 568 * @param {!Array.<string>} attrs |
| 569 * @return {boolean} |
| 570 */ |
| 571 _setAttributesPayload(attrs) { |
| 572 var attributesChanged = !this._attributes || attrs.length !== this._attribut
es.length * 2; |
| 573 var oldAttributesMap = this._attributesMap || {}; |
| 574 |
| 575 this._attributes = []; |
| 576 this._attributesMap = {}; |
| 577 |
| 578 for (var i = 0; i < attrs.length; i += 2) { |
| 579 var name = attrs[i]; |
| 580 var value = attrs[i + 1]; |
| 581 this._addAttribute(name, value); |
| 582 |
| 583 if (attributesChanged) |
| 584 continue; |
| 585 |
| 586 if (!oldAttributesMap[name] || oldAttributesMap[name].value !== value) |
| 587 attributesChanged = true; |
| 588 } |
| 589 return attributesChanged; |
| 590 } |
| 591 |
| 592 /** |
| 593 * @param {!WebInspector.DOMNode} prev |
| 594 * @param {!DOMAgent.Node} payload |
| 595 * @return {!WebInspector.DOMNode} |
| 596 */ |
| 597 _insertChild(prev, payload) { |
| 598 var node = WebInspector.DOMNode.create(this._domModel, this.ownerDocument, t
his._isInShadowTree, payload); |
| 599 this._children.splice(this._children.indexOf(prev) + 1, 0, node); |
| 600 this._renumber(); |
| 601 return node; |
| 602 } |
| 603 |
| 604 /** |
| 605 * @param {!WebInspector.DOMNode} node |
| 606 */ |
| 607 _removeChild(node) { |
| 608 if (node.pseudoType()) { |
| 609 this._pseudoElements.delete(node.pseudoType()); |
| 610 } else { |
| 611 var shadowRootIndex = this._shadowRoots.indexOf(node); |
| 612 if (shadowRootIndex !== -1) { |
| 613 this._shadowRoots.splice(shadowRootIndex, 1); |
| 614 } else { |
| 615 console.assert(this._children.indexOf(node) !== -1); |
| 616 this._children.splice(this._children.indexOf(node), 1); |
| 617 } |
| 618 } |
| 619 node.parentNode = null; |
| 620 this._subtreeMarkerCount -= node._subtreeMarkerCount; |
| 621 if (node._subtreeMarkerCount) |
| 622 this._domModel.dispatchEventToListeners(WebInspector.DOMModel.Events.Marke
rsChanged, this); |
| 623 this._renumber(); |
| 624 } |
| 625 |
| 626 /** |
| 627 * @param {!Array.<!DOMAgent.Node>} payloads |
| 628 */ |
| 629 _setChildrenPayload(payloads) { |
| 630 // We set children in the constructor. |
| 631 if (this._contentDocument) |
| 632 return; |
| 633 |
| 634 this._children = []; |
| 635 for (var i = 0; i < payloads.length; ++i) { |
| 636 var payload = payloads[i]; |
| 637 var node = WebInspector.DOMNode.create(this._domModel, this.ownerDocument,
this._isInShadowTree, payload); |
| 638 this._children.push(node); |
| 639 } |
| 640 this._renumber(); |
| 641 } |
| 642 |
| 643 /** |
| 644 * @param {!Array.<!DOMAgent.Node>|undefined} payloads |
| 645 */ |
| 646 _setPseudoElements(payloads) { |
| 647 this._pseudoElements = new Map(); |
| 648 if (!payloads) |
| 649 return; |
| 650 |
| 651 for (var i = 0; i < payloads.length; ++i) { |
| 652 var node = WebInspector.DOMNode.create(this._domModel, this.ownerDocument,
this._isInShadowTree, payloads[i]); |
| 653 node.parentNode = this; |
| 654 this._pseudoElements.set(node.pseudoType(), node); |
| 655 } |
| 656 } |
| 657 |
| 658 /** |
| 659 * @param {!Array.<!DOMAgent.BackendNode>} payloads |
| 660 */ |
| 661 _setDistributedNodePayloads(payloads) { |
| 662 this._distributedNodes = []; |
| 663 for (var payload of payloads) |
| 664 this._distributedNodes.push(new WebInspector.DOMNodeShortcut( |
| 665 this._domModel.target(), payload.backendNodeId, payload.nodeType, payl
oad.nodeName)); |
| 666 } |
| 667 |
| 668 _renumber() { |
| 669 this._childNodeCount = this._children.length; |
| 670 if (this._childNodeCount === 0) { |
| 671 this.firstChild = null; |
| 672 this.lastChild = null; |
| 673 return; |
| 674 } |
| 675 this.firstChild = this._children[0]; |
| 676 this.lastChild = this._children[this._childNodeCount - 1]; |
| 677 for (var i = 0; i < this._childNodeCount; ++i) { |
| 678 var child = this._children[i]; |
| 679 child.index = i; |
| 680 child.nextSibling = i + 1 < this._childNodeCount ? this._children[i + 1] :
null; |
| 681 child.previousSibling = i - 1 >= 0 ? this._children[i - 1] : null; |
| 682 child.parentNode = this; |
| 683 } |
| 684 } |
| 685 |
| 686 /** |
| 687 * @param {string} name |
| 688 * @param {string} value |
| 689 */ |
| 690 _addAttribute(name, value) { |
| 691 var attr = {name: name, value: value, _node: this}; |
| 692 this._attributesMap[name] = attr; |
| 693 this._attributes.push(attr); |
| 694 } |
| 695 |
| 696 /** |
| 697 * @param {string} name |
| 698 * @param {string} value |
| 699 */ |
| 700 _setAttribute(name, value) { |
| 701 var attr = this._attributesMap[name]; |
| 702 if (attr) |
| 703 attr.value = value; |
| 704 else |
| 705 this._addAttribute(name, value); |
| 706 } |
| 707 |
| 708 /** |
| 709 * @param {string} name |
| 710 */ |
| 711 _removeAttribute(name) { |
| 712 var attr = this._attributesMap[name]; |
| 713 if (attr) { |
| 714 this._attributes.remove(attr); |
| 715 delete this._attributesMap[name]; |
| 716 } |
| 717 } |
| 718 |
| 719 /** |
| 720 * @param {!WebInspector.DOMNode} targetNode |
| 721 * @param {?WebInspector.DOMNode} anchorNode |
| 722 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback |
| 723 */ |
| 724 copyTo(targetNode, anchorNode, callback) { |
| 725 this._agent.copyTo( |
| 726 this.id, targetNode.id, anchorNode ? anchorNode.id : undefined, this._do
mModel._markRevision(this, callback)); |
| 727 } |
| 728 |
| 729 /** |
| 730 * @param {!WebInspector.DOMNode} targetNode |
| 731 * @param {?WebInspector.DOMNode} anchorNode |
| 732 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback |
| 733 */ |
| 734 moveTo(targetNode, anchorNode, callback) { |
| 735 this._agent.moveTo( |
| 736 this.id, targetNode.id, anchorNode ? anchorNode.id : undefined, this._do
mModel._markRevision(this, callback)); |
| 737 } |
| 738 |
| 739 /** |
| 740 * @return {boolean} |
| 741 */ |
| 742 isXMLNode() { |
| 743 return !!this._xmlVersion; |
| 744 } |
| 745 |
| 746 /** |
| 747 * @param {string} name |
| 748 * @param {?*} value |
| 749 */ |
| 750 setMarker(name, value) { |
| 751 if (value === null) { |
| 752 if (!this._markers.has(name)) |
| 753 return; |
| 754 |
| 755 this._markers.delete(name); |
| 756 for (var node = this; node; node = node.parentNode) |
| 757 --node._subtreeMarkerCount; |
| 758 for (var node = this; node; node = node.parentNode) |
| 759 this._domModel.dispatchEventToListeners(WebInspector.DOMModel.Events.Mar
kersChanged, node); |
| 760 return; |
| 761 } |
| 762 |
| 763 if (this.parentNode && !this._markers.has(name)) { |
| 764 for (var node = this; node; node = node.parentNode) |
| 765 ++node._subtreeMarkerCount; |
| 766 } |
| 767 this._markers.set(name, value); |
| 768 for (var node = this; node; node = node.parentNode) |
| 769 this._domModel.dispatchEventToListeners(WebInspector.DOMModel.Events.Marke
rsChanged, node); |
| 770 } |
| 771 |
| 772 /** |
| 773 * @param {string} name |
| 774 * @return {?T} |
| 775 * @template T |
| 776 */ |
| 777 marker(name) { |
| 778 return this._markers.get(name) || null; |
| 779 } |
| 780 |
| 781 /** |
| 782 * @param {function(!WebInspector.DOMNode, string)} visitor |
| 783 */ |
| 784 traverseMarkers(visitor) { |
| 785 /** |
| 786 * @param {!WebInspector.DOMNode} node |
| 787 */ |
| 788 function traverse(node) { |
| 789 if (!node._subtreeMarkerCount) |
| 790 return; |
| 791 for (var marker of node._markers.keys()) |
| 792 visitor(node, marker); |
| 793 if (!node._children) |
| 794 return; |
| 795 for (var child of node._children) |
| 796 traverse(child); |
| 797 } |
| 798 traverse(this); |
| 799 } |
| 800 |
| 801 /** |
| 802 * @param {string} url |
| 803 * @return {?string} |
| 804 */ |
| 805 resolveURL(url) { |
| 806 if (!url) |
| 807 return url; |
| 808 for (var frameOwnerCandidate = this; frameOwnerCandidate; frameOwnerCandidat
e = frameOwnerCandidate.parentNode) { |
| 809 if (frameOwnerCandidate.baseURL) |
| 810 return WebInspector.ParsedURL.completeURL(frameOwnerCandidate.baseURL, u
rl); |
| 811 } |
| 812 return null; |
| 813 } |
| 814 |
| 815 /** |
| 816 * @param {string=} mode |
| 817 * @param {!RuntimeAgent.RemoteObjectId=} objectId |
| 818 */ |
| 819 highlight(mode, objectId) { |
| 820 this._domModel.highlightDOMNode(this.id, mode, undefined, objectId); |
| 821 } |
| 822 |
| 823 highlightForTwoSeconds() { |
| 824 this._domModel.highlightDOMNodeForTwoSeconds(this.id); |
| 825 } |
| 826 |
| 827 /** |
| 828 * @param {string=} objectGroup |
| 829 * @param {function(?WebInspector.RemoteObject)=} callback |
| 830 */ |
| 831 resolveToObject(objectGroup, callback) { |
| 832 this._agent.resolveNode(this.id, objectGroup, mycallback.bind(this)); |
| 833 |
| 834 /** |
| 835 * @param {?Protocol.Error} error |
| 836 * @param {!RuntimeAgent.RemoteObject} object |
| 837 * @this {WebInspector.DOMNode} |
| 838 */ |
| 839 function mycallback(error, object) { |
| 840 if (!callback) |
| 841 return; |
| 842 |
| 843 if (error || !object) |
| 844 callback(null); |
| 845 else |
| 846 callback(this.target().runtimeModel.createRemoteObject(object)); |
| 847 } |
| 848 } |
| 849 |
| 850 /** |
| 851 * @param {string=} objectGroup |
| 852 * @return {!Promise<!WebInspector.RemoteObject>} |
| 853 */ |
| 854 resolveToObjectPromise(objectGroup) { |
| 855 return new Promise(resolveToObject.bind(this)); |
| 856 /** |
| 857 * @param {function(?)} fulfill |
| 858 * @param {function(*)} reject |
| 859 * @this {WebInspector.DOMNode} |
| 860 */ |
| 861 function resolveToObject(fulfill, reject) { |
| 862 this.resolveToObject(objectGroup, mycallback); |
| 863 function mycallback(object) { |
| 864 if (object) |
| 865 fulfill(object); |
| 866 else |
| 867 reject(null); |
| 868 } |
| 869 } |
| 870 } |
| 871 |
| 872 /** |
| 873 * @param {function(?DOMAgent.BoxModel)} callback |
| 874 */ |
| 875 boxModel(callback) { |
| 876 this._agent.getBoxModel(this.id, this._domModel._wrapClientCallback(callback
)); |
| 877 } |
| 878 |
| 879 setAsInspectedNode() { |
| 880 var node = this; |
| 881 while (true) { |
| 882 var ancestor = node.ancestorUserAgentShadowRoot(); |
| 883 if (!ancestor) |
| 884 break; |
| 885 ancestor = node.ancestorShadowHost(); |
| 886 if (!ancestor) |
| 887 break; |
| 888 // User agent shadow root, keep climbing up. |
| 889 node = ancestor; |
| 890 } |
| 891 this._agent.setInspectedNode(node.id); |
| 892 } |
| 893 |
| 894 /** |
| 895 * @return {?WebInspector.DOMNode} |
| 896 */ |
| 897 enclosingElementOrSelf() { |
| 898 var node = this; |
| 899 if (node && node.nodeType() === Node.TEXT_NODE && node.parentNode) |
| 900 node = node.parentNode; |
| 901 |
| 902 if (node && node.nodeType() !== Node.ELEMENT_NODE) |
| 903 node = null; |
| 904 return node; |
| 905 } |
| 906 }; |
56 | 907 |
57 /** | 908 /** |
58 * @enum {string} | 909 * @enum {string} |
59 */ | 910 */ |
60 WebInspector.DOMNode.PseudoElementNames = { | 911 WebInspector.DOMNode.PseudoElementNames = { |
61 Before: "before", | 912 Before: 'before', |
62 After: "after" | 913 After: 'after' |
63 }; | 914 }; |
64 | 915 |
65 /** | 916 /** |
66 * @enum {string} | 917 * @enum {string} |
67 */ | 918 */ |
68 WebInspector.DOMNode.ShadowRootTypes = { | 919 WebInspector.DOMNode.ShadowRootTypes = { |
69 UserAgent: "user-agent", | 920 UserAgent: 'user-agent', |
70 Open: "open", | 921 Open: 'open', |
71 Closed: "closed" | 922 Closed: 'closed' |
72 }; | 923 }; |
73 | 924 |
74 /** @typedef {{name: string, value: string, _node: WebInspector.DOMNode}} */ | 925 /** @typedef {{name: string, value: string, _node: WebInspector.DOMNode}} */ |
75 WebInspector.DOMNode.Attribute; | 926 WebInspector.DOMNode.Attribute; |
76 | 927 |
77 WebInspector.DOMNode.prototype = { | |
78 /** | |
79 * @param {?WebInspector.DOMDocument} doc | |
80 * @param {boolean} isInShadowTree | |
81 * @param {!DOMAgent.Node} payload | |
82 */ | |
83 _init: function(doc, isInShadowTree, payload) | |
84 { | |
85 this._agent = this._domModel._agent; | |
86 this.ownerDocument = doc; | |
87 this._isInShadowTree = isInShadowTree; | |
88 | |
89 this.id = payload.nodeId; | |
90 this._domModel._idToDOMNode[this.id] = this; | |
91 this._nodeType = payload.nodeType; | |
92 this._nodeName = payload.nodeName; | |
93 this._localName = payload.localName; | |
94 this._nodeValue = payload.nodeValue; | |
95 this._pseudoType = payload.pseudoType; | |
96 this._shadowRootType = payload.shadowRootType; | |
97 this._frameOwnerFrameId = payload.frameId || null; | |
98 this._xmlVersion = payload.xmlVersion; | |
99 | |
100 this._shadowRoots = []; | |
101 | |
102 this._attributes = []; | |
103 this._attributesMap = {}; | |
104 if (payload.attributes) | |
105 this._setAttributesPayload(payload.attributes); | |
106 | |
107 /** @type {!Map<string, ?>} */ | |
108 this._markers = new Map(); | |
109 this._subtreeMarkerCount = 0; | |
110 | |
111 this._childNodeCount = payload.childNodeCount || 0; | |
112 this._children = null; | |
113 | |
114 this.nextSibling = null; | |
115 this.previousSibling = null; | |
116 this.firstChild = null; | |
117 this.lastChild = null; | |
118 this.parentNode = null; | |
119 | |
120 if (payload.shadowRoots) { | |
121 for (var i = 0; i < payload.shadowRoots.length; ++i) { | |
122 var root = payload.shadowRoots[i]; | |
123 var node = WebInspector.DOMNode.create(this._domModel, this.owne
rDocument, true, root); | |
124 this._shadowRoots.push(node); | |
125 node.parentNode = this; | |
126 } | |
127 } | |
128 | |
129 if (payload.templateContent) { | |
130 this._templateContent = WebInspector.DOMNode.create(this._domModel,
this.ownerDocument, true, payload.templateContent); | |
131 this._templateContent.parentNode = this; | |
132 } | |
133 | |
134 if (payload.importedDocument) { | |
135 this._importedDocument = WebInspector.DOMNode.create(this._domModel,
this.ownerDocument, true, payload.importedDocument); | |
136 this._importedDocument.parentNode = this; | |
137 } | |
138 | |
139 if (payload.distributedNodes) | |
140 this._setDistributedNodePayloads(payload.distributedNodes); | |
141 | |
142 if (payload.children) | |
143 this._setChildrenPayload(payload.children); | |
144 | |
145 this._setPseudoElements(payload.pseudoElements); | |
146 | |
147 if (payload.contentDocument) { | |
148 this._contentDocument = new WebInspector.DOMDocument(this._domModel,
payload.contentDocument); | |
149 this._children = [this._contentDocument]; | |
150 this._renumber(); | |
151 } | |
152 | |
153 if (this._nodeType === Node.ELEMENT_NODE) { | |
154 // HTML and BODY from internal iframes should not overwrite top-leve
l ones. | |
155 if (this.ownerDocument && !this.ownerDocument.documentElement && thi
s._nodeName === "HTML") | |
156 this.ownerDocument.documentElement = this; | |
157 if (this.ownerDocument && !this.ownerDocument.body && this._nodeName
=== "BODY") | |
158 this.ownerDocument.body = this; | |
159 } else if (this._nodeType === Node.DOCUMENT_TYPE_NODE) { | |
160 this.publicId = payload.publicId; | |
161 this.systemId = payload.systemId; | |
162 this.internalSubset = payload.internalSubset; | |
163 } else if (this._nodeType === Node.ATTRIBUTE_NODE) { | |
164 this.name = payload.name; | |
165 this.value = payload.value; | |
166 } | |
167 }, | |
168 | |
169 /** | |
170 * @return {!WebInspector.DOMModel} | |
171 */ | |
172 domModel: function() | |
173 { | |
174 return this._domModel; | |
175 }, | |
176 | |
177 /** | |
178 * @return {?Array.<!WebInspector.DOMNode>} | |
179 */ | |
180 children: function() | |
181 { | |
182 return this._children ? this._children.slice() : null; | |
183 }, | |
184 | |
185 /** | |
186 * @return {boolean} | |
187 */ | |
188 hasAttributes: function() | |
189 { | |
190 return this._attributes.length > 0; | |
191 }, | |
192 | |
193 /** | |
194 * @return {number} | |
195 */ | |
196 childNodeCount: function() | |
197 { | |
198 return this._childNodeCount; | |
199 }, | |
200 | |
201 /** | |
202 * @return {boolean} | |
203 */ | |
204 hasShadowRoots: function() | |
205 { | |
206 return !!this._shadowRoots.length; | |
207 }, | |
208 | |
209 /** | |
210 * @return {!Array.<!WebInspector.DOMNode>} | |
211 */ | |
212 shadowRoots: function() | |
213 { | |
214 return this._shadowRoots.slice(); | |
215 }, | |
216 | |
217 /** | |
218 * @return {?WebInspector.DOMNode} | |
219 */ | |
220 templateContent: function() | |
221 { | |
222 return this._templateContent || null; | |
223 }, | |
224 | |
225 /** | |
226 * @return {?WebInspector.DOMNode} | |
227 */ | |
228 importedDocument: function() | |
229 { | |
230 return this._importedDocument || null; | |
231 }, | |
232 | |
233 /** | |
234 * @return {number} | |
235 */ | |
236 nodeType: function() | |
237 { | |
238 return this._nodeType; | |
239 }, | |
240 | |
241 /** | |
242 * @return {string} | |
243 */ | |
244 nodeName: function() | |
245 { | |
246 return this._nodeName; | |
247 }, | |
248 | |
249 /** | |
250 * @return {string|undefined} | |
251 */ | |
252 pseudoType: function() | |
253 { | |
254 return this._pseudoType; | |
255 }, | |
256 | |
257 /** | |
258 * @return {boolean} | |
259 */ | |
260 hasPseudoElements: function() | |
261 { | |
262 return this._pseudoElements.size > 0; | |
263 }, | |
264 | |
265 /** | |
266 * @return {!Map<string, !WebInspector.DOMNode>} | |
267 */ | |
268 pseudoElements: function() | |
269 { | |
270 return this._pseudoElements; | |
271 }, | |
272 | |
273 /** | |
274 * @return {?WebInspector.DOMNode} | |
275 */ | |
276 beforePseudoElement: function() | |
277 { | |
278 if (!this._pseudoElements) | |
279 return null; | |
280 return this._pseudoElements.get(WebInspector.DOMNode.PseudoElementNames.
Before); | |
281 }, | |
282 | |
283 /** | |
284 * @return {?WebInspector.DOMNode} | |
285 */ | |
286 afterPseudoElement: function() | |
287 { | |
288 if (!this._pseudoElements) | |
289 return null; | |
290 return this._pseudoElements.get(WebInspector.DOMNode.PseudoElementNames.
After); | |
291 }, | |
292 | |
293 /** | |
294 * @return {boolean} | |
295 */ | |
296 isInsertionPoint: function() | |
297 { | |
298 return !this.isXMLNode() && (this._nodeName === "SHADOW" || this._nodeNa
me === "CONTENT" || this._nodeName === "SLOT"); | |
299 }, | |
300 | |
301 /** | |
302 * @return {!Array.<!WebInspector.DOMNodeShortcut>} | |
303 */ | |
304 distributedNodes: function() | |
305 { | |
306 return this._distributedNodes || []; | |
307 }, | |
308 | |
309 /** | |
310 * @return {boolean} | |
311 */ | |
312 isInShadowTree: function() | |
313 { | |
314 return this._isInShadowTree; | |
315 }, | |
316 | |
317 /** | |
318 * @return {?WebInspector.DOMNode} | |
319 */ | |
320 ancestorShadowHost: function() | |
321 { | |
322 var ancestorShadowRoot = this.ancestorShadowRoot(); | |
323 return ancestorShadowRoot ? ancestorShadowRoot.parentNode : null; | |
324 }, | |
325 | |
326 /** | |
327 * @return {?WebInspector.DOMNode} | |
328 */ | |
329 ancestorShadowRoot: function() | |
330 { | |
331 if (!this._isInShadowTree) | |
332 return null; | |
333 | |
334 var current = this; | |
335 while (current && !current.isShadowRoot()) | |
336 current = current.parentNode; | |
337 return current; | |
338 }, | |
339 | |
340 /** | |
341 * @return {?WebInspector.DOMNode} | |
342 */ | |
343 ancestorUserAgentShadowRoot: function() | |
344 { | |
345 var ancestorShadowRoot = this.ancestorShadowRoot(); | |
346 if (!ancestorShadowRoot) | |
347 return null; | |
348 return ancestorShadowRoot.shadowRootType() === WebInspector.DOMNode.Shad
owRootTypes.UserAgent ? ancestorShadowRoot : null; | |
349 }, | |
350 | |
351 /** | |
352 * @return {boolean} | |
353 */ | |
354 isShadowRoot: function() | |
355 { | |
356 return !!this._shadowRootType; | |
357 }, | |
358 | |
359 /** | |
360 * @return {?string} | |
361 */ | |
362 shadowRootType: function() | |
363 { | |
364 return this._shadowRootType || null; | |
365 }, | |
366 | |
367 /** | |
368 * @return {string} | |
369 */ | |
370 nodeNameInCorrectCase: function() | |
371 { | |
372 var shadowRootType = this.shadowRootType(); | |
373 if (shadowRootType) | |
374 return "#shadow-root (" + shadowRootType + ")"; | |
375 | |
376 // If there is no local name, it's case sensitive | |
377 if (!this.localName()) | |
378 return this.nodeName(); | |
379 | |
380 // If the names are different lengths, there is a prefix and it's case s
ensitive | |
381 if (this.localName().length !== this.nodeName().length) | |
382 return this.nodeName(); | |
383 | |
384 // Return the localname, which will be case insensitive if its an html n
ode | |
385 return this.localName(); | |
386 }, | |
387 | |
388 /** | |
389 * @param {string} name | |
390 * @param {function(?Protocol.Error, number)=} callback | |
391 */ | |
392 setNodeName: function(name, callback) | |
393 { | |
394 this._agent.setNodeName(this.id, name, this._domModel._markRevision(this
, callback)); | |
395 }, | |
396 | |
397 /** | |
398 * @return {string} | |
399 */ | |
400 localName: function() | |
401 { | |
402 return this._localName; | |
403 }, | |
404 | |
405 /** | |
406 * @return {string} | |
407 */ | |
408 nodeValue: function() | |
409 { | |
410 return this._nodeValue; | |
411 }, | |
412 | |
413 /** | |
414 * @param {string} value | |
415 * @param {function(?Protocol.Error)=} callback | |
416 */ | |
417 setNodeValue: function(value, callback) | |
418 { | |
419 this._agent.setNodeValue(this.id, value, this._domModel._markRevision(th
is, callback)); | |
420 }, | |
421 | |
422 /** | |
423 * @param {string} name | |
424 * @return {string} | |
425 */ | |
426 getAttribute: function(name) | |
427 { | |
428 var attr = this._attributesMap[name]; | |
429 return attr ? attr.value : undefined; | |
430 }, | |
431 | |
432 /** | |
433 * @param {string} name | |
434 * @param {string} text | |
435 * @param {function(?Protocol.Error)=} callback | |
436 */ | |
437 setAttribute: function(name, text, callback) | |
438 { | |
439 this._agent.setAttributesAsText(this.id, text, name, this._domModel._mar
kRevision(this, callback)); | |
440 }, | |
441 | |
442 /** | |
443 * @param {string} name | |
444 * @param {string} value | |
445 * @param {function(?Protocol.Error)=} callback | |
446 */ | |
447 setAttributeValue: function(name, value, callback) | |
448 { | |
449 this._agent.setAttributeValue(this.id, name, value, this._domModel._mark
Revision(this, callback)); | |
450 }, | |
451 | |
452 /** | |
453 * @return {!Array<!WebInspector.DOMNode.Attribute>} | |
454 */ | |
455 attributes: function() | |
456 { | |
457 return this._attributes; | |
458 }, | |
459 | |
460 /** | |
461 * @param {string} name | |
462 * @param {function(?Protocol.Error)=} callback | |
463 */ | |
464 removeAttribute: function(name, callback) | |
465 { | |
466 /** | |
467 * @param {?Protocol.Error} error | |
468 * @this {WebInspector.DOMNode} | |
469 */ | |
470 function mycallback(error) | |
471 { | |
472 if (!error) { | |
473 delete this._attributesMap[name]; | |
474 for (var i = 0; i < this._attributes.length; ++i) { | |
475 if (this._attributes[i].name === name) { | |
476 this._attributes.splice(i, 1); | |
477 break; | |
478 } | |
479 } | |
480 } | |
481 | |
482 this._domModel._markRevision(this, callback)(error); | |
483 } | |
484 this._agent.removeAttribute(this.id, name, mycallback.bind(this)); | |
485 }, | |
486 | |
487 /** | |
488 * @param {function(?Array.<!WebInspector.DOMNode>)=} callback | |
489 */ | |
490 getChildNodes: function(callback) | |
491 { | |
492 if (this._children) { | |
493 if (callback) | |
494 callback(this.children()); | |
495 return; | |
496 } | |
497 | |
498 /** | |
499 * @this {WebInspector.DOMNode} | |
500 * @param {?Protocol.Error} error | |
501 */ | |
502 function mycallback(error) | |
503 { | |
504 if (callback) | |
505 callback(error ? null : this.children()); | |
506 } | |
507 | |
508 this._agent.requestChildNodes(this.id, undefined, mycallback.bind(this))
; | |
509 }, | |
510 | |
511 /** | |
512 * @param {number} depth | |
513 * @param {function(?Array.<!WebInspector.DOMNode>)=} callback | |
514 */ | |
515 getSubtree: function(depth, callback) | |
516 { | |
517 /** | |
518 * @this {WebInspector.DOMNode} | |
519 * @param {?Protocol.Error} error | |
520 */ | |
521 function mycallback(error) | |
522 { | |
523 if (callback) | |
524 callback(error ? null : this._children); | |
525 } | |
526 | |
527 this._agent.requestChildNodes(this.id, depth, mycallback.bind(this)); | |
528 }, | |
529 | |
530 /** | |
531 * @param {function(?Protocol.Error, string)=} callback | |
532 */ | |
533 getOuterHTML: function(callback) | |
534 { | |
535 this._agent.getOuterHTML(this.id, callback); | |
536 }, | |
537 | |
538 /** | |
539 * @param {string} html | |
540 * @param {function(?Protocol.Error)=} callback | |
541 */ | |
542 setOuterHTML: function(html, callback) | |
543 { | |
544 this._agent.setOuterHTML(this.id, html, this._domModel._markRevision(thi
s, callback)); | |
545 }, | |
546 | |
547 /** | |
548 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback | |
549 */ | |
550 removeNode: function(callback) | |
551 { | |
552 this._agent.removeNode(this.id, this._domModel._markRevision(this, callb
ack)); | |
553 }, | |
554 | |
555 /** | |
556 * @param {function(?string)=} callback | |
557 */ | |
558 copyNode: function(callback) | |
559 { | |
560 function copy(error, text) | |
561 { | |
562 if (!error) | |
563 InspectorFrontendHost.copyText(text); | |
564 if (callback) | |
565 callback(error ? null : text); | |
566 } | |
567 this._agent.getOuterHTML(this.id, copy); | |
568 }, | |
569 | |
570 /** | |
571 * @return {string} | |
572 */ | |
573 path: function() | |
574 { | |
575 /** | |
576 * @param {?WebInspector.DOMNode} node | |
577 */ | |
578 function canPush(node) | |
579 { | |
580 return node && ("index" in node || (node.isShadowRoot() && node.pare
ntNode)) && node._nodeName.length; | |
581 } | |
582 | |
583 var path = []; | |
584 var node = this; | |
585 while (canPush(node)) { | |
586 var index = typeof node.index === "number" ? node.index : (node.shad
owRootType() === WebInspector.DOMNode.ShadowRootTypes.UserAgent ? "u" : "a"); | |
587 path.push([index, node._nodeName]); | |
588 node = node.parentNode; | |
589 } | |
590 path.reverse(); | |
591 return path.join(","); | |
592 }, | |
593 | |
594 /** | |
595 * @param {!WebInspector.DOMNode} node | |
596 * @return {boolean} | |
597 */ | |
598 isAncestor: function(node) | |
599 { | |
600 if (!node) | |
601 return false; | |
602 | |
603 var currentNode = node.parentNode; | |
604 while (currentNode) { | |
605 if (this === currentNode) | |
606 return true; | |
607 currentNode = currentNode.parentNode; | |
608 } | |
609 return false; | |
610 }, | |
611 | |
612 /** | |
613 * @param {!WebInspector.DOMNode} descendant | |
614 * @return {boolean} | |
615 */ | |
616 isDescendant: function(descendant) | |
617 { | |
618 return descendant !== null && descendant.isAncestor(this); | |
619 }, | |
620 | |
621 /** | |
622 * @return {?PageAgent.FrameId} | |
623 */ | |
624 frameId: function() | |
625 { | |
626 var node = this.parentNode || this; | |
627 while (!node._frameOwnerFrameId && node.parentNode) | |
628 node = node.parentNode; | |
629 return node._frameOwnerFrameId; | |
630 }, | |
631 | |
632 /** | |
633 * @param {!Array.<string>} attrs | |
634 * @return {boolean} | |
635 */ | |
636 _setAttributesPayload: function(attrs) | |
637 { | |
638 var attributesChanged = !this._attributes || attrs.length !== this._attr
ibutes.length * 2; | |
639 var oldAttributesMap = this._attributesMap || {}; | |
640 | |
641 this._attributes = []; | |
642 this._attributesMap = {}; | |
643 | |
644 for (var i = 0; i < attrs.length; i += 2) { | |
645 var name = attrs[i]; | |
646 var value = attrs[i + 1]; | |
647 this._addAttribute(name, value); | |
648 | |
649 if (attributesChanged) | |
650 continue; | |
651 | |
652 if (!oldAttributesMap[name] || oldAttributesMap[name].value !== valu
e) | |
653 attributesChanged = true; | |
654 } | |
655 return attributesChanged; | |
656 }, | |
657 | |
658 /** | |
659 * @param {!WebInspector.DOMNode} prev | |
660 * @param {!DOMAgent.Node} payload | |
661 * @return {!WebInspector.DOMNode} | |
662 */ | |
663 _insertChild: function(prev, payload) | |
664 { | |
665 var node = WebInspector.DOMNode.create(this._domModel, this.ownerDocumen
t, this._isInShadowTree, payload); | |
666 this._children.splice(this._children.indexOf(prev) + 1, 0, node); | |
667 this._renumber(); | |
668 return node; | |
669 }, | |
670 | |
671 /** | |
672 * @param {!WebInspector.DOMNode} node | |
673 */ | |
674 _removeChild: function(node) | |
675 { | |
676 if (node.pseudoType()) { | |
677 this._pseudoElements.delete(node.pseudoType()); | |
678 } else { | |
679 var shadowRootIndex = this._shadowRoots.indexOf(node); | |
680 if (shadowRootIndex !== -1) { | |
681 this._shadowRoots.splice(shadowRootIndex, 1); | |
682 } else { | |
683 console.assert(this._children.indexOf(node) !== -1); | |
684 this._children.splice(this._children.indexOf(node), 1); | |
685 } | |
686 } | |
687 node.parentNode = null; | |
688 this._subtreeMarkerCount -= node._subtreeMarkerCount; | |
689 if (node._subtreeMarkerCount) | |
690 this._domModel.dispatchEventToListeners(WebInspector.DOMModel.Events
.MarkersChanged, this); | |
691 this._renumber(); | |
692 }, | |
693 | |
694 /** | |
695 * @param {!Array.<!DOMAgent.Node>} payloads | |
696 */ | |
697 _setChildrenPayload: function(payloads) | |
698 { | |
699 // We set children in the constructor. | |
700 if (this._contentDocument) | |
701 return; | |
702 | |
703 this._children = []; | |
704 for (var i = 0; i < payloads.length; ++i) { | |
705 var payload = payloads[i]; | |
706 var node = WebInspector.DOMNode.create(this._domModel, this.ownerDoc
ument, this._isInShadowTree, payload); | |
707 this._children.push(node); | |
708 } | |
709 this._renumber(); | |
710 }, | |
711 | |
712 /** | |
713 * @param {!Array.<!DOMAgent.Node>|undefined} payloads | |
714 */ | |
715 _setPseudoElements: function(payloads) | |
716 { | |
717 this._pseudoElements = new Map(); | |
718 if (!payloads) | |
719 return; | |
720 | |
721 for (var i = 0; i < payloads.length; ++i) { | |
722 var node = WebInspector.DOMNode.create(this._domModel, this.ownerDoc
ument, this._isInShadowTree, payloads[i]); | |
723 node.parentNode = this; | |
724 this._pseudoElements.set(node.pseudoType(), node); | |
725 } | |
726 }, | |
727 | |
728 /** | |
729 * @param {!Array.<!DOMAgent.BackendNode>} payloads | |
730 */ | |
731 _setDistributedNodePayloads: function(payloads) | |
732 { | |
733 this._distributedNodes = []; | |
734 for (var payload of payloads) | |
735 this._distributedNodes.push(new WebInspector.DOMNodeShortcut(this._d
omModel.target(), payload.backendNodeId, payload.nodeType, payload.nodeName)); | |
736 }, | |
737 | |
738 _renumber: function() | |
739 { | |
740 this._childNodeCount = this._children.length; | |
741 if (this._childNodeCount === 0) { | |
742 this.firstChild = null; | |
743 this.lastChild = null; | |
744 return; | |
745 } | |
746 this.firstChild = this._children[0]; | |
747 this.lastChild = this._children[this._childNodeCount - 1]; | |
748 for (var i = 0; i < this._childNodeCount; ++i) { | |
749 var child = this._children[i]; | |
750 child.index = i; | |
751 child.nextSibling = i + 1 < this._childNodeCount ? this._children[i
+ 1] : null; | |
752 child.previousSibling = i - 1 >= 0 ? this._children[i - 1] : null; | |
753 child.parentNode = this; | |
754 } | |
755 }, | |
756 | |
757 /** | |
758 * @param {string} name | |
759 * @param {string} value | |
760 */ | |
761 _addAttribute: function(name, value) | |
762 { | |
763 var attr = { | |
764 name: name, | |
765 value: value, | |
766 _node: this | |
767 }; | |
768 this._attributesMap[name] = attr; | |
769 this._attributes.push(attr); | |
770 }, | |
771 | |
772 /** | |
773 * @param {string} name | |
774 * @param {string} value | |
775 */ | |
776 _setAttribute: function(name, value) | |
777 { | |
778 var attr = this._attributesMap[name]; | |
779 if (attr) | |
780 attr.value = value; | |
781 else | |
782 this._addAttribute(name, value); | |
783 }, | |
784 | |
785 /** | |
786 * @param {string} name | |
787 */ | |
788 _removeAttribute: function(name) | |
789 { | |
790 var attr = this._attributesMap[name]; | |
791 if (attr) { | |
792 this._attributes.remove(attr); | |
793 delete this._attributesMap[name]; | |
794 } | |
795 }, | |
796 | |
797 /** | |
798 * @param {!WebInspector.DOMNode} targetNode | |
799 * @param {?WebInspector.DOMNode} anchorNode | |
800 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback | |
801 */ | |
802 copyTo: function(targetNode, anchorNode, callback) | |
803 { | |
804 this._agent.copyTo(this.id, targetNode.id, anchorNode ? anchorNode.id :
undefined, this._domModel._markRevision(this, callback)); | |
805 }, | |
806 | |
807 /** | |
808 * @param {!WebInspector.DOMNode} targetNode | |
809 * @param {?WebInspector.DOMNode} anchorNode | |
810 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback | |
811 */ | |
812 moveTo: function(targetNode, anchorNode, callback) | |
813 { | |
814 this._agent.moveTo(this.id, targetNode.id, anchorNode ? anchorNode.id :
undefined, this._domModel._markRevision(this, callback)); | |
815 }, | |
816 | |
817 /** | |
818 * @return {boolean} | |
819 */ | |
820 isXMLNode: function() | |
821 { | |
822 return !!this._xmlVersion; | |
823 }, | |
824 | |
825 /** | |
826 * @param {string} name | |
827 * @param {?*} value | |
828 */ | |
829 setMarker: function(name, value) | |
830 { | |
831 if (value === null) { | |
832 if (!this._markers.has(name)) | |
833 return; | |
834 | |
835 this._markers.delete(name); | |
836 for (var node = this; node; node = node.parentNode) | |
837 --node._subtreeMarkerCount; | |
838 for (var node = this; node; node = node.parentNode) | |
839 this._domModel.dispatchEventToListeners(WebInspector.DOMModel.Ev
ents.MarkersChanged, node); | |
840 return; | |
841 } | |
842 | |
843 if (this.parentNode && !this._markers.has(name)) { | |
844 for (var node = this; node; node = node.parentNode) | |
845 ++node._subtreeMarkerCount; | |
846 } | |
847 this._markers.set(name, value); | |
848 for (var node = this; node; node = node.parentNode) | |
849 this._domModel.dispatchEventToListeners(WebInspector.DOMModel.Events
.MarkersChanged, node); | |
850 }, | |
851 | |
852 /** | |
853 * @param {string} name | |
854 * @return {?T} | |
855 * @template T | |
856 */ | |
857 marker: function(name) | |
858 { | |
859 return this._markers.get(name) || null; | |
860 }, | |
861 | |
862 /** | |
863 * @param {function(!WebInspector.DOMNode, string)} visitor | |
864 */ | |
865 traverseMarkers: function(visitor) | |
866 { | |
867 /** | |
868 * @param {!WebInspector.DOMNode} node | |
869 */ | |
870 function traverse(node) | |
871 { | |
872 if (!node._subtreeMarkerCount) | |
873 return; | |
874 for (var marker of node._markers.keys()) | |
875 visitor(node, marker); | |
876 if (!node._children) | |
877 return; | |
878 for (var child of node._children) | |
879 traverse(child); | |
880 } | |
881 traverse(this); | |
882 }, | |
883 | |
884 /** | |
885 * @param {string} url | |
886 * @return {?string} | |
887 */ | |
888 resolveURL: function(url) | |
889 { | |
890 if (!url) | |
891 return url; | |
892 for (var frameOwnerCandidate = this; frameOwnerCandidate; frameOwnerCand
idate = frameOwnerCandidate.parentNode) { | |
893 if (frameOwnerCandidate.baseURL) | |
894 return WebInspector.ParsedURL.completeURL(frameOwnerCandidate.ba
seURL, url); | |
895 } | |
896 return null; | |
897 }, | |
898 | |
899 /** | |
900 * @param {string=} mode | |
901 * @param {!RuntimeAgent.RemoteObjectId=} objectId | |
902 */ | |
903 highlight: function(mode, objectId) | |
904 { | |
905 this._domModel.highlightDOMNode(this.id, mode, undefined, objectId); | |
906 }, | |
907 | |
908 highlightForTwoSeconds: function() | |
909 { | |
910 this._domModel.highlightDOMNodeForTwoSeconds(this.id); | |
911 }, | |
912 | |
913 /** | |
914 * @param {string=} objectGroup | |
915 * @param {function(?WebInspector.RemoteObject)=} callback | |
916 */ | |
917 resolveToObject: function(objectGroup, callback) | |
918 { | |
919 this._agent.resolveNode(this.id, objectGroup, mycallback.bind(this)); | |
920 | |
921 /** | |
922 * @param {?Protocol.Error} error | |
923 * @param {!RuntimeAgent.RemoteObject} object | |
924 * @this {WebInspector.DOMNode} | |
925 */ | |
926 function mycallback(error, object) | |
927 { | |
928 if (!callback) | |
929 return; | |
930 | |
931 if (error || !object) | |
932 callback(null); | |
933 else | |
934 callback(this.target().runtimeModel.createRemoteObject(object)); | |
935 } | |
936 }, | |
937 | |
938 /** | |
939 * @param {string=} objectGroup | |
940 * @return {!Promise<!WebInspector.RemoteObject>} | |
941 */ | |
942 resolveToObjectPromise: function(objectGroup) | |
943 { | |
944 return new Promise(resolveToObject.bind(this)); | |
945 /** | |
946 * @param {function(?)} fulfill | |
947 * @param {function(*)} reject | |
948 * @this {WebInspector.DOMNode} | |
949 */ | |
950 function resolveToObject(fulfill, reject) | |
951 { | |
952 this.resolveToObject(objectGroup, mycallback); | |
953 function mycallback(object) | |
954 { | |
955 if (object) | |
956 fulfill(object); | |
957 else | |
958 reject(null); | |
959 } | |
960 } | |
961 }, | |
962 | |
963 /** | |
964 * @param {function(?DOMAgent.BoxModel)} callback | |
965 */ | |
966 boxModel: function(callback) | |
967 { | |
968 this._agent.getBoxModel(this.id, this._domModel._wrapClientCallback(call
back)); | |
969 }, | |
970 | |
971 setAsInspectedNode: function() | |
972 { | |
973 var node = this; | |
974 while (true) { | |
975 var ancestor = node.ancestorUserAgentShadowRoot(); | |
976 if (!ancestor) | |
977 break; | |
978 ancestor = node.ancestorShadowHost(); | |
979 if (!ancestor) | |
980 break; | |
981 // User agent shadow root, keep climbing up. | |
982 node = ancestor; | |
983 } | |
984 this._agent.setInspectedNode(node.id); | |
985 }, | |
986 | |
987 /** | |
988 * @return {?WebInspector.DOMNode} | |
989 */ | |
990 enclosingElementOrSelf: function() | |
991 { | |
992 var node = this; | |
993 if (node && node.nodeType() === Node.TEXT_NODE && node.parentNode) | |
994 node = node.parentNode; | |
995 | |
996 if (node && node.nodeType() !== Node.ELEMENT_NODE) | |
997 node = null; | |
998 return node; | |
999 }, | |
1000 | |
1001 __proto__: WebInspector.SDKObject.prototype | |
1002 }; | |
1003 | |
1004 /** | 928 /** |
1005 * @param {!WebInspector.Target} target | 929 * @unrestricted |
1006 * @param {number} backendNodeId | |
1007 * @constructor | |
1008 */ | 930 */ |
1009 WebInspector.DeferredDOMNode = function(target, backendNodeId) | 931 WebInspector.DeferredDOMNode = class { |
1010 { | 932 /** |
| 933 * @param {!WebInspector.Target} target |
| 934 * @param {number} backendNodeId |
| 935 */ |
| 936 constructor(target, backendNodeId) { |
1011 this._domModel = WebInspector.DOMModel.fromTarget(target); | 937 this._domModel = WebInspector.DOMModel.fromTarget(target); |
1012 this._backendNodeId = backendNodeId; | 938 this._backendNodeId = backendNodeId; |
| 939 } |
| 940 |
| 941 /** |
| 942 * @param {function(?WebInspector.DOMNode)} callback |
| 943 */ |
| 944 resolve(callback) { |
| 945 if (!this._domModel) { |
| 946 callback(null); |
| 947 return; |
| 948 } |
| 949 |
| 950 this._domModel.pushNodesByBackendIdsToFrontend(new Set([this._backendNodeId]
), onGotNode.bind(this)); |
| 951 |
| 952 /** |
| 953 * @param {?Map<number, ?WebInspector.DOMNode>} nodeIds |
| 954 * @this {WebInspector.DeferredDOMNode} |
| 955 */ |
| 956 function onGotNode(nodeIds) { |
| 957 callback(nodeIds && (nodeIds.get(this._backendNodeId) || null)); |
| 958 } |
| 959 } |
| 960 |
| 961 /** |
| 962 * @return {!Promise.<!WebInspector.DOMNode>} |
| 963 */ |
| 964 resolvePromise() { |
| 965 /** |
| 966 * @param {function(?)} fulfill |
| 967 * @param {function(*)} reject |
| 968 * @this {WebInspector.DeferredDOMNode} |
| 969 */ |
| 970 function resolveNode(fulfill, reject) { |
| 971 /** |
| 972 * @param {?WebInspector.DOMNode} node |
| 973 */ |
| 974 function mycallback(node) { |
| 975 fulfill(node); |
| 976 } |
| 977 this.resolve(mycallback); |
| 978 } |
| 979 return new Promise(resolveNode.bind(this)); |
| 980 } |
| 981 |
| 982 /** |
| 983 * @return {number} |
| 984 */ |
| 985 backendNodeId() { |
| 986 return this._backendNodeId; |
| 987 } |
| 988 |
| 989 highlight() { |
| 990 if (this._domModel) |
| 991 this._domModel.highlightDOMNode(undefined, undefined, this._backendNodeId)
; |
| 992 } |
1013 }; | 993 }; |
1014 | 994 |
1015 WebInspector.DeferredDOMNode.prototype = { | |
1016 /** | |
1017 * @param {function(?WebInspector.DOMNode)} callback | |
1018 */ | |
1019 resolve: function(callback) | |
1020 { | |
1021 if (!this._domModel) { | |
1022 callback(null); | |
1023 return; | |
1024 } | |
1025 | |
1026 this._domModel.pushNodesByBackendIdsToFrontend(new Set([this._backendNod
eId]), onGotNode.bind(this)); | |
1027 | |
1028 /** | |
1029 * @param {?Map<number, ?WebInspector.DOMNode>} nodeIds | |
1030 * @this {WebInspector.DeferredDOMNode} | |
1031 */ | |
1032 function onGotNode(nodeIds) | |
1033 { | |
1034 callback(nodeIds && (nodeIds.get(this._backendNodeId) || null)); | |
1035 } | |
1036 }, | |
1037 | |
1038 /** | |
1039 * @return {!Promise.<!WebInspector.DOMNode>} | |
1040 */ | |
1041 resolvePromise: function() | |
1042 { | |
1043 /** | |
1044 * @param {function(?)} fulfill | |
1045 * @param {function(*)} reject | |
1046 * @this {WebInspector.DeferredDOMNode} | |
1047 */ | |
1048 function resolveNode(fulfill, reject) | |
1049 { | |
1050 /** | |
1051 * @param {?WebInspector.DOMNode} node | |
1052 */ | |
1053 function mycallback(node) | |
1054 { | |
1055 fulfill(node); | |
1056 } | |
1057 this.resolve(mycallback); | |
1058 } | |
1059 return new Promise(resolveNode.bind(this)); | |
1060 }, | |
1061 | |
1062 /** | |
1063 * @return {number} | |
1064 */ | |
1065 backendNodeId: function() | |
1066 { | |
1067 return this._backendNodeId; | |
1068 }, | |
1069 | |
1070 highlight: function() | |
1071 { | |
1072 if (this._domModel) | |
1073 this._domModel.highlightDOMNode(undefined, undefined, this._backendN
odeId); | |
1074 } | |
1075 }; | |
1076 | |
1077 /** | 995 /** |
1078 * @constructor | 996 * @unrestricted |
1079 * @param {!WebInspector.Target} target | |
1080 * @param {number} backendNodeId | |
1081 * @param {number} nodeType | |
1082 * @param {string} nodeName | |
1083 */ | 997 */ |
1084 WebInspector.DOMNodeShortcut = function(target, backendNodeId, nodeType, nodeNam
e) | 998 WebInspector.DOMNodeShortcut = class { |
1085 { | 999 /** |
| 1000 * @param {!WebInspector.Target} target |
| 1001 * @param {number} backendNodeId |
| 1002 * @param {number} nodeType |
| 1003 * @param {string} nodeName |
| 1004 */ |
| 1005 constructor(target, backendNodeId, nodeType, nodeName) { |
1086 this.nodeType = nodeType; | 1006 this.nodeType = nodeType; |
1087 this.nodeName = nodeName; | 1007 this.nodeName = nodeName; |
1088 this.deferredNode = new WebInspector.DeferredDOMNode(target, backendNodeId); | 1008 this.deferredNode = new WebInspector.DeferredDOMNode(target, backendNodeId); |
| 1009 } |
1089 }; | 1010 }; |
1090 | 1011 |
1091 /** | 1012 /** |
1092 * @extends {WebInspector.DOMNode} | 1013 * @unrestricted |
1093 * @constructor | |
1094 * @param {!WebInspector.DOMModel} domModel | |
1095 * @param {!DOMAgent.Node} payload | |
1096 */ | 1014 */ |
1097 WebInspector.DOMDocument = function(domModel, payload) | 1015 WebInspector.DOMDocument = class extends WebInspector.DOMNode { |
1098 { | 1016 /** |
1099 WebInspector.DOMNode.call(this, domModel); | 1017 * @param {!WebInspector.DOMModel} domModel |
| 1018 * @param {!DOMAgent.Node} payload |
| 1019 */ |
| 1020 constructor(domModel, payload) { |
| 1021 super(domModel); |
1100 this._init(this, false, payload); | 1022 this._init(this, false, payload); |
1101 this.documentURL = payload.documentURL || ""; | 1023 this.documentURL = payload.documentURL || ''; |
1102 this.baseURL = payload.baseURL || ""; | 1024 this.baseURL = payload.baseURL || ''; |
1103 this._listeners = {}; | 1025 this._listeners = {}; |
| 1026 } |
1104 }; | 1027 }; |
1105 | 1028 |
1106 WebInspector.DOMDocument.prototype = { | |
1107 __proto__: WebInspector.DOMNode.prototype | |
1108 }; | |
1109 | |
1110 /** | 1029 /** |
1111 * @constructor | 1030 * @unrestricted |
1112 * @extends {WebInspector.SDKModel} | |
1113 * @param {!WebInspector.Target} target | |
1114 */ | 1031 */ |
1115 WebInspector.DOMModel = function(target) { | 1032 WebInspector.DOMModel = class extends WebInspector.SDKModel { |
1116 WebInspector.SDKModel.call(this, WebInspector.DOMModel, target); | 1033 /** |
| 1034 * @param {!WebInspector.Target} target |
| 1035 */ |
| 1036 constructor(target) { |
| 1037 super(WebInspector.DOMModel, target); |
1117 | 1038 |
1118 this._agent = target.domAgent(); | 1039 this._agent = target.domAgent(); |
1119 | 1040 |
1120 /** @type {!Object.<number, !WebInspector.DOMNode>} */ | 1041 /** @type {!Object.<number, !WebInspector.DOMNode>} */ |
1121 this._idToDOMNode = {}; | 1042 this._idToDOMNode = {}; |
1122 /** @type {?WebInspector.DOMDocument} */ | 1043 /** @type {?WebInspector.DOMDocument} */ |
1123 this._document = null; | 1044 this._document = null; |
1124 /** @type {!Object.<number, boolean>} */ | 1045 /** @type {!Object.<number, boolean>} */ |
1125 this._attributeLoadNodeIds = {}; | 1046 this._attributeLoadNodeIds = {}; |
1126 target.registerDOMDispatcher(new WebInspector.DOMDispatcher(this)); | 1047 target.registerDOMDispatcher(new WebInspector.DOMDispatcher(this)); |
1127 | 1048 |
1128 this._inspectModeEnabled = false; | 1049 this._inspectModeEnabled = false; |
1129 | 1050 |
1130 this._defaultHighlighter = new WebInspector.DefaultDOMNodeHighlighter(this._
agent); | 1051 this._defaultHighlighter = new WebInspector.DefaultDOMNodeHighlighter(this._
agent); |
1131 this._highlighter = this._defaultHighlighter; | 1052 this._highlighter = this._defaultHighlighter; |
1132 | 1053 |
1133 this._agent.enable(); | 1054 this._agent.enable(); |
| 1055 } |
| 1056 |
| 1057 /** |
| 1058 * @param {!WebInspector.RemoteObject} object |
| 1059 */ |
| 1060 static highlightObjectAsDOMNode(object) { |
| 1061 var domModel = WebInspector.DOMModel.fromTarget(object.target()); |
| 1062 if (domModel) |
| 1063 domModel.highlightDOMNode(undefined, undefined, undefined, object.objectId
); |
| 1064 } |
| 1065 |
| 1066 /** |
| 1067 * @return {!Array<!WebInspector.DOMModel>} |
| 1068 */ |
| 1069 static instances() { |
| 1070 var result = []; |
| 1071 for (var target of WebInspector.targetManager.targets()) { |
| 1072 var domModel = WebInspector.DOMModel.fromTarget(target); |
| 1073 if (domModel) |
| 1074 result.push(domModel); |
| 1075 } |
| 1076 return result; |
| 1077 } |
| 1078 |
| 1079 static hideDOMNodeHighlight() { |
| 1080 for (var domModel of WebInspector.DOMModel.instances()) |
| 1081 domModel.highlightDOMNode(0); |
| 1082 } |
| 1083 |
| 1084 static muteHighlight() { |
| 1085 WebInspector.DOMModel.hideDOMNodeHighlight(); |
| 1086 WebInspector.DOMModel._highlightDisabled = true; |
| 1087 } |
| 1088 |
| 1089 static unmuteHighlight() { |
| 1090 WebInspector.DOMModel._highlightDisabled = false; |
| 1091 } |
| 1092 |
| 1093 static cancelSearch() { |
| 1094 for (var domModel of WebInspector.DOMModel.instances()) |
| 1095 domModel._cancelSearch(); |
| 1096 } |
| 1097 |
| 1098 /** |
| 1099 * @param {!WebInspector.Target} target |
| 1100 * @return {?WebInspector.DOMModel} |
| 1101 */ |
| 1102 static fromTarget(target) { |
| 1103 return /** @type {?WebInspector.DOMModel} */ (target.model(WebInspector.DOMM
odel)); |
| 1104 } |
| 1105 |
| 1106 /** |
| 1107 * @param {!WebInspector.DOMNode} node |
| 1108 */ |
| 1109 _scheduleMutationEvent(node) { |
| 1110 if (!this.hasEventListeners(WebInspector.DOMModel.Events.DOMMutated)) |
| 1111 return; |
| 1112 |
| 1113 this._lastMutationId = (this._lastMutationId || 0) + 1; |
| 1114 Promise.resolve().then(callObserve.bind(this, node, this._lastMutationId)); |
| 1115 |
| 1116 /** |
| 1117 * @this {WebInspector.DOMModel} |
| 1118 * @param {!WebInspector.DOMNode} node |
| 1119 * @param {number} mutationId |
| 1120 */ |
| 1121 function callObserve(node, mutationId) { |
| 1122 if (!this.hasEventListeners(WebInspector.DOMModel.Events.DOMMutated) || th
is._lastMutationId !== mutationId) |
| 1123 return; |
| 1124 |
| 1125 this.dispatchEventToListeners(WebInspector.DOMModel.Events.DOMMutated, nod
e); |
| 1126 } |
| 1127 } |
| 1128 |
| 1129 /** |
| 1130 * @param {function(!WebInspector.DOMDocument)=} callback |
| 1131 */ |
| 1132 requestDocument(callback) { |
| 1133 if (this._document) { |
| 1134 if (callback) |
| 1135 callback(this._document); |
| 1136 return; |
| 1137 } |
| 1138 |
| 1139 if (this._pendingDocumentRequestCallbacks) { |
| 1140 this._pendingDocumentRequestCallbacks.push(callback); |
| 1141 return; |
| 1142 } |
| 1143 |
| 1144 this._pendingDocumentRequestCallbacks = [callback]; |
| 1145 |
| 1146 /** |
| 1147 * @this {WebInspector.DOMModel} |
| 1148 * @param {?Protocol.Error} error |
| 1149 * @param {!DOMAgent.Node} root |
| 1150 */ |
| 1151 function onDocumentAvailable(error, root) { |
| 1152 if (!error) |
| 1153 this._setDocument(root); |
| 1154 |
| 1155 for (var i = 0; i < this._pendingDocumentRequestCallbacks.length; ++i) { |
| 1156 var callback = this._pendingDocumentRequestCallbacks[i]; |
| 1157 if (callback) |
| 1158 callback(this._document); |
| 1159 } |
| 1160 delete this._pendingDocumentRequestCallbacks; |
| 1161 } |
| 1162 |
| 1163 this._agent.getDocument(undefined, undefined, onDocumentAvailable.bind(this)
); |
| 1164 } |
| 1165 |
| 1166 /** |
| 1167 * @return {?WebInspector.DOMDocument} |
| 1168 */ |
| 1169 existingDocument() { |
| 1170 return this._document; |
| 1171 } |
| 1172 |
| 1173 /** |
| 1174 * @param {!RuntimeAgent.RemoteObjectId} objectId |
| 1175 * @param {function(?WebInspector.DOMNode)=} callback |
| 1176 */ |
| 1177 pushNodeToFrontend(objectId, callback) { |
| 1178 /** |
| 1179 * @param {?DOMAgent.NodeId} nodeId |
| 1180 * @this {!WebInspector.DOMModel} |
| 1181 */ |
| 1182 function mycallback(nodeId) { |
| 1183 callback(nodeId ? this.nodeForId(nodeId) : null); |
| 1184 } |
| 1185 this._dispatchWhenDocumentAvailable(this._agent.requestNode.bind(this._agent
, objectId), mycallback.bind(this)); |
| 1186 } |
| 1187 |
| 1188 /** |
| 1189 * @param {string} path |
| 1190 * @param {function(?number)=} callback |
| 1191 */ |
| 1192 pushNodeByPathToFrontend(path, callback) { |
| 1193 this._dispatchWhenDocumentAvailable(this._agent.pushNodeByPathToFrontend.bin
d(this._agent, path), callback); |
| 1194 } |
| 1195 |
| 1196 /** |
| 1197 * @param {!Set<number>} backendNodeIds |
| 1198 * @param {function(?Map<number, ?WebInspector.DOMNode>)} callback |
| 1199 */ |
| 1200 pushNodesByBackendIdsToFrontend(backendNodeIds, callback) { |
| 1201 var backendNodeIdsArray = backendNodeIds.valuesArray(); |
| 1202 /** |
| 1203 * @param {?Array<!DOMAgent.NodeId>} nodeIds |
| 1204 * @this {!WebInspector.DOMModel} |
| 1205 */ |
| 1206 function mycallback(nodeIds) { |
| 1207 if (!nodeIds) { |
| 1208 callback(null); |
| 1209 return; |
| 1210 } |
| 1211 /** @type {!Map<number, ?WebInspector.DOMNode>} */ |
| 1212 var map = new Map(); |
| 1213 for (var i = 0; i < nodeIds.length; ++i) { |
| 1214 if (nodeIds[i]) |
| 1215 map.set(backendNodeIdsArray[i], this.nodeForId(nodeIds[i])); |
| 1216 } |
| 1217 callback(map); |
| 1218 } |
| 1219 this._dispatchWhenDocumentAvailable( |
| 1220 this._agent.pushNodesByBackendIdsToFrontend.bind(this._agent, backendNod
eIdsArray), mycallback.bind(this)); |
| 1221 } |
| 1222 |
| 1223 /** |
| 1224 * @param {function(!T)=} callback |
| 1225 * @return {function(?Protocol.Error, !T=)|undefined} |
| 1226 * @template T |
| 1227 */ |
| 1228 _wrapClientCallback(callback) { |
| 1229 if (!callback) |
| 1230 return; |
| 1231 /** |
| 1232 * @param {?Protocol.Error} error |
| 1233 * @param {!T=} result |
| 1234 * @template T |
| 1235 */ |
| 1236 var wrapper = function(error, result) { |
| 1237 // Caller is responsible for handling the actual error. |
| 1238 callback(error ? null : result); |
| 1239 }; |
| 1240 return wrapper; |
| 1241 } |
| 1242 |
| 1243 /** |
| 1244 * @param {function(function(?Protocol.Error, !T=)=)} func |
| 1245 * @param {function(!T)=} callback |
| 1246 * @template T |
| 1247 */ |
| 1248 _dispatchWhenDocumentAvailable(func, callback) { |
| 1249 var callbackWrapper = this._wrapClientCallback(callback); |
| 1250 |
| 1251 /** |
| 1252 * @this {WebInspector.DOMModel} |
| 1253 */ |
| 1254 function onDocumentAvailable() { |
| 1255 if (this._document) |
| 1256 func(callbackWrapper); |
| 1257 else { |
| 1258 if (callbackWrapper) |
| 1259 callbackWrapper('No document'); |
| 1260 } |
| 1261 } |
| 1262 this.requestDocument(onDocumentAvailable.bind(this)); |
| 1263 } |
| 1264 |
| 1265 /** |
| 1266 * @param {!DOMAgent.NodeId} nodeId |
| 1267 * @param {string} name |
| 1268 * @param {string} value |
| 1269 */ |
| 1270 _attributeModified(nodeId, name, value) { |
| 1271 var node = this._idToDOMNode[nodeId]; |
| 1272 if (!node) |
| 1273 return; |
| 1274 |
| 1275 node._setAttribute(name, value); |
| 1276 this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrModified, {no
de: node, name: name}); |
| 1277 this._scheduleMutationEvent(node); |
| 1278 } |
| 1279 |
| 1280 /** |
| 1281 * @param {!DOMAgent.NodeId} nodeId |
| 1282 * @param {string} name |
| 1283 */ |
| 1284 _attributeRemoved(nodeId, name) { |
| 1285 var node = this._idToDOMNode[nodeId]; |
| 1286 if (!node) |
| 1287 return; |
| 1288 node._removeAttribute(name); |
| 1289 this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrRemoved, {nod
e: node, name: name}); |
| 1290 this._scheduleMutationEvent(node); |
| 1291 } |
| 1292 |
| 1293 /** |
| 1294 * @param {!Array.<!DOMAgent.NodeId>} nodeIds |
| 1295 */ |
| 1296 _inlineStyleInvalidated(nodeIds) { |
| 1297 for (var i = 0; i < nodeIds.length; ++i) |
| 1298 this._attributeLoadNodeIds[nodeIds[i]] = true; |
| 1299 if ('_loadNodeAttributesTimeout' in this) |
| 1300 return; |
| 1301 this._loadNodeAttributesTimeout = setTimeout(this._loadNodeAttributes.bind(t
his), 20); |
| 1302 } |
| 1303 |
| 1304 _loadNodeAttributes() { |
| 1305 /** |
| 1306 * @this {WebInspector.DOMModel} |
| 1307 * @param {!DOMAgent.NodeId} nodeId |
| 1308 * @param {?Protocol.Error} error |
| 1309 * @param {!Array.<string>} attributes |
| 1310 */ |
| 1311 function callback(nodeId, error, attributes) { |
| 1312 if (error) { |
| 1313 // We are calling _loadNodeAttributes asynchronously, it is ok if node i
s not found. |
| 1314 return; |
| 1315 } |
| 1316 var node = this._idToDOMNode[nodeId]; |
| 1317 if (node) { |
| 1318 if (node._setAttributesPayload(attributes)) { |
| 1319 this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrModifie
d, {node: node, name: 'style'}); |
| 1320 this._scheduleMutationEvent(node); |
| 1321 } |
| 1322 } |
| 1323 } |
| 1324 |
| 1325 delete this._loadNodeAttributesTimeout; |
| 1326 |
| 1327 for (var nodeId in this._attributeLoadNodeIds) { |
| 1328 var nodeIdAsNumber = parseInt(nodeId, 10); |
| 1329 this._agent.getAttributes(nodeIdAsNumber, callback.bind(this, nodeIdAsNumb
er)); |
| 1330 } |
| 1331 this._attributeLoadNodeIds = {}; |
| 1332 } |
| 1333 |
| 1334 /** |
| 1335 * @param {!DOMAgent.NodeId} nodeId |
| 1336 * @param {string} newValue |
| 1337 */ |
| 1338 _characterDataModified(nodeId, newValue) { |
| 1339 var node = this._idToDOMNode[nodeId]; |
| 1340 node._nodeValue = newValue; |
| 1341 this.dispatchEventToListeners(WebInspector.DOMModel.Events.CharacterDataModi
fied, node); |
| 1342 this._scheduleMutationEvent(node); |
| 1343 } |
| 1344 |
| 1345 /** |
| 1346 * @param {!DOMAgent.NodeId} nodeId |
| 1347 * @return {?WebInspector.DOMNode} |
| 1348 */ |
| 1349 nodeForId(nodeId) { |
| 1350 return this._idToDOMNode[nodeId] || null; |
| 1351 } |
| 1352 |
| 1353 _documentUpdated() { |
| 1354 this._setDocument(null); |
| 1355 } |
| 1356 |
| 1357 /** |
| 1358 * @param {?DOMAgent.Node} payload |
| 1359 */ |
| 1360 _setDocument(payload) { |
| 1361 this._idToDOMNode = {}; |
| 1362 if (payload && 'nodeId' in payload) |
| 1363 this._document = new WebInspector.DOMDocument(this, payload); |
| 1364 else |
| 1365 this._document = null; |
| 1366 this.dispatchEventToListeners(WebInspector.DOMModel.Events.DocumentUpdated,
this._document); |
| 1367 } |
| 1368 |
| 1369 /** |
| 1370 * @param {!DOMAgent.Node} payload |
| 1371 */ |
| 1372 _setDetachedRoot(payload) { |
| 1373 if (payload.nodeName === '#document') |
| 1374 new WebInspector.DOMDocument(this, payload); |
| 1375 else |
| 1376 WebInspector.DOMNode.create(this, null, false, payload); |
| 1377 } |
| 1378 |
| 1379 /** |
| 1380 * @param {!DOMAgent.NodeId} parentId |
| 1381 * @param {!Array.<!DOMAgent.Node>} payloads |
| 1382 */ |
| 1383 _setChildNodes(parentId, payloads) { |
| 1384 if (!parentId && payloads.length) { |
| 1385 this._setDetachedRoot(payloads[0]); |
| 1386 return; |
| 1387 } |
| 1388 |
| 1389 var parent = this._idToDOMNode[parentId]; |
| 1390 parent._setChildrenPayload(payloads); |
| 1391 } |
| 1392 |
| 1393 /** |
| 1394 * @param {!DOMAgent.NodeId} nodeId |
| 1395 * @param {number} newValue |
| 1396 */ |
| 1397 _childNodeCountUpdated(nodeId, newValue) { |
| 1398 var node = this._idToDOMNode[nodeId]; |
| 1399 node._childNodeCount = newValue; |
| 1400 this.dispatchEventToListeners(WebInspector.DOMModel.Events.ChildNodeCountUpd
ated, node); |
| 1401 this._scheduleMutationEvent(node); |
| 1402 } |
| 1403 |
| 1404 /** |
| 1405 * @param {!DOMAgent.NodeId} parentId |
| 1406 * @param {!DOMAgent.NodeId} prevId |
| 1407 * @param {!DOMAgent.Node} payload |
| 1408 */ |
| 1409 _childNodeInserted(parentId, prevId, payload) { |
| 1410 var parent = this._idToDOMNode[parentId]; |
| 1411 var prev = this._idToDOMNode[prevId]; |
| 1412 var node = parent._insertChild(prev, payload); |
| 1413 this._idToDOMNode[node.id] = node; |
| 1414 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted, nod
e); |
| 1415 this._scheduleMutationEvent(node); |
| 1416 } |
| 1417 |
| 1418 /** |
| 1419 * @param {!DOMAgent.NodeId} parentId |
| 1420 * @param {!DOMAgent.NodeId} nodeId |
| 1421 */ |
| 1422 _childNodeRemoved(parentId, nodeId) { |
| 1423 var parent = this._idToDOMNode[parentId]; |
| 1424 var node = this._idToDOMNode[nodeId]; |
| 1425 parent._removeChild(node); |
| 1426 this._unbind(node); |
| 1427 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved, {nod
e: node, parent: parent}); |
| 1428 this._scheduleMutationEvent(node); |
| 1429 } |
| 1430 |
| 1431 /** |
| 1432 * @param {!DOMAgent.NodeId} hostId |
| 1433 * @param {!DOMAgent.Node} root |
| 1434 */ |
| 1435 _shadowRootPushed(hostId, root) { |
| 1436 var host = this._idToDOMNode[hostId]; |
| 1437 if (!host) |
| 1438 return; |
| 1439 var node = WebInspector.DOMNode.create(this, host.ownerDocument, true, root)
; |
| 1440 node.parentNode = host; |
| 1441 this._idToDOMNode[node.id] = node; |
| 1442 host._shadowRoots.unshift(node); |
| 1443 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted, nod
e); |
| 1444 this._scheduleMutationEvent(node); |
| 1445 } |
| 1446 |
| 1447 /** |
| 1448 * @param {!DOMAgent.NodeId} hostId |
| 1449 * @param {!DOMAgent.NodeId} rootId |
| 1450 */ |
| 1451 _shadowRootPopped(hostId, rootId) { |
| 1452 var host = this._idToDOMNode[hostId]; |
| 1453 if (!host) |
| 1454 return; |
| 1455 var root = this._idToDOMNode[rootId]; |
| 1456 if (!root) |
| 1457 return; |
| 1458 host._removeChild(root); |
| 1459 this._unbind(root); |
| 1460 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved, {nod
e: root, parent: host}); |
| 1461 this._scheduleMutationEvent(root); |
| 1462 } |
| 1463 |
| 1464 /** |
| 1465 * @param {!DOMAgent.NodeId} parentId |
| 1466 * @param {!DOMAgent.Node} pseudoElement |
| 1467 */ |
| 1468 _pseudoElementAdded(parentId, pseudoElement) { |
| 1469 var parent = this._idToDOMNode[parentId]; |
| 1470 if (!parent) |
| 1471 return; |
| 1472 var node = WebInspector.DOMNode.create(this, parent.ownerDocument, false, ps
eudoElement); |
| 1473 node.parentNode = parent; |
| 1474 this._idToDOMNode[node.id] = node; |
| 1475 console.assert(!parent._pseudoElements.get(node.pseudoType())); |
| 1476 parent._pseudoElements.set(node.pseudoType(), node); |
| 1477 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted, nod
e); |
| 1478 this._scheduleMutationEvent(node); |
| 1479 } |
| 1480 |
| 1481 /** |
| 1482 * @param {!DOMAgent.NodeId} parentId |
| 1483 * @param {!DOMAgent.NodeId} pseudoElementId |
| 1484 */ |
| 1485 _pseudoElementRemoved(parentId, pseudoElementId) { |
| 1486 var parent = this._idToDOMNode[parentId]; |
| 1487 if (!parent) |
| 1488 return; |
| 1489 var pseudoElement = this._idToDOMNode[pseudoElementId]; |
| 1490 if (!pseudoElement) |
| 1491 return; |
| 1492 parent._removeChild(pseudoElement); |
| 1493 this._unbind(pseudoElement); |
| 1494 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved, {nod
e: pseudoElement, parent: parent}); |
| 1495 this._scheduleMutationEvent(pseudoElement); |
| 1496 } |
| 1497 |
| 1498 /** |
| 1499 * @param {!DOMAgent.NodeId} insertionPointId |
| 1500 * @param {!Array.<!DOMAgent.BackendNode>} distributedNodes |
| 1501 */ |
| 1502 _distributedNodesUpdated(insertionPointId, distributedNodes) { |
| 1503 var insertionPoint = this._idToDOMNode[insertionPointId]; |
| 1504 if (!insertionPoint) |
| 1505 return; |
| 1506 insertionPoint._setDistributedNodePayloads(distributedNodes); |
| 1507 this.dispatchEventToListeners(WebInspector.DOMModel.Events.DistributedNodesC
hanged, insertionPoint); |
| 1508 this._scheduleMutationEvent(insertionPoint); |
| 1509 } |
| 1510 |
| 1511 /** |
| 1512 * @param {!WebInspector.DOMNode} node |
| 1513 */ |
| 1514 _unbind(node) { |
| 1515 delete this._idToDOMNode[node.id]; |
| 1516 for (var i = 0; node._children && i < node._children.length; ++i) |
| 1517 this._unbind(node._children[i]); |
| 1518 for (var i = 0; i < node._shadowRoots.length; ++i) |
| 1519 this._unbind(node._shadowRoots[i]); |
| 1520 var pseudoElements = node.pseudoElements(); |
| 1521 for (var value of pseudoElements.values()) |
| 1522 this._unbind(value); |
| 1523 if (node._templateContent) |
| 1524 this._unbind(node._templateContent); |
| 1525 } |
| 1526 |
| 1527 /** |
| 1528 * @param {!DOMAgent.BackendNodeId} backendNodeId |
| 1529 */ |
| 1530 _inspectNodeRequested(backendNodeId) { |
| 1531 var deferredNode = new WebInspector.DeferredDOMNode(this.target(), backendNo
deId); |
| 1532 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInspected, de
ferredNode); |
| 1533 } |
| 1534 |
| 1535 /** |
| 1536 * @param {string} query |
| 1537 * @param {boolean} includeUserAgentShadowDOM |
| 1538 * @param {function(number)} searchCallback |
| 1539 */ |
| 1540 performSearch(query, includeUserAgentShadowDOM, searchCallback) { |
| 1541 WebInspector.DOMModel.cancelSearch(); |
| 1542 |
| 1543 /** |
| 1544 * @param {?Protocol.Error} error |
| 1545 * @param {string} searchId |
| 1546 * @param {number} resultsCount |
| 1547 * @this {WebInspector.DOMModel} |
| 1548 */ |
| 1549 function callback(error, searchId, resultsCount) { |
| 1550 this._searchId = searchId; |
| 1551 searchCallback(resultsCount); |
| 1552 } |
| 1553 this._agent.performSearch(query, includeUserAgentShadowDOM, callback.bind(th
is)); |
| 1554 } |
| 1555 |
| 1556 /** |
| 1557 * @param {string} query |
| 1558 * @param {boolean} includeUserAgentShadowDOM |
| 1559 * @return {!Promise.<number>} |
| 1560 */ |
| 1561 performSearchPromise(query, includeUserAgentShadowDOM) { |
| 1562 return new Promise(performSearch.bind(this)); |
| 1563 |
| 1564 /** |
| 1565 * @param {function(number)} resolve |
| 1566 * @this {WebInspector.DOMModel} |
| 1567 */ |
| 1568 function performSearch(resolve) { |
| 1569 this._agent.performSearch(query, includeUserAgentShadowDOM, callback.bind(
this)); |
| 1570 |
| 1571 /** |
| 1572 * @param {?Protocol.Error} error |
| 1573 * @param {string} searchId |
| 1574 * @param {number} resultsCount |
| 1575 * @this {WebInspector.DOMModel} |
| 1576 */ |
| 1577 function callback(error, searchId, resultsCount) { |
| 1578 if (!error) |
| 1579 this._searchId = searchId; |
| 1580 resolve(error ? 0 : resultsCount); |
| 1581 } |
| 1582 } |
| 1583 } |
| 1584 |
| 1585 /** |
| 1586 * @param {number} index |
| 1587 * @param {?function(?WebInspector.DOMNode)} callback |
| 1588 */ |
| 1589 searchResult(index, callback) { |
| 1590 if (this._searchId) |
| 1591 this._agent.getSearchResults(this._searchId, index, index + 1, searchResul
tsCallback.bind(this)); |
| 1592 else |
| 1593 callback(null); |
| 1594 |
| 1595 /** |
| 1596 * @param {?Protocol.Error} error |
| 1597 * @param {!Array.<number>} nodeIds |
| 1598 * @this {WebInspector.DOMModel} |
| 1599 */ |
| 1600 function searchResultsCallback(error, nodeIds) { |
| 1601 if (error) { |
| 1602 console.error(error); |
| 1603 callback(null); |
| 1604 return; |
| 1605 } |
| 1606 if (nodeIds.length !== 1) |
| 1607 return; |
| 1608 |
| 1609 callback(this.nodeForId(nodeIds[0])); |
| 1610 } |
| 1611 } |
| 1612 |
| 1613 _cancelSearch() { |
| 1614 if (this._searchId) { |
| 1615 this._agent.discardSearchResults(this._searchId); |
| 1616 delete this._searchId; |
| 1617 } |
| 1618 } |
| 1619 |
| 1620 /** |
| 1621 * @param {!DOMAgent.NodeId} nodeId |
| 1622 * @return {!Promise<!Array<string>>} |
| 1623 */ |
| 1624 classNamesPromise(nodeId) { |
| 1625 return new Promise(promiseBody.bind(this)); |
| 1626 |
| 1627 /** |
| 1628 * @param {function(!Array<string>)} fulfill |
| 1629 * @this {WebInspector.DOMModel} |
| 1630 */ |
| 1631 function promiseBody(fulfill) { |
| 1632 this._agent.collectClassNamesFromSubtree(nodeId, classNamesCallback); |
| 1633 |
| 1634 /** |
| 1635 * @param {?string} error |
| 1636 * @param {?Array<string>} classNames |
| 1637 */ |
| 1638 function classNamesCallback(error, classNames) { |
| 1639 if (!error && classNames) |
| 1640 fulfill(classNames); |
| 1641 else |
| 1642 fulfill([]); |
| 1643 } |
| 1644 } |
| 1645 } |
| 1646 |
| 1647 /** |
| 1648 * @param {!DOMAgent.NodeId} nodeId |
| 1649 * @param {string} selectors |
| 1650 * @param {function(?DOMAgent.NodeId)=} callback |
| 1651 */ |
| 1652 querySelector(nodeId, selectors, callback) { |
| 1653 this._agent.querySelector(nodeId, selectors, this._wrapClientCallback(callba
ck)); |
| 1654 } |
| 1655 |
| 1656 /** |
| 1657 * @param {!DOMAgent.NodeId} nodeId |
| 1658 * @param {string} selectors |
| 1659 * @param {function(!Array.<!DOMAgent.NodeId>=)=} callback |
| 1660 */ |
| 1661 querySelectorAll(nodeId, selectors, callback) { |
| 1662 this._agent.querySelectorAll(nodeId, selectors, this._wrapClientCallback(cal
lback)); |
| 1663 } |
| 1664 |
| 1665 /** |
| 1666 * @param {!DOMAgent.NodeId=} nodeId |
| 1667 * @param {string=} mode |
| 1668 * @param {!DOMAgent.BackendNodeId=} backendNodeId |
| 1669 * @param {!RuntimeAgent.RemoteObjectId=} objectId |
| 1670 */ |
| 1671 highlightDOMNode(nodeId, mode, backendNodeId, objectId) { |
| 1672 this.highlightDOMNodeWithConfig(nodeId, {mode: mode}, backendNodeId, objectI
d); |
| 1673 } |
| 1674 |
| 1675 /** |
| 1676 * @param {!DOMAgent.NodeId=} nodeId |
| 1677 * @param {!{mode: (string|undefined), showInfo: (boolean|undefined), selector
s: (string|undefined)}=} config |
| 1678 * @param {!DOMAgent.BackendNodeId=} backendNodeId |
| 1679 * @param {!RuntimeAgent.RemoteObjectId=} objectId |
| 1680 */ |
| 1681 highlightDOMNodeWithConfig(nodeId, config, backendNodeId, objectId) { |
| 1682 if (WebInspector.DOMModel._highlightDisabled) |
| 1683 return; |
| 1684 config = config || {mode: 'all', showInfo: undefined, selectors: undefined}; |
| 1685 if (this._hideDOMNodeHighlightTimeout) { |
| 1686 clearTimeout(this._hideDOMNodeHighlightTimeout); |
| 1687 delete this._hideDOMNodeHighlightTimeout; |
| 1688 } |
| 1689 var highlightConfig = this._buildHighlightConfig(config.mode); |
| 1690 if (typeof config.showInfo !== 'undefined') |
| 1691 highlightConfig.showInfo = config.showInfo; |
| 1692 if (typeof config.selectors !== 'undefined') |
| 1693 highlightConfig.selectorList = config.selectors; |
| 1694 this._highlighter.highlightDOMNode(this.nodeForId(nodeId || 0), highlightCon
fig, backendNodeId, objectId); |
| 1695 } |
| 1696 |
| 1697 /** |
| 1698 * @param {!DOMAgent.NodeId} nodeId |
| 1699 */ |
| 1700 highlightDOMNodeForTwoSeconds(nodeId) { |
| 1701 this.highlightDOMNode(nodeId); |
| 1702 this._hideDOMNodeHighlightTimeout = |
| 1703 setTimeout(WebInspector.DOMModel.hideDOMNodeHighlight.bind(WebInspector.
DOMModel), 2000); |
| 1704 } |
| 1705 |
| 1706 /** |
| 1707 * @param {!PageAgent.FrameId} frameId |
| 1708 */ |
| 1709 highlightFrame(frameId) { |
| 1710 if (WebInspector.DOMModel._highlightDisabled) |
| 1711 return; |
| 1712 this._highlighter.highlightFrame(frameId); |
| 1713 } |
| 1714 |
| 1715 /** |
| 1716 * @param {!DOMAgent.InspectMode} mode |
| 1717 * @param {function(?Protocol.Error)=} callback |
| 1718 */ |
| 1719 setInspectMode(mode, callback) { |
| 1720 /** |
| 1721 * @this {WebInspector.DOMModel} |
| 1722 */ |
| 1723 function onDocumentAvailable() { |
| 1724 this._inspectModeEnabled = mode !== DOMAgent.InspectMode.None; |
| 1725 this.dispatchEventToListeners(WebInspector.DOMModel.Events.InspectModeWill
BeToggled, this._inspectModeEnabled); |
| 1726 this._highlighter.setInspectMode(mode, this._buildHighlightConfig(), callb
ack); |
| 1727 } |
| 1728 this.requestDocument(onDocumentAvailable.bind(this)); |
| 1729 } |
| 1730 |
| 1731 /** |
| 1732 * @return {boolean} |
| 1733 */ |
| 1734 inspectModeEnabled() { |
| 1735 return this._inspectModeEnabled; |
| 1736 } |
| 1737 |
| 1738 /** |
| 1739 * @param {string=} mode |
| 1740 * @return {!DOMAgent.HighlightConfig} |
| 1741 */ |
| 1742 _buildHighlightConfig(mode) { |
| 1743 mode = mode || 'all'; |
| 1744 var showRulers = WebInspector.moduleSetting('showMetricsRulers').get(); |
| 1745 var highlightConfig = {showInfo: mode === 'all', showRulers: showRulers, sho
wExtensionLines: showRulers}; |
| 1746 if (mode === 'all' || mode === 'content') |
| 1747 highlightConfig.contentColor = WebInspector.Color.PageHighlight.Content.to
ProtocolRGBA(); |
| 1748 |
| 1749 if (mode === 'all' || mode === 'padding') |
| 1750 highlightConfig.paddingColor = WebInspector.Color.PageHighlight.Padding.to
ProtocolRGBA(); |
| 1751 |
| 1752 if (mode === 'all' || mode === 'border') |
| 1753 highlightConfig.borderColor = WebInspector.Color.PageHighlight.Border.toPr
otocolRGBA(); |
| 1754 |
| 1755 if (mode === 'all' || mode === 'margin') |
| 1756 highlightConfig.marginColor = WebInspector.Color.PageHighlight.Margin.toPr
otocolRGBA(); |
| 1757 |
| 1758 if (mode === 'all') { |
| 1759 highlightConfig.eventTargetColor = WebInspector.Color.PageHighlight.EventT
arget.toProtocolRGBA(); |
| 1760 highlightConfig.shapeColor = WebInspector.Color.PageHighlight.Shape.toProt
ocolRGBA(); |
| 1761 highlightConfig.shapeMarginColor = WebInspector.Color.PageHighlight.ShapeM
argin.toProtocolRGBA(); |
| 1762 highlightConfig.displayAsMaterial = Runtime.experiments.isEnabled('inspect
Tooltip'); |
| 1763 } |
| 1764 return highlightConfig; |
| 1765 } |
| 1766 |
| 1767 /** |
| 1768 * @param {!WebInspector.DOMNode} node |
| 1769 * @param {function(?Protocol.Error, ...)=} callback |
| 1770 * @return {function(...)} |
| 1771 * @template T |
| 1772 */ |
| 1773 _markRevision(node, callback) { |
| 1774 /** |
| 1775 * @param {?Protocol.Error} error |
| 1776 * @this {WebInspector.DOMModel} |
| 1777 */ |
| 1778 function wrapperFunction(error) { |
| 1779 if (!error) |
| 1780 this.markUndoableState(); |
| 1781 |
| 1782 if (callback) |
| 1783 callback.apply(this, arguments); |
| 1784 } |
| 1785 return wrapperFunction.bind(this); |
| 1786 } |
| 1787 |
| 1788 markUndoableState() { |
| 1789 this._agent.markUndoableState(); |
| 1790 } |
| 1791 |
| 1792 /** |
| 1793 * @param {function(?Protocol.Error)=} callback |
| 1794 */ |
| 1795 undo(callback) { |
| 1796 /** |
| 1797 * @param {?Protocol.Error} error |
| 1798 * @this {WebInspector.DOMModel} |
| 1799 */ |
| 1800 function mycallback(error) { |
| 1801 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoComplet
ed); |
| 1802 callback(error); |
| 1803 } |
| 1804 |
| 1805 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoRequested
); |
| 1806 this._agent.undo(callback); |
| 1807 } |
| 1808 |
| 1809 /** |
| 1810 * @param {function(?Protocol.Error)=} callback |
| 1811 */ |
| 1812 redo(callback) { |
| 1813 /** |
| 1814 * @param {?Protocol.Error} error |
| 1815 * @this {WebInspector.DOMModel} |
| 1816 */ |
| 1817 function mycallback(error) { |
| 1818 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoComplet
ed); |
| 1819 callback(error); |
| 1820 } |
| 1821 |
| 1822 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoRequested
); |
| 1823 this._agent.redo(callback); |
| 1824 } |
| 1825 |
| 1826 /** |
| 1827 * @param {?WebInspector.DOMNodeHighlighter} highlighter |
| 1828 */ |
| 1829 setHighlighter(highlighter) { |
| 1830 this._highlighter = highlighter || this._defaultHighlighter; |
| 1831 } |
| 1832 |
| 1833 /** |
| 1834 * @param {number} x |
| 1835 * @param {number} y |
| 1836 * @param {function(?WebInspector.DOMNode)} callback |
| 1837 */ |
| 1838 nodeForLocation(x, y, callback) { |
| 1839 this._agent.getNodeForLocation(x, y, mycallback.bind(this)); |
| 1840 |
| 1841 /** |
| 1842 * @param {?Protocol.Error} error |
| 1843 * @param {number} nodeId |
| 1844 * @this {WebInspector.DOMModel} |
| 1845 */ |
| 1846 function mycallback(error, nodeId) { |
| 1847 if (error) { |
| 1848 callback(null); |
| 1849 return; |
| 1850 } |
| 1851 callback(this.nodeForId(nodeId)); |
| 1852 } |
| 1853 } |
| 1854 |
| 1855 /** |
| 1856 * @param {!WebInspector.RemoteObject} object |
| 1857 * @param {function(?WebInspector.DOMNode)} callback |
| 1858 */ |
| 1859 pushObjectAsNodeToFrontend(object, callback) { |
| 1860 if (object.isNode()) |
| 1861 this.pushNodeToFrontend(object.objectId, callback); |
| 1862 else |
| 1863 callback(null); |
| 1864 } |
| 1865 |
| 1866 /** |
| 1867 * @override |
| 1868 * @return {!Promise} |
| 1869 */ |
| 1870 suspendModel() { |
| 1871 return new Promise(promiseBody.bind(this)); |
| 1872 |
| 1873 /** |
| 1874 * @param {function()} fulfill |
| 1875 * @this {WebInspector.DOMModel} |
| 1876 */ |
| 1877 function promiseBody(fulfill) { |
| 1878 this._agent.disable(callback.bind(this)); |
| 1879 |
| 1880 /** |
| 1881 * @this {WebInspector.DOMModel} |
| 1882 */ |
| 1883 function callback() { |
| 1884 this._setDocument(null); |
| 1885 fulfill(); |
| 1886 } |
| 1887 } |
| 1888 } |
| 1889 |
| 1890 /** |
| 1891 * @override |
| 1892 * @return {!Promise} |
| 1893 */ |
| 1894 resumeModel() { |
| 1895 return new Promise(promiseBody.bind(this)); |
| 1896 |
| 1897 /** |
| 1898 * @param {function()} fulfill |
| 1899 * @this {WebInspector.DOMModel} |
| 1900 */ |
| 1901 function promiseBody(fulfill) { |
| 1902 this._agent.enable(fulfill); |
| 1903 } |
| 1904 } |
| 1905 |
| 1906 /** |
| 1907 * @param {!DOMAgent.NodeId} nodeId |
| 1908 */ |
| 1909 nodeHighlightRequested(nodeId) { |
| 1910 var node = this.nodeForId(nodeId); |
| 1911 if (!node) |
| 1912 return; |
| 1913 |
| 1914 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeHighlightedIn
Overlay, node); |
| 1915 } |
1134 }; | 1916 }; |
1135 | 1917 |
1136 /** @enum {symbol} */ | 1918 /** @enum {symbol} */ |
1137 WebInspector.DOMModel.Events = { | 1919 WebInspector.DOMModel.Events = { |
1138 AttrModified: Symbol("AttrModified"), | 1920 AttrModified: Symbol('AttrModified'), |
1139 AttrRemoved: Symbol("AttrRemoved"), | 1921 AttrRemoved: Symbol('AttrRemoved'), |
1140 CharacterDataModified: Symbol("CharacterDataModified"), | 1922 CharacterDataModified: Symbol('CharacterDataModified'), |
1141 DOMMutated: Symbol("DOMMutated"), | 1923 DOMMutated: Symbol('DOMMutated'), |
1142 NodeInserted: Symbol("NodeInserted"), | 1924 NodeInserted: Symbol('NodeInserted'), |
1143 NodeInspected: Symbol("NodeInspected"), | 1925 NodeInspected: Symbol('NodeInspected'), |
1144 NodeHighlightedInOverlay: Symbol("NodeHighlightedInOverlay"), | 1926 NodeHighlightedInOverlay: Symbol('NodeHighlightedInOverlay'), |
1145 NodeRemoved: Symbol("NodeRemoved"), | 1927 NodeRemoved: Symbol('NodeRemoved'), |
1146 DocumentUpdated: Symbol("DocumentUpdated"), | 1928 DocumentUpdated: Symbol('DocumentUpdated'), |
1147 ChildNodeCountUpdated: Symbol("ChildNodeCountUpdated"), | 1929 ChildNodeCountUpdated: Symbol('ChildNodeCountUpdated'), |
1148 UndoRedoRequested: Symbol("UndoRedoRequested"), | 1930 UndoRedoRequested: Symbol('UndoRedoRequested'), |
1149 UndoRedoCompleted: Symbol("UndoRedoCompleted"), | 1931 UndoRedoCompleted: Symbol('UndoRedoCompleted'), |
1150 DistributedNodesChanged: Symbol("DistributedNodesChanged"), | 1932 DistributedNodesChanged: Symbol('DistributedNodesChanged'), |
1151 ModelSuspended: Symbol("ModelSuspended"), | 1933 ModelSuspended: Symbol('ModelSuspended'), |
1152 InspectModeWillBeToggled: Symbol("InspectModeWillBeToggled"), | 1934 InspectModeWillBeToggled: Symbol('InspectModeWillBeToggled'), |
1153 MarkersChanged: Symbol("MarkersChanged") | 1935 MarkersChanged: Symbol('MarkersChanged') |
1154 }; | 1936 }; |
1155 | 1937 |
| 1938 |
1156 /** | 1939 /** |
1157 * @param {!WebInspector.RemoteObject} object | 1940 * @implements {DOMAgent.Dispatcher} |
| 1941 * @unrestricted |
1158 */ | 1942 */ |
1159 WebInspector.DOMModel.highlightObjectAsDOMNode = function(object) | 1943 WebInspector.DOMDispatcher = class { |
1160 { | 1944 /** |
1161 var domModel = WebInspector.DOMModel.fromTarget(object.target()); | 1945 * @param {!WebInspector.DOMModel} domModel |
1162 if (domModel) | 1946 */ |
1163 domModel.highlightDOMNode(undefined, undefined, undefined, object.object
Id); | 1947 constructor(domModel) { |
1164 }; | |
1165 | |
1166 /** | |
1167 * @return {!Array<!WebInspector.DOMModel>} | |
1168 */ | |
1169 WebInspector.DOMModel.instances = function() | |
1170 { | |
1171 var result = []; | |
1172 for (var target of WebInspector.targetManager.targets()) { | |
1173 var domModel = WebInspector.DOMModel.fromTarget(target); | |
1174 if (domModel) | |
1175 result.push(domModel); | |
1176 } | |
1177 return result; | |
1178 }; | |
1179 | |
1180 WebInspector.DOMModel.hideDOMNodeHighlight = function() | |
1181 { | |
1182 for (var domModel of WebInspector.DOMModel.instances()) | |
1183 domModel.highlightDOMNode(0); | |
1184 }; | |
1185 | |
1186 WebInspector.DOMModel.muteHighlight = function() | |
1187 { | |
1188 WebInspector.DOMModel.hideDOMNodeHighlight(); | |
1189 WebInspector.DOMModel._highlightDisabled = true; | |
1190 }; | |
1191 | |
1192 WebInspector.DOMModel.unmuteHighlight = function() | |
1193 { | |
1194 WebInspector.DOMModel._highlightDisabled = false; | |
1195 }; | |
1196 | |
1197 WebInspector.DOMModel.cancelSearch = function() | |
1198 { | |
1199 for (var domModel of WebInspector.DOMModel.instances()) | |
1200 domModel._cancelSearch(); | |
1201 }; | |
1202 | |
1203 WebInspector.DOMModel.prototype = { | |
1204 /** | |
1205 * @param {!WebInspector.DOMNode} node | |
1206 */ | |
1207 _scheduleMutationEvent: function(node) | |
1208 { | |
1209 if (!this.hasEventListeners(WebInspector.DOMModel.Events.DOMMutated)) | |
1210 return; | |
1211 | |
1212 this._lastMutationId = (this._lastMutationId || 0) + 1; | |
1213 Promise.resolve().then(callObserve.bind(this, node, this._lastMutationId
)); | |
1214 | |
1215 /** | |
1216 * @this {WebInspector.DOMModel} | |
1217 * @param {!WebInspector.DOMNode} node | |
1218 * @param {number} mutationId | |
1219 */ | |
1220 function callObserve(node, mutationId) | |
1221 { | |
1222 if (!this.hasEventListeners(WebInspector.DOMModel.Events.DOMMutated)
|| this._lastMutationId !== mutationId) | |
1223 return; | |
1224 | |
1225 this.dispatchEventToListeners(WebInspector.DOMModel.Events.DOMMutate
d, node); | |
1226 } | |
1227 }, | |
1228 | |
1229 /** | |
1230 * @param {function(!WebInspector.DOMDocument)=} callback | |
1231 */ | |
1232 requestDocument: function(callback) | |
1233 { | |
1234 if (this._document) { | |
1235 if (callback) | |
1236 callback(this._document); | |
1237 return; | |
1238 } | |
1239 | |
1240 if (this._pendingDocumentRequestCallbacks) { | |
1241 this._pendingDocumentRequestCallbacks.push(callback); | |
1242 return; | |
1243 } | |
1244 | |
1245 this._pendingDocumentRequestCallbacks = [callback]; | |
1246 | |
1247 /** | |
1248 * @this {WebInspector.DOMModel} | |
1249 * @param {?Protocol.Error} error | |
1250 * @param {!DOMAgent.Node} root | |
1251 */ | |
1252 function onDocumentAvailable(error, root) | |
1253 { | |
1254 if (!error) | |
1255 this._setDocument(root); | |
1256 | |
1257 for (var i = 0; i < this._pendingDocumentRequestCallbacks.length; ++
i) { | |
1258 var callback = this._pendingDocumentRequestCallbacks[i]; | |
1259 if (callback) | |
1260 callback(this._document); | |
1261 } | |
1262 delete this._pendingDocumentRequestCallbacks; | |
1263 } | |
1264 | |
1265 this._agent.getDocument(undefined, undefined, onDocumentAvailable.bind(t
his)); | |
1266 }, | |
1267 | |
1268 /** | |
1269 * @return {?WebInspector.DOMDocument} | |
1270 */ | |
1271 existingDocument: function() | |
1272 { | |
1273 return this._document; | |
1274 }, | |
1275 | |
1276 /** | |
1277 * @param {!RuntimeAgent.RemoteObjectId} objectId | |
1278 * @param {function(?WebInspector.DOMNode)=} callback | |
1279 */ | |
1280 pushNodeToFrontend: function(objectId, callback) | |
1281 { | |
1282 /** | |
1283 * @param {?DOMAgent.NodeId} nodeId | |
1284 * @this {!WebInspector.DOMModel} | |
1285 */ | |
1286 function mycallback(nodeId) | |
1287 { | |
1288 callback(nodeId ? this.nodeForId(nodeId) : null); | |
1289 } | |
1290 this._dispatchWhenDocumentAvailable(this._agent.requestNode.bind(this._a
gent, objectId), mycallback.bind(this)); | |
1291 }, | |
1292 | |
1293 /** | |
1294 * @param {string} path | |
1295 * @param {function(?number)=} callback | |
1296 */ | |
1297 pushNodeByPathToFrontend: function(path, callback) | |
1298 { | |
1299 this._dispatchWhenDocumentAvailable(this._agent.pushNodeByPathToFrontend
.bind(this._agent, path), callback); | |
1300 }, | |
1301 | |
1302 /** | |
1303 * @param {!Set<number>} backendNodeIds | |
1304 * @param {function(?Map<number, ?WebInspector.DOMNode>)} callback | |
1305 */ | |
1306 pushNodesByBackendIdsToFrontend: function(backendNodeIds, callback) | |
1307 { | |
1308 var backendNodeIdsArray = backendNodeIds.valuesArray(); | |
1309 /** | |
1310 * @param {?Array<!DOMAgent.NodeId>} nodeIds | |
1311 * @this {!WebInspector.DOMModel} | |
1312 */ | |
1313 function mycallback(nodeIds) | |
1314 { | |
1315 if (!nodeIds) { | |
1316 callback(null); | |
1317 return; | |
1318 } | |
1319 /** @type {!Map<number, ?WebInspector.DOMNode>} */ | |
1320 var map = new Map(); | |
1321 for (var i = 0; i < nodeIds.length; ++i) { | |
1322 if (nodeIds[i]) | |
1323 map.set(backendNodeIdsArray[i], this.nodeForId(nodeIds[i])); | |
1324 } | |
1325 callback(map); | |
1326 } | |
1327 this._dispatchWhenDocumentAvailable(this._agent.pushNodesByBackendIdsToF
rontend.bind(this._agent, backendNodeIdsArray), mycallback.bind(this)); | |
1328 }, | |
1329 | |
1330 /** | |
1331 * @param {function(!T)=} callback | |
1332 * @return {function(?Protocol.Error, !T=)|undefined} | |
1333 * @template T | |
1334 */ | |
1335 _wrapClientCallback: function(callback) | |
1336 { | |
1337 if (!callback) | |
1338 return; | |
1339 /** | |
1340 * @param {?Protocol.Error} error | |
1341 * @param {!T=} result | |
1342 * @template T | |
1343 */ | |
1344 var wrapper = function(error, result) | |
1345 { | |
1346 // Caller is responsible for handling the actual error. | |
1347 callback(error ? null : result); | |
1348 }; | |
1349 return wrapper; | |
1350 }, | |
1351 | |
1352 /** | |
1353 * @param {function(function(?Protocol.Error, !T=)=)} func | |
1354 * @param {function(!T)=} callback | |
1355 * @template T | |
1356 */ | |
1357 _dispatchWhenDocumentAvailable: function(func, callback) | |
1358 { | |
1359 var callbackWrapper = this._wrapClientCallback(callback); | |
1360 | |
1361 /** | |
1362 * @this {WebInspector.DOMModel} | |
1363 */ | |
1364 function onDocumentAvailable() | |
1365 { | |
1366 if (this._document) | |
1367 func(callbackWrapper); | |
1368 else { | |
1369 if (callbackWrapper) | |
1370 callbackWrapper("No document"); | |
1371 } | |
1372 } | |
1373 this.requestDocument(onDocumentAvailable.bind(this)); | |
1374 }, | |
1375 | |
1376 /** | |
1377 * @param {!DOMAgent.NodeId} nodeId | |
1378 * @param {string} name | |
1379 * @param {string} value | |
1380 */ | |
1381 _attributeModified: function(nodeId, name, value) | |
1382 { | |
1383 var node = this._idToDOMNode[nodeId]; | |
1384 if (!node) | |
1385 return; | |
1386 | |
1387 node._setAttribute(name, value); | |
1388 this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrModified,
{ node: node, name: name }); | |
1389 this._scheduleMutationEvent(node); | |
1390 }, | |
1391 | |
1392 /** | |
1393 * @param {!DOMAgent.NodeId} nodeId | |
1394 * @param {string} name | |
1395 */ | |
1396 _attributeRemoved: function(nodeId, name) | |
1397 { | |
1398 var node = this._idToDOMNode[nodeId]; | |
1399 if (!node) | |
1400 return; | |
1401 node._removeAttribute(name); | |
1402 this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrRemoved,
{ node: node, name: name }); | |
1403 this._scheduleMutationEvent(node); | |
1404 }, | |
1405 | |
1406 /** | |
1407 * @param {!Array.<!DOMAgent.NodeId>} nodeIds | |
1408 */ | |
1409 _inlineStyleInvalidated: function(nodeIds) | |
1410 { | |
1411 for (var i = 0; i < nodeIds.length; ++i) | |
1412 this._attributeLoadNodeIds[nodeIds[i]] = true; | |
1413 if ("_loadNodeAttributesTimeout" in this) | |
1414 return; | |
1415 this._loadNodeAttributesTimeout = setTimeout(this._loadNodeAttributes.bi
nd(this), 20); | |
1416 }, | |
1417 | |
1418 _loadNodeAttributes: function() | |
1419 { | |
1420 /** | |
1421 * @this {WebInspector.DOMModel} | |
1422 * @param {!DOMAgent.NodeId} nodeId | |
1423 * @param {?Protocol.Error} error | |
1424 * @param {!Array.<string>} attributes | |
1425 */ | |
1426 function callback(nodeId, error, attributes) | |
1427 { | |
1428 if (error) { | |
1429 // We are calling _loadNodeAttributes asynchronously, it is ok i
f node is not found. | |
1430 return; | |
1431 } | |
1432 var node = this._idToDOMNode[nodeId]; | |
1433 if (node) { | |
1434 if (node._setAttributesPayload(attributes)) { | |
1435 this.dispatchEventToListeners(WebInspector.DOMModel.Events.A
ttrModified, { node: node, name: "style" }); | |
1436 this._scheduleMutationEvent(node); | |
1437 } | |
1438 } | |
1439 } | |
1440 | |
1441 delete this._loadNodeAttributesTimeout; | |
1442 | |
1443 for (var nodeId in this._attributeLoadNodeIds) { | |
1444 var nodeIdAsNumber = parseInt(nodeId, 10); | |
1445 this._agent.getAttributes(nodeIdAsNumber, callback.bind(this, nodeId
AsNumber)); | |
1446 } | |
1447 this._attributeLoadNodeIds = {}; | |
1448 }, | |
1449 | |
1450 /** | |
1451 * @param {!DOMAgent.NodeId} nodeId | |
1452 * @param {string} newValue | |
1453 */ | |
1454 _characterDataModified: function(nodeId, newValue) | |
1455 { | |
1456 var node = this._idToDOMNode[nodeId]; | |
1457 node._nodeValue = newValue; | |
1458 this.dispatchEventToListeners(WebInspector.DOMModel.Events.CharacterData
Modified, node); | |
1459 this._scheduleMutationEvent(node); | |
1460 }, | |
1461 | |
1462 /** | |
1463 * @param {!DOMAgent.NodeId} nodeId | |
1464 * @return {?WebInspector.DOMNode} | |
1465 */ | |
1466 nodeForId: function(nodeId) | |
1467 { | |
1468 return this._idToDOMNode[nodeId] || null; | |
1469 }, | |
1470 | |
1471 _documentUpdated: function() | |
1472 { | |
1473 this._setDocument(null); | |
1474 }, | |
1475 | |
1476 /** | |
1477 * @param {?DOMAgent.Node} payload | |
1478 */ | |
1479 _setDocument: function(payload) | |
1480 { | |
1481 this._idToDOMNode = {}; | |
1482 if (payload && "nodeId" in payload) | |
1483 this._document = new WebInspector.DOMDocument(this, payload); | |
1484 else | |
1485 this._document = null; | |
1486 this.dispatchEventToListeners(WebInspector.DOMModel.Events.DocumentUpdat
ed, this._document); | |
1487 }, | |
1488 | |
1489 /** | |
1490 * @param {!DOMAgent.Node} payload | |
1491 */ | |
1492 _setDetachedRoot: function(payload) | |
1493 { | |
1494 if (payload.nodeName === "#document") | |
1495 new WebInspector.DOMDocument(this, payload); | |
1496 else | |
1497 WebInspector.DOMNode.create(this, null, false, payload); | |
1498 }, | |
1499 | |
1500 /** | |
1501 * @param {!DOMAgent.NodeId} parentId | |
1502 * @param {!Array.<!DOMAgent.Node>} payloads | |
1503 */ | |
1504 _setChildNodes: function(parentId, payloads) | |
1505 { | |
1506 if (!parentId && payloads.length) { | |
1507 this._setDetachedRoot(payloads[0]); | |
1508 return; | |
1509 } | |
1510 | |
1511 var parent = this._idToDOMNode[parentId]; | |
1512 parent._setChildrenPayload(payloads); | |
1513 }, | |
1514 | |
1515 /** | |
1516 * @param {!DOMAgent.NodeId} nodeId | |
1517 * @param {number} newValue | |
1518 */ | |
1519 _childNodeCountUpdated: function(nodeId, newValue) | |
1520 { | |
1521 var node = this._idToDOMNode[nodeId]; | |
1522 node._childNodeCount = newValue; | |
1523 this.dispatchEventToListeners(WebInspector.DOMModel.Events.ChildNodeCoun
tUpdated, node); | |
1524 this._scheduleMutationEvent(node); | |
1525 }, | |
1526 | |
1527 /** | |
1528 * @param {!DOMAgent.NodeId} parentId | |
1529 * @param {!DOMAgent.NodeId} prevId | |
1530 * @param {!DOMAgent.Node} payload | |
1531 */ | |
1532 _childNodeInserted: function(parentId, prevId, payload) | |
1533 { | |
1534 var parent = this._idToDOMNode[parentId]; | |
1535 var prev = this._idToDOMNode[prevId]; | |
1536 var node = parent._insertChild(prev, payload); | |
1537 this._idToDOMNode[node.id] = node; | |
1538 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted,
node); | |
1539 this._scheduleMutationEvent(node); | |
1540 }, | |
1541 | |
1542 /** | |
1543 * @param {!DOMAgent.NodeId} parentId | |
1544 * @param {!DOMAgent.NodeId} nodeId | |
1545 */ | |
1546 _childNodeRemoved: function(parentId, nodeId) | |
1547 { | |
1548 var parent = this._idToDOMNode[parentId]; | |
1549 var node = this._idToDOMNode[nodeId]; | |
1550 parent._removeChild(node); | |
1551 this._unbind(node); | |
1552 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved,
{node: node, parent: parent}); | |
1553 this._scheduleMutationEvent(node); | |
1554 }, | |
1555 | |
1556 /** | |
1557 * @param {!DOMAgent.NodeId} hostId | |
1558 * @param {!DOMAgent.Node} root | |
1559 */ | |
1560 _shadowRootPushed: function(hostId, root) | |
1561 { | |
1562 var host = this._idToDOMNode[hostId]; | |
1563 if (!host) | |
1564 return; | |
1565 var node = WebInspector.DOMNode.create(this, host.ownerDocument, true, r
oot); | |
1566 node.parentNode = host; | |
1567 this._idToDOMNode[node.id] = node; | |
1568 host._shadowRoots.unshift(node); | |
1569 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted,
node); | |
1570 this._scheduleMutationEvent(node); | |
1571 }, | |
1572 | |
1573 /** | |
1574 * @param {!DOMAgent.NodeId} hostId | |
1575 * @param {!DOMAgent.NodeId} rootId | |
1576 */ | |
1577 _shadowRootPopped: function(hostId, rootId) | |
1578 { | |
1579 var host = this._idToDOMNode[hostId]; | |
1580 if (!host) | |
1581 return; | |
1582 var root = this._idToDOMNode[rootId]; | |
1583 if (!root) | |
1584 return; | |
1585 host._removeChild(root); | |
1586 this._unbind(root); | |
1587 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved,
{node: root, parent: host}); | |
1588 this._scheduleMutationEvent(root); | |
1589 }, | |
1590 | |
1591 /** | |
1592 * @param {!DOMAgent.NodeId} parentId | |
1593 * @param {!DOMAgent.Node} pseudoElement | |
1594 */ | |
1595 _pseudoElementAdded: function(parentId, pseudoElement) | |
1596 { | |
1597 var parent = this._idToDOMNode[parentId]; | |
1598 if (!parent) | |
1599 return; | |
1600 var node = WebInspector.DOMNode.create(this, parent.ownerDocument, false
, pseudoElement); | |
1601 node.parentNode = parent; | |
1602 this._idToDOMNode[node.id] = node; | |
1603 console.assert(!parent._pseudoElements.get(node.pseudoType())); | |
1604 parent._pseudoElements.set(node.pseudoType(), node); | |
1605 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted,
node); | |
1606 this._scheduleMutationEvent(node); | |
1607 }, | |
1608 | |
1609 /** | |
1610 * @param {!DOMAgent.NodeId} parentId | |
1611 * @param {!DOMAgent.NodeId} pseudoElementId | |
1612 */ | |
1613 _pseudoElementRemoved: function(parentId, pseudoElementId) | |
1614 { | |
1615 var parent = this._idToDOMNode[parentId]; | |
1616 if (!parent) | |
1617 return; | |
1618 var pseudoElement = this._idToDOMNode[pseudoElementId]; | |
1619 if (!pseudoElement) | |
1620 return; | |
1621 parent._removeChild(pseudoElement); | |
1622 this._unbind(pseudoElement); | |
1623 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved,
{node: pseudoElement, parent: parent}); | |
1624 this._scheduleMutationEvent(pseudoElement); | |
1625 }, | |
1626 | |
1627 /** | |
1628 * @param {!DOMAgent.NodeId} insertionPointId | |
1629 * @param {!Array.<!DOMAgent.BackendNode>} distributedNodes | |
1630 */ | |
1631 _distributedNodesUpdated: function(insertionPointId, distributedNodes) | |
1632 { | |
1633 var insertionPoint = this._idToDOMNode[insertionPointId]; | |
1634 if (!insertionPoint) | |
1635 return; | |
1636 insertionPoint._setDistributedNodePayloads(distributedNodes); | |
1637 this.dispatchEventToListeners(WebInspector.DOMModel.Events.DistributedNo
desChanged, insertionPoint); | |
1638 this._scheduleMutationEvent(insertionPoint); | |
1639 }, | |
1640 | |
1641 /** | |
1642 * @param {!WebInspector.DOMNode} node | |
1643 */ | |
1644 _unbind: function(node) | |
1645 { | |
1646 delete this._idToDOMNode[node.id]; | |
1647 for (var i = 0; node._children && i < node._children.length; ++i) | |
1648 this._unbind(node._children[i]); | |
1649 for (var i = 0; i < node._shadowRoots.length; ++i) | |
1650 this._unbind(node._shadowRoots[i]); | |
1651 var pseudoElements = node.pseudoElements(); | |
1652 for (var value of pseudoElements.values()) | |
1653 this._unbind(value); | |
1654 if (node._templateContent) | |
1655 this._unbind(node._templateContent); | |
1656 }, | |
1657 | |
1658 /** | |
1659 * @param {!DOMAgent.BackendNodeId} backendNodeId | |
1660 */ | |
1661 _inspectNodeRequested: function(backendNodeId) | |
1662 { | |
1663 var deferredNode = new WebInspector.DeferredDOMNode(this.target(), backe
ndNodeId); | |
1664 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInspected
, deferredNode); | |
1665 }, | |
1666 | |
1667 /** | |
1668 * @param {string} query | |
1669 * @param {boolean} includeUserAgentShadowDOM | |
1670 * @param {function(number)} searchCallback | |
1671 */ | |
1672 performSearch: function(query, includeUserAgentShadowDOM, searchCallback) | |
1673 { | |
1674 WebInspector.DOMModel.cancelSearch(); | |
1675 | |
1676 /** | |
1677 * @param {?Protocol.Error} error | |
1678 * @param {string} searchId | |
1679 * @param {number} resultsCount | |
1680 * @this {WebInspector.DOMModel} | |
1681 */ | |
1682 function callback(error, searchId, resultsCount) | |
1683 { | |
1684 this._searchId = searchId; | |
1685 searchCallback(resultsCount); | |
1686 } | |
1687 this._agent.performSearch(query, includeUserAgentShadowDOM, callback.bin
d(this)); | |
1688 }, | |
1689 | |
1690 /** | |
1691 * @param {string} query | |
1692 * @param {boolean} includeUserAgentShadowDOM | |
1693 * @return {!Promise.<number>} | |
1694 */ | |
1695 performSearchPromise: function(query, includeUserAgentShadowDOM) | |
1696 { | |
1697 return new Promise(performSearch.bind(this)); | |
1698 | |
1699 /** | |
1700 * @param {function(number)} resolve | |
1701 * @this {WebInspector.DOMModel} | |
1702 */ | |
1703 function performSearch(resolve) | |
1704 { | |
1705 this._agent.performSearch(query, includeUserAgentShadowDOM, callback
.bind(this)); | |
1706 | |
1707 /** | |
1708 * @param {?Protocol.Error} error | |
1709 * @param {string} searchId | |
1710 * @param {number} resultsCount | |
1711 * @this {WebInspector.DOMModel} | |
1712 */ | |
1713 function callback(error, searchId, resultsCount) | |
1714 { | |
1715 if (!error) | |
1716 this._searchId = searchId; | |
1717 resolve(error ? 0 : resultsCount); | |
1718 } | |
1719 } | |
1720 }, | |
1721 | |
1722 /** | |
1723 * @param {number} index | |
1724 * @param {?function(?WebInspector.DOMNode)} callback | |
1725 */ | |
1726 searchResult: function(index, callback) | |
1727 { | |
1728 if (this._searchId) | |
1729 this._agent.getSearchResults(this._searchId, index, index + 1, searc
hResultsCallback.bind(this)); | |
1730 else | |
1731 callback(null); | |
1732 | |
1733 /** | |
1734 * @param {?Protocol.Error} error | |
1735 * @param {!Array.<number>} nodeIds | |
1736 * @this {WebInspector.DOMModel} | |
1737 */ | |
1738 function searchResultsCallback(error, nodeIds) | |
1739 { | |
1740 if (error) { | |
1741 console.error(error); | |
1742 callback(null); | |
1743 return; | |
1744 } | |
1745 if (nodeIds.length !== 1) | |
1746 return; | |
1747 | |
1748 callback(this.nodeForId(nodeIds[0])); | |
1749 } | |
1750 }, | |
1751 | |
1752 _cancelSearch: function() | |
1753 { | |
1754 if (this._searchId) { | |
1755 this._agent.discardSearchResults(this._searchId); | |
1756 delete this._searchId; | |
1757 } | |
1758 }, | |
1759 | |
1760 /** | |
1761 * @param {!DOMAgent.NodeId} nodeId | |
1762 * @return {!Promise<!Array<string>>} | |
1763 */ | |
1764 classNamesPromise: function(nodeId) | |
1765 { | |
1766 return new Promise(promiseBody.bind(this)); | |
1767 | |
1768 /** | |
1769 * @param {function(!Array<string>)} fulfill | |
1770 * @this {WebInspector.DOMModel} | |
1771 */ | |
1772 function promiseBody(fulfill) | |
1773 { | |
1774 this._agent.collectClassNamesFromSubtree(nodeId, classNamesCallback)
; | |
1775 | |
1776 /** | |
1777 * @param {?string} error | |
1778 * @param {?Array<string>} classNames | |
1779 */ | |
1780 function classNamesCallback(error, classNames) | |
1781 { | |
1782 if (!error && classNames) | |
1783 fulfill(classNames); | |
1784 else | |
1785 fulfill([]); | |
1786 } | |
1787 } | |
1788 }, | |
1789 | |
1790 /** | |
1791 * @param {!DOMAgent.NodeId} nodeId | |
1792 * @param {string} selectors | |
1793 * @param {function(?DOMAgent.NodeId)=} callback | |
1794 */ | |
1795 querySelector: function(nodeId, selectors, callback) | |
1796 { | |
1797 this._agent.querySelector(nodeId, selectors, this._wrapClientCallback(ca
llback)); | |
1798 }, | |
1799 | |
1800 /** | |
1801 * @param {!DOMAgent.NodeId} nodeId | |
1802 * @param {string} selectors | |
1803 * @param {function(!Array.<!DOMAgent.NodeId>=)=} callback | |
1804 */ | |
1805 querySelectorAll: function(nodeId, selectors, callback) | |
1806 { | |
1807 this._agent.querySelectorAll(nodeId, selectors, this._wrapClientCallback
(callback)); | |
1808 }, | |
1809 | |
1810 /** | |
1811 * @param {!DOMAgent.NodeId=} nodeId | |
1812 * @param {string=} mode | |
1813 * @param {!DOMAgent.BackendNodeId=} backendNodeId | |
1814 * @param {!RuntimeAgent.RemoteObjectId=} objectId | |
1815 */ | |
1816 highlightDOMNode: function(nodeId, mode, backendNodeId, objectId) | |
1817 { | |
1818 this.highlightDOMNodeWithConfig(nodeId, { mode: mode }, backendNodeId, o
bjectId); | |
1819 }, | |
1820 | |
1821 /** | |
1822 * @param {!DOMAgent.NodeId=} nodeId | |
1823 * @param {!{mode: (string|undefined), showInfo: (boolean|undefined), select
ors: (string|undefined)}=} config | |
1824 * @param {!DOMAgent.BackendNodeId=} backendNodeId | |
1825 * @param {!RuntimeAgent.RemoteObjectId=} objectId | |
1826 */ | |
1827 highlightDOMNodeWithConfig: function(nodeId, config, backendNodeId, objectId
) | |
1828 { | |
1829 if (WebInspector.DOMModel._highlightDisabled) | |
1830 return; | |
1831 config = config || { mode: "all", showInfo: undefined, selectors: undefi
ned }; | |
1832 if (this._hideDOMNodeHighlightTimeout) { | |
1833 clearTimeout(this._hideDOMNodeHighlightTimeout); | |
1834 delete this._hideDOMNodeHighlightTimeout; | |
1835 } | |
1836 var highlightConfig = this._buildHighlightConfig(config.mode); | |
1837 if (typeof config.showInfo !== "undefined") | |
1838 highlightConfig.showInfo = config.showInfo; | |
1839 if (typeof config.selectors !== "undefined") | |
1840 highlightConfig.selectorList = config.selectors; | |
1841 this._highlighter.highlightDOMNode(this.nodeForId(nodeId || 0), highligh
tConfig, backendNodeId, objectId); | |
1842 }, | |
1843 | |
1844 /** | |
1845 * @param {!DOMAgent.NodeId} nodeId | |
1846 */ | |
1847 highlightDOMNodeForTwoSeconds: function(nodeId) | |
1848 { | |
1849 this.highlightDOMNode(nodeId); | |
1850 this._hideDOMNodeHighlightTimeout = setTimeout(WebInspector.DOMModel.hid
eDOMNodeHighlight.bind(WebInspector.DOMModel), 2000); | |
1851 }, | |
1852 | |
1853 /** | |
1854 * @param {!PageAgent.FrameId} frameId | |
1855 */ | |
1856 highlightFrame: function(frameId) | |
1857 { | |
1858 if (WebInspector.DOMModel._highlightDisabled) | |
1859 return; | |
1860 this._highlighter.highlightFrame(frameId); | |
1861 }, | |
1862 | |
1863 /** | |
1864 * @param {!DOMAgent.InspectMode} mode | |
1865 * @param {function(?Protocol.Error)=} callback | |
1866 */ | |
1867 setInspectMode: function(mode, callback) | |
1868 { | |
1869 /** | |
1870 * @this {WebInspector.DOMModel} | |
1871 */ | |
1872 function onDocumentAvailable() | |
1873 { | |
1874 this._inspectModeEnabled = mode !== DOMAgent.InspectMode.None; | |
1875 this.dispatchEventToListeners(WebInspector.DOMModel.Events.InspectMo
deWillBeToggled, this._inspectModeEnabled); | |
1876 this._highlighter.setInspectMode(mode, this._buildHighlightConfig(),
callback); | |
1877 } | |
1878 this.requestDocument(onDocumentAvailable.bind(this)); | |
1879 }, | |
1880 | |
1881 /** | |
1882 * @return {boolean} | |
1883 */ | |
1884 inspectModeEnabled: function() | |
1885 { | |
1886 return this._inspectModeEnabled; | |
1887 }, | |
1888 | |
1889 /** | |
1890 * @param {string=} mode | |
1891 * @return {!DOMAgent.HighlightConfig} | |
1892 */ | |
1893 _buildHighlightConfig: function(mode) | |
1894 { | |
1895 mode = mode || "all"; | |
1896 var showRulers = WebInspector.moduleSetting("showMetricsRulers").get(); | |
1897 var highlightConfig = { showInfo: mode === "all", showRulers: showRulers
, showExtensionLines: showRulers }; | |
1898 if (mode === "all" || mode === "content") | |
1899 highlightConfig.contentColor = WebInspector.Color.PageHighlight.Cont
ent.toProtocolRGBA(); | |
1900 | |
1901 if (mode === "all" || mode === "padding") | |
1902 highlightConfig.paddingColor = WebInspector.Color.PageHighlight.Padd
ing.toProtocolRGBA(); | |
1903 | |
1904 if (mode === "all" || mode === "border") | |
1905 highlightConfig.borderColor = WebInspector.Color.PageHighlight.Borde
r.toProtocolRGBA(); | |
1906 | |
1907 if (mode === "all" || mode === "margin") | |
1908 highlightConfig.marginColor = WebInspector.Color.PageHighlight.Margi
n.toProtocolRGBA(); | |
1909 | |
1910 if (mode === "all") { | |
1911 highlightConfig.eventTargetColor = WebInspector.Color.PageHighlight.
EventTarget.toProtocolRGBA(); | |
1912 highlightConfig.shapeColor = WebInspector.Color.PageHighlight.Shape.
toProtocolRGBA(); | |
1913 highlightConfig.shapeMarginColor = WebInspector.Color.PageHighlight.
ShapeMargin.toProtocolRGBA(); | |
1914 highlightConfig.displayAsMaterial = Runtime.experiments.isEnabled("i
nspectTooltip"); | |
1915 } | |
1916 return highlightConfig; | |
1917 }, | |
1918 | |
1919 /** | |
1920 * @param {!WebInspector.DOMNode} node | |
1921 * @param {function(?Protocol.Error, ...)=} callback | |
1922 * @return {function(...)} | |
1923 * @template T | |
1924 */ | |
1925 _markRevision: function(node, callback) | |
1926 { | |
1927 /** | |
1928 * @param {?Protocol.Error} error | |
1929 * @this {WebInspector.DOMModel} | |
1930 */ | |
1931 function wrapperFunction(error) | |
1932 { | |
1933 if (!error) | |
1934 this.markUndoableState(); | |
1935 | |
1936 if (callback) | |
1937 callback.apply(this, arguments); | |
1938 } | |
1939 return wrapperFunction.bind(this); | |
1940 }, | |
1941 | |
1942 markUndoableState: function() | |
1943 { | |
1944 this._agent.markUndoableState(); | |
1945 }, | |
1946 | |
1947 /** | |
1948 * @param {function(?Protocol.Error)=} callback | |
1949 */ | |
1950 undo: function(callback) | |
1951 { | |
1952 /** | |
1953 * @param {?Protocol.Error} error | |
1954 * @this {WebInspector.DOMModel} | |
1955 */ | |
1956 function mycallback(error) | |
1957 { | |
1958 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoC
ompleted); | |
1959 callback(error); | |
1960 } | |
1961 | |
1962 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoReque
sted); | |
1963 this._agent.undo(callback); | |
1964 }, | |
1965 | |
1966 /** | |
1967 * @param {function(?Protocol.Error)=} callback | |
1968 */ | |
1969 redo: function(callback) | |
1970 { | |
1971 /** | |
1972 * @param {?Protocol.Error} error | |
1973 * @this {WebInspector.DOMModel} | |
1974 */ | |
1975 function mycallback(error) | |
1976 { | |
1977 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoC
ompleted); | |
1978 callback(error); | |
1979 } | |
1980 | |
1981 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoReque
sted); | |
1982 this._agent.redo(callback); | |
1983 }, | |
1984 | |
1985 /** | |
1986 * @param {?WebInspector.DOMNodeHighlighter} highlighter | |
1987 */ | |
1988 setHighlighter: function(highlighter) | |
1989 { | |
1990 this._highlighter = highlighter || this._defaultHighlighter; | |
1991 }, | |
1992 | |
1993 /** | |
1994 * @param {number} x | |
1995 * @param {number} y | |
1996 * @param {function(?WebInspector.DOMNode)} callback | |
1997 */ | |
1998 nodeForLocation: function(x, y, callback) | |
1999 { | |
2000 this._agent.getNodeForLocation(x, y, mycallback.bind(this)); | |
2001 | |
2002 /** | |
2003 * @param {?Protocol.Error} error | |
2004 * @param {number} nodeId | |
2005 * @this {WebInspector.DOMModel} | |
2006 */ | |
2007 function mycallback(error, nodeId) | |
2008 { | |
2009 if (error) { | |
2010 callback(null); | |
2011 return; | |
2012 } | |
2013 callback(this.nodeForId(nodeId)); | |
2014 } | |
2015 }, | |
2016 | |
2017 /** | |
2018 * @param {!WebInspector.RemoteObject} object | |
2019 * @param {function(?WebInspector.DOMNode)} callback | |
2020 */ | |
2021 pushObjectAsNodeToFrontend: function(object, callback) | |
2022 { | |
2023 if (object.isNode()) | |
2024 this.pushNodeToFrontend(object.objectId, callback); | |
2025 else | |
2026 callback(null); | |
2027 }, | |
2028 | |
2029 /** | |
2030 * @override | |
2031 * @return {!Promise} | |
2032 */ | |
2033 suspendModel: function() | |
2034 { | |
2035 return new Promise(promiseBody.bind(this)); | |
2036 | |
2037 /** | |
2038 * @param {function()} fulfill | |
2039 * @this {WebInspector.DOMModel} | |
2040 */ | |
2041 function promiseBody(fulfill) | |
2042 { | |
2043 this._agent.disable(callback.bind(this)); | |
2044 | |
2045 /** | |
2046 * @this {WebInspector.DOMModel} | |
2047 */ | |
2048 function callback() | |
2049 { | |
2050 this._setDocument(null); | |
2051 fulfill(); | |
2052 } | |
2053 } | |
2054 }, | |
2055 | |
2056 /** | |
2057 * @override | |
2058 * @return {!Promise} | |
2059 */ | |
2060 resumeModel: function() | |
2061 { | |
2062 return new Promise(promiseBody.bind(this)); | |
2063 | |
2064 /** | |
2065 * @param {function()} fulfill | |
2066 * @this {WebInspector.DOMModel} | |
2067 */ | |
2068 function promiseBody(fulfill) | |
2069 { | |
2070 this._agent.enable(fulfill); | |
2071 } | |
2072 }, | |
2073 | |
2074 /** | |
2075 * @param {!DOMAgent.NodeId} nodeId | |
2076 */ | |
2077 nodeHighlightRequested: function(nodeId) | |
2078 { | |
2079 var node = this.nodeForId(nodeId); | |
2080 if (!node) | |
2081 return; | |
2082 | |
2083 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeHighlight
edInOverlay, node); | |
2084 }, | |
2085 | |
2086 __proto__: WebInspector.SDKModel.prototype | |
2087 }; | |
2088 | |
2089 /** | |
2090 * @constructor | |
2091 * @implements {DOMAgent.Dispatcher} | |
2092 * @param {!WebInspector.DOMModel} domModel | |
2093 */ | |
2094 WebInspector.DOMDispatcher = function(domModel) | |
2095 { | |
2096 this._domModel = domModel; | 1948 this._domModel = domModel; |
2097 }; | 1949 } |
2098 | 1950 |
2099 WebInspector.DOMDispatcher.prototype = { | 1951 /** |
2100 /** | 1952 * @override |
2101 * @override | 1953 */ |
2102 */ | 1954 documentUpdated() { |
2103 documentUpdated: function() | 1955 this._domModel._documentUpdated(); |
2104 { | 1956 } |
2105 this._domModel._documentUpdated(); | 1957 |
2106 }, | 1958 /** |
2107 | 1959 * @override |
2108 /** | 1960 * @param {!DOMAgent.NodeId} nodeId |
2109 * @override | 1961 */ |
2110 * @param {!DOMAgent.NodeId} nodeId | 1962 inspectNodeRequested(nodeId) { |
2111 */ | 1963 this._domModel._inspectNodeRequested(nodeId); |
2112 inspectNodeRequested: function(nodeId) | 1964 } |
2113 { | 1965 |
2114 this._domModel._inspectNodeRequested(nodeId); | 1966 /** |
2115 }, | 1967 * @override |
2116 | 1968 * @param {!DOMAgent.NodeId} nodeId |
2117 /** | 1969 * @param {string} name |
2118 * @override | 1970 * @param {string} value |
2119 * @param {!DOMAgent.NodeId} nodeId | 1971 */ |
2120 * @param {string} name | 1972 attributeModified(nodeId, name, value) { |
2121 * @param {string} value | 1973 this._domModel._attributeModified(nodeId, name, value); |
2122 */ | 1974 } |
2123 attributeModified: function(nodeId, name, value) | 1975 |
2124 { | 1976 /** |
2125 this._domModel._attributeModified(nodeId, name, value); | 1977 * @override |
2126 }, | 1978 * @param {!DOMAgent.NodeId} nodeId |
2127 | 1979 * @param {string} name |
2128 /** | 1980 */ |
2129 * @override | 1981 attributeRemoved(nodeId, name) { |
2130 * @param {!DOMAgent.NodeId} nodeId | 1982 this._domModel._attributeRemoved(nodeId, name); |
2131 * @param {string} name | 1983 } |
2132 */ | 1984 |
2133 attributeRemoved: function(nodeId, name) | 1985 /** |
2134 { | 1986 * @override |
2135 this._domModel._attributeRemoved(nodeId, name); | 1987 * @param {!Array.<!DOMAgent.NodeId>} nodeIds |
2136 }, | 1988 */ |
2137 | 1989 inlineStyleInvalidated(nodeIds) { |
2138 /** | 1990 this._domModel._inlineStyleInvalidated(nodeIds); |
2139 * @override | 1991 } |
2140 * @param {!Array.<!DOMAgent.NodeId>} nodeIds | 1992 |
2141 */ | 1993 /** |
2142 inlineStyleInvalidated: function(nodeIds) | 1994 * @override |
2143 { | 1995 * @param {!DOMAgent.NodeId} nodeId |
2144 this._domModel._inlineStyleInvalidated(nodeIds); | 1996 * @param {string} characterData |
2145 }, | 1997 */ |
2146 | 1998 characterDataModified(nodeId, characterData) { |
2147 /** | 1999 this._domModel._characterDataModified(nodeId, characterData); |
2148 * @override | 2000 } |
2149 * @param {!DOMAgent.NodeId} nodeId | 2001 |
2150 * @param {string} characterData | 2002 /** |
2151 */ | 2003 * @override |
2152 characterDataModified: function(nodeId, characterData) | 2004 * @param {!DOMAgent.NodeId} parentId |
2153 { | 2005 * @param {!Array.<!DOMAgent.Node>} payloads |
2154 this._domModel._characterDataModified(nodeId, characterData); | 2006 */ |
2155 }, | 2007 setChildNodes(parentId, payloads) { |
2156 | 2008 this._domModel._setChildNodes(parentId, payloads); |
2157 /** | 2009 } |
2158 * @override | 2010 |
2159 * @param {!DOMAgent.NodeId} parentId | 2011 /** |
2160 * @param {!Array.<!DOMAgent.Node>} payloads | 2012 * @override |
2161 */ | 2013 * @param {!DOMAgent.NodeId} nodeId |
2162 setChildNodes: function(parentId, payloads) | 2014 * @param {number} childNodeCount |
2163 { | 2015 */ |
2164 this._domModel._setChildNodes(parentId, payloads); | 2016 childNodeCountUpdated(nodeId, childNodeCount) { |
2165 }, | 2017 this._domModel._childNodeCountUpdated(nodeId, childNodeCount); |
2166 | 2018 } |
2167 /** | 2019 |
2168 * @override | 2020 /** |
2169 * @param {!DOMAgent.NodeId} nodeId | 2021 * @override |
2170 * @param {number} childNodeCount | 2022 * @param {!DOMAgent.NodeId} parentNodeId |
2171 */ | 2023 * @param {!DOMAgent.NodeId} previousNodeId |
2172 childNodeCountUpdated: function(nodeId, childNodeCount) | 2024 * @param {!DOMAgent.Node} payload |
2173 { | 2025 */ |
2174 this._domModel._childNodeCountUpdated(nodeId, childNodeCount); | 2026 childNodeInserted(parentNodeId, previousNodeId, payload) { |
2175 }, | 2027 this._domModel._childNodeInserted(parentNodeId, previousNodeId, payload); |
2176 | 2028 } |
2177 /** | 2029 |
2178 * @override | 2030 /** |
2179 * @param {!DOMAgent.NodeId} parentNodeId | 2031 * @override |
2180 * @param {!DOMAgent.NodeId} previousNodeId | 2032 * @param {!DOMAgent.NodeId} parentNodeId |
2181 * @param {!DOMAgent.Node} payload | 2033 * @param {!DOMAgent.NodeId} nodeId |
2182 */ | 2034 */ |
2183 childNodeInserted: function(parentNodeId, previousNodeId, payload) | 2035 childNodeRemoved(parentNodeId, nodeId) { |
2184 { | 2036 this._domModel._childNodeRemoved(parentNodeId, nodeId); |
2185 this._domModel._childNodeInserted(parentNodeId, previousNodeId, payload)
; | 2037 } |
2186 }, | 2038 |
2187 | 2039 /** |
2188 /** | 2040 * @override |
2189 * @override | 2041 * @param {!DOMAgent.NodeId} hostId |
2190 * @param {!DOMAgent.NodeId} parentNodeId | 2042 * @param {!DOMAgent.Node} root |
2191 * @param {!DOMAgent.NodeId} nodeId | 2043 */ |
2192 */ | 2044 shadowRootPushed(hostId, root) { |
2193 childNodeRemoved: function(parentNodeId, nodeId) | 2045 this._domModel._shadowRootPushed(hostId, root); |
2194 { | 2046 } |
2195 this._domModel._childNodeRemoved(parentNodeId, nodeId); | 2047 |
2196 }, | 2048 /** |
2197 | 2049 * @override |
2198 /** | 2050 * @param {!DOMAgent.NodeId} hostId |
2199 * @override | 2051 * @param {!DOMAgent.NodeId} rootId |
2200 * @param {!DOMAgent.NodeId} hostId | 2052 */ |
2201 * @param {!DOMAgent.Node} root | 2053 shadowRootPopped(hostId, rootId) { |
2202 */ | 2054 this._domModel._shadowRootPopped(hostId, rootId); |
2203 shadowRootPushed: function(hostId, root) | 2055 } |
2204 { | 2056 |
2205 this._domModel._shadowRootPushed(hostId, root); | 2057 /** |
2206 }, | 2058 * @override |
2207 | 2059 * @param {!DOMAgent.NodeId} parentId |
2208 /** | 2060 * @param {!DOMAgent.Node} pseudoElement |
2209 * @override | 2061 */ |
2210 * @param {!DOMAgent.NodeId} hostId | 2062 pseudoElementAdded(parentId, pseudoElement) { |
2211 * @param {!DOMAgent.NodeId} rootId | 2063 this._domModel._pseudoElementAdded(parentId, pseudoElement); |
2212 */ | 2064 } |
2213 shadowRootPopped: function(hostId, rootId) | 2065 |
2214 { | 2066 /** |
2215 this._domModel._shadowRootPopped(hostId, rootId); | 2067 * @override |
2216 }, | 2068 * @param {!DOMAgent.NodeId} parentId |
2217 | 2069 * @param {!DOMAgent.NodeId} pseudoElementId |
2218 /** | 2070 */ |
2219 * @override | 2071 pseudoElementRemoved(parentId, pseudoElementId) { |
2220 * @param {!DOMAgent.NodeId} parentId | 2072 this._domModel._pseudoElementRemoved(parentId, pseudoElementId); |
2221 * @param {!DOMAgent.Node} pseudoElement | 2073 } |
2222 */ | 2074 |
2223 pseudoElementAdded: function(parentId, pseudoElement) | 2075 /** |
2224 { | 2076 * @override |
2225 this._domModel._pseudoElementAdded(parentId, pseudoElement); | 2077 * @param {!DOMAgent.NodeId} insertionPointId |
2226 }, | 2078 * @param {!Array.<!DOMAgent.BackendNode>} distributedNodes |
2227 | 2079 */ |
2228 /** | 2080 distributedNodesUpdated(insertionPointId, distributedNodes) { |
2229 * @override | 2081 this._domModel._distributedNodesUpdated(insertionPointId, distributedNodes); |
2230 * @param {!DOMAgent.NodeId} parentId | 2082 } |
2231 * @param {!DOMAgent.NodeId} pseudoElementId | 2083 |
2232 */ | 2084 /** |
2233 pseudoElementRemoved: function(parentId, pseudoElementId) | 2085 * @override |
2234 { | 2086 * @param {!DOMAgent.NodeId} nodeId |
2235 this._domModel._pseudoElementRemoved(parentId, pseudoElementId); | 2087 */ |
2236 }, | 2088 nodeHighlightRequested(nodeId) { |
2237 | 2089 this._domModel.nodeHighlightRequested(nodeId); |
2238 /** | 2090 } |
2239 * @override | |
2240 * @param {!DOMAgent.NodeId} insertionPointId | |
2241 * @param {!Array.<!DOMAgent.BackendNode>} distributedNodes | |
2242 */ | |
2243 distributedNodesUpdated: function(insertionPointId, distributedNodes) | |
2244 { | |
2245 this._domModel._distributedNodesUpdated(insertionPointId, distributedNod
es); | |
2246 }, | |
2247 | |
2248 /** | |
2249 * @override | |
2250 * @param {!DOMAgent.NodeId} nodeId | |
2251 */ | |
2252 nodeHighlightRequested: function(nodeId) | |
2253 { | |
2254 this._domModel.nodeHighlightRequested(nodeId); | |
2255 } | |
2256 }; | 2091 }; |
2257 | 2092 |
2258 /** | 2093 /** |
2259 * @interface | 2094 * @interface |
2260 */ | 2095 */ |
2261 WebInspector.DOMNodeHighlighter = function() { | 2096 WebInspector.DOMNodeHighlighter = function() {}; |
| 2097 |
| 2098 WebInspector.DOMNodeHighlighter.prototype = { |
| 2099 /** |
| 2100 * @param {?WebInspector.DOMNode} node |
| 2101 * @param {!DOMAgent.HighlightConfig} config |
| 2102 * @param {!DOMAgent.BackendNodeId=} backendNodeId |
| 2103 * @param {!RuntimeAgent.RemoteObjectId=} objectId |
| 2104 */ |
| 2105 highlightDOMNode: function(node, config, backendNodeId, objectId) {}, |
| 2106 |
| 2107 /** |
| 2108 * @param {!DOMAgent.InspectMode} mode |
| 2109 * @param {!DOMAgent.HighlightConfig} config |
| 2110 * @param {function(?Protocol.Error)=} callback |
| 2111 */ |
| 2112 setInspectMode: function(mode, config, callback) {}, |
| 2113 |
| 2114 /** |
| 2115 * @param {!PageAgent.FrameId} frameId |
| 2116 */ |
| 2117 highlightFrame: function(frameId) {} |
2262 }; | 2118 }; |
2263 | 2119 |
2264 WebInspector.DOMNodeHighlighter.prototype = { | 2120 /** |
2265 /** | 2121 * @implements {WebInspector.DOMNodeHighlighter} |
2266 * @param {?WebInspector.DOMNode} node | 2122 * @unrestricted |
2267 * @param {!DOMAgent.HighlightConfig} config | 2123 */ |
2268 * @param {!DOMAgent.BackendNodeId=} backendNodeId | 2124 WebInspector.DefaultDOMNodeHighlighter = class { |
2269 * @param {!RuntimeAgent.RemoteObjectId=} objectId | 2125 /** |
2270 */ | 2126 * @param {!Protocol.DOMAgent} agent |
2271 highlightDOMNode: function(node, config, backendNodeId, objectId) {}, | 2127 */ |
2272 | 2128 constructor(agent) { |
2273 /** | 2129 this._agent = agent; |
2274 * @param {!DOMAgent.InspectMode} mode | 2130 } |
2275 * @param {!DOMAgent.HighlightConfig} config | 2131 |
2276 * @param {function(?Protocol.Error)=} callback | 2132 /** |
2277 */ | 2133 * @override |
2278 setInspectMode: function(mode, config, callback) {}, | 2134 * @param {?WebInspector.DOMNode} node |
2279 | 2135 * @param {!DOMAgent.HighlightConfig} config |
2280 /** | 2136 * @param {!DOMAgent.BackendNodeId=} backendNodeId |
2281 * @param {!PageAgent.FrameId} frameId | 2137 * @param {!RuntimeAgent.RemoteObjectId=} objectId |
2282 */ | 2138 */ |
2283 highlightFrame: function(frameId) {} | 2139 highlightDOMNode(node, config, backendNodeId, objectId) { |
| 2140 if (objectId || node || backendNodeId) |
| 2141 this._agent.highlightNode(config, (objectId || backendNodeId) ? undefined
: node.id, backendNodeId, objectId); |
| 2142 else |
| 2143 this._agent.hideHighlight(); |
| 2144 } |
| 2145 |
| 2146 /** |
| 2147 * @override |
| 2148 * @param {!DOMAgent.InspectMode} mode |
| 2149 * @param {!DOMAgent.HighlightConfig} config |
| 2150 * @param {function(?Protocol.Error)=} callback |
| 2151 */ |
| 2152 setInspectMode(mode, config, callback) { |
| 2153 this._agent.setInspectMode(mode, config, callback); |
| 2154 } |
| 2155 |
| 2156 /** |
| 2157 * @override |
| 2158 * @param {!PageAgent.FrameId} frameId |
| 2159 */ |
| 2160 highlightFrame(frameId) { |
| 2161 this._agent.highlightFrame( |
| 2162 frameId, WebInspector.Color.PageHighlight.Content.toProtocolRGBA(), |
| 2163 WebInspector.Color.PageHighlight.ContentOutline.toProtocolRGBA()); |
| 2164 } |
2284 }; | 2165 }; |
2285 | 2166 |
2286 /** | 2167 |
2287 * @constructor | |
2288 * @implements {WebInspector.DOMNodeHighlighter} | |
2289 * @param {!Protocol.DOMAgent} agent | |
2290 */ | |
2291 WebInspector.DefaultDOMNodeHighlighter = function(agent) | |
2292 { | |
2293 this._agent = agent; | |
2294 }; | |
2295 | |
2296 WebInspector.DefaultDOMNodeHighlighter.prototype = { | |
2297 /** | |
2298 * @override | |
2299 * @param {?WebInspector.DOMNode} node | |
2300 * @param {!DOMAgent.HighlightConfig} config | |
2301 * @param {!DOMAgent.BackendNodeId=} backendNodeId | |
2302 * @param {!RuntimeAgent.RemoteObjectId=} objectId | |
2303 */ | |
2304 highlightDOMNode: function(node, config, backendNodeId, objectId) | |
2305 { | |
2306 if (objectId || node || backendNodeId) | |
2307 this._agent.highlightNode(config, (objectId || backendNodeId) ? unde
fined : node.id, backendNodeId, objectId); | |
2308 else | |
2309 this._agent.hideHighlight(); | |
2310 }, | |
2311 | |
2312 /** | |
2313 * @override | |
2314 * @param {!DOMAgent.InspectMode} mode | |
2315 * @param {!DOMAgent.HighlightConfig} config | |
2316 * @param {function(?Protocol.Error)=} callback | |
2317 */ | |
2318 setInspectMode: function(mode, config, callback) | |
2319 { | |
2320 this._agent.setInspectMode(mode, config, callback); | |
2321 }, | |
2322 | |
2323 /** | |
2324 * @override | |
2325 * @param {!PageAgent.FrameId} frameId | |
2326 */ | |
2327 highlightFrame: function(frameId) | |
2328 { | |
2329 this._agent.highlightFrame(frameId, WebInspector.Color.PageHighlight.Con
tent.toProtocolRGBA(), WebInspector.Color.PageHighlight.ContentOutline.toProtoco
lRGBA()); | |
2330 } | |
2331 }; | |
2332 | |
2333 /** | |
2334 * @param {!WebInspector.Target} target | |
2335 * @return {?WebInspector.DOMModel} | |
2336 */ | |
2337 WebInspector.DOMModel.fromTarget = function(target) | |
2338 { | |
2339 return /** @type {?WebInspector.DOMModel} */ (target.model(WebInspector.DOMM
odel)); | |
2340 }; | |
OLD | NEW |