diff --git a/packages/core/package.json b/packages/core/package.json index 0006d1dcc..4ceaf21e9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "grapesjs", "description": "Free and Open Source Web Builder Framework", - "version": "0.22.3", + "version": "0.22.4", "author": "Artur Arseniev", "license": "BSD-3-Clause", "homepage": "http://grapesjs.com", diff --git a/packages/core/src/dom_components/model/Components.ts b/packages/core/src/dom_components/model/Components.ts index a8d225412..26b609155 100644 --- a/packages/core/src/dom_components/model/Components.ts +++ b/packages/core/src/dom_components/model/Components.ts @@ -63,15 +63,20 @@ const getComponentsFromDefs = ( } } + // Here `result` might be a Component + const cmp = isFunction(result.components) ? (result as unknown as Component) : null; + if (components) { - const newComponents = getComponentsFromDefs(components, all); + const newComponents = getComponentsFromDefs(components, all, opts); - if (isFunction(result.components)) { - const cmps = result.components(); - cmps.length > 0 && cmps.reset(newComponents, opts); + if (cmp) { + cmp.components().reset(newComponents, opts); } else { result.components = newComponents; } + } else if (cmp) { + // The component already exists but the parsed one is without components + cmp.components().reset([], opts); } return result; diff --git a/packages/core/src/dom_components/view/ComponentImageView.ts b/packages/core/src/dom_components/view/ComponentImageView.ts index d127bfc99..19d9de56b 100644 --- a/packages/core/src/dom_components/view/ComponentImageView.ts +++ b/packages/core/src/dom_components/view/ComponentImageView.ts @@ -95,9 +95,12 @@ export default class ComponentImageView { const hoveredCls = `${ppfx}hovered`; const noPointerCls = `${ppfx}no-pointer`; const pointerInitCls = `${ppfx}pointer-init`; - const toRemove = [selectedCls, selectedParentCls, freezedCls, hoveredCls, noPointerCls]; + const toRemove = [selectedCls, selectedParentCls, freezedCls, hoveredCls, noPointerCls, pointerInitCls]; const selCls = extHl && !opts.noExtHl ? '' : selectedCls; this.$el.removeClass(toRemove.join(' ')); const actualCls = el.getAttribute('class') || ''; diff --git a/packages/core/src/rich_text_editor/config/config.ts b/packages/core/src/rich_text_editor/config/config.ts index 961d108f0..e8a42cbcc 100644 --- a/packages/core/src/rich_text_editor/config/config.ts +++ b/packages/core/src/rich_text_editor/config/config.ts @@ -1,6 +1,12 @@ +import ComponentTextView from '../../dom_components/view/ComponentTextView'; import Editor from '../../editor'; import RichTextEditor from '../model/RichTextEditor'; +export interface CustomRteOptions { + event?: MouseEvent; + view: ComponentTextView; +} + export interface CustomRTE { /** * If true, the returned HTML content will be parsed into Components, allowing @@ -11,16 +17,16 @@ export interface CustomRTE { /** * Create or enable the custom RTE. */ - enable: (el: HTMLElement, rte: T | undefined) => T | Promise; + enable: (el: HTMLElement, rte: T | undefined, opts: CustomRteOptions) => T | Promise; /** * Disable the custom RTE. */ - disable: (el: HTMLElement, rte: T) => any | Promise; + disable: (el: HTMLElement, rte: T, opts: CustomRteOptions) => any | Promise; /** * Get HTML content from the custom RTE. * If not specified, it will use the innerHTML of the element (passed also as `content` in options). */ - getContent?: (el: HTMLElement, rte: T | undefined) => string | Promise; + getContent?: (el: HTMLElement, rte: T | undefined, opts: CustomRteOptions) => string | Promise; /** * Destroy the custom RTE. * Will be triggered on editor destroy. diff --git a/packages/core/src/rich_text_editor/index.ts b/packages/core/src/rich_text_editor/index.ts index 05fe6fe93..10e246051 100644 --- a/packages/core/src/rich_text_editor/index.ts +++ b/packages/core/src/rich_text_editor/index.ts @@ -40,14 +40,14 @@ import { debounce, isFunction, isString } from 'underscore'; import { Module } from '../abstract'; import { Debounced, DisableOptions, Model } from '../common'; -import ComponentView from '../dom_components/view/ComponentView'; import EditorModel from '../editor/model/Editor'; import { createEl, cx, on, removeEl } from '../utils/dom'; import { hasWin, isDef } from '../utils/mixins'; -import defConfig, { CustomRTE, RichTextEditorConfig } from './config/config'; +import defConfig, { CustomRTE, CustomRteOptions, RichTextEditorConfig } from './config/config'; import RichTextEditor, { RichTextEditorAction } from './model/RichTextEditor'; import CanvasEvents from '../canvas/types'; import { ComponentsEvents } from '../dom_components/types'; +import ComponentTextView from '../dom_components/view/ComponentTextView'; export type RichTextEditorEvent = 'rte:enable' | 'rte:disable' | 'rte:custom'; @@ -64,7 +64,7 @@ const events = { }; interface ModelRTE { - currentView?: ComponentView; + currentView?: ComponentTextView; } export interface RteDisableResult { @@ -360,13 +360,13 @@ export default class RichTextEditorModule extends Module { const result = model.getAttributes(); expect(result.class).toEqual(undefined); }); + + test('updateStatus removes previous classes and adds new ones', () => { + model.addClass('selected'); + + model.set('locked', true); + view.updateStatus(); + expect(view.el.getAttribute('class')).toEqual('no-pointer'); + + model.set('locked', false); + view.updateStatus(); + expect(view.el.getAttribute('class')).toEqual('pointer-init'); + + model.set('locked'); + view.updateStatus(); + expect(view.el.getAttribute('class')).toEqual(''); + }); });