-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
consider using beforeunload event sparsely #8595
Comments
Bad effects which it is causing: gitpod-io/gitpod#1959 |
In order to reproduce with Theia:
|
I did a prototype, it's looking very promising, but it does not really work in electron. Although calling I used this service to wrap the import { injectable } from 'inversify';
import { Event as TheiaEvent, Emitter } from '../common';
const lifecycle: Lifecycle = require('page-lifecycle/dist/lifecycle.es5');
/**
* The API documentation is [here](https://github.com/GoogleChromeLabs/page-lifecycle#api).
*/
export interface Lifecycle {
readonly state: LifecycleState;
readonly pageWasDiscarded: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
addEventListener(type: 'statechange', listener: (event: LifecycleEvent) => any): void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
removeListener(type: 'statechange', listener: (event: LifecycleEvent) => any): void;
addUnsavedChanges(id: Object | Symbol): void;
removeUnsavedChanges(id: Object | Symbol): void;
}
/**
* See https://developers.google.com/web/updates/2018/07/page-lifecycle-api.
*/
export type LifecycleState = 'active' | 'passive' | 'hidden' | 'frozen' | 'terminated' | 'discarded';
export interface LifecycleEvent {
readonly oldState: LifecycleState;
readonly newState: LifecycleState;
readonly originalEvent: Event;
}
@injectable()
export class PageLifecycle {
protected readonly instance = lifecycle;
protected readonly stateChangedEmitter = new Emitter<LifecycleEvent>();
constructor() {
this.instance.addEventListener('statechange', this.onStateChange.bind(this));
}
protected onStateChange(event: LifecycleEvent): void {
this.stateChangedEmitter.fire(event);
}
get state(): LifecycleState {
return this.instance.state;
}
get onStateChanged(): TheiaEvent<LifecycleEvent> {
return this.stateChangedEmitter.event;
}
addUnsavedChanges(id: Object | Symbol): void {
this.instance.addUnsavedChanges(id);
}
removeUnsavedChanges(id: Object | Symbol): void {
this.instance.removeUnsavedChanges(id);
}
} and this simple logic to track dirty widgets and call protected trackDirtyState(widget: Widget): void {
const saveable = Saveable.get(widget);
if (!saveable) {
return;
}
const toDisposeOnWidgetClose = new DisposableCollection();
const widgetDisposeListener = () => toDisposeOnWidgetClose.dispose();
toDisposeOnWidgetClose.pushAll([
Disposable.create(() => widget.disposed.disconnect(widgetDisposeListener)),
Disposable.create(() => this.pageLifecycle.removeUnsavedChanges(widget)),
saveable.onDirtyChanged(() => {
if (saveable.dirty) {
this.pageLifecycle.addUnsavedChanges(widget);
} else {
this.pageLifecycle.removeUnsavedChanges(widget);
}
})
]);
widget.disposed.connect(() => widgetDisposeListener);
} |
Using
unload
andbeforeunload
events is not recommended: https://developers.google.com/web/updates/2018/07/page-lifecycle-api#the-beforeunload-eventIn order to detect last page interaction one can use
pagehide
andvisibilitychange
events instead: https://developers.google.com/web/updates/2018/07/page-lifecycle-api#advice-hiddenbeforeunload
event should be installed only when there is unsaved changes and removed when there are notThe text was updated successfully, but these errors were encountered: