forked from cybrespace/mastodon
Show confirmation dialog on leaving WebUI while composing (#5616)
* Show confirmation dialog on leaving WebUI while composing Currently, Back button and Back hotkey can cause leaving from WebUI, as well as browser's back button. Users may hit those buttons accidentally, and their composing text will be lost. So this prevents it by showing confirmation dialog from `onbeforeunload` event. * Fix message and comments
This commit is contained in:
parent
cfd7b7a0b7
commit
49a285ce15
|
@ -39,13 +39,19 @@ import {
|
||||||
} from './util/async-components';
|
} from './util/async-components';
|
||||||
import { HotKeys } from 'react-hotkeys';
|
import { HotKeys } from 'react-hotkeys';
|
||||||
import { me } from '../../initial_state';
|
import { me } from '../../initial_state';
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
||||||
// Without this it ends up in ~8 very commonly used bundles.
|
// Without this it ends up in ~8 very commonly used bundles.
|
||||||
import '../../components/status';
|
import '../../components/status';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
beforeUnload: { id: 'ui.beforeunload', defaultMessage: 'Your draft will be lost if you leave Mastodon.' },
|
||||||
|
});
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
isComposing: state.getIn(['compose', 'is_composing']),
|
isComposing: state.getIn(['compose', 'is_composing']),
|
||||||
|
hasComposingText: state.getIn(['compose', 'text']) !== '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const keyMap = {
|
const keyMap = {
|
||||||
|
@ -75,6 +81,7 @@ const keyMap = {
|
||||||
};
|
};
|
||||||
|
|
||||||
@connect(mapStateToProps)
|
@connect(mapStateToProps)
|
||||||
|
@injectIntl
|
||||||
@withRouter
|
@withRouter
|
||||||
export default class UI extends React.Component {
|
export default class UI extends React.Component {
|
||||||
|
|
||||||
|
@ -86,7 +93,9 @@ export default class UI extends React.Component {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
isComposing: PropTypes.bool,
|
isComposing: PropTypes.bool,
|
||||||
|
hasComposingText: PropTypes.bool,
|
||||||
location: PropTypes.object,
|
location: PropTypes.object,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -94,6 +103,17 @@ export default class UI extends React.Component {
|
||||||
draggingOver: false,
|
draggingOver: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleBeforeUnload = (e) => {
|
||||||
|
const { intl, isComposing, hasComposingText } = this.props;
|
||||||
|
|
||||||
|
if (isComposing && hasComposingText) {
|
||||||
|
// Setting returnValue to any string causes confirmation dialog.
|
||||||
|
// Many browsers no longer display this text to users,
|
||||||
|
// but we set user-friendly message for other browsers, e.g. Edge.
|
||||||
|
e.returnValue = intl.formatMessage(messages.beforeUnload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleResize = debounce(() => {
|
handleResize = debounce(() => {
|
||||||
// The cached heights are no longer accurate, invalidate
|
// The cached heights are no longer accurate, invalidate
|
||||||
this.props.dispatch(clearHeight());
|
this.props.dispatch(clearHeight());
|
||||||
|
@ -168,6 +188,7 @@ export default class UI extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount () {
|
componentWillMount () {
|
||||||
|
window.addEventListener('beforeunload', this.handleBeforeUnload, false);
|
||||||
window.addEventListener('resize', this.handleResize, { passive: true });
|
window.addEventListener('resize', this.handleResize, { passive: true });
|
||||||
document.addEventListener('dragenter', this.handleDragEnter, false);
|
document.addEventListener('dragenter', this.handleDragEnter, false);
|
||||||
document.addEventListener('dragover', this.handleDragOver, false);
|
document.addEventListener('dragover', this.handleDragOver, false);
|
||||||
|
@ -209,6 +230,7 @@ export default class UI extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
window.removeEventListener('beforeunload', this.handleBeforeUnload);
|
||||||
window.removeEventListener('resize', this.handleResize);
|
window.removeEventListener('resize', this.handleResize);
|
||||||
document.removeEventListener('dragenter', this.handleDragEnter);
|
document.removeEventListener('dragenter', this.handleDragEnter);
|
||||||
document.removeEventListener('dragover', this.handleDragOver);
|
document.removeEventListener('dragover', this.handleDragOver);
|
||||||
|
|
Loading…
Reference in New Issue