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

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: 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 ownValue = this.nodeNameInCorrectCase();
719 var parent = this.parentNode;
720 if (!parent || parent._nodeType === Node.DOCUMENT_NODE)
721 return new WebInspector.DOMNode.PathStep(ownValue, true);
722
723 var nodeName = this.nodeNameInCorrectCase();
aandrey 2013/11/18 13:43:51 move above and get rid of ownValue
apavlov 2013/11/18 15:03:59 Done.
724 var uniqueClassNamesArray = (this.getAttribute("class") || "").split(/\s +/g);
aandrey 2013/11/18 13:43:51 this array is not unique, and can contain empty st
apavlov 2013/11/18 15:03:59 It is not unique, but it cannot contain empty stri
aandrey 2013/11/18 15:15:56 FYI. a = document.createElement("div"); a.classNa
725 var uniqueClassNamesLeft = uniqueClassNamesArray.length;
726 var uniqueClassNames = uniqueClassNamesArray.keySet();
727 var needsClassNames;
aandrey 2013/11/18 13:43:51 plz init (with "false" I believe?)
apavlov 2013/11/18 15:03:59 Done.
728 var needsNthChild;
aandrey 2013/11/18 13:43:51 ditto
apavlov 2013/11/18 15:03:59 Done.
729 var ownIndex = -1;
730 var siblings = parent.children();
731 for (var i = 0; (ownIndex === -1 || !needsNthChild) && i < siblings.leng th; ++i) {
732 var sibling = siblings[i];
733 if (sibling === this) {
734 ownIndex = i;
735 continue;
736 }
737 if (sibling.nodeNameInCorrectCase() !== nodeName)
738 continue;
739 if (!uniqueClassNamesLeft) {
740 needsNthChild = true;
741 continue;
742 }
743
744 needsClassNames = true;
745 var siblingClasses = (sibling.getAttribute("class") || "").split(/\s +/g).keySet();
aandrey 2013/11/18 13:43:51 code dup, plz extract
apavlov 2013/11/18 15:03:59 Done.
746 for (var siblingClass in siblingClasses) {
747 if (!uniqueClassNames.hasOwnProperty(siblingClass))
748 continue;
749 delete uniqueClassNames[siblingClass];
750 if (!--uniqueClassNamesLeft) {
aandrey 2013/11/18 13:43:51 Did you mean uniqueClassNamesLeft to be initialize
apavlov 2013/11/18 15:03:59 Yep. Fixed
751 needsNthChild = true;
752 break;
753 }
754 }
755 }
756
757 var result = nodeName;
758 if (needsClassNames && uniqueClassNamesLeft) {
759 for (var className in uniqueClassNames)
760 result += "." + className;
761 }
762 if (needsNthChild)
763 result += ":nth-child(" + (ownIndex + 1) + ")";
764 return new WebInspector.DOMNode.PathStep(result, false);
765 },
766
767 /**
768 * @param {boolean} optimized
769 * @return {string}
770 */
674 xPath: function(optimized) 771 xPath: function(optimized)
675 { 772 {
676 if (this._nodeType === Node.DOCUMENT_NODE) 773 if (this._nodeType === Node.DOCUMENT_NODE)
677 return "/"; 774 return "/";
678 775
679 var steps = []; 776 var steps = [];
680 var contextNode = this; 777 var contextNode = this;
681 while (contextNode) { 778 while (contextNode) {
682 var step = contextNode._xPathValue(optimized); 779 var step = contextNode._xPathValue(optimized);
683 if (!step) 780 if (!step)
684 break; // Error - bail out early. 781 break; // Error - bail out early.
685 steps.push(step); 782 steps.push(step);
686 if (step.optimized) 783 if (step.optimized)
687 break; 784 break;
688 contextNode = contextNode.parentNode; 785 contextNode = contextNode.parentNode;
689 } 786 }
690 787
691 steps.reverse(); 788 steps.reverse();
692 return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/") ; 789 return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/") ;
693 }, 790 },
694 791
695 /** 792 /**
696 * @param {boolean} optimized 793 * @param {boolean} optimized
697 * @return {WebInspector.DOMNode.XPathStep} 794 * @return {WebInspector.DOMNode.PathStep}
698 */ 795 */
699 _xPathValue: function(optimized) 796 _xPathValue: function(optimized)
700 { 797 {
701 var ownValue; 798 var ownValue;
702 var ownIndex = this._xPathIndex(); 799 var ownIndex = this._xPathIndex();
703 if (ownIndex === -1) 800 if (ownIndex === -1)
704 return null; // Error. 801 return null; // Error.
705 802
706 switch (this._nodeType) { 803 switch (this._nodeType) {
707 case Node.ELEMENT_NODE: 804 case Node.ELEMENT_NODE:
708 if (optimized && this.getAttribute("id")) 805 if (optimized && this.getAttribute("id"))
709 return new WebInspector.DOMNode.XPathStep("//*[@id=\"" + this.ge tAttribute("id") + "\"]", true); 806 return new WebInspector.DOMNode.PathStep("//*[@id=\"" + this.get Attribute("id") + "\"]", true);
710 ownValue = this._localName; 807 ownValue = this._localName;
711 break; 808 break;
712 case Node.ATTRIBUTE_NODE: 809 case Node.ATTRIBUTE_NODE:
713 ownValue = "@" + this._nodeName; 810 ownValue = "@" + this._nodeName;
714 break; 811 break;
715 case Node.TEXT_NODE: 812 case Node.TEXT_NODE:
716 case Node.CDATA_SECTION_NODE: 813 case Node.CDATA_SECTION_NODE:
717 ownValue = "text()"; 814 ownValue = "text()";
718 break; 815 break;
719 case Node.PROCESSING_INSTRUCTION_NODE: 816 case Node.PROCESSING_INSTRUCTION_NODE:
720 ownValue = "processing-instruction()"; 817 ownValue = "processing-instruction()";
721 break; 818 break;
722 case Node.COMMENT_NODE: 819 case Node.COMMENT_NODE:
723 ownValue = "comment()"; 820 ownValue = "comment()";
724 break; 821 break;
725 case Node.DOCUMENT_NODE: 822 case Node.DOCUMENT_NODE:
726 ownValue = ""; 823 ownValue = "";
727 break; 824 break;
728 default: 825 default:
729 ownValue = ""; 826 ownValue = "";
730 break; 827 break;
731 } 828 }
732 829
733 if (ownIndex > 0) 830 if (ownIndex > 0)
734 ownValue += "[" + ownIndex + "]"; 831 ownValue += "[" + ownIndex + "]";
735 832
736 return new WebInspector.DOMNode.XPathStep(ownValue, this._nodeType === N ode.DOCUMENT_NODE); 833 return new WebInspector.DOMNode.PathStep(ownValue, this._nodeType === No de.DOCUMENT_NODE);
737 }, 834 },
738 835
739 /** 836 /**
740 * @return {number} 837 * @return {number}
741 */ 838 */
742 _xPathIndex: function() 839 _xPathIndex: function()
743 { 840 {
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. 841 // 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) 842 function areNodesSimilar(left, right)
746 { 843 {
(...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after
1735 setInspectModeEnabled: function(enabled, inspectShadowDOM, config, callback) 1832 setInspectModeEnabled: function(enabled, inspectShadowDOM, config, callback)
1736 { 1833 {
1737 DOMAgent.setInspectModeEnabled(enabled, inspectShadowDOM, config, callba ck); 1834 DOMAgent.setInspectModeEnabled(enabled, inspectShadowDOM, config, callba ck);
1738 } 1835 }
1739 } 1836 }
1740 1837
1741 /** 1838 /**
1742 * @type {?WebInspector.DOMAgent} 1839 * @type {?WebInspector.DOMAgent}
1743 */ 1840 */
1744 WebInspector.domAgent = null; 1841 WebInspector.domAgent = null;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698