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