diff --git a/conference.js b/conference.js index 233f7cc3d..53d6fd7bb 100644 --- a/conference.js +++ b/conference.js @@ -409,12 +409,9 @@ class ConferenceConnector { break; // not enough rights to create conference - case ConferenceErrors.AUTHENTICATION_REQUIRED: - { - // schedule reconnect to check if someone else created the room - this.reconnectTimeout = setTimeout(function () { - room.join(); - }, 5000); + case ConferenceErrors.AUTHENTICATION_REQUIRED: { + // Schedule reconnect to check if someone else created the room. + this.reconnectTimeout = setTimeout(() => room.join(), 5000); const { password } = APP.store.getState()['features/base/conference']; @@ -1449,9 +1446,9 @@ export default { APP.UI.changeDisplayName(id, formattedDisplayName); }); - room.on(ConferenceEvents.LOCK_STATE_CHANGED, (...args) => { - APP.store.dispatch(lockStateChanged(room, ...args)); - }); + room.on( + ConferenceEvents.LOCK_STATE_CHANGED, + (...args) => APP.store.dispatch(lockStateChanged(room, ...args))); room.on(ConferenceEvents.PARTICIPANT_PROPERTY_CHANGED, (participant, name, oldValue, newValue) => { diff --git a/css/modals/invite/_invite.scss b/css/modals/invite/_invite.scss index cb04334b9..0b63df770 100644 --- a/css/modals/invite/_invite.scss +++ b/css/modals/invite/_invite.scss @@ -24,18 +24,18 @@ margin-top: 10px; } - .password-overview-toggle-edit, - .remove-password-link { - cursor: pointer; - text-decoration: none; - } - .password-overview-status, .remove-password { display: flex; justify-content: space-between; } + .password-overview-toggle-edit, + .remove-password-link { + cursor: pointer; + text-decoration: none; + } + .remove-password { margin-top: 15px; } diff --git a/modules/UI/side_pannels/contactlist/ContactList.js b/modules/UI/side_pannels/contactlist/ContactList.js index 51a0274be..e3d843fb5 100644 --- a/modules/UI/side_pannels/contactlist/ContactList.js +++ b/modules/UI/side_pannels/contactlist/ContactList.js @@ -24,9 +24,7 @@ class ContactList { * @returns {Boolean} */ isLocked() { - const conference = APP.store.getState()['features/base/conference']; - - return conference.locked; + return APP.store.getState()['features/base/conference'].locked; } /** @@ -36,9 +34,9 @@ class ContactList { * @param isLocal */ addContact(id, isLocal) { - let isExist = this.contacts.some((el) => el.id === id); + const exists = this.contacts.some(el => el.id === id); - if (!isExist) { + if (!exists) { let newContact = new Contact({ id, isLocal }); this.contacts.push(newContact); APP.UI.emitEvent(UIEvents.CONTACT_ADDED, { id, isLocal }); @@ -92,4 +90,4 @@ class ContactList { } } -export default ContactList; \ No newline at end of file +export default ContactList; diff --git a/modules/UI/side_pannels/contactlist/ContactListView.js b/modules/UI/side_pannels/contactlist/ContactListView.js index f290d65b9..c348ee557 100644 --- a/modules/UI/side_pannels/contactlist/ContactListView.js +++ b/modules/UI/side_pannels/contactlist/ContactListView.js @@ -1,5 +1,4 @@ /* global $, APP, interfaceConfig */ -const logger = require("jitsi-meet-logger").getLogger(__filename); import { openInviteDialog } from '../../../../react/features/invite'; @@ -7,6 +6,8 @@ import Avatar from '../../avatar/Avatar'; import UIEvents from '../../../../service/UI/UIEvents'; import UIUtil from '../../util/UIUtil'; +const logger = require('jitsi-meet-logger').getLogger(__filename); + let numberOfContacts = 0; const sidePanelsContainerId = 'sideToolbarContainer'; const htmlStr = ` @@ -169,20 +170,28 @@ var ContactListView = { APP.UI.addListener(UIEvents.USER_AVATAR_CHANGED, changeAvatar); APP.UI.addListener(UIEvents.DISPLAY_NAME_CHANGED, displayNameChange); }, + /** * Updates the view according to the passed in lock state. * - * @param {boolean} isLocked - True if the locked UI state should display. + * @param {boolean} locked - True to display the locked UI state or false to + * display the unlocked UI state. */ - setLockDisplay(isLocked) { - const showKey = isLocked ? this.lockKey : this.unlockKey; - const hideKey = !isLocked ? this.lockKey : this.unlockKey; - const showId = `contactList${showKey}`; - const hideId = `contactList${hideKey}`; + setLockDisplay(locked) { + let hideKey, showKey; - $(`#${showId}`).show(); - $(`#${hideId}`).hide(); + if (locked) { + hideKey = this.unlockKey; + showKey = this.lockKey; + } else { + hideKey = this.lockKey; + showKey = this.unlockKey; + } + + $(`#contactList${hideKey}`).hide(); + $(`#contactList${showKey}`).show(); }, + /** * Indicates if the chat is currently visible. * @@ -277,4 +286,4 @@ var ContactListView = { } }; -export default ContactListView; \ No newline at end of file +export default ContactListView; diff --git a/react/features/base/conference/actionTypes.js b/react/features/base/conference/actionTypes.js index f04ce7c46..c7c56dbcb 100644 --- a/react/features/base/conference/actionTypes.js +++ b/react/features/base/conference/actionTypes.js @@ -118,7 +118,7 @@ export const SET_PASSWORD = Symbol('SET_PASSWORD'); /** * The type of Redux action which signals that setting a password on a - * JitsiConference encountered an error and failed. + * JitsiConference failed (with an error). * * { * type: SET_PASSWORD_FAILED, diff --git a/react/features/base/conference/reducer.js b/react/features/base/conference/reducer.js index 3008ae298..f4355f9cc 100644 --- a/react/features/base/conference/reducer.js +++ b/react/features/base/conference/reducer.js @@ -85,6 +85,14 @@ function _conferenceFailed(state, action) { audioOnlyVideoMuted: undefined, conference: undefined, leaving: undefined, + + /** + * The indicator of how the conference/room is locked. If falsy, the + * conference/room is unlocked; otherwise, it's either + * {@code LOCKED_LOCALLY| or {@code LOCKED_REMOTELY}. + * + * @type {string} + */ locked: passwordRequired ? LOCKED_REMOTELY : undefined, password: undefined, @@ -211,14 +219,14 @@ function _lockStateChanged(state, action) { return state; } - let lockState; + let locked; if (action.locked) { - lockState = state.locked || LOCKED_REMOTELY; + locked = state.locked || LOCKED_REMOTELY; } return setStateProperties(state, { - locked: lockState, + locked, password: action.locked ? state.password : null }); } @@ -265,7 +273,7 @@ function _setPassword(state, action) { const conference = action.conference; switch (action.method) { - case conference.join: { + case conference.join: if (state.passwordRequired === conference) { return ( setStateProperties(state, { @@ -280,16 +288,14 @@ function _setPassword(state, action) { passwordRequired: undefined })); } - break; - } - case conference.lock: { + + case conference.lock: return setStateProperties(state, { locked: action.password ? LOCKED_LOCALLY : undefined, password: action.password }); } - } return state; } diff --git a/react/features/invite/actions.js b/react/features/invite/actions.js index 3ca5f7ca1..2f34428cd 100644 --- a/react/features/invite/actions.js +++ b/react/features/invite/actions.js @@ -10,9 +10,7 @@ import { InviteDialog } from './components'; * @returns {Function} */ export function openInviteDialog() { - return dispatch => { - dispatch(openDialog(InviteDialog, { - conferenceUrl: encodeURI(APP.ConferenceUrl.getInviteUrl()) - })); - }; + return openDialog(InviteDialog, { + conferenceUrl: encodeURI(APP.ConferenceUrl.getInviteUrl()) + }); } diff --git a/react/features/invite/components/AddPasswordForm.js b/react/features/invite/components/AddPasswordForm.js index ce5e62f65..4e5fff075 100644 --- a/react/features/invite/components/AddPasswordForm.js +++ b/react/features/invite/components/AddPasswordForm.js @@ -5,11 +5,11 @@ import { setPassword } from '../../base/conference'; import { translate } from '../../base/i18n'; /** - * A React Component for locking a JitsiConference with a password. + * A React {@code Component} for locking a JitsiConference with a password. */ class AddPasswordForm extends Component { /** - * AddPasswordForm component's property types. + * {@code AddPasswordForm}'s property types. * * @static */ @@ -33,7 +33,7 @@ class AddPasswordForm extends Component { } /** - * Initializes a new AddPasswordForm instance. + * Initializes a new {@code AddPasswordForm} instance. * * @param {Object} props - The read-only properties with which the new * instance is to be initialized. @@ -42,9 +42,17 @@ class AddPasswordForm extends Component { super(props); this.state = { + /** + * The current value to display in {@code AddPasswordForm} + * component's input field. The value is also used as the desired + * new password when creating a {@code setPassword} action. + * + * @type {string} + */ password: '' }; + // Bind event handlers so they are only bound once for every instance. this._onKeyDown = this._onKeyDown.bind(this); this._onPasswordChange = this._onPasswordChange.bind(this); this._onSubmit = this._onSubmit.bind(this); @@ -57,6 +65,8 @@ class AddPasswordForm extends Component { * @returns {ReactElement} */ render() { + const { t } = this.props; + return (
@@ -122,7 +131,7 @@ class AddPasswordForm extends Component { return; } - const conference = this.props.conference; + const { conference } = this.props; this.props.dispatch(setPassword( conference, diff --git a/react/features/invite/components/InviteDialog.js b/react/features/invite/components/InviteDialog.js index ddb8c10f6..97b71d678 100644 --- a/react/features/invite/components/InviteDialog.js +++ b/react/features/invite/components/InviteDialog.js @@ -13,12 +13,13 @@ import PasswordContainer from './PasswordContainer'; import ShareLinkForm from './ShareLinkForm'; /** - * A React Component for displaying other components responsible for copying the - * current conference url and for setting or removing a conference password. + * A React {@code Component} for displaying other components responsible for + * copying the current conference url and for setting or removing a conference + * password. */ class InviteDialog extends Component { /** - * InviteDialog component's property types. + * {@code InviteDialog} component's property types. * * @static */ @@ -61,19 +62,23 @@ class InviteDialog extends Component { * @returns {ReactElement} */ render() { + const { _conference } = this.props; + const titleString + = this.props.t( + 'invite.inviteTo', + { conferenceName: _conference.room }); + return ( + titleString = { titleString }>
@@ -82,7 +87,8 @@ class InviteDialog extends Component { } /** - * Maps (parts of) the Redux state to the associated InviteDialog's props. + * Maps (parts of) the Redux state to the associated {@code InviteDialog}'s + * props. * * @param {Object} state - The Redux state. * @private diff --git a/react/features/invite/components/LockStatePanel.js b/react/features/invite/components/LockStatePanel.js index 1f701f124..0439bb941 100644 --- a/react/features/invite/components/LockStatePanel.js +++ b/react/features/invite/components/LockStatePanel.js @@ -7,7 +7,7 @@ import { translate } from '../../base/i18n'; */ class LockStatePanel extends Component { /** - * LockStatePanel component's property types. + * {@code LockStatePanel}'s property types. * * @static */ @@ -30,15 +30,25 @@ class LockStatePanel extends Component { * @returns {ReactElement} */ render() { - const [ lockStateClass, lockIconClass, lockTextKey ] = this.props.locked - ? [ 'is-locked', 'icon-security-locked', 'invite.locked' ] - : [ 'is-unlocked', 'icon-security', 'invite.unlocked' ]; + let iconClass; + let stateClass; + let textKey; + + if (this.props.locked) { + iconClass = 'icon-security-locked'; + stateClass = 'is-locked'; + textKey = 'invite.locked'; + } else { + iconClass = 'icon-security'; + stateClass = 'is-unlocked'; + textKey = 'invite.unlocked'; + } return ( -
- +
+ - { this.props.t(lockTextKey) } + { this.props.t(textKey) }
); diff --git a/react/features/invite/components/PasswordContainer.js b/react/features/invite/components/PasswordContainer.js index 9c044ddac..956237188 100644 --- a/react/features/invite/components/PasswordContainer.js +++ b/react/features/invite/components/PasswordContainer.js @@ -8,12 +8,12 @@ import LockStatePanel from './LockStatePanel'; import RemovePasswordForm from './RemovePasswordForm'; /** - * React component for displaying the current room lock state as well as + * React {@code Component} for displaying the current room lock state as well as * exposing features to modify the room lock. */ class PasswordContainer extends Component { /** - * PasswordContainer component's property types. + * {@code PasswordContainer}'s property types. * * @static */ @@ -49,7 +49,7 @@ class PasswordContainer extends Component { } /** - * Initializes a new PasswordContainer instance. + * Initializes a new {@code PasswordContainer} instance. * * @param {Object} props - The read-only properties with which the new * instance is to be initialized. @@ -58,9 +58,16 @@ class PasswordContainer extends Component { super(props); this.state = { + /** + * Whether or not the form to edit the password should display. If + * true, the form should display. + * + * @type {boolean} + */ isEditingPassword: false }; + // Bind event handlers so they are only bound once for every instance. this._onTogglePasswordEdit = this._onTogglePasswordEdit.bind(this); } @@ -105,12 +112,14 @@ class PasswordContainer extends Component { return null; } - return this.props.locked - ? - : ; + return ( + this.props.locked + ? + : + ); } /** diff --git a/react/features/invite/components/RemovePasswordForm.js b/react/features/invite/components/RemovePasswordForm.js index bcf82adfb..69925c5ef 100644 --- a/react/features/invite/components/RemovePasswordForm.js +++ b/react/features/invite/components/RemovePasswordForm.js @@ -5,11 +5,11 @@ import { setPassword } from '../../base/conference'; import { translate } from '../../base/i18n'; /** - * A React Component for removing a lock from a JitsiConference. + * A React {@code Component} for removing a lock from a JitsiConference. */ class RemovePasswordForm extends Component { /** - * RemovePasswordForm component's property types. + * {@code RemovePasswordForm}'s property types. * * @static */ @@ -43,7 +43,7 @@ class RemovePasswordForm extends Component { } /** - * Initializes a new RemovePasswordForm instance. + * Initializes a new {@code RemovePasswordForm} instance. * * @param {Object} props - The read-only properties with which the new * instance is to be initialized. @@ -51,6 +51,7 @@ class RemovePasswordForm extends Component { constructor(props) { super(props); + // Bind event handlers so they are only bound once for every instance. this._onClick = this._onClick.bind(this); } @@ -83,15 +84,15 @@ class RemovePasswordForm extends Component { * @returns {ReactElement} */ _getPasswordPreviewText() { + const { lockedLocally, password, t } = this.props; + return ( - { `${this.props.t('dialog.currentPassword')} ` } + { `${t('dialog.currentPassword')} ` } - { this.props.lockedLocally - ? this.props.password - : this.props.t('passwordSetRemotely') } + { lockedLocally ? password : t('passwordSetRemotely') } ); @@ -104,7 +105,7 @@ class RemovePasswordForm extends Component { * @returns {void} */ _onClick() { - const conference = this.props.conference; + const { conference } = this.props; this.props.dispatch(setPassword( conference, diff --git a/react/features/invite/components/ShareLinkForm.js b/react/features/invite/components/ShareLinkForm.js index f2c52deeb..e2a7a5fb0 100644 --- a/react/features/invite/components/ShareLinkForm.js +++ b/react/features/invite/components/ShareLinkForm.js @@ -5,12 +5,12 @@ import { translate } from '../../base/i18n'; const logger = require('jitsi-meet-logger').getLogger(__filename); /** - * A React Component for displaying a value with a copy button that can be - * clicked to copy the value onto the clipboard. + * A React {@code Component} for displaying a value with a copy button to copy + * the value into the clipboard. */ class ShareLinkForm extends Component { /** - * ShareLinkForm component's property types. + * {@code ShareLinkForm}'s property types. * * @static */ @@ -20,14 +20,14 @@ class ShareLinkForm extends Component { */ t: React.PropTypes.func, - /** - * The value to be displayed and copied onto the clipboard. + /** + * The value to be displayed and copied into the clipboard. */ toCopy: React.PropTypes.string } /** - * Initializes a new ShareLinkForm instance. + * Initializes a new {@code ShareLinkForm} instance. * * @param {Object} props - The read-only properties with which the new * instance is to be initialized. @@ -35,8 +35,17 @@ class ShareLinkForm extends Component { constructor(props) { super(props); + /** + * The internal reference to the DOM/HTML element backing the React + * {@code Component} input with id {@code inviteLinkRef}. It is + * necessary for the implementation of copying to the clipboard. + * + * @private + * @type {HTMLInputElement} + */ this._inputElement = null; + // Bind event handlers so they are only bound once for every instance. this._onClick = this._onClick.bind(this); this._setInput = this._setInput.bind(this); } @@ -48,15 +57,15 @@ class ShareLinkForm extends Component { * @returns {ReactElement} */ render() { - const inputValue = this.props.toCopy - || this.props.t('inviteUrlDefaultMsg'); + const { t } = this.props; + const inputValue = this.props.toCopy || t('inviteUrlDefaultMsg'); - // FIXME input is used here instead of atlaskit field-text because - // field-text does not currently support readonly + // FIXME An input HTML element is used here instead of atlaskit's + // field-text because the latter does not currently support readOnly. return (
- { this.props.t('dialog.copy') } + { t('dialog.copy') }
@@ -95,10 +104,11 @@ class ShareLinkForm extends Component { } /** - * Sets the internal reference to the DOM element for the input field so it - * may be accessed directly. + * Sets the internal reference to the DOM/HTML element backing the React + * {@code Component} input with id {@code inviteLinkRef}. * - * @param {Object} element - DOM element for the component's input. + * @param {HTMLInputElement} element - The DOM/HTML element for this + * {@code Component}'s input. * @private * @returns {void} */ diff --git a/react/features/room-lock/components/PasswordRequiredPrompt.web.js b/react/features/room-lock/components/PasswordRequiredPrompt.web.js index 9ead15c95..11d98076c 100644 --- a/react/features/room-lock/components/PasswordRequiredPrompt.web.js +++ b/react/features/room-lock/components/PasswordRequiredPrompt.web.js @@ -1,7 +1,8 @@ /* global APP */ + +import AKFieldText from '@atlaskit/field-text'; import React, { Component } from 'react'; import { connect } from 'react-redux'; -import AKFieldText from '@atlaskit/field-text'; import UIEvents from '../../../../service/UI/UIEvents'; @@ -39,7 +40,9 @@ class PasswordRequiredPrompt extends Component { constructor(props) { super(props); - this.state = { password: '' }; + this.state = { + password: '' + }; this._onPasswordChanged = this._onPasswordChanged.bind(this); this._onSubmit = this._onSubmit.bind(this); @@ -69,19 +72,18 @@ class PasswordRequiredPrompt extends Component { * @protected */ _renderBody() { - const { t } = this.props; - return (
-
); +
+ ); } /** @@ -92,7 +94,9 @@ class PasswordRequiredPrompt extends Component { * @returns {void} */ _onPasswordChanged(event) { - this.setState({ password: event.target.value }); + this.setState({ + password: event.target.value + }); } /** @@ -102,25 +106,26 @@ class PasswordRequiredPrompt extends Component { * @returns {void} */ _onSubmit() { - const conference = this.props.conference; + const { conference } = this.props; - // 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. + // We received that password is required, but user is trying anyway to + // login without a password. Mark the room as not locked in case she + // 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 while some components are not listening - // for lock state updates in redux + // XXX Temporary solution while some components are not listening + // for lock state updates in redux. APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK, false); } - this.props.dispatch(setPassword( - conference, conference.join, this.state.password)); + this.props.dispatch( + setPassword(conference, conference.join, this.state.password)); - // we have used the password lets clean it - this.setState({ password: undefined }); + // We have used the password so let's clean it. + this.setState({ + password: undefined + }); return true; } diff --git a/react/features/room-lock/constants.js b/react/features/room-lock/constants.js index 0ca678407..e4dbee45c 100644 --- a/react/features/room-lock/constants.js +++ b/react/features/room-lock/constants.js @@ -1,12 +1,15 @@ /** - * The room lock state where the password was set by the current user. + * The conference/room lock state which identifies that the password was set by + * the current/local participant/user. * * @type {string} */ export const LOCKED_LOCALLY = 'LOCKED_LOCALLY'; /** - * The room lock state where the password was set by a remote user. + * The conference/room lock state which identifies that the password was set by + * a remote participant/user. + * * @type {string} */ export const LOCKED_REMOTELY = 'LOCKED_REMOTELY'; diff --git a/react/features/room-lock/middleware.js b/react/features/room-lock/middleware.js index 7b392b994..0f346f41e 100644 --- a/react/features/room-lock/middleware.js +++ b/react/features/room-lock/middleware.js @@ -1,5 +1,4 @@ /* global APP */ -const logger = require('jitsi-meet-logger').getLogger(__filename); import UIEvents from '../../../service/UI/UIEvents'; @@ -8,11 +7,13 @@ import { LOCK_STATE_CHANGED, SET_PASSWORD_FAILED } from '../base/conference'; -import JitsiMeetJS from '../base/lib-jitsi-meet'; +import { JitsiConferenceErrors } from '../base/lib-jitsi-meet'; import { MiddlewareRegistry } from '../base/redux'; import { _showPasswordDialog } from './actions'; +const logger = require('jitsi-meet-logger').getLogger(__filename); + /** * Middleware that captures conference failed and checks for password required * error and requests a dialog for user to enter password. @@ -21,41 +22,39 @@ import { _showPasswordDialog } from './actions'; * @returns {Function} */ MiddlewareRegistry.register(store => next => action => { - switch (action.type) { case CONFERENCE_FAILED: { - const JitsiConferenceErrors = JitsiMeetJS.errors.conference; + const { conference, error } = action; - if (action.conference - && JitsiConferenceErrors.PASSWORD_REQUIRED === action.error) { - // XXX temporary solution while some components are not listening - // for lock state updates in redux + if (conference && error === JitsiConferenceErrors.PASSWORD_REQUIRED) { + // XXX Temporary solution while some components are not listening + // for lock state updates in redux. if (typeof APP !== 'undefined') { APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK, true); } - store.dispatch(_showPasswordDialog(action.conference)); + store.dispatch(_showPasswordDialog(conference)); } break; } - case LOCK_STATE_CHANGED: { + + case LOCK_STATE_CHANGED: // TODO Remove this logic when all components interested in the lock // state change event are moved into react/redux. if (typeof APP !== 'undefined') { APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK, action.locked); } - break; - } + case SET_PASSWORD_FAILED: - return _notifySetPasswordError(store, next, action); + return _setPasswordFailed(store, next, action); } return next(action); }); /** - * Handles errors that occur when a password is failed to be set. + * Handles errors that occur when a password fails to be set. * * @param {Store} store - The Redux store in which the specified action is being * dispatched. @@ -67,20 +66,24 @@ MiddlewareRegistry.register(store => next => action => { * @returns {Object} The new state that is the result of the reduction of the * specified action. */ -function _notifySetPasswordError(store, next, action) { +function _setPasswordFailed(store, next, action) { if (typeof APP !== 'undefined') { - // TODO remove this logic when displaying of error messages on web is - // handled through react/redux - if (action.error - === JitsiMeetJS.errors.conference.PASSWORD_NOT_SUPPORTED) { + // TODO Remove this logic when displaying of error messages on web is + // handled through react/redux. + const { error } = action; + let title; + let message; + + if (error === JitsiConferenceErrors.PASSWORD_NOT_SUPPORTED) { logger.warn('room passwords not supported'); - APP.UI.messageHandler.showError( - 'dialog.warning', 'dialog.passwordNotSupported'); + title = 'dialog.warning'; + message = 'dialog.passwordNotSupported'; } else { - logger.warn('setting password failed', action.error); - APP.UI.messageHandler.showError( - 'dialog.lockTitle', 'dialog.lockMessage'); + logger.warn('setting password failed', error); + title = 'dialog.lockTitle'; + message = 'dialog.lockMessage'; } + APP.UI.messageHandler.showError(title, message); } return next(action);