Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(944)

Unified Diff: Source/devtools/front_end/DOMAgent.js

Issue 75253002: DevTools: [Elements] Implement "Copy CSS Path" context menu item for elements (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Improve JsDoc Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
},
/**
« no previous file with comments | « LayoutTests/inspector/elements/elements-css-path-expected.txt ('k') | Source/devtools/front_end/ElementsTreeOutline.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698