summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js')
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js1867
1 files changed, 1867 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js b/chromium/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js
new file mode 100644
index 00000000000..f2fe1b05793
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js
@@ -0,0 +1,1867 @@
+/*
+ * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.TargetAware}
+ * @param {!WebInspector.DOMModel} domModel
+ * @param {?WebInspector.DOMDocument} doc
+ * @param {boolean} isInShadowTree
+ * @param {!DOMAgent.Node} payload
+ */
+WebInspector.DOMNode = function(domModel, doc, isInShadowTree, payload) {
+ WebInspector.TargetAware.call(this, domModel.target());
+ this._domModel = domModel;
+ this._agent = domModel._agent;
+ this.ownerDocument = doc;
+ this._isInShadowTree = isInShadowTree;
+
+ this.id = payload.nodeId;
+ domModel._idToDOMNode[this.id] = this;
+ this._nodeType = payload.nodeType;
+ this._nodeName = payload.nodeName;
+ this._localName = payload.localName;
+ this._nodeValue = payload.nodeValue;
+ this._pseudoType = payload.pseudoType;
+ this._shadowRootType = payload.shadowRootType;
+ this._frameId = payload.frameId || null;
+
+ this._shadowRoots = [];
+
+ this._attributes = [];
+ this._attributesMap = {};
+ if (payload.attributes)
+ this._setAttributesPayload(payload.attributes);
+
+ this._userProperties = {};
+ this._descendantUserPropertyCounters = {};
+
+ this._childNodeCount = payload.childNodeCount || 0;
+ this._children = null;
+
+ this.nextSibling = null;
+ this.previousSibling = null;
+ this.firstChild = null;
+ this.lastChild = null;
+ this.parentNode = null;
+
+ if (payload.shadowRoots) {
+ for (var i = 0; i < payload.shadowRoots.length; ++i) {
+ var root = payload.shadowRoots[i];
+ var node = new WebInspector.DOMNode(this._domModel, this.ownerDocument, true, root);
+ this._shadowRoots.push(node);
+ node.parentNode = this;
+ }
+ }
+
+ if (payload.templateContent) {
+ this._templateContent = new WebInspector.DOMNode(this._domModel, this.ownerDocument, true, payload.templateContent);
+ this._templateContent.parentNode = this;
+ }
+
+ if (payload.importedDocument) {
+ this._importedDocument = new WebInspector.DOMNode(this._domModel, this.ownerDocument, true, payload.importedDocument);
+ this._importedDocument.parentNode = this;
+ }
+
+ if (payload.children)
+ this._setChildrenPayload(payload.children);
+
+ this._setPseudoElements(payload.pseudoElements);
+
+ if (payload.contentDocument) {
+ this._contentDocument = new WebInspector.DOMDocument(domModel, payload.contentDocument);
+ this._children = [this._contentDocument];
+ this._renumber();
+ }
+
+ if (this._nodeType === Node.ELEMENT_NODE) {
+ // HTML and BODY from internal iframes should not overwrite top-level ones.
+ if (this.ownerDocument && !this.ownerDocument.documentElement && this._nodeName === "HTML")
+ this.ownerDocument.documentElement = this;
+ if (this.ownerDocument && !this.ownerDocument.body && this._nodeName === "BODY")
+ this.ownerDocument.body = this;
+ } else if (this._nodeType === Node.DOCUMENT_TYPE_NODE) {
+ this.publicId = payload.publicId;
+ this.systemId = payload.systemId;
+ this.internalSubset = payload.internalSubset;
+ } else if (this._nodeType === Node.ATTRIBUTE_NODE) {
+ this.name = payload.name;
+ this.value = payload.value;
+ }
+}
+
+/**
+ * @enum {string}
+ */
+WebInspector.DOMNode.PseudoElementNames = {
+ Before: "before",
+ After: "after"
+}
+
+/**
+ * @enum {string}
+ */
+WebInspector.DOMNode.ShadowRootTypes = {
+ UserAgent: "user-agent",
+ Author: "author"
+}
+
+WebInspector.DOMNode.prototype = {
+ /**
+ * @return {!WebInspector.DOMModel}
+ */
+ domModel: function()
+ {
+ return this._domModel;
+ },
+
+ /**
+ * @return {?Array.<!WebInspector.DOMNode>}
+ */
+ children: function()
+ {
+ return this._children ? this._children.slice() : null;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ hasAttributes: function()
+ {
+ return this._attributes.length > 0;
+ },
+
+ /**
+ * @return {number}
+ */
+ childNodeCount: function()
+ {
+ return this._childNodeCount;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ hasShadowRoots: function()
+ {
+ return !!this._shadowRoots.length;
+ },
+
+ /**
+ * @return {!Array.<!WebInspector.DOMNode>}
+ */
+ shadowRoots: function()
+ {
+ return this._shadowRoots.slice();
+ },
+
+ /**
+ * @return {?WebInspector.DOMNode}
+ */
+ templateContent: function()
+ {
+ return this._templateContent;
+ },
+
+ /**
+ * @return {?WebInspector.DOMNode}
+ */
+ importedDocument: function()
+ {
+ return this._importedDocument;
+ },
+
+ /**
+ * @return {number}
+ */
+ nodeType: function()
+ {
+ return this._nodeType;
+ },
+
+ /**
+ * @return {string}
+ */
+ nodeName: function()
+ {
+ return this._nodeName;
+ },
+
+ /**
+ * @return {string|undefined}
+ */
+ pseudoType: function()
+ {
+ return this._pseudoType;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ hasPseudoElements: function()
+ {
+ return Object.keys(this._pseudoElements).length !== 0;
+ },
+
+ /**
+ * @return {!Object.<string, !WebInspector.DOMNode>}
+ */
+ pseudoElements: function()
+ {
+ return this._pseudoElements;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isInShadowTree: function()
+ {
+ return this._isInShadowTree;
+ },
+
+ /**
+ * @return {?WebInspector.DOMNode}
+ */
+ ancestorUserAgentShadowRoot: function()
+ {
+ if (!this._isInShadowTree)
+ return null;
+
+ var current = this;
+ while (!current.isShadowRoot())
+ current = current.parentNode;
+ return current.shadowRootType() === WebInspector.DOMNode.ShadowRootTypes.UserAgent ? current : null;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isShadowRoot: function()
+ {
+ return !!this._shadowRootType;
+ },
+
+ /**
+ * @return {?string}
+ */
+ shadowRootType: function()
+ {
+ return this._shadowRootType || null;
+ },
+
+ /**
+ * @return {string}
+ */
+ nodeNameInCorrectCase: function()
+ {
+ var shadowRootType = this.shadowRootType();
+ if (shadowRootType)
+ return "#shadow-root" + (shadowRootType === WebInspector.DOMNode.ShadowRootTypes.UserAgent ? " (user-agent)" : "");
+ return this.isXMLNode() ? this.nodeName() : this.nodeName().toLowerCase();
+ },
+
+ /**
+ * @param {string} name
+ * @param {function(?Protocol.Error, number)=} callback
+ */
+ setNodeName: function(name, callback)
+ {
+ this._agent.setNodeName(this.id, name, this._domModel._markRevision(this, callback));
+ },
+
+ /**
+ * @return {string}
+ */
+ localName: function()
+ {
+ return this._localName;
+ },
+
+ /**
+ * @return {string}
+ */
+ nodeValue: function()
+ {
+ return this._nodeValue;
+ },
+
+ /**
+ * @param {string} value
+ * @param {function(?Protocol.Error)=} callback
+ */
+ setNodeValue: function(value, callback)
+ {
+ this._agent.setNodeValue(this.id, value, this._domModel._markRevision(this, callback));
+ },
+
+ /**
+ * @param {string} name
+ * @return {string}
+ */
+ getAttribute: function(name)
+ {
+ var attr = this._attributesMap[name];
+ return attr ? attr.value : undefined;
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} text
+ * @param {function(?Protocol.Error)=} callback
+ */
+ setAttribute: function(name, text, callback)
+ {
+ this._agent.setAttributesAsText(this.id, text, name, this._domModel._markRevision(this, callback));
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} value
+ * @param {function(?Protocol.Error)=} callback
+ */
+ setAttributeValue: function(name, value, callback)
+ {
+ this._agent.setAttributeValue(this.id, name, value, this._domModel._markRevision(this, callback));
+ },
+
+ /**
+ * @return {!Object}
+ */
+ attributes: function()
+ {
+ return this._attributes;
+ },
+
+ /**
+ * @param {string} name
+ * @param {function(?Protocol.Error)=} callback
+ */
+ removeAttribute: function(name, callback)
+ {
+ /**
+ * @param {?Protocol.Error} error
+ * @this {WebInspector.DOMNode}
+ */
+ function mycallback(error)
+ {
+ if (!error) {
+ delete this._attributesMap[name];
+ for (var i = 0; i < this._attributes.length; ++i) {
+ if (this._attributes[i].name === name) {
+ this._attributes.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ this._domModel._markRevision(this, callback)(error);
+ }
+ this._agent.removeAttribute(this.id, name, mycallback.bind(this));
+ },
+
+ /**
+ * @param {function(?Array.<!WebInspector.DOMNode>)=} callback
+ */
+ getChildNodes: function(callback)
+ {
+ if (this._children) {
+ if (callback)
+ callback(this.children());
+ return;
+ }
+
+ /**
+ * @this {WebInspector.DOMNode}
+ * @param {?Protocol.Error} error
+ */
+ function mycallback(error)
+ {
+ if (callback)
+ callback(error ? null : this.children());
+ }
+
+ this._agent.requestChildNodes(this.id, undefined, mycallback.bind(this));
+ },
+
+ /**
+ * @param {number} depth
+ * @param {function(?Array.<!WebInspector.DOMNode>)=} callback
+ */
+ getSubtree: function(depth, callback)
+ {
+ /**
+ * @this {WebInspector.DOMNode}
+ * @param {?Protocol.Error} error
+ */
+ function mycallback(error)
+ {
+ if (callback)
+ callback(error ? null : this._children);
+ }
+
+ this._agent.requestChildNodes(this.id, depth, mycallback.bind(this));
+ },
+
+ /**
+ * @param {function(?Protocol.Error, string)=} callback
+ */
+ getOuterHTML: function(callback)
+ {
+ this._agent.getOuterHTML(this.id, callback);
+ },
+
+ /**
+ * @param {string} html
+ * @param {function(?Protocol.Error)=} callback
+ */
+ setOuterHTML: function(html, callback)
+ {
+ this._agent.setOuterHTML(this.id, html, this._domModel._markRevision(this, callback));
+ },
+
+ /**
+ * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback
+ */
+ removeNode: function(callback)
+ {
+ this._agent.removeNode(this.id, this._domModel._markRevision(this, callback));
+ },
+
+ copyNode: function()
+ {
+ function copy(error, text)
+ {
+ if (!error)
+ InspectorFrontendHost.copyText(text);
+ }
+ this._agent.getOuterHTML(this.id, copy);
+ },
+
+ /**
+ * @param {string} objectGroupId
+ * @param {function(?Array.<!WebInspector.DOMModel.EventListener>)} callback
+ */
+ eventListeners: function(objectGroupId, callback)
+ {
+ var target = this.target();
+
+ /**
+ * @param {?Protocol.Error} error
+ * @param {!Array.<!DOMAgent.EventListener>} payloads
+ */
+ function mycallback(error, payloads)
+ {
+ if (error) {
+ callback(null);
+ return;
+ }
+ callback(payloads.map(function(payload) {
+ return new WebInspector.DOMModel.EventListener(target, payload);
+ }));
+ }
+ this._agent.getEventListenersForNode(this.id, objectGroupId, mycallback);
+ },
+
+ /**
+ * @return {string}
+ */
+ path: function()
+ {
+ /**
+ * @param {?WebInspector.DOMNode} node
+ */
+ function canPush(node)
+ {
+ return node && ("index" in node || (node.isShadowRoot() && node.parentNode)) && node._nodeName.length;
+ }
+
+ var path = [];
+ var node = this;
+ while (canPush(node)) {
+ var index = typeof node.index === "number" ? node.index : (node.shadowRootType() === WebInspector.DOMNode.ShadowRootTypes.UserAgent ? "u" : "a");
+ path.push([index, node._nodeName]);
+ node = node.parentNode;
+ }
+ path.reverse();
+ return path.join(",");
+ },
+
+ /**
+ * @param {!WebInspector.DOMNode} node
+ * @return {boolean}
+ */
+ isAncestor: function(node)
+ {
+ if (!node)
+ return false;
+
+ var currentNode = node.parentNode;
+ while (currentNode) {
+ if (this === currentNode)
+ return true;
+ currentNode = currentNode.parentNode;
+ }
+ return false;
+ },
+
+ /**
+ * @param {!WebInspector.DOMNode} descendant
+ * @return {boolean}
+ */
+ isDescendant: function(descendant)
+ {
+ return descendant !== null && descendant.isAncestor(this);
+ },
+
+ /**
+ * @return {?PageAgent.FrameId}
+ */
+ frameId: function()
+ {
+ var node = this;
+ while (!node._frameId && node.parentNode)
+ node = node.parentNode;
+ return node._frameId;
+ },
+
+ /**
+ * @param {!Array.<string>} attrs
+ * @return {boolean}
+ */
+ _setAttributesPayload: function(attrs)
+ {
+ var attributesChanged = !this._attributes || attrs.length !== this._attributes.length * 2;
+ var oldAttributesMap = this._attributesMap || {};
+
+ this._attributes = [];
+ this._attributesMap = {};
+
+ for (var i = 0; i < attrs.length; i += 2) {
+ var name = attrs[i];
+ var value = attrs[i + 1];
+ this._addAttribute(name, value);
+
+ if (attributesChanged)
+ continue;
+
+ if (!oldAttributesMap[name] || oldAttributesMap[name].value !== value)
+ attributesChanged = true;
+ }
+ return attributesChanged;
+ },
+
+ /**
+ * @param {!WebInspector.DOMNode} prev
+ * @param {!DOMAgent.Node} payload
+ * @return {!WebInspector.DOMNode}
+ */
+ _insertChild: function(prev, payload)
+ {
+ var node = new WebInspector.DOMNode(this._domModel, this.ownerDocument, this._isInShadowTree, payload);
+ this._children.splice(this._children.indexOf(prev) + 1, 0, node);
+ this._renumber();
+ return node;
+ },
+
+ /**
+ * @param {!WebInspector.DOMNode} node
+ */
+ _removeChild: function(node)
+ {
+ if (node.pseudoType()) {
+ delete this._pseudoElements[node.pseudoType()];
+ } else {
+ var shadowRootIndex = this._shadowRoots.indexOf(node);
+ if (shadowRootIndex !== -1)
+ this._shadowRoots.splice(shadowRootIndex, 1);
+ else
+ this._children.splice(this._children.indexOf(node), 1);
+ }
+ node.parentNode = null;
+ node._updateChildUserPropertyCountsOnRemoval(this);
+ this._renumber();
+ },
+
+ /**
+ * @param {!Array.<!DOMAgent.Node>} payloads
+ */
+ _setChildrenPayload: function(payloads)
+ {
+ // We set children in the constructor.
+ if (this._contentDocument)
+ return;
+
+ this._children = [];
+ for (var i = 0; i < payloads.length; ++i) {
+ var payload = payloads[i];
+ var node = new WebInspector.DOMNode(this._domModel, this.ownerDocument, this._isInShadowTree, payload);
+ this._children.push(node);
+ }
+ this._renumber();
+ },
+
+ /**
+ * @param {!Array.<!DOMAgent.Node>|undefined} payloads
+ */
+ _setPseudoElements: function(payloads)
+ {
+ this._pseudoElements = {};
+ if (!payloads)
+ return;
+
+ for (var i = 0; i < payloads.length; ++i) {
+ var node = new WebInspector.DOMNode(this._domModel, this.ownerDocument, this._isInShadowTree, payloads[i]);
+ node.parentNode = this;
+ this._pseudoElements[node.pseudoType()] = node;
+ }
+ },
+
+ _renumber: function()
+ {
+ this._childNodeCount = this._children.length;
+ if (this._childNodeCount == 0) {
+ this.firstChild = null;
+ this.lastChild = null;
+ return;
+ }
+ this.firstChild = this._children[0];
+ this.lastChild = this._children[this._childNodeCount - 1];
+ for (var i = 0; i < this._childNodeCount; ++i) {
+ var child = this._children[i];
+ child.index = i;
+ child.nextSibling = i + 1 < this._childNodeCount ? this._children[i + 1] : null;
+ child.previousSibling = i - 1 >= 0 ? this._children[i - 1] : null;
+ child.parentNode = this;
+ }
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} value
+ */
+ _addAttribute: function(name, value)
+ {
+ var attr = {
+ name: name,
+ value: value,
+ _node: this
+ };
+ this._attributesMap[name] = attr;
+ this._attributes.push(attr);
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} value
+ */
+ _setAttribute: function(name, value)
+ {
+ var attr = this._attributesMap[name];
+ if (attr)
+ attr.value = value;
+ else
+ this._addAttribute(name, value);
+ },
+
+ /**
+ * @param {string} name
+ */
+ _removeAttribute: function(name)
+ {
+ var attr = this._attributesMap[name];
+ if (attr) {
+ this._attributes.remove(attr);
+ delete this._attributesMap[name];
+ }
+ },
+
+ /**
+ * @param {!WebInspector.DOMNode} targetNode
+ * @param {?WebInspector.DOMNode} anchorNode
+ * @param {function(?Protocol.Error, !DOMAgent.NodeId=)=} callback
+ */
+ moveTo: function(targetNode, anchorNode, callback)
+ {
+ this._agent.moveTo(this.id, targetNode.id, anchorNode ? anchorNode.id : undefined, this._domModel._markRevision(this, callback));
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isXMLNode: function()
+ {
+ return !!this.ownerDocument && !!this.ownerDocument.xmlVersion;
+ },
+
+ _updateChildUserPropertyCountsOnRemoval: function(parentNode)
+ {
+ var result = {};
+ if (this._userProperties) {
+ for (var name in this._userProperties)
+ result[name] = (result[name] || 0) + 1;
+ }
+
+ if (this._descendantUserPropertyCounters) {
+ for (var name in this._descendantUserPropertyCounters) {
+ var counter = this._descendantUserPropertyCounters[name];
+ result[name] = (result[name] || 0) + counter;
+ }
+ }
+
+ for (var name in result)
+ parentNode._updateDescendantUserPropertyCount(name, -result[name]);
+ },
+
+ _updateDescendantUserPropertyCount: function(name, delta)
+ {
+ if (!this._descendantUserPropertyCounters.hasOwnProperty(name))
+ this._descendantUserPropertyCounters[name] = 0;
+ this._descendantUserPropertyCounters[name] += delta;
+ if (!this._descendantUserPropertyCounters[name])
+ delete this._descendantUserPropertyCounters[name];
+ if (this.parentNode)
+ this.parentNode._updateDescendantUserPropertyCount(name, delta);
+ },
+
+ setUserProperty: function(name, value)
+ {
+ if (value === null) {
+ this.removeUserProperty(name);
+ return;
+ }
+
+ if (this.parentNode && !this._userProperties.hasOwnProperty(name))
+ this.parentNode._updateDescendantUserPropertyCount(name, 1);
+
+ this._userProperties[name] = value;
+ },
+
+ removeUserProperty: function(name)
+ {
+ if (!this._userProperties.hasOwnProperty(name))
+ return;
+
+ delete this._userProperties[name];
+ if (this.parentNode)
+ this.parentNode._updateDescendantUserPropertyCount(name, -1);
+ },
+
+ /**
+ * @param {string} name
+ * @return {?T}
+ * @template T
+ */
+ getUserProperty: function(name)
+ {
+ return (this._userProperties && this._userProperties[name]) || null;
+ },
+
+ /**
+ * @param {string} name
+ * @return {number}
+ */
+ descendantUserPropertyCount: function(name)
+ {
+ return this._descendantUserPropertyCounters && this._descendantUserPropertyCounters[name] ? this._descendantUserPropertyCounters[name] : 0;
+ },
+
+ /**
+ * @param {string} url
+ * @return {?string}
+ */
+ resolveURL: function(url)
+ {
+ if (!url)
+ return url;
+ for (var frameOwnerCandidate = this; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) {
+ if (frameOwnerCandidate.baseURL)
+ return WebInspector.ParsedURL.completeURL(frameOwnerCandidate.baseURL, url);
+ }
+ return null;
+ },
+
+ /**
+ * @param {string=} mode
+ * @param {!RuntimeAgent.RemoteObjectId=} objectId
+ */
+ highlight: function(mode, objectId)
+ {
+ this._domModel.highlightDOMNode(this.id, mode, objectId);
+ },
+
+ highlightForTwoSeconds: function()
+ {
+ this._domModel.highlightDOMNodeForTwoSeconds(this.id);
+ },
+
+ reveal: function()
+ {
+ WebInspector.Revealer.reveal(this);
+ },
+
+ /**
+ * @param {string=} objectGroup
+ * @param {function(?WebInspector.RemoteObject)=} callback
+ */
+ resolveToObject: function(objectGroup, callback)
+ {
+ this._agent.resolveNode(this.id, objectGroup, mycallback.bind(this));
+
+ /**
+ * @param {?Protocol.Error} error
+ * @param {!RuntimeAgent.RemoteObject} object
+ * @this {WebInspector.DOMNode}
+ */
+ function mycallback(error, object)
+ {
+ if (!callback)
+ return;
+
+ if (error || !object)
+ callback(null);
+ else
+ callback(this.target().runtimeModel.createRemoteObject(object));
+ }
+ },
+
+ /**
+ * @param {function(?DOMAgent.BoxModel)} callback
+ */
+ boxModel: function(callback)
+ {
+ this._agent.getBoxModel(this.id, this._domModel._wrapClientCallback(callback));
+ },
+
+ __proto__: WebInspector.TargetAware.prototype
+}
+
+/**
+ * @extends {WebInspector.DOMNode}
+ * @constructor
+ * @param {!WebInspector.DOMModel} domModel
+ * @param {!DOMAgent.Node} payload
+ */
+WebInspector.DOMDocument = function(domModel, payload)
+{
+ WebInspector.DOMNode.call(this, domModel, this, false, payload);
+ this.documentURL = payload.documentURL || "";
+ this.baseURL = payload.baseURL || "";
+ this.xmlVersion = payload.xmlVersion;
+ this._listeners = {};
+}
+
+WebInspector.DOMDocument.prototype = {
+ __proto__: WebInspector.DOMNode.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.TargetAwareObject}
+ * @param {!WebInspector.Target} target
+ */
+WebInspector.DOMModel = function(target) {
+ WebInspector.TargetAwareObject.call(this, target);
+
+ this._agent = target.domAgent();
+
+ /** @type {!Object.<number, !WebInspector.DOMNode>} */
+ this._idToDOMNode = {};
+ /** @type {?WebInspector.DOMDocument} */
+ this._document = null;
+ /** @type {!Object.<number, boolean>} */
+ this._attributeLoadNodeIds = {};
+ target.registerDOMDispatcher(new WebInspector.DOMDispatcher(this));
+
+ this._defaultHighlighter = new WebInspector.DefaultDOMNodeHighlighter(this._agent);
+ this._highlighter = this._defaultHighlighter;
+ this._agent.enable();
+}
+
+WebInspector.DOMModel.Events = {
+ AttrModified: "AttrModified",
+ AttrRemoved: "AttrRemoved",
+ CharacterDataModified: "CharacterDataModified",
+ NodeInserted: "NodeInserted",
+ NodeRemoved: "NodeRemoved",
+ DocumentUpdated: "DocumentUpdated",
+ ChildNodeCountUpdated: "ChildNodeCountUpdated",
+ UndoRedoRequested: "UndoRedoRequested",
+ UndoRedoCompleted: "UndoRedoCompleted",
+}
+
+WebInspector.DOMModel.prototype = {
+ /**
+ * @param {function(!WebInspector.DOMDocument)=} callback
+ */
+ requestDocument: function(callback)
+ {
+ if (this._document) {
+ if (callback)
+ callback(this._document);
+ return;
+ }
+
+ if (this._pendingDocumentRequestCallbacks) {
+ this._pendingDocumentRequestCallbacks.push(callback);
+ return;
+ }
+
+ this._pendingDocumentRequestCallbacks = [callback];
+
+ /**
+ * @this {WebInspector.DOMModel}
+ * @param {?Protocol.Error} error
+ * @param {!DOMAgent.Node} root
+ */
+ function onDocumentAvailable(error, root)
+ {
+ if (!error)
+ this._setDocument(root);
+
+ for (var i = 0; i < this._pendingDocumentRequestCallbacks.length; ++i) {
+ var callback = this._pendingDocumentRequestCallbacks[i];
+ if (callback)
+ callback(this._document);
+ }
+ delete this._pendingDocumentRequestCallbacks;
+ }
+
+ this._agent.getDocument(onDocumentAvailable.bind(this));
+ },
+
+ /**
+ * @return {?WebInspector.DOMDocument}
+ */
+ existingDocument: function()
+ {
+ return this._document;
+ },
+
+ /**
+ * @param {!RuntimeAgent.RemoteObjectId} objectId
+ * @param {function(?WebInspector.DOMNode)=} callback
+ */
+ pushNodeToFrontend: function(objectId, callback)
+ {
+ /**
+ * @param {?DOMAgent.NodeId} nodeId
+ * @this {!WebInspector.DOMModel}
+ */
+ function mycallback(nodeId)
+ {
+ callback(nodeId ? this.nodeForId(nodeId) : null);
+ }
+ this._dispatchWhenDocumentAvailable(this._agent.requestNode.bind(this._agent, objectId), mycallback.bind(this));
+ },
+
+ /**
+ * @param {string} path
+ * @param {function(?number)=} callback
+ */
+ pushNodeByPathToFrontend: function(path, callback)
+ {
+ this._dispatchWhenDocumentAvailable(this._agent.pushNodeByPathToFrontend.bind(this._agent, path), callback);
+ },
+
+ /**
+ * @param {!Array.<number>} backendNodeIds
+ * @param {function(?Array.<number>)=} callback
+ */
+ pushNodesByBackendIdsToFrontend: function(backendNodeIds, callback)
+ {
+ this._dispatchWhenDocumentAvailable(this._agent.pushNodesByBackendIdsToFrontend.bind(this._agent, backendNodeIds), callback);
+ },
+
+ /**
+ * @param {function(!T)=} callback
+ * @return {function(?Protocol.Error, !T=)|undefined}
+ * @template T
+ */
+ _wrapClientCallback: function(callback)
+ {
+ if (!callback)
+ return;
+ /**
+ * @param {?Protocol.Error} error
+ * @param {!T=} result
+ * @template T
+ */
+ var wrapper = function(error, result)
+ {
+ // Caller is responsible for handling the actual error.
+ callback(error ? null : result);
+ };
+ return wrapper;
+ },
+
+ /**
+ * @param {function(function(?Protocol.Error, !T=)=)} func
+ * @param {function(!T)=} callback
+ * @template T
+ */
+ _dispatchWhenDocumentAvailable: function(func, callback)
+ {
+ var callbackWrapper = this._wrapClientCallback(callback);
+
+ /**
+ * @this {WebInspector.DOMModel}
+ */
+ function onDocumentAvailable()
+ {
+ if (this._document)
+ func(callbackWrapper);
+ else {
+ if (callbackWrapper)
+ callbackWrapper("No document");
+ }
+ }
+ this.requestDocument(onDocumentAvailable.bind(this));
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {string} name
+ * @param {string} value
+ */
+ _attributeModified: function(nodeId, name, value)
+ {
+ var node = this._idToDOMNode[nodeId];
+ if (!node)
+ return;
+
+ node._setAttribute(name, value);
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrModified, { node: node, name: name });
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {string} name
+ */
+ _attributeRemoved: function(nodeId, name)
+ {
+ var node = this._idToDOMNode[nodeId];
+ if (!node)
+ return;
+ node._removeAttribute(name);
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrRemoved, { node: node, name: name });
+ },
+
+ /**
+ * @param {!Array.<!DOMAgent.NodeId>} nodeIds
+ */
+ _inlineStyleInvalidated: function(nodeIds)
+ {
+ for (var i = 0; i < nodeIds.length; ++i)
+ this._attributeLoadNodeIds[nodeIds[i]] = true;
+ if ("_loadNodeAttributesTimeout" in this)
+ return;
+ this._loadNodeAttributesTimeout = setTimeout(this._loadNodeAttributes.bind(this), 20);
+ },
+
+ _loadNodeAttributes: function()
+ {
+ /**
+ * @this {WebInspector.DOMModel}
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {?Protocol.Error} error
+ * @param {!Array.<string>} attributes
+ */
+ function callback(nodeId, error, attributes)
+ {
+ if (error) {
+ // We are calling _loadNodeAttributes asynchronously, it is ok if node is not found.
+ return;
+ }
+ var node = this._idToDOMNode[nodeId];
+ if (node) {
+ if (node._setAttributesPayload(attributes))
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.AttrModified, { node: node, name: "style" });
+ }
+ }
+
+ delete this._loadNodeAttributesTimeout;
+
+ for (var nodeId in this._attributeLoadNodeIds) {
+ var nodeIdAsNumber = parseInt(nodeId, 10);
+ this._agent.getAttributes(nodeIdAsNumber, callback.bind(this, nodeIdAsNumber));
+ }
+ this._attributeLoadNodeIds = {};
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {string} newValue
+ */
+ _characterDataModified: function(nodeId, newValue)
+ {
+ var node = this._idToDOMNode[nodeId];
+ node._nodeValue = newValue;
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.CharacterDataModified, node);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @return {?WebInspector.DOMNode}
+ */
+ nodeForId: function(nodeId)
+ {
+ return this._idToDOMNode[nodeId] || null;
+ },
+
+ _documentUpdated: function()
+ {
+ this._setDocument(null);
+ },
+
+ /**
+ * @param {?DOMAgent.Node} payload
+ */
+ _setDocument: function(payload)
+ {
+ this._idToDOMNode = {};
+ if (payload && "nodeId" in payload)
+ this._document = new WebInspector.DOMDocument(this, payload);
+ else
+ this._document = null;
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.DocumentUpdated, this._document);
+ },
+
+ /**
+ * @param {!DOMAgent.Node} payload
+ */
+ _setDetachedRoot: function(payload)
+ {
+ if (payload.nodeName === "#document")
+ new WebInspector.DOMDocument(this, payload);
+ else
+ new WebInspector.DOMNode(this, null, false, payload);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentId
+ * @param {!Array.<!DOMAgent.Node>} payloads
+ */
+ _setChildNodes: function(parentId, payloads)
+ {
+ if (!parentId && payloads.length) {
+ this._setDetachedRoot(payloads[0]);
+ return;
+ }
+
+ var parent = this._idToDOMNode[parentId];
+ parent._setChildrenPayload(payloads);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {number} newValue
+ */
+ _childNodeCountUpdated: function(nodeId, newValue)
+ {
+ var node = this._idToDOMNode[nodeId];
+ node._childNodeCount = newValue;
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.ChildNodeCountUpdated, node);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentId
+ * @param {!DOMAgent.NodeId} prevId
+ * @param {!DOMAgent.Node} payload
+ */
+ _childNodeInserted: function(parentId, prevId, payload)
+ {
+ var parent = this._idToDOMNode[parentId];
+ var prev = this._idToDOMNode[prevId];
+ var node = parent._insertChild(prev, payload);
+ this._idToDOMNode[node.id] = node;
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted, node);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentId
+ * @param {!DOMAgent.NodeId} nodeId
+ */
+ _childNodeRemoved: function(parentId, nodeId)
+ {
+ var parent = this._idToDOMNode[parentId];
+ var node = this._idToDOMNode[nodeId];
+ parent._removeChild(node);
+ this._unbind(node);
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved, {node: node, parent: parent});
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} hostId
+ * @param {!DOMAgent.Node} root
+ */
+ _shadowRootPushed: function(hostId, root)
+ {
+ var host = this._idToDOMNode[hostId];
+ if (!host)
+ return;
+ var node = new WebInspector.DOMNode(this, host.ownerDocument, true, root);
+ node.parentNode = host;
+ this._idToDOMNode[node.id] = node;
+ host._shadowRoots.push(node);
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted, node);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} hostId
+ * @param {!DOMAgent.NodeId} rootId
+ */
+ _shadowRootPopped: function(hostId, rootId)
+ {
+ var host = this._idToDOMNode[hostId];
+ if (!host)
+ return;
+ var root = this._idToDOMNode[rootId];
+ if (!root)
+ return;
+ host._removeChild(root);
+ this._unbind(root);
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved, {node: root, parent: host});
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentId
+ * @param {!DOMAgent.Node} pseudoElement
+ */
+ _pseudoElementAdded: function(parentId, pseudoElement)
+ {
+ var parent = this._idToDOMNode[parentId];
+ if (!parent)
+ return;
+ var node = new WebInspector.DOMNode(this, parent.ownerDocument, false, pseudoElement);
+ node.parentNode = parent;
+ this._idToDOMNode[node.id] = node;
+ console.assert(!parent._pseudoElements[node.pseudoType()]);
+ parent._pseudoElements[node.pseudoType()] = node;
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeInserted, node);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentId
+ * @param {!DOMAgent.NodeId} pseudoElementId
+ */
+ _pseudoElementRemoved: function(parentId, pseudoElementId)
+ {
+ var parent = this._idToDOMNode[parentId];
+ if (!parent)
+ return;
+ var pseudoElement = this._idToDOMNode[pseudoElementId];
+ if (!pseudoElement)
+ return;
+ parent._removeChild(pseudoElement);
+ this._unbind(pseudoElement);
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.NodeRemoved, {node: pseudoElement, parent: parent});
+ },
+
+ /**
+ * @param {!WebInspector.DOMNode} node
+ */
+ _unbind: function(node)
+ {
+ delete this._idToDOMNode[node.id];
+ for (var i = 0; node._children && i < node._children.length; ++i)
+ this._unbind(node._children[i]);
+ for (var i = 0; i < node._shadowRoots.length; ++i)
+ this._unbind(node._shadowRoots[i]);
+ var pseudoElements = node.pseudoElements();
+ for (var id in pseudoElements)
+ this._unbind(pseudoElements[id]);
+ if (node._templateContent)
+ this._unbind(node._templateContent);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ */
+ _inspectNodeRequested: function(nodeId)
+ {
+ WebInspector.Revealer.reveal(this.nodeForId(nodeId))
+ },
+
+ /**
+ * @param {string} query
+ * @param {function(number)} searchCallback
+ */
+ performSearch: function(query, searchCallback)
+ {
+ this.cancelSearch();
+
+ /**
+ * @param {?Protocol.Error} error
+ * @param {string} searchId
+ * @param {number} resultsCount
+ * @this {WebInspector.DOMModel}
+ */
+ function callback(error, searchId, resultsCount)
+ {
+ this._searchId = searchId;
+ searchCallback(resultsCount);
+ }
+ this._agent.performSearch(query, callback.bind(this));
+ },
+
+ /**
+ * @param {number} index
+ * @param {?function(?WebInspector.DOMNode)} callback
+ */
+ searchResult: function(index, callback)
+ {
+ if (this._searchId)
+ this._agent.getSearchResults(this._searchId, index, index + 1, searchResultsCallback.bind(this));
+ else
+ callback(null);
+
+ /**
+ * @param {?Protocol.Error} error
+ * @param {!Array.<number>} nodeIds
+ * @this {WebInspector.DOMModel}
+ */
+ function searchResultsCallback(error, nodeIds)
+ {
+ if (error) {
+ console.error(error);
+ callback(null);
+ return;
+ }
+ if (nodeIds.length != 1)
+ return;
+
+ callback(this.nodeForId(nodeIds[0]));
+ }
+ },
+
+ cancelSearch: function()
+ {
+ if (this._searchId) {
+ this._agent.discardSearchResults(this._searchId);
+ delete this._searchId;
+ }
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {string} selectors
+ * @param {function(?DOMAgent.NodeId)=} callback
+ */
+ querySelector: function(nodeId, selectors, callback)
+ {
+ this._agent.querySelector(nodeId, selectors, this._wrapClientCallback(callback));
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {string} selectors
+ * @param {function(!Array.<!DOMAgent.NodeId>=)=} callback
+ */
+ querySelectorAll: function(nodeId, selectors, callback)
+ {
+ this._agent.querySelectorAll(nodeId, selectors, this._wrapClientCallback(callback));
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId=} nodeId
+ * @param {string=} mode
+ * @param {!RuntimeAgent.RemoteObjectId=} objectId
+ */
+ highlightDOMNode: function(nodeId, mode, objectId)
+ {
+ this.highlightDOMNodeWithConfig(nodeId, { mode: mode }, objectId);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId=} nodeId
+ * @param {!{mode: (string|undefined), showInfo: (boolean|undefined)}=} config
+ * @param {!RuntimeAgent.RemoteObjectId=} objectId
+ */
+ highlightDOMNodeWithConfig: function(nodeId, config, objectId)
+ {
+ config = config || { mode: "all", showInfo: undefined };
+ if (this._hideDOMNodeHighlightTimeout) {
+ clearTimeout(this._hideDOMNodeHighlightTimeout);
+ delete this._hideDOMNodeHighlightTimeout;
+ }
+ var highlightConfig = this._buildHighlightConfig(config.mode);
+ if (typeof config.showInfo !== "undefined")
+ highlightConfig.showInfo = config.showInfo;
+ this._highlighter.highlightDOMNode(this.nodeForId(nodeId || 0), highlightConfig, objectId);
+ },
+
+ hideDOMNodeHighlight: function()
+ {
+ this.highlightDOMNode(0);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ */
+ highlightDOMNodeForTwoSeconds: function(nodeId)
+ {
+ this.highlightDOMNode(nodeId);
+ this._hideDOMNodeHighlightTimeout = setTimeout(this.hideDOMNodeHighlight.bind(this), 2000);
+ },
+
+ /**
+ * @param {boolean} enabled
+ * @param {boolean} inspectUAShadowDOM
+ * @param {function(?Protocol.Error)=} callback
+ */
+ setInspectModeEnabled: function(enabled, inspectUAShadowDOM, callback)
+ {
+ /**
+ * @this {WebInspector.DOMModel}
+ */
+ function onDocumentAvailable()
+ {
+ this._highlighter.setInspectModeEnabled(enabled, inspectUAShadowDOM, this._buildHighlightConfig(), callback);
+ }
+ this.requestDocument(onDocumentAvailable.bind(this));
+ },
+
+ /**
+ * @param {string=} mode
+ * @return {!DOMAgent.HighlightConfig}
+ */
+ _buildHighlightConfig: function(mode)
+ {
+ mode = mode || "all";
+ // FIXME: split show rulers and show extension lines.
+ var highlightConfig = { showInfo: mode === "all", showRulers: WebInspector.overridesSupport.showMetricsRulers() };
+ if (mode === "all" || mode === "content")
+ highlightConfig.contentColor = WebInspector.Color.PageHighlight.Content.toProtocolRGBA();
+
+ if (mode === "all" || mode === "padding")
+ highlightConfig.paddingColor = WebInspector.Color.PageHighlight.Padding.toProtocolRGBA();
+
+ if (mode === "all" || mode === "border")
+ highlightConfig.borderColor = WebInspector.Color.PageHighlight.Border.toProtocolRGBA();
+
+ if (mode === "all" || mode === "margin")
+ highlightConfig.marginColor = WebInspector.Color.PageHighlight.Margin.toProtocolRGBA();
+
+ if (mode === "all")
+ highlightConfig.eventTargetColor = WebInspector.Color.PageHighlight.EventTarget.toProtocolRGBA();
+
+ return highlightConfig;
+ },
+
+ /**
+ * @param {!WebInspector.DOMNode} node
+ * @param {function(?Protocol.Error, ...)=} callback
+ * @return {function(...)}
+ * @template T
+ */
+ _markRevision: function(node, callback)
+ {
+ /**
+ * @param {?Protocol.Error} error
+ * @this {WebInspector.DOMModel}
+ */
+ function wrapperFunction(error)
+ {
+ if (!error)
+ this.markUndoableState();
+
+ if (callback)
+ callback.apply(this, arguments);
+ }
+ return wrapperFunction.bind(this);
+ },
+
+ /**
+ * @param {boolean} emulationEnabled
+ */
+ emulateTouchEventObjects: function(emulationEnabled)
+ {
+ const injectedFunction = function() {
+ const touchEvents = ["ontouchstart", "ontouchend", "ontouchmove", "ontouchcancel"];
+ var recepients = [window.__proto__, document.__proto__];
+ for (var i = 0; i < touchEvents.length; ++i) {
+ for (var j = 0; j < recepients.length; ++j) {
+ if (!(touchEvents[i] in recepients[j]))
+ Object.defineProperty(recepients[j], touchEvents[i], { value: null, writable: true, configurable: true, enumerable: true });
+ }
+ }
+ }
+
+ if (emulationEnabled && !this._addTouchEventsScriptInjecting) {
+ this._addTouchEventsScriptInjecting = true;
+ PageAgent.addScriptToEvaluateOnLoad("(" + injectedFunction.toString() + ")()", scriptAddedCallback.bind(this));
+ } else {
+ if (typeof this._addTouchEventsScriptId !== "undefined") {
+ PageAgent.removeScriptToEvaluateOnLoad(this._addTouchEventsScriptId);
+ delete this._addTouchEventsScriptId;
+ }
+ }
+
+ /**
+ * @param {?Protocol.Error} error
+ * @param {string} scriptId
+ * @this {WebInspector.DOMModel}
+ */
+ function scriptAddedCallback(error, scriptId)
+ {
+ delete this._addTouchEventsScriptInjecting;
+ if (error)
+ return;
+ this._addTouchEventsScriptId = scriptId;
+ }
+
+ PageAgent.setTouchEmulationEnabled(emulationEnabled);
+ },
+
+ markUndoableState: function()
+ {
+ this._agent.markUndoableState();
+ },
+
+ /**
+ * @param {function(?Protocol.Error)=} callback
+ */
+ undo: function(callback)
+ {
+ /**
+ * @param {?Protocol.Error} error
+ * @this {WebInspector.DOMModel}
+ */
+ function mycallback(error)
+ {
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoCompleted);
+ callback(error);
+ }
+
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoRequested);
+ this._agent.undo(callback);
+ },
+
+ /**
+ * @param {function(?Protocol.Error)=} callback
+ */
+ redo: function(callback)
+ {
+ /**
+ * @param {?Protocol.Error} error
+ * @this {WebInspector.DOMModel}
+ */
+ function mycallback(error)
+ {
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoCompleted);
+ callback(error);
+ }
+
+ this.dispatchEventToListeners(WebInspector.DOMModel.Events.UndoRedoRequested);
+ this._agent.redo(callback);
+ },
+
+ /**
+ * @param {?WebInspector.DOMNodeHighlighter} highlighter
+ */
+ setHighlighter: function(highlighter)
+ {
+ this._highlighter = highlighter || this._defaultHighlighter;
+ },
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {function(?WebInspector.DOMNode)} callback
+ */
+ nodeForLocation: function(x, y, callback)
+ {
+ this._agent.getNodeForLocation(x, y, mycallback.bind(this));
+
+ /**
+ * @param {?Protocol.Error} error
+ * @param {number} nodeId
+ * @this {WebInspector.DOMModel}
+ */
+ function mycallback(error, nodeId)
+ {
+ if (error) {
+ callback(null);
+ return;
+ }
+ callback(this.nodeForId(nodeId));
+ }
+ },
+
+ __proto__: WebInspector.TargetAwareObject.prototype
+}
+
+/**
+ * @constructor
+ * @implements {DOMAgent.Dispatcher}
+ * @param {!WebInspector.DOMModel} domModel
+ */
+WebInspector.DOMDispatcher = function(domModel)
+{
+ this._domModel = domModel;
+}
+
+WebInspector.DOMDispatcher.prototype = {
+ documentUpdated: function()
+ {
+ this._domModel._documentUpdated();
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ */
+ inspectNodeRequested: function(nodeId)
+ {
+ this._domModel._inspectNodeRequested(nodeId);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {string} name
+ * @param {string} value
+ */
+ attributeModified: function(nodeId, name, value)
+ {
+ this._domModel._attributeModified(nodeId, name, value);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {string} name
+ */
+ attributeRemoved: function(nodeId, name)
+ {
+ this._domModel._attributeRemoved(nodeId, name);
+ },
+
+ /**
+ * @param {!Array.<!DOMAgent.NodeId>} nodeIds
+ */
+ inlineStyleInvalidated: function(nodeIds)
+ {
+ this._domModel._inlineStyleInvalidated(nodeIds);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {string} characterData
+ */
+ characterDataModified: function(nodeId, characterData)
+ {
+ this._domModel._characterDataModified(nodeId, characterData);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentId
+ * @param {!Array.<!DOMAgent.Node>} payloads
+ */
+ setChildNodes: function(parentId, payloads)
+ {
+ this._domModel._setChildNodes(parentId, payloads);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} nodeId
+ * @param {number} childNodeCount
+ */
+ childNodeCountUpdated: function(nodeId, childNodeCount)
+ {
+ this._domModel._childNodeCountUpdated(nodeId, childNodeCount);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentNodeId
+ * @param {!DOMAgent.NodeId} previousNodeId
+ * @param {!DOMAgent.Node} payload
+ */
+ childNodeInserted: function(parentNodeId, previousNodeId, payload)
+ {
+ this._domModel._childNodeInserted(parentNodeId, previousNodeId, payload);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentNodeId
+ * @param {!DOMAgent.NodeId} nodeId
+ */
+ childNodeRemoved: function(parentNodeId, nodeId)
+ {
+ this._domModel._childNodeRemoved(parentNodeId, nodeId);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} hostId
+ * @param {!DOMAgent.Node} root
+ */
+ shadowRootPushed: function(hostId, root)
+ {
+ this._domModel._shadowRootPushed(hostId, root);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} hostId
+ * @param {!DOMAgent.NodeId} rootId
+ */
+ shadowRootPopped: function(hostId, rootId)
+ {
+ this._domModel._shadowRootPopped(hostId, rootId);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentId
+ * @param {!DOMAgent.Node} pseudoElement
+ */
+ pseudoElementAdded: function(parentId, pseudoElement)
+ {
+ this._domModel._pseudoElementAdded(parentId, pseudoElement);
+ },
+
+ /**
+ * @param {!DOMAgent.NodeId} parentId
+ * @param {!DOMAgent.NodeId} pseudoElementId
+ */
+ pseudoElementRemoved: function(parentId, pseudoElementId)
+ {
+ this._domModel._pseudoElementRemoved(parentId, pseudoElementId);
+ }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.TargetAware}
+ * @param {!WebInspector.Target} target
+ * @param {!DOMAgent.EventListener} payload
+ */
+WebInspector.DOMModel.EventListener = function(target, payload)
+{
+ WebInspector.TargetAware.call(this, target);
+ this._payload = payload;
+}
+
+WebInspector.DOMModel.EventListener.prototype = {
+ /**
+ * @return {!DOMAgent.EventListener}
+ */
+ payload: function()
+ {
+ return this._payload;
+ },
+
+ /**
+ * @return {?WebInspector.DOMNode}
+ */
+ node: function()
+ {
+ return this.target().domModel.nodeForId(this._payload.nodeId);
+ },
+
+ /**
+ * @return {!WebInspector.DebuggerModel.Location}
+ */
+ location: function()
+ {
+ return WebInspector.DebuggerModel.Location.fromPayload(this.target(), this._payload.location);
+ },
+
+ /**
+ * @return {?WebInspector.RemoteObject}
+ */
+ handler: function()
+ {
+ return this._payload.handler ? this.target().runtimeModel.createRemoteObject(this._payload.handler) : null;
+ },
+
+ __proto__: WebInspector.TargetAware.prototype
+}
+
+/**
+ * @interface
+ */
+WebInspector.DOMNodeHighlighter = function() {
+}
+
+WebInspector.DOMNodeHighlighter.prototype = {
+ /**
+ * @param {?WebInspector.DOMNode} node
+ * @param {!DOMAgent.HighlightConfig} config
+ * @param {!RuntimeAgent.RemoteObjectId=} objectId
+ */
+ highlightDOMNode: function(node, config, objectId) {},
+
+ /**
+ * @param {boolean} enabled
+ * @param {boolean} inspectUAShadowDOM
+ * @param {!DOMAgent.HighlightConfig} config
+ * @param {function(?Protocol.Error)=} callback
+ */
+ setInspectModeEnabled: function(enabled, inspectUAShadowDOM, config, callback) {}
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.DOMNodeHighlighter}
+ * @param {!Protocol.DOMAgent} agent
+ */
+WebInspector.DefaultDOMNodeHighlighter = function(agent)
+{
+ this._agent = agent;
+}
+
+WebInspector.DefaultDOMNodeHighlighter.prototype = {
+ /**
+ * @param {?WebInspector.DOMNode} node
+ * @param {!DOMAgent.HighlightConfig} config
+ * @param {!RuntimeAgent.RemoteObjectId=} objectId
+ */
+ highlightDOMNode: function(node, config, objectId)
+ {
+ if (objectId || node)
+ this._agent.highlightNode(config, objectId ? undefined : node.id, objectId);
+ else
+ this._agent.hideHighlight();
+ },
+
+ /**
+ * @param {boolean} enabled
+ * @param {boolean} inspectUAShadowDOM
+ * @param {!DOMAgent.HighlightConfig} config
+ * @param {function(?Protocol.Error)=} callback
+ */
+ setInspectModeEnabled: function(enabled, inspectUAShadowDOM, config, callback)
+ {
+ this._agent.setInspectModeEnabled(enabled, inspectUAShadowDOM, config, callback);
+ }
+}
+
+/**
+ * @type {!WebInspector.DOMModel}
+ */
+WebInspector.domModel;