From 27d33ee7bf3ffd0d4a97060337d40444f5bd4911 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:31:21 +0200 Subject: [PATCH 01/24] Update .gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 76d31bfc104..c53c948e514 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,5 @@ change-output.md before_commit /coverage/ .idea/ -/dist/fabric.require.js -/dist/fabric.min.js.gz +/dist/ /cli_output/ From f4913f6871b51e3fc7e74c251a2d59cf6c6bc659 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:33:29 +0200 Subject: [PATCH 02/24] artifact mixins --- src/canvas/canvas_gestures.mixin.ts | 409 +++++++++++++-------------- src/mixins/canvas_animation.mixin.ts | 4 +- 2 files changed, 205 insertions(+), 208 deletions(-) diff --git a/src/canvas/canvas_gestures.mixin.ts b/src/canvas/canvas_gestures.mixin.ts index e637ee004f2..087279d4d0f 100644 --- a/src/canvas/canvas_gestures.mixin.ts +++ b/src/canvas/canvas_gestures.mixin.ts @@ -2,210 +2,209 @@ import { scalingEqually } from '../controls/scale'; import { fireEvent } from '../util/fireEvent'; - -(function (global) { - var fabric = global.fabric, - degreesToRadians = fabric.util.degreesToRadians, - radiansToDegrees = fabric.util.radiansToDegrees; - - /** - * Adds support for multi-touch gestures using the Event.js library. - * Fires the following custom events: - * - touch:gesture - * - touch:drag - * - touch:orientation - * - touch:shake - * - touch:longpress - */ - fabric.util.object.extend( - fabric.Canvas.prototype, - /** @lends fabric.Canvas.prototype */ { - /** - * Method that defines actions when an Event.js gesture is detected on an object. Currently only supports - * 2 finger gestures. - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onTransformGesture: function (e, self) { - if ( - this.isDrawingMode || - !e.touches || - e.touches.length !== 2 || - 'gesture' !== self.gesture - ) { - return; - } - - var target = this.findTarget(e); - if ('undefined' !== typeof target) { - this.__gesturesParams = { - e: e, - self: self, - target: target, - }; - - this.__gesturesRenderer(); - } - - this.fire('touch:gesture', { - target: target, - e: e, - self: self, - }); - }, - __gesturesParams: null, - __gesturesRenderer: function () { - if (this.__gesturesParams === null || this._currentTransform === null) { - return; - } - - var self = this.__gesturesParams.self, - t = this._currentTransform, - e = this.__gesturesParams.e; - - t.action = 'scale'; - t.originX = t.originY = 'center'; - - this._scaleObjectBy(self.scale, e); - - if (self.rotation !== 0) { - t.action = 'rotate'; - this._rotateObjectByAngle(self.rotation, e); - } - - this.requestRenderAll(); - - t.action = 'drag'; - }, - - /** - * Method that defines actions when an Event.js drag is detected. - * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onDrag: function (e, self) { - this.fire('touch:drag', { - e: e, - self: self, - }); - }, - - /** - * Method that defines actions when an Event.js orientation event is detected. - * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onOrientationChange: function (e, self) { - this.fire('touch:orientation', { +import { + degreesToRadians, + radiansToDegrees, +} from '../util/misc/radiansDegreesConversion'; +import { Canvas } from './canvas_events'; + +/** + * Adds support for multi-touch gestures using the Event.js library. + * Fires the following custom events: + * - touch:gesture + * - touch:drag + * - touch:orientation + * - touch:shake + * - touch:longpress + */ +Object.assign( + Canvas.prototype, + /** @lends fabric.Canvas.prototype */ { + /** + * Method that defines actions when an Event.js gesture is detected on an object. Currently only supports + * 2 finger gestures. + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onTransformGesture: function (e, self) { + if ( + this.isDrawingMode || + !e.touches || + e.touches.length !== 2 || + 'gesture' !== self.gesture + ) { + return; + } + + var target = this.findTarget(e); + if ('undefined' !== typeof target) { + this.__gesturesParams = { e: e, self: self, - }); - }, - - /** - * Method that defines actions when an Event.js shake event is detected. - * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onShake: function (e, self) { - this.fire('touch:shake', { - e: e, - self: self, - }); - }, - - /** - * Method that defines actions when an Event.js longpress event is detected. - * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onLongPress: function (e, self) { - this.fire('touch:longpress', { - e: e, - self: self, - }); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js gesture - * @param {Event} [self] Inner Event object - */ - _onGesture: function (e, self) { - this.__onTransformGesture(e, self); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js drag - * @param {Event} [self] Inner Event object - */ - _onDrag: function (e, self) { - this.__onDrag(e, self); - }, - - /** - * Scales an object by a factor - * @param {Number} s The scale factor to apply to the current scale level - * @param {Event} e Event object by Event.js - */ - _scaleObjectBy: function (s, e) { - var t = this._currentTransform, - target = t.target; - t.gestureScale = s; - target._scaling = true; - return scalingEqually(e, t, 0, 0); - }, - - /** - * Rotates object by an angle - * @param {Number} curAngle The angle of rotation in degrees - * @param {Event} e Event object by Event.js - */ - _rotateObjectByAngle: function (curAngle, e) { - var t = this._currentTransform; - - if (t.target.get('lockRotation')) { - return; - } - t.target.rotate(radiansToDegrees(degreesToRadians(curAngle) + t.theta)); - fireEvent('rotating', { - target: t.target, - e: e, - transform: t, - }); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js orientation change - * @param {Event} [self] Inner Event object - */ - _onOrientationChange: function (e, self) { - this.__onOrientationChange(e, self); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js shake - * @param {Event} [self] Inner Event object - */ - _onShake: function (e, self) { - this.__onShake(e, self); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js shake - * @param {Event} [self] Inner Event object - */ - _onLongPress: function (e, self) { - this.__onLongPress(e, self); - }, - } - ); -})(typeof exports !== 'undefined' ? exports : window); + target: target, + }; + + this.__gesturesRenderer(); + } + + this.fire('touch:gesture', { + target: target, + e: e, + self: self, + }); + }, + __gesturesParams: null, + __gesturesRenderer: function () { + if (this.__gesturesParams === null || this._currentTransform === null) { + return; + } + + var self = this.__gesturesParams.self, + t = this._currentTransform, + e = this.__gesturesParams.e; + + t.action = 'scale'; + t.originX = t.originY = 'center'; + + this._scaleObjectBy(self.scale, e); + + if (self.rotation !== 0) { + t.action = 'rotate'; + this._rotateObjectByAngle(self.rotation, e); + } + + this.requestRenderAll(); + + t.action = 'drag'; + }, + + /** + * Method that defines actions when an Event.js drag is detected. + * + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onDrag: function (e, self) { + this.fire('touch:drag', { + e: e, + self: self, + }); + }, + + /** + * Method that defines actions when an Event.js orientation event is detected. + * + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onOrientationChange: function (e, self) { + this.fire('touch:orientation', { + e: e, + self: self, + }); + }, + + /** + * Method that defines actions when an Event.js shake event is detected. + * + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onShake: function (e, self) { + this.fire('touch:shake', { + e: e, + self: self, + }); + }, + + /** + * Method that defines actions when an Event.js longpress event is detected. + * + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onLongPress: function (e, self) { + this.fire('touch:longpress', { + e: e, + self: self, + }); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js gesture + * @param {Event} [self] Inner Event object + */ + _onGesture: function (e, self) { + this.__onTransformGesture(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js drag + * @param {Event} [self] Inner Event object + */ + _onDrag: function (e, self) { + this.__onDrag(e, self); + }, + + /** + * Scales an object by a factor + * @param {Number} s The scale factor to apply to the current scale level + * @param {Event} e Event object by Event.js + */ + _scaleObjectBy: function (s, e) { + var t = this._currentTransform, + target = t.target; + t.gestureScale = s; + target._scaling = true; + return scalingEqually(e, t, 0, 0); + }, + + /** + * Rotates object by an angle + * @param {Number} curAngle The angle of rotation in degrees + * @param {Event} e Event object by Event.js + */ + _rotateObjectByAngle: function (curAngle, e) { + var t = this._currentTransform; + + if (t.target.get('lockRotation')) { + return; + } + t.target.rotate(radiansToDegrees(degreesToRadians(curAngle) + t.theta)); + fireEvent('rotating', { + target: t.target, + e: e, + transform: t, + }); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js orientation change + * @param {Event} [self] Inner Event object + */ + _onOrientationChange: function (e, self) { + this.__onOrientationChange(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js shake + * @param {Event} [self] Inner Event object + */ + _onShake: function (e, self) { + this.__onShake(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js shake + * @param {Event} [self] Inner Event object + */ + _onLongPress: function (e, self) { + this.__onLongPress(e, self); + }, + } +); diff --git a/src/mixins/canvas_animation.mixin.ts b/src/mixins/canvas_animation.mixin.ts index a7f7dff0078..662cddcf068 100644 --- a/src/mixins/canvas_animation.mixin.ts +++ b/src/mixins/canvas_animation.mixin.ts @@ -1,8 +1,6 @@ // @ts-nocheck -import { getEnv } from '../env'; - -fabric.util.object.extend( +Object.assign( fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ { /** From 787efad2e97787002b78ce11456428de96eab39c Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:33:59 +0200 Subject: [PATCH 03/24] Update stateful.mixin.ts --- src/mixins/stateful.mixin.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mixins/stateful.mixin.ts b/src/mixins/stateful.mixin.ts index bb40a02483e..4879c69f203 100644 --- a/src/mixins/stateful.mixin.ts +++ b/src/mixins/stateful.mixin.ts @@ -1,6 +1,6 @@ // @ts-nocheck import type { FabricObject } from '../shapes/Object/Object'; -import { extend } from '../util/lang_object'; +import { cloneDeep } from '../util/internals/cloneDeep'; const originalSet = 'stateProperties'; @@ -77,11 +77,10 @@ export class StatefulMixin { } private saveProps(destination: string, props: (keyof FabricObject)[]) { - const savedProps = props.reduce((o, key) => { - o[key] = this[key]; + props.reduce((o, key) => { + o[key] = cloneDeep(this[key]); return o; - }, {}); - extend(this[destination], savedProps, true); + }, this[destination]); } /** From 98ef94fdb20fbe3980e44667cba76724e9b214aa Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:34:30 +0200 Subject: [PATCH 04/24] Update line.class.ts --- src/shapes/line.class.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/shapes/line.class.ts b/src/shapes/line.class.ts index bd1798b9767..e1e91e7ffc1 100644 --- a/src/shapes/line.class.ts +++ b/src/shapes/line.class.ts @@ -1,11 +1,10 @@ import { SHARED_ATTRIBUTES } from '../parser/attributes'; import { parseAttributes } from '../parser/parseAttributes'; +import { Point } from '../point.class'; import { TClassProperties } from '../typedefs'; -import { clone } from '../util/lang_object'; import { classRegistry } from '../util/class_registry'; -import { FabricObject, cacheProperties } from './Object/FabricObject'; -import { Point } from '../point.class'; import { isFiller } from '../util/types'; +import { cacheProperties, FabricObject } from './Object/FabricObject'; // @TODO this code is terrible and Line should be a special case of polyline. @@ -298,12 +297,16 @@ export class Line extends FabricObject { * @param {Object} object Object to create an instance from * @returns {Promise} */ - static fromObject(object: Record) { - const options = clone(object, true); - options.points = [object.x1, object.y1, object.x2, object.y2]; - return this._fromObject(options, { - extraParam: 'points', - }).then((fabricLine) => { + static fromObject({ x1, y1, x2, y2, ...object }: Record) { + return this._fromObject( + { + ...object, + points: [x1, y1, x2, y2], + }, + { + extraParam: 'points', + } + ).then((fabricLine) => { return fabricLine; }); } From d6f7c3815f1303addae804c452aa530697285278 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:35:30 +0200 Subject: [PATCH 05/24] Update Object.ts --- src/shapes/Object/Object.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/shapes/Object/Object.ts b/src/shapes/Object/Object.ts index 4614bf60af5..c2da5eab5a2 100644 --- a/src/shapes/Object/Object.ts +++ b/src/shapes/Object/Object.ts @@ -1,20 +1,23 @@ import { cache } from '../../cache'; +import type { Canvas } from '../../canvas/canvas_events'; +import { StaticCanvas } from '../../canvas/static_canvas.class'; import { config } from '../../config'; import { ALIASING_LIMIT, iMatrix, VERSION } from '../../constants'; import { ObjectEvents } from '../../EventTypeDefs'; -import { AnimatableObject } from './AnimatableObject'; +import type { Gradient } from '../../gradient/gradient.class'; +import type { Pattern } from '../../pattern.class'; import { Point } from '../../point.class'; import { Shadow } from '../../shadow.class'; import type { + TCacheCanvasDimensions, TClassProperties, TDegree, TFiller, TSize, - TCacheCanvasDimensions, } from '../../typedefs'; -import { classRegistry } from '../../util/class_registry'; import { runningAnimations } from '../../util/animation/AnimationRegistry'; -import { clone } from '../../util/lang_object'; +import { classRegistry } from '../../util/class_registry'; +import { cloneDeep } from '../../util/internals/cloneDeep'; import { capitalize } from '../../util/lang_string'; import { capValue } from '../../util/misc/capValue'; import { createCanvasElement, toDataURL } from '../../util/misc/dom'; @@ -26,19 +29,15 @@ import { } from '../../util/misc/objectTransforms'; import { pick } from '../../util/misc/pick'; import { toFixed } from '../../util/misc/toFixed'; -import type { Group } from '../group.class'; -import { StaticCanvas } from '../../canvas/static_canvas.class'; import { isFiller, isSerializableFiller, isTextObject } from '../../util/types'; +import type { Group } from '../group.class'; import { Image } from '../image.class'; +import { AnimatableObject } from './AnimatableObject'; import { cacheProperties, fabricObjectDefaultValues, stateProperties, } from './defaultValues'; -import type { Gradient } from '../../gradient/gradient.class'; -import type { Pattern } from '../../pattern.class'; -import type { Canvas } from '../../canvas/canvas_events'; -import { removeTransformMatrixForSvgParsing } from '../../util/transform_matrix_removal'; export type TCachedFabricObject = FabricObject & Required< @@ -1850,7 +1849,7 @@ export class FabricObject< ...options }: { extraParam?: string; signal?: AbortSignal } = {} ): Promise { - return enlivenObjectEnlivables(clone(object, true), options).then( + return enlivenObjectEnlivables(cloneDeep(object), options).then( (enlivedMap) => { const allOptions = { ...options, ...enlivedMap }; // from the resulting enlived options, extract options.extraParam to arg0 From bd55fa94d83cf67abe4f79b47455231fae83c324 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:35:43 +0200 Subject: [PATCH 06/24] cloneDeep --- src/util/internals/cloneDeep.ts | 2 ++ src/util/lang_object.ts | 60 --------------------------------- 2 files changed, 2 insertions(+), 60 deletions(-) create mode 100644 src/util/internals/cloneDeep.ts delete mode 100644 src/util/lang_object.ts diff --git a/src/util/internals/cloneDeep.ts b/src/util/internals/cloneDeep.ts new file mode 100644 index 00000000000..8d7125d5696 --- /dev/null +++ b/src/util/internals/cloneDeep.ts @@ -0,0 +1,2 @@ +export const cloneDeep = (object: T): T => + JSON.parse(JSON.stringify(object)); diff --git a/src/util/lang_object.ts b/src/util/lang_object.ts deleted file mode 100644 index 971e61ac082..00000000000 --- a/src/util/lang_object.ts +++ /dev/null @@ -1,60 +0,0 @@ -//@ts-nocheck - -import { getEnv } from '../env'; - -/** - * Copies all enumerable properties of one js object to another - * this does not and cannot compete with generic utils. - * Does not clone or extend FabricObject subclasses. - * This is mostly for internal use and has extra handling for fabricJS objects - * it skips the canvas and group properties in deep cloning. - * @param {Object} destination Where to copy to - * @param {Object} source Where to copy from - * @param {Boolean} [deep] Whether to extend nested objects - * @return {Object} - */ - -export const extend = (destination, source, deep) => { - // the deep clone is for internal use, is not meant to avoid - // javascript traps or cloning html element or self referenced objects. - if (deep) { - if (!getEnv().isLikelyNode && source instanceof Element) { - // avoid cloning deep images, canvases, - destination = source; - } else if (Array.isArray(source)) { - destination = []; - for (let i = 0, len = source.length; i < len; i++) { - destination[i] = extend({}, source[i], deep); - } - } else if (source && typeof source === 'object') { - for (const property in source) { - if (property === 'canvas' || property === 'group') { - // we do not want to clone this props at all. - // we want to keep the keys in the copy - destination[property] = null; - } else if (Object.prototype.hasOwnProperty.call(source, property)) { - destination[property] = extend({}, source[property], deep); - } - } - } else { - // this sounds odd for an extend but is ok for recursive use - destination = source; - } - } else { - for (const property in source) { - destination[property] = source[property]; - } - } - return destination; -}; - -/** - * Creates an empty object and copies all enumerable properties of another object to it - * This method is mostly for internal use, and not intended for duplicating shapes in canvas. - * @param {Object} object Object to clone - * @param {Boolean} [deep] Whether to clone nested objects - * @return {Object} - */ -//TODO: this function return an empty object if you try to clone null -export const clone = (object: T, deep: boolean): T => - deep ? extend({}, object, deep) : { ...object }; From 1313a97a7ee1bb435e63306eeec48e1520cedbfd Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:35:51 +0200 Subject: [PATCH 07/24] Update textStyles.ts --- src/util/misc/textStyles.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/util/misc/textStyles.ts b/src/util/misc/textStyles.ts index 836181cc1fa..ea2a41c414d 100644 --- a/src/util/misc/textStyles.ts +++ b/src/util/misc/textStyles.ts @@ -1,4 +1,8 @@ -import { clone } from '../lang_object'; +import type { + TextStyle, + TextStyleDeclaration, +} from '../../mixins/text_style.mixin'; +import { cloneDeep } from '../internals/cloneDeep'; /** * @param {Object} prevStyle first style to compare @@ -7,8 +11,8 @@ import { clone } from '../lang_object'; * @return {boolean} true if the style changed */ export const hasStyleChanged = ( - prevStyle: any, - thisStyle: any, + prevStyle: TextStyleDeclaration, + thisStyle: TextStyleDeclaration, forTextSpans = false ) => prevStyle.fill !== thisStyle.fill || @@ -33,13 +37,13 @@ export const hasStyleChanged = ( * @param {String} text the text string that the styles are applied to * @return {{start: number, end: number, style: object}[]} */ -export const stylesToArray = (styles: any, text: string) => { +export const stylesToArray = (styles: TextStyle, text: string) => { const textLines = text.split('\n'), stylesArray = []; let charIndex = -1, prevStyle = {}; // clone style structure to prevent mutation - styles = clone(styles, true); + styles = cloneDeep(styles); //loop through each textLine for (let i = 0; i < textLines.length; i++) { @@ -82,7 +86,7 @@ export const stylesToArray = (styles: any, text: string) => { export const stylesFromArray = (styles: any, text: string) => { if (!Array.isArray(styles)) { // clone to prevent mutation - return clone(styles, true); + return cloneDeep(styles); } const textLines = text.split('\n'), stylesObject = {} as Record< From 0456ecb18bda6775c3766d0e334e20cf0effb4ae Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:35:55 +0200 Subject: [PATCH 08/24] Update index.ts --- index.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/index.ts b/index.ts index 7098a3b748c..67cc5a00338 100644 --- a/index.ts +++ b/index.ts @@ -88,7 +88,6 @@ import { stylesToArray, hasStyleChanged, } from './src/util/misc/textStyles'; -import { clone, extend } from './src/util/lang_object'; import { createCanvasElement, createImage, @@ -194,10 +193,6 @@ const util = { stylesToArray, hasStyleChanged, getElementOffset, - object: { - clone, - extend, - }, createCanvasElement, createImage, copyCanvasElement, From 6cbf2a88f294d0ad1f8f98ce7092461863079a2f Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:36:00 +0200 Subject: [PATCH 09/24] tests --- test/unit/canvas.js | 8 +++--- test/unit/canvas_static.js | 4 +-- test/unit/circle.js | 17 ++++++------ test/unit/ellipse.js | 13 +++++---- test/unit/image.js | 17 +++++------- test/unit/object_clipPath.js | 10 +++---- test/unit/parser.js | 9 +++--- test/unit/path.js | 9 +++--- test/unit/polygon.js | 34 ++++++++++------------- test/unit/polyline.js | 30 ++++++++++---------- test/unit/rect.js | 19 +++++++------ test/unit/text.js | 10 ++++--- test/unit/util.js | 53 ------------------------------------ 13 files changed, 88 insertions(+), 145 deletions(-) diff --git a/test/unit/canvas.js b/test/unit/canvas.js index 42236848b0e..b00cee2e786 100644 --- a/test/unit/canvas.js +++ b/test/unit/canvas.js @@ -84,14 +84,14 @@ var upperCanvasEl = canvas.upperCanvasEl; var lowerCanvasEl = canvas.lowerCanvasEl; - function makeRect(options) { + function makeRect(options = {}) { var defaultOptions = { width: 10, height: 10 }; - return new fabric.Rect(fabric.util.object.extend(defaultOptions, options || { })); + return new fabric.Rect({ ...defaultOptions, ...options }); } - function makeTriangle(options) { + function makeTriangle(options = {}) { var defaultOptions = { width: 30, height: 30 }; - return new fabric.Triangle(fabric.util.object.extend(defaultOptions, options || { })); + return new fabric.Triangle({ ...defaultOptions, ...options }); } let ORIGINAL_DPR; diff --git a/test/unit/canvas_static.js b/test/unit/canvas_static.js index abbc3dfddd6..b16aa9210dc 100644 --- a/test/unit/canvas_static.js +++ b/test/unit/canvas_static.js @@ -154,9 +154,9 @@ var lowerCanvasEl = canvas.lowerCanvasEl; - function makeRect(options) { + function makeRect(options={}) { var defaultOptions = { width: 10, height: 10 }; - return new fabric.Rect(fabric.util.object.extend(defaultOptions, options || { })); + return new fabric.Rect({ ...defaultOptions, ...options }); } QUnit.module('fabric.StaticCanvas', { diff --git a/test/unit/circle.js b/test/unit/circle.js index eec90d6ebc1..afcdc2b7ec1 100644 --- a/test/unit/circle.js +++ b/test/unit/circle.js @@ -124,17 +124,18 @@ assert.ok(typeof circle.toObject === 'function'); assert.deepEqual(circle.toObject(), defaultProperties); - circle.set('left', 100).set('top', 200).set('radius', 15); - - var augmentedProperties = fabric.util.object.extend(fabric.util.object.clone(defaultProperties), { - left: 100, - top: 200, - width: 30, + circle.set('left', 100); + circle.set('top', 200); + circle.set('radius', 15); + + assert.deepEqual(circle.toObject(), { + ...defaultProperties, + left: 100, + top: 200, + width: 30, height: 30, radius: 15 }); - - assert.deepEqual(circle.toObject(), augmentedProperties); }); QUnit.test('toSVG with full circle', function(assert) { diff --git a/test/unit/ellipse.js b/test/unit/ellipse.js index c3fe6144c21..9bb89aaede7 100644 --- a/test/unit/ellipse.js +++ b/test/unit/ellipse.js @@ -61,9 +61,13 @@ assert.ok(typeof ellipse.toObject === 'function'); assert.deepEqual(ellipse.toObject(), defaultProperties); - ellipse.set('left', 100).set('top', 200).set('rx', 15).set('ry', 25); + ellipse.set('left', 100); + ellipse.set('top', 200); + ellipse.set('rx', 15); + ellipse.set('ry', 25); - var augmentedProperties = fabric.util.object.extend(fabric.util.object.clone(defaultProperties), { + assert.deepEqual(ellipse.toObject(), { + ...defaultProperties, left: 100, top: 200, rx: 15, @@ -72,8 +76,6 @@ height: 50 }); - assert.deepEqual(ellipse.toObject(), augmentedProperties); - ellipse.set('rx', 30); assert.deepEqual(ellipse.width, ellipse.rx * 2); @@ -83,7 +85,8 @@ QUnit.test('isNotVisible', function(assert) { var ellipse = new fabric.Ellipse(); - ellipse.set('rx', 0).set('ry', 0); + ellipse.set('rx', 0); + ellipse.set('ry', 0); assert.equal(ellipse.isNotVisible(), false, 'isNotVisible false when rx/ry are 0 because strokeWidth is > 0'); diff --git a/test/unit/image.js b/test/unit/image.js index 21013ce67c8..0af4bd49984 100644 --- a/test/unit/image.js +++ b/test/unit/image.js @@ -466,12 +466,7 @@ QUnit.test('fromObject', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Image.fromObject === 'function'); - - // should not throw error when no callback is given - var obj = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_IMG_OBJECT), { - src: IMG_SRC - }); - fabric.Image.fromObject(obj).then(function(instance){ + fabric.Image.fromObject({ ...REFERENCE_IMG_OBJECT, src: IMG_SRC }).then(function (instance) { assert.ok(instance instanceof fabric.Image); done(); }); @@ -480,7 +475,8 @@ QUnit.test('fromObject with clipPath and filters', function(assert) { var done = assert.async(); // should not throw error when no callback is given - var obj = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_IMG_OBJECT), { + var obj = { + ...REFERENCE_IMG_OBJECT, src: IMG_SRC, clipPath: (new fabric.Rect({ width: 100, height: 100 })).toObject(), filters: [{ @@ -490,7 +486,7 @@ resizeFilter: { type: 'Resize', } - }); + }; fabric.Image.fromObject(obj).then(function(instance){ assert.ok(instance instanceof fabric.Image); assert.ok(instance.clipPath instanceof fabric.Rect); @@ -506,9 +502,10 @@ var done = assert.async(); assert.ok(typeof fabric.Image.fromObject === 'function'); - var obj = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_IMG_OBJECT), { + var obj = { + ...REFERENCE_IMG_OBJECT, src: IMG_SRC - }); + }; var brightness = { type: 'Brightness', brightness: 0.1 diff --git a/test/unit/object_clipPath.js b/test/unit/object_clipPath.js index 220f623b94e..91477eacd2b 100644 --- a/test/unit/object_clipPath.js +++ b/test/unit/object_clipPath.js @@ -53,14 +53,12 @@ assert.deepEqual(emptyObjectRepr, cObj.toObject()); cObj.clipPath = new fabric.Object(); - var expected = fabric.util.object.clone(emptyObjectRepr); - var expectedClipPath = fabric.util.object.clone(emptyObjectRepr); - expectedClipPath = fabric.util.object.extend(expectedClipPath, { + expected.clipPath = { + ...emptyObjectRepr, inverted: cObj.clipPath.inverted, absolutePositioned: cObj.clipPath.absolutePositioned, - }); - expected.clipPath = expectedClipPath; - assert.deepEqual(expected, cObj.toObject()); + }; + assert.deepEqual(emptyObjectRepr, cObj.toObject()); cObj.clipPath.excludeFromExport = true; assert.ok(cObj.toObject().clipPath === undefined); }); diff --git a/test/unit/parser.js b/test/unit/parser.js index 0cf0ecb4de1..122765593b8 100644 --- a/test/unit/parser.js +++ b/test/unit/parser.js @@ -141,10 +141,11 @@ return el; } - function getOptions(options) { - return fabric.util.object.extend(fabric.util.object.clone({ - left: 10, top: 20, width: 30, height: 40 - }), options || { }); + function getOptions(options = {}) { + return { + left: 10, top: 20, width: 30, height: 40, + ...options, + } } var elements = [ diff --git a/test/unit/path.js b/test/unit/path.js index d4ed9f8c67a..896cff737cd 100644 --- a/test/unit/path.js +++ b/test/unit/path.js @@ -127,7 +127,7 @@ updatePath(path, REFERENCE_PATH_OBJECT.path, true); assert.deepEqual(path.toObject(), REFERENCE_PATH_OBJECT); updatePath(path, REFERENCE_PATH_OBJECT.path, false); - var opts = fabric.util.object.clone(REFERENCE_PATH_OBJECT); + var opts = { ...REFERENCE_PATH_OBJECT }; delete opts.path; path.set(opts); updatePath(path, 'M 100 100 L 300 100 L 200 300 z', true); @@ -226,7 +226,7 @@ makePathObject(function(path) { var src = 'http://example.com/'; path.sourcePath = src; - var clonedRef = fabric.util.object.clone(REFERENCE_PATH_OBJECT); + var clonedRef = { ...REFERENCE_PATH_OBJECT }; clonedRef.sourcePath = src; delete clonedRef.path; assert.deepEqual(path.toDatalessObject(), clonedRef, 'if sourcePath the object looses path'); @@ -285,12 +285,13 @@ fabric.Path.fromElement(elPath, function(path) { assert.ok(path instanceof fabric.Path); - assert.deepEqual(path.toObject(), fabric.util.object.extend(REFERENCE_PATH_OBJECT, { + assert.deepEqual(path.toObject(), { + ...REFERENCE_PATH_OBJECT, strokeDashArray: [5, 2], strokeLineCap: 'round', strokeLineJoin: 'bevel', strokeMiterLimit: 5 - })); + }); var ANGLE_DEG = 90; elPath.setAttributeNS(namespace, 'transform', 'rotate(' + ANGLE_DEG + ')'); diff --git a/test/unit/polygon.js b/test/unit/polygon.js index 80e3eeaaa35..7b290f2be1e 100644 --- a/test/unit/polygon.js +++ b/test/unit/polygon.js @@ -149,11 +149,10 @@ var polygon = new fabric.Polygon(getPoints()); assert.ok(typeof polygon.toObject === 'function'); - var objectWithOriginalPoints = fabric.util.object.extend(polygon.toObject(), { + assert.deepEqual({ + ...polygon.toObject(), points: getPoints() - }); - - assert.deepEqual(objectWithOriginalPoints, REFERENCE_OBJECT); + }, REFERENCE_OBJECT); }); QUnit.test('toSVG', function(assert) { @@ -176,13 +175,10 @@ QUnit.test('fromElement without points', function(assert) { assert.ok(typeof fabric.Polygon.fromElement === 'function'); - var empty_object = fabric.util.object.extend({}, REFERENCE_OBJECT); - empty_object = fabric.util.object.extend(empty_object, REFERENCE_EMPTY_OBJECT); - var elPolygonWithoutPoints = fabric.getDocument().createElementNS('http://www.w3.org/2000/svg', 'polygon'); fabric.Polygon.fromElement(elPolygonWithoutPoints, function(polygon) { - assert.deepEqual(polygon.toObject(), empty_object); + assert.deepEqual(polygon.toObject(), { ...REFERENCE_OBJECT, ...REFERENCE_EMPTY_OBJECT }); }); }); @@ -190,10 +186,8 @@ var namespace = 'http://www.w3.org/2000/svg'; var elPolygonWithEmptyPoints = fabric.getDocument().createElementNS(namespace, 'polygon'); elPolygonWithEmptyPoints.setAttributeNS(namespace, 'points', ''); - var empty_object = fabric.util.object.extend({}, REFERENCE_OBJECT); - empty_object = fabric.util.object.extend(empty_object, REFERENCE_EMPTY_OBJECT); fabric.Polygon.fromElement(elPolygonWithEmptyPoints, function(polygon) { - assert.deepEqual(polygon.toObject(), empty_object); + assert.deepEqual(polygon.toObject(), { ...REFERENCE_OBJECT, ...REFERENCE_EMPTY_OBJECT }); }); }); @@ -203,13 +197,12 @@ elPolygon.setAttributeNS(namespace, 'points', '10,12 20,22'); fabric.Polygon.fromElement(elPolygon, function(polygon) { assert.ok(polygon instanceof fabric.Polygon); - var expected = fabric.util.object.extend( - fabric.util.object.clone(REFERENCE_OBJECT), { - points: [{ x: 10, y: 12 }, { x: 20, y: 22 }], - left: 10, - top: 12 - }); - assert.deepEqual(polygon.toObject(), expected); + assert.deepEqual(polygon.toObject(), { + ...REFERENCE_OBJECT, + points: [{ x: 10, y: 12 }, { x: 20, y: 22 }], + left: 10, + top: 12 + }); }); }); @@ -233,7 +226,8 @@ { x: 30, y: 30 }, { x: 10, y: 10 } ]; - assert.deepEqual(polygonWithAttrs.toObject(), fabric.util.object.extend(REFERENCE_OBJECT, { + assert.deepEqual(polygonWithAttrs.toObject(), { + ...REFERENCE_OBJECT, width: 20, height: 20, fill: 'rgb(255,255,255)', @@ -247,7 +241,7 @@ points: expectedPoints, top: 10, left: 10, - })); + }); }); }); QUnit.test('fromElement with null', function(assert) { diff --git a/test/unit/polyline.js b/test/unit/polyline.js index 9be187facd6..3e2977c3d32 100644 --- a/test/unit/polyline.js +++ b/test/unit/polyline.js @@ -72,11 +72,11 @@ QUnit.test('toObject', function(assert) { var polyline = new fabric.Polyline(getPoints()); assert.ok(typeof polyline.toObject === 'function'); - var objectWithOriginalPoints = fabric.util.object.extend(polyline.toObject(), { - points: getPoints() - }); - assert.deepEqual(objectWithOriginalPoints, REFERENCE_OBJECT); + assert.deepEqual({ + ...polyline.toObject(), + points: getPoints() + }, REFERENCE_OBJECT); }); QUnit.test('toSVG', function(assert) { @@ -99,10 +99,8 @@ QUnit.test('fromElement without points', function(assert) { assert.ok(typeof fabric.Polyline.fromElement === 'function'); var elPolylineWithoutPoints = fabric.getDocument().createElementNS('http://www.w3.org/2000/svg', 'polyline'); - var empty_object = fabric.util.object.extend({}, REFERENCE_OBJECT); - empty_object = fabric.util.object.extend(empty_object, REFERENCE_EMPTY_OBJECT); fabric.Polyline.fromElement(elPolylineWithoutPoints, function(polyline) { - assert.deepEqual(polyline.toObject(), empty_object); + assert.deepEqual(polyline.toObject(), { ...REFERENCE_OBJECT, ...REFERENCE_EMPTY_OBJECT }); }); }); @@ -111,9 +109,7 @@ var elPolylineWithEmptyPoints = fabric.getDocument().createElementNS(namespace, 'polyline'); elPolylineWithEmptyPoints.setAttributeNS(namespace, 'points', ''); fabric.Polyline.fromElement(elPolylineWithEmptyPoints, function(polyline) { - var empty_object = fabric.util.object.extend({}, REFERENCE_OBJECT); - empty_object = fabric.util.object.extend(empty_object, REFERENCE_EMPTY_OBJECT); - assert.deepEqual(polyline.toObject(), empty_object); + assert.deepEqual(polyline.toObject(), { ...REFERENCE_OBJECT, ...REFERENCE_EMPTY_OBJECT }); }); }); @@ -124,10 +120,11 @@ elPolyline.setAttributeNS(namespace, 'stroke-width', 1); fabric.Polyline.fromElement(elPolyline, function(polyline) { assert.ok(polyline instanceof fabric.Polyline); - var obj = fabric.util.object.extend({}, REFERENCE_OBJECT); - obj.top = 12; - obj.left = 10; - assert.deepEqual(polyline.toObject(), obj); + assert.deepEqual(polyline.toObject(), { + ...REFERENCE_OBJECT, + left: 10, + top: 12 + }); }); }); @@ -147,7 +144,8 @@ fabric.Polyline.fromElement(elPolylineWithAttrs, function(polylineWithAttrs) { var expectedPoints = [{x: 10, y: 10}, {x: 20, y: 20}, {x: 30, y: 30}, {x: 10, y: 10}]; - assert.deepEqual(polylineWithAttrs.toObject(), fabric.util.object.extend(REFERENCE_OBJECT, { + assert.deepEqual(polylineWithAttrs.toObject(), { + ...REFERENCE_OBJECT, width: 20, height: 20, fill: 'rgb(255,255,255)', @@ -161,7 +159,7 @@ points: expectedPoints, left: 10, top: 10, - })); + }); }); }); diff --git a/test/unit/rect.js b/test/unit/rect.js index d1149615c48..e4869bdae28 100644 --- a/test/unit/rect.js +++ b/test/unit/rect.js @@ -78,10 +78,12 @@ assert.ok(rect instanceof fabric.Rect); assert.deepEqual(rect.toObject(), REFERENCE_RECT); - var expectedObject = fabric.util.object.extend({ }, REFERENCE_RECT); - expectedObject.fill = {type: 'linear',coords: {x1: 0,y1: 0,x2: 200,y2: 0},colorStops: [{offset: '0',color: 'rgb(255,0,0)',opacity: 1},{offset: '1',color: 'rgb(0,0,255)',opacity: 1}],offsetX: 0,offsetY: 0}; - expectedObject.stroke = {type: 'linear',coords: {x1: 0,y1: 0,x2: 200,y2: 0},colorStops: [{offset: '0',color: 'rgb(255,0,0)',opacity: 1},{offset: '1',color: 'rgb(0,0,255)',opacity: 1}],offsetX: 0,offsetY: 0}; - return fabric.Rect.fromObject(expectedObject).then(function(rect2) { + var expectedObject = { + ...REFERENCE_RECT, + fill: { type: 'linear', coords: { x1: 0, y1: 0, x2: 200, y2: 0 }, colorStops: [{ offset: '0', color: 'rgb(255,0,0)', opacity: 1 }, { offset: '1', color: 'rgb(0,0,255)', opacity: 1 }], offsetX: 0, offsetY: 0 }, + stroke: { type: 'linear', coords: { x1: 0, y1: 0, x2: 200, y2: 0 }, colorStops: [{ offset: '0', color: 'rgb(255,0,0)', opacity: 1 }, { offset: '1', color: 'rgb(0,0,255)', opacity: 1 }], offsetX: 0, offsetY: 0 } + }; + return fabric.Rect.fromObject(expectedObject).then(function (rect2) { assert.ok(rect2.fill instanceof fabric.Gradient); assert.ok(rect2.stroke instanceof fabric.Gradient); done(); @@ -106,10 +108,8 @@ var elRect = fabric.getDocument().createElementNS('http://www.w3.org/2000/svg', 'rect'); fabric.Rect.fromElement(elRect, function(rect) { - var expectedObject = fabric.util.object.extend({ }, REFERENCE_RECT); - expectedObject.visible = false; assert.ok(rect instanceof fabric.Rect); - assert.deepEqual(rect.toObject(), expectedObject); + assert.deepEqual(rect.toObject(), { ...REFERENCE_RECT, visible: false }); }); }); @@ -136,7 +136,8 @@ fabric.Rect.fromElement(elRectWithAttrs, function(rectWithAttrs) { assert.ok(rectWithAttrs instanceof fabric.Rect); assert.equal(rectWithAttrs.strokeUniform, true, 'strokeUniform is parsed'); - var expectedObject = fabric.util.object.extend(REFERENCE_RECT, { + var expectedObject = { + ...REFERENCE_RECT, left: 10, top: 20, width: 222, @@ -152,7 +153,7 @@ rx: 11, ry: 12, strokeUniform: true - }); + }; assert.deepEqual(rectWithAttrs.toObject(), expectedObject); }); }); diff --git a/test/unit/text.js b/test/unit/text.js index ed451c1a1b1..2b99c005278 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -208,14 +208,15 @@ fabric.Text.fromElement(elText, function(text) { assert.ok(text instanceof fabric.Text); - var expectedObject = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_TEXT_OBJECT), { + var expectedObject = { + ...REFERENCE_TEXT_OBJECT, left: 0, top: -14.05, width: 8, height: 18.08, fontSize: 16, originX: 'left' - }); + }; assert.deepEqual(text.toObject(), expectedObject, 'parsed object is what expected'); }); }); @@ -249,7 +250,8 @@ assert.ok(textWithAttrs instanceof fabric.Text); - var expectedObject = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_TEXT_OBJECT), { + var expectedObject = { + ...REFERENCE_TEXT_OBJECT, /* left varies slightly due to node-canvas rendering */ left: fabric.util.toFixed(textWithAttrs.left + '', 2), top: -88.03, @@ -270,7 +272,7 @@ fontWeight: 'bold', fontSize: 123, underline: true, - }); + }; assert.deepEqual(textWithAttrs.toObject(), expectedObject); }); }); diff --git a/test/unit/util.js b/test/unit/util.js index 1c32ccf0225..5d2caa3cdff 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -171,59 +171,6 @@ assert.equal(capitalize('2foo'), '2foo'); }); - QUnit.test('fabric.util.object.extend', function(assert) { - var extend = fabric.util.object.extend; - - assert.ok(typeof extend === 'function'); - - var destination = { x: 1 }, - source = { y: 2 }; - - extend(destination, source); - - assert.equal(destination.x, 1); - assert.equal(destination.y, 2); - assert.equal(source.x, undefined); - assert.equal(source.y, 2); - - destination = { x: 1 }; - source = { x: 2 }; - - extend(destination, source); - - assert.equal(destination.x, 2); - assert.equal(source.x, 2); - }); - - QUnit.test('fabric.util.object.extend deep', function(assert) { - var extend = fabric.util.object.extend; - var d = function() { }; - var destination = { x: 1 }, - source = { y: 2, a: { b: 1, c: [1, 2, 3, d] } }; - - extend(destination, source, true); - - assert.equal(destination.x, 1, 'x is still in destination'); - assert.equal(destination.y, 2, 'y has been added'); - assert.deepEqual(destination.a, source.a, 'a has been copied deeply'); - assert.notEqual(destination.a, source.a, 'is not the same object'); - assert.ok(typeof source.a.c[3] === 'function', 'is a function'); - assert.equal(destination.a.c[3], source.a.c[3], 'functions get referenced'); - }); - - QUnit.test('fabric.util.object.clone', function(assert) { - var clone = fabric.util.object.clone; - - assert.ok(typeof clone === 'function'); - - var obj = { x: 1, y: [1, 2, 3] }, - _clone = clone(obj); - - assert.equal(_clone.x, 1); - assert.notEqual(obj, _clone); - assert.equal(_clone.y, obj.y); - }); - QUnit.test('Function.prototype.bind', function(assert) { assert.ok(typeof Function.prototype.bind === 'function'); From dc0848901935504c375309d502823e47e45e7ebc Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:40:36 +0200 Subject: [PATCH 10/24] safeguard --- src/mixins/stateful.mixin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixins/stateful.mixin.ts b/src/mixins/stateful.mixin.ts index 4879c69f203..30fcd49e3f9 100644 --- a/src/mixins/stateful.mixin.ts +++ b/src/mixins/stateful.mixin.ts @@ -78,7 +78,7 @@ export class StatefulMixin { private saveProps(destination: string, props: (keyof FabricObject)[]) { props.reduce((o, key) => { - o[key] = cloneDeep(this[key]); + o[key] = this[key] ? cloneDeep(this[key]) : this[key]; return o; }, this[destination]); } From 9b58dab71abca036783f3419bc5be9b7d95f9e66 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:48:33 +0200 Subject: [PATCH 11/24] fix(): test patch 6cbf2a88f --- test/unit/object_clipPath.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/unit/object_clipPath.js b/test/unit/object_clipPath.js index 91477eacd2b..38a2e31800e 100644 --- a/test/unit/object_clipPath.js +++ b/test/unit/object_clipPath.js @@ -53,12 +53,16 @@ assert.deepEqual(emptyObjectRepr, cObj.toObject()); cObj.clipPath = new fabric.Object(); - expected.clipPath = { + + assert.deepEqual({ ...emptyObjectRepr, - inverted: cObj.clipPath.inverted, + clipPath: { + ...emptyObjectRepr, + inverted: cObj.clipPath.inverted, absolutePositioned: cObj.clipPath.absolutePositioned, - }; - assert.deepEqual(emptyObjectRepr, cObj.toObject()); + } + }, cObj.toObject()); + cObj.clipPath.excludeFromExport = true; assert.ok(cObj.toObject().clipPath === undefined); }); From 138e008d52f2d0dde68ab3fe1845290c32672571 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:48:44 +0200 Subject: [PATCH 12/24] Update textStyles.ts --- src/util/misc/textStyles.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/util/misc/textStyles.ts b/src/util/misc/textStyles.ts index ea2a41c414d..5ff28b91008 100644 --- a/src/util/misc/textStyles.ts +++ b/src/util/misc/textStyles.ts @@ -83,7 +83,10 @@ export const stylesToArray = (styles: TextStyle, text: string) => { * @param {String} text the text string that the styles are applied to * @return {Object} */ -export const stylesFromArray = (styles: any, text: string) => { +export const stylesFromArray = ( + styles: TextStyle | (TextStyleDeclaration & { start: number; end: number })[], + text: string +) => { if (!Array.isArray(styles)) { // clone to prevent mutation return cloneDeep(styles); From 1c2b62f0cd1480379e661006a46046722d334b22 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 08:49:08 +0200 Subject: [PATCH 13/24] safeguard --- src/shapes/text.class.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shapes/text.class.ts b/src/shapes/text.class.ts index 2bc8e4a3ea2..2d9ed783a5c 100644 --- a/src/shapes/text.class.ts +++ b/src/shapes/text.class.ts @@ -1859,7 +1859,7 @@ export class Text< return this._fromObject( { ...object, - styles: stylesFromArray(object.styles, object.text), + styles: stylesFromArray(object.styles || {}, object.text), }, { extraParam: 'text', From 11ec7112c3e125ae458aaa73ce5f9bad785a7a19 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 09:05:53 +0200 Subject: [PATCH 14/24] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f293a66626..944a7b9da86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## [next] +- chore(): replace `clone(obj, true)` with `cloneDeep(obj)` and remove all `extend`, `clone` calls in favor of object spreads. [#8600](https://github.com/fabricjs/fabric.js/pull/8600) + BREAKING: + `clone` and `extend` are used in all examples unfortunately so the community must have adopted them. + Devs using `extend` on classes should mutate the prototype directly (or with `defineProperty`) or subclass. + Using `clone` or `extend` to assign to an object was always a bad idea. Use lodash or whatever. - chore(TS): remove all remaining empty declarations [#8593](https://github.com/fabricjs/fabric.js/pull/8593) - refactor(IText): modernize IText cursor animation based on animation API changes (and fix minor regression) plus leftovers from #8547 [#8583](https://github.com/fabricjs/fabric.js/pull/8583) - refactor(Canvas, IText): Handle cross instance text editing states to an EditingManager class [#8543](https://github.com/fabricjs/fabric.js/pull/8543) From 369255d4eb662a1da1fa2aae485b698204ee340d Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 09:09:58 +0200 Subject: [PATCH 15/24] Update textStyles.ts --- src/util/misc/textStyles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/misc/textStyles.ts b/src/util/misc/textStyles.ts index 5ff28b91008..d62d0f77e32 100644 --- a/src/util/misc/textStyles.ts +++ b/src/util/misc/textStyles.ts @@ -84,7 +84,7 @@ export const stylesToArray = (styles: TextStyle, text: string) => { * @return {Object} */ export const stylesFromArray = ( - styles: TextStyle | (TextStyleDeclaration & { start: number; end: number })[], + styles: (TextStyleDeclaration & { start: number; end: number })[] | TextStyle, text: string ) => { if (!Array.isArray(styles)) { From 98497efe72fcca92f26b620e5d754ec81271b4da Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 09:13:14 +0200 Subject: [PATCH 16/24] types --- src/util/misc/textStyles.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/util/misc/textStyles.ts b/src/util/misc/textStyles.ts index d62d0f77e32..992fc562ce3 100644 --- a/src/util/misc/textStyles.ts +++ b/src/util/misc/textStyles.ts @@ -4,6 +4,12 @@ import type { } from '../../mixins/text_style.mixin'; import { cloneDeep } from '../internals/cloneDeep'; +export type TextStyleArray = { + start: number; + end: number; + style: TextStyleDeclaration; +}[]; + /** * @param {Object} prevStyle first style to compare * @param {Object} thisStyle second style to compare @@ -37,7 +43,10 @@ export const hasStyleChanged = ( * @param {String} text the text string that the styles are applied to * @return {{start: number, end: number, style: object}[]} */ -export const stylesToArray = (styles: TextStyle, text: string) => { +export const stylesToArray = ( + styles: TextStyle, + text: string +): TextStyleArray => { const textLines = text.split('\n'), stylesArray = []; let charIndex = -1, @@ -84,9 +93,9 @@ export const stylesToArray = (styles: TextStyle, text: string) => { * @return {Object} */ export const stylesFromArray = ( - styles: (TextStyleDeclaration & { start: number; end: number })[] | TextStyle, + styles: TextStyleArray | TextStyle, text: string -) => { +): TextStyle => { if (!Array.isArray(styles)) { // clone to prevent mutation return cloneDeep(styles); From b20aac1de6f9f46af3f0c0852bf34a6d5076a946 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 15 Jan 2023 09:15:34 +0200 Subject: [PATCH 17/24] artifact imports f4913f687 --- src/canvas/canvas_gestures.mixin.ts | 375 +++++++++++++-------------- src/mixins/canvas_animation.mixin.ts | 220 ++++++++-------- 2 files changed, 296 insertions(+), 299 deletions(-) diff --git a/src/canvas/canvas_gestures.mixin.ts b/src/canvas/canvas_gestures.mixin.ts index 087279d4d0f..96884413f56 100644 --- a/src/canvas/canvas_gestures.mixin.ts +++ b/src/canvas/canvas_gestures.mixin.ts @@ -17,194 +17,191 @@ import { Canvas } from './canvas_events'; * - touch:shake * - touch:longpress */ -Object.assign( - Canvas.prototype, - /** @lends fabric.Canvas.prototype */ { - /** - * Method that defines actions when an Event.js gesture is detected on an object. Currently only supports - * 2 finger gestures. - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onTransformGesture: function (e, self) { - if ( - this.isDrawingMode || - !e.touches || - e.touches.length !== 2 || - 'gesture' !== self.gesture - ) { - return; - } - - var target = this.findTarget(e); - if ('undefined' !== typeof target) { - this.__gesturesParams = { - e: e, - self: self, - target: target, - }; - - this.__gesturesRenderer(); - } - - this.fire('touch:gesture', { - target: target, - e: e, - self: self, - }); - }, - __gesturesParams: null, - __gesturesRenderer: function () { - if (this.__gesturesParams === null || this._currentTransform === null) { - return; - } - - var self = this.__gesturesParams.self, - t = this._currentTransform, - e = this.__gesturesParams.e; - - t.action = 'scale'; - t.originX = t.originY = 'center'; - - this._scaleObjectBy(self.scale, e); - - if (self.rotation !== 0) { - t.action = 'rotate'; - this._rotateObjectByAngle(self.rotation, e); - } - - this.requestRenderAll(); - - t.action = 'drag'; - }, - - /** - * Method that defines actions when an Event.js drag is detected. - * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onDrag: function (e, self) { - this.fire('touch:drag', { +Object.assign(Canvas.prototype, { + /** + * Method that defines actions when an Event.js gesture is detected on an object. Currently only supports + * 2 finger gestures. + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onTransformGesture: function (e, self) { + if ( + this.isDrawingMode || + !e.touches || + e.touches.length !== 2 || + 'gesture' !== self.gesture + ) { + return; + } + + var target = this.findTarget(e); + if ('undefined' !== typeof target) { + this.__gesturesParams = { e: e, self: self, - }); - }, - - /** - * Method that defines actions when an Event.js orientation event is detected. - * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onOrientationChange: function (e, self) { - this.fire('touch:orientation', { - e: e, - self: self, - }); - }, - - /** - * Method that defines actions when an Event.js shake event is detected. - * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onShake: function (e, self) { - this.fire('touch:shake', { - e: e, - self: self, - }); - }, - - /** - * Method that defines actions when an Event.js longpress event is detected. - * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js - */ - __onLongPress: function (e, self) { - this.fire('touch:longpress', { - e: e, - self: self, - }); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js gesture - * @param {Event} [self] Inner Event object - */ - _onGesture: function (e, self) { - this.__onTransformGesture(e, self); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js drag - * @param {Event} [self] Inner Event object - */ - _onDrag: function (e, self) { - this.__onDrag(e, self); - }, - - /** - * Scales an object by a factor - * @param {Number} s The scale factor to apply to the current scale level - * @param {Event} e Event object by Event.js - */ - _scaleObjectBy: function (s, e) { - var t = this._currentTransform, - target = t.target; - t.gestureScale = s; - target._scaling = true; - return scalingEqually(e, t, 0, 0); - }, - - /** - * Rotates object by an angle - * @param {Number} curAngle The angle of rotation in degrees - * @param {Event} e Event object by Event.js - */ - _rotateObjectByAngle: function (curAngle, e) { - var t = this._currentTransform; - - if (t.target.get('lockRotation')) { - return; - } - t.target.rotate(radiansToDegrees(degreesToRadians(curAngle) + t.theta)); - fireEvent('rotating', { - target: t.target, - e: e, - transform: t, - }); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js orientation change - * @param {Event} [self] Inner Event object - */ - _onOrientationChange: function (e, self) { - this.__onOrientationChange(e, self); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js shake - * @param {Event} [self] Inner Event object - */ - _onShake: function (e, self) { - this.__onShake(e, self); - }, - - /** - * @private - * @param {Event} [e] Event object fired on Event.js shake - * @param {Event} [self] Inner Event object - */ - _onLongPress: function (e, self) { - this.__onLongPress(e, self); - }, - } -); + target: target, + }; + + this.__gesturesRenderer(); + } + + this.fire('touch:gesture', { + target: target, + e: e, + self: self, + }); + }, + __gesturesParams: null, + __gesturesRenderer: function () { + if (this.__gesturesParams === null || this._currentTransform === null) { + return; + } + + var self = this.__gesturesParams.self, + t = this._currentTransform, + e = this.__gesturesParams.e; + + t.action = 'scale'; + t.originX = t.originY = 'center'; + + this._scaleObjectBy(self.scale, e); + + if (self.rotation !== 0) { + t.action = 'rotate'; + this._rotateObjectByAngle(self.rotation, e); + } + + this.requestRenderAll(); + + t.action = 'drag'; + }, + + /** + * Method that defines actions when an Event.js drag is detected. + * + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onDrag: function (e, self) { + this.fire('touch:drag', { + e: e, + self: self, + }); + }, + + /** + * Method that defines actions when an Event.js orientation event is detected. + * + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onOrientationChange: function (e, self) { + this.fire('touch:orientation', { + e: e, + self: self, + }); + }, + + /** + * Method that defines actions when an Event.js shake event is detected. + * + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onShake: function (e, self) { + this.fire('touch:shake', { + e: e, + self: self, + }); + }, + + /** + * Method that defines actions when an Event.js longpress event is detected. + * + * @param {Event} e Event object by Event.js + * @param {Event} self Event proxy object by Event.js + */ + __onLongPress: function (e, self) { + this.fire('touch:longpress', { + e: e, + self: self, + }); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js gesture + * @param {Event} [self] Inner Event object + */ + _onGesture: function (e, self) { + this.__onTransformGesture(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js drag + * @param {Event} [self] Inner Event object + */ + _onDrag: function (e, self) { + this.__onDrag(e, self); + }, + + /** + * Scales an object by a factor + * @param {Number} s The scale factor to apply to the current scale level + * @param {Event} e Event object by Event.js + */ + _scaleObjectBy: function (s, e) { + var t = this._currentTransform, + target = t.target; + t.gestureScale = s; + target._scaling = true; + return scalingEqually(e, t, 0, 0); + }, + + /** + * Rotates object by an angle + * @param {Number} curAngle The angle of rotation in degrees + * @param {Event} e Event object by Event.js + */ + _rotateObjectByAngle: function (curAngle, e) { + var t = this._currentTransform; + + if (t.target.get('lockRotation')) { + return; + } + t.target.rotate(radiansToDegrees(degreesToRadians(curAngle) + t.theta)); + fireEvent('rotating', { + target: t.target, + e: e, + transform: t, + }); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js orientation change + * @param {Event} [self] Inner Event object + */ + _onOrientationChange: function (e, self) { + this.__onOrientationChange(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js shake + * @param {Event} [self] Inner Event object + */ + _onShake: function (e, self) { + this.__onShake(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js shake + * @param {Event} [self] Inner Event object + */ + _onLongPress: function (e, self) { + this.__onLongPress(e, self); + }, +}); diff --git a/src/mixins/canvas_animation.mixin.ts b/src/mixins/canvas_animation.mixin.ts index 662cddcf068..0c507ff9ce2 100644 --- a/src/mixins/canvas_animation.mixin.ts +++ b/src/mixins/canvas_animation.mixin.ts @@ -1,121 +1,121 @@ // @ts-nocheck -Object.assign( - fabric.StaticCanvas.prototype, - /** @lends fabric.StaticCanvas.prototype */ { - /** - * Animation duration (in ms) for fx* methods - * @type Number - * @default - */ - FX_DURATION: 500, +import { StaticCanvas } from '../canvas/static_canvas.class'; +import { animate } from '../util/animation/animate'; - /** - * Centers object horizontally with animation. - * @param {fabric.Object} object Object to center - * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties - * @param {Function} [callbacks.onComplete] Invoked on completion - * @param {Function} [callbacks.onChange] Invoked on every step of animation - * @return {fabric.AnimationContext} context - */ - fxCenterObjectH: function (object, callbacks) { - callbacks = callbacks || {}; +Object.assign(StaticCanvas.prototype, { + /** + * Animation duration (in ms) for fx* methods + * @type Number + * @default + */ + FX_DURATION: 500, - var empty = function () {}, - onComplete = callbacks.onComplete || empty, - onChange = callbacks.onChange || empty, - _this = this; + /** + * Centers object horizontally with animation. + * @param {fabric.Object} object Object to center + * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties + * @param {Function} [callbacks.onComplete] Invoked on completion + * @param {Function} [callbacks.onChange] Invoked on every step of animation + * @return {fabric.AnimationContext} context + */ + fxCenterObjectH: function (object, callbacks) { + callbacks = callbacks || {}; - return fabric.util.animate({ - target: this, - startValue: object.getX(), - endValue: this.getCenterPoint().x, - duration: this.FX_DURATION, - onChange: function (value) { - object.setX(value); - _this.requestRenderAll(); - onChange(); - }, - onComplete: function () { - object.setCoords(); - onComplete(); - }, - }); - }, + var empty = function () {}, + onComplete = callbacks.onComplete || empty, + onChange = callbacks.onChange || empty, + _this = this; - /** - * Centers object vertically with animation. - * @param {fabric.Object} object Object to center - * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties - * @param {Function} [callbacks.onComplete] Invoked on completion - * @param {Function} [callbacks.onChange] Invoked on every step of animation - * @return {fabric.AnimationContext} context - */ - fxCenterObjectV: function (object, callbacks) { - callbacks = callbacks || {}; + return animate({ + target: this, + startValue: object.getX(), + endValue: this.getCenterPoint().x, + duration: this.FX_DURATION, + onChange: function (value) { + object.setX(value); + _this.requestRenderAll(); + onChange(); + }, + onComplete: function () { + object.setCoords(); + onComplete(); + }, + }); + }, - var empty = function () {}, - onComplete = callbacks.onComplete || empty, - onChange = callbacks.onChange || empty, - _this = this; + /** + * Centers object vertically with animation. + * @param {fabric.Object} object Object to center + * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties + * @param {Function} [callbacks.onComplete] Invoked on completion + * @param {Function} [callbacks.onChange] Invoked on every step of animation + * @return {fabric.AnimationContext} context + */ + fxCenterObjectV: function (object, callbacks) { + callbacks = callbacks || {}; - return fabric.util.animate({ - target: this, - startValue: object.getY(), - endValue: this.getCenterPoint().y, - duration: this.FX_DURATION, - onChange: function (value) { - object.setY(value); - _this.requestRenderAll(); - onChange(); - }, - onComplete: function () { - object.setCoords(); - onComplete(); - }, - }); - }, + var empty = function () {}, + onComplete = callbacks.onComplete || empty, + onChange = callbacks.onChange || empty, + _this = this; - /** - * Same as `fabric.Canvas#remove` but animated - * @param {fabric.Object} object Object to remove - * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties - * @param {Function} [callbacks.onComplete] Invoked on completion - * @param {Function} [callbacks.onChange] Invoked on every step of animation - * @return {fabric.AnimationContext} context - */ - fxRemove: function (object, callbacks) { - callbacks = callbacks || {}; - var empty = function () {}, - onComplete = callbacks.onComplete || empty, - onChange = callbacks.onChange || empty, - _this = this; + return animate({ + target: this, + startValue: object.getY(), + endValue: this.getCenterPoint().y, + duration: this.FX_DURATION, + onChange: function (value) { + object.setY(value); + _this.requestRenderAll(); + onChange(); + }, + onComplete: function () { + object.setCoords(); + onComplete(); + }, + }); + }, - return fabric.util.animate({ - target: this, - startValue: object.opacity, - endValue: 0, - duration: this.FX_DURATION, - onChange: function (value) { - object.set('opacity', value); - _this.requestRenderAll(); - onChange(); - }, - onComplete: function () { - _this.remove(object); - onComplete(); - }, - }); - }, + /** + * Same as `fabric.Canvas#remove` but animated + * @param {fabric.Object} object Object to remove + * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties + * @param {Function} [callbacks.onComplete] Invoked on completion + * @param {Function} [callbacks.onChange] Invoked on every step of animation + * @return {fabric.AnimationContext} context + */ + fxRemove: function (object, callbacks) { + callbacks = callbacks || {}; + var empty = function () {}, + onComplete = callbacks.onComplete || empty, + onChange = callbacks.onChange || empty, + _this = this; - /** - * @param {fabric.Object} object Object to straighten - * @return {fabric.Canvas} thisArg - */ - fxStraightenObject: function (object: FabricObject) { - return object.fxStraighten({ - onChange: this.requestRenderAllBound, - }); - }, - } -); + return animate({ + target: this, + startValue: object.opacity, + endValue: 0, + duration: this.FX_DURATION, + onChange: function (value) { + object.set('opacity', value); + _this.requestRenderAll(); + onChange(); + }, + onComplete: function () { + _this.remove(object); + onComplete(); + }, + }); + }, + + /** + * @param {fabric.Object} object Object to straighten + * @return {fabric.Canvas} thisArg + */ + fxStraightenObject: function (object: FabricObject) { + return object.fxStraighten({ + onChange: this.requestRenderAllBound, + }); + }, +}); From f28e66cad0715b61b071842ef1a0b0e3f0c8c4dd Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 16 Jan 2023 16:03:55 +0200 Subject: [PATCH 18/24] this will cause a conflict with #8598 --- src/mixins/itext_behavior.mixin.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mixins/itext_behavior.mixin.ts b/src/mixins/itext_behavior.mixin.ts index 2cc5161f825..0ab9f4d8401 100644 --- a/src/mixins/itext_behavior.mixin.ts +++ b/src/mixins/itext_behavior.mixin.ts @@ -5,7 +5,6 @@ import { DragEventData, DropEventData, ObjectEvents, - TEvent, TPointerEvent, } from '../EventTypeDefs'; import { Point } from '../point.class'; @@ -15,7 +14,7 @@ import { animate } from '../util/animation/animate'; import { TOnAnimationChangeCallback } from '../util/animation/types'; import type { ValueAnimation } from '../util/animation/ValueAnimation'; import { setStyle } from '../util/dom_style'; -import { clone } from '../util/lang_object'; +import { cloneDeep } from '../util/internals/cloneDeep'; import { createCanvasElement } from '../util/misc/dom'; import { isIdentityMatrix } from '../util/misc/matrix'; import { TextStyleDeclaration } from './text_style.mixin'; @@ -470,7 +469,7 @@ export abstract class ITextBehaviorMixin< const offset = correction.add(diff).transform(vpt, true); // prepare instance for drag image snapshot by making all non selected text invisible const bgc = this.backgroundColor; - const styles = clone(this.styles, true); + const styles = cloneDeep(this.styles); delete this.backgroundColor; const styleOverride = { stroke: 'transparent', From 775b1c1024e069939e7fb8d48c6a9393c0390971 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 22 Jan 2023 08:30:25 +0200 Subject: [PATCH 19/24] Update DraggableTextDelegate.ts --- src/mixins/DraggableTextDelegate.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mixins/DraggableTextDelegate.ts b/src/mixins/DraggableTextDelegate.ts index a9f1869706c..532f77edd07 100644 --- a/src/mixins/DraggableTextDelegate.ts +++ b/src/mixins/DraggableTextDelegate.ts @@ -4,7 +4,7 @@ import { DragEventData, DropEventData, TPointerEvent } from '../EventTypeDefs'; import { Point } from '../point.class'; import type { IText } from '../shapes/itext.class'; import { setStyle } from '../util/dom_style'; -import { clone } from '../util/lang_object'; +import { cloneDeep } from '../util/internals/cloneDeep'; import { createCanvasElement } from '../util/misc/dom'; import { isIdentityMatrix } from '../util/misc/matrix'; import { TextStyleDeclaration } from './text_style.mixin'; @@ -127,7 +127,7 @@ export class DraggableTextDelegate { const offset = correction.add(diff).transform(vpt, true); // prepare instance for drag image snapshot by making all non selected text invisible const bgc = target.backgroundColor; - const styles = clone(target.styles, true); + const styles = cloneDeep(target.styles); target.backgroundColor = ''; const styleOverride = { stroke: 'transparent', From 4d3d2b5c92731ac9bb6abda895ac4cada58c5bd2 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 22 Jan 2023 08:36:59 +0200 Subject: [PATCH 20/24] Update itext_click_behaviour.js --- test/unit/itext_click_behaviour.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/itext_click_behaviour.js b/test/unit/itext_click_behaviour.js index f015da89319..99745082cda 100644 --- a/test/unit/itext_click_behaviour.js +++ b/test/unit/itext_click_behaviour.js @@ -19,7 +19,7 @@ assert.equal(cursorState, active, `cursor animation state should be ${active}`); } - function wait(ms = 16) { + function wait(ms = 32) { return new Promise(resolve => setTimeout(resolve, ms)); } From dad3cbe534040c49cf12d8d430a2f26aa27f59bf Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 22 Jan 2023 21:46:47 +0100 Subject: [PATCH 21/24] Update CHANGELOG.md --- CHANGELOG.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aff767da862..3c70d285c44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,7 @@ ## [next] -- chore(): replace `clone(obj, true)` with `cloneDeep(obj)` and remove all `extend`, `clone` calls in favor of object spreads. [#8600](https://github.com/fabricjs/fabric.js/pull/8600) - BREAKING: - `clone` and `extend` are used in all examples unfortunately so the community must have adopted them. - Devs using `extend` on classes should mutate the prototype directly (or with `defineProperty`) or subclass. - Using `clone` or `extend` to assign to an object was always a bad idea. Use lodash or whatever. +- BREAKING: refactor `clone(obj, true)` with `cloneDeep(obj)` and remove all `extend`, `clone` calls in favor of object spreads. [#8600](https://github.com/fabricjs/fabric.js/pull/8600) - chore(TS): Fix some error caused by ts-nocheck removals [#8615](https://github.com/fabricjs/fabric.js/pull/8615) - refactor(IText): extract draggable text logic to a delegate [#8598](https://github.com/fabricjs/fabric.js/pull/8598) - chore(TS): Update StaticCanvas to remove ts-nocheck [#8606](https://github.com/fabricjs/fabric.js/pull/8606) From 6056fde1918a8628d9e65d557e4fbac38c3bdef2 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 22 Jan 2023 21:53:06 +0100 Subject: [PATCH 22/24] import reordering --- src/shapes/Object/Object.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/shapes/Object/Object.ts b/src/shapes/Object/Object.ts index faab68d60e4..edffd211b41 100644 --- a/src/shapes/Object/Object.ts +++ b/src/shapes/Object/Object.ts @@ -1,22 +1,19 @@ import { cache } from '../../cache'; -import type { Canvas } from '../../canvas/canvas_events'; -import { StaticCanvas } from '../../canvas/static_canvas.class'; import { config } from '../../config'; import { ALIASING_LIMIT, iMatrix, VERSION } from '../../constants'; import { ObjectEvents } from '../../EventTypeDefs'; -import type { Gradient } from '../../gradient/gradient.class'; -import type { Pattern } from '../../pattern.class'; +import { AnimatableObject } from './AnimatableObject'; import { Point } from '../../point.class'; import { Shadow } from '../../shadow.class'; import type { - TCacheCanvasDimensions, TClassProperties, TDegree, TFiller, TSize, + TCacheCanvasDimensions, } from '../../typedefs'; -import { runningAnimations } from '../../util/animation/AnimationRegistry'; import { classRegistry } from '../../util/class_registry'; +import { runningAnimations } from '../../util/animation/AnimationRegistry'; import { cloneDeep } from '../../util/internals/cloneDeep'; import { capitalize } from '../../util/lang_string'; import { capValue } from '../../util/misc/capValue'; @@ -29,15 +26,19 @@ import { } from '../../util/misc/objectTransforms'; import { pick } from '../../util/misc/pick'; import { toFixed } from '../../util/misc/toFixed'; -import { isFiller, isSerializableFiller, isTextObject } from '../../util/types'; import type { Group } from '../group.class'; +import { StaticCanvas } from '../../canvas/static_canvas.class'; +import { isFiller, isSerializableFiller, isTextObject } from '../../util/types'; import { Image } from '../image.class'; -import { AnimatableObject } from './AnimatableObject'; import { cacheProperties, fabricObjectDefaultValues, stateProperties, } from './defaultValues'; +import type { Gradient } from '../../gradient/gradient.class'; +import type { Pattern } from '../../pattern.class'; +import type { Canvas } from '../../canvas/canvas_events'; +import { removeTransformMatrixForSvgParsing } from '../../util/transform_matrix_removal'; export type TCachedFabricObject = FabricObject & Required< @@ -1363,7 +1364,7 @@ export class FabricObject< this._applyPatternForTransformedGradient(ctx, stroke); } else { // is a simple gradient or pattern - ctx.strokeStyle = stroke.toLive(ctx)!; + ctx.strokeStyle = stroke.toLive(ctx); this._applyPatternGradientTransform(ctx, stroke); } } else { @@ -1376,7 +1377,7 @@ export class FabricObject< _setFillStyles(ctx: CanvasRenderingContext2D, { fill }: Pick) { if (fill) { if (isFiller(fill)) { - ctx.fillStyle = fill.toLive(ctx)!; + ctx.fillStyle = fill.toLive(ctx); this._applyPatternGradientTransform(ctx, fill); } else { ctx.fillStyle = fill; @@ -1582,7 +1583,7 @@ export class FabricObject< dims.zoomY / this.scaleY / retinaScaling ); this._applyPatternGradientTransform(pCtx, filler); - pCtx.fillStyle = filler.toLive(ctx)!; + pCtx.fillStyle = filler.toLive(ctx); pCtx.fill(); ctx.translate( -this.width / 2 - this.strokeWidth / 2, From cf2c42dd8ed10445603e263a52eeed5220b996de Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 22 Jan 2023 21:55:04 +0100 Subject: [PATCH 23/24] more import reordering --- src/shapes/line.class.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shapes/line.class.ts b/src/shapes/line.class.ts index cea70c52e6b..6bcd354df24 100644 --- a/src/shapes/line.class.ts +++ b/src/shapes/line.class.ts @@ -1,10 +1,10 @@ import { SHARED_ATTRIBUTES } from '../parser/attributes'; import { parseAttributes } from '../parser/parseAttributes'; -import { Point } from '../point.class'; import { TClassProperties } from '../typedefs'; import { classRegistry } from '../util/class_registry'; -import { isFiller } from '../util/types'; import { cacheProperties, FabricObject } from './Object/FabricObject'; +import { Point } from '../point.class'; +import { isFiller } from '../util/types'; // @TODO this code is terrible and Line should be a special case of polyline. From 2c9dc2bbda27d9de48323e8507e6920bf29764f2 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 22 Jan 2023 21:57:01 +0100 Subject: [PATCH 24/24] more reordering and somewhing wrong with my master --- src/shapes/Object/Object.ts | 6 +++--- src/shapes/line.class.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shapes/Object/Object.ts b/src/shapes/Object/Object.ts index edffd211b41..21373d9e04c 100644 --- a/src/shapes/Object/Object.ts +++ b/src/shapes/Object/Object.ts @@ -1364,7 +1364,7 @@ export class FabricObject< this._applyPatternForTransformedGradient(ctx, stroke); } else { // is a simple gradient or pattern - ctx.strokeStyle = stroke.toLive(ctx); + ctx.strokeStyle = stroke.toLive(ctx)!; this._applyPatternGradientTransform(ctx, stroke); } } else { @@ -1377,7 +1377,7 @@ export class FabricObject< _setFillStyles(ctx: CanvasRenderingContext2D, { fill }: Pick) { if (fill) { if (isFiller(fill)) { - ctx.fillStyle = fill.toLive(ctx); + ctx.fillStyle = fill.toLive(ctx)!; this._applyPatternGradientTransform(ctx, fill); } else { ctx.fillStyle = fill; @@ -1583,7 +1583,7 @@ export class FabricObject< dims.zoomY / this.scaleY / retinaScaling ); this._applyPatternGradientTransform(pCtx, filler); - pCtx.fillStyle = filler.toLive(ctx); + pCtx.fillStyle = filler.toLive(ctx)!; pCtx.fill(); ctx.translate( -this.width / 2 - this.strokeWidth / 2, diff --git a/src/shapes/line.class.ts b/src/shapes/line.class.ts index 6bcd354df24..4a2ecc053e6 100644 --- a/src/shapes/line.class.ts +++ b/src/shapes/line.class.ts @@ -2,7 +2,7 @@ import { SHARED_ATTRIBUTES } from '../parser/attributes'; import { parseAttributes } from '../parser/parseAttributes'; import { TClassProperties } from '../typedefs'; import { classRegistry } from '../util/class_registry'; -import { cacheProperties, FabricObject } from './Object/FabricObject'; +import { FabricObject, cacheProperties } from './Object/FabricObject'; import { Point } from '../point.class'; import { isFiller } from '../util/types';