summaryrefslogtreecommitdiff
path: root/Source/WebCore/inspector/front-end/DOMAgent.js
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/inspector/front-end/DOMAgent.js')
-rw-r--r--Source/WebCore/inspector/front-end/DOMAgent.js189
1 files changed, 166 insertions, 23 deletions
diff --git a/Source/WebCore/inspector/front-end/DOMAgent.js b/Source/WebCore/inspector/front-end/DOMAgent.js
index 0473235d8..c17f20394 100644
--- a/Source/WebCore/inspector/front-end/DOMAgent.js
+++ b/Source/WebCore/inspector/front-end/DOMAgent.js
@@ -40,6 +40,7 @@ WebInspector.DOMNode = function(domAgent, doc, payload) {
this.ownerDocument = doc;
this.id = payload.nodeId;
+ domAgent._idToDOMNode[this.id] = this;
this._nodeType = payload.nodeType;
this._nodeName = payload.nodeName;
this._localName = payload.localName;
@@ -84,6 +85,24 @@ WebInspector.DOMNode = function(domAgent, doc, payload) {
}
}
+/**
+ * @constructor
+ * @param {string} value
+ * @param {boolean} optimized
+ */
+WebInspector.DOMNode.XPathStep = function(value, optimized)
+{
+ this.value = value;
+ this.optimized = optimized;
+}
+
+WebInspector.DOMNode.XPathStep.prototype = {
+ toString: function()
+ {
+ return this.value;
+ }
+}
+
WebInspector.DOMNode.prototype = {
/**
* @return {boolean}
@@ -280,6 +299,14 @@ WebInspector.DOMNode.prototype = {
},
/**
+ * @param {boolean} optimized
+ */
+ copyXPath: function(optimized)
+ {
+ InspectorFrontendHost.copyText(this.xPath(optimized));
+ },
+
+ /**
* @param {function(?Protocol.Error)=} callback
*/
eventListeners: function(callback)
@@ -489,6 +516,121 @@ WebInspector.DOMNode.prototype = {
isXMLNode: function()
{
return !!this.ownerDocument && !!this.ownerDocument.xmlVersion;
+ },
+
+ /**
+ * @param {boolean} optimized
+ * @return {string}
+ */
+ xPath: function(optimized)
+ {
+ if (this._nodeType === Node.DOCUMENT_NODE)
+ return "/";
+
+ var steps = [];
+ var contextNode = this;
+ while (contextNode) {
+ var step = contextNode._xPathValue(optimized);
+ if (!step)
+ break; // Error - bail out early.
+ steps.push(step);
+ if (step.optimized)
+ break;
+ contextNode = contextNode.parentNode;
+ }
+
+ steps.reverse();
+ return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/");
+ },
+
+ /**
+ * @param {boolean} optimized
+ * @return {WebInspector.DOMNode.XPathStep}
+ */
+ _xPathValue: function(optimized)
+ {
+ var ownValue;
+ var ownIndex = this._xPathIndex();
+ if (ownIndex === -1)
+ return null; // Error.
+
+ switch (this._nodeType) {
+ case Node.ELEMENT_NODE:
+ if (optimized && this.getAttribute("id"))
+ return new WebInspector.DOMNode.XPathStep("//*[@id=\"" + this.getAttribute("id") + "\"]", true);
+ ownValue = this._localName;
+ break;
+ case Node.ATTRIBUTE_NODE:
+ ownValue = "@" + this._nodeName;
+ break;
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ ownValue = "text()";
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ ownValue = "processing-instruction()";
+ break;
+ case Node.COMMENT_NODE:
+ ownValue = "comment()";
+ break;
+ case Node.DOCUMENT_NODE:
+ ownValue = "";
+ break;
+ default:
+ ownValue = "";
+ break;
+ }
+
+ if (ownIndex > 0)
+ ownValue += "[" + ownIndex + "]";
+
+ return new WebInspector.DOMNode.XPathStep(ownValue, this._nodeType === Node.DOCUMENT_NODE);
+ },
+
+ /**
+ * @return {number}
+ */
+ _xPathIndex: function()
+ {
+ // Returns -1 in case of error, 0 if no siblings matching the same expression, <XPath index among the same expression-matching sibling nodes> otherwise.
+ function areNodesSimilar(left, right)
+ {
+ if (left === right)
+ return true;
+
+ if (left._nodeType === Node.ELEMENT_NODE && right._nodeType === Node.ELEMENT_NODE)
+ return left._localName === right._localName;
+
+ if (left._nodeType === right._nodeType)
+ return true;
+
+ // XPath treats CDATA as text nodes.
+ var leftType = left._nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : left._nodeType;
+ var rightType = right._nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : right._nodeType;
+ return leftType === rightType;
+ }
+
+ var siblings = this.parentNode ? this.parentNode.children : null;
+ if (!siblings)
+ return 0; // Root node - no siblings.
+ var hasSameNamedElements;
+ for (var i = 0; i < siblings.length; ++i) {
+ if (areNodesSimilar(this, siblings[i]) && siblings[i] !== this) {
+ hasSameNamedElements = true;
+ break;
+ }
+ }
+ if (!hasSameNamedElements)
+ return 0;
+ var ownIndex = 1; // XPath indices start with 1.
+ for (var i = 0; i < siblings.length; ++i) {
+ if (areNodesSimilar(this, siblings[i])) {
+ if (siblings[i] === this)
+ return ownIndex;
+ ++ownIndex;
+ }
+ }
+ return -1; // An error occurred: |this| not found in parent's children.
}
}
@@ -503,7 +645,6 @@ WebInspector.DOMDocument = function(domAgent, payload)
WebInspector.DOMNode.call(this, domAgent, this, payload);
this.documentURL = payload.documentURL || "";
this.xmlVersion = payload.xmlVersion;
- domAgent._idToDOMNode[this.id] = this;
this._listeners = {};
}
@@ -521,6 +662,10 @@ WebInspector.DOMAgent = function() {
InspectorBackend.registerDOMDispatcher(new WebInspector.DOMDispatcher(this));
if (WebInspector.experimentsSettings.freeFlowDOMEditing.isEnabled())
new WebInspector.DOMModelResourceBinding(this);
+
+ if (WebInspector.settings.emulateTouchEvents.get())
+ this._emulateTouchEventsChanged();
+ WebInspector.settings.emulateTouchEvents.addChangeListener(this._emulateTouchEventsChanged, this);
}
WebInspector.DOMAgent.Events = {
@@ -731,11 +876,9 @@ WebInspector.DOMAgent.prototype = {
_setDocument: function(payload)
{
this._idToDOMNode = {};
- if (payload && "nodeId" in payload) {
+ if (payload && "nodeId" in payload)
this._document = new WebInspector.DOMDocument(this, payload);
- if (this._document.children)
- this._bindNodes(this._document.children);
- } else
+ else
this._document = null;
this.dispatchEventToListeners(WebInspector.DOMAgent.Events.DocumentUpdated, this._document);
},
@@ -745,8 +888,7 @@ WebInspector.DOMAgent.prototype = {
*/
_setDetachedRoot: function(payload)
{
- var root = new WebInspector.DOMNode(this, null, payload);
- this._idToDOMNode[payload.nodeId] = root;
+ new WebInspector.DOMNode(this, null, payload);
},
/**
@@ -762,20 +904,6 @@ WebInspector.DOMAgent.prototype = {
var parent = this._idToDOMNode[parentId];
parent._setChildrenPayload(payloads);
- this._bindNodes(parent.children);
- },
-
- /**
- * @param {Array.<WebInspector.DOMNode>} children
- */
- _bindNodes: function(children)
- {
- for (var i = 0; i < children.length; ++i) {
- var child = children[i];
- this._idToDOMNode[child.id] = child;
- if (child.children)
- this._bindNodes(child.children);
- }
},
/**
@@ -812,8 +940,18 @@ WebInspector.DOMAgent.prototype = {
var parent = this._idToDOMNode[parentId];
var node = this._idToDOMNode[nodeId];
parent._removeChild(node);
+ this._unbind(node);
this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeRemoved, {node:node, parent:parent});
- delete this._idToDOMNode[nodeId];
+ },
+
+ /**
+ * @param {DOMAgent.Node} 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]);
},
/**
@@ -978,7 +1116,7 @@ WebInspector.DOMAgent.prototype = {
function wrapperFunction(error)
{
if (callback)
- callback(error);
+ callback.apply(this, arguments);
if (error || !WebInspector.experimentsSettings.freeFlowDOMEditing.isEnabled())
return;
if (this._captureDOMTimer)
@@ -1016,6 +1154,11 @@ WebInspector.DOMAgent.prototype = {
}
DOMAgent.getOuterHTML(node.ownerDocument.id, callback);
+ },
+
+ _emulateTouchEventsChanged: function()
+ {
+ DOMAgent.setTouchEmulationEnabled(WebInspector.settings.emulateTouchEvents.get());
}
}