Merge pull request #2423 from umbraco/v15/feature/ufm-as-text
UFM as text
This commit is contained in:
@@ -13,6 +13,7 @@ interface UmbControllerHostBaseDeclaration extends Omit<UmbControllerHost, 'getH
|
||||
* This enables controllers to be added to the life cycle of this element.
|
||||
* @param {object} superClass - superclass to be extended.
|
||||
* @mixin
|
||||
* @returns {UmbControllerHost} - A class which extends the given superclass.
|
||||
*/
|
||||
export const UmbControllerHostMixin = <T extends ClassConstructor>(superClass: T) => {
|
||||
class UmbControllerHostBaseClass extends superClass implements UmbControllerHostBaseDeclaration {
|
||||
@@ -26,7 +27,8 @@ export const UmbControllerHostMixin = <T extends ClassConstructor>(superClass: T
|
||||
|
||||
/**
|
||||
* Tests if a controller is assigned to this element.
|
||||
* @param {UmbController} ctrl
|
||||
* @param {UmbController} ctrl - The controller to check for.
|
||||
* @returns {boolean} - true if the controller is assigned
|
||||
*/
|
||||
hasUmbController(ctrl: UmbController): boolean {
|
||||
return this.#controllers.indexOf(ctrl) !== -1;
|
||||
@@ -34,15 +36,16 @@ export const UmbControllerHostMixin = <T extends ClassConstructor>(superClass: T
|
||||
|
||||
/**
|
||||
* Retrieve controllers matching a filter of this element.
|
||||
* @param {method} filterMethod
|
||||
* @param {Function} filterMethod - filter method
|
||||
* @returns {Array<UmbController>} - currently assigned controllers passing the filter method.
|
||||
*/
|
||||
getUmbControllers(filterMethod: (ctrl: UmbController) => boolean): UmbController[] {
|
||||
getUmbControllers(filterMethod: (ctrl: UmbController) => boolean): Array<UmbController> {
|
||||
return this.#controllers.filter(filterMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a controller to this element.
|
||||
* @param {UmbController} ctrl
|
||||
* @param {UmbController} ctrl - the controller to append to this host.
|
||||
*/
|
||||
addUmbController(ctrl: UmbController): void {
|
||||
// If this specific class is already added, then skip out.
|
||||
@@ -68,7 +71,7 @@ export const UmbControllerHostMixin = <T extends ClassConstructor>(superClass: T
|
||||
/**
|
||||
* Remove a controller from this element.
|
||||
* Notice this will also destroy the controller.
|
||||
* @param {UmbController} ctrl
|
||||
* @param {UmbController} ctrl - The controller to remove and destroy from this host.
|
||||
*/
|
||||
removeUmbController(ctrl: UmbController): void {
|
||||
const index = this.#controllers.indexOf(ctrl);
|
||||
|
||||
@@ -23,6 +23,7 @@ import type {
|
||||
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import type { UmbBlockTypeBaseModel } from '@umbraco-cms/backoffice/block-type';
|
||||
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import { UmbUfmVirtualRenderController } from '@umbraco-cms/backoffice/ufm';
|
||||
|
||||
export abstract class UmbBlockEntryContext<
|
||||
BlockManagerContextTokenType extends UmbContextToken<BlockManagerContextType>,
|
||||
@@ -94,6 +95,8 @@ export abstract class UmbBlockEntryContext<
|
||||
#label = new UmbStringState('');
|
||||
public readonly label = this.#label.asObservable();
|
||||
|
||||
#labelRender = new UmbUfmVirtualRenderController(this);
|
||||
|
||||
#generateWorkspaceEditContentPath = (path?: string, contentKey?: string) =>
|
||||
path && contentKey ? path + 'edit/' + encodeFilePath(contentKey) + '/view/content' : '';
|
||||
|
||||
@@ -244,6 +247,11 @@ export abstract class UmbBlockEntryContext<
|
||||
) {
|
||||
super(host, 'UmbBlockEntryContext');
|
||||
|
||||
this.observe(this.label, (label) => {
|
||||
this.#labelRender.markdown = label;
|
||||
});
|
||||
this.#watchContentForLabelRender();
|
||||
|
||||
// Consume block manager:
|
||||
this.consumeContext(blockManagerContextToken, (manager) => {
|
||||
this._manager = manager;
|
||||
@@ -340,6 +348,12 @@ export abstract class UmbBlockEntryContext<
|
||||
);
|
||||
}
|
||||
|
||||
async #watchContentForLabelRender() {
|
||||
this.observe(await this.contentValues(), (content) => {
|
||||
this.#labelRender.value = content;
|
||||
});
|
||||
}
|
||||
|
||||
getContentKey() {
|
||||
return this._layout.value?.contentKey;
|
||||
}
|
||||
@@ -361,7 +375,7 @@ export abstract class UmbBlockEntryContext<
|
||||
* @returns {string} - the value of the label.
|
||||
*/
|
||||
getLabel() {
|
||||
return this.#label.value;
|
||||
return this.#labelRender.toString();
|
||||
}
|
||||
|
||||
#updateCreatePaths() {
|
||||
|
||||
@@ -34,6 +34,10 @@ export class UmbUfmRenderElement extends UmbLitElement {
|
||||
});
|
||||
}
|
||||
|
||||
override toString(): string {
|
||||
return this.shadowRoot?.textContent ?? '';
|
||||
}
|
||||
|
||||
override render() {
|
||||
return until(this.#renderMarkdown());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { UmbUfmRenderElement } from '../components/index.js';
|
||||
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
|
||||
/**
|
||||
* Renders a UFM
|
||||
*/
|
||||
export class UmbUfmVirtualRenderController extends UmbControllerBase {
|
||||
#element: UmbUfmRenderElement;
|
||||
|
||||
#getTextFromDescendants(element?: Element | null): string {
|
||||
if (!element) return '';
|
||||
|
||||
const items: Array<string> = [];
|
||||
|
||||
items.push(element.shadowRoot?.textContent ?? element.textContent ?? '');
|
||||
|
||||
if (element.shadowRoot !== null) {
|
||||
Array.from(element.shadowRoot.children).forEach((element) => {
|
||||
items.push(this.#getTextFromDescendants(element));
|
||||
});
|
||||
}
|
||||
|
||||
if (element.children !== null) {
|
||||
Array.from(element.children).forEach((element) => {
|
||||
items.push(this.#getTextFromDescendants(element));
|
||||
});
|
||||
}
|
||||
|
||||
return items.filter((x) => x).join(' ');
|
||||
}
|
||||
|
||||
set markdown(markdown: string | undefined) {
|
||||
this.#element.markdown = markdown;
|
||||
}
|
||||
get markdown(): string | undefined {
|
||||
return this.#element.markdown;
|
||||
}
|
||||
|
||||
set value(value: unknown | undefined) {
|
||||
this.#element.value = value;
|
||||
}
|
||||
get value(): unknown | undefined {
|
||||
return this.#element.value;
|
||||
}
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host);
|
||||
|
||||
const element = new UmbUfmRenderElement();
|
||||
element.inline = true;
|
||||
element.style.visibility = 'hidden';
|
||||
this.getHostElement().appendChild(element);
|
||||
this.#element = element;
|
||||
}
|
||||
|
||||
override hostConnected(): void {}
|
||||
|
||||
override toString(): string {
|
||||
return this.#getTextFromDescendants(this.#element);
|
||||
}
|
||||
|
||||
override destroy(): void {
|
||||
super.destroy();
|
||||
this.#element?.destroy();
|
||||
(this.#element as any) = undefined;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from './types.js';
|
||||
export * from './components/index.js';
|
||||
export * from './contexts/index.js';
|
||||
export * from './controllers/ufm-virtual-render.controller.js';
|
||||
export * from './plugins/index.js';
|
||||
export * from './types.js';
|
||||
export * from './ufm-component.extension.js';
|
||||
export * from './ufm-filter.extension.js';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { UmbUfmFilterApi } from './ufm-filter.extension.js';
|
||||
|
||||
// TODO: This is not a type? So it should ideally be move to a different file. [NL]
|
||||
export abstract class UmbUfmFilterBase implements UmbUfmFilterApi {
|
||||
abstract filter(...args: Array<unknown>): string | undefined | null;
|
||||
destroy() {}
|
||||
|
||||
Reference in New Issue
Block a user