diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts index d450aefc1e..c99998fc80 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts @@ -13,6 +13,7 @@ import { } from '@umbraco-cms/backoffice/workspace'; import { appendToFrozenArray, + jsonStringComparison, UmbArrayState, UmbObjectState, UmbStringState, @@ -29,6 +30,7 @@ import { UmbRequestReloadStructureForEntityEvent, } from '@umbraco-cms/backoffice/entity-action'; import { UmbValidationContext } from '@umbraco-cms/backoffice/validation'; +import { UMB_DISCARD_CHANGES_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; type EntityType = UmbDataTypeDetailModel; @@ -100,6 +102,7 @@ export class UmbDataTypeWorkspaceContext constructor(host: UmbControllerHost) { super(host, 'Umb.Workspace.DataType'); + window.addEventListener('willchangestate', this.#onWillNavigate); this.addValidationContext(new UmbValidationContext(this)); this.#observePropertyEditorSchemaAlias(); @@ -421,6 +424,49 @@ export class UmbDataTypeWorkspaceContext await this.repository.delete(unique); } + #hasUnpersistedChanges() { + const persisted = this.#persistedData.getValue(); + const current = this.#currentData.getValue(); + return jsonStringComparison(persisted, current) === false; + } + + #resetCurrentData() { + this.#currentData.setValue(this.#persistedData.getValue()); + } + + #willNavigateAway(newUrl: string) { + let willNavigateAway = false; + + if (this.getIsNew()) { + willNavigateAway = !newUrl.includes(`${this.getEntityType()}/create`); + } else { + willNavigateAway = !newUrl.includes(this.getUnique()!); + } + + return willNavigateAway; + } + + #onWillNavigate = async (e: CustomEvent) => { + const newUrl = e.detail.url; + + if (this.#willNavigateAway(newUrl) && this.#hasUnpersistedChanges()) { + e.preventDefault(); + const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + const modal = modalManager.open(this, UMB_DISCARD_CHANGES_MODAL); + + try { + // navigate to the new url when discarding changes + await modal.onSubmit(); + // Reset the current data so we don't end in a endless loop of asking to discard changes. + this.#resetCurrentData(); + history.pushState({}, '', e.detail.url); + return true; + } catch { + return false; + } + } + }; + public override destroy(): void { this.#persistedData.destroy(); this.#currentData.destroy(); @@ -428,6 +474,7 @@ export class UmbDataTypeWorkspaceContext this.#propertyEditorUiIcon.destroy(); this.#propertyEditorUiName.destroy(); this.repository.destroy(); + window.removeEventListener('willchangestate', this.#onWillNavigate); super.destroy(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts index 2b3c41411d..6aaaa38eaa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts @@ -929,10 +929,27 @@ export class UmbDocumentWorkspaceContext return jsonStringComparison(persisted, current) === false; } - #onWillNavigate = async (e: CustomEvent) => { - const willNavigateAway = !e.detail.url.includes(this.getUnique()); + #resetCurrentData() { + this.#currentData.setValue(this.#persistedData.getValue()); + } - if (willNavigateAway && this.#hasUnpersistedChanges()) { + #willNavigateAway(newUrl: string) { + let willNavigateAway = false; + + if (this.getIsNew()) { + const contentTypeUnique = this.#currentData.getValue()?.documentType.unique; + willNavigateAway = !newUrl.includes(`${this.getEntityType()}/create`) || !newUrl.includes(contentTypeUnique!); + } else { + willNavigateAway = !newUrl.includes(this.getUnique()!); + } + + return willNavigateAway; + } + + #onWillNavigate = async (e: CustomEvent) => { + const newUrl = e.detail.url; + + if (this.#willNavigateAway(newUrl) && this.#hasUnpersistedChanges()) { e.preventDefault(); const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); const modal = modalManager.open(this, UMB_DISCARD_CHANGES_MODAL); @@ -941,7 +958,7 @@ export class UmbDocumentWorkspaceContext // navigate to the new url when discarding changes await modal.onSubmit(); // Reset the current data so we don't end in a endless loop of asking to discard changes. - this.#currentData.setValue(this.#persistedData.getValue()); + this.#resetCurrentData(); history.pushState({}, '', e.detail.url); return true; } catch {