diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/manager/block-list-manager.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/manager/block-list-manager.context.ts index 4f32598ee1..a53003c06a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/manager/block-list-manager.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/manager/block-list-manager.context.ts @@ -1,5 +1,5 @@ import type { UmbBlockListLayoutModel, UmbBlockListTypeModel } from '../types.js'; -import { UmbBlockManagerContext } from '@umbraco-cms/backoffice/block'; +import { UmbBlockManagerContext } from '../../block/manager/block-manager.context.js'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts index c897630ce7..4e779bc0bc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts @@ -86,6 +86,8 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement //config.useLiveEditing //config.useInlineEditingAsDefault this.style.maxWidth = config.getValueByAlias('maxPropertyWidth') ?? ''; + + this.#context.setEditorConfiguration(config); } @state() diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context-token.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context-token.ts new file mode 100644 index 0000000000..eb7dacc74b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context-token.ts @@ -0,0 +1,4 @@ +import type { UmbBlockManagerContext } from './block-manager.context.js'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; + +export const UMB_BLOCK_MANAGER_CONTEXT = new UmbContextToken('UmbBlockManagerContext'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context.ts index c5c713f38e..4baf548c1b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context.ts @@ -1,14 +1,18 @@ -import type { UmbBlockLayoutBaseModel, UmbBlockDataType } from '..//types.js'; -import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; +import type { UmbBlockLayoutBaseModel, UmbBlockDataType } from '../types.js'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbArrayState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, UmbClassState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type'; import { buildUdi, getKeyFromUdi } from '@umbraco-cms/backoffice/utils'; -import { UmbBlockTypeBaseModel } from '@umbraco-cms/backoffice/block'; -import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal'; +import { + UMB_BLOCK_MANAGER_CONTEXT, + UMB_BLOCK_WORKSPACE_MODAL, + UmbBlockTypeBaseModel, +} from '@umbraco-cms/backoffice/block'; +import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal'; import { UmbContentTypeModel } from '@umbraco-cms/backoffice/content-type'; import { UmbId } from '@umbraco-cms/backoffice/id'; +import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor'; // TODO: We are using backend model here, I think we should get our own model: type ElementTypeModel = UmbContentTypeModel; @@ -29,6 +33,9 @@ export abstract class UmbBlockManagerContext< #blockTypes = new UmbArrayState(>[], (x) => x.contentElementTypeKey); public readonly blockTypes = this.#blockTypes.asObservable(); + #editorConfiguration = new UmbClassState(undefined); + public readonly editorConfiguration = this.#editorConfiguration.asObservable(); + #layouts = new UmbArrayState(>[], (x) => x.contentUdi); public readonly layouts = this.#layouts.asObservable(); @@ -38,6 +45,10 @@ export abstract class UmbBlockManagerContext< #settings = new UmbArrayState(>[], (x) => x.udi); public readonly settings = this.#settings.asObservable(); + setEditorConfiguration(configs: UmbPropertyEditorConfigCollection) { + this.#editorConfiguration.setValue(configs); + } + setBlockTypes(blockTypes: Array) { this.#blockTypes.setValue(blockTypes); } @@ -59,9 +70,8 @@ export abstract class UmbBlockManagerContext< constructor(host: UmbControllerHost) { super(host, UMB_BLOCK_MANAGER_CONTEXT); - // TODO: Make specific modal token that requires data. // IDEA: Make a Workspace registration controller that can be used to register a workspace, which does both edit and create?. - new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL) + new UmbModalRouteRegistrationController(this, UMB_BLOCK_WORKSPACE_MODAL) .addAdditionalPath('block') .onSetup(() => { return { data: { entityType: 'block', preset: {} }, modal: { size: 'medium' } }; @@ -185,7 +195,3 @@ export abstract class UmbBlockManagerContext< this.#contents.removeOne(contentUdi); } } - -export const UMB_BLOCK_MANAGER_CONTEXT = new UmbContextToken( - 'UmbBlockManagerContext', -); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/index.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/index.ts index 6303015d84..631569a5df 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/index.ts @@ -1 +1 @@ -export * from './block-manager.context.js'; +export * from './block-manager.context-token.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index 8558c4e029..f1f1482956 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -7,6 +7,7 @@ import { ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry'; import { UmbId } from '@umbraco-cms/backoffice/id'; import { UMB_BLOCK_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/block'; import { buildUdi } from '@umbraco-cms/backoffice/utils'; +import { UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal'; export class UmbBlockWorkspaceContext< LayoutDataType extends UmbBlockLayoutBaseModel = UmbBlockLayoutBaseModel, @@ -18,12 +19,15 @@ export class UmbBlockWorkspaceContext< #blockManager?: typeof UMB_BLOCK_MANAGER_CONTEXT.TYPE; #retrieveBlockManager; + #editorConfigPromise?: Promise; #entityType: string; #isNew = new UmbBooleanState(undefined); readonly isNew = this.#isNew.asObservable(); + #liveEditingMode?: boolean; + #layout = new UmbObjectState(undefined); readonly layout = this.#layout.asObservable(); //readonly unique = this.#layout.asObservablePart((x) => x?.contentUdi); @@ -43,13 +47,25 @@ export class UmbBlockWorkspaceContext< this.#entityType = workspaceArgs.manifest.meta?.entityType; this.workspaceAlias = workspaceArgs.manifest.alias; + this.consumeContext(UMB_MODAL_CONTEXT_TOKEN, (context) => { + context.onSubmit().catch(this.#modalRejected); + }); + this.#retrieveBlockManager = this.consumeContext(UMB_BLOCK_MANAGER_CONTEXT, (context) => { this.#blockManager = context; + this.#editorConfigPromise = this.observe(context.editorConfiguration, (editorConfigs) => { + if (editorConfigs) { + const value = editorConfigs.getValueByAlias('useLiveEditing'); + this.#liveEditingMode = value; + } + }).asPromise(); + // TODO: Observe or just get the LiveEditing setting? }).asPromise(); } async load(unique: string) { await this.#retrieveBlockManager; + await this.#editorConfigPromise; if (!this.#blockManager) { throw new Error('Block manager not found'); return; @@ -60,7 +76,6 @@ export class UmbBlockWorkspaceContext< (layoutData) => { this.#layout.setValue(layoutData as LayoutDataType); - // // Content: const contentUdi = layoutData?.contentUdi; if (contentUdi) { @@ -88,20 +103,9 @@ export class UmbBlockWorkspaceContext< 'observeLayout', ); - /* - if ( liveEditingMode) { - this.observe(this.layout, (layoutData) => { - if(layoutData) { - this.#blockManager?.setOneLayout(layoutData); - } - }); - this.observe(this.content.data, (contentData) => { - if(contentData) { - this.#blockManager?.setOneContent(contentData); - } - }); + if (this.#liveEditingMode) { + this.#establishLiveSync(); } - */ } async create(contentElementTypeId: string) { @@ -122,6 +126,28 @@ export class UmbBlockWorkspaceContext< this.setIsNew(true); this.#layout.setValue(layout as LayoutDataType); + + if (this.#liveEditingMode) { + this.#establishLiveSync(); + } + } + + #establishLiveSync() { + this.observe(this.layout, (layoutData) => { + if (layoutData) { + this.#blockManager?.setOneLayout(layoutData); + } + }); + this.observe(this.content.data, (contentData) => { + if (contentData) { + this.#blockManager?.setOneContent(contentData); + } + }); + this.observe(this.settings.data, (settingsData) => { + if (settingsData) { + this.#blockManager?.setOneSettings(settingsData); + } + }); } getIsNew() { @@ -180,20 +206,36 @@ export class UmbBlockWorkspaceContext< } } - // TODO: Save the block, but only in non-live-editing mode. - this.#blockManager.setOneLayout(layoutData); + if (!this.#liveEditingMode) { + // TODO: Save the block, but only in non-live-editing mode. + this.#blockManager.setOneLayout(layoutData); - if (contentData) { - this.#blockManager.setOneContent(contentData); - } - const settingsData = this.settings.getData(); - if (settingsData) { - this.#blockManager.setOneSettings(settingsData); + if (contentData) { + this.#blockManager.setOneContent(contentData); + } + const settingsData = this.settings.getData(); + if (settingsData) { + this.#blockManager.setOneSettings(settingsData); + } } this.saveComplete(layoutData); } + #modalRejected = () => { + if (this.#liveEditingMode) { + // Revert + // Did it exist before? + if (this.getIsNew() === true) { + // Remove the block? + const contentUdi = this.#layout.value?.contentUdi; + if (contentUdi) { + this.#blockManager?.deleteBlock(contentUdi); + } + } + } + }; + public destroy(): void { this.#layout.destroy(); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/index.ts index 563618d951..2ddc9d732c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/index.ts @@ -1,3 +1,4 @@ +export * from './saveable-workspace.context-token.js'; export * from './publishable-workspace.context-token.js'; export * from './workspace-action-menu/index.js'; export * from './workspace-action/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/saveable-workspace.context-token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/saveable-workspace.context-token.ts new file mode 100644 index 0000000000..d0046df232 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/saveable-workspace.context-token.ts @@ -0,0 +1,12 @@ +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; +import { UmbWorkspaceContextInterface, UmbSaveableWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; + +export const UMB_SAVEABLE_WORKSPACE_CONTEXT = new UmbContextToken< + UmbWorkspaceContextInterface, + UmbSaveableWorkspaceContextInterface +>( + 'UmbWorkspaceContext', + undefined, + (context): context is UmbSaveableWorkspaceContextInterface => + (context as UmbSaveableWorkspaceContextInterface).getIsNew !== undefined, +); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-footer/workspace-footer.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-footer/workspace-footer.element.ts index 7f55c1c89c..81a92dd38a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-footer/workspace-footer.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-footer/workspace-footer.element.ts @@ -3,6 +3,7 @@ import { css, html, customElement, state } from '@umbraco-cms/backoffice/externa import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UMB_MODAL_CONTEXT_TOKEN, UmbModalContext } from '@umbraco-cms/backoffice/modal'; +import { UMB_SAVEABLE_WORKSPACE_CONTEXT, UMB_WORKSPACE_CONTEXT } from '..'; /** * @element umb-workspace-footer @@ -22,14 +23,20 @@ export class UmbWorkspaceFooterLayoutElement extends UmbLitElement { @state() _modalContext?: UmbModalContext; + @state() + _isNew?: boolean; + constructor() { super(); + this.consumeContext(UMB_SAVEABLE_WORKSPACE_CONTEXT, (context) => { + this._isNew = context.getIsNew(); + }); this.consumeContext(UMB_MODAL_CONTEXT_TOKEN, (context) => { this._modalContext = context; }); } - private _onClose = () => { + #rejectModal = () => { this._modalContext?.reject(); }; @@ -39,7 +46,10 @@ export class UmbWorkspaceFooterLayoutElement extends UmbLitElement { ${this._modalContext - ? html`` + ? html`` : ''}