diff options
Diffstat (limited to 'Source/WebCore/inspector/front-end/DOMAgent.js')
-rw-r--r-- | Source/WebCore/inspector/front-end/DOMAgent.js | 189 |
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()); } } |