mirror of https://github.com/jitsi/jitsi-meet
parent
51f0c8a388
commit
61470c0d24
@ -1,162 +0,0 @@ |
|||||||
/* global APP */ |
|
||||||
|
|
||||||
import UIUtil from '../util/UIUtil'; |
|
||||||
|
|
||||||
/** |
|
||||||
* Show dialog which asks for required conference password. |
|
||||||
* @returns {Promise<string>} password or nothing if user canceled |
|
||||||
*/ |
|
||||||
export default class RequirePasswordDialog { |
|
||||||
constructor() { |
|
||||||
this.titleKey = 'dialog.passwordRequired'; |
|
||||||
this.labelKey = 'dialog.passwordLabel'; |
|
||||||
this.errorKey = 'dialog.incorrectPassword'; |
|
||||||
this.errorId = 'passwordRequiredError'; |
|
||||||
this.inputId = 'passwordRequiredInput'; |
|
||||||
this.inputErrorClass = 'error'; |
|
||||||
this.isOpened = false; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Registering dialog listeners |
|
||||||
* @private |
|
||||||
*/ |
|
||||||
_registerListeners() { |
|
||||||
let el = document.getElementById(this.inputId); |
|
||||||
el.addEventListener('keypress', this._hideError.bind(this)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Helper method returning dialog body |
|
||||||
* @returns {string} |
|
||||||
* @private |
|
||||||
*/ |
|
||||||
_getBodyMessage() { |
|
||||||
return ( |
|
||||||
`<div class="form-control">
|
|
||||||
<label class="input-control__label" |
|
||||||
data-i18n="${this.labelKey}"></label> |
|
||||||
<input class="input-control__input input-control" |
|
||||||
name="lockKey" type="text" |
|
||||||
data-i18n="[placeholder]dialog.password" |
|
||||||
autofocus id="${this.inputId}"> |
|
||||||
<p class="form-control__hint form-control__hint_error hide" |
|
||||||
id="${this.errorId}" |
|
||||||
data-i18n="${this.errorKey}"></p> |
|
||||||
</div>` |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Asking for a password |
|
||||||
* @returns {Promise} |
|
||||||
*/ |
|
||||||
askForPassword() { |
|
||||||
if (!this.isOpened) { |
|
||||||
return this.open(); |
|
||||||
} |
|
||||||
|
|
||||||
return new Promise((resolve, reject) => { |
|
||||||
this.resolve = resolve; |
|
||||||
this.reject = reject; |
|
||||||
this._showError(); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Opens the dialog |
|
||||||
* @returns {Promise} |
|
||||||
*/ |
|
||||||
open() { |
|
||||||
let { titleKey } = this; |
|
||||||
let msgString = this._getBodyMessage(); |
|
||||||
|
|
||||||
return new Promise((resolve, reject) => { |
|
||||||
this.resolve = resolve; |
|
||||||
this.reject = reject; |
|
||||||
let submitFunction = this._submitFunction.bind(this); |
|
||||||
let closeFunction = this._closeFunction.bind(this); |
|
||||||
|
|
||||||
this._dialog = APP.UI.messageHandler.openTwoButtonDialog({ |
|
||||||
titleKey, |
|
||||||
msgString, |
|
||||||
leftButtonKey: "dialog.Ok", |
|
||||||
submitFunction, |
|
||||||
closeFunction, |
|
||||||
focus: ':input:first' |
|
||||||
}); |
|
||||||
|
|
||||||
this._registerListeners(); |
|
||||||
this.isOpened = true; |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Submit dialog callback |
|
||||||
* @param e - event |
|
||||||
* @param v - value |
|
||||||
* @param m - message |
|
||||||
* @param f - form |
|
||||||
* @private |
|
||||||
*/ |
|
||||||
_submitFunction(e, v, m, f) { |
|
||||||
e.preventDefault(); |
|
||||||
this._processInput(v, f); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Processing input in dialog |
|
||||||
* @param v - value |
|
||||||
* @param f - form |
|
||||||
* @private |
|
||||||
*/ |
|
||||||
_processInput(v, f) { |
|
||||||
if (v && f.lockKey) { |
|
||||||
this.resolve(UIUtil.escapeHtml(f.lockKey)); |
|
||||||
} else { |
|
||||||
this.reject(APP.UI.messageHandler.CANCEL); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Close dialog callback |
|
||||||
* @private |
|
||||||
*/ |
|
||||||
_closeFunction(e, v, m, f) { |
|
||||||
this._processInput(v, f); |
|
||||||
this._hideError(); |
|
||||||
this.close(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Method showing error hint |
|
||||||
* @private |
|
||||||
*/ |
|
||||||
_showError() { |
|
||||||
let className = this.inputErrorClass; |
|
||||||
let input = document.getElementById(this.inputId); |
|
||||||
document.getElementById(this.errorId).classList.remove('hide'); |
|
||||||
input.classList.add(className); |
|
||||||
input.select(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Method hiding error hint |
|
||||||
* @private |
|
||||||
*/ |
|
||||||
_hideError() { |
|
||||||
let className = this.inputErrorClass; |
|
||||||
document.getElementById(this.errorId).classList.add('hide'); |
|
||||||
document.getElementById(this.inputId).classList.remove(className); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Close the dialog |
|
||||||
*/ |
|
||||||
close() { |
|
||||||
if (this._dialog) { |
|
||||||
this._dialog.close(); |
|
||||||
} |
|
||||||
this.isOpened = false; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,127 @@ |
|||||||
|
/* global APP */ |
||||||
|
import React, { Component } from 'react'; |
||||||
|
import { connect } from 'react-redux'; |
||||||
|
import AKFieldText from '@atlaskit/field-text'; |
||||||
|
|
||||||
|
import { setPassword } from '../../base/conference'; |
||||||
|
import { Dialog } from '../../base/dialog'; |
||||||
|
import { translate } from '../../base/i18n'; |
||||||
|
|
||||||
|
/** |
||||||
|
* Implements a React Component which prompts the user when a password is |
||||||
|
* required to join a conference. |
||||||
|
*/ |
||||||
|
class PasswordRequiredPrompt extends Component { |
||||||
|
/** |
||||||
|
* PasswordRequiredPrompt component's property types. |
||||||
|
* |
||||||
|
* @static |
||||||
|
*/ |
||||||
|
static propTypes = { |
||||||
|
/** |
||||||
|
* The JitsiConference which requires a password. |
||||||
|
* |
||||||
|
* @type {JitsiConference} |
||||||
|
*/ |
||||||
|
conference: React.PropTypes.object, |
||||||
|
dispatch: React.PropTypes.func, |
||||||
|
t: React.PropTypes.func |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initializes a new PasswordRequiredPrompt instance. |
||||||
|
* |
||||||
|
* @param {Object} props - The read-only properties with which the new |
||||||
|
* instance is to be initialized. |
||||||
|
*/ |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
|
||||||
|
this.state = { password: '' }; |
||||||
|
|
||||||
|
this._onPasswordChanged = this._onPasswordChanged.bind(this); |
||||||
|
this._onSubmit = this._onSubmit.bind(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Implements React's {@link Component#render()}. |
||||||
|
* |
||||||
|
* @inheritdoc |
||||||
|
* @returns {ReactElement} |
||||||
|
*/ |
||||||
|
render() { |
||||||
|
return ( |
||||||
|
<Dialog |
||||||
|
isModal = { true } |
||||||
|
onSubmit = { this._onSubmit } |
||||||
|
titleKey = 'dialog.passwordRequired' |
||||||
|
width = 'small'> |
||||||
|
{ this._renderBody() } |
||||||
|
</Dialog>); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Display component in dialog body. |
||||||
|
* |
||||||
|
* @returns {ReactElement} |
||||||
|
* @protected |
||||||
|
*/ |
||||||
|
_renderBody() { |
||||||
|
const { t } = this.props; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div> |
||||||
|
<AKFieldText |
||||||
|
compact = { true } |
||||||
|
label = { t('dialog.passwordLabel') } |
||||||
|
name = 'lockKey' |
||||||
|
onChange = { this._onPasswordChanged } |
||||||
|
shouldFitContainer = { true } |
||||||
|
type = 'text' |
||||||
|
value = { this.state.password } /> |
||||||
|
</div>); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notifies this dialog that password has changed. |
||||||
|
* |
||||||
|
* @param {Object} event - The details of the notification/event. |
||||||
|
* @private |
||||||
|
* @returns {void} |
||||||
|
*/ |
||||||
|
_onPasswordChanged(event) { |
||||||
|
this.setState({ password: event.target.value }); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Dispatches action to submit value from thus dialog. |
||||||
|
* |
||||||
|
* @private |
||||||
|
* @returns {void} |
||||||
|
*/ |
||||||
|
_onSubmit() { |
||||||
|
const conference = this.props.conference; |
||||||
|
|
||||||
|
// we received that password is required, but user is trying
|
||||||
|
// anyway to login without a password, mark room as not
|
||||||
|
// locked in case he succeeds (maybe someone removed the
|
||||||
|
// password meanwhile), if it is still locked another
|
||||||
|
// password required will be received and the room again
|
||||||
|
// will be marked as locked.
|
||||||
|
if (!this.state.password || this.state.password === '') { |
||||||
|
// XXX temporary solution till we move the whole invite logic
|
||||||
|
// in react
|
||||||
|
APP.conference.invite.setLockedFromElsewhere(false); |
||||||
|
} |
||||||
|
|
||||||
|
this.props.dispatch(setPassword( |
||||||
|
conference, conference.join, this.state.password)); |
||||||
|
|
||||||
|
// we have used the password lets clean it
|
||||||
|
this.setState({ password: undefined }); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default translate(connect()(PasswordRequiredPrompt)); |
@ -1 +1,2 @@ |
|||||||
export { default as RoomLockPrompt } from './RoomLockPrompt'; |
export { default as RoomLockPrompt } from './RoomLockPrompt'; |
||||||
|
export { default as PasswordRequiredPrompt } from './PasswordRequiredPrompt'; |
||||||
|
@ -1,4 +1,5 @@ |
|||||||
export * from './actions'; |
export * from './actions'; |
||||||
export * from './components'; |
export * from './components'; |
||||||
|
|
||||||
|
import './middleware'; |
||||||
import './reducer'; |
import './reducer'; |
||||||
|
@ -0,0 +1,36 @@ |
|||||||
|
/* global APP */ |
||||||
|
import JitsiMeetJS from '../base/lib-jitsi-meet'; |
||||||
|
|
||||||
|
import { CONFERENCE_FAILED } from '../base/conference'; |
||||||
|
import { MiddlewareRegistry } from '../base/redux'; |
||||||
|
import { _showPasswordDialog } from './actions'; |
||||||
|
|
||||||
|
/** |
||||||
|
* Middleware that captures conference failed and checks for password required |
||||||
|
* error and requests a dialog for user to enter password. |
||||||
|
* |
||||||
|
* @param {Store} store - Redux store. |
||||||
|
* @returns {Function} |
||||||
|
*/ |
||||||
|
MiddlewareRegistry.register(store => next => action => { |
||||||
|
|
||||||
|
switch (action.type) { |
||||||
|
case CONFERENCE_FAILED: { |
||||||
|
const JitsiConferenceErrors = JitsiMeetJS.errors.conference; |
||||||
|
|
||||||
|
if (action.conference |
||||||
|
&& JitsiConferenceErrors.PASSWORD_REQUIRED === action.error) { |
||||||
|
// XXX temporary solution till we move the whole invite
|
||||||
|
// logic in react
|
||||||
|
if (typeof APP !== 'undefined') { |
||||||
|
APP.conference.invite.setLockedFromElsewhere(true); |
||||||
|
} |
||||||
|
|
||||||
|
store.dispatch(_showPasswordDialog(action.conference)); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return next(action); |
||||||
|
}); |
Loading…
Reference in new issue