live editing mode

This commit is contained in:
Niels Lyngsø
2024-01-22 19:31:37 +01:00
parent 214bbd0f4a
commit ea1b916529
9 changed files with 114 additions and 37 deletions

View File

@@ -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';

View File

@@ -86,6 +86,8 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
//config.useLiveEditing
//config.useInlineEditingAsDefault
this.style.maxWidth = config.getValueByAlias<string>('maxPropertyWidth') ?? '';
this.#context.setEditorConfiguration(config);
}
@state()

View File

@@ -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>('UmbBlockManagerContext');

View File

@@ -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(<Array<BlockType>>[], (x) => x.contentElementTypeKey);
public readonly blockTypes = this.#blockTypes.asObservable();
#editorConfiguration = new UmbClassState<UmbPropertyEditorConfigCollection | undefined>(undefined);
public readonly editorConfiguration = this.#editorConfiguration.asObservable();
#layouts = new UmbArrayState(<Array<BlockLayoutType>>[], (x) => x.contentUdi);
public readonly layouts = this.#layouts.asObservable();
@@ -38,6 +45,10 @@ export abstract class UmbBlockManagerContext<
#settings = new UmbArrayState(<Array<UmbBlockDataType>>[], (x) => x.udi);
public readonly settings = this.#settings.asObservable();
setEditorConfiguration(configs: UmbPropertyEditorConfigCollection) {
this.#editorConfiguration.setValue(configs);
}
setBlockTypes(blockTypes: Array<BlockType>) {
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, UmbBlockManagerContext>(
'UmbBlockManagerContext',
);

View File

@@ -1 +1 @@
export * from './block-manager.context.js';
export * from './block-manager.context-token.js';

View File

@@ -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<unknown>;
#entityType: string;
#isNew = new UmbBooleanState<boolean | undefined>(undefined);
readonly isNew = this.#isNew.asObservable();
#liveEditingMode?: boolean;
#layout = new UmbObjectState<LayoutDataType | undefined>(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<boolean>('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();
}

View File

@@ -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';

View File

@@ -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,
);

View File

@@ -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 {
<umb-footer-layout>
<slot></slot>
${this._modalContext
? html`<uui-button slot="actions" label="Close" @click=${this._onClose}></uui-button>`
? html`<uui-button
slot="actions"
label=${this._isNew ? 'Cancel' : 'Close'}
@click=${this.#rejectModal}></uui-button>`
: ''}
<slot name="actions" slot="actions"></slot>
<umb-extension-slot