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) => {