diff --git a/package.json b/package.json index 1a396271b..322e17f85 100644 --- a/package.json +++ b/package.json @@ -105,13 +105,13 @@ "redux-throttle": "0.1.1", "rimraf": "^2.6.1", "scratch-audio": "0.1.0-prerelease.20181023202904", - "scratch-blocks": "0.1.0-prerelease.1545162154", - "scratch-l10n": "3.1.20181213173343", + "scratch-blocks": "0.1.0-prerelease.1545364693", + "scratch-l10n": "3.1.20181220222259", "scratch-paint": "0.2.0-prerelease.20181220194927", - "scratch-render": "0.1.0-prerelease.20181220195236", - "scratch-storage": "1.2.1", + "scratch-render": "0.1.0-prerelease.20181226153401", + "scratch-storage": "1.2.2", "scratch-svg-renderer": "0.2.0-prerelease.20181220183040", - "scratch-vm": "0.2.0-prerelease.20181220195716", + "scratch-vm": "0.2.0-prerelease.20181226213940", "selenium-webdriver": "3.6.0", "startaudiocontext": "1.2.1", "style-loader": "^0.23.0", diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index b1f6cc44e..a203310b1 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -141,6 +141,7 @@ const GUIComponent = props => { diff --git a/src/components/loader/loader.css b/src/components/loader/loader.css index 1b6ab40ce..a1f0003c3 100644 --- a/src/components/loader/loader.css +++ b/src/components/loader/loader.css @@ -2,7 +2,7 @@ @import "../../css/z-index.css"; .background { - position: fixed; + position: absolute; top: 0; left: 0; width: 100%; diff --git a/src/components/menu-bar/login-dropdown.jsx b/src/components/menu-bar/login-dropdown.jsx index 0116d7342..fcfcd8117 100644 --- a/src/components/menu-bar/login-dropdown.jsx +++ b/src/components/menu-bar/login-dropdown.jsx @@ -35,6 +35,11 @@ const LoginDropdownMessages = defineMessages({ // eslint-disable-line no-unused- defaultMessage: 'Need Help?', description: 'Button text for user to indicate that they need help', id: 'login.needHelp' + }, + validationRequired: { + defaultMessage: 'This field is required', + description: 'Message to tell user they must enter text in a form field', + id: 'form.validationRequired' } }); diff --git a/src/components/stage-wrapper/stage-wrapper.jsx b/src/components/stage-wrapper/stage-wrapper.jsx index 021f6742b..821e2c001 100644 --- a/src/components/stage-wrapper/stage-wrapper.jsx +++ b/src/components/stage-wrapper/stage-wrapper.jsx @@ -6,6 +6,7 @@ import Box from '../box/box.jsx'; import {STAGE_DISPLAY_SIZES} from '../../lib/layout-constants.js'; import StageHeader from '../../containers/stage-header.jsx'; import Stage from '../../containers/stage.jsx'; +import Loader from '../loader/loader.jsx'; import styles from './stage-wrapper.css'; @@ -13,6 +14,7 @@ const StageWrapperComponent = function (props) { const { isRtl, isRendererSupported, + loading, stageSize, vm } = props; @@ -38,6 +40,9 @@ const StageWrapperComponent = function (props) { null } + {loading ? ( + + ) : null} ); }; @@ -45,6 +50,7 @@ const StageWrapperComponent = function (props) { StageWrapperComponent.propTypes = { isRendererSupported: PropTypes.bool.isRequired, isRtl: PropTypes.bool, + loading: PropTypes.bool, stageSize: PropTypes.oneOf(Object.keys(STAGE_DISPLAY_SIZES)).isRequired, vm: PropTypes.instanceOf(VM).isRequired }; diff --git a/src/containers/sb-file-uploader.jsx b/src/containers/sb-file-uploader.jsx index 8eeb04e4d..66d33c13c 100644 --- a/src/containers/sb-file-uploader.jsx +++ b/src/containers/sb-file-uploader.jsx @@ -80,8 +80,9 @@ class SBFileUploader extends React.Component { } getProjectTitleFromFilename (fileInputFilename) { if (!fileInputFilename) return ''; - // only parse title from files like "filename.sb2" or "filename.sb3" - const matches = fileInputFilename.match(/^(.*)\.sb[23]$/); + // only parse title with valid scratch project extensions + // (.sb, .sb2, and .sb3) + const matches = fileInputFilename.match(/^(.*)\.sb[23]?$/); if (!matches) return ''; return matches[1].substring(0, 100); // truncate project title to max 100 chars } diff --git a/src/lib/blocks.js b/src/lib/blocks.js index 601804c65..eadf6d6ff 100644 --- a/src/lib/blocks.js +++ b/src/lib/blocks.js @@ -260,8 +260,12 @@ export default function (vm) { return stageOptions.concat(stageVariableMenuItems); } // Get all the local variables (no lists) and add them to the menu. - const spriteVariableOptions = - vm.runtime.getSpriteTargetByName(selectedItem).getAllVariableNamesInScopeByType('', true); + const target = vm.runtime.getSpriteTargetByName(selectedItem); + let spriteVariableOptions = []; + // The target should exist, but there are ways for it not to (e.g. #4203). + if (target) { + spriteVariableOptions = target.getAllVariableNamesInScopeByType('', true); + } const spriteVariableMenuItems = spriteVariableOptions.map(variable => [variable, variable]); return spriteOptions.concat(spriteVariableMenuItems); } diff --git a/src/lib/vm-manager-hoc.jsx b/src/lib/vm-manager-hoc.jsx index 5632266a2..926c25cd7 100644 --- a/src/lib/vm-manager-hoc.jsx +++ b/src/lib/vm-manager-hoc.jsx @@ -53,9 +53,6 @@ const vmManagerHOC = function (WrappedComponent) { loadProject () { return this.props.vm.loadProject(this.props.projectData) .then(() => { - // Mark all the assets as clean since they just got loaded - this.props.vm.assets.forEach(asset => (asset.clean = true)); - this.props.onLoadedProject(this.props.loadingState, this.props.canSave); // Wrap in a setTimeout because skin loading in // the renderer can be async. diff --git a/test/unit/containers/sb-file-uploader.test.jsx b/test/unit/containers/sb-file-uploader.test.jsx index 856b8f058..083dbfa2d 100644 --- a/test/unit/containers/sb-file-uploader.test.jsx +++ b/test/unit/containers/sb-file-uploader.test.jsx @@ -65,14 +65,14 @@ describe('SBFileUploader Container', () => { expect(projectName).toBe('my project is great'); }); - test('sets blank title with .sb filename', () => { + test('correctly sets title with .sb filename', () => { const wrapper = shallowWithIntl(getContainer(), {context: {store}}); const instance = wrapper .dive() // unwrap redux Connect(InjectIntl(SBFileUploader)) .dive() // unwrap InjectIntl(SBFileUploader) .instance(); // SBFileUploader const projectName = instance.getProjectTitleFromFilename('my project is great.sb'); - expect(projectName).toBe(''); + expect(projectName).toBe('my project is great'); }); test('sets blank title with filename with no extension', () => {