Handles Enter key to submit dialogs.

If there is no focused node inside the dialog we focus any of the available buttons, submit button is first.
This commit is contained in:
damencho 2017-06-06 15:36:25 -05:00 committed by hristoterezov
parent bf7415e6b5
commit 8e3dfcf0d0
1 changed files with 122 additions and 17 deletions

View File

@ -7,6 +7,18 @@ import { translate } from '../../i18n';
import { DIALOG_PROP_TYPES } from '../constants';
/**
* The ID to be used for the cancel button if enabled.
* @type {string}
*/
const CANCEL_BUTTON_ID = 'modal-dialog-cancel-button';
/**
* The ID to be used for the ok button if enabled.
* @type {string}
*/
const OK_BUTTON_ID = 'modal-dialog-ok-button';
/**
* Web dialog that uses atlaskit modal-dialog to display dialogs.
*/
@ -63,7 +75,34 @@ class StatelessDialog extends Component {
// Bind event handlers so they are only bound once for every instance.
this._onCancel = this._onCancel.bind(this);
this._onDialogDismissed = this._onDialogDismissed.bind(this);
this._onKeyDown = this._onKeyDown.bind(this);
this._onSubmit = this._onSubmit.bind(this);
this._setDialogElement = this._setDialogElement.bind(this);
}
/**
* React Component method that executes once component is mounted.
*
* @inheritdoc
*/
componentDidMount() {
this._updateButtonFocus();
}
/**
* React Component method that executes once component is updated.
*
* @param {Object} prevProps - The previous properties, before the update.
* @returns {void}
*/
componentDidUpdate(prevProps) {
// if there is an update in any of the buttons enable/disable props
// update the focus if needed
if (prevProps.okDisabled !== this.props.okDisabled
|| prevProps.cancelDisabled !== this.props.cancelDisabled
|| prevProps.submitDisabled !== this.props.submitDisabled) {
this._updateButtonFocus();
}
}
/**
@ -74,21 +113,25 @@ class StatelessDialog extends Component {
*/
render() {
return (
<ModalDialog
footer = { this._renderFooter() }
header = { this._renderHeader() }
isOpen = { true }
onDialogDismissed = { this._onDialogDismissed }
width = { this.props.width || 'medium' }>
<div>
<form
className = 'modal-dialog-form'
id = 'modal-dialog-form'
onSubmit = { this._onSubmit }>
{ this.props.children }
</form>
</div>
</ModalDialog>
<div
onKeyDown = { this._onKeyDown }
ref = { this._setDialogElement }>
<ModalDialog
footer = { this._renderFooter() }
header = { this._renderHeader() }
isOpen = { true }
onDialogDismissed = { this._onDialogDismissed }
width = { this.props.width || 'medium' }>
<div>
<form
className = 'modal-dialog-form'
id = 'modal-dialog-form'
onSubmit = { this._onSubmit }>
{ this.props.children }
</form>
</div>
</ModalDialog>
</div>
);
}
@ -139,7 +182,7 @@ class StatelessDialog extends Component {
return (
<AKButton
appearance = 'subtle'
id = 'modal-dialog-cancel-button'
id = { CANCEL_BUTTON_ID }
onClick = { this._onCancel }>
{ this.props.t(this.props.cancelTitleKey || 'dialog.Cancel') }
</AKButton>
@ -196,13 +239,75 @@ class StatelessDialog extends Component {
<AKButton
appearance = 'primary'
form = 'modal-dialog-form'
id = 'modal-dialog-ok-button'
id = { OK_BUTTON_ID }
isDisabled = { this.props.okDisabled }
onClick = { this._onSubmit }>
{ this.props.t(this.props.okTitleKey || 'dialog.Ok') }
</AKButton>
);
}
/**
* Sets the instance variable for the div containing the component's dialog
* element so it can be accessed directly.
*
* @param {Object} element - The DOM element for the component's dialog.
* @private
* @returns {void}
*/
_setDialogElement(element) {
this._dialogElement = element;
}
/**
* Handles 'Enter' key in the dialog to submit/hide dialog depending on
* the available buttons and their disabled state.
*
* @param {Object} event - the key event.
* @private
* @returns {void}
*/
_onKeyDown(event) {
if (event.key === 'Enter') {
if (this.props.submitDisabled && !this.props.cancelDisabled) {
this._onCancel();
} else if (!this.props.okDisabled) {
this._onSubmit();
}
}
}
/**
* Updates focused button, if we have a reference to the dialog element.
* Focus on available button if there is no focus already.
*
* @private
* @returns {void}
*/
_updateButtonFocus() {
if (this._dialogElement) {
// if we have a focused element inside the dialog, skip changing
// the focus
if (this._dialogElement.contains(document.activeElement)) {
return;
}
let buttonToFocus;
if (this.props.submitDisabled) {
buttonToFocus = this._dialogElement
.querySelector(`[id=${CANCEL_BUTTON_ID}]`);
} else if (!this.props.okDisabled) {
buttonToFocus = this._dialogElement
.querySelector(`[id=${OK_BUTTON_ID}]`);
}
if (buttonToFocus) {
buttonToFocus.focus();
}
}
}
}
export default translate(StatelessDialog);