Chromium Code Reviews| Index: Source/devtools/front_end/DOMPresentationUtils.js |
| diff --git a/Source/devtools/front_end/DOMPresentationUtils.js b/Source/devtools/front_end/DOMPresentationUtils.js |
| index 181fcd90dfbdcacc13943426fe3be6e92a5438d3..8d2c5680238fa4ed6f403bdf5b9703eb6d1ee396 100644 |
| --- a/Source/devtools/front_end/DOMPresentationUtils.js |
| +++ b/Source/devtools/front_end/DOMPresentationUtils.js |
| @@ -158,3 +158,169 @@ WebInspector.DOMPresentationUtils.buildImagePreviewContents = function(imageURL, |
| userCallback(container); |
| } |
| } |
| + |
| +WebInspector.DOMPresentationUtils.cssPathValue = function(node, optimized) |
|
aandrey
2013/11/20 16:20:49
jsdocs plz
apavlov
2013/11/21 07:31:35
Done.
|
| +{ |
| + if (node.nodeType() !== Node.ELEMENT_NODE) |
| + return null; |
| + |
| + var id = node.getAttribute("id"); |
| + if (optimized) { |
| + if (id) |
| + return new WebInspector.DOMNodePathStep(idSelector(id), true); |
| + var nodeNameLower = node.nodeName().toLowerCase(); |
| + if (nodeNameLower === "body" || nodeNameLower === "head" || nodeNameLower === "html") |
| + return new WebInspector.DOMNodePathStep(node.nodeNameInCorrectCase(), true); |
| + } |
| + var nodeName = node.nodeNameInCorrectCase(); |
| + |
| + // The "id" presence should terminate the traversal, hence |true|. |
|
aandrey
2013/11/20 16:20:49
sound obvious to me... maybe remove?
apavlov
2013/11/21 07:31:35
Done.
|
| + if (id) |
| + return new WebInspector.DOMNodePathStep(nodeName + idSelector(id), true); |
| + var parent = node.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(node); |
|
aandrey
2013/11/20 16:20:49
they are no longer unique, once you removed keySet
apavlov
2013/11/21 07:31:35
Done.
|
| + 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 === node) { |
| + ownIndex = i; |
| + continue; |
| + } |
| + if (needsNthChild) |
| + continue; |
| + if (sibling.nodeNameInCorrectCase() !== nodeName) |
| + continue; |
| + |
| + needsClassNames = true; |
| + var ownClassNames = uniqueClassNamesArray.keySet(); |
|
aandrey
2013/11/20 16:20:49
maybe write a utility method to remove a given arr
apavlov
2013/11/21 07:31:35
The problem is that we still need to know how many
|
| + 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); |
| +} |
| + |
| +/** |
| + * @constructor |
| + * @param {string} value |
| + * @param {boolean} optimized |
| + */ |
| +WebInspector.DOMNodePathStep = function(value, optimized) |
| +{ |
| + this.value = value; |
| + this.optimized = optimized; |
| +} |
| + |
| +WebInspector.DOMNodePathStep.prototype = { |
| + toString: function() |
| + { |
| + return this.value; |
| + } |
| +} |