Bug 1378851 - Use ES classes in devtools highlighters rather than SDK heritage module; r=sole
authorPatrick Brosset <pbrosset@mozilla.com>
Fri, 21 Jul 2017 13:00:04 +0200
changeset 418862 8c43cee08f5b295c499294bad4b677b20ee9fd39
parent 418861 2b78ed90d46333844e91a9debcee3381e4fe7cc4
child 418863 e75d2b5e5d29a09dd886e57643c9cbbdf4e8d8c6
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssole
bugs1378851
milestone56.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 1378851 - Use ES classes in devtools highlighters rather than SDK heritage module; r=sole MozReview-Commit-ID: 7ahFmbrMd8a
devtools/server/actors/highlighters/box-model.js
devtools/server/actors/highlighters/css-grid.js
devtools/server/actors/highlighters/css-transform.js
devtools/server/actors/highlighters/geometry-editor.js
--- a/devtools/server/actors/highlighters/box-model.js
+++ b/devtools/server/actors/highlighters/box-model.js
@@ -1,15 +1,14 @@
  /* 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 { extend } = require("sdk/core/heritage");
 const { AutoRefreshHighlighter } = require("./auto-refresh");
 const {
   CanvasFrameAnonymousContentHelper,
   createNode,
   createSVGNode,
   getBindingElementAndPseudo,
   hasPseudoClassLock,
   isNodeValid,
@@ -87,43 +86,41 @@ const PSEUDO_CLASSES = [":hover", ":acti
  *           <span class="box-model-infobar-pseudo-classes">:hover</span>
  *         </div>
  *       </div>
  *       <div class="box-model-infobar-arrow box-model-infobar-arrow-bottom"/>
  *     </div>
  *   </div>
  * </div>
  */
-function BoxModelHighlighter(highlighterEnv) {
-  AutoRefreshHighlighter.call(this, highlighterEnv);
-
-  this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
-    this._buildMarkup.bind(this));
+class BoxModelHighlighter extends AutoRefreshHighlighter {
+  constructor(highlighterEnv) {
+    super(highlighterEnv);
 
-  /**
-   * Optionally customize each region's fill color by adding an entry to the
-   * regionFill property: `highlighter.regionFill.margin = "red";
-   */
-  this.regionFill = {};
+    this.ID_CLASS_PREFIX = "box-model-";
+
+    this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
+      this._buildMarkup.bind(this));
 
-  this.onPageHide = this.onPageHide.bind(this);
-  this.onWillNavigate = this.onWillNavigate.bind(this);
-
-  this.highlighterEnv.on("will-navigate", this.onWillNavigate);
+    /**
+     * Optionally customize each region's fill color by adding an entry to the
+     * regionFill property: `highlighter.regionFill.margin = "red";
+     */
+    this.regionFill = {};
 
-  let { pageListenerTarget } = highlighterEnv;
-  pageListenerTarget.addEventListener("pagehide", this.onPageHide);
-}
+    this.onPageHide = this.onPageHide.bind(this);
+    this.onWillNavigate = this.onWillNavigate.bind(this);
+
+    this.highlighterEnv.on("will-navigate", this.onWillNavigate);
 
-BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
-  typeName: "BoxModelHighlighter",
+    let { pageListenerTarget } = highlighterEnv;
+    pageListenerTarget.addEventListener("pagehide", this.onPageHide);
+  }
 
-  ID_CLASS_PREFIX: "box-model-",
-
-  _buildMarkup: function () {
+  _buildMarkup() {
     let doc = this.win.document;
 
     let highlighterContainer = doc.createElement("div");
     highlighterContainer.className = "highlighter-container box-model";
 
     // Build the root wrapper, used to adapt to the page zoom.
     let rootWrapper = createNode(this.win, {
       parent: highlighterContainer,
@@ -252,86 +249,86 @@ BoxModelHighlighter.prototype = extend(A
       attributes: {
         "class": "infobar-dimensions",
         "id": "infobar-dimensions"
       },
       prefix: this.ID_CLASS_PREFIX
     });
 
     return highlighterContainer;
-  },
+  }
 
   /**
    * Destroy the nodes. Remove listeners.
    */
-  destroy: function () {
+  destroy() {
     this.highlighterEnv.off("will-navigate", this.onWillNavigate);
 
     let { pageListenerTarget } = this.highlighterEnv;
     if (pageListenerTarget) {
       pageListenerTarget.removeEventListener("pagehide", this.onPageHide);
     }
 
     this.markup.destroy();
     AutoRefreshHighlighter.prototype.destroy.call(this);
-  },
+  }
 
-  getElement: function (id) {
+  getElement(id) {
     return this.markup.getElement(this.ID_CLASS_PREFIX + id);
-  },
+  }
 
   /**
    * Override the AutoRefreshHighlighter's _isNodeValid method to also return true for
    * text nodes since these can also be highlighted.
    * @param {DOMNode} node
    * @return {Boolean}
    */
-  _isNodeValid: function (node) {
+  _isNodeValid(node) {
     return node && (isNodeValid(node) || isNodeValid(node, nodeConstants.TEXT_NODE));
-  },
+  }
 
   /**
    * Show the highlighter on a given node
    */
-  _show: function () {
+  _show() {
     if (BOX_MODEL_REGIONS.indexOf(this.options.region) == -1) {
       this.options.region = "content";
     }
 
     let shown = this._update();
     this._trackMutations();
     this.emit("ready");
     return shown;
-  },
+  }
 
   /**
    * Track the current node markup mutations so that the node info bar can be
    * updated to reflects the node's attributes
    */
-  _trackMutations: function () {
+  _trackMutations() {
     if (isNodeValid(this.currentNode)) {
       let win = this.currentNode.ownerGlobal;
       this.currentNodeObserver = new win.MutationObserver(this.update);
       this.currentNodeObserver.observe(this.currentNode, {attributes: true});
     }
-  },
+  }
 
-  _untrackMutations: function () {
+  _untrackMutations() {
     if (isNodeValid(this.currentNode) && this.currentNodeObserver) {
       this.currentNodeObserver.disconnect();
       this.currentNodeObserver = null;
     }
-  },
+  }
 
   /**
    * Update the highlighter on the current highlighted node (the one that was
    * passed as an argument to show(node)).
    * Should be called whenever node size or attributes change
    */
-  _update: function () {
+  _update() {
     let shown = false;
     setIgnoreLayoutChanges(true);
 
     if (this._updateBoxModel()) {
       // Show the infobar only if configured to do so and the node is an element or a text
       // node.
       if (!this.options.hideInfoBar && (
           this.currentNode.nodeType === this.currentNode.ELEMENT_NODE ||
@@ -345,75 +342,75 @@ BoxModelHighlighter.prototype = extend(A
     } else {
       // Nothing to highlight (0px rectangle like a <script> tag for instance)
       this._hide();
     }
 
     setIgnoreLayoutChanges(false, this.highlighterEnv.window.document.documentElement);
 
     return shown;
-  },
+  }
 
-  _scrollUpdate: function () {
+  _scrollUpdate() {
     this._moveInfobar();
-  },
+  }
 
   /**
    * Hide the highlighter, the outline and the infobar.
    */
-  _hide: function () {
+  _hide() {
     setIgnoreLayoutChanges(true);
 
     this._untrackMutations();
     this._hideBoxModel();
     this._hideInfobar();
 
     setIgnoreLayoutChanges(false, this.highlighterEnv.window.document.documentElement);
-  },
+  }
 
   /**
    * Hide the infobar
    */
-  _hideInfobar: function () {
+  _hideInfobar() {
     this.getElement("infobar-container").setAttribute("hidden", "true");
-  },
+  }
 
   /**
    * Show the infobar
    */
-  _showInfobar: function () {
+  _showInfobar() {
     this.getElement("infobar-container").removeAttribute("hidden");
     this._updateInfobar();
-  },
+  }
 
   /**
    * Hide the box model
    */
-  _hideBoxModel: function () {
+  _hideBoxModel() {
     this.getElement("elements").setAttribute("hidden", "true");
-  },
+  }
 
   /**
    * Show the box model
    */
-  _showBoxModel: function () {
+  _showBoxModel() {
     this.getElement("elements").removeAttribute("hidden");
-  },
+  }
 
   /**
    * Calculate an outer quad based on the quads returned by getAdjustedQuads.
    * The BoxModelHighlighter may highlight more than one boxes, so in this case
    * create a new quad that "contains" all of these quads.
    * This is useful to position the guides and infobar.
    * This may happen if the BoxModelHighlighter is used to highlight an inline
    * element that spans line breaks.
    * @param {String} region The box-model region to get the outer quad for.
    * @return {Object} A quad-like object {p1,p2,p3,p4,bounds}
    */
-  _getOuterQuad: function (region) {
+  _getOuterQuad(region) {
     let quads = this.currentQuads[region];
     if (!quads.length) {
       return null;
     }
 
     let quad = {
       p1: {x: Infinity, y: Infinity},
       p2: {x: -Infinity, y: Infinity},
@@ -447,25 +444,25 @@ BoxModelHighlighter.prototype = extend(A
       quad.bounds.right = Math.max(quad.bounds.right, q.bounds.right);
     }
     quad.bounds.x = quad.bounds.left;
     quad.bounds.y = quad.bounds.top;
     quad.bounds.width = quad.bounds.right - quad.bounds.left;
     quad.bounds.height = quad.bounds.bottom - quad.bounds.top;
 
     return quad;
-  },
+  }
 
   /**
    * Update the box model as per the current node.
    *
    * @return {boolean}
    *         True if the current node has a box model to be highlighted
    */
-  _updateBoxModel: function () {
+  _updateBoxModel() {
     let options = this.options;
     options.region = options.region || "content";
 
     if (!this._nodeNeedsHighlighting()) {
       this._hideBoxModel();
       return false;
     }
 
@@ -511,19 +508,19 @@ BoxModelHighlighter.prototype = extend(A
       }
     }
 
     // Un-zoom the root wrapper if the page was zoomed.
     let rootId = this.ID_CLASS_PREFIX + "elements";
     this.markup.scaleRootElement(this.currentNode, rootId);
 
     return true;
-  },
+  }
 
-  _getBoxPathCoordinates: function (boxQuad, nextBoxQuad) {
+  _getBoxPathCoordinates(boxQuad, nextBoxQuad) {
     let {p1, p2, p3, p4} = boxQuad;
 
     let path;
     if (!nextBoxQuad || !this.options.onlyRegionArea) {
       // If this is the content box (inner-most box) or if we're not being asked
       // to highlight only region areas, then draw a simple rectangle.
       path = "M" + p1.x + "," + p1.y + " " +
              "L" + p2.x + "," + p2.y + " " +
@@ -540,30 +537,30 @@ BoxModelHighlighter.prototype = extend(A
              "L" + np1.x + "," + np1.y + " " +
              "L" + np4.x + "," + np4.y + " " +
              "L" + np3.x + "," + np3.y + " " +
              "L" + np2.x + "," + np2.y + " " +
              "L" + np1.x + "," + np1.y;
     }
 
     return path;
-  },
+  }
 
   /**
    * Can the current node be highlighted? Does it have quads.
    * @return {Boolean}
    */
-  _nodeNeedsHighlighting: function () {
+  _nodeNeedsHighlighting() {
     return this.currentQuads.margin.length ||
            this.currentQuads.border.length ||
            this.currentQuads.padding.length ||
            this.currentQuads.content.length;
-  },
+  }
 
-  _getOuterBounds: function () {
+  _getOuterBounds() {
     for (let region of ["margin", "border", "padding", "content"]) {
       let quad = this._getOuterQuad(region);
 
       if (!quad) {
         // Invisible element such as a script tag.
         break;
       }
 
@@ -579,24 +576,24 @@ BoxModelHighlighter.prototype = extend(A
       height: 0,
       left: 0,
       right: 0,
       top: 0,
       width: 0,
       x: 0,
       y: 0
     };
-  },
+  }
 
   /**
    * We only want to show guides for horizontal and vertical edges as this helps
    * to line them up. This method finds these edges and displays a guide there.
    * @param {String} region The region around which the guides should be shown.
    */
-  _showGuides: function (region) {
+  _showGuides(region) {
     let {p1, p2, p3, p4} = this._getOuterQuad(region);
 
     let allX = [p1.x, p2.x, p3.x, p4.x].sort((a, b) => a - b);
     let allY = [p1.y, p2.y, p3.y, p4.y].sort((a, b) => a - b);
     let toShowX = [];
     let toShowY = [];
 
     for (let arr of [allX, allY]) {
@@ -614,34 +611,34 @@ BoxModelHighlighter.prototype = extend(A
       }
     }
 
     // Move guide into place or hide it if no valid co-ordinate was found.
     this._updateGuide("top", Math.round(toShowY[0]));
     this._updateGuide("right", Math.round(toShowX[1]) - 1);
     this._updateGuide("bottom", Math.round(toShowY[1] - 1));
     this._updateGuide("left", Math.round(toShowX[0]));
-  },
+  }
 
-  _hideGuides: function () {
+  _hideGuides() {
     for (let side of BOX_MODEL_SIDES) {
       this.getElement("guide-" + side).setAttribute("hidden", "true");
     }
-  },
+  }
 
   /**
    * Move a guide to the appropriate position and display it. If no point is
    * passed then the guide is hidden.
    *
    * @param  {String} side
    *         The guide to update
    * @param  {Integer} point
    *         x or y co-ordinate. If this is undefined we hide the guide.
    */
-  _updateGuide: function (side, point = -1) {
+  _updateGuide(side, point = -1) {
     let guide = this.getElement("guide-" + side);
 
     if (point <= 0) {
       guide.setAttribute("hidden", "true");
       return false;
     }
 
     if (side === "top" || side === "bottom") {
@@ -654,22 +651,22 @@ BoxModelHighlighter.prototype = extend(A
       guide.setAttribute("y1", "0");
       guide.setAttribute("x2", point + "");
       guide.setAttribute("y2", "100%");
     }
 
     guide.removeAttribute("hidden");
 
     return true;
-  },
+  }
 
   /**
    * Update node information (displayName#id.class)
    */
-  _updateInfobar: function () {
+  _updateInfobar() {
     if (!this.currentNode) {
       return;
     }
 
     let {bindingElement: node, pseudo} =
         getBindingElementAndPseudo(this.currentNode);
 
     // Update the tag, id, classes, pseudo-classes and dimensions
@@ -698,44 +695,45 @@ BoxModelHighlighter.prototype = extend(A
 
     this.getElement("infobar-tagname").setTextContent(displayName);
     this.getElement("infobar-id").setTextContent(id);
     this.getElement("infobar-classes").setTextContent(classList);
     this.getElement("infobar-pseudo-classes").setTextContent(pseudos);
     this.getElement("infobar-dimensions").setTextContent(dim);
 
     this._moveInfobar();
-  },
+  }
 
-  _getPseudoClasses: function (node) {
+  _getPseudoClasses(node) {
     if (node.nodeType !== nodeConstants.ELEMENT_NODE) {
       // hasPseudoClassLock can only be used on Elements.
       return [];
     }
 
     return PSEUDO_CLASSES.filter(pseudo => hasPseudoClassLock(node, pseudo));
-  },
+  }
 
   /**
    * Move the Infobar to the right place in the highlighter.
    */
-  _moveInfobar: function () {
+  _moveInfobar() {
     let bounds = this._getOuterBounds();
     let container = this.getElement("infobar-container");
 
     moveInfobar(container, bounds, this.win);
-  },
+  }
 
-  onPageHide: function ({ target }) {
+  onPageHide({ target }) {
     // If a pagehide event is triggered for current window's highlighter, hide the
     // highlighter.
     if (target.defaultView === this.win) {
       this.hide();
     }
-  },
+  }
 
-  onWillNavigate: function ({ isTopLevel }) {
+  onWillNavigate({ isTopLevel }) {
     if (isTopLevel) {
       this.hide();
     }
   }
-});
+}
+
 exports.BoxModelHighlighter = BoxModelHighlighter;
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -1,16 +1,15 @@
 /* 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 { extend } = require("sdk/core/heritage");
 const { AutoRefreshHighlighter } = require("./auto-refresh");
 const {
   CanvasFrameAnonymousContentHelper,
   createNode,
   createSVGNode,
   moveInfobar,
 } = require("./utils/markup");
 const {
@@ -339,47 +338,45 @@ function drawRoundedRect(ctx, x, y, widt
  *       <div class="css-grid-infobar-text">
  *         <span class="css-grid-line-infobar-number">Grid Line Number</span>
  *         <span class="css-grid-line-infobar-names">Grid Line Names></span>
  *       </div>
  *     </div>
  *   </div>
  * </div>
  */
-function CssGridHighlighter(highlighterEnv) {
-  AutoRefreshHighlighter.call(this, highlighterEnv);
+class CssGridHighlighter extends AutoRefreshHighlighter {
+  constructor(highlighterEnv) {
+    super(highlighterEnv);
 
-  this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
-    this._buildMarkup.bind(this));
+    this.ID_CLASS_PREFIX = "css-grid-";
 
-  this.onNavigate = this.onNavigate.bind(this);
-  this.onPageHide = this.onPageHide.bind(this);
-  this.onWillNavigate = this.onWillNavigate.bind(this);
+    this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
+      this._buildMarkup.bind(this));
 
-  this.highlighterEnv.on("navigate", this.onNavigate);
-  this.highlighterEnv.on("will-navigate", this.onWillNavigate);
-
-  let { pageListenerTarget } = highlighterEnv;
-  pageListenerTarget.addEventListener("pagehide", this.onPageHide);
+    this.onNavigate = this.onNavigate.bind(this);
+    this.onPageHide = this.onPageHide.bind(this);
+    this.onWillNavigate = this.onWillNavigate.bind(this);
 
-  // Initialize the <canvas> position to the top left corner of the page
-  this._canvasPosition = {
-    x: 0,
-    y: 0
-  };
+    this.highlighterEnv.on("navigate", this.onNavigate);
+    this.highlighterEnv.on("will-navigate", this.onWillNavigate);
+
+    let { pageListenerTarget } = highlighterEnv;
+    pageListenerTarget.addEventListener("pagehide", this.onPageHide);
 
-  // Calling `calculateCanvasPosition` anyway since the highlighter could be initialized
-  // on a page that has scrolled already.
-  this.calculateCanvasPosition();
-}
+    // Initialize the <canvas> position to the top left corner of the page
+    this._canvasPosition = {
+      x: 0,
+      y: 0
+    };
 
-CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
-  typeName: "CssGridHighlighter",
-
-  ID_CLASS_PREFIX: "css-grid-",
+    // Calling `calculateCanvasPosition` anyway since the highlighter could be initialized
+    // on a page that has scrolled already.
+    this.calculateCanvasPosition();
+  }
 
   _buildMarkup() {
     let container = createNode(this.win, {
       attributes: {
         "class": "highlighter-container"
       }
     });
 
@@ -584,50 +581,50 @@ CssGridHighlighter.prototype = extend(Au
       attributes: {
         "class": "line-infobar-names",
         "id": "line-infobar-names"
       },
       prefix: this.ID_CLASS_PREFIX
     });
 
     return container;
-  },
+  }
 
   destroy() {
     let { highlighterEnv } = this;
     highlighterEnv.off("navigate", this.onNavigate);
     highlighterEnv.off("will-navigate", this.onWillNavigate);
 
     let { pageListenerTarget } = highlighterEnv;
     if (pageListenerTarget) {
       pageListenerTarget.removeEventListener("pagehide", this.onPageHide);
     }
 
     this.markup.destroy();
 
     // Clear the pattern cache to avoid dead object exceptions (Bug 1342051).
     this._clearCache();
     AutoRefreshHighlighter.prototype.destroy.call(this);
-  },
+  }
 
   getElement(id) {
     return this.markup.getElement(this.ID_CLASS_PREFIX + id);
-  },
+  }
 
   get ctx() {
     return this.canvas.getCanvasContext("2d");
-  },
+  }
 
   get canvas() {
     return this.getElement("canvas");
-  },
+  }
 
   get color() {
     return this.options.color || DEFAULT_GRID_COLOR;
-  },
+  }
 
   /**
    * Gets the grid gap pattern used to render the gap regions based on the device
    * pixel ratio given.
    *
    * @param {Number} devicePixelRatio
    *         The device pixel ratio we want the pattern for.
    * @param  {Object} dimension
@@ -673,156 +670,156 @@ CssGridHighlighter.prototype = extend(Au
     ctx.restore();
 
     let pattern = ctx.createPattern(canvas, "repeat");
 
     gridPatternMap.set(dimension, pattern);
     gCachedGridPattern.set(devicePixelRatio, gridPatternMap);
 
     return pattern;
-  },
+  }
 
   /**
    * Called when the page navigates. Used to clear the cached gap patterns and avoid
    * using DeadWrapper objects as gap patterns the next time.
    */
   onNavigate() {
     this._clearCache();
-  },
+  }
 
-  onPageHide: function ({ target }) {
+  onPageHide({ target }) {
     // If a page hide event is triggered for current window's highlighter, hide the
     // highlighter.
     if (target.defaultView === this.win) {
       this.hide();
     }
-  },
+  }
 
   onWillNavigate({ isTopLevel }) {
     if (isTopLevel) {
       this.hide();
     }
-  },
+  }
 
   _show() {
     if (Services.prefs.getBoolPref(CSS_GRID_ENABLED_PREF) && !this.isGrid()) {
       this.hide();
       return false;
     }
 
     // The grid pattern cache should be cleared in case the color changed.
     this._clearCache();
 
     // Hide the canvas, grid element highlights and infobar.
     this._hide();
 
     return this._update();
-  },
+  }
 
   _clearCache() {
     gCachedGridPattern.clear();
-  },
+  }
 
   /**
    * Shows the grid area highlight for the given area name.
    *
    * @param  {String} areaName
    *         Grid area name.
    */
   showGridArea(areaName) {
     this.renderGridArea(areaName);
-  },
+  }
 
   /**
    * Shows all the grid area highlights for the current grid.
    */
   showAllGridAreas() {
     this.renderGridArea();
-  },
+  }
 
   /**
    * Clear the grid area highlights.
    */
   clearGridAreas() {
     let areas = this.getElement("areas");
     areas.setAttribute("d", "");
-  },
+  }
 
   /**
    * Shows the grid cell highlight for the given grid cell options.
    *
    * @param  {Number} options.gridFragmentIndex
    *         Index of the grid fragment to render the grid cell highlight.
    * @param  {Number} options.rowNumber
    *         Row number of the grid cell to highlight.
    * @param  {Number} options.columnNumber
    *         Column number of the grid cell to highlight.
    */
   showGridCell({ gridFragmentIndex, rowNumber, columnNumber }) {
     this.renderGridCell(gridFragmentIndex, rowNumber, columnNumber);
-  },
+  }
 
   /**
    * Shows the grid line highlight for the given grid line options.
    *
    * @param  {Number} options.gridFragmentIndex
    *         Index of the grid fragment to render the grid line highlight.
    * @param  {Number} options.lineNumber
    *         Line number of the grid line to highlight.
    * @param  {String} options.type
    *         The dimension type of the grid line.
    */
   showGridLineNames({ gridFragmentIndex, lineNumber, type }) {
     this.renderGridLineNames(gridFragmentIndex, lineNumber, type);
-  },
+  }
 
   /**
    * Clear the grid cell highlights.
    */
   clearGridCell() {
     let cells = this.getElement("cells");
     cells.setAttribute("d", "");
-  },
+  }
 
   /**
    * Checks if the current node has a CSS Grid layout.
    *
    * @return  {Boolean} true if the current node has a CSS grid layout, false otherwise.
    */
   isGrid() {
     return this.currentNode.getGridFragments().length > 0;
-  },
+  }
 
   /**
    * Is a given grid fragment valid? i.e. does it actually have tracks? In some cases, we
    * may have a fragment that defines column tracks but doesn't have any rows (or vice
    * versa). In which case we do not want to draw anything for that fragment.
    *
    * @param {Object} fragment
    * @return {Boolean}
    */
   isValidFragment(fragment) {
     return fragment.cols.tracks.length && fragment.rows.tracks.length;
-  },
+  }
 
   /**
    * The AutoRefreshHighlighter's _hasMoved method returns true only if the
    * element's quads have changed. Override it so it also returns true if the
    * element's grid has changed (which can happen when you change the
    * grid-template-* CSS properties with the highlighter displayed).
    */
   _hasMoved() {
     let hasMoved = AutoRefreshHighlighter.prototype._hasMoved.call(this);
 
     let oldGridData = stringifyGridFragments(this.gridData);
     this.gridData = this.currentNode.getGridFragments();
     let newGridData = stringifyGridFragments(this.gridData);
 
     return hasMoved || oldGridData !== newGridData;
-  },
+  }
 
   /**
    * Update the highlighter on the current highlighted node (the one that was
    * passed as an argument to show(node)).
    * Should be called whenever node's geometry or grid changes.
    */
   _update() {
     setIgnoreLayoutChanges(true);
@@ -878,17 +875,17 @@ CssGridHighlighter.prototype = extend(Au
     this._showGrid();
     this._showGridElements();
 
     root.setAttribute("style",
       `position:absolute; width:${width}px;height:${height}px; overflow:hidden`);
 
     setIgnoreLayoutChanges(false, this.highlighterEnv.document.documentElement);
     return true;
-  },
+  }
 
   /**
    * Update the grid information displayed in the grid area info bar.
    *
    * @param  {GridArea} area
    *         The grid area object.
    * @param  {Object} bounds
    *          A DOMRect-like object represent the grid area rectangle.
@@ -902,17 +899,17 @@ CssGridHighlighter.prototype = extend(Au
     this.getElement("area-infobar-name").setTextContent(area.name);
     this.getElement("area-infobar-dimensions").setTextContent(dim);
 
     let container = this.getElement("area-infobar-container");
     moveInfobar(container, bounds, this.win, {
       position: "bottom",
       hideIfOffscreen: true
     });
-  },
+  }
 
   /**
    * Update the grid information displayed in the grid cell info bar.
    *
    * @param  {Number} rowNumber
    *         The grid cell's row number.
    * @param  {Number} columnNumber
    *         The grid cell's column number.
@@ -930,17 +927,17 @@ CssGridHighlighter.prototype = extend(Au
     this.getElement("cell-infobar-position").setTextContent(position);
     this.getElement("cell-infobar-dimensions").setTextContent(dim);
 
     let container = this.getElement("cell-infobar-container");
     moveInfobar(container, bounds, this.win, {
       position: "top",
       hideIfOffscreen: true
     });
-  },
+  }
 
   /**
    * Update the grid information displayed in the grid line info bar.
    *
    * @param  {String} gridLineNames
    *         Comma-separated string of names for the grid line.
    * @param  {Number} gridLineNumber
    *         The grid line number.
@@ -951,29 +948,29 @@ CssGridHighlighter.prototype = extend(Au
    */
   _updateGridLineInfobar(gridLineNames, gridLineNumber, x, y) {
     this.getElement("line-infobar-number").setTextContent(gridLineNumber);
     this.getElement("line-infobar-names").setTextContent(gridLineNames);
 
     let container = this.getElement("line-infobar-container");
     moveInfobar(container,
       getBoundsFromPoints([{x, y}, {x, y}, {x, y}, {x, y}]), this.win);
-  },
+  }
 
   /**
    * The <canvas>'s position needs to be updated if the page scrolls too much, in order
    * to give the illusion that it always covers the viewport.
    */
   _scrollUpdate() {
     let hasPositionChanged = this.calculateCanvasPosition();
 
     if (hasPositionChanged) {
       this._update();
     }
-  },
+  }
 
   /**
    * This method is responsible to do the math that updates the <canvas>'s position,
    * in accordance with the page's scroll, document's size, canvas size, and
    * viewport's size.
    * It's called when a page's scroll is detected.
    *
    * @return {Boolean} `true` if the <canvas> position was updated, `false` otherwise.
@@ -1023,34 +1020,34 @@ CssGridHighlighter.prototype = extend(Au
       this._canvasPosition.x = Math.min(leftThreshold, rightBoundary);
       hasUpdated = true;
     } else if (x > leftBoundary && x > leftThreshold) {
       this._canvasPosition.x = Math.max(rightThreshold, leftBoundary);
       hasUpdated = true;
     }
 
     return hasUpdated;
-  },
+  }
 
   /**
    * Updates the <canvas> element's style in accordance with the current window's
    * devicePixelRatio, and the position calculated in `calculateCanvasPosition`; it also
    * clears the drawing context.
    */
   updateCanvasElement() {
     let size = CANVAS_SIZE / this.win.devicePixelRatio;
     let { x, y } = this._canvasPosition;
 
     // Resize the canvas taking the dpr into account so as to have crisp lines, and
     // translating it to give the perception that it always covers the viewport.
     this.canvas.setAttribute("style",
       `width:${size}px;height:${size}px; transform: translate(${x}px, ${y}px);`);
 
     this.ctx.clearRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);
-  },
+  }
 
   /**
    * Updates the current matrices for both canvas drawing and SVG, taking in account the
    * following transformations, in this order:
    *   1. The scale given by the display pixel ratio.
    *   2. The translation to the top left corner of the element.
    *   3. The scale given by the current zoom.
    *   4. The translation given by the top and left padding of the element.
@@ -1084,33 +1081,33 @@ CssGridHighlighter.prototype = extend(Au
       m = multiply(m, nodeMatrix);
       this.hasNodeTransformations = true;
     }
 
     // Finally, we translate the origin based on the node's padding and border values.
     m = multiply(m, translate(paddingLeft + borderLeft, paddingTop + borderTop));
 
     this.currentMatrix = m;
-  },
+  }
 
   getFirstRowLinePos(fragment) {
     return fragment.rows.lines[0].start;
-  },
+  }
 
   getLastRowLinePos(fragment) {
     return fragment.rows.lines[fragment.rows.lines.length - 1].start;
-  },
+  }
 
   getFirstColLinePos(fragment) {
     return fragment.cols.lines[0].start;
-  },
+  }
 
   getLastColLinePos(fragment) {
     return fragment.cols.lines[fragment.cols.lines.length - 1].start;
-  },
+  }
 
   /**
    * Get the GridLine index of the last edge of the explicit grid for a grid dimension.
    *
    * @param  {GridTracks} tracks
    *         The grid track of a given grid dimension.
    * @return {Number} index of the last edge of the explicit grid for a grid dimension.
    */
@@ -1119,17 +1116,17 @@ CssGridHighlighter.prototype = extend(Au
 
     // Traverse the grid track backwards until we find an explicit track.
     while (trackIndex >= 0 && tracks[trackIndex].type != "explicit") {
       trackIndex--;
     }
 
     // The grid line index is the grid track index + 1.
     return trackIndex + 1;
-  },
+  }
 
   renderFragment(fragment) {
     if (!this.isValidFragment(fragment)) {
       return;
     }
 
     this.renderLines(fragment.cols, COLUMNS, "left", "top", "height",
                      this.getFirstRowLinePos(fragment),
@@ -1144,17 +1141,17 @@ CssGridHighlighter.prototype = extend(Au
 
     // Line numbers are rendered in a 2nd step to avoid overlapping with existing lines.
     if (this.options.showGridLineNumbers) {
       this.renderLineNumbers(fragment.cols, COLUMNS, "left", "top",
                        this.getFirstRowLinePos(fragment));
       this.renderLineNumbers(fragment.rows, ROWS, "top", "left",
                        this.getFirstColLinePos(fragment));
     }
-  },
+  }
 
   /**
    * Renders the grid area overlay on the css grid highlighter canvas.
    */
   renderGridAreaOverlay() {
     let padding = 1;
 
     for (let i = 0; i < this.gridData.length; i++) {
@@ -1191,17 +1188,17 @@ CssGridHighlighter.prototype = extend(Au
                         areaColStartLinePos, areaColEnd.start,
                         ROWS, "areaEdge");
 
         this.renderGridAreaName(fragment, area);
       }
     }
 
     this.ctx.restore();
-  },
+  }
 
   /**
    * Render grid area name on the containing grid area cell.
    *
    * @param  {Object} fragment
    *         The grid fragment of the grid container.
    * @param  {Object} area
    *         The area overlay to render on the CSS highlighter canvas.
@@ -1265,17 +1262,17 @@ CssGridHighlighter.prototype = extend(Au
         drawRoundedRect(this.ctx, rectXPos, rectYPos, boxWidth, boxHeight, radius);
 
         this.ctx.fillStyle = this.color;
         this.ctx.fillText(area.name, x, y + padding);
       }
     }
 
     this.ctx.restore();
-  },
+  }
 
   /**
    * Render the grid lines given the grid dimension information of the
    * column or row lines.
    *
    * @param  {GridDimension} gridDimension
    *         Column or row grid dimension object.
    * @param  {Object} quad.bounds
@@ -1317,17 +1314,17 @@ CssGridHighlighter.prototype = extend(Au
       // Render a second line to illustrate the gutter for non-zero breadth.
       if (line.breadth > 0) {
         this.renderGridGap(linePos, lineStartPos, lineEndPos, line.breadth,
                            dimensionType);
         this.renderLine(linePos + line.breadth, lineStartPos, lineEndPos, dimensionType,
                         gridDimension.tracks[i].type);
       }
     }
-  },
+  }
 
   /**
    * Render the grid lines given the grid dimension information of the
    * column or row lines.
    *
    * see @param for renderLines.
    */
   renderLineNumbers(gridDimension, dimensionType, mainSide, crossSide,
@@ -1348,17 +1345,17 @@ CssGridHighlighter.prototype = extend(Au
       // For such lines the API returns always 0 as line's number.
       if (line.number === 0) {
         continue;
       }
 
       this.renderGridLineNumber(line.number, linePos, lineStartPos, line.breadth,
         dimensionType);
     }
-  },
+  }
 
   /**
    * Render the grid line on the css grid highlighter canvas.
    *
    * @param  {Number} linePos
    *         The line position along the x-axis for a column grid line and
    *         y-axis for a row grid line.
    * @param  {Number} startPos
@@ -1407,17 +1404,17 @@ CssGridHighlighter.prototype = extend(Au
     if (GRID_LINES_PROPERTIES[lineType].lineWidth) {
       this.ctx.lineWidth = GRID_LINES_PROPERTIES[lineType].lineWidth * devicePixelRatio;
     } else {
       this.ctx.lineWidth = lineWidth;
     }
 
     this.ctx.stroke();
     this.ctx.restore();
-  },
+  }
 
   /**
    * Render the grid line number on the css grid highlighter canvas.
    *
    * @param  {Number} lineNumber
    *         The grid line number.
    * @param  {Number} linePos
    *         The line position along the x-axis for a column grid line and
@@ -1492,17 +1489,17 @@ CssGridHighlighter.prototype = extend(Au
     let radius = 2 * displayPixelRatio;
     drawRoundedRect(this.ctx, x, y, boxWidth, boxHeight, radius);
 
     // Write the line number inside of the rectangle.
     this.ctx.fillStyle = "black";
     this.ctx.fillText(lineNumber, x + padding, y + textHeight + padding);
 
     this.ctx.restore();
-  },
+  }
 
   /**
    * Render the grid gap area on the css grid highlighter canvas.
    *
    * @param  {Number} linePos
    *         The line position along the x-axis for a column grid line and
    *         y-axis for a row grid line.
    * @param  {Number} startPos
@@ -1546,17 +1543,17 @@ CssGridHighlighter.prototype = extend(Au
         endPos = this._winDimensions.width;
         startPos = -endPos;
       }
       drawRect(this.ctx, startPos, linePos, endPos, linePos + breadth,
         this.currentMatrix);
     }
     this.ctx.fill();
     this.ctx.restore();
-  },
+  }
 
   /**
    * Render the grid area highlight for the given area name or for all the grid areas.
    *
    * @param  {String} areaName
    *         Name of the grid area to be highlighted. If no area name is provided, all
    *         the grid areas should be highlighted.
    */
@@ -1606,17 +1603,17 @@ CssGridHighlighter.prototype = extend(Au
           this._showGridAreaInfoBar();
           this._updateGridAreaInfobar(area, bounds);
         }
       }
     }
 
     let areas = this.getElement("areas");
     areas.setAttribute("d", paths.join(" "));
-  },
+  }
 
   /**
    * Render the grid cell highlight for the given grid fragment index, row and column
    * number.
    *
    * @param  {Number} gridFragmentIndex
    *         Index of the grid fragment to render the grid cell highlight.
    * @param  {Number} rowNumber
@@ -1661,17 +1658,17 @@ CssGridHighlighter.prototype = extend(Au
       y: Math.round(point.y / displayPixelRatio)
     })));
 
     let cells = this.getElement("cells");
     cells.setAttribute("d", getPathDescriptionFromPoints(svgPoints));
 
     this._showGridCellInfoBar();
     this._updateGridCellInfobar(rowNumber, columnNumber, bounds);
-  },
+  }
 
   /**
    * Render the grid line name highlight for the given grid fragment index, lineNumber,
    * and dimensionType.
    *
    * @param  {Number} gridFragmentIndex
    *         Index of the grid fragment to render the grid line highlight.
    * @param  {Number} lineNumber
@@ -1710,66 +1707,65 @@ CssGridHighlighter.prototype = extend(Au
       : colXPosition.start + (bounds.left / currentZoom);
 
     let y = dimensionType === ROWS
       ? linePos.start + (bounds.top / currentZoom)
       : rowYPosition.start + (bounds.top / currentZoom);
 
     this._showGridLineInfoBar();
     this._updateGridLineInfobar(names.join(", "), lineNumber, x, y);
-  },
+  }
 
   /**
    * Hide the highlighter, the canvas and the infobars.
    */
   _hide() {
     setIgnoreLayoutChanges(true);
     this._hideGrid();
     this._hideGridElements();
     this._hideGridAreaInfoBar();
     this._hideGridCellInfoBar();
     this._hideGridLineInfoBar();
     setIgnoreLayoutChanges(false, this.highlighterEnv.document.documentElement);
-  },
+  }
 
   _hideGrid() {
     this.getElement("canvas").setAttribute("hidden", "true");
-  },
+  }
 
   _showGrid() {
     this.getElement("canvas").removeAttribute("hidden");
-  },
+  }
 
   _hideGridElements() {
     this.getElement("elements").setAttribute("hidden", "true");
-  },
+  }
 
   _showGridElements() {
     this.getElement("elements").removeAttribute("hidden");
-  },
+  }
 
   _hideGridAreaInfoBar() {
     this.getElement("area-infobar-container").setAttribute("hidden", "true");
-  },
+  }
 
   _showGridAreaInfoBar() {
     this.getElement("area-infobar-container").removeAttribute("hidden");
-  },
+  }
 
   _hideGridCellInfoBar() {
     this.getElement("cell-infobar-container").setAttribute("hidden", "true");
-  },
+  }
 
   _showGridCellInfoBar() {
     this.getElement("cell-infobar-container").removeAttribute("hidden");
-  },
+  }
 
   _hideGridLineInfoBar() {
     this.getElement("line-infobar-container").setAttribute("hidden", "true");
-  },
+  }
 
   _showGridLineInfoBar() {
     this.getElement("line-infobar-container").removeAttribute("hidden");
-  },
-
-});
+  }
+}
 
 exports.CssGridHighlighter = CssGridHighlighter;
--- a/devtools/server/actors/highlighters/css-transform.js
+++ b/devtools/server/actors/highlighters/css-transform.js
@@ -1,15 +1,14 @@
 /* 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 { extend } = require("sdk/core/heritage");
 const { AutoRefreshHighlighter } = require("./auto-refresh");
 const {
   CanvasFrameAnonymousContentHelper, getComputedStyle,
   createSVGNode, createNode } = require("./utils/markup");
 const { setIgnoreLayoutChanges,
   getNodeBounds } = require("devtools/shared/layout/utils");
 
 // The minimum distance a line should be before it has an arrow marker-end
@@ -17,29 +16,27 @@ const ARROW_LINE_MIN_DISTANCE = 10;
 
 var MARKER_COUNTER = 1;
 
 /**
  * The CssTransformHighlighter is the class that draws an outline around a
  * transformed element and an outline around where it would be if untransformed
  * as well as arrows connecting the 2 outlines' corners.
  */
-function CssTransformHighlighter(highlighterEnv) {
-  AutoRefreshHighlighter.call(this, highlighterEnv);
+class CssTransformHighlighter extends AutoRefreshHighlighter {
+  constructor(highlighterEnv) {
+    super(highlighterEnv);
 
-  this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
-    this._buildMarkup.bind(this));
-}
+    this.ID_CLASS_PREFIX = "css-transform-";
 
-CssTransformHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
-  typeName: "CssTransformHighlighter",
+    this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
+      this._buildMarkup.bind(this));
+  }
 
-  ID_CLASS_PREFIX: "css-transform-",
-
-  _buildMarkup: function () {
+  _buildMarkup() {
     let container = createNode(this.win, {
       attributes: {
         "class": "highlighter-container"
       }
     });
 
     // The root wrapper is used to unzoom the highlighter when needed.
     let rootWrapper = createNode(this.win, {
@@ -125,79 +122,79 @@ CssTransformHighlighter.prototype = exte
           "class": "line",
           "marker-end": "url(#" + this.markerId + ")"
         },
         prefix: this.ID_CLASS_PREFIX
       });
     }
 
     return container;
-  },
+  }
 
   /**
    * Destroy the nodes. Remove listeners.
    */
-  destroy: function () {
+  destroy() {
     AutoRefreshHighlighter.prototype.destroy.call(this);
     this.markup.destroy();
-  },
+  }
 
-  getElement: function (id) {
+  getElement(id) {
     return this.markup.getElement(this.ID_CLASS_PREFIX + id);
-  },
+  }
 
   /**
    * Show the highlighter on a given node
    */
-  _show: function () {
+  _show() {
     if (!this._isTransformed(this.currentNode)) {
       this.hide();
       return false;
     }
 
     return this._update();
-  },
+  }
 
   /**
    * Checks if the supplied node is transformed and not inline
    */
-  _isTransformed: function (node) {
+  _isTransformed(node) {
     let style = getComputedStyle(node);
     return style && (style.transform !== "none" && style.display !== "inline");
-  },
+  }
 
-  _setPolygonPoints: function (quad, id) {
+  _setPolygonPoints(quad, id) {
     let points = [];
     for (let point of ["p1", "p2", "p3", "p4"]) {
       points.push(quad[point].x + "," + quad[point].y);
     }
     this.getElement(id).setAttribute("points", points.join(" "));
-  },
+  }
 
-  _setLinePoints: function (p1, p2, id) {
+  _setLinePoints(p1, p2, id) {
     let line = this.getElement(id);
     line.setAttribute("x1", p1.x);
     line.setAttribute("y1", p1.y);
     line.setAttribute("x2", p2.x);
     line.setAttribute("y2", p2.y);
 
     let dist = Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
     if (dist < ARROW_LINE_MIN_DISTANCE) {
       line.removeAttribute("marker-end");
     } else {
       line.setAttribute("marker-end", "url(#" + this.markerId + ")");
     }
-  },
+  }
 
   /**
    * Update the highlighter on the current highlighted node (the one that was
    * passed as an argument to show(node)).
    * Should be called whenever node size or attributes change
    */
-  _update: function () {
+  _update() {
     setIgnoreLayoutChanges(true);
 
     // Getting the points for the transformed shape
     let quads = this.currentQuads.border;
     if (!quads.length ||
         quads[0].bounds.width <= 0 || quads[0].bounds.height <= 0) {
       this._hideShapes();
       return false;
@@ -216,28 +213,29 @@ CssTransformHighlighter.prototype = exte
 
     // Adapt to the current zoom
     this.markup.scaleRootElement(this.currentNode, this.ID_CLASS_PREFIX + "root");
 
     this._showShapes();
 
     setIgnoreLayoutChanges(false, this.highlighterEnv.window.document.documentElement);
     return true;
-  },
+  }
 
   /**
    * Hide the highlighter, the outline and the infobar.
    */
-  _hide: function () {
+  _hide() {
     setIgnoreLayoutChanges(true);
     this._hideShapes();
     setIgnoreLayoutChanges(false, this.highlighterEnv.window.document.documentElement);
-  },
+  }
 
-  _hideShapes: function () {
+  _hideShapes() {
     this.getElement("elements").setAttribute("hidden", "true");
-  },
+  }
 
-  _showShapes: function () {
+  _showShapes() {
     this.getElement("elements").removeAttribute("hidden");
   }
-});
+}
+
 exports.CssTransformHighlighter = CssTransformHighlighter;
--- a/devtools/server/actors/highlighters/geometry-editor.js
+++ b/devtools/server/actors/highlighters/geometry-editor.js
@@ -1,15 +1,14 @@
 /* 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 { extend } = require("sdk/core/heritage");
 const { AutoRefreshHighlighter } = require("./auto-refresh");
 const { CanvasFrameAnonymousContentHelper, getCSSStyleRules, getComputedStyle,
         createSVGNode, createNode } = require("./utils/markup");
 const { setIgnoreLayoutChanges, getAdjustedQuads } = require("devtools/shared/layout/utils");
 
 const GEOMETRY_LABEL_SIZE = 6;
 
 // List of all DOM Events subscribed directly to the document from the
@@ -197,50 +196,48 @@ exports.getDefinedGeometryProperties = g
  * The highlighter displays lines and labels for each of the defined properties
  * in and around the element (relative to the offset parent when one exists).
  * The highlighter also highlights the element itself and its offset parent if
  * there is one.
  *
  * Note that the class name contains the word Editor because the aim is for the
  * handles to be draggable in content to make the geometry editable.
  */
-function GeometryEditorHighlighter(highlighterEnv) {
-  AutoRefreshHighlighter.call(this, highlighterEnv);
+class GeometryEditorHighlighter extends AutoRefreshHighlighter {
+  constructor(highlighterEnv) {
+    super(highlighterEnv);
+
+    this.ID_CLASS_PREFIX = "geometry-editor-";
 
-  // The list of element geometry properties that can be set.
-  this.definedProperties = new Map();
+    // The list of element geometry properties that can be set.
+    this.definedProperties = new Map();
 
-  this.markup = new CanvasFrameAnonymousContentHelper(highlighterEnv,
-    this._buildMarkup.bind(this));
+    this.markup = new CanvasFrameAnonymousContentHelper(highlighterEnv,
+      this._buildMarkup.bind(this));
 
-  let { pageListenerTarget } = this.highlighterEnv;
+    let { pageListenerTarget } = this.highlighterEnv;
 
-  // Register the geometry editor instance to all events we're interested in.
-  DOM_EVENTS.forEach(type => pageListenerTarget.addEventListener(type, this));
+    // Register the geometry editor instance to all events we're interested in.
+    DOM_EVENTS.forEach(type => pageListenerTarget.addEventListener(type, this));
+
+    // Register the mousedown event for each Geometry Editor's handler.
+    // Those events are automatically removed when the markup is destroyed.
+    let onMouseDown = this.handleEvent.bind(this);
 
-  // Register the mousedown event for each Geometry Editor's handler.
-  // Those events are automatically removed when the markup is destroyed.
-  let onMouseDown = this.handleEvent.bind(this);
+    for (let side of GeoProp.SIDES) {
+      this.getElement("handler-" + side)
+        .addEventListener("mousedown", onMouseDown);
+    }
 
-  for (let side of GeoProp.SIDES) {
-    this.getElement("handler-" + side)
-      .addEventListener("mousedown", onMouseDown);
+    this.onWillNavigate = this.onWillNavigate.bind(this);
+
+    this.highlighterEnv.on("will-navigate", this.onWillNavigate);
   }
 
-  this.onWillNavigate = this.onWillNavigate.bind(this);
-
-  this.highlighterEnv.on("will-navigate", this.onWillNavigate);
-}
-
-GeometryEditorHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
-  typeName: "GeometryEditorHighlighter",
-
-  ID_CLASS_PREFIX: "geometry-editor-",
-
-  _buildMarkup: function () {
+  _buildMarkup() {
     let container = createNode(this.win, {
       attributes: {"class": "highlighter-container"}
     });
 
     let root = createNode(this.win, {
       parent: container,
       attributes: {
         "id": "root",
@@ -356,19 +353,19 @@ GeometryEditorHighlighter.prototype = ex
           "x": GeoProp.isHorizontal(name) ? "30" : "35",
           "y": "10"
         },
         prefix: this.ID_CLASS_PREFIX
       });
     }
 
     return container;
-  },
+  }
 
-  destroy: function () {
+  destroy() {
     // Avoiding exceptions if `destroy` is called multiple times; and / or the
     // highlighter environment was already destroyed.
     if (!this.highlighterEnv) {
       return;
     }
 
     let { pageListenerTarget } = this.highlighterEnv;
 
@@ -378,19 +375,19 @@ GeometryEditorHighlighter.prototype = ex
     }
 
     AutoRefreshHighlighter.prototype.destroy.call(this);
 
     this.markup.destroy();
     this.definedProperties.clear();
     this.definedProperties = null;
     this.offsetParent = null;
-  },
+  }
 
-  handleEvent: function (event, id) {
+  handleEvent(event, id) {
     // No event handling if the highlighter is hidden
     if (this.getElement("root").hasAttribute("hidden")) {
       return;
     }
 
     const { target, type, pageX, pageY } = event;
 
     switch (type) {
@@ -471,23 +468,23 @@ GeometryEditorHighlighter.prototype = ex
         // it will override the inline style too. To ensure Geometry Editor
         // will always update the element, we have to add `!important` as
         // well.
         this.currentNode.style.setProperty(
           side, (value + delta) + unit, "important");
 
         break;
     }
-  },
+  }
 
-  getElement: function (id) {
+  getElement(id) {
     return this.markup.getElement(this.ID_CLASS_PREFIX + id);
-  },
+  }
 
-  _show: function () {
+  _show() {
     this.computedStyle = getComputedStyle(this.currentNode);
     let pos = this.computedStyle.position;
     // XXX: sticky positioning is ignored for now. To be implemented next.
     if (pos === "sticky") {
       this.hide();
       return false;
     }
 
@@ -495,19 +492,19 @@ GeometryEditorHighlighter.prototype = ex
     if (!hasUpdated) {
       this.hide();
       return false;
     }
 
     this.getElement("root").removeAttribute("hidden");
 
     return true;
-  },
+  }
 
-  _update: function () {
+  _update() {
     // At each update, the position or/and size may have changed, so get the
     // list of defined properties, and re-position the arrows and highlighters.
     this.definedProperties = getDefinedGeometryProperties(this.currentNode);
 
     if (!this.definedProperties.size) {
       console.warn("The element does not have editable geometry properties");
       return false;
     }
@@ -520,31 +517,31 @@ GeometryEditorHighlighter.prototype = ex
     this.updateArrows();
 
     // Avoid zooming the arrows when content is zoomed.
     let node = this.currentNode;
     this.markup.scaleRootElement(node, this.ID_CLASS_PREFIX + "root");
 
     setIgnoreLayoutChanges(false, this.highlighterEnv.document.documentElement);
     return true;
-  },
+  }
 
   /**
    * Update the offset parent rectangle.
    * There are 3 different cases covered here:
    * - the node is absolutely/fixed positioned, and an offsetParent is defined
    *   (i.e. it's not just positioned in the viewport): the offsetParent node
    *   is highlighted (i.e. the rectangle is shown),
    * - the node is relatively positioned: the rectangle is shown where the node
    *   would originally have been (because that's where the relative positioning
    *   is calculated from),
    * - the node has no offset parent at all: the offsetParent rectangle is
    *   hidden.
    */
-  updateOffsetParent: function () {
+  updateOffsetParent() {
     // Get the offsetParent, if any.
     this.offsetParent = getOffsetParent(this.currentNode);
     // And the offsetParent quads.
     this.parentQuads = getAdjustedQuads(
         this.win, this.offsetParent.element, "padding");
 
     let el = this.getElement("offset-parent");
 
@@ -575,51 +572,51 @@ GeometryEditorHighlighter.prototype = ex
       }
     }
 
     if (isHighlighted) {
       el.removeAttribute("hidden");
     } else {
       el.setAttribute("hidden", "true");
     }
-  },
+  }
 
-  updateCurrentNode: function () {
+  updateCurrentNode() {
     let box = this.getElement("current-node");
     let {p1, p2, p3, p4} = this.currentQuads.margin[0];
     let attr = p1.x + "," + p1.y + " " +
                p2.x + "," + p2.y + " " +
                p3.x + "," + p3.y + " " +
                p4.x + "," + p4.y;
     box.setAttribute("points", attr);
     box.removeAttribute("hidden");
-  },
+  }
 
-  _hide: function () {
+  _hide() {
     setIgnoreLayoutChanges(true);
 
     this.getElement("root").setAttribute("hidden", "true");
     this.getElement("current-node").setAttribute("hidden", "true");
     this.getElement("offset-parent").setAttribute("hidden", "true");
     this.hideArrows();
 
     this.definedProperties.clear();
 
     setIgnoreLayoutChanges(false, this.highlighterEnv.document.documentElement);
-  },
+  }
 
-  hideArrows: function () {
+  hideArrows() {
     for (let side of GeoProp.SIDES) {
       this.getElement("arrow-" + side).setAttribute("hidden", "true");
       this.getElement("label-" + side).setAttribute("hidden", "true");
       this.getElement("handler-" + side).setAttribute("hidden", "true");
     }
-  },
+  }
 
-  updateArrows: function () {
+  updateArrows() {
     this.hideArrows();
 
     // Position arrows always end at the node's margin box.
     let marginBox = this.currentQuads.margin[0].bounds;
 
     // Position the side arrows which need to be visible.
     // Arrows always start at the offsetParent edge, and end at the middle
     // position of the node's margin edge.
@@ -666,19 +663,19 @@ GeometryEditorHighlighter.prototype = ex
       let mainAxisStartPos = getSideArrowStartPos(side);
       let mainAxisEndPos = marginBox[side];
       let crossAxisPos = marginBox[GeoProp.crossAxisStart(side)] +
                          marginBox[GeoProp.crossAxisSize(side)] / 2;
 
       this.updateArrow(side, mainAxisStartPos, mainAxisEndPos, crossAxisPos,
                        sideProp.cssRule.style.getPropertyValue(side));
     }
-  },
+  }
 
-  updateArrow: function (side, mainStart, mainEnd, crossPos, labelValue) {
+  updateArrow(side, mainStart, mainEnd, crossPos, labelValue) {
     let arrowEl = this.getElement("arrow-" + side);
     let labelEl = this.getElement("label-" + side);
     let labelTextEl = this.getElement("label-text-" + side);
     let handlerEl = this.getElement("handler-" + side);
 
     // Position the arrow <line>.
     arrowEl.setAttribute(GeoProp.axis(side) + "1", mainStart);
     arrowEl.setAttribute(GeoProp.crossAxis(side) + "1", crossPos);
@@ -704,17 +701,18 @@ GeometryEditorHighlighter.prototype = ex
       }
     }
     let labelCross = crossPos;
     labelEl.setAttribute("transform", GeoProp.isHorizontal(side)
                          ? "translate(" + labelMain + " " + labelCross + ")"
                          : "translate(" + labelCross + " " + labelMain + ")");
     labelEl.removeAttribute("hidden");
     labelTextEl.setTextContent(labelValue);
-  },
+  }
 
   onWillNavigate({ isTopLevel }) {
     if (isTopLevel) {
       this.hide();
     }
-  },
-});
+  }
+}
+
 exports.GeometryEditorHighlighter = GeometryEditorHighlighter;