fix(profile_button): unclickable

This commit is contained in:
hristoterezov 2017-09-22 17:02:34 -05:00 committed by yanas
parent 70de9a683f
commit 66da77bcf5
8 changed files with 154 additions and 127 deletions

View File

@ -1248,11 +1248,7 @@ const UIListeners = new Map([
], [
UIEvents.TOGGLE_PROFILE,
() => {
const {
isGuest
} = APP.store.getState()['features/jwt'];
isGuest && UI.toggleSidePanel('profile_container');
UI.toggleSidePanel('profile_container');
}
], [
UIEvents.TOGGLE_FILMSTRIP,

View File

@ -100,11 +100,10 @@ export function dockToolbox(dock: boolean): Function {
* closure.
*
* @param {Function} dispatch - Redux action dispatcher.
* @param {Function} getState - The function fetching the Redux state.
* @returns {Object} Button on mount/unmount handlers.
* @private
*/
function _getButtonHandlers(dispatch, getState) {
function _getButtonHandlers(dispatch) {
const localRaiseHandHandler
= (...args) => dispatch(changeLocalRaiseHand(...args));
const toggleFullScreenHandler
@ -136,17 +135,6 @@ function _getButtonHandlers(dispatch, getState) {
toggleFullScreenHandler)
},
/**
* Mount handler for profile button.
*
* @type {Object}
*/
profile: {
onMount: () =>
getState()['features/jwt']
|| dispatch(setProfileButtonUnclickable(true))
},
/**
* Mount/Unmount handlers for raisehand button.
*
@ -246,9 +234,9 @@ export function setButtonPopupTimeout(buttonName, popupName, timeout) {
* @returns {Function}
*/
export function setDefaultToolboxButtons(): Function {
return (dispatch: Dispatch, getState: Function) => {
return (dispatch: Dispatch) => {
// Save dispatch function in closure.
const buttonHandlers = _getButtonHandlers(dispatch, getState);
const buttonHandlers = _getButtonHandlers(dispatch);
const toolboxButtons = getDefaultToolboxButtons(buttonHandlers);
dispatch({
@ -258,22 +246,6 @@ export function setDefaultToolboxButtons(): Function {
};
}
/**
* Signals that unclickable property of profile button should change its value.
*
* @param {boolean} unclickable - Shows whether button is unclickable.
* @returns {Function}
*/
export function setProfileButtonUnclickable(unclickable: boolean): Function {
return (dispatch: Dispatch<*>) => {
const buttonName = 'profile';
dispatch(setToolbarButton(buttonName, {
unclickable
}));
};
}
/**
* Shows desktop sharing button.
*

View File

@ -0,0 +1,126 @@
/* @flow */
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { DEFAULT_AVATAR_RELATIVE_PATH } from '../../base/participants';
import UIEvents from '../../../../service/UI/UIEvents';
import ToolbarButton from './ToolbarButton';
declare var APP: Object;
declare var JitsiMeetJS: Object;
/**
* The default configuration for the button.
*
* @type {Object}
*/
const DEFAULT_BUTTON_CONFIGURATION = {
buttonName: 'profile',
classNames: [ 'button' ],
enabled: true,
id: 'toolbar_button_profile',
tooltipKey: 'profile.setDisplayNameLabel'
};
/**
* React {@code Component} for the profile button.
*
* @extends Component
*/
class ProfileButton extends Component {
_onClick: Function;
/**
* {@code ProfileButton}'s property types.
*
* @static
*/
static propTypes = {
/**
* Whether the button support clicking or not.
*/
_unclickable: React.PropTypes.bool,
/**
* Whether the side panel is opened or not.
*/
toggled: React.PropTypes.bool,
/**
* From which side tooltips should display. Will be re-used for
* displaying the inline dialog for video quality adjustment.
*/
tooltipPosition: React.PropTypes.string
};
/**
* Initializes a new {@code ProfileButton} instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props) {
super(props);
// Bind event handlers so they are only bound once for every instance.
this._onClick = this._onClick.bind(this);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const { _unclickable, tooltipPosition, toggled } = this.props;
const buttonConfiguration = {
...DEFAULT_BUTTON_CONFIGURATION,
unclickable: _unclickable,
toggled
};
return (
<ToolbarButton
button = { buttonConfiguration }
onClick = { this._onClick }
tooltipPosition = { tooltipPosition }>
<img
id = 'avatar'
src = { DEFAULT_AVATAR_RELATIVE_PATH } />
</ToolbarButton>
);
}
/**
* Click handler for the button.
*
* @returns {void}
*/
_onClick() {
if (!this.props._unclickable) {
JitsiMeetJS.analytics.sendEvent('toolbar.profile.toggled');
APP.UI.emitEvent(UIEvents.TOGGLE_PROFILE);
}
}
}
/**
* Maps (parts of) the Redux state to the associated {@code ProfileButton}
* component's props.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _unclickable: boolean
* }}
*/
function _mapStateToProps(state) {
return {
_unclickable: !state['features/jwt'].isGuest
};
}
export default connect(_mapStateToProps)(ProfileButton);

View File

@ -68,12 +68,7 @@ export default class StatelessToolbarButton extends AbstractToolbarButton {
/**
* Object describing button.
*/
button: React.PropTypes.object.isRequired,
/**
* Handler for button's reference.
*/
createRefToButton: React.PropTypes.func
button: React.PropTypes.object.isRequired
};
/**
@ -102,10 +97,8 @@ export default class StatelessToolbarButton extends AbstractToolbarButton {
return (
<a
{ ...attributes }
onClick = { this._onClick }
ref = { this.props.createRefToButton }>
{ this._renderInnerElementsIfRequired() }
{ this._renderChildComponentIfRequired() }
onClick = { this._onClick }>
{ this.props.children }
</a>
);
}
@ -131,35 +124,4 @@ export default class StatelessToolbarButton extends AbstractToolbarButton {
onClick(event);
}
}
/**
* Render any configured child component for the toolbar button.
*
* @returns {ReactElement|null}
* @private
*/
_renderChildComponentIfRequired(): ReactElement<*> | null {
if (this.props.button.childComponent) {
const Child = this.props.button.childComponent;
return <Child />;
}
return null;
}
/**
* If toolbar button should contain children elements
* renders them.
*
* @returns {ReactElement|null}
* @private
*/
_renderInnerElementsIfRequired(): ReactElement<*> | null {
if (this.props.button.html) {
return this.props.button.html;
}
return null;
}
}

View File

@ -128,15 +128,22 @@ class Toolbar extends Component {
const [ key, button ] = keyValuePair;
if (button.component) {
return (
<button.component
key = { key }
toggled = { button.toggled }
tooltipPosition = { this.props.tooltipPosition } />
);
}
const { tooltipPosition } = this.props;
const { onClick, onMount, onUnmount } = button;
const {
childComponent: ChildComponent,
onClick,
onMount,
onUnmount
} = button;
const onClickWithDispatch = (...args) =>
onClick && onClick(this.props.dispatch, ...args);
@ -147,7 +154,10 @@ class Toolbar extends Component {
onClick = { onClickWithDispatch }
onMount = { onMount }
onUnmount = { onUnmount }
tooltipPosition = { tooltipPosition } />
tooltipPosition = { tooltipPosition }>
{ button.html || null }
{ ChildComponent ? <ChildComponent /> : null }
</ToolbarButton>
);
}
}

View File

@ -32,7 +32,6 @@ const TOOLTIP_TO_POPUP_POSITION = {
*/
class ToolbarButton extends Component {
button: Object;
_createRefToButton: Function;
_onClick: Function;
@ -99,7 +98,6 @@ class ToolbarButton extends Component {
};
// Bind methods to save the context
this._createRefToButton = this._createRefToButton.bind(this);
this._onClick = this._onClick.bind(this);
this._onMouseOut = this._onMouseOut.bind(this);
this._onMouseOver = this._onMouseOver.bind(this);
@ -142,8 +140,7 @@ class ToolbarButton extends Component {
const { button, t, tooltipPosition } = this.props;
const props = {
...this.props,
onClick: this._onClick,
createRefToButton: this._createRefToButton
onClick: this._onClick
};
const buttonComponent = ( // eslint-disable-line no-extra-parens
@ -153,7 +150,9 @@ class ToolbarButton extends Component {
onMouseOver = { this._onMouseOver }
position = { tooltipPosition }
visible = { this.state.showTooltip }>
<StatelessToolbarButton { ...props } />
<StatelessToolbarButton { ...props }>
{ this.props.children }
</StatelessToolbarButton>
</Tooltip>
);
let children = buttonComponent;
@ -192,18 +191,6 @@ class ToolbarButton extends Component {
this.setState({ showTooltip: false });
}
/**
* Creates reference to current toolbar button.
*
* @param {HTMLElement} element - HTMLElement representing the toolbar
* button.
* @returns {void}
* @private
*/
_createRefToButton(element: HTMLElement): void {
this.button = element;
}
/**
* Parses the props and state to find any popup that should be displayed
* and returns an object describing how the popup should display.
@ -230,21 +217,6 @@ class ToolbarButton extends Component {
});
}
/**
* If toolbar button should contain children elements
* renders them.
*
* @returns {ReactElement|null}
* @private
*/
_renderInnerElementsIfRequired(): ReactElement<*> | null {
if (this.props.button.html) {
return this.props.button.html;
}
return null;
}
/**
* Hides any displayed tooltip.
*

View File

@ -2,15 +2,14 @@
import React from 'react';
import { DEFAULT_AVATAR_RELATIVE_PATH } from '../base/participants';
import { ParticipantCounter } from '../contact-list';
import { openDeviceSelectionDialog } from '../device-selection';
import { openDialOutDialog } from '../dial-out';
import { openAddPeopleDialog, openInviteDialog } from '../invite';
import UIEvents from '../../../service/UI/UIEvents';
import { VideoQualityButton } from '../video-quality';
import UIEvents from '../../../service/UI/UIEvents';
import { ParticipantCounter } from '../contact-list';
import ProfileButton from './components/ProfileButton';
declare var APP: Object;
declare var interfaceConfig: Object;
@ -328,18 +327,8 @@ const buttons: Object = {
* The descriptor of the profile toolbar button.
*/
profile: {
classNames: [ 'button' ],
enabled: true,
html: <img
id = 'avatar'
src = { DEFAULT_AVATAR_RELATIVE_PATH } />,
id: 'toolbar_button_profile',
onClick() {
JitsiMeetJS.analytics.sendEvent('toolbar.profile.toggled');
APP.UI.emitEvent(UIEvents.TOGGLE_PROFILE);
},
sideContainerId: 'profile_container',
tooltipKey: 'profile.setDisplayNameLabel'
component: ProfileButton,
sideContainerId: 'profile_container'
},
/**