2 * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
3 * Copyright (C) 2009 Joseph Pecoraro
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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.
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.
34 * @extends {WebInspector.SDKObject}
35 * @param {!WebInspector.DOMModel} domModel
36 * @param {?WebInspector.DOMDocument} doc
37 * @param {boolean} isInShadowTree
38 * @param {!DOMAgent.Node} payload
40 WebInspector.DOMNode = function(domModel, doc, isInShadowTree, payload) {
41 WebInspector.SDKObject.call(this, domModel.target());
42 this._domModel = domModel;
43 this._agent = domModel._agent;
44 this.ownerDocument = doc;
45 this._isInShadowTree = isInShadowTree;
47 this.id = payload.nodeId;
48 domModel._idToDOMNode[this.id] = this;
49 this._nodeType = payload.nodeType;
50 this._nodeName = payload.nodeName;
51 this._localName = payload.localName;
52 this._nodeValue = payload.nodeValue;
53 this._pseudoType = payload.pseudoType;
54 this._shadowRootType = payload.shadowRootType;
55 this._frameId = payload.frameId || null;
57 this._shadowRoots = [];
59 this._attributes = [];
60 this._attributesMap = {};
61 if (payload.attributes)
62 this._setAttributesPayload(payload.attributes);
64 this._userProperties = {};
65 this._descendantUserPropertyCounters = {};
67 this._childNodeCount = payload.childNodeCount || 0;
68 this._children = null;
70 this.nextSibling = null;
71 this.previousSibling = null;
72 this.firstChild = null;
73 this.lastChild = null;
74 this.parentNode = null;
76 if (payload.shadowRoots) {
77 for (var i = 0; i < payload.shadowRoots.length; ++i) {
78 var root = payload.shadowRoots[i];
79 var node = new WebInspector.DOMNode(this._domModel, this.ownerDocument, true, root);
80 this._shadowRoots.push(node);
81 node.parentNode = this;
85 if (payload.templateContent) {
86 this._templateContent = new WebInspector.DOMNode(this._domModel, this.ownerDocument, true, payload.templateContent);
87 this._templateContent.parentNode = this;
90 if (payload.importedDocument) {
91 this._importedDocument = new WebInspector.DOMNode(this._domModel, this.ownerDocument, true, payload.importedDocument);
92 this._importedDocument.parentNode = this;
96 this._setChildrenPayload(payload.children);
98 this._setPseudoElements(payload.pseudoElements);
100 if (payload.contentDocument) {
101 this._contentDocument = new WebInspector.DOMDocument(domModel, payload.contentDocument);
102 this._children = [this._contentDocument];
106 if (this._nodeType === Node.ELEMENT_NODE) {
107 // HTML and BODY from internal iframes should not overwrite top-level ones.
108 if (this.ownerDocument && !this.ownerDocument.documentElement && this._nodeName === "HTML")
109 this.ownerDocument.documentElement = this;
110 if (this.ownerDocument && !this.ownerDocument.body && this._nodeName === "BODY")
111 this.ownerDocument.body = this;
112 } else if (this._nodeType === Node.DOCUMENT_TYPE_NODE) {
113 this.publicId = payload.publicId;
114 this.systemId = payload.systemId;
115 this.internalSubset = payload.internalSubset;
116 } else if (this._nodeType === Node.ATTRIBUTE_NODE) {
117 this.name = payload.name;
118 this.value = payload.value;
125 WebInspector.DOMNode.PseudoElementNames = {
133 WebInspector.DOMNode.ShadowRootTypes = {
134 UserAgent: "user-agent",
138 WebInspector.DOMNode.prototype = {
140 * @return {!WebInspector.DOMModel}
144 return this._domModel;
148 * @return {?Array.<!WebInspector.DOMNode>}
152 return this._children ? this._children.slice() : null;
158 hasAttributes: function()
160 return this._attributes.length > 0;
166 childNodeCount: function()
168 return this._childNodeCount;
174 hasShadowRoots: function()
176 return !!this._shadowRoots.length;
180 * @return {!Array.<!WebInspector.DOMNode>}
182 shadowRoots: function()
184 return this._shadowRoots.slice();
188 * @return {?WebInspector.DOMNode}
190 templateContent: function()
192 return this._templateContent;
196 * @return {?WebInspector.DOMNode}
198 importedDocument: function()
200 return this._importedDocument;
208 return this._nodeType;
216 return this._nodeName;
220 * @return {string|undefined}
222 pseudoType: function()
224 return this._pseudoType;
230 hasPseudoElements: function()
232 return Object.keys(this._pseudoElements).length !== 0;
236 * @return {!Object.<string, !WebInspector.DOMNode>}
238 pseudoElements: function()
240 return this._pseudoElements;
246 isInShadowTree: function()
248 return this._isInShadowTree;
252 * @return {?WebInspector.DOMNode}
254 ancestorUserAgentShadowRoot: function()
256 if (!this._isInShadowTree)
260 while (!current.isShadowRoot())
261 current = current.parentNode;
262 return current.shadowRootType() === WebInspector.DOMNode.ShadowRootTypes.UserAgent ? current : null;
268 isShadowRoot: function()
270 return !!this._shadowRootType;
276 shadowRootType: function()
278 return this._shadowRootType || null;
284 nodeNameInCorrectCase: function()
286 var shadowRootType = this.shadowRootType();
288 return "#shadow-root" + (shadowRootType === WebInspector.DOMNode.ShadowRootTypes.UserAgent ? " (user-agent)" : "");
289 return this.isXMLNode() ? this.nodeName() : this.nodeName().toLowerCase();
293 * @param {string} name
294 * @param {function(?Protocol.Error, number)=} callback
296 setNodeName: function(name, callback)
298 this._agent.setNodeName(this.id, name, this._domModel._markRevision(this, callback));
304 localName: function()
306 return this._localName;
312 nodeValue: function()
314 return this._nodeValue;
318 * @param {string} value
319 * @param {function(?Protocol.Error)=} callback
321 setNodeValue: function(value, callback)
323 this._agent.setNodeValue(this.id, value, this._domModel._markRevision(this, callback));
327 * @param {string} name
330 getAttribute: function(name)
332 var attr = this._attributesMap[name];
333 return attr ? attr.value : undefined;
337 * @param {string} name
338 * @param {string} text
339 * @param {function(?Protocol.Error)=} callback
341 setAttribute: function(name, text, callback)
343 this._agent.setAttributesAsText(this.id, text, name, this._domModel._markRevision(this, callback));
347 * @param {string} name
348 * @param {string} value
349 * @param {function(?Protocol.Error)=} callback
351 setAttributeValue: function(name, value, callback)
353 this._agent.setAttributeValue(this.id, name, value, this._domModel._markRevision(this, callback));
359 attributes: function()
361 return this._attributes;
365 * @param {string} name
366 * @param {function(?Protocol.Error)=} callback
368 removeAttribute: function(name, callback)
371 * @param {?Protocol.Error} error
372 * @this {WebInspector.DOMNode}
374 function mycallback(error)
377 delete this._attributesMap[name];
378 for (var i = 0; i < this._attributes.length; ++i) {
379 if (this._attributes[i].name === name) {
380 this._attributes.splice(i, 1);
386 this._domModel._markRevision(this, callback)(error);
388 this._agent.removeAttribute(this.id, name, mycallback.bind(this));
392 * @param {function(?Array.<!WebInspector.DOMNode>)=} callback
394 getChildNodes: function(callback)
396 if (this._children) {
398 callback(this.children());
403 * @this {WebInspector.DOMNode}
404 * @param {?Protocol.Error} error
406 function mycallback(error)
409 callback(error ? null : this.children());
412 this._agent.requestChildNodes(this.id, undefined, mycallback.bind(this));
416 * @param {number} depth
417 * @param {function(?Array.<!WebInspector.DOMNode>)=} callback
419 getSubtree: function(depth, callback)
422 * @this {WebInspector.DOMNode}
423 * @param {?Protocol.Error} error
425 function mycallback(error)
428 callback(error ? null : this._children);
431 this._agent.requestChildNodes(this.id, depth, mycallback.bind(this));
435 * @param {function(?Protocol.Error, string)=} callback
437 getOuterHTML: function(callback)
439 this._agent.getOuterHTML(this.id, callback);
443 * @param {string} html
444 * @param {function(?Protocol.Error)=} callback
446 setOuterHTML: function(html, callback)
448 this._agent.setOuterHTML(this.id, html, this._domModel._markRevision(this, callback));
452 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback
454 removeNode: function(callback)
456 this._agent.removeNode(this.id, this._domModel._markRevision(this, callback));
460 * @param {function(?string)=} callback
462 copyNode: function(callback)
464 function copy(error, text)
467 InspectorFrontendHost.copyText(text);
469 callback(error ? null : text);
471 this._agent.getOuterHTML(this.id, copy);
475 * @param {string} objectGroupId
476 * @param {function(?Array.<!WebInspector.DOMModel.EventListener>)} callback
478 eventListeners: function(objectGroupId, callback)
480 var target = this.target();
483 * @param {?Protocol.Error} error
484 * @param {!Array.<!DOMAgent.EventListener>} payloads
486 function mycallback(error, payloads)
492 callback(payloads.map(function(payload) {
493 return new WebInspector.DOMModel.EventListener(target, payload);
496 this._agent.getEventListenersForNode(this.id, objectGroupId, mycallback);
505 * @param {?WebInspector.DOMNode} node
507 function canPush(node)
509 return node && ("index" in node || (node.isShadowRoot() && node.parentNode)) && node._nodeName.length;
514 while (canPush(node)) {
515 var index = typeof node.index === "number" ? node.index : (node.shadowRootType() === WebInspector.DOMNode.ShadowRootTypes.UserAgent ? "u" : "a");
516 path.push([index, node._nodeName]);
517 node = node.parentNode;
520 return path.join(",");
524 * @param {!WebInspector.DOMNode} node
527 isAncestor: function(node)
532 var currentNode = node.parentNode;
533 while (currentNode) {
534 if (this === currentNode)
536 currentNode = currentNode.parentNode;
542 * @param {!WebInspector.DOMNode} descendant
545 isDescendant: function(descendant)
547 return descendant !== null && descendant.isAncestor(this);
551 * @return {?PageAgent.FrameId}
556 while (!node._frameId && node.parentNode)
557 node = node.parentNode;
558 return node._frameId;
562 * @param {!Array.<string>} attrs
565 _setAttributesPayload: function(attrs)
567 var attributesChanged = !this._attributes || attrs.length !== this._attributes.length * 2;
568 var oldAttributesMap = this._attributesMap || {};
570 this._attributes = [];
571 this._attributesMap = {};
573 for (var i = 0; i < attrs.length; i += 2) {
575 var value = attrs[i + 1];
576 this._addAttribute(name, value);
578 if (attributesChanged)
581 if (!oldAttributesMap[name] || oldAttributesMap[name].value !== value)
582 attributesChanged = true;
584 return attributesChanged;
588 * @param {!WebInspector.DOMNode} prev
589 * @param {!DOMAgent.Node} payload
590 * @return {!WebInspector.DOMNode}
592 _insertChild: function(prev, payload)
594 var node = new WebInspector.DOMNode(this._domModel, this.ownerDocument, this._isInShadowTree, payload);
595 this._children.splice(this._children.indexOf(prev) + 1, 0, node);
601 * @param {!WebInspector.DOMNode} node
603 _removeChild: function(node)
605 if (node.pseudoType()) {
606 delete this._pseudoElements[node.pseudoType()];
608 var shadowRootIndex = this._shadowRoots.indexOf(node);
609 if (shadowRootIndex !== -1)
610 this._shadowRoots.splice(shadowRootIndex, 1);
612 this._children.splice(this._children.indexOf(node), 1);
614 node.parentNode = null;
615 node._updateChildUserPropertyCountsOnRemoval(this);
620 * @param {!Array.<!DOMAgent.Node>} payloads
622 _setChildrenPayload: function(payloads)
624 // We set children in the constructor.
625 if (this._contentDocument)
629 for (var i = 0; i < payloads.length; ++i) {
630 var payload = payloads[i];
631 var node = new WebInspector.DOMNode(this._domModel, this.ownerDocument, this._isInShadowTree, payload);
632 this._children.push(node);
638 * @param {!Array.<!DOMAgent.Node>|undefined} payloads
640 _setPseudoElements: function(payloads)
642 this._pseudoElements = {};
646 for (var i = 0; i < payloads.length; ++i) {
647 var node = new WebInspector.DOMNode(this._domModel, this.ownerDocument, this._isInShadowTree, payloads[i]);
648 node.parentNode = this;
649 this._pseudoElements[node.pseudoType()] = node;
653 _renumber: function()
655 this._childNodeCount = this._children.length;
656 if (this._childNodeCount == 0) {
657 this.firstChild = null;
658 this.lastChild = null;
661 this.firstChild = this._children[0];
662 this.lastChild = this._children[this._childNodeCount - 1];
663 for (var i = 0; i < this._childNodeCount; ++i) {
664 var child = this._children[i];
666 child.nextSibling = i + 1 < this._childNodeCount ? this._children[i + 1] : null;
667 child.previousSibling = i - 1 >= 0 ? this._children[i - 1] : null;
668 child.parentNode = this;
673 * @param {string} name
674 * @param {string} value
676 _addAttribute: function(name, value)
683 this._attributesMap[name] = attr;
684 this._attributes.push(attr);
688 * @param {string} name
689 * @param {string} value
691 _setAttribute: function(name, value)
693 var attr = this._attributesMap[name];
697 this._addAttribute(name, value);
701 * @param {string} name
703 _removeAttribute: function(name)
705 var attr = this._attributesMap[name];
707 this._attributes.remove(attr);
708 delete this._attributesMap[name];
713 * @param {!WebInspector.DOMNode} targetNode
714 * @param {?WebInspector.DOMNode} anchorNode
715 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback
717 copyTo: function(targetNode, anchorNode, callback)
719 this._agent.copyTo(this.id, targetNode.id, anchorNode ? anchorNode.id : undefined, this._domModel._markRevision(this, callback));
723 * @param {!WebInspector.DOMNode} targetNode
724 * @param {?WebInspector.DOMNode} anchorNode
725 * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback
727 moveTo: function(targetNode, anchorNode, callback)
729 this._agent.moveTo(this.id, targetNode.id, anchorNode ? anchorNode.id : undefined, this._domModel._markRevision(this, callback));
735 isXMLNode: function()
737 return !!this.ownerDocument && !!this.ownerDocument.xmlVersion;
740 _updateChildUserPropertyCountsOnRemoval: function(parentNode)
743 if (this._userProperties) {
744 for (var name in this._userProperties)
745 result[name] = (result[name] || 0) + 1;
748 if (this._descendantUserPropertyCounters) {
749 for (var name in this._descendantUserPropertyCounters) {
750 var counter = this._descendantUserPropertyCounters[name];
751 result[name] = (result[name] || 0) + counter;
755 for (var name in result)
756 parentNode._updateDescendantUserPropertyCount(name, -result[name]);
759 _updateDescendantUserPropertyCount: function(name, delta)
761 if (!this._descendantUserPropertyCounters.hasOwnProperty(name))
762 this._descendantUserPropertyCounters[name] = 0;
763 this._descendantUserPropertyCounters[name] += delta;
764 if (!this._descendantUserPropertyCounters[name])
765 delete this._descendantUserPropertyCounters[name];
767 this.parentNode._updateDescendantUserPropertyCount(name, delta);
770 setUserProperty: function(name, value)
772 if (value === null) {
773 this.removeUserProperty(name);
777 if (this.parentNode && !this._userProperties.hasOwnProperty(name))
778 this.parentNode._updateDescendantUserPropertyCount(name, 1);
780 this._userProperties[name] = value;
783 removeUserProperty: function(name)
785 if (!this._userProperties.hasOwnProperty(name))
788 delete this._userProperties[name];
790 this.parentNode._updateDescendantUserPropertyCount(name, -1);
794 * @param {string} name
798 getUserProperty: function(name)
800 return (this._userProperties && this._userProperties[name]) || null;
804 * @param {string} name
807 descendantUserPropertyCount: function(name)
809 return this._descendantUserPropertyCounters && this._descendantUserPropertyCounters[name] ? this._descendantUserPropertyCounters[name] : 0;
813 * @param {string} url
816 resolveURL: function(url)
820 for (var frameOwnerCandidate = this; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) {
821 if (frameOwnerCandidate.baseURL)
822 return WebInspector.ParsedURL.completeURL(frameOwnerCandidate.baseURL, url);
828 * @param {string=} mode
829 * @param {!RuntimeAgent.RemoteObjectId=} objectId
831 highlight: function(mode, objectId)
833 this._domModel.highlightDOMNode(this.id, mode, objectId);
836 highlightForTwoSeconds: function()
838 this._domModel.highlightDOMNodeForTwoSeconds(this.id);
842 * @param {string=} objectGroup
843 * @param {function(?WebInspector.RemoteObject)=} callback
845 resolveToObject: function(objectGroup, callback)
847 this._agent.resolveNode(this.id, objectGroup, mycallback.bind(this));
850 * @param {?Protocol.Error} error
851 * @param {!RuntimeAgent.RemoteObject} object
852 * @this {WebInspector.DOMNode}
854 function mycallback(error, object)
859 if (error || !object)
862 callback(this.target().runtimeModel.createRemoteObject(object));
867 * @param {function(?DOMAgent.BoxModel)} callback
869 boxModel: function(callback)
871 this._agent.getBoxModel(this.id, this._domModel._wrapClientCallback(callback));
874 __proto__: WebInspector.SDKObject.prototype
878 * @param {!WebInspector.Target} target
879 * @param {number} backendNodeId
882 WebInspector.DeferredDOMNode = function(target, backendNodeId)
884 this._target = target;
885 this._backendNodeId = backendNodeId;
888 WebInspector.DeferredDOMNode.prototype = {
890 * @param {function(?WebInspector.DOMNode)} callback
892 resolve: function(callback)
894 this._target.domModel.pushNodesByBackendIdsToFrontend([this._backendNodeId], onGotNode.bind(this));
897 * @param {?Array.<number>} nodeIds
898 * @this {WebInspector.DeferredDOMNode}
900 function onGotNode(nodeIds)
902 if (!nodeIds || !nodeIds[0]) {
906 callback(this._target.domModel.nodeForId(nodeIds[0]));
912 * @extends {WebInspector.DOMNode}
914 * @param {!WebInspector.DOMModel} domModel
915 * @param {!DOMAgent.Node} payload
917 WebInspector.DOMDocument = function(domModel, payload)
919 WebInspector.DOMNode.call(this, domModel, this, false, payload);
920 this.documentURL = payload.documentURL || "";
921 this.baseURL = payload.baseURL || "";
922 this.xmlVersion = payload.xmlVersion;
923 this._listeners = {};
926 WebInspector.DOMDocument.prototype = {
927 __proto__: WebInspector.DOMNode.prototype
932 * @extends {WebInspector.SDKModel}
933 * @param {!WebInspector.Target} target
935 WebInspector.DOMModel = function(target) {
936 WebInspector.SDKModel.call(this, WebInspector.DOMModel, target);
938 this._agent = target.domAgent();
940 /** @type {!Object.<number, !WebInspector.DOMNode>} */
941 this._idToDOMNode = {};
942 /** @type {?WebInspector.DOMDocument} */
943 this._document = null;
944 /** @type {!Object.<number, boolean>} */
945 this._attributeLoadNodeIds = {};
946 target.registerDOMDispatcher(new WebInspector.DOMDispatcher(this));
948 this._defaultHighlighter = new WebInspector.DefaultDOMNodeHighlighter(this._agent);
949 this._highlighter = this._defaultHighlighter;
951 if (WebInspector.experimentsSettings.disableAgentsWhenProfile.isEnabled())
952 WebInspector.profilingLock().addEventListener(WebInspector.Lock.Events.StateChanged, this._profilingStateChanged, this);
954 this._agent.enable();
957 WebInspector.DOMModel.Events = {
958 AttrModified: "AttrModified",
959 AttrRemoved: "AttrRemoved",
960 CharacterDataModified: "CharacterDataModified",
961 NodeInserted: "NodeInserted",
962 NodeInspected: "NodeInspected",
963 NodeRemoved: "NodeRemoved",
964 DocumentUpdated: "DocumentUpdated",
965 ChildNodeCountUpdated: "ChildNodeCountUpdated",
966 UndoRedoRequested: "UndoRedoRequested",
967 UndoRedoCompleted: "UndoRedoCompleted",
970 WebInspector.DOMModel.prototype = {
971 _profilingStateChanged: function()
973 if (WebInspector.profilingLock().isAcquired())
974 this._agent.disable();
976 this._agent.enable();
980 * @param {function(!WebInspector.DOMDocument)=} callback
982 requestDocument: function(callback)
984 if (this._document) {
986 callback(this._document);
990 if (this._pendingDocumentRequestCallbacks) {
991 this._pendingDocumentRequestCallbacks.push(callback);
995 this._pendingDocumentRequestCallbacks = [callback];
998 * @this {WebInspector.DOMModel}
999 * @param {?Protocol.Error} error
1000 * @param {!DOMAgent.Node} root
1002 function onDocumentAvailable(error, root)
1005 this._setDocument(root);
1007 for (var i = 0; i < this._pendingDocumentRequestCallbacks.length; ++i) {
1008 var callback = this._pendingDocumentRequestCallbacks[i];
1010 callback(this._document);
1012 delete this._pendingDocumentRequestCallbacks;
1015 this._agent.getDocument(onDocumentAvailable.bind(this));
1019 * @return {?WebInspector.DOMDocument}
1021 existingDocument: function()
1023 return this._document;
1027 * @param {!RuntimeAgent.RemoteObjectId} objectId
1028 * @param {function(?WebInspector.DOMNode)=} callback
1030 pushNodeToFrontend: function(objectId, callback)
1033 * @param {?DOMAgent.NodeId} nodeId
1034 * @this {!WebInspector.DOMModel}
1036 function mycallback(nodeId)
1038 callback(nodeId ? this.nodeForId(nodeId) : null);
1040 this._dispatchWhenDocumentAvailable(this._agent.requestNode.bind(this._agent, objectId), mycallback.bind(this));
1044 * @param {string} path
1045 * @param {function(?number)=} callback
1047 pushNodeByPathToFrontend: function(path, callback)
1049 this._dispatchWhenDocumentAvailable(this._agent.pushNodeByPathToFrontend.bind(this._agent, path), callback);
1053 * @param {!Array.<number>} backendNodeIds
1054 * @param {function(?Array.<number>)=} callback
1056 pushNodesByBackendIdsToFrontend: function(backendNodeIds, callback)
1058 this._dispatchWhenDocumentAvailable(this._agent.pushNodesByBackendIdsToFrontend.bind(this._agent, backendNodeIds), callback);
1062 * @param {function(!T)=} callback
1063 * @return {function(?Protocol.Error, !T=)|undefined}
1066 _wrapClientCallback: function(callback)
1071 * @param {?Protocol.Error} error
1072 * @param {!T=} result
1075 var wrapper = function(error, result)
1077 // Caller is responsible for handling the actual error.
1078 callback(error ? null : result);
1084 * @param {function(function(?Protocol.Error, !T=)=)} func
1085 * @param {function(!T)=} callback
1088 _dispatchWhenDocumentAvailable: function(func, callback)
1090 var callbackWrapper = this._wrapClientCallback(callback);
1093 * @this {WebInspector.DOMModel}
1095 function onDocumentAvailable()
1098 func(callbackWrapper);
1100 if (callbackWrapper)
1101 callbackWrapper("No document");
1104 this.requestDocument(onDocumentAvailable.bind(this));
1108 * @param {!DOMAgent.NodeId} nodeId
1109 * @param {string} name
1110 * @param {string} value
1112 _attributeModified: function(nodeId, name, value)
1114 var node = this._idToDOMNode[nodeId];
1118 node._setAttribute(name, value);
1119 this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrModified, { node: node, name: name });
1123 * @param {!DOMAgent.NodeId} nodeId
1124 * @param {string} name
1126 _attributeRemoved: function(nodeId, name)
1128 var node = this._idToDOMNode[nodeId];
1131 node._removeAttribute(name);
1132 this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrRemoved, { node: node, name: name });
1136 * @param {!Array.<!DOMAgent.NodeId>} nodeIds
1138 _inlineStyleInvalidated: function(nodeIds)
1140 for (var i = 0; i < nodeIds.length; ++i)
1141 this._attributeLoadNodeIds[nodeIds[i]] = true;
1142 if ("_loadNodeAttributesTimeout" in this)
1144 this._loadNodeAttributesTimeout = setTimeout(this._loadNodeAttributes.bind(this), 20);
1147 _loadNodeAttributes: function()
1150 * @this {WebInspector.DOMModel}
1151 * @param {!DOMAgent.NodeId} nodeId
1152 * @param {?Protocol.Error} error
1153 * @param {!Array.<string>} attributes
1155 function callback(nodeId, error, attributes)
1158 // We are calling _loadNodeAttributes asynchronously, it is ok if node is not found.
1161 var node = this._idToDOMNode[nodeId];
1163 if (node._setAttributesPayload(attributes))
1164 this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrModified, { node: node, name: "style" });
1168 delete this._loadNodeAttributesTimeout;
1170 for (var nodeId in this._attributeLoadNodeIds) {
1171 var nodeIdAsNumber = parseInt(nodeId, 10);
1172 this._agent.getAttributes(nodeIdAsNumber, callback.bind(this, nodeIdAsNumber));
1174 this._attributeLoadNodeIds = {};
1178 * @param {!DOMAgent.NodeId} nodeId
1179 * @param {string} newValue
1181 _characterDataModified: function(nodeId, newValue)
1183 var node = this._idToDOMNode[nodeId];
1184 node._nodeValue = newValue;
1185 this.dispatchEventToListeners(WebInspector.DOMModel.Events.CharacterDataModified, node);
1189 * @param {!DOMAgent.NodeId} nodeId
1190 * @return {?WebInspector.DOMNode}
1192 nodeForId: function(nodeId)
1194 return this._idToDOMNode[nodeId] || null;
1197 _documentUpdated: function()
1199 this._setDocument(null);
1203 * @param {?DOMAgent.Node} payload
1205 _setDocument: function(payload)
1207 this._idToDOMNode = {};
1208 if (payload && "nodeId" in payload)
1209 this._document = new WebInspector.DOMDocument(this, payload);
1211 this._document = null;
1212 this.dispatchEventToListeners(WebInspector.DOMModel.Events.DocumentUpdated, this._document);
1216 * @param {!DOMAgent.Node} payload
1218 _setDetachedRoot: function(payload)
1220 if (payload.nodeName === "#document")
1221 new WebInspector.DOMDocument(this, payload);
1223 new WebInspector.DOMNode(this, null, false, payload);
1227 * @param {!DOMAgent.NodeId} parentId
1228 * @param {!Array.<!DOMAgent.Node>} payloads
1230 _setChildNodes: function(parentId, payloads)
1232 if (!parentId && payloads.length) {
1233 this._setDetachedRoot(payloads[0]);
1237 var parent = this._idToDOMNode[parentId];
1238 parent._setChildrenPayload(payloads);
1242 * @param {!DOMAgent.NodeId} nodeId
1243 * @param {number} newValue
1245 _childNodeCountUpdated: function(nodeId, newValue)
1247 var node = this._idToDOMNode[nodeId];
1248 node._childNodeCount = newValue;
1249 this.dispatchEventToListeners(WebInspector.DOMModel.Events.ChildNodeCountUpdated, node);
1253 * @param {!DOMAgent.NodeId} parentId
1254 * @param {!DOMAgent.NodeId} prevId
1255 * @param {!DOMAgent.Node} payload
1257 _childNodeInserted: function(parentId, prevId, payload)
1259 var parent = this._idToDOMNode[parentId];
1260 var prev = this._idToDOMNode[prevId];
1261 var node = parent._insertChild(prev, payload);
1262 this._idToDOMNode[node.id] = node;
1263 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted, node);
1267 * @param {!DOMAgent.NodeId} parentId
1268 * @param {!DOMAgent.NodeId} nodeId
1270 _childNodeRemoved: function(parentId, nodeId)
1272 var parent = this._idToDOMNode[parentId];
1273 var node = this._idToDOMNode[nodeId];
1274 parent._removeChild(node);
1276 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved, {node: node, parent: parent});
1280 * @param {!DOMAgent.NodeId} hostId
1281 * @param {!DOMAgent.Node} root
1283 _shadowRootPushed: function(hostId, root)
1285 var host = this._idToDOMNode[hostId];
1288 var node = new WebInspector.DOMNode(this, host.ownerDocument, true, root);
1289 node.parentNode = host;
1290 this._idToDOMNode[node.id] = node;
1291 host._shadowRoots.push(node);
1292 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted, node);
1296 * @param {!DOMAgent.NodeId} hostId
1297 * @param {!DOMAgent.NodeId} rootId
1299 _shadowRootPopped: function(hostId, rootId)
1301 var host = this._idToDOMNode[hostId];
1304 var root = this._idToDOMNode[rootId];
1307 host._removeChild(root);
1309 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved, {node: root, parent: host});
1313 * @param {!DOMAgent.NodeId} parentId
1314 * @param {!DOMAgent.Node} pseudoElement
1316 _pseudoElementAdded: function(parentId, pseudoElement)
1318 var parent = this._idToDOMNode[parentId];
1321 var node = new WebInspector.DOMNode(this, parent.ownerDocument, false, pseudoElement);
1322 node.parentNode = parent;
1323 this._idToDOMNode[node.id] = node;
1324 console.assert(!parent._pseudoElements[node.pseudoType()]);
1325 parent._pseudoElements[node.pseudoType()] = node;
1326 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted, node);
1330 * @param {!DOMAgent.NodeId} parentId
1331 * @param {!DOMAgent.NodeId} pseudoElementId
1333 _pseudoElementRemoved: function(parentId, pseudoElementId)
1335 var parent = this._idToDOMNode[parentId];
1338 var pseudoElement = this._idToDOMNode[pseudoElementId];
1341 parent._removeChild(pseudoElement);
1342 this._unbind(pseudoElement);
1343 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved, {node: pseudoElement, parent: parent});
1347 * @param {!WebInspector.DOMNode} node
1349 _unbind: function(node)
1351 delete this._idToDOMNode[node.id];
1352 for (var i = 0; node._children && i < node._children.length; ++i)
1353 this._unbind(node._children[i]);
1354 for (var i = 0; i < node._shadowRoots.length; ++i)
1355 this._unbind(node._shadowRoots[i]);
1356 var pseudoElements = node.pseudoElements();
1357 for (var id in pseudoElements)
1358 this._unbind(pseudoElements[id]);
1359 if (node._templateContent)
1360 this._unbind(node._templateContent);
1364 * @param {!DOMAgent.NodeId} nodeId
1366 _inspectNodeRequested: function(nodeId)
1368 this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInspected, this.nodeForId(nodeId));
1372 * @param {string} query
1373 * @param {boolean} includeUserAgentShadowDOM
1374 * @param {function(number)} searchCallback
1376 performSearch: function(query, includeUserAgentShadowDOM, searchCallback)
1378 this.cancelSearch();
1381 * @param {?Protocol.Error} error
1382 * @param {string} searchId
1383 * @param {number} resultsCount
1384 * @this {WebInspector.DOMModel}
1386 function callback(error, searchId, resultsCount)
1388 this._searchId = searchId;
1389 searchCallback(resultsCount);
1391 this._agent.performSearch(query, includeUserAgentShadowDOM, callback.bind(this));
1395 * @param {string} query
1396 * @param {boolean} includeUserAgentShadowDOM
1397 * @return {!Promise.<number>}
1399 performSearchPromise: function(query, includeUserAgentShadowDOM)
1401 return new Promise(performSearch.bind(this));
1404 * @param {function(number)} resolve
1405 * @this {WebInspector.DOMModel}
1407 function performSearch(resolve)
1409 this._agent.performSearch(query, includeUserAgentShadowDOM, callback.bind(this));
1412 * @param {?Protocol.Error} error
1413 * @param {string} searchId
1414 * @param {number} resultsCount
1415 * @this {WebInspector.DOMModel}
1417 function callback(error, searchId, resultsCount)
1420 this._searchId = searchId;
1421 resolve(error ? 0 : resultsCount);
1427 * @param {number} index
1428 * @param {?function(?WebInspector.DOMNode)} callback
1430 searchResult: function(index, callback)
1433 this._agent.getSearchResults(this._searchId, index, index + 1, searchResultsCallback.bind(this));
1438 * @param {?Protocol.Error} error
1439 * @param {!Array.<number>} nodeIds
1440 * @this {WebInspector.DOMModel}
1442 function searchResultsCallback(error, nodeIds)
1445 console.error(error);
1449 if (nodeIds.length != 1)
1452 callback(this.nodeForId(nodeIds[0]));
1456 cancelSearch: function()
1458 if (this._searchId) {
1459 this._agent.discardSearchResults(this._searchId);
1460 delete this._searchId;
1465 * @param {!DOMAgent.NodeId} nodeId
1466 * @param {string} selectors
1467 * @param {function(?DOMAgent.NodeId)=} callback
1469 querySelector: function(nodeId, selectors, callback)
1471 this._agent.querySelector(nodeId, selectors, this._wrapClientCallback(callback));
1475 * @param {!DOMAgent.NodeId} nodeId
1476 * @param {string} selectors
1477 * @param {function(!Array.<!DOMAgent.NodeId>=)=} callback
1479 querySelectorAll: function(nodeId, selectors, callback)
1481 this._agent.querySelectorAll(nodeId, selectors, this._wrapClientCallback(callback));
1485 * @param {!DOMAgent.NodeId=} nodeId
1486 * @param {string=} mode
1487 * @param {!RuntimeAgent.RemoteObjectId=} objectId
1489 highlightDOMNode: function(nodeId, mode, objectId)
1491 this.highlightDOMNodeWithConfig(nodeId, { mode: mode }, objectId);
1495 * @param {!DOMAgent.NodeId=} nodeId
1496 * @param {!{mode: (string|undefined), showInfo: (boolean|undefined)}=} config
1497 * @param {!RuntimeAgent.RemoteObjectId=} objectId
1499 highlightDOMNodeWithConfig: function(nodeId, config, objectId)
1501 config = config || { mode: "all", showInfo: undefined };
1502 if (this._hideDOMNodeHighlightTimeout) {
1503 clearTimeout(this._hideDOMNodeHighlightTimeout);
1504 delete this._hideDOMNodeHighlightTimeout;
1506 var highlightConfig = this._buildHighlightConfig(config.mode);
1507 if (typeof config.showInfo !== "undefined")
1508 highlightConfig.showInfo = config.showInfo;
1509 this._highlighter.highlightDOMNode(this.nodeForId(nodeId || 0), highlightConfig, objectId);
1512 hideDOMNodeHighlight: function()
1514 this.highlightDOMNode(0);
1518 * @param {!DOMAgent.NodeId} nodeId
1520 highlightDOMNodeForTwoSeconds: function(nodeId)
1522 this.highlightDOMNode(nodeId);
1523 this._hideDOMNodeHighlightTimeout = setTimeout(this.hideDOMNodeHighlight.bind(this), 2000);
1527 * @param {boolean} enabled
1528 * @param {boolean} inspectUAShadowDOM
1529 * @param {function(?Protocol.Error)=} callback
1531 setInspectModeEnabled: function(enabled, inspectUAShadowDOM, callback)
1534 * @this {WebInspector.DOMModel}
1536 function onDocumentAvailable()
1538 this._highlighter.setInspectModeEnabled(enabled, inspectUAShadowDOM, this._buildHighlightConfig(), callback);
1540 this.requestDocument(onDocumentAvailable.bind(this));
1544 * @param {string=} mode
1545 * @return {!DOMAgent.HighlightConfig}
1547 _buildHighlightConfig: function(mode)
1549 mode = mode || "all";
1550 var highlightConfig = { showInfo: mode === "all", showRulers: WebInspector.overridesSupport.showMetricsRulers(), showExtensionLines: WebInspector.overridesSupport.showExtensionLines()};
1551 if (mode === "all" || mode === "content")
1552 highlightConfig.contentColor = WebInspector.Color.PageHighlight.Content.toProtocolRGBA();
1554 if (mode === "all" || mode === "padding")
1555 highlightConfig.paddingColor = WebInspector.Color.PageHighlight.Padding.toProtocolRGBA();
1557 if (mode === "all" || mode === "border")
1558 highlightConfig.borderColor = WebInspector.Color.PageHighlight.Border.toProtocolRGBA();
1560 if (mode === "all" || mode === "margin")
1561 highlightConfig.marginColor = WebInspector.Color.PageHighlight.Margin.toProtocolRGBA();
1563 if (mode === "all") {
1564 highlightConfig.eventTargetColor = WebInspector.Color.PageHighlight.EventTarget.toProtocolRGBA();
1565 highlightConfig.shapeColor = WebInspector.Color.PageHighlight.Shape.toProtocolRGBA();
1566 highlightConfig.shapeMarginColor = WebInspector.Color.PageHighlight.ShapeMargin.toProtocolRGBA();
1568 return highlightConfig;
1572 * @param {!WebInspector.DOMNode} node
1573 * @param {function(?Protocol.Error, ...)=} callback
1574 * @return {function(...)}
1577 _markRevision: function(node, callback)
1580 * @param {?Protocol.Error} error
1581 * @this {WebInspector.DOMModel}
1583 function wrapperFunction(error)
1586 this.markUndoableState();
1589 callback.apply(this, arguments);
1591 return wrapperFunction.bind(this);
1595 * @param {boolean} emulationEnabled
1597 emulateTouchEventObjects: function(emulationEnabled)
1599 const injectedFunction = function() {
1600 const touchEvents = ["ontouchstart", "ontouchend", "ontouchmove", "ontouchcancel"];
1601 var recepients = [window.__proto__, document.__proto__];
1602 for (var i = 0; i < touchEvents.length; ++i) {
1603 for (var j = 0; j < recepients.length; ++j) {
1604 if (!(touchEvents[i] in recepients[j]))
1605 Object.defineProperty(recepients[j], touchEvents[i], { value: null, writable: true, configurable: true, enumerable: true });
1610 if (emulationEnabled && !this._addTouchEventsScriptInjecting) {
1611 this._addTouchEventsScriptInjecting = true;
1612 PageAgent.addScriptToEvaluateOnLoad("(" + injectedFunction.toString() + ")()", scriptAddedCallback.bind(this));
1614 if (typeof this._addTouchEventsScriptId !== "undefined") {
1615 PageAgent.removeScriptToEvaluateOnLoad(this._addTouchEventsScriptId);
1616 delete this._addTouchEventsScriptId;
1621 * @param {?Protocol.Error} error
1622 * @param {string} scriptId
1623 * @this {WebInspector.DOMModel}
1625 function scriptAddedCallback(error, scriptId)
1627 delete this._addTouchEventsScriptInjecting;
1630 this._addTouchEventsScriptId = scriptId;
1633 PageAgent.setTouchEmulationEnabled(emulationEnabled);
1636 markUndoableState: function()
1638 this._agent.markUndoableState();
1642 * @param {function(?Protocol.Error)=} callback
1644 undo: function(callback)
1647 * @param {?Protocol.Error} error
1648 * @this {WebInspector.DOMModel}
1650 function mycallback(error)
1652 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoCompleted);
1656 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoRequested);
1657 this._agent.undo(callback);
1661 * @param {function(?Protocol.Error)=} callback
1663 redo: function(callback)
1666 * @param {?Protocol.Error} error
1667 * @this {WebInspector.DOMModel}
1669 function mycallback(error)
1671 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoCompleted);
1675 this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoRequested);
1676 this._agent.redo(callback);
1680 * @param {?WebInspector.DOMNodeHighlighter} highlighter
1682 setHighlighter: function(highlighter)
1684 this._highlighter = highlighter || this._defaultHighlighter;
1690 * @param {function(?WebInspector.DOMNode)} callback
1692 nodeForLocation: function(x, y, callback)
1694 this._agent.getNodeForLocation(x, y, mycallback.bind(this));
1697 * @param {?Protocol.Error} error
1698 * @param {number} nodeId
1699 * @this {WebInspector.DOMModel}
1701 function mycallback(error, nodeId)
1707 callback(this.nodeForId(nodeId));
1711 __proto__: WebInspector.SDKModel.prototype
1716 * @implements {DOMAgent.Dispatcher}
1717 * @param {!WebInspector.DOMModel} domModel
1719 WebInspector.DOMDispatcher = function(domModel)
1721 this._domModel = domModel;
1724 WebInspector.DOMDispatcher.prototype = {
1725 documentUpdated: function()
1727 this._domModel._documentUpdated();
1731 * @param {!DOMAgent.NodeId} nodeId
1733 inspectNodeRequested: function(nodeId)
1735 this._domModel._inspectNodeRequested(nodeId);
1739 * @param {!DOMAgent.NodeId} nodeId
1740 * @param {string} name
1741 * @param {string} value
1743 attributeModified: function(nodeId, name, value)
1745 this._domModel._attributeModified(nodeId, name, value);
1749 * @param {!DOMAgent.NodeId} nodeId
1750 * @param {string} name
1752 attributeRemoved: function(nodeId, name)
1754 this._domModel._attributeRemoved(nodeId, name);
1758 * @param {!Array.<!DOMAgent.NodeId>} nodeIds
1760 inlineStyleInvalidated: function(nodeIds)
1762 this._domModel._inlineStyleInvalidated(nodeIds);
1766 * @param {!DOMAgent.NodeId} nodeId
1767 * @param {string} characterData
1769 characterDataModified: function(nodeId, characterData)
1771 this._domModel._characterDataModified(nodeId, characterData);
1775 * @param {!DOMAgent.NodeId} parentId
1776 * @param {!Array.<!DOMAgent.Node>} payloads
1778 setChildNodes: function(parentId, payloads)
1780 this._domModel._setChildNodes(parentId, payloads);
1784 * @param {!DOMAgent.NodeId} nodeId
1785 * @param {number} childNodeCount
1787 childNodeCountUpdated: function(nodeId, childNodeCount)
1789 this._domModel._childNodeCountUpdated(nodeId, childNodeCount);
1793 * @param {!DOMAgent.NodeId} parentNodeId
1794 * @param {!DOMAgent.NodeId} previousNodeId
1795 * @param {!DOMAgent.Node} payload
1797 childNodeInserted: function(parentNodeId, previousNodeId, payload)
1799 this._domModel._childNodeInserted(parentNodeId, previousNodeId, payload);
1803 * @param {!DOMAgent.NodeId} parentNodeId
1804 * @param {!DOMAgent.NodeId} nodeId
1806 childNodeRemoved: function(parentNodeId, nodeId)
1808 this._domModel._childNodeRemoved(parentNodeId, nodeId);
1812 * @param {!DOMAgent.NodeId} hostId
1813 * @param {!DOMAgent.Node} root
1815 shadowRootPushed: function(hostId, root)
1817 this._domModel._shadowRootPushed(hostId, root);
1821 * @param {!DOMAgent.NodeId} hostId
1822 * @param {!DOMAgent.NodeId} rootId
1824 shadowRootPopped: function(hostId, rootId)
1826 this._domModel._shadowRootPopped(hostId, rootId);
1830 * @param {!DOMAgent.NodeId} parentId
1831 * @param {!DOMAgent.Node} pseudoElement
1833 pseudoElementAdded: function(parentId, pseudoElement)
1835 this._domModel._pseudoElementAdded(parentId, pseudoElement);
1839 * @param {!DOMAgent.NodeId} parentId
1840 * @param {!DOMAgent.NodeId} pseudoElementId
1842 pseudoElementRemoved: function(parentId, pseudoElementId)
1844 this._domModel._pseudoElementRemoved(parentId, pseudoElementId);
1850 * @extends {WebInspector.SDKObject}
1851 * @param {!WebInspector.Target} target
1852 * @param {!DOMAgent.EventListener} payload
1854 WebInspector.DOMModel.EventListener = function(target, payload)
1856 WebInspector.SDKObject.call(this, target);
1857 this._payload = payload;
1858 var sourceName = this._payload.sourceName;
1860 var script = target.debuggerModel.scriptForId(payload.location.scriptId);
1861 sourceName = script ? script.contentURL() : "";
1863 this._sourceName = sourceName;
1866 WebInspector.DOMModel.EventListener.prototype = {
1868 * @return {!DOMAgent.EventListener}
1872 return this._payload;
1876 * @return {?WebInspector.DOMNode}
1880 return this.target().domModel.nodeForId(this._payload.nodeId);
1884 * @return {!WebInspector.DebuggerModel.Location}
1886 location: function()
1888 return WebInspector.DebuggerModel.Location.fromPayload(this.target(), this._payload.location);
1892 * @return {?WebInspector.RemoteObject}
1896 return this._payload.handler ? this.target().runtimeModel.createRemoteObject(this._payload.handler) : null;
1902 sourceName: function()
1904 return this._sourceName;
1907 __proto__: WebInspector.SDKObject.prototype
1913 WebInspector.DOMNodeHighlighter = function() {
1916 WebInspector.DOMNodeHighlighter.prototype = {
1918 * @param {?WebInspector.DOMNode} node
1919 * @param {!DOMAgent.HighlightConfig} config
1920 * @param {!RuntimeAgent.RemoteObjectId=} objectId
1922 highlightDOMNode: function(node, config, objectId) {},
1925 * @param {boolean} enabled
1926 * @param {boolean} inspectUAShadowDOM
1927 * @param {!DOMAgent.HighlightConfig} config
1928 * @param {function(?Protocol.Error)=} callback
1930 setInspectModeEnabled: function(enabled, inspectUAShadowDOM, config, callback) {}
1935 * @implements {WebInspector.DOMNodeHighlighter}
1936 * @param {!Protocol.DOMAgent} agent
1938 WebInspector.DefaultDOMNodeHighlighter = function(agent)
1940 this._agent = agent;
1943 WebInspector.DefaultDOMNodeHighlighter.prototype = {
1945 * @param {?WebInspector.DOMNode} node
1946 * @param {!DOMAgent.HighlightConfig} config
1947 * @param {!RuntimeAgent.RemoteObjectId=} objectId
1949 highlightDOMNode: function(node, config, objectId)
1951 if (objectId || node)
1952 this._agent.highlightNode(config, objectId ? undefined : node.id, objectId);
1954 this._agent.hideHighlight();
1958 * @param {boolean} enabled
1959 * @param {boolean} inspectUAShadowDOM
1960 * @param {!DOMAgent.HighlightConfig} config
1961 * @param {function(?Protocol.Error)=} callback
1963 setInspectModeEnabled: function(enabled, inspectUAShadowDOM, config, callback)
1965 WebInspector.overridesSupport.setTouchEmulationSuspended(enabled);
1966 this._agent.setInspectModeEnabled(enabled, inspectUAShadowDOM, config, callback);