refactor inline

This commit is contained in:
Niels Lyngsø
2024-10-11 11:58:18 +02:00
parent bb878d33f9
commit 7be0e0dcbd
9 changed files with 240 additions and 192 deletions

View File

@@ -1,12 +1,26 @@
import { UMB_BLOCK_GRID_ENTRY_CONTEXT } from '../../context/block-grid-entry.context-token.js';
import { UmbBlockGridInlinePropertyDatasetContext } from './block-grid-inline-property-dataset.context.js';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { css, customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
import '../block-grid-areas-container/index.js';
import '../ref-grid-block/index.js';
import type { UmbBlockEditorCustomViewConfiguration } from '@umbraco-cms/backoffice/block-custom-view';
import type { UmbBlockDataType } from '@umbraco-cms/backoffice/block';
import {
type UMB_BLOCK_WORKSPACE_CONTEXT,
UMB_BLOCK_WORKSPACE_ALIAS,
type UmbBlockDataType,
} from '@umbraco-cms/backoffice/block';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import {
UmbExtensionApiInitializer,
UmbExtensionsApiInitializer,
type UmbApiConstructorArgumentsMethodType,
} from '@umbraco-cms/backoffice/extension-api';
import { UmbLanguageItemRepository } from '@umbraco-cms/backoffice/language';
const apiArgsCreator: UmbApiConstructorArgumentsMethodType<unknown> = (manifest: unknown) => {
return [{ manifest }];
};
/**
* @element umb-block-grid-block-inline
@@ -14,15 +28,19 @@ import type { UmbBlockDataType } from '@umbraco-cms/backoffice/block';
@customElement('umb-block-grid-block-inline')
export class UmbBlockGridBlockInlineElement extends UmbLitElement {
//
#blockContext?: typeof UMB_BLOCK_GRID_ENTRY_CONTEXT.TYPE;
#workspaceContext?: typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE;
#contentKey?: string;
@property({ attribute: false })
config?: UmbBlockEditorCustomViewConfiguration;
@property({ type: String, reflect: false })
label?: string;
@property({ type: String, reflect: false })
icon?: string;
@property({ attribute: false })
config?: UmbBlockEditorCustomViewConfiguration;
@property({ type: Boolean, reflect: true })
unpublished?: boolean;
@@ -30,37 +48,133 @@ export class UmbBlockGridBlockInlineElement extends UmbLitElement {
content?: UmbBlockDataType;
@state()
_inlineProperty: UmbPropertyTypeModel | undefined;
private _exposed?: boolean;
@state()
_isOpen = false;
@state()
_inlineProperty?: UmbPropertyTypeModel;
@state()
private _ownerContentTypeName?: string;
@state()
private _variantName?: string;
constructor() {
super();
this.consumeContext(UMB_BLOCK_GRID_ENTRY_CONTEXT, (context) => {
new UmbBlockGridInlinePropertyDatasetContext(this, context);
this.consumeContext(UMB_BLOCK_GRID_ENTRY_CONTEXT, (blockContext) => {
this.#blockContext = blockContext;
this.observe(
context.firstPropertyType,
(property) => {
this._inlineProperty = property;
this.#blockContext.unique,
(contentKey) => {
this.#contentKey = contentKey;
this.#load();
},
'inlineProperty',
'observeContentKey',
);
});
new UmbExtensionApiInitializer(
this,
umbExtensionsRegistry,
UMB_BLOCK_WORKSPACE_ALIAS,
apiArgsCreator,
(permitted, ctrl) => {
const context = ctrl.api as typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE;
if (permitted && context) {
this.#workspaceContext = context;
this.#workspaceContext.establishLiveSync();
this.#load();
this.observe(
this.#workspaceContext.content.structure.contentTypeProperties,
(contentTypeProperties) => {
this._inlineProperty = contentTypeProperties[0];
},
'observeProperties',
);
this.observe(
this.#workspaceContext.exposed,
(exposed) => {
this._exposed = exposed;
},
'observeExposed',
);
this.observe(
context.content.structure.ownerContentTypeName,
(name) => {
this._ownerContentTypeName = name;
},
'observeContentTypeName',
);
this.observe(
context.variantId,
async (variantId) => {
if (variantId) {
context.content.setup(this, variantId);
// TODO: Support segment name?
const culture = variantId.culture;
if (culture) {
const languageRepository = new UmbLanguageItemRepository(this);
const { data } = await languageRepository.requestItems([culture]);
const name = data?.[0].name;
this._variantName = name ? this.localize.string(name) : undefined;
}
}
},
'observeVariant',
);
new UmbExtensionsApiInitializer(this, umbExtensionsRegistry, 'workspaceContext', [
this,
this.#workspaceContext,
]);
}
},
);
}
#load() {
if (!this.#workspaceContext || !this.#contentKey) return;
this.#workspaceContext.load(this.#contentKey);
}
#expose = () => {
this.#workspaceContext?.expose();
};
override render() {
return html`<umb-ref-grid-block
standalone
href=${(this.config?.showContentEdit ? this.config?.editContentPath : undefined) ?? ''}>
<umb-icon slot="icon" .name=${this.icon}></umb-icon>
<umb-ufm-render slot="name" inline .markdown=${this.label} .value=${this.content}></umb-ufm-render>
<umb-property-type-based-property
.property=${this._inlineProperty}
slot="areas"></umb-property-type-based-property>
<umb-block-grid-areas-container slot="areas"></umb-block-grid-areas-container>
${this.#renderInside()}
</umb-ref-grid-block>`;
}
#renderInside() {
if (this._exposed === false) {
return html`<uui-button style="position:absolute; inset:0;" @click=${this.#expose}
><uui-icon name="icon-add"></uui-icon>
<umb-localize
key="blockEditor_createThisFor"
.args=${[this._ownerContentTypeName, this._variantName]}></umb-localize
></uui-button>`;
} else {
return html`<umb-property-type-based-property
.property=${this._inlineProperty}
slot="areas"></umb-property-type-based-property>
<umb-block-grid-areas-container slot="areas"></umb-block-grid-areas-container>`;
}
}
static override styles = [
css`
umb-block-grid-areas-container {

View File

@@ -1,6 +0,0 @@
import type { UmbBlockGridInlinePropertyDatasetContext } from './block-grid-inline-property-dataset.context.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
// TODO: Add discriminator:
export const UMB_BLOCK_GRID_INLINE_PROPERTY_DATASET_CONTEXT =
new UmbContextToken<UmbBlockGridInlinePropertyDatasetContext>('UmbPropertyDatasetContext');

View File

@@ -1,73 +0,0 @@
import type { UmbBlockGridEntryContext } from '../../context/block-grid-entry.context.js';
import { UMB_BLOCK_GRID_INLINE_PROPERTY_DATASET_CONTEXT } from './block-grid-inline-property-dataset.context-token.js';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
export class UmbBlockGridInlinePropertyDatasetContext extends UmbControllerBase implements UmbPropertyDatasetContext {
#entryContext: UmbBlockGridEntryContext;
#readOnly = new UmbBooleanState(false);
public readOnly = this.#readOnly.asObservable();
// default data:
getVariantId() {
return UmbVariantId.CreateInvariant();
}
getEntityType() {
return this.#entryContext.getEntityType();
}
getUnique() {
return this.#entryContext.getUnique();
}
getName(): string | undefined {
return 'TODO: get label';
}
readonly name: Observable<string | undefined> = 'TODO: get label observable' as any;
constructor(host: UmbControllerHost, entryContext: UmbBlockGridEntryContext) {
// The controller alias, is a very generic name cause we want only one of these for this controller host.
super(host, UMB_PROPERTY_DATASET_CONTEXT.toString());
this.#entryContext = entryContext;
this.provideContext(UMB_BLOCK_GRID_INLINE_PROPERTY_DATASET_CONTEXT, this);
}
/**
* @function propertyValueByAlias
* @param {string} propertyAlias
* @returns {Promise<Observable<ReturnType | undefined> | undefined>}
* @description Get an Observable for the value of this property.
*/
async propertyValueByAlias<ReturnType = unknown>(propertyAlias: string) {
// TODO: Investigate how I do that with the workspaces..
return await this.#entryContext.contentPropertyValueByAlias<ReturnType>(propertyAlias);
}
/**
* @function setPropertyValue
* @param {string} propertyAlias
* @param {unknown} value - value can be a promise resolving into the actual value or the raw value it self.
* @returns {Promise<void>}
* @description Set the value of this property.
*/
async setPropertyValue(propertyAlias: string, value: unknown) {
// TODO: Investigate how I do that with the workspaces..
return this.#entryContext.setContentPropertyValue(propertyAlias, value);
}
/**
* Gets the read-only state of the current variant culture.
* @returns {*} {boolean}
* @memberof UmbBlockGridInlinePropertyDatasetContext
*/
getReadOnly(): boolean {
return this.#readOnly.getValue();
}
}

View File

@@ -9,13 +9,11 @@ import {
UmbArrayState,
UmbBooleanState,
UmbNumberState,
UmbObjectState,
appendToFrozenArray,
mergeObservables,
observeMultiple,
} from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
import { UmbBlockEntryContext } from '@umbraco-cms/backoffice/block';
import type { UmbBlockGridTypeModel, UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid';
@@ -68,9 +66,6 @@ export class UmbBlockGridEntryContext
([a, b]) => a === true && b === false,
);
#firstPropertyType = new UmbObjectState<UmbPropertyTypeModel | undefined>(undefined);
readonly firstPropertyType = this.#firstPropertyType.asObservable();
readonly scaleManager = new UmbBlockGridScaleManager(this);
constructor(host: UmbControllerHost) {
@@ -253,9 +248,7 @@ export class UmbBlockGridEntryContext
);
}
_gotContentType(contentType: UmbContentTypeModel | undefined) {
this.#firstPropertyType.setValue(contentType?.properties[0]);
}
_gotContentType() {}
#calcColumnSpan(columnSpan: number, relevantColumnSpanOptions: number[], layoutColumns: number) {
if (relevantColumnSpanOptions.length > 0) {

View File

@@ -4,13 +4,22 @@ import {
type UmbBlockDataType,
type UMB_BLOCK_WORKSPACE_CONTEXT,
} from '@umbraco-cms/backoffice/block';
import { UmbExtensionsApiInitializer, createExtensionApi } from '@umbraco-cms/backoffice/extension-api';
import {
UmbExtensionApiInitializer,
UmbExtensionsApiInitializer,
type UmbApiConstructorArgumentsMethodType,
} from '@umbraco-cms/backoffice/extension-api';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { css, customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import '../../../block/workspace/views/edit/block-workspace-view-edit-content-no-router.element.js';
import { UmbLanguageItemRepository } from '@umbraco-cms/backoffice/language';
const apiArgsCreator: UmbApiConstructorArgumentsMethodType<unknown> = (manifest: unknown) => {
return [{ manifest }];
};
/**
* @element umb-inline-list-block
@@ -33,9 +42,18 @@ export class UmbInlineListBlockElement extends UmbLitElement {
@property({ attribute: false })
content?: UmbBlockDataType;
@state()
private _exposed?: boolean;
@state()
_isOpen = false;
@state()
private _ownerContentTypeName?: string;
@state()
private _variantName?: string;
constructor() {
super();
@@ -50,22 +68,60 @@ export class UmbInlineListBlockElement extends UmbLitElement {
'observeContentKey',
);
});
this.observe(umbExtensionsRegistry.byTypeAndAlias('workspace', UMB_BLOCK_WORKSPACE_ALIAS), (manifest) => {
if (manifest) {
createExtensionApi(this, manifest, [{ manifest: manifest }]).then((context) => {
if (context) {
this.#workspaceContext = context as typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE;
this.#workspaceContext.establishLiveSync();
this.#load();
new UmbExtensionsApiInitializer(this, umbExtensionsRegistry, 'workspaceContext', [
this,
this.#workspaceContext,
]);
}
});
}
});
new UmbExtensionApiInitializer(
this,
umbExtensionsRegistry,
UMB_BLOCK_WORKSPACE_ALIAS,
apiArgsCreator,
(permitted, ctrl) => {
const context = ctrl.api as typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE;
if (permitted && context) {
this.#workspaceContext = context;
this.#workspaceContext.establishLiveSync();
this.#load();
this.observe(
this.#workspaceContext.exposed,
(exposed) => {
this._exposed = exposed;
},
'observeExposed',
);
this.observe(
context.content.structure.ownerContentTypeName,
(name) => {
this._ownerContentTypeName = name;
},
'observeContentTypeName',
);
this.observe(
context.variantId,
async (variantId) => {
if (variantId) {
context.content.setup(this, variantId);
// TODO: Support segment name?
const culture = variantId.culture;
if (culture) {
const languageRepository = new UmbLanguageItemRepository(this);
const { data } = await languageRepository.requestItems([culture]);
const name = data?.[0].name;
this._variantName = name ? this.localize.string(name) : undefined;
}
}
},
'observeVariant',
);
new UmbExtensionsApiInitializer(this, umbExtensionsRegistry, 'workspaceContext', [
this,
this.#workspaceContext,
]);
}
},
);
}
#load() {
@@ -73,6 +129,10 @@ export class UmbInlineListBlockElement extends UmbLitElement {
this.#workspaceContext.load(this.#contentKey);
}
#expose = () => {
this.#workspaceContext?.expose();
};
override render() {
return html`
<div id="host">
@@ -89,18 +149,16 @@ export class UmbInlineListBlockElement extends UmbLitElement {
this._isOpen = !this._isOpen;
}}>
<uui-symbol-expand .open=${this._isOpen}></uui-symbol-expand>
${this.#renderContent()}
${this.#renderBlockInfo()}
<slot></slot>
<slot name="tag"></slot>
</button>
${this._isOpen === true
? html`<umb-block-workspace-view-edit-content-no-router></umb-block-workspace-view-edit-content-no-router>`
: ''}
${this._isOpen === true ? this.#renderInside() : ''}
</div>
`;
}
#renderContent() {
#renderBlockInfo() {
return html`
<span id="content">
<span id="icon">
@@ -113,6 +171,19 @@ export class UmbInlineListBlockElement extends UmbLitElement {
`;
}
#renderInside() {
if (this._exposed === false) {
return html`<uui-button style="position:absolute; inset:0;" @click=${this.#expose}
><uui-icon name="icon-add"></uui-icon>
<umb-localize
key="blockEditor_createThisFor"
.args=${[this._ownerContentTypeName, this._variantName]}></umb-localize
></uui-button>`;
} else {
return html`<umb-block-workspace-view-edit-content-no-router></umb-block-workspace-view-edit-content-no-router>`;
}
}
static override styles = [
UmbTextStyles,
css`

View File

@@ -1,5 +1,6 @@
import type { UmbBlockDataModel, UmbBlockDataValueModel } from '../types.js';
import type { UmbBlockDataModel, UmbBlockDataValueModel, UmbBlockLayoutBaseModel } from '../types.js';
import { UmbBlockElementPropertyDatasetContext } from './block-element-property-dataset.context.js';
import type { UmbBlockWorkspaceContext } from './block-workspace.context.js';
import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
import { UmbContentTypeStructureManager } from '@umbraco-cms/backoffice/content-type';
import {
@@ -18,7 +19,7 @@ import { UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils';
import { UmbDataTypeItemRepositoryManager } from '@umbraco-cms/backoffice/data-type';
export class UmbBlockElementManager
export class UmbBlockElementManager<LayoutDataType extends UmbBlockLayoutBaseModel = UmbBlockLayoutBaseModel>
extends UmbControllerBase
implements UmbElementPropertyDataOwner<UmbBlockDataModel, UmbContentTypeModel>
{
@@ -37,6 +38,8 @@ export class UmbBlockElementManager
#variantId = new UmbClassState<UmbVariantId | undefined>(undefined);
readonly variantId = this.#variantId.asObservable();
readonly name;
readonly getName;
readonly unique = this.#data.createObservablePartOfCurrent((data) => data?.key);
readonly contentTypeId = this.#data.createObservablePartOfCurrent((data) => data?.contentTypeKey);
@@ -55,9 +58,13 @@ export class UmbBlockElementManager
readonly validation = new UmbValidationController(this);
constructor(host: UmbControllerHost, dataPathPropertyName: string) {
constructor(host: UmbBlockWorkspaceContext<LayoutDataType>, dataPathPropertyName: string) {
super(host);
// Ugly, but we just inherit these from the workspace context: [NL]
this.name = host.name;
this.getName = host.getName;
this.observe(this.contentTypeId, (id) => this.structure.loadType(id));
this.observe(this.unique, (key) => {
if (key) {

View File

@@ -9,19 +9,18 @@ export class UmbBlockElementPropertyDatasetContext
extends UmbElementPropertyDatasetContext
implements UmbPropertyDatasetContext
{
name;
culture;
segment;
getName(): string {
return 'Block';
}
readonly name;
readonly culture;
readonly segment;
readonly getName;
constructor(host: UmbControllerHost, elementManager: UmbBlockElementManager, variantId?: UmbVariantId) {
// The controller alias, is a very generic name cause we want only one of these for this controller host.
super(host, elementManager, variantId);
// Ugly, but we just inherit these from the workspace context: [NL]
this.name = elementManager.name;
this.getName = elementManager.getName;
this.culture = createObservablePart(elementManager.variantId, (v) => v?.culture);
this.segment = createObservablePart(elementManager.variantId, (v) => v?.segment);
}

View File

@@ -6,7 +6,6 @@ import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbPropertyTypeContainerModel } from '@umbraco-cms/backoffice/content-type';
import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/workspace';
import { UmbLanguageItemRepository } from '@umbraco-cms/backoffice/language';
/**
* @element umb-block-workspace-view-edit-content-no-router
@@ -29,15 +28,6 @@ export class UmbBlockWorkspaceViewEditContentNoRouterElement extends UmbLitEleme
//@state()
//private _activeTabName?: string | null | undefined;
@state()
private _ownerContentTypeName?: string;
@state()
private _variantName?: string;
@state()
private _exposed?: boolean;
#blockWorkspace?: typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE;
#tabsStructureHelper = new UmbContentTypeContainerStructureHelper(this);
@@ -58,40 +48,6 @@ export class UmbBlockWorkspaceViewEditContentNoRouterElement extends UmbLitEleme
this.#tabsStructureHelper.setStructureManager(context.content.structure);
this.#observeRootGroups();
this.observe(
context.content.structure.ownerContentTypeName,
(name) => {
this._ownerContentTypeName = name;
},
'observeContentTypeName',
);
this.observe(
context.variantId,
async (variantId) => {
if (variantId) {
context.content.setup(this, variantId);
// TODO: Support segment name?
const culture = variantId.culture;
if (culture) {
const languageRepository = new UmbLanguageItemRepository(this);
const { data } = await languageRepository.requestItems([culture]);
const name = data?.[0].name;
this._variantName = name ? this.localize.string(name) : undefined;
}
}
},
'observeVariant',
);
this.observe(
context.exposed,
(exposed) => {
this._exposed = exposed;
},
'observeExposed',
);
});
}
@@ -128,19 +84,7 @@ export class UmbBlockWorkspaceViewEditContentNoRouterElement extends UmbLitEleme
this._activeTabId = tabId;
}
#expose = () => {
this.#blockWorkspace?.expose();
};
override render() {
if (this._exposed === false) {
return html`<uui-button style="position:absolute; inset:0;" @click=${this.#expose}
><uui-icon name="icon-add"></uui-icon>
<umb-localize
key="blockEditor_createThisFor"
.args=${[this._ownerContentTypeName, this._variantName]}></umb-localize
></uui-button>`;
}
if (!this._tabs) return;
return html`
${this._tabs.length > 1 || (this._tabs.length === 1 && this._hasRootGroups)

View File

@@ -107,7 +107,6 @@ export class UmbPropertyDatasetContextBase
/**
* Gets the read-only state of the current variant culture.
* @returns {*} {boolean}
* @memberof UmbBlockGridInlinePropertyDatasetContext
*/
getReadOnly(): boolean {
return this.#readOnly.getValue();