From 8141b6b07e3e1b1ea4ad1f0ac8027c202c2adeb6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 2 Dec 2024 14:48:28 +0100 Subject: [PATCH] Hotfix: unnecessary Discard Changes dialog for RTEs (#17692) * remove code duplication * remove unused code * allow value to be undefined * dot not build model if we have no markup * do update the layout value if we don't get any layouts * reset internals if there are no value * clear value if tiny mce doesn't have any markup * clear value if tip tap doesn't have any markup * add method to check if tip tap element is empty * use method to check for empty tip tap --- .../rte/components/rte-base.element.ts | 81 ++++++++++--------- .../property-editor-ui-tiny-mce.element.ts | 17 +++- .../input-tiptap/input-tiptap.element.ts | 8 ++ .../property-editor-ui-tiptap.element.ts | 20 +++-- 4 files changed, 78 insertions(+), 48 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts index b6e7a4f42a..60f61c75b3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts @@ -10,9 +10,11 @@ import type { import { UmbBlockRteEntriesContext, UmbBlockRteManagerContext, + type UmbBlockRteLayoutModel, type UmbBlockRteTypeModel, } from '@umbraco-cms/backoffice/block-rte'; import { UMB_PROPERTY_CONTEXT, UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; +import type { UmbBlockValueType } from '@umbraco-cms/backoffice/block'; // eslint-disable-next-line local-rules/enforce-element-suffix-on-element-class-name export abstract class UmbPropertyEditorUiRteElementBase extends UmbLitElement implements UmbPropertyEditorUiElement { @@ -35,6 +37,16 @@ export abstract class UmbPropertyEditorUiRteElementBase extends UmbLitElement im }, }) public set value(value: UmbPropertyEditorUiValueType | undefined) { + if (!value) { + this._value = undefined; + this._markup = ''; + this.#managerContext.setLayouts([]); + this.#managerContext.setContents([]); + this.#managerContext.setSettings([]); + this.#managerContext.setExposes([]); + return; + } + const buildUpValue: Partial = value ? { ...value } : {}; buildUpValue.markup ??= ''; buildUpValue.blocks ??= { layout: {}, contentData: [], settingsData: [], expose: [] }; @@ -69,10 +81,7 @@ export abstract class UmbPropertyEditorUiRteElementBase extends UmbLitElement im protected _config?: UmbPropertyEditorConfigCollection; @state() - protected _value: UmbPropertyEditorUiValueType = { - markup: '', - blocks: { layout: {}, contentData: [], settingsData: [], expose: [] }, - }; + protected _value?: UmbPropertyEditorUiValueType | undefined; /** * Separate state for markup, to avoid re-rendering/re-setting the value of the Tiptap editor when the value does not really change. @@ -127,49 +136,30 @@ export abstract class UmbPropertyEditorUiRteElementBase extends UmbLitElement im // Observe the value of the property and update the editor value. this.observe(this.#managerContext.layouts, (layouts) => { - this._value = { - ...this._value, - blocks: { ...this._value.blocks, layout: { [UMB_BLOCK_RTE_PROPERTY_EDITOR_SCHEMA_ALIAS]: layouts } }, - }; - this._fireChangeEvent(); + const blocksValue = + this._value && layouts?.length > 0 + ? { ...this._value.blocks, layout: { [UMB_BLOCK_RTE_PROPERTY_EDITOR_SCHEMA_ALIAS]: layouts } } + : undefined; + + this.#setBlocksValue(blocksValue); }); + this.observe(this.#managerContext.contents, (contents) => { - this._value = { ...this._value, blocks: { ...this._value.blocks, contentData: contents } }; - this._fireChangeEvent(); + const blocksValue = this._value ? { ...this._value.blocks, contentData: contents } : undefined; + this.#setBlocksValue(blocksValue); }); + this.observe(this.#managerContext.settings, (settings) => { - this._value = { ...this._value, blocks: { ...this._value.blocks, settingsData: settings } }; - this._fireChangeEvent(); + const blocksValue = this._value ? { ...this._value.blocks, settingsData: settings } : undefined; + this.#setBlocksValue(blocksValue); }); + this.observe(this.#managerContext.exposes, (exposes) => { - this._value = { ...this._value, blocks: { ...this._value.blocks, expose: exposes } }; - this._fireChangeEvent(); + const blocksValue = this._value ? { ...this._value.blocks, expose: exposes } : undefined; + this.#setBlocksValue(blocksValue); }); - - // The above could potentially be replaced with a single observeMultiple call, but it is not done for now to avoid potential issues with the order of the updates. - /*this.observe( - observeMultiple([ - this.#managerContext.layouts, - this.#managerContext.contents, - this.#managerContext.settings, - this.#managerContext.exposes, - ]).pipe(debounceTime(20)), - ([layouts, contents, settings, exposes]) => { - this._value = { - ...this._value, - blocks: { - layout: { [UMB_BLOCK_RTE_PROPERTY_EDITOR_SCHEMA_ALIAS]: layouts }, - contentData: contents, - settingsData: settings, - expose: exposes, - }, - }; - - this._fireChangeEvent(); - }, - 'motherObserver', - );*/ }); + this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (context) => { this.#managerContext.setVariantId(context.getVariantId()); }); @@ -191,6 +181,19 @@ export abstract class UmbPropertyEditorUiRteElementBase extends UmbLitElement im }); } + #setBlocksValue(blocksValue?: UmbBlockValueType) { + if (!blocksValue || !this._value) { + return; + } + + this._value = { + ...this._value, + blocks: blocksValue, + }; + + this._fireChangeEvent(); + } + protected _fireChangeEvent() { this.dispatchEvent(new UmbPropertyValueChangeEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/property-editors/tiny-mce/property-editor-ui-tiny-mce.element.ts b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/property-editors/tiny-mce/property-editor-ui-tiny-mce.element.ts index 6033e78ead..b10349366c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/property-editors/tiny-mce/property-editor-ui-tiny-mce.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/property-editors/tiny-mce/property-editor-ui-tiny-mce.element.ts @@ -12,6 +12,13 @@ export class UmbPropertyEditorUITinyMceElement extends UmbPropertyEditorUiRteEle #onChange(event: CustomEvent & { target: UmbInputTinyMceElement }) { const value = typeof event.target.value === 'string' ? event.target.value : ''; + // If we don't get any markup clear the property editor value. + if (value === '') { + this.value = undefined; + this._fireChangeEvent(); + return; + } + // Clone the DOM, to remove the classes and attributes on the original: const div = document.createElement('div'); div.innerHTML = value; @@ -38,10 +45,12 @@ export class UmbPropertyEditorUITinyMceElement extends UmbPropertyEditorUiRteEle this._latestMarkup = markup; - this._value = { - ...this._value, - markup: markup, - }; + this._value = this._value + ? { + ...this._value, + markup: markup, + } + : undefined; this._fireChangeEvent(); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/input-tiptap/input-tiptap.element.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/input-tiptap/input-tiptap.element.ts index 130d8aee6f..4743f758d1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/input-tiptap/input-tiptap.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/input-tiptap/input-tiptap.element.ts @@ -67,6 +67,14 @@ export class UmbInputTiptapElement extends UmbFormControlMixin((resolve) => { this.observe(umbExtensionsRegistry.byType('tiptapExtension'), async (manifests) => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/property-editors/tiptap/property-editor-ui-tiptap.element.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/property-editors/tiptap/property-editor-ui-tiptap.element.ts index d0340572ff..5cd865f02c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/property-editors/tiptap/property-editor-ui-tiptap.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/property-editors/tiptap/property-editor-ui-tiptap.element.ts @@ -12,7 +12,15 @@ const elementName = 'umb-property-editor-ui-tiptap'; @customElement(elementName) export class UmbPropertyEditorUiTiptapElement extends UmbPropertyEditorUiRteElementBase { #onChange(event: CustomEvent & { target: UmbInputTiptapElement }) { - const value = event.target.value; + const tipTapElement = event.target; + const value = tipTapElement.value; + + // If we don't get any markup clear the property editor value. + if (tipTapElement.isEmpty()) { + this.value = undefined; + this._fireChangeEvent(); + return; + } // Remove unused Blocks of Blocks Layout. Leaving only the Blocks that are present in Markup. const usedContentKeys: string[] = []; @@ -32,10 +40,12 @@ export class UmbPropertyEditorUiTiptapElement extends UmbPropertyEditorUiRteElem this._latestMarkup = value; - this._value = { - ...this._value, - markup: this._latestMarkup, - }; + this._value = this._value + ? { + ...this._value, + markup: this._latestMarkup, + } + : undefined; this._fireChangeEvent(); }