Changeset 224314 in webkit
- Timestamp:
- Nov 1, 2017 8:34:44 PM (7 years ago)
- Location:
- trunk/Source/WebInspectorUI
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebInspectorUI/ChangeLog
r224303 r224314 1 2017-11-01 Devin Rousso <webkit@devinrousso.com> 2 3 Web Inspector: consolidate DOMTreeElement contextmenu items into submenus 4 https://bugs.webkit.org/show_bug.cgi?id=178996 5 6 Reviewed by Joseph Pecoraro. 7 8 * Localizations/en.lproj/localizedStrings.js: 9 10 * UserInterface/Views/ContextMenu.js: 11 (WI.ContextSubMenuItem.prototype.appendItem): 12 (WI.ContextSubMenuItem.prototype.appendSubMenuItem): 13 (WI.ContextSubMenuItem.prototype.appendCheckboxItem): 14 (WI.ContextSubMenuItem.prototype.pushItem): 15 (WI.ContextSubMenuItem.prototype._pushItem): Deleted. 16 Made `pushItem` public so that it is possible to create a ContextMenuItem without 17 immediately adding it to the ContextMenu. 18 19 (WI.ContextSubMenuItem.prototype._buildDescriptor): 20 (WI.ContextMenu.prototype._buildDescriptor): 21 Filter out submenus that have no items. 22 23 * UserInterface/Views/ContextMenuUtilities.js: 24 (WI.appendContextMenuItemsForDOMNode): 25 * UserInterface/Views/DOMTreeElement.js: 26 (WI.DOMTreeElement.prototype.toggleElementVisibility): 27 (WI.DOMTreeElement.prototype._populateTagContextMenu): 28 (WI.DOMTreeElement.prototype._populateTextContextMenu): 29 (WI.DOMTreeElement.prototype._populateNodeContextMenu): 30 (WI.DOMTreeElement.prototype._populateForcedPseudoStateItems): Deleted. 31 Add relevant items to the provided submenus and reorder the entire contextmenu for better 32 readability and consistency. 33 34 * UserInterface/Views/DOMTreeOutline.js: 35 (WI.DOMTreeOutline.prototype.populateContextMenu): 36 Create submenus for Add, Edit, Copy, and Delete, and pass them to the DOMTreeElement 37 "populate*ContextMenu" functions so that they can add items to each submenu. 38 39 (WI.DOMTreeOutline.prototype._hideElement): 40 Move to DOMTreeElement so that it can be used by a contextmenu item. 41 1 42 2017-11-01 Ross Kirsling <ross.kirsling@sony.com> 2 43 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r224142 r224314 65 65 localizedStrings["Action"] = "Action"; 66 66 localizedStrings["Activity Viewer"] = "Activity Viewer"; 67 localizedStrings["Add"] = "Add"; 67 68 localizedStrings["Add %s Rule"] = "Add %s Rule"; 68 69 localizedStrings["Add Action"] = "Add Action"; 69 localizedStrings["Add Attribute"] = "Add Attribute";70 70 localizedStrings["Add Breakpoint"] = "Add Breakpoint"; 71 71 localizedStrings["Add New"] = "Add New"; … … 170 170 localizedStrings["Cap"] = "Cap"; 171 171 localizedStrings["Caps"] = "Caps"; 172 localizedStrings["Capture Element Screenshot"] = "Capture ElementScreenshot";172 localizedStrings["Capture Screenshot"] = "Capture Screenshot"; 173 173 localizedStrings["Capturing"] = "Capturing"; 174 174 localizedStrings["Catch Variables"] = "Catch Variables"; … … 246 246 localizedStrings["Controls"] = "Controls"; 247 247 localizedStrings["Cookies"] = "Cookies"; 248 localizedStrings["Copy"] = "Copy"; 248 249 localizedStrings["Copy Action"] = "Copy Action"; 249 250 localizedStrings["Copy Link Address"] = "Copy Link Address"; … … 252 253 localizedStrings["Copy Rule"] = "Copy Rule"; 253 254 localizedStrings["Copy Selected"] = "Copy Selected"; 254 localizedStrings["Copy Selector Path"] = "Copy Selector Path";255 255 localizedStrings["Copy Table"] = "Copy Table"; 256 localizedStrings["Copy XPath"] = "Copy XPath";257 256 localizedStrings["Copy as HTML"] = "Copy as HTML"; 258 257 localizedStrings["Copy as cURL"] = "Copy as cURL"; … … 290 289 localizedStrings["Delete Breakpoint"] = "Delete Breakpoint"; 291 290 localizedStrings["Delete Breakpoints"] = "Delete Breakpoints"; 292 localizedStrings["Delete Node"] = "Delete Node";293 291 localizedStrings["Detach into separate window"] = "Detach into separate window"; 294 292 localizedStrings["Detached"] = "Detached"; … … 323 321 localizedStrings["Dynamically calculated for the selected element and did not match"] = "Dynamically calculated for the selected element and did not match"; 324 322 localizedStrings["Edit"] = "Edit"; 325 localizedStrings["Edit Attribute"] = "Edit Attribute";326 323 localizedStrings["Edit Breakpoint…"] = "Edit Breakpoint…"; 327 localizedStrings["Edit Text"] = "Edit Text";328 localizedStrings["Edit as HTML"] = "Edit as HTML";329 324 localizedStrings["Edit configuration"] = "Edit configuration"; 330 325 localizedStrings["Edit custom gradient"] = "Edit custom gradient"; … … 459 454 localizedStrings["Grouping Method"] = "Grouping Method"; 460 455 localizedStrings["Grow"] = "Grow"; 456 localizedStrings["HTML"] = "HTML"; 461 457 localizedStrings["HTML Attributes"] = "HTML Attributes"; 462 458 localizedStrings["HTTP"] = "HTTP"; … … 817 813 localizedStrings["Selected Value"] = "Selected Value"; 818 814 localizedStrings["Selected WebSocket"] = "Selected WebSocket"; 815 localizedStrings["Selector Path"] = "Selector Path"; 819 816 localizedStrings["Self"] = "Self"; 820 817 localizedStrings["Self Size"] = "Self Size"; … … 921 918 localizedStrings["Tab width:"] = "Tab width:"; 922 919 localizedStrings["Tabs"] = "Tabs"; 920 localizedStrings["Tag"] = "Tag"; 923 921 localizedStrings["Take snapshot"] = "Take snapshot"; 924 922 localizedStrings["Template Content"] = "Template Content"; … … 954 952 localizedStrings["Timing"] = "Timing"; 955 953 localizedStrings["Toggle Classes"] = "Toggle Classes"; 954 localizedStrings["Toggle Visibility"] = "Toggle Visibility"; 956 955 localizedStrings["Top"] = "Top"; 957 956 localizedStrings["Top Functions"] = "Top Functions"; … … 1029 1028 localizedStrings["XHR Breakpoints"] = "XHR Breakpoints"; 1030 1029 localizedStrings["XHRs"] = "XHRs"; 1030 localizedStrings["XPath"] = "XPath"; 1031 1031 localizedStrings["Y"] = "Y"; 1032 1032 localizedStrings["Y1"] = "Y1"; -
trunk/Source/WebInspectorUI/UserInterface/Views/ContextMenu.js
r220119 r224314 97 97 { 98 98 let item = new WI.ContextMenuItem(this._contextMenu, "item", label, disabled); 99 this. _pushItem(item);99 this.pushItem(item); 100 100 this._contextMenu._setHandler(item.id(), handler); 101 101 return item; … … 105 105 { 106 106 let item = new WI.ContextSubMenuItem(this._contextMenu, label, disabled); 107 this. _pushItem(item);107 this.pushItem(item); 108 108 return item; 109 109 } … … 112 112 { 113 113 let item = new WI.ContextMenuItem(this._contextMenu, "checkbox", label, disabled, checked); 114 this. _pushItem(item);114 this.pushItem(item); 115 115 this._contextMenu._setHandler(item.id(), handler); 116 116 return item; … … 123 123 } 124 124 125 _pushItem(item)125 pushItem(item) 126 126 { 127 127 if (this._pendingSeparator) { … … 137 137 } 138 138 139 // Private 140 139 141 _buildDescriptor() 140 142 { 141 let subItems = this._items.map((item) => item._buildDescriptor()); 143 if (this.isEmpty()) 144 return null; 145 146 let subItems = this._items.map((item) => item._buildDescriptor()).filter((item) => !!item); 142 147 return {type: "subMenu", label: this._label, enabled: !this._disabled, subItems}; 143 148 } … … 225 230 _buildDescriptor() 226 231 { 227 return this._items.map((item) => item._buildDescriptor()) ;232 return this._items.map((item) => item._buildDescriptor()).filter((item) => !!item); 228 233 } 229 234 -
trunk/Source/WebInspectorUI/UserInterface/Views/ContextMenuUtilities.js
r222188 r224314 110 110 return; 111 111 112 let copySubMenu = options.copySubMenu || contextMenu.appendSubMenuItem(WI.UIString("Copy")); 113 112 114 let isElement = domNode.nodeType() === Node.ELEMENT_NODE; 113 if (isElement) {114 contextMenu.appendItem(WI.UIString("Scroll Into View"), () => {115 domNode.scrollIntoView();116 });117 }118 119 contextMenu.appendSeparator();120 121 115 if (domNode.ownerDocument && isElement) { 122 co ntextMenu.appendItem(WI.UIString("CopySelector Path"), () => {116 copySubMenu.appendItem(WI.UIString("Selector Path"), () => { 123 117 let cssPath = WI.cssPath(domNode); 124 118 InspectorFrontendHost.copyText(cssPath); … … 127 121 128 122 if (domNode.ownerDocument && !domNode.isPseudoElement()) { 129 co ntextMenu.appendItem(WI.UIString("CopyXPath"), () => {123 copySubMenu.appendItem(WI.UIString("XPath"), () => { 130 124 let xpath = WI.xpath(domNode); 131 125 InspectorFrontendHost.copyText(xpath); … … 133 127 } 134 128 129 contextMenu.appendSeparator(); 130 135 131 if (domNode.isCustomElement()) { 136 contextMenu.appendSeparator();137 132 contextMenu.appendItem(WI.UIString("Jump to Definition"), () => { 138 133 function didGetFunctionDetails(error, response) { … … 165 160 }); 166 161 }); 162 163 contextMenu.appendSeparator(); 167 164 } 168 165 … … 194 191 195 192 if (window.PageAgent) { 196 contextMenu.appendItem(WI.UIString("Capture ElementScreenshot"), () => {193 contextMenu.appendItem(WI.UIString("Capture Screenshot"), () => { 197 194 PageAgent.snapshotNode(domNode.id, (error, dataURL) => { 198 195 if (error) { … … 225 222 }); 226 223 } 224 225 if (isElement) { 226 contextMenu.appendItem(WI.UIString("Scroll Into View"), () => { 227 domNode.scrollIntoView(); 228 }); 229 } 230 231 contextMenu.appendSeparator(); 227 232 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js
r222188 r224314 284 284 } 285 285 286 toggleElementVisibility() 287 { 288 let effectiveNode = this.representedObject; 289 if (effectiveNode.isPseudoElement()) { 290 effectiveNode = effectiveNode.parentNode; 291 console.assert(effectiveNode); 292 if (!effectiveNode) 293 return; 294 } 295 296 if (effectiveNode.nodeType() !== Node.ELEMENT_NODE) 297 return; 298 299 function inspectedPage_node_injectStyleAndToggleClass() { 300 let hideElementStyleSheetIdOrClassName = "__WebInspectorHideElement__"; 301 let styleElement = document.getElementById(hideElementStyleSheetIdOrClassName); 302 if (!styleElement) { 303 styleElement = document.createElement("style"); 304 styleElement.id = hideElementStyleSheetIdOrClassName; 305 styleElement.textContent = "." + hideElementStyleSheetIdOrClassName + " { visibility: hidden !important; }"; 306 document.head.appendChild(styleElement); 307 } 308 309 this.classList.toggle(hideElementStyleSheetIdOrClassName); 310 } 311 312 WI.RemoteObject.resolveNode(effectiveNode).then((object) => { 313 object.callFunction(inspectedPage_node_injectStyleAndToggleClass, undefined, false, () => { }); 314 object.release(); 315 }); 316 } 317 286 318 _createTooltipForNode() 287 319 { … … 698 730 } 699 731 700 _populateTagContextMenu(contextMenu, event )732 _populateTagContextMenu(contextMenu, event, subMenus) 701 733 { 702 734 let node = this.representedObject; 703 if (!node.isInUserAgentShadowTree()) { 704 let attribute = event.target.enclosingNodeOrSelfWithClass("html-attribute"); 705 706 if (event.target && event.target.tagName === "A") { 707 let url = event.target.href; 708 709 contextMenu.appendItem(WI.UIString("Open in New Tab"), () => { 710 const frame = null; 711 WI.openURL(url, frame, {alwaysOpenExternally: true}); 735 let isNonShadowEditable = !node.isInUserAgentShadowTree() && this.editable; 736 737 if (event.target && event.target.tagName === "A") { 738 let url = event.target.href; 739 740 contextMenu.appendItem(WI.UIString("Open in New Tab"), () => { 741 const frame = null; 742 WI.openURL(url, frame, {alwaysOpenExternally: true}); 743 }); 744 745 if (WI.frameResourceManager.resourceForURL(url)) { 746 contextMenu.appendItem(WI.UIString("Reveal in Resources Tab"), () => { 747 let frame = WI.frameResourceManager.frameForIdentifier(node.frameIdentifier); 748 749 const options = { 750 ignoreNetworkTab: true, 751 ignoreSearchTab: true, 752 }; 753 WI.openURL(url, frame, options); 712 754 }); 713 714 if (WI.frameResourceManager.resourceForURL(url)) { 715 contextMenu.appendItem(WI.UIString("Reveal in Resources Tab"), () => { 716 let frame = WI.frameResourceManager.frameForIdentifier(node.frameIdentifier); 717 718 const options = { 719 ignoreNetworkTab: true, 720 ignoreSearchTab: true, 721 }; 722 WI.openURL(url, frame, options); 723 }); 724 } 725 726 contextMenu.appendItem(WI.UIString("Copy Link Address"), () => { 727 InspectorFrontendHost.copyText(url); 728 }); 729 730 contextMenu.appendSeparator(); 731 } 732 733 // Add attribute-related actions. 734 if (this.editable) { 735 contextMenu.appendItem(WI.UIString("Add Attribute"), this._addNewAttribute.bind(this)); 736 if (attribute) 737 contextMenu.appendItem(WI.UIString("Edit Attribute"), this._startEditingAttribute.bind(this, attribute, event.target)); 738 contextMenu.appendSeparator(); 739 } 740 741 if (WI.cssStyleManager.canForcePseudoClasses()) { 742 let pseudoSubMenu = contextMenu.appendSubMenuItem(WI.UIString("Forced Pseudo-Classes")); 743 this._populateForcedPseudoStateItems(pseudoSubMenu); 744 contextMenu.appendSeparator(); 745 } 746 } 747 748 this._populateNodeContextMenu(contextMenu); 749 } 750 751 _populateForcedPseudoStateItems(subMenu) 752 { 753 var node = this.representedObject; 754 var enabledPseudoClasses = node.enabledPseudoClasses; 755 // These strings don't need to be localized as they are CSS pseudo-classes. 756 WI.CSSStyleManager.ForceablePseudoClasses.forEach(function(pseudoClass) { 757 var label = pseudoClass.capitalize(); 758 var enabled = enabledPseudoClasses.includes(pseudoClass); 759 subMenu.appendCheckboxItem(label, function() { 760 node.setPseudoClassEnabled(pseudoClass, !enabled); 761 }, enabled, false); 762 }); 763 } 764 765 _populateTextContextMenu(contextMenu, textNode) 766 { 767 if (this.editable) 768 contextMenu.appendItem(WI.UIString("Edit Text"), this._startEditingTextNode.bind(this, textNode)); 769 770 this._populateNodeContextMenu(contextMenu); 771 } 772 773 _populateNodeContextMenu(contextMenu) 755 } 756 757 contextMenu.appendItem(WI.UIString("Copy Link Address"), () => { 758 InspectorFrontendHost.copyText(url); 759 }); 760 } 761 762 contextMenu.appendSeparator(); 763 764 this._populateNodeContextMenu(contextMenu, subMenus); 765 766 contextMenu.appendItem(WI.UIString("Toggle Visibility"), this.toggleElementVisibility.bind(this)); 767 768 subMenus.add.appendItem(WI.UIString("Attribute"), this._addNewAttribute.bind(this), !isNonShadowEditable); 769 770 let attribute = event.target.enclosingNodeOrSelfWithClass("html-attribute"); 771 subMenus.edit.appendItem(WI.UIString("Attribute"), this._startEditingAttribute.bind(this, attribute, event.target), !attribute || ! isNonShadowEditable); 772 773 let attributeName = null; 774 if (attribute) { 775 let attributeNameElement = attribute.getElementsByClassName("html-attribute-name")[0]; 776 if (attributeNameElement) 777 attributeName = attributeNameElement.textContent.trim(); 778 } 779 780 let attributeValue = this.representedObject.getAttribute(attributeName); 781 subMenus.copy.appendItem(WI.UIString("Attribute"), () => { 782 let text = attributeName; 783 if (attributeValue) 784 text += "=\"" + attributeValue.replace(/"/g, "\\\"") + "\""; 785 InspectorFrontendHost.copyText(text); 786 }, !attribute || !isNonShadowEditable); 787 788 subMenus.delete.appendItem(WI.UIString("Attribute"), () => { 789 this.representedObject.removeAttribute(attributeName); 790 }, !attribute || !isNonShadowEditable); 791 792 subMenus.edit.appendItem(WI.UIString("Tag"), () => { 793 this._startEditingTagName(); 794 }, !isNonShadowEditable); 795 796 contextMenu.appendSeparator(); 797 798 if (WI.cssStyleManager.canForcePseudoClasses()) { 799 let pseudoSubMenu = contextMenu.appendSubMenuItem(WI.UIString("Forced Pseudo-Classes")); 800 801 let enabledPseudoClasses = this.representedObject.enabledPseudoClasses; 802 WI.CSSStyleManager.ForceablePseudoClasses.forEach((pseudoClass) => { 803 let enabled = enabledPseudoClasses.includes(pseudoClass); 804 pseudoSubMenu.appendCheckboxItem(pseudoClass.capitalize(), () => { 805 this.representedObject.setPseudoClassEnabled(pseudoClass, !enabled); 806 }, enabled); 807 }); 808 809 contextMenu.appendSeparator(); 810 } 811 } 812 813 _populateTextContextMenu(contextMenu, textNode, subMenus) 814 { 815 this._populateNodeContextMenu(contextMenu, subMenus); 816 817 subMenus.edit.appendItem(WI.UIString("Text"), this._startEditingTextNode.bind(this, textNode), !this.editable); 818 819 subMenus.copy.appendItem(WI.UIString("Text"), () => { 820 InspectorFrontendHost.copyText(textNode.textContent); 821 }, !textNode.textContent.length); 822 } 823 824 _populateNodeContextMenu(contextMenu, subMenus) 774 825 { 775 826 let node = this.representedObject; 776 827 777 // Add free-form node-related actions.778 if (this.editable)779 contextMenu.appendItem(WI.UIString("Edit as HTML"), this._editAsHTML.bind(this));780 if (!node.isPseudoElement())781 contextMenu.appendItem(WI.UIString("Copy as HTML"), this._copyHTML.bind(this)); 782 if (this.editable)783 contextMenu. appendItem(WI.UIString("Delete Node"), this.remove.bind(this));828 // FIXME: <https://webkit.org/b/179042> Web Inspector: add contextmenu item to arbitrarily add HTML/Child to DOMTree 829 subMenus.edit.appendItem(WI.UIString("HTML"), this._editAsHTML.bind(this), !this.editable); 830 subMenus.copy.appendItem(WI.UIString("HTML"), this._copyHTML.bind(this), node.isPseudoElement()); 831 subMenus.delete.appendItem(WI.UIString("Node"), this.remove.bind(this), !this.editable); 832 833 for (let subMenu of Object.values(subMenus)) 834 contextMenu.pushItem(subMenu); 784 835 } 785 836 -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.js
r222188 r224314 244 244 let pseudoElement = event.target.enclosingNodeOrSelfWithClass("html-pseudo-element"); 245 245 246 let subMenus = { 247 add: new WI.ContextSubMenuItem(contextMenu, WI.UIString("Add")), 248 edit: new WI.ContextSubMenuItem(contextMenu, WI.UIString("Edit")), 249 copy: new WI.ContextSubMenuItem(contextMenu, WI.UIString("Copy")), 250 delete: new WI.ContextSubMenuItem(contextMenu, WI.UIString("Delete")), 251 }; 252 246 253 if (tag && treeElement._populateTagContextMenu) 247 treeElement._populateTagContextMenu(contextMenu, event );254 treeElement._populateTagContextMenu(contextMenu, event, subMenus); 248 255 else if (textNode && treeElement._populateTextContextMenu) 249 treeElement._populateTextContextMenu(contextMenu, textNode );256 treeElement._populateTextContextMenu(contextMenu, textNode, subMenus); 250 257 else if ((commentNode || pseudoElement) && treeElement._populateNodeContextMenu) 251 treeElement._populateNodeContextMenu(contextMenu); 252 253 const options = {excludeRevealElement: this._excludeRevealElementContextMenu}; 258 treeElement._populateNodeContextMenu(contextMenu, subMenus); 259 260 let options = { 261 excludeRevealElement: this._excludeRevealElementContextMenu, 262 copySubMenu: subMenus.copy, 263 }; 254 264 WI.appendContextMenuItemsForDOMNode(contextMenu, treeElement.representedObject, options); 255 265 … … 491 501 event.preventDefault(); 492 502 493 var effectiveNode = this.selectedTreeElement.representedObject; 494 console.assert(effectiveNode); 495 if (!effectiveNode) 496 return; 497 498 if (effectiveNode.isPseudoElement()) { 499 effectiveNode = effectiveNode.parentNode; 500 console.assert(effectiveNode); 501 if (!effectiveNode) 502 return; 503 } 504 505 if (effectiveNode.nodeType() !== Node.ELEMENT_NODE) 506 return; 507 508 function inspectedPage_node_injectStyleAndToggleClass() { 509 let hideElementStyleSheetIdOrClassName = "__WebInspectorHideElement__"; 510 let styleElement = document.getElementById(hideElementStyleSheetIdOrClassName); 511 if (!styleElement) { 512 styleElement = document.createElement("style"); 513 styleElement.id = hideElementStyleSheetIdOrClassName; 514 styleElement.textContent = "." + hideElementStyleSheetIdOrClassName + " { visibility: hidden !important; }"; 515 document.head.appendChild(styleElement); 516 } 517 518 this.classList.toggle(hideElementStyleSheetIdOrClassName); 519 } 520 521 WI.RemoteObject.resolveNode(effectiveNode).then((object) => { 522 object.callFunction(inspectedPage_node_injectStyleAndToggleClass, undefined, false, () => { }); 523 object.release(); 524 }); 503 this.selectedTreeElement.toggleElementVisibility(); 525 504 } 526 505 };
Note: See TracChangeset
for help on using the changeset viewer.