2015-07-15 12:30:11 +08:00
|
|
|
import Component from 'flarum/Component';
|
|
|
|
import LoadingIndicator from 'flarum/components/LoadingIndicator';
|
|
|
|
import Alert from 'flarum/components/Alert';
|
2015-07-17 13:17:49 +08:00
|
|
|
import Button from 'flarum/components/Button';
|
2015-07-15 12:30:11 +08:00
|
|
|
import icon from 'flarum/helpers/icon';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 {
|
|
|
|
constructor(...args) {
|
|
|
|
super(...args);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An alert component to show below the header.
|
|
|
|
*
|
|
|
|
* @type {Alert}
|
|
|
|
*/
|
|
|
|
this.alert = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether or not the form is processing.
|
|
|
|
*
|
|
|
|
* @type {Boolean}
|
|
|
|
*/
|
|
|
|
this.loading = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
view() {
|
|
|
|
if (this.alert) {
|
|
|
|
this.alert.props.dismissible = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2015-07-17 13:17:49 +08:00
|
|
|
<div className={'Modal modal-dialog ' + this.className()}>
|
|
|
|
<div className="Modal-content">
|
|
|
|
<div className="Modal-close Page-backControl">
|
|
|
|
{Button.component({
|
|
|
|
icon: 'times',
|
|
|
|
onclick: this.hide.bind(this),
|
|
|
|
className: 'Button Button--icon Button--link'
|
|
|
|
})}
|
2015-07-15 12:30:11 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<form onsubmit={this.onsubmit.bind(this)}>
|
2015-07-17 13:17:49 +08:00
|
|
|
<div className="Modal-header">
|
|
|
|
<h3 className="Page-titleControl Page-titleControl--text">{this.title()}</h3>
|
2015-07-15 12:30:11 +08:00
|
|
|
</div>
|
|
|
|
|
2015-07-17 13:17:49 +08:00
|
|
|
{alert ? <div className="Modal-alert">{this.alert}</div> : ''}
|
2015-07-15 12:30:11 +08:00
|
|
|
|
|
|
|
{this.content()}
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{LoadingIndicator.component({
|
2015-07-17 13:17:49 +08:00
|
|
|
className: 'Modal-loading ' + (this.loading ? 'active' : '')
|
2015-07-15 12:30:11 +08:00
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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() {
|
2015-07-17 13:17:49 +08:00
|
|
|
this.$('form :input:first').select();
|
2015-07-15 12:30:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hide the modal.
|
|
|
|
*/
|
|
|
|
hide() {
|
|
|
|
app.modal.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Show an alert describing errors returned from the API, and give focus to
|
|
|
|
* the first relevant field.
|
|
|
|
*
|
2015-07-17 13:17:49 +08:00
|
|
|
* @param {Object} response
|
2015-07-15 12:30:11 +08:00
|
|
|
*/
|
2015-07-17 13:17:49 +08:00
|
|
|
handleErrors(response) {
|
|
|
|
const errors = response && response.errors;
|
|
|
|
|
2015-07-15 12:30:11 +08:00
|
|
|
if (errors) {
|
|
|
|
this.alert(new Alert({
|
|
|
|
type: 'warning',
|
|
|
|
message: errors.map((error, k) => [error.detail, k < errors.length - 1 ? m('br') : ''])
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
m.redraw();
|
|
|
|
|
|
|
|
if (errors) {
|
2015-07-17 13:17:49 +08:00
|
|
|
this.$('form [name=' + errors[0].path + ']').select();
|
2015-07-15 12:30:11 +08:00
|
|
|
} else {
|
2015-07-17 13:17:49 +08:00
|
|
|
this.$('form :input:first').select();
|
2015-07-15 12:30:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|