fix: Blocks do not work in the rich text editors (#17711)
* fix: do not add attributes or html elements to custom elements before they are created Due to the way browsers treat custom elements, they are not allowed to add attributes and/or child elements upon creation. They must wait until the `connectedCallback`. That means any controller that wants to add elements should also wait until the host is connected (`hostConnected`). * test: add generic tests for rte block elements * chore: cleanup imports
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
import { type UmbTestRunnerWindow, defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
|
||||
import UmbBlockRteEntryInlineElement from './block-rte-entry-inline.element.js';
|
||||
|
||||
const blockGuid = '00000000-0000-0000-0000-000000000000';
|
||||
|
||||
describe('UmbBlockRteEntryInline', () => {
|
||||
let element: UmbBlockRteEntryInlineElement;
|
||||
|
||||
beforeEach(async () => {
|
||||
element = await fixture(html`<umb-rte-block-inline .contentKey=${blockGuid}></umb-rte-block-inline>`);
|
||||
});
|
||||
|
||||
it('is defined with its own instance', () => {
|
||||
expect(element).to.be.instanceOf(UmbBlockRteEntryInlineElement);
|
||||
});
|
||||
|
||||
if ((window as UmbTestRunnerWindow).__UMBRACO_TEST_RUN_A11Y_TEST) {
|
||||
it('passes the a11y audit', async () => {
|
||||
await expect(element).to.be.accessible(defaultA11yConfig);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -21,7 +21,6 @@ import type { UmbExtensionElementInitializer } from '@umbraco-cms/backoffice/ext
|
||||
*/
|
||||
@customElement('umb-rte-block')
|
||||
export class UmbBlockRteEntryElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
||||
//
|
||||
@property({ type: String, attribute: 'data-content-key', reflect: true })
|
||||
public get contentKey(): string | undefined {
|
||||
return this._contentKey;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
import { type UmbTestRunnerWindow, defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
|
||||
import UmbBlockRteEntryElement from './block-rte-entry.element.js';
|
||||
|
||||
const blockGuid = '00000000-0000-0000-0000-000000000000';
|
||||
|
||||
describe('UmbBlockRteEntry', () => {
|
||||
let element: UmbBlockRteEntryElement;
|
||||
|
||||
beforeEach(async () => {
|
||||
element = await fixture(html`<umb-rte-block .contentKey=${blockGuid}></umb-rte-block>`);
|
||||
});
|
||||
|
||||
it('is defined with its own instance', () => {
|
||||
expect(element).to.be.instanceOf(UmbBlockRteEntryElement);
|
||||
});
|
||||
|
||||
if ((window as UmbTestRunnerWindow).__UMBRACO_TEST_RUN_A11Y_TEST) {
|
||||
it('passes the a11y audit', async () => {
|
||||
await expect(element).to.be.accessible(defaultA11yConfig);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
|
||||
import { type UmbTestRunnerWindow, defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
|
||||
import UmbRefRteBlockElement from './ref-rte-block.element.js';
|
||||
|
||||
describe('UmbRefRteBlock', () => {
|
||||
let element: UmbRefRteBlockElement;
|
||||
|
||||
beforeEach(async () => {
|
||||
element = await fixture(html`<umb-ref-rte-block></umb-ref-rte-block>`);
|
||||
});
|
||||
|
||||
it('is defined with its own instance', () => {
|
||||
expect(element).to.be.instanceOf(UmbRefRteBlockElement);
|
||||
});
|
||||
|
||||
if ((window as UmbTestRunnerWindow).__UMBRACO_TEST_RUN_A11Y_TEST) {
|
||||
it('passes the a11y audit', async () => {
|
||||
await expect(element).to.be.accessible(defaultA11yConfig);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,12 +1,11 @@
|
||||
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;
|
||||
#element?: UmbUfmRenderElement;
|
||||
|
||||
#getTextFromDescendants(element?: Element | null): string {
|
||||
if (!element) return '';
|
||||
@@ -31,30 +30,42 @@ export class UmbUfmVirtualRenderController extends UmbControllerBase {
|
||||
}
|
||||
|
||||
set markdown(markdown: string | undefined) {
|
||||
this.#markdown = markdown;
|
||||
if (this.#element) {
|
||||
this.#element.markdown = markdown;
|
||||
}
|
||||
get markdown(): string | undefined {
|
||||
return this.#element.markdown;
|
||||
}
|
||||
get markdown(): string | undefined {
|
||||
return this.#markdown;
|
||||
}
|
||||
#markdown: string | undefined;
|
||||
|
||||
set value(value: unknown | undefined) {
|
||||
this.#value = value;
|
||||
if (this.#element) {
|
||||
this.#element.value = value;
|
||||
}
|
||||
get value(): unknown | undefined {
|
||||
return this.#element.value;
|
||||
}
|
||||
get value(): unknown | undefined {
|
||||
return this.#value;
|
||||
}
|
||||
#value: unknown | undefined;
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host);
|
||||
|
||||
override hostConnected(): void {
|
||||
const element = new UmbUfmRenderElement();
|
||||
element.inline = true;
|
||||
element.style.visibility = 'hidden';
|
||||
|
||||
element.markdown = this.#markdown;
|
||||
element.value = this.#value;
|
||||
|
||||
this.getHostElement().appendChild(element);
|
||||
this.#element = element;
|
||||
}
|
||||
|
||||
override hostConnected(): void {}
|
||||
override hostDisconnected(): void {
|
||||
this.#element?.remove();
|
||||
}
|
||||
|
||||
override toString(): string {
|
||||
return this.#getTextFromDescendants(this.#element);
|
||||
|
||||
Reference in New Issue
Block a user