Index: Source/devtools/front_end/DOMAgent.js |
diff --git a/Source/devtools/front_end/DOMAgent.js b/Source/devtools/front_end/DOMAgent.js |
index 45467bc785d2b124fa86413c1df121a4feaaf940..cff17a2f9dae9ad330581f40bdec626d2845c893 100644 |
--- a/Source/devtools/front_end/DOMAgent.js |
+++ b/Source/devtools/front_end/DOMAgent.js |
@@ -119,13 +119,13 @@ WebInspector.DOMNode.PseudoElementNames = { |
* @param {string} value |
* @param {boolean} optimized |
*/ |
-WebInspector.DOMNode.XPathStep = function(value, optimized) |
+WebInspector.DOMNode.PathStep = function(value, optimized) |
{ |
this.value = value; |
this.optimized = optimized; |
} |
-WebInspector.DOMNode.XPathStep.prototype = { |
+WebInspector.DOMNode.PathStep.prototype = { |
toString: function() |
{ |
return this.value; |
@@ -416,6 +416,14 @@ WebInspector.DOMNode.prototype = { |
/** |
* @param {boolean} optimized |
*/ |
+ copyCSSPath: function(optimized) |
+ { |
+ InspectorFrontendHost.copyText(this.cssPath(optimized)); |
+ }, |
+ |
+ /** |
+ * @param {boolean} optimized |
+ */ |
copyXPath: function(optimized) |
{ |
InspectorFrontendHost.copyText(this.xPath(optimized)); |
@@ -671,6 +679,110 @@ WebInspector.DOMNode.prototype = { |
* @param {boolean} optimized |
* @return {string} |
*/ |
+ cssPath: function(optimized) |
+ { |
+ if (this._nodeType !== Node.ELEMENT_NODE) |
+ return ""; |
+ |
+ var steps = []; |
+ var contextNode = this; |
+ while (contextNode) { |
+ var step = contextNode._cssPathValue(optimized); |
+ if (!step) |
+ break; // Error - bail out early. |
+ steps.push(step); |
+ if (step.optimized) |
+ break; |
+ contextNode = contextNode.parentNode; |
+ } |
+ |
+ steps.reverse(); |
+ return steps.join(" > "); |
+ }, |
+ |
+ /** |
+ * @param {boolean} optimized |
+ * @return {WebInspector.DOMNode.PathStep} |
+ */ |
+ _cssPathValue: function(optimized) |
+ { |
+ if (this._nodeType !== Node.ELEMENT_NODE) |
+ return null; |
+ if (optimized) { |
+ if (this.getAttribute("id")) |
+ return new WebInspector.DOMNode.PathStep("#" + this.getAttribute("id"), true); |
aandrey
2013/11/18 16:27:22
"id" can contain spaces. can it be written properl
|
+ var nodeNameLower = this._nodeName.toLowerCase(); |
+ if (nodeNameLower === "body" || nodeNameLower === "head" || nodeNameLower === "html") |
+ return new WebInspector.DOMNode.PathStep(this.nodeNameInCorrectCase(), true); |
+ } |
+ var nodeName = this.nodeNameInCorrectCase(); |
+ var parent = this.parentNode; |
+ if (!parent || parent._nodeType === Node.DOCUMENT_NODE) |
+ return new WebInspector.DOMNode.PathStep(nodeName, true); |
+ |
+ /** |
+ * @param {WebInspector.DOMNode} node |
+ * @return {Object.<string, boolean>} |
+ */ |
+ function elementClassNames(node) |
+ { |
+ var classAttribute = node.getAttribute("class"); |
+ if (!classAttribute) |
+ return {}; |
+ |
+ return classAttribute.split(/\s+/g).filter(function(name) { |
aandrey
2013/11/18 16:27:22
.filter(Boolean).keySet();
|
+ return !!name; |
+ }).keySet(); |
+ } |
+ |
+ var uniqueClassNames = elementClassNames(this); |
+ var uniqueClassNamesLeft = 0; |
+ for (var name in uniqueClassNames) |
+ ++uniqueClassNamesLeft; |
+ var needsClassNames = false; |
+ var needsNthChild = false; |
+ var ownIndex = -1; |
+ var siblings = parent.children(); |
+ for (var i = 0; (ownIndex === -1 || !needsNthChild) && i < siblings.length; ++i) { |
+ var sibling = siblings[i]; |
+ if (sibling === this) { |
+ ownIndex = i; |
+ continue; |
+ } |
+ if (sibling.nodeNameInCorrectCase() !== nodeName) |
+ continue; |
+ if (!uniqueClassNamesLeft) { |
+ needsNthChild = true; |
+ continue; |
+ } |
+ |
+ needsClassNames = true; |
+ var siblingClassNames = elementClassNames(sibling); |
+ for (var siblingClass in siblingClassNames) { |
+ if (!uniqueClassNames.hasOwnProperty(siblingClass)) |
+ continue; |
+ delete uniqueClassNames[siblingClass]; |
+ if (!--uniqueClassNamesLeft) { |
+ needsNthChild = true; |
+ break; |
+ } |
+ } |
+ } |
+ |
+ var result = nodeName; |
+ if (needsClassNames && uniqueClassNamesLeft) { |
+ for (var className in uniqueClassNames) |
+ result += "." + className; |
+ } |
+ if (needsNthChild) |
+ result += ":nth-child(" + (ownIndex + 1) + ")"; |
+ return new WebInspector.DOMNode.PathStep(result, false); |
+ }, |
+ |
+ /** |
+ * @param {boolean} optimized |
+ * @return {string} |
+ */ |
xPath: function(optimized) |
{ |
if (this._nodeType === Node.DOCUMENT_NODE) |
@@ -694,7 +806,7 @@ WebInspector.DOMNode.prototype = { |
/** |
* @param {boolean} optimized |
- * @return {WebInspector.DOMNode.XPathStep} |
+ * @return {WebInspector.DOMNode.PathStep} |
*/ |
_xPathValue: function(optimized) |
{ |
@@ -706,7 +818,7 @@ WebInspector.DOMNode.prototype = { |
switch (this._nodeType) { |
case Node.ELEMENT_NODE: |
if (optimized && this.getAttribute("id")) |
- return new WebInspector.DOMNode.XPathStep("//*[@id=\"" + this.getAttribute("id") + "\"]", true); |
+ return new WebInspector.DOMNode.PathStep("//*[@id=\"" + this.getAttribute("id") + "\"]", true); |
ownValue = this._localName; |
break; |
case Node.ATTRIBUTE_NODE: |
@@ -733,7 +845,7 @@ WebInspector.DOMNode.prototype = { |
if (ownIndex > 0) |
ownValue += "[" + ownIndex + "]"; |
- return new WebInspector.DOMNode.XPathStep(ownValue, this._nodeType === Node.DOCUMENT_NODE); |
+ return new WebInspector.DOMNode.PathStep(ownValue, this._nodeType === Node.DOCUMENT_NODE); |
}, |
/** |