Bug 1287090 - HTMLTooltip: support host changes by retrieving top window dynamically;r=bgrins draft
authorJulian Descottes <jdescottes@mozilla.com>
Fri, 15 Jul 2016 16:30:54 +0200
changeset 389113 7990bd4ef4c519495231fc71a2176847c2dfd3cf
parent 389112 8b57c89f86db1e9a8ae0ef756363558f86130ff4
child 525660 689f2a3db6bbac60bcacfe487de212c11f67e1ba
push id23303
push userjdescottes@mozilla.com
push dateMon, 18 Jul 2016 16:47:30 +0000
reviewersbgrins
bugs1287090
milestone50.0a1
Bug 1287090 - HTMLTooltip: support host changes by retrieving top window dynamically;r=bgrins MozReview-Commit-ID: 9RcM2h41DdV
devtools/client/inspector/markup/test/browser.ini
devtools/client/inspector/markup/test/browser_markup_events-windowed-host.js
devtools/client/shared/widgets/HTMLTooltip.js
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -85,16 +85,17 @@ subsuite = clipboard
 [browser_markup_events_jquery_1.3.js]
 [browser_markup_events_jquery_1.4.js]
 [browser_markup_events_jquery_1.6.js]
 [browser_markup_events_jquery_1.7.js]
 [browser_markup_events_jquery_1.11.1.js]
 [browser_markup_events_jquery_2.1.1.js]
 [browser_markup_events-overflow.js]
 skip-if = true # Bug 1177550
+[browser_markup_events-windowed-host.js]
 [browser_markup_links_01.js]
 [browser_markup_links_02.js]
 [browser_markup_links_03.js]
 [browser_markup_links_04.js]
 subsuite = clipboard
 [browser_markup_links_05.js]
 [browser_markup_links_06.js]
 [browser_markup_links_07.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_events-windowed-host.js
@@ -0,0 +1,61 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/*
+ * Test that the event details tooltip can be hidden by clicking outside of the tooltip
+ * after switching hosts.
+ */
+
+const TEST_URL = URL_ROOT + "doc_markup_events-overflow.html";
+
+registerCleanupFunction(() => {
+  // Restore the default Toolbox host position after the test.
+  Services.prefs.clearUserPref("devtools.toolbox.host");
+});
+
+add_task(function* () {
+  let { inspector, toolbox } = yield openInspectorForURL(TEST_URL);
+  yield runTests(inspector);
+
+  yield toolbox.switchHost("window");
+  yield runTests(inspector);
+
+  yield toolbox.switchHost("bottom");
+  yield runTests(inspector);
+
+  yield toolbox.destroy();
+});
+
+function* runTests(inspector) {
+  let markupContainer = yield getContainerForSelector("#events", inspector);
+  let evHolder = markupContainer.elt.querySelector(".markupview-events");
+  let tooltip = inspector.markup.eventDetailsTooltip;
+
+  info("Clicking to open event tooltip.");
+
+  let onInspectorUpdated = inspector.once("inspector-updated");
+  let onTooltipShown = tooltip.once("shown");
+  EventUtils.synthesizeMouseAtCenter(evHolder, {}, inspector.markup.doc.defaultView);
+
+  yield onTooltipShown;
+  // New node is selected when clicking on the events bubble, wait for inspector-updated.
+  yield onInspectorUpdated;
+
+  ok(tooltip.isVisible(), "EventTooltip visible.");
+
+  onInspectorUpdated = inspector.once("inspector-updated");
+  let onTooltipHidden = tooltip.once("hidden");
+
+  info("Click on another tag to hide the event tooltip");
+  let h1 = yield getContainerForSelector("h1", inspector);
+  let tag = h1.elt.querySelector(".tag");
+  EventUtils.synthesizeMouseAtCenter(tag, {}, inspector.markup.doc.defaultView);
+
+  yield onTooltipHidden;
+  // New node is selected, wait for inspector-updated.
+  yield onInspectorUpdated;
+
+  ok(!tooltip.isVisible(), "EventTooltip hidden.");
+}
--- a/devtools/client/shared/widgets/HTMLTooltip.js
+++ b/devtools/client/shared/widgets/HTMLTooltip.js
@@ -217,20 +217,21 @@ function HTMLTooltip(toolbox, {
   EventEmitter.decorate(this);
 
   this.doc = toolbox.doc;
   this.type = type;
   this.autofocus = autofocus;
   this.consumeOutsideClicks = consumeOutsideClicks;
   this.useXulWrapper = this._isXUL() && useXulWrapper;
 
-  this._position = null;
+  // The top window is used to attach click event listeners to close the tooltip if the
+  // user clicks on the content page.
+  this.topWindow = this._getTopWindow();
 
-  // Use the topmost window to listen for click events to close the tooltip
-  this.topWindow = this.doc.defaultView.top;
+  this._position = null;
 
   this._onClick = this._onClick.bind(this);
 
   this._toggle = new TooltipToggle(this);
   this.startTogglingOnHover = this._toggle.start.bind(this._toggle);
   this.stopTogglingOnHover = this._toggle.stop.bind(this._toggle);
 
   this.container = this._createContainer();
@@ -377,16 +378,18 @@ HTMLTooltip.prototype = {
     this.container.classList.add("tooltip-visible");
 
     // Keep a pointer on the focused element to refocus it when hiding the tooltip.
     this._focusedElement = this.doc.activeElement;
 
     this.doc.defaultView.clearTimeout(this.attachEventsTimer);
     this.attachEventsTimer = this.doc.defaultView.setTimeout(() => {
       this._maybeFocusTooltip();
+      // Updated the top window reference each time in case the host changes.
+      this.topWindow = this._getTopWindow();
       this.topWindow.addEventListener("click", this._onClick, true);
       this.emit("shown");
     }, 0);
   }),
 
   /**
    * Calculate the rect of the viewport that limits the tooltip dimensions. When using a
    * XUL panel wrapper, the viewport will be able to use the whole screen (excluding space
@@ -545,16 +548,20 @@ HTMLTooltip.prototype = {
     // http://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus .
     let focusableSelector = "a, button, iframe, input, select, textarea";
     let focusableElement = this.panel.querySelector(focusableSelector);
     if (this.autofocus && focusableElement) {
       focusableElement.focus();
     }
   },
 
+  _getTopWindow: function () {
+    return this.doc.defaultView.top;
+  },
+
   /**
    * Check if the tooltip's owner document is a XUL document.
    */
   _isXUL: function () {
     return this.doc.documentElement.namespaceURI === XUL_NS;
   },
 
   _createXulPanelWrapper: function () {