Skip to content

Commit b63ac51

Browse files
committed
move project title management into titled hoc
1 parent 91e2fc9 commit b63ac51

File tree

2 files changed

+90
-44
lines changed

2 files changed

+90
-44
lines changed

src/containers/gui.jsx

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ import {compose} from 'redux';
44
import {connect} from 'react-redux';
55
import ReactModal from 'react-modal';
66
import VM from 'scratch-vm';
7-
import {defineMessages, injectIntl, intlShape} from 'react-intl';
7+
import {injectIntl, intlShape} from 'react-intl';
88

99
import ErrorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
1010
import {
1111
getIsError,
12-
getIsShowingProject,
13-
getIsShowingWithoutId
12+
getIsShowingProject
1413
} from '../reducers/project-state';
15-
import {setProjectTitle} from '../reducers/project-title';
1614
import {
1715
activateTab,
1816
BLOCKS_TAB_INDEX,
@@ -30,6 +28,7 @@ import {
3028
import FontLoaderHOC from '../lib/font-loader-hoc.jsx';
3129
import LocalizationHOC from '../lib/localization-hoc.jsx';
3230
import ProjectFetcherHOC from '../lib/project-fetcher-hoc.jsx';
31+
import TitledHOC from '../lib/titled-hoc.jsx';
3332
import ProjectSaverHOC from '../lib/project-saver-hoc.jsx';
3433
import QueryParserHOC from '../lib/query-parser-hoc.jsx';
3534
import storage from '../lib/storage';
@@ -40,45 +39,21 @@ import cloudManagerHOC from '../lib/cloud-manager-hoc.jsx';
4039
import GUIComponent from '../components/gui/gui.jsx';
4140
import {setIsScratchDesktop} from '../lib/isScratchDesktop.js';
4241

43-
const messages = defineMessages({
44-
defaultProjectTitle: {
45-
id: 'gui.gui.defaultProjectTitle',
46-
description: 'Default title for project',
47-
defaultMessage: 'Scratch Project'
48-
}
49-
});
50-
5142
class GUI extends React.Component {
5243
componentDidMount () {
5344
setIsScratchDesktop(this.props.isScratchDesktop);
54-
this.setReduxTitle(this.props.projectTitle);
5545
this.props.onStorageInit(storage);
5646
this.props.onVmInit(this.props.vm);
5747
}
5848
componentDidUpdate (prevProps) {
5949
if (this.props.projectId !== prevProps.projectId && this.props.projectId !== null) {
6050
this.props.onUpdateProjectId(this.props.projectId);
6151
}
62-
if (this.props.projectTitle !== prevProps.projectTitle) {
63-
this.setReduxTitle(this.props.projectTitle);
64-
}
6552
if (this.props.isShowingProject && !prevProps.isShowingProject) {
6653
// this only notifies container when a project changes from not yet loaded to loaded
6754
// At this time the project view in www doesn't need to know when a project is unloaded
6855
this.props.onProjectLoaded();
6956
}
70-
if (this.props.isShowingWithoutId && !prevProps.isShowingWithoutId) {
71-
this.props.onUpdateProjectTitle(this.props.intl.formatMessage(messages.defaultProjectTitle));
72-
}
73-
}
74-
setReduxTitle (newTitle) {
75-
if (newTitle === null || typeof newTitle === 'undefined') {
76-
this.props.onUpdateReduxProjectTitle(
77-
this.props.intl.formatMessage(messages.defaultProjectTitle)
78-
);
79-
} else {
80-
this.props.onUpdateReduxProjectTitle(newTitle);
81-
}
8257
}
8358
render () {
8459
if (this.props.isError) {
@@ -96,11 +71,9 @@ class GUI extends React.Component {
9671
onProjectLoaded,
9772
onStorageInit,
9873
onUpdateProjectId,
99-
onUpdateReduxProjectTitle,
10074
onVmInit,
10175
projectHost,
10276
projectId,
103-
projectTitle,
10477
/* eslint-enable no-unused-vars */
10578
children,
10679
fetchingProject,
@@ -137,11 +110,9 @@ GUI.propTypes = {
137110
onStorageInit: PropTypes.func,
138111
onUpdateProjectId: PropTypes.func,
139112
onUpdateProjectTitle: PropTypes.func,
140-
onUpdateReduxProjectTitle: PropTypes.func,
141113
onVmInit: PropTypes.func,
142114
projectHost: PropTypes.string,
143115
projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
144-
projectTitle: PropTypes.string,
145116
telemetryModalVisible: PropTypes.bool,
146117
vm: PropTypes.instanceOf(VM).isRequired
147118
};
@@ -151,7 +122,6 @@ GUI.defaultProps = {
151122
onStorageInit: storageInstance => storageInstance.addOfficialScratchWebStores(),
152123
onProjectLoaded: () => {},
153124
onUpdateProjectId: () => {},
154-
onUpdateProjectTitle: () => {},
155125
onVmInit: (/* vm */) => {}
156126
};
157127

@@ -172,7 +142,6 @@ const mapStateToProps = state => {
172142
isPlayerOnly: state.scratchGui.mode.isPlayerOnly,
173143
isRtl: state.locales.isRtl,
174144
isShowingProject: getIsShowingProject(loadingState),
175-
isShowingWithoutId: getIsShowingWithoutId(loadingState),
176145
loadingStateVisible: state.scratchGui.modals.loadingProject,
177146
projectId: state.scratchGui.projectState.projectId,
178147
soundsTabVisible: state.scratchGui.editorTab.activeTabIndex === SOUNDS_TAB_INDEX,
@@ -193,8 +162,7 @@ const mapDispatchToProps = dispatch => ({
193162
onActivateSoundsTab: () => dispatch(activateTab(SOUNDS_TAB_INDEX)),
194163
onRequestCloseBackdropLibrary: () => dispatch(closeBackdropLibrary()),
195164
onRequestCloseCostumeLibrary: () => dispatch(closeCostumeLibrary()),
196-
onRequestCloseTelemetryModal: () => dispatch(closeTelemetryModal()),
197-
onUpdateReduxProjectTitle: title => dispatch(setProjectTitle(title))
165+
onRequestCloseTelemetryModal: () => dispatch(closeTelemetryModal())
198166
});
199167

200168
const ConnectedGUI = injectIntl(connect(
@@ -211,6 +179,7 @@ const WrappedGui = compose(
211179
FontLoaderHOC,
212180
QueryParserHOC,
213181
ProjectFetcherHOC,
182+
TitledHOC,
214183
ProjectSaverHOC,
215184
vmListenerHOC,
216185
vmManagerHOC,

src/lib/titled-hoc.jsx

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
1+
import PropTypes from 'prop-types';
12
import React from 'react';
23
import bindAll from 'lodash.bindall';
4+
import {connect} from 'react-redux';
5+
import {defineMessages, injectIntl, intlShape} from 'react-intl';
6+
7+
import {getIsShowingWithoutId} from '../reducers/project-state';
8+
import {setProjectTitle} from '../reducers/project-title';
9+
10+
const messages = defineMessages({
11+
defaultProjectTitle: {
12+
id: 'gui.gui.defaultProjectTitle',
13+
description: 'Default title for project',
14+
defaultMessage: 'Scratch Project'
15+
}
16+
});
317

418
/* Higher Order Component to get and set the project title
519
* @param {React.Component} WrappedComponent component to receive project title related props
@@ -12,26 +26,89 @@ const TitledHOC = function (WrappedComponent) {
1226
bindAll(this, [
1327
'handleUpdateProjectTitle'
1428
]);
15-
this.state = {
16-
projectTitle: null
17-
};
29+
}
30+
componentDidMount () {
31+
this.setReduxTitle(this.props.projectTitle);
32+
}
33+
componentDidUpdate (prevProps) {
34+
if (this.props.projectTitle !== prevProps.projectTitle) {
35+
this.setReduxTitle(this.props.projectTitle);
36+
}
37+
if (this.props.isShowingWithoutId && !prevProps.isShowingWithoutId) {
38+
const defaultProjectTitle = this.titleWithDefault();
39+
this.setReduxTitle(defaultProjectTitle);
40+
this.props.onUpdateProjectTitle(defaultProjectTitle);
41+
}
42+
}
43+
titleWithDefault (title) {
44+
if (title === null || typeof title === 'undefined') {
45+
return this.props.intl.formatMessage(messages.defaultProjectTitle);
46+
}
47+
return title;
48+
}
49+
setReduxTitle (newTitle) {
50+
if (newTitle === null || typeof newTitle === 'undefined') {
51+
this.props.onUpdateReduxProjectTitle(
52+
this.props.intl.formatMessage(messages.defaultProjectTitle)
53+
);
54+
} else {
55+
this.props.onUpdateReduxProjectTitle(newTitle);
56+
}
1857
}
1958
handleUpdateProjectTitle (newTitle) {
20-
this.setState({projectTitle: newTitle});
59+
this.setReduxTitle(newTitle);
60+
this.props.onUpdateProjectTitle(newTitle);
2161
}
2262
render () {
63+
const {
64+
/* eslint-disable no-unused-vars */
65+
intl,
66+
isShowingWithoutId,
67+
// for children, we replace onUpdateProjectTitle with our own
68+
onUpdateProjectTitle,
69+
onUpdateReduxProjectTitle,
70+
// we don't pass projectTitle prop to children -- they must use
71+
// redux value
72+
projectTitle,
73+
/* eslint-enable no-unused-vars */
74+
...componentProps
75+
} = this.props;
2376
return (
2477
<WrappedComponent
25-
canEditTitle
26-
projectTitle={this.state.projectTitle}
2778
onUpdateProjectTitle={this.handleUpdateProjectTitle}
28-
{...this.props}
79+
{...componentProps}
2980
/>
3081
);
3182
}
3283
}
3384

34-
return TitledComponent;
85+
TitledComponent.propTypes = {
86+
intl: intlShape,
87+
isShowingWithoutId: PropTypes.bool,
88+
onUpdateProjectTitle: PropTypes.func,
89+
onUpdateReduxProjectTitle: PropTypes.func,
90+
projectTitle: PropTypes.string
91+
};
92+
93+
TitledComponent.defaultProps = {
94+
onUpdateProjectTitle: () => {}
95+
};
96+
97+
const mapStateToProps = state => {
98+
const loadingState = state.scratchGui.projectState.loadingState;
99+
return {
100+
isShowingWithoutId: getIsShowingWithoutId(loadingState)
101+
};
102+
};
103+
104+
const mapDispatchToProps = dispatch => ({
105+
onUpdateReduxProjectTitle: title => dispatch(setProjectTitle(title))
106+
});
107+
108+
return injectIntl(connect(
109+
mapStateToProps,
110+
mapDispatchToProps,
111+
)(TitledComponent));
35112
};
36113

37114
export {

0 commit comments

Comments
 (0)