Merge pull request #812 from jitsi/attach-shortcuts-to-features

Attach keyboard shortcuts to features
This commit is contained in:
hristoterezov 2016-08-29 16:05:12 -05:00 committed by GitHub
commit cac7ccf176
6 changed files with 260 additions and 160 deletions

View File

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

View File

@ -279,67 +279,7 @@
<div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
<div class="header"><h3 data-i18n="keyboardShortcuts.keyboardShortcuts"></h3></div>
<div class="content">
<ul class="item">
<li>
<span class="item-action">
<kbd class="regular-key">M</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.mute"></span>
</li>
<li>
<span class="item-action">
<kbd class="regular-key">V</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.videoMute"></span>
</li>
<li>
<span class="item-action">
<kbd class="regular-key">C</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.toggleChat"></span>
</li>
<li>
<span class="item-action">
<kbd class="regular-key">R</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.raiseHand"></span>
</li>
<li>
<span class="item-action">
<kbd class="regular-key">T</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.pushToTalk"></span>
</li>
<li>
<span class="item-action">
<kbd class="regular-key">D</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.toggleScreensharing"></span>
</li>
<li class="item-details">
<span class="item-action">
<kbd class="regular-key">F</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.toggleFilmstrip"></span>
</li>
<li>
<span class="item-action">
<kbd class="regular-key">?</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.toggleShortcuts"></span>
</li>
<li>
<span class="item-action">
<kbd class="regular-key">0</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.focusLocal"></span>
</li>
<li>
<span class="item-action">
<kbd class="regular-key">1-9</kbd>
</span>
<span class="item-description" data-i18n="keyboardShortcuts.focusRemote"></span>
</li>
<ul id="keyboard-shortcuts-list" class="item">
</ul>
</div>
</div>

View File

@ -3,9 +3,22 @@ import UIUtil from '../util/UIUtil';
import UIEvents from '../../../service/UI/UIEvents';
const defaultBottomToolbarButtons = {
'chat': '#bottom_toolbar_chat',
'contacts': '#bottom_toolbar_contact_list',
'filmstrip': '#bottom_toolbar_film_strip'
'chat': {
id: '#bottom_toolbar_chat'
},
'contacts': {
id: '#bottom_toolbar_contact_list'
},
'filmstrip': {
id: '#bottom_toolbar_film_strip',
shortcut: "F",
shortcutAttr: "filmstripPopover",
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent("shortcut.film.toggled");
APP.UI.toggleFilmStrip();
},
shortcutDescription: "keyboardShortcuts.toggleFilmstrip"
}
};
const BottomToolbar = {
@ -32,6 +45,7 @@ const BottomToolbar = {
isEnabled() {
return this.enabled;
},
setupListeners (emitter) {
UIUtil.hideDisabledButtons(defaultBottomToolbarButtons);
@ -52,6 +66,22 @@ const BottomToolbar = {
}
};
Object.keys(defaultBottomToolbarButtons).forEach(
id => {
if (UIUtil.isButtonEnabled(id)) {
var button = defaultBottomToolbarButtons[id];
if (button.shortcut)
APP.keyboardshortcut.registerShortcut(
button.shortcut,
button.shortcutAttr,
button.shortcutFunc,
button.shortcutDescription
);
}
}
);
Object.keys(buttonHandlers).forEach(
buttonId => $(`#${buttonId}`).click(buttonHandlers[buttonId])
);

View File

@ -110,7 +110,8 @@ const buttonHandlers = {
},
"toolbar_button_fullScreen": function() {
JitsiMeetJS.analytics.sendEvent('toolbar.fullscreen.enabled');
UIUtil.buttonClick("#toolbar_button_fullScreen", "icon-full-screen icon-exit-full-screen");
UIUtil.buttonClick("#toolbar_button_fullScreen",
"icon-full-screen icon-exit-full-screen");
emitter.emit(UIEvents.FULLSCREEN_TOGGLE);
},
"toolbar_button_sip": function () {
@ -152,16 +153,64 @@ const buttonHandlers = {
}
};
const defaultToolbarButtons = {
'microphone': '#toolbar_button_mute',
'camera': '#toolbar_button_camera',
'desktop': '#toolbar_button_desktopsharing',
'security': '#toolbar_button_security',
'invite': '#toolbar_button_link',
'chat': '#toolbar_button_chat',
'etherpad': '#toolbar_button_etherpad',
'fullscreen': '#toolbar_button_fullScreen',
'settings': '#toolbar_button_settings',
'hangup': '#toolbar_button_hangup'
'microphone': {
id: '#toolbar_button_mute',
shortcut: 'M',
shortcutAttr: 'mutePopover',
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.audiomute.toggled');
APP.conference.toggleAudioMuted();
},
shortcutDescription: "keyboardShortcuts.mute"
},
'camera': {
id: '#toolbar_button_camera',
shortcut: 'V',
shortcutAttr: 'toggleVideoPopover',
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.videomute.toggled');
APP.conference.toggleVideoMuted();
},
shortcutDescription: "keyboardShortcuts.videoMute"
},
'desktop': {
id: '#toolbar_button_desktopsharing',
shortcut: 'D',
shortcutAttr: 'toggleDesktopSharingPopover',
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.screen.toggled');
APP.conference.toggleScreenSharing();
},
shortcutDescription: "keyboardShortcuts.toggleScreensharing"
},
'security': {
id: '#toolbar_button_security'
},
'invite': {
id: '#toolbar_button_link'
},
'chat': {
id: '#toolbar_button_chat',
shortcut: 'C',
shortcutAttr: 'toggleChatPopover',
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.chat.toggled');
APP.UI.toggleChat();
},
shortcutDescription: "keyboardShortcuts.toggleChat"
},
'etherpad': {
id: '#toolbar_button_etherpad'
},
'fullscreen': {
id: '#toolbar_button_fullScreen'
},
'settings': {
id: '#toolbar_button_settings'
},
'hangup': {
id: '#toolbar_button_hangup'
}
};
function dialpadButtonClicked() {
@ -197,6 +246,22 @@ const Toolbar = {
UIUtil.hideDisabledButtons(defaultToolbarButtons);
Object.keys(defaultToolbarButtons).forEach(
id => {
if (UIUtil.isButtonEnabled(id)) {
var button = defaultToolbarButtons[id];
if (button.shortcut)
APP.keyboardshortcut.registerShortcut(
button.shortcut,
button.shortcutAttr,
button.shortcutFunc,
button.shortcutDescription
);
}
}
);
Object.keys(buttonHandlers).forEach(
buttonId => $(`#${buttonId}`).click(function(event) {
!$(this).prop('disabled') && buttonHandlers[buttonId](event);

View File

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

View File

@ -1,91 +1,62 @@
/* global APP, $, JitsiMeetJS */
//maps keycode to character, id of popover for given function and function
var shortcuts = {};
function initShortcutHandlers() {
shortcuts = {
"ESCAPE": {
character: "Esc",
function: function() {
APP.UI.showKeyboardShortcutsPanel(false);
}
},
"C": {
character: "C",
id: "toggleChatPopover",
function: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.chat.toggled');
APP.UI.toggleChat();
}
},
"D": {
character: "D",
id: "toggleDesktopSharingPopover",
function: function () {
JitsiMeetJS.analytics.sendEvent('shortcut.screen.toggled');
APP.conference.toggleScreenSharing();
}
},
"F": {
character: "F",
id: "filmstripPopover",
function: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.film.toggled');
APP.UI.toggleFilmStrip();
}
},
"M": {
character: "M",
id: "mutePopover",
function: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.audiomute.toggled');
APP.conference.toggleAudioMuted();
}
},
"R": {
character: "R",
function: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.raisedhand.toggled');
APP.conference.maybeToggleRaisedHand();
}
},
"T": {
character: "T",
function: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.talk.clicked');
APP.conference.muteAudio(true);
}
},
"V": {
character: "V",
id: "toggleVideoPopover",
function: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.videomute.toggled');
APP.conference.toggleVideoMuted();
}
},
"?": {
character: "?",
function: function(e) {
JitsiMeetJS.analytics.sendEvent('shortcut.shortcut.help');
APP.UI.toggleKeyboardShortcutsPanel();
}
}
};
/**
* Initialise global shortcuts.
* Global shortcuts are shortcuts for features that don't have a button or
* link associated with the action. In other words they represent actions
* triggered _only_ with a shortcut.
*/
function initGlobalShortcuts() {
KeyboardShortcut.registerShortcut("ESCAPE", null, function() {
APP.UI.showKeyboardShortcutsPanel(false);
});
KeyboardShortcut.registerShortcut("?", null, function() {
JitsiMeetJS.analytics.sendEvent("shortcut.shortcut.help");
APP.UI.toggleKeyboardShortcutsPanel();
}, "keyboardShortcuts.toggleShortcuts");
KeyboardShortcut.registerShortcut("R", null, function() {
JitsiMeetJS.analytics.sendEvent("shortcut.raisedhand.toggled");
APP.conference.maybeToggleRaisedHand();
}, "keyboardShortcuts.raiseHand");
KeyboardShortcut.registerShortcut("T", null, function() {
JitsiMeetJS.analytics.sendEvent("shortcut.talk.clicked");
APP.conference.muteAudio(true);
}, "keyboardShortcuts.pushToTalk");
/**
* FIXME: Currently focus keys are directly implemented below in onkeyup.
* They should be moved to the SmallVideo instead.
*/
KeyboardShortcut._addShortcutToHelp("0", "keyboardShortcuts.focusLocal");
KeyboardShortcut._addShortcutToHelp("1-9", "keyboardShortcuts.focusRemote");
}
/**
* Map of shortcuts. When a shortcut is registered it enters the mapping.
* @type {{}}
*/
let _shortcuts = {};
/**
* Maps keycode to character, id of popover for given function and function.
*/
var KeyboardShortcut = {
init: function () {
initShortcutHandlers();
initGlobalShortcuts();
var self = this;
window.onkeyup = function(e) {
var key = self.getKeyboardKey(e).toUpperCase();
var key = self._getKeyboardKey(e).toUpperCase();
var num = parseInt(key, 10);
if(!($(":focus").is("input[type=text]") ||
$(":focus").is("input[type=password]") ||
$(":focus").is("textarea"))) {
if (shortcuts.hasOwnProperty(key)) {
shortcuts[key].function(e);
if (_shortcuts.hasOwnProperty(key)) {
_shortcuts[key].function(e);
}
else if (!isNaN(num) && num >= 0 && num <= 9) {
APP.UI.clickOnVideo(num + 1);
@ -101,7 +72,7 @@ var KeyboardShortcut = {
if(!($(":focus").is("input[type=text]") ||
$(":focus").is("input[type=password]") ||
$(":focus").is("textarea"))) {
var key = self.getKeyboardKey(e).toUpperCase();
var key = self._getKeyboardKey(e).toUpperCase();
if(key === "T") {
if(APP.conference.isLocalAudioMuted())
APP.conference.muteAudio(false);
@ -112,20 +83,58 @@ var KeyboardShortcut = {
trigger: 'click hover',
content: function() {
return this.getAttribute("content") +
self.getShortcut(this.getAttribute("shortcut"));
self._getShortcut(this.getAttribute("shortcut"));
}
});
},
/**
* Registers a new shortcut.
*
* @param shortcutChar the shortcut character triggering the action
* @param shortcutAttr the "shortcut" html element attribute mappring an
* element to this shortcut and used to show the shortcut character on the
* element tooltip
* @param exec the function to be executed when the shortcut is pressed
* @param helpDescription the description of the shortcut that would appear
* in the help menu
*/
registerShortcut: function( shortcutChar,
shortcutAttr,
exec,
helpDescription) {
_shortcuts[shortcutChar] = {
character: shortcutChar,
shortcutAttr: shortcutAttr,
function: exec
};
if (helpDescription)
this._addShortcutToHelp(shortcutChar, helpDescription);
},
/**
* Unregisters a shortcut.
*
* @param shortcutChar unregisters the given shortcut, which means it will
* no longer be usable
*/
unregisterShortcut: function(shortcutChar) {
_shortcuts.remove(shortcutChar);
this._removeShortcutFromHelp(shortcutChar);
},
/**
*
* @param id indicates the popover associated with the shortcut
* @returns {string} the keyboard shortcut used for the id given
*/
getShortcut: function (id) {
for (var key in shortcuts) {
if (shortcuts.hasOwnProperty(key)) {
if (shortcuts[key].id === id) {
return " (" + shortcuts[key].character + ")";
_getShortcut: function (id) {
for (var key in _shortcuts) {
if (_shortcuts.hasOwnProperty(key)) {
if (_shortcuts[key].shortcutAttr === id) {
return " (" + _shortcuts[key].character + ")";
}
}
}
@ -135,7 +144,7 @@ var KeyboardShortcut = {
* @param e a KeyboardEvent
* @returns {string} e.key or something close if not supported
*/
getKeyboardKey: function (e) {
_getKeyboardKey: function (e) {
if (typeof e.key === "string") {
return e.key;
}
@ -156,6 +165,57 @@ var KeyboardShortcut = {
} else {
return String.fromCharCode(e.which).toLowerCase();
}
},
/**
* Adds the given shortcut to the help dialog.
*
* @param shortcutChar the shortcut character
* @param shortcutDescriptionKey the description of the shortcut
* @private
*/
_addShortcutToHelp: function (shortcutChar, shortcutDescriptionKey) {
var listElement = document.createElement("li");
listElement.id = shortcutChar;
var spanElement = document.createElement("span");
spanElement.className = "item-action";
var kbdElement = document.createElement("kbd");
kbdElement.className = "regular-key";
kbdElement.innerHTML = shortcutChar;
spanElement.appendChild(kbdElement);
var descriptionElement = document.createElement("span");
descriptionElement.className = "item-description";
descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
descriptionElement.innerHTML
= APP.translation.translateString(shortcutDescriptionKey);
listElement.appendChild(spanElement);
listElement.appendChild(descriptionElement);
var parentListElement
= document.getElementById("keyboard-shortcuts-list");
if (parentListElement)
parentListElement.appendChild(listElement);
},
/**
* Removes the list element corresponding to the given shortcut from the
* help dialog
* @private
*/
_removeShortcutFromHelp: function (shortcutChar) {
var parentListElement
= document.getElementById("keyboard-shortcuts-list");
var shortcutElement = document.getElementById(shortcutChar);
if (shortcutElement)
parentListElement.removeChild(shortcutElement);
}
};