Bug 1206133 - fire ready event in SwatchBasedEditorTooltips after widget initialization;r=bgrins draft
authorJulian Descottes <jdescottes@mozilla.com>
Mon, 08 Aug 2016 11:29:00 +0200
changeset 397833 1add5471d6f9f4e5ca24bbef45c6f6d81af578e0
parent 397832 5488d220ba431e0fe55bcacaae804336d7c14b37
child 397834 f91c82b4bc08d894d70f60e2e44221d7b59d6540
push id25415
push userjdescottes@mozilla.com
push dateMon, 08 Aug 2016 13:00:33 +0000
reviewersbgrins
bugs1206133
milestone51.0a1
Bug 1206133 - 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,44 @@ 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 null;
   },
 
   hide: function () {
     this.tooltip.hide();
   },
 
   /**
    * Add a new swatch DOM element to the list of swatch elements this editor
@@ -792,19 +804,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 +827,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 +952,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 +1025,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.