diff --git a/packages/core/src/editor/index.ts b/packages/core/src/editor/index.ts index 2ea4967b3..b5174084f 100644 --- a/packages/core/src/editor/index.ts +++ b/packages/core/src/editor/index.ts @@ -91,6 +91,7 @@ import UtilsModule from '../utils'; import html from '../utils/html'; import defConfig, { EditorConfig, EditorConfigKeys } from './config/config'; import EditorModel, { EditorLoadOptions } from './model/Editor'; +import { EditorEvents } from './types'; import EditorView from './view/EditorView'; export type ParsedRule = { @@ -130,6 +131,7 @@ export default class Editor implements IBaseModule { $: any; em: EditorModel; config: EditorConfigType; + events = EditorEvents; constructor(config: EditorConfig = {}, opts: any = {}) { const defaults = defConfig(); diff --git a/packages/core/src/editor/model/Editor.ts b/packages/core/src/editor/model/Editor.ts index fe2d85e13..034b1522b 100644 --- a/packages/core/src/editor/model/Editor.ts +++ b/packages/core/src/editor/model/Editor.ts @@ -45,6 +45,7 @@ import { CanvasSpotBuiltInTypes } from '../../canvas/model/CanvasSpot'; import DataSourceManager from '../../data_sources'; import { ComponentsEvents } from '../../dom_components/types'; import { InitEditorConfig } from '../..'; +import { EditorEvents } from '../types'; Backbone.$ = $; @@ -89,6 +90,7 @@ const logs = { export interface EditorLoadOptions { /** Clear the editor state (eg. dirty counter, undo manager, etc.). */ clear?: boolean; + initial?: boolean; } export default class EditorModel extends Model { @@ -333,6 +335,7 @@ export default class EditorModel extends Model { */ loadOnStart() { const { projectData, headless } = this.config; + const loadOpts: EditorLoadOptions = { initial: true }; const sm = this.Storage; // In `onLoad`, the module will try to load the data from its configurations. @@ -345,16 +348,16 @@ export default class EditorModel extends Model { }; if (headless) { - projectData && this.loadData(projectData); + projectData && this.loadData(projectData, loadOpts); postLoad(); } else { // Defer for storage load events. this._storageTimeout = setTimeout(async () => { if (projectData) { - this.loadData(projectData); + this.loadData(projectData, loadOpts); } else if (sm?.canAutoload()) { try { - await this.load(); + await this.load({}, loadOpts); } catch (error) { this.logError(error as string); } @@ -388,7 +391,7 @@ export default class EditorModel extends Model { if (!opts.isClear) { this.updateItr && clearTimeout(this.updateItr); - this.updateItr = setTimeout(() => this.trigger('update')); + this.updateItr = setTimeout(() => this.trigger(EditorEvents.update)); } if (this.config.noticeOnUnload) { @@ -851,7 +854,7 @@ export default class EditorModel extends Model { */ async load(options?: T, loadOptions: EditorLoadOptions = {}) { const result = await this.Storage.load(options); - this.loadData(result); + this.loadData(result, loadOptions); // Wait in order to properly update the dirty counter (#5385) await wait(); @@ -875,12 +878,15 @@ export default class EditorModel extends Model { return JSON.parse(JSON.stringify(result)); } - loadData(data: ProjectData = {}): ProjectData { - if (!isEmptyObj(data)) { + loadData(project: ProjectData = {}, opts: EditorLoadOptions = {}): ProjectData { + let loaded = false; + if (!isEmptyObj(project)) { this.storables.forEach((module) => module.clear()); - this.storables.forEach((module) => module.load(data)); + this.storables.forEach((module) => module.load(project)); + loaded = true; } - return data; + this.trigger(EditorEvents.projectLoad, { project, loaded, initial: !!opts.initial }); + return project; } /** @@ -1025,7 +1031,7 @@ export default class EditorModel extends Model { */ destroyAll() { const { config, view } = this; - this.trigger('destroy'); + this.trigger(EditorEvents.destroy); const editor = this.getEditor(); // @ts-ignore const { editors = [] } = config.grapesjs || {}; @@ -1048,7 +1054,7 @@ export default class EditorModel extends Model { editors.splice(editors.indexOf(editor), 1); //@ts-ignore hasWin() && $(config.el).empty().attr(this.attrsOrig); - this.trigger('destroyed'); + this.trigger(EditorEvents.destroyed); } getEditing(): Component | undefined { @@ -1066,12 +1072,13 @@ export default class EditorModel extends Model { } log(msg: string, opts: any = {}) { + const logEvent = EditorEvents.log; const { ns, level = 'debug' } = opts; - this.trigger('log', msg, opts); - level && this.trigger(`log:${level}`, msg, opts); + this.trigger(logEvent, msg, opts); + level && this.trigger(`${logEvent}:${level}`, msg, opts); if (ns) { - const logNs = `log-${ns}`; + const logNs = `${logEvent}-${ns}`; this.trigger(logNs, msg, opts); level && this.trigger(`${logNs}:${level}`, msg, opts); } diff --git a/packages/core/src/editor/types.ts b/packages/core/src/editor/types.ts new file mode 100644 index 000000000..b39431c37 --- /dev/null +++ b/packages/core/src/editor/types.ts @@ -0,0 +1,52 @@ +/**{START_EVENTS}*/ +export enum EditorEvents { + /** + * @event `update` Event triggered on any change of the project (eg. component added/removed, style changes, etc.) + * @example + * editor.on('update', () => { ... }); + */ + update = 'update', + + /** + * @event `undo` Undo executed. + * @example + * editor.on('undo', () => { ... }); + */ + undo = 'undo', + + /** + * @event `redo` Redo executed. + * @example + * editor.on('redo', () => { ... }); + */ + redo = 'redo', + + /** + * @event `project:load` Project JSON loaded in the editor. The event is triggered on the initial load and on the `editor.loadProjectData` method. + * @example + * editor.on('project:load', ({ project, initial }) => { ... }); + */ + projectLoad = 'project:load', + + /** + * @event `log` Log message triggered. + * @example + * editor.on('log', (msg, opts) => { ... }); + */ + log = 'log', + + /** + * @event `destroy` Editor started destroy (on `editor.destroy()`). + * @example + * editor.on('destroy', () => { ... }); + */ + destroy = 'destroy', + + /** + * @event `destroyed` Editor destroyed. + * @example + * editor.on('destroyed', () => { ... }); + */ + destroyed = 'destroyed', +} +/**{END_EVENTS}*/ diff --git a/packages/core/src/undo_manager/index.ts b/packages/core/src/undo_manager/index.ts index 5ff3c2ba0..07deafeaa 100644 --- a/packages/core/src/undo_manager/index.ts +++ b/packages/core/src/undo_manager/index.ts @@ -29,6 +29,7 @@ import { isArray, isBoolean, isEmpty, unique, times } from 'underscore'; import { Module } from '../abstract'; import EditorModel from '../editor/model/Editor'; import defConfig, { UndoManagerConfig } from './config'; +import { EditorEvents } from '../editor/types'; export interface UndoGroup { index: number; @@ -144,7 +145,7 @@ export default class UndoManagerModule extends Module { em.getSelectedAll().map((c) => c.trigger('rerender:layer')); }); - ['undo', 'redo'].forEach((ev) => this.um.on(ev, () => em.trigger(ev))); + [EditorEvents.undo, EditorEvents.redo].forEach((ev) => this.um.on(ev, () => em.trigger(ev))); } postLoad() {