Index: Source/devtools/front_end/DOMAgent.js |
diff --git a/Source/devtools/front_end/DOMAgent.js b/Source/devtools/front_end/DOMAgent.js |
index 320e88c01c7322119317b9cb53ee4c0e334ee025..f68cf3356da91f0a4065d6e9543cef795177e312 100644 |
--- a/Source/devtools/front_end/DOMAgent.js |
+++ b/Source/devtools/front_end/DOMAgent.js |
@@ -120,24 +120,6 @@ WebInspector.DOMNode.ShadowRootTypes = { |
Author: "author" |
} |
-/** |
- * @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 {Array.<WebInspector.DOMNode>} |
@@ -430,6 +412,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)); |
@@ -466,23 +456,12 @@ WebInspector.DOMNode.prototype = { |
appropriateSelectorFor: function(justSelector) |
{ |
var lowerCaseName = this.localName() || this.nodeName().toLowerCase(); |
- |
- var id = this.getAttribute("id"); |
- if (id) { |
- var selector = "#" + id; |
- return (justSelector ? selector : lowerCaseName + selector); |
- } |
- |
- var className = this.getAttribute("class"); |
- if (className) { |
- var selector = "." + className.trim().replace(/\s+/g, "."); |
- return (justSelector ? selector : lowerCaseName + selector); |
- } |
- |
+ if (this._nodeType !== Node.ELEMENT_NODE) |
+ return lowerCaseName; |
if (lowerCaseName === "input" && this.getAttribute("type")) |
return lowerCaseName + "[type=\"" + this.getAttribute("type") + "\"]"; |
- return lowerCaseName; |
+ return this.cssPath(justSelector); |
}, |
/** |
@@ -685,6 +664,177 @@ 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 = WebInspector.DOMPresentationUtils.cssPathValue(contextNode, optimized); |
aandrey
2013/11/21 10:17:34
there is a dependency problem: "sdk" module (conta
|
+ 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.DOMNodePathStep} |
+ */ |
+ _cssPathValue: function(optimized) |
aandrey
2013/11/21 10:17:34
remove this method
|
+ { |
+ if (this._nodeType !== Node.ELEMENT_NODE) |
+ return null; |
+ if (optimized) { |
+ var id = this.getAttribute("id"); |
+ if (id) |
+ return new WebInspector.DOMNodePathStep(idSelector(id), true); |
+ var nodeNameLower = this._nodeName.toLowerCase(); |
+ if (nodeNameLower === "body" || nodeNameLower === "head" || nodeNameLower === "html") |
+ return new WebInspector.DOMNodePathStep(this.nodeNameInCorrectCase(), true); |
+ } |
+ var nodeName = this.nodeNameInCorrectCase(); |
+ var parent = this.parentNode; |
+ if (!parent || parent._nodeType === Node.DOCUMENT_NODE) |
+ return new WebInspector.DOMNodePathStep(nodeName, true); |
+ |
+ /** |
+ * @param {WebInspector.DOMNode} node |
+ * @return {Array.<string>} |
+ */ |
+ function elementClassNames(node) |
+ { |
+ var classAttribute = node.getAttribute("class"); |
+ if (!classAttribute) |
+ return []; |
+ |
+ return classAttribute.split(/\s+/g).filter(Boolean); |
+ } |
+ |
+ /** |
+ * @param {string} id |
+ * @return {string} |
+ */ |
+ function idSelector(id) |
+ { |
+ return "#" + escapeIdentifierIfNeeded(id); |
+ } |
+ |
+ /** |
+ * @param {string} ident |
+ * @return {string} |
+ */ |
+ function escapeIdentifierIfNeeded(ident) |
+ { |
+ if (isCSSIdentifier(ident)) |
+ return ident; |
+ var shouldEscapeFirst = /^(?:[0-9]|-[0-9-]?)/.test(ident); |
+ var lastIndex = ident.length - 1; |
+ return ident.replace(/./g, function(c, i) { |
+ return ((shouldEscapeFirst && i === 0) || !isCSSIdentChar(c)) ? escapeAsciiChar(c, i === lastIndex) : c; |
+ }); |
+ } |
+ |
+ /** |
+ * @param {string} c |
+ * @param {boolean} isLast |
+ * @return {string} |
+ */ |
+ function escapeAsciiChar(c, isLast) |
+ { |
+ return "\\" + toHexByte(c) + (isLast ? "" : " "); |
+ } |
+ |
+ /** |
+ * @param {string} c |
+ */ |
+ function toHexByte(c) |
+ { |
+ var hexByte = c.charCodeAt(0).toString(16); |
+ if (hexByte.length === 1) |
+ hexByte = "0" + hexByte; |
+ return hexByte; |
+ } |
+ |
+ /** |
+ * @param {string} c |
+ * @return {boolean} |
+ */ |
+ function isCSSIdentChar(c) |
+ { |
+ if (/[a-zA-Z0-9_-]/.test(c)) |
+ return true; |
+ return c.charCodeAt(0) >= 0xA0; |
+ } |
+ |
+ /** |
+ * @param {string} value |
+ * @return {boolean} |
+ */ |
+ function isCSSIdentifier(value) |
+ { |
+ return /^-?[a-zA-Z_][a-zA-Z0-9_-]*$/.test(value); |
+ } |
+ |
+ var uniqueClassNamesArray = elementClassNames(this); |
+ 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 (needsNthChild) |
+ continue; |
+ if (sibling.nodeNameInCorrectCase() !== nodeName) |
+ continue; |
+ |
+ needsClassNames = true; |
+ var ownClassNames = uniqueClassNamesArray.keySet(); |
+ var ownClassNameCount = 0; |
+ for (var name in ownClassNames) |
+ ++ownClassNameCount; |
+ if (ownClassNameCount === 0) { |
+ needsNthChild = true; |
+ continue; |
+ } |
+ var siblingClassNames = elementClassNames(sibling).keySet(); |
+ for (var siblingClass in siblingClassNames) { |
+ if (!ownClassNames.hasOwnProperty(siblingClass)) |
+ continue; |
+ delete ownClassNames[siblingClass]; |
+ if (!--ownClassNameCount) { |
+ needsNthChild = true; |
+ break; |
+ } |
+ } |
+ } |
+ |
+ var result = nodeName; |
+ if (needsNthChild) { |
+ result += ":nth-child(" + (ownIndex + 1) + ")"; |
+ } else if (needsClassNames) { |
+ for (var name in uniqueClassNamesArray.keySet()) |
+ result += "." + escapeIdentifierIfNeeded(name); |
+ } |
+ return new WebInspector.DOMNodePathStep(result, false); |
+ }, |
+ |
+ /** |
+ * @param {boolean} optimized |
+ * @return {string} |
+ */ |
xPath: function(optimized) |
{ |
if (this._nodeType === Node.DOCUMENT_NODE) |
@@ -708,7 +858,7 @@ WebInspector.DOMNode.prototype = { |
/** |
* @param {boolean} optimized |
- * @return {WebInspector.DOMNode.XPathStep} |
+ * @return {WebInspector.DOMNodePathStep} |
*/ |
_xPathValue: function(optimized) |
{ |
@@ -720,7 +870,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.DOMNodePathStep("//*[@id=\"" + this.getAttribute("id") + "\"]", true); |
ownValue = this._localName; |
break; |
case Node.ATTRIBUTE_NODE: |
@@ -747,7 +897,7 @@ WebInspector.DOMNode.prototype = { |
if (ownIndex > 0) |
ownValue += "[" + ownIndex + "]"; |
- return new WebInspector.DOMNode.XPathStep(ownValue, this._nodeType === Node.DOCUMENT_NODE); |
+ return new WebInspector.DOMNodePathStep(ownValue, this._nodeType === Node.DOCUMENT_NODE); |
}, |
/** |