From 2dc06c28e30b1e88dadfe7877071868b6bad0671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=8F=D0=BD=20=D0=9C=D0=B8=D0=BD=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 1 Jul 2019 13:02:25 +0100 Subject: [PATCH] Adds option to be able to cancel locked rooms and leave. (#4391) * Adds option to be able to cancel locked rooms and leave. * Removes not needed operations when canceling password prompt. --- conference.js | 83 +--------------- react/features/app/actions.js | 95 ++++++++++++++++++- react/features/room-lock/actions.js | 17 +++- .../components/PasswordRequiredPrompt.web.js | 23 ++++- 4 files changed, 136 insertions(+), 82 deletions(-) diff --git a/conference.js b/conference.js index f01a99f8b..b06a798a3 100644 --- a/conference.js +++ b/conference.js @@ -23,7 +23,8 @@ import { sendAnalytics } from './react/features/analytics'; import { - redirectWithStoredParams, + maybeRedirectToWelcomePage, + redirectToStaticPage, reloadWithStoredParams } from './react/features/app'; @@ -101,10 +102,7 @@ import { trackAdded, trackRemoved } from './react/features/base/tracks'; -import { - getLocationContextRoot, - getJitsiMeetGlobalNS -} from './react/features/base/util'; +import { getJitsiMeetGlobalNS } from './react/features/base/util'; import { addMessage } from './react/features/chat'; import { showDesktopPicker } from './react/features/desktop-picker'; import { appendSuffix } from './react/features/display-name'; @@ -211,77 +209,6 @@ function muteLocalVideo(muted) { APP.store.dispatch(setVideoMuted(muted)); } -/** - * Check if the welcome page is enabled and redirects to it. - * If requested show a thank you dialog before that. - * If we have a close page enabled, redirect to it without - * showing any other dialog. - * - * @param {object} options used to decide which particular close page to show - * or if close page is disabled, whether we should show the thankyou dialog - * @param {boolean} options.showThankYou - whether we should - * show thank you dialog - * @param {boolean} options.feedbackSubmitted - whether feedback was submitted - */ -function maybeRedirectToWelcomePage(options) { - // if close page is enabled redirect to it, without further action - if (config.enableClosePage) { - const { isGuest } = APP.store.getState()['features/base/jwt']; - - // save whether current user is guest or not, before navigating - // to close page - window.sessionStorage.setItem('guest', isGuest); - redirectToStaticPage(`static/${ - options.feedbackSubmitted ? 'close.html' : 'close2.html'}`); - - return; - } - - // else: show thankYou dialog only if there is no feedback - if (options.showThankYou) { - APP.store.dispatch(showNotification({ - titleArguments: { appName: interfaceConfig.APP_NAME }, - titleKey: 'dialog.thankYou' - })); - } - - // if Welcome page is enabled redirect to welcome page after 3 sec, if - // there is a thank you message to be shown, 0.5s otherwise. - if (config.enableWelcomePage) { - setTimeout( - () => { - APP.store.dispatch(redirectWithStoredParams('/')); - }, - options.showThankYou ? 3000 : 500); - } -} - -/** - * Assigns a specific pathname to window.location.pathname taking into account - * the context root of the Web app. - * - * @param {string} pathname - The pathname to assign to - * window.location.pathname. If the specified pathname is relative, the context - * root of the Web app will be prepended to the specified pathname before - * assigning it to window.location.pathname. - * @return {void} - */ -function redirectToStaticPage(pathname) { - const windowLocation = window.location; - let newPathname = pathname; - - if (!newPathname.startsWith('/')) { - // A pathname equal to ./ specifies the current directory. It will be - // fine but pointless to include it because contextRoot is the current - // directory. - newPathname.startsWith('./') - && (newPathname = newPathname.substring(2)); - newPathname = getLocationContextRoot(windowLocation) + newPathname; - } - - windowLocation.pathname = newPathname; -} - /** * A queue for the async replaceLocalTrack action so that multiple audio * replacements cannot happen simultaneously. This solves the issue where @@ -347,7 +274,7 @@ class ConferenceConnector { case JitsiConferenceErrors.NOT_ALLOWED_ERROR: { // let's show some auth not allowed page - redirectToStaticPage('static/authError.html'); + APP.store.dispatch(redirectToStaticPage('static/authError.html')); break; } @@ -2596,7 +2523,7 @@ export default { room = undefined; APP.API.notifyReadyToClose(); - maybeRedirectToWelcomePage(values[0]); + APP.store.dispatch(maybeRedirectToWelcomePage(values[0])); }); }, diff --git a/react/features/app/actions.js b/react/features/app/actions.js index 2fd41a453..38db19749 100644 --- a/react/features/app/actions.js +++ b/react/features/app/actions.js @@ -13,10 +13,18 @@ import { import { connect, disconnect, setLocationURL } from '../base/connection'; import { loadConfig } from '../base/lib-jitsi-meet'; import { createDesiredLocalTracks } from '../base/tracks'; -import { parseURIString, toURLString } from '../base/util'; +import { + getLocationContextRoot, + parseURIString, + toURLString +} from '../base/util'; +import { showNotification } from '../notifications'; import { setFatalError } from '../overlay'; -import { getDefaultURL } from './functions'; +import { + getDefaultURL, + getName +} from './functions'; const logger = require('jitsi-meet-logger').getLogger(__filename); @@ -136,6 +144,34 @@ export function redirectWithStoredParams(pathname: string) { }; } +/** + * Assigns a specific pathname to window.location.pathname taking into account + * the context root of the Web app. + * + * @param {string} pathname - The pathname to assign to + * window.location.pathname. If the specified pathname is relative, the context + * root of the Web app will be prepended to the specified pathname before + * assigning it to window.location.pathname. + * @returns {Function} + */ +export function redirectToStaticPage(pathname: string) { + return () => { + const windowLocation = window.location; + let newPathname = pathname; + + if (!newPathname.startsWith('/')) { + // A pathname equal to ./ specifies the current directory. It will be + // fine but pointless to include it because contextRoot is the current + // directory. + newPathname.startsWith('./') + && (newPathname = newPathname.substring(2)); + newPathname = getLocationContextRoot(windowLocation) + newPathname; + } + + windowLocation.pathname = newPathname; + }; +} + /** * Reloads the page. * @@ -182,3 +218,58 @@ export function reloadWithStoredParams() { } }; } + +/** + * Check if the welcome page is enabled and redirects to it. + * If requested show a thank you dialog before that. + * If we have a close page enabled, redirect to it without + * showing any other dialog. + * + * @param {Object} options - Used to decide which particular close page to show + * or if close page is disabled, whether we should show the thankyou dialog. + * @param {boolean} options.showThankYou - Whether we should + * show thank you dialog. + * @param {boolean} options.feedbackSubmitted - Whether feedback was submitted. + * @returns {Function} + */ +export function maybeRedirectToWelcomePage(options: Object = {}) { + return (dispatch: Dispatch, getState: Function) => { + + const { + enableClosePage + } = getState()['features/base/config']; + + // if close page is enabled redirect to it, without further action + if (enableClosePage) { + const { isGuest } = getState()['features/base/jwt']; + + // save whether current user is guest or not, before navigating + // to close page + window.sessionStorage.setItem('guest', isGuest); + + dispatch(redirectToStaticPage(`static/${ + options.feedbackSubmitted ? 'close.html' : 'close2.html'}`)); + + return; + } + + // else: show thankYou dialog only if there is no feedback + if (options.showThankYou) { + dispatch(showNotification({ + titleArguments: { appName: getName() }, + titleKey: 'dialog.thankYou' + })); + } + + // if Welcome page is enabled redirect to welcome page after 3 sec, if + // there is a thank you message to be shown, 0.5s otherwise. + if (getState()['features/base/config'].enableWelcomePage) { + setTimeout( + () => { + dispatch(redirectWithStoredParams('/')); + }, + options.showThankYou ? 3000 : 500); + } + }; +} + diff --git a/react/features/room-lock/actions.js b/react/features/room-lock/actions.js index 83a0f6aec..aaa55f694 100644 --- a/react/features/room-lock/actions.js +++ b/react/features/room-lock/actions.js @@ -2,7 +2,10 @@ import type { Dispatch } from 'redux'; -import { appNavigate } from '../app'; +import { + appNavigate, + maybeRedirectToWelcomePage +} from '../app'; import { conferenceLeft, JITSI_CONFERENCE_URL_KEY, @@ -11,6 +14,8 @@ import { import { hideDialog, openDialog } from '../base/dialog'; import { PasswordRequiredPrompt, RoomLockPrompt } from './components'; +declare var APP: Object; + /** * Begins a (user) request to lock a specific conference/room. * @@ -44,6 +49,16 @@ export function beginRoomLockRequest(conference: ?Object) { */ export function _cancelPasswordRequiredPrompt(conference: Object) { return (dispatch: Dispatch, getState: Function) => { + + if (typeof APP !== 'undefined') { + // when we are redirecting the library should handle any + // unload and clean of the connection. + APP.API.notifyReadyToClose(); + dispatch(maybeRedirectToWelcomePage()); + + return; + } + // Canceling PasswordRequiredPrompt is to navigate the app/user to // WelcomePage. In other words, the canceling invalidates the // locationURL. Make sure that the canceling indeed has the intent to diff --git a/react/features/room-lock/components/PasswordRequiredPrompt.web.js b/react/features/room-lock/components/PasswordRequiredPrompt.web.js index 01276ed31..0d5d5e6cf 100644 --- a/react/features/room-lock/components/PasswordRequiredPrompt.web.js +++ b/react/features/room-lock/components/PasswordRequiredPrompt.web.js @@ -9,6 +9,8 @@ import { Dialog } from '../../base/dialog'; import { translate } from '../../base/i18n'; import { connect } from '../../base/redux'; +import { _cancelPasswordRequiredPrompt } from '../actions'; + /** * The type of the React {@code Component} props of * {@link PasswordRequiredPrompt}. @@ -63,6 +65,7 @@ class PasswordRequiredPrompt extends Component { // Bind event handlers so they are only bound once per instance. this._onPasswordChanged = this._onPasswordChanged.bind(this); + this._onCancel = this._onCancel.bind(this); this._onSubmit = this._onSubmit.bind(this); } @@ -75,7 +78,9 @@ class PasswordRequiredPrompt extends Component { render() { return ( @@ -121,6 +126,22 @@ class PasswordRequiredPrompt extends Component { }); } + _onCancel: () => boolean; + + /** + * Dispatches action to cancel and dismiss this dialog. + * + * @private + * @returns {boolean} + */ + _onCancel() { + + this.props.dispatch( + _cancelPasswordRequiredPrompt(this.props.conference)); + + return true; + } + _onSubmit: () => boolean; /**