Skip to content

Commit 8b3b738

Browse files
Merge pull request #240 from jekyll/confirm-navigation
Confirm navigation if there are unsaved changes
2 parents 186d308 + d5e4e98 commit 8b3b738

File tree

9 files changed

+109
-26
lines changed

9 files changed

+109
-26
lines changed

src/containers/views/Configuration.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { Component, PropTypes } from 'react';
22
import { connect } from 'react-redux';
33
import { bindActionCreators } from 'redux';
4+
import { withRouter } from 'react-router';
45

56
// Components
67
import Editor from '../../components/Editor';
@@ -10,6 +11,17 @@ import { putConfig, onEditorChange } from '../../actions/config';
1011

1112
export class Configuration extends Component {
1213

14+
componentDidMount() {
15+
const { router, route } = this.props;
16+
router.setRouteLeaveHook(route, this.routerWillLeave.bind(this));
17+
}
18+
19+
routerWillLeave(nextLocation) {
20+
const { editorChanged } = this.props;
21+
if (editorChanged)
22+
return 'You have unsaved changes on this page. Are you sure you want to leave?';
23+
}
24+
1325
handleSaveClick() {
1426
const { editorChanged, putConfig } = this.props;
1527
if (editorChanged) {
@@ -62,7 +74,9 @@ Configuration.propTypes = {
6274
onEditorChange: PropTypes.func.isRequired,
6375
putConfig: PropTypes.func.isRequired,
6476
updated: PropTypes.bool.isRequired,
65-
editorChanged: PropTypes.bool.isRequired
77+
editorChanged: PropTypes.bool.isRequired,
78+
router: PropTypes.object.isRequired,
79+
route: PropTypes.object.isRequired
6680
};
6781

68-
export default connect(mapStateToProps, mapDispatchToProps)(Configuration);
82+
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Configuration));

src/containers/views/DataFileEdit.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { Component, PropTypes } from 'react';
22
import { connect } from 'react-redux';
33
import { bindActionCreators } from 'redux';
4-
import { browserHistory } from 'react-router';
4+
import { browserHistory, withRouter } from 'react-router';
55
import { Link } from 'react-router';
66
import _ from 'underscore';
77

@@ -24,10 +24,17 @@ export class DataFileEdit extends Component {
2424
}
2525

2626
componentDidMount() {
27-
const { fetchDataFile, params } = this.props;
27+
const { fetchDataFile, params, router, route } = this.props;
28+
router.setRouteLeaveHook(route, this.routerWillLeave.bind(this));
2829
fetchDataFile(params.data_file);
2930
}
3031

32+
routerWillLeave(nextLocation) {
33+
const { datafileChanged } = this.props;
34+
if (datafileChanged)
35+
return 'You have unsaved changes on this page. Are you sure you want to leave?';
36+
}
37+
3138
handleClickSave() {
3239
const { datafileChanged, putDataFile, params } = this.props;
3340
if (datafileChanged) {
@@ -131,7 +138,9 @@ DataFileEdit.propTypes = {
131138
updated: PropTypes.bool.isRequired,
132139
datafileChanged: PropTypes.bool.isRequired,
133140
errors: PropTypes.array.isRequired,
134-
params: PropTypes.object.isRequired
141+
params: PropTypes.object.isRequired,
142+
router: PropTypes.object.isRequired,
143+
route: PropTypes.object.isRequired
135144
};
136145

137-
export default connect(mapStateToProps, mapDispatchToProps)(DataFileEdit);
146+
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(DataFileEdit));

src/containers/views/DataFileNew.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { Component, PropTypes } from 'react';
22
import { connect } from 'react-redux';
33
import { bindActionCreators } from 'redux';
4-
import { browserHistory } from 'react-router';
4+
import { browserHistory, withRouter } from 'react-router';
55
import _ from 'underscore';
66

77
// Constants
@@ -22,13 +22,24 @@ export class DataFileNew extends Component {
2222
clearErrors();
2323
}
2424

25+
componentDidMount() {
26+
const { router, route } = this.props;
27+
router.setRouteLeaveHook(route, this.routerWillLeave.bind(this));
28+
}
29+
2530
componentWillReceiveProps(nextProps) {
2631
if (this.props.updated !== nextProps.updated) {
2732
const filename = this.refs.breadcrumbs.refs.input.value;
2833
browserHistory.push(`${ADMIN_PREFIX}/datafiles/${filename}`);
2934
}
3035
}
3136

37+
routerWillLeave(nextLocation) {
38+
const { datafileChanged } = this.props;
39+
if (datafileChanged)
40+
return 'You have unsaved changes on this page. Are you sure you want to leave?';
41+
}
42+
3243
handleClickSave() {
3344
const { datafileChanged, putDataFile } = this.props;
3445
if (datafileChanged) {
@@ -104,7 +115,9 @@ DataFileNew.propTypes = {
104115
clearErrors: PropTypes.func.isRequired,
105116
errors: PropTypes.array.isRequired,
106117
updated: PropTypes.bool.isRequired,
107-
datafileChanged: PropTypes.bool.isRequired
118+
datafileChanged: PropTypes.bool.isRequired,
119+
router: PropTypes.object.isRequired,
120+
route: PropTypes.object.isRequired
108121
};
109122

110-
export default connect(mapStateToProps, mapDispatchToProps)(DataFileNew);
123+
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(DataFileNew));

src/containers/views/DocumentEdit.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { PropTypes, Component } from 'react';
22
import { connect } from 'react-redux';
33
import { bindActionCreators } from 'redux';
4-
import { browserHistory } from 'react-router';
4+
import { browserHistory, withRouter } from 'react-router';
55
import { Link } from 'react-router';
66
import _ from 'underscore';
77

@@ -31,7 +31,8 @@ export class DocumentEdit extends Component {
3131
}
3232

3333
componentDidMount() {
34-
const { fetchDocument, params } = this.props;
34+
const { fetchDocument, params, router, route } = this.props;
35+
router.setRouteLeaveHook(route, this.routerWillLeave.bind(this));
3536
fetchDocument(params.collection_name, params.id);
3637
}
3738

@@ -49,6 +50,12 @@ export class DocumentEdit extends Component {
4950
}
5051
}
5152

53+
routerWillLeave(nextLocation) {
54+
const { fieldChanged } = this.props;
55+
if (fieldChanged)
56+
return 'You have unsaved changes on this page. Are you sure you want to leave?';
57+
}
58+
5259
handleClickSave(id, collection) {
5360
const { putDocument, fieldChanged } = this.props;
5461
if (fieldChanged) {
@@ -151,7 +158,9 @@ DocumentEdit.propTypes = {
151158
errors: PropTypes.array.isRequired,
152159
updated: PropTypes.bool.isRequired,
153160
fieldChanged: PropTypes.bool.isRequired,
154-
params: PropTypes.object.isRequired
161+
params: PropTypes.object.isRequired,
162+
router: PropTypes.object.isRequired,
163+
route: PropTypes.object.isRequired
155164
};
156165

157166
function mapStateToProps(state) {
@@ -178,4 +187,4 @@ function mapDispatchToProps(dispatch) {
178187
}, dispatch);
179188
}
180189

181-
export default connect(mapStateToProps, mapDispatchToProps)(DocumentEdit);
190+
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(DocumentEdit));

src/containers/views/DocumentNew.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { PropTypes, Component } from 'react';
22
import { connect } from 'react-redux';
33
import { bindActionCreators } from 'redux';
4-
import { browserHistory } from 'react-router';
4+
import { browserHistory, withRouter } from 'react-router';
55
import _ from 'underscore';
66

77
// Constants
@@ -29,6 +29,11 @@ export class DocumentNew extends Component {
2929
clearErrors();
3030
}
3131

32+
componentDidMount() {
33+
const { router, route } = this.props;
34+
router.setRouteLeaveHook(route, this.routerWillLeave.bind(this));
35+
}
36+
3237
componentWillReceiveProps(nextProps) {
3338
if (this.props.updated !== nextProps.updated) {
3439
const path = nextProps.currentDocument.path;
@@ -39,6 +44,12 @@ export class DocumentNew extends Component {
3944
}
4045
}
4146

47+
routerWillLeave(nextLocation) {
48+
const { fieldChanged } = this.props;
49+
if (fieldChanged)
50+
return 'You have unsaved changes on this page. Are you sure you want to leave?';
51+
}
52+
4253
handleClickSave() {
4354
const { fieldChanged, putDocument, params } = this.props;
4455
if (fieldChanged) {
@@ -109,7 +120,9 @@ DocumentNew.propTypes = {
109120
errors: PropTypes.array.isRequired,
110121
fieldChanged: PropTypes.bool.isRequired,
111122
updated: PropTypes.bool.isRequired,
112-
params: PropTypes.object.isRequired
123+
params: PropTypes.object.isRequired,
124+
router: PropTypes.object.isRequired,
125+
route: PropTypes.object.isRequired
113126
};
114127

115128

@@ -134,4 +147,4 @@ function mapDispatchToProps(dispatch) {
134147
}, dispatch);
135148
}
136149

137-
export default connect(mapStateToProps, mapDispatchToProps)(DocumentNew);
150+
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(DocumentNew));

src/containers/views/Documents.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { Component, PropTypes } from 'react';
2-
import { Link, withRouter } from 'react-router';
2+
import { Link } from 'react-router';
33
import { connect } from 'react-redux';
44
import { bindActionCreators } from 'redux';
55
import _ from 'underscore';
@@ -146,4 +146,4 @@ function mapDispatchToProps(dispatch) {
146146
}, dispatch);
147147
}
148148

149-
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Documents));
149+
export default connect(mapStateToProps, mapDispatchToProps)(Documents);

src/containers/views/PageEdit.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { PropTypes, Component } from 'react';
22
import { connect } from 'react-redux';
33
import { bindActionCreators } from 'redux';
4-
import { browserHistory } from 'react-router';
4+
import { browserHistory, withRouter } from 'react-router';
55
import { Link } from 'react-router';
66
import _ from 'underscore';
77

@@ -28,7 +28,8 @@ export class PageEdit extends Component {
2828
}
2929

3030
componentDidMount() {
31-
const { fetchPage, params } = this.props;
31+
const { fetchPage, params, router, route } = this.props;
32+
router.setRouteLeaveHook(route, this.routerWillLeave.bind(this));
3233
fetchPage(params.id);
3334
}
3435

@@ -43,6 +44,12 @@ export class PageEdit extends Component {
4344
}
4445
}
4546

47+
routerWillLeave(nextLocation) {
48+
const { fieldChanged } = this.props;
49+
if (fieldChanged)
50+
return 'You have unsaved changes on this page. Are you sure you want to leave?';
51+
}
52+
4653
handleClickSave(name) {
4754
const { putPage, fieldChanged } = this.props;
4855
if (fieldChanged) {
@@ -143,7 +150,9 @@ PageEdit.propTypes = {
143150
errors: PropTypes.array.isRequired,
144151
fieldChanged: PropTypes.bool.isRequired,
145152
updated: PropTypes.bool.isRequired,
146-
params: PropTypes.object.isRequired
153+
params: PropTypes.object.isRequired,
154+
router: PropTypes.object.isRequired,
155+
route: PropTypes.object.isRequired
147156
};
148157

149158

@@ -170,4 +179,4 @@ function mapDispatchToProps(dispatch) {
170179
}, dispatch);
171180
}
172181

173-
export default connect(mapStateToProps, mapDispatchToProps)(PageEdit);
182+
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(PageEdit));

src/containers/views/PageNew.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { PropTypes, Component } from 'react';
22
import { connect } from 'react-redux';
33
import { bindActionCreators } from 'redux';
4-
import { browserHistory } from 'react-router';
4+
import { browserHistory, withRouter } from 'react-router';
55
import _ from 'underscore';
66

77
// Constants
@@ -29,12 +29,23 @@ export class PageNew extends Component {
2929
clearErrors();
3030
}
3131

32+
componentDidMount() {
33+
const { router, route } = this.props;
34+
router.setRouteLeaveHook(route, this.routerWillLeave.bind(this));
35+
}
36+
3237
componentWillReceiveProps(nextProps) {
3338
if (this.props.updated !== nextProps.updated) {
3439
browserHistory.push(`${ADMIN_PREFIX}/pages/${nextProps.page.name}`);
3540
}
3641
}
3742

43+
routerWillLeave(nextLocation) {
44+
const { fieldChanged } = this.props;
45+
if (fieldChanged)
46+
return 'You have unsaved changes on this page. Are you sure you want to leave?';
47+
}
48+
3849
handleClickSave() {
3950
const { fieldChanged, putPage } = this.props;
4051
if (fieldChanged) {
@@ -100,7 +111,9 @@ PageNew.propTypes = {
100111
clearErrors: PropTypes.func.isRequired,
101112
errors: PropTypes.array.isRequired,
102113
fieldChanged: PropTypes.bool.isRequired,
103-
updated: PropTypes.bool.isRequired
114+
updated: PropTypes.bool.isRequired,
115+
router: PropTypes.object.isRequired,
116+
route: PropTypes.object.isRequired
104117
};
105118

106119

@@ -125,4 +138,4 @@ function mapDispatchToProps(dispatch) {
125138
}, dispatch);
126139
}
127140

128-
export default connect(mapStateToProps, mapDispatchToProps)(PageNew);
141+
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(PageNew));

src/reducers/config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export default function config(state = {
4343
updated: false
4444
});
4545
default:
46-
return state;
46+
return Object.assign({}, state, {
47+
updated: false,
48+
editorChanged: false
49+
});
4750
}
4851
}

0 commit comments

Comments
 (0)