multiple fixes in one commit

This commit is contained in:
Niels Lyngsø
2024-05-28 00:07:34 +02:00
parent 2829605bf5
commit de24c82a4e
10 changed files with 112 additions and 40 deletions

View File

@@ -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;
});

View File

@@ -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`<uui-button label="edit" compact href=${this._workspaceEditContentPath}>
<uui-icon name="icon-edit"></uui-icon>
</uui-button>`
</uui-button>`
: ''}
${this._hasSettings && this._workspaceEditSettingsPath
? html`<uui-button label="Edit settings" compact href=${this._workspaceEditSettingsPath}>
<uui-icon name="icon-settings"></uui-icon>
</uui-button>`
</uui-button>`
: ''}
<uui-button label="delete" compact @click=${() => this.#context.requestDelete()}>
<uui-icon name="icon-remove"></uui-icon>

View File

@@ -11,7 +11,7 @@ export class UmbBlockRteEntryInlineElement extends UmbBlockRteEntryElement {
...UmbBlockRteEntryElement.styles,
css`
:host {
display: inline;
display: inline-block;
}
`,
];

View File

@@ -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<UmbBlockListLayoutModel> = { contentUdi: undefined!, urls: {} }; // Set to undefined cause it will be set before we render.
_blockViewProps: UmbBlockViewPropsType<UmbBlockRteLayoutModel> = { 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`<umb-ref-rte-block .label=${this._label}></umb-ref-rte-block>`;
return html`<umb-ref-rte-block .label=${this._label} .icon=${this._icon}></umb-ref-rte-block>`;
}
#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;

View File

@@ -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`<uui-ref-node
standalone
.name=${this.label ?? ''}
href=${this._workspaceEditPath ?? '#'}></uui-ref-node>`;
return html`<uui-ref-node standalone .name=${this.label ?? ''} href=${this._workspaceEditPath ?? '#'}
><uui-icon slot="icon" .name=${this.icon ?? null}></uui-icon
></uui-ref-node>`;
}
static styles = [

View File

@@ -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);

View File

@@ -24,7 +24,19 @@ export class UmbBlockRteManagerContext<
partialLayoutEntry?: Omit<BlockLayoutType, 'contentUdi'>,
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(
`<umb-rte-block-inline data-content-udi="${layoutEntry.contentUdi}"><!--Umbraco-Block--></umb-rte-block-inline>`,
@@ -45,9 +61,7 @@ export class UmbBlockRteManagerContext<
);
}
this._layouts.appendOne(layoutEntry);
this.insertBlockData(layoutEntry, content, settings, modalData);
this.#editor.fire('change');
return true;
}

View File

@@ -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<UmbContentTypeModel | undefined>(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<BlockType | undefined>(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',

View File

@@ -22,6 +22,7 @@ export interface UmbBlockViewUrlsPropType {
export interface UmbBlockViewPropsType<BlockLayoutType extends UmbBlockLayoutBaseModel> {
label?: string;
icon?: string;
contentUdi: string;
layout?: BlockLayoutType;
content?: UmbBlockDataType;

View File

@@ -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<HTMLLinkElement>('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: [