Mosaico upgraded to 0.17.5

Work started on confirmation dialogs displayed when one navigates from a page with unsaved changes
This commit is contained in:
Tomas Bures 2019-05-08 19:54:19 +02:00
parent 4f77272042
commit 48dcf2c701
399 changed files with 4032 additions and 77702 deletions

View file

@ -331,11 +331,41 @@ class PanelRoute extends Component {
}
export class BeforeUnloadListeners {
constructor() {
this.listeners = new Set();
}
register(listener) {
this.listeners.add(listener);
}
deregister(listener) {
this.listeners.delete(listener);
}
shouldUnloadBeCancelled() {
for (const lst of this.listeners) {
if (lst.handler()) return true;
}
return false;
}
async shouldUnloadBeCancelledAsync() {
for (const lst of this.listeners) {
if (await lst.handlerAsync()) return true;
}
return false;
}
}
@withRouter
@withComponentMixins([
withTranslation,
withErrorHandling
])
], ['onNavigationConfirmationDialog'])
export class SectionContent extends Component {
constructor(props) {
super(props);
@ -348,6 +378,10 @@ export class SectionContent extends Component {
// noinspection JSIgnoredPromiseFromCall
this.closeFlashMessage();
});
this.beforeUnloadListeners = new BeforeUnloadListeners();
this.beforeUnloadHandler = ::this.onBeforeUnload;
this.historyUnblock = null;
}
static propTypes = {
@ -355,6 +389,34 @@ export class SectionContent extends Component {
root: PropTypes.string.isRequired
}
onBeforeUnload(event) {
if (this.beforeUnloadListeners.shouldUnloadBeCancelled()) {
event.preventDefault();
event.returnValue = '';
}
}
onNavigationConfirmationDialog(message, callback) {
this.beforeUnloadListeners.shouldUnloadBeCancelledAsync().then(res => {
if (res) {
const allowTransition = window.confirm(message);
callback(allowTransition);
} else {
callback(true);
}
});
}
componentDidMount() {
window.addEventListener('beforeunload', this.beforeUnloadHandler);
this.historyUnblock = this.props.history.block('Changes you made may not be saved. Are you sure you want to leave this page?');
}
componentWillUnmount() {
window.removeEventListener('beforeunload', this.beforeUnloadHandler);
this.historyUnblock();
}
setFlashMessage(severity, text) {
this.setState({
flashMessageText: text,
@ -381,6 +443,14 @@ export class SectionContent extends Component {
}
}
registerBeforeUnloadHandlers(handlers) {
this.beforeUnloadListeners.register(handlers);
}
deregisterBeforeUnloadHandlers(handlers) {
this.beforeUnloadListeners.deregister(handlers);
}
errorHandler(error) {
if (error instanceof interoperableErrors.NotLoggedInError) {
if (window.location.pathname !== '/login') { // There may be multiple async requests failing at the same time. So we take the pathname only from the first one.
@ -440,6 +510,8 @@ export class SectionContent extends Component {
export class Section extends Component {
constructor(props) {
super(props);
this.getUserConfirmationHandler = ::this.onGetUserConfirmation;
this.sectionContent = null;
}
static propTypes = {
@ -447,6 +519,10 @@ export class Section extends Component {
root: PropTypes.string.isRequired
}
onGetUserConfirmation(message, callback) {
this.sectionContent.onNavigationConfirmationDialog(message, callback);
}
render() {
let structure = this.props.structure;
if (typeof structure === 'function') {
@ -454,8 +530,8 @@ export class Section extends Component {
}
return (
<Router basename={getBaseDir()}>
<SectionContent root={this.props.root} structure={structure} />
<Router basename={getBaseDir()} getUserConfirmation={this.getUserConfirmationHandler}>
<SectionContent wrappedComponentRef={node => this.sectionContent = node} root={this.props.root} structure={structure} />
</Router>
);
}