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

Side by Side 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: Comments addressed 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. 2 * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
3 * Copyright (C) 2009 Joseph Pecoraro 3 * Copyright (C) 2009 Joseph Pecoraro
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are 6 * modification, are permitted provided that the following conditions are
7 * met: 7 * met:
8 * 8 *
9 * * Redistributions of source code must retain the above copyright 9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 WebInspector.DOMNode.PseudoElementNames = { 112 WebInspector.DOMNode.PseudoElementNames = {
113 Before: "before", 113 Before: "before",
114 After: "after" 114 After: "after"
115 } 115 }
116 116
117 /** 117 /**
118 * @constructor 118 * @constructor
119 * @param {string} value 119 * @param {string} value
120 * @param {boolean} optimized 120 * @param {boolean} optimized
121 */ 121 */
122 WebInspector.DOMNode.XPathStep = function(value, optimized) 122 WebInspector.DOMNode.PathStep = function(value, optimized)
123 { 123 {
124 this.value = value; 124 this.value = value;
125 this.optimized = optimized; 125 this.optimized = optimized;
126 } 126 }
127 127
128 WebInspector.DOMNode.XPathStep.prototype = { 128 WebInspector.DOMNode.PathStep.prototype = {
129 toString: function() 129 toString: function()
130 { 130 {
131 return this.value; 131 return this.value;
132 } 132 }
133 } 133 }
134 134
135 WebInspector.DOMNode.prototype = { 135 WebInspector.DOMNode.prototype = {
136 /** 136 /**
137 * @return {Array.<WebInspector.DOMNode>} 137 * @return {Array.<WebInspector.DOMNode>}
138 */ 138 */
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 { 409 {
410 if (!error) 410 if (!error)
411 InspectorFrontendHost.copyText(text); 411 InspectorFrontendHost.copyText(text);
412 } 412 }
413 DOMAgent.getOuterHTML(this.id, copy); 413 DOMAgent.getOuterHTML(this.id, copy);
414 }, 414 },
415 415
416 /** 416 /**
417 * @param {boolean} optimized 417 * @param {boolean} optimized
418 */ 418 */
419 copyCSSPath: function(optimized)
420 {
421 InspectorFrontendHost.copyText(this.cssPath(optimized));
422 },
423
424 /**
425 * @param {boolean} optimized
426 */
419 copyXPath: function(optimized) 427 copyXPath: function(optimized)
420 { 428 {
421 InspectorFrontendHost.copyText(this.xPath(optimized)); 429 InspectorFrontendHost.copyText(this.xPath(optimized));
422 }, 430 },
423 431
424 /** 432 /**
425 * @param {string} objectGroupId 433 * @param {string} objectGroupId
426 * @param {function(?Protocol.Error)=} callback 434 * @param {function(?Protocol.Error)=} callback
427 */ 435 */
428 eventListeners: function(objectGroupId, callback) 436 eventListeners: function(objectGroupId, callback)
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
664 */ 672 */
665 isXMLNode: function() 673 isXMLNode: function()
666 { 674 {
667 return !!this.ownerDocument && !!this.ownerDocument.xmlVersion; 675 return !!this.ownerDocument && !!this.ownerDocument.xmlVersion;
668 }, 676 },
669 677
670 /** 678 /**
671 * @param {boolean} optimized 679 * @param {boolean} optimized
672 * @return {string} 680 * @return {string}
673 */ 681 */
682 cssPath: function(optimized)
683 {
684 if (this._nodeType !== Node.ELEMENT_NODE)
685 return "";
686
687 var steps = [];
688 var contextNode = this;
689 while (contextNode) {
690 var step = contextNode._cssPathValue(optimized);
691 if (!step)
692 break; // Error - bail out early.
693 steps.push(step);
694 if (step.optimized)
695 break;
696 contextNode = contextNode.parentNode;
697 }
698
699 steps.reverse();
700 return steps.join(" > ");
701 },
702
703 /**
704 * @param {boolean} optimized
705 * @return {WebInspector.DOMNode.PathStep}
706 */
707 _cssPathValue: function(optimized)
708 {
709 if (this._nodeType !== Node.ELEMENT_NODE)
710 return null;
711 if (optimized) {
712 if (this.getAttribute("id"))
713 return new WebInspector.DOMNode.PathStep("#" + this.getAttribute ("id"), true);
714 var nodeNameLower = this._nodeName.toLowerCase();
715 if (nodeNameLower === "body" || nodeNameLower === "head" || nodeName Lower === "html")
716 return new WebInspector.DOMNode.PathStep(this.nodeNameInCorrectC ase(), true);
717 }
718 var nodeName = this.nodeNameInCorrectCase();
719 var parent = this.parentNode;
720 if (!parent || parent._nodeType === Node.DOCUMENT_NODE)
721 return new WebInspector.DOMNode.PathStep(nodeName, true);
722
723 /**
724 * @param {WebInspector.DOMNode} node
725 * @return {Object}
aandrey 2013/11/18 15:36:26 @return {!Object.<string, boolean>}
726 */
727 function elementClassNames(node)
728 {
729 return (node.getAttribute("class") || "").split(/\s+/g).keySet();
aandrey 2013/11/18 15:36:26 again, empty strings. a = document.createElement(
730 }
731
732 var uniqueClassNames = elementClassNames(this);
733 var uniqueClassNamesLeft = 0;
734 for (var name in uniqueClassNames)
735 ++uniqueClassNamesLeft;
736 var needsClassNames = false;
737 var needsNthChild = false;
738 var ownIndex = -1;
739 var siblings = parent.children();
740 for (var i = 0; (ownIndex === -1 || !needsNthChild) && i < siblings.leng th; ++i) {
741 var sibling = siblings[i];
742 if (sibling === this) {
743 ownIndex = i;
744 continue;
745 }
746 if (sibling.nodeNameInCorrectCase() !== nodeName)
747 continue;
748 if (!uniqueClassNamesLeft) {
749 needsNthChild = true;
750 continue;
751 }
752
753 needsClassNames = true;
754 var siblingClassNames = elementClassNames(sibling);
755 for (var siblingClass in siblingClassNames) {
756 if (!uniqueClassNames.hasOwnProperty(siblingClass))
757 continue;
758 delete uniqueClassNames[siblingClass];
759 if (!--uniqueClassNamesLeft) {
760 needsNthChild = true;
761 break;
aandrey 2013/11/18 15:36:26 this could break while ownIndex is still -1
762 }
763 }
764 }
765
766 var result = nodeName;
767 if (needsClassNames && uniqueClassNamesLeft) {
768 for (var className in uniqueClassNames)
769 result += "." + className;
770 }
771 if (needsNthChild)
772 result += ":nth-child(" + (ownIndex + 1) + ")";
aandrey 2013/11/18 15:36:26 ownIndex may be -1 here. add a test.
aandrey 2013/11/18 15:43:05 Ah, seems I was wrong.
773 return new WebInspector.DOMNode.PathStep(result, false);
774 },
775
776 /**
777 * @param {boolean} optimized
778 * @return {string}
779 */
674 xPath: function(optimized) 780 xPath: function(optimized)
675 { 781 {
676 if (this._nodeType === Node.DOCUMENT_NODE) 782 if (this._nodeType === Node.DOCUMENT_NODE)
677 return "/"; 783 return "/";
678 784
679 var steps = []; 785 var steps = [];
680 var contextNode = this; 786 var contextNode = this;
681 while (contextNode) { 787 while (contextNode) {
682 var step = contextNode._xPathValue(optimized); 788 var step = contextNode._xPathValue(optimized);
683 if (!step) 789 if (!step)
684 break; // Error - bail out early. 790 break; // Error - bail out early.
685 steps.push(step); 791 steps.push(step);
686 if (step.optimized) 792 if (step.optimized)
687 break; 793 break;
688 contextNode = contextNode.parentNode; 794 contextNode = contextNode.parentNode;
689 } 795 }
690 796
691 steps.reverse(); 797 steps.reverse();
692 return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/") ; 798 return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/") ;
693 }, 799 },
694 800
695 /** 801 /**
696 * @param {boolean} optimized 802 * @param {boolean} optimized
697 * @return {WebInspector.DOMNode.XPathStep} 803 * @return {WebInspector.DOMNode.PathStep}
698 */ 804 */
699 _xPathValue: function(optimized) 805 _xPathValue: function(optimized)
700 { 806 {
701 var ownValue; 807 var ownValue;
702 var ownIndex = this._xPathIndex(); 808 var ownIndex = this._xPathIndex();
703 if (ownIndex === -1) 809 if (ownIndex === -1)
704 return null; // Error. 810 return null; // Error.
705 811
706 switch (this._nodeType) { 812 switch (this._nodeType) {
707 case Node.ELEMENT_NODE: 813 case Node.ELEMENT_NODE:
708 if (optimized && this.getAttribute("id")) 814 if (optimized && this.getAttribute("id"))
709 return new WebInspector.DOMNode.XPathStep("//*[@id=\"" + this.ge tAttribute("id") + "\"]", true); 815 return new WebInspector.DOMNode.PathStep("//*[@id=\"" + this.get Attribute("id") + "\"]", true);
710 ownValue = this._localName; 816 ownValue = this._localName;
711 break; 817 break;
712 case Node.ATTRIBUTE_NODE: 818 case Node.ATTRIBUTE_NODE:
713 ownValue = "@" + this._nodeName; 819 ownValue = "@" + this._nodeName;
714 break; 820 break;
715 case Node.TEXT_NODE: 821 case Node.TEXT_NODE:
716 case Node.CDATA_SECTION_NODE: 822 case Node.CDATA_SECTION_NODE:
717 ownValue = "text()"; 823 ownValue = "text()";
718 break; 824 break;
719 case Node.PROCESSING_INSTRUCTION_NODE: 825 case Node.PROCESSING_INSTRUCTION_NODE:
720 ownValue = "processing-instruction()"; 826 ownValue = "processing-instruction()";
721 break; 827 break;
722 case Node.COMMENT_NODE: 828 case Node.COMMENT_NODE:
723 ownValue = "comment()"; 829 ownValue = "comment()";
724 break; 830 break;
725 case Node.DOCUMENT_NODE: 831 case Node.DOCUMENT_NODE:
726 ownValue = ""; 832 ownValue = "";
727 break; 833 break;
728 default: 834 default:
729 ownValue = ""; 835 ownValue = "";
730 break; 836 break;
731 } 837 }
732 838
733 if (ownIndex > 0) 839 if (ownIndex > 0)
734 ownValue += "[" + ownIndex + "]"; 840 ownValue += "[" + ownIndex + "]";
735 841
736 return new WebInspector.DOMNode.XPathStep(ownValue, this._nodeType === N ode.DOCUMENT_NODE); 842 return new WebInspector.DOMNode.PathStep(ownValue, this._nodeType === No de.DOCUMENT_NODE);
737 }, 843 },
738 844
739 /** 845 /**
740 * @return {number} 846 * @return {number}
741 */ 847 */
742 _xPathIndex: function() 848 _xPathIndex: function()
743 { 849 {
744 // Returns -1 in case of error, 0 if no siblings matching the same expre ssion, <XPath index among the same expression-matching sibling nodes> otherwise. 850 // Returns -1 in case of error, 0 if no siblings matching the same expre ssion, <XPath index among the same expression-matching sibling nodes> otherwise.
745 function areNodesSimilar(left, right) 851 function areNodesSimilar(left, right)
746 { 852 {
(...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after
1735 setInspectModeEnabled: function(enabled, inspectShadowDOM, config, callback) 1841 setInspectModeEnabled: function(enabled, inspectShadowDOM, config, callback)
1736 { 1842 {
1737 DOMAgent.setInspectModeEnabled(enabled, inspectShadowDOM, config, callba ck); 1843 DOMAgent.setInspectModeEnabled(enabled, inspectShadowDOM, config, callba ck);
1738 } 1844 }
1739 } 1845 }
1740 1846
1741 /** 1847 /**
1742 * @type {?WebInspector.DOMAgent} 1848 * @type {?WebInspector.DOMAgent}
1743 */ 1849 */
1744 WebInspector.domAgent = null; 1850 WebInspector.domAgent = null;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698