mirror of https://github.com/jitsi/jitsi-meet
feat(toolbox): axe the old toolbox (#2731)
This PR takes The Bulldozer Approach (R): removes the old toolbox and lots of associated code, though not all of it. Subsequent cleanups will follow.pull/2773/head jitsi-meet_2927
parent
0cd32c8155
commit
b73b51f1f4
@ -1,97 +0,0 @@ |
||||
/* @flow */ |
||||
|
||||
import PropTypes from 'prop-types'; |
||||
import React, { Component } from 'react'; |
||||
import { connect } from 'react-redux'; |
||||
|
||||
import { getToolbarClassNames } from '../functions'; |
||||
import Toolbar from './Toolbar'; |
||||
|
||||
declare var interfaceConfig: Object; |
||||
|
||||
/** |
||||
* Implementation of PrimaryToolbar React Component. |
||||
* |
||||
* @class PrimaryToolbar |
||||
* @extends Component |
||||
*/ |
||||
class PrimaryToolbar extends Component<*, *> { |
||||
static propTypes = { |
||||
|
||||
/** |
||||
* Contains toolbar buttons for primary toolbar. |
||||
*/ |
||||
_primaryToolbarButtons: PropTypes.instanceOf(Map), |
||||
|
||||
/** |
||||
* Shows whether toolbox is visible. |
||||
*/ |
||||
_visible: PropTypes.bool |
||||
}; |
||||
|
||||
state: Object; |
||||
|
||||
/** |
||||
* Renders primary toolbar component. |
||||
* |
||||
* @returns {ReactElement} |
||||
*/ |
||||
render(): React$Element<*> | null { |
||||
const { _primaryToolbarButtons } = this.props; |
||||
|
||||
// The number of buttons to show in the toolbar isn't fixed, it depends
|
||||
// on the availability of features and configuration parameters. So
|
||||
// there may be nothing to render.
|
||||
if (_primaryToolbarButtons.size === 0) { |
||||
return null; |
||||
} |
||||
|
||||
const { primaryToolbarClassName } = getToolbarClassNames(this.props); |
||||
const tooltipPosition |
||||
= interfaceConfig.filmStripOnly ? 'left' : 'bottom'; |
||||
|
||||
return ( |
||||
<Toolbar |
||||
className = { primaryToolbarClassName } |
||||
toolbarButtons = { _primaryToolbarButtons } |
||||
tooltipPosition = { tooltipPosition } /> |
||||
); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Maps part of Redux store to React component props. |
||||
* |
||||
* @param {Object} state - Snapshot of Redux store. |
||||
* @returns {{ |
||||
* _primaryToolbarButtons: Map, |
||||
* _visible: boolean |
||||
* }} |
||||
* @private |
||||
*/ |
||||
function _mapStateToProps(state: Object): Object { |
||||
const { |
||||
primaryToolbarButtons, |
||||
visible |
||||
} = state['features/toolbox']; |
||||
|
||||
return { |
||||
/** |
||||
* Default toolbar buttons for primary toolbar. |
||||
* |
||||
* @private |
||||
* @type {Map} |
||||
*/ |
||||
_primaryToolbarButtons: primaryToolbarButtons, |
||||
|
||||
/** |
||||
* Shows whether toolbox is visible. |
||||
* |
||||
* @private |
||||
* @type {boolean} |
||||
*/ |
||||
_visible: visible |
||||
}; |
||||
} |
||||
|
||||
export default connect(_mapStateToProps)(PrimaryToolbar); |
@ -1,188 +0,0 @@ |
||||
/* @flow */ |
||||
|
||||
import PropTypes from 'prop-types'; |
||||
import React, { Component } from 'react'; |
||||
import { connect } from 'react-redux'; |
||||
|
||||
import { FeedbackButton } from '../../feedback'; |
||||
import UIEvents from '../../../../service/UI/UIEvents'; |
||||
|
||||
import { |
||||
toggleSideToolbarContainer |
||||
} from '../actions'; |
||||
import { getToolbarClassNames } from '../functions'; |
||||
import Toolbar from './Toolbar'; |
||||
|
||||
declare var APP: Object; |
||||
declare var config: Object; |
||||
|
||||
/** |
||||
* Implementation of secondary toolbar React component. |
||||
* |
||||
* @class SecondaryToolbar |
||||
* @extends Component |
||||
*/ |
||||
class SecondaryToolbar extends Component<*, *> { |
||||
state: Object; |
||||
|
||||
/** |
||||
* Secondary toolbar property types. |
||||
* |
||||
* @static |
||||
*/ |
||||
static propTypes = { |
||||
/** |
||||
* Application ID for callstats.io API. The {@code FeedbackButton} will |
||||
* display if defined. |
||||
*/ |
||||
_callStatsID: PropTypes.string, |
||||
|
||||
/** |
||||
* The indicator which determines whether the local participant is a |
||||
* guest in the conference. |
||||
*/ |
||||
_isGuest: PropTypes.bool, |
||||
|
||||
/** |
||||
* Handler dispatching toggle toolbar container. |
||||
*/ |
||||
_onSideToolbarContainerToggled: PropTypes.func, |
||||
|
||||
/** |
||||
* Contains map of secondary toolbar buttons. |
||||
*/ |
||||
_secondaryToolbarButtons: PropTypes.instanceOf(Map), |
||||
|
||||
/** |
||||
* Shows whether toolbox is visible. |
||||
*/ |
||||
_visible: PropTypes.bool |
||||
}; |
||||
|
||||
/** |
||||
* Register legacy UI listener. |
||||
* |
||||
* @returns {void} |
||||
*/ |
||||
componentDidMount(): void { |
||||
APP.UI.addListener( |
||||
UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED, |
||||
this.props._onSideToolbarContainerToggled); |
||||
} |
||||
|
||||
/** |
||||
* Unregisters legacy UI listener. |
||||
* |
||||
* @returns {void} |
||||
*/ |
||||
componentWillUnmount(): void { |
||||
APP.UI.removeListener( |
||||
UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED, |
||||
this.props._onSideToolbarContainerToggled); |
||||
} |
||||
|
||||
/** |
||||
* Renders secondary toolbar component. |
||||
* |
||||
* @returns {ReactElement} |
||||
*/ |
||||
render(): React$Element<*> | null { |
||||
const { _callStatsID, _secondaryToolbarButtons } = this.props; |
||||
|
||||
// The number of buttons to show in the toolbar isn't fixed, it depends
|
||||
// on the availability of features and configuration parameters. So
|
||||
// there may be nothing to render.
|
||||
if (_secondaryToolbarButtons.size === 0) { |
||||
return null; |
||||
} |
||||
|
||||
const { secondaryToolbarClassName } = getToolbarClassNames(this.props); |
||||
|
||||
return ( |
||||
<Toolbar |
||||
className = { secondaryToolbarClassName } |
||||
toolbarButtons = { _secondaryToolbarButtons } |
||||
tooltipPosition = 'right'> |
||||
{ _callStatsID |
||||
? <FeedbackButton tooltipPosition = 'right' /> : null } |
||||
</Toolbar> |
||||
); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Maps some of Redux actions to component's props. |
||||
* |
||||
* @param {Function} dispatch - Redux action dispatcher. |
||||
* @returns {{ |
||||
* _onSideToolbarContainerToggled |
||||
* }} |
||||
* @private |
||||
*/ |
||||
function _mapDispatchToProps(dispatch: Function): Object { |
||||
return { |
||||
|
||||
/** |
||||
* Dispatches an action signalling that side toolbar container is |
||||
* toggled. |
||||
* |
||||
* @param {string} containerId - Id of side toolbar container. |
||||
* @returns {Object} Dispatched action. |
||||
*/ |
||||
_onSideToolbarContainerToggled(containerId: string) { |
||||
dispatch(toggleSideToolbarContainer(containerId)); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Maps part of Redux state to component's props. |
||||
* |
||||
* @param {Object} state - Snapshot of Redux store. |
||||
* @returns {{ |
||||
* _isGuest: boolean, |
||||
* _secondaryToolbarButtons: Map, |
||||
* _visible: boolean |
||||
* }} |
||||
* @private |
||||
*/ |
||||
function _mapStateToProps(state: Object): Object { |
||||
const { isGuest } = state['features/base/jwt']; |
||||
const { secondaryToolbarButtons, visible } = state['features/toolbox']; |
||||
const { callStatsID } = state['features/base/config']; |
||||
|
||||
return { |
||||
/** |
||||
* Application ID for callstats.io API. |
||||
*/ |
||||
_callStatsID: callStatsID, |
||||
|
||||
/** |
||||
* The indicator which determines whether the local participant is a |
||||
* guest in the conference. |
||||
* |
||||
* @private |
||||
* @type {boolean} |
||||
*/ |
||||
_isGuest: isGuest, |
||||
|
||||
/** |
||||
* Default toolbar buttons for secondary toolbar. |
||||
* |
||||
* @private |
||||
* @type {Map} |
||||
*/ |
||||
_secondaryToolbarButtons: secondaryToolbarButtons, |
||||
|
||||
/** |
||||
* The indicator which determines whether the {@code SecondaryToolbar} |
||||
* is visible. |
||||
* |
||||
* @private |
||||
* @type {boolean} |
||||
*/ |
||||
_visible: visible |
||||
}; |
||||
} |
||||
|
||||
export default connect(_mapStateToProps, _mapDispatchToProps)(SecondaryToolbar); |
@ -1,181 +0,0 @@ |
||||
// @flow
|
||||
|
||||
import PropTypes from 'prop-types'; |
||||
import React, { Component } from 'react'; |
||||
import { connect } from 'react-redux'; |
||||
|
||||
import { setToolbarHovered } from '../actions'; |
||||
|
||||
import StatelessToolbar from './StatelessToolbar'; |
||||
import ToolbarButton from './ToolbarButton'; |
||||
|
||||
/** |
||||
* Implements a toolbar in React/Web. It is a strip that contains a set of |
||||
* toolbar items such as buttons. Toolbar is commonly placed inside of a |
||||
* Toolbox. |
||||
* |
||||
* @class Toolbar |
||||
* @extends Component |
||||
*/ |
||||
class Toolbar extends Component<*> { |
||||
/** |
||||
* Base toolbar component's property types. |
||||
* |
||||
* @static |
||||
*/ |
||||
static propTypes = { |
||||
/** |
||||
* Children of current React component. |
||||
*/ |
||||
children: PropTypes.element, |
||||
|
||||
/** |
||||
* Toolbar's class name. |
||||
*/ |
||||
className: PropTypes.string, |
||||
|
||||
/** |
||||
* Used to dispatch an action when a button is clicked or on mouse |
||||
* out/in event. |
||||
*/ |
||||
dispatch: PropTypes.func, |
||||
|
||||
/** |
||||
* Map with toolbar buttons. |
||||
*/ |
||||
toolbarButtons: PropTypes.instanceOf(Map), |
||||
|
||||
/** |
||||
* Indicates the position of the tooltip. |
||||
*/ |
||||
tooltipPosition: PropTypes.oneOf([ 'bottom', 'left', 'right', 'top' ]) |
||||
}; |
||||
|
||||
/** |
||||
* Constructor of Primary toolbar class. |
||||
* |
||||
* @param {Object} props - Object containing React component properties. |
||||
*/ |
||||
constructor(props: Object) { |
||||
super(props); |
||||
|
||||
// Bind callbacks to preverse this.
|
||||
this._onMouseOut = this._onMouseOut.bind(this); |
||||
this._onMouseOver = this._onMouseOver.bind(this); |
||||
this._renderToolbarButton = this._renderToolbarButton.bind(this); |
||||
} |
||||
|
||||
/** |
||||
* Implements React's {@link Component#render()}. |
||||
* |
||||
* @inheritdoc |
||||
* @returns {ReactElement} |
||||
*/ |
||||
render(): React$Element<*> { |
||||
const props = { |
||||
className: this.props.className, |
||||
onMouseOut: this._onMouseOut, |
||||
onMouseOver: this._onMouseOver |
||||
}; |
||||
|
||||
return ( |
||||
<StatelessToolbar { ...props }> |
||||
{ |
||||
[ ...this.props.toolbarButtons.entries() ] |
||||
.map(this._renderToolbarButton) |
||||
} |
||||
{ |
||||
this.props.children |
||||
} |
||||
</StatelessToolbar> |
||||
); |
||||
} |
||||
|
||||
_onMouseOut: () => void; |
||||
|
||||
/** |
||||
* Dispatches an action signalling that toolbar is no being hovered. |
||||
* |
||||
* @protected |
||||
* @returns {void} |
||||
*/ |
||||
_onMouseOut() { |
||||
this.props.dispatch(setToolbarHovered(false)); |
||||
} |
||||
|
||||
_onMouseOver: () => void; |
||||
|
||||
/** |
||||
* Dispatches an action signalling that toolbar is now being hovered. |
||||
* |
||||
* @protected |
||||
* @returns {void} |
||||
*/ |
||||
_onMouseOver() { |
||||
this.props.dispatch(setToolbarHovered(true)); |
||||
} |
||||
|
||||
_renderToolbarButton: (Array<*>) => React$Element<*>; |
||||
|
||||
/** |
||||
* Renders toolbar button. Method is passed to map function. |
||||
* |
||||
* @param {Array} keyValuePair - Key value pair containing button and its |
||||
* key. |
||||
* @private |
||||
* @returns {ReactElement} A toolbar button. |
||||
*/ |
||||
_renderToolbarButton([ key, button ]): React$Element<*> { |
||||
const { tooltipPosition } = this.props; |
||||
|
||||
if (button.component) { |
||||
return ( |
||||
<button.component |
||||
key = { key } |
||||
toggled = { button.toggled } |
||||
tooltipPosition = { tooltipPosition } /> |
||||
); |
||||
} |
||||
|
||||
const { |
||||
childComponent: ChildComponent, |
||||
onClick, |
||||
onMount, |
||||
onUnmount |
||||
} = button; |
||||
const onClickWithDispatch = (...args) => |
||||
onClick && onClick(this.props.dispatch, ...args); |
||||
|
||||
return ( |
||||
<ToolbarButton |
||||
button = { button } |
||||
key = { key } |
||||
|
||||
// TODO The following disables an eslint error alerting about a
|
||||
// known potential/theoretical performance pernalty:
|
||||
//
|
||||
// A bind call or arrow function in a JSX prop will create a
|
||||
// brand new function on every single render. This is bad for
|
||||
// performance, as it will result in the garbage collector being
|
||||
// invoked way more than is necessary. It may also cause
|
||||
// unnecessary re-renders if a brand new function is passed as a
|
||||
// prop to a component that uses reference equality check on the
|
||||
// prop to determine if it should update.
|
||||
//
|
||||
// I'm not addressing the potential/theoretical performance
|
||||
// penalty at the time of this writing because I don't know for
|
||||
// a fact that it's a practical performance penalty in the case.
|
||||
//
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick = { onClickWithDispatch } |
||||
onMount = { onMount } |
||||
onUnmount = { onUnmount } |
||||
tooltipPosition = { tooltipPosition }> |
||||
{ button.html || null } |
||||
{ ChildComponent ? <ChildComponent /> : null } |
||||
</ToolbarButton> |
||||
); |
||||
} |
||||
} |
||||
|
||||
export default connect()(Toolbar); |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@ |
||||
export default undefined; |
@ -1,532 +0,0 @@ |
||||
// @flow
|
||||
|
||||
import React from 'react'; |
||||
|
||||
import { setFullScreen } from '../toolbox'; |
||||
import { |
||||
ACTION_SHORTCUT_TRIGGERED as TRIGGERED, |
||||
AUDIO_MUTE, |
||||
VIDEO_MUTE, |
||||
createShortcutEvent, |
||||
createToolbarEvent, |
||||
sendAnalytics |
||||
} from '../analytics'; |
||||
import { |
||||
getLocalParticipant, |
||||
participantUpdated |
||||
} from '../base/participants'; |
||||
import { ParticipantCounter } from '../contact-list'; |
||||
import { openDeviceSelectionDialog } from '../device-selection'; |
||||
import { InfoDialogButton } from '../invite'; |
||||
import UIEvents from '../../../service/UI/UIEvents'; |
||||
import { VideoQualityButton } from '../video-quality'; |
||||
|
||||
import ProfileButton from './components/ProfileButton'; |
||||
|
||||
declare var APP: Object; |
||||
declare var interfaceConfig: Object; |
||||
|
||||
/** |
||||
* The cache of {@link getDefaultButtons()}. |
||||
*/ |
||||
let defaultButtons: Object; |
||||
|
||||
/** |
||||
* Returns a map of all button descriptors and according properties. |
||||
* |
||||
* @returns {Object} - The maps of default button descriptors. |
||||
*/ |
||||
export default function getDefaultButtons() { |
||||
if (defaultButtons) { |
||||
return defaultButtons; |
||||
} |
||||
|
||||
defaultButtons = { |
||||
/** |
||||
* The descriptor of the camera toolbar button. |
||||
*/ |
||||
camera: { |
||||
classNames: [ 'button', 'icon-camera' ], |
||||
enabled: true, |
||||
isDisplayed: () => true, |
||||
id: 'toolbar_button_camera', |
||||
onClick() { |
||||
// TODO: Why is this different from the code which handles
|
||||
// a keyboard shortcut?
|
||||
const newVideoMutedState = !APP.conference.isLocalVideoMuted(); |
||||
|
||||
// The 'enable' attribute in the event is set to true if the
|
||||
// button click triggered a mute action, and set to false if it
|
||||
// triggered an unmute action.
|
||||
sendAnalytics(createToolbarEvent( |
||||
VIDEO_MUTE, |
||||
{ |
||||
enable: newVideoMutedState |
||||
})); |
||||
APP.UI.emitEvent(UIEvents.VIDEO_MUTED, newVideoMutedState); |
||||
}, |
||||
popups: [ |
||||
{ |
||||
dataAttr: 'audioOnly.featureToggleDisabled', |
||||
dataInterpolate: { feature: 'video mute' }, |
||||
id: 'unmuteWhileAudioOnly' |
||||
} |
||||
], |
||||
shortcut: 'V', |
||||
shortcutAttr: 'toggleVideoPopover', |
||||
shortcutFunc() { |
||||
if (APP.conference.isAudioOnly()) { |
||||
APP.UI.emitEvent(UIEvents.VIDEO_UNMUTING_WHILE_AUDIO_ONLY); |
||||
|
||||
return; |
||||
} |
||||
|
||||
// The 'enable' attribute in the event is set to true if the
|
||||
// shortcut triggered a mute action, and set to false if it
|
||||
// triggered an unmute action.
|
||||
sendAnalytics(createShortcutEvent( |
||||
VIDEO_MUTE, |
||||
TRIGGERED, |
||||
{ enable: !APP.conference.isLocalVideoMuted() })); |
||||
APP.conference.toggleVideoMuted(); |
||||
}, |
||||
shortcutDescription: 'keyboardShortcuts.videoMute', |
||||
tooltipKey: 'toolbar.videomute' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the chat toolbar button. |
||||
*/ |
||||
chat: { |
||||
classNames: [ 'button', 'icon-chat' ], |
||||
enabled: true, |
||||
html: <span className = 'badge-round'> |
||||
<span id = 'unreadMessages' /></span>, |
||||
id: 'toolbar_button_chat', |
||||
onClick() { |
||||
// The 'enable' attribute is set to true if the click resulted
|
||||
// in the chat panel being shown, and to false if it was hidden.
|
||||
sendAnalytics(createToolbarEvent( |
||||
'toggle.chat', |
||||
{ |
||||
enable: !APP.UI.isChatVisible() |
||||
})); |
||||
APP.UI.emitEvent(UIEvents.TOGGLE_CHAT); |
||||
}, |
||||
shortcut: 'C', |
||||
shortcutAttr: 'toggleChatPopover', |
||||
shortcutFunc() { |
||||
// The 'enable' attribute is set to true if the shortcut
|
||||
// resulted in the chat panel being shown, and to false if it
|
||||
// was hidden.
|
||||
sendAnalytics(createShortcutEvent( |
||||
'toggle.chat', |
||||
{ |
||||
enable: !APP.UI.isChatVisible() |
||||
})); |
||||
APP.UI.toggleChat(); |
||||
}, |
||||
shortcutDescription: 'keyboardShortcuts.toggleChat', |
||||
sideContainerId: 'chat_container', |
||||
tooltipKey: 'toolbar.chat' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the contact list toolbar button. |
||||
*/ |
||||
contacts: { |
||||
childComponent: ParticipantCounter, |
||||
classNames: [ 'button', 'icon-contactList' ], |
||||
enabled: true, |
||||
id: 'toolbar_contact_list', |
||||
onClick() { |
||||
// TODO: Include an 'enable' attribute which specifies whether
|
||||
// the contacts panel was shown or hidden.
|
||||
sendAnalytics(createToolbarEvent('contacts')); |
||||
APP.UI.emitEvent(UIEvents.TOGGLE_CONTACT_LIST); |
||||
}, |
||||
sideContainerId: 'contacts_container', |
||||
tooltipKey: 'bottomtoolbar.contactlist' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the desktop sharing toolbar button. |
||||
*/ |
||||
desktop: { |
||||
classNames: [ 'button', 'icon-share-desktop' ], |
||||
enabled: true, |
||||
id: 'toolbar_button_desktopsharing', |
||||
onClick() { |
||||
// TODO: Why is the button clicked handled differently that
|
||||
// a keyboard shortcut press (firing a TOGGLE_SCREENSHARING
|
||||
// event vs. directly calling toggleScreenSharing())?
|
||||
sendAnalytics(createToolbarEvent( |
||||
'screen.sharing', |
||||
{ |
||||
enable: !APP.conference.isSharingScreen |
||||
})); |
||||
APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING); |
||||
}, |
||||
popups: [ |
||||
{ |
||||
dataAttr: 'audioOnly.featureToggleDisabled', |
||||
dataInterpolate: { feature: 'screen sharing' }, |
||||
id: 'screenshareWhileAudioOnly' |
||||
} |
||||
], |
||||
shortcut: 'D', |
||||
shortcutAttr: 'toggleDesktopSharingPopover', |
||||
shortcutFunc() { |
||||
// The 'enable' attribute is set to true if pressing the
|
||||
// shortcut resulted in screen sharing being enabled, and false
|
||||
// if it resulted in screen sharing being disabled.
|
||||
sendAnalytics(createShortcutEvent( |
||||
'toggle.screen.sharing', |
||||
TRIGGERED, |
||||
{ enable: !APP.conference.isSharingScreen })); |
||||
|
||||
// eslint-disable-next-line no-empty-function
|
||||
APP.conference.toggleScreenSharing().catch(() => {}); |
||||
}, |
||||
shortcutDescription: 'keyboardShortcuts.toggleScreensharing', |
||||
tooltipKey: 'toolbar.sharescreen' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the device selection toolbar button. |
||||
*/ |
||||
fodeviceselection: { |
||||
classNames: [ 'button', 'icon-settings' ], |
||||
enabled: true, |
||||
isDisplayed() { |
||||
return interfaceConfig.filmStripOnly; |
||||
}, |
||||
id: 'toolbar_button_fodeviceselection', |
||||
onClick(dispatch: Function) { |
||||
sendAnalytics( |
||||
createToolbarEvent('filmstrip.only.device.selection')); |
||||
|
||||
dispatch(openDeviceSelectionDialog()); |
||||
}, |
||||
sideContainerId: 'settings_container', |
||||
tooltipKey: 'toolbar.Settings' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the dialpad toolbar button. |
||||
*/ |
||||
dialpad: { |
||||
classNames: [ 'button', 'icon-dialpad' ], |
||||
enabled: true, |
||||
|
||||
// TODO: remove it after UI.updateDTMFSupport fix
|
||||
hidden: true, |
||||
id: 'toolbar_button_dialpad', |
||||
onClick() { |
||||
sendAnalytics(createToolbarEvent('dialpad')); |
||||
}, |
||||
tooltipKey: 'toolbar.dialpad' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the etherpad toolbar button. |
||||
*/ |
||||
etherpad: { |
||||
classNames: [ 'button', 'icon-share-doc' ], |
||||
enabled: true, |
||||
hidden: true, |
||||
id: 'toolbar_button_etherpad', |
||||
onClick() { |
||||
// The 'enable' attribute is set to true if the click resulted
|
||||
// in the etherpad panel being shown, or false it it was hidden.
|
||||
sendAnalytics(createToolbarEvent( |
||||
'toggle.etherpad', |
||||
{ |
||||
enable: !APP.UI.isEtherpadVisible() |
||||
})); |
||||
APP.UI.emitEvent(UIEvents.ETHERPAD_CLICKED); |
||||
}, |
||||
tooltipKey: 'toolbar.etherpad' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the toolbar button which toggles full-screen mode. |
||||
*/ |
||||
fullscreen: { |
||||
classNames: [ 'button', 'icon-full-screen' ], |
||||
enabled: true, |
||||
id: 'toolbar_button_fullScreen', |
||||
onClick() { |
||||
const state = APP.store.getState(); |
||||
const isFullScreen = Boolean( |
||||
state['features/toolbox'].fullScreen); |
||||
|
||||
// The 'enable' attribute is set to true if the action resulted
|
||||
// in fullscreen mode being enabled.
|
||||
sendAnalytics(createToolbarEvent( |
||||
'toggle.fullscreen', |
||||
{ |
||||
enable: !isFullScreen |
||||
})); |
||||
|
||||
APP.store.dispatch(setFullScreen(!isFullScreen)); |
||||
}, |
||||
shortcut: 'S', |
||||
shortcutAttr: 'toggleFullscreenPopover', |
||||
shortcutDescription: 'keyboardShortcuts.fullScreen', |
||||
shortcutFunc() { |
||||
const state = APP.store.getState(); |
||||
const isFullScreen = Boolean( |
||||
state['features/toolbox'].fullScreen); |
||||
|
||||
// The 'enable' attribute is set to true if the action resulted
|
||||
// in fullscreen mode being enabled.
|
||||
sendAnalytics(createShortcutEvent( |
||||
'toggle.fullscreen', |
||||
{ |
||||
enable: !isFullScreen |
||||
})); |
||||
|
||||
APP.store.dispatch(setFullScreen(!isFullScreen)); |
||||
}, |
||||
tooltipKey: 'toolbar.fullscreen' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the toolbar button which hangs up the |
||||
* call/conference. |
||||
*/ |
||||
hangup: { |
||||
classNames: [ 'button', 'icon-hangup', 'button_hangup' ], |
||||
enabled: true, |
||||
isDisplayed: () => true, |
||||
id: 'toolbar_button_hangup', |
||||
onClick() { |
||||
sendAnalytics(createToolbarEvent('hangup')); |
||||
APP.UI.emitEvent(UIEvents.HANGUP); |
||||
}, |
||||
tooltipKey: 'toolbar.hangup' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the toolbar button which opens a dialog for the |
||||
* conference URL and inviting others. |
||||
*/ |
||||
info: { |
||||
component: InfoDialogButton |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the microphone toolbar button. |
||||
*/ |
||||
microphone: { |
||||
classNames: [ 'button', 'icon-microphone' ], |
||||
enabled: true, |
||||
isDisplayed: () => true, |
||||
id: 'toolbar_button_mute', |
||||
onClick() { |
||||
const sharedVideoManager = APP.UI.getSharedVideoManager(); |
||||
|
||||
// TODO: Clicking the mute button and pressing the mute shortcut
|
||||
// could be handled in a uniform manner. The code below checks
|
||||
// the mute status and fires the appropriate event (MUTED or
|
||||
// UNMUTED), while the code which handles the keyboard shortcut
|
||||
// calls toggleAudioMuted(). Also strangely the the user is
|
||||
// only warned if they click the button (and not if they use
|
||||
// the shortcut).
|
||||
if (APP.conference.isLocalAudioMuted()) { |
||||
// If there's a shared video with the volume "on" and we
|
||||
// aren't the video owner, we warn the user
|
||||
// that currently it's not possible to unmute.
|
||||
if (sharedVideoManager |
||||
&& sharedVideoManager.isSharedVideoVolumeOn() |
||||
&& !sharedVideoManager.isSharedVideoOwner()) { |
||||
APP.UI.showCustomToolbarPopup( |
||||
'microphone', 'unableToUnmutePopup', true, 5000); |
||||
} else { |
||||
sendAnalytics(createToolbarEvent( |
||||
AUDIO_MUTE, |
||||
{ enable: false })); |
||||
APP.UI.emitEvent(UIEvents.AUDIO_MUTED, false, true); |
||||
} |
||||
} else { |
||||
sendAnalytics(createToolbarEvent( |
||||
AUDIO_MUTE, |
||||
{ enable: true })); |
||||
APP.UI.emitEvent(UIEvents.AUDIO_MUTED, true, true); |
||||
} |
||||
}, |
||||
popups: [ |
||||
{ |
||||
dataAttr: 'toolbar.micMutedPopup', |
||||
id: 'micMutedPopup' |
||||
}, |
||||
{ |
||||
dataAttr: 'toolbar.unableToUnmutePopup', |
||||
id: 'unableToUnmutePopup' |
||||
}, |
||||
{ |
||||
dataAttr: 'toolbar.talkWhileMutedPopup', |
||||
id: 'talkWhileMutedPopup' |
||||
} |
||||
], |
||||
shortcut: 'M', |
||||
shortcutAttr: 'mutePopover', |
||||
shortcutFunc() { |
||||
// The 'enable' attribute in the event is set to true if the
|
||||
// shortcut triggered a mute action, and set to false if it
|
||||
// triggered an unmute action.
|
||||
sendAnalytics(createShortcutEvent( |
||||
AUDIO_MUTE, |
||||
TRIGGERED, |
||||
{ enable: !APP.conference.isLocalAudioMuted() })); |
||||
APP.conference.toggleAudioMuted(); |
||||
}, |
||||
shortcutDescription: 'keyboardShortcuts.mute', |
||||
tooltipKey: 'toolbar.mute' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the profile toolbar button. |
||||
*/ |
||||
profile: { |
||||
component: ProfileButton, |
||||
sideContainerId: 'profile_container' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the "Raise hand" toolbar button. |
||||
*/ |
||||
raisehand: { |
||||
classNames: [ 'button', 'icon-raised-hand' ], |
||||
enabled: true, |
||||
id: 'toolbar_button_raisehand', |
||||
onClick() { |
||||
// TODO: reduce duplication with shortcutFunc below.
|
||||
const localParticipant |
||||
= getLocalParticipant(APP.store.getState()); |
||||
const currentRaisedHand = localParticipant.raisedHand; |
||||
|
||||
// The 'enable' attribute is set to true if the pressing of the
|
||||
// shortcut resulted in the hand being raised, and to false
|
||||
// if it resulted in the hand being 'lowered'.
|
||||
sendAnalytics(createToolbarEvent( |
||||
'raise.hand', |
||||
{ enable: !currentRaisedHand })); |
||||
|
||||
APP.store.dispatch(participantUpdated({ |
||||
id: localParticipant.id, |
||||
local: true, |
||||
raisedHand: !currentRaisedHand |
||||
})); |
||||
}, |
||||
shortcut: 'R', |
||||
shortcutAttr: 'raiseHandPopover', |
||||
shortcutDescription: 'keyboardShortcuts.raiseHand', |
||||
shortcutFunc() { |
||||
const localParticipant |
||||
= getLocalParticipant(APP.store.getState()); |
||||
const currentRaisedHand = localParticipant.raisedHand; |
||||
|
||||
// The 'enable' attribute is set to true if the pressing of the
|
||||
// shortcut resulted in the hand being raised, and to false
|
||||
// if it resulted in the hand being 'lowered'.
|
||||
sendAnalytics(createShortcutEvent( |
||||
'toggle.raise.hand', |
||||
TRIGGERED, |
||||
{ enable: !currentRaisedHand })); |
||||
|
||||
APP.store.dispatch(participantUpdated({ |
||||
id: localParticipant.id, |
||||
local: true, |
||||
raisedHand: !currentRaisedHand |
||||
})); |
||||
}, |
||||
tooltipKey: 'toolbar.raiseHand' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the recording toolbar button. Requires additional |
||||
* initialization in the recording module. |
||||
*/ |
||||
recording: { |
||||
classNames: [ 'button' ], |
||||
enabled: true, |
||||
|
||||
// will be displayed once the recording functionality is detected
|
||||
hidden: true, |
||||
id: 'toolbar_button_record', |
||||
tooltipKey: 'liveStreaming.buttonTooltip' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the settings toolbar button. |
||||
*/ |
||||
settings: { |
||||
classNames: [ 'button', 'icon-settings' ], |
||||
enabled: true, |
||||
id: 'toolbar_button_settings', |
||||
onClick() { |
||||
// TODO: Include an 'enable' attribute which specifies whether
|
||||
// the settings panel was shown or hidden.
|
||||
sendAnalytics(createToolbarEvent('settings')); |
||||
APP.UI.emitEvent(UIEvents.TOGGLE_SETTINGS); |
||||
}, |
||||
sideContainerId: 'settings_container', |
||||
tooltipKey: 'toolbar.Settings' |
||||
}, |
||||
|
||||
/** |
||||
* The descriptor of the "Share YouTube video" toolbar button. |
||||
*/ |
||||
sharedvideo: { |
||||
classNames: [ 'button', 'icon-shared-video' ], |
||||
enabled: true, |
||||
id: 'toolbar_button_sharedvideo', |
||||
onClick() { |
||||
// The 'enable' attribute is set to true if the click resulted
|
||||
// in the "start sharing video" dialog being shown, and false
|
||||
// if it resulted in the "stop sharing video" dialog being
|
||||
// shown.
|
||||
sendAnalytics(createToolbarEvent( |
||||
'shared.video.toggled', |
||||
{ |
||||
enable: !APP.UI.isSharedVideoShown() |
||||
})); |
||||
APP.UI.emitEvent(UIEvents.SHARED_VIDEO_CLICKED); |
||||
}, |
||||
popups: [ |
||||
{ |
||||
dataAttr: 'toolbar.sharedVideoMutedPopup', |
||||
id: 'sharedVideoMutedPopup' |
||||
} |
||||
], |
||||
tooltipKey: 'toolbar.sharedvideo' |
||||
}, |
||||
|
||||
videoquality: { |
||||
component: VideoQualityButton |
||||
} |
||||
}; |
||||
|
||||
Object.keys(defaultButtons).forEach(name => { |
||||
const button = defaultButtons[name]; |
||||
|
||||
if (!button.isDisplayed) { |
||||
button.isDisplayed = _isDisplayed; |
||||
} |
||||
}); |
||||
|
||||
return defaultButtons; |
||||
} |
||||
|
||||
/** |
||||
* The default implementation of the {@code isDisplayed} method of the toolbar |
||||
* button definition returned by {@link getDefaultButtons()}. |
||||
* |
||||
* @returns {boolean} If the user intarface is full i.e. not filmstrip-only, |
||||
* then {@code true}; otherwise, {@code false}. |
||||
*/ |
||||
function _isDisplayed() { |
||||
return !interfaceConfig.filmStripOnly; |
||||
} |
Loading…
Reference in new issue