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:
virtuacoplenny 2017-11-13 14:58:00 -08:00 committed by yanas
parent f3798cc2b6
commit dc26b17d8b
13 changed files with 133 additions and 161 deletions

View File

@ -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);
}
}

View File

@ -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';

View File

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

View File

@ -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;
}

View File

@ -1,12 +0,0 @@
.shortcuts-list {
padding: 0;
&__description {
margin-left: em(16, 14);
vertical-align: top;
}
&__item {
margin-bottom: em(7, 14);
}
}

View File

@ -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>

View File

@ -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

21
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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);

View File

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

View File

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