From 1ca111bc39c6bc5e1082cf50277e704541f9aa43 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 14 Mar 2022 18:39:39 +0200 Subject: [PATCH 01/16] graphemeSplit + wordSplit --- src/mixins/itext_behavior.mixin.js | 4 ++-- src/mixins/itext_key_behavior.mixin.js | 2 +- src/shapes/text.class.js | 11 ++++++++++- src/shapes/textbox.class.js | 13 +++++++++++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/mixins/itext_behavior.mixin.js b/src/mixins/itext_behavior.mixin.js index 4d075b4f4a4..2cb6c093d32 100644 --- a/src/mixins/itext_behavior.mixin.js +++ b/src/mixins/itext_behavior.mixin.js @@ -432,12 +432,12 @@ */ fromStringToGraphemeSelection: function(start, end, text) { var smallerTextStart = text.slice(0, start), - graphemeStart = fabric.util.string.graphemeSplit(smallerTextStart).length; + graphemeStart = this.graphemeSplit(smallerTextStart).length; if (start === end) { return { selectionStart: graphemeStart, selectionEnd: graphemeStart }; } var smallerTextEnd = text.slice(start, end), - graphemeEnd = fabric.util.string.graphemeSplit(smallerTextEnd).length; + graphemeEnd = this.graphemeSplit(smallerTextEnd).length; return { selectionStart: graphemeStart, selectionEnd: graphemeStart + graphemeEnd }; }, diff --git a/src/mixins/itext_key_behavior.mixin.js b/src/mixins/itext_key_behavior.mixin.js index d45217fd7c2..509f27cb100 100644 --- a/src/mixins/itext_key_behavior.mixin.js +++ b/src/mixins/itext_key_behavior.mixin.js @@ -679,7 +679,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot if (end > start) { this.removeStyleFromTo(start, end); } - var graphemes = fabric.util.string.graphemeSplit(text); + var graphemes = this.graphemeSplit(text); this.insertNewStyleBlock(graphemes, start, style); this._text = [].concat(this._text.slice(0, start), graphemes, this._text.slice(end)); this.text = this._text.join(''); diff --git a/src/shapes/text.class.js b/src/shapes/text.class.js index 2bb6bc2e5f7..cb7cba5f52f 100644 --- a/src/shapes/text.class.js +++ b/src/shapes/text.class.js @@ -1512,6 +1512,15 @@ this.callSuper('render', ctx); }, + /** + * + * @param {string} value + * @returns {string[]} array of graphemes + */ + graphemeSplit: function (value) { + return fabric.util.string.graphemeSplit(value); + }, + /** * Returns the text as an array of lines. * @param {String} text text to split @@ -1523,7 +1532,7 @@ newLine = ['\n'], newText = []; for (var i = 0; i < lines.length; i++) { - newLines[i] = fabric.util.string.graphemeSplit(lines[i]); + newLines[i] = this.graphemeSplit(lines[i]); newText = newText.concat(newLines[i], newLine); } newText.pop(); diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index 06cf7982cfc..c91d2a45670 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -298,6 +298,15 @@ return width; }, + /** + * + * @param {string} value + * @returns {string[]} array of words + */ + wordSplit: function (value) { + return value.split(this._wordJoiners); + }, + /** * Wraps a line of text using the width of the Textbox and a context. * @param {Array} line The grapheme array that represent the line @@ -313,7 +322,7 @@ graphemeLines = [], line = [], // spaces in different languages? - words = splitByGrapheme ? fabric.util.string.graphemeSplit(_line) : _line.split(this._wordJoiners), + words = splitByGrapheme ? this.graphemeSplit(_line) : this.wordSplit(_line), word = '', offset = 0, infix = splitByGrapheme ? '' : ' ', @@ -330,7 +339,7 @@ desiredWidth -= reservedSpace; for (var i = 0; i < words.length; i++) { // if using splitByGrapheme words are already in graphemes. - word = splitByGrapheme ? words[i] : fabric.util.string.graphemeSplit(words[i]); + word = splitByGrapheme ? words[i] : this.graphemeSplit(words[i]); wordWidth = this._measureWord(word, lineIndex, offset); offset += word.length; From bf8ce5d5a8675c9fcd04d961da3678f461daaafe Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 14 Mar 2022 19:09:29 +0200 Subject: [PATCH 02/16] fix flex wrap --- src/shapes/textbox.class.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index c91d2a45670..93e28da4e74 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -271,7 +271,7 @@ var wrapped = [], i; this.isWrapping = true; for (i = 0; i < lines.length; i++) { - wrapped = wrapped.concat(this._wrapLine(lines[i], i, desiredWidth)); + wrapped.push.apply(wrapped, this._wrapLine(lines[i], i, desiredWidth)); } this.isWrapping = false; return wrapped; @@ -344,7 +344,7 @@ offset += word.length; lineWidth += infixWidth + wordWidth - additionalSpace; - if (lineWidth > desiredWidth && !lineJustStarted) { + if (lineWidth > Math.max(desiredWidth, largestWordWidth) && !lineJustStarted) { graphemeLines.push(line); line = []; lineWidth = wordWidth; From 6565527588675ad12a24654fffc17bd0f8a74fe2 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 14 Mar 2022 20:46:18 +0200 Subject: [PATCH 03/16] fix(): word flickering --- src/shapes/textbox.class.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index 93e28da4e74..345209af79b 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -337,14 +337,21 @@ words.push([]); } desiredWidth -= reservedSpace; + var data = words.map(function (word) { + // if using splitByGrapheme words are already in graphemes. + word = splitByGrapheme ? word : this.graphemeSplit(word); + var width = this._measureWord(word, lineIndex); + largestWordWidth = Math.max(width, largestWordWidth); + return { word, width }; + }.bind(this)); + var maxWidth = Math.max(desiredWidth, largestWordWidth, this.dynamicMinWidth); for (var i = 0; i < words.length; i++) { - // if using splitByGrapheme words are already in graphemes. - word = splitByGrapheme ? words[i] : this.graphemeSplit(words[i]); + word = data[i].word; wordWidth = this._measureWord(word, lineIndex, offset); offset += word.length; lineWidth += infixWidth + wordWidth - additionalSpace; - if (lineWidth > Math.max(desiredWidth, largestWordWidth) && !lineJustStarted) { + if (lineWidth > maxWidth && !lineJustStarted) { graphemeLines.push(line); line = []; lineWidth = wordWidth; From 4fd6519c904fc4b0ae07a31b2ce86c672efd53fc Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 14 Mar 2022 21:04:14 +0200 Subject: [PATCH 04/16] fix(): control flickering --- src/controls.actions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controls.actions.js b/src/controls.actions.js index b66aa8cb030..e7277c72978 100644 --- a/src/controls.actions.js +++ b/src/controls.actions.js @@ -690,9 +690,9 @@ strokePadding = target.strokeWidth / (target.strokeUniform ? target.scaleX : 1), multiplier = isTransformCentered(transform) ? 2 : 1, oldWidth = target.width, - newWidth = Math.abs(localPoint.x * multiplier / target.scaleX) - strokePadding; + newWidth = Math.ceil(Math.abs(localPoint.x * multiplier / target.scaleX) - strokePadding); target.set('width', Math.max(newWidth, 0)); - return oldWidth !== newWidth; + return oldWidth !== target.width; } /** From 4d72c3492928a079c0acb449edf837a6ee2b981c Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 14 Mar 2022 21:07:21 +0200 Subject: [PATCH 05/16] lint --- src/shapes/text.class.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shapes/text.class.js b/src/shapes/text.class.js index cb7cba5f52f..aca4591a6e8 100644 --- a/src/shapes/text.class.js +++ b/src/shapes/text.class.js @@ -1513,8 +1513,8 @@ }, /** - * - * @param {string} value + * + * @param {string} value * @returns {string[]} array of graphemes */ graphemeSplit: function (value) { From 591dbb0550d48adeb40e7af9690dc8d2e8441291 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 14 Mar 2022 21:09:15 +0200 Subject: [PATCH 06/16] Update textbox.class.js --- src/shapes/textbox.class.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index 345209af79b..837238c5719 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -299,8 +299,8 @@ }, /** - * - * @param {string} value + * + * @param {string} value * @returns {string[]} array of words */ wordSplit: function (value) { @@ -338,11 +338,11 @@ } desiredWidth -= reservedSpace; var data = words.map(function (word) { - // if using splitByGrapheme words are already in graphemes. + // if using splitByGrapheme words are already in graphemes. word = splitByGrapheme ? word : this.graphemeSplit(word); var width = this._measureWord(word, lineIndex); largestWordWidth = Math.max(width, largestWordWidth); - return { word, width }; + return { word: word, width: width }; }.bind(this)); var maxWidth = Math.max(desiredWidth, largestWordWidth, this.dynamicMinWidth); for (var i = 0; i < words.length; i++) { From d0a750e5b6d3d57809c1c654f488d4efbbff357a Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 14 Mar 2022 21:12:31 +0200 Subject: [PATCH 07/16] Update controls.actions.js --- src/controls.actions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controls.actions.js b/src/controls.actions.js index e7277c72978..0883853e34d 100644 --- a/src/controls.actions.js +++ b/src/controls.actions.js @@ -692,6 +692,7 @@ oldWidth = target.width, newWidth = Math.ceil(Math.abs(localPoint.x * multiplier / target.scaleX) - strokePadding); target.set('width', Math.max(newWidth, 0)); + // check against actual target width in case `newWidth` was rejected return oldWidth !== target.width; } From b4b189055dad86db3d96da94bdf650206b8bf543 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 14 Mar 2022 21:20:03 +0200 Subject: [PATCH 08/16] Update controls_handlers.js --- test/unit/controls_handlers.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/unit/controls_handlers.js b/test/unit/controls_handlers.js index 9a30bf60b02..60f89e02738 100644 --- a/test/unit/controls_handlers.js +++ b/test/unit/controls_handlers.js @@ -21,11 +21,22 @@ }); QUnit.test('changeWidth changes the width', function(assert) { assert.equal(transform.target.width, 100); - fabric.controlsUtils.changeWidth(eventData, transform, 200, 300); + var changed = fabric.controlsUtils.changeWidth(eventData, transform, 200, 300); + assert.ok(changed, 'control changed target'); assert.equal(transform.target.width, 199); assert.equal(transform.target.left, 0); assert.equal(transform.target.top, 0); }); + QUnit.test('changeWidth does not change the width', function (assert) { + var target = new fabric.Rect({ width: 100, height: 100, canvas }); + target._set = () => { }; + assert.equal(target.width, 100); + var changed = fabric.controlsUtils.changeWidth(eventData, Object.assign({}, transform, { target }), 200, 300); + assert.ok(!changed, 'control change was rejected'); + assert.equal(target.width, 100); + assert.equal(target.left, 0); + assert.equal(target.top, 0); + }); QUnit.test('changeWidth changes the width with centered transform', function(assert) { transform.originX = 'center'; transform.originY = 'center'; From 0e2345663cf6294f930e642a52a26b3b72ac9ae1 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 14 Mar 2022 21:23:01 +0200 Subject: [PATCH 09/16] Update controls_handlers.js --- test/unit/controls_handlers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/controls_handlers.js b/test/unit/controls_handlers.js index 60f89e02738..f986eca4d58 100644 --- a/test/unit/controls_handlers.js +++ b/test/unit/controls_handlers.js @@ -62,13 +62,13 @@ transform.target.strokeUniform = true; transform.target.scaleX = 3; fabric.controlsUtils.changeWidth(eventData, transform, 200, 300); - assert.equal(Math.floor(transform.target.width), 61); + assert.equal(Math.ceil(transform.target.width), 62); }); QUnit.test('changeWidth changes the width with big strokeWidth + scaling', function(assert) { transform.target.strokeWidth = 15; transform.target.scaleX = 3; fabric.controlsUtils.changeWidth(eventData, transform, 200, 300); - assert.equal(Math.floor(transform.target.width), 51); + assert.equal(Math.ceil(transform.target.width), 52); }); QUnit.test('changeWidth will fire events on canvas and target resizing', function(assert) { var done = assert.async(); From f6864cba191c8aea1629ab4dc86c9377465e8ffa Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 21 Mar 2022 16:34:48 +0200 Subject: [PATCH 10/16] JSDOC --- src/shapes/text.class.js | 2 +- src/shapes/textbox.class.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shapes/text.class.js b/src/shapes/text.class.js index aca4591a6e8..6db8f16e532 100644 --- a/src/shapes/text.class.js +++ b/src/shapes/text.class.js @@ -1513,7 +1513,7 @@ }, /** - * + * Override this method to customize grapheme splitting * @param {string} value * @returns {string[]} array of graphemes */ diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index 837238c5719..e4f386e5287 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -299,7 +299,7 @@ }, /** - * + * Override this method to customize word splitting * @param {string} value * @returns {string[]} array of words */ From 5aa9b1b227f9eaf7fc5fc54a7d05861a0d64f9f1 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 21 Mar 2022 17:00:11 +0200 Subject: [PATCH 11/16] fix(): account for char offset/styles --- src/shapes/textbox.class.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index e4f386e5287..ee276c3ff50 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -340,14 +340,16 @@ var data = words.map(function (word) { // if using splitByGrapheme words are already in graphemes. word = splitByGrapheme ? word : this.graphemeSplit(word); - var width = this._measureWord(word, lineIndex); + var width = this._measureWord(word, lineIndex, offset); largestWordWidth = Math.max(width, largestWordWidth); + offset += word.length + 1; return { word: word, width: width }; }.bind(this)); var maxWidth = Math.max(desiredWidth, largestWordWidth, this.dynamicMinWidth); + offset = 0; for (var i = 0; i < words.length; i++) { word = data[i].word; - wordWidth = this._measureWord(word, lineIndex, offset); + wordWidth = data[i].width; offset += word.length; lineWidth += infixWidth + wordWidth - additionalSpace; @@ -369,10 +371,6 @@ infixWidth = splitByGrapheme ? 0 : this._measureWord([infix], lineIndex, offset); offset++; lineJustStarted = false; - // keep track of largest word - if (wordWidth > largestWordWidth) { - largestWordWidth = wordWidth; - } } i && graphemeLines.push(line); From 4f4d400cace8d3820a172d65796bdd5b1a6ae640 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 21 Mar 2022 17:04:37 +0200 Subject: [PATCH 12/16] **BREAKING**: rename method make public for overriding --- src/shapes/textbox.class.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index ee276c3ff50..64d32d0c161 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -279,15 +279,16 @@ /** * Helper function to measure a string of text, given its lineIndex and charIndex offset - * it gets called when charBounds are not available yet. + * It gets called when charBounds are not available yet. + * Override if necessary + * * @param {CanvasRenderingContext2D} ctx * @param {String} text * @param {number} lineIndex * @param {number} charOffset * @returns {number} - * @private */ - _measureWord: function(word, lineIndex, charOffset) { + measureWord: function(word, lineIndex, charOffset) { var width = 0, prevGrapheme, skipLeft = true; charOffset = charOffset || 0; for (var i = 0, len = word.length; i < len; i++) { @@ -340,7 +341,7 @@ var data = words.map(function (word) { // if using splitByGrapheme words are already in graphemes. word = splitByGrapheme ? word : this.graphemeSplit(word); - var width = this._measureWord(word, lineIndex, offset); + var width = this.measureWord(word, lineIndex, offset); largestWordWidth = Math.max(width, largestWordWidth); offset += word.length + 1; return { word: word, width: width }; @@ -368,7 +369,7 @@ } line = line.concat(word); - infixWidth = splitByGrapheme ? 0 : this._measureWord([infix], lineIndex, offset); + infixWidth = splitByGrapheme ? 0 : this.measureWord([infix], lineIndex, offset); offset++; lineJustStarted = false; } From d1113bcf66b4698a1568a63f2db0f1facadd8d17 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 21 Mar 2022 17:06:30 +0200 Subject: [PATCH 13/16] Update textbox.class.js --- src/shapes/textbox.class.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index 64d32d0c161..f517f94af10 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -281,6 +281,7 @@ * Helper function to measure a string of text, given its lineIndex and charIndex offset * It gets called when charBounds are not available yet. * Override if necessary + * Use with {@link fabric.Textbox#wordSplit} * * @param {CanvasRenderingContext2D} ctx * @param {String} text @@ -301,6 +302,7 @@ /** * Override this method to customize word splitting + * Use with {@link fabric.Textbox#measureWord} * @param {string} value * @returns {string[]} array of words */ From 12438915b325c377c8ac104e057e246adde2342c Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 21 Mar 2022 17:15:00 +0200 Subject: [PATCH 14/16] Update textbox.class.js --- src/shapes/textbox.class.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index f517f94af10..77827b62ac7 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -340,6 +340,7 @@ words.push([]); } desiredWidth -= reservedSpace; + // measure words var data = words.map(function (word) { // if using splitByGrapheme words are already in graphemes. word = splitByGrapheme ? word : this.graphemeSplit(word); @@ -349,6 +350,7 @@ return { word: word, width: width }; }.bind(this)); var maxWidth = Math.max(desiredWidth, largestWordWidth, this.dynamicMinWidth); + // layout words offset = 0; for (var i = 0; i < words.length; i++) { word = data[i].word; From bb2627100585b2424c9032742565aa7ff5f0fe90 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 22 Mar 2022 10:16:24 +0200 Subject: [PATCH 15/16] revert rename now PR is non breaking --- src/shapes/textbox.class.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index 77827b62ac7..ce423a2de81 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -289,7 +289,7 @@ * @param {number} charOffset * @returns {number} */ - measureWord: function(word, lineIndex, charOffset) { + _measureWord: function(word, lineIndex, charOffset) { var width = 0, prevGrapheme, skipLeft = true; charOffset = charOffset || 0; for (var i = 0, len = word.length; i < len; i++) { @@ -302,7 +302,7 @@ /** * Override this method to customize word splitting - * Use with {@link fabric.Textbox#measureWord} + * Use with {@link fabric.Textbox#_measureWord} * @param {string} value * @returns {string[]} array of words */ @@ -344,7 +344,7 @@ var data = words.map(function (word) { // if using splitByGrapheme words are already in graphemes. word = splitByGrapheme ? word : this.graphemeSplit(word); - var width = this.measureWord(word, lineIndex, offset); + var width = this._measureWord(word, lineIndex, offset); largestWordWidth = Math.max(width, largestWordWidth); offset += word.length + 1; return { word: word, width: width }; @@ -373,7 +373,7 @@ } line = line.concat(word); - infixWidth = splitByGrapheme ? 0 : this.measureWord([infix], lineIndex, offset); + infixWidth = splitByGrapheme ? 0 : this._measureWord([infix], lineIndex, offset); offset++; lineJustStarted = false; } From ff6b99db3241b75ac479b64ace8756671d2924f6 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 22 Mar 2022 10:54:35 +0200 Subject: [PATCH 16/16] fix(tests): wrong textbox tests --- test/unit/textbox.js | 63 +++++++++++++------------------------------- 1 file changed, 18 insertions(+), 45 deletions(-) diff --git a/test/unit/textbox.js b/test/unit/textbox.js index 90f8ff75461..636b48dd5fa 100644 --- a/test/unit/textbox.js +++ b/test/unit/textbox.js @@ -440,58 +440,31 @@ assert.deepEqual(textbox.styles[0], {}, 'style is an empty object'); }); - QUnit.test('_deleteStyleDeclaration', function(assert) { - var textbox = new fabric.Textbox('aaa aaq ggg gg oee eee', { - styles: { - 0: { - 0: { fontSize: 4 }, - 1: { fontSize: 4 }, - 2: { fontSize: 4 }, - 3: { fontSize: 4 }, - 4: { fontSize: 4 }, - 5: { fontSize: 4 }, - 6: { fontSize: 4 }, - 7: { fontSize: 4 }, - 8: { fontSize: 4 }, - 9: { fontSize: 4 }, - 10: { fontSize: 4 }, - 11: { fontSize: 4 }, - 12: { fontSize: 4 }, - 13: { fontSize: 4 }, - 14: { fontSize: 4 }, - 15: { fontSize: 4 }, - 16: { fontSize: 4 }, - }, - }, + QUnit.test('_deleteStyleDeclaration', function (assert) { + var text = 'aaa aaq ggg gg oee eee'; + var styles = {}; + for (var index = 0; index < text.length; index++) { + styles[index] = { fontSize: 4 }; + + } + var textbox = new fabric.Textbox(text, { + styles: { 0: styles }, width: 5, }); + assert.equal(typeof textbox._deleteStyleDeclaration, 'function', 'function exists'); textbox._deleteStyleDeclaration(2, 2); assert.equal(textbox.styles[0][10], undefined, 'style has been removed'); }); QUnit.test('_setStyleDeclaration', function(assert) { - var textbox = new fabric.Textbox('aaa aaq ggg gg oee eee', { - styles: { - 0: { - 0: { fontSize: 4 }, - 1: { fontSize: 4 }, - 2: { fontSize: 4 }, - 3: { fontSize: 4 }, - 4: { fontSize: 4 }, - 5: { fontSize: 4 }, - 6: { fontSize: 4 }, - 7: { fontSize: 4 }, - 8: { fontSize: 4 }, - 9: { fontSize: 4 }, - 10: { fontSize: 4 }, - 11: { fontSize: 4 }, - 12: { fontSize: 4 }, - 13: { fontSize: 4 }, - 14: { fontSize: 4 }, - 15: { fontSize: 4 }, - 16: { fontSize: 4 }, - }, - }, + var text = 'aaa aaq ggg gg oee eee'; + var styles = {}; + for (var index = 0; index < text.length; index++) { + styles[index] = { fontSize: 4 }; + + } + var textbox = new fabric.Textbox(text, { + styles: { 0: styles }, width: 5, }); assert.equal(typeof textbox._setStyleDeclaration, 'function', 'function exists');