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 4beee2607a..0172936a37 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 @@ -48,6 +48,15 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper } private _contentUdi?: string | undefined; + /** + * Sets the element to readonly mode, meaning value cannot be changed but still able to read and select its content. + * @type {boolean} + * @attr + * @default false + */ + @property({ type: Boolean, reflect: true }) + public readonly = false; + #context = new UmbBlockListEntryContext(this); @state() @@ -252,33 +261,7 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper >${this._inlineEditingMode ? this.#renderInlineBlock() : this.#renderRefBlock()} - ${this._showContentEdit && this._workspaceEditContentPath - ? html` - - ${this._contentInvalid - ? html`!` - : nothing} - ` - : nothing} - ${this._hasSettings && this._workspaceEditSettingsPath - ? html` - - ${this._settingsInvalid - ? html`!` - : nothing} - ` - : nothing} - this.#context.requestDelete()}> - - + ${this.#renderEditContentAction()} ${this.#renderEditSettingsAction()} ${this.#renderDeleteAction()} ${!this._showContentEdit && this._contentInvalid ? html`!` @@ -286,6 +269,45 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper `; } + #renderEditContentAction() { + return html` ${this._showContentEdit && this._workspaceEditContentPath + ? html` + + ${this._contentInvalid + ? html`!` + : nothing} + ` + : nothing}`; + } + + #renderEditSettingsAction() { + return html` + ${this._hasSettings && this._workspaceEditSettingsPath + ? html` + + ${this._settingsInvalid + ? html`!` + : nothing} + ` + : nothing} + `; + } + + #renderDeleteAction() { + if (this.readonly) return nothing; + return html` this.#context.requestDelete()}> + + `; + } + override render() { return this.#renderBlock(); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/manifests.ts index c3d07105cc..e734bfaad1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/manifests.ts @@ -14,6 +14,7 @@ export const manifests: Array = [ propertyEditorSchemaAlias: UMB_BLOCK_LIST_PROPERTY_EDITOR_ALIAS, icon: 'icon-thumbnail-list', group: 'lists', + supportsReadOnly: true, settings: { properties: [ { 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 2d60a0d689..5aa7bfe843 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 @@ -4,7 +4,7 @@ import type { UmbBlockListLayoutModel, UmbBlockListValueModel } from '../../type import type { UmbBlockListEntryElement } from '../../components/block-list-entry/index.js'; import { UMB_BLOCK_LIST_PROPERTY_EDITOR_ALIAS } from './manifests.js'; import { UmbLitElement, umbDestroyOnDisconnect } from '@umbraco-cms/backoffice/lit-element'; -import { html, customElement, property, state, repeat, css } from '@umbraco-cms/backoffice/external/lit'; +import { html, customElement, property, state, repeat, css, nothing } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { UmbPropertyEditorUiElement, UmbBlockTypeBaseModel } from '@umbraco-cms/backoffice/extension-registry'; import { @@ -113,6 +113,27 @@ export class UmbPropertyEditorUIBlockListElement } } + /** + * Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content. + * @type {boolean} + * @attr + * @default false + */ + @property({ type: Boolean, reflect: true }) + public get readonly() { + return this.#readonly; + } + public set readonly(value) { + this.#readonly = value; + + if (this.#readonly) { + this.#sorter.disable(); + } else { + this.#sorter.enable(); + } + } + #readonly = false; + @state() private _limitMin?: number; @state() @@ -205,6 +226,32 @@ export class UmbPropertyEditorUIBlockListElement } override render() { + return html` ${repeat( + this._layouts, + (x) => x.contentUdi, + (layoutEntry, index) => html` + ${this.#renderInlineCreateButton(index)} + + + `, + )} + ${this.#renderCreateButton()} ${this.#renderPasteButton()} `; + } + + #renderInlineCreateButton(index: number) { + if (this.readonly) return nothing; + return html``; + } + + #renderCreateButton() { + if (this.readonly) return nothing; + let createPath: string | undefined; if (this._blocks?.length === 1) { const elementKey = this._blocks[0].contentElementTypeKey; @@ -213,28 +260,22 @@ export class UmbPropertyEditorUIBlockListElement } else { createPath = this._catalogueRouteBuilder?.({ view: 'create', index: -1 }); } - return html` ${repeat( - this._layouts, - (x) => x.contentUdi, - (layoutEntry, index) => - html` - - `, - )} - - - - - - `; + + return html` + + `; + } + + #renderPasteButton() { + if (this.readonly) return nothing; + return html` + + + + `; } static override styles = [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts index c7451f7806..4db36b5497 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts @@ -1,5 +1,6 @@ import { UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT } from './block-element-property-dataset.context-token.js'; import type { UmbBlockElementManager } from './block-element-manager.js'; +import { UMB_BLOCK_WORKSPACE_CONTEXT } from './block-workspace.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'; @@ -36,6 +37,16 @@ export class UmbBlockElementPropertyDatasetContext extends UmbControllerBase imp super(host, UMB_PROPERTY_DATASET_CONTEXT.toString()); this.#elementManager = elementManager; + this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspace) => { + this.observe( + workspace.readOnlyState.isOn, + (value) => { + this.#currentVariantCultureIsReadOnly.setValue(value); + }, + 'umbObserveReadOnlyStates', + ); + }); + this.provideContext(UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT, this); } 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 9ff8c1d3ad..19e304d8db 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 @@ -10,7 +10,7 @@ import { UmbClassState, UmbObjectState, UmbStringState } from '@umbraco-cms/back import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry'; import { UMB_MODAL_CONTEXT, type UmbModalContext } from '@umbraco-cms/backoffice/modal'; -import { decodeFilePath } from '@umbraco-cms/backoffice/utils'; +import { decodeFilePath, UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils'; import { UMB_BLOCK_ENTRIES_CONTEXT, UMB_BLOCK_MANAGER_CONTEXT, @@ -60,6 +60,8 @@ export class UmbBlockWorkspaceContext(undefined); readonly variantId = this.#variantId.asObservable(); + public readonly readOnlyState = new UmbReadOnlyVariantStateManager(this); + constructor(host: UmbControllerHost, workspaceArgs: { manifest: ManifestWorkspace }) { super(host, workspaceArgs.manifest.alias); const manifest = workspaceArgs.manifest; @@ -92,6 +94,25 @@ export class UmbBlockWorkspaceContext { this.#variantId.setValue(variantId); }); + + // If the current property is readonly all inner block content should also be readonly. + this.observe(context.isReadOnly, (isReadOnly) => { + const unique = 'UMB_PROPERTY_CONTEXT'; + const variantId = this.#variantId.getValue(); + if (variantId === undefined) return; + + if (isReadOnly) { + const state = { + unique, + variantId, + message: '', + }; + + this.readOnlyState?.addState(state); + } else { + this.readOnlyState?.removeState(unique); + } + }); }); this.observe(this.variantId, (variantId) => {