浏览代码

feat(tooltips): convert popup tooltips to InlineDialog

master
Leonard Kim 8 年前
父节点
当前提交
e3361e2f3b

+ 8
- 4
conference.js 查看文件

1263
      * @returns {void}
1263
      * @returns {void}
1264
      */
1264
      */
1265
     _displayAudioOnlyTooltip(featureName) {
1265
     _displayAudioOnlyTooltip(featureName) {
1266
+        let buttonName = null;
1266
         let tooltipElementId = null;
1267
         let tooltipElementId = null;
1267
 
1268
 
1268
         switch (featureName) {
1269
         switch (featureName) {
1269
         case 'screenShare':
1270
         case 'screenShare':
1270
-            tooltipElementId = '#screenshareWhileAudioOnly';
1271
+            buttonName = 'desktop';
1272
+            tooltipElementId = 'screenshareWhileAudioOnly';
1271
             break;
1273
             break;
1272
         case 'videoMute':
1274
         case 'videoMute':
1273
-            tooltipElementId = '#unmuteWhileAudioOnly';
1275
+            buttonName = 'camera';
1276
+            tooltipElementId = 'unmuteWhileAudioOnly';
1274
             break;
1277
             break;
1275
         }
1278
         }
1276
 
1279
 
1277
         if (tooltipElementId) {
1280
         if (tooltipElementId) {
1278
             APP.UI.showToolbar(6000);
1281
             APP.UI.showToolbar(6000);
1279
             APP.UI.showCustomToolbarPopup(
1282
             APP.UI.showCustomToolbarPopup(
1280
-                tooltipElementId, true, 5000);
1283
+                buttonName, tooltipElementId, true, 5000);
1281
         }
1284
         }
1282
     },
1285
     },
1283
 
1286
 
1697
         room.on(ConferenceEvents.TALK_WHILE_MUTED, () => {
1700
         room.on(ConferenceEvents.TALK_WHILE_MUTED, () => {
1698
             APP.UI.showToolbar(6000);
1701
             APP.UI.showToolbar(6000);
1699
 
1702
 
1700
-            APP.UI.showCustomToolbarPopup('#talkWhileMutedPopup', true, 5000);
1703
+            APP.UI.showCustomToolbarPopup(
1704
+                'microphone', 'talkWhileMutedPopup', true, 5000);
1701
         });
1705
         });
1702
 
1706
 
1703
         room.on(
1707
         room.on(

+ 2
- 2
css/_toolbars.scss 查看文件

130
 
130
 
131
         @include transform(translateX(-50%));
131
         @include transform(translateX(-50%));
132
 
132
 
133
-        .button:first-child {
133
+        > div:first-child .button {
134
             border-bottom-left-radius: 3px;
134
             border-bottom-left-radius: 3px;
135
             border-top-left-radius: 3px;
135
             border-top-left-radius: 3px;
136
         }
136
         }
137
-        .button:last-child {
137
+        > div:last-child .button {
138
             border-bottom-right-radius: 3px;
138
             border-bottom-right-radius: 3px;
139
             border-top-right-radius: 3px;
139
             border-top-right-radius: 3px;
140
         }
140
         }

+ 2
- 2
lang/main.json 查看文件

114
         "login": "Login",
114
         "login": "Login",
115
         "logout": "Logout",
115
         "logout": "Logout",
116
         "dialpad": "Open / Close dialpad",
116
         "dialpad": "Open / Close dialpad",
117
-        "sharedVideoMutedPopup": "Your shared video has been muted so<br/>that you can talk to the other participants.",
118
-        "micMutedPopup": "Your microphone has been muted so that you<br/>would fully enjoy your shared video.",
117
+        "sharedVideoMutedPopup": "Your shared video has been muted so that you can talk to the other participants.",
118
+        "micMutedPopup": "Your microphone has been muted so that you would fully enjoy your shared video.",
119
         "talkWhileMutedPopup": "Trying to speak? You are muted.",
119
         "talkWhileMutedPopup": "Trying to speak? You are muted.",
120
         "unableToUnmutePopup": "You cannot un-mute while the shared video is on.",
120
         "unableToUnmutePopup": "You cannot un-mute while the shared video is on.",
121
         "cameraDisabled": "Camera is not available",
121
         "cameraDisabled": "Camera is not available",

+ 16
- 6
modules/UI/UI.js 查看文件

30
 import { openDisplayNamePrompt } from '../../react/features/display-name';
30
 import { openDisplayNamePrompt } from '../../react/features/display-name';
31
 import {
31
 import {
32
     checkAutoEnableDesktopSharing,
32
     checkAutoEnableDesktopSharing,
33
+    clearButtonPopup,
33
     dockToolbox,
34
     dockToolbox,
35
+    setButtonPopupTimeout,
34
     setToolbarButton,
36
     setToolbarButton,
35
     showDialPadButton,
37
     showDialPadButton,
36
     showEtherpadButton,
38
     showEtherpadButton,
609
 
611
 
610
 /**
612
 /**
611
  * Show custom popup/tooltip for a specified button.
613
  * Show custom popup/tooltip for a specified button.
612
- * @param popupSelectorID the selector id of the popup to show
613
- * @param show true or false/show or hide the popup
614
- * @param timeout the time to show the popup
614
+ *
615
+ * @param {string} buttonName - The name of the button as specified in the
616
+ * button configurations for the toolbar.
617
+ * @param {string} popupSelectorID - The id of the popup to show as specified in
618
+ * the button configurations for the toolbar.
619
+ * @param {boolean} show - True or false/show or hide the popup
620
+ * @param {number} timeout - The time to show the popup
621
+ * @returns {void}
615
  */
622
  */
616
-UI.showCustomToolbarPopup = function (popupSelectorID, show, timeout) {
617
-    eventEmitter.emit(UIEvents.SHOW_CUSTOM_TOOLBAR_BUTTON_POPUP,
618
-        popupSelectorID, show, timeout);
623
+UI.showCustomToolbarPopup = function (buttonName, popupID, show, timeout) {
624
+    const action = show
625
+        ? setButtonPopupTimeout(buttonName, popupID, timeout)
626
+        : clearButtonPopup(buttonName);
627
+
628
+    APP.store.dispatch(action);
619
 };
629
 };
620
 
630
 
621
 /**
631
 /**

+ 0
- 3
modules/UI/recording/Recording.js 查看文件

18
 
18
 
19
 import UIEvents from "../../../service/UI/UIEvents";
19
 import UIEvents from "../../../service/UI/UIEvents";
20
 import UIUtil from '../util/UIUtil';
20
 import UIUtil from '../util/UIUtil';
21
-import { setTooltip } from '../util/Tooltip';
22
 import VideoLayout from '../videolayout/VideoLayout';
21
 import VideoLayout from '../videolayout/VideoLayout';
23
 
22
 
24
 import { setToolboxEnabled } from '../../../react/features/toolbox';
23
 import { setToolboxEnabled } from '../../../react/features/toolbox';
324
     initRecordingButton() {
323
     initRecordingButton() {
325
         const selector = $('#toolbar_button_record');
324
         const selector = $('#toolbar_button_record');
326
 
325
 
327
-        setTooltip(selector, 'liveStreaming.buttonTooltip', 'right');
328
-
329
         selector.addClass(this.baseClass);
326
         selector.addClass(this.baseClass);
330
         selector.attr("data-i18n", "[content]" + this.recordingButtonTooltip);
327
         selector.attr("data-i18n", "[content]" + this.recordingButtonTooltip);
331
         APP.translation.translateElement(selector);
328
         APP.translation.translateElement(selector);

+ 4
- 2
modules/UI/shared_video/SharedVideo.js 查看文件

558
         if(show)
558
         if(show)
559
             this.showSharedVideoMutedPopup(false);
559
             this.showSharedVideoMutedPopup(false);
560
 
560
 
561
-        APP.UI.showCustomToolbarPopup('#micMutedPopup', show, 5000);
561
+        APP.UI.showCustomToolbarPopup(
562
+            'microphone', 'micMutedPopup', show, 5000);
562
     }
563
     }
563
 
564
 
564
     /**
565
     /**
571
         if(show)
572
         if(show)
572
             this.showMicMutedPopup(false);
573
             this.showMicMutedPopup(false);
573
 
574
 
574
-        APP.UI.showCustomToolbarPopup('#sharedVideoMutedPopup', show, 5000);
575
+        APP.UI.showCustomToolbarPopup(
576
+            'sharedvideo', 'sharedVideoMutedPopup', show, 5000);
575
     }
577
     }
576
 }
578
 }
577
 
579
 

+ 63
- 0
react/features/toolbox/actions.web.js 查看文件

20
 } from './actions.native';
20
 } from './actions.native';
21
 import { SET_DEFAULT_TOOLBOX_BUTTONS } from './actionTypes';
21
 import { SET_DEFAULT_TOOLBOX_BUTTONS } from './actionTypes';
22
 import {
22
 import {
23
+    getButton,
23
     getDefaultToolboxButtons,
24
     getDefaultToolboxButtons,
24
     isButtonEnabled
25
     isButtonEnabled
25
 } from './functions';
26
 } from './functions';
48
     };
49
     };
49
 }
50
 }
50
 
51
 
52
+/**
53
+ * Dispatches an action to hide any popups displayed by the associated button.
54
+ *
55
+ * @param {string} buttonName - The name of the button as specified in the
56
+ * button configurations for the toolbar.
57
+ * @returns {Function}
58
+ */
59
+export function clearButtonPopup(buttonName) {
60
+    return (dispatch, getState) => {
61
+        _clearPopupTimeout(buttonName, getState());
62
+
63
+        dispatch(setToolbarButton(buttonName, {
64
+            popupDisplay: null
65
+        }));
66
+    };
67
+}
68
+
51
 /**
69
 /**
52
  * Docks/undocks the Toolbox.
70
  * Docks/undocks the Toolbox.
53
  *
71
  *
195
     };
213
     };
196
 }
214
 }
197
 
215
 
216
+/**
217
+ * Dispatches an action to show the popup associated with a button. Sets a
218
+ * timeout to be fired which will dismiss the popup.
219
+ *
220
+ * @param {string} buttonName - The name of the button as specified in the
221
+ * button configurations for the toolbar.
222
+ * @param {string} popupName - The id of the popup to show as specified in
223
+ * the button configurations for the toolbar.
224
+ * @param {number} timeout - The time in milliseconds to show the popup.
225
+ * @returns {Function}
226
+ */
227
+export function setButtonPopupTimeout(buttonName, popupName, timeout) {
228
+    return (dispatch, getState) => {
229
+        _clearPopupTimeout(buttonName, getState());
230
+
231
+        const newTimeoutId = setTimeout(() => {
232
+            dispatch(clearButtonPopup(buttonName));
233
+        }, timeout);
234
+
235
+        dispatch(setToolbarButton(buttonName, {
236
+            popupDisplay: {
237
+                popupID: popupName,
238
+                timeoutID: newTimeoutId
239
+            }
240
+        }));
241
+    };
242
+}
243
+
198
 /**
244
 /**
199
  * Sets the default toolbar buttons of the Toolbox.
245
  * Sets the default toolbar buttons of the Toolbox.
200
  *
246
  *
387
         }
433
         }
388
     };
434
     };
389
 }
435
 }
436
+
437
+/**
438
+ * Clears the timeout set for hiding a button popup.
439
+ *
440
+ * @param {string} buttonName - The name of the button as specified in the
441
+ * button configurations for the toolbar.
442
+ * @param {Object} state - The redux state in which the button is expected to
443
+ * be defined.
444
+ * @private
445
+ * @returns {void}
446
+ */
447
+function _clearPopupTimeout(buttonName, state) {
448
+    const { popupDisplay } = getButton(buttonName, state);
449
+    const { timeoutID } = popupDisplay || {};
450
+
451
+    clearTimeout(timeoutID);
452
+}

+ 58
- 34
react/features/toolbox/components/ToolbarButton.web.js 查看文件

1
 /* @flow */
1
 /* @flow */
2
 
2
 
3
+import AKInlineDialog from '@atlaskit/inline-dialog';
3
 import { Tooltip } from '@atlaskit/tooltip';
4
 import { Tooltip } from '@atlaskit/tooltip';
4
 import React, { Component } from 'react';
5
 import React, { Component } from 'react';
5
 
6
 
11
 
12
 
12
 declare var APP: Object;
13
 declare var APP: Object;
13
 
14
 
15
+/**
16
+ * Mapping of tooltip positions to equivalent {@code AKInlineDialog} positions.
17
+ *
18
+ * @private
19
+ */
20
+const TOOLTIP_TO_POPUP_POSITION = {
21
+    bottom: 'bottom center',
22
+    left: 'left middle',
23
+    top: 'top center',
24
+    right: 'right middle'
25
+};
26
+
14
 /**
27
 /**
15
  * Represents a button in Toolbar on React.
28
  * Represents a button in Toolbar on React.
16
  *
29
  *
127
      */
140
      */
128
     render(): ReactElement<*> {
141
     render(): ReactElement<*> {
129
         const { button, t, tooltipPosition } = this.props;
142
         const { button, t, tooltipPosition } = this.props;
130
-        const popups = button.popups || [];
131
-
132
         const props = {
143
         const props = {
133
             ...this.props,
144
             ...this.props,
134
             onClick: this._onClick,
145
             onClick: this._onClick,
135
             createRefToButton: this._createRefToButton
146
             createRefToButton: this._createRefToButton
136
         };
147
         };
137
 
148
 
138
-        return (
149
+        const buttonComponent = ( // eslint-disable-line no-extra-parens
139
             <Tooltip
150
             <Tooltip
140
                 description = { button.tooltipText || t(button.tooltipKey) }
151
                 description = { button.tooltipText || t(button.tooltipKey) }
141
                 onMouseOut = { this._onMouseOut }
152
                 onMouseOut = { this._onMouseOut }
142
                 onMouseOver = { this._onMouseOver }
153
                 onMouseOver = { this._onMouseOver }
143
                 position = { tooltipPosition }
154
                 position = { tooltipPosition }
144
                 visible = { this.state.showTooltip }>
155
                 visible = { this.state.showTooltip }>
145
-                <StatelessToolbarButton { ...props }>
146
-                    { this._renderPopups(popups) }
147
-                </StatelessToolbarButton>
156
+                <StatelessToolbarButton { ...props } />
148
             </Tooltip>
157
             </Tooltip>
149
         );
158
         );
159
+
160
+        const popupConfig = this._getPopupDisplayConfiguration();
161
+
162
+        if (popupConfig) {
163
+            const { dataAttr, dataInterpolate, position } = popupConfig;
164
+
165
+            return (
166
+                <AKInlineDialog
167
+                    content = { t(dataAttr, dataInterpolate) }
168
+                    isOpen = { Boolean(popupConfig) }
169
+                    position = { position }>
170
+                    { buttonComponent }
171
+                </AKInlineDialog>
172
+            );
173
+        }
174
+
175
+        return buttonComponent;
150
     }
176
     }
151
 
177
 
152
     /**
178
     /**
174
     }
200
     }
175
 
201
 
176
     /**
202
     /**
177
-     * If toolbar button should contain children elements
178
-     * renders them.
203
+     * Parses the props and state to find any popup that should be displayed
204
+     * and returns an object describing how the popup should display.
179
      *
205
      *
180
-     * @returns {ReactElement|null}
181
      * @private
206
      * @private
207
+     * @returns {Object|null}
182
      */
208
      */
183
-    _renderInnerElementsIfRequired(): ReactElement<*> | null {
184
-        if (this.props.button.html) {
185
-            return this.props.button.html;
209
+    _getPopupDisplayConfiguration() {
210
+        const { button, tooltipPosition } = this.props;
211
+        const { popups, popupDisplay } = button;
212
+
213
+        if (!popups || !popupDisplay) {
214
+            return null;
186
         }
215
         }
187
 
216
 
188
-        return null;
217
+        const { popupID } = popupDisplay;
218
+        const currentPopup = popups.find(popup => popup.id === popupID);
219
+
220
+        return Object.assign(
221
+            {},
222
+            currentPopup || {},
223
+            {
224
+                position: TOOLTIP_TO_POPUP_POSITION[tooltipPosition]
225
+            });
189
     }
226
     }
190
 
227
 
191
     /**
228
     /**
192
-     * Renders popup element for toolbar button.
229
+     * If toolbar button should contain children elements
230
+     * renders them.
193
      *
231
      *
194
-     * @param {Array} popups - Array of popup objects.
195
-     * @returns {Array}
232
+     * @returns {ReactElement|null}
196
      * @private
233
      * @private
197
      */
234
      */
198
-    _renderPopups(popups: Array<*> = []): Array<*> {
199
-        return popups.map(popup => {
200
-            let gravity = 'n';
201
-
202
-            if (popup.dataAttrPosition) {
203
-                gravity = popup.dataAttrPosition;
204
-            }
205
-
206
-            const title = this.props.t(popup.dataAttr, popup.dataInterpolate);
235
+    _renderInnerElementsIfRequired(): ReactElement<*> | null {
236
+        if (this.props.button.html) {
237
+            return this.props.button.html;
238
+        }
207
 
239
 
208
-            return (
209
-                <div
210
-                    className = { popup.className }
211
-                    data-popup = { gravity }
212
-                    id = { popup.id }
213
-                    key = { popup.id }
214
-                    title = { title } />
215
-            );
216
-        });
240
+        return null;
217
     }
241
     }
218
 
242
 
219
     /**
243
     /**

+ 1
- 19
react/features/toolbox/components/Toolbox.web.js 查看文件

3
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
4
 import { connect } from 'react-redux';
4
 import { connect } from 'react-redux';
5
 
5
 
6
-import UIEvents from '../../../../service/UI/UIEvents';
7
-
8
 import {
6
 import {
9
     setDefaultToolboxButtons,
7
     setDefaultToolboxButtons,
10
     setToolboxAlwaysVisible
8
     setToolboxAlwaysVisible
11
 } from '../actions';
9
 } from '../actions';
12
 import {
10
 import {
13
-    abstractMapStateToProps,
14
-    showCustomToolbarPopup
11
+    abstractMapStateToProps
15
 } from '../functions';
12
 } from '../functions';
16
 import Notice from './Notice';
13
 import Notice from './Notice';
17
 import PrimaryToolbar from './PrimaryToolbar';
14
 import PrimaryToolbar from './PrimaryToolbar';
71
     componentDidMount(): void {
68
     componentDidMount(): void {
72
         this.props._setToolboxAlwaysVisible();
69
         this.props._setToolboxAlwaysVisible();
73
 
70
 
74
-        APP.UI.addListener(
75
-            UIEvents.SHOW_CUSTOM_TOOLBAR_BUTTON_POPUP,
76
-            showCustomToolbarPopup);
77
-
78
         // FIXME The redux action SET_DEFAULT_TOOLBOX_BUTTONS and related source
71
         // FIXME The redux action SET_DEFAULT_TOOLBOX_BUTTONS and related source
79
         // code such as the redux action creator setDefaultToolboxButtons and
72
         // code such as the redux action creator setDefaultToolboxButtons and
80
         // _setDefaultToolboxButtons were introduced to solve the following bug
73
         // _setDefaultToolboxButtons were introduced to solve the following bug
89
         this.props._setDefaultToolboxButtons();
82
         this.props._setDefaultToolboxButtons();
90
     }
83
     }
91
 
84
 
92
-    /**
93
-     *  Unregisters legacy UI listeners.
94
-     *
95
-     *  @returns {void}
96
-     */
97
-    componentWillUnmount(): void {
98
-        APP.UI.removeListener(
99
-            UIEvents.SHOW_CUSTOM_TOOLBAR_BUTTON_POPUP,
100
-            showCustomToolbarPopup);
101
-    }
102
-
103
     /**
85
     /**
104
      * Implements React's {@link Component#render()}.
86
      * Implements React's {@link Component#render()}.
105
      *
87
      *

+ 0
- 7
react/features/toolbox/defaultToolbarButtons.js 查看文件

51
         },
51
         },
52
         popups: [
52
         popups: [
53
             {
53
             {
54
-                className: 'loginmenu',
55
                 dataAttr: 'audioOnly.featureToggleDisabled',
54
                 dataAttr: 'audioOnly.featureToggleDisabled',
56
                 dataInterpolate: { feature: 'video mute' },
55
                 dataInterpolate: { feature: 'video mute' },
57
                 id: 'unmuteWhileAudioOnly'
56
                 id: 'unmuteWhileAudioOnly'
143
         },
142
         },
144
         popups: [
143
         popups: [
145
             {
144
             {
146
-                className: 'loginmenu',
147
                 dataAttr: 'audioOnly.featureToggleDisabled',
145
                 dataAttr: 'audioOnly.featureToggleDisabled',
148
                 dataInterpolate: { feature: 'screen sharing' },
146
                 dataInterpolate: { feature: 'screen sharing' },
149
                 id: 'screenshareWhileAudioOnly'
147
                 id: 'screenshareWhileAudioOnly'
313
         },
311
         },
314
         popups: [
312
         popups: [
315
             {
313
             {
316
-                className: 'loginmenu',
317
                 dataAttr: 'toolbar.micMutedPopup',
314
                 dataAttr: 'toolbar.micMutedPopup',
318
                 id: 'micMutedPopup'
315
                 id: 'micMutedPopup'
319
             },
316
             },
320
             {
317
             {
321
-                className: 'loginmenu',
322
                 dataAttr: 'toolbar.unableToUnmutePopup',
318
                 dataAttr: 'toolbar.unableToUnmutePopup',
323
                 id: 'unableToUnmutePopup'
319
                 id: 'unableToUnmutePopup'
324
             },
320
             },
325
             {
321
             {
326
-                className: 'loginmenu',
327
                 dataAttr: 'toolbar.talkWhileMutedPopup',
322
                 dataAttr: 'toolbar.talkWhileMutedPopup',
328
                 id: 'talkWhileMutedPopup'
323
                 id: 'talkWhileMutedPopup'
329
             }
324
             }
419
         },
414
         },
420
         popups: [
415
         popups: [
421
             {
416
             {
422
-                className: 'loginmenu extendedToolbarPopup',
423
                 dataAttr: 'toolbar.sharedVideoMutedPopup',
417
                 dataAttr: 'toolbar.sharedVideoMutedPopup',
424
-                dataAttrPosition: 'w',
425
                 id: 'sharedVideoMutedPopup'
418
                 id: 'sharedVideoMutedPopup'
426
             }
419
             }
427
         ],
420
         ],

+ 1
- 1
react/features/toolbox/functions.web.js 查看文件

7
 declare var AJS: Object;
7
 declare var AJS: Object;
8
 declare var interfaceConfig: Object;
8
 declare var interfaceConfig: Object;
9
 
9
 
10
-export { abstractMapStateToProps } from './functions.native';
10
+export { abstractMapStateToProps, getButton } from './functions.native';
11
 
11
 
12
 /**
12
 /**
13
  * Returns an object which contains the default buttons for the primary and
13
  * Returns an object which contains the default buttons for the primary and

正在加载...
取消
保存