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
This commit is contained in:
parent
f3798cc2b6
commit
dc26b17d8b
|
@ -1,25 +1,10 @@
|
|||
#keyboard-shortcuts {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: $defaultToolbarSize;
|
||||
overflow: hidden;
|
||||
padding: 20px;
|
||||
margin-left: 10px;
|
||||
z-index: $zindex10;
|
||||
border-radius: $borderRadius;
|
||||
background-attachment: scroll;
|
||||
background-size: auto auto;
|
||||
color: rgba(255, 255, 255, .8);
|
||||
background-color: rgba(0, 0, 0, .8);
|
||||
}
|
||||
|
||||
#keyboard-shortcuts .item-action {
|
||||
color: #209EFF;
|
||||
font-size: 14pt;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#keyboard-shortcuts-list {
|
||||
.shortcuts-list {
|
||||
list-style-type: none;
|
||||
}
|
||||
padding: 0;
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: em(7, 14);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
@import 'redirect_page';
|
||||
@import 'components/form-control';
|
||||
@import 'components/link';
|
||||
@import 'shortcuts/main';
|
||||
@import 'components/button-control';
|
||||
@import 'components/input-control';
|
||||
@import 'components/input-slider';
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
/* Import shortcuts blocks */
|
||||
|
||||
@import 'regular-key';
|
||||
@import 'shortcuts-list';
|
|
@ -1,11 +0,0 @@
|
|||
.regular-key {
|
||||
display: table-cell;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-family: $baseFontFamily;
|
||||
color: $defaultDarkColor;
|
||||
font-size: 12px;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
.shortcuts-list {
|
||||
padding: 0;
|
||||
|
||||
&__description {
|
||||
margin-left: em(16, 14);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
&__item {
|
||||
margin-bottom: em(7, 14);
|
||||
}
|
||||
}
|
|
@ -139,11 +139,5 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="react"></div>
|
||||
<div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
|
||||
<div class="content">
|
||||
<ul id="keyboard-shortcuts-list" class="shortcuts-list">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,40 +2,25 @@
|
|||
|
||||
import { toggleDialog } from '../../react/features/base/dialog';
|
||||
import { sendAnalyticsEvent } from '../../react/features/analytics';
|
||||
import { KeyboardShortcutsDialog }
|
||||
from '../../react/features/keyboard-shortcuts';
|
||||
import { SpeakerStats } from '../../react/features/speaker-stats';
|
||||
|
||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
|
||||
/**
|
||||
* The reference to the shortcut dialogs when opened.
|
||||
*/
|
||||
let keyboardShortcutDialog = null;
|
||||
|
||||
/**
|
||||
* Shows or hides the keyboard shortcuts dialog.
|
||||
* @param {boolean} show whether to show or hide the dialog
|
||||
*/
|
||||
function showKeyboardShortcutsPanel(show) {
|
||||
if (show
|
||||
&& !APP.UI.messageHandler.isDialogOpened()
|
||||
&& keyboardShortcutDialog === null) {
|
||||
const msg = $('#keyboard-shortcuts').html();
|
||||
const buttons = { Close: true };
|
||||
|
||||
keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
|
||||
'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
|
||||
} else if (keyboardShortcutDialog !== null) {
|
||||
keyboardShortcutDialog.close();
|
||||
keyboardShortcutDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of shortcuts. When a shortcut is registered it enters the mapping.
|
||||
* @type {{}}
|
||||
*/
|
||||
const _shortcuts = {};
|
||||
|
||||
/**
|
||||
* Map of registered keyboard keys and translation keys describing the
|
||||
* action performed by the key.
|
||||
* @type {Map}
|
||||
*/
|
||||
const _shortcutsHelp = new Map();
|
||||
|
||||
/**
|
||||
* True if the keyboard shortcuts are enabled and false if not.
|
||||
* @type {boolean}
|
||||
|
@ -133,30 +118,7 @@ const KeyboardShortcut = {
|
|||
*/
|
||||
unregisterShortcut(shortcutChar) {
|
||||
_shortcuts.remove(shortcutChar);
|
||||
|
||||
this._removeShortcutFromHelp(shortcutChar);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the tooltip string for the given shortcut attribute.
|
||||
*
|
||||
* @param shortcutAttr indicates the popover associated with the shortcut
|
||||
* @returns {string} the tooltip string to add to the given shortcut popover
|
||||
* or an empty string if the shortcutAttr is null, an empty string or not
|
||||
* found in the shortcut mapping
|
||||
*/
|
||||
getShortcutTooltip(shortcutAttr) {
|
||||
if (typeof shortcutAttr === 'string' && shortcutAttr.length > 0) {
|
||||
for (const key in _shortcuts) {
|
||||
if (_shortcuts.hasOwnProperty(key)
|
||||
&& _shortcuts[key].shortcutAttr
|
||||
&& _shortcuts[key].shortcutAttr === shortcutAttr) {
|
||||
return ` (${_shortcuts[key].character})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
_shortcutsHelp.delete(shortcutChar);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -196,56 +158,7 @@ const KeyboardShortcut = {
|
|||
* @private
|
||||
*/
|
||||
_addShortcutToHelp(shortcutChar, shortcutDescriptionKey) {
|
||||
|
||||
const listElement = document.createElement('li');
|
||||
const itemClass = 'shortcuts-list__item';
|
||||
|
||||
listElement.className = itemClass;
|
||||
listElement.id = shortcutChar;
|
||||
|
||||
const spanElement = document.createElement('span');
|
||||
|
||||
spanElement.className = 'item-action';
|
||||
|
||||
const kbdElement = document.createElement('kbd');
|
||||
const classes = 'aui-label regular-key';
|
||||
|
||||
kbdElement.className = classes;
|
||||
kbdElement.innerHTML = shortcutChar;
|
||||
spanElement.appendChild(kbdElement);
|
||||
|
||||
const descriptionElement = document.createElement('span');
|
||||
const descriptionClass = 'shortcuts-list__description';
|
||||
|
||||
descriptionElement.className = descriptionClass;
|
||||
descriptionElement.setAttribute('data-i18n', shortcutDescriptionKey);
|
||||
APP.translation.translateElement($(descriptionElement));
|
||||
|
||||
listElement.appendChild(spanElement);
|
||||
listElement.appendChild(descriptionElement);
|
||||
|
||||
const 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(shortcutChar) {
|
||||
const parentListElement
|
||||
= document.getElementById('keyboard-shortcuts-list');
|
||||
|
||||
const shortcutElement = document.getElementById(shortcutChar);
|
||||
|
||||
if (shortcutElement) {
|
||||
parentListElement.removeChild(shortcutElement);
|
||||
}
|
||||
_shortcutsHelp.set(shortcutChar, shortcutDescriptionKey);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -255,13 +168,11 @@ const KeyboardShortcut = {
|
|||
* triggered _only_ with a shortcut.
|
||||
*/
|
||||
_initGlobalShortcuts() {
|
||||
this.registerShortcut('ESCAPE', null, () => {
|
||||
showKeyboardShortcutsPanel(false);
|
||||
});
|
||||
|
||||
this.registerShortcut('?', null, () => {
|
||||
sendAnalyticsEvent('shortcut.shortcut.help');
|
||||
showKeyboardShortcutsPanel(true);
|
||||
APP.store.dispatch(toggleDialog(KeyboardShortcutsDialog, {
|
||||
shortcutDescriptions: _shortcutsHelp
|
||||
}));
|
||||
}, 'keyboardShortcuts.toggleShortcuts');
|
||||
|
||||
// register SPACE shortcut in two steps to insure visibility of help
|
||||
|
|
|
@ -348,6 +348,27 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@atlaskit/lozenge": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/lozenge/-/lozenge-3.4.2.tgz",
|
||||
"integrity": "sha1-GjCzTEGjj3jHcmSeCd2qS4AlMuw=",
|
||||
"requires": {
|
||||
"@atlaskit/util-shared-styles": "1.7.1",
|
||||
"babel-runtime": "6.26.0",
|
||||
"prop-types": "15.6.0",
|
||||
"styled-components": "1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@atlaskit/util-shared-styles": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/util-shared-styles/-/util-shared-styles-1.7.1.tgz",
|
||||
"integrity": "sha1-CDLLbMF5dDHEzPZ9F4qkES3zBeI=",
|
||||
"requires": {
|
||||
"babel-runtime": "6.26.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@atlaskit/modal-dialog": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/modal-dialog/-/modal-dialog-2.6.0.tgz",
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
"@atlaskit/icon": "10.0.0",
|
||||
"@atlaskit/inline-dialog": "5.0.2",
|
||||
"@atlaskit/inline-message": "3.0.1",
|
||||
"@atlaskit/lozenge": "3.4.2",
|
||||
"@atlaskit/modal-dialog": "2.6.0",
|
||||
"@atlaskit/multi-select": "7.1.3",
|
||||
"@atlaskit/spinner": "4.0.0",
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
import Lozenge from '@atlaskit/lozenge';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { Dialog } from '../../base/dialog';
|
||||
import { translate } from '../../base/i18n';
|
||||
|
||||
/**
|
||||
* Implements a React {@link Component} which displays a dialog describing
|
||||
* registered keyboard shortcuts.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class KeyboardShortcutsDialog extends Component {
|
||||
/**
|
||||
* {@code KeyboardShortcutsDialog} component's property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* A Map with keyboard keys as keys and translation keys as values.
|
||||
*/
|
||||
shortcutDescriptions: PropTypes.object,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: PropTypes.func
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const shortcuts = Array.from(this.props.shortcutDescriptions)
|
||||
.map(description => this._renderShortcutsListItem(...description));
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
cancelTitleKey = { 'dialog.close' }
|
||||
submitDisabled = { true }
|
||||
titleKey = 'keyboardShortcuts.keyboardShortcuts'
|
||||
width = 'small'>
|
||||
<div
|
||||
id = 'keyboard-shortcuts'>
|
||||
<ul
|
||||
className = 'shortcuts-list'
|
||||
id = 'keyboard-shortcuts-list'>
|
||||
{ shortcuts }
|
||||
</ul>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code ReactElement} for describing a single keyboard shortcut.
|
||||
*
|
||||
* @param {string} keyboardKey - The keyboard key that triggers an action.
|
||||
* @param {string} translationKey - A description of what the action does.
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderShortcutsListItem(keyboardKey, translationKey) {
|
||||
return (
|
||||
<li
|
||||
className = 'shortcuts-list__item'
|
||||
key = { keyboardKey }>
|
||||
<span className = 'shortcuts-list__description'>
|
||||
{ this.props.t(translationKey) }
|
||||
</span>
|
||||
<span className = 'item-action'>
|
||||
<Lozenge isBold = { true }>
|
||||
{ keyboardKey }
|
||||
</Lozenge>
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(KeyboardShortcutsDialog);
|
|
@ -0,0 +1 @@
|
|||
export { default as KeyboardShortcutsDialog } from './KeyboardShortcutsDialog';
|
|
@ -0,0 +1 @@
|
|||
export * from './components';
|
Loading…
Reference in New Issue