Small changes in the Model dialog logic to make it more React-like.
This commit is contained in:
parent
8e54879539
commit
ed5b81b6e6
2 changed files with 46 additions and 30 deletions
68
client/src/lib/bootstrap-components.js
vendored
68
client/src/lib/bootstrap-components.js
vendored
|
@ -85,53 +85,69 @@ class ModalDialog extends Component {
|
||||||
this.state = {
|
this.state = {
|
||||||
buttons: this.props.buttons || [ { label: t('Close'), className: 'btn-default', onClickAsync: null } ]
|
buttons: this.props.buttons || [ { label: t('Close'), className: 'btn-default', onClickAsync: null } ]
|
||||||
};
|
};
|
||||||
|
|
||||||
this.buttonClicked = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
onCloseAsync: PropTypes.func,
|
onCloseAsync: PropTypes.func,
|
||||||
onButtonClickAsync: PropTypes.func,
|
onButtonClickAsync: PropTypes.func,
|
||||||
buttons: PropTypes.array
|
buttons: PropTypes.array,
|
||||||
|
hidden: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
this.props.hidden - this is the desired state of the modal
|
||||||
|
this.hidden - this is the actual state of the modal - this is because there is no public API on Bootstrap modal to know whether the modal is shown or not
|
||||||
|
*/
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const jqModal = jQuery(this.domModal);
|
const jqModal = jQuery(this.domModal);
|
||||||
|
|
||||||
jqModal.on('shown.bs.modal', () => jqModal.focus());
|
jqModal.on('shown.bs.modal', () => jqModal.focus());
|
||||||
jqModal.on('hidden.bs.modal', () => this.onHide());
|
jqModal.on('hide.bs.modal', ::this.onHide);
|
||||||
jqModal.modal();
|
|
||||||
|
|
||||||
|
this.hidden = this.props.hidden;
|
||||||
|
jqModal.modal({
|
||||||
|
show: !this.props.hidden
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
componentDidUpdate() {
|
||||||
const jqModal = jQuery(this.domModal);
|
if (this.props.hidden != this.hidden) {
|
||||||
jqModal.modal('hide');
|
const jqModal = jQuery(this.domModal);
|
||||||
|
this.hidden = this.props.hidden;
|
||||||
|
jqModal.modal(this.props.hidden ? 'hide' : 'show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
// We discard the modal in a hard way (without hiding it). Thus we have to take care of the backgrop too.
|
||||||
|
jQuery('.modal-backdrop').remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
onHide(evt) {
|
||||||
|
// Hide event is emited is both when hidden through user action or through API. We have to let the API
|
||||||
|
// calls through, otherwise the modal would never hide. The user actions, which change the desired state,
|
||||||
|
// are capture, converted to onClose callback and prevented. It's up to the parent to decide whether to
|
||||||
|
// hide the modal or not.
|
||||||
|
if (!this.props.hidden) {
|
||||||
|
this.onClose();
|
||||||
|
evt.preventDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@withAsyncErrorHandler
|
@withAsyncErrorHandler
|
||||||
async onHide() {
|
async onClose() {
|
||||||
if (this.buttonClicked === null) {
|
if (this.props.onCloseAsync) {
|
||||||
if (this.props.onCloseAsync) {
|
await this.props.onCloseAsync();
|
||||||
await this.props.onCloseAsync();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const idx = this.buttonClicked;
|
|
||||||
this.buttonClicked = null;
|
|
||||||
|
|
||||||
const buttonSpec = this.state.buttons[idx];
|
|
||||||
if (buttonSpec.onClickAsync) {
|
|
||||||
await buttonSpec.onClickAsync(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async onButtonClick(idx) {
|
async onButtonClick(idx) {
|
||||||
this.buttonClicked = idx;
|
const buttonSpec = this.state.buttons[idx];
|
||||||
const jqModal = jQuery(this.domModal);
|
if (buttonSpec.onClickAsync) {
|
||||||
jqModal.modal('hide');
|
await buttonSpec.onClickAsync(idx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -150,7 +166,7 @@ class ModalDialog extends Component {
|
||||||
<div className="modal-dialog" role="document">
|
<div className="modal-dialog" role="document">
|
||||||
<div className="modal-content">
|
<div className="modal-content">
|
||||||
<div className="modal-header">
|
<div className="modal-header">
|
||||||
<button type="button" className="close" aria-label={t('Close')} onClick={::this.close}><span aria-hidden="true">×</span></button>
|
<button type="button" className="close" aria-label={t('Close')} onClick={::this.onClose}><span aria-hidden="true">×</span></button>
|
||||||
<h4 className="modal-title">{this.props.title}</h4>
|
<h4 className="modal-title">{this.props.title}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-body">{this.props.children}</div>
|
<div className="modal-body">{this.props.children}</div>
|
||||||
|
|
|
@ -163,10 +163,10 @@ export default class CUD extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
async performDelete() {
|
async performDelete() {
|
||||||
await this.hideDeleteModal();
|
|
||||||
|
|
||||||
const t = this.props.t;
|
const t = this.props.t;
|
||||||
|
|
||||||
|
await this.hideDeleteModal();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.disableForm();
|
this.disableForm();
|
||||||
this.setFormStatusMessage('info', t('Deleting namespace...'));
|
this.setFormStatusMessage('info', t('Deleting namespace...'));
|
||||||
|
@ -198,8 +198,8 @@ export default class CUD extends Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{!this.isEditGlobal() && deleteConfirmationShown &&
|
{!this.isEditGlobal() && !this.hasChildren && edit &&
|
||||||
<ModalDialog title={t('Confirm deletion')} onCloseAsync={::this.hideDeleteModal} buttons={[
|
<ModalDialog hidden={!deleteConfirmationShown} title={t('Confirm deletion')} onCloseAsync={::this.hideDeleteModal} buttons={[
|
||||||
{ label: t('No'), className: 'btn-primary', onClickAsync: ::this.hideDeleteModal },
|
{ label: t('No'), className: 'btn-primary', onClickAsync: ::this.hideDeleteModal },
|
||||||
{ label: t('Yes'), className: 'btn-danger', onClickAsync: ::this.performDelete }
|
{ label: t('Yes'), className: 'btn-danger', onClickAsync: ::this.performDelete }
|
||||||
]}>
|
]}>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue