Web Inspector: Audit: make it easier to jump to any returned DOM node in the Elements tab
https://bugs.webkit.org/show_bug.cgi?id=197470
<rdar://problem/50466774>

Reviewed by Joseph Pecoraro.

Right now, the only way to jump to the Elements tab for any DOM nodes returned by an audit
is to context menu and "Reveal in DOM Tree". Providing a more visible/discoverable way to
jump to the Elements tab will help developers diagnose issues easier.

* UserInterface/Views/AuditTestCaseContentView.js:
(WI.AuditTestCaseContentView.prototype.layout):
* UserInterface/Views/AuditTestCaseContentView.css:
(.content-view.audit-test-case > section table):

* UserInterface/Views/DOMTreeElement.js:
(WI.DOMTreeElement):
(WI.DOMTreeElement.prototype.set showGoToArrow): Added.
(WI.DOMTreeElement.prototype._buildTagDOM):
(WI.DOMTreeElement.prototype._nodeTitleInfo):
Provide a way to insert a go-to arrow right after the:
 - open tag, if the close tag is rendered on a separate line
 - close tag, if the close tag is rendered on the same line

* UserInterface/Views/DOMTreeOutline.js:
(WI.DOMTreeOutline):
Allow `DOMTreeOutline` to be non-selectable.

* UserInterface/Views/DOMTreeOutline.css:
(.tree-outline.dom:not(.non-selectable):focus li:matches(.selected, .hovered) .selection-area): Added.
(.tree-outline.dom:not(.non-selectable) li.hovered:not(.selected) .selection-area): Added.
(.tree-outline.dom li .html-tag ~ .go-to-arrow): Added.
(.tree-outline.dom li:not(.hovered) .html-tag ~ .go-to-arrow): Added.
(.tree-outline.dom:focus li:matches(.selected, .hovered) .selection-area): Deleted.
(.tree-outline.dom li.hovered:not(.selected) .selection-area): Deleted.
Ensure that hovering a non-selectable node doesn't change the background color.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@245497 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog
index 0f4e285..26470e0 100644
--- a/Source/WebInspectorUI/ChangeLog
+++ b/Source/WebInspectorUI/ChangeLog
@@ -1,5 +1,44 @@
 2019-05-17  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: Audit: make it easier to jump to any returned DOM node in the Elements tab
+        https://bugs.webkit.org/show_bug.cgi?id=197470
+        <rdar://problem/50466774>
+
+        Reviewed by Joseph Pecoraro.
+
+        Right now, the only way to jump to the Elements tab for any DOM nodes returned by an audit
+        is to context menu and "Reveal in DOM Tree". Providing a more visible/discoverable way to
+        jump to the Elements tab will help developers diagnose issues easier.
+
+        * UserInterface/Views/AuditTestCaseContentView.js:
+        (WI.AuditTestCaseContentView.prototype.layout):
+        * UserInterface/Views/AuditTestCaseContentView.css:
+        (.content-view.audit-test-case > section table):
+
+        * UserInterface/Views/DOMTreeElement.js:
+        (WI.DOMTreeElement):
+        (WI.DOMTreeElement.prototype.set showGoToArrow): Added.
+        (WI.DOMTreeElement.prototype._buildTagDOM):
+        (WI.DOMTreeElement.prototype._nodeTitleInfo):
+        Provide a way to insert a go-to arrow right after the:
+         - open tag, if the close tag is rendered on a separate line
+         - close tag, if the close tag is rendered on the same line
+
+        * UserInterface/Views/DOMTreeOutline.js:
+        (WI.DOMTreeOutline):
+        Allow `DOMTreeOutline` to be non-selectable.
+
+        * UserInterface/Views/DOMTreeOutline.css:
+        (.tree-outline.dom:not(.non-selectable):focus li:matches(.selected, .hovered) .selection-area): Added.
+        (.tree-outline.dom:not(.non-selectable) li.hovered:not(.selected) .selection-area): Added.
+        (.tree-outline.dom li .html-tag ~ .go-to-arrow): Added.
+        (.tree-outline.dom li:not(.hovered) .html-tag ~ .go-to-arrow): Added.
+        (.tree-outline.dom:focus li:matches(.selected, .hovered) .selection-area): Deleted.
+        (.tree-outline.dom li.hovered:not(.selected) .selection-area): Deleted.
+        Ensure that hovering a non-selectable node doesn't change the background color.
+
+2019-05-17  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: Elements: context menu items in DOM tree should work when not clicking directly on the node representation
         https://bugs.webkit.org/show_bug.cgi?id=197541
 
diff --git a/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css b/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css
index ea6ccdb..a2101af 100644
--- a/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css
+++ b/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css
@@ -101,6 +101,7 @@
 }
 
 .content-view.audit-test-case > section table {
+    width: 100%;
     border-collapse: collapse;
 }
 
diff --git a/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js b/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js
index 1a8d7fd..d0d5df0 100644
--- a/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js
+++ b/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js
@@ -153,11 +153,12 @@
                 let dataElement = rowElement.appendChild(document.createElement("td"));
 
                 if (domNode instanceof WI.DOMNode) {
-                    let treeOutline = new WI.DOMTreeOutline;
+                    let treeOutline = new WI.DOMTreeOutline({selectable: false});
                     treeOutline.setVisible(true);
                     treeOutline.rootDOMNode = domNode;
 
                     let rootTreeElement = treeOutline.children[0];
+                    rootTreeElement.showGoToArrow = true;
                     if (!rootTreeElement.hasChildren)
                         treeOutline.element.classList.add("single-node");
 
diff --git a/Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js
index c39534b..e6f1ee8 100644
--- a/Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js
+++ b/Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js
@@ -47,6 +47,7 @@
         this._boundHighlightAnimationEnd = this._highlightAnimationEnd.bind(this);
         this._subtreeBreakpointCount = 0;
 
+        this._showGoToArrow = false;
         this._highlightedAttributes = new Set;
         this._recentlyModifiedAttributes = new Map;
         this._closeTagTreeElement = null;
@@ -271,6 +272,16 @@
         return count;
     }
 
+    set showGoToArrow(x)
+    {
+        if (this._showGoToArrow === x)
+            return;
+
+        this._showGoToArrow = x;
+
+        this.updateTitle();
+    }
+
     attributeDidChange(name)
     {
         if (this._recentlyModifiedAttributes.has(name))
@@ -1353,7 +1364,7 @@
             attrSpanElement.classList.add("highlight");
     }
 
-    _buildTagDOM(parentElement, tagName, isClosingTag, isDistinctTreeElement)
+    _buildTagDOM({parentElement, tagName, isClosingTag, isDistinctTreeElement, willRenderCloseTagInline})
     {
         var node = this.representedObject;
         var classes = ["html-tag"];
@@ -1373,6 +1384,14 @@
         }
         tagElement.append(">");
         parentElement.append("\u200B");
+
+        if (this._showGoToArrow && node.nodeType() === Node.ELEMENT_NODE && willRenderCloseTagInline === isClosingTag) {
+            let goToArrowElement = parentElement.appendChild(WI.createGoToArrowButton());
+            goToArrowElement.title = WI.UIString("Reveal in Elements Tab");
+            goToArrowElement.addEventListener("click", (event) => {
+                WI.domManager.inspectElement(this.representedObject.id);
+            });
+        }
     }
 
     _nodeTitleInfo()
@@ -1418,23 +1437,42 @@
 
                 var tagName = node.nodeNameInCorrectCase();
                 if (this._elementCloseTag) {
-                    this._buildTagDOM(info.titleDOM, tagName, true, true);
+                    this._buildTagDOM({
+                        parentElement: info.titleDOM,
+                        tagName,
+                        isClosingTag: true,
+                        isDistinctTreeElement: true,
+                        willRenderCloseTagInline: false,
+                    });
                     info.hasChildren = false;
                     break;
                 }
 
-                this._buildTagDOM(info.titleDOM, tagName, false, false);
-
                 var textChild = this._singleTextChild(node);
                 var showInlineText = textChild && textChild.nodeValue().length < WI.DOMTreeElement.MaximumInlineTextChildLength;
+                var showInlineEllipsis = !this.expanded && !showInlineText && (this.treeOutline.isXMLMimeType || !WI.DOMTreeElement.ForbiddenClosingTagElements.has(tagName));
 
-                if (!this.expanded && (!showInlineText && (this.treeOutline.isXMLMimeType || !WI.DOMTreeElement.ForbiddenClosingTagElements.has(tagName)))) {
+                this._buildTagDOM({
+                    parentElement: info.titleDOM,
+                    tagName,
+                    isClosingTag: false,
+                    isDistinctTreeElement: false,
+                    willRenderCloseTagInline: showInlineText || showInlineEllipsis,
+                });
+
+                if (showInlineEllipsis) {
                     if (this.hasChildren) {
                         var textNodeElement = info.titleDOM.createChild("span", "html-text-node");
                         textNodeElement.textContent = ellipsis;
                         info.titleDOM.append("\u200B");
                     }
-                    this._buildTagDOM(info.titleDOM, tagName, true, false);
+                    this._buildTagDOM({
+                        parentElement: info.titleDOM,
+                        tagName,
+                        isClosingTag: true,
+                        isDistinctTreeElement: false,
+                        willRenderCloseTagInline: true,
+                    });
                 }
 
                 // If this element only has a single child that is a text node,
@@ -1453,7 +1491,13 @@
 
                     info.titleDOM.append("\u200B");
 
-                    this._buildTagDOM(info.titleDOM, tagName, true, false);
+                    this._buildTagDOM({
+                        parentElement: info.titleDOM,
+                        tagName,
+                        isClosingTag: true,
+                        isDistinctTreeElement: false,
+                        willRenderCloseTagInline: true,
+                    });
                     info.hasChildren = false;
                 }
                 break;
diff --git a/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.css b/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.css
index f96b187..a340188 100644
--- a/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.css
+++ b/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.css
@@ -62,11 +62,11 @@
     border-top: 2px solid var(--selected-background-color);
 }
 
-.tree-outline.dom:focus li:matches(.selected, .hovered) .selection-area {
+.tree-outline.dom:not(.non-selectable):focus li:matches(.selected, .hovered) .selection-area {
     background-color: var(--selected-background-color);
 }
 
-.tree-outline.dom li.hovered:not(.selected) .selection-area {
+.tree-outline.dom:not(.non-selectable) li.hovered:not(.selected) .selection-area {
     opacity: 0.3;
 }
 
@@ -175,6 +175,15 @@
     -webkit-margin-start: calc(-1 * var(--sublist-margin-start) - var(--sublist-border-width-start));
 }
 
+.tree-outline.dom li .html-tag ~ .go-to-arrow {
+    height: 13px;
+    vertical-align: -3px;
+}
+
+.tree-outline.dom li:not(.hovered) .html-tag ~ .go-to-arrow {
+    visibility: hidden;
+}
+
 .tree-outline.dom li.parent::before {
     position: relative;
     z-index: 20;
diff --git a/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.js b/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.js
index 1227a2b..404075d 100644
--- a/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.js
+++ b/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.js
@@ -30,9 +30,9 @@
 
 WI.DOMTreeOutline = class DOMTreeOutline extends WI.TreeOutline
 {
-    constructor({omitRootDOMNode, excludeRevealElementContextMenu, showLastSelected} = {})
+    constructor({selectable, omitRootDOMNode, excludeRevealElementContextMenu, showLastSelected} = {})
     {
-        super();
+        super(selectable);
 
         this.element.addEventListener("mousedown", this._onmousedown.bind(this), false);
         this.element.addEventListener("mousemove", this._onmousemove.bind(this), false);