OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. | |
3 * Copyright (C) 2009 Joseph Pecoraro | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are | |
7 * met: | |
8 * | |
9 * * Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * * Redistributions in binary form must reproduce the above | |
12 * copyright notice, this list of conditions and the following disclaimer | |
13 * in the documentation and/or other materials provided with the | |
14 * distribution. | |
15 * * Neither the name of Google Inc. nor the names of its | |
16 * contributors may be used to endorse or promote products derived from | |
17 * this software without specific prior written permission. | |
18 * | |
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
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. | |
30 */ | |
31 | |
32 /** | |
33 * @constructor | |
34 * @param {!WebInspector.DOMAgent} domAgent | |
35 * @param {?WebInspector.DOMDocument} doc | |
36 * @param {boolean} isInShadowTree | |
37 * @param {!DOMAgent.Node} payload | |
38 */ | |
39 WebInspector.DOMNode = function(domAgent, doc, isInShadowTree, payload) { | |
40 this._domAgent = domAgent; | |
41 this.ownerDocument = doc; | |
42 this._isInShadowTree = isInShadowTree; | |
43 | |
44 this.id = payload.nodeId; | |
45 domAgent._idToDOMNode[this.id] = this; | |
46 this._nodeType = payload.nodeType; | |
47 this._nodeName = payload.nodeName; | |
48 this._localName = payload.localName; | |
49 this._nodeValue = payload.nodeValue; | |
50 this._pseudoType = payload.pseudoType; | |
51 this._shadowRootType = payload.shadowRootType; | |
52 this._frameId = payload.frameId || null; | |
53 | |
54 this._shadowRoots = []; | |
55 | |
56 this._attributes = []; | |
57 this._attributesMap = {}; | |
58 if (payload.attributes) | |
59 this._setAttributesPayload(payload.attributes); | |
60 | |
61 this._userProperties = {}; | |
62 this._descendantUserPropertyCounters = {}; | |
63 | |
64 this._childNodeCount = payload.childNodeCount || 0; | |
65 this._children = null; | |
66 | |
67 this.nextSibling = null; | |
68 this.previousSibling = null; | |
69 this.firstChild = null; | |
70 this.lastChild = null; | |
71 this.parentNode = null; | |
72 | |
73 if (payload.shadowRoots) { | |
74 for (var i = 0; i < payload.shadowRoots.length; ++i) { | |
75 var root = payload.shadowRoots[i]; | |
76 var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocume
nt, true, root); | |
77 this._shadowRoots.push(node); | |
78 node.parentNode = this; | |
79 } | |
80 } | |
81 | |
82 if (payload.templateContent) { | |
83 this._templateContent = new WebInspector.DOMNode(this._domAgent, this.ow
nerDocument, true, payload.templateContent); | |
84 this._templateContent.parentNode = this; | |
85 } | |
86 | |
87 if (payload.importedDocument) { | |
88 this._importedDocument = new WebInspector.DOMNode(this._domAgent, this.o
wnerDocument, true, payload.importedDocument); | |
89 this._importedDocument.parentNode = this; | |
90 } | |
91 | |
92 if (payload.children) | |
93 this._setChildrenPayload(payload.children); | |
94 | |
95 this._setPseudoElements(payload.pseudoElements); | |
96 | |
97 if (payload.contentDocument) { | |
98 this._contentDocument = new WebInspector.DOMDocument(domAgent, payload.c
ontentDocument); | |
99 this._children = [this._contentDocument]; | |
100 this._renumber(); | |
101 } | |
102 | |
103 if (this._nodeType === Node.ELEMENT_NODE) { | |
104 // HTML and BODY from internal iframes should not overwrite top-level on
es. | |
105 if (this.ownerDocument && !this.ownerDocument.documentElement && this._n
odeName === "HTML") | |
106 this.ownerDocument.documentElement = this; | |
107 if (this.ownerDocument && !this.ownerDocument.body && this._nodeName ===
"BODY") | |
108 this.ownerDocument.body = this; | |
109 } else if (this._nodeType === Node.DOCUMENT_TYPE_NODE) { | |
110 this.publicId = payload.publicId; | |
111 this.systemId = payload.systemId; | |
112 this.internalSubset = payload.internalSubset; | |
113 } else if (this._nodeType === Node.ATTRIBUTE_NODE) { | |
114 this.name = payload.name; | |
115 this.value = payload.value; | |
116 } | |
117 } | |
118 | |
119 /** | |
120 * @enum {string} | |
121 */ | |
122 WebInspector.DOMNode.PseudoElementNames = { | |
123 Before: "before", | |
124 After: "after" | |
125 } | |
126 | |
127 /** | |
128 * @enum {string} | |
129 */ | |
130 WebInspector.DOMNode.ShadowRootTypes = { | |
131 UserAgent: "user-agent", | |
132 Author: "author" | |
133 } | |
134 | |
135 WebInspector.DOMNode.prototype = { | |
136 /** | |
137 * @return {?Array.<!WebInspector.DOMNode>} | |
138 */ | |
139 children: function() | |
140 { | |
141 return this._children ? this._children.slice() : null; | |
142 }, | |
143 | |
144 /** | |
145 * @return {boolean} | |
146 */ | |
147 hasAttributes: function() | |
148 { | |
149 return this._attributes.length > 0; | |
150 }, | |
151 | |
152 /** | |
153 * @return {number} | |
154 */ | |
155 childNodeCount: function() | |
156 { | |
157 return this._childNodeCount; | |
158 }, | |
159 | |
160 /** | |
161 * @return {boolean} | |
162 */ | |
163 hasShadowRoots: function() | |
164 { | |
165 return !!this._shadowRoots.length; | |
166 }, | |
167 | |
168 /** | |
169 * @return {!Array.<!WebInspector.DOMNode>} | |
170 */ | |
171 shadowRoots: function() | |
172 { | |
173 return this._shadowRoots.slice(); | |
174 }, | |
175 | |
176 /** | |
177 * @return {?WebInspector.DOMNode} | |
178 */ | |
179 templateContent: function() | |
180 { | |
181 return this._templateContent; | |
182 }, | |
183 | |
184 /** | |
185 * @return {?WebInspector.DOMNode} | |
186 */ | |
187 importedDocument: function() | |
188 { | |
189 return this._importedDocument; | |
190 }, | |
191 | |
192 /** | |
193 * @return {number} | |
194 */ | |
195 nodeType: function() | |
196 { | |
197 return this._nodeType; | |
198 }, | |
199 | |
200 /** | |
201 * @return {string} | |
202 */ | |
203 nodeName: function() | |
204 { | |
205 return this._nodeName; | |
206 }, | |
207 | |
208 /** | |
209 * @return {string|undefined} | |
210 */ | |
211 pseudoType: function() | |
212 { | |
213 return this._pseudoType; | |
214 }, | |
215 | |
216 /** | |
217 * @return {boolean} | |
218 */ | |
219 hasPseudoElements: function() | |
220 { | |
221 return Object.keys(this._pseudoElements).length !== 0; | |
222 }, | |
223 | |
224 /** | |
225 * @return {!Object.<string, !WebInspector.DOMNode>} | |
226 */ | |
227 pseudoElements: function() | |
228 { | |
229 return this._pseudoElements; | |
230 }, | |
231 | |
232 /** | |
233 * @return {boolean} | |
234 */ | |
235 isInShadowTree: function() | |
236 { | |
237 return this._isInShadowTree; | |
238 }, | |
239 | |
240 /** | |
241 * @return {?WebInspector.DOMNode} | |
242 */ | |
243 ancestorUserAgentShadowRoot: function() | |
244 { | |
245 if (!this._isInShadowTree) | |
246 return null; | |
247 | |
248 var current = this; | |
249 while (!current.isShadowRoot()) | |
250 current = current.parentNode; | |
251 return current.shadowRootType() === WebInspector.DOMNode.ShadowRootTypes
.UserAgent ? current : null; | |
252 }, | |
253 | |
254 /** | |
255 * @return {boolean} | |
256 */ | |
257 isShadowRoot: function() | |
258 { | |
259 return !!this._shadowRootType; | |
260 }, | |
261 | |
262 /** | |
263 * @return {?string} | |
264 */ | |
265 shadowRootType: function() | |
266 { | |
267 return this._shadowRootType || null; | |
268 }, | |
269 | |
270 /** | |
271 * @return {string} | |
272 */ | |
273 nodeNameInCorrectCase: function() | |
274 { | |
275 var shadowRootType = this.shadowRootType(); | |
276 if (shadowRootType) | |
277 return "#shadow-root" + (shadowRootType === WebInspector.DOMNode.Sha
dowRootTypes.UserAgent ? " (user-agent)" : ""); | |
278 return this.isXMLNode() ? this.nodeName() : this.nodeName().toLowerCase(
); | |
279 }, | |
280 | |
281 /** | |
282 * @param {string} name | |
283 * @param {function(?Protocol.Error)=} callback | |
284 */ | |
285 setNodeName: function(name, callback) | |
286 { | |
287 DOMAgent.setNodeName(this.id, name, WebInspector.domAgent._markRevision(
this, callback)); | |
288 }, | |
289 | |
290 /** | |
291 * @return {string} | |
292 */ | |
293 localName: function() | |
294 { | |
295 return this._localName; | |
296 }, | |
297 | |
298 /** | |
299 * @return {string} | |
300 */ | |
301 nodeValue: function() | |
302 { | |
303 return this._nodeValue; | |
304 }, | |
305 | |
306 /** | |
307 * @param {string} value | |
308 * @param {function(?Protocol.Error)=} callback | |
309 */ | |
310 setNodeValue: function(value, callback) | |
311 { | |
312 DOMAgent.setNodeValue(this.id, value, WebInspector.domAgent._markRevisio
n(this, callback)); | |
313 }, | |
314 | |
315 /** | |
316 * @param {string} name | |
317 * @return {string} | |
318 */ | |
319 getAttribute: function(name) | |
320 { | |
321 var attr = this._attributesMap[name]; | |
322 return attr ? attr.value : undefined; | |
323 }, | |
324 | |
325 /** | |
326 * @param {string} name | |
327 * @param {string} text | |
328 * @param {function(?Protocol.Error)=} callback | |
329 */ | |
330 setAttribute: function(name, text, callback) | |
331 { | |
332 DOMAgent.setAttributesAsText(this.id, text, name, WebInspector.domAgent.
_markRevision(this, callback)); | |
333 }, | |
334 | |
335 /** | |
336 * @param {string} name | |
337 * @param {string} value | |
338 * @param {function(?Protocol.Error)=} callback | |
339 */ | |
340 setAttributeValue: function(name, value, callback) | |
341 { | |
342 DOMAgent.setAttributeValue(this.id, name, value, WebInspector.domAgent._
markRevision(this, callback)); | |
343 }, | |
344 | |
345 /** | |
346 * @return {!Object} | |
347 */ | |
348 attributes: function() | |
349 { | |
350 return this._attributes; | |
351 }, | |
352 | |
353 /** | |
354 * @param {string} name | |
355 * @param {function(?Protocol.Error)=} callback | |
356 */ | |
357 removeAttribute: function(name, callback) | |
358 { | |
359 /** | |
360 * @param {?Protocol.Error} error | |
361 * @this {WebInspector.DOMNode} | |
362 */ | |
363 function mycallback(error) | |
364 { | |
365 if (!error) { | |
366 delete this._attributesMap[name]; | |
367 for (var i = 0; i < this._attributes.length; ++i) { | |
368 if (this._attributes[i].name === name) { | |
369 this._attributes.splice(i, 1); | |
370 break; | |
371 } | |
372 } | |
373 } | |
374 | |
375 WebInspector.domAgent._markRevision(this, callback)(error); | |
376 } | |
377 DOMAgent.removeAttribute(this.id, name, mycallback.bind(this)); | |
378 }, | |
379 | |
380 /** | |
381 * @param {function(?Array.<!WebInspector.DOMNode>)=} callback | |
382 */ | |
383 getChildNodes: function(callback) | |
384 { | |
385 if (this._children) { | |
386 if (callback) | |
387 callback(this.children()); | |
388 return; | |
389 } | |
390 | |
391 /** | |
392 * @this {WebInspector.DOMNode} | |
393 * @param {?Protocol.Error} error | |
394 */ | |
395 function mycallback(error) | |
396 { | |
397 if (callback) | |
398 callback(error ? null : this.children()); | |
399 } | |
400 | |
401 DOMAgent.requestChildNodes(this.id, undefined, mycallback.bind(this)); | |
402 }, | |
403 | |
404 /** | |
405 * @param {number} depth | |
406 * @param {function(?Array.<!WebInspector.DOMNode>)=} callback | |
407 */ | |
408 getSubtree: function(depth, callback) | |
409 { | |
410 /** | |
411 * @this {WebInspector.DOMNode} | |
412 * @param {?Protocol.Error} error | |
413 */ | |
414 function mycallback(error) | |
415 { | |
416 if (callback) | |
417 callback(error ? null : this._children); | |
418 } | |
419 | |
420 DOMAgent.requestChildNodes(this.id, depth, mycallback.bind(this)); | |
421 }, | |
422 | |
423 /** | |
424 * @param {function(?Protocol.Error)=} callback | |
425 */ | |
426 getOuterHTML: function(callback) | |
427 { | |
428 DOMAgent.getOuterHTML(this.id, callback); | |
429 }, | |
430 | |
431 /** | |
432 * @param {string} html | |
433 * @param {function(?Protocol.Error)=} callback | |
434 */ | |
435 setOuterHTML: function(html, callback) | |
436 { | |
437 DOMAgent.setOuterHTML(this.id, html, WebInspector.domAgent._markRevision
(this, callback)); | |
438 }, | |
439 | |
440 /** | |
441 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback | |
442 */ | |
443 removeNode: function(callback) | |
444 { | |
445 DOMAgent.removeNode(this.id, WebInspector.domAgent._markRevision(this, c
allback)); | |
446 }, | |
447 | |
448 copyNode: function() | |
449 { | |
450 function copy(error, text) | |
451 { | |
452 if (!error) | |
453 InspectorFrontendHost.copyText(text); | |
454 } | |
455 DOMAgent.getOuterHTML(this.id, copy); | |
456 }, | |
457 | |
458 /** | |
459 * @param {string} objectGroupId | |
460 * @param {function(?Protocol.Error)=} callback | |
461 */ | |
462 eventListeners: function(objectGroupId, callback) | |
463 { | |
464 DOMAgent.getEventListenersForNode(this.id, objectGroupId, callback); | |
465 }, | |
466 | |
467 /** | |
468 * @return {string} | |
469 */ | |
470 path: function() | |
471 { | |
472 /** | |
473 * @param {?WebInspector.DOMNode} node | |
474 */ | |
475 function canPush(node) | |
476 { | |
477 return node && ("index" in node || (node.isShadowRoot() && node.pare
ntNode)) && node._nodeName.length; | |
478 } | |
479 | |
480 var path = []; | |
481 var node = this; | |
482 while (canPush(node)) { | |
483 var index = typeof node.index === "number" ? node.index : (node.shad
owRootType() === WebInspector.DOMNode.ShadowRootTypes.UserAgent ? "u" : "a"); | |
484 path.push([index, node._nodeName]); | |
485 node = node.parentNode; | |
486 } | |
487 path.reverse(); | |
488 return path.join(","); | |
489 }, | |
490 | |
491 /** | |
492 * @param {!WebInspector.DOMNode} node | |
493 * @return {boolean} | |
494 */ | |
495 isAncestor: function(node) | |
496 { | |
497 if (!node) | |
498 return false; | |
499 | |
500 var currentNode = node.parentNode; | |
501 while (currentNode) { | |
502 if (this === currentNode) | |
503 return true; | |
504 currentNode = currentNode.parentNode; | |
505 } | |
506 return false; | |
507 }, | |
508 | |
509 /** | |
510 * @param {!WebInspector.DOMNode} descendant | |
511 * @return {boolean} | |
512 */ | |
513 isDescendant: function(descendant) | |
514 { | |
515 return descendant !== null && descendant.isAncestor(this); | |
516 }, | |
517 | |
518 /** | |
519 * @return {?PageAgent.FrameId} | |
520 */ | |
521 frameId: function() | |
522 { | |
523 var node = this; | |
524 while (!node._frameId && node.parentNode) | |
525 node = node.parentNode; | |
526 return node._frameId; | |
527 }, | |
528 | |
529 /** | |
530 * @param {!Array.<string>} attrs | |
531 * @return {boolean} | |
532 */ | |
533 _setAttributesPayload: function(attrs) | |
534 { | |
535 var attributesChanged = !this._attributes || attrs.length !== this._attr
ibutes.length * 2; | |
536 var oldAttributesMap = this._attributesMap || {}; | |
537 | |
538 this._attributes = []; | |
539 this._attributesMap = {}; | |
540 | |
541 for (var i = 0; i < attrs.length; i += 2) { | |
542 var name = attrs[i]; | |
543 var value = attrs[i + 1]; | |
544 this._addAttribute(name, value); | |
545 | |
546 if (attributesChanged) | |
547 continue; | |
548 | |
549 if (!oldAttributesMap[name] || oldAttributesMap[name].value !== valu
e) | |
550 attributesChanged = true; | |
551 } | |
552 return attributesChanged; | |
553 }, | |
554 | |
555 /** | |
556 * @param {!WebInspector.DOMNode} prev | |
557 * @param {!DOMAgent.Node} payload | |
558 * @return {!WebInspector.DOMNode} | |
559 */ | |
560 _insertChild: function(prev, payload) | |
561 { | |
562 var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument,
this._isInShadowTree, payload); | |
563 this._children.splice(this._children.indexOf(prev) + 1, 0, node); | |
564 this._renumber(); | |
565 return node; | |
566 }, | |
567 | |
568 /** | |
569 * @param {!WebInspector.DOMNode} node | |
570 */ | |
571 _removeChild: function(node) | |
572 { | |
573 if (node.pseudoType()) { | |
574 delete this._pseudoElements[node.pseudoType()]; | |
575 } else { | |
576 var shadowRootIndex = this._shadowRoots.indexOf(node); | |
577 if (shadowRootIndex !== -1) | |
578 this._shadowRoots.splice(shadowRootIndex, 1); | |
579 else | |
580 this._children.splice(this._children.indexOf(node), 1); | |
581 } | |
582 node.parentNode = null; | |
583 node._updateChildUserPropertyCountsOnRemoval(this); | |
584 this._renumber(); | |
585 }, | |
586 | |
587 /** | |
588 * @param {!Array.<!DOMAgent.Node>} payloads | |
589 */ | |
590 _setChildrenPayload: function(payloads) | |
591 { | |
592 // We set children in the constructor. | |
593 if (this._contentDocument) | |
594 return; | |
595 | |
596 this._children = []; | |
597 for (var i = 0; i < payloads.length; ++i) { | |
598 var payload = payloads[i]; | |
599 var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocume
nt, this._isInShadowTree, payload); | |
600 this._children.push(node); | |
601 } | |
602 this._renumber(); | |
603 }, | |
604 | |
605 /** | |
606 * @param {!Array.<!DOMAgent.Node>|undefined} payloads | |
607 */ | |
608 _setPseudoElements: function(payloads) | |
609 { | |
610 this._pseudoElements = {}; | |
611 if (!payloads) | |
612 return; | |
613 | |
614 for (var i = 0; i < payloads.length; ++i) { | |
615 var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocume
nt, this._isInShadowTree, payloads[i]); | |
616 node.parentNode = this; | |
617 this._pseudoElements[node.pseudoType()] = node; | |
618 } | |
619 }, | |
620 | |
621 _renumber: function() | |
622 { | |
623 this._childNodeCount = this._children.length; | |
624 if (this._childNodeCount == 0) { | |
625 this.firstChild = null; | |
626 this.lastChild = null; | |
627 return; | |
628 } | |
629 this.firstChild = this._children[0]; | |
630 this.lastChild = this._children[this._childNodeCount - 1]; | |
631 for (var i = 0; i < this._childNodeCount; ++i) { | |
632 var child = this._children[i]; | |
633 child.index = i; | |
634 child.nextSibling = i + 1 < this._childNodeCount ? this._children[i
+ 1] : null; | |
635 child.previousSibling = i - 1 >= 0 ? this._children[i - 1] : null; | |
636 child.parentNode = this; | |
637 } | |
638 }, | |
639 | |
640 /** | |
641 * @param {string} name | |
642 * @param {string} value | |
643 */ | |
644 _addAttribute: function(name, value) | |
645 { | |
646 var attr = { | |
647 name: name, | |
648 value: value, | |
649 _node: this | |
650 }; | |
651 this._attributesMap[name] = attr; | |
652 this._attributes.push(attr); | |
653 }, | |
654 | |
655 /** | |
656 * @param {string} name | |
657 * @param {string} value | |
658 */ | |
659 _setAttribute: function(name, value) | |
660 { | |
661 var attr = this._attributesMap[name]; | |
662 if (attr) | |
663 attr.value = value; | |
664 else | |
665 this._addAttribute(name, value); | |
666 }, | |
667 | |
668 /** | |
669 * @param {string} name | |
670 */ | |
671 _removeAttribute: function(name) | |
672 { | |
673 var attr = this._attributesMap[name]; | |
674 if (attr) { | |
675 this._attributes.remove(attr); | |
676 delete this._attributesMap[name]; | |
677 } | |
678 }, | |
679 | |
680 /** | |
681 * @param {!WebInspector.DOMNode} targetNode | |
682 * @param {?WebInspector.DOMNode} anchorNode | |
683 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback | |
684 */ | |
685 moveTo: function(targetNode, anchorNode, callback) | |
686 { | |
687 DOMAgent.moveTo(this.id, targetNode.id, anchorNode ? anchorNode.id : und
efined, WebInspector.domAgent._markRevision(this, callback)); | |
688 }, | |
689 | |
690 /** | |
691 * @return {boolean} | |
692 */ | |
693 isXMLNode: function() | |
694 { | |
695 return !!this.ownerDocument && !!this.ownerDocument.xmlVersion; | |
696 }, | |
697 | |
698 _updateChildUserPropertyCountsOnRemoval: function(parentNode) | |
699 { | |
700 var result = {}; | |
701 if (this._userProperties) { | |
702 for (var name in this._userProperties) | |
703 result[name] = (result[name] || 0) + 1; | |
704 } | |
705 | |
706 if (this._descendantUserPropertyCounters) { | |
707 for (var name in this._descendantUserPropertyCounters) { | |
708 var counter = this._descendantUserPropertyCounters[name]; | |
709 result[name] = (result[name] || 0) + counter; | |
710 } | |
711 } | |
712 | |
713 for (var name in result) | |
714 parentNode._updateDescendantUserPropertyCount(name, -result[name]); | |
715 }, | |
716 | |
717 _updateDescendantUserPropertyCount: function(name, delta) | |
718 { | |
719 if (!this._descendantUserPropertyCounters.hasOwnProperty(name)) | |
720 this._descendantUserPropertyCounters[name] = 0; | |
721 this._descendantUserPropertyCounters[name] += delta; | |
722 if (!this._descendantUserPropertyCounters[name]) | |
723 delete this._descendantUserPropertyCounters[name]; | |
724 if (this.parentNode) | |
725 this.parentNode._updateDescendantUserPropertyCount(name, delta); | |
726 }, | |
727 | |
728 setUserProperty: function(name, value) | |
729 { | |
730 if (value === null) { | |
731 this.removeUserProperty(name); | |
732 return; | |
733 } | |
734 | |
735 if (this.parentNode && !this._userProperties.hasOwnProperty(name)) | |
736 this.parentNode._updateDescendantUserPropertyCount(name, 1); | |
737 | |
738 this._userProperties[name] = value; | |
739 }, | |
740 | |
741 removeUserProperty: function(name) | |
742 { | |
743 if (!this._userProperties.hasOwnProperty(name)) | |
744 return; | |
745 | |
746 delete this._userProperties[name]; | |
747 if (this.parentNode) | |
748 this.parentNode._updateDescendantUserPropertyCount(name, -1); | |
749 }, | |
750 | |
751 /** | |
752 * @param {string} name | |
753 * @return {?T} | |
754 * @template T | |
755 */ | |
756 getUserProperty: function(name) | |
757 { | |
758 return (this._userProperties && this._userProperties[name]) || null; | |
759 }, | |
760 | |
761 /** | |
762 * @param {string} name | |
763 * @return {number} | |
764 */ | |
765 descendantUserPropertyCount: function(name) | |
766 { | |
767 return this._descendantUserPropertyCounters && this._descendantUserPrope
rtyCounters[name] ? this._descendantUserPropertyCounters[name] : 0; | |
768 }, | |
769 | |
770 /** | |
771 * @param {string} url | |
772 * @return {?string} | |
773 */ | |
774 resolveURL: function(url) | |
775 { | |
776 if (!url) | |
777 return url; | |
778 for (var frameOwnerCandidate = this; frameOwnerCandidate; frameOwnerCand
idate = frameOwnerCandidate.parentNode) { | |
779 if (frameOwnerCandidate.baseURL) | |
780 return WebInspector.ParsedURL.completeURL(frameOwnerCandidate.ba
seURL, url); | |
781 } | |
782 return null; | |
783 } | |
784 } | |
785 | |
786 /** | |
787 * @extends {WebInspector.DOMNode} | |
788 * @constructor | |
789 * @param {!WebInspector.DOMAgent} domAgent | |
790 * @param {!DOMAgent.Node} payload | |
791 */ | |
792 WebInspector.DOMDocument = function(domAgent, payload) | |
793 { | |
794 WebInspector.DOMNode.call(this, domAgent, this, false, payload); | |
795 this.documentURL = payload.documentURL || ""; | |
796 this.baseURL = payload.baseURL || ""; | |
797 this.xmlVersion = payload.xmlVersion; | |
798 this._listeners = {}; | |
799 } | |
800 | |
801 WebInspector.DOMDocument.prototype = { | |
802 __proto__: WebInspector.DOMNode.prototype | |
803 } | |
804 | |
805 /** | |
806 * @extends {WebInspector.Object} | |
807 * @constructor | |
808 */ | |
809 WebInspector.DOMAgent = function() { | |
810 /** @type {!Object.<number, !WebInspector.DOMNode>} */ | |
811 this._idToDOMNode = {}; | |
812 /** @type {?WebInspector.DOMDocument} */ | |
813 this._document = null; | |
814 /** @type {!Object.<number, boolean>} */ | |
815 this._attributeLoadNodeIds = {}; | |
816 InspectorBackend.registerDOMDispatcher(new WebInspector.DOMDispatcher(this))
; | |
817 | |
818 this._defaultHighlighter = new WebInspector.DefaultDOMNodeHighlighter(); | |
819 this._highlighter = this._defaultHighlighter; | |
820 } | |
821 | |
822 WebInspector.DOMAgent.Events = { | |
823 AttrModified: "AttrModified", | |
824 AttrRemoved: "AttrRemoved", | |
825 CharacterDataModified: "CharacterDataModified", | |
826 NodeInserted: "NodeInserted", | |
827 NodeRemoved: "NodeRemoved", | |
828 DocumentUpdated: "DocumentUpdated", | |
829 ChildNodeCountUpdated: "ChildNodeCountUpdated", | |
830 UndoRedoRequested: "UndoRedoRequested", | |
831 UndoRedoCompleted: "UndoRedoCompleted", | |
832 } | |
833 | |
834 WebInspector.DOMAgent.prototype = { | |
835 /** | |
836 * @param {function(!WebInspector.DOMDocument)=} callback | |
837 */ | |
838 requestDocument: function(callback) | |
839 { | |
840 if (this._document) { | |
841 if (callback) | |
842 callback(this._document); | |
843 return; | |
844 } | |
845 | |
846 if (this._pendingDocumentRequestCallbacks) { | |
847 this._pendingDocumentRequestCallbacks.push(callback); | |
848 return; | |
849 } | |
850 | |
851 this._pendingDocumentRequestCallbacks = [callback]; | |
852 | |
853 /** | |
854 * @this {WebInspector.DOMAgent} | |
855 * @param {?Protocol.Error} error | |
856 * @param {!DOMAgent.Node} root | |
857 */ | |
858 function onDocumentAvailable(error, root) | |
859 { | |
860 if (!error) | |
861 this._setDocument(root); | |
862 | |
863 for (var i = 0; i < this._pendingDocumentRequestCallbacks.length; ++
i) { | |
864 var callback = this._pendingDocumentRequestCallbacks[i]; | |
865 if (callback) | |
866 callback(this._document); | |
867 } | |
868 delete this._pendingDocumentRequestCallbacks; | |
869 } | |
870 | |
871 DOMAgent.getDocument(onDocumentAvailable.bind(this)); | |
872 }, | |
873 | |
874 /** | |
875 * @return {?WebInspector.DOMDocument} | |
876 */ | |
877 existingDocument: function() | |
878 { | |
879 return this._document; | |
880 }, | |
881 | |
882 /** | |
883 * @param {!RuntimeAgent.RemoteObjectId} objectId | |
884 * @param {function(?DOMAgent.NodeId)=} callback | |
885 */ | |
886 pushNodeToFrontend: function(objectId, callback) | |
887 { | |
888 this._dispatchWhenDocumentAvailable(DOMAgent.requestNode.bind(DOMAgent,
objectId), callback); | |
889 }, | |
890 | |
891 /** | |
892 * @param {string} path | |
893 * @param {function(?number)=} callback | |
894 */ | |
895 pushNodeByPathToFrontend: function(path, callback) | |
896 { | |
897 this._dispatchWhenDocumentAvailable(DOMAgent.pushNodeByPathToFrontend.bi
nd(DOMAgent, path), callback); | |
898 }, | |
899 | |
900 /** | |
901 * @param {!Array.<number>} backendNodeIds | |
902 * @param {function(?Array.<number>)=} callback | |
903 */ | |
904 pushNodesByBackendIdsToFrontend: function(backendNodeIds, callback) | |
905 { | |
906 this._dispatchWhenDocumentAvailable(DOMAgent.pushNodesByBackendIdsToFron
tend.bind(DOMAgent, backendNodeIds), callback); | |
907 }, | |
908 | |
909 /** | |
910 * @param {function(!T)=} callback | |
911 * @return {function(?Protocol.Error, !T=)|undefined} | |
912 * @template T | |
913 */ | |
914 _wrapClientCallback: function(callback) | |
915 { | |
916 if (!callback) | |
917 return; | |
918 /** | |
919 * @param {?Protocol.Error} error | |
920 * @param {!T=} result | |
921 * @template T | |
922 */ | |
923 return function(error, result) | |
924 { | |
925 // Caller is responsible for handling the actual error. | |
926 callback(error ? null : result); | |
927 } | |
928 }, | |
929 | |
930 /** | |
931 * @param {function(function(?Protocol.Error, !T=)=)} func | |
932 * @param {function(!T)=} callback | |
933 * @template T | |
934 */ | |
935 _dispatchWhenDocumentAvailable: function(func, callback) | |
936 { | |
937 var callbackWrapper = this._wrapClientCallback(callback); | |
938 | |
939 /** | |
940 * @this {WebInspector.DOMAgent} | |
941 */ | |
942 function onDocumentAvailable() | |
943 { | |
944 if (this._document) | |
945 func(callbackWrapper); | |
946 else { | |
947 if (callbackWrapper) | |
948 callbackWrapper("No document"); | |
949 } | |
950 } | |
951 this.requestDocument(onDocumentAvailable.bind(this)); | |
952 }, | |
953 | |
954 /** | |
955 * @param {!DOMAgent.NodeId} nodeId | |
956 * @param {string} name | |
957 * @param {string} value | |
958 */ | |
959 _attributeModified: function(nodeId, name, value) | |
960 { | |
961 var node = this._idToDOMNode[nodeId]; | |
962 if (!node) | |
963 return; | |
964 | |
965 node._setAttribute(name, value); | |
966 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.AttrModified,
{ node: node, name: name }); | |
967 }, | |
968 | |
969 /** | |
970 * @param {!DOMAgent.NodeId} nodeId | |
971 * @param {string} name | |
972 */ | |
973 _attributeRemoved: function(nodeId, name) | |
974 { | |
975 var node = this._idToDOMNode[nodeId]; | |
976 if (!node) | |
977 return; | |
978 node._removeAttribute(name); | |
979 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.AttrRemoved,
{ node: node, name: name }); | |
980 }, | |
981 | |
982 /** | |
983 * @param {!Array.<!DOMAgent.NodeId>} nodeIds | |
984 */ | |
985 _inlineStyleInvalidated: function(nodeIds) | |
986 { | |
987 for (var i = 0; i < nodeIds.length; ++i) | |
988 this._attributeLoadNodeIds[nodeIds[i]] = true; | |
989 if ("_loadNodeAttributesTimeout" in this) | |
990 return; | |
991 this._loadNodeAttributesTimeout = setTimeout(this._loadNodeAttributes.bi
nd(this), 20); | |
992 }, | |
993 | |
994 _loadNodeAttributes: function() | |
995 { | |
996 /** | |
997 * @this {WebInspector.DOMAgent} | |
998 * @param {!DOMAgent.NodeId} nodeId | |
999 * @param {?Protocol.Error} error | |
1000 * @param {!Array.<string>} attributes | |
1001 */ | |
1002 function callback(nodeId, error, attributes) | |
1003 { | |
1004 if (error) { | |
1005 // We are calling _loadNodeAttributes asynchronously, it is ok i
f node is not found. | |
1006 return; | |
1007 } | |
1008 var node = this._idToDOMNode[nodeId]; | |
1009 if (node) { | |
1010 if (node._setAttributesPayload(attributes)) | |
1011 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.A
ttrModified, { node: node, name: "style" }); | |
1012 } | |
1013 } | |
1014 | |
1015 delete this._loadNodeAttributesTimeout; | |
1016 | |
1017 for (var nodeId in this._attributeLoadNodeIds) { | |
1018 var nodeIdAsNumber = parseInt(nodeId, 10); | |
1019 DOMAgent.getAttributes(nodeIdAsNumber, callback.bind(this, nodeIdAsN
umber)); | |
1020 } | |
1021 this._attributeLoadNodeIds = {}; | |
1022 }, | |
1023 | |
1024 /** | |
1025 * @param {!DOMAgent.NodeId} nodeId | |
1026 * @param {string} newValue | |
1027 */ | |
1028 _characterDataModified: function(nodeId, newValue) | |
1029 { | |
1030 var node = this._idToDOMNode[nodeId]; | |
1031 node._nodeValue = newValue; | |
1032 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.CharacterData
Modified, node); | |
1033 }, | |
1034 | |
1035 /** | |
1036 * @param {!DOMAgent.NodeId} nodeId | |
1037 * @return {?WebInspector.DOMNode} | |
1038 */ | |
1039 nodeForId: function(nodeId) | |
1040 { | |
1041 return this._idToDOMNode[nodeId] || null; | |
1042 }, | |
1043 | |
1044 _documentUpdated: function() | |
1045 { | |
1046 this._setDocument(null); | |
1047 }, | |
1048 | |
1049 /** | |
1050 * @param {?DOMAgent.Node} payload | |
1051 */ | |
1052 _setDocument: function(payload) | |
1053 { | |
1054 this._idToDOMNode = {}; | |
1055 if (payload && "nodeId" in payload) | |
1056 this._document = new WebInspector.DOMDocument(this, payload); | |
1057 else | |
1058 this._document = null; | |
1059 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.DocumentUpdat
ed, this._document); | |
1060 }, | |
1061 | |
1062 /** | |
1063 * @param {!DOMAgent.Node} payload | |
1064 */ | |
1065 _setDetachedRoot: function(payload) | |
1066 { | |
1067 if (payload.nodeName === "#document") | |
1068 new WebInspector.DOMDocument(this, payload); | |
1069 else | |
1070 new WebInspector.DOMNode(this, null, false, payload); | |
1071 }, | |
1072 | |
1073 /** | |
1074 * @param {!DOMAgent.NodeId} parentId | |
1075 * @param {!Array.<!DOMAgent.Node>} payloads | |
1076 */ | |
1077 _setChildNodes: function(parentId, payloads) | |
1078 { | |
1079 if (!parentId && payloads.length) { | |
1080 this._setDetachedRoot(payloads[0]); | |
1081 return; | |
1082 } | |
1083 | |
1084 var parent = this._idToDOMNode[parentId]; | |
1085 parent._setChildrenPayload(payloads); | |
1086 }, | |
1087 | |
1088 /** | |
1089 * @param {!DOMAgent.NodeId} nodeId | |
1090 * @param {number} newValue | |
1091 */ | |
1092 _childNodeCountUpdated: function(nodeId, newValue) | |
1093 { | |
1094 var node = this._idToDOMNode[nodeId]; | |
1095 node._childNodeCount = newValue; | |
1096 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.ChildNodeCoun
tUpdated, node); | |
1097 }, | |
1098 | |
1099 /** | |
1100 * @param {!DOMAgent.NodeId} parentId | |
1101 * @param {!DOMAgent.NodeId} prevId | |
1102 * @param {!DOMAgent.Node} payload | |
1103 */ | |
1104 _childNodeInserted: function(parentId, prevId, payload) | |
1105 { | |
1106 var parent = this._idToDOMNode[parentId]; | |
1107 var prev = this._idToDOMNode[prevId]; | |
1108 var node = parent._insertChild(prev, payload); | |
1109 this._idToDOMNode[node.id] = node; | |
1110 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeInserted,
node); | |
1111 }, | |
1112 | |
1113 /** | |
1114 * @param {!DOMAgent.NodeId} parentId | |
1115 * @param {!DOMAgent.NodeId} nodeId | |
1116 */ | |
1117 _childNodeRemoved: function(parentId, nodeId) | |
1118 { | |
1119 var parent = this._idToDOMNode[parentId]; | |
1120 var node = this._idToDOMNode[nodeId]; | |
1121 parent._removeChild(node); | |
1122 this._unbind(node); | |
1123 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeRemoved,
{node: node, parent: parent}); | |
1124 }, | |
1125 | |
1126 /** | |
1127 * @param {!DOMAgent.NodeId} hostId | |
1128 * @param {!DOMAgent.Node} root | |
1129 */ | |
1130 _shadowRootPushed: function(hostId, root) | |
1131 { | |
1132 var host = this._idToDOMNode[hostId]; | |
1133 if (!host) | |
1134 return; | |
1135 var node = new WebInspector.DOMNode(this, host.ownerDocument, true, root
); | |
1136 node.parentNode = host; | |
1137 this._idToDOMNode[node.id] = node; | |
1138 host._shadowRoots.push(node); | |
1139 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeInserted,
node); | |
1140 }, | |
1141 | |
1142 /** | |
1143 * @param {!DOMAgent.NodeId} hostId | |
1144 * @param {!DOMAgent.NodeId} rootId | |
1145 */ | |
1146 _shadowRootPopped: function(hostId, rootId) | |
1147 { | |
1148 var host = this._idToDOMNode[hostId]; | |
1149 if (!host) | |
1150 return; | |
1151 var root = this._idToDOMNode[rootId]; | |
1152 if (!root) | |
1153 return; | |
1154 host._removeChild(root); | |
1155 this._unbind(root); | |
1156 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeRemoved,
{node: root, parent: host}); | |
1157 }, | |
1158 | |
1159 /** | |
1160 * @param {!DOMAgent.NodeId} parentId | |
1161 * @param {!DOMAgent.Node} pseudoElement | |
1162 */ | |
1163 _pseudoElementAdded: function(parentId, pseudoElement) | |
1164 { | |
1165 var parent = this._idToDOMNode[parentId]; | |
1166 if (!parent) | |
1167 return; | |
1168 var node = new WebInspector.DOMNode(this, parent.ownerDocument, false, p
seudoElement); | |
1169 node.parentNode = parent; | |
1170 this._idToDOMNode[node.id] = node; | |
1171 console.assert(!parent._pseudoElements[node.pseudoType()]); | |
1172 parent._pseudoElements[node.pseudoType()] = node; | |
1173 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeInserted,
node); | |
1174 }, | |
1175 | |
1176 /** | |
1177 * @param {!DOMAgent.NodeId} parentId | |
1178 * @param {!DOMAgent.NodeId} pseudoElementId | |
1179 */ | |
1180 _pseudoElementRemoved: function(parentId, pseudoElementId) | |
1181 { | |
1182 var parent = this._idToDOMNode[parentId]; | |
1183 if (!parent) | |
1184 return; | |
1185 var pseudoElement = this._idToDOMNode[pseudoElementId]; | |
1186 if (!pseudoElement) | |
1187 return; | |
1188 parent._removeChild(pseudoElement); | |
1189 this._unbind(pseudoElement); | |
1190 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeRemoved,
{node: pseudoElement, parent: parent}); | |
1191 }, | |
1192 | |
1193 /** | |
1194 * @param {!WebInspector.DOMNode} node | |
1195 */ | |
1196 _unbind: function(node) | |
1197 { | |
1198 delete this._idToDOMNode[node.id]; | |
1199 for (var i = 0; node._children && i < node._children.length; ++i) | |
1200 this._unbind(node._children[i]); | |
1201 for (var i = 0; i < node._shadowRoots.length; ++i) | |
1202 this._unbind(node._shadowRoots[i]); | |
1203 var pseudoElements = node.pseudoElements(); | |
1204 for (var id in pseudoElements) | |
1205 this._unbind(pseudoElements[id]); | |
1206 if (node._templateContent) | |
1207 this._unbind(node._templateContent); | |
1208 }, | |
1209 | |
1210 /** | |
1211 * @param {number} nodeId | |
1212 */ | |
1213 inspectElement: function(nodeId) | |
1214 { | |
1215 WebInspector.Revealer.reveal(this.nodeForId(nodeId)); | |
1216 }, | |
1217 | |
1218 /** | |
1219 * @param {!DOMAgent.NodeId} nodeId | |
1220 */ | |
1221 _inspectNodeRequested: function(nodeId) | |
1222 { | |
1223 this.inspectElement(nodeId); | |
1224 }, | |
1225 | |
1226 /** | |
1227 * @param {string} query | |
1228 * @param {function(number)} searchCallback | |
1229 */ | |
1230 performSearch: function(query, searchCallback) | |
1231 { | |
1232 this.cancelSearch(); | |
1233 | |
1234 /** | |
1235 * @param {?Protocol.Error} error | |
1236 * @param {string} searchId | |
1237 * @param {number} resultsCount | |
1238 * @this {WebInspector.DOMAgent} | |
1239 */ | |
1240 function callback(error, searchId, resultsCount) | |
1241 { | |
1242 this._searchId = searchId; | |
1243 searchCallback(resultsCount); | |
1244 } | |
1245 DOMAgent.performSearch(query, callback.bind(this)); | |
1246 }, | |
1247 | |
1248 /** | |
1249 * @param {number} index | |
1250 * @param {?function(?WebInspector.DOMNode)} callback | |
1251 */ | |
1252 searchResult: function(index, callback) | |
1253 { | |
1254 if (this._searchId) | |
1255 DOMAgent.getSearchResults(this._searchId, index, index + 1, searchRe
sultsCallback.bind(this)); | |
1256 else | |
1257 callback(null); | |
1258 | |
1259 /** | |
1260 * @param {?Protocol.Error} error | |
1261 * @param {!Array.<number>} nodeIds | |
1262 * @this {WebInspector.DOMAgent} | |
1263 */ | |
1264 function searchResultsCallback(error, nodeIds) | |
1265 { | |
1266 if (error) { | |
1267 console.error(error); | |
1268 callback(null); | |
1269 return; | |
1270 } | |
1271 if (nodeIds.length != 1) | |
1272 return; | |
1273 | |
1274 callback(this.nodeForId(nodeIds[0])); | |
1275 } | |
1276 }, | |
1277 | |
1278 cancelSearch: function() | |
1279 { | |
1280 if (this._searchId) { | |
1281 DOMAgent.discardSearchResults(this._searchId); | |
1282 delete this._searchId; | |
1283 } | |
1284 }, | |
1285 | |
1286 /** | |
1287 * @param {!DOMAgent.NodeId} nodeId | |
1288 * @param {string} selectors | |
1289 * @param {function(?DOMAgent.NodeId)=} callback | |
1290 */ | |
1291 querySelector: function(nodeId, selectors, callback) | |
1292 { | |
1293 DOMAgent.querySelector(nodeId, selectors, this._wrapClientCallback(callb
ack)); | |
1294 }, | |
1295 | |
1296 /** | |
1297 * @param {!DOMAgent.NodeId} nodeId | |
1298 * @param {string} selectors | |
1299 * @param {function(!Array.<!DOMAgent.NodeId>=)=} callback | |
1300 */ | |
1301 querySelectorAll: function(nodeId, selectors, callback) | |
1302 { | |
1303 DOMAgent.querySelectorAll(nodeId, selectors, this._wrapClientCallback(ca
llback)); | |
1304 }, | |
1305 | |
1306 /** | |
1307 * @param {!DOMAgent.NodeId=} nodeId | |
1308 * @param {string=} mode | |
1309 * @param {!RuntimeAgent.RemoteObjectId=} objectId | |
1310 */ | |
1311 highlightDOMNode: function(nodeId, mode, objectId) | |
1312 { | |
1313 if (this._hideDOMNodeHighlightTimeout) { | |
1314 clearTimeout(this._hideDOMNodeHighlightTimeout); | |
1315 delete this._hideDOMNodeHighlightTimeout; | |
1316 } | |
1317 this._highlighter.highlightDOMNode(nodeId || 0, this._buildHighlightConf
ig(mode), objectId); | |
1318 }, | |
1319 | |
1320 hideDOMNodeHighlight: function() | |
1321 { | |
1322 this.highlightDOMNode(0); | |
1323 }, | |
1324 | |
1325 /** | |
1326 * @param {!DOMAgent.NodeId} nodeId | |
1327 */ | |
1328 highlightDOMNodeForTwoSeconds: function(nodeId) | |
1329 { | |
1330 this.highlightDOMNode(nodeId); | |
1331 this._hideDOMNodeHighlightTimeout = setTimeout(this.hideDOMNodeHighlight
.bind(this), 2000); | |
1332 }, | |
1333 | |
1334 /** | |
1335 * @param {boolean} enabled | |
1336 * @param {boolean} inspectUAShadowDOM | |
1337 * @param {function(?Protocol.Error)=} callback | |
1338 */ | |
1339 setInspectModeEnabled: function(enabled, inspectUAShadowDOM, callback) | |
1340 { | |
1341 /** | |
1342 * @this {WebInspector.DOMAgent} | |
1343 */ | |
1344 function onDocumentAvailable() | |
1345 { | |
1346 this._highlighter.setInspectModeEnabled(enabled, inspectUAShadowDOM,
this._buildHighlightConfig(), callback); | |
1347 } | |
1348 this.requestDocument(onDocumentAvailable.bind(this)); | |
1349 }, | |
1350 | |
1351 /** | |
1352 * @param {string=} mode | |
1353 * @return {!DOMAgent.HighlightConfig} | |
1354 */ | |
1355 _buildHighlightConfig: function(mode) | |
1356 { | |
1357 mode = mode || "all"; | |
1358 var highlightConfig = { showInfo: mode === "all", showRulers: WebInspect
or.settings.showMetricsRulers.get() }; | |
1359 if (mode === "all" || mode === "content") | |
1360 highlightConfig.contentColor = WebInspector.Color.PageHighlight.Cont
ent.toProtocolRGBA(); | |
1361 | |
1362 if (mode === "all" || mode === "padding") | |
1363 highlightConfig.paddingColor = WebInspector.Color.PageHighlight.Padd
ing.toProtocolRGBA(); | |
1364 | |
1365 if (mode === "all" || mode === "border") | |
1366 highlightConfig.borderColor = WebInspector.Color.PageHighlight.Borde
r.toProtocolRGBA(); | |
1367 | |
1368 if (mode === "all" || mode === "margin") | |
1369 highlightConfig.marginColor = WebInspector.Color.PageHighlight.Margi
n.toProtocolRGBA(); | |
1370 | |
1371 if (mode === "all") | |
1372 highlightConfig.eventTargetColor = WebInspector.Color.PageHighlight.
EventTarget.toProtocolRGBA(); | |
1373 | |
1374 return highlightConfig; | |
1375 }, | |
1376 | |
1377 /** | |
1378 * @param {!WebInspector.DOMNode} node | |
1379 * @param {function(?Protocol.Error, !A=, !B=)=} callback | |
1380 * @return {function(?Protocol.Error, !A=, !B=)} | |
1381 * @template A,B | |
1382 */ | |
1383 _markRevision: function(node, callback) | |
1384 { | |
1385 /** | |
1386 * @param {?Protocol.Error} error | |
1387 * @this {WebInspector.DOMAgent} | |
1388 */ | |
1389 function wrapperFunction(error) | |
1390 { | |
1391 if (!error) | |
1392 this.markUndoableState(); | |
1393 | |
1394 if (callback) | |
1395 callback.apply(this, arguments); | |
1396 } | |
1397 return wrapperFunction.bind(this); | |
1398 }, | |
1399 | |
1400 /** | |
1401 * @param {boolean} emulationEnabled | |
1402 */ | |
1403 emulateTouchEventObjects: function(emulationEnabled) | |
1404 { | |
1405 const injectedFunction = function() { | |
1406 const touchEvents = ["ontouchstart", "ontouchend", "ontouchmove", "o
ntouchcancel"]; | |
1407 var recepients = [window.__proto__, document.__proto__]; | |
1408 for (var i = 0; i < touchEvents.length; ++i) { | |
1409 for (var j = 0; j < recepients.length; ++j) { | |
1410 if (!(touchEvents[i] in recepients[j])) | |
1411 Object.defineProperty(recepients[j], touchEvents[i], { v
alue: null, writable: true, configurable: true, enumerable: true }); | |
1412 } | |
1413 } | |
1414 } | |
1415 | |
1416 if (emulationEnabled && !this._addTouchEventsScriptInjecting) { | |
1417 this._addTouchEventsScriptInjecting = true; | |
1418 PageAgent.addScriptToEvaluateOnLoad("(" + injectedFunction.toString(
) + ")()", scriptAddedCallback.bind(this)); | |
1419 } else { | |
1420 if (typeof this._addTouchEventsScriptId !== "undefined") { | |
1421 PageAgent.removeScriptToEvaluateOnLoad(this._addTouchEventsScrip
tId); | |
1422 delete this._addTouchEventsScriptId; | |
1423 } | |
1424 } | |
1425 | |
1426 /** | |
1427 * @param {?Protocol.Error} error | |
1428 * @param {string} scriptId | |
1429 * @this {WebInspector.DOMAgent} | |
1430 */ | |
1431 function scriptAddedCallback(error, scriptId) | |
1432 { | |
1433 delete this._addTouchEventsScriptInjecting; | |
1434 if (error) | |
1435 return; | |
1436 this._addTouchEventsScriptId = scriptId; | |
1437 } | |
1438 | |
1439 PageAgent.setTouchEmulationEnabled(emulationEnabled); | |
1440 }, | |
1441 | |
1442 markUndoableState: function() | |
1443 { | |
1444 DOMAgent.markUndoableState(); | |
1445 }, | |
1446 | |
1447 /** | |
1448 * @param {function(?Protocol.Error)=} callback | |
1449 */ | |
1450 undo: function(callback) | |
1451 { | |
1452 /** | |
1453 * @param {?Protocol.Error} error | |
1454 * @this {WebInspector.DOMAgent} | |
1455 */ | |
1456 function mycallback(error) | |
1457 { | |
1458 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.UndoRedoC
ompleted); | |
1459 callback(error); | |
1460 } | |
1461 | |
1462 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.UndoRedoReque
sted); | |
1463 DOMAgent.undo(callback); | |
1464 }, | |
1465 | |
1466 /** | |
1467 * @param {function(?Protocol.Error)=} callback | |
1468 */ | |
1469 redo: function(callback) | |
1470 { | |
1471 /** | |
1472 * @param {?Protocol.Error} error | |
1473 * @this {WebInspector.DOMAgent} | |
1474 */ | |
1475 function mycallback(error) | |
1476 { | |
1477 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.UndoRedoC
ompleted); | |
1478 callback(error); | |
1479 } | |
1480 | |
1481 this.dispatchEventToListeners(WebInspector.DOMAgent.Events.UndoRedoReque
sted); | |
1482 DOMAgent.redo(callback); | |
1483 }, | |
1484 | |
1485 /** | |
1486 * @param {?WebInspector.DOMNodeHighlighter} highlighter | |
1487 */ | |
1488 setHighlighter: function(highlighter) | |
1489 { | |
1490 this._highlighter = highlighter || this._defaultHighlighter; | |
1491 }, | |
1492 | |
1493 __proto__: WebInspector.Object.prototype | |
1494 } | |
1495 | |
1496 /** | |
1497 * @constructor | |
1498 * @implements {DOMAgent.Dispatcher} | |
1499 * @param {!WebInspector.DOMAgent} domAgent | |
1500 */ | |
1501 WebInspector.DOMDispatcher = function(domAgent) | |
1502 { | |
1503 this._domAgent = domAgent; | |
1504 } | |
1505 | |
1506 WebInspector.DOMDispatcher.prototype = { | |
1507 documentUpdated: function() | |
1508 { | |
1509 this._domAgent._documentUpdated(); | |
1510 }, | |
1511 | |
1512 /** | |
1513 * @param {!DOMAgent.NodeId} nodeId | |
1514 */ | |
1515 inspectNodeRequested: function(nodeId) | |
1516 { | |
1517 this._domAgent._inspectNodeRequested(nodeId); | |
1518 }, | |
1519 | |
1520 /** | |
1521 * @param {!DOMAgent.NodeId} nodeId | |
1522 * @param {string} name | |
1523 * @param {string} value | |
1524 */ | |
1525 attributeModified: function(nodeId, name, value) | |
1526 { | |
1527 this._domAgent._attributeModified(nodeId, name, value); | |
1528 }, | |
1529 | |
1530 /** | |
1531 * @param {!DOMAgent.NodeId} nodeId | |
1532 * @param {string} name | |
1533 */ | |
1534 attributeRemoved: function(nodeId, name) | |
1535 { | |
1536 this._domAgent._attributeRemoved(nodeId, name); | |
1537 }, | |
1538 | |
1539 /** | |
1540 * @param {!Array.<!DOMAgent.NodeId>} nodeIds | |
1541 */ | |
1542 inlineStyleInvalidated: function(nodeIds) | |
1543 { | |
1544 this._domAgent._inlineStyleInvalidated(nodeIds); | |
1545 }, | |
1546 | |
1547 /** | |
1548 * @param {!DOMAgent.NodeId} nodeId | |
1549 * @param {string} characterData | |
1550 */ | |
1551 characterDataModified: function(nodeId, characterData) | |
1552 { | |
1553 this._domAgent._characterDataModified(nodeId, characterData); | |
1554 }, | |
1555 | |
1556 /** | |
1557 * @param {!DOMAgent.NodeId} parentId | |
1558 * @param {!Array.<!DOMAgent.Node>} payloads | |
1559 */ | |
1560 setChildNodes: function(parentId, payloads) | |
1561 { | |
1562 this._domAgent._setChildNodes(parentId, payloads); | |
1563 }, | |
1564 | |
1565 /** | |
1566 * @param {!DOMAgent.NodeId} nodeId | |
1567 * @param {number} childNodeCount | |
1568 */ | |
1569 childNodeCountUpdated: function(nodeId, childNodeCount) | |
1570 { | |
1571 this._domAgent._childNodeCountUpdated(nodeId, childNodeCount); | |
1572 }, | |
1573 | |
1574 /** | |
1575 * @param {!DOMAgent.NodeId} parentNodeId | |
1576 * @param {!DOMAgent.NodeId} previousNodeId | |
1577 * @param {!DOMAgent.Node} payload | |
1578 */ | |
1579 childNodeInserted: function(parentNodeId, previousNodeId, payload) | |
1580 { | |
1581 this._domAgent._childNodeInserted(parentNodeId, previousNodeId, payload)
; | |
1582 }, | |
1583 | |
1584 /** | |
1585 * @param {!DOMAgent.NodeId} parentNodeId | |
1586 * @param {!DOMAgent.NodeId} nodeId | |
1587 */ | |
1588 childNodeRemoved: function(parentNodeId, nodeId) | |
1589 { | |
1590 this._domAgent._childNodeRemoved(parentNodeId, nodeId); | |
1591 }, | |
1592 | |
1593 /** | |
1594 * @param {!DOMAgent.NodeId} hostId | |
1595 * @param {!DOMAgent.Node} root | |
1596 */ | |
1597 shadowRootPushed: function(hostId, root) | |
1598 { | |
1599 this._domAgent._shadowRootPushed(hostId, root); | |
1600 }, | |
1601 | |
1602 /** | |
1603 * @param {!DOMAgent.NodeId} hostId | |
1604 * @param {!DOMAgent.NodeId} rootId | |
1605 */ | |
1606 shadowRootPopped: function(hostId, rootId) | |
1607 { | |
1608 this._domAgent._shadowRootPopped(hostId, rootId); | |
1609 }, | |
1610 | |
1611 /** | |
1612 * @param {!DOMAgent.NodeId} parentId | |
1613 * @param {!DOMAgent.Node} pseudoElement | |
1614 */ | |
1615 pseudoElementAdded: function(parentId, pseudoElement) | |
1616 { | |
1617 this._domAgent._pseudoElementAdded(parentId, pseudoElement); | |
1618 }, | |
1619 | |
1620 /** | |
1621 * @param {!DOMAgent.NodeId} parentId | |
1622 * @param {!DOMAgent.NodeId} pseudoElementId | |
1623 */ | |
1624 pseudoElementRemoved: function(parentId, pseudoElementId) | |
1625 { | |
1626 this._domAgent._pseudoElementRemoved(parentId, pseudoElementId); | |
1627 } | |
1628 } | |
1629 | |
1630 /** | |
1631 * @interface | |
1632 */ | |
1633 WebInspector.DOMNodeHighlighter = function() { | |
1634 } | |
1635 | |
1636 WebInspector.DOMNodeHighlighter.prototype = { | |
1637 /** | |
1638 * @param {!DOMAgent.NodeId} nodeId | |
1639 * @param {!DOMAgent.HighlightConfig} config | |
1640 * @param {!RuntimeAgent.RemoteObjectId=} objectId | |
1641 */ | |
1642 highlightDOMNode: function(nodeId, config, objectId) {}, | |
1643 | |
1644 /** | |
1645 * @param {boolean} enabled | |
1646 * @param {boolean} inspectUAShadowDOM | |
1647 * @param {!DOMAgent.HighlightConfig} config | |
1648 * @param {function(?Protocol.Error)=} callback | |
1649 */ | |
1650 setInspectModeEnabled: function(enabled, inspectUAShadowDOM, config, callbac
k) {} | |
1651 } | |
1652 | |
1653 /** | |
1654 * @constructor | |
1655 * @implements {WebInspector.DOMNodeHighlighter} | |
1656 */ | |
1657 WebInspector.DefaultDOMNodeHighlighter = function() { | |
1658 } | |
1659 | |
1660 WebInspector.DefaultDOMNodeHighlighter.prototype = { | |
1661 /** | |
1662 * @param {!DOMAgent.NodeId} nodeId | |
1663 * @param {!DOMAgent.HighlightConfig} config | |
1664 * @param {!RuntimeAgent.RemoteObjectId=} objectId | |
1665 */ | |
1666 highlightDOMNode: function(nodeId, config, objectId) | |
1667 { | |
1668 if (objectId || nodeId) | |
1669 DOMAgent.highlightNode(config, objectId ? undefined : nodeId, object
Id); | |
1670 else | |
1671 DOMAgent.hideHighlight(); | |
1672 }, | |
1673 | |
1674 /** | |
1675 * @param {boolean} enabled | |
1676 * @param {boolean} inspectUAShadowDOM | |
1677 * @param {!DOMAgent.HighlightConfig} config | |
1678 * @param {function(?Protocol.Error)=} callback | |
1679 */ | |
1680 setInspectModeEnabled: function(enabled, inspectUAShadowDOM, config, callbac
k) | |
1681 { | |
1682 DOMAgent.setInspectModeEnabled(enabled, inspectUAShadowDOM, config, call
back); | |
1683 } | |
1684 } | |
1685 | |
1686 /** | |
1687 * @type {!WebInspector.DOMAgent} | |
1688 */ | |
1689 WebInspector.domAgent; | |
OLD | NEW |