tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 25f6ed5dcb5535f39a21402dccec899d731b92de
parent a8c9dab64432c0494c803ccabd7b9cacef75adae
Author: Lorenz A <me@lorenzackermann.xyz>
Date:   Mon, 15 Dec 2025 10:33:24 +0000

Bug 2004258 - [devtools] Turn devtools/client/shared/widgets/CubicBezierWidget.js into an ES class. r=devtools-reviewers,nchevobbe

Differential Revision: https://phabricator.services.mozilla.com/D276360

Diffstat:
Mdevtools/client/shared/widgets/CubicBezierWidget.js | 360++++++++++++++++++++++++++++++++++++++++---------------------------------------
1 file changed, 181 insertions(+), 179 deletions(-)

diff --git a/devtools/client/shared/widgets/CubicBezierWidget.js b/devtools/client/shared/widgets/CubicBezierWidget.js @@ -39,42 +39,40 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml"; /** * CubicBezier data structure helper * Accepts an array of coordinates and exposes a few useful getters - * - * @param {Array} coordinates i.e. [.42, 0, .58, 1] */ -function CubicBezier(coordinates) { - if (!coordinates) { - throw new Error("No offsets were defined"); - } - - this.coordinates = coordinates.map(n => +n); - - for (let i = 4; i--; ) { - const xy = this.coordinates[i]; - if (isNaN(xy) || (!(i % 2) && (xy < 0 || xy > 1))) { - throw new Error(`Wrong coordinate at ${i}(${xy})`); +class CubicBezier { + /** + * @param {Array<number>} coordinates i.e. [.42, 0, .58, 1] + */ + constructor(coordinates) { + if (!coordinates) { + throw new Error("No offsets were defined"); } - } - this.coordinates.toString = function () { - return ( - this.map(n => { - return (Math.round(n * 100) / 100 + "").replace(/^0\./, "."); - }) + "" - ); - }; -} + this.coordinates = coordinates.map(n => +n); -exports.CubicBezier = CubicBezier; + for (let i = 4; i--; ) { + const xy = this.coordinates[i]; + if (isNaN(xy) || (!(i % 2) && (xy < 0 || xy > 1))) { + throw new Error(`Wrong coordinate at ${i}(${xy})`); + } + } -CubicBezier.prototype = { + this.coordinates.toString = function () { + return ( + this.map(n => { + return (Math.round(n * 100) / 100 + "").replace(/^0\./, "."); + }) + "" + ); + }; + } get P1() { return this.coordinates.slice(0, 2); - }, + } get P2() { return this.coordinates.slice(2); - }, + } toString() { // Check first if current coords are one of css predefined functions @@ -83,35 +81,36 @@ CubicBezier.prototype = { ); return predefName || "cubic-bezier(" + this.coordinates + ")"; - }, -}; + } +} + +exports.CubicBezier = CubicBezier; /** * Bezier curve canvas plotting class - * - * @param {DOMNode} canvas - * @param {CubicBezier} bezier - * @param {Array} padding Amount of horizontal,vertical padding around the graph */ -function BezierCanvas(canvas, bezier, padding) { - this.canvas = canvas; - this.bezier = bezier; - this.padding = getPadding(padding); - - // Convert to a cartesian coordinate system with axes from 0 to 1 - this.ctx = this.canvas.getContext("2d"); - const p = this.padding; - - this.ctx.scale( - canvas.width * (1 - p[1] - p[3]), - -canvas.height * (1 - p[0] - p[2]) - ); - this.ctx.translate(p[3] / (1 - p[1] - p[3]), -1 - p[0] / (1 - p[0] - p[2])); -} - -exports.BezierCanvas = BezierCanvas; +class BezierCanvas { + /** + * @param {HTMLCanvasElement} canvas + * @param {CubicBezier} bezier + * @param {Array} padding Amount of horizontal,vertical padding around the graph + */ + constructor(canvas, bezier, padding) { + this.canvas = canvas; + this.bezier = bezier; + this.padding = getPadding(padding); + + // Convert to a cartesian coordinate system with axes from 0 to 1 + this.ctx = this.canvas.getContext("2d"); + const p = this.padding; + + this.ctx.scale( + canvas.width * (1 - p[1] - p[3]), + -canvas.height * (1 - p[0] - p[2]) + ); + this.ctx.translate(p[3] / (1 - p[1] - p[3]), -1 - p[0] / (1 - p[0] - p[2])); + } -BezierCanvas.prototype = { /** * Get P1 and P2 current top/left offsets so they can be positioned * @@ -138,7 +137,7 @@ BezierCanvas.prototype = { "px", }, ]; - }, + } /** * Convert an element's left/top offsets into coordinates @@ -154,7 +153,7 @@ BezierCanvas.prototype = { (parseFloat(element.style.left) - p[3]) / (w + p[1] + p[3]), (h - parseFloat(element.style.top) - p[2]) / (h - p[0] - p[2]), ]; - }, + } /** * Draw the cubic bezier curve for the current coordinates @@ -222,80 +221,77 @@ BezierCanvas.prototype = { this.ctx.bezierCurveTo(xy[0], xy[1], xy[2], xy[3], 1, 1); this.ctx.stroke(); this.ctx.closePath(); - }, -}; + } +} + +exports.BezierCanvas = BezierCanvas; /** * Cubic-bezier widget. Uses the BezierCanvas class to draw the curve and * adds the control points and user interaction * - * @param {DOMNode} parent The container where the graph should be created - * @param {Array} coordinates Coordinates of the curve to be drawn - * * Emits "updated" events whenever the curve is changed. Along with the event is * sent a CubicBezier object */ -function CubicBezierWidget( - parent, - coordinates = PRESETS["ease-in"]["ease-in-sine"] -) { - EventEmitter.decorate(this); - - this.parent = parent; - const { curve, p1, p2 } = this._initMarkup(); - - this.curveBoundingBox = curve.getBoundingClientRect(); - this.curve = curve; - this.p1 = p1; - this.p2 = p2; - - // Create and plot the bezier curve - this.bezierCanvas = new BezierCanvas( - this.curve, - new CubicBezier(coordinates), - [0.3, 0] - ); - this.bezierCanvas.plot(); - - // Place the control points - const offsets = this.bezierCanvas.offsets; - this.p1.style.left = offsets[0].left; - this.p1.style.top = offsets[0].top; - this.p2.style.left = offsets[1].left; - this.p2.style.top = offsets[1].top; - - this._onPointMouseDown = this._onPointMouseDown.bind(this); - this._onPointKeyDown = this._onPointKeyDown.bind(this); - this._onCurveClick = this._onCurveClick.bind(this); - this._onNewCoordinates = this._onNewCoordinates.bind(this); - this.onPrefersReducedMotionChange = - this.onPrefersReducedMotionChange.bind(this); - - // Add preset preview menu - this.presets = new CubicBezierPresetWidget(parent); - - // Add the timing function previewer - // if prefers-reduced-motion is not set - this.reducedMotion = parent.ownerGlobal.matchMedia( - "(prefers-reduced-motion)" - ); - if (!this.reducedMotion.matches) { - this.timingPreview = new TimingFunctionPreviewWidget(parent); - } +class CubicBezierWidget extends EventEmitter { + /** + * @param {Element} parent The container where the graph should be created + * @param {Array<number>} coordinates Coordinates of the curve to be drawn + */ + constructor(parent, coordinates = PRESETS["ease-in"]["ease-in-sine"]) { + super(); + + this.parent = parent; + const { curve, p1, p2 } = this._initMarkup(); + + this.curveBoundingBox = curve.getBoundingClientRect(); + this.curve = curve; + this.p1 = p1; + this.p2 = p2; + + // Create and plot the bezier curve + this.bezierCanvas = new BezierCanvas( + this.curve, + new CubicBezier(coordinates), + [0.3, 0] + ); + this.bezierCanvas.plot(); - // add event listener to change prefers-reduced-motion - // of the timing function preview during runtime - this.reducedMotion.addEventListener( - "change", - this.onPrefersReducedMotionChange - ); + // Place the control points + const offsets = this.bezierCanvas.offsets; + this.p1.style.left = offsets[0].left; + this.p1.style.top = offsets[0].top; + this.p2.style.left = offsets[1].left; + this.p2.style.top = offsets[1].top; - this._initEvents(); -} + this._onPointMouseDown = this._onPointMouseDown.bind(this); + this._onPointKeyDown = this._onPointKeyDown.bind(this); + this._onCurveClick = this._onCurveClick.bind(this); + this._onNewCoordinates = this._onNewCoordinates.bind(this); + this.onPrefersReducedMotionChange = + this.onPrefersReducedMotionChange.bind(this); -exports.CubicBezierWidget = CubicBezierWidget; + // Add preset preview menu + this.presets = new CubicBezierPresetWidget(parent); + + // Add the timing function previewer + // if prefers-reduced-motion is not set + this.reducedMotion = parent.ownerGlobal.matchMedia( + "(prefers-reduced-motion)" + ); + if (!this.reducedMotion.matches) { + this.timingPreview = new TimingFunctionPreviewWidget(parent); + } + + // add event listener to change prefers-reduced-motion + // of the timing function preview during runtime + this.reducedMotion.addEventListener( + "change", + this.onPrefersReducedMotionChange + ); -CubicBezierWidget.prototype = { + this._initEvents(); + } _initMarkup() { const doc = this.parent.ownerDocument; @@ -345,7 +341,7 @@ CubicBezierWidget.prototype = { p2, curve, }; - }, + } onPrefersReducedMotionChange(event) { // if prefers-reduced-motion is enabled destroy timing function preview @@ -358,11 +354,11 @@ CubicBezierWidget.prototype = { } else if (!this.timingPreview) { this.timingPreview = new TimingFunctionPreviewWidget(this.parent); } - }, + } _removeMarkup() { this.parent.querySelector(".display-wrap").remove(); - }, + } _initEvents() { this.p1.addEventListener("mousedown", this._onPointMouseDown); @@ -374,7 +370,7 @@ CubicBezierWidget.prototype = { this.curve.addEventListener("click", this._onCurveClick); this.presets.on("new-coordinates", this._onNewCoordinates); - }, + } _removeEvents() { this.p1.removeEventListener("mousedown", this._onPointMouseDown); @@ -386,7 +382,7 @@ CubicBezierWidget.prototype = { this.curve.removeEventListener("click", this._onCurveClick); this.presets.off("new-coordinates", this._onNewCoordinates); - }, + } _onPointMouseDown(event) { // Updating the boundingbox in case it has changed @@ -419,7 +415,7 @@ CubicBezierWidget.prototype = { point.focus(); doc.onmousemove = doc.onmouseup = null; }; - }, + } _onPointKeyDown(event) { const point = event.target; @@ -450,7 +446,7 @@ CubicBezierWidget.prototype = { this._updateFromPoints(); } - }, + } _onCurveClick(event) { this.curveBoundingBox = this.curve.getBoundingClientRect(); @@ -479,11 +475,11 @@ CubicBezierWidget.prototype = { point.style.top = y + "px"; this._updateFromPoints(); - }, + } _onNewCoordinates(coordinates) { this.coordinates = coordinates; - }, + } /** * Get the current point coordinates and redraw the curve to match @@ -497,7 +493,7 @@ CubicBezierWidget.prototype = { this.presets.refreshMenu(coordinates); this._redraw(coordinates); - }, + } /** * Redraw the curve @@ -513,7 +509,7 @@ CubicBezierWidget.prototype = { if (this.timingPreview) { this.timingPreview.preview(this.bezierCanvas.bezier.toString()); } - }, + } /** * Set new coordinates for the control points and redraw the curve @@ -529,7 +525,7 @@ CubicBezierWidget.prototype = { this.p1.style.top = offsets[0].top; this.p2.style.left = offsets[1].left; this.p2.style.top = offsets[1].top; - }, + } /** * Set new coordinates for the control point and redraw the curve @@ -549,7 +545,7 @@ CubicBezierWidget.prototype = { this.presets.refreshMenu(coordinates); this.coordinates = coordinates; - }, + } destroy() { this._removeEvents(); @@ -569,41 +565,43 @@ CubicBezierWidget.prototype = { this.presets.destroy(); this.curve = this.p1 = this.p2 = null; - }, -}; + } +} + +exports.CubicBezierWidget = CubicBezierWidget; /** * CubicBezierPreset widget. * Builds a menu of presets from CubicBezierPresets * - * @param {DOMNode} parent The container where the preset panel should be - * created - * * Emits "new-coordinate" event along with the coordinates * whenever a preset is selected. */ -function CubicBezierPresetWidget(parent) { - this.parent = parent; +class CubicBezierPresetWidget extends EventEmitter { + /** + * @param {Element} parent The container where the preset panel should be + * created + */ + constructor(parent) { + super(); - const { presetPane, presets, categories } = this._initMarkup(); - this.presetPane = presetPane; - this.presets = presets; - this.categories = categories; + this.parent = parent; - this._activeCategory = null; - this._activePresetList = null; - this._activePreset = null; + const { presetPane, presets, categories } = this._initMarkup(); + this.presetPane = presetPane; + this.presets = presets; + this.categories = categories; - this._onCategoryClick = this._onCategoryClick.bind(this); - this._onPresetClick = this._onPresetClick.bind(this); + this._activeCategory = null; + this._activePresetList = null; + this._activePreset = null; - EventEmitter.decorate(this); - this._initEvents(); -} + this._onCategoryClick = this._onCategoryClick.bind(this); + this._onPresetClick = this._onPresetClick.bind(this); -exports.CubicBezierPresetWidget = CubicBezierPresetWidget; + this._initEvents(); + } -CubicBezierPresetWidget.prototype = { /* * Constructs a list of all preset categories and a list * of presets for each category. @@ -655,7 +653,7 @@ CubicBezierPresetWidget.prototype = { presets: allPresets, categories: allCategories, }; - }, + } _createCategory(categoryLabel) { const doc = this.parent.ownerDocument; @@ -669,11 +667,11 @@ CubicBezierPresetWidget.prototype = { category.setAttribute("title", categoryDisplayLabel); return category; - }, + } _normalizeCategoryLabel(categoryLabel) { return categoryLabel.replace("/-/g", " "); - }, + } _createPresetList(categoryLabel) { const doc = this.parent.ownerDocument; @@ -688,7 +686,7 @@ CubicBezierPresetWidget.prototype = { }); return presetList; - }, + } _createPreset(categoryLabel, presetLabel) { const doc = this.parent.ownerDocument; @@ -720,11 +718,11 @@ CubicBezierPresetWidget.prototype = { preset.setAttribute("title", presetDisplayLabel); return preset; - }, + } _normalizePresetLabel(categoryLabel, presetLabel) { return presetLabel.replace(categoryLabel + "-", "").replace("/-/g", " "); - }, + } _initEvents() { for (const category of this.categories) { @@ -734,7 +732,7 @@ CubicBezierPresetWidget.prototype = { for (const preset of this.presets) { preset.addEventListener("click", this._onPresetClick); } - }, + } _removeEvents() { for (const category of this.categories) { @@ -744,41 +742,41 @@ CubicBezierPresetWidget.prototype = { for (const preset of this.presets) { preset.removeEventListener("click", this._onPresetClick); } - }, + } _onPresetClick(event) { this.emit("new-coordinates", event.currentTarget.coordinates); this.activePreset = event.currentTarget; - }, + } _onCategoryClick(event) { this.activeCategory = event.target; - }, + } _setActivePresetList(presetListId) { const presetList = this.presetPane.querySelector("#" + presetListId); swapClassName("active-preset-list", this._activePresetList, presetList); this._activePresetList = presetList; - }, + } set activeCategory(category) { swapClassName("active-category", this._activeCategory, category); this._activeCategory = category; this._setActivePresetList("preset-category-" + category.id); - }, + } get activeCategory() { return this._activeCategory; - }, + } set activePreset(preset) { swapClassName("active-preset", this._activePreset, preset); this._activePreset = preset; - }, + } get activePreset() { return this._activePreset; - }, + } /** * Called by CubicBezierWidget onload and when @@ -816,29 +814,33 @@ CubicBezierPresetWidget.prototype = { this.activeCategory = category; this.activePreset = preset; - }, + } destroy() { this._removeEvents(); this.parent.querySelector(".preset-pane").remove(); - }, -}; + } +} + +exports.CubicBezierPresetWidget = CubicBezierPresetWidget; /** * The TimingFunctionPreviewWidget animates a dot on a scale with a given * timing-function * - * @param {DOMNode} parent The container where this widget should go */ -function TimingFunctionPreviewWidget(parent) { - this.previousValue = null; +class TimingFunctionPreviewWidget { + /** + * @param {Element} parent The container where this widget should go + */ + constructor(parent) { + this.previousValue = null; - this.parent = parent; - this._initMarkup(); -} + this.parent = parent; + this._initMarkup(); + } -TimingFunctionPreviewWidget.prototype = { - PREVIEW_DURATION: 1000, + PREVIEW_DURATION = 1000; _initMarkup() { const doc = this.parent.ownerDocument; @@ -855,13 +857,13 @@ TimingFunctionPreviewWidget.prototype = { container.appendChild(scale); this.parent.appendChild(container); - }, + } destroy() { this.dot.getAnimations().forEach(anim => anim.cancel()); this.parent.querySelector(".timing-function-preview").remove(); this.parent = this.dot = null; - }, + } /** * Preview a new timing function. The current preview will only be stopped if @@ -881,7 +883,7 @@ TimingFunctionPreviewWidget.prototype = { } this.previousValue = value; - }, + } /** * Re-start the preview animation from the beginning. @@ -934,8 +936,8 @@ TimingFunctionPreviewWidget.prototype = { iterations: Infinity, } ); - }, -}; + } +} // Helpers