diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/action/action-event.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/action/action-event.context.ts index 8a27568c6724..8d868d63eee0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/action/action-event.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/action/action-event.context.ts @@ -1,11 +1,29 @@ +import type { UmbEntityActionEvent } from '@umbraco-cms/backoffice/entity-action'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { Subject } from '@umbraco-cms/backoffice/external/rxjs'; export class UmbActionEventContext extends UmbContextBase { + /* It is not possible to add native event listeners to all events on a event target. + This is a workaround to be able to listen to all events. + It could potentially replace the need for the native events if we want to. */ + public readonly events = new Subject(); + constructor(host: UmbControllerHost) { super(host, UMB_ACTION_EVENT_CONTEXT); } + + /* Override the native dispatchEvent method to also push the event to the subject */ + override dispatchEvent(event: UmbEntityActionEvent): boolean { + this.events.next(event); + return super.dispatchEvent(event); + } + + // TODO: revisit this. This is currently used to prevent a + public localDispatchEvent(event: UmbEntityActionEvent) { + super.dispatchEvent(event); + } } export const UMB_ACTION_EVENT_CONTEXT = new UmbContextToken( diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action.event.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action.event.ts index c9d598d10b0a..dfdba1cc41a7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action.event.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action.event.ts @@ -26,4 +26,11 @@ export class UmbEntityActionEvent< getEventUnique(): string | undefined { return this._args.eventUnique; } + + toObject(): ArgsType { + return { + ...this._args, + type: this.type, + }; + } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity.event.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity.event.ts new file mode 100644 index 000000000000..15938b5c2586 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity.event.ts @@ -0,0 +1,12 @@ +import type { UmbEntityActionEventArgs } from './entity-action.event.js'; +import { UmbEntityActionEvent } from './entity-action.event.js'; + +interface UmbGenericEntityActionEventArgs extends UmbEntityActionEventArgs { + type: string; +} + +export class UmbEntityEvent extends UmbEntityActionEvent { + constructor(args: UmbGenericEntityActionEventArgs) { + super(args.type, args); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/event/broadcast/entity-action-event-broadcast.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/event/broadcast/entity-action-event-broadcast.manager.ts new file mode 100644 index 000000000000..14434d8c153f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/event/broadcast/entity-action-event-broadcast.manager.ts @@ -0,0 +1,37 @@ +import { UmbEntityActionEvent } from '../../entity-action.event.js'; +import { UmbEntityEvent } from '../../entity.event.js'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; + +export class UmbEntityActionEventBroadcastManager extends UmbControllerBase { + #broadcastChannel = new BroadcastChannel('umbraco-backoffice-entity-action-event'); + #actionEventContext?: typeof UMB_ACTION_EVENT_CONTEXT.TYPE; + + constructor(host: UmbControllerHost) { + super(host); + + this.consumeContext(UMB_ACTION_EVENT_CONTEXT, (context) => { + this.#actionEventContext = context; + + // Broadcast all events from the action event context to the broadcast channel + this.observe(this.#actionEventContext?.events, (event) => { + if (event instanceof UmbEntityActionEvent) { + this.#broadcastEvent(event); + } + }); + }); + + this.#broadcastChannel.onmessage = (event: MessageEvent) => { + /* We know when the event is from this channel the data will include + all the args for a UmbEntityEvent */ + const entityEvent = new UmbEntityEvent(event.data); + this.#actionEventContext?.localDispatchEvent(entityEvent); + }; + } + + #broadcastEvent(event: UmbEntityActionEvent) { + const eventObject = event.toObject(); + this.#broadcastChannel.postMessage(eventObject); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/event/broadcast/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/event/broadcast/index.ts new file mode 100644 index 000000000000..75ae01a4e58d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/event/broadcast/index.ts @@ -0,0 +1 @@ +export * from './entity-action-event-broadcast.manager.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/event/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/event/index.ts new file mode 100644 index 000000000000..2bdb3809b462 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/event/index.ts @@ -0,0 +1 @@ +export * from './broadcast/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/index.ts index 2104b5fe36f4..2c8f947b1b91 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/index.ts @@ -8,6 +8,8 @@ export * from './entity-action.event.js'; export * from './has-children/index.js'; export * from './entity-updated.event.js'; export * from './entity-deleted.event.js'; +export * from './entity.event.js'; +export * from './event/index.js'; export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts index 0a23247e5ac7..d6478a7d1b6f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts @@ -2,6 +2,7 @@ import { UMB_AUTH_CONTEXT } from './auth/auth.context.token.js'; import { UmbBackofficeNotificationContainerElement, UmbBackofficeModalContainerElement } from './components/index.js'; import { UmbActionEventContext } from './action/action-event.context.js'; import { manifests as coreManifests } from './manifests.js'; +import { UmbEntityActionEventBroadcastManager } from './entity-action/index.js'; import { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; import { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; import { UmbExtensionsApiInitializer, type UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; @@ -17,6 +18,8 @@ export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => { new UmbExtensionsApiInitializer(host, extensionRegistry, 'treeStore', [host]); new UmbExtensionsApiInitializer(host, extensionRegistry, 'itemStore', [host]); + new UmbEntityActionEventBroadcastManager(host); + extensionRegistry.registerMany(coreManifests); const notificationContainerElement = new UmbBackofficeNotificationContainerElement();