ringcentral-widgets
Version:
RingCentral Integration Widget Library
135 lines (111 loc) • 3.17 kB
text/typescript
import { RcModuleV2 } from '@ringcentral-integration/core';
import { Module } from 'ringcentral-integration/lib/di';
import { Deps } from './Beforeunload.interface';
const UNLOAD_EVENT_NAME = 'beforeunload';
type BeforeunloadFn = () => boolean;
export class Beforeunload extends RcModuleV2<Deps> {
_window: Window;
private get list() {
return this._list;
}
private set list(value) {
this._list = value;
if (this._bindState && this._list.length === 0) {
this._window.removeEventListener(
UNLOAD_EVENT_NAME,
this._beforeunloadHandler,
);
// TODO: binding event here, that will not emit when close tab, not sure why
// this._window.removeEventListener('unload', this._onAfterUnload);
this._bindState = false;
} else if (!this._bindState && this._list.length > 0) {
this._window.addEventListener(
UNLOAD_EVENT_NAME,
this._beforeunloadHandler,
);
// TODO: binding event here, that will not emit when close tab, not sure why
// this._window.addEventListener('unload', this._onAfterUnload);
this._bindState = true;
}
}
private _list: BeforeunloadFn[] = [];
private _bindState = false;
constructor() {
super({
deps: {},
});
this._window = this._deps.beforeunloadOptions?.originWindow ?? window;
}
/**
* add method into window event beforeunload
* @param cb a callback with boolean, if return `true` that will block browser close.
*/
add(cb: BeforeunloadFn) {
const index = this.list.indexOf(cb);
if (index === -1) {
this.list = [...this.list, cb];
return this.list.length;
}
return index;
}
/**
* remove check from check list.
* @param cb a callback that you add previous.
*/
remove(cb: BeforeunloadFn) {
const index = this.list.indexOf(cb);
if (index > -1) {
this._removeItem(index);
}
return index;
}
/**
* clear all check methods
*/
clear() {
this.list = [];
}
/**
* check all should block callback, and return should we need block
*/
checkShouldBlock() {
for (const fn of this._list) {
if (fn()) {
return true;
}
}
return false;
}
/**
* that method will trigger after check not leave success
*/
onAfterUnload(cb: () => void, notNeedCheck = false) {
this._window.addEventListener('unload', () => {
if (notNeedCheck || this.checkShouldBlock()) {
cb();
}
});
}
removeAfterUnloadListener(cb: () => void) {
console.log('removeAfterUnloadListener~~');
this._window.removeEventListener('unload', cb);
}
private _removeItem(i: number) {
const list = [...this.list];
list.splice(i, 1);
this.list = list;
}
private _beforeunloadHandler = (event: BeforeUnloadEvent) => {
if (this.checkShouldBlock()) {
event.preventDefault();
event.returnValue = '';
return;
}
// Guarantee the browser unload by removing the returnValue property of the event
delete event.returnValue;
};
}