6 files changed
+98
-11
No files matched your search
+1
-1
@@ -95,7 +95,7 @@
|
||||
"scratch-render": "0.1.0-prerelease.20180502115145",
|
||||
"scratch-svg-renderer": "0.1.0-prerelease.20180423193917",
|
||||
"scratch-storage": "0.4.1",
|
||||
"scratch-vm": "0.1.0-prerelease.1525459625",
|
||||
"scratch-vm": "0.1.0-prerelease.1525460669",
|
||||
"selenium-webdriver": "3.6.0",
|
||||
"startaudiocontext": "1.2.1",
|
||||
"style-loader": "^0.20.0",
|
||||
|
||||
@@ -34,7 +34,7 @@ const messages = defineMessages({
|
||||
addSpriteFromFile: {
|
||||
id: 'gui.spriteSelector.addSpriteFromFile',
|
||||
description: 'Button to add a sprite in the target pane from file',
|
||||
defaultMessage: 'Coming Soon'
|
||||
defaultMessage: 'Upload'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -51,12 +51,15 @@ const SpriteSelectorComponent = function (props) {
|
||||
onChangeSpriteY,
|
||||
onDeleteSprite,
|
||||
onDuplicateSprite,
|
||||
onFileUploadClick,
|
||||
onNewSpriteClick,
|
||||
onSurpriseSpriteClick,
|
||||
onPaintSpriteClick,
|
||||
onSelectSprite,
|
||||
onSpriteUpload,
|
||||
onSurpriseSpriteClick,
|
||||
raised,
|
||||
selectedId,
|
||||
spriteFileInput,
|
||||
sprites,
|
||||
...componentProps
|
||||
} = props;
|
||||
@@ -121,7 +124,11 @@ const SpriteSelectorComponent = function (props) {
|
||||
moreButtons={[
|
||||
{
|
||||
title: intl.formatMessage(messages.addSpriteFromFile),
|
||||
img: fileUploadIcon
|
||||
img: fileUploadIcon,
|
||||
onClick: onFileUploadClick,
|
||||
fileAccept: '.svg, .png, .jpg, .jpeg, .sprite2', // TODO add sprite 3
|
||||
fileChange: onSpriteUpload,
|
||||
fileInput: spriteFileInput
|
||||
}, {
|
||||
title: intl.formatMessage(messages.addSpriteFromSurprise),
|
||||
img: surpriseIcon,
|
||||
@@ -154,12 +161,15 @@ SpriteSelectorComponent.propTypes = {
|
||||
onChangeSpriteY: PropTypes.func,
|
||||
onDeleteSprite: PropTypes.func,
|
||||
onDuplicateSprite: PropTypes.func,
|
||||
onFileUploadClick: PropTypes.func,
|
||||
onNewSpriteClick: PropTypes.func,
|
||||
onPaintSpriteClick: PropTypes.func,
|
||||
onSelectSprite: PropTypes.func,
|
||||
onSpriteUpload: PropTypes.func,
|
||||
onSurpriseSpriteClick: PropTypes.func,
|
||||
raised: PropTypes.bool,
|
||||
selectedId: PropTypes.string,
|
||||
spriteFileInput: PropTypes.func,
|
||||
sprites: PropTypes.shape({
|
||||
id: PropTypes.shape({
|
||||
costume: PropTypes.shape({
|
||||
|
||||
@@ -17,6 +17,7 @@ import styles from './target-pane.css';
|
||||
*/
|
||||
const TargetPane = ({
|
||||
editingTarget,
|
||||
fileInputRef,
|
||||
hoveredTarget,
|
||||
spriteLibraryVisible,
|
||||
onChangeSpriteDirection,
|
||||
@@ -27,11 +28,13 @@ const TargetPane = ({
|
||||
onChangeSpriteY,
|
||||
onDeleteSprite,
|
||||
onDuplicateSprite,
|
||||
onFileUploadClick,
|
||||
onNewSpriteClick,
|
||||
onSurpriseSpriteClick,
|
||||
onPaintSpriteClick,
|
||||
onRequestCloseSpriteLibrary,
|
||||
onSelectSprite,
|
||||
onSpriteUpload,
|
||||
onSurpriseSpriteClick,
|
||||
raiseSprites,
|
||||
stage,
|
||||
sprites,
|
||||
@@ -48,6 +51,7 @@ const TargetPane = ({
|
||||
hoveredTarget={hoveredTarget}
|
||||
raised={raiseSprites}
|
||||
selectedId={editingTarget}
|
||||
spriteFileInput={fileInputRef}
|
||||
sprites={sprites}
|
||||
onChangeSpriteDirection={onChangeSpriteDirection}
|
||||
onChangeSpriteName={onChangeSpriteName}
|
||||
@@ -57,9 +61,11 @@ const TargetPane = ({
|
||||
onChangeSpriteY={onChangeSpriteY}
|
||||
onDeleteSprite={onDeleteSprite}
|
||||
onDuplicateSprite={onDuplicateSprite}
|
||||
onFileUploadClick={onFileUploadClick}
|
||||
onNewSpriteClick={onNewSpriteClick}
|
||||
onPaintSpriteClick={onPaintSpriteClick}
|
||||
onSelectSprite={onSelectSprite}
|
||||
onSpriteUpload={onSpriteUpload}
|
||||
onSurpriseSpriteClick={onSurpriseSpriteClick}
|
||||
/>
|
||||
<div className={styles.stageSelectorWrapper}>
|
||||
@@ -108,6 +114,7 @@ const spriteShape = PropTypes.shape({
|
||||
TargetPane.propTypes = {
|
||||
editingTarget: PropTypes.string,
|
||||
extensionLibraryVisible: PropTypes.bool,
|
||||
fileInputRef: PropTypes.func,
|
||||
hoveredTarget: PropTypes.shape({
|
||||
hoveredSprite: PropTypes.string,
|
||||
receivedBlocks: PropTypes.bool
|
||||
@@ -120,11 +127,13 @@ TargetPane.propTypes = {
|
||||
onChangeSpriteY: PropTypes.func,
|
||||
onDeleteSprite: PropTypes.func,
|
||||
onDuplicateSprite: PropTypes.func,
|
||||
onFileUploadClick: PropTypes.func,
|
||||
onNewSpriteClick: PropTypes.func,
|
||||
onPaintSpriteClick: PropTypes.func,
|
||||
onRequestCloseExtensionLibrary: PropTypes.func,
|
||||
onRequestCloseSpriteLibrary: PropTypes.func,
|
||||
onSelectSprite: PropTypes.func,
|
||||
onSpriteUpload: PropTypes.func,
|
||||
onSurpriseSpriteClick: PropTypes.func,
|
||||
raiseSprites: PropTypes.bool,
|
||||
spriteLibraryVisible: PropTypes.bool,
|
||||
|
||||
@@ -39,7 +39,7 @@ class SpriteLibrary extends React.PureComponent {
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
handleItemSelect (item) {
|
||||
this.props.vm.addSprite2(JSON.stringify(item.json));
|
||||
this.props.vm.addSprite(JSON.stringify(item.json));
|
||||
analytics.event({
|
||||
category: 'library',
|
||||
action: 'Select Sprite',
|
||||
|
||||
@@ -13,6 +13,7 @@ import {setReceivedBlocks} from '../reducers/hovered-target';
|
||||
|
||||
import TargetPaneComponent from '../components/target-pane/target-pane.jsx';
|
||||
import spriteLibraryContent from '../lib/libraries/sprites.json';
|
||||
import {handleFileUpload, spriteUpload} from '../lib/file-uploader.js';
|
||||
|
||||
class TargetPane extends React.Component {
|
||||
constructor (props) {
|
||||
@@ -27,9 +28,13 @@ class TargetPane extends React.Component {
|
||||
'handleChangeSpriteY',
|
||||
'handleDeleteSprite',
|
||||
'handleDuplicateSprite',
|
||||
'handleNewSprite',
|
||||
'handleSelectSprite',
|
||||
'handleSurpriseSpriteClick',
|
||||
'handlePaintSpriteClick'
|
||||
'handlePaintSpriteClick',
|
||||
'handleFileUploadClick',
|
||||
'handleSpriteUpload',
|
||||
'setFileInput'
|
||||
]);
|
||||
}
|
||||
componentDidMount () {
|
||||
@@ -67,19 +72,34 @@ class TargetPane extends React.Component {
|
||||
}
|
||||
handleSurpriseSpriteClick () {
|
||||
const item = spriteLibraryContent[Math.floor(Math.random() * spriteLibraryContent.length)];
|
||||
this.props.vm.addSprite2(JSON.stringify(item.json));
|
||||
this.props.vm.addSprite(JSON.stringify(item.json));
|
||||
}
|
||||
handlePaintSpriteClick () {
|
||||
// @todo this is brittle, will need to be refactored for localized libraries
|
||||
const emptyItem = spriteLibraryContent.find(item => item.name === 'Empty');
|
||||
if (emptyItem) {
|
||||
this.props.vm.addSprite2(JSON.stringify(emptyItem.json)).then(() => {
|
||||
this.props.vm.addSprite(JSON.stringify(emptyItem.json)).then(() => {
|
||||
setTimeout(() => { // Wait for targets update to propagate before tab switching
|
||||
this.props.onActivateTab(COSTUMES_TAB_INDEX);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
handleNewSprite (spriteJSONString) {
|
||||
this.props.vm.addSprite(spriteJSONString);
|
||||
}
|
||||
handleFileUploadClick () {
|
||||
this.fileInput.click();
|
||||
}
|
||||
handleSpriteUpload (e) {
|
||||
const storage = this.props.vm.runtime.storage;
|
||||
handleFileUpload(e.target, (buffer, fileType, fileName) => {
|
||||
spriteUpload(buffer, fileType, fileName, storage, this.handleNewSprite);
|
||||
});
|
||||
}
|
||||
setFileInput (input) {
|
||||
this.fileInput = input;
|
||||
}
|
||||
handleBlockDragEnd (blocks) {
|
||||
if (this.props.hoveredTarget.sprite && this.props.hoveredTarget.sprite !== this.props.editingTarget) {
|
||||
this.props.vm.shareBlocksToTarget(blocks, this.props.hoveredTarget.sprite);
|
||||
@@ -95,6 +115,7 @@ class TargetPane extends React.Component {
|
||||
return (
|
||||
<TargetPaneComponent
|
||||
{...componentProps}
|
||||
fileInputRef={this.setFileInput}
|
||||
onChangeSpriteDirection={this.handleChangeSpriteDirection}
|
||||
onChangeSpriteName={this.handleChangeSpriteName}
|
||||
onChangeSpriteSize={this.handleChangeSpriteSize}
|
||||
@@ -103,8 +124,10 @@ class TargetPane extends React.Component {
|
||||
onChangeSpriteY={this.handleChangeSpriteY}
|
||||
onDeleteSprite={this.handleDeleteSprite}
|
||||
onDuplicateSprite={this.handleDuplicateSprite}
|
||||
onFileUploadClick={this.handleFileUploadClick}
|
||||
onPaintSpriteClick={this.handlePaintSpriteClick}
|
||||
onSelectSprite={this.handleSelectSprite}
|
||||
onSpriteUpload={this.handleSpriteUpload}
|
||||
onSurpriseSpriteClick={this.handleSurpriseSpriteClick}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -47,6 +47,7 @@ const handleFileUpload = function (fileInput, onload) {
|
||||
* @property {string} dataFormat The data format of this asset, typically
|
||||
* the extension to be used for that particular asset, e.g. 'svg' for vector images
|
||||
* @property {string} md5 The md5 hash of the asset data, followed by '.'' and dataFormat
|
||||
* @property {string} The md5 hash of the asset data // TODO remove duplication....
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -71,7 +72,8 @@ const cacheAsset = function (storage, fileName, assetType, dataFormat, data) {
|
||||
return {
|
||||
name: fileName,
|
||||
dataFormat: dataFormat,
|
||||
md5: `${md5}.${dataFormat}`
|
||||
md5: `${md5}.${dataFormat}`,
|
||||
assetId: md5
|
||||
};
|
||||
};
|
||||
|
||||
@@ -106,6 +108,7 @@ const costumeUpload = function (fileData, fileType, costumeName, storage, handle
|
||||
break;
|
||||
}
|
||||
default:
|
||||
log.warn(`Encountered unexpected file type: ${fileType}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -158,6 +161,7 @@ const soundUpload = function (fileData, fileType, soundName, storage, handleSoun
|
||||
break;
|
||||
}
|
||||
default:
|
||||
log.warn(`Encountered unexpected file type: ${fileType}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -171,8 +175,49 @@ const soundUpload = function (fileData, fileType, soundName, storage, handleSoun
|
||||
handleSound(vmSound);
|
||||
};
|
||||
|
||||
const spriteUpload = function (fileData, fileType, spriteName, storage, handleSprite) {
|
||||
switch (fileType) {
|
||||
case '':
|
||||
case 'application/zip': { // We think this is a .sprite2 or .sprite3 file
|
||||
handleSprite(new Uint8Array(fileData));
|
||||
return;
|
||||
}
|
||||
case 'image/svg+xml':
|
||||
case 'image/png':
|
||||
case 'image/jpeg': {
|
||||
// Make a sprite from an image by making it a costume first
|
||||
costumeUpload(fileData, fileType, `${spriteName}-costume1`, storage, (vmCostume => {
|
||||
const newSprite = {
|
||||
name: spriteName,
|
||||
isStage: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
visible: true,
|
||||
size: 100,
|
||||
rotationStyle: 'all around',
|
||||
direction: 90,
|
||||
draggable: true,
|
||||
currentCostume: 0,
|
||||
blocks: {},
|
||||
variables: {},
|
||||
costumes: [vmCostume],
|
||||
sounds: [] // TODO are all of these necessary?
|
||||
};
|
||||
// TODO probably just want sprite upload to handle this object directly
|
||||
handleSprite(JSON.stringify(newSprite));
|
||||
}));
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
log.warn(`Encountered unexpected file type: ${fileType}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
handleFileUpload,
|
||||
costumeUpload,
|
||||
soundUpload
|
||||
soundUpload,
|
||||
spriteUpload
|
||||
};
|
||||
Reference in new issue
Block a user