LP1888723 Unsaved changes navigation warning
authorBill Erickson <berickxx@gmail.com>
Mon, 14 Dec 2020 17:20:38 +0000 (09:20 -0800)
committerGalen Charlton <gmc@equinoxOLI.org>
Sun, 15 Aug 2021 23:55:46 +0000 (19:55 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Ruth Frasur <rfrasur@library.in.gov>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/staff/cat/volcopy/routing.module.ts
Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.component.ts

index c5d3f67..5558fae 100644 (file)
@@ -1,18 +1,12 @@
 import {NgModule} from '@angular/core';
 import {RouterModule, Routes} from '@angular/router';
 import {VolCopyComponent} from './volcopy.component';
+import {CanDeactivateGuard} from '@eg/share/util/can-deactivate.guard';
 
 const routes: Routes = [{
     path: ':tab/:target/:target_id',
-    component: VolCopyComponent
-  /*
-  }, {
-    path: 'templates'
-    component: VolCopyComponent
-  }, {
-    path: 'configure'
-    component: VolCopyComponent
-    */
+    component: VolCopyComponent,
+    canDeactivate: [CanDeactivateGuard]
 }];
 
 @NgModule({
index fc25423..fc6fcd1 100644 (file)
@@ -1,5 +1,10 @@
 <eg-staff-banner bannerText="Holdings Editor" i18n-bannerText></eg-staff-banner>
 
+<eg-confirm-dialog #pendingChangesDialog
+  i18n-dialogTitle dialogTitle="Unsaved Changes Confirmation" 
+  i18n-dialogBoby  dialogBody="Unsaved changes will be lost.  Continue navigation?">
+</eg-confirm-dialog>
+
 <div class="row" *ngIf="sessionExpired">
   <div class="col-lg-6 mt-4 offset-lg-3 alert alert-danger d-flex justify-content-center" i18n>
     Holdings Editor Session Expired
       <ng-template ngbNavContent>
         <div class="mt-2">
           <eg-vol-edit [context]="context"
-            (canSaveChange)="volsCanSave = $event"></eg-vol-edit>
+            (canSaveChange)="volsCanSaveChange($event)"></eg-vol-edit>
         </div>
         <ng-container *ngIf="volcopy.defaults.values.unified_display">
           <div class="mt-2">
             <eg-copy-attrs [context]="context" 
-              (canSaveChange)="attrsCanSave = $event"></eg-copy-attrs>
+              (canSaveChange)="attrsCanSaveChange($event)"></eg-copy-attrs>
           </div>
         </ng-container>
       </ng-template>
@@ -35,7 +40,7 @@
         <ng-template ngbNavContent>
           <div class="mt-2">
             <eg-copy-attrs [context]="context"
-              (canSaveChange)="attrsCanSave = $event"></eg-copy-attrs>
+              (canSaveChange)="attrsCanSaveChange($event)"></eg-copy-attrs>
           </div>
         </ng-template>
       </li>
index 397cc2f..9250cc2 100644 (file)
@@ -1,4 +1,4 @@
-import {Component, OnInit, AfterViewInit, ViewChild, Renderer2} from '@angular/core';
+import {Component, OnInit, AfterViewInit, ViewChild, HostListener} from '@angular/core';
 import {Router, ActivatedRoute, ParamMap} from '@angular/router';
 import {tap} from 'rxjs/operators';
 import {IdlObject, IdlService} from '@eg/core/idl.service';
@@ -10,6 +10,7 @@ import {PcrudService} from '@eg/core/pcrud.service';
 import {HoldingsService, CallNumData} from '@eg/staff/share/holdings/holdings.service';
 import {VolCopyContext} from './volcopy';
 import {ProgressInlineComponent} from '@eg/share/dialog/progress-inline.component';
+import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
 import {AnonCacheService} from '@eg/share/util/anon-cache.service';
 import {VolCopyService} from './volcopy.service';
 import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
@@ -60,11 +61,14 @@ export class VolCopyComponent implements OnInit {
 
     volsCanSave = true;
     attrsCanSave = true;
+    changesPending = false;
+
+    @ViewChild('pendingChangesDialog', {static: false})
+        pendingChangesDialog: ConfirmDialogComponent;
 
     constructor(
         private router: Router,
         private route: ActivatedRoute,
-        private renderer: Renderer2,
         private evt: EventService,
         private idl: IdlService,
         private org: OrgService,
@@ -410,7 +414,10 @@ export class VolCopyComponent implements OnInit {
 
             return this.load(Object.keys(ids).map(id => Number(id)));
 
-        }).then(_ => this.loading = false);
+        }).then(_ => {
+            this.loading = false;
+            this.changesPending = false;
+        });
     }
 
     broadcastChanges(volumes: IdlObject[]) {
@@ -496,6 +503,35 @@ export class VolCopyComponent implements OnInit {
     isNotSaveable(): boolean {
         return !(this.volsCanSave && this.attrsCanSave);
     }
+
+    volsCanSaveChange(can: boolean) {
+        this.volsCanSave = can;
+        this.changesPending = true;
+    }
+
+    attrsCanSaveChange(can: boolean) {
+        this.attrsCanSave = can;
+        this.changesPending = true;
+    }
+
+    @HostListener('window:beforeunload', ['$event'])
+    canDeactivate($event?: Event): Promise<boolean> {
+
+        if (!this.changesPending) { return Promise.resolve(true); }
+
+        // Each warning dialog clears the current "changes are pending"
+        // flag so the user is not presented with the dialog again
+        // unless new changes are made.
+        this.changesPending = false;
+
+        if ($event) { // window.onbeforeunload
+            $event.preventDefault();
+            $event.returnValue = true;
+
+        } else { // tab OR route change.
+            return this.pendingChangesDialog.open().toPromise();
+        }
+    }
 }