From 3c1a9eef0dc0b6941d254e01fdd7ebe327ca1bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 1 Jul 2024 09:46:42 +0200 Subject: [PATCH] Block Editor Custom View specific conditionals --- .../block-grid-entry.element.ts | 53 ++++++------ .../src/packages/block/block-grid/types.ts | 1 + .../block-list-entry.element.ts | 85 +++++++++++++------ .../src/packages/block/block-list/types.ts | 1 + .../packages/block/custom-view/manifest.ts | 4 +- .../models/block-editor-custom-view.model.ts | 16 +++- .../src/packages/core/utils/index.ts | 1 + ...tring-or-string-array-contains.function.ts | 3 + 8 files changed, 108 insertions(+), 56 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/utils/string/string-or-string-array-contains.function.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-entry/block-grid-entry.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-entry/block-grid-entry.element.ts index 76be03cd46..32ed7dc718 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-entry/block-grid-entry.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-entry/block-grid-entry.element.ts @@ -2,12 +2,13 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { html, css, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit'; import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; import type { ManifestBlockEditorCustomView, UmbBlockEditorCustomViewProperties, UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; +import { stringOrStringArrayContains } from '@umbraco-cms/backoffice/utils'; import { UmbBlockGridEntryContext } from '../../context/block-grid-entry.context.js'; -import type { UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid'; +import { UMB_BLOCK_GRID, type UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid'; + import '../block-grid-block-inline/index.js'; import '../block-grid-block/index.js'; import '../block-scale-handler/index.js'; - /** * @element umb-block-grid-entry */ @@ -84,7 +85,6 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper @state() _inlineCreateAboveWidth?: string; - // TODO: use this type on the Element Interface for the Manifest. @state() _blockViewProps: UmbBlockEditorCustomViewProperties = { contentUdi: undefined!, urls: {} }; // Set to undefined cause it will be set before we render. @@ -99,55 +99,55 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper // Misc: this.observe(this.#context.showContentEdit, (show) => { this._showContentEdit = show; - }); + }, null); this.observe(this.#context.settingsElementTypeKey, (key) => { this._hasSettings = !!key; - }); + }, null); this.observe(this.#context.canScale, (canScale) => { this._canScale = canScale; - }); + }, null); this.observe(this.#context.label, (label) => { this.#updateBlockViewProps({ label }); this._label = label; - }); + }, null); this.observe(this.#context.contentElementTypeIcon, (icon) => { this.#updateBlockViewProps({ icon }); this._icon = icon; - }); + }, null); this.observe(this.#context.inlineEditingMode, (mode) => { this._inlineEditingMode = mode; - }); + }, null); // Data: this.observe(this.#context.layout, (layout) => { this.#updateBlockViewProps({ layout }); - }); + }, null); this.observe(this.#context.content, (content) => { this.#updateBlockViewProps({ content }); - }); + }, null); this.observe(this.#context.settings, (settings) => { this.#updateBlockViewProps({ settings }); - }); + }, null); // Paths: this.observe(this.#context.createBeforePath, (createPath) => { //const oldValue = this._createBeforePath; this._createBeforePath = createPath; //this.requestUpdate('_createPath', oldValue); - }); + }, null); this.observe(this.#context.createAfterPath, (createPath) => { //const oldValue = this._createAfterPath; this._createAfterPath = createPath; //this.requestUpdate('_createPath', oldValue); - }); + }, null); this.observe(this.#context.workspaceEditContentPath, (path) => { this._workspaceEditContentPath = path; this.#updateBlockViewProps({ urls: { ...this._blockViewProps.urls, editContent: path } }); - }); + }, null); this.observe(this.#context.workspaceEditSettingsPath, (path) => { this._workspaceEditSettingsPath = path; this.#updateBlockViewProps({ urls: { ...this._blockViewProps.urls, editSettings: path } }); - }); + }, null); } override connectedCallback(): void { @@ -175,13 +175,13 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper if (contentElementTypeKey) { this.setAttribute('data-content-element-type-key', contentElementTypeKey); } - }); + }, 'contentElementTypeKey'); this.observe(this.#context.contentElementTypeAlias, (contentElementTypeAlias) => { if (contentElementTypeAlias) { this._contentTypeAlias = contentElementTypeAlias; this.setAttribute('data-content-element-type-alias', contentElementTypeAlias); } - }); + }, 'contentElementTypeAlias'); this.#callUpdateInlineCreateButtons(); } @@ -228,6 +228,16 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper } }; + #extensionSlotFilterMethod = (manifest:ManifestBlockEditorCustomView) => { + if(manifest.forContentTypeAlias && !stringOrStringArrayContains(manifest.forContentTypeAlias, this._contentTypeAlias!)) { + return false; + } + if(manifest.forBlockEditor && !stringOrStringArrayContains(manifest.forBlockEditor, UMB_BLOCK_GRID)) { + return false; + } + return true; + } + #renderInlineEditBlock() { return html``; } - #extensionSlotFilterMethod = (manifest:ManifestBlockEditorCustomView) => { - if(manifest.forContentTypeAlias?.indexOf(this._contentTypeAlias!) === -1) { - return false; - } - return true; - } - #renderBlock() { return this.contentUdi && this._contentTypeAlias ? html` diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/types.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/types.ts index 7925df893a..392c67f0f2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/types.ts @@ -2,6 +2,7 @@ import type { UmbBlockLayoutBaseModel, UmbBlockValueType } from '@umbraco-cms/ba import type { UmbBlockTypeWithGroupKey } from '@umbraco-cms/backoffice/block-type'; export const UMB_BLOCK_GRID_TYPE = 'block-grid-type'; +export const UMB_BLOCK_GRID = 'block-grid'; // Configuration models: export interface UmbBlockGridTypeModel extends UmbBlockTypeWithGroupKey { diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts index e7bc5a771f..02feff3482 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts @@ -1,11 +1,11 @@ -import { UmbBlockListEntryContext } from '../../context/block-list-entry.context.js'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { html, css, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; -import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; +import type { ManifestBlockEditorCustomView, UmbBlockEditorCustomViewProperties, UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; import '../ref-list-block/index.js'; import '../inline-list-block/index.js'; -import type { UmbBlockViewPropsType } from '@umbraco-cms/backoffice/block'; -import type { UmbBlockListLayoutModel } from '@umbraco-cms/backoffice/block-list'; +import { stringOrStringArrayContains } from '@umbraco-cms/backoffice/utils'; +import { UmbBlockListEntryContext } from '../../context/block-list-entry.context.js'; +import { UMB_BLOCK_LIST, type UmbBlockListLayoutModel } from '../../types.js'; /** * @element umb-block-list-entry @@ -34,6 +34,9 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper #context = new UmbBlockListEntryContext(this); + @state() + _contentTypeAlias?:string; + @state() _showContentEdit = false; @state() @@ -54,52 +57,79 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper @state() _inlineEditingMode?: boolean; - // TODO: use this type on the Element Interface for the Manifest. @state() - _blockViewProps: UmbBlockViewPropsType = { contentUdi: undefined!, urls: {} }; // Set to undefined cause it will be set before we render. + _blockViewProps: UmbBlockEditorCustomViewProperties = { contentUdi: undefined!, urls: {} }; // Set to undefined cause it will be set before we render. + + #updateBlockViewProps(incoming: Partial>) { + this._blockViewProps = { ...this._blockViewProps, ...incoming }; + this.requestUpdate('_blockViewProps'); + } constructor() { super(); this.observe(this.#context.showContentEdit, (showContentEdit) => { this._showContentEdit = showContentEdit; - }); + }, null); this.observe(this.#context.settingsElementTypeKey, (settingsElementTypeKey) => { this._hasSettings = !!settingsElementTypeKey; - }); + }, null); this.observe(this.#context.label, (label) => { + this.#updateBlockViewProps({ label }); this._label = label; - this._blockViewProps.label = label; - this.requestUpdate('_blockViewProps'); - }); + }, null); this.observe(this.#context.contentElementTypeIcon, (icon) => { + this.#updateBlockViewProps({ icon }); this._icon = icon; - this._blockViewProps.icon = icon; - this.requestUpdate('_blockViewProps'); - }); + }, null); this.observe(this.#context.inlineEditingMode, (inlineEditingMode) => { this._inlineEditingMode = inlineEditingMode; - }); + }, null); // Data props: this.observe(this.#context.layout, (layout) => { - this._blockViewProps.layout = layout; - }); + this.#updateBlockViewProps({ layout }); + }, null); this.observe(this.#context.content, (content) => { - this._blockViewProps.content = content; - }); + this.#updateBlockViewProps({ content }); + }, null); this.observe(this.#context.settings, (settings) => { - this._blockViewProps.settings = settings; - }); + this.#updateBlockViewProps({ settings }); + }, null); this.observe(this.#context.workspaceEditContentPath, (path) => { this._workspaceEditContentPath = path; - this._blockViewProps.urls.editContent = path; - this.requestUpdate('_blockViewProps'); - }); + this.#updateBlockViewProps({ urls: { ...this._blockViewProps.urls, editContent: path } }); + }, null); this.observe(this.#context.workspaceEditSettingsPath, (path) => { this._workspaceEditSettingsPath = path; - this._blockViewProps.urls.editSettings = path; - this.requestUpdate('_blockViewProps'); - }); + this.#updateBlockViewProps({ urls: { ...this._blockViewProps.urls, editSettings: path } }); + }, null); + } + + + override connectedCallback(): void { + super.connectedCallback(); + // element styling: + this.observe(this.#context.contentElementTypeKey, (contentElementTypeKey) => { + if (contentElementTypeKey) { + this.setAttribute('data-content-element-type-key', contentElementTypeKey); + } + }, 'contentElementTypeKey'); + this.observe(this.#context.contentElementTypeAlias, (contentElementTypeAlias) => { + if (contentElementTypeAlias) { + this._contentTypeAlias = contentElementTypeAlias; + this.setAttribute('data-content-element-type-alias', contentElementTypeAlias); + } + }, 'contentElementTypeAlias'); + } + + #extensionSlotFilterMethod = (manifest:ManifestBlockEditorCustomView) => { + if(manifest.forContentTypeAlias && !stringOrStringArrayContains(manifest.forContentTypeAlias, this._contentTypeAlias!)) { + return false; + } + if(manifest.forBlockEditor && !stringOrStringArrayContains(manifest.forBlockEditor, UMB_BLOCK_LIST)) { + return false; + } + return true; } #renderRefBlock() { @@ -116,6 +146,7 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper type="blockEditorCustomView" default-element=${this._inlineEditingMode ? 'umb-inline-list-block' : 'umb-ref-list-block'} .props=${this._blockViewProps} + .filter=${this.#extensionSlotFilterMethod} >${this._inlineEditingMode ? this.#renderInlineBlock() : this.#renderRefBlock()} diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/types.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/types.ts index dc5894a548..a85c2635df 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/types.ts @@ -2,6 +2,7 @@ import type { UmbBlockTypeBaseModel } from '../block-type/index.js'; import type { UmbBlockLayoutBaseModel, UmbBlockValueType } from '@umbraco-cms/backoffice/block'; export const UMB_BLOCK_LIST_TYPE = 'block-list-type'; +export const UMB_BLOCK_LIST = 'block-list'; export interface UmbBlockListTypeModel extends UmbBlockTypeBaseModel {} export interface UmbBlockListLayoutModel extends UmbBlockLayoutBaseModel {} diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/custom-view/manifest.ts b/src/Umbraco.Web.UI.Client/src/packages/block/custom-view/manifest.ts index 44e6dfbe54..69b00c5af3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/custom-view/manifest.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/custom-view/manifest.ts @@ -5,6 +5,6 @@ export const manifest:ManifestBlockEditorCustomView = { alias: 'Umb.blockEditorCustomView.TestView', name: 'Block Editor Custom View Test', element: () => import('./custom-view.element.js'), - //forContentTypeAlias: [] - //forBlockType?: Array; + forContentTypeAlias: 'elementTypeHeadline', + forBlockEditor: 'block-grid' } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/block-editor-custom-view.model.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/block-editor-custom-view.model.ts index 7ceea8278f..72e0216a71 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/block-editor-custom-view.model.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/block-editor-custom-view.model.ts @@ -3,6 +3,18 @@ import type { UmbBlockEditorCustomViewElement } from '../interfaces/index.js'; export interface ManifestBlockEditorCustomView extends ManifestElement { type: 'blockEditorCustomView'; - forContentTypeAlias?: Array; - forBlockType?: Array; + /** + * @property {string | Array } - Declare if this Custom View only must appear at specific Content Types by Alias. + * @description Optional condition if you like this custom view to only appear at for one or more specific Content Types. + * @example 'my-element-type-alias' + * @example ['my-element-type-alias-A', 'my-element-type-alias-B'] + */ + forContentTypeAlias?: string | Array; + /** + * @property {string | Array } - Declare if this Custom View only must appear at specific Block Editors. + * @description Optional condition if you like this custom view to only appear at a specific type of Block Editor. + * @example 'block-list' + * @example ['block-list', 'block-grid'] + */ + forBlockEditor?: string | Array; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/utils/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/utils/index.ts index f7ec7dd723..a7e6fb6913 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/utils/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/utils/index.ts @@ -19,5 +19,6 @@ export * from './string/from-camel-case.function.js'; export * from './string/generate-umbraco-alias.function.js'; export * from './string/increment-string.function.js'; export * from './string/split-string-to-array.js'; +export * from './string/string-or-string-array-contains.function.js'; export * from './string/to-camel-case/to-camel-case.function.js'; export type * from './type/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/utils/string/string-or-string-array-contains.function.ts b/src/Umbraco.Web.UI.Client/src/packages/core/utils/string/string-or-string-array-contains.function.ts new file mode 100644 index 0000000000..54f8dc419f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/utils/string/string-or-string-array-contains.function.ts @@ -0,0 +1,3 @@ +export function stringOrStringArrayContains(value: string | Array, search: string) { + return Array.isArray(value) ? value.indexOf(search) !== -1 : value === search; +}