Merge pull request #3082 from LLK/develop

Freeze
This commit is contained in:
Andrew Sliwinski authored and GitHub committed 2018-09-06 11:14:39 -04:00
commit a96f9e80be
8 files changed
+117 -78

No files matched your search

+4 -4
View File
@@ -87,9 +87,9 @@
"react-redux": "5.0.7",
"react-responsive": "5.0.0",
"react-style-proptype": "3.2.1",
"react-tabs": "2.2.2",
"react-tabs": "2.3.0",
"react-test-renderer": "16.2.0",
"react-tooltip": "3.6.1",
"react-tooltip": "3.8.0",
"react-virtualized": "9.20.1",
"redux": "3.7.2",
"redux-mock-store": "^1.2.3",
@@ -98,11 +98,11 @@
"scratch-audio": "0.1.0-prerelease.20180625202813",
"scratch-blocks": "0.1.0-prerelease.1535662135",
"scratch-l10n": "3.0.20180830210150",
"scratch-paint": "0.2.0-prerelease.20180831175055",
"scratch-paint": "0.2.0-prerelease.20180905220723",
"scratch-render": "0.1.0-prerelease.20180824141819",
"scratch-storage": "1.0.2",
"scratch-svg-renderer": "0.2.0-prerelease.20180817005452",
"scratch-vm": "0.2.0-prerelease.20180830155110",
"scratch-vm": "0.2.0-prerelease.20180906133035",
"selenium-webdriver": "3.6.0",
"startaudiocontext": "1.2.1",
"style-loader": "^0.23.0",
@@ -84,4 +84,8 @@ BrowserModal.propTypes = {
onBack: PropTypes.func.isRequired
};
export default injectIntl(BrowserModal);
const WrappedBrowserModal = injectIntl(BrowserModal);
WrappedBrowserModal.setAppElement = ReactModal.setAppElement;
export default WrappedBrowserModal;
+1 -3
View File
@@ -62,7 +62,6 @@ const GUIComponent = props => {
costumeLibraryVisible,
costumesTabVisible,
enableCommunity,
hideIntro,
importInfoVisible,
intl,
isPlayerOnly,
@@ -116,7 +115,7 @@ const GUIComponent = props => {
{...componentProps}
>
{previewInfoVisible ? (
<PreviewModal hideIntro={hideIntro} />
<PreviewModal />
) : null}
{loading ? (
<Loader />
@@ -282,7 +281,6 @@ GUIComponent.propTypes = {
costumeLibraryVisible: PropTypes.bool,
costumesTabVisible: PropTypes.bool,
enableCommunity: PropTypes.bool,
hideIntro: PropTypes.bool,
importInfoVisible: PropTypes.bool,
intl: intlShape.isRequired,
isPlayerOnly: PropTypes.bool,
+9 -3
View File
@@ -72,10 +72,15 @@ class GUI extends React.Component {
`Failed to load project from server [id=${window.location.hash}]: ${this.state.errorMessage}`);
}
const {
/* eslint-disable no-unused-vars */
assetHost,
hideIntro,
projectData,
projectHost,
/* eslint-enable no-unused-vars */
children,
fetchingProject,
loadingStateVisible,
projectData, // eslint-disable-line no-unused-vars
vm,
...componentProps
} = this.props;
@@ -94,6 +99,7 @@ class GUI extends React.Component {
GUI.propTypes = {
children: PropTypes.node,
fetchingProject: PropTypes.bool,
hideIntro: PropTypes.bool,
importInfoVisible: PropTypes.bool,
loadingStateVisible: PropTypes.bool,
onSeeCommunity: PropTypes.func,
@@ -102,7 +108,7 @@ GUI.propTypes = {
vm: PropTypes.instanceOf(VM)
};
const mapStateToProps = state => ({
const mapStateToProps = (state, ownProps) => ({
activeTabIndex: state.scratchGui.editorTab.activeTabIndex,
backdropLibraryVisible: state.scratchGui.modals.backdropLibrary,
blocksTabVisible: state.scratchGui.editorTab.activeTabIndex === BLOCKS_TAB_INDEX,
@@ -113,7 +119,7 @@ const mapStateToProps = state => ({
isPlayerOnly: state.scratchGui.mode.isPlayerOnly,
isRtl: state.locales.isRtl,
loadingStateVisible: state.scratchGui.modals.loadingProject,
previewInfoVisible: state.scratchGui.modals.previewInfo,
previewInfoVisible: state.scratchGui.modals.previewInfo && !ownProps.hideIntro,
targetIsStage: (
state.scratchGui.targets.stage &&
state.scratchGui.targets.stage.id === state.scratchGui.targets.editingTarget
+6 -26
View File
@@ -6,8 +6,6 @@ import {connect} from 'react-redux';
import tabletFullScreen from '../lib/tablet-full-screen';
import PreviewModalComponent from '../components/preview-modal/preview-modal.jsx';
import BrowserModalComponent from '../components/browser-modal/browser-modal.jsx';
import supportedBrowser from '../lib/supported-browser';
import {
closePreviewInfo,
@@ -27,25 +25,6 @@ class PreviewModal extends React.Component {
previewing: false
};
}
/**
* Conditionally returns an intro modal depending on the hideIntro prop
* @returns { React.Component | null } null if hideIntro is true, the intro modal component otherwise
*/
introIfShown () {
if (this.props.hideIntro) {
return null; // If hideIntro is true, the intro modal should not appear
}
// otherwise, show the intro modal
return (<PreviewModalComponent
isRtl={this.props.isRtl}
previewing={this.state.previewing}
onCancel={this.handleCancel}
onTryIt={this.handleTryIt}
onViewProject={this.handleViewProject}
/>);
}
handleTryIt () {
this.setState({previewing: true});
// try to run in fullscreen mode on tablets.
@@ -59,18 +38,19 @@ class PreviewModal extends React.Component {
this.props.onViewProject();
}
render () {
return (supportedBrowser() ?
this.introIfShown() :
<BrowserModalComponent
return (
<PreviewModalComponent
isRtl={this.props.isRtl}
onBack={this.handleCancel}
previewing={this.state.previewing}
onCancel={this.handleCancel}
onTryIt={this.handleTryIt}
onViewProject={this.handleViewProject}
/>
);
}
}
PreviewModal.propTypes = {
hideIntro: PropTypes.bool,
isRtl: PropTypes.bool,
onTryIt: PropTypes.func,
onViewProject: PropTypes.func
+48 -22
View File
@@ -4,7 +4,6 @@ import {Provider} from 'react-redux';
import {createStore, combineReducers, compose} from 'redux';
import ConnectedIntlProvider from './connected-intl-provider.jsx';
import guiReducer, {guiInitialState, guiMiddleware, initFullScreen, initPlayer} from '../reducers/gui';
import localesReducer, {initLocale, localesInitialState} from '../reducers/locales';
import {setPlayer, setFullScreen} from '../reducers/mode.js';
@@ -12,49 +11,76 @@ import {setPlayer, setFullScreen} from '../reducers/mode.js';
import locales from 'scratch-l10n';
import {detectLocale} from './detect-locale';
import {ScratchPaintReducer} from 'scratch-paint';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const enhancer = composeEnhancers(guiMiddleware);
/*
* Higher Order Component to provide redux state. If an `intl` prop is provided
* it will override the internal `intl` redux state
* @param {React.Component} WrappedComponent - component to provide state for
* @param {boolean} localesOnly - only provide the locale state, not everything
* required by the GUI. Used to exclude excess state when
only rendering modals, not the GUI.
* @returns {React.Component} component with redux and intl state provided
*/
const AppStateHOC = function (WrappedComponent) {
const AppStateHOC = function (WrappedComponent, localesOnly) {
class AppStateWrapper extends React.Component {
constructor (props) {
super(props);
let initializedGui = guiInitialState;
if (props.isFullScreen) {
initializedGui = initFullScreen(initializedGui);
}
if (props.isPlayerOnly) {
initializedGui = initPlayer(initializedGui);
}
let initialState = {};
let reducers = {};
let enhancer;
let initializedLocales = localesInitialState;
const locale = detectLocale(Object.keys(locales));
if (locale !== 'en') {
initializedLocales = initLocale(initializedLocales, locale);
}
if (localesOnly) {
// Used for instantiating minimal state for the unsupported
// browser modal
reducers = {locales: localesReducer};
initialState = {locales: initializedLocales};
enhancer = composeEnhancers();
} else {
// You are right, this is gross. But it's necessary to avoid
// importing unneeded code that will crash unsupported browsers.
const guiRedux = require('../reducers/gui');
const guiReducer = guiRedux.default;
const {
guiInitialState,
guiMiddleware,
initFullScreen,
initPlayer
} = guiRedux;
const {ScratchPaintReducer} = require('scratch-paint');
const reducer = combineReducers({
locales: localesReducer,
scratchGui: guiReducer,
scratchPaint: ScratchPaintReducer
});
this.store = createStore(
reducer,
{
let initializedGui = guiInitialState;
if (props.isFullScreen) {
initializedGui = initFullScreen(initializedGui);
}
if (props.isPlayerOnly) {
initializedGui = initPlayer(initializedGui);
}
reducers = {
locales: localesReducer,
scratchGui: guiReducer,
scratchPaint: ScratchPaintReducer
};
initialState = {
locales: initializedLocales,
scratchGui: initializedGui
},
enhancer);
};
enhancer = composeEnhancers(guiMiddleware);
}
const reducer = combineReducers(reducers);
this.store = createStore(
reducer,
initialState,
enhancer
);
}
componentDidUpdate (prevProps) {
if (localesOnly) return;
if (prevProps.isPlayerOnly !== this.props.isPlayerOnly) {
this.store.dispatch(setPlayer(this.props.isPlayerOnly));
}
+13 -19
View File
@@ -7,17 +7,12 @@ import React from 'react';
import ReactDOM from 'react-dom';
import analytics from '../lib/analytics';
import GUI from '../containers/gui.jsx';
import HashParserHOC from '../lib/hash-parser-hoc.jsx';
import AppStateHOC from '../lib/app-state-hoc.jsx';
import BrowserModalComponent from '../components/browser-modal/browser-modal.jsx';
import supportedBrowser from '../lib/supported-browser';
import styles from './index.css';
if (process.env.NODE_ENV === 'production' && typeof window === 'object') {
// Warn before navigating away
window.onbeforeunload = () => true;
}
// Register "base" page view
analytics.pageview('/');
@@ -25,16 +20,15 @@ const appTarget = document.createElement('div');
appTarget.className = styles.app;
document.body.appendChild(appTarget);
GUI.setAppElement(appTarget);
const WrappedGui = HashParserHOC(AppStateHOC(GUI));
if (supportedBrowser()) {
// require needed here to avoid importing unsupported browser-crashing code
// at the top level
require('./render-gui.jsx').default(appTarget);
// TODO a hack for testing the backpack, allow backpack host to be set by url param
const backpackHostMatches = window.location.href.match(/[?&]backpack_host=([^&]*)&?/);
const backpackHost = backpackHostMatches ? backpackHostMatches[1] : null;
const backpackOptions = {
visible: true,
host: backpackHost
};
ReactDOM.render(<WrappedGui backpackOptions={backpackOptions} />, appTarget);
} else {
BrowserModalComponent.setAppElement(appTarget);
const WrappedBrowserModalComponent = AppStateHOC(BrowserModalComponent, true /* localesOnly */);
const handleBack = () => {};
// eslint-disable-next-line react/jsx-no-bind
ReactDOM.render(<WrappedBrowserModalComponent onBack={handleBack} />, appTarget);
}
+31
View File
@@ -0,0 +1,31 @@
import React from 'react';
import ReactDOM from 'react-dom';
import AppStateHOC from '../lib/app-state-hoc.jsx';
import GUI from '../containers/gui.jsx';
import HashParserHOC from '../lib/hash-parser-hoc.jsx';
/*
* Render the GUI playground. This is a separate function because importing anything
* that instantiates the VM causes unsupported browsers to crash
* {object} appTarget - the DOM element to render to
*/
export default appTarget => {
GUI.setAppElement(appTarget);
const WrappedGui = HashParserHOC(AppStateHOC(GUI));
// TODO a hack for testing the backpack, allow backpack host to be set by url param
const backpackHostMatches = window.location.href.match(/[?&]backpack_host=([^&]*)&?/);
const backpackHost = backpackHostMatches ? backpackHostMatches[1] : null;
const backpackOptions = {
visible: true,
host: backpackHost
};
if (process.env.NODE_ENV === 'production' && typeof window === 'object') {
// Warn before navigating away
window.onbeforeunload = () => true;
}
ReactDOM.render(<WrappedGui backpackOptions={backpackOptions} />, appTarget);
};