Browse Source

feat(toolbar-button-clicked) Enhance toolbar buttons with notify click

- add possibility to allow execution of the button's routine besides triggering
`toolbarButtonClicked` API event
- keep backwards compatibility
- get rid of `ToolbarButton`
master
Horatiu Muresan 3 years ago
parent
commit
197dbfbbcb
No account linked to committer's email address
48 changed files with 459 additions and 524 deletions
  1. 54
    34
      config.js
  2. 4
    2
      modules/API/API.js
  3. 0
    8
      react/features/base/toolbox/components/AbstractAudioMuteButton.js
  4. 42
    4
      react/features/base/toolbox/components/AbstractButton.js
  5. 0
    8
      react/features/base/toolbox/components/AbstractVideoMuteButton.js
  6. 11
    1
      react/features/base/toolbox/components/ToolboxItem.web.js
  7. 27
    1
      react/features/base/toolbox/components/web/ToolboxButtonWithIcon.js
  8. 0
    16
      react/features/chat/components/web/ChatButton.js
  9. 1
    7
      react/features/embed-meeting/components/EmbedMeetingButton.js
  10. 1
    8
      react/features/etherpad/components/SharedDocumentButton.web.js
  11. 1
    7
      react/features/feedback/components/FeedbackButton.web.js
  12. 1
    7
      react/features/invite/components/add-people-dialog/web/InviteButton.js
  13. 1
    7
      react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.web.js
  14. 1
    7
      react/features/local-recording/components/LocalRecordingButton.web.js
  15. 0
    16
      react/features/participants-pane/components/web/ParticipantsPaneButton.js
  16. 73
    0
      react/features/reactions/components/web/RaiseHandButton.js
  17. 24
    20
      react/features/reactions/components/web/ReactionsMenuButton.js
  18. 1
    7
      react/features/recording/components/LiveStream/AbstractLiveStreamButton.js
  19. 1
    7
      react/features/recording/components/Recording/AbstractRecordButton.js
  20. 1
    7
      react/features/screen-share/components/ShareAudioButton.js
  21. 1
    7
      react/features/security/components/security-dialog/AbstractSecurityDialogButton.js
  22. 36
    1
      react/features/security/components/security-dialog/web/PasswordSection.js
  23. 9
    1
      react/features/security/components/security-dialog/web/SecurityDialog.js
  24. 1
    11
      react/features/settings/components/web/SettingsButton.js
  25. 0
    8
      react/features/shared-video/components/web/SharedVideoButton.js
  26. 1
    7
      react/features/speaker-stats/components/web/SpeakerStatsButton.js
  27. 1
    7
      react/features/subtitles/components/AbstractClosedCaptionButton.js
  28. 2
    2
      react/features/toolbox/components/AudioMuteButton.js
  29. 1
    7
      react/features/toolbox/components/DownloadButton.js
  30. 1
    7
      react/features/toolbox/components/HelpButton.js
  31. 1
    7
      react/features/toolbox/components/MuteEveryoneButton.js
  32. 1
    7
      react/features/toolbox/components/MuteEveryonesVideoButton.js
  33. 2
    2
      react/features/toolbox/components/VideoMuteButton.js
  34. 21
    10
      react/features/toolbox/components/web/AudioSettingsButton.js
  35. 0
    16
      react/features/toolbox/components/web/FullscreenButton.js
  36. 13
    32
      react/features/toolbox/components/web/OverflowMenuButton.js
  37. 73
    0
      react/features/toolbox/components/web/OverflowToggleButton.js
  38. 1
    7
      react/features/toolbox/components/web/ProfileButton.js
  39. 0
    16
      react/features/toolbox/components/web/ShareDesktopButton.js
  40. 1
    7
      react/features/toolbox/components/web/ToggleCameraButton.js
  41. 0
    135
      react/features/toolbox/components/web/ToolbarButton.js
  42. 21
    10
      react/features/toolbox/components/web/Toolbox.js
  43. 21
    10
      react/features/toolbox/components/web/VideoSettingsButton.js
  44. 0
    1
      react/features/toolbox/components/web/index.js
  45. 5
    0
      react/features/toolbox/constants.js
  46. 1
    7
      react/features/video-layout/components/TileViewButton.js
  47. 0
    18
      react/features/video-quality/components/VideoQualityButton.web.js
  48. 1
    7
      react/features/virtual-background/components/VideoBackgroundButton.js

+ 54
- 34
config.js View File

615
     //     alwaysVisible: false
615
     //     alwaysVisible: false
616
     // },
616
     // },
617
 
617
 
618
-    // Toolbar buttons which have their click event exposed through the API on
619
-    // `toolbarButtonClicked` event instead of executing the normal click routine.
618
+    // Toolbar buttons which have their click/tap event exposed through the API on
619
+    // `toolbarButtonClicked`. Passing a string for the button key will
620
+    // prevent execution of the click/tap routine; passing an object with `key` and
621
+    // `preventExecution` flag on false will not prevent execution of the click/tap
622
+    // routine. Below array with mixed mode for passing the buttons.
620
     // buttonsWithNotifyClick: [
623
     // buttonsWithNotifyClick: [
621
-    //    'camera',
622
-    //    'chat',
623
-    //    'closedcaptions',
624
-    //    'desktop',
625
-    //    'download',
626
-    //    'embedmeeting',
627
-    //    'etherpad',
628
-    //    'feedback',
629
-    //    'filmstrip',
630
-    //    'fullscreen',
631
-    //    'hangup',
632
-    //    'help',
633
-    //    'invite',
634
-    //    'livestreaming',
635
-    //    'microphone',
636
-    //    'mute-everyone',
637
-    //    'mute-video-everyone',
638
-    //    'participants-pane',
639
-    //    'profile',
640
-    //    'raisehand',
641
-    //    'recording',
642
-    //    'security',
643
-    //    'select-background',
644
-    //    'settings',
645
-    //    'shareaudio',
646
-    //    'sharedvideo',
647
-    //    'shortcuts',
648
-    //    'stats',
649
-    //    'tileview',
650
-    //    'toggle-camera',
651
-    //    'videoquality',
652
-    //    '__end'
624
+    //     'camera',
625
+    //     {
626
+    //         key: 'chat',
627
+    //         preventExecution: false
628
+    //     },
629
+    //     {
630
+    //         key: 'closedcaptions',
631
+    //         preventExecution: true
632
+    //     },
633
+    //     'desktop',
634
+    //     'download',
635
+    //     'embedmeeting',
636
+    //     'etherpad',
637
+    //     'feedback',
638
+    //     'filmstrip',
639
+    //     'fullscreen',
640
+    //     'hangup',
641
+    //     'help',
642
+    //     {
643
+    //         key: 'invite',
644
+    //         preventExecution: false
645
+    //     },
646
+    //     'livestreaming',
647
+    //     'microphone',
648
+    //     'mute-everyone',
649
+    //     'mute-video-everyone',
650
+    //     'participants-pane',
651
+    //     'profile',
652
+    //     {
653
+    //         key: 'raisehand',
654
+    //         preventExecution: true
655
+    //     },
656
+    //     'recording',
657
+    //     'security',
658
+    //     'select-background',
659
+    //     'settings',
660
+    //     'shareaudio',
661
+    //     'sharedvideo',
662
+    //     'shortcuts',
663
+    //     'stats',
664
+    //     'tileview',
665
+    //     'toggle-camera',
666
+    //     'videoquality',
667
+    //     // The add passcode button from the security dialog.
668
+    //     {
669
+    //         key: 'add-passcode',
670
+    //         preventExecution: false
671
+    //     }
672
+    //     '__end'
653
     // ],
673
     // ],
654
 
674
 
655
     // List of pre meeting screens buttons to hide. The values must be one or more of the 5 allowed buttons:
675
     // List of pre meeting screens buttons to hide. The values must be one or more of the 5 allowed buttons:

+ 4
- 2
modules/API/API.js View File

1521
      * Notify external application ( if API is enabled) that a toolbar button was clicked.
1521
      * Notify external application ( if API is enabled) that a toolbar button was clicked.
1522
      *
1522
      *
1523
      * @param {string} key - The key of the toolbar button.
1523
      * @param {string} key - The key of the toolbar button.
1524
+     * @param {boolean} preventExecution - Whether execution of the button click was prevented or not.
1524
      * @returns {void}
1525
      * @returns {void}
1525
      */
1526
      */
1526
-    notifyToolbarButtonClicked(key: string) {
1527
+    notifyToolbarButtonClicked(key: string, preventExecution: boolean) {
1527
         this._sendEvent({
1528
         this._sendEvent({
1528
             name: 'toolbar-button-clicked',
1529
             name: 'toolbar-button-clicked',
1529
-            key
1530
+            key,
1531
+            preventExecution
1530
         });
1532
         });
1531
     }
1533
     }
1532
 
1534
 

+ 0
- 8
react/features/base/toolbox/components/AbstractAudioMuteButton.js View File

23
      * @returns {void}
23
      * @returns {void}
24
      */
24
      */
25
     _handleClick() {
25
     _handleClick() {
26
-        const { handleClick } = this.props;
27
-
28
-        if (handleClick) {
29
-            handleClick();
30
-
31
-            return;
32
-        }
33
-
34
         this._setAudioMuted(!this._isAudioMuted());
26
         this._setAudioMuted(!this._isAudioMuted());
35
     }
27
     }
36
 
28
 

+ 42
- 4
react/features/base/toolbox/components/AbstractButton.js View File

2
 
2
 
3
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
4
 
4
 
5
+import { NOTIFY_CLICK_MODE } from '../../../toolbox/constants';
5
 import { combineStyles } from '../../styles';
6
 import { combineStyles } from '../../styles';
6
 
7
 
7
 import type { Styles } from './AbstractToolboxItem';
8
 import type { Styles } from './AbstractToolboxItem';
14
      */
15
      */
15
     afterClick: ?Function,
16
     afterClick: ?Function,
16
 
17
 
18
+    /**
19
+     * The button's key.
20
+     */
21
+    buttonKey?: string,
22
+
17
     /**
23
     /**
18
      * Extra styles which will be applied in conjunction with `styles` or
24
      * Extra styles which will be applied in conjunction with `styles` or
19
      * `toggledStyles` when the button is disabled;.
25
      * `toggledStyles` when the button is disabled;.
25
      */
31
      */
26
      handleClick?: Function,
32
      handleClick?: Function,
27
 
33
 
34
+    /**
35
+     * Notify mode for `toolbarButtonClicked` event -
36
+     * whether to only notify or to also prevent button click routine.
37
+     */
38
+    notifyMode?: string,
39
+
28
     /**
40
     /**
29
      * Whether to show the label or not.
41
      * Whether to show the label or not.
30
      */
42
      */
51
     visible: boolean
63
     visible: boolean
52
 };
64
 };
53
 
65
 
66
+declare var APP: Object;
67
+
54
 /**
68
 /**
55
  * Default style for disabled buttons.
69
  * Default style for disabled buttons.
56
  */
70
  */
134
         this._onClick = this._onClick.bind(this);
148
         this._onClick = this._onClick.bind(this);
135
     }
149
     }
136
 
150
 
151
+    /**
152
+     * Helper function to be implemented by subclasses, which should be used
153
+     * to handle a key being down.
154
+     *
155
+     * @protected
156
+     * @returns {void}
157
+     */
158
+    _onKeyDown() {
159
+        // To be implemented by subclass.
160
+    }
161
+
137
     /**
162
     /**
138
      * Helper function to be implemented by subclasses, which should be used
163
      * Helper function to be implemented by subclasses, which should be used
139
      * to handle the button being clicked / pressed.
164
      * to handle the button being clicked / pressed.
248
     _onClick: (*) => void;
273
     _onClick: (*) => void;
249
 
274
 
250
     /**
275
     /**
251
-     * Handles clicking / pressing the button, and toggles the audio mute state
252
-     * accordingly.
276
+     * Handles clicking / pressing the button.
253
      *
277
      *
254
      * @param {Object} e - Event.
278
      * @param {Object} e - Event.
255
      * @private
279
      * @private
256
      * @returns {void}
280
      * @returns {void}
257
      */
281
      */
258
     _onClick(e) {
282
     _onClick(e) {
259
-        const { afterClick } = this.props;
283
+        const { afterClick, handleClick, notifyMode, buttonKey } = this.props;
284
+
285
+        if (typeof APP !== 'undefined' && notifyMode) {
286
+            APP.API.notifyToolbarButtonClicked(
287
+                buttonKey, notifyMode === NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
288
+            );
289
+        }
290
+
291
+        if (notifyMode !== NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY) {
292
+            if (handleClick) {
293
+                handleClick();
294
+            }
295
+
296
+            this._handleClick();
297
+        }
260
 
298
 
261
-        this._handleClick();
262
         afterClick && afterClick(e);
299
         afterClick && afterClick(e);
263
 
300
 
264
         // blur after click to release focus from button to allow PTT.
301
         // blur after click to release focus from button to allow PTT.
288
             <ToolboxItem
325
             <ToolboxItem
289
                 disabled = { this._isDisabled() }
326
                 disabled = { this._isDisabled() }
290
                 onClick = { this._onClick }
327
                 onClick = { this._onClick }
328
+                onKeyDown = { this._onKeyDown }
291
                 { ...props } />
329
                 { ...props } />
292
         );
330
         );
293
     }
331
     }

+ 0
- 8
react/features/base/toolbox/components/AbstractVideoMuteButton.js View File

22
      * @returns {void}
22
      * @returns {void}
23
      */
23
      */
24
     _handleClick() {
24
     _handleClick() {
25
-        const { handleClick } = this.props;
26
-
27
-        if (handleClick) {
28
-            handleClick();
29
-
30
-            return;
31
-        }
32
-
33
         this._setVideoMuted(!this._isVideoMuted());
25
         this._setVideoMuted(!this._isVideoMuted());
34
     }
26
     }
35
 
27
 

+ 11
- 1
react/features/base/toolbox/components/ToolboxItem.web.js View File

6
 import { Tooltip } from '../../tooltip';
6
 import { Tooltip } from '../../tooltip';
7
 
7
 
8
 import AbstractToolboxItem from './AbstractToolboxItem';
8
 import AbstractToolboxItem from './AbstractToolboxItem';
9
-import type { Props } from './AbstractToolboxItem';
9
+import type { Props as AbstractToolboxItemProps } from './AbstractToolboxItem';
10
+
11
+type Props = AbstractToolboxItemProps & {
12
+
13
+    /**
14
+    * On key down handler.
15
+    */
16
+    onKeyDown: Function
17
+};
10
 
18
 
11
 /**
19
 /**
12
  * Web implementation of {@code AbstractToolboxItem}.
20
  * Web implementation of {@code AbstractToolboxItem}.
53
             disabled,
61
             disabled,
54
             elementAfter,
62
             elementAfter,
55
             onClick,
63
             onClick,
64
+            onKeyDown,
56
             showLabel,
65
             showLabel,
57
             tooltipPosition,
66
             tooltipPosition,
58
             toggled
67
             toggled
64
             'aria-label': this.accessibilityLabel,
73
             'aria-label': this.accessibilityLabel,
65
             className: className + (disabled ? ' disabled' : ''),
74
             className: className + (disabled ? ' disabled' : ''),
66
             onClick: disabled ? undefined : onClick,
75
             onClick: disabled ? undefined : onClick,
76
+            onKeyDown: disabled ? undefined : onKeyDown,
67
             onKeyPress: this._onKeyPress,
77
             onKeyPress: this._onKeyPress,
68
             tabIndex: 0,
78
             tabIndex: 0,
69
             role: showLabel ? 'menuitem' : 'button'
79
             role: showLabel ? 'menuitem' : 'button'

+ 27
- 1
react/features/base/toolbox/components/web/ToolboxButtonWithIcon.js View File

2
 
2
 
3
 import React from 'react';
3
 import React from 'react';
4
 
4
 
5
+import { NOTIFY_CLICK_MODE } from '../../../../toolbox/constants';
5
 import { Icon } from '../../../icons';
6
 import { Icon } from '../../../icons';
6
 import { Tooltip } from '../../../tooltip';
7
 import { Tooltip } from '../../../tooltip';
7
 
8
 
8
 type Props = {
9
 type Props = {
9
 
10
 
11
+    /**
12
+     * The button's key.
13
+     */
14
+    buttonKey?: string,
15
+
10
     /**
16
     /**
11
      * The decorated component (ToolboxButton).
17
      * The decorated component (ToolboxButton).
12
      */
18
      */
22
      */
28
      */
23
     iconDisabled: boolean,
29
     iconDisabled: boolean,
24
 
30
 
31
+    /**
32
+     * Notify mode for `toolbarButtonClicked` event -
33
+     * whether to only notify or to also prevent button click routine.
34
+     */
35
+    notifyMode?: string,
36
+
25
     /**
37
     /**
26
      * Click handler for the small icon.
38
      * Click handler for the small icon.
27
      */
39
      */
68
     iconId: string
80
     iconId: string
69
 };
81
 };
70
 
82
 
83
+declare var APP: Object;
84
+
71
 /**
85
 /**
72
  * Displays the `ToolboxButtonWithIcon` component.
86
  * Displays the `ToolboxButtonWithIcon` component.
73
  *
87
  *
80
         icon,
94
         icon,
81
         iconDisabled,
95
         iconDisabled,
82
         iconTooltip,
96
         iconTooltip,
97
+        buttonKey,
98
+        notifyMode,
83
         onIconClick,
99
         onIconClick,
84
         onIconKeyDown,
100
         onIconKeyDown,
85
         styles,
101
         styles,
97
             = 'settings-button-small-icon settings-button-small-icon--disabled';
113
             = 'settings-button-small-icon settings-button-small-icon--disabled';
98
     } else {
114
     } else {
99
         iconProps.className = 'settings-button-small-icon';
115
         iconProps.className = 'settings-button-small-icon';
100
-        iconProps.onClick = onIconClick;
116
+        iconProps.onClick = () => {
117
+            if (typeof APP !== 'undefined' && notifyMode) {
118
+                APP.API.notifyToolbarButtonClicked(
119
+                    buttonKey, notifyMode === NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
120
+                );
121
+            }
122
+
123
+            if (notifyMode !== NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY) {
124
+                onIconClick();
125
+            }
126
+        };
101
         iconProps.onKeyDown = onIconKeyDown;
127
         iconProps.onKeyDown = onIconKeyDown;
102
         iconProps.role = 'button';
128
         iconProps.role = 'button';
103
         iconProps.tabIndex = 0;
129
         iconProps.tabIndex = 0;

+ 0
- 16
react/features/chat/components/web/ChatButton.js View File

49
         // Unused.
49
         // Unused.
50
     }
50
     }
51
 
51
 
52
-    /**
53
-     * Handles clicking / pressing the button, and opens the appropriate dialog.
54
-     *
55
-     * @protected
56
-     * @returns {void}
57
-     */
58
-    _handleClick() {
59
-        const { handleClick } = this.props;
60
-
61
-        if (handleClick) {
62
-            handleClick();
63
-
64
-            return;
65
-        }
66
-    }
67
-
68
     /**
52
     /**
69
      * Indicates whether this button is in toggled state or not.
53
      * Indicates whether this button is in toggled state or not.
70
      *
54
      *

+ 1
- 7
react/features/embed-meeting/components/EmbedMeetingButton.js View File

36
      * @returns {void}
36
      * @returns {void}
37
      */
37
      */
38
     _handleClick() {
38
     _handleClick() {
39
-        const { dispatch, handleClick } = this.props;
40
-
41
-        if (handleClick) {
42
-            handleClick();
43
-
44
-            return;
45
-        }
39
+        const { dispatch } = this.props;
46
 
40
 
47
         sendAnalytics(createToolbarEvent('embed.meeting'));
41
         sendAnalytics(createToolbarEvent('embed.meeting'));
48
         dispatch(openDialog(EmbedMeetingDialog));
42
         dispatch(openDialog(EmbedMeetingDialog));

+ 1
- 8
react/features/etherpad/components/SharedDocumentButton.web.js View File

9
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
9
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
10
 import { toggleDocument } from '../../etherpad/actions';
10
 import { toggleDocument } from '../../etherpad/actions';
11
 
11
 
12
-
13
 type Props = AbstractButtonProps & {
12
 type Props = AbstractButtonProps & {
14
 
13
 
15
     /**
14
     /**
59
      * @returns {void}
58
      * @returns {void}
60
      */
59
      */
61
     _handleClick() {
60
     _handleClick() {
62
-        const { _editing, dispatch, handleClick } = this.props;
63
-
64
-        if (handleClick) {
65
-            handleClick();
66
-
67
-            return;
68
-        }
61
+        const { _editing, dispatch } = this.props;
69
 
62
 
70
         sendAnalytics(createToolbarEvent(
63
         sendAnalytics(createToolbarEvent(
71
             'toggle.etherpad',
64
             'toggle.etherpad',

+ 1
- 7
react/features/feedback/components/FeedbackButton.web.js View File

40
      * @returns {void}
40
      * @returns {void}
41
      */
41
      */
42
     _handleClick() {
42
     _handleClick() {
43
-        const { _conference, dispatch, handleClick } = this.props;
44
-
45
-        if (handleClick) {
46
-            handleClick();
47
-
48
-            return;
49
-        }
43
+        const { _conference, dispatch } = this.props;
50
 
44
 
51
         sendAnalytics(createToolbarEvent('feedback'));
45
         sendAnalytics(createToolbarEvent('feedback'));
52
         dispatch(openFeedbackDialog(_conference));
46
         dispatch(openFeedbackDialog(_conference));

+ 1
- 7
react/features/invite/components/add-people-dialog/web/InviteButton.js View File

34
      * @returns {void}
34
      * @returns {void}
35
      */
35
      */
36
     _handleClick() {
36
     _handleClick() {
37
-        const { dispatch, handleClick } = this.props;
38
-
39
-        if (handleClick) {
40
-            handleClick();
41
-
42
-            return;
43
-        }
37
+        const { dispatch } = this.props;
44
 
38
 
45
         sendAnalytics(createToolbarEvent('invite'));
39
         sendAnalytics(createToolbarEvent('invite'));
46
         dispatch(beginAddPeople());
40
         dispatch(beginAddPeople());

+ 1
- 7
react/features/keyboard-shortcuts/components/KeyboardShortcutsButton.web.js View File

34
      * @returns {void}
34
      * @returns {void}
35
      */
35
      */
36
     _handleClick() {
36
     _handleClick() {
37
-        const { dispatch, handleClick } = this.props;
38
-
39
-        if (handleClick) {
40
-            handleClick();
41
-
42
-            return;
43
-        }
37
+        const { dispatch } = this.props;
44
 
38
 
45
         sendAnalytics(createToolbarEvent('shortcuts'));
39
         sendAnalytics(createToolbarEvent('shortcuts'));
46
         dispatch(openKeyboardShortcutsDialog());
40
         dispatch(openKeyboardShortcutsDialog());

+ 1
- 7
react/features/local-recording/components/LocalRecordingButton.web.js View File

36
      * @returns {void}
36
      * @returns {void}
37
      */
37
      */
38
     _handleClick() {
38
     _handleClick() {
39
-        const { dispatch, handleClick } = this.props;
40
-
41
-        if (handleClick) {
42
-            handleClick();
43
-
44
-            return;
45
-        }
39
+        const { dispatch } = this.props;
46
 
40
 
47
         sendAnalytics(createToolbarEvent('local.recording'));
41
         sendAnalytics(createToolbarEvent('local.recording'));
48
         dispatch(openDialog(LocalRecordingInfoDialog));
42
         dispatch(openDialog(LocalRecordingInfoDialog));

+ 0
- 16
react/features/participants-pane/components/web/ParticipantsPaneButton.js View File

25
     label = 'toolbar.participants';
25
     label = 'toolbar.participants';
26
     tooltip = 'toolbar.participants';
26
     tooltip = 'toolbar.participants';
27
 
27
 
28
-    /**
29
-     * Handles clicking / pressing the button, and opens the appropriate dialog.
30
-     *
31
-     * @protected
32
-     * @returns {void}
33
-     */
34
-    _handleClick() {
35
-        const { handleClick } = this.props;
36
-
37
-        if (handleClick) {
38
-            handleClick();
39
-
40
-            return;
41
-        }
42
-    }
43
-
44
     /**
28
     /**
45
      * Indicates whether this button is in toggled state or not.
29
      * Indicates whether this button is in toggled state or not.
46
      *
30
      *

+ 73
- 0
react/features/reactions/components/web/RaiseHandButton.js View File

1
+// @flow
2
+
3
+import { translate } from '../../../base/i18n';
4
+import { IconRaisedHand } from '../../../base/icons';
5
+import { getLocalParticipant, hasRaisedHand } from '../../../base/participants';
6
+import { connect } from '../../../base/redux';
7
+import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
8
+
9
+
10
+/**
11
+ * The type of the React {@code Component} props of {@link RaiseHandButton}.
12
+ */
13
+type Props = AbstractButtonProps & {
14
+
15
+    /**
16
+     * Whether or not the hand is raised.
17
+     */
18
+     raisedHand: boolean,
19
+};
20
+
21
+/**
22
+ * Implementation of a button for raising hand.
23
+ */
24
+class RaiseHandButton extends AbstractButton<Props, *> {
25
+    accessibilityLabel = 'toolbar.accessibilityLabel.raiseHand';
26
+    icon = IconRaisedHand;
27
+    label = 'toolbar.raiseHand';
28
+    toggledLabel = 'toolbar.raiseHand';
29
+
30
+    /**
31
+     * Retrieves tooltip dynamically.
32
+     */
33
+    get tooltip() {
34
+        return 'toolbar.raiseHand';
35
+    }
36
+
37
+    /**
38
+     * Required by linter due to AbstractButton overwritten prop being writable.
39
+     *
40
+     * @param {string} _value - The value.
41
+     */
42
+    set tooltip(_value) {
43
+        // Unused.
44
+    }
45
+
46
+    /**
47
+     * Indicates whether this button is in toggled state or not.
48
+     *
49
+     * @override
50
+     * @protected
51
+     * @returns {boolean}
52
+     */
53
+    _isToggled() {
54
+        return this.props.raisedHand;
55
+    }
56
+}
57
+
58
+
59
+/**
60
+ * Function that maps parts of Redux state tree into component props.
61
+ *
62
+ * @param {Object} state - Redux state.
63
+ * @returns {Object}
64
+ */
65
+const mapStateToProps = state => {
66
+    const localParticipant = getLocalParticipant(state);
67
+
68
+    return {
69
+        raisedHand: hasRaisedHand(localParticipant)
70
+    };
71
+};
72
+
73
+export default translate(connect(mapStateToProps)(RaiseHandButton));

+ 24
- 20
react/features/reactions/components/web/ReactionsMenuButton.js View File

4
 
4
 
5
 import { isMobileBrowser } from '../../../base/environment/utils';
5
 import { isMobileBrowser } from '../../../base/environment/utils';
6
 import { translate } from '../../../base/i18n';
6
 import { translate } from '../../../base/i18n';
7
-import { IconArrowUp, IconRaisedHand } from '../../../base/icons';
8
-import { getLocalParticipant, hasRaisedHand } from '../../../base/participants';
7
+import { IconArrowUp } from '../../../base/icons';
9
 import { connect } from '../../../base/redux';
8
 import { connect } from '../../../base/redux';
10
 import { ToolboxButtonWithIcon } from '../../../base/toolbox/components';
9
 import { ToolboxButtonWithIcon } from '../../../base/toolbox/components';
11
-import ToolbarButton from '../../../toolbox/components/web/ToolbarButton';
12
 import { toggleReactionsMenuVisibility } from '../../actions.web';
10
 import { toggleReactionsMenuVisibility } from '../../actions.web';
13
 import { type ReactionEmojiProps } from '../../constants';
11
 import { type ReactionEmojiProps } from '../../constants';
14
 import { getReactionsQueue, isReactionsEnabled } from '../../functions.any';
12
 import { getReactionsQueue, isReactionsEnabled } from '../../functions.any';
15
 import { getReactionsMenuVisibility } from '../../functions.web';
13
 import { getReactionsMenuVisibility } from '../../functions.web';
16
 
14
 
15
+import RaiseHandButton from './RaiseHandButton';
17
 import ReactionEmoji from './ReactionEmoji';
16
 import ReactionEmoji from './ReactionEmoji';
18
 import ReactionsMenuPopup from './ReactionsMenuPopup';
17
 import ReactionsMenuPopup from './ReactionsMenuPopup';
19
 
18
 
24
      */
23
      */
25
     _reactionsEnabled: Boolean,
24
     _reactionsEnabled: Boolean,
26
 
25
 
26
+    /**
27
+     * The button's key.
28
+     */
29
+     buttonKey?: string,
30
+
27
     /**
31
     /**
28
      * Redux dispatch function.
32
      * Redux dispatch function.
29
      */
33
      */
45
     isMobile: boolean,
49
     isMobile: boolean,
46
 
50
 
47
     /**
51
     /**
48
-     * Whether or not the local participant's hand is raised.
52
+     * Notify mode for `toolbarButtonClicked` event -
53
+     * whether to only notify or to also prevent button click routine.
49
      */
54
      */
50
-    raisedHand: boolean,
55
+    notifyMode?: string,
51
 
56
 
52
     /**
57
     /**
53
      * The array of reactions to be displayed.
58
      * The array of reactions to be displayed.
70
  */
75
  */
71
 function ReactionsMenuButton({
76
 function ReactionsMenuButton({
72
     _reactionsEnabled,
77
     _reactionsEnabled,
78
+    buttonKey,
73
     dispatch,
79
     dispatch,
74
     handleClick,
80
     handleClick,
75
     isOpen,
81
     isOpen,
76
     isMobile,
82
     isMobile,
77
-    raisedHand,
83
+    notifyMode,
78
     reactionsQueue,
84
     reactionsQueue,
79
     t
85
     t
80
 }: Props) {
86
 }: Props) {
82
         dispatch(toggleReactionsMenuVisibility());
88
         dispatch(toggleReactionsMenuVisibility());
83
     }, [ dispatch ]);
89
     }, [ dispatch ]);
84
 
90
 
85
-    const raiseHandButton = (<ToolbarButton
86
-        accessibilityLabel = { t('toolbar.accessibilityLabel.raiseHand') }
87
-        icon = { IconRaisedHand }
88
-        key = 'raise-hand'
89
-        onClick = { handleClick }
90
-        toggled = { raisedHand }
91
-        tooltip = { t('toolbar.raiseHand') } />);
92
-
93
     return (
91
     return (
94
         <div className = 'reactions-menu-popup-container'>
92
         <div className = 'reactions-menu-popup-container'>
95
             <ReactionsMenuPopup>
93
             <ReactionsMenuPopup>
96
-                {!_reactionsEnabled || isMobile ? raiseHandButton
94
+                {!_reactionsEnabled || isMobile ? (
95
+                    <RaiseHandButton
96
+                        buttonKey = { buttonKey }
97
+                        handleClick = { handleClick }
98
+                        notifyMode = { notifyMode } />)
97
                     : (
99
                     : (
98
                         <ToolboxButtonWithIcon
100
                         <ToolboxButtonWithIcon
99
                             ariaControls = 'reactions-menu-dialog'
101
                             ariaControls = 'reactions-menu-dialog'
100
                             ariaExpanded = { isOpen }
102
                             ariaExpanded = { isOpen }
101
                             ariaHasPopup = { true }
103
                             ariaHasPopup = { true }
102
                             ariaLabel = { t('toolbar.accessibilityLabel.reactionsMenu') }
104
                             ariaLabel = { t('toolbar.accessibilityLabel.reactionsMenu') }
105
+                            buttonKey = { buttonKey }
103
                             icon = { IconArrowUp }
106
                             icon = { IconArrowUp }
104
                             iconDisabled = { false }
107
                             iconDisabled = { false }
105
                             iconId = 'reactions-menu-button'
108
                             iconId = 'reactions-menu-button'
106
                             iconTooltip = { t(`toolbar.${isOpen ? 'closeReactionsMenu' : 'openReactionsMenu'}`) }
109
                             iconTooltip = { t(`toolbar.${isOpen ? 'closeReactionsMenu' : 'openReactionsMenu'}`) }
110
+                            notifyMode = { notifyMode }
107
                             onIconClick = { toggleReactionsMenu }>
111
                             onIconClick = { toggleReactionsMenu }>
108
-                            {raiseHandButton}
112
+                            <RaiseHandButton
113
+                                buttonKey = { buttonKey }
114
+                                handleClick = { handleClick }
115
+                                notifyMode = { notifyMode } />
109
                         </ToolboxButtonWithIcon>
116
                         </ToolboxButtonWithIcon>
110
                     )}
117
                     )}
111
             </ReactionsMenuPopup>
118
             </ReactionsMenuPopup>
125
  * @returns {Object}
132
  * @returns {Object}
126
  */
133
  */
127
 function mapStateToProps(state) {
134
 function mapStateToProps(state) {
128
-    const localParticipant = getLocalParticipant(state);
129
-
130
     return {
135
     return {
131
         _reactionsEnabled: isReactionsEnabled(state),
136
         _reactionsEnabled: isReactionsEnabled(state),
132
         isOpen: getReactionsMenuVisibility(state),
137
         isOpen: getReactionsMenuVisibility(state),
133
         isMobile: isMobileBrowser(),
138
         isMobile: isMobileBrowser(),
134
-        reactionsQueue: getReactionsQueue(state),
135
-        raisedHand: hasRaisedHand(localParticipant)
139
+        reactionsQueue: getReactionsQueue(state)
136
     };
140
     };
137
 }
141
 }
138
 
142
 

+ 1
- 7
react/features/recording/components/LiveStream/AbstractLiveStreamButton.js View File

77
      * @returns {void}
77
      * @returns {void}
78
      */
78
      */
79
     async _handleClick() {
79
     async _handleClick() {
80
-        const { _isLiveStreamRunning, dispatch, handleClick } = this.props;
81
-
82
-        if (handleClick) {
83
-            handleClick();
84
-
85
-            return;
86
-        }
80
+        const { _isLiveStreamRunning, dispatch } = this.props;
87
 
81
 
88
         const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
82
         const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
89
 
83
 

+ 1
- 7
react/features/recording/components/Recording/AbstractRecordButton.js View File

78
      * @returns {void}
78
      * @returns {void}
79
      */
79
      */
80
     async _handleClick() {
80
     async _handleClick() {
81
-        const { _isRecordingRunning, dispatch, handleClick } = this.props;
82
-
83
-        if (handleClick) {
84
-            handleClick();
85
-
86
-            return;
87
-        }
81
+        const { _isRecordingRunning, dispatch } = this.props;
88
 
82
 
89
         sendAnalytics(createToolbarEvent(
83
         sendAnalytics(createToolbarEvent(
90
             'recording.button',
84
             'recording.button',

+ 1
- 7
react/features/screen-share/components/ShareAudioButton.js View File

47
      * @returns {void}
47
      * @returns {void}
48
      */
48
      */
49
     _handleClick() {
49
     _handleClick() {
50
-        const { dispatch, handleClick } = this.props;
51
-
52
-        if (handleClick) {
53
-            handleClick();
54
-
55
-            return;
56
-        }
50
+        const { dispatch } = this.props;
57
 
51
 
58
         dispatch(startAudioScreenShareFlow());
52
         dispatch(startAudioScreenShareFlow());
59
         dispatch(setOverflowMenuVisible(false));
53
         dispatch(setOverflowMenuVisible(false));

+ 1
- 7
react/features/security/components/security-dialog/AbstractSecurityDialogButton.js View File

56
      * @returns {void}
56
      * @returns {void}
57
      */
57
      */
58
     _handleClick() {
58
     _handleClick() {
59
-        const { _locked, handleClick } = this.props;
60
-
61
-        if (handleClick) {
62
-            handleClick();
63
-
64
-            return;
65
-        }
59
+        const { _locked } = this.props;
66
 
60
 
67
         sendAnalytics(createToolbarEvent('toggle.security', { enable: !_locked }));
61
         sendAnalytics(createToolbarEvent('toggle.security', { enable: !_locked }));
68
         this._handleClickSecurityButton();
62
         this._handleClickSecurityButton();

+ 36
- 1
react/features/security/components/security-dialog/web/PasswordSection.js View File

6
 
6
 
7
 import { translate } from '../../../../base/i18n';
7
 import { translate } from '../../../../base/i18n';
8
 import { copyText } from '../../../../base/util';
8
 import { copyText } from '../../../../base/util';
9
+import { NOTIFY_CLICK_MODE } from '../../../../toolbox/constants';
9
 
10
 
10
 import PasswordForm from './PasswordForm';
11
 import PasswordForm from './PasswordForm';
11
 
12
 
13
+const KEY = 'add-passcode';
14
+
12
 type Props = {
15
 type Props = {
13
 
16
 
17
+    /**
18
+     * Toolbar buttons which have their click exposed through the API.
19
+     */
20
+     buttonsWithNotifyClick: Array<string | Object>,
21
+
14
     /**
22
     /**
15
      * Whether or not the current user can modify the current password.
23
      * Whether or not the current user can modify the current password.
16
      */
24
      */
59
     t: Function
67
     t: Function
60
 };
68
 };
61
 
69
 
70
+declare var APP: Object;
71
+
62
 /**
72
 /**
63
  * Component that handles the password manipulation from the invite dialog.
73
  * Component that handles the password manipulation from the invite dialog.
64
  *
74
  *
65
  * @returns {React$Element<any>}
75
  * @returns {React$Element<any>}
66
  */
76
  */
67
 function PasswordSection({
77
 function PasswordSection({
78
+    buttonsWithNotifyClick,
68
     canEditPassword,
79
     canEditPassword,
69
     conference,
80
     conference,
70
     locked,
81
     locked,
97
      * @returns {void}
108
      * @returns {void}
98
      */
109
      */
99
     function onTogglePasswordEditState() {
110
     function onTogglePasswordEditState() {
100
-        setPasswordEditEnabled(!passwordEditEnabled);
111
+        if (typeof APP === 'undefined' || !buttonsWithNotifyClick?.length) {
112
+            setPasswordEditEnabled(!passwordEditEnabled);
113
+
114
+            return;
115
+        }
116
+
117
+        let notifyMode;
118
+        const notify = buttonsWithNotifyClick.find(
119
+            (btn: string | Object) =>
120
+                (typeof btn === 'string' && btn === KEY)
121
+                || (typeof btn === 'object' && btn.key === KEY)
122
+        );
123
+
124
+        if (notify) {
125
+            notifyMode = typeof notify === 'string' || notify.preventExecution
126
+                ? NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
127
+                : NOTIFY_CLICK_MODE.ONLY_NOTIFY;
128
+            APP.API.notifyToolbarButtonClicked(
129
+                KEY, notifyMode === NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
130
+            );
131
+        }
132
+
133
+        if (notifyMode === NOTIFY_CLICK_MODE.ONLY_NOTIFY) {
134
+            setPasswordEditEnabled(!passwordEditEnabled);
135
+        }
101
     }
136
     }
102
 
137
 
103
     /**
138
     /**

+ 9
- 1
react/features/security/components/security-dialog/web/SecurityDialog.js View File

13
 
13
 
14
 type Props = {
14
 type Props = {
15
 
15
 
16
+    /**
17
+     * Toolbar buttons which have their click exposed through the API.
18
+     */
19
+     _buttonsWithNotifyClick: Array<string | Object>,
20
+
16
     /**
21
     /**
17
      * Whether or not the current user can modify the current password.
22
      * Whether or not the current user can modify the current password.
18
      */
23
      */
57
  * @returns {React$Element<any>}
62
  * @returns {React$Element<any>}
58
  */
63
  */
59
 function SecurityDialog({
64
 function SecurityDialog({
65
+    _buttonsWithNotifyClick,
60
     _canEditPassword,
66
     _canEditPassword,
61
     _conference,
67
     _conference,
62
     _locked,
68
     _locked,
82
             <div className = 'security-dialog'>
88
             <div className = 'security-dialog'>
83
                 <LobbySection />
89
                 <LobbySection />
84
                 <PasswordSection
90
                 <PasswordSection
91
+                    buttonsWithNotifyClick = { _buttonsWithNotifyClick }
85
                     canEditPassword = { _canEditPassword }
92
                     canEditPassword = { _canEditPassword }
86
                     conference = { _conference }
93
                     conference = { _conference }
87
                     locked = { _locked }
94
                     locked = { _locked }
117
         locked,
124
         locked,
118
         password
125
         password
119
     } = state['features/base/conference'];
126
     } = state['features/base/conference'];
120
-    const { roomPasswordNumberOfDigits } = state['features/base/config'];
127
+    const { roomPasswordNumberOfDigits, buttonsWithNotifyClick } = state['features/base/config'];
121
 
128
 
122
     const showE2ee = Boolean(e2eeSupported) && isLocalParticipantModerator(state);
129
     const showE2ee = Boolean(e2eeSupported) && isLocalParticipantModerator(state);
123
 
130
 
124
     return {
131
     return {
132
+        _buttonsWithNotifyClick: buttonsWithNotifyClick,
125
         _canEditPassword: isLocalParticipantModerator(state),
133
         _canEditPassword: isLocalParticipantModerator(state),
126
         _conference: conference,
134
         _conference: conference,
127
         _dialIn: state['features/invite'],
135
         _dialIn: state['features/invite'],

+ 1
- 11
react/features/settings/components/web/SettingsButton.js View File

40
      * @returns {void}
40
      * @returns {void}
41
      */
41
      */
42
     _handleClick() {
42
     _handleClick() {
43
-        const {
44
-            defaultTab = SETTINGS_TABS.DEVICES,
45
-            dispatch,
46
-            handleClick
47
-        } = this.props;
48
-
49
-        if (handleClick) {
50
-            handleClick();
51
-
52
-            return;
53
-        }
43
+        const { defaultTab = SETTINGS_TABS.DEVICES, dispatch } = this.props;
54
 
44
 
55
         sendAnalytics(createToolbarEvent('settings'));
45
         sendAnalytics(createToolbarEvent('settings'));
56
         dispatch(openSettingsDialog(defaultTab));
46
         dispatch(openSettingsDialog(defaultTab));

+ 0
- 8
react/features/shared-video/components/web/SharedVideoButton.js View File

66
      * @returns {void}
66
      * @returns {void}
67
      */
67
      */
68
     _handleClick() {
68
     _handleClick() {
69
-        const { handleClick } = this.props;
70
-
71
-        if (handleClick) {
72
-            handleClick();
73
-
74
-            return;
75
-        }
76
-
77
         this._doToggleSharedVideo();
69
         this._doToggleSharedVideo();
78
     }
70
     }
79
 
71
 

+ 1
- 7
react/features/speaker-stats/components/web/SpeakerStatsButton.js View File

20
      * @returns {void}
20
      * @returns {void}
21
      */
21
      */
22
     _handleClick() {
22
     _handleClick() {
23
-        const { dispatch, handleClick } = this.props;
24
-
25
-        if (handleClick) {
26
-            handleClick();
27
-
28
-            return;
29
-        }
23
+        const { dispatch } = this.props;
30
 
24
 
31
         sendAnalytics(createToolbarEvent('speaker.stats'));
25
         sendAnalytics(createToolbarEvent('speaker.stats'));
32
         dispatch(openDialog(SpeakerStats));
26
         dispatch(openDialog(SpeakerStats));

+ 1
- 7
react/features/subtitles/components/AbstractClosedCaptionButton.js View File

38
      * @returns {void}
38
      * @returns {void}
39
      */
39
      */
40
     async _handleClick() {
40
     async _handleClick() {
41
-        const { _requestingSubtitles, dispatch, handleClick } = this.props;
42
-
43
-        if (handleClick) {
44
-            handleClick();
45
-
46
-            return;
47
-        }
41
+        const { _requestingSubtitles, dispatch } = this.props;
48
 
42
 
49
         sendAnalytics(createToolbarEvent('transcribing.ccButton',
43
         sendAnalytics(createToolbarEvent('transcribing.ccButton',
50
             {
44
             {

+ 2
- 2
react/features/toolbox/components/AudioMuteButton.js View File

10
 import { translate } from '../../base/i18n';
10
 import { translate } from '../../base/i18n';
11
 import { MEDIA_TYPE } from '../../base/media';
11
 import { MEDIA_TYPE } from '../../base/media';
12
 import { connect } from '../../base/redux';
12
 import { connect } from '../../base/redux';
13
-import { AbstractAudioMuteButton } from '../../base/toolbox/components';
13
+import { AbstractAudioMuteButton, AbstractButton } from '../../base/toolbox/components';
14
 import type { AbstractButtonProps } from '../../base/toolbox/components';
14
 import type { AbstractButtonProps } from '../../base/toolbox/components';
15
 import { isLocalTrackMuted } from '../../base/tracks';
15
 import { isLocalTrackMuted } from '../../base/tracks';
16
 import { muteLocal } from '../../video-menu/actions';
16
 import { muteLocal } from '../../video-menu/actions';
120
                 ACTION_SHORTCUT_TRIGGERED,
120
                 ACTION_SHORTCUT_TRIGGERED,
121
                 { enable: !this._isAudioMuted() }));
121
                 { enable: !this._isAudioMuted() }));
122
 
122
 
123
-        super._handleClick();
123
+        AbstractButton.prototype._onClick.call(this);
124
     }
124
     }
125
 
125
 
126
     /**
126
     /**

+ 1
- 7
react/features/toolbox/components/DownloadButton.js View File

32
      * @returns {void}
32
      * @returns {void}
33
      */
33
      */
34
     _handleClick() {
34
     _handleClick() {
35
-        const { _downloadAppsUrl, handleClick } = this.props;
36
-
37
-        if (handleClick) {
38
-            handleClick();
39
-
40
-            return;
41
-        }
35
+        const { _downloadAppsUrl } = this.props;
42
 
36
 
43
         sendAnalytics(createToolbarEvent('download.pressed'));
37
         sendAnalytics(createToolbarEvent('download.pressed'));
44
         openURLInBrowser(_downloadAppsUrl);
38
         openURLInBrowser(_downloadAppsUrl);

+ 1
- 7
react/features/toolbox/components/HelpButton.js View File

33
      * @returns {void}
33
      * @returns {void}
34
      */
34
      */
35
     _handleClick() {
35
     _handleClick() {
36
-        const { _userDocumentationURL, handleClick } = this.props;
37
-
38
-        if (handleClick) {
39
-            handleClick();
40
-
41
-            return;
42
-        }
36
+        const { _userDocumentationURL } = this.props;
43
 
37
 
44
         sendAnalytics(createToolbarEvent('help.pressed'));
38
         sendAnalytics(createToolbarEvent('help.pressed'));
45
         openURLInBrowser(_userDocumentationURL);
39
         openURLInBrowser(_userDocumentationURL);

+ 1
- 7
react/features/toolbox/components/MuteEveryoneButton.js View File

39
      * @returns {void}
39
      * @returns {void}
40
      */
40
      */
41
     _handleClick() {
41
     _handleClick() {
42
-        const { dispatch, localParticipantId, handleClick } = this.props;
43
-
44
-        if (handleClick) {
45
-            handleClick();
46
-
47
-            return;
48
-        }
42
+        const { dispatch, localParticipantId } = this.props;
49
 
43
 
50
         sendAnalytics(createToolbarEvent('mute.everyone.pressed'));
44
         sendAnalytics(createToolbarEvent('mute.everyone.pressed'));
51
         dispatch(openDialog(MuteEveryoneDialog, {
45
         dispatch(openDialog(MuteEveryoneDialog, {

+ 1
- 7
react/features/toolbox/components/MuteEveryonesVideoButton.js View File

39
      * @returns {void}
39
      * @returns {void}
40
      */
40
      */
41
     _handleClick() {
41
     _handleClick() {
42
-        const { dispatch, localParticipantId, handleClick } = this.props;
43
-
44
-        if (handleClick) {
45
-            handleClick();
46
-
47
-            return;
48
-        }
42
+        const { dispatch, localParticipantId } = this.props;
49
 
43
 
50
         sendAnalytics(createToolbarEvent('mute.everyone.pressed'));
44
         sendAnalytics(createToolbarEvent('mute.everyone.pressed'));
51
         dispatch(openDialog(MuteEveryonesVideoDialog, {
45
         dispatch(openDialog(MuteEveryonesVideoDialog, {

+ 2
- 2
react/features/toolbox/components/VideoMuteButton.js View File

16
     setVideoMuted
16
     setVideoMuted
17
 } from '../../base/media';
17
 } from '../../base/media';
18
 import { connect } from '../../base/redux';
18
 import { connect } from '../../base/redux';
19
-import { AbstractVideoMuteButton } from '../../base/toolbox/components';
19
+import { AbstractButton, AbstractVideoMuteButton } from '../../base/toolbox/components';
20
 import type { AbstractButtonProps } from '../../base/toolbox/components';
20
 import type { AbstractButtonProps } from '../../base/toolbox/components';
21
 import { getLocalVideoType, isLocalCameraTrackMuted } from '../../base/tracks';
21
 import { getLocalVideoType, isLocalCameraTrackMuted } from '../../base/tracks';
22
 import { isVideoMuteButtonDisabled } from '../functions';
22
 import { isVideoMuteButtonDisabled } from '../functions';
146
                 ACTION_SHORTCUT_TRIGGERED,
146
                 ACTION_SHORTCUT_TRIGGERED,
147
                 { enable: !this._isVideoMuted() }));
147
                 { enable: !this._isVideoMuted() }));
148
 
148
 
149
-        super._handleClick();
149
+        AbstractButton.prototype._onClick.call(this);
150
     }
150
     }
151
 
151
 
152
     /**
152
     /**

+ 21
- 10
react/features/toolbox/components/web/AudioSettingsButton.js View File

15
 
15
 
16
 type Props = {
16
 type Props = {
17
 
17
 
18
+    /**
19
+     * The button's key.
20
+     */
21
+     buttonKey?: string,
22
+
18
     /**
23
     /**
19
      * External handler for click action.
24
      * External handler for click action.
20
      */
25
      */
35
      */
40
      */
36
     isDisabled: boolean,
41
     isDisabled: boolean,
37
 
42
 
43
+    /**
44
+     * Notify mode for `toolbarButtonClicked` event -
45
+     * whether to only notify or to also prevent button click routine.
46
+     */
47
+    notifyMode?: string,
48
+
38
     /**
49
     /**
39
      * Used for translation.
50
      * Used for translation.
40
      */
51
      */
94
      * @returns {void}
105
      * @returns {void}
95
      */
106
      */
96
     _onClick() {
107
     _onClick() {
97
-        const { handleClick, onAudioOptionsClick } = this.props;
98
-
99
-        if (handleClick) {
100
-            handleClick();
101
-
102
-            return;
103
-        }
108
+        const { onAudioOptionsClick } = this.props;
104
 
109
 
105
         onAudioOptionsClick();
110
         onAudioOptionsClick();
106
     }
111
     }
111
      * @inheritdoc
116
      * @inheritdoc
112
      */
117
      */
113
     render() {
118
     render() {
114
-        const { handleClick, hasPermissions, isDisabled, visible, isOpen, t } = this.props;
119
+        const { hasPermissions, isDisabled, visible, isOpen, buttonKey, notifyMode, t } = this.props;
115
         const settingsDisabled = !hasPermissions
120
         const settingsDisabled = !hasPermissions
116
             || isDisabled
121
             || isDisabled
117
             || !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported();
122
             || !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported();
123
                     ariaExpanded = { isOpen }
128
                     ariaExpanded = { isOpen }
124
                     ariaHasPopup = { true }
129
                     ariaHasPopup = { true }
125
                     ariaLabel = { t('toolbar.audioSettings') }
130
                     ariaLabel = { t('toolbar.audioSettings') }
131
+                    buttonKey = { buttonKey }
126
                     icon = { IconArrowUp }
132
                     icon = { IconArrowUp }
127
                     iconDisabled = { settingsDisabled }
133
                     iconDisabled = { settingsDisabled }
128
                     iconId = 'audio-settings-button'
134
                     iconId = 'audio-settings-button'
129
                     iconTooltip = { t('toolbar.audioSettings') }
135
                     iconTooltip = { t('toolbar.audioSettings') }
136
+                    notifyMode = { notifyMode }
130
                     onIconClick = { this._onClick }
137
                     onIconClick = { this._onClick }
131
                     onIconKeyDown = { this._onEscClick }>
138
                     onIconKeyDown = { this._onEscClick }>
132
-                    <AudioMuteButton handleClick = { handleClick } />
139
+                    <AudioMuteButton
140
+                        buttonKey = { buttonKey }
141
+                        notifyMode = { notifyMode } />
133
                 </ToolboxButtonWithIcon>
142
                 </ToolboxButtonWithIcon>
134
             </AudioSettingsPopup>
143
             </AudioSettingsPopup>
135
-        ) : <AudioMuteButton handleClick = { handleClick } />;
144
+        ) : <AudioMuteButton
145
+            buttonKey = { buttonKey }
146
+            notifyMode = { notifyMode } />;
136
     }
147
     }
137
 }
148
 }
138
 
149
 

+ 0
- 16
react/features/toolbox/components/web/FullscreenButton.js View File

61
         // Unused.
61
         // Unused.
62
     }
62
     }
63
 
63
 
64
-    /**
65
-     * Handles clicking / pressing the button, and opens the appropriate dialog.
66
-     *
67
-     * @protected
68
-     * @returns {void}
69
-     */
70
-    _handleClick() {
71
-        const { handleClick } = this.props;
72
-
73
-        if (handleClick) {
74
-            handleClick();
75
-
76
-            return;
77
-        }
78
-    }
79
-
80
     /**
64
     /**
81
      * Indicates whether this button is in toggled state or not.
65
      * Indicates whether this button is in toggled state or not.
82
      *
66
      *

+ 13
- 32
react/features/toolbox/components/web/OverflowMenuButton.js View File

5
 
5
 
6
 import { createToolbarEvent, sendAnalytics } from '../../../analytics';
6
 import { createToolbarEvent, sendAnalytics } from '../../../analytics';
7
 import { translate } from '../../../base/i18n';
7
 import { translate } from '../../../base/i18n';
8
-import { IconHorizontalPoints } from '../../../base/icons';
9
 import { connect } from '../../../base/redux';
8
 import { connect } from '../../../base/redux';
10
 import { ReactionEmoji, ReactionsMenu } from '../../../reactions/components';
9
 import { ReactionEmoji, ReactionsMenu } from '../../../reactions/components';
11
 import { type ReactionEmojiProps } from '../../../reactions/constants';
10
 import { type ReactionEmojiProps } from '../../../reactions/constants';
13
 
12
 
14
 import Drawer from './Drawer';
13
 import Drawer from './Drawer';
15
 import JitsiPortal from './JitsiPortal';
14
 import JitsiPortal from './JitsiPortal';
16
-import ToolbarButton from './ToolbarButton';
15
+import OverflowToggleButton from './OverflowToggleButton';
17
 
16
 
18
 /**
17
 /**
19
  * The type of the React {@code Component} props of {@link OverflowMenuButton}.
18
  * The type of the React {@code Component} props of {@link OverflowMenuButton}.
78
 
77
 
79
         // Bind event handlers so they are only bound once per instance.
78
         // Bind event handlers so they are only bound once per instance.
80
         this._onCloseDialog = this._onCloseDialog.bind(this);
79
         this._onCloseDialog = this._onCloseDialog.bind(this);
81
-        this._onToggleDialogVisibility
82
-            = this._onToggleDialogVisibility.bind(this);
80
+        this._toggleDialogVisibility
81
+            = this._toggleDialogVisibility.bind(this);
83
         this._onEscClick = this._onEscClick.bind(this);
82
         this._onEscClick = this._onEscClick.bind(this);
84
     }
83
     }
85
 
84
 
113
                 {
112
                 {
114
                     overflowDrawer ? (
113
                     overflowDrawer ? (
115
                         <>
114
                         <>
116
-                            {this._renderToolbarButton()}
115
+                            <OverflowToggleButton
116
+                                handleClick = { this._toggleDialogVisibility }
117
+                                isOpen = { isOpen }
118
+                                onKeyDown = { this._onEscClick } />
117
                             <JitsiPortal>
119
                             <JitsiPortal>
118
                                 <Drawer
120
                                 <Drawer
119
                                     isOpen = { isOpen }
121
                                     isOpen = { isOpen }
136
                             isOpen = { isOpen }
138
                             isOpen = { isOpen }
137
                             onClose = { this._onCloseDialog }
139
                             onClose = { this._onCloseDialog }
138
                             placement = 'top-end'>
140
                             placement = 'top-end'>
139
-                            {this._renderToolbarButton()}
141
+                            <OverflowToggleButton
142
+                                handleClick = { this._toggleDialogVisibility }
143
+                                isOpen = { isOpen }
144
+                                onKeyDown = { this._onEscClick } />
140
                         </InlineDialog>
145
                         </InlineDialog>
141
                     )
146
                     )
142
                 }
147
                 }
144
         );
149
         );
145
     }
150
     }
146
 
151
 
147
-    _renderToolbarButton: () => React$Node;
148
-
149
-    /**
150
-     * Renders the actual toolbar overflow menu button.
151
-     *
152
-     * @returns {ReactElement}
153
-     */
154
-    _renderToolbarButton() {
155
-        const { ariaControls, isOpen, t } = this.props;
156
-
157
-        return (
158
-            <ToolbarButton
159
-                accessibilityLabel =
160
-                    { t('toolbar.accessibilityLabel.moreActions') }
161
-                aria-controls = { ariaControls }
162
-                aria-haspopup = 'true'
163
-                icon = { IconHorizontalPoints }
164
-                onClick = { this._onToggleDialogVisibility }
165
-                onKeyDown = { this._onEscClick }
166
-                toggled = { isOpen }
167
-                tooltip = { t('toolbar.moreActions') } />
168
-        );
169
-    }
170
-
171
     _onCloseDialog: () => void;
152
     _onCloseDialog: () => void;
172
 
153
 
173
     /**
154
     /**
181
         this.props.onVisibilityChange(false);
162
         this.props.onVisibilityChange(false);
182
     }
163
     }
183
 
164
 
184
-    _onToggleDialogVisibility: () => void;
165
+    _toggleDialogVisibility: () => void;
185
 
166
 
186
     /**
167
     /**
187
      * Callback invoked to signal that an event has occurred that should change
168
      * Callback invoked to signal that an event has occurred that should change
190
      * @private
171
      * @private
191
      * @returns {void}
172
      * @returns {void}
192
      */
173
      */
193
-    _onToggleDialogVisibility() {
174
+    _toggleDialogVisibility() {
194
         sendAnalytics(createToolbarEvent('overflow'));
175
         sendAnalytics(createToolbarEvent('overflow'));
195
 
176
 
196
         this.props.onVisibilityChange(!this.props.isOpen);
177
         this.props.onVisibilityChange(!this.props.isOpen);

+ 73
- 0
react/features/toolbox/components/web/OverflowToggleButton.js View File

1
+// @flow
2
+
3
+import { translate } from '../../../base/i18n';
4
+import { IconHorizontalPoints } from '../../../base/icons';
5
+import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
6
+
7
+
8
+/**
9
+ * The type of the React {@code Component} props of {@link OverflowToggleButton}.
10
+ */
11
+type Props = AbstractButtonProps & {
12
+
13
+    /**
14
+     * Whether the more options menu is open.
15
+     */
16
+    isOpen: boolean,
17
+
18
+    /**
19
+     * External handler for key down action.
20
+     */
21
+     onKeyDown: Function,
22
+};
23
+
24
+/**
25
+ * Implementation of a button for toggleing the overflow menu.
26
+ */
27
+class OverflowToggleButton extends AbstractButton<Props, *> {
28
+    accessibilityLabel = 'toolbar.accessibilityLabel.moreActions';
29
+    icon = IconHorizontalPoints;
30
+    label = 'toolbar.moreActions';
31
+    toggledLabel = 'toolbar.moreActions';
32
+
33
+    /**
34
+     * Retrieves tooltip dynamically.
35
+     */
36
+    get tooltip() {
37
+        return 'toolbar.moreActions';
38
+    }
39
+
40
+    /**
41
+     * Required by linter due to AbstractButton overwritten prop being writable.
42
+     *
43
+     * @param {string} _value - The value.
44
+     */
45
+    set tooltip(_value) {
46
+        // Unused.
47
+    }
48
+
49
+    /**
50
+     * Indicates whether this button is in toggled state or not.
51
+     *
52
+     * @override
53
+     * @protected
54
+     * @returns {boolean}
55
+     */
56
+    _isToggled() {
57
+        return this.props.isOpen;
58
+    }
59
+
60
+    /**
61
+     * Indicates whether a key was pressed.
62
+     *
63
+     * @override
64
+     * @protected
65
+     * @returns {boolean}
66
+     */
67
+    _onKeyDown() {
68
+        this.props.onKeyDown();
69
+    }
70
+}
71
+
72
+
73
+export default translate(OverflowToggleButton);

+ 1
- 7
react/features/toolbox/components/web/ProfileButton.js View File

95
      * @returns {void}
95
      * @returns {void}
96
      */
96
      */
97
     _handleClick() {
97
     _handleClick() {
98
-        const { dispatch, _unclickable, handleClick } = this.props;
99
-
100
-        if (handleClick) {
101
-            handleClick();
102
-
103
-            return;
104
-        }
98
+        const { dispatch, _unclickable } = this.props;
105
 
99
 
106
         if (!_unclickable) {
100
         if (!_unclickable) {
107
             sendAnalytics(createToolbarEvent('profile'));
101
             sendAnalytics(createToolbarEvent('profile'));

+ 0
- 16
react/features/toolbox/components/web/ShareDesktopButton.js View File

67
         // Unused.
67
         // Unused.
68
     }
68
     }
69
 
69
 
70
-    /**
71
-     * Handles clicking / pressing the button, and opens the appropriate dialog.
72
-     *
73
-     * @protected
74
-     * @returns {void}
75
-     */
76
-    _handleClick() {
77
-        const { handleClick } = this.props;
78
-
79
-        if (handleClick) {
80
-            handleClick();
81
-
82
-            return;
83
-        }
84
-    }
85
-
86
     /**
70
     /**
87
      * Indicates whether this button is in toggled state or not.
71
      * Indicates whether this button is in toggled state or not.
88
      *
72
      *

+ 1
- 7
react/features/toolbox/components/web/ToggleCameraButton.js View File

41
      * @returns {void}
41
      * @returns {void}
42
      */
42
      */
43
     _handleClick() {
43
     _handleClick() {
44
-        const { dispatch, handleClick } = this.props;
45
-
46
-        if (handleClick) {
47
-            handleClick();
48
-
49
-            return;
50
-        }
44
+        const { dispatch } = this.props;
51
 
45
 
52
         dispatch(toggleCamera());
46
         dispatch(toggleCamera());
53
     }
47
     }

+ 0
- 135
react/features/toolbox/components/web/ToolbarButton.js View File

1
-/* @flow */
2
-
3
-import React from 'react';
4
-
5
-import { Icon } from '../../../base/icons';
6
-import { Tooltip } from '../../../base/tooltip';
7
-import AbstractToolbarButton from '../AbstractToolbarButton';
8
-import type { Props as AbstractToolbarButtonProps }
9
-    from '../AbstractToolbarButton';
10
-
11
-/**
12
- * The type of the React {@code Component} props of {@link ToolbarButton}.
13
- */
14
-export type Props = AbstractToolbarButtonProps & {
15
-
16
-    /**
17
-     * The text to display in the tooltip.
18
-     */
19
-    tooltip: string,
20
-
21
-    /**
22
-     * From which direction the tooltip should appear, relative to the
23
-     * button.
24
-     */
25
-    tooltipPosition: string,
26
-
27
-    /**
28
-     * KeyDown handler.
29
-     */
30
-    onKeyDown?: Function
31
-};
32
-
33
-/**
34
- * Represents a button in the toolbar.
35
- *
36
- * @augments AbstractToolbarButton
37
- */
38
-class ToolbarButton extends AbstractToolbarButton<Props> {
39
-    /**
40
-     * Default values for {@code ToolbarButton} component's properties.
41
-     *
42
-     * @static
43
-     */
44
-    static defaultProps = {
45
-        tooltipPosition: 'top'
46
-    };
47
-
48
-    /**
49
-     * Initializes a new {@code ToolbarButton} instance.
50
-     *
51
-     * @inheritdoc
52
-     */
53
-    constructor(props: Props) {
54
-        super(props);
55
-
56
-        this._onKeyPress = this._onKeyPress.bind(this);
57
-        this._onClick = this._onClick.bind(this);
58
-    }
59
-
60
-    _onKeyPress: (Object) => void;
61
-
62
-    /**
63
-     * Handles 'Enter' and Space key on the button to trigger onClick for accessibility.
64
-     *
65
-     * @param {Object} event - The key event.
66
-     * @private
67
-     * @returns {void}
68
-     */
69
-    _onKeyPress(event) {
70
-        if (event.key === 'Enter' || event.key === ' ') {
71
-            event.preventDefault();
72
-            this.props.onClick();
73
-        }
74
-    }
75
-    _onClick: (Object) => void;
76
-
77
-    /**
78
-     * Handles button click.
79
-     *
80
-     * @param {Object} e - The key event.
81
-     * @private
82
-     * @returns {void}
83
-     */
84
-    _onClick(e) {
85
-        this.props.onClick(e);
86
-
87
-        // blur after click to release focus from button to allow PTT.
88
-        e && e.currentTarget && e.currentTarget.blur();
89
-    }
90
-
91
-    /**
92
-     * Renders the button of this {@code ToolbarButton}.
93
-     *
94
-     * @param {Object} children - The children, if any, to be rendered inside
95
-     * the button. Presumably, contains the icon of this {@code ToolbarButton}.
96
-     * @protected
97
-     * @returns {ReactElement} The button of this {@code ToolbarButton}.
98
-     */
99
-    _renderButton(children) {
100
-        return (
101
-            <div
102
-                aria-label = { this.props.accessibilityLabel }
103
-                aria-pressed = { this.props.toggled }
104
-                className = 'toolbox-button'
105
-                onClick = { this._onClick }
106
-                onKeyDown = { this.props.onKeyDown }
107
-                onKeyPress = { this._onKeyPress }
108
-                role = 'button'
109
-                tabIndex = { 0 }>
110
-                { this.props.tooltip
111
-                    ? <Tooltip
112
-                        content = { this.props.tooltip }
113
-                        position = { this.props.tooltipPosition }>
114
-                        { children }
115
-                    </Tooltip>
116
-                    : children }
117
-            </div>
118
-        );
119
-    }
120
-
121
-    /**
122
-     * Renders the icon of this {@code ToolbarButton}.
123
-     *
124
-     * @inheritdoc
125
-     */
126
-    _renderIcon() {
127
-        return (
128
-            <div className = { `toolbox-icon ${this.props.toggled ? 'toggled' : ''}` }>
129
-                <Icon src = { this.props.icon } />
130
-            </div>
131
-        );
132
-    }
133
-}
134
-
135
-export default ToolbarButton;

+ 21
- 10
react/features/toolbox/components/web/Toolbox.js View File

76
     setToolbarHovered,
76
     setToolbarHovered,
77
     showToolbox
77
     showToolbox
78
 } from '../../actions';
78
 } from '../../actions';
79
-import { THRESHOLDS, NOT_APPLICABLE, DRAWER_MAX_HEIGHT } from '../../constants';
79
+import { THRESHOLDS, NOT_APPLICABLE, DRAWER_MAX_HEIGHT, NOTIFY_CLICK_MODE } from '../../constants';
80
 import { isToolboxVisible } from '../../functions';
80
 import { isToolboxVisible } from '../../functions';
81
 import DownloadButton from '../DownloadButton';
81
 import DownloadButton from '../DownloadButton';
82
 import HangupButton from '../HangupButton';
82
 import HangupButton from '../HangupButton';
106
     /**
106
     /**
107
      * Toolbar buttons which have their click exposed through the API.
107
      * Toolbar buttons which have their click exposed through the API.
108
      */
108
      */
109
-    _buttonsWithNotifyClick: Array<string>,
109
+    _buttonsWithNotifyClick: Array<string | Object>,
110
 
110
 
111
     /**
111
     /**
112
      * Whether or not the chat feature is currently displayed.
112
      * Whether or not the chat feature is currently displayed.
819
     }
819
     }
820
 
820
 
821
     /**
821
     /**
822
-     * Overwrites click handlers for buttons in case click is exposed through the iframe API.
822
+     * Sets the notify click mode for the buttons.
823
      *
823
      *
824
      * @param {Object} buttons - The list of toolbar buttons.
824
      * @param {Object} buttons - The list of toolbar buttons.
825
      * @returns {void}
825
      * @returns {void}
826
      */
826
      */
827
-    _overwriteButtonsClickHandlers(buttons) {
827
+    _setButtonsNotifyClickMode(buttons) {
828
         if (typeof APP === 'undefined' || !this.props._buttonsWithNotifyClick?.length) {
828
         if (typeof APP === 'undefined' || !this.props._buttonsWithNotifyClick?.length) {
829
             return;
829
             return;
830
         }
830
         }
831
 
831
 
832
         Object.values(buttons).forEach((button: any) => {
832
         Object.values(buttons).forEach((button: any) => {
833
-            if (
834
-                typeof button === 'object'
835
-                && this.props._buttonsWithNotifyClick.includes(button.key)
836
-            ) {
837
-                button.handleClick = () => APP.API.notifyToolbarButtonClicked(button.key);
833
+            if (typeof button === 'object') {
834
+                const notify = this.props._buttonsWithNotifyClick.find(
835
+                    (btn: string | Object) =>
836
+                        (typeof btn === 'string' && btn === button.key)
837
+                        || (typeof btn === 'object' && btn.key === button.key)
838
+                );
839
+
840
+                if (notify) {
841
+                    const notifyMode = typeof notify === 'string' || notify.preventExecution
842
+                        ? NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
843
+                        : NOTIFY_CLICK_MODE.ONLY_NOTIFY;
844
+
845
+                    button.notifyMode = notifyMode;
846
+                }
838
             }
847
             }
839
         });
848
         });
840
     }
849
     }
854
 
863
 
855
         const buttons = this._getAllButtons();
864
         const buttons = this._getAllButtons();
856
 
865
 
857
-        this._overwriteButtonsClickHandlers(buttons);
866
+        this._setButtonsNotifyClickMode(buttons);
858
         const isHangupVisible = isToolbarButtonEnabled('hangup', _toolbarButtons);
867
         const isHangupVisible = isToolbarButtonEnabled('hangup', _toolbarButtons);
859
         const { order } = THRESHOLDS.find(({ width }) => _clientWidth > width)
868
         const { order } = THRESHOLDS.find(({ width }) => _clientWidth > width)
860
             || THRESHOLDS[THRESHOLDS.length - 1];
869
             || THRESHOLDS[THRESHOLDS.length - 1];
1265
                         {mainMenuButtons.map(({ Content, key, ...rest }) => Content !== Separator && (
1274
                         {mainMenuButtons.map(({ Content, key, ...rest }) => Content !== Separator && (
1266
                             <Content
1275
                             <Content
1267
                                 { ...rest }
1276
                                 { ...rest }
1277
+                                buttonKey = { key }
1268
                                 key = { key } />))}
1278
                                 key = { key } />))}
1269
 
1279
 
1270
                         {Boolean(overflowMenuButtons.length) && (
1280
                         {Boolean(overflowMenuButtons.length) && (
1292
                                                 {showSeparator && <Separator key = { `hr${group}` } />}
1302
                                                 {showSeparator && <Separator key = { `hr${group}` } />}
1293
                                                 <Content
1303
                                                 <Content
1294
                                                     { ...rest }
1304
                                                     { ...rest }
1305
+                                                    buttonKey = { key }
1295
                                                     key = { key }
1306
                                                     key = { key }
1296
                                                     showLabel = { true } />
1307
                                                     showLabel = { true } />
1297
                                             </Fragment>
1308
                                             </Fragment>

+ 21
- 10
react/features/toolbox/components/web/VideoSettingsButton.js View File

16
 
16
 
17
 type Props = {
17
 type Props = {
18
 
18
 
19
+    /**
20
+     * The button's key.
21
+     */
22
+     buttonKey?: string,
23
+
19
     /**
24
     /**
20
      * External handler for click action.
25
      * External handler for click action.
21
      */
26
      */
41
      */
46
      */
42
     isDisabled: boolean,
47
     isDisabled: boolean,
43
 
48
 
49
+    /**
50
+     * Notify mode for `toolbarButtonClicked` event -
51
+     * whether to only notify or to also prevent button click routine.
52
+     */
53
+    notifyMode?: string,
54
+
44
     /**
55
     /**
45
      * Flag controlling the visibility of the button.
56
      * Flag controlling the visibility of the button.
46
      * VideoSettings popup is currently disabled on mobile browsers
57
      * VideoSettings popup is currently disabled on mobile browsers
112
      * @returns {void}
123
      * @returns {void}
113
      */
124
      */
114
     _onClick() {
125
     _onClick() {
115
-        const { handleClick, onVideoOptionsClick } = this.props;
116
-
117
-        if (handleClick) {
118
-            handleClick();
119
-
120
-            return;
121
-        }
126
+        const { onVideoOptionsClick } = this.props;
122
 
127
 
123
         onVideoOptionsClick();
128
         onVideoOptionsClick();
124
     }
129
     }
129
      * @inheritdoc
134
      * @inheritdoc
130
      */
135
      */
131
     render() {
136
     render() {
132
-        const { handleClick, t, visible, isOpen } = this.props;
137
+        const { t, visible, isOpen, buttonKey, notifyMode } = this.props;
133
 
138
 
134
         return visible ? (
139
         return visible ? (
135
             <VideoSettingsPopup>
140
             <VideoSettingsPopup>
138
                     ariaExpanded = { isOpen }
143
                     ariaExpanded = { isOpen }
139
                     ariaHasPopup = { true }
144
                     ariaHasPopup = { true }
140
                     ariaLabel = { this.props.t('toolbar.videoSettings') }
145
                     ariaLabel = { this.props.t('toolbar.videoSettings') }
146
+                    buttonKey = { buttonKey }
141
                     icon = { IconArrowUp }
147
                     icon = { IconArrowUp }
142
                     iconDisabled = { this._isIconDisabled() }
148
                     iconDisabled = { this._isIconDisabled() }
143
                     iconId = 'video-settings-button'
149
                     iconId = 'video-settings-button'
144
                     iconTooltip = { t('toolbar.videoSettings') }
150
                     iconTooltip = { t('toolbar.videoSettings') }
151
+                    notifyMode = { notifyMode }
145
                     onIconClick = { this._onClick }
152
                     onIconClick = { this._onClick }
146
                     onIconKeyDown = { this._onEscClick }>
153
                     onIconKeyDown = { this._onEscClick }>
147
-                    <VideoMuteButton handleClick = { handleClick } />
154
+                    <VideoMuteButton
155
+                        buttonKey = { buttonKey }
156
+                        notifyMode = { notifyMode } />
148
                 </ToolboxButtonWithIcon>
157
                 </ToolboxButtonWithIcon>
149
             </VideoSettingsPopup>
158
             </VideoSettingsPopup>
150
-        ) : <VideoMuteButton handleClick = { handleClick } />;
159
+        ) : <VideoMuteButton
160
+            buttonKey = { buttonKey }
161
+            notifyMode = { notifyMode } />;
151
     }
162
     }
152
 }
163
 }
153
 
164
 

+ 0
- 1
react/features/toolbox/components/web/index.js View File

1
 export { default as AudioSettingsButton } from './AudioSettingsButton';
1
 export { default as AudioSettingsButton } from './AudioSettingsButton';
2
 export { default as VideoSettingsButton } from './VideoSettingsButton';
2
 export { default as VideoSettingsButton } from './VideoSettingsButton';
3
-export { default as ToolbarButton } from './ToolbarButton';
4
 export { default as Toolbox } from './Toolbox';
3
 export { default as Toolbox } from './Toolbox';
5
 export { default as Drawer } from './Drawer';
4
 export { default as Drawer } from './Drawer';
6
 export { default as JitsiPortal } from './JitsiPortal';
5
 export { default as JitsiPortal } from './JitsiPortal';

+ 5
- 0
react/features/toolbox/constants.js View File

33
 export const TOOLBAR_TIMEOUT = 4000;
33
 export const TOOLBAR_TIMEOUT = 4000;
34
 
34
 
35
 export const DRAWER_MAX_HEIGHT = '80vh - 64px';
35
 export const DRAWER_MAX_HEIGHT = '80vh - 64px';
36
+
37
+export const NOTIFY_CLICK_MODE = {
38
+    ONLY_NOTIFY: 'ONLY_NOTIFY',
39
+    PREVENT_AND_NOTIFY: 'PREVENT_AND_NOTIFY'
40
+};

+ 1
- 7
react/features/video-layout/components/TileViewButton.js View File

52
      * @returns {void}
52
      * @returns {void}
53
      */
53
      */
54
     _handleClick() {
54
     _handleClick() {
55
-        const { _tileViewEnabled, dispatch, handleClick } = this.props;
56
-
57
-        if (handleClick) {
58
-            handleClick();
59
-
60
-            return;
61
-        }
55
+        const { _tileViewEnabled, dispatch } = this.props;
62
 
56
 
63
         const value = !_tileViewEnabled;
57
         const value = !_tileViewEnabled;
64
 
58
 

+ 0
- 18
react/features/video-quality/components/VideoQualityButton.web.js View File

39
     label = 'videoStatus.performanceSettings';
39
     label = 'videoStatus.performanceSettings';
40
     tooltip = 'videoStatus.performanceSettings';
40
     tooltip = 'videoStatus.performanceSettings';
41
     icon = IconGauge;
41
     icon = IconGauge;
42
-
43
-
44
-    /**
45
-     * Handles clicking / pressing the button.
46
-     *
47
-     * @override
48
-     * @protected
49
-     * @returns {void}
50
-     */
51
-    _handleClick() {
52
-        const { handleClick } = this.props;
53
-
54
-        if (handleClick) {
55
-            handleClick();
56
-
57
-            return;
58
-        }
59
-    }
60
 }
42
 }
61
 
43
 
62
 export default translate(VideoQualityButton);
44
 export default translate(VideoQualityButton);

+ 1
- 7
react/features/virtual-background/components/VideoBackgroundButton.js View File

43
      * @returns {void}
43
      * @returns {void}
44
      */
44
      */
45
     _handleClick() {
45
     _handleClick() {
46
-        const { dispatch, handleClick } = this.props;
47
-
48
-        if (handleClick) {
49
-            handleClick();
50
-
51
-            return;
52
-        }
46
+        const { dispatch } = this.props;
53
 
47
 
54
         dispatch(openDialog(VirtualBackgroundDialog));
48
         dispatch(openDialog(VirtualBackgroundDialog));
55
     }
49
     }

Loading…
Cancel
Save