Ver código fonte

Attach keyboard shortcuts to features

master
yanas 8 anos atrás
pai
commit
7076ada6f4

+ 5
- 0
css/keyboard-shortcuts.css Ver arquivo

@@ -16,4 +16,9 @@
16 16
 #keyboard-shortcuts .item-action {
17 17
     color: #209EFF;
18 18
     font-size: 14pt;
19
+    padding-right: 5px;
20
+}
21
+
22
+#keyboard-shortcuts-list {
23
+    list-style-type: none;
19 24
 }

+ 1
- 61
index.html Ver arquivo

@@ -279,67 +279,7 @@
279 279
     <div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
280 280
         <div class="header"><h3 data-i18n="keyboardShortcuts.keyboardShortcuts"></h3></div>
281 281
         <div class="content">
282
-            <ul class="item">
283
-                <li>
284
-                    <span class="item-action">
285
-                        <kbd class="regular-key">M</kbd>
286
-                    </span>
287
-                    <span class="item-description" data-i18n="keyboardShortcuts.mute"></span>
288
-                </li>
289
-                <li>
290
-                    <span class="item-action">
291
-                        <kbd class="regular-key">V</kbd>
292
-                    </span>
293
-                    <span class="item-description" data-i18n="keyboardShortcuts.videoMute"></span>
294
-                </li>
295
-                <li>
296
-                    <span class="item-action">
297
-                        <kbd class="regular-key">C</kbd>
298
-                    </span>
299
-                    <span class="item-description" data-i18n="keyboardShortcuts.toggleChat"></span>
300
-                </li>
301
-                <li>
302
-                    <span class="item-action">
303
-                        <kbd class="regular-key">R</kbd>
304
-                    </span>
305
-                    <span class="item-description" data-i18n="keyboardShortcuts.raiseHand"></span>
306
-                </li>
307
-                <li>
308
-                    <span class="item-action">
309
-                        <kbd class="regular-key">T</kbd>
310
-                    </span>
311
-                    <span class="item-description" data-i18n="keyboardShortcuts.pushToTalk"></span>
312
-                </li>
313
-                <li>
314
-                    <span class="item-action">
315
-                        <kbd class="regular-key">D</kbd>
316
-                    </span>
317
-                    <span class="item-description" data-i18n="keyboardShortcuts.toggleScreensharing"></span>
318
-                </li>
319
-                <li class="item-details">
320
-                    <span class="item-action">
321
-                        <kbd class="regular-key">F</kbd>
322
-                    </span>
323
-                    <span class="item-description" data-i18n="keyboardShortcuts.toggleFilmstrip"></span>
324
-                </li>
325
-                <li>
326
-                    <span class="item-action">
327
-                        <kbd class="regular-key">?</kbd>
328
-                    </span>
329
-                    <span class="item-description" data-i18n="keyboardShortcuts.toggleShortcuts"></span>
330
-                </li>
331
-                <li>
332
-                    <span class="item-action">
333
-                        <kbd class="regular-key">0</kbd>
334
-                    </span>
335
-                    <span class="item-description" data-i18n="keyboardShortcuts.focusLocal"></span>
336
-                </li>
337
-                <li>
338
-                    <span class="item-action">
339
-                        <kbd class="regular-key">1-9</kbd>
340
-                    </span>
341
-                    <span class="item-description" data-i18n="keyboardShortcuts.focusRemote"></span>
342
-                </li>
282
+            <ul id="keyboard-shortcuts-list" class="item">
343 283
             </ul>
344 284
         </div>
345 285
     </div>

+ 9
- 3
modules/UI/toolbars/BottomToolbar.js Ver arquivo

@@ -3,9 +3,15 @@ import UIUtil from '../util/UIUtil';
3 3
 import UIEvents from '../../../service/UI/UIEvents';
4 4
 
5 5
 const defaultBottomToolbarButtons = {
6
-    'chat':      '#bottom_toolbar_chat',
7
-    'contacts':  '#bottom_toolbar_contact_list',
8
-    'filmstrip': '#bottom_toolbar_film_strip'
6
+    'chat': {
7
+        id: '#bottom_toolbar_chat'
8
+    },
9
+    'contacts': {
10
+        id: '#bottom_toolbar_contact_list'
11
+    },
12
+    'filmstrip': {
13
+        id: '#bottom_toolbar_film_strip'
14
+    }
9 15
 };
10 16
 
11 17
 const BottomToolbar = {

+ 77
- 11
modules/UI/toolbars/Toolbar.js Ver arquivo

@@ -2,6 +2,7 @@
2 2
 /* jshint -W101 */
3 3
 import UIUtil from '../util/UIUtil';
4 4
 import UIEvents from '../../../service/UI/UIEvents';
5
+import KeyboardShortcut from '../../keyboardshortcut/KeyboardShortcut';
5 6
 
6 7
 let roomUrl = null;
7 8
 let emitter = null;
@@ -110,7 +111,8 @@ const buttonHandlers = {
110 111
     },
111 112
     "toolbar_button_fullScreen": function() {
112 113
         JitsiMeetJS.analytics.sendEvent('toolbar.fullscreen.enabled');
113
-        UIUtil.buttonClick("#toolbar_button_fullScreen", "icon-full-screen icon-exit-full-screen");
114
+        UIUtil.buttonClick("#toolbar_button_fullScreen",
115
+            "icon-full-screen icon-exit-full-screen");
114 116
         emitter.emit(UIEvents.FULLSCREEN_TOGGLE);
115 117
     },
116 118
     "toolbar_button_sip": function () {
@@ -152,16 +154,64 @@ const buttonHandlers = {
152 154
     }
153 155
 };
154 156
 const defaultToolbarButtons = {
155
-    'microphone': '#toolbar_button_mute',
156
-    'camera':     '#toolbar_button_camera',
157
-    'desktop':    '#toolbar_button_desktopsharing',
158
-    'security':   '#toolbar_button_security',
159
-    'invite':     '#toolbar_button_link',
160
-    'chat':       '#toolbar_button_chat',
161
-    'etherpad':   '#toolbar_button_etherpad',
162
-    'fullscreen': '#toolbar_button_fullScreen',
163
-    'settings':   '#toolbar_button_settings',
164
-    'hangup':     '#toolbar_button_hangup'
157
+    'microphone': {
158
+        id: '#toolbar_button_mute',
159
+        shortcut: 'M',
160
+        shortcutAttr: 'mutePopover',
161
+        shortcutFunc: function() {
162
+            JitsiMeetJS.analytics.sendEvent('shortcut.audiomute.toggled');
163
+            APP.conference.toggleAudioMuted();
164
+        },
165
+        shortcutDescription: "keyboardShortcuts.mute"
166
+    },
167
+    'camera': {
168
+        id: '#toolbar_button_camera',
169
+        shortcut: 'V',
170
+        shortcutAttr: 'toggleVideoPopover',
171
+        shortcutFunc: function() {
172
+            JitsiMeetJS.analytics.sendEvent('shortcut.videomute.toggled');
173
+            APP.conference.toggleVideoMuted();
174
+        },
175
+        shortcutDescription: "keyboardShortcuts.videoMute"
176
+    },
177
+    'desktop': {
178
+        id: '#toolbar_button_desktopsharing',
179
+        shortcut: 'D',
180
+        shortcutAttr: 'toggleDesktopSharingPopover',
181
+        shortcutFunc: function() {
182
+            JitsiMeetJS.analytics.sendEvent('shortcut.screen.toggled');
183
+            APP.conference.toggleScreenSharing();
184
+        },
185
+        shortcutDescription: "keyboardShortcuts.toggleScreensharing"
186
+    },
187
+    'security': {
188
+        id: '#toolbar_button_security'
189
+    },
190
+    'invite': {
191
+        id: '#toolbar_button_link'
192
+    },
193
+    'chat': {
194
+        id: '#toolbar_button_chat',
195
+        shortcut: 'C',
196
+        shortcutAttr: 'toggleChatPopover',
197
+        shortcutFunc: function() {
198
+            JitsiMeetJS.analytics.sendEvent('shortcut.chat.toggled');
199
+            APP.UI.toggleChat();
200
+        },
201
+        shortcutDescription: "keyboardShortcuts.toggleChat"
202
+    },
203
+    'etherpad': {
204
+        id: '#toolbar_button_etherpad'
205
+    },
206
+    'fullscreen': {
207
+        id: '#toolbar_button_fullScreen'
208
+    },
209
+    'settings': {
210
+        id: '#toolbar_button_settings'
211
+    },
212
+    'hangup': {
213
+        id: '#toolbar_button_hangup'
214
+    }
165 215
 };
166 216
 
167 217
 function dialpadButtonClicked() {
@@ -197,6 +247,22 @@ const Toolbar = {
197 247
 
198 248
         UIUtil.hideDisabledButtons(defaultToolbarButtons);
199 249
 
250
+        Object.keys(defaultToolbarButtons).forEach(
251
+            id => {
252
+                if (UIUtil.isButtonEnabled(id)) {
253
+                    var button = defaultToolbarButtons[id];
254
+
255
+                    if (button.shortcut)
256
+                        KeyboardShortcut.registerShortcut(
257
+                            button.shortcut,
258
+                            button.shortcutAttr,
259
+                            button.shortcutFunc,
260
+                            button.shortcutDescription
261
+                        );
262
+                }
263
+            }
264
+        );
265
+
200 266
         Object.keys(buttonHandlers).forEach(
201 267
             buttonId => $(`#${buttonId}`).click(function(event) {
202 268
                 !$(this).prop('disabled') && buttonHandlers[buttonId](event);

+ 1
- 1
modules/UI/util/UIUtil.js Ver arquivo

@@ -130,7 +130,7 @@
130 130
         var selector = Object.keys(mappings)
131 131
           .map(function (buttonName) {
132 132
                 return UIUtil.isButtonEnabled(buttonName)
133
-                    ? null : mappings[buttonName]; })
133
+                    ? null : mappings[buttonName].id; })
134 134
           .filter(function (item) { return item; })
135 135
           .join(',');
136 136
         $(selector).hide();

+ 128
- 84
modules/keyboardshortcut/keyboardshortcut.js Ver arquivo

@@ -1,91 +1,64 @@
1 1
 /* global APP, $, JitsiMeetJS */
2
-//maps keycode to character, id of popover for given function and function
3
-var shortcuts = {};
4
-function initShortcutHandlers() {
5
-    shortcuts = {
6
-        "ESCAPE": {
7
-            character: "Esc",
8
-            function: function() {
9
-                APP.UI.showKeyboardShortcutsPanel(false);
10
-            }
11
-        },
12
-        "C": {
13
-            character: "C",
14
-            id: "toggleChatPopover",
15
-            function: function() {
16
-                JitsiMeetJS.analytics.sendEvent('shortcut.chat.toggled');
17
-                APP.UI.toggleChat();
18
-            }
19
-        },
20
-        "D": {
21
-            character: "D",
22
-            id: "toggleDesktopSharingPopover",
23
-            function: function () {
24
-                JitsiMeetJS.analytics.sendEvent('shortcut.screen.toggled');
25
-                APP.conference.toggleScreenSharing();
26
-            }
27
-        },
28
-        "F": {
29
-            character: "F",
30
-            id: "filmstripPopover",
31
-            function: function() {
32
-                JitsiMeetJS.analytics.sendEvent('shortcut.film.toggled');
33
-                APP.UI.toggleFilmStrip();
34
-            }
35
-        },
36
-        "M": {
37
-            character: "M",
38
-            id: "mutePopover",
39
-            function: function() {
40
-                JitsiMeetJS.analytics.sendEvent('shortcut.audiomute.toggled');
41
-                APP.conference.toggleAudioMuted();
42
-            }
43
-        },
44
-        "R": {
45
-            character: "R",
46
-            function: function() {
47
-                JitsiMeetJS.analytics.sendEvent('shortcut.raisedhand.toggled');
48
-                APP.conference.maybeToggleRaisedHand();
49
-            }
50 2
 
51
-        },
52
-        "T": {
53
-            character: "T",
54
-            function: function() {
55
-                JitsiMeetJS.analytics.sendEvent('shortcut.talk.clicked');
56
-                APP.conference.muteAudio(true);
57
-            }
58
-        },
59
-        "V": {
60
-            character: "V",
61
-            id: "toggleVideoPopover",
62
-            function: function() {
63
-                JitsiMeetJS.analytics.sendEvent('shortcut.videomute.toggled');
64
-                APP.conference.toggleVideoMuted();
65
-            }
66
-        },
67
-        "?": {
68
-            character: "?",
69
-            function: function(e) {
70
-                JitsiMeetJS.analytics.sendEvent('shortcut.shortcut.help');
71
-                APP.UI.toggleKeyboardShortcutsPanel();
72
-            }
73
-        }
74
-    };
3
+/**
4
+ * Initialise global shortcuts.
5
+ * Global shortcuts are shortcuts for features that don't have a button or
6
+ * link associated with the action. In other words they represent actions
7
+ * triggered _only_ with a shortcut.
8
+ */
9
+function initGlobalShortcuts() {
10
+
11
+    KeyboardShortcut.registerShortcut("ESCAPE", null, function() {
12
+        APP.UI.showKeyboardShortcutsPanel(false);
13
+    });
14
+
15
+    KeyboardShortcut.registerShortcut("?", null, function() {
16
+        JitsiMeetJS.analytics.sendEvent("shortcut.shortcut.help");
17
+        APP.UI.toggleKeyboardShortcutsPanel();
18
+    }, "keyboardShortcuts.toggleShortcuts");
19
+
20
+    KeyboardShortcut.registerShortcut("R", null, function() {
21
+        JitsiMeetJS.analytics.sendEvent("shortcut.raisedhand.toggled");
22
+        APP.conference.maybeToggleRaisedHand();
23
+    }, "keyboardShortcuts.raiseHand");
24
+
25
+    KeyboardShortcut.registerShortcut("T", null, function() {
26
+        JitsiMeetJS.analytics.sendEvent("shortcut.talk.clicked");
27
+        APP.conference.muteAudio(true);
28
+    }, "keyboardShortcuts.pushToTalk");
29
+
30
+    KeyboardShortcut.registerShortcut("F", 'filmstripPopover', function() {
31
+        JitsiMeetJS.analytics.sendEvent("shortcut.film.toggled");
32
+        APP.UI.toggleFilmStrip();
33
+    }, "keyboardShortcuts.toggleFilmstrip");
34
+
35
+    // Focus keys are directly implemented below.
36
+    KeyboardShortcut._addShortcutToHelp("0", "keyboardShortcuts.focusLocal");
37
+    KeyboardShortcut._addShortcutToHelp("1-9", "keyboardShortcuts.focusRemote");
75 38
 }
76 39
 
40
+/**
41
+ * Map of shortcuts. When a shortcut is registered it enters the mapping.
42
+ * @type {{}}
43
+ */
44
+let _shortcuts = {};
45
+
46
+/**
47
+ * Maps keycode to character, id of popover for given function and function.
48
+ */
77 49
 var KeyboardShortcut = {
78 50
     init: function () {
79
-        initShortcutHandlers();
51
+        initGlobalShortcuts();
52
+
80 53
         var self = this;
81 54
         window.onkeyup = function(e) {
82
-            var key = self.getKeyboardKey(e).toUpperCase();
55
+            var key = self._getKeyboardKey(e).toUpperCase();
83 56
             var num = parseInt(key, 10);
84 57
             if(!($(":focus").is("input[type=text]") ||
85 58
                 $(":focus").is("input[type=password]") ||
86 59
                 $(":focus").is("textarea"))) {
87
-                if (shortcuts.hasOwnProperty(key)) {
88
-                    shortcuts[key].function(e);
60
+                if (_shortcuts.hasOwnProperty(key)) {
61
+                    _shortcuts[key].function(e);
89 62
                 }
90 63
                 else if (!isNaN(num) && num >= 0 && num <= 9) {
91 64
                     APP.UI.clickOnVideo(num + 1);
@@ -101,7 +74,7 @@ var KeyboardShortcut = {
101 74
             if(!($(":focus").is("input[type=text]") ||
102 75
                 $(":focus").is("input[type=password]") ||
103 76
                 $(":focus").is("textarea"))) {
104
-                var key = self.getKeyboardKey(e).toUpperCase();
77
+                var key = self._getKeyboardKey(e).toUpperCase();
105 78
                 if(key === "T") {
106 79
                     if(APP.conference.isLocalAudioMuted())
107 80
                         APP.conference.muteAudio(false);
@@ -112,20 +85,56 @@ var KeyboardShortcut = {
112 85
             trigger: 'click hover',
113 86
             content: function() {
114 87
                 return this.getAttribute("content") +
115
-                    self.getShortcut(this.getAttribute("shortcut"));
88
+                    self._getShortcut(this.getAttribute("shortcut"));
116 89
             }
117 90
         });
118 91
     },
92
+
93
+    /**
94
+     * Registers a new shortcut.
95
+     *
96
+     * @param shortcutChar the shortcut character triggering the action
97
+     * @param shortcutAttr the "shortcut" html element attribute mappring an
98
+     * element to this shortcut and used to show the shortcut character on the
99
+     * element tooltip
100
+     * @param exec the function to be executed when the shortcut is pressed
101
+     * @param helpDescription the description of the shortcut that would appear
102
+     * in the help menu
103
+     */
104
+    registerShortcut: function( shortcutChar,
105
+                                shortcutAttr,
106
+                                exec,
107
+                                helpDescription) {
108
+        _shortcuts[shortcutChar] = {
109
+            character: shortcutChar,
110
+            shortcutAttr: shortcutAttr,
111
+            function: exec
112
+        };
113
+
114
+        if (helpDescription)
115
+            this._addShortcutToHelp(shortcutChar, helpDescription);
116
+    },
117
+
118
+    /**
119
+     * Unregisters a shortcut.
120
+     *
121
+     * @param shortcutChar unregisters the given shortcut, which means it will
122
+     * no longer be usable
123
+     */
124
+    unregisterShortcut: function(shortcutChar) {
125
+        _shortcuts.remove(shortcutChar);
126
+    },
127
+
119 128
     /**
120 129
      *
121 130
      * @param id indicates the popover associated with the shortcut
122 131
      * @returns {string} the keyboard shortcut used for the id given
123 132
      */
124
-    getShortcut: function (id) {
125
-        for (var key in shortcuts) {
126
-            if (shortcuts.hasOwnProperty(key)) {
127
-                if (shortcuts[key].id === id) {
128
-                    return " (" + shortcuts[key].character + ")";
133
+    _getShortcut: function (id) {
134
+        for (var key in _shortcuts) {
135
+            if (_shortcuts.hasOwnProperty(key)) {
136
+                if (_shortcuts[key].shortcutAttr === id) {
137
+                    return " (" + _shortcuts[key].character + ")";
129 138
                 }
130 139
             }
131 140
         }
@@ -135,7 +144,7 @@ var KeyboardShortcut = {
135 144
      * @param e a KeyboardEvent
136 145
      * @returns {string} e.key or something close if not supported
137 146
      */
138
-    getKeyboardKey: function (e) {
147
+    _getKeyboardKey: function (e) {
139 148
         if (typeof e.key === "string") {
140 149
             return e.key;
141 150
         }
@@ -156,6 +165,41 @@ var KeyboardShortcut = {
156 165
         } else {
157 166
             return String.fromCharCode(e.which).toLowerCase();
158 167
         }
168
+    },
169
+
170
+    /**
171
+     * Adds the given shortcut to the help dialog.
172
+     *
173
+     * @param shortcutChar the shortcut character
174
+     * @param shortcutDescriptionKey the description of the shortcut
175
+     * @private
176
+     */
177
+    _addShortcutToHelp: function (shortcutChar, shortcutDescriptionKey) {
178
+
179
+        var listElement = document.createElement("li");
180
+
181
+        var spanElement = document.createElement("span");
182
+        spanElement.className = "item-action";
183
+
184
+        var kbdElement = document.createElement("kbd");
185
+        kbdElement.className = "regular-key";
186
+        kbdElement.innerHTML = shortcutChar;
187
+        spanElement.appendChild(kbdElement);
188
+
189
+        var descriptionElement = document.createElement("span");
190
+        descriptionElement.className = "item-description";
191
+        descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
192
+        descriptionElement.innerHTML
193
+            = APP.translation.translateString(shortcutDescriptionKey);
194
+
195
+        listElement.appendChild(spanElement);
196
+        listElement.appendChild(descriptionElement);
197
+
198
+        var parentListElement
199
+            = document.getElementById("keyboard-shortcuts-list");
200
+
201
+        if (parentListElement)
202
+            parentListElement.appendChild(listElement);
159 203
     }
160 204
 };
161 205
 

Carregando…
Cancelar
Salvar