From 093bcfea78082e89fd02e033319c058257ffa99e Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sat, 3 Apr 2021 16:09:31 -0500 Subject: [PATCH] Consolidate project ID and URL search param changing --- .../featured-projects.jsx | 4 +- .../tw-project-input/project-input.jsx | 9 +++-- src/containers/tw-settings-modal.jsx | 6 +-- src/lib/tw-navigation-utils.js | 39 +++++++++++++++++++ src/lib/tw-state-manager-hoc.jsx | 18 +-------- 5 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 src/lib/tw-navigation-utils.js diff --git a/src/components/tw-featured-projects/featured-projects.jsx b/src/components/tw-featured-projects/featured-projects.jsx index 631de728c..27afeba63 100644 --- a/src/components/tw-featured-projects/featured-projects.jsx +++ b/src/components/tw-featured-projects/featured-projects.jsx @@ -6,8 +6,8 @@ import {FormattedMessage} from 'react-intl'; import {connect} from 'react-redux'; import StudioView from '../tw-studioview/studioview.jsx'; import styles from './featured-projects.css'; -import {getIsLoading, getIsFetchingWithId, setProjectId} from '../../reducers/project-state'; import analytics from '../../lib/analytics'; +import { setProjectId } from '../../lib/tw-navigation-utils.js'; class FeaturedProjects extends React.Component { constructor (props) { @@ -87,7 +87,7 @@ FeaturedProjects.propTypes = { const mapStateToProps = () => ({}); const mapDispatchToProps = dispatch => ({ - setProjectId: projectId => dispatch(setProjectId(projectId)) + setProjectId: projectId => setProjectId(dispatch, projectId) }); export default connect( diff --git a/src/components/tw-project-input/project-input.jsx b/src/components/tw-project-input/project-input.jsx index ae4e9b58b..2c12b2cce 100644 --- a/src/components/tw-project-input/project-input.jsx +++ b/src/components/tw-project-input/project-input.jsx @@ -2,9 +2,9 @@ import PropTypes from 'prop-types'; import React from 'react'; import {connect} from 'react-redux'; import bindAll from 'lodash.bindall'; - -import {defaultProjectId, setProjectId, getIsLoading, getIsFetchingWithId} from '../../reducers/project-state'; +import {defaultProjectId, getIsLoading, getIsFetchingWithId} from '../../reducers/project-state'; import styles from './project-input.css'; +import { setProjectId } from '../../lib/tw-navigation-utils'; const PROJECT_BASE = 'https://scratch.mit.edu/projects/'; @@ -103,11 +103,12 @@ ProjectInput.propTypes = { const mapStateToProps = state => ({ projectId: state.scratchGui.projectState.projectId, - loading: getIsLoading(state.scratchGui.projectState.loadingState) || getIsFetchingWithId(state.scratchGui.projectState.loadingState) + loading: getIsLoading(state.scratchGui.projectState.loadingState) || + getIsFetchingWithId(state.scratchGui.projectState.loadingState) }); const mapDispatchToProps = dispatch => ({ - setProjectId: projectId => dispatch(setProjectId(projectId)) + setProjectId: projectId => setProjectId(dispatch, projectId) }); export default connect( diff --git a/src/containers/tw-settings-modal.jsx b/src/containers/tw-settings-modal.jsx index 98d20fc8b..da521885a 100644 --- a/src/containers/tw-settings-modal.jsx +++ b/src/containers/tw-settings-modal.jsx @@ -6,6 +6,7 @@ import {connect} from 'react-redux'; import {closeSettingsModal} from '../reducers/modals'; import SettingsModalComponent from '../components/tw-settings-modal/settings-modal.jsx'; import twStageSize from '../lib/tw-stage-size'; +import {searchParamsToString} from '../lib/tw-navigation-utils'; const messages = defineMessages({ confirmReload: { @@ -115,9 +116,8 @@ class UsernameModal extends React.Component { } else { urlParams.set('size', `${this.state.stageWidth}x${this.state.stageHeight}`); } - const search = urlParams.toString(); - const newUrl = `${location.pathname}${search.length > 0 ? '?' : ''}${search}`; - location.href = newUrl; + const search = searchParamsToString(urlParams); + location.href = `${location.pathname}${search}`; } render () { const { diff --git a/src/lib/tw-navigation-utils.js b/src/lib/tw-navigation-utils.js new file mode 100644 index 000000000..d1191e269 --- /dev/null +++ b/src/lib/tw-navigation-utils.js @@ -0,0 +1,39 @@ +import {setProjectId as reduxSetProjectId} from '../reducers/project-state'; + +const setProjectId = (dispatch, projectId) => { + // TODO + dispatch(reduxSetProjectId(projectId)); +}; + +const searchParamsToString = params => { + let newSearch = params.toString(); + if (newSearch.length > 0) { + // Add leading question mark + newSearch = `?${newSearch}`; + newSearch = newSearch + // Remove '=' from empty values + // eslint-disable-next-line no-div-regex + .replace(/=(?=$|&)/g, '') + // Decode / and : (common in project_url setting) + .replace(/%2F/g, '/') + .replace(/%3A/g, ':'); + } + return newSearch; +}; + +/** + * Change URL search params to something else in place + * @param {URLSearchParams} params New URLSearchParams + */ +const setSearchParams = params => { + const newSearch = searchParamsToString(params); + if (location.search !== newSearch) { + history.replaceState(null, null, `${location.pathname}${newSearch}${location.hash}`); + } +}; + +export { + setProjectId, + searchParamsToString, + setSearchParams +}; diff --git a/src/lib/tw-state-manager-hoc.jsx b/src/lib/tw-state-manager-hoc.jsx index d2868fdab..70c277e20 100644 --- a/src/lib/tw-state-manager-hoc.jsx +++ b/src/lib/tw-state-manager-hoc.jsx @@ -18,6 +18,7 @@ import { setFullScreen } from '../reducers/mode'; import {generateRandomUsername} from './tw-username'; +import {setSearchParams} from './tw-navigation-utils'; /* eslint-disable no-alert */ @@ -465,22 +466,7 @@ const TWStateManager = function (WrappedComponent) { searchParams.set('limitless', ''); } - let newSearch = searchParams.toString(); - if (newSearch.length > 0) { - // Add leading question mark - newSearch = `?${newSearch}`; - newSearch = newSearch - // Remove '=' from empty values - // eslint-disable-next-line no-div-regex - .replace(/=(?=$|&)/g, '') - // Decode / and : (common in project_url setting) - .replace(/%2F/g, '/') - .replace(/%3A/g, ':'); - } - - if (location.search !== newSearch) { - history.replaceState(null, null, `${location.pathname}${newSearch}${location.hash}`); - } + setSearchParams(searchParams); } } componentWillUnmount () {