mirror of
https://github.com/flarum/framework.git
synced 2024-11-29 04:33:47 +08:00
9896378b59
- Use cookies + CSRF token for API authentication in the default client. This mitigates potential XSS attacks by making the token unavailable to JavaScript. The Authorization header is still supported, but not used by default. - Make sensitive/destructive actions (editing a user, permanently deleting anything, visiting the admin CP) require the user to re-enter their password if they haven't entered it in the last 30 minutes. - Refactor and clean up the authentication middleware. - Add an `onhide` hook to the Modal component. (+1 squashed commit)
140 lines
2.7 KiB
JavaScript
140 lines
2.7 KiB
JavaScript
import Component from 'flarum/Component';
|
|
import Alert from 'flarum/components/Alert';
|
|
import Button from 'flarum/components/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 {
|
|
init() {
|
|
/**
|
|
* An alert component to show below the header.
|
|
*
|
|
* @type {Alert}
|
|
*/
|
|
this.alert = null;
|
|
}
|
|
|
|
view() {
|
|
if (this.alert) {
|
|
this.alert.props.dismissible = false;
|
|
}
|
|
|
|
return (
|
|
<div className={'Modal modal-dialog ' + this.className()}>
|
|
<div className="Modal-content">
|
|
{this.isDismissible() ? (
|
|
<div className="Modal-close App-backControl">
|
|
{Button.component({
|
|
icon: 'times',
|
|
onclick: this.hide.bind(this),
|
|
className: 'Button Button--icon Button--link'
|
|
})}
|
|
</div>
|
|
) : ''}
|
|
|
|
<form onsubmit={this.onsubmit.bind(this)}>
|
|
<div className="Modal-header">
|
|
<h3 className="App-titleControl App-titleControl--text">{this.title()}</h3>
|
|
</div>
|
|
|
|
{alert ? <div className="Modal-alert">{this.alert}</div> : ''}
|
|
|
|
{this.content()}
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Determine whether or not the modal should be dismissible via an 'x' button.
|
|
*
|
|
* @return {Boolean}
|
|
*/
|
|
isDismissible() {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 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();
|
|
}
|
|
|
|
onhide() {
|
|
}
|
|
|
|
/**
|
|
* Hide the modal.
|
|
*/
|
|
hide() {
|
|
app.modal.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.alert = 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();
|
|
}
|
|
}
|
|
}
|