Skip to content

Commit 34cad5f

Browse files
authored
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
1 parent e8d4634 commit 34cad5f

File tree

5 files changed

+89
-11
lines changed

5 files changed

+89
-11
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { expect, fixture, html } from '@open-wc/testing';
2+
import { type UmbTestRunnerWindow, defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
3+
import UmbBlockRteEntryInlineElement from './block-rte-entry-inline.element.js';
4+
5+
const blockGuid = '00000000-0000-0000-0000-000000000000';
6+
7+
describe('UmbBlockRteEntryInline', () => {
8+
let element: UmbBlockRteEntryInlineElement;
9+
10+
beforeEach(async () => {
11+
element = await fixture(html`<umb-rte-block-inline .contentKey=${blockGuid}></umb-rte-block-inline>`);
12+
});
13+
14+
it('is defined with its own instance', () => {
15+
expect(element).to.be.instanceOf(UmbBlockRteEntryInlineElement);
16+
});
17+
18+
if ((window as UmbTestRunnerWindow).__UMBRACO_TEST_RUN_A11Y_TEST) {
19+
it('passes the a11y audit', async () => {
20+
await expect(element).to.be.accessible(defaultA11yConfig);
21+
});
22+
}
23+
});

src/Umbraco.Web.UI.Client/src/packages/block/block-rte/components/block-rte-entry/block-rte-entry.element.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import type { UmbExtensionElementInitializer } from '@umbraco-cms/backoffice/ext
2121
*/
2222
@customElement('umb-rte-block')
2323
export class UmbBlockRteEntryElement extends UmbLitElement implements UmbPropertyEditorUiElement {
24-
//
2524
@property({ type: String, attribute: 'data-content-key', reflect: true })
2625
public get contentKey(): string | undefined {
2726
return this._contentKey;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { expect, fixture, html } from '@open-wc/testing';
2+
import { type UmbTestRunnerWindow, defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
3+
import UmbBlockRteEntryElement from './block-rte-entry.element.js';
4+
5+
const blockGuid = '00000000-0000-0000-0000-000000000000';
6+
7+
describe('UmbBlockRteEntry', () => {
8+
let element: UmbBlockRteEntryElement;
9+
10+
beforeEach(async () => {
11+
element = await fixture(html`<umb-rte-block .contentKey=${blockGuid}></umb-rte-block>`);
12+
});
13+
14+
it('is defined with its own instance', () => {
15+
expect(element).to.be.instanceOf(UmbBlockRteEntryElement);
16+
});
17+
18+
if ((window as UmbTestRunnerWindow).__UMBRACO_TEST_RUN_A11Y_TEST) {
19+
it('passes the a11y audit', async () => {
20+
await expect(element).to.be.accessible(defaultA11yConfig);
21+
});
22+
}
23+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { expect, fixture, html } from '@open-wc/testing';
2+
3+
import { type UmbTestRunnerWindow, defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
4+
import UmbRefRteBlockElement from './ref-rte-block.element.js';
5+
6+
describe('UmbRefRteBlock', () => {
7+
let element: UmbRefRteBlockElement;
8+
9+
beforeEach(async () => {
10+
element = await fixture(html`<umb-ref-rte-block></umb-ref-rte-block>`);
11+
});
12+
13+
it('is defined with its own instance', () => {
14+
expect(element).to.be.instanceOf(UmbRefRteBlockElement);
15+
});
16+
17+
if ((window as UmbTestRunnerWindow).__UMBRACO_TEST_RUN_A11Y_TEST) {
18+
it('passes the a11y audit', async () => {
19+
await expect(element).to.be.accessible(defaultA11yConfig);
20+
});
21+
}
22+
});

src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { UmbUfmRenderElement } from '../components/index.js';
22
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
3-
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
43

54
/**
65
* Renders a UFM
76
*/
87
export class UmbUfmVirtualRenderController extends UmbControllerBase {
9-
#element: UmbUfmRenderElement;
8+
#element?: UmbUfmRenderElement;
109

1110
#getTextFromDescendants(element?: Element | null): string {
1211
if (!element) return '';
@@ -31,30 +30,42 @@ export class UmbUfmVirtualRenderController extends UmbControllerBase {
3130
}
3231

3332
set markdown(markdown: string | undefined) {
34-
this.#element.markdown = markdown;
33+
this.#markdown = markdown;
34+
if (this.#element) {
35+
this.#element.markdown = markdown;
36+
}
3537
}
3638
get markdown(): string | undefined {
37-
return this.#element.markdown;
39+
return this.#markdown;
3840
}
41+
#markdown: string | undefined;
3942

4043
set value(value: unknown | undefined) {
41-
this.#element.value = value;
44+
this.#value = value;
45+
if (this.#element) {
46+
this.#element.value = value;
47+
}
4248
}
4349
get value(): unknown | undefined {
44-
return this.#element.value;
50+
return this.#value;
4551
}
52+
#value: unknown | undefined;
4653

47-
constructor(host: UmbControllerHost) {
48-
super(host);
49-
54+
override hostConnected(): void {
5055
const element = new UmbUfmRenderElement();
5156
element.inline = true;
5257
element.style.visibility = 'hidden';
58+
59+
element.markdown = this.#markdown;
60+
element.value = this.#value;
61+
5362
this.getHostElement().appendChild(element);
5463
this.#element = element;
5564
}
5665

57-
override hostConnected(): void {}
66+
override hostDisconnected(): void {
67+
this.#element?.remove();
68+
}
5869

5970
override toString(): string {
6071
return this.#getTextFromDescendants(this.#element);

0 commit comments

Comments
 (0)