Skip to content

Commit

Permalink
Add events for script components (#6364)
Browse files Browse the repository at this point in the history
  • Loading branch information
artf authored Jan 3, 2025
1 parent cdeae9c commit 9831c9d
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 10 deletions.
22 changes: 13 additions & 9 deletions packages/core/src/canvas/view/CanvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import Frame from '../model/Frame';
import { GetBoxRectOptions, ToWorldOption } from '../types';
import FrameView from './FrameView';
import FramesView from './FramesView';
import { ComponentsEvents } from '../../dom_components/types';

export interface MarginPaddingOffsets {
marginTop?: number;
Expand Down Expand Up @@ -567,9 +568,10 @@ export default class CanvasView extends ModuleView<Canvas> {
* @private
*/
//TODO change type after the ComponentView was updated to ts
updateScript(view: any) {
const model = view.model;
const id = model.getId();
updateScript(view: ComponentView) {
const component = view.model;
const id = component.getId();
const dataToEmit = { component, view, el: view.el };

if (!view.scriptContainer) {
view.scriptContainer = createEl('div', { 'data-id': id });
Expand All @@ -582,21 +584,23 @@ export default class CanvasView extends ModuleView<Canvas> {
// In editor, I make use of setTimeout as during the append process of elements
// those will not be available immediately, therefore 'item' variable
const script = document.createElement('script');
const scriptFn = model.getScriptString();
const scriptFnStr = model.get('script-props') ? scriptFn : `function(){\n${scriptFn}\n;}`;
const scriptProps = JSON.stringify(model.__getScriptProps());
const scriptFn = component.getScriptString();
const scriptFnStr = component.get('script-props') ? scriptFn : `function(){\n${scriptFn}\n;}`;
const scriptProps = JSON.stringify(component.__getScriptProps());
script.innerHTML = `
setTimeout(function() {
var item = document.getElementById('${id}');
if (!item) return;
var script = (${scriptFnStr}).bind(item);
script(${scriptProps});
script(${scriptProps}, { el: item });
}, 1);`;
// #873
// Adding setTimeout will make js components work on init of the editor

// #873 Adding setTimeout will make js components work on init of the editor
setTimeout(() => {
component.emitWithEitor(ComponentsEvents.scriptMountBefore, dataToEmit);
const scr = view.scriptContainer;
scr?.appendChild(script);
component.emitWithEitor(ComponentsEvents.scriptMount, dataToEmit);
}, 0);
}

Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/dom_components/model/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,10 @@ export default class Component extends StyleableModel<ComponentProperties> {
});
}

emitWithEitor(event: string, data?: Record<string, any>) {
[this.em, this].forEach((item) => item?.trigger(event, data));
}

/**
* Execute callback function on itself and all inner components
* @param {Function} clb Callback function, the model is passed as an argument
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/dom_components/model/Components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ Component> {

if (!removed.opt.temporary) {
em.Commands.run('core:component-style-clear', { target: removed });
removed.views.forEach((view) => {
view.scriptContainer &&
removed.emitWithEitor(ComponentsEvents.scriptUnmount, { component: removed, view, el: view.el });
});
removed.removed();
removed.trigger('removed');
em.trigger(ComponentsEvents.remove, removed);
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/dom_components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ export enum ComponentsEvents {
select = 'component:select',
selectBefore = 'component:select:before',

/**
* @event `component:script:mount` Component with script is mounted.
* @example
* editor.on('component:script:mount', ({ component, view, el }) => { ... });
*/
scriptMount = 'component:script:mount',
scriptMountBefore = 'component:script:mount:before',

/**
* @event `component:script:unmount` Component with script is unmounted. This is triggered when the component is removed or the script execution has to be refreshed. This event might be useful to clean up resources.
* @example
* editor.on('component:script:unmount', ({ component, view, el }) => { ... });
*/
scriptUnmount = 'component:script:unmount',

/**
* @event `symbol:main:add` Added new main symbol.
* @example
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/dom_components/view/ComponentView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Component, { avoidInline } from '../model/Component';
import Components from '../model/Components';
import { ComponentOptions } from '../model/types';
import ComponentsView from './ComponentsView';
import { ComponentsEvents } from '../types';

type ClbObj = ReturnType<ComponentView['_clbObj']>;

Expand Down Expand Up @@ -515,7 +516,9 @@ TComp> {
* Recreate the element of the view
*/
reset() {
const { el } = this;
const view = this;
const { el, model } = view;
view.scriptContainer && model.emitWithEitor(ComponentsEvents.scriptUnmount, { component: model, view, el });
// @ts-ignore
this.el = '';
this._ensureElement();
Expand Down

0 comments on commit 9831c9d

Please sign in to comment.