import Component from '../Component';
import Alert from './Alert';
import Button from './Button';
/**
* The `Modal` component displays a modal dialog, wrapped in a form. Subclasses
* should implement the `className`, `title`, and `content` methods.
*
* @abstract
*/
export default class Modal extends Component {
/**
* Determine whether or not the modal should be dismissible via an 'x' button.
*/
static isDismissible = true;
/**
* Attributes for an alert component to show below the header.
*
* @type {object}
*/
alertAttrs = null;
oncreate(vnode) {
super.oncreate(vnode);
this.attrs.animateShow(() => this.onready());
}
onbeforeremove(vnode) {
super.onbeforeremove(vnode);
// If the global modal state currently contains a modal,
// we've just opened up a new one, and accordingly,
// we don't need to show a hide animation.
if (!this.attrs.state.modal) {
this.attrs.animateHide();
// Here, we ensure that the animation has time to complete.
// See https://mithril.js.org/lifecycle-methods.html#onbeforeremove
// Bootstrap's Modal.TRANSITION_DURATION is 300 ms.
return new Promise((resolve) => setTimeout(resolve, 300));
}
}
view() {
if (this.alertAttrs) {
this.alertAttrs.dismissible = false;
}
return (
{this.constructor.isDismissible ? (
{Button.component({
icon: 'fas fa-times',
onclick: this.hide.bind(this),
className: 'Button Button--icon Button--link',
})}
) : (
''
)}
);
}
/**
* Get the class name to apply to the modal.
*
* @return {String}
* @abstract
*/
className() {}
/**
* Get the title of the modal dialog.
*
* @return {String}
* @abstract
*/
title() {}
/**
* Get the content of the modal.
*
* @return {VirtualElement}
* @abstract
*/
content() {}
/**
* Handle the modal form's submit event.
*
* @param {Event} e
*/
onsubmit() {}
/**
* Focus on the first input when the modal is ready to be used.
*/
onready() {
this.$('form').find('input, select, textarea').first().focus().select();
}
/**
* Hide the modal.
*/
hide() {
this.attrs.state.close();
}
/**
* Stop loading.
*/
loaded() {
this.loading = false;
m.redraw();
}
/**
* Show an alert describing an error returned from the API, and give focus to
* the first relevant field.
*
* @param {RequestError} error
*/
onerror(error) {
this.alertAttrs = error.alert;
m.redraw();
if (error.status === 422 && error.response.errors) {
this.$('form [name=' + error.response.errors[0].source.pointer.replace('/data/attributes/', '') + ']').select();
} else {
this.onready();
}
}
}