diff --git a/packages/core/src/asset_manager/model/Asset.ts b/packages/core/src/asset_manager/model/Asset.ts index 91d80a9976..3d54b3b1a3 100644 --- a/packages/core/src/asset_manager/model/Asset.ts +++ b/packages/core/src/asset_manager/model/Asset.ts @@ -38,7 +38,7 @@ export default class Asset extends Model { * asset.getSrc(); // -> 'https://.../image.png' * */ getSrc() { - return this.get('src'); + return this.get('src') || ''; } /** @@ -51,7 +51,7 @@ export default class Asset extends Model { * asset.getFilename(); // -> 'image' * */ getFilename() { - return this.get('src').split('/').pop().split('?').shift(); + return this.getSrc().split('/').pop().split('?').shift(); } /** diff --git a/packages/core/src/editor/index.ts b/packages/core/src/editor/index.ts index 650be53388..20d738360c 100644 --- a/packages/core/src/editor/index.ts +++ b/packages/core/src/editor/index.ts @@ -567,11 +567,12 @@ export default class Editor implements IBaseModule { /** * Load data from the JSON project * @param {Object} data Project to load + * @param {Object} [options] Custom options that could be passed to the project load events. * @example * editor.loadProjectData({ pages: [...], styles: [...], ... }) */ - loadProjectData(data: ProjectData) { - return this.em.loadData(data); + loadProjectData(data: ProjectData, options: EditorLoadOptions & Record = {}) { + return this.em.loadData(data, options); } storeData() { diff --git a/packages/core/src/editor/model/Editor.ts b/packages/core/src/editor/model/Editor.ts index 3ee5c87cb0..5fb4ac3296 100644 --- a/packages/core/src/editor/model/Editor.ts +++ b/packages/core/src/editor/model/Editor.ts @@ -71,11 +71,11 @@ const deps: (new (em: EditorModel) => IModule)[] = [ DataSourceManager, ]; const storableDeps: (new (em: EditorModel) => IModule & IStorableModule)[] = [ + DataSourceManager, // Ensure DS are loaded before other modules AssetManager, CssComposer, PageManager, ComponentManager, - DataSourceManager, ]; Extender({ $ }); @@ -115,6 +115,7 @@ export default class EditorModel extends Model { events = EditorEvents; __skip = false; defaultRunning = false; + loadTriggered = false; destroyed = false; _config: InitEditorConfig; _storageTimeout?: ReturnType; @@ -460,7 +461,7 @@ export default class EditorModel extends Model { * */ handleUpdates(model: any, val: any, opt: any = {}) { // Component has been added temporarily - do not update storage or record changes - if (this.__skip || opt.temporary || opt.noCount || opt.avoidStore || opt.partial || !this.get('ready')) { + if (this.__skip || !this.loadTriggered || opt.temporary || opt.noCount || opt.avoidStore || opt.partial) { return; } @@ -906,14 +907,16 @@ export default class EditorModel extends Model { return project; } - loadData(project: ProjectData = {}, opts: EditorLoadOptions = {}): ProjectData { + loadData(project: ProjectData = {}, options: EditorLoadOptions = {}): ProjectData { + const evData = { project, options, initial: !!options.initial }; let loaded = false; if (!isEmptyObj(project)) { this.storables.forEach((module) => module.clear()); this.storables.forEach((module) => module.load(project)); loaded = true; } - this.trigger(EditorEvents.projectLoad, { project, loaded, initial: !!opts.initial }); + this.trigger(EditorEvents.projectLoad, { ...evData, loaded }); + loaded && this.trigger(EditorEvents.projectLoaded, evData); return project; } diff --git a/packages/core/src/editor/types.ts b/packages/core/src/editor/types.ts index 58ee3ad662..9c4a709552 100644 --- a/packages/core/src/editor/types.ts +++ b/packages/core/src/editor/types.ts @@ -35,6 +35,16 @@ export enum EditorEvents { */ projectLoad = 'project:load', + /** + * @event `project:loaded` Similar to `project:load`, but triggers only if the project is loaded successfully. + * @example + * editor.on('project:loaded', ({ project, initial }) => { ... }); + * + * // Loading an empty project, won't trigger this event. + * editor.loadProjectData({}); + */ + projectLoaded = 'project:loaded', + /** * @event `project:get` Event triggered on request of the project data. This can be used to extend the project with custom data. * @example diff --git a/packages/core/src/editor/view/EditorView.ts b/packages/core/src/editor/view/EditorView.ts index a45d063271..2958557e5b 100644 --- a/packages/core/src/editor/view/EditorView.ts +++ b/packages/core/src/editor/view/EditorView.ts @@ -12,7 +12,6 @@ export default class EditorView extends View { model.once('change:ready', () => { Panels.active(); Panels.disableButtons(); - UndoManager.clear(); if (model.getConfig().telemetry) { this.sendTelemetryData().catch(() => { @@ -22,6 +21,8 @@ export default class EditorView extends View { setTimeout(() => { model.trigger(EditorEvents.load, model.Editor); + model.loadTriggered = true; + UndoManager.clear(); model.clearDirtyCount(); }); }); diff --git a/packages/core/src/utils/Resizer.ts b/packages/core/src/utils/Resizer.ts index 3cc39b5e61..6275dc8a89 100644 --- a/packages/core/src/utils/Resizer.ts +++ b/packages/core/src/utils/Resizer.ts @@ -581,7 +581,7 @@ export default class Resizer { this.updateRect(true, ev); } - this.selectedHandler?.releasePointerCapture(ev.pointerId); + ev.pointerId && this.selectedHandler?.releasePointerCapture(ev.pointerId); this.toggleFrames(); this.onEnd?.(ev, { docs, config, el, resizer: this }); this.moved = false;