Bug 1293211 - fire ready event in SwatchBasedEditorTooltips after widget initialization;r=bgrins draft
authorJulian Descottes <jdescottes@mozilla.com>
Tue, 09 Aug 2016 09:22:16 +0200
changeset 398495 dd7feb69cb5a019892a737871ae48c85d903dee4
parent 398494 db0c040c86e1c74588e4e3769bd00539e6720146
child 398496 96524d4a3a94eb0716973911cdc3b262d7a03b77
push id25542
push userjdescottes@mozilla.com
push dateTue, 09 Aug 2016 07:23:26 +0000
reviewersbgrins
bugs1293211
milestone51.0a1
Bug 1293211 - fire ready event in SwatchBasedEditorTooltips after widget initialization;r=bgrins Now that showing a XUL panel is asynchronous, tests need to be able to wait for the complete initialization of the editor tooltips. Waiting for the tooltip 'shown' event is not enough here because tooltips are also waiting for this event to start initializing their widgets. MozReview-Commit-ID: DGTyeVrHNb
devtools/client/shared/widgets/Tooltip.js
--- a/devtools/client/shared/widgets/Tooltip.js
+++ b/devtools/client/shared/widgets/Tooltip.js
@@ -12,16 +12,17 @@ const {CubicBezierWidget} =
 const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
 const {TooltipToggle} = require("devtools/client/shared/widgets/tooltip/TooltipToggle");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {colorUtils} = require("devtools/shared/css-color");
 const Heritage = require("sdk/core/heritage");
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 const {HTMLTooltip} = require("devtools/client/shared/widgets/HTMLTooltip");
 const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
+const {Task} = require("devtools/shared/task");
 
 loader.lazyRequireGetter(this, "beautify", "devtools/shared/jsbeautify/beautify");
 loader.lazyRequireGetter(this, "setNamedTimeout", "devtools/client/shared/widgets/view-helpers", true);
 loader.lazyRequireGetter(this, "clearNamedTimeout", "devtools/client/shared/widgets/view-helpers", true);
 loader.lazyRequireGetter(this, "setNamedTimeout", "devtools/client/shared/widgets/view-helpers", true);
 
 XPCOMUtils.defineLazyModuleGetter(this, "VariablesView",
   "resource://devtools/client/shared/widgets/VariablesView.jsm");
@@ -553,16 +554,17 @@ Tooltip.prototype = {
 /**
  * Base class for all (color, gradient, ...)-swatch based value editors inside
  * tooltips
  *
  * @param {Toolbox} toolbox
  *        The devtools toolbox, needed to get the devtools main window.
  */
 function SwatchBasedEditorTooltip(toolbox, stylesheet) {
+  EventEmitter.decorate(this);
   // Creating a tooltip instance
   // This one will consume outside clicks as it makes more sense to let the user
   // close the tooltip by clicking out
   // It will also close on <escape> and <enter>
   this.tooltip = new HTMLTooltip(toolbox, {
     type: "arrow",
     consumeOutsideClicks: true,
     useXulWrapper: true,
@@ -600,34 +602,45 @@ function SwatchBasedEditorTooltip(toolbo
   // activeSwatch property will hold the reference to the swatch DOM element
   // that was clicked
   this.activeSwatch = null;
 
   this._onSwatchClick = this._onSwatchClick.bind(this);
 }
 
 SwatchBasedEditorTooltip.prototype = {
+  /**
+   * Show the editor tooltip for the currently active swatch.
+   *
+   * @return {Promise} a promise that resolves once the editor tooltip is displayed, or
+   *         immediately if there is no currently active swatch.
+   */
   show: function () {
     if (this.activeSwatch) {
+      let onShown = this.tooltip.once("shown");
       this.tooltip.show(this.activeSwatch, "topcenter bottomleft");
 
       // When the tooltip is closed by clicking outside the panel we want to
       // commit any changes.
       this.tooltip.once("hidden", () => {
         if (!this._reverted && !this.eyedropperOpen) {
           this.commit();
         }
         this._reverted = false;
 
         // Once the tooltip is hidden we need to clean up any remaining objects.
         if (!this.eyedropperOpen) {
           this.activeSwatch = null;
         }
       });
+
+      return onShown;
     }
+
+    return Promise.resolve();
   },
 
   hide: function () {
     this.tooltip.hide();
   },
 
   /**
    * Add a new swatch DOM element to the list of swatch elements this editor
@@ -792,19 +805,19 @@ Heritage.extend(SwatchBasedEditorTooltip
 
     return spectrum;
   },
 
   /**
    * Overriding the SwatchBasedEditorTooltip.show function to set spectrum's
    * color.
    */
-  show: function () {
+  show: Task.async(function* () {
     // Call then parent class' show function
-    SwatchBasedEditorTooltip.prototype.show.call(this);
+    yield SwatchBasedEditorTooltip.prototype.show.call(this);
     // Then set spectrum's color and listen to color changes to preview them
     if (this.activeSwatch) {
       this.currentSwatchColor = this.activeSwatch.nextSibling;
       this._originalColor = this.currentSwatchColor.textContent;
       let color = this.activeSwatch.style.backgroundColor;
       this.spectrum.off("changed", this._onSpectrumColorChange);
       this.spectrum.rgb = this._colorToRgba(color);
       this.spectrum.on("changed", this._onSpectrumColorChange);
@@ -815,18 +828,19 @@ Heritage.extend(SwatchBasedEditorTooltip
     target.actorHasMethod("inspector", "pickColorFromPage").then(value => {
       let tooltipDoc = this.tooltip.doc;
       let eyeButton = tooltipDoc.querySelector("#eyedropper-button");
       if (value) {
         eyeButton.addEventListener("click", this._openEyeDropper);
       } else {
         eyeButton.style.display = "none";
       }
+      this.emit("ready");
     }, e => console.error(e));
-  },
+  }),
 
   _onSpectrumColorChange: function (event, rgba, cssColor) {
     this._selectColor(cssColor);
   },
 
   _selectColor: function (color) {
     if (this.activeSwatch) {
       this.activeSwatch.style.backgroundColor = color;
@@ -939,29 +953,30 @@ Heritage.extend(SwatchBasedEditorTooltip
 
     return def.promise;
   },
 
   /**
    * Overriding the SwatchBasedEditorTooltip.show function to set the cubic
    * bezier curve in the widget
    */
-  show: function () {
+  show: Task.async(function* () {
     // Call the parent class' show function
-    SwatchBasedEditorTooltip.prototype.show.call(this);
+    yield SwatchBasedEditorTooltip.prototype.show.call(this);
     // Then set the curve and listen to changes to preview them
     if (this.activeSwatch) {
       this.currentBezierValue = this.activeSwatch.nextSibling;
       this.widget.then(widget => {
         widget.off("updated", this._onUpdate);
         widget.cssCubicBezierValue = this.currentBezierValue.textContent;
         widget.on("updated", this._onUpdate);
+        this.emit("ready");
       });
     }
-  },
+  }),
 
   _onUpdate: function (event, bezier) {
     if (!this.activeSwatch) {
       return;
     }
 
     this.currentBezierValue.textContent = bezier + "";
     this.preview(bezier + "");
@@ -1011,28 +1026,29 @@ Heritage.extend(SwatchBasedEditorTooltip
     let container = doc.createElementNS(XHTML_NS, "div");
     container.id = "filter-container";
 
     this.tooltip.setContent(container, { width: 510, height: 200 });
 
     return new CSSFilterEditorWidget(container, filter);
   },
 
-  show: function () {
+  show: Task.async(function* () {
     // Call the parent class' show function
-    SwatchBasedEditorTooltip.prototype.show.call(this);
+    yield SwatchBasedEditorTooltip.prototype.show.call(this);
     // Then set the filter value and listen to changes to preview them
     if (this.activeSwatch) {
       this.currentFilterValue = this.activeSwatch.nextSibling;
       this.widget.off("updated", this._onUpdate);
       this.widget.on("updated", this._onUpdate);
       this.widget.setCssValue(this.currentFilterValue.textContent);
       this.widget.render();
+      this.emit("ready");
     }
-  },
+  }),
 
   _onUpdate: function (event, filters) {
     if (!this.activeSwatch) {
       return;
     }
 
     // Remove the old children and reparse the property value to
     // recompute them.