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 de8480d127..dd7b87b52f 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
@@ -60,6 +60,9 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper
@state()
_label = '';
+ @state()
+ _icon?: string;
+
@state()
_workspaceEditContentPath?: string;
@@ -105,6 +108,10 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper
this.#updateBlockViewProps({ label });
this._label = label;
});
+ this.observe(this.#context.contentElementTypeIcon, (icon) => {
+ this.#updateBlockViewProps({ icon });
+ this._icon = icon;
+ });
this.observe(this.#context.inlineEditingMode, (mode) => {
this._inlineEditingMode = mode;
});
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 bca25ac505..8ecc6faf3b 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
@@ -42,6 +42,9 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper
@state()
_label = '';
+ @state()
+ _icon?: string;
+
@state()
_workspaceEditContentPath?: string;
@@ -65,10 +68,14 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper
this._hasSettings = !!settingsElementTypeKey;
});
this.observe(this.#context.label, (label) => {
- const oldValue = this._label;
- this._blockViewProps.label = label;
this._label = label;
- this.requestUpdate('label', oldValue);
+ this._blockViewProps.label = label;
+ this.requestUpdate('_blockViewProps');
+ });
+ this.observe(this.#context.contentElementTypeIcon, (icon) => {
+ this._icon = icon;
+ this._blockViewProps.icon = icon;
+ this.requestUpdate('_blockViewProps');
});
this.observe(this.#context.inlineEditingMode, (inlineEditingMode) => {
this._inlineEditingMode = inlineEditingMode;
@@ -115,12 +122,12 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper
${this._showContentEdit && this._workspaceEditContentPath
? html`
- `
+ `
: ''}
${this._hasSettings && this._workspaceEditSettingsPath
? html`
- `
+ `
: ''}
this.#context.requestDelete()}>
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/block-rte-entry/block-rte-entry-inline.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/block-rte-entry/block-rte-entry-inline.element.ts
index 1769cc53b7..f2e59b38d8 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/block-rte-entry/block-rte-entry-inline.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/block-rte-entry/block-rte-entry-inline.element.ts
@@ -11,7 +11,7 @@ export class UmbBlockRteEntryInlineElement extends UmbBlockRteEntryElement {
...UmbBlockRteEntryElement.styles,
css`
:host {
- display: inline;
+ display: inline-block;
}
`,
];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/block-rte-entry/block-rte-entry.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/block-rte-entry/block-rte-entry.element.ts
index d043e02a88..0b7cd42ec6 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/block-rte-entry/block-rte-entry.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/block-rte-entry/block-rte-entry.element.ts
@@ -1,10 +1,10 @@
import { UmbBlockRteEntryContext } from '../../context/block-rte-entry.context.js';
+import type { UmbBlockRteLayoutModel } from '../../types.js';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { html, css, property, state, customElement } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import '../ref-rte-block/index.js';
import type { UmbBlockViewPropsType } from '@umbraco-cms/backoffice/block';
-import type { UmbBlockListLayoutModel } from '@umbraco-cms/backoffice/block-list';
/**
* @element umb-rte-block
@@ -34,6 +34,9 @@ export class UmbBlockRteEntryElement extends UmbLitElement implements UmbPropert
@state()
_label = '';
+ @state()
+ _icon?: string;
+
@state()
_workspaceEditContentPath?: string;
@@ -42,7 +45,7 @@ export class UmbBlockRteEntryElement extends UmbLitElement implements UmbPropert
// 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: UmbBlockViewPropsType = { contentUdi: undefined!, urls: {} }; // Set to undefined cause it will be set before we render.
constructor() {
super();
@@ -57,10 +60,14 @@ export class UmbBlockRteEntryElement extends UmbLitElement implements UmbPropert
this._hasSettings = !!settingsElementTypeKey;
});
this.observe(this.#context.label, (label) => {
- const oldValue = this._label;
- this._blockViewProps.label = label;
this._label = label;
- this.requestUpdate('label', oldValue);
+ this._blockViewProps.label = label;
+ this.requestUpdate('_blockViewProps');
+ });
+ this.observe(this.#context.contentElementTypeIcon, (icon) => {
+ this._icon = icon;
+ this._blockViewProps.icon = icon;
+ this.requestUpdate('_blockViewProps');
});
// Data props:
this.observe(this.#context.layout, (layout) => {
@@ -84,8 +91,17 @@ export class UmbBlockRteEntryElement extends UmbLitElement implements UmbPropert
});
}
+ connectedCallback() {
+ super.connectedCallback();
+
+ // eslint-disable-next-line wc/no-self-class
+ this.classList.add('uui-font');
+ // eslint-disable-next-line wc/no-self-class
+ this.classList.add('uui-text');
+ }
+
#renderRefBlock() {
- return html``;
+ return html``;
}
#renderBlock() {
@@ -123,6 +139,8 @@ export class UmbBlockRteEntryElement extends UmbLitElement implements UmbPropert
:host {
position: relative;
display: block;
+ user-select: none;
+ user-drag: auto;
}
uui-action-bar {
position: absolute;
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/ref-rte-block/ref-rte-block.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/ref-rte-block/ref-rte-block.element.ts
index f688cbebbd..16fc522e7c 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/ref-rte-block/ref-rte-block.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/ref-rte-block/ref-rte-block.element.ts
@@ -11,6 +11,9 @@ export class UmbRefRteBlockElement extends UmbLitElement {
@property({ type: String })
label?: string;
+ @property({ type: String })
+ icon?: string;
+
@state()
_workspaceEditPath?: string;
@@ -29,10 +32,9 @@ export class UmbRefRteBlockElement extends UmbLitElement {
}
render() {
- return html``;
+ return html``;
}
static styles = [
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/context/block-rte-entry.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/context/block-rte-entry.context.ts
index 6e0add4c7a..ce54601d05 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/context/block-rte-entry.context.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/context/block-rte-entry.context.ts
@@ -19,7 +19,7 @@ export class UmbBlockRteEntryContext extends UmbBlockEntryContext<
(x) => !!x?.forceHideContentEditorInOverlay,
);
- readonly showContentEdit = this.forceHideContentEditorInOverlay;
+ readonly showContentEdit = this._blockType.asObservablePart((x) => !x?.forceHideContentEditorInOverlay);
constructor(host: UmbControllerHost) {
super(host, UMB_BLOCK_RTE_MANAGER_CONTEXT, UMB_BLOCK_RTE_ENTRIES_CONTEXT);
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/context/block-rte-manager.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/context/block-rte-manager.context.ts
index 0c06ba5c3e..ad1f02748f 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/context/block-rte-manager.context.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-rte/context/block-rte-manager.context.ts
@@ -24,7 +24,19 @@ export class UmbBlockRteManagerContext<
partialLayoutEntry?: Omit,
modalData?: UmbBlockRteWorkspaceData,
) {
- return super.createBlockData(contentElementTypeKey, partialLayoutEntry);
+ const data = super.createBlockData(contentElementTypeKey, partialLayoutEntry);
+
+ // Find block type.
+ const blockType = this.getBlockTypes().find((x) => x.contentElementTypeKey === contentElementTypeKey);
+ if (!blockType) {
+ throw new Error(`Cannot create block, missing block type for ${contentElementTypeKey}`);
+ }
+
+ if (blockType.displayInline) {
+ data.layout.displayInline = true;
+ }
+
+ return data;
}
insert(
@@ -35,6 +47,10 @@ export class UmbBlockRteManagerContext<
) {
if (!this.#editor) return false;
+ this._layouts.appendOne(layoutEntry);
+
+ this.insertBlockData(layoutEntry, content, settings, modalData);
+
if (layoutEntry.displayInline) {
this.#editor.selection.setContent(
``,
@@ -45,9 +61,7 @@ export class UmbBlockRteManagerContext<
);
}
- this._layouts.appendOne(layoutEntry);
-
- this.insertBlockData(layoutEntry, content, settings, modalData);
+ this.#editor.fire('change');
return true;
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entry.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entry.context.ts
index 8087e78717..422391fe62 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entry.context.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entry.context.ts
@@ -67,10 +67,11 @@ export abstract class UmbBlockEntryContext<
#createAfterPath = new UmbStringState(undefined);
readonly createAfterPath = this.#createAfterPath.asObservable();
- #contentElementTypeName = new UmbStringState(undefined);
- public readonly contentElementTypeName = this.#contentElementTypeName.asObservable();
- #contentElementTypeAlias = new UmbStringState(undefined);
- public readonly contentElementTypeAlias = this.#contentElementTypeAlias.asObservable();
+ #contentElementType = new UmbObjectState(undefined);
+ public readonly contentElementType = this.#contentElementType.asObservable();
+ public readonly contentElementTypeName = this.#contentElementType.asObservablePart((x) => x?.name);
+ public readonly contentElementTypeAlias = this.#contentElementType.asObservablePart((x) => x?.alias);
+ public readonly contentElementTypeIcon = this.#contentElementType.asObservablePart((x) => x?.icon);
_blockType = new UmbObjectState(undefined);
public readonly blockType = this._blockType.asObservable();
@@ -301,8 +302,9 @@ export abstract class UmbBlockEntryContext<
this.observe(
this._manager.contentTypeOf(contentTypeKey),
(contentType) => {
- this.#contentElementTypeAlias.setValue(contentType?.alias);
- this.#contentElementTypeName.setValue(contentType?.name);
+ //this.#contentElementTypeAlias.setValue(contentType?.alias);
+ //this.#contentElementTypeName.setValue(contentType?.name);
+ this.#contentElementType.setValue(contentType);
this._gotContentType(contentType);
},
'observeContentElementType',
diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts
index 7f1289a083..a35e8e7038 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts
@@ -22,6 +22,7 @@ export interface UmbBlockViewUrlsPropType {
export interface UmbBlockViewPropsType {
label?: string;
+ icon?: string;
contentUdi: string;
layout?: BlockLayoutType;
content?: UmbBlockDataType;
diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/components/input-tiny-mce/input-tiny-mce.defaults.ts b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/components/input-tiny-mce/input-tiny-mce.defaults.ts
index 788354893c..c9ef4682e4 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/components/input-tiny-mce/input-tiny-mce.defaults.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/components/input-tiny-mce/input-tiny-mce.defaults.ts
@@ -1,5 +1,6 @@
import { UMB_CONTENT_REQUEST_EVENT_TYPE, type UmbContextRequestEvent } from '@umbraco-cms/backoffice/context-api';
import type { RawEditorOptions } from '@umbraco-cms/backoffice/external/tinymce';
+import { UUIIconRequestEvent } from '@umbraco-cms/backoffice/external/uui';
//export const UMB_BLOCK_ENTRY_WEB_COMPONENTS_ABSOLUTE_PATH = '/umbraco/backoffice/packages/block/block-rte/index.js';
export const UMB_BLOCK_ENTRY_WEB_COMPONENTS_ABSOLUTE_PATH = '@umbraco-cms/backoffice/block-rte';
@@ -13,6 +14,7 @@ export const defaultFallbackConfig: RawEditorOptions = {
invalid_elements: 'font',
extended_valid_elements:
'@[id|class|style],umb-rte-block[!data-content-udi],-umb-rte-block-inline[!data-content-udi],-div[id|dir|class|align|style],ins[datetime|cite],-ul[class|style],-li[class|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align],span[id|class|style|lang],figure,figcaption',
+ custom_elements: 'umb-rte-block[!data-content-udi],~umb-rte-block-inline[!data-content-udi]',
toolbar: [
'styles',
'bold',
@@ -30,7 +32,7 @@ export const defaultFallbackConfig: RawEditorOptions = {
],
init_instance_callback: function (editor) {
- // The following code is the context api proxy.
+ // The following code is the context api proxy. [NL]
// It re-dispatches the context api request event to the origin target of this modal, in other words the element that initiated the modal. [NL]
editor.dom.doc.addEventListener(UMB_CONTENT_REQUEST_EVENT_TYPE, ((event: UmbContextRequestEvent) => {
if (!editor.iframeElement) return;
@@ -39,6 +41,19 @@ export const defaultFallbackConfig: RawEditorOptions = {
editor.iframeElement.dispatchEvent(event.clone());
}) as EventListener);
+ // Proxy for retrieving icons from outside the iframe [NL]
+ editor.dom.doc.addEventListener(UUIIconRequestEvent.ICON_REQUEST, ((event: UUIIconRequestEvent) => {
+ if (!editor.iframeElement) return;
+
+ const newEvent = new UUIIconRequestEvent(UUIIconRequestEvent.ICON_REQUEST, {
+ detail: event.detail,
+ });
+ editor.iframeElement.dispatchEvent(newEvent);
+ if (newEvent.icon !== null) {
+ event.acceptRequest(newEvent.icon);
+ }
+ }) as EventListener);
+
// Transfer our import-map to the iframe: [NL]
const importMapTag = document.head.querySelector('script[type="importmap"]');
if (importMapTag) {
@@ -48,8 +63,17 @@ export const defaultFallbackConfig: RawEditorOptions = {
editor.dom.doc.head.appendChild(importMap);
}
+ // Transfer our stylesheets to the iframe: [NL]
+ const stylesheetTags = document.head.querySelectorAll('link[rel="stylesheet"]');
+ stylesheetTags.forEach((stylesheetTag) => {
+ const stylesheet = document.createElement('link');
+ stylesheet.rel = 'stylesheet';
+ stylesheet.href = stylesheetTag.href;
+ editor.dom.doc.head.appendChild(stylesheet);
+ });
+
// TODO: Lets use/adapt the router-slot logic so we do not need to add this here [NL]
- // TODO: When transfering this code, make sure that we check for target='_parent' or target='top' if its happening within a iframe. [NL]
+ // TODO: When transferring this code, make sure that we check for target='_parent' or target='top' if its happening within a iframe. [NL]
editor.dom.doc.addEventListener('click', (e: MouseEvent) => {
// If we try to open link in a new tab, then we want to skip skip:
//if ((isWindows && e.ctrlKey) || (!isWindows && e.metaKey)) return;
@@ -92,17 +116,14 @@ export const defaultFallbackConfig: RawEditorOptions = {
window.history.pushState(null, '', path);
});
- function appendScript(path: string) {
- const script = document.createElement('script');
- script.type = 'text/javascript';
- script.setAttribute('type', 'module');
- script.text = `import "${path}";`;
- editor.dom.doc.head.appendChild(script);
- }
-
- // Load the umb-rte-block component inside the iframe [NL]
- appendScript('@umbraco-cms/backoffice/extension-registry');
- appendScript(UMB_BLOCK_ENTRY_WEB_COMPONENTS_ABSOLUTE_PATH);
+ // Load backoffice JS so we can get the umb-rte-block component registered inside the iframe [NL]
+ const script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.setAttribute('type', 'module');
+ // TODO: Check that we actually get the same extension registry, or find a way so we can make it do so. — It could be some kind of iframe detection? [NL]
+ script.text = `import "@umbraco-cms/backoffice/extension-registry";`;
+ script.text = `import "${UMB_BLOCK_ENTRY_WEB_COMPONENTS_ABSOLUTE_PATH}";`;
+ editor.dom.doc.head.appendChild(script);
},
style_formats: [