From 22e2c17ff4a11a78ba5a7a48d3bcd868b10f6043 Mon Sep 17 00:00:00 2001 From: Ben Wheeler <wheeler.benjamin@gmail.com> Date: Fri, 11 Oct 2019 16:17:02 -0400 Subject: [PATCH] =?UTF-8?q?don=E2=80=99t=20pass=20onUpdateProjectTitle=20b?= =?UTF-8?q?elow=20titledHIC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/gui/gui.jsx | 3 -- src/components/menu-bar/menu-bar.jsx | 3 -- .../menu-bar/project-title-input.jsx | 52 ++++++++----------- src/containers/gui.jsx | 2 - src/containers/sb-file-uploader.jsx | 8 +-- src/lib/titled-hoc.jsx | 47 ++++++----------- .../unit/containers/sb-file-uploader.test.jsx | 3 -- 7 files changed, 41 insertions(+), 77 deletions(-) diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index ab7ec87b0..9846eed75 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -94,7 +94,6 @@ const GUIComponent = props => { onLogOut, onOpenRegistration, onToggleLoginOpen, - onUpdateProjectTitle, onActivateCostumesTab, onActivateSoundsTab, onActivateTab, @@ -228,7 +227,6 @@ const GUIComponent = props => { onSeeCommunity={onSeeCommunity} onShare={onShare} onToggleLoginOpen={onToggleLoginOpen} - onUpdateProjectTitle={onUpdateProjectTitle} /> <Box className={styles.bodyWrapper}> <Box className={styles.flexWrapper}> @@ -406,7 +404,6 @@ GUIComponent.propTypes = { onTelemetryModalOptIn: PropTypes.func, onTelemetryModalOptOut: PropTypes.func, onToggleLoginOpen: PropTypes.func, - onUpdateProjectTitle: PropTypes.func, renderLogin: PropTypes.func, showComingSoon: PropTypes.bool, soundsTabVisible: PropTypes.bool, diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx index 1fa7a01cc..98bc128a9 100644 --- a/src/components/menu-bar/menu-bar.jsx +++ b/src/components/menu-bar/menu-bar.jsx @@ -395,7 +395,6 @@ class MenuBar extends React.Component { <SBFileUploader canSave={this.props.canSave} userOwnsProject={this.props.userOwnsProject} - onUpdateProjectTitle={this.props.onUpdateProjectTitle} > {(className, renderFileInput, handleLoadProject) => ( <MenuItem @@ -495,7 +494,6 @@ class MenuBar extends React.Component { > <ProjectTitleInput className={classNames(styles.titleFieldGrowable)} - onUpdateProjectTitle={this.props.onUpdateProjectTitle} /> </MenuBarItemTooltip> </div> @@ -746,7 +744,6 @@ MenuBar.propTypes = { onSeeCommunity: PropTypes.func, onShare: PropTypes.func, onToggleLoginOpen: PropTypes.func, - onUpdateProjectTitle: PropTypes.func, projectTitle: PropTypes.string, renderLogin: PropTypes.func, sessionExists: PropTypes.bool, diff --git a/src/components/menu-bar/project-title-input.jsx b/src/components/menu-bar/project-title-input.jsx index b9b5aa6d8..4f90914a3 100644 --- a/src/components/menu-bar/project-title-input.jsx +++ b/src/components/menu-bar/project-title-input.jsx @@ -1,9 +1,9 @@ import classNames from 'classnames'; import {connect} from 'react-redux'; import PropTypes from 'prop-types'; -import bindAll from 'lodash.bindall'; import React from 'react'; import {defineMessages, intlShape, injectIntl} from 'react-intl'; +import {setProjectTitle} from '../../reducers/project-title'; import BufferedInputHOC from '../forms/buffered-input-hoc.jsx'; import Input from '../forms/input.jsx'; @@ -19,39 +19,27 @@ const messages = defineMessages({ } }); -class ProjectTitleInput extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleUpdateProjectTitle' - ]); - } - // call onUpdateProjectTitle if it is defined (only defined when gui - // is used within scratch-www) - handleUpdateProjectTitle (newTitle) { - if (this.props.onUpdateProjectTitle) { - this.props.onUpdateProjectTitle(newTitle); - } - } - render () { - return ( - <BufferedInput - className={classNames(styles.titleField, this.props.className)} - maxLength="100" - placeholder={this.props.intl.formatMessage(messages.projectTitlePlaceholder)} - tabIndex="0" - type="text" - value={this.props.projectTitle} - onSubmit={this.handleUpdateProjectTitle} - /> - ); - } -} +const ProjectTitleInput = ({ + className, + handleUpdateReduxProjectTitle, + intl, + projectTitle +}) => ( + <BufferedInput + className={classNames(styles.titleField, className)} + maxLength="100" + placeholder={intl.formatMessage(messages.projectTitlePlaceholder)} + tabIndex="0" + type="text" + value={projectTitle} + onSubmit={handleUpdateReduxProjectTitle} + /> +); ProjectTitleInput.propTypes = { className: PropTypes.string, + handleUpdateReduxProjectTitle: PropTypes.func, intl: intlShape.isRequired, - onUpdateProjectTitle: PropTypes.func, projectTitle: PropTypes.string }; @@ -59,7 +47,9 @@ const mapStateToProps = state => ({ projectTitle: state.scratchGui.projectTitle }); -const mapDispatchToProps = () => ({}); +const mapDispatchToProps = dispatch => ({ + handleUpdateReduxProjectTitle: title => dispatch(setProjectTitle(title)) +}); export default injectIntl(connect( mapStateToProps, diff --git a/src/containers/gui.jsx b/src/containers/gui.jsx index d7b8f78c2..314c38893 100644 --- a/src/containers/gui.jsx +++ b/src/containers/gui.jsx @@ -103,13 +103,11 @@ GUI.propTypes = { isLoading: PropTypes.bool, isScratchDesktop: PropTypes.bool, isShowingProject: PropTypes.bool, - isShowingWithoutId: PropTypes.bool, loadingStateVisible: PropTypes.bool, onProjectLoaded: PropTypes.func, onSeeCommunity: PropTypes.func, onStorageInit: PropTypes.func, onUpdateProjectId: PropTypes.func, - onUpdateProjectTitle: PropTypes.func, onVmInit: PropTypes.func, projectHost: PropTypes.string, projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), diff --git a/src/containers/sb-file-uploader.jsx b/src/containers/sb-file-uploader.jsx index ae5f42915..c4f484c22 100644 --- a/src/containers/sb-file-uploader.jsx +++ b/src/containers/sb-file-uploader.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import {connect} from 'react-redux'; import {defineMessages, injectIntl, intlShape} from 'react-intl'; +import {setProjectTitle} from '../reducers/project-title'; import log from '../lib/log'; import sharedMessages from '../lib/shared-messages'; @@ -131,7 +132,7 @@ class SBFileUploader extends React.Component { // This is necessary in case the user wants to reload a project if (filename) { const uploadedProjectTitle = this.getProjectTitleFromFilename(filename); - this.props.onUpdateProjectTitle(uploadedProjectTitle); + this.props.updateReduxProjectTitle(uploadedProjectTitle); } this.resetFileInput(); }) @@ -179,9 +180,9 @@ SBFileUploader.propTypes = { loadingState: PropTypes.oneOf(LoadingStates), onLoadingFinished: PropTypes.func, onLoadingStarted: PropTypes.func, - onUpdateProjectTitle: PropTypes.func, projectChanged: PropTypes.bool, requestProjectUpload: PropTypes.func, + updateReduxProjectTitle: PropTypes.func, userOwnsProject: PropTypes.bool, vm: PropTypes.shape({ loadProject: PropTypes.func @@ -209,7 +210,8 @@ const mapDispatchToProps = (dispatch, ownProps) => ({ dispatch(closeFileMenu()); }, requestProjectUpload: loadingState => dispatch(requestProjectUpload(loadingState)), - onLoadingStarted: () => dispatch(openLoadingProject()) + onLoadingStarted: () => dispatch(openLoadingProject()), + updateReduxProjectTitle: title => dispatch(setProjectTitle(title)) }); // Allow incoming props to override redux-provided props. Used to mock in tests. diff --git a/src/lib/titled-hoc.jsx b/src/lib/titled-hoc.jsx index fc8c33b8e..30ed66217 100644 --- a/src/lib/titled-hoc.jsx +++ b/src/lib/titled-hoc.jsx @@ -1,6 +1,5 @@ import PropTypes from 'prop-types'; import React from 'react'; -import bindAll from 'lodash.bindall'; import {connect} from 'react-redux'; import {defineMessages, injectIntl, intlShape} from 'react-intl'; @@ -21,23 +20,18 @@ const messages = defineMessages({ */ const TitledHOC = function (WrappedComponent) { class TitledComponent extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleUpdateProjectTitle' - ]); - } componentDidMount () { - this.setReduxTitle(this.props.projectTitle); + this.props.updateReduxProjectTitle(this.titleWithDefault(this.props.projectTitle)); } componentDidUpdate (prevProps) { if (this.props.projectTitle !== prevProps.projectTitle) { - this.setReduxTitle(this.props.projectTitle); + this.props.updateReduxProjectTitle(this.titleWithDefault(this.props.projectTitle)); } - if (this.props.isShowingWithoutId && !prevProps.isShowingWithoutId) { - const defaultProjectTitle = this.titleWithDefault(); - this.setReduxTitle(defaultProjectTitle); - this.props.onUpdateProjectTitle(defaultProjectTitle); + // if the projectTitle hasn't changed, but the reduxProjectTitle + // HAS changed, we need to report that change to the projectTitle's owner + if (this.props.reduxProjectTitle !== prevProps.reduxProjectTitle && + this.props.reduxProjectTitle !== this.props.projectTitle) { + this.props.onUpdateProjectTitle(this.props.reduxProjectTitle); } } titleWithDefault (title) { @@ -46,19 +40,6 @@ const TitledHOC = function (WrappedComponent) { } return title; } - setReduxTitle (newTitle) { - if (newTitle === null || typeof newTitle === 'undefined') { - this.props.onUpdateReduxProjectTitle( - this.props.intl.formatMessage(messages.defaultProjectTitle) - ); - } else { - this.props.onUpdateReduxProjectTitle(newTitle); - } - } - handleUpdateProjectTitle (newTitle) { - this.setReduxTitle(newTitle); - this.props.onUpdateProjectTitle(newTitle); - } render () { const { /* eslint-disable no-unused-vars */ @@ -66,16 +47,16 @@ const TitledHOC = function (WrappedComponent) { isShowingWithoutId, // for children, we replace onUpdateProjectTitle with our own onUpdateProjectTitle, - onUpdateReduxProjectTitle, // we don't pass projectTitle prop to children -- they must use // redux value projectTitle, + reduxProjectTitle, + updateReduxProjectTitle, /* eslint-enable no-unused-vars */ ...componentProps } = this.props; return ( <WrappedComponent - onUpdateProjectTitle={this.handleUpdateProjectTitle} {...componentProps} /> ); @@ -86,8 +67,9 @@ const TitledHOC = function (WrappedComponent) { intl: intlShape, isShowingWithoutId: PropTypes.bool, onUpdateProjectTitle: PropTypes.func, - onUpdateReduxProjectTitle: PropTypes.func, - projectTitle: PropTypes.string + projectTitle: PropTypes.string, + reduxProjectTitle: PropTypes.string, + updateReduxProjectTitle: PropTypes.func }; TitledComponent.defaultProps = { @@ -97,12 +79,13 @@ const TitledHOC = function (WrappedComponent) { const mapStateToProps = state => { const loadingState = state.scratchGui.projectState.loadingState; return { - isShowingWithoutId: getIsShowingWithoutId(loadingState) + isShowingWithoutId: getIsShowingWithoutId(loadingState), + reduxProjectTitle: state.scratchGui.projectTitle }; }; const mapDispatchToProps = dispatch => ({ - onUpdateReduxProjectTitle: title => dispatch(setProjectTitle(title)) + updateReduxProjectTitle: title => dispatch(setProjectTitle(title)) }); return injectIntl(connect( diff --git a/test/unit/containers/sb-file-uploader.test.jsx b/test/unit/containers/sb-file-uploader.test.jsx index 083dbfa2d..c757114b4 100644 --- a/test/unit/containers/sb-file-uploader.test.jsx +++ b/test/unit/containers/sb-file-uploader.test.jsx @@ -11,7 +11,6 @@ describe('SBFileUploader Container', () => { const mockStore = configureStore(); let onLoadingFinished; let onLoadingStarted; - let onUpdateProjectTitle; let store; // Wrap this in a function so it gets test specific states and can be reused. @@ -20,7 +19,6 @@ describe('SBFileUploader Container', () => { <SBFileUploader onLoadingFinished={onLoadingFinished} onLoadingStarted={onLoadingStarted} - onUpdateProjectTitle={onUpdateProjectTitle} > {(renderFileInput, loadProject) => ( <div @@ -40,7 +38,6 @@ describe('SBFileUploader Container', () => { vm: {} } }); - onUpdateProjectTitle = jest.fn(); onLoadingFinished = jest.fn(); onLoadingStarted = jest.fn(); }); -- GitLab