Bug 1393453 - Moves Tooltips to ES6 classes retaining decorators r=zer0
authorBharat Raghunathan <bharatraghunthan9767@gmail.com>
Wed, 20 Sep 2017 09:42:50 +0530
changeset 383231 71dcce73cbdbeddd7a9ff8c7e972fa72af6e71fc
parent 383230 fd98557b7d2ad826ccaf7bb168b865f66a3413e1
child 383232 3ed0fecec71ef745dd62008170e2aaadd1034c74
push id95539
push userkwierso@gmail.com
push dateThu, 28 Sep 2017 00:01:12 +0000
treeherdermozilla-inbound@72de90e66155 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerszer0
bugs1393453
milestone58.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 1393453 - Moves Tooltips to ES6 classes retaining decorators r=zer0 MozReview-Commit-ID: 98kX9zA0Lka
devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip.js
devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
devtools/client/shared/widgets/tooltip/SwatchCubicBezierTooltip.js
devtools/client/shared/widgets/tooltip/SwatchFilterTooltip.js
devtools/client/shared/widgets/tooltip/Tooltip.js
--- a/devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip.js
@@ -17,96 +17,97 @@ const INLINE_TOOLTIP_CLASS = "inline-too
  *
  * @param {Document} document
  *        The document to attach the SwatchBasedEditorTooltip. This is either the toolbox
  *        document if the tooltip is a popup tooltip or the panel's document if it is an
  *        inline editor.
  * @param {Boolean} useInline
  *        A boolean flag representing whether or not the InlineTooltip should be used.
  */
-function SwatchBasedEditorTooltip(document, useInline) {
-  EventEmitter.decorate(this);
+
+class SwatchBasedEditorTooltip {
+  constructor(document, useInline) {
+    EventEmitter.decorate(this);
+
+    this.useInline = useInline;
 
-  this.useInline = useInline;
+    // Creating a tooltip instance
+    if (useInline) {
+      this.tooltip = new InlineTooltip(document);
+    } else {
+      // 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(document, {
+        type: "arrow",
+        consumeOutsideClicks: true,
+        useXulWrapper: true,
+      });
+    }
 
-  // Creating a tooltip instance
-  if (useInline) {
-    this.tooltip = new InlineTooltip(document);
-  } else {
-    // 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(document, {
-      type: "arrow",
-      consumeOutsideClicks: true,
-      useXulWrapper: true,
+    // By default, swatch-based editor tooltips revert value change on <esc> and
+    // commit value change on <enter>
+    this.shortcuts = new KeyShortcuts({
+      window: this.tooltip.topWindow
+    });
+    this.shortcuts.on("Escape", (name, event) => {
+      if (!this.tooltip.isVisible()) {
+        return;
+      }
+      this.revert();
+      this.hide();
+      event.stopPropagation();
+      event.preventDefault();
     });
+    this.shortcuts.on("Return", (name, event) => {
+      if (!this.tooltip.isVisible()) {
+        return;
+      }
+      this.commit();
+      this.hide();
+      event.stopPropagation();
+      event.preventDefault();
+    });
+
+    // All target swatches are kept in a map, indexed by swatch DOM elements
+    this.swatches = new Map();
+
+    // When a swatch is clicked, and for as long as the tooltip is shown, the
+    // activeSwatch property will hold the reference to the swatch DOM element
+    // that was clicked
+    this.activeSwatch = null;
+
+    this._onSwatchClick = this._onSwatchClick.bind(this);
   }
 
-  // By default, swatch-based editor tooltips revert value change on <esc> and
-  // commit value change on <enter>
-  this.shortcuts = new KeyShortcuts({
-    window: this.tooltip.topWindow
-  });
-  this.shortcuts.on("Escape", (name, event) => {
-    if (!this.tooltip.isVisible()) {
-      return;
-    }
-    this.revert();
-    this.hide();
-    event.stopPropagation();
-    event.preventDefault();
-  });
-  this.shortcuts.on("Return", (name, event) => {
-    if (!this.tooltip.isVisible()) {
-      return;
-    }
-    this.commit();
-    this.hide();
-    event.stopPropagation();
-    event.preventDefault();
-  });
-
-  // All target swatches are kept in a map, indexed by swatch DOM elements
-  this.swatches = new Map();
-
-  // When a swatch is clicked, and for as long as the tooltip is shown, the
-  // 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 = {
-  /**
+ /**
    * Reports if the tooltip is currently shown
    *
    * @return {Boolean} True if the tooltip is displayed.
    */
-  isVisible: function () {
+  isVisible() {
     return this.tooltip.isVisible();
-  },
+  }
 
   /**
    * Reports if the tooltip is currently editing the targeted value
    *
    * @return {Boolean} True if the tooltip is editing.
    */
-  isEditing: function () {
+  isEditing() {
     return this.isVisible();
-  },
+  }
 
   /**
    * 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 () {
+  show() {
     let tooltipAnchor = this.useInline ?
       this.activeSwatch.closest(`.${INLINE_TOOLTIP_CLASS}`) :
       this.activeSwatch;
 
     if (tooltipAnchor) {
       let onShown = this.tooltip.once("shown");
       this.tooltip.show(tooltipAnchor, "topcenter bottomleft");
 
@@ -123,21 +124,21 @@ SwatchBasedEditorTooltip.prototype = {
           this.activeSwatch = null;
         }
       });
 
       return onShown;
     }
 
     return Promise.resolve();
-  },
+  }
 
-  hide: function () {
+  hide() {
     this.tooltip.hide();
-  },
+  }
 
   /**
    * Add a new swatch DOM element to the list of swatch elements this editor
    * tooltip knows about. That means from now on, clicking on that swatch will
    * toggle the editor.
    *
    * @param {node} swatchEl
    *        The element to add
@@ -146,17 +147,17 @@ SwatchBasedEditorTooltip.prototype = {
    *        value change, or revert a change, or commit a change.
    *        - onShow: will be called when one of the swatch tooltip is shown
    *        - onPreview: will be called when one of the sub-classes calls
    *        preview
    *        - onRevert: will be called when the user ESCapes out of the tooltip
    *        - onCommit: will be called when the user presses ENTER or clicks
    *        outside the tooltip.
    */
-  addSwatch: function (swatchEl, callbacks = {}) {
+  addSwatch(swatchEl, callbacks = {}) {
     if (!callbacks.onShow) {
       callbacks.onShow = function () {};
     }
     if (!callbacks.onPreview) {
       callbacks.onPreview = function () {};
     }
     if (!callbacks.onRevert) {
       callbacks.onRevert = function () {};
@@ -164,79 +165,79 @@ SwatchBasedEditorTooltip.prototype = {
     if (!callbacks.onCommit) {
       callbacks.onCommit = function () {};
     }
 
     this.swatches.set(swatchEl, {
       callbacks: callbacks
     });
     swatchEl.addEventListener("click", this._onSwatchClick);
-  },
+  }
 
-  removeSwatch: function (swatchEl) {
+  removeSwatch(swatchEl) {
     if (this.swatches.has(swatchEl)) {
       if (this.activeSwatch === swatchEl) {
         this.hide();
         this.activeSwatch = null;
       }
       swatchEl.removeEventListener("click", this._onSwatchClick);
       this.swatches.delete(swatchEl);
     }
-  },
+  }
 
-  _onSwatchClick: function (event) {
+  _onSwatchClick(event) {
     let swatch = this.swatches.get(event.target);
 
     if (event.shiftKey) {
       event.stopPropagation();
       return;
     }
     if (swatch) {
       this.activeSwatch = event.target;
       this.show();
       swatch.callbacks.onShow();
       event.stopPropagation();
     }
-  },
+  }
 
   /**
    * Not called by this parent class, needs to be taken care of by sub-classes
    */
-  preview: function (value) {
+  preview(value) {
     if (this.activeSwatch) {
       let swatch = this.swatches.get(this.activeSwatch);
       swatch.callbacks.onPreview(value);
     }
-  },
+  }
 
   /**
    * This parent class only calls this on <esc> keypress
    */
-  revert: function () {
+  revert() {
     if (this.activeSwatch) {
       this._reverted = true;
       let swatch = this.swatches.get(this.activeSwatch);
       this.tooltip.once("hidden", () => {
         swatch.callbacks.onRevert();
       });
     }
-  },
+  }
 
   /**
    * This parent class only calls this on <enter> keypress
    */
-  commit: function () {
+  commit() {
     if (this.activeSwatch) {
       let swatch = this.swatches.get(this.activeSwatch);
       swatch.callbacks.onCommit();
     }
-  },
+  }
 
-  destroy: function () {
+  destroy() {
     this.swatches.clear();
     this.activeSwatch = null;
     this.tooltip.off("keypress", this._onTooltipKeypress);
     this.tooltip.destroy();
     this.shortcuts.destroy();
   }
-};
+}
 
 module.exports = SwatchBasedEditorTooltip;
--- a/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
@@ -1,25 +1,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Services = require("Services");
-const {Task} = require("devtools/shared/task");
 const {colorUtils} = require("devtools/shared/css/color");
 const {ColorWidget} = require("devtools/client/shared/widgets/ColorWidget");
 const {Spectrum} = require("devtools/client/shared/widgets/Spectrum");
 const SwatchBasedEditorTooltip = require("devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip");
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper("devtools/client/locales/inspector.properties");
 
-const {extend} = require("devtools/shared/extend");
-
 const colorWidgetPref = "devtools.inspector.colorWidget.enabled";
 const NEW_COLOR_WIDGET = Services.prefs.getBoolPref(colorWidgetPref);
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 
 /**
  * The swatch color picker tooltip class is a specific class meant to be used
  * along with output-parser's generated color swatches.
  * It extends the parent SwatchBasedEditorTooltip class.
@@ -30,37 +27,36 @@ const XHTML_NS = "http://www.w3.org/1999
  *        The document to attach the SwatchColorPickerTooltip. This is either the toolbox
  *        document if the tooltip is a popup tooltip or the panel's document if it is an
  *        inline editor.
  * @param {InspectorPanel} inspector
  *        The inspector panel, needed for the eyedropper.
  * @param {Function} supportsCssColor4ColorFunction
  *        A function for checking the supporting of css-color-4 color function.
  */
-function SwatchColorPickerTooltip(document,
-                                  inspector,
-                                  {supportsCssColor4ColorFunction}) {
-  SwatchBasedEditorTooltip.call(this, document);
 
-  this.inspector = inspector;
+class SwatchColorPickerTooltip extends SwatchBasedEditorTooltip {
+  constructor(document, inspector, {supportsCssColor4ColorFunction}) {
+    super(document);
+    this.inspector = inspector;
 
-  // Creating a spectrum instance. this.spectrum will always be a promise that
-  // resolves to the spectrum instance
-  this.spectrum = this.setColorPickerContent([0, 0, 0, 1]);
-  this._onSpectrumColorChange = this._onSpectrumColorChange.bind(this);
-  this._openEyeDropper = this._openEyeDropper.bind(this);
-  this.cssColor4 = supportsCssColor4ColorFunction();
-}
+    // Creating a spectrum instance. this.spectrum will always be a promise that
+    // resolves to the spectrum instance
+    this.spectrum = this.setColorPickerContent([0, 0, 0, 1]);
+    this._onSpectrumColorChange = this._onSpectrumColorChange.bind(this);
+    this._openEyeDropper = this._openEyeDropper.bind(this);
+    this.cssColor4 = supportsCssColor4ColorFunction();
+  }
 
-SwatchColorPickerTooltip.prototype = extend(SwatchBasedEditorTooltip.prototype, {
   /**
    * Fill the tooltip with a new instance of the spectrum color picker widget
    * initialized with the given color, and return the instance of spectrum
    */
-  setColorPickerContent: function (color) {
+
+  setColorPickerContent(color) {
     let { doc } = this.tooltip;
 
     let container = doc.createElementNS(XHTML_NS, "div");
     container.id = "spectrum-tooltip";
 
     let widget;
     let node = doc.createElementNS(XHTML_NS, "div");
 
@@ -88,85 +84,85 @@ SwatchColorPickerTooltip.prototype = ext
 
     // Wait for the tooltip to be shown before calling widget.show
     // as it expect to be visible in order to compute DOM element sizes.
     this.tooltip.once("shown", () => {
       widget.show();
     });
 
     return widget;
-  },
+  }
 
   /**
    * Overriding the SwatchBasedEditorTooltip.show function to set spectrum's
    * color.
    */
-  show: Task.async(function* () {
+  async show() {
     // set contrast enabled for the spectrum
     let name = this.activeSwatch.dataset.propertyName;
 
     if (this.isContrastCompatible === undefined) {
       let target = this.inspector.target;
-      this.isContrastCompatible = yield target.actorHasMethod(
+      this.isContrastCompatible = await target.actorHasMethod(
         "domnode",
         "getClosestBackgroundColor"
       );
     }
 
     // only enable contrast if it is compatible and if the type of property is color.
     this.spectrum.contrastEnabled = (name === "color") && this.isContrastCompatible;
 
     // Call then parent class' show function
-    yield SwatchBasedEditorTooltip.prototype.show.call(this);
+    await super.show();
 
     // 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);
       this.spectrum.updateUI();
     }
 
     let eyeButton = this.tooltip.container.querySelector("#eyedropper-button");
-    let canShowEyeDropper = yield this.inspector.supportsEyeDropper();
+    let canShowEyeDropper = await this.inspector.supportsEyeDropper();
     if (canShowEyeDropper) {
       eyeButton.disabled = false;
       eyeButton.removeAttribute("title");
       eyeButton.addEventListener("click", this._openEyeDropper);
     } else {
       eyeButton.disabled = true;
       eyeButton.title = L10N.getStr("eyedropper.disabled.title");
     }
     this.emit("ready");
-  }),
+  }
 
-  _onSpectrumColorChange: function (event, rgba, cssColor) {
+  _onSpectrumColorChange(event, rgba, cssColor) {
     this._selectColor(cssColor);
-  },
+  }
 
-  _selectColor: function (color) {
+  _selectColor(color) {
     if (this.activeSwatch) {
       this.activeSwatch.style.backgroundColor = color;
       this.activeSwatch.parentNode.dataset.color = color;
 
       color = this._toDefaultType(color);
       this.currentSwatchColor.textContent = color;
       this.preview(color);
 
       if (this.eyedropperOpen) {
         this.commit();
       }
     }
-  },
+  }
 
-  _openEyeDropper: function () {
+  _openEyeDropper() {
     let {inspector, toolbox, telemetry} = this.inspector;
     telemetry.toolOpened("pickereyedropper");
 
     // cancelling picker(if it is already selected) on opening eye-dropper
     toolbox.highlighterUtils.cancelPicker();
 
     inspector.pickColorFromPage(toolbox, {copyOnSelect: false}).then(() => {
       this.eyedropperOpen = true;
@@ -181,45 +177,45 @@ SwatchColorPickerTooltip.prototype = ext
       toolbox.win.focus();
       this._selectColor(color);
       this._onEyeDropperDone();
     });
 
     inspector.once("color-pick-canceled", () => {
       this._onEyeDropperDone();
     });
-  },
+  }
 
-  _onEyeDropperDone: function () {
+  _onEyeDropperDone() {
     this.eyedropperOpen = false;
     this.activeSwatch = null;
-  },
+  }
 
-  _colorToRgba: function (color) {
+  _colorToRgba(color) {
     color = new colorUtils.CssColor(color, this.cssColor4);
     let rgba = color.getRGBATuple();
     return [rgba.r, rgba.g, rgba.b, rgba.a];
-  },
+  }
 
-  _toDefaultType: function (color) {
+  _toDefaultType(color) {
     let colorObj = new colorUtils.CssColor(color);
     colorObj.setAuthoredUnitFromColor(this._originalColor, this.cssColor4);
     return colorObj.toString();
-  },
+  }
 
   /**
    * Overriding the SwatchBasedEditorTooltip.isEditing function to consider the
    * eyedropper.
    */
-  isEditing: function () {
+  isEditing() {
     return this.tooltip.isVisible() || this.eyedropperOpen;
-  },
+  }
 
-  destroy: function () {
-    SwatchBasedEditorTooltip.prototype.destroy.call(this);
+  destroy() {
+    super.destroy();
     this.inspector = null;
     this.currentSwatchColor = null;
     this.spectrum.off("changed", this._onSpectrumColorChange);
     this.spectrum.destroy();
   }
-});
+}
 
 module.exports = SwatchColorPickerTooltip;
--- a/devtools/client/shared/widgets/tooltip/SwatchCubicBezierTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchCubicBezierTooltip.js
@@ -1,51 +1,50 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const defer = require("devtools/shared/defer");
-const {Task} = require("devtools/shared/task");
 const {CubicBezierWidget} = require("devtools/client/shared/widgets/CubicBezierWidget");
 const SwatchBasedEditorTooltip = require("devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip");
 
-const {extend} = require("devtools/shared/extend");
-
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 
 /**
  * The swatch cubic-bezier tooltip class is a specific class meant to be used
  * along with rule-view's generated cubic-bezier swatches.
  * It extends the parent SwatchBasedEditorTooltip class.
  * It just wraps a standard Tooltip and sets its content with an instance of a
  * CubicBezierWidget.
  *
  * @param {Document} document
  *        The document to attach the SwatchCubicBezierTooltip. This is either the toolbox
  *        document if the tooltip is a popup tooltip or the panel's document if it is an
  *        inline editor.
  */
-function SwatchCubicBezierTooltip(document) {
-  SwatchBasedEditorTooltip.call(this, document);
+
+class SwatchCubicBezierTooltip extends SwatchBasedEditorTooltip {
+  constructor(document) {
+    super(document);
 
-  // Creating a cubic-bezier instance.
-  // this.widget will always be a promise that resolves to the widget instance
-  this.widget = this.setCubicBezierContent([0, 0, 1, 1]);
-  this._onUpdate = this._onUpdate.bind(this);
-}
+    // Creating a cubic-bezier instance.
+    // this.widget will always be a promise that resolves to the widget instance
+    this.widget = this.setCubicBezierContent([0, 0, 1, 1]);
+    this._onUpdate = this._onUpdate.bind(this);
+  }
 
-SwatchCubicBezierTooltip.prototype = extend(SwatchBasedEditorTooltip.prototype, {
   /**
    * Fill the tooltip with a new instance of the cubic-bezier widget
    * initialized with the given value, and return a promise that resolves to
    * the instance of the widget
    */
-  setCubicBezierContent: function (bezier) {
+
+  setCubicBezierContent(bezier) {
     let { doc } = this.tooltip;
 
     let container = doc.createElementNS(XHTML_NS, "div");
     container.className = "cubic-bezier-container";
 
     this.tooltip.setContent(container, { width: 510, height: 370 });
 
     let def = defer();
@@ -53,49 +52,49 @@ SwatchCubicBezierTooltip.prototype = ext
     // Wait for the tooltip to be shown before calling instanciating the widget
     // as it expect its DOM elements to be visible.
     this.tooltip.once("shown", () => {
       let widget = new CubicBezierWidget(container, bezier);
       def.resolve(widget);
     });
 
     return def.promise;
-  },
+  }
 
   /**
    * Overriding the SwatchBasedEditorTooltip.show function to set the cubic
    * bezier curve in the widget
    */
-  show: Task.async(function* () {
+  async show() {
     // Call the parent class' show function
-    yield SwatchBasedEditorTooltip.prototype.show.call(this);
+    await super.show();
     // 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) {
+  _onUpdate(event, bezier) {
     if (!this.activeSwatch) {
       return;
     }
 
     this.currentBezierValue.textContent = bezier + "";
     this.preview(bezier + "");
-  },
+  }
 
-  destroy: function () {
-    SwatchBasedEditorTooltip.prototype.destroy.call(this);
+  destroy() {
+    super.destroy();
     this.currentBezierValue = null;
     this.widget.then(widget => {
       widget.off("updated", this._onUpdate);
       widget.destroy();
     });
   }
-});
+}
 
 module.exports = SwatchCubicBezierTooltip;
--- a/devtools/client/shared/widgets/tooltip/SwatchFilterTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchFilterTooltip.js
@@ -1,20 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const {Task} = require("devtools/shared/task");
 const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
 const SwatchBasedEditorTooltip = require("devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip");
 
-const {extend} = require("devtools/shared/extend");
-
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 
 /**
  * The swatch-based css filter tooltip class is a specific class meant to be
  * used along with rule-view's generated css filter swatches.
  * It extends the parent SwatchBasedEditorTooltip class.
  * It just wraps a standard Tooltip and sets its content with an instance of a
  * CSSFilterEditorWidget.
@@ -22,94 +19,95 @@ const XHTML_NS = "http://www.w3.org/1999
  * @param {Document} document
  *        The document to attach the SwatchFilterTooltip. This is either the toolbox
  *        document if the tooltip is a popup tooltip or the panel's document if it is an
  *        inline editor.
  * @param {function} cssIsValid
  *        A function to check that css declaration's name and values are valid together.
  *        This can be obtained from "shared/fronts/css-properties.js".
  */
-function SwatchFilterTooltip(document, cssIsValid) {
-  SwatchBasedEditorTooltip.call(this, document);
-  this._cssIsValid = cssIsValid;
+
+class SwatchFilterTooltip extends SwatchBasedEditorTooltip {
+  constructor(document, cssIsValid) {
+    super(document);
+    this._cssIsValid = cssIsValid;
 
-  // Creating a filter editor instance.
-  this.widget = this.setFilterContent("none");
-  this._onUpdate = this._onUpdate.bind(this);
-}
+    // Creating a filter editor instance.
+    this.widget = this.setFilterContent("none");
+    this._onUpdate = this._onUpdate.bind(this);
+  }
 
-SwatchFilterTooltip.prototype = extend(SwatchBasedEditorTooltip.prototype, {
   /**
    * Fill the tooltip with a new instance of the CSSFilterEditorWidget
    * widget initialized with the given filter value, and return a promise
    * that resolves to the instance of the widget when ready.
    */
-  setFilterContent: function (filter) {
+
+  setFilterContent(filter) {
     let { doc } = this.tooltip;
 
     let container = doc.createElementNS(XHTML_NS, "div");
     container.id = "filter-container";
 
     this.tooltip.setContent(container, { width: 510, height: 200 });
 
     return new CSSFilterEditorWidget(container, filter, this._cssIsValid);
-  },
+  }
 
-  show: Task.async(function* () {
+  async show() {
     // Call the parent class' show function
-    yield SwatchBasedEditorTooltip.prototype.show.call(this);
+    await super.show();
     // 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) {
+  _onUpdate(event, filters) {
     if (!this.activeSwatch) {
       return;
     }
 
     // Remove the old children and reparse the property value to
     // recompute them.
     while (this.currentFilterValue.firstChild) {
       this.currentFilterValue.firstChild.remove();
     }
     let node = this._parser.parseCssProperty("filter", filters, this._options);
     this.currentFilterValue.appendChild(node);
 
     this.preview();
-  },
+  }
 
-  destroy: function () {
-    SwatchBasedEditorTooltip.prototype.destroy.call(this);
+  destroy() {
+    super.destroy();
     this.currentFilterValue = null;
     this.widget.off("updated", this._onUpdate);
     this.widget.destroy();
-  },
+  }
 
   /**
    * Like SwatchBasedEditorTooltip.addSwatch, but accepts a parser object
    * to use when previewing the updated property value.
    *
    * @param {node} swatchEl
    *        @see SwatchBasedEditorTooltip.addSwatch
    * @param {object} callbacks
    *        @see SwatchBasedEditorTooltip.addSwatch
    * @param {object} parser
    *        A parser object; @see OutputParser object
    * @param {object} options
    *        options to pass to the output parser, with
    *          the option |filterSwatch| set.
    */
-  addSwatch: function (swatchEl, callbacks, parser, options) {
-    SwatchBasedEditorTooltip.prototype.addSwatch.call(this, swatchEl,
-                                                      callbacks);
+  addSwatch(swatchEl, callbacks, parser, options) {
+    super.addSwatch(swatchEl, callbacks);
     this._parser = parser;
     this._options = options;
   }
-});
+}
 
 module.exports = SwatchFilterTooltip;
--- a/devtools/client/shared/widgets/tooltip/Tooltip.js
+++ b/devtools/client/shared/widgets/tooltip/Tooltip.js
@@ -82,154 +82,155 @@ const POPUP_EVENTS = ["shown", "hidden",
  *
  * Fires these events:
  * - showing : just before the tooltip shows
  * - shown : when the tooltip is shown
  * - hiding : just before the tooltip closes
  * - hidden : when the tooltip gets hidden
  * - keypress : when any key gets pressed, with keyCode
  */
-function Tooltip(doc, {
+
+class Tooltip {
+  constructor(doc, {
   consumeOutsideClick = false,
   closeOnKeys = [ESCAPE_KEYCODE],
   noAutoFocus = true,
   closeOnEvents = [],
   } = {}) {
-  EventEmitter.decorate(this);
+    EventEmitter.decorate(this);
 
-  this.doc = doc;
-  this.consumeOutsideClick = consumeOutsideClick;
-  this.closeOnKeys = closeOnKeys;
-  this.noAutoFocus = noAutoFocus;
-  this.closeOnEvents = closeOnEvents;
+    this.defaultPosition = "before_start";
+    // px
+    this.defaultOffsetX = 0;
+    // px
+    this.defaultOffsetY = 0;
+    // px
 
-  this.panel = this._createPanel();
+    this.doc = doc;
+    this.consumeOutsideClick = consumeOutsideClick;
+    this.closeOnKeys = closeOnKeys;
+    this.noAutoFocus = noAutoFocus;
+    this.closeOnEvents = closeOnEvents;
 
-  // Create tooltip toggle helper and decorate the Tooltip instance with
-  // shortcut methods.
-  this._toggle = new TooltipToggle(this);
-  this.startTogglingOnHover = this._toggle.start.bind(this._toggle);
-  this.stopTogglingOnHover = this._toggle.stop.bind(this._toggle);
+    this.panel = this._createPanel();
+
+    // Create tooltip toggle helper and decorate the Tooltip instance with
+    // shortcut methods.
+    this._toggle = new TooltipToggle(this);
+    this.startTogglingOnHover = this._toggle.start.bind(this._toggle);
+    this.stopTogglingOnHover = this._toggle.stop.bind(this._toggle);
 
   // Emit show/hide events when the panel does.
-  for (let eventName of POPUP_EVENTS) {
-    this["_onPopup" + eventName] = (name => {
-      return e => {
-        if (e.target === this.panel) {
-          this.emit(name);
-        }
-      };
-    })(eventName);
-    this.panel.addEventListener("popup" + eventName,
-      this["_onPopup" + eventName]);
-  }
+    for (let eventName of POPUP_EVENTS) {
+      this["_onPopup" + eventName] = (name => {
+        return e => {
+          if (e.target === this.panel) {
+            this.emit(name);
+          }
+        };
+      })(eventName);
+      this.panel.addEventListener("popup" + eventName,
+        this["_onPopup" + eventName]);
+    }
 
   // Listen to keypress events to close the tooltip if configured to do so
-  let win = this.doc.querySelector("window");
-  this._onKeyPress = event => {
-    if (this.panel.hidden) {
-      return;
-    }
+    let win = this.doc.querySelector("window");
+    this._onKeyPress = event => {
+      if (this.panel.hidden) {
+        return;
+      }
 
-    this.emit("keypress", event.keyCode);
-    if (this.closeOnKeys.indexOf(event.keyCode) !== -1 &&
-        this.isShown()) {
-      event.stopPropagation();
-      this.hide();
-    }
-  };
-  win.addEventListener("keypress", this._onKeyPress);
+      this.emit("keypress", event.keyCode);
+      if (this.closeOnKeys.indexOf(event.keyCode) !== -1 &&
+          this.isShown()) {
+        event.stopPropagation();
+        this.hide();
+      }
+    };
+    win.addEventListener("keypress", this._onKeyPress);
 
   // Listen to custom emitters' events to close the tooltip
-  this.hide = this.hide.bind(this);
-  for (let {emitter, event, useCapture} of this.closeOnEvents) {
-    for (let add of ["addEventListener", "on"]) {
-      if (add in emitter) {
-        emitter[add](event, this.hide, useCapture);
-        break;
+    this.hide = this.hide.bind(this);
+    for (let {emitter, event, useCapture} of this.closeOnEvents) {
+      for (let add of ["addEventListener", "on"]) {
+        if (add in emitter) {
+          emitter[add](event, this.hide, useCapture);
+          break;
+        }
       }
     }
   }
-}
-
-Tooltip.prototype = {
-  defaultPosition: "before_start",
-  // px
-  defaultOffsetX: 0,
-  // px
-  defaultOffsetY: 0,
-  // px
 
   /**
    * Show the tooltip. It might be wise to append some content first if you
    * don't want the tooltip to be empty. You may access the content of the
    * tooltip by setting a XUL node to t.content.
    * @param {node} anchor
    *        Which node should the tooltip be shown on
    * @param {string} position [optional]
    *        Optional tooltip position. Defaults to before_start
    *        https://developer.mozilla.org/en-US/docs/XUL/PopupGuide/Positioning
    * @param {number} x, y [optional]
    *        The left and top offset coordinates, in pixels.
    */
-  show: function (anchor,
+  show(anchor,
     position = this.defaultPosition,
     x = this.defaultOffsetX,
     y = this.defaultOffsetY) {
     this.panel.hidden = false;
     this.panel.openPopup(anchor, position, x, y);
-  },
+  }
 
   /**
    * Hide the tooltip
    */
-  hide: function () {
+  hide() {
     this.panel.hidden = true;
     this.panel.hidePopup();
-  },
+  }
 
-  isShown: function () {
+  isShown() {
     return this.panel &&
            this.panel.state !== "closed" &&
            this.panel.state !== "hiding";
-  },
+  }
 
-  setSize: function (width, height) {
+  setSize(width, height) {
     this.panel.sizeTo(width, height);
-  },
+  }
 
   /**
    * Empty the tooltip's content
    */
-  empty: function () {
+  empty() {
     while (this.panel.hasChildNodes()) {
       this.panel.firstChild.remove();
     }
-  },
+  }
 
   /**
    * Gets this panel's visibility state.
    * @return boolean
    */
-  isHidden: function () {
+  isHidden() {
     return this.panel.state == "closed" || this.panel.state == "hiding";
-  },
+  }
 
   /**
    * Gets if this panel has any child nodes.
    * @return boolean
    */
-  isEmpty: function () {
+  isEmpty() {
     return !this.panel.hasChildNodes();
-  },
+  }
 
   /**
    * Get rid of references and event listeners
    */
-  destroy: function () {
+  destroy() {
     this.hide();
 
     for (let eventName of POPUP_EVENTS) {
       this.panel.removeEventListener("popup" + eventName,
         this["_onPopup" + eventName]);
     }
 
     let win = this.doc.querySelector("window");
@@ -247,26 +248,26 @@ Tooltip.prototype = {
     this.content = null;
 
     this._toggle.destroy();
 
     this.doc = null;
 
     this.panel.remove();
     this.panel = null;
-  },
+  }
 
   /**
    * Returns the outer container node (that includes the arrow etc.). Happens
    * to be identical to this.panel here, can be different element in other
    * Tooltip implementations.
    */
   get container() {
     return this.panel;
-  },
+  }
 
   /**
    * Set the content of this tooltip. Will first empty the tooltip and then
    * append the new content element.
    * Consider using one of the set<type>Content() functions instead.
    * @param {node} content
    *        A node that can be appended in the tooltip XUL element
    */
@@ -279,33 +280,33 @@ Tooltip.prototype = {
     this.panel.removeAttribute("clamped-dimensions");
     this.panel.removeAttribute("clamped-dimensions-no-min-height");
     this.panel.removeAttribute("clamped-dimensions-no-max-or-min-height");
     this.panel.removeAttribute("wide");
 
     if (content) {
       this.panel.appendChild(content);
     }
-  },
+  }
 
   get content() {
     return this.panel.firstChild;
-  },
+  }
 
   /**
    * Sets some text as the content of this tooltip.
    *
    * @param {array} messages
    *        A list of text messages.
    * @param {string} messagesClass [optional]
    *        A style class for the text messages.
    * @param {string} containerClass [optional]
    *        A style class for the text messages container.
    */
-  setTextContent: function (
+  setTextContent(
     {
       messages,
       messagesClass,
       containerClass
     },
     extraButtons = []) {
     messagesClass = messagesClass || "default-tooltip-simple-text-colors";
     containerClass = containerClass || "default-tooltip-simple-text-colors";
@@ -326,17 +327,17 @@ Tooltip.prototype = {
       let button = this.doc.createElement("button");
       button.className = className;
       button.setAttribute("label", label);
       button.addEventListener("command", command);
       vbox.appendChild(button);
     }
 
     this.content = vbox;
-  },
+  }
 
   /**
    * Load a document into an iframe, and set the iframe
    * to be the tooltip's content.
    *
    * Used by tooltips that want to load their interface
    * into an iframe from a URL.
    *
@@ -352,17 +353,17 @@ Tooltip.prototype = {
    *
    * This function creates an iframe, loads the specified document
    * into it, sets the tooltip's content to the iframe, and returns
    * a promise.
    *
    * When the document is loaded, the function gets the content window
    * and resolves the promise with the content window.
    */
-  setIFrameContent: function ({width, height}, url) {
+  setIFrameContent({width, height}, url) {
     let def = defer();
 
     // Create an iframe
     let iframe = this.doc.createElementNS(XHTML_NS, "iframe");
     iframe.setAttribute("transparent", true);
     iframe.setAttribute("width", width);
     iframe.setAttribute("height", height);
     iframe.setAttribute("flex", "1");
@@ -378,17 +379,17 @@ Tooltip.prototype = {
 
     // load the document from url into the iframe
     iframe.setAttribute("src", url);
 
     // Put the iframe in the tooltip
     this.content = iframe;
 
     return def.promise;
-  },
+  }
 
   /**
    * Create the tooltip panel
    */
   _createPanel() {
     let panel = this.doc.createElement("panel");
     panel.setAttribute("hidden", true);
     panel.setAttribute("ignorekeys", true);
@@ -400,11 +401,11 @@ Tooltip.prototype = {
     panel.setAttribute("type", "arrow");
     panel.setAttribute("level", "top");
 
     panel.setAttribute("class", "devtools-tooltip theme-tooltip-panel");
     this.doc.querySelector("window").appendChild(panel);
 
     return panel;
   }
-};
+}
 
 module.exports = Tooltip;