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 {
|
.shortcuts-list {
|
||||||
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 {
|
|
||||||
list-style-type: none;
|
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 'redirect_page';
|
||||||
@import 'components/form-control';
|
@import 'components/form-control';
|
||||||
@import 'components/link';
|
@import 'components/link';
|
||||||
@import 'shortcuts/main';
|
|
||||||
@import 'components/button-control';
|
@import 'components/button-control';
|
||||||
@import 'components/input-control';
|
@import 'components/input-control';
|
||||||
@import 'components/input-slider';
|
@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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="react"></div>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -2,40 +2,25 @@
|
||||||
|
|
||||||
import { toggleDialog } from '../../react/features/base/dialog';
|
import { toggleDialog } from '../../react/features/base/dialog';
|
||||||
import { sendAnalyticsEvent } from '../../react/features/analytics';
|
import { sendAnalyticsEvent } from '../../react/features/analytics';
|
||||||
|
import { KeyboardShortcutsDialog }
|
||||||
|
from '../../react/features/keyboard-shortcuts';
|
||||||
import { SpeakerStats } from '../../react/features/speaker-stats';
|
import { SpeakerStats } from '../../react/features/speaker-stats';
|
||||||
|
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
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.
|
* Map of shortcuts. When a shortcut is registered it enters the mapping.
|
||||||
* @type {{}}
|
* @type {{}}
|
||||||
*/
|
*/
|
||||||
const _shortcuts = {};
|
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.
|
* True if the keyboard shortcuts are enabled and false if not.
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
@ -133,30 +118,7 @@ const KeyboardShortcut = {
|
||||||
*/
|
*/
|
||||||
unregisterShortcut(shortcutChar) {
|
unregisterShortcut(shortcutChar) {
|
||||||
_shortcuts.remove(shortcutChar);
|
_shortcuts.remove(shortcutChar);
|
||||||
|
_shortcutsHelp.delete(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 '';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,56 +158,7 @@ const KeyboardShortcut = {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_addShortcutToHelp(shortcutChar, shortcutDescriptionKey) {
|
_addShortcutToHelp(shortcutChar, shortcutDescriptionKey) {
|
||||||
|
_shortcutsHelp.set(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);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -255,13 +168,11 @@ const KeyboardShortcut = {
|
||||||
* triggered _only_ with a shortcut.
|
* triggered _only_ with a shortcut.
|
||||||
*/
|
*/
|
||||||
_initGlobalShortcuts() {
|
_initGlobalShortcuts() {
|
||||||
this.registerShortcut('ESCAPE', null, () => {
|
|
||||||
showKeyboardShortcutsPanel(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.registerShortcut('?', null, () => {
|
this.registerShortcut('?', null, () => {
|
||||||
sendAnalyticsEvent('shortcut.shortcut.help');
|
sendAnalyticsEvent('shortcut.shortcut.help');
|
||||||
showKeyboardShortcutsPanel(true);
|
APP.store.dispatch(toggleDialog(KeyboardShortcutsDialog, {
|
||||||
|
shortcutDescriptions: _shortcutsHelp
|
||||||
|
}));
|
||||||
}, 'keyboardShortcuts.toggleShortcuts');
|
}, 'keyboardShortcuts.toggleShortcuts');
|
||||||
|
|
||||||
// register SPACE shortcut in two steps to insure visibility of help
|
// 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": {
|
"@atlaskit/modal-dialog": {
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@atlaskit/modal-dialog/-/modal-dialog-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@atlaskit/modal-dialog/-/modal-dialog-2.6.0.tgz",
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
"@atlaskit/icon": "10.0.0",
|
"@atlaskit/icon": "10.0.0",
|
||||||
"@atlaskit/inline-dialog": "5.0.2",
|
"@atlaskit/inline-dialog": "5.0.2",
|
||||||
"@atlaskit/inline-message": "3.0.1",
|
"@atlaskit/inline-message": "3.0.1",
|
||||||
|
"@atlaskit/lozenge": "3.4.2",
|
||||||
"@atlaskit/modal-dialog": "2.6.0",
|
"@atlaskit/modal-dialog": "2.6.0",
|
||||||
"@atlaskit/multi-select": "7.1.3",
|
"@atlaskit/multi-select": "7.1.3",
|
||||||
"@atlaskit/spinner": "4.0.0",
|
"@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