gristlabs_grist-core/app/client/components/UnsavedChanges.ts

49 lines
1.6 KiB
TypeScript
Raw Permalink Normal View History

/**
* Module to help deal with unsaved changes when closing a page.
*/
import {Disposable} from 'grainjs';
/**
* Create an UnsavedChanges object to indicate there are UnsavedChanges. Dispose it when this is
* no longer the case. The optional callback will be called to confirm there are indeed unsaved
* changes. If omitted, it is assumed that there are.
*/
export class UnsavedChange extends Disposable {
constructor(
// If given, saveChanges() will call it to save changes.
private _saveCB?: () => Promise<void>,
// If given, it may return false to indicate that actually nothing has changed.
private _haveChanges?: () => boolean,
) {
super();
unsavedChanges.add(this);
this.onDispose(() => unsavedChanges.delete(this));
}
public haveUnsavedChanges() { return !this._haveChanges || this._haveChanges(); }
public async save(): Promise<void> { return this._saveCB && this._saveCB(); }
}
export class UnsavedChangeSet {
private _changes = new Set<UnsavedChange>();
/**
* Check if there are any unsaved changes out there.
*/
public haveUnsavedChanges(): boolean {
return Array.from(this._changes).some((c) => c.haveUnsavedChanges());
}
/**
* Save any unsaved changes out there.
*/
public async saveChanges(): Promise<void> {
await Promise.all(Array.from(this._changes).map((c) => c.save()));
}
public add(unsaved: UnsavedChange) { this._changes.add(unsaved); }
public delete(unsaved: UnsavedChange) { this._changes.delete(unsaved); }
}
// Global set of UnsavedChanges, checked on page unload.
export const unsavedChanges = new UnsavedChangeSet();