From d3abac15efa2cd2b6001e01241ec8de3e9745bfc Mon Sep 17 00:00:00 2001 From: Collins Lagat <40242691+collins-lagat@users.noreply.github.com> Date: Mon, 22 Aug 2022 14:55:32 +0300 Subject: [PATCH] Fix: `"TypeError: this.parseStyle is not a function"` when `setStyles` is called internally (bug introduced in GrapesJS v19.5) (#4520) * wrap `ParserHtml().parseStyle` around a class method currently when the model is extended via the `.extend` method, the `parseStyle` property is "hoisted" from the parent to the child. ideally, it should be be located on the parent which is the `prototype` of the child. the consequence of this is that when you run: `Object.hasOwnProperty.call(child, 'parseStyle')`, you get `true`. this is problematic as `parseStyle` is required by `setStyle` of `Dom_Components::Model::Component` which expects `parseStyle` to exist on its prototype (`StyleableModel`). But `parseStyle` is "hoisted" to be the property of any component that extends `Dom_Components::Model::Component`, thus, `this.parseStyle` will always be `undefined` when its called by any method that exists in objects that are lower in the prototypal chain than the topmost object (where `parseStyle` is defined). If `setStyle` is called further down the prototypal chain, it throws the following error: `"this.parseStyle is not a function"` * fix: prevent requesting a new parser on each parse --- src/domain_abstract/model/StyleableModel.js | 11 +++++++++- test/specs/dom_components/model/Component.js | 23 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/domain_abstract/model/StyleableModel.js b/src/domain_abstract/model/StyleableModel.js index 593a42bff..4b0e8077e 100644 --- a/src/domain_abstract/model/StyleableModel.js +++ b/src/domain_abstract/model/StyleableModel.js @@ -3,8 +3,17 @@ import { shallowDiff } from '../../utils/mixins'; import ParserHtml from '../../parser/model/ParserHtml'; import { Model } from '../../common'; +const parserHtml = ParserHtml(); + export default class StyleableModel extends Model { - parseStyle = ParserHtml().parseStyle; + /** + * Forward style string to `parseStyle` to be parse to an object + * @param {string} str + * @returns + */ + parseStyle(str) { + return parserHtml.parseStyle(str); + } /** * To trigger the style change event on models I have to diff --git a/test/specs/dom_components/model/Component.js b/test/specs/dom_components/model/Component.js index 46bcbe922..0ea337fd3 100644 --- a/test/specs/dom_components/model/Component.js +++ b/test/specs/dom_components/model/Component.js @@ -417,6 +417,29 @@ describe('Component', () => { }; newObj.components().each(model => inhereted(model)); }); + + test('setStyle parses styles correctly', () => { + const styles = 'padding: 12px;height:auto;'; + const expectedObj = { + padding: '12px', + height: 'auto', + }; + + const c = new Component(); + + expect(c.setStyle(styles)).toEqual(expectedObj); + }); + + test('setStyle should be called successfully when invoked internally', () => { + const ExtendedComponent = Component.extend({ + init() { + const styles = 'padding: 12px;height:auto;'; + this.setStyle(styles); + }, + }); + + expect(() => new ExtendedComponent()).not.toThrowError(); + }); }); describe('Image Component', () => {