| OLD | NEW |
| 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 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 WebInspector.DOMNode.PseudoElementNames = { | 113 WebInspector.DOMNode.PseudoElementNames = { |
| 114 Before: "before", | 114 Before: "before", |
| 115 After: "after" | 115 After: "after" |
| 116 } | 116 } |
| 117 | 117 |
| 118 WebInspector.DOMNode.ShadowRootTypes = { | 118 WebInspector.DOMNode.ShadowRootTypes = { |
| 119 UserAgent: "user-agent", | 119 UserAgent: "user-agent", |
| 120 Author: "author" | 120 Author: "author" |
| 121 } | 121 } |
| 122 | 122 |
| 123 /** | |
| 124 * @constructor | |
| 125 * @param {string} value | |
| 126 * @param {boolean} optimized | |
| 127 */ | |
| 128 WebInspector.DOMNode.XPathStep = function(value, optimized) | |
| 129 { | |
| 130 this.value = value; | |
| 131 this.optimized = optimized; | |
| 132 } | |
| 133 | |
| 134 WebInspector.DOMNode.XPathStep.prototype = { | |
| 135 toString: function() | |
| 136 { | |
| 137 return this.value; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 WebInspector.DOMNode.prototype = { | 123 WebInspector.DOMNode.prototype = { |
| 142 /** | 124 /** |
| 143 * @return {Array.<WebInspector.DOMNode>} | 125 * @return {Array.<WebInspector.DOMNode>} |
| 144 */ | 126 */ |
| 145 children: function() | 127 children: function() |
| 146 { | 128 { |
| 147 return this._children ? this._children.slice() : null; | 129 return this._children ? this._children.slice() : null; |
| 148 }, | 130 }, |
| 149 | 131 |
| 150 /** | 132 /** |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 { | 405 { |
| 424 if (!error) | 406 if (!error) |
| 425 InspectorFrontendHost.copyText(text); | 407 InspectorFrontendHost.copyText(text); |
| 426 } | 408 } |
| 427 DOMAgent.getOuterHTML(this.id, copy); | 409 DOMAgent.getOuterHTML(this.id, copy); |
| 428 }, | 410 }, |
| 429 | 411 |
| 430 /** | 412 /** |
| 431 * @param {boolean} optimized | 413 * @param {boolean} optimized |
| 432 */ | 414 */ |
| 415 copyCSSPath: function(optimized) |
| 416 { |
| 417 InspectorFrontendHost.copyText(this.cssPath(optimized)); |
| 418 }, |
| 419 |
| 420 /** |
| 421 * @param {boolean} optimized |
| 422 */ |
| 433 copyXPath: function(optimized) | 423 copyXPath: function(optimized) |
| 434 { | 424 { |
| 435 InspectorFrontendHost.copyText(this.xPath(optimized)); | 425 InspectorFrontendHost.copyText(this.xPath(optimized)); |
| 436 }, | 426 }, |
| 437 | 427 |
| 438 /** | 428 /** |
| 439 * @param {string} objectGroupId | 429 * @param {string} objectGroupId |
| 440 * @param {function(?Protocol.Error)=} callback | 430 * @param {function(?Protocol.Error)=} callback |
| 441 */ | 431 */ |
| 442 eventListeners: function(objectGroupId, callback) | 432 eventListeners: function(objectGroupId, callback) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 459 return path.join(","); | 449 return path.join(","); |
| 460 }, | 450 }, |
| 461 | 451 |
| 462 /** | 452 /** |
| 463 * @param {boolean} justSelector | 453 * @param {boolean} justSelector |
| 464 * @return {string} | 454 * @return {string} |
| 465 */ | 455 */ |
| 466 appropriateSelectorFor: function(justSelector) | 456 appropriateSelectorFor: function(justSelector) |
| 467 { | 457 { |
| 468 var lowerCaseName = this.localName() || this.nodeName().toLowerCase(); | 458 var lowerCaseName = this.localName() || this.nodeName().toLowerCase(); |
| 469 | 459 if (this._nodeType !== Node.ELEMENT_NODE) |
| 470 var id = this.getAttribute("id"); | 460 return lowerCaseName; |
| 471 if (id) { | |
| 472 var selector = "#" + id; | |
| 473 return (justSelector ? selector : lowerCaseName + selector); | |
| 474 } | |
| 475 | |
| 476 var className = this.getAttribute("class"); | |
| 477 if (className) { | |
| 478 var selector = "." + className.trim().replace(/\s+/g, "."); | |
| 479 return (justSelector ? selector : lowerCaseName + selector); | |
| 480 } | |
| 481 | |
| 482 if (lowerCaseName === "input" && this.getAttribute("type")) | 461 if (lowerCaseName === "input" && this.getAttribute("type")) |
| 483 return lowerCaseName + "[type=\"" + this.getAttribute("type") + "\"]
"; | 462 return lowerCaseName + "[type=\"" + this.getAttribute("type") + "\"]
"; |
| 484 | 463 |
| 485 return lowerCaseName; | 464 return this.cssPath(justSelector); |
| 486 }, | 465 }, |
| 487 | 466 |
| 488 /** | 467 /** |
| 489 * @param {WebInspector.DOMNode} node | 468 * @param {WebInspector.DOMNode} node |
| 490 * @return {boolean} | 469 * @return {boolean} |
| 491 */ | 470 */ |
| 492 isAncestor: function(node) | 471 isAncestor: function(node) |
| 493 { | 472 { |
| 494 if (!node) | 473 if (!node) |
| 495 return false; | 474 return false; |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 */ | 657 */ |
| 679 isXMLNode: function() | 658 isXMLNode: function() |
| 680 { | 659 { |
| 681 return !!this.ownerDocument && !!this.ownerDocument.xmlVersion; | 660 return !!this.ownerDocument && !!this.ownerDocument.xmlVersion; |
| 682 }, | 661 }, |
| 683 | 662 |
| 684 /** | 663 /** |
| 685 * @param {boolean} optimized | 664 * @param {boolean} optimized |
| 686 * @return {string} | 665 * @return {string} |
| 687 */ | 666 */ |
| 667 cssPath: function(optimized) |
| 668 { |
| 669 if (this._nodeType !== Node.ELEMENT_NODE) |
| 670 return ""; |
| 671 |
| 672 var steps = []; |
| 673 var contextNode = this; |
| 674 while (contextNode) { |
| 675 var step = WebInspector.DOMPresentationUtils.cssPathValue(contextNod
e, optimized); |
| 676 if (!step) |
| 677 break; // Error - bail out early. |
| 678 steps.push(step); |
| 679 if (step.optimized) |
| 680 break; |
| 681 contextNode = contextNode.parentNode; |
| 682 } |
| 683 |
| 684 steps.reverse(); |
| 685 return steps.join(" > "); |
| 686 }, |
| 687 |
| 688 /** |
| 689 * @param {boolean} optimized |
| 690 * @return {WebInspector.DOMNodePathStep} |
| 691 */ |
| 692 _cssPathValue: function(optimized) |
| 693 { |
| 694 if (this._nodeType !== Node.ELEMENT_NODE) |
| 695 return null; |
| 696 if (optimized) { |
| 697 var id = this.getAttribute("id"); |
| 698 if (id) |
| 699 return new WebInspector.DOMNodePathStep(idSelector(id), true); |
| 700 var nodeNameLower = this._nodeName.toLowerCase(); |
| 701 if (nodeNameLower === "body" || nodeNameLower === "head" || nodeName
Lower === "html") |
| 702 return new WebInspector.DOMNodePathStep(this.nodeNameInCorrectCa
se(), true); |
| 703 } |
| 704 var nodeName = this.nodeNameInCorrectCase(); |
| 705 var parent = this.parentNode; |
| 706 if (!parent || parent._nodeType === Node.DOCUMENT_NODE) |
| 707 return new WebInspector.DOMNodePathStep(nodeName, true); |
| 708 |
| 709 /** |
| 710 * @param {WebInspector.DOMNode} node |
| 711 * @return {Array.<string>} |
| 712 */ |
| 713 function elementClassNames(node) |
| 714 { |
| 715 var classAttribute = node.getAttribute("class"); |
| 716 if (!classAttribute) |
| 717 return []; |
| 718 |
| 719 return classAttribute.split(/\s+/g).filter(Boolean); |
| 720 } |
| 721 |
| 722 /** |
| 723 * @param {string} id |
| 724 * @return {string} |
| 725 */ |
| 726 function idSelector(id) |
| 727 { |
| 728 return "#" + escapeIdentifierIfNeeded(id); |
| 729 } |
| 730 |
| 731 /** |
| 732 * @param {string} ident |
| 733 * @return {string} |
| 734 */ |
| 735 function escapeIdentifierIfNeeded(ident) |
| 736 { |
| 737 if (isCSSIdentifier(ident)) |
| 738 return ident; |
| 739 var shouldEscapeFirst = /^(?:[0-9]|-[0-9-]?)/.test(ident); |
| 740 var lastIndex = ident.length - 1; |
| 741 return ident.replace(/./g, function(c, i) { |
| 742 return ((shouldEscapeFirst && i === 0) || !isCSSIdentChar(c)) ?
escapeAsciiChar(c, i === lastIndex) : c; |
| 743 }); |
| 744 } |
| 745 |
| 746 /** |
| 747 * @param {string} c |
| 748 * @param {boolean} isLast |
| 749 * @return {string} |
| 750 */ |
| 751 function escapeAsciiChar(c, isLast) |
| 752 { |
| 753 return "\\" + toHexByte(c) + (isLast ? "" : " "); |
| 754 } |
| 755 |
| 756 /** |
| 757 * @param {string} c |
| 758 */ |
| 759 function toHexByte(c) |
| 760 { |
| 761 var hexByte = c.charCodeAt(0).toString(16); |
| 762 if (hexByte.length === 1) |
| 763 hexByte = "0" + hexByte; |
| 764 return hexByte; |
| 765 } |
| 766 |
| 767 /** |
| 768 * @param {string} c |
| 769 * @return {boolean} |
| 770 */ |
| 771 function isCSSIdentChar(c) |
| 772 { |
| 773 if (/[a-zA-Z0-9_-]/.test(c)) |
| 774 return true; |
| 775 return c.charCodeAt(0) >= 0xA0; |
| 776 } |
| 777 |
| 778 /** |
| 779 * @param {string} value |
| 780 * @return {boolean} |
| 781 */ |
| 782 function isCSSIdentifier(value) |
| 783 { |
| 784 return /^-?[a-zA-Z_][a-zA-Z0-9_-]*$/.test(value); |
| 785 } |
| 786 |
| 787 var uniqueClassNamesArray = elementClassNames(this); |
| 788 var needsClassNames = false; |
| 789 var needsNthChild = false; |
| 790 var ownIndex = -1; |
| 791 var siblings = parent.children(); |
| 792 for (var i = 0; (ownIndex === -1 || !needsNthChild) && i < siblings.leng
th; ++i) { |
| 793 var sibling = siblings[i]; |
| 794 if (sibling === this) { |
| 795 ownIndex = i; |
| 796 continue; |
| 797 } |
| 798 if (needsNthChild) |
| 799 continue; |
| 800 if (sibling.nodeNameInCorrectCase() !== nodeName) |
| 801 continue; |
| 802 |
| 803 needsClassNames = true; |
| 804 var ownClassNames = uniqueClassNamesArray.keySet(); |
| 805 var ownClassNameCount = 0; |
| 806 for (var name in ownClassNames) |
| 807 ++ownClassNameCount; |
| 808 if (ownClassNameCount === 0) { |
| 809 needsNthChild = true; |
| 810 continue; |
| 811 } |
| 812 var siblingClassNames = elementClassNames(sibling).keySet(); |
| 813 for (var siblingClass in siblingClassNames) { |
| 814 if (!ownClassNames.hasOwnProperty(siblingClass)) |
| 815 continue; |
| 816 delete ownClassNames[siblingClass]; |
| 817 if (!--ownClassNameCount) { |
| 818 needsNthChild = true; |
| 819 break; |
| 820 } |
| 821 } |
| 822 } |
| 823 |
| 824 var result = nodeName; |
| 825 if (needsNthChild) { |
| 826 result += ":nth-child(" + (ownIndex + 1) + ")"; |
| 827 } else if (needsClassNames) { |
| 828 for (var name in uniqueClassNamesArray.keySet()) |
| 829 result += "." + escapeIdentifierIfNeeded(name); |
| 830 } |
| 831 return new WebInspector.DOMNodePathStep(result, false); |
| 832 }, |
| 833 |
| 834 /** |
| 835 * @param {boolean} optimized |
| 836 * @return {string} |
| 837 */ |
| 688 xPath: function(optimized) | 838 xPath: function(optimized) |
| 689 { | 839 { |
| 690 if (this._nodeType === Node.DOCUMENT_NODE) | 840 if (this._nodeType === Node.DOCUMENT_NODE) |
| 691 return "/"; | 841 return "/"; |
| 692 | 842 |
| 693 var steps = []; | 843 var steps = []; |
| 694 var contextNode = this; | 844 var contextNode = this; |
| 695 while (contextNode) { | 845 while (contextNode) { |
| 696 var step = contextNode._xPathValue(optimized); | 846 var step = contextNode._xPathValue(optimized); |
| 697 if (!step) | 847 if (!step) |
| 698 break; // Error - bail out early. | 848 break; // Error - bail out early. |
| 699 steps.push(step); | 849 steps.push(step); |
| 700 if (step.optimized) | 850 if (step.optimized) |
| 701 break; | 851 break; |
| 702 contextNode = contextNode.parentNode; | 852 contextNode = contextNode.parentNode; |
| 703 } | 853 } |
| 704 | 854 |
| 705 steps.reverse(); | 855 steps.reverse(); |
| 706 return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/")
; | 856 return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/")
; |
| 707 }, | 857 }, |
| 708 | 858 |
| 709 /** | 859 /** |
| 710 * @param {boolean} optimized | 860 * @param {boolean} optimized |
| 711 * @return {WebInspector.DOMNode.XPathStep} | 861 * @return {WebInspector.DOMNodePathStep} |
| 712 */ | 862 */ |
| 713 _xPathValue: function(optimized) | 863 _xPathValue: function(optimized) |
| 714 { | 864 { |
| 715 var ownValue; | 865 var ownValue; |
| 716 var ownIndex = this._xPathIndex(); | 866 var ownIndex = this._xPathIndex(); |
| 717 if (ownIndex === -1) | 867 if (ownIndex === -1) |
| 718 return null; // Error. | 868 return null; // Error. |
| 719 | 869 |
| 720 switch (this._nodeType) { | 870 switch (this._nodeType) { |
| 721 case Node.ELEMENT_NODE: | 871 case Node.ELEMENT_NODE: |
| 722 if (optimized && this.getAttribute("id")) | 872 if (optimized && this.getAttribute("id")) |
| 723 return new WebInspector.DOMNode.XPathStep("//*[@id=\"" + this.ge
tAttribute("id") + "\"]", true); | 873 return new WebInspector.DOMNodePathStep("//*[@id=\"" + this.getA
ttribute("id") + "\"]", true); |
| 724 ownValue = this._localName; | 874 ownValue = this._localName; |
| 725 break; | 875 break; |
| 726 case Node.ATTRIBUTE_NODE: | 876 case Node.ATTRIBUTE_NODE: |
| 727 ownValue = "@" + this._nodeName; | 877 ownValue = "@" + this._nodeName; |
| 728 break; | 878 break; |
| 729 case Node.TEXT_NODE: | 879 case Node.TEXT_NODE: |
| 730 case Node.CDATA_SECTION_NODE: | 880 case Node.CDATA_SECTION_NODE: |
| 731 ownValue = "text()"; | 881 ownValue = "text()"; |
| 732 break; | 882 break; |
| 733 case Node.PROCESSING_INSTRUCTION_NODE: | 883 case Node.PROCESSING_INSTRUCTION_NODE: |
| 734 ownValue = "processing-instruction()"; | 884 ownValue = "processing-instruction()"; |
| 735 break; | 885 break; |
| 736 case Node.COMMENT_NODE: | 886 case Node.COMMENT_NODE: |
| 737 ownValue = "comment()"; | 887 ownValue = "comment()"; |
| 738 break; | 888 break; |
| 739 case Node.DOCUMENT_NODE: | 889 case Node.DOCUMENT_NODE: |
| 740 ownValue = ""; | 890 ownValue = ""; |
| 741 break; | 891 break; |
| 742 default: | 892 default: |
| 743 ownValue = ""; | 893 ownValue = ""; |
| 744 break; | 894 break; |
| 745 } | 895 } |
| 746 | 896 |
| 747 if (ownIndex > 0) | 897 if (ownIndex > 0) |
| 748 ownValue += "[" + ownIndex + "]"; | 898 ownValue += "[" + ownIndex + "]"; |
| 749 | 899 |
| 750 return new WebInspector.DOMNode.XPathStep(ownValue, this._nodeType === N
ode.DOCUMENT_NODE); | 900 return new WebInspector.DOMNodePathStep(ownValue, this._nodeType === Nod
e.DOCUMENT_NODE); |
| 751 }, | 901 }, |
| 752 | 902 |
| 753 /** | 903 /** |
| 754 * @return {number} | 904 * @return {number} |
| 755 */ | 905 */ |
| 756 _xPathIndex: function() | 906 _xPathIndex: function() |
| 757 { | 907 { |
| 758 // 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. | 908 // 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. |
| 759 function areNodesSimilar(left, right) | 909 function areNodesSimilar(left, right) |
| 760 { | 910 { |
| (...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1749 setInspectModeEnabled: function(enabled, inspectShadowDOM, config, callback) | 1899 setInspectModeEnabled: function(enabled, inspectShadowDOM, config, callback) |
| 1750 { | 1900 { |
| 1751 DOMAgent.setInspectModeEnabled(enabled, inspectShadowDOM, config, callba
ck); | 1901 DOMAgent.setInspectModeEnabled(enabled, inspectShadowDOM, config, callba
ck); |
| 1752 } | 1902 } |
| 1753 } | 1903 } |
| 1754 | 1904 |
| 1755 /** | 1905 /** |
| 1756 * @type {?WebInspector.DOMAgent} | 1906 * @type {?WebInspector.DOMAgent} |
| 1757 */ | 1907 */ |
| 1758 WebInspector.domAgent = null; | 1908 WebInspector.domAgent = null; |
| OLD | NEW |