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 PasswordRequiredPrompt } from './PasswordRequiredPrompt'; |
||||
|
@ -1,4 +1,5 @@ |
||||
export * from './actions'; |
||||
export * from './components'; |
||||
|
||||
import './middleware'; |
||||
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