From 71dd7d586e50e0a250a8fa80fced2b2710a219e6 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Thu, 21 Apr 2022 07:50:57 +0300 Subject: [PATCH 01/14] welcome `class` --- .eslintrc.json | 1 + package-lock.json | 38 ++++++++------------------------------ package.json | 2 +- 3 files changed, 10 insertions(+), 31 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index f3d848c6348..ae3f66ec064 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,6 +4,7 @@ }, "globals": { "Promise": true, + "class": true, "define": true, "eventjs": true, "exports": true, diff --git a/package-lock.json b/package-lock.json index a27329f1b92..834fba44006 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "pixelmatch": "^4.0.2", "qunit": "^2.17.2", "testem": "^3.2.0", - "uglify-js": "^3.3.28" + "uglify-js": "^3.15.4" }, "engines": { "node": ">=14.0.0" @@ -5986,14 +5986,10 @@ } }, "node_modules/uglify-js": { - "version": "3.3.28", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.28.tgz", - "integrity": "sha512-68Rc/aA6cswiaQ5SrE979UJcXX+ADA1z33/ZsPd+fbAiVdjZ16OXdbtGO+rJUUBgK6qdf3SOPhQf3K/ybF5Miw==", + "version": "3.15.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz", + "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==", "dev": true, - "dependencies": { - "commander": "~2.15.0", - "source-map": "~0.6.1" - }, "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -6001,12 +5997,6 @@ "node": ">=0.8.0" } }, - "node_modules/uglify-js/node_modules/commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, "node_modules/underscore": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.2.tgz", @@ -11022,22 +11012,10 @@ } }, "uglify-js": { - "version": "3.3.28", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.28.tgz", - "integrity": "sha512-68Rc/aA6cswiaQ5SrE979UJcXX+ADA1z33/ZsPd+fbAiVdjZ16OXdbtGO+rJUUBgK6qdf3SOPhQf3K/ybF5Miw==", - "dev": true, - "requires": { - "commander": "~2.15.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - } - } + "version": "3.15.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz", + "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==", + "dev": true }, "underscore": { "version": "1.13.2", diff --git a/package.json b/package.json index f75251bda63..f12246b35b3 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "pixelmatch": "^4.0.2", "qunit": "^2.17.2", "testem": "^3.2.0", - "uglify-js": "^3.3.28" + "uglify-js": "^3.15.4" }, "engines": { "node": ">=14.0.0" From 66afcf0b86b3588b0fbea64d322603e1899b4578 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Thu, 21 Apr 2022 07:54:48 +0300 Subject: [PATCH 02/14] refactor controls to class --- build.js | 1 - src/control.class.js | 131 +++++++++++--- src/controls.render.js | 101 ----------- src/mixins/default_controls.js | 214 +++++++++++++---------- src/mixins/object_geometry.mixin.js | 10 +- src/mixins/object_interactivity.mixin.js | 23 +-- src/shapes/object.class.js | 3 +- src/shapes/textbox.class.js | 11 ++ 8 files changed, 253 insertions(+), 241 deletions(-) delete mode 100644 src/controls.render.js diff --git a/build.js b/build.js index 91fe3924799..26ec1762e68 100644 --- a/build.js +++ b/build.js @@ -150,7 +150,6 @@ var filesToInclude = [ 'src/intersection.class.js', 'src/color.class.js', ifSpecifiedInclude('interaction', 'src/controls.actions.js'), - ifSpecifiedInclude('interaction', 'src/controls.render.js'), ifSpecifiedInclude('interaction', 'src/control.class.js'), ifSpecifiedInclude('gradient', 'src/gradient.class.js'), diff --git a/src/control.class.js b/src/control.class.js index 7e2ea099989..527e5d8efc3 100644 --- a/src/control.class.js +++ b/src/control.class.js @@ -2,7 +2,8 @@ 'use strict'; - var fabric = global.fabric || (global.fabric = { }); + var fabric = global.fabric || (global.fabric = {}), + degreesToRadians = fabric.util.degreesToRadians; function Control(options) { for (var i in options) { @@ -167,33 +168,30 @@ /** * Returns control actionHandler * @param {Event} eventData the native mouse event - * @param {fabric.Object} fabricObject on which the control is displayed * @param {fabric.Control} control control for which the action handler is being asked * @return {Function} the action handler */ - getActionHandler: function(/* eventData, fabricObject, control */) { + getActionHandler: function(/* eventData, control */) { return this.actionHandler; }, /** * Returns control mouseDown handler * @param {Event} eventData the native mouse event - * @param {fabric.Object} fabricObject on which the control is displayed * @param {fabric.Control} control control for which the action handler is being asked * @return {Function} the action handler */ - getMouseDownHandler: function(/* eventData, fabricObject, control */) { + getMouseDownHandler: function(/* eventData, control */) { return this.mouseDownHandler; }, /** * Returns control mouseUp handler * @param {Event} eventData the native mouse event - * @param {fabric.Object} fabricObject on which the control is displayed * @param {fabric.Control} control control for which the action handler is being asked * @return {Function} the action handler */ - getMouseUpHandler: function(/* eventData, fabricObject, control */) { + getMouseUpHandler: function(/* eventData, control */) { return this.mouseUpHandler; }, @@ -206,7 +204,7 @@ * @param {fabric.Object} object on which the control is displayed * @return {String} */ - cursorStyleHandler: function(eventData, control /* fabricObject */) { + cursorStyleHandler: function(eventData, control) { return control.cursorStyle; }, @@ -217,7 +215,7 @@ * @param {fabric.Object} object on which the control is displayed * @return {String} */ - getActionName: function(eventData, control /* fabricObject */) { + getActionName: function(eventData, control) { return control.actionName; }, @@ -227,11 +225,7 @@ * @param {String} controlKey key where the control is memorized on the * @return {Boolean} */ - getVisibility: function(fabricObject, controlKey) { - var objectVisibility = fabricObject._controlsVisibility; - if (objectVisibility && typeof objectVisibility[controlKey] !== 'undefined') { - return objectVisibility[controlKey]; - } + getVisibility: function () { return this.visible; }, @@ -240,15 +234,16 @@ * @param {Boolean} visibility for the object * @return {Void} */ - setVisibility: function(visibility /* name, fabricObject */) { + setVisibility: function(visibility) { this.visible = visibility; }, - positionHandler: function(dim, finalMatrix /*, fabricObject, currentControl */) { - var point = fabric.util.transformPoint({ - x: this.x * dim.x + this.offsetX, - y: this.y * dim.y + this.offsetY }, finalMatrix); + positionHandler: function(dim, finalMatrix /*, currentControl */) { + var point = fabric.util.transformPoint( + new fabric.Point(this.x * dim.x + this.offsetX, this.y * dim.y + this.offsetY), + finalMatrix + ); return point; }, @@ -322,18 +317,106 @@ * @param {Number} left position of the canvas where we are about to render the control. * @param {Number} top position of the canvas where we are about to render the control. * @param {Object} styleOverride - * @param {fabric.Object} fabricObject the object where the control is about to be rendered */ - render: function(ctx, left, top, styleOverride, fabricObject) { + render: function (ctx, left, top, styleOverride) { styleOverride = styleOverride || {}; - switch (styleOverride.cornerStyle || fabricObject.cornerStyle) { + switch (styleOverride.cornerStyle || this.object.cornerStyle) { case 'circle': - fabric.controlsUtils.renderCircleControl.call(this, ctx, left, top, styleOverride, fabricObject); + this.renderCircleControl(ctx, left, top, styleOverride); break; default: - fabric.controlsUtils.renderSquareControl.call(this, ctx, left, top, styleOverride, fabricObject); + this.renderSquareControl(ctx, left, top, styleOverride); } }, + + /** + * Render a round control, as per fabric features. + * This function is written to respect object properties like transparentCorners, cornerSize + * cornerColor, cornerStrokeColor + * plus the addition of offsetY and offsetX. + * @param {CanvasRenderingContext2D} ctx context to render on + * @param {Number} left x coordinate where the control center should be + * @param {Number} top y coordinate where the control center should be + * @param {Object} styleOverride override for fabric.Object controls style + */ + renderCircleControl: function (ctx, left, top, styleOverride) { + var fabricObject = this.object; + styleOverride = styleOverride || {}; + var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize, + ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize, + transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ? + styleOverride.transparentCorners : fabricObject.transparentCorners, + methodName = transparentCorners ? 'stroke' : 'fill', + stroke = !transparentCorners && (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor), + myLeft = left, + myTop = top, size; + ctx.save(); + ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor; + ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor; + // as soon as fabric react v5, remove ie11, use proper ellipse code. + if (xSize > ySize) { + size = xSize; + ctx.scale(1.0, ySize / xSize); + myTop = top * xSize / ySize; + } + else if (ySize > xSize) { + size = ySize; + ctx.scale(xSize / ySize, 1.0); + myLeft = left * ySize / xSize; + } + else { + size = xSize; + } + // this is still wrong + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.arc(myLeft, myTop, size / 2, 0, 2 * Math.PI, false); + ctx[methodName](); + if (stroke) { + ctx.stroke(); + } + ctx.restore(); + }, + + /** + * Render a square control, as per fabric features. + * This function is written to respect object properties like transparentCorners, cornerSize + * cornerColor, cornerStrokeColor + * plus the addition of offsetY and offsetX. + * @param {CanvasRenderingContext2D} ctx context to render on + * @param {Number} left x coordinate where the control center should be + * @param {Number} top y coordinate where the control center should be + * @param {Object} styleOverride override for fabric.Object controls style + */ + renderSquareControl: function (ctx, left, top, styleOverride) { + var fabricObject = this.object; + styleOverride = styleOverride || {}; + var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize, + ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize, + transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ? + styleOverride.transparentCorners : fabricObject.transparentCorners, + methodName = transparentCorners ? 'stroke' : 'fill', + stroke = !transparentCorners && ( + styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor + ), xSizeBy2 = xSize / 2, ySizeBy2 = ySize / 2; + ctx.save(); + ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor; + ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor; + // this is still wrong + ctx.lineWidth = 1; + ctx.translate(left, top); + // angle is relative to canvas plane + var angle = fabricObject.getTotalAngle(); + ctx.rotate(degreesToRadians(angle)); + // this does not work, and fixed with ( && ) does not make sense. + // to have real transparent corners we need the controls on upperCanvas + // transparentCorners || ctx.clearRect(-xSizeBy2, -ySizeBy2, xSize, ySize); + ctx[methodName + 'Rect'](-xSizeBy2, -ySizeBy2, xSize, ySize); + if (stroke) { + ctx.strokeRect(-xSizeBy2, -ySizeBy2, xSize, ySize); + } + ctx.restore(); + } }; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/controls.render.js b/src/controls.render.js deleted file mode 100644 index 4c1ca95f57b..00000000000 --- a/src/controls.render.js +++ /dev/null @@ -1,101 +0,0 @@ -(function(global) { - - 'use strict'; - - var fabric = global.fabric || (global.fabric = { }), - degreesToRadians = fabric.util.degreesToRadians, - controls = fabric.controlsUtils; - - /** - * Render a round control, as per fabric features. - * This function is written to respect object properties like transparentCorners, cornerSize - * cornerColor, cornerStrokeColor - * plus the addition of offsetY and offsetX. - * @param {CanvasRenderingContext2D} ctx context to render on - * @param {Number} left x coordinate where the control center should be - * @param {Number} top y coordinate where the control center should be - * @param {Object} styleOverride override for fabric.Object controls style - * @param {fabric.Object} fabricObject the fabric object for which we are rendering controls - */ - function renderCircleControl (ctx, left, top, styleOverride, fabricObject) { - styleOverride = styleOverride || {}; - var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize, - ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize, - transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ? - styleOverride.transparentCorners : fabricObject.transparentCorners, - methodName = transparentCorners ? 'stroke' : 'fill', - stroke = !transparentCorners && (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor), - myLeft = left, - myTop = top, size; - ctx.save(); - ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor; - ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor; - // as soon as fabric react v5, remove ie11, use proper ellipse code. - if (xSize > ySize) { - size = xSize; - ctx.scale(1.0, ySize / xSize); - myTop = top * xSize / ySize; - } - else if (ySize > xSize) { - size = ySize; - ctx.scale(xSize / ySize, 1.0); - myLeft = left * ySize / xSize; - } - else { - size = xSize; - } - // this is still wrong - ctx.lineWidth = 1; - ctx.beginPath(); - ctx.arc(myLeft, myTop, size / 2, 0, 2 * Math.PI, false); - ctx[methodName](); - if (stroke) { - ctx.stroke(); - } - ctx.restore(); - } - - /** - * Render a square control, as per fabric features. - * This function is written to respect object properties like transparentCorners, cornerSize - * cornerColor, cornerStrokeColor - * plus the addition of offsetY and offsetX. - * @param {CanvasRenderingContext2D} ctx context to render on - * @param {Number} left x coordinate where the control center should be - * @param {Number} top y coordinate where the control center should be - * @param {Object} styleOverride override for fabric.Object controls style - * @param {fabric.Object} fabricObject the fabric object for which we are rendering controls - */ - function renderSquareControl(ctx, left, top, styleOverride, fabricObject) { - styleOverride = styleOverride || {}; - var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize, - ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize, - transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ? - styleOverride.transparentCorners : fabricObject.transparentCorners, - methodName = transparentCorners ? 'stroke' : 'fill', - stroke = !transparentCorners && ( - styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor - ), xSizeBy2 = xSize / 2, ySizeBy2 = ySize / 2; - ctx.save(); - ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor; - ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor; - // this is still wrong - ctx.lineWidth = 1; - ctx.translate(left, top); - // angle is relative to canvas plane - var angle = fabricObject.getTotalAngle(); - ctx.rotate(degreesToRadians(angle)); - // this does not work, and fixed with ( && ) does not make sense. - // to have real transparent corners we need the controls on upperCanvas - // transparentCorners || ctx.clearRect(-xSizeBy2, -ySizeBy2, xSize, ySize); - ctx[methodName + 'Rect'](-xSizeBy2, -ySizeBy2, xSize, ySize); - if (stroke) { - ctx.strokeRect(-xSizeBy2, -ySizeBy2, xSize, ySize); - } - ctx.restore(); - } - - controls.renderCircleControl = renderCircleControl; - controls.renderSquareControl = renderSquareControl; - -})(typeof exports !== 'undefined' ? exports : this); diff --git a/src/mixins/default_controls.js b/src/mixins/default_controls.js index 32d3a2f444c..923b1b7b402 100644 --- a/src/mixins/default_controls.js +++ b/src/mixins/default_controls.js @@ -6,109 +6,139 @@ scalingEqually = controlsUtils.scalingEqually, scalingYOrSkewingX = controlsUtils.scalingYOrSkewingX, scalingXOrSkewingY = controlsUtils.scalingXOrSkewingY, - scaleOrSkewActionName = controlsUtils.scaleOrSkewActionName, - objectControls = fabric.Object.prototype.controls; + scaleOrSkewActionName = controlsUtils.scaleOrSkewActionName; - objectControls.ml = new fabric.Control({ - x: -0.5, - y: 0, - cursorStyleHandler: scaleSkewStyleHandler, - actionHandler: scalingXOrSkewingY, - getActionName: scaleOrSkewActionName, - }); + class ObjectControls { + constructor(object) { + this.object = object; + this.controls = [ + 'ml', + 'mr', + 'mb', + 'mt', + 'tl', + 'tr', + 'bl', + 'br', + 'mtr' + ]; - objectControls.mr = new fabric.Control({ - x: 0.5, - y: 0, - cursorStyleHandler: scaleSkewStyleHandler, - actionHandler: scalingXOrSkewingY, - getActionName: scaleOrSkewActionName, - }); + this.ml = new fabric.Control({ + x: -0.5, + y: 0, + cursorStyleHandler: scaleSkewStyleHandler, + actionHandler: scalingXOrSkewingY, + getActionName: scaleOrSkewActionName, + object: this.object + }); - objectControls.mb = new fabric.Control({ - x: 0, - y: 0.5, - cursorStyleHandler: scaleSkewStyleHandler, - actionHandler: scalingYOrSkewingX, - getActionName: scaleOrSkewActionName, - }); + this.mr = new fabric.Control({ + x: 0.5, + y: 0, + cursorStyleHandler: scaleSkewStyleHandler, + actionHandler: scalingXOrSkewingY, + getActionName: scaleOrSkewActionName, + object: this.object + }); - objectControls.mt = new fabric.Control({ - x: 0, - y: -0.5, - cursorStyleHandler: scaleSkewStyleHandler, - actionHandler: scalingYOrSkewingX, - getActionName: scaleOrSkewActionName, - }); + this.mb = new fabric.Control({ + x: 0, + y: 0.5, + cursorStyleHandler: scaleSkewStyleHandler, + actionHandler: scalingYOrSkewingX, + getActionName: scaleOrSkewActionName, + object: this.object + }); - objectControls.tl = new fabric.Control({ - x: -0.5, - y: -0.5, - cursorStyleHandler: scaleStyleHandler, - actionHandler: scalingEqually - }); + this.mt = new fabric.Control({ + x: 0, + y: -0.5, + cursorStyleHandler: scaleSkewStyleHandler, + actionHandler: scalingYOrSkewingX, + getActionName: scaleOrSkewActionName, + object: this.object + }); - objectControls.tr = new fabric.Control({ - x: 0.5, - y: -0.5, - cursorStyleHandler: scaleStyleHandler, - actionHandler: scalingEqually - }); + this.tl = new fabric.Control({ + x: -0.5, + y: -0.5, + cursorStyleHandler: scaleStyleHandler, + actionHandler: scalingEqually, + object: this.object + }); - objectControls.bl = new fabric.Control({ - x: -0.5, - y: 0.5, - cursorStyleHandler: scaleStyleHandler, - actionHandler: scalingEqually - }); + this.tr = new fabric.Control({ + x: 0.5, + y: -0.5, + cursorStyleHandler: scaleStyleHandler, + actionHandler: scalingEqually, + object: this.object + }); - objectControls.br = new fabric.Control({ - x: 0.5, - y: 0.5, - cursorStyleHandler: scaleStyleHandler, - actionHandler: scalingEqually - }); + this.bl = new fabric.Control({ + x: -0.5, + y: 0.5, + cursorStyleHandler: scaleStyleHandler, + actionHandler: scalingEqually, + object: this.object + }); - objectControls.mtr = new fabric.Control({ - x: 0, - y: -0.5, - actionHandler: controlsUtils.rotationWithSnapping, - cursorStyleHandler: controlsUtils.rotationStyleHandler, - offsetY: -40, - withConnection: true, - actionName: 'rotate', - }); + this.br = new fabric.Control({ + x: 0.5, + y: 0.5, + cursorStyleHandler: scaleStyleHandler, + actionHandler: scalingEqually, + object: this.object + }); - if (fabric.Textbox) { - // this is breaking the prototype inheritance, no time / ideas to fix it. - // is important to document that if you want to have all objects to have a - // specific custom control, you have to add it to Object prototype and to Textbox - // prototype. The controls are shared as references. So changes to control `tr` - // can still apply to all objects if needed. - var textBoxControls = fabric.Textbox.prototype.controls = { }; + this.mtr = new fabric.Control({ + x: 0, + y: -0.5, + actionHandler: controlsUtils.rotationWithSnapping, + cursorStyleHandler: controlsUtils.rotationStyleHandler, + offsetY: -40, + withConnection: true, + actionName: 'rotate', + object: this.object + }); + } - textBoxControls.mtr = objectControls.mtr; - textBoxControls.tr = objectControls.tr; - textBoxControls.br = objectControls.br; - textBoxControls.tl = objectControls.tl; - textBoxControls.bl = objectControls.bl; - textBoxControls.mt = objectControls.mt; - textBoxControls.mb = objectControls.mb; - - textBoxControls.mr = new fabric.Control({ - x: 0.5, - y: 0, - actionHandler: controlsUtils.changeWidth, - cursorStyleHandler: scaleSkewStyleHandler, - actionName: 'resizing', - }); + /** + * Calls a function for each control. The function gets called, + * with the control, the object that is calling the iterator and the control's key + * @param {(control: fabric.Control, key: string) => any} callback function to iterate over the controls + */ + forEachControl(callback) { + this.controls.forEach(function (key) { + callback.call(this.object, this[key], key); + }.bind(this)); + } + } + + class TextboxControls extends ObjectControls { + constructor(object) { + super(object); + + this.mr = new fabric.Control({ + x: 0.5, + y: 0, + actionHandler: controlsUtils.changeWidth, + cursorStyleHandler: scaleSkewStyleHandler, + actionName: 'resizing', + object: this.object + }) - textBoxControls.ml = new fabric.Control({ - x: -0.5, - y: 0, - actionHandler: controlsUtils.changeWidth, - cursorStyleHandler: scaleSkewStyleHandler, - actionName: 'resizing', - }); + this.ml = new fabric.Control({ + x: -0.5, + y: 0, + actionHandler: controlsUtils.changeWidth, + cursorStyleHandler: scaleSkewStyleHandler, + actionName: 'resizing', + object: this.object + }) + } } + + fabric.ObjectControls = ObjectControls; + fabric.TextboxControls = TextboxControls; })(); diff --git a/src/mixins/object_geometry.mixin.js b/src/mixins/object_geometry.mixin.js index 43cce0216fa..bf8fd717093 100644 --- a/src/mixins/object_geometry.mixin.js +++ b/src/mixins/object_geometry.mixin.js @@ -60,12 +60,6 @@ */ matrixCache: null, - /** - * custom controls interface - * controls are added by default_controls.js - */ - controls: { }, - /** * return correct set of coordinates for intersection * this will return either aCoords or lineCoords. @@ -467,8 +461,8 @@ finalMatrix = multiplyMatrices(finalMatrix, [1 / vpt[0], 0, 0, 1 / vpt[3], 0, 0]), dim = this._calculateCurrentDimensions(), coords = {}; - this.forEachControl(function(control, key, fabricObject) { - coords[key] = control.positionHandler(dim, finalMatrix, fabricObject); + this.forEachControl(function(control, key) { + coords[key] = control.positionHandler(dim, finalMatrix); }); // debug code diff --git a/src/mixins/object_interactivity.mixin.js b/src/mixins/object_interactivity.mixin.js index 62335fa8996..128cfe35eb5 100644 --- a/src/mixins/object_interactivity.mixin.js +++ b/src/mixins/object_interactivity.mixin.js @@ -55,9 +55,7 @@ * @param {Function} fn function to iterate over the controls over */ forEachControl: function(fn) { - for (var i in this.controls) { - fn(this.controls[i], i, this); - }; + this.controls.forEachControl(fn); }, /** @@ -194,10 +192,10 @@ shouldStroke = false; ctx.beginPath(); - this.forEachControl(function (control, key, fabricObject) { + this.forEachControl(function (control, key) { // in this moment, the ctx is centered on the object. // width and height of the above function are the size of the bbox. - if (control.withConnection && control.getVisibility(fabricObject, key)) { + if (control.withConnection && control.getVisibility()) { // reset movement for each control shouldStroke = true; ctx.moveTo(control.x * width, control.y * height); @@ -232,10 +230,10 @@ } this._setLineDash(ctx, styleOverride.cornerDashArray || this.cornerDashArray); this.setCoords(); - this.forEachControl(function(control, key, fabricObject) { - if (control.getVisibility(fabricObject, key)) { - p = fabricObject.oCoords[key]; - control.render(ctx, p.x, p.y, styleOverride, fabricObject); + this.forEachControl(function(control, key) { + if (control.getVisibility()) { + p = this.oCoords[key]; + control.render(ctx, p.x, p.y, styleOverride); } }); ctx.restore(); @@ -249,7 +247,7 @@ * @returns {Boolean} true if the specified control is visible, false otherwise */ isControlVisible: function(controlKey) { - return this.controls[controlKey] && this.controls[controlKey].getVisibility(this, controlKey); + return this.controls[controlKey] && this.controls[controlKey].getVisibility(); }, /** @@ -260,10 +258,7 @@ * @chainable */ setControlVisible: function(controlKey, visible) { - if (!this._controlsVisibility) { - this._controlsVisibility = {}; - } - this._controlsVisibility[controlKey] = visible; + this.controls[controlKey] && this.controls[controlKey].setVisibility(visible); return this; }, diff --git a/src/shapes/object.class.js b/src/shapes/object.class.js index c91e9adc063..0158140d8e2 100644 --- a/src/shapes/object.class.js +++ b/src/shapes/object.class.js @@ -649,7 +649,8 @@ * Constructor * @param {Object} [options] Options object */ - initialize: function(options) { + initialize: function (options) { + this.controls = new fabric.ObjectControls(this); if (options) { this.setOptions(options); } diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index 3faff27b7b0..e57c7a3ccbb 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -78,6 +78,17 @@ */ splitByGrapheme: false, + /** + * Constructor + * @param {String} text Text string + * @param {Object} [options] Options object + * @return {fabric.Textbox} thisArg + */ + initialize: function (text, options) { + this.callSuper('initialize', text, options); + (!options || !options.controls) && (this.controls = new fabric.TextboxControls(this)); + }, + /** * Unlike superclass's version of this function, Textbox does not update * its width. From 3072dc3da513bab00998d540985050b4fd4380ba Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Thu, 21 Apr 2022 07:57:55 +0300 Subject: [PATCH 03/14] appropiate binding --- src/mixins/default_controls.js | 2 +- src/mixins/object_interactivity.mixin.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mixins/default_controls.js b/src/mixins/default_controls.js index 923b1b7b402..83665f275dc 100644 --- a/src/mixins/default_controls.js +++ b/src/mixins/default_controls.js @@ -110,7 +110,7 @@ */ forEachControl(callback) { this.controls.forEach(function (key) { - callback.call(this.object, this[key], key); + callback(this[key], key); }.bind(this)); } } diff --git a/src/mixins/object_interactivity.mixin.js b/src/mixins/object_interactivity.mixin.js index 128cfe35eb5..3a444f6da13 100644 --- a/src/mixins/object_interactivity.mixin.js +++ b/src/mixins/object_interactivity.mixin.js @@ -55,7 +55,7 @@ * @param {Function} fn function to iterate over the controls over */ forEachControl: function(fn) { - this.controls.forEachControl(fn); + this.controls.forEachControl(fn.bind(this)); }, /** From 7d60a2e66d8820c159a7a78032049cd33c9231f7 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Thu, 21 Apr 2022 08:52:12 +0300 Subject: [PATCH 04/14] Update object_interactivity.js --- test/unit/object_interactivity.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/unit/object_interactivity.js b/test/unit/object_interactivity.js index 8fde9fc25d8..838fde939a9 100644 --- a/test/unit/object_interactivity.js +++ b/test/unit/object_interactivity.js @@ -151,11 +151,11 @@ // set size for bottom left corner and have different results for bl than normal setCornerCoords test QUnit.test('_setCornerCoords_customControlSize', function(assert) { + var controls = new fabric.ObjectControls(); //set custom corner size - fabric.Object.prototype.controls.bl.sizeX = 30; - fabric.Object.prototype.controls.bl.sizeY = 10; - - var cObj = new fabric.Object({ top: 10, left: 10, width: 10, height: 10, strokeWidth: 0 }); + controls.bl.sizeX = 30; + controls.bl.sizeY = 10; + var cObj = new fabric.Object({ top: 10, left: 10, width: 10, height: 10, strokeWidth: 0, controls }); assert.ok(typeof cObj._setCornerCoords === 'function', '_setCornerCoords should exist'); cObj.setCoords(); @@ -200,9 +200,6 @@ assert.equal(cObj.oCoords.mtr.corner.br.x.toFixed(2), 21.5); assert.equal(cObj.oCoords.mtr.corner.br.y.toFixed(2), -23.5); - // reset - fabric.Object.prototype.controls.bl.sizeX = null; - fabric.Object.prototype.controls.bl.sizeY = null; }); QUnit.test('_findTargetCorner', function(assert) { From 6cdb5dc352544f44cd8a3016ef6de58f539130a5 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Thu, 21 Apr 2022 08:52:18 +0300 Subject: [PATCH 05/14] Update canvas_events.js --- test/unit/canvas_events.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/test/unit/canvas_events.js b/test/unit/canvas_events.js index 6b89d6b56f4..385707bfd12 100644 --- a/test/unit/canvas_events.js +++ b/test/unit/canvas_events.js @@ -396,9 +396,7 @@ var rect = new fabric.Rect({ left: 0, top: 0, width: 3, height: 3, strokeWidth: 0 }); var mouseUpCalled = false; var mouseDownCalled = false; - rect.controls = { - br: fabric.Object.prototype.controls.br, - }; + rect.controls = new fabric.ObjectControls(); rect.controls.br.mouseUpHandler = function() { mouseUpCalled = true; }; @@ -422,9 +420,7 @@ var e3 = { clientX: 100, clientY: 100, which: 1 }; var rect = new fabric.Rect({ left: 0, top: 0, width: 3, height: 3, strokeWidth: 0 }); var mouseUpCalled = false; - rect.controls = { - br: fabric.Object.prototype.controls.br, - }; + rect.controls = new fabric.ObjectControls(); rect.controls.br.mouseUpHandler = function() { mouseUpCalled = true; }; @@ -446,10 +442,7 @@ var mouseUpCalled1 = false; var mouseUpCalled2 = false; - rect.controls = { - br: fabric.Object.prototype.controls.br, - tr: fabric.Object.prototype.controls.tr, - }; + rect.controls = new fabric.ObjectControls(); rect.controls.br.mouseUpHandler = function() { mouseUpCalled1 = true; }; From a956b79e815ff65cb9c8dba1b77f8b2d6236d572 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Thu, 21 Apr 2022 09:15:06 +0300 Subject: [PATCH 06/14] Update object_clipPath.js --- src/mixins/default_controls.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/mixins/default_controls.js b/src/mixins/default_controls.js index 83665f275dc..836f1e14e17 100644 --- a/src/mixins/default_controls.js +++ b/src/mixins/default_controls.js @@ -10,7 +10,6 @@ class ObjectControls { constructor(object) { - this.object = object; this.controls = [ 'ml', 'mr', @@ -29,7 +28,7 @@ cursorStyleHandler: scaleSkewStyleHandler, actionHandler: scalingXOrSkewingY, getActionName: scaleOrSkewActionName, - object: this.object + object: object }); this.mr = new fabric.Control({ @@ -38,7 +37,7 @@ cursorStyleHandler: scaleSkewStyleHandler, actionHandler: scalingXOrSkewingY, getActionName: scaleOrSkewActionName, - object: this.object + object: object }); this.mb = new fabric.Control({ @@ -47,7 +46,7 @@ cursorStyleHandler: scaleSkewStyleHandler, actionHandler: scalingYOrSkewingX, getActionName: scaleOrSkewActionName, - object: this.object + object: object }); this.mt = new fabric.Control({ @@ -56,7 +55,7 @@ cursorStyleHandler: scaleSkewStyleHandler, actionHandler: scalingYOrSkewingX, getActionName: scaleOrSkewActionName, - object: this.object + object: object }); this.tl = new fabric.Control({ @@ -64,7 +63,7 @@ y: -0.5, cursorStyleHandler: scaleStyleHandler, actionHandler: scalingEqually, - object: this.object + object: object }); this.tr = new fabric.Control({ @@ -72,7 +71,7 @@ y: -0.5, cursorStyleHandler: scaleStyleHandler, actionHandler: scalingEqually, - object: this.object + object: object }); this.bl = new fabric.Control({ @@ -80,7 +79,7 @@ y: 0.5, cursorStyleHandler: scaleStyleHandler, actionHandler: scalingEqually, - object: this.object + object: object }); this.br = new fabric.Control({ @@ -88,7 +87,7 @@ y: 0.5, cursorStyleHandler: scaleStyleHandler, actionHandler: scalingEqually, - object: this.object + object: object }); this.mtr = new fabric.Control({ @@ -99,7 +98,7 @@ offsetY: -40, withConnection: true, actionName: 'rotate', - object: this.object + object: object }); } @@ -125,7 +124,7 @@ actionHandler: controlsUtils.changeWidth, cursorStyleHandler: scaleSkewStyleHandler, actionName: 'resizing', - object: this.object + object: object }) this.ml = new fabric.Control({ @@ -134,7 +133,7 @@ actionHandler: controlsUtils.changeWidth, cursorStyleHandler: scaleSkewStyleHandler, actionName: 'resizing', - object: this.object + object: object }) } } From a2a342bdfca47005a395b79abcc0237fc4daea57 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 30 Apr 2022 09:52:05 +0300 Subject: [PATCH 07/14] fix(Stateful): port from #7901 support circular refs! --- src/mixins/stateful.mixin.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/mixins/stateful.mixin.js b/src/mixins/stateful.mixin.js index 29673617670..1418c612b52 100644 --- a/src/mixins/stateful.mixin.js +++ b/src/mixins/stateful.mixin.js @@ -6,16 +6,23 @@ /* Depends on `stateProperties` */ - function saveProps(origin, destination, props) { - var tmpObj = { }, deep = true; - props.forEach(function(prop) { - tmpObj[prop] = origin[prop]; - }); + function _saveProps(origin, props) { + return props.reduce(function (saved, prop) { + var value = origin[prop]; + saved[prop] = value instanceof fabric.Object ? + _saveProps(value, value[originalSet]) : + value && typeof value.toObject === 'function' ? + value.toObject() : + value; + return saved; + }, {}); + } - extend(origin[destination], tmpObj, deep); + function saveProps(origin, destination, props) { + extend(origin[destination], _saveProps(origin, props), true); } - function _isEqual(origValue, currentValue, firstPass) { + function _isEqual(origValue, currentValue, skipShallowTest) { if (origValue === currentValue) { // if the objects are identical, return return true; @@ -35,7 +42,7 @@ var keys = Object.keys(origValue), key; if (!currentValue || typeof currentValue !== 'object' || - (!firstPass && keys.length !== Object.keys(currentValue).length) + (!skipShallowTest && keys.length !== Object.keys(currentValue).length) ) { return false; } @@ -47,7 +54,7 @@ if (key === 'canvas' || key === 'group') { continue; } - if (!_isEqual(origValue[key], currentValue[key])) { + if (!_isEqual(origValue[key], currentValue[key], currentValue[key] instanceof fabric.Object)) { return false; } } From c5169f6379b53398bb7d656fe086a6674a93a784 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 30 Apr 2022 10:52:17 +0300 Subject: [PATCH 08/14] remove keys prop --- src/mixins/default_controls.js | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/mixins/default_controls.js b/src/mixins/default_controls.js index 836f1e14e17..5134ad06fda 100644 --- a/src/mixins/default_controls.js +++ b/src/mixins/default_controls.js @@ -10,18 +10,6 @@ class ObjectControls { constructor(object) { - this.controls = [ - 'ml', - 'mr', - 'mb', - 'mt', - 'tl', - 'tr', - 'bl', - 'br', - 'mtr' - ]; - this.ml = new fabric.Control({ x: -0.5, y: 0, @@ -108,9 +96,9 @@ * @param {(control: fabric.Control, key: string) => any} callback function to iterate over the controls */ forEachControl(callback) { - this.controls.forEach(function (key) { + for (var key in this) { callback(this[key], key); - }.bind(this)); + } } } From 61b104526f9590d9f4b0a7186b172df33117ee4c Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 30 Apr 2022 10:59:45 +0300 Subject: [PATCH 09/14] Update object_interactivity.js --- test/unit/object_interactivity.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/unit/object_interactivity.js b/test/unit/object_interactivity.js index 838fde939a9..2d4c99b4abd 100644 --- a/test/unit/object_interactivity.js +++ b/test/unit/object_interactivity.js @@ -36,13 +36,14 @@ assert.ok(fabric.Object); var cObj = new fabric.Object({ }); - var cObj2 = new fabric.Object({ }); - + var cObj2 = new fabric.Object({}); + assert.ok(cObj.controls instanceof fabric.ObjectControls, 'controls should exist'); + assert.ok(cObj.controls !== cObj2.controls, 'controls should not be shared'); cObj.setControlVisible('tl', false); assert.equal(cObj.isControlVisible('tl'), false, 'setting to false worked for cObj'); assert.equal(cObj2.isControlVisible('tl'), true, 'setting to false did not work for cObj2'); cObj.controls.tl.setVisibility(false); - assert.equal(cObj2.isControlVisible('tl'), false, 'setting directly on controls works for every object'); + assert.equal(cObj2.isControlVisible('tl'), true, 'controls should not be shared'); cObj.setControlVisible('tl', true); assert.equal(cObj.isControlVisible('tl'), true, 'object setting takes precedence'); // restore original visibility From a5ebd3a862b51255a8860b31fc8506c3785888ad Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 30 Apr 2022 11:15:40 +0300 Subject: [PATCH 10/14] Update canvas_events.js --- test/unit/canvas_events.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/unit/canvas_events.js b/test/unit/canvas_events.js index 385707bfd12..9cce7bcc5ed 100644 --- a/test/unit/canvas_events.js +++ b/test/unit/canvas_events.js @@ -396,7 +396,6 @@ var rect = new fabric.Rect({ left: 0, top: 0, width: 3, height: 3, strokeWidth: 0 }); var mouseUpCalled = false; var mouseDownCalled = false; - rect.controls = new fabric.ObjectControls(); rect.controls.br.mouseUpHandler = function() { mouseUpCalled = true; }; @@ -420,7 +419,6 @@ var e3 = { clientX: 100, clientY: 100, which: 1 }; var rect = new fabric.Rect({ left: 0, top: 0, width: 3, height: 3, strokeWidth: 0 }); var mouseUpCalled = false; - rect.controls = new fabric.ObjectControls(); rect.controls.br.mouseUpHandler = function() { mouseUpCalled = true; }; @@ -433,7 +431,7 @@ assert.equal(mouseUpCalled, true, 'mouse up handler for control has been called anyway'); }); - QUnit.test('A transform than ends on a new control, calls both mouseup handler', function(assert) { + QUnit.test('A transform that ends on a new control, calls both mouseup handler', function(assert) { var e = { clientX: 3, clientY: 3, which: 1 }; var e1 = { clientX: 6, clientY: 6, which: 1 }; var e2 = { clientX: 9, clientY: 9, which: 1 }; @@ -441,8 +439,6 @@ var rect = new fabric.Rect({ left: 0, top: 0, width: 3, height: 3, strokeWidth: 0 }); var mouseUpCalled1 = false; var mouseUpCalled2 = false; - - rect.controls = new fabric.ObjectControls(); rect.controls.br.mouseUpHandler = function() { mouseUpCalled1 = true; }; From 8ef537320b8c1dea463d30e8b56098e1e17b77fa Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 30 Apr 2022 11:59:15 +0300 Subject: [PATCH 11/14] expose `attach` + cleanup --- src/mixins/default_controls.js | 58 ++++++++++++++++------------------ src/shapes/object.class.js | 11 ++++--- src/shapes/textbox.class.js | 6 ++-- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/mixins/default_controls.js b/src/mixins/default_controls.js index 5134ad06fda..54ee06f0126 100644 --- a/src/mixins/default_controls.js +++ b/src/mixins/default_controls.js @@ -6,17 +6,19 @@ scalingEqually = controlsUtils.scalingEqually, scalingYOrSkewingX = controlsUtils.scalingYOrSkewingX, scalingXOrSkewingY = controlsUtils.scalingXOrSkewingY, - scaleOrSkewActionName = controlsUtils.scaleOrSkewActionName; + scaleOrSkewActionName = controlsUtils.scaleOrSkewActionName, + rotationWithSnapping = controlsUtils.rotationWithSnapping, + rotationStyleHandler = controlsUtils.rotationStyleHandler, + changeWidth = controlsUtils.changeWidth; class ObjectControls { - constructor(object) { + constructor() { this.ml = new fabric.Control({ x: -0.5, y: 0, cursorStyleHandler: scaleSkewStyleHandler, actionHandler: scalingXOrSkewingY, - getActionName: scaleOrSkewActionName, - object: object + getActionName: scaleOrSkewActionName }); this.mr = new fabric.Control({ @@ -24,8 +26,7 @@ y: 0, cursorStyleHandler: scaleSkewStyleHandler, actionHandler: scalingXOrSkewingY, - getActionName: scaleOrSkewActionName, - object: object + getActionName: scaleOrSkewActionName }); this.mb = new fabric.Control({ @@ -33,8 +34,7 @@ y: 0.5, cursorStyleHandler: scaleSkewStyleHandler, actionHandler: scalingYOrSkewingX, - getActionName: scaleOrSkewActionName, - object: object + getActionName: scaleOrSkewActionName }); this.mt = new fabric.Control({ @@ -42,51 +42,51 @@ y: -0.5, cursorStyleHandler: scaleSkewStyleHandler, actionHandler: scalingYOrSkewingX, - getActionName: scaleOrSkewActionName, - object: object + getActionName: scaleOrSkewActionName }); this.tl = new fabric.Control({ x: -0.5, y: -0.5, cursorStyleHandler: scaleStyleHandler, - actionHandler: scalingEqually, - object: object + actionHandler: scalingEqually }); this.tr = new fabric.Control({ x: 0.5, y: -0.5, cursorStyleHandler: scaleStyleHandler, - actionHandler: scalingEqually, - object: object + actionHandler: scalingEqually }); this.bl = new fabric.Control({ x: -0.5, y: 0.5, cursorStyleHandler: scaleStyleHandler, - actionHandler: scalingEqually, - object: object + actionHandler: scalingEqually }); this.br = new fabric.Control({ x: 0.5, y: 0.5, cursorStyleHandler: scaleStyleHandler, - actionHandler: scalingEqually, - object: object + actionHandler: scalingEqually }); this.mtr = new fabric.Control({ x: 0, y: -0.5, - actionHandler: controlsUtils.rotationWithSnapping, - cursorStyleHandler: controlsUtils.rotationStyleHandler, + actionHandler: rotationWithSnapping, + cursorStyleHandler: rotationStyleHandler, offsetY: -40, withConnection: true, - actionName: 'rotate', - object: object + actionName: 'rotate' + }); + } + + attach(object) { + this.forEachControl(function (control) { + control.object = object; }); } @@ -103,25 +103,23 @@ } class TextboxControls extends ObjectControls { - constructor(object) { - super(object); + constructor() { + super(); this.mr = new fabric.Control({ x: 0.5, y: 0, - actionHandler: controlsUtils.changeWidth, + actionHandler: changeWidth, cursorStyleHandler: scaleSkewStyleHandler, - actionName: 'resizing', - object: object + actionName: 'resizing' }) this.ml = new fabric.Control({ x: -0.5, y: 0, - actionHandler: controlsUtils.changeWidth, + actionHandler: changeWidth, cursorStyleHandler: scaleSkewStyleHandler, - actionName: 'resizing', - object: object + actionName: 'resizing' }) } } diff --git a/src/shapes/object.class.js b/src/shapes/object.class.js index 0158140d8e2..9a0ca83967b 100644 --- a/src/shapes/object.class.js +++ b/src/shapes/object.class.js @@ -650,10 +650,10 @@ * @param {Object} [options] Options object */ initialize: function (options) { - this.controls = new fabric.ObjectControls(this); - if (options) { - this.setOptions(options); - } + options || (options = {}); + this.setOptions(Object.assign(options, { + controls: options.controls || new fabric.ObjectControls() + })); }, /** @@ -1003,6 +1003,9 @@ else if (key === 'shadow' && value && !(value instanceof fabric.Shadow)) { value = new fabric.Shadow(value); } + else if (key === 'controls') { + value.attach(this); + } else if (key === 'dirty' && this.group) { this.group.set('dirty', value); } diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index e57c7a3ccbb..d6d89cc2599 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -85,8 +85,10 @@ * @return {fabric.Textbox} thisArg */ initialize: function (text, options) { - this.callSuper('initialize', text, options); - (!options || !options.controls) && (this.controls = new fabric.TextboxControls(this)); + options || (options = {}); + this.callSuper('initialize', text, Object.assign(options, { + controls: options.controls || new fabric.TextboxControls() + })); }, /** From c01f3df45402ab9587d5f3c773277afa3d629d42 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 30 Apr 2022 12:23:41 +0300 Subject: [PATCH 12/14] fix(): don't use `set` I don't know why there's a bug but I am really fed up with all this old js --- src/shapes/object.class.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/shapes/object.class.js b/src/shapes/object.class.js index 9a0ca83967b..48a495a6497 100644 --- a/src/shapes/object.class.js +++ b/src/shapes/object.class.js @@ -650,10 +650,11 @@ * @param {Object} [options] Options object */ initialize: function (options) { - options || (options = {}); - this.setOptions(Object.assign(options, { - controls: options.controls || new fabric.ObjectControls() - })); + options = Object.assign(options || {}); + this.controls = options.controls || new fabric.ObjectControls(); + this.controls.attach(this); + delete options.controls; + this.setOptions(options); }, /** From e6f4f9b1685f1f30f830949ad23af12817b8829a Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 30 Apr 2022 12:46:41 +0300 Subject: [PATCH 13/14] lint --- src/control.class.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/control.class.js b/src/control.class.js index 527e5d8efc3..48ec4935249 100644 --- a/src/control.class.js +++ b/src/control.class.js @@ -343,13 +343,13 @@ var fabricObject = this.object; styleOverride = styleOverride || {}; var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize, - ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize, - transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ? - styleOverride.transparentCorners : fabricObject.transparentCorners, - methodName = transparentCorners ? 'stroke' : 'fill', - stroke = !transparentCorners && (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor), - myLeft = left, - myTop = top, size; + ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize, + transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ? + styleOverride.transparentCorners : fabricObject.transparentCorners, + methodName = transparentCorners ? 'stroke' : 'fill', + stroke = !transparentCorners && (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor), + myLeft = left, + myTop = top, size; ctx.save(); ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor; ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor; @@ -392,13 +392,13 @@ var fabricObject = this.object; styleOverride = styleOverride || {}; var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize, - ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize, - transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ? - styleOverride.transparentCorners : fabricObject.transparentCorners, - methodName = transparentCorners ? 'stroke' : 'fill', - stroke = !transparentCorners && ( - styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor - ), xSizeBy2 = xSize / 2, ySizeBy2 = ySize / 2; + ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize, + transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ? + styleOverride.transparentCorners : fabricObject.transparentCorners, + methodName = transparentCorners ? 'stroke' : 'fill', + stroke = !transparentCorners && ( + styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor + ), xSizeBy2 = xSize / 2, ySizeBy2 = ySize / 2; ctx.save(); ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor; ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor; From 15e585b1e7e4d0d56e64ad09611e3bd763721494 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 30 Apr 2022 12:50:14 +0300 Subject: [PATCH 14/14] JSDOC --- src/mixins/default_controls.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mixins/default_controls.js b/src/mixins/default_controls.js index 54ee06f0126..1d53c19bc29 100644 --- a/src/mixins/default_controls.js +++ b/src/mixins/default_controls.js @@ -84,6 +84,10 @@ }); } + /** + * **MUST** be called for controls to function properly, see {@link fabric.Object#initialize} + * @param {fabric.Object} object + */ attach(object) { this.forEachControl(function (control) { control.object = object;