From 1add438a1f2c4369a9ecaa0fbeb5c3a3123bbd55 Mon Sep 17 00:00:00 2001 From: Horatiu Muresan <39557534+horymury@users.noreply.github.com> Date: Tue, 14 Sep 2021 10:07:20 +0300 Subject: [PATCH] feat(toolbar-buttons): Add event for notify overwritten toolbar buttons --- config.js | 37 +++++++++++++++++++ modules/API/API.js | 13 +++++++ modules/API/external/external_api.js | 3 +- react/features/base/config/configWhitelist.js | 1 + .../components/AbstractAudioMuteButton.js | 8 ++++ .../base/toolbox/components/AbstractButton.js | 5 +++ .../components/AbstractVideoMuteButton.js | 8 ++++ .../chat/components/web/ChatButton.js | 13 ++++--- .../components/EmbedMeetingButton.js | 8 +++- .../components/SharedDocumentButton.js | 12 +++++- .../feedback/components/FeedbackButton.web.js | 8 +++- .../add-people-dialog/web/InviteButton.js | 8 +++- .../components/KeyboardShortcutsButton.web.js | 8 +++- .../components/LocalRecordingButton.web.js | 8 +++- .../components/ParticipantsPaneButton.js | 13 ++++--- .../LiveStream/AbstractLiveStreamButton.js | 8 +++- .../Recording/AbstractRecordButton.js | 8 +++- .../components/ShareAudioButton.js | 12 +++++- .../security-dialog/SecurityDialogButton.js | 12 +++++- .../settings/components/web/SettingsButton.js | 10 ++++- .../components/web/SharedVideoButton.js | 8 ++++ .../components/SpeakerStatsButton.js | 8 +++- .../components/AbstractClosedCaptionButton.js | 8 +++- .../toolbox/components/DownloadButton.js | 10 ++++- .../features/toolbox/components/HelpButton.js | 10 ++++- .../toolbox/components/MuteEveryoneButton.js | 8 +++- .../components/MuteEveryonesVideoButton.js | 8 +++- .../components/web/AudioSettingsButton.js | 35 +++++++++++++++--- .../components/web/FullscreenButton.js | 13 ++++--- .../toolbox/components/web/ProfileButton.js | 8 +++- .../toolbox/components/web/RaiseHandButton.js | 13 ++++--- .../components/web/ShareDesktopButton.js | 13 ++++--- .../components/web/ToggleCameraButton.js | 10 ++++- .../toolbox/components/web/Toolbox.js | 32 +++++++++++++++- .../components/web/VideoSettingsButton.js | 37 ++++++++++++++++--- .../video-layout/components/TileViewButton.js | 9 ++++- .../components/VideoQualityButton.web.js | 13 ++++--- .../components/VideoBackgroundButton.js | 8 +++- 38 files changed, 380 insertions(+), 74 deletions(-) diff --git a/config.js b/config.js index 31f94af0c..47cd0edb0 100644 --- a/config.js +++ b/config.js @@ -539,6 +539,43 @@ var config = { // '__end' // ], + // Toolbar buttons which have their click event exposed through the API on + // `toolbarButtonClicked` event instead of executing the normal click routine. + // buttonsWithNotifyClick: [ + // 'camera', + // 'chat', + // 'closedcaptions', + // 'desktop', + // 'download', + // 'embedmeeting', + // 'etherpad', + // 'feedback', + // 'filmstrip', + // 'fullscreen', + // 'hangup', + // 'help', + // 'invite', + // 'livestreaming', + // 'microphone', + // 'mute-everyone', + // 'mute-video-everyone', + // 'participants-pane', + // 'profile', + // 'raisehand', + // 'recording', + // 'security', + // 'select-background', + // 'settings', + // 'shareaudio', + // 'sharedvideo', + // 'shortcuts', + // 'stats', + // 'tileview', + // 'toggle-camera', + // 'videoquality', + // '__end' + // ], + // List of pre meeting screens buttons to hide. The values must be one or more of the 5 allowed buttons: // 'microphone', 'camera', 'select-background', 'invite', 'settings' // hiddenPremeetingButtons: [], diff --git a/modules/API/API.js b/modules/API/API.js index 6acfe789e..c35e7abbd 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -1342,6 +1342,19 @@ class API { }); } + /** + * Notify external application ( if API is enabled) that a toolbar button was clicked. + * + * @param {string} key - The key of the toolbar button. + * @returns {void} + */ + notifyToolbarButtonClicked(key: string) { + this._sendEvent({ + name: 'toolbar-button-clicked', + key + }); + } + /** * Disposes the allocated resources. * diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 069fa1cbf..ad457406e 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -112,7 +112,8 @@ const events = { 'dominant-speaker-changed': 'dominantSpeakerChanged', 'subject-change': 'subjectChange', 'suspend-detected': 'suspendDetected', - 'tile-view-changed': 'tileViewChanged' + 'tile-view-changed': 'tileViewChanged', + 'toolbar-button-clicked': 'toolbarButtonClicked' }; /** diff --git a/react/features/base/config/configWhitelist.js b/react/features/base/config/configWhitelist.js index 6ffb60d89..6a79f72ca 100644 --- a/react/features/base/config/configWhitelist.js +++ b/react/features/base/config/configWhitelist.js @@ -19,6 +19,7 @@ export default [ 'apiLogLevels', 'avgRtpStatsN', 'backgroundAlpha', + 'buttonsWithNotifyClick', /** * The display name of the CallKit call representing the conference/meeting diff --git a/react/features/base/toolbox/components/AbstractAudioMuteButton.js b/react/features/base/toolbox/components/AbstractAudioMuteButton.js index 4e0222ffd..99a907a39 100644 --- a/react/features/base/toolbox/components/AbstractAudioMuteButton.js +++ b/react/features/base/toolbox/components/AbstractAudioMuteButton.js @@ -23,6 +23,14 @@ export default class AbstractAudioMuteButton * @returns {void} */ _handleClick() { + const { handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + this._setAudioMuted(!this._isAudioMuted()); } diff --git a/react/features/base/toolbox/components/AbstractButton.js b/react/features/base/toolbox/components/AbstractButton.js index 802dfe36a..27d21bd06 100644 --- a/react/features/base/toolbox/components/AbstractButton.js +++ b/react/features/base/toolbox/components/AbstractButton.js @@ -20,6 +20,11 @@ export type Props = { */ disabledStyles: ?Styles, + /** + * External handler for click action. + */ + handleClick?: Function, + /** * Whether to show the label or not. */ diff --git a/react/features/base/toolbox/components/AbstractVideoMuteButton.js b/react/features/base/toolbox/components/AbstractVideoMuteButton.js index 400de5b9f..cda037ff9 100644 --- a/react/features/base/toolbox/components/AbstractVideoMuteButton.js +++ b/react/features/base/toolbox/components/AbstractVideoMuteButton.js @@ -22,6 +22,14 @@ export default class AbstractVideoMuteButton

* @returns {void} */ _handleClick() { + const { handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + this._setVideoMuted(!this._isVideoMuted()); } diff --git a/react/features/chat/components/web/ChatButton.js b/react/features/chat/components/web/ChatButton.js index 9791dbb6b..83f79e51f 100644 --- a/react/features/chat/components/web/ChatButton.js +++ b/react/features/chat/components/web/ChatButton.js @@ -18,11 +18,6 @@ type Props = AbstractButtonProps & { * Whether or not the chat feature is currently displayed. */ _chatOpen: boolean, - - /** - * External handler for click action. - */ - handleClick: Function }; /** @@ -61,7 +56,13 @@ class ChatButton extends AbstractButton { * @returns {void} */ _handleClick() { - this.props.handleClick(); + const { handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } } /** diff --git a/react/features/embed-meeting/components/EmbedMeetingButton.js b/react/features/embed-meeting/components/EmbedMeetingButton.js index 95b0de9a8..35dd8e380 100644 --- a/react/features/embed-meeting/components/EmbedMeetingButton.js +++ b/react/features/embed-meeting/components/EmbedMeetingButton.js @@ -36,7 +36,13 @@ class EmbedMeetingButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { dispatch } = this.props; + const { dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('embed.meeting')); dispatch(openDialog(EmbedMeetingDialog)); diff --git a/react/features/etherpad/components/SharedDocumentButton.js b/react/features/etherpad/components/SharedDocumentButton.js index fd119a7f0..bc6efbb5d 100644 --- a/react/features/etherpad/components/SharedDocumentButton.js +++ b/react/features/etherpad/components/SharedDocumentButton.js @@ -59,12 +59,20 @@ class SharedDocumentButton extends AbstractButton { * @returns {void} */ _handleClick() { + const { _editing, dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + sendAnalytics(createToolbarEvent( 'toggle.etherpad', { - enable: !this.props._editing + enable: !_editing })); - this.props.dispatch(toggleDocument()); + dispatch(toggleDocument()); } /** diff --git a/react/features/feedback/components/FeedbackButton.web.js b/react/features/feedback/components/FeedbackButton.web.js index f8bf191d9..b2b366dd6 100644 --- a/react/features/feedback/components/FeedbackButton.web.js +++ b/react/features/feedback/components/FeedbackButton.web.js @@ -40,7 +40,13 @@ class FeedbackButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { _conference, dispatch } = this.props; + const { _conference, dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('feedback')); dispatch(openFeedbackDialog(_conference)); diff --git a/react/features/invite/components/add-people-dialog/web/InviteButton.js b/react/features/invite/components/add-people-dialog/web/InviteButton.js index 3a3ea8f2c..271d397b1 100644 --- a/react/features/invite/components/add-people-dialog/web/InviteButton.js +++ b/react/features/invite/components/add-people-dialog/web/InviteButton.js @@ -34,7 +34,13 @@ class InviteButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { dispatch } = this.props; + const { dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('invite')); dispatch(beginAddPeople()); diff --git a/react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.web.js b/react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.web.js index 2e9056748..0ce2721c4 100644 --- a/react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.web.js +++ b/react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.web.js @@ -34,7 +34,13 @@ class KeyboardShortcutsButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { dispatch } = this.props; + const { dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('shortcuts')); dispatch(openKeyboardShortcutsDialog()); diff --git a/react/features/local-recording/components/LocalRecordingButton.web.js b/react/features/local-recording/components/LocalRecordingButton.web.js index 0d1fc8451..e67ff8ec8 100644 --- a/react/features/local-recording/components/LocalRecordingButton.web.js +++ b/react/features/local-recording/components/LocalRecordingButton.web.js @@ -36,7 +36,13 @@ class LocalRecording extends AbstractButton { * @returns {void} */ _handleClick() { - const { dispatch } = this.props; + const { dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('local.recording')); dispatch(openDialog(LocalRecordingInfoDialog)); diff --git a/react/features/participants-pane/components/ParticipantsPaneButton.js b/react/features/participants-pane/components/ParticipantsPaneButton.js index ca5f20a19..69cf81101 100644 --- a/react/features/participants-pane/components/ParticipantsPaneButton.js +++ b/react/features/participants-pane/components/ParticipantsPaneButton.js @@ -14,11 +14,6 @@ type Props = AbstractButtonProps & { * Whether or not the participants pane is open. */ _isOpen: boolean, - - /** - * External handler for click action. - */ - handleClick: Function }; /** @@ -37,7 +32,13 @@ class ParticipantsPaneButton extends AbstractButton { * @returns {void} */ _handleClick() { - this.props.handleClick(); + const { handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } } /** diff --git a/react/features/recording/components/LiveStream/AbstractLiveStreamButton.js b/react/features/recording/components/LiveStream/AbstractLiveStreamButton.js index d0934497a..09abae569 100644 --- a/react/features/recording/components/LiveStream/AbstractLiveStreamButton.js +++ b/react/features/recording/components/LiveStream/AbstractLiveStreamButton.js @@ -76,7 +76,13 @@ export default class AbstractLiveStreamButton extends AbstractButton

extends AbstractButton * @returns {void} */ async _handleClick() { - const { _isRecordingRunning, dispatch } = this.props; + const { _isRecordingRunning, dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent( 'recording.button', diff --git a/react/features/screen-share/components/ShareAudioButton.js b/react/features/screen-share/components/ShareAudioButton.js index d8ab1dd71..fabbc4dac 100644 --- a/react/features/screen-share/components/ShareAudioButton.js +++ b/react/features/screen-share/components/ShareAudioButton.js @@ -47,8 +47,16 @@ class ShareAudioButton extends AbstractButton { * @returns {void} */ _handleClick() { - this.props.dispatch(startAudioScreenShareFlow()); - this.props.dispatch(setOverflowMenuVisible(false)); + const { dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + + dispatch(startAudioScreenShareFlow()); + dispatch(setOverflowMenuVisible(false)); } /** diff --git a/react/features/security/components/security-dialog/SecurityDialogButton.js b/react/features/security/components/security-dialog/SecurityDialogButton.js index 049342a7b..87fd498e0 100644 --- a/react/features/security/components/security-dialog/SecurityDialogButton.js +++ b/react/features/security/components/security-dialog/SecurityDialogButton.js @@ -48,8 +48,16 @@ class SecurityDialogButton extends AbstractButton { * @returns {void} */ _handleClick() { - sendAnalytics(createToolbarEvent('toggle.security', { enable: !this.props._locked })); - this.props.dispatch(toggleSecurityDialog()); + const { _locked, dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + + sendAnalytics(createToolbarEvent('toggle.security', { enable: !_locked })); + dispatch(toggleSecurityDialog()); } /** diff --git a/react/features/settings/components/web/SettingsButton.js b/react/features/settings/components/web/SettingsButton.js index 52ddf7fb5..6017f647d 100644 --- a/react/features/settings/components/web/SettingsButton.js +++ b/react/features/settings/components/web/SettingsButton.js @@ -42,7 +42,15 @@ class SettingsButton extends AbstractButton { _handleClick() { const { defaultTab = SETTINGS_TABS.DEVICES, - dispatch } = this.props; + dispatch, + handleClick + } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('settings')); dispatch(openSettingsDialog(defaultTab)); diff --git a/react/features/shared-video/components/web/SharedVideoButton.js b/react/features/shared-video/components/web/SharedVideoButton.js index eb9b73c5d..c226b5d50 100644 --- a/react/features/shared-video/components/web/SharedVideoButton.js +++ b/react/features/shared-video/components/web/SharedVideoButton.js @@ -66,6 +66,14 @@ class SharedVideoButton extends AbstractButton { * @returns {void} */ _handleClick() { + const { handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + this._doToggleSharedVideo(); } diff --git a/react/features/speaker-stats/components/SpeakerStatsButton.js b/react/features/speaker-stats/components/SpeakerStatsButton.js index c00806c03..4c56762b2 100644 --- a/react/features/speaker-stats/components/SpeakerStatsButton.js +++ b/react/features/speaker-stats/components/SpeakerStatsButton.js @@ -41,7 +41,13 @@ class SpeakerStatsButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { _conference, dispatch } = this.props; + const { _conference, dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('speaker.stats')); dispatch(openDialog(SpeakerStats, { diff --git a/react/features/subtitles/components/AbstractClosedCaptionButton.js b/react/features/subtitles/components/AbstractClosedCaptionButton.js index 0d1f2f867..9dcb8a82a 100644 --- a/react/features/subtitles/components/AbstractClosedCaptionButton.js +++ b/react/features/subtitles/components/AbstractClosedCaptionButton.js @@ -38,7 +38,13 @@ export class AbstractClosedCaptionButton * @returns {void} */ async _handleClick() { - const { _requestingSubtitles, dispatch } = this.props; + const { _requestingSubtitles, dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('transcribing.ccButton', { diff --git a/react/features/toolbox/components/DownloadButton.js b/react/features/toolbox/components/DownloadButton.js index dfc40ad32..40e612b18 100644 --- a/react/features/toolbox/components/DownloadButton.js +++ b/react/features/toolbox/components/DownloadButton.js @@ -32,8 +32,16 @@ class DownloadButton extends AbstractButton { * @returns {void} */ _handleClick() { + const { _downloadAppsUrl, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + sendAnalytics(createToolbarEvent('download.pressed')); - openURLInBrowser(this.props._downloadAppsUrl); + openURLInBrowser(_downloadAppsUrl); } } diff --git a/react/features/toolbox/components/HelpButton.js b/react/features/toolbox/components/HelpButton.js index 33a2edf30..37316a2af 100644 --- a/react/features/toolbox/components/HelpButton.js +++ b/react/features/toolbox/components/HelpButton.js @@ -33,8 +33,16 @@ class HelpButton extends AbstractButton { * @returns {void} */ _handleClick() { + const { _userDocumentationURL, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + sendAnalytics(createToolbarEvent('help.pressed')); - openURLInBrowser(this.props._userDocumentationURL); + openURLInBrowser(_userDocumentationURL); } } diff --git a/react/features/toolbox/components/MuteEveryoneButton.js b/react/features/toolbox/components/MuteEveryoneButton.js index 226dfdaf8..a93aec13e 100644 --- a/react/features/toolbox/components/MuteEveryoneButton.js +++ b/react/features/toolbox/components/MuteEveryoneButton.js @@ -39,7 +39,13 @@ class MuteEveryoneButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { dispatch, localParticipantId } = this.props; + const { dispatch, localParticipantId, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('mute.everyone.pressed')); dispatch(openDialog(MuteEveryoneDialog, { diff --git a/react/features/toolbox/components/MuteEveryonesVideoButton.js b/react/features/toolbox/components/MuteEveryonesVideoButton.js index a13f4452c..209b1a6bd 100644 --- a/react/features/toolbox/components/MuteEveryonesVideoButton.js +++ b/react/features/toolbox/components/MuteEveryonesVideoButton.js @@ -39,7 +39,13 @@ class MuteEveryonesVideoButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { dispatch, localParticipantId } = this.props; + const { dispatch, localParticipantId, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } sendAnalytics(createToolbarEvent('mute.everyone.pressed')); dispatch(openDialog(MuteEveryonesVideoDialog, { diff --git a/react/features/toolbox/components/web/AudioSettingsButton.js b/react/features/toolbox/components/web/AudioSettingsButton.js index 3881eeaca..aad64df32 100644 --- a/react/features/toolbox/components/web/AudioSettingsButton.js +++ b/react/features/toolbox/components/web/AudioSettingsButton.js @@ -15,6 +15,11 @@ import AudioMuteButton from '../AudioMuteButton'; type Props = { + /** + * External handler for click action. + */ + handleClick: Function, + /** * Indicates whether audio permissions have been granted or denied. */ @@ -62,6 +67,7 @@ class AudioSettingsButton extends Component { super(props); this._onEscClick = this._onEscClick.bind(this); + this._onClick = this._onClick.bind(this); } _onEscClick: (KeyboardEvent) => void; @@ -76,17 +82,36 @@ class AudioSettingsButton extends Component { if (event.key === 'Escape' && this.props.isOpen) { event.preventDefault(); event.stopPropagation(); - this.props.onAudioOptionsClick(); + this._onClick(); } } + _onClick: () => void; + + /** + * Click handler for the more actions entries. + * + * @returns {void} + */ + _onClick() { + const { handleClick, onAudioOptionsClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + + onAudioOptionsClick(); + } + /** * Implements React's {@link Component#render}. * * @inheritdoc */ render() { - const { hasPermissions, isDisabled, onAudioOptionsClick, visible, isOpen, t } = this.props; + const { handleClick, hasPermissions, isDisabled, visible, isOpen, t } = this.props; const settingsDisabled = !hasPermissions || isDisabled || !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported(); @@ -102,12 +127,12 @@ class AudioSettingsButton extends Component { iconDisabled = { settingsDisabled } iconId = 'audio-settings-button' iconTooltip = { t('toolbar.audioSettings') } - onIconClick = { onAudioOptionsClick } + onIconClick = { this._onClick } onIconKeyDown = { this._onEscClick }> - + - ) : ; + ) : ; } } diff --git a/react/features/toolbox/components/web/FullscreenButton.js b/react/features/toolbox/components/web/FullscreenButton.js index 40e3a7328..6c8547253 100644 --- a/react/features/toolbox/components/web/FullscreenButton.js +++ b/react/features/toolbox/components/web/FullscreenButton.js @@ -11,11 +11,6 @@ type Props = AbstractButtonProps & { * Whether or not the app is currently in full screen. */ _fullScreen: boolean, - - /** - * External handler for click action. - */ - handleClick: Function }; /** @@ -73,7 +68,13 @@ class FullscreenButton extends AbstractButton { * @returns {void} */ _handleClick() { - this.props.handleClick(); + const { handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } } /** diff --git a/react/features/toolbox/components/web/ProfileButton.js b/react/features/toolbox/components/web/ProfileButton.js index 884607e8a..55c0ff463 100644 --- a/react/features/toolbox/components/web/ProfileButton.js +++ b/react/features/toolbox/components/web/ProfileButton.js @@ -87,7 +87,13 @@ class ProfileButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { dispatch, _unclickable } = this.props; + const { dispatch, _unclickable, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } if (!_unclickable) { sendAnalytics(createToolbarEvent('profile')); diff --git a/react/features/toolbox/components/web/RaiseHandButton.js b/react/features/toolbox/components/web/RaiseHandButton.js index a12242417..8a0e4153c 100644 --- a/react/features/toolbox/components/web/RaiseHandButton.js +++ b/react/features/toolbox/components/web/RaiseHandButton.js @@ -12,11 +12,6 @@ type Props = AbstractButtonProps & { * Whether or not the local participant's hand is raised. */ _raisedHand: boolean, - - /** - * External handler for click action. - */ - handleClick: Function }; /** @@ -51,7 +46,13 @@ class RaiseHandButton extends AbstractButton { * @returns {void} */ _handleClick() { - this.props.handleClick(); + const { handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } } /** diff --git a/react/features/toolbox/components/web/ShareDesktopButton.js b/react/features/toolbox/components/web/ShareDesktopButton.js index 163aba926..3208ba454 100644 --- a/react/features/toolbox/components/web/ShareDesktopButton.js +++ b/react/features/toolbox/components/web/ShareDesktopButton.js @@ -29,11 +29,6 @@ type Props = AbstractButtonProps & { * The redux {@code dispatch} function. */ dispatch: Function, - - /** - * External handler for click action. - */ - handleClick: Function }; /** @@ -79,7 +74,13 @@ class ShareDesktopButton extends AbstractButton { * @returns {void} */ _handleClick() { - this.props.handleClick(); + const { handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } } /** diff --git a/react/features/toolbox/components/web/ToggleCameraButton.js b/react/features/toolbox/components/web/ToggleCameraButton.js index 60c2a0792..0abf86c9b 100644 --- a/react/features/toolbox/components/web/ToggleCameraButton.js +++ b/react/features/toolbox/components/web/ToggleCameraButton.js @@ -41,7 +41,15 @@ class ToggleCameraButton extends AbstractButton { * @returns {void} */ _handleClick() { - this.props.dispatch(toggleCamera()); + const { dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + + dispatch(toggleCamera()); } /** diff --git a/react/features/toolbox/components/web/Toolbox.js b/react/features/toolbox/components/web/Toolbox.js index a9fc38d95..725320908 100644 --- a/react/features/toolbox/components/web/Toolbox.js +++ b/react/features/toolbox/components/web/Toolbox.js @@ -103,6 +103,11 @@ type Props = { */ _backgroundType: String, + /** + * Toolbar buttons which have their click exposed through the API. + */ + _buttonsWithNotifyClick: Array, + /** * Whether or not the chat feature is currently displayed. */ @@ -835,6 +840,24 @@ class Toolbox extends Component { }; } + /** + * Overwrites click handlers for buttons in case click is exposed through the iframe API. + * + * @param {Object} buttons - The list of toolbar buttons. + * @returns {void} + */ + _overwriteButtonsClickHandlers(buttons) { + if (typeof APP === 'undefined' || !this.props._buttonsWithNotifyClick?.length) { + return; + } + + Object.values(buttons).forEach((button: any) => { + if (this.props._buttonsWithNotifyClick.includes(button.key)) { + button.handleClick = () => APP.API.notifyToolbarButtonClicked(button.key); + } + }); + } + /** * Returns all buttons that need to be rendered. * @@ -849,6 +872,8 @@ class Toolbox extends Component { const buttons = this._getAllButtons(); + + this._overwriteButtonsClickHandlers(buttons); const isHangupVisible = isToolbarButtonEnabled('hangup', _toolbarButtons); const { order } = THRESHOLDS.find(({ width }) => _clientWidth > width) || THRESHOLDS[THRESHOLDS.length - 1]; @@ -1313,7 +1338,9 @@ function _mapStateToProps(state, ownProps) { let desktopSharingEnabled = JitsiMeetJS.isDesktopSharingEnabled(); const { callStatsID, - enableFeaturesBasedOnToken + disableProfile, + enableFeaturesBasedOnToken, + buttonsWithNotifyClick } = state['features/base/config']; const { fullScreen, @@ -1345,6 +1372,7 @@ function _mapStateToProps(state, ownProps) { return { _backgroundType: state['features/virtual-background'].backgroundType, + _buttonsWithNotifyClick: buttonsWithNotifyClick, _chatOpen: state['features/chat'].isOpen, _clientWidth: clientWidth, _conference: conference, @@ -1353,7 +1381,7 @@ function _mapStateToProps(state, ownProps) { _dialog: Boolean(state['features/base/dialog'].component), _feedbackConfigured: Boolean(callStatsID), _fullScreen: fullScreen, - _isProfileDisabled: Boolean(state['features/base/config'].disableProfile), + _isProfileDisabled: Boolean(disableProfile), _isMobile: isMobileBrowser(), _isVpaasMeeting: isVpaasMeeting(state), _localParticipantID: localParticipant?.id, diff --git a/react/features/toolbox/components/web/VideoSettingsButton.js b/react/features/toolbox/components/web/VideoSettingsButton.js index 13590a03c..5a7e330c8 100644 --- a/react/features/toolbox/components/web/VideoSettingsButton.js +++ b/react/features/toolbox/components/web/VideoSettingsButton.js @@ -16,6 +16,11 @@ import VideoMuteButton from '../VideoMuteButton'; type Props = { + /** + * External handler for click action. + */ + handleClick: Function, + /** * Click handler for the small icon. Opens video options. */ @@ -62,7 +67,7 @@ type Props = { */ class VideoSettingsButton extends Component { /** - * Initializes a new {@code AudioSettingsButton} instance. + * Initializes a new {@code VideoSettingsButton} instance. * * @inheritdoc */ @@ -70,6 +75,7 @@ class VideoSettingsButton extends Component { super(props); this._onEscClick = this._onEscClick.bind(this); + this._onClick = this._onClick.bind(this); } /** @@ -94,17 +100,36 @@ class VideoSettingsButton extends Component { if (event.key === 'Escape' && this.props.isOpen) { event.preventDefault(); event.stopPropagation(); - this.props.onVideoOptionsClick(); + this._onClick(); } } + _onClick: () => void; + + /** + * Click handler for the more actions entries. + * + * @returns {void} + */ + _onClick() { + const { handleClick, onVideoOptionsClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + + onVideoOptionsClick(); + } + /** * Implements React's {@link Component#render}. * * @inheritdoc */ render() { - const { onVideoOptionsClick, t, visible, isOpen } = this.props; + const { handleClick, t, visible, isOpen } = this.props; return visible ? ( @@ -117,12 +142,12 @@ class VideoSettingsButton extends Component { iconDisabled = { this._isIconDisabled() } iconId = 'video-settings-button' iconTooltip = { t('toolbar.videoSettings') } - onIconClick = { onVideoOptionsClick } + onIconClick = { this._onClick } onIconKeyDown = { this._onEscClick }> - + - ) : ; + ) : ; } } diff --git a/react/features/video-layout/components/TileViewButton.js b/react/features/video-layout/components/TileViewButton.js index 243ce289d..1421f8924 100644 --- a/react/features/video-layout/components/TileViewButton.js +++ b/react/features/video-layout/components/TileViewButton.js @@ -51,7 +51,14 @@ class TileViewButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { _tileViewEnabled, dispatch } = this.props; + const { _tileViewEnabled, dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } + const value = !_tileViewEnabled; sendAnalytics(createToolbarEvent( diff --git a/react/features/video-quality/components/VideoQualityButton.web.js b/react/features/video-quality/components/VideoQualityButton.web.js index 87979b99d..85b3b22c1 100644 --- a/react/features/video-quality/components/VideoQualityButton.web.js +++ b/react/features/video-quality/components/VideoQualityButton.web.js @@ -42,11 +42,6 @@ type Props = AbstractButtonProps & { */ _videoQuality: number, - /** - * Callback to invoke when {@link VideoQualityButton} is clicked. - */ - handleClick: Function, - /** * Invoked to obtain translated strings. */ @@ -97,7 +92,13 @@ class VideoQualityButton extends AbstractButton { * @returns {void} */ _handleClick() { - this.props.handleClick(); + const { handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } } } diff --git a/react/features/virtual-background/components/VideoBackgroundButton.js b/react/features/virtual-background/components/VideoBackgroundButton.js index 42d474ca2..923cbd15e 100644 --- a/react/features/virtual-background/components/VideoBackgroundButton.js +++ b/react/features/virtual-background/components/VideoBackgroundButton.js @@ -43,7 +43,13 @@ class VideoBackgroundButton extends AbstractButton { * @returns {void} */ _handleClick() { - const { dispatch } = this.props; + const { dispatch, handleClick } = this.props; + + if (handleClick) { + handleClick(); + + return; + } dispatch(openDialog(VirtualBackgroundDialog)); }