Bug 1266450 - part4: allow tooltips to have a variable height;r=bgrins
authorJulian Descottes <jdescottes@mozilla.com>
Fri, 03 Jun 2016 12:52:59 +0200
changeset 301231 2ad8e1757b864d955fbf80c249e3bf9f08279a42
parent 301230 ed461f8fe522f8090766443fc771384add572506
child 301232 42e38084205ef6aa7d70d212c6e0532c63311e21
push id78263
push usercbook@mozilla.com
push dateThu, 09 Jun 2016 10:13:31 +0000
treeherdermozilla-inbound@3d132a280ca0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgrins
bugs1266450
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1266450 - part4: allow tooltips to have a variable height;r=bgrins With this changeset the tooltip's effective height can be smaller than the height specified when calling setContent. If the tooltip content is dynamic, this allows to display a small tooltip frame if the content is collapsed, and a bigger tooltip frame when it is expanded. MozReview-Commit-ID: 44vA0Rdz62m
devtools/client/shared/test/browser.ini
devtools/client/shared/test/browser_html_tooltip_arrow-01.js
devtools/client/shared/test/browser_html_tooltip_arrow-02.js
devtools/client/shared/test/browser_html_tooltip_variable-height.js
devtools/client/shared/widgets/HTMLTooltip.js
devtools/client/themes/tooltips.css
--- a/devtools/client/shared/test/browser.ini
+++ b/devtools/client/shared/test/browser.ini
@@ -115,16 +115,17 @@ skip-if = e10s # Bug 1221911, bug 122228
 skip-if = e10s # Bug 1221911, bug 1222289, frequent e10s timeouts
 [browser_html_tooltip-01.js]
 [browser_html_tooltip-02.js]
 [browser_html_tooltip-03.js]
 [browser_html_tooltip-04.js]
 [browser_html_tooltip-05.js]
 [browser_html_tooltip_arrow-01.js]
 [browser_html_tooltip_arrow-02.js]
+[browser_html_tooltip_variable-height.js]
 [browser_inplace-editor-01.js]
 [browser_inplace-editor-02.js]
 [browser_inplace-editor_autocomplete_01.js]
 [browser_inplace-editor_autocomplete_02.js]
 [browser_inplace-editor_autocomplete_offset.js]
 [browser_inplace-editor_maxwidth.js]
 [browser_key_shortcuts.js]
 [browser_layoutHelpers.js]
--- a/devtools/client/shared/test/browser_html_tooltip_arrow-01.js
+++ b/devtools/client/shared/test/browser_html_tooltip_arrow-01.js
@@ -54,17 +54,17 @@ add_task(function* () {
   yield pushPref("devtools.toolbox.footer.height", 200);
 
   yield addTab("about:blank");
   let [,, doc] = yield createHost("bottom", TEST_URI);
 
   info("Create HTML tooltip");
   let tooltip = new HTMLTooltip({doc}, {type: "arrow"});
   let div = doc.createElementNS(HTML_NS, "div");
-  div.style.height = "100%";
+  div.style.height = "35px";
   yield tooltip.setContent(div, 200, 35);
 
   let {right: docRight} = doc.documentElement.getBoundingClientRect();
 
   let elements = [...doc.querySelectorAll(".anchor")];
   for (let el of elements) {
     info("Display the tooltip on an anchor.");
     yield showTooltip(tooltip, el);
--- a/devtools/client/shared/test/browser_html_tooltip_arrow-02.js
+++ b/devtools/client/shared/test/browser_html_tooltip_arrow-02.js
@@ -48,17 +48,17 @@ add_task(function* () {
   yield pushPref("devtools.toolbox.footer.height", 200);
 
   yield addTab("about:blank");
   let [,, doc] = yield createHost("bottom", TEST_URI);
 
   info("Create HTML tooltip");
   let tooltip = new HTMLTooltip({doc}, {type: "arrow"});
   let div = doc.createElementNS(HTML_NS, "div");
-  div.style.height = "100%";
+  div.style.height = "35px";
   yield tooltip.setContent(div, 200, 35);
 
   let {right: docRight} = doc.documentElement.getBoundingClientRect();
 
   let elements = [...doc.querySelectorAll(".anchor")];
   for (let el of elements) {
     info("Display the tooltip on an anchor.");
     yield showTooltip(tooltip, el);
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/test/browser_html_tooltip_variable-height.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+/* import-globals-from helper_html_tooltip.js */
+
+"use strict";
+
+/**
+ * Test the HTMLTooltip content can have a variable height.
+ */
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+const TEST_URI = `data:text/xml;charset=UTF-8,<?xml version="1.0"?>
+  <?xml-stylesheet href="chrome://global/skin/global.css"?>
+  <?xml-stylesheet href="chrome://devtools/skin/tooltips.css"?>
+  <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+   title="Tooltip test">
+    <vbox flex="1">
+      <hbox id="box1" flex="1">test1</hbox>
+      <hbox id="box2" flex="1">test2</hbox>
+      <hbox id="box3" flex="1">test3</hbox>
+      <hbox id="box4" flex="1">test4</hbox>
+    </vbox>
+  </window>`;
+
+const CONTAINER_HEIGHT = 200;
+const CONTAINER_WIDTH = 200;
+const TOOLTIP_HEIGHT = 50;
+
+const {HTMLTooltip} = require("devtools/client/shared/widgets/HTMLTooltip");
+loadHelperScript("helper_html_tooltip.js");
+
+add_task(function* () {
+  // Force the toolbox to be 400px tall => 50px for each box.
+  yield pushPref("devtools.toolbox.footer.height", 400);
+
+  yield addTab("about:blank");
+  let [,, doc] = yield createHost("bottom", TEST_URI);
+
+  let tooltip = new HTMLTooltip({doc}, {});
+  info("Set tooltip content 50px tall, but request a container 200px tall");
+  let tooltipContent = doc.createElementNS(HTML_NS, "div");
+  tooltipContent.style.cssText = "height: " + TOOLTIP_HEIGHT + "px; background: red;";
+  tooltip.setContent(tooltipContent, CONTAINER_WIDTH, CONTAINER_HEIGHT);
+
+  info("Show the tooltip and check the container and panel height.");
+  yield showTooltip(tooltip, doc.getElementById("box1"));
+
+  let containerRect = tooltip.container.getBoundingClientRect();
+  let panelRect = tooltip.panel.getBoundingClientRect();
+  is(containerRect.height, CONTAINER_HEIGHT,
+    "Tooltip container has the expected height.");
+  is(panelRect.height, TOOLTIP_HEIGHT, "Tooltip panel has the expected height.");
+
+  info("Click below the tooltip panel but in the tooltip filler element.");
+  let onHidden = once(tooltip, "hidden");
+  EventUtils.synthesizeMouse(tooltip.container, 100, 100, {}, doc.defaultView);
+  yield onHidden;
+
+  info("Show the tooltip one more time, and increase the content height");
+  yield showTooltip(tooltip, doc.getElementById("box1"));
+  tooltipContent.style.height = (2 * CONTAINER_HEIGHT) + "px";
+
+  info("Click at the same coordinates as earlier, this time it should hit the tooltip.");
+  let onPanelClick = once(tooltip.panel, "click");
+  EventUtils.synthesizeMouse(tooltip.container, 100, 100, {}, doc.defaultView);
+  yield onPanelClick;
+  is(tooltip.isVisible(), true, "Tooltip is still visible");
+
+  info("Click below the tooltip container, the tooltip should be closed.");
+  onHidden = once(tooltip, "hidden");
+  EventUtils.synthesizeMouse(tooltip.container, 100, CONTAINER_HEIGHT + 10,
+    {}, doc.defaultView);
+  yield onHidden;
+});
--- a/devtools/client/shared/widgets/HTMLTooltip.js
+++ b/devtools/client/shared/widgets/HTMLTooltip.js
@@ -106,17 +106,19 @@ HTMLTooltip.prototype = {
    * Set the tooltip content element. The preferred width/height should also be
    * specified here.
    *
    * @param {Element} content
    *        The tooltip content, should be a HTML element.
    * @param {Number} width
    *        Preferred width for the tooltip container
    * @param {Number} height
-   *        Preferred height for the tooltip container
+   *        Preferred height for the tooltip container. If the content height is
+   *        smaller than the container's height, the tooltip will automatically
+   *        shrink around the content.
    * @return {Promise} a promise that will resolve when the content has been
    *         added in the tooltip container.
    */
   setContent: function (content, width, height) {
     let themeHeight = EXTRA_HEIGHT[this.type] + 2 * EXTRA_BORDER[this.type];
     let themeWidth = 2 * EXTRA_BORDER[this.type];
 
     this.preferredWidth = width + themeWidth;
@@ -202,17 +204,18 @@ HTMLTooltip.prototype = {
     this.container.remove();
   },
 
   _createContainer: function () {
     let container = this.doc.createElementNS(XHTML_NS, "div");
     container.setAttribute("type", this.type);
     container.classList.add("tooltip-container");
 
-    let html = '<div class="tooltip-panel"></div>';
+    let html = '<div class="tooltip-filler"></div>';
+    html += '<div class="tooltip-panel"></div>';
 
     if (this.type === TYPE.ARROW) {
       html += '<div class="tooltip-arrow"></div>';
     }
     container.innerHTML = html;
     return container;
   },
 
--- a/devtools/client/themes/tooltips.css
+++ b/devtools/client/themes/tooltips.css
@@ -100,68 +100,81 @@
 }
 
 .tooltip-container {
   display: none;
   position: fixed;
   z-index: 9999;
   display: none;
   background: transparent;
+  pointer-events: none;
+  overflow: hidden;
+}
+
+.tooltip-top {
+  flex-direction: column;
+}
+
+.tooltip-bottom {
+  flex-direction: column-reverse;
 }
 
 .tooltip-panel{
   background-color: var(--theme-tooltip-background);
+  pointer-events: all;
 }
 
 .tooltip-visible {
-  display: block;
-}
-
-.tooltip-container[type="normal"] > .tooltip-panel {
-  height: 100%;
-  width: 100%;
+  display: flex;
 }
 
 /* Tooltip : arrow style */
 
 .tooltip-container[type="arrow"] {
   filter: drop-shadow(0 3px 4px var(--theme-tooltip-shadow));
 }
 
 .tooltip-container[type="arrow"] > .tooltip-panel {
-  position: absolute;
+  position: relative;
+  flex-grow: 0;
+  min-height: 10px;
   box-sizing: border-box;
-  height: calc(100% - 13px);
   width: 100%;
 
   border: 3px solid var(--theme-tooltip-border);
   border-radius: 5px;
 }
 
 .tooltip-top[type="arrow"] .tooltip-panel {
   top: 0;
 }
 
 .tooltip-bottom[type="arrow"] .tooltip-panel {
   bottom: 0;
 }
 
 .tooltip-arrow {
-  position: absolute;
+  position: relative;
   height: 16px;
   width: 32px;
   overflow: hidden;
+  pointer-events: all;
+  flex-shrink: 0;
+}
+
+.tooltip-filler {
+  flex: 1;
 }
 
 .tooltip-top .tooltip-arrow {
-  bottom: 0;
+  margin-top: -3px;
 }
 
 .tooltip-bottom .tooltip-arrow {
-  top: 0;
+  margin-bottom: -3px;
 }
 
 .tooltip-arrow:before {
   content: "";
   position: absolute;
   width: 21px;
   height: 21px;
   margin-left: 4px;