From ab3dc36d9edd204bbf08b978180d3fed4262cb6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 7 Oct 2024 21:31:18 +0200 Subject: [PATCH 1/4] ufm as text --- .../controller-api/controller-host.mixin.ts | 13 ++++-- .../block/context/block-entry.context.ts | 16 ++++++- .../label-value/label-value.element.ts | 4 ++ .../ufm-render/ufm-render.element.ts | 5 ++ .../ufm-virtual-render.controller.ts | 46 +++++++++++++++++++ .../src/packages/ufm/index.ts | 3 +- .../src/packages/ufm/types.ts | 1 + 7 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts diff --git a/src/Umbraco.Web.UI.Client/src/libs/controller-api/controller-host.mixin.ts b/src/Umbraco.Web.UI.Client/src/libs/controller-api/controller-host.mixin.ts index 61561ea731..a0d880a33e 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/controller-api/controller-host.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/controller-api/controller-host.mixin.ts @@ -13,6 +13,7 @@ interface UmbControllerHostBaseDeclaration extends Omit(superClass: T) => { class UmbControllerHostBaseClass extends superClass implements UmbControllerHostBaseDeclaration { @@ -26,7 +27,8 @@ export const UmbControllerHostMixin = (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 = (superClass: T /** * Retrieve controllers matching a filter of this element. - * @param {method} filterMethod + * @param {Function} filterMethod - filter method + * @returns {Array} - currently assigned controllers passing the filter method. */ - getUmbControllers(filterMethod: (ctrl: UmbController) => boolean): UmbController[] { + getUmbControllers(filterMethod: (ctrl: UmbController) => boolean): Array { 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 = (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); 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 e21288f03e..a593f17c32 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 @@ -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, @@ -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.getAsText(); } #updateCreatePaths() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts index 64081048ac..d4a5a0747c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts @@ -26,6 +26,10 @@ export class UmbUfmLabelValueElement extends UmbUfmElementBase { ); }); } + + override createRenderRoot() { + return this; + } } export { UmbUfmLabelValueElement as element }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts index 6bf24160e5..02012bec1b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts @@ -34,6 +34,11 @@ export class UmbUfmRenderElement extends UmbLitElement { }); } + getAsText(): string { + console.log(this.shadowRoot); + return this.shadowRoot?.textContent ?? ''; + } + override render() { return until(this.#renderMarkdown()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts new file mode 100644 index 0000000000..68aff56dc0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts @@ -0,0 +1,46 @@ +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; + + 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'; + console.log(this.getHostElement()); + this.getHostElement().appendChild(element); + this.#element = element; + } + + override hostConnected(): void {} + + getAsText(): string { + return this.#element.getAsText(); + } + + override destroy(): void { + super.destroy(); + this.#element?.destroy(); + (this.#element as any) = undefined; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/index.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/index.ts index 481d5818a8..6735e76614 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/types.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/types.ts index 066099c1db..e97116b6c1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/types.ts @@ -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): string | undefined | null; destroy() {} From 2afcf96614dbe9d8d23c7b1fdc95cdae1366a9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 8 Oct 2024 07:53:07 +0200 Subject: [PATCH 2/4] move light-dom declaration to base element --- .../ufm/components/label-value/label-value.element.ts | 4 ---- .../src/packages/ufm/components/ufm-element-base.ts | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts index d4a5a0747c..64081048ac 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts @@ -26,10 +26,6 @@ export class UmbUfmLabelValueElement extends UmbUfmElementBase { ); }); } - - override createRenderRoot() { - return this; - } } export { UmbUfmLabelValueElement as element }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts index 524d281f81..2b1a81e31b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts @@ -36,6 +36,10 @@ export abstract class UmbUfmElementBase extends UmbLitElement { }); } + override createRenderRoot() { + return this; + } + override render() { if (!this.#ufmContext) return nothing; From e71440b4c7cbb016aee7e421b45d7403f84bb7fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 8 Oct 2024 08:25:50 +0200 Subject: [PATCH 3/4] rename method to toString() --- .../src/packages/block/block/context/block-entry.context.ts | 2 +- .../packages/ufm/components/ufm-render/ufm-render.element.ts | 3 +-- .../packages/ufm/controllers/ufm-virtual-render.controller.ts | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) 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 a593f17c32..efc4e79a3f 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 @@ -375,7 +375,7 @@ export abstract class UmbBlockEntryContext< * @returns {string} - the value of the label. */ getLabel() { - return this.#labelRender.getAsText(); + return this.#labelRender.toString(); } #updateCreatePaths() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts index 02012bec1b..76de2ba178 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts @@ -34,8 +34,7 @@ export class UmbUfmRenderElement extends UmbLitElement { }); } - getAsText(): string { - console.log(this.shadowRoot); + override toString(): string { return this.shadowRoot?.textContent ?? ''; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts index 68aff56dc0..9a7cf8b669 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts @@ -34,8 +34,8 @@ export class UmbUfmVirtualRenderController extends UmbControllerBase { override hostConnected(): void {} - getAsText(): string { - return this.#element.getAsText(); + override toString(): string { + return this.#element.toString(); } override destroy(): void { From 9f9b83a9dda9d7621922b5d25d19843261bc1409 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Tue, 8 Oct 2024 15:47:24 +0100 Subject: [PATCH 4/4] Traverse the Shadow DOM children to gather text content. --- .../ufm/components/ufm-element-base.ts | 4 --- .../ufm-virtual-render.controller.ts | 26 +++++++++++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts index 2b1a81e31b..524d281f81 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts @@ -36,10 +36,6 @@ export abstract class UmbUfmElementBase extends UmbLitElement { }); } - override createRenderRoot() { - return this; - } - override render() { if (!this.#ufmContext) return nothing; diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts index 9a7cf8b669..c8ead67af2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts @@ -8,12 +8,35 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; export class UmbUfmVirtualRenderController extends UmbControllerBase { #element: UmbUfmRenderElement; + #getTextFromDescendants(element?: Element | null): string { + if (!element) return ''; + + const items: Array = []; + + 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; } @@ -27,7 +50,6 @@ export class UmbUfmVirtualRenderController extends UmbControllerBase { const element = new UmbUfmRenderElement(); element.inline = true; element.style.visibility = 'hidden'; - console.log(this.getHostElement()); this.getHostElement().appendChild(element); this.#element = element; } @@ -35,7 +57,7 @@ export class UmbUfmVirtualRenderController extends UmbControllerBase { override hostConnected(): void {} override toString(): string { - return this.#element.toString(); + return this.#getTextFromDescendants(this.#element); } override destroy(): void {