@@ -16,7 +16,7 @@ import {
16
16
observeMultiple ,
17
17
} from '@umbraco-cms/backoffice/observable-api' ;
18
18
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api' ;
19
- import { UMB_MODAL_CONTEXT } from '@umbraco-cms/backoffice/modal' ;
19
+ import { UMB_DISCARD_CHANGES_MODAL , UMB_MODAL_CONTEXT , UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal' ;
20
20
import { decodeFilePath , UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils' ;
21
21
import {
22
22
UMB_BLOCK_ENTRIES_CONTEXT ,
@@ -81,6 +81,8 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
81
81
const manifest = workspaceArgs . manifest ;
82
82
this . #entityType = manifest . meta ?. entityType ;
83
83
84
+ window . addEventListener ( 'willchangestate' , this . #onWillNavigate) ;
85
+
84
86
this . addValidationContext ( this . content . validation ) ;
85
87
this . addValidationContext ( this . settings . validation ) ;
86
88
@@ -223,6 +225,51 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
223
225
) ;
224
226
}
225
227
228
+ #allowNavigateAway = false ;
229
+ #onWillNavigate = async ( e : CustomEvent ) => {
230
+ const newUrl = e . detail . url ;
231
+
232
+ if ( this . #allowNavigateAway) {
233
+ return true ;
234
+ }
235
+
236
+ if ( this . _checkWillNavigateAway ( newUrl ) && this . getHasUnpersistedChanges ( ) ) {
237
+ /* Since ours modals are async while events are synchronous, we need to prevent the default behavior of the event, even if the modal hasn’t been resolved yet.
238
+ Once the modal is resolved (the user accepted to discard the changes and navigate away from the route), we will push a new history state.
239
+ This push will make the "willchangestate" event happen again and due to this somewhat "backward" behavior,
240
+ we set an "allowNavigateAway"-flag to prevent the "discard-changes" functionality from running in a loop.*/
241
+ e . preventDefault ( ) ;
242
+ const modalManager = await this . getContext ( UMB_MODAL_MANAGER_CONTEXT ) . catch ( ( ) => undefined ) ;
243
+ const modal = modalManager ?. open ( this , UMB_DISCARD_CHANGES_MODAL ) ;
244
+ if ( modal ) {
245
+ try {
246
+ // navigate to the new url when discarding changes
247
+ await modal . onSubmit ( ) ;
248
+ this . #allowNavigateAway = true ;
249
+ history . pushState ( { } , '' , e . detail . url ) ;
250
+ return true ;
251
+ } catch {
252
+ return false ;
253
+ }
254
+ } else {
255
+ console . error ( 'No modal manager found!' ) ;
256
+ }
257
+ }
258
+
259
+ return true ;
260
+ } ;
261
+
262
+ /**
263
+ * Check if the workspace is about to navigate away.
264
+ * @protected
265
+ * @param {string } newUrl The new url that the workspace is navigating to.
266
+ * @returns { boolean } true if the workspace is navigating away.
267
+ * @memberof UmbEntityWorkspaceContextBase
268
+ */
269
+ protected _checkWillNavigateAway ( newUrl : string ) : boolean {
270
+ return ! newUrl . includes ( this . routes . getActiveLocalPath ( ) ) ;
271
+ }
272
+
226
273
setEditorSize ( editorSize : UUIModalSidebarSize ) {
227
274
this . #modalContext?. setModalSize ( editorSize ) ;
228
275
}
@@ -236,6 +283,7 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
236
283
this . #initialSettings = undefined ;
237
284
this . content . resetState ( ) ;
238
285
this . settings . resetState ( ) ;
286
+ this . #allowNavigateAway = false ;
239
287
this . removeUmbControllerByAlias ( UmbWorkspaceIsNewRedirectControllerAlias ) ;
240
288
}
241
289
@@ -471,6 +519,10 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
471
519
}
472
520
473
521
const settingsData = this . settings . getData ( ) ;
522
+ this . content . setPersistedData ( contentData ) ;
523
+ if ( settingsData ) {
524
+ this . settings . setPersistedData ( settingsData ) ;
525
+ }
474
526
475
527
if ( ! this . #liveEditingMode) {
476
528
if ( this . getIsNew ( ) === true ) {
@@ -542,6 +594,7 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
542
594
543
595
public override destroy ( ) : void {
544
596
super . destroy ( ) ;
597
+ window . removeEventListener ( 'willchangestate' , this . #onWillNavigate) ;
545
598
this . #layout?. destroy ( ) ;
546
599
this . #name?. destroy ( ) ;
547
600
this . #layout = undefined as any ;
0 commit comments