diff --git a/config.js b/config.js index f39f135fb3..1c1dfe71de 100644 --- a/config.js +++ b/config.js @@ -400,6 +400,9 @@ var config = { // Disables or enables RTX (RFC 4588) (defaults to false). // disableRtx: false, + // Moves all Jitsi Meet 'beforeunload' logic (cleanup, leaving, disconnecting, etc) to the 'unload' event. + // disableBeforeUnloadHandlers: true, + // Disables or enables TCC support in this client (default: enabled). // enableTcc: true, diff --git a/react/features/base/conference/middleware.any.js b/react/features/base/conference/middleware.any.js index 31ed8f0f0f..0ddc729e5c 100644 --- a/react/features/base/conference/middleware.any.js +++ b/react/features/base/conference/middleware.any.js @@ -79,7 +79,7 @@ MiddlewareRegistry.register(store => next => action => { return _conferenceSubjectChanged(store, next, action); case CONFERENCE_WILL_LEAVE: - _conferenceWillLeave(); + _conferenceWillLeave(store); break; case PARTICIPANT_UPDATED: @@ -102,7 +102,6 @@ MiddlewareRegistry.register(store => next => action => { return next(action); }); - /** * Makes sure to leave a failed conference in order to release any allocated * resources like peer connections, emit participant left events, etc. @@ -168,12 +167,11 @@ function _conferenceFailed({ dispatch, getState }, next, action) { // good to know that it happen, so log it (on the info level). logger.info('JitsiConference.leave() rejected with:', reason); }); - } else if (typeof beforeUnloadHandler !== 'undefined') { + } else { // FIXME: Workaround for the web version. Currently, the creation of the // conference is handled by /conference.js and appropriate failure handlers // are set there. - window.removeEventListener('beforeunload', beforeUnloadHandler); - beforeUnloadHandler = undefined; + _removeUnloadHandler(getState); } if (enableForcedReload && error?.name === JitsiConferenceErrors.CONFERENCE_RESTARTED) { @@ -201,7 +199,7 @@ function _conferenceJoined({ dispatch, getState }, next, action) { const result = next(action); const { conference } = action; const { pendingSubjectChange } = getState()['features/base/conference']; - const { requireDisplayName } = getState()['features/base/config']; + const { requireDisplayName, disableBeforeUnloadHandlers = false } = getState()['features/base/config']; pendingSubjectChange && dispatch(setSubject(pendingSubjectChange)); @@ -213,7 +211,7 @@ function _conferenceJoined({ dispatch, getState }, next, action) { beforeUnloadHandler = () => { dispatch(conferenceWillLeave(conference)); }; - window.addEventListener('beforeunload', beforeUnloadHandler); + window.addEventListener(disableBeforeUnloadHandlers ? 'unload' : 'beforeunload', beforeUnloadHandler); if (requireDisplayName && !getLocalParticipant(getState)?.name @@ -287,10 +285,7 @@ function _connectionFailed({ dispatch, getState }, next, action) { const result = next(action); - if (typeof beforeUnloadHandler !== 'undefined') { - window.removeEventListener('beforeunload', beforeUnloadHandler); - beforeUnloadHandler = undefined; - } + _removeUnloadHandler(getState); // FIXME: Workaround for the web version. Currently, the creation of the // conference is handled by /conference.js and appropriate failure handlers @@ -367,13 +362,11 @@ function _conferenceSubjectChanged({ dispatch, getState }, next, action) { * store. * * @private + * @param {Object} store - The redux store. * @returns {void} */ -function _conferenceWillLeave() { - if (typeof beforeUnloadHandler !== 'undefined') { - window.removeEventListener('beforeunload', beforeUnloadHandler); - beforeUnloadHandler = undefined; - } +function _conferenceWillLeave({ getState }: { getState: Function }) { + _removeUnloadHandler(getState); } /** @@ -425,6 +418,21 @@ function _pinParticipant({ getState }, next, action) { return next(action); } +/** + * Removes the unload handler. + * + * @param {Function} getState - The redux getState function. + * @returns {void} + */ +function _removeUnloadHandler(getState) { + if (typeof beforeUnloadHandler !== 'undefined') { + const { disableBeforeUnloadHandlers = false } = getState()['features/base/config']; + + window.removeEventListener(disableBeforeUnloadHandlers ? 'unload' : 'beforeunload', beforeUnloadHandler); + beforeUnloadHandler = undefined; + } +} + /** * Requests the specified tones to be played. * diff --git a/react/features/base/config/configWhitelist.js b/react/features/base/config/configWhitelist.js index 45c671f007..0992fd70bd 100644 --- a/react/features/base/config/configWhitelist.js +++ b/react/features/base/config/configWhitelist.js @@ -91,6 +91,7 @@ export default [ 'disableAP', 'disableAddingBackgroundImages', 'disableAudioLevels', + 'disableBeforeUnloadHandlers', 'disableChatSmileys', 'disableDeepLinking', 'disabledSounds', diff --git a/react/features/external-api/middleware.js b/react/features/external-api/middleware.js index aeb78d6288..ca0e53e24a 100644 --- a/react/features/external-api/middleware.js +++ b/react/features/external-api/middleware.js @@ -1,11 +1,13 @@ // @flow +import { getJitsiMeetTransport } from '../../../modules/transport'; import { CONFERENCE_FAILED, CONFERENCE_JOINED, DATA_CHANNEL_OPENED, KICKED_OUT } from '../base/conference'; +import { SET_CONFIG } from '../base/config'; import { NOTIFY_CAMERA_ERROR, NOTIFY_MIC_ERROR } from '../base/devices'; import { JitsiConferenceErrors } from '../base/lib-jitsi-meet'; import { @@ -171,6 +173,22 @@ MiddlewareRegistry.register(store => next => action => { APP.API.notifyUserRoleChanged(action.participant.id, action.participant.role); break; + case SET_CONFIG: { + const state = store.getState(); + const { disableBeforeUnloadHandlers = false } = state['features/base/config']; + + /** + * Disposing the API when the user closes the page. + */ + window.addEventListener(disableBeforeUnloadHandlers ? 'unload' : 'beforeunload', () => { + APP.API.notifyConferenceLeft(APP.conference.roomName); + APP.API.dispose(); + getJitsiMeetTransport().dispose(); + }); + + break; + } + case SET_FILMSTRIP_VISIBLE: APP.API.notifyFilmstripDisplayChanged(action.visible); break; diff --git a/react/index.web.js b/react/index.web.js index c187f6e49a..6a2b73d1d2 100644 --- a/react/index.web.js +++ b/react/index.web.js @@ -3,8 +3,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { getJitsiMeetTransport } from '../modules/transport'; - import { App } from './features/app/components'; import { getLogger } from './features/base/logging/functions'; import { Platform } from './features/base/react'; @@ -41,21 +39,6 @@ if (OS === 'ios') { }); } -/** - * Stops collecting the logs and disposing the API when the user closes the - * page. - */ -window.addEventListener('beforeunload', () => { - // Stop the LogCollector - if (APP.logCollectorStarted) { - APP.logCollector.stop(); - APP.logCollectorStarted = false; - } - APP.API.notifyConferenceLeft(APP.conference.roomName); - APP.API.dispose(); - getJitsiMeetTransport().dispose(); -}); - const globalNS = getJitsiMeetGlobalNS(); globalNS.entryPoints = {