Web Inspector: Styles: completion popover doesn't hide when switching panels
authornvasilyev@apple.com <nvasilyev@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Feb 2018 22:45:50 +0000 (22:45 +0000)
committernvasilyev@apple.com <nvasilyev@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Feb 2018 22:45:50 +0000 (22:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=182464
<rdar://problem/37202763>

Reviewed by Timothy Hatcher.

Save the position of the anchor, an element the popover is shown for, and hide the completion popover
when the position changes.

* UserInterface/Views/CompletionSuggestionsView.js:
(WI.CompletionSuggestionsView.prototype.showUntilAnchorMoves):
When the popover is visible, check every 200ms if the anchor moved.

(WI.CompletionSuggestionsView.prototype.hide):
* UserInterface/Views/SpreadsheetTextField.js:
(WI.SpreadsheetTextField.prototype._updateCompletions):
(WI.SpreadsheetTextField.prototype._getCaretRect):
getBoundingClientRect returns {x: 0, y: 0} when it can't determine node's position.
This happens when a node isn't attached to DOM, attached to DOM but not visible, and
a number of odd cases.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@228487 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Views/CompletionSuggestionsView.js
Source/WebInspectorUI/UserInterface/Views/SpreadsheetTextField.js

index a45d525..473535e 100644 (file)
@@ -1,3 +1,26 @@
+2018-02-14  Nikita Vasilyev  <nvasilyev@apple.com>
+
+        Web Inspector: Styles: completion popover doesn't hide when switching panels
+        https://bugs.webkit.org/show_bug.cgi?id=182464
+        <rdar://problem/37202763>
+
+        Reviewed by Timothy Hatcher.
+
+        Save the position of the anchor, an element the popover is shown for, and hide the completion popover
+        when the position changes.
+
+        * UserInterface/Views/CompletionSuggestionsView.js:
+        (WI.CompletionSuggestionsView.prototype.showUntilAnchorMoves):
+        When the popover is visible, check every 200ms if the anchor moved.
+
+        (WI.CompletionSuggestionsView.prototype.hide):
+        * UserInterface/Views/SpreadsheetTextField.js:
+        (WI.SpreadsheetTextField.prototype._updateCompletions):
+        (WI.SpreadsheetTextField.prototype._getCaretRect):
+        getBoundingClientRect returns {x: 0, y: 0} when it can't determine node's position.
+        This happens when a node isn't attached to DOM, attached to DOM but not visible, and
+        a number of odd cases.
+
 2018-02-14  Matt Baker  <mattbaker@apple.com>
 
         Web Inspector: TabBar redesign: only show allowed tabs in the available tabs context menu
index ffb58ae..30cc228 100644 (file)
@@ -33,6 +33,7 @@ WI.CompletionSuggestionsView = class CompletionSuggestionsView extends WI.Object
         this._preventBlur = preventBlur || false;
 
         this._selectedIndex = NaN;
+        this._anchorBounds = null;
 
         this._element = document.createElement("div");
         this._element.classList.add("completion-suggestions", WI.Popover.IgnoreAutoDismissClassName);
@@ -157,9 +158,36 @@ WI.CompletionSuggestionsView = class CompletionSuggestionsView extends WI.Object
         document.body.appendChild(this._element);
     }
 
+    showUntilAnchorMoves(getAnchorBounds)
+    {
+        this._anchorBounds = getAnchorBounds();
+        if (!this._anchorBounds) {
+            this.hide();
+            return;
+        }
+
+        this.show(this._anchorBounds);
+
+        let hideWhenMoved = () => {
+            let anchorBounds = getAnchorBounds();
+            if (!anchorBounds || !anchorBounds.equals(this._anchorBounds))
+                this.hide();
+        };
+
+        if (this._hideWhenMovedIdentifier)
+            clearInterval(this._hideWhenMovedIdentifier);
+
+        this._hideWhenMovedIdentifier = setInterval(hideWhenMoved, 200);
+    }
+
     hide()
     {
         this._element.remove();
+        this._anchorBounds = null;
+        if (this._hideWhenMovedIdentifier) {
+            clearInterval(this._hideWhenMovedIdentifier);
+            this._hideWhenMovedIdentifier = 0;
+        }
     }
 
     update(completions, selectedIndex)
index ea15e10..16512f6 100644 (file)
@@ -377,8 +377,10 @@ WI.SpreadsheetTextField = class SpreadsheetTextField
             // No need to show the completion popover that matches the suggestion hint.
             this._suggestionsView.hide();
         } else {
-            let caretRect = this._getCaretRect(prefix, completionPrefix);
-            this._suggestionsView.show(caretRect);
+            let startOffset = prefix.length - completionPrefix.length;
+            this._suggestionsView.showUntilAnchorMoves(() => {
+                return this._getCaretRect(startOffset);
+            });
         }
 
         this._suggestionsView.selectedIndex = NaN;
@@ -389,19 +391,30 @@ WI.SpreadsheetTextField = class SpreadsheetTextField
             this.suggestionHint = "";
     }
 
-    _getCaretRect(prefix, completionPrefix)
+    _getCaretRect(startOffset)
     {
-        let startOffset = prefix.length - completionPrefix.length;
         let selection = window.getSelection();
 
-        if (startOffset > 0 && selection.rangeCount) {
+        let isHidden = (clientRect) => {
+            return clientRect.x === 0 && clientRect.y === 0
+        };
+
+        if (selection.rangeCount) {
             let range = selection.getRangeAt(0).cloneRange();
             range.setStart(range.startContainer, startOffset);
             let clientRect = range.getBoundingClientRect();
-            return WI.Rect.rectFromClientRect(clientRect);
+
+            if (!isHidden(clientRect)) {
+                // This happens after deleting value. However, when focusing
+                // on an empty value clientRect is visible.
+                return WI.Rect.rectFromClientRect(clientRect);
+            }
         }
 
         let clientRect = this._element.getBoundingClientRect();
+        if (isHidden(clientRect))
+            return null;
+
         const leftPadding = parseInt(getComputedStyle(this._element).paddingLeft) || 0;
         return new WI.Rect(clientRect.left + leftPadding, clientRect.top, clientRect.width, clientRect.height);
     }