Browse Source

feat(keyboard-shortcuts): show help in a react dialog (#2148)

* feat(keyboard-shortcuts): show help in a react dialog

- Move shortcut help dom declaration to a react component
- Let open/close logic be handled by AtlasKit Dialog
- Remove static html for help from index.html
- Consolidate keyboard shortcut css

* squash: use lozenge for key styling

* squash: use different iteration style

* squash: update package-lock for lozenge
master
virtuacoplenny 6 years ago
parent
commit
dc26b17d8b

+ 8
- 23
css/_keyboard-shortcuts.scss View File

@@ -1,25 +1,10 @@
1
-#keyboard-shortcuts {
2
-    display: none;
3
-    position: absolute;
4
-    bottom: 20px;
5
-    left: $defaultToolbarSize;
6
-    overflow: hidden;
7
-    padding: 20px;
8
-    margin-left: 10px;
9
-    z-index: $zindex10;
10
-    border-radius: $borderRadius;
11
-    background-attachment: scroll;
12
-    background-size: auto auto;
13
-    color: rgba(255, 255, 255, .8);
14
-    background-color: rgba(0, 0, 0, .8);
15
-}
1
+.shortcuts-list {
2
+    list-style-type: none;
3
+    padding: 0;
16 4
 
17
-#keyboard-shortcuts .item-action {
18
-    color: #209EFF;
19
-    font-size: 14pt;
20
-    padding-right: 5px;
5
+    &__item {
6
+        display: flex;
7
+        justify-content: space-between;
8
+        margin-bottom: em(7, 14);
9
+    }
21 10
 }
22
-
23
-#keyboard-shortcuts-list {
24
-    list-style-type: none;
25
-}

+ 0
- 1
css/main.scss View File

@@ -61,7 +61,6 @@
61 61
 @import 'redirect_page';
62 62
 @import 'components/form-control';
63 63
 @import 'components/link';
64
-@import 'shortcuts/main';
65 64
 @import 'components/button-control';
66 65
 @import 'components/input-control';
67 66
 @import 'components/input-slider';

+ 0
- 4
css/shortcuts/_main.scss View File

@@ -1,4 +0,0 @@
1
-/* Import shortcuts blocks */
2
-
3
-@import 'regular-key';
4
-@import 'shortcuts-list';

+ 0
- 11
css/shortcuts/_regular-key.scss View File

@@ -1,11 +0,0 @@
1
-.regular-key {
2
-    display: table-cell;
3
-    width: 25px;
4
-    height: 20px;
5
-    padding: 0;
6
-    text-align: center;
7
-    vertical-align: middle;
8
-    font-family: $baseFontFamily;
9
-    color: $defaultDarkColor;
10
-    font-size: 12px;
11
-}

+ 0
- 12
css/shortcuts/_shortcuts-list.scss View File

@@ -1,12 +0,0 @@
1
-.shortcuts-list {
2
-    padding: 0;
3
-
4
-    &__description {
5
-        margin-left: em(16, 14);
6
-        vertical-align: top;
7
-    }
8
-
9
-    &__item {
10
-        margin-bottom: em(7, 14);
11
-    }
12
-}

+ 0
- 6
index.html View File

@@ -139,11 +139,5 @@
139 139
   </head>
140 140
   <body>
141 141
     <div id="react"></div>
142
-    <div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
143
-        <div class="content">
144
-            <ul id="keyboard-shortcuts-list" class="shortcuts-list">
145
-            </ul>
146
-        </div>
147
-    </div>
148 142
   </body>
149 143
 </html>

+ 14
- 103
modules/keyboardshortcut/keyboardshortcut.js View File

@@ -2,40 +2,25 @@
2 2
 
3 3
 import { toggleDialog } from '../../react/features/base/dialog';
4 4
 import { sendAnalyticsEvent } from '../../react/features/analytics';
5
+import { KeyboardShortcutsDialog }
6
+    from '../../react/features/keyboard-shortcuts';
5 7
 import { SpeakerStats } from '../../react/features/speaker-stats';
6 8
 
7 9
 const logger = require('jitsi-meet-logger').getLogger(__filename);
8 10
 
9
-/**
10
- * The reference to the shortcut dialogs when opened.
11
- */
12
-let keyboardShortcutDialog = null;
13
-
14
-/**
15
- * Shows or hides the keyboard shortcuts dialog.
16
- * @param {boolean} show whether to show or hide the dialog
17
- */
18
-function showKeyboardShortcutsPanel(show) {
19
-    if (show
20
-            && !APP.UI.messageHandler.isDialogOpened()
21
-            && keyboardShortcutDialog === null) {
22
-        const msg = $('#keyboard-shortcuts').html();
23
-        const buttons = { Close: true };
24
-
25
-        keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
26
-            'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
27
-    } else if (keyboardShortcutDialog !== null) {
28
-        keyboardShortcutDialog.close();
29
-        keyboardShortcutDialog = null;
30
-    }
31
-}
32
-
33 11
 /**
34 12
  * Map of shortcuts. When a shortcut is registered it enters the mapping.
35 13
  * @type {{}}
36 14
  */
37 15
 const _shortcuts = {};
38 16
 
17
+/**
18
+ * Map of registered keyboard keys and translation keys describing the
19
+ * action performed by the key.
20
+ * @type {Map}
21
+ */
22
+const _shortcutsHelp = new Map();
23
+
39 24
 /**
40 25
  * True if the keyboard shortcuts are enabled and false if not.
41 26
  * @type {boolean}
@@ -133,30 +118,7 @@ const KeyboardShortcut = {
133 118
      */
134 119
     unregisterShortcut(shortcutChar) {
135 120
         _shortcuts.remove(shortcutChar);
136
-
137
-        this._removeShortcutFromHelp(shortcutChar);
138
-    },
139
-
140
-    /**
141
-     * Returns the tooltip string for the given shortcut attribute.
142
-     *
143
-     * @param shortcutAttr indicates the popover associated with the shortcut
144
-     * @returns {string} the tooltip string to add to the given shortcut popover
145
-     * or an empty string if the shortcutAttr is null, an empty string or not
146
-     * found in the shortcut mapping
147
-     */
148
-    getShortcutTooltip(shortcutAttr) {
149
-        if (typeof shortcutAttr === 'string' && shortcutAttr.length > 0) {
150
-            for (const key in _shortcuts) {
151
-                if (_shortcuts.hasOwnProperty(key)
152
-                    && _shortcuts[key].shortcutAttr
153
-                    && _shortcuts[key].shortcutAttr === shortcutAttr) {
154
-                    return ` (${_shortcuts[key].character})`;
155
-                }
156
-            }
157
-        }
158
-
159
-        return '';
121
+        _shortcutsHelp.delete(shortcutChar);
160 122
     },
161 123
 
162 124
     /**
@@ -196,56 +158,7 @@ const KeyboardShortcut = {
196 158
      * @private
197 159
      */
198 160
     _addShortcutToHelp(shortcutChar, shortcutDescriptionKey) {
199
-
200
-        const listElement = document.createElement('li');
201
-        const itemClass = 'shortcuts-list__item';
202
-
203
-        listElement.className = itemClass;
204
-        listElement.id = shortcutChar;
205
-
206
-        const spanElement = document.createElement('span');
207
-
208
-        spanElement.className = 'item-action';
209
-
210
-        const kbdElement = document.createElement('kbd');
211
-        const classes = 'aui-label regular-key';
212
-
213
-        kbdElement.className = classes;
214
-        kbdElement.innerHTML = shortcutChar;
215
-        spanElement.appendChild(kbdElement);
216
-
217
-        const descriptionElement = document.createElement('span');
218
-        const descriptionClass = 'shortcuts-list__description';
219
-
220
-        descriptionElement.className = descriptionClass;
221
-        descriptionElement.setAttribute('data-i18n', shortcutDescriptionKey);
222
-        APP.translation.translateElement($(descriptionElement));
223
-
224
-        listElement.appendChild(spanElement);
225
-        listElement.appendChild(descriptionElement);
226
-
227
-        const parentListElement
228
-            = document.getElementById('keyboard-shortcuts-list');
229
-
230
-        if (parentListElement) {
231
-            parentListElement.appendChild(listElement);
232
-        }
233
-    },
234
-
235
-    /**
236
-     * Removes the list element corresponding to the given shortcut from the
237
-     * help dialog
238
-     * @private
239
-     */
240
-    _removeShortcutFromHelp(shortcutChar) {
241
-        const parentListElement
242
-            = document.getElementById('keyboard-shortcuts-list');
243
-
244
-        const shortcutElement = document.getElementById(shortcutChar);
245
-
246
-        if (shortcutElement) {
247
-            parentListElement.removeChild(shortcutElement);
248
-        }
161
+        _shortcutsHelp.set(shortcutChar, shortcutDescriptionKey);
249 162
     },
250 163
 
251 164
     /**
@@ -255,13 +168,11 @@ const KeyboardShortcut = {
255 168
      * triggered _only_ with a shortcut.
256 169
      */
257 170
     _initGlobalShortcuts() {
258
-        this.registerShortcut('ESCAPE', null, () => {
259
-            showKeyboardShortcutsPanel(false);
260
-        });
261
-
262 171
         this.registerShortcut('?', null, () => {
263 172
             sendAnalyticsEvent('shortcut.shortcut.help');
264
-            showKeyboardShortcutsPanel(true);
173
+            APP.store.dispatch(toggleDialog(KeyboardShortcutsDialog, {
174
+                shortcutDescriptions: _shortcutsHelp
175
+            }));
265 176
         }, 'keyboardShortcuts.toggleShortcuts');
266 177
 
267 178
         // register SPACE shortcut in two steps to insure visibility of help

+ 21
- 0
package-lock.json View File

@@ -348,6 +348,27 @@
348 348
         }
349 349
       }
350 350
     },
351
+    "@atlaskit/lozenge": {
352
+      "version": "3.4.2",
353
+      "resolved": "https://registry.npmjs.org/@atlaskit/lozenge/-/lozenge-3.4.2.tgz",
354
+      "integrity": "sha1-GjCzTEGjj3jHcmSeCd2qS4AlMuw=",
355
+      "requires": {
356
+        "@atlaskit/util-shared-styles": "1.7.1",
357
+        "babel-runtime": "6.26.0",
358
+        "prop-types": "15.6.0",
359
+        "styled-components": "1.3.0"
360
+      },
361
+      "dependencies": {
362
+        "@atlaskit/util-shared-styles": {
363
+          "version": "1.7.1",
364
+          "resolved": "https://registry.npmjs.org/@atlaskit/util-shared-styles/-/util-shared-styles-1.7.1.tgz",
365
+          "integrity": "sha1-CDLLbMF5dDHEzPZ9F4qkES3zBeI=",
366
+          "requires": {
367
+            "babel-runtime": "6.26.0"
368
+          }
369
+        }
370
+      }
371
+    },
351 372
     "@atlaskit/modal-dialog": {
352 373
       "version": "2.6.0",
353 374
       "resolved": "https://registry.npmjs.org/@atlaskit/modal-dialog/-/modal-dialog-2.6.0.tgz",

+ 1
- 0
package.json View File

@@ -25,6 +25,7 @@
25 25
     "@atlaskit/icon": "10.0.0",
26 26
     "@atlaskit/inline-dialog": "5.0.2",
27 27
     "@atlaskit/inline-message": "3.0.1",
28
+    "@atlaskit/lozenge": "3.4.2",
28 29
     "@atlaskit/modal-dialog": "2.6.0",
29 30
     "@atlaskit/multi-select": "7.1.3",
30 31
     "@atlaskit/spinner": "4.0.0",

+ 0
- 0
react/features/keyboard-shortcuts/components/KeyboardShortcutsDialog.native.js View File


+ 86
- 0
react/features/keyboard-shortcuts/components/KeyboardShortcutsDialog.web.js View File

@@ -0,0 +1,86 @@
1
+import Lozenge from '@atlaskit/lozenge';
2
+import PropTypes from 'prop-types';
3
+import React, { Component } from 'react';
4
+
5
+import { Dialog } from '../../base/dialog';
6
+import { translate } from '../../base/i18n';
7
+
8
+/**
9
+ * Implements a React {@link Component} which displays a dialog describing
10
+ * registered keyboard shortcuts.
11
+ *
12
+ * @extends Component
13
+ */
14
+class KeyboardShortcutsDialog extends Component {
15
+    /**
16
+     * {@code KeyboardShortcutsDialog} component's property types.
17
+     *
18
+     * @static
19
+     */
20
+    static propTypes = {
21
+        /**
22
+         * A Map with keyboard keys as keys and translation keys as values.
23
+         */
24
+        shortcutDescriptions: PropTypes.object,
25
+
26
+        /**
27
+         * Invoked to obtain translated strings.
28
+         */
29
+        t: PropTypes.func
30
+    };
31
+
32
+    /**
33
+     * Implements React's {@link Component#render()}.
34
+     *
35
+     * @inheritdoc
36
+     * @returns {ReactElement}
37
+     */
38
+    render() {
39
+        const shortcuts = Array.from(this.props.shortcutDescriptions)
40
+            .map(description => this._renderShortcutsListItem(...description));
41
+
42
+        return (
43
+            <Dialog
44
+                cancelTitleKey = { 'dialog.close' }
45
+                submitDisabled = { true }
46
+                titleKey = 'keyboardShortcuts.keyboardShortcuts'
47
+                width = 'small'>
48
+                <div
49
+                    id = 'keyboard-shortcuts'>
50
+                    <ul
51
+                        className = 'shortcuts-list'
52
+                        id = 'keyboard-shortcuts-list'>
53
+                        { shortcuts }
54
+                    </ul>
55
+                </div>
56
+            </Dialog>
57
+        );
58
+    }
59
+
60
+    /**
61
+     * Creates a {@code ReactElement} for describing a single keyboard shortcut.
62
+     *
63
+     * @param {string} keyboardKey - The keyboard key that triggers an action.
64
+     * @param {string} translationKey - A description of what the action does.
65
+     * @private
66
+     * @returns {ReactElement}
67
+     */
68
+    _renderShortcutsListItem(keyboardKey, translationKey) {
69
+        return (
70
+            <li
71
+                className = 'shortcuts-list__item'
72
+                key = { keyboardKey }>
73
+                <span className = 'shortcuts-list__description'>
74
+                    { this.props.t(translationKey) }
75
+                </span>
76
+                <span className = 'item-action'>
77
+                    <Lozenge isBold = { true }>
78
+                        { keyboardKey }
79
+                    </Lozenge>
80
+                </span>
81
+            </li>
82
+        );
83
+    }
84
+}
85
+
86
+export default translate(KeyboardShortcutsDialog);

+ 1
- 0
react/features/keyboard-shortcuts/components/index.js View File

@@ -0,0 +1 @@
1
+export { default as KeyboardShortcutsDialog } from './KeyboardShortcutsDialog';

+ 1
- 0
react/features/keyboard-shortcuts/index.js View File

@@ -0,0 +1 @@
1
+export * from './components';

Loading…
Cancel
Save