Merge pull request #9 from rschamp/lint

eslint-config-scratch: React + ES6 Edition
This commit is contained in:
Ray Schamp authored and GitHub committed 2016-10-24 09:43:49 -04:00
commit cdbf45ae91
31 files changed
+383 -332

No files matched your search

-25
View File
@@ -1,25 +0,0 @@
{
"parser": "babel-eslint",
"rules": {
"curly": [2, "multi-line"],
"eol-last": [2],
"indent": [2, 4],
"linebreak-style": [2, "unix"],
"max-len": [2, 120, 4],
"no-trailing-spaces": [2, { "skipBlankLines": true }],
"no-unused-vars": [2, {"args": "after-used", "varsIgnorePattern": "^_"}],
"quotes": [2, "single"],
"semi": [2, "always"],
"space-before-function-paren": [2, "always"],
"strict": [2, "never"]
},
"env": {
"browser": true,
"es6": true,
"node": true
},
"plugins": [
"react"
],
"extends": ["eslint:recommended", "plugin:react/recommended"]
}
+5
View File
@@ -0,0 +1,5 @@
module.exports = {
env: {
node: true
}
};
+7 -2
View File
@@ -18,6 +18,9 @@
"start": "webpack-dev-server --port $npm_package_config_port --content-base=./build",
"test": "npm run lint && npm run build"
},
"eslintConfig": {
"extends": ["scratch"]
},
"author": "Massachusetts Institute of Technology",
"license": "BSD-3-Clause",
"homepage": "https://github.com/LLK/scratch-gui#readme",
@@ -31,14 +34,15 @@
},
"devDependencies": {
"babel-core": "6.14.0",
"babel-eslint": "6.1.2",
"babel-eslint": "7.0.0",
"babel-loader": "6.2.5",
"babel-plugin-transform-object-rest-spread": "6.16.0",
"babel-preset-es2015": "6.14.0",
"babel-preset-react": "6.11.1",
"copy-webpack-plugin": "3.0.1",
"eslint": "3.5.0",
"eslint-plugin-react": "6.2.1",
"eslint-config-scratch": "^1.0.0",
"eslint-plugin-react": "6.4.1",
"gh-pages": "0.11.0",
"html-webpack-plugin": "2.22.0",
"husky": "0.11.9",
@@ -50,6 +54,7 @@
"react": "15.3.2",
"react-dom": "15.3.2",
"react-modal": "1.5.2",
"react-style-proptype": "1.2.0",
"scratch-blocks": "latest",
"scratch-render": "latest",
"scratch-vm": "latest",
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
env: {
node: false,
browser: true
},
extends: ['scratch/es6', 'scratch/react']
};
@@ -8,8 +8,8 @@ class BlocksComponent extends React.Component {
} = this.props;
return (
<div
ref={componentRef}
className="scratch-blocks"
ref={componentRef}
style={{
position: 'absolute',
top: 0,
@@ -16,46 +16,54 @@ class CostumeCanvas extends React.Component {
componentDidUpdate (prevProps) {
if (prevProps.url !== this.props.url) {
this.load();
} else {
if (prevProps.width !== this.props.width ||
prevProps.height !== this.props.height ||
prevProps.direction !== this.props.direction) {
this.draw();
}
} else if (
prevProps.width !== this.props.width ||
prevProps.height !== this.props.height ||
prevProps.direction !== this.props.direction
) {
this.draw();
}
}
draw () {
if (!this.refs.costumeCanvas) {
if (!this.canvas) {
return;
}
// Draw the costume to the rendered canvas.
const img = this.img;
const context = this.refs.costumeCanvas.getContext('2d');
const context = this.canvas.getContext('2d');
// Scale to fit.
let scale;
// Choose the larger dimension to scale by.
if (img.width > img.height) {
scale = this.refs.costumeCanvas.width / img.width;
scale = this.canvas.width / img.width;
} else {
scale = this.refs.costumeCanvas.height / img.height;
scale = this.canvas.height / img.height;
}
// Rotate by the Scratch-value direction.
const angle = (-90 + this.props.direction) * Math.PI / 180;
// Rotation origin point will be center of the canvas.
const contextTranslateX = this.refs.costumeCanvas.width / 2;
const contextTranslateY = this.refs.costumeCanvas.height / 2;
const contextTranslateX = this.canvas.width / 2;
const contextTranslateY = this.canvas.height / 2;
// First, clear the canvas.
context.clearRect(0, 0,
this.refs.costumeCanvas.width, this.refs.costumeCanvas.height);
this.canvas.width, this.canvas.height);
// Translate the context to the center of the canvas,
// then rotate canvas drawing by `angle`.
context.translate(contextTranslateX, contextTranslateY);
context.rotate(angle);
context.drawImage(img,
0, 0, img.width, img.height,
-(scale * img.width / 2), -(scale * img.height / 2),
-(scale * img.width / 2), -(scale * img.height / 2),
scale * img.width,
scale * img.height);
// Reset the canvas rotation and translation to 0, (0, 0).
context.rotate(-angle);
context.translate(-contextTranslateX, -contextTranslateY);
@@ -72,8 +80,8 @@ class CostumeCanvas extends React.Component {
url: url
}, (err, response, body) => {
if (!err) {
svgToImage(body, (err, img) => {
if (!err) {
svgToImage(body, (svgErr, img) => {
if (!svgErr) {
this.img = img;
this.draw();
}
@@ -84,7 +92,7 @@ class CostumeCanvas extends React.Component {
} else {
// Raster graphics: create Image and draw it.
let img = new Image();
const img = new Image();
img.src = url;
img.onload = () => {
this.img = img;
@@ -93,11 +101,13 @@ class CostumeCanvas extends React.Component {
}
}
render () {
return <canvas
ref='costumeCanvas'
width={this.props.width}
height={this.props.height}
/>;
return (
<canvas
height={this.props.height}
width={this.props.width}
ref={this._getCanvas} // eslint-disable-line react/jsx-sort-props
/>
);
}
}
@@ -108,10 +118,10 @@ CostumeCanvas.defaultProps = {
};
CostumeCanvas.propTypes = {
url: React.PropTypes.string,
width: React.PropTypes.number,
direction: React.PropTypes.number,
height: React.PropTypes.number,
direction: React.PropTypes.number
url: React.PropTypes.string,
width: React.PropTypes.number
};
module.exports = CostumeCanvas;
File renamed without changes.
File renamed without changes.
@@ -1,13 +1,26 @@
const bindAll = require('lodash.bindall');
const React = require('react');
const stylePropType = require('react-style-proptype');
const CostumeCanvas = require('./costume-canvas');
const CostumeCanvas = require('./costume-canvas.jsx');
class LibraryItem extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['handleClick']);
}
handleClick (e) {
this.props.onSelect(this.props.id);
e.preventDefault();
}
render () {
let style = (this.props.selected) ?
const style = (this.props.selected) ?
this.props.selectedGridTileStyle : this.props.gridTileStyle;
return (
<div style={style} onClick={() => this.props.onSelect(this.props.id)}>
<div
style={style}
onClick={this.handleClick}
>
<CostumeCanvas url={this.props.iconURL} />
<p>{this.props.name}</p>
</div>
@@ -37,13 +50,13 @@ LibraryItem.defaultProps = {
};
LibraryItem.propTypes = {
name: React.PropTypes.string,
gridTileStyle: stylePropType,
iconURL: React.PropTypes.string,
gridTileStyle: React.PropTypes.object,
selectedGridTileStyle: React.PropTypes.object,
selected: React.PropTypes.bool,
id: React.PropTypes.number,
name: React.PropTypes.string,
onSelect: React.PropTypes.func,
id: React.PropTypes.number
selected: React.PropTypes.bool,
selectedGridTileStyle: stylePropType
};
module.exports = LibraryItem;
-69
View File
@@ -1,69 +0,0 @@
const bindAll = require('lodash.bindall');
const React = require('react');
const LibraryItem = require('./library-item');
const ModalComponent = require('./modal');
class LibraryComponent extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['onSelect']);
this.state = {selectedItem: null};
}
onSelect (id) {
if (this.state.selectedItem == id) {
// Double select: select as the library's value.
this.props.onRequestClose();
this.props.onItemSelected(this.props.data[id]);
}
this.setState({selectedItem: id});
}
render () {
let itemId = 0;
let gridItems = this.props.data.map((dataItem) => {
let id = itemId;
itemId++;
const scratchURL = (dataItem.md5) ? 'https://cdn.assets.scratch.mit.edu/internalapi/asset/' +
dataItem.md5 + '/get/' : dataItem.rawURL;
return <LibraryItem
name={dataItem.name}
iconURL={scratchURL}
key={'item_' + id}
selected={this.state.selectedItem == id}
onSelect={this.onSelect}
id={id}
/>;
});
const scrollGridStyle = {
overflow: 'scroll',
position: 'absolute',
top: '70px',
bottom: '20px',
left: '30px',
right: '30px'
};
return (
<ModalComponent
onRequestClose={this.props.onRequestClose}
visible={this.props.visible}
>
<h1>{this.props.title}</h1>
<div style={scrollGridStyle}>
{gridItems}
</div>
</ModalComponent>
);
}
}
LibraryComponent.propTypes = {
title: React.PropTypes.string,
data: React.PropTypes.array,
visible: React.PropTypes.bool,
onRequestClose: React.PropTypes.func,
onItemSelected: React.PropTypes.func
};
module.exports = LibraryComponent;
+74
View File
@@ -0,0 +1,74 @@
const bindAll = require('lodash.bindall');
const React = require('react');
const LibraryItem = require('./library-item.jsx');
const ModalComponent = require('./modal.jsx');
class LibraryComponent extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['handleSelect']);
this.state = {selectedItem: null};
}
handleSelect (id) {
if (this.state.selectedItem === id) {
// Double select: select as the library's value.
this.props.onRequestClose();
this.props.onItemSelected(this.props.data[id]);
}
this.setState({selectedItem: id});
}
render () {
const scrollGridStyle = {
overflow: 'scroll',
position: 'absolute',
top: '70px',
bottom: '20px',
left: '30px',
right: '30px'
};
return (
<ModalComponent
visible={this.props.visible}
onRequestClose={this.props.onRequestClose}
>
<h1>{this.props.title}</h1>
<div style={scrollGridStyle}>
{this.props.data.map((dataItem, itemId) => {
const scratchURL = dataItem.md5 ?
`https://cdn.assets.scratch.mit.edu/internalapi/asset/${dataItem.md5}/get/` :
dataItem.rawURL;
return (
<LibraryItem
iconURL={scratchURL}
id={itemId}
key={`item_${itemId}`}
name={dataItem.name}
selected={this.state.selectedItem === itemId}
onSelect={this.handleSelect}
/>
);
})}
</div>
</ModalComponent>
);
}
}
LibraryComponent.propTypes = {
data: React.PropTypes.arrayOf(
/* eslint-disable react/no-unused-prop-types, lines-around-comment */
React.PropTypes.shape({
md5: React.PropTypes.string,
name: React.PropTypes.string,
rawURL: React.PropTypes.string,
})
/* eslint-enable react/no-unused-prop-types, lines-around-comment */
),
onItemSelected: React.PropTypes.func,
onRequestClose: React.PropTypes.func,
title: React.PropTypes.string,
visible: React.PropTypes.bool
};
module.exports = LibraryComponent;
@@ -1,20 +1,21 @@
const React = require('react');
const ReactModal = require('react-modal');
const stylePropType = require('react-style-proptype');
class ModalComponent extends React.Component {
render () {
return (
<ReactModal
ref="modal"
style={this.props.modalStyle}
isOpen={this.props.visible}
ref={m => (this.modal = m)}
style={this.props.modalStyle}
onRequestClose={this.props.onRequestClose}
>
<div
onClick={this.props.onRequestClose}
style={this.props.closeButtonStyle}
onClick={this.props.onRequestClose}
>
x
{'x'}
</div>
{this.props.children}
</ReactModal>
@@ -61,8 +62,8 @@ ModalComponent.defaultProps = {
ModalComponent.propTypes = {
children: React.PropTypes.node,
modalStyle: React.PropTypes.object,
closeButtonStyle: React.PropTypes.object,
closeButtonStyle: stylePropType,
modalStyle: stylePropType,
onRequestClose: React.PropTypes.func,
visible: React.PropTypes.bool
};
@@ -26,7 +26,10 @@ class SpriteSelectorComponent extends React.Component {
onChange={onChange}
>
{sprites.map(sprite => (
<option value={sprite.id} key={sprite.id}>
<option
key={sprite.id}
value={sprite.id}
>
{sprite.name}
</option>
))}
@@ -43,16 +46,16 @@ class SpriteSelectorComponent extends React.Component {
SpriteSelectorComponent.propTypes = {
onChange: React.PropTypes.func,
openNewBackdrop: React.PropTypes.func,
openNewCostume: React.PropTypes.func,
openNewSprite: React.PropTypes.func,
sprites: React.PropTypes.arrayOf(
React.PropTypes.shape({
id: React.PropTypes.string,
name: React.PropTypes.string
})
),
value: React.PropTypes.arrayOf(React.PropTypes.string),
openNewSprite: React.PropTypes.func,
openNewCostume: React.PropTypes.func,
openNewBackdrop: React.PropTypes.func
value: React.PropTypes.arrayOf(React.PropTypes.string)
};
module.exports = SpriteSelectorComponent;
@@ -27,12 +27,12 @@ class StageComponent extends React.Component {
StageComponent.propTypes = {
canvasRef: React.PropTypes.func,
width: React.PropTypes.number,
height: React.PropTypes.number
height: React.PropTypes.number,
width: React.PropTypes.number
};
StageComponent.defaultProps = {
canvasRef: function () {},
canvasRef: () => {},
width: 480,
height: 360
};
File renamed without changes.
@@ -3,13 +3,13 @@ const React = require('react');
const VM = require('scratch-vm');
const MediaLibrary = require('../lib/media-library');
const LibaryComponent = require('../components/library');
const LibaryComponent = require('../components/library.jsx');
class BackdropLibrary extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['setData', 'selectItem']);
bindAll(this, ['setData', 'handleItemSelect']);
this.state = {backdropData: []};
}
componentWillReceiveProps (nextProps) {
@@ -20,9 +20,9 @@ class BackdropLibrary extends React.Component {
setData (data) {
this.setState({backdropData: data});
}
selectItem (item) {
var vmBackdrop = {
skin: 'https://cdn.assets.scratch.mit.edu/internalapi/asset/' + item.md5 + '/get/',
handleItemSelect (item) {
const vmBackdrop = {
skin: `https://cdn.assets.scratch.mit.edu/internalapi/asset/${item.md5}/get/`,
name: item.name,
rotationCenterX: item.info[0],
rotationCenterY: item.info[1]
@@ -33,21 +33,23 @@ class BackdropLibrary extends React.Component {
this.props.vm.addBackdrop(vmBackdrop);
}
render () {
return <LibaryComponent
title="Backdrop Library"
visible={this.props.visible}
data={this.state.backdropData}
onRequestClose={this.props.onRequestClose}
onItemSelected={this.selectItem}
/>;
return (
<LibaryComponent
data={this.state.backdropData}
title="Backdrop Library"
visible={this.props.visible}
onItemSelected={this.handleItemSelect}
onRequestClose={this.props.onRequestClose}
/>
);
}
}
BackdropLibrary.propTypes = {
vm: React.PropTypes.instanceOf(VM).isRequired,
mediaLibrary: React.PropTypes.instanceOf(MediaLibrary),
onRequestClose: React.PropTypes.func,
visible: React.PropTypes.bool,
onRequestClose: React.PropTypes.func
vm: React.PropTypes.instanceOf(VM).isRequired
};
module.exports = BackdropLibrary;
@@ -4,7 +4,7 @@ const React = require('react');
const ScratchBlocks = require('scratch-blocks');
const VM = require('scratch-vm');
const BlocksComponent = require('../components/blocks');
const BlocksComponent = require('../components/blocks.jsx');
class Blocks extends React.Component {
constructor (props) {
@@ -21,7 +21,7 @@ class Blocks extends React.Component {
]);
}
componentDidMount () {
let workspaceConfig = defaultsDeep({}, Blocks.defaultOptions, this.props.options);
const workspaceConfig = defaultsDeep({}, Blocks.defaultOptions, this.props.options);
this.workspace = ScratchBlocks.inject(this.blocks, workspaceConfig);
this.attachVM();
}
@@ -31,9 +31,10 @@ class Blocks extends React.Component {
}
attachVM () {
this.workspace.addChangeListener(this.props.vm.blockListener);
this.workspace.getFlyout().getWorkspace().addChangeListener(
this.props.vm.flyoutBlockListener
);
this.workspace
.getFlyout()
.getWorkspace()
.addChangeListener(this.props.vm.flyoutBlockListener);
this.props.vm.on('STACK_GLOW_ON', this.onStackGlowOn);
this.props.vm.on('STACK_GLOW_OFF', this.onStackGlowOff);
this.props.vm.on('BLOCK_GLOW_ON', this.onBlockGlowOn);
@@ -79,7 +80,7 @@ class Blocks extends React.Component {
} = this.props;
return (
<BlocksComponent
componentRef={c => this.blocks = c}
componentRef={c => (this.blocks = c)}
{...props}
/>
);
@@ -3,13 +3,13 @@ const React = require('react');
const VM = require('scratch-vm');
const MediaLibrary = require('../lib/media-library');
const LibaryComponent = require('../components/library');
const LibaryComponent = require('../components/library.jsx');
class CostumeLibrary extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['setData', 'selectItem']);
bindAll(this, ['setData', 'handleItemSelected']);
this.state = {costumeData: []};
}
componentWillReceiveProps (nextProps) {
@@ -20,9 +20,9 @@ class CostumeLibrary extends React.Component {
setData (data) {
this.setState({costumeData: data});
}
selectItem (item) {
var vmCostume = {
skin: 'https://cdn.assets.scratch.mit.edu/internalapi/asset/' + item.md5 + '/get/',
handleItemSelected (item) {
const vmCostume = {
skin: `https://cdn.assets.scratch.mit.edu/internalapi/asset/$(item.md5)/get/`,
name: item.name,
rotationCenterX: item.info[0],
rotationCenterY: item.info[1]
@@ -33,21 +33,23 @@ class CostumeLibrary extends React.Component {
this.props.vm.addCostume(vmCostume);
}
render () {
return <LibaryComponent
title="Costume Library"
visible={this.props.visible}
data={this.state.costumeData}
onRequestClose={this.props.onRequestClose}
onItemSelected={this.selectItem}
/>;
return (
<LibaryComponent
data={this.state.costumeData}
title="Costume Library"
visible={this.props.visible}
onItemSelected={this.handleItemSelected}
onRequestClose={this.props.onRequestClose}
/>
);
}
}
CostumeLibrary.propTypes = {
vm: React.PropTypes.instanceOf(VM).isRequired,
mediaLibrary: React.PropTypes.instanceOf(MediaLibrary),
onRequestClose: React.PropTypes.func,
visible: React.PropTypes.bool,
onRequestClose: React.PropTypes.func
vm: React.PropTypes.instanceOf(VM).isRequired
};
module.exports = CostumeLibrary;
@@ -1,14 +1,16 @@
const bindAll = require('lodash.bindall');
const React = require('react');
const GreenFlagComponent = require('../components/green-flag');
const VM = require('scratch-vm');
const GreenFlagComponent = require('../components/green-flag.jsx');
class GreenFlag extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['onClick']);
bindAll(this, ['handleClick']);
}
onClick (e) {
handleClick (e) {
e.preventDefault();
this.props.vm.greenFlag();
}
@@ -19,7 +21,7 @@ class GreenFlag extends React.Component {
} = this.props;
return (
<GreenFlagComponent
onClick={this.onClick}
onClick={this.handleClick}
{...props}
/>
);
@@ -27,7 +29,7 @@ class GreenFlag extends React.Component {
}
GreenFlag.propTypes = {
vm: React.PropTypes.object
vm: React.PropTypes.instanceOf(VM)
};
module.exports = GreenFlag;
@@ -5,17 +5,18 @@ const VM = require('scratch-vm');
const VMManager = require('../lib/vm-manager');
const MediaLibrary = require('../lib/media-library');
const shapeFromPropTypes = require('../lib/shape-from-prop-types');
const Blocks = require('./blocks');
const GUIComponent = require('../components/gui');
const GreenFlag = require('./green-flag');
const SpriteSelector = require('./sprite-selector');
const Stage = require('./stage');
const StopAll = require('./stop-all');
const Blocks = require('./blocks.jsx');
const GUIComponent = require('../components/gui.jsx');
const GreenFlag = require('./green-flag.jsx');
const SpriteSelector = require('./sprite-selector.jsx');
const Stage = require('./stage.jsx');
const StopAll = require('./stop-all.jsx');
const SpriteLibrary = require('./sprite-library');
const CostumeLibrary = require('./costume-library');
const BackdropLibrary = require('./backdrop-library');
const SpriteLibrary = require('./sprite-library.jsx');
const CostumeLibrary = require('./costume-library.jsx');
const BackdropLibrary = require('./backdrop-library.jsx');
class GUI extends React.Component {
constructor (props) {
@@ -30,15 +31,15 @@ class GUI extends React.Component {
this.props.vm.loadProject(this.props.projectData);
this.props.vm.start();
}
componentWillUnmount () {
this.vmManager.detachKeyboardEvents();
this.props.vm.stopAll();
}
componentWillReceiveProps (nextProps) {
if (this.props.projectData !== nextProps.projectData) {
this.props.vm.loadProject(nextProps.projectData);
}
}
componentWillUnmount () {
this.vmManager.detachKeyboardEvents();
this.props.vm.stopAll();
}
openModal (modalName) {
this.setState({currentModal: modalName});
}
@@ -60,67 +61,68 @@ class GUI extends React.Component {
vm,
...guiProps
} = this.props;
backdropLibraryProps = defaultsDeep({}, backdropLibraryProps, {
mediaLibrary: this.mediaLibrary,
onRequestClose: this.closeModal,
visible: this.state.currentModal === 'backdrop-library'
});
blocksProps = defaultsDeep({}, blocksProps, {
options: {
media: basePath + 'static/blocks-media/'
media: `${basePath}static/blocks-media/`
}
});
costumeLibraryProps = defaultsDeep({}, costumeLibraryProps, {
mediaLibrary: this.mediaLibrary,
onRequestClose: this.closeModal,
visible: this.state.currentModal === 'costume-library'
});
spriteLibraryProps = defaultsDeep({}, spriteLibraryProps, {
mediaLibrary: this.mediaLibrary,
onRequestClose: this.closeModal,
visible: this.state.currentModal === 'sprite-library'
});
spriteSelectorProps = defaultsDeep({}, spriteSelectorProps, {
openNewBackdrop: () => this.openModal('backdrop-library'),
openNewCostume: () => this.openModal('costume-library'),
openNewSprite: () => this.openModal('sprite-library')
});
spriteLibraryProps = defaultsDeep({}, spriteLibraryProps, {
mediaLibrary: this.mediaLibrary,
onRequestClose: this.closeModal,
visible: this.state.currentModal == 'sprite-library'
});
costumeLibraryProps = defaultsDeep({}, costumeLibraryProps, {
mediaLibrary: this.mediaLibrary,
onRequestClose: this.closeModal,
visible: this.state.currentModal == 'costume-library'
});
backdropLibraryProps = defaultsDeep({}, backdropLibraryProps, {
mediaLibrary: this.mediaLibrary,
onRequestClose: this.closeModal,
visible: this.state.currentModal == 'backdrop-library'
});
if (this.props.children) {
return (
<GUIComponent {... guiProps}>
{this.props.children}
</GUIComponent>
);
} else {
return (
<GUIComponent {... guiProps}>
<GreenFlag vm={vm} {...greenFlagProps} />
<StopAll vm={vm} {...stopAllProps} />
<Stage vm={vm} {...stageProps} />
<SpriteSelector vm={vm} {... spriteSelectorProps} />
<Blocks vm={vm} {... blocksProps} />
<SpriteLibrary vm={vm} {...spriteLibraryProps} />
<CostumeLibrary vm={vm} {...costumeLibraryProps} />
<BackdropLibrary vm={vm} {...backdropLibraryProps} />
</GUIComponent>
);
}
/* eslint-disable react/jsx-max-props-per-line, lines-around-comment */
return (
<GUIComponent {... guiProps}>
<GreenFlag vm={vm} {...greenFlagProps} />
<StopAll vm={vm} {...stopAllProps} />
<Stage vm={vm} {...stageProps} />
<SpriteSelector vm={vm} {... spriteSelectorProps} />
<Blocks vm={vm} {... blocksProps} />
<SpriteLibrary vm={vm} {...spriteLibraryProps} />
<CostumeLibrary vm={vm} {...costumeLibraryProps} />
<BackdropLibrary vm={vm} {...backdropLibraryProps} />
</GUIComponent>
);
/* eslint-enable react/jsx-max-props-per-line, lines-around-comment */
}
}
GUI.propTypes = {
backdropLibraryProps: React.PropTypes.object,
backdropLibraryProps: shapeFromPropTypes(BackdropLibrary.propTypes, {omit: ['vm']}),
basePath: React.PropTypes.string,
blocksProps: React.PropTypes.object,
costumeLibraryProps: React.PropTypes.object,
blocksProps: shapeFromPropTypes(Blocks.propTypes, {omit: ['vm']}),
children: React.PropTypes.node,
greenFlagProps: React.PropTypes.object,
costumeLibraryProps: shapeFromPropTypes(CostumeLibrary.propTypes, {omit: ['vm']}),
greenFlagProps: shapeFromPropTypes(GreenFlag.propTypes, {omit: ['vm']}),
projectData: React.PropTypes.string,
spriteLibraryProps: React.PropTypes.object,
spriteSelectorProps: React.PropTypes.object,
stageProps: React.PropTypes.object,
stopAllProps: React.PropTypes.object,
vm: React.PropTypes.object,
spriteLibraryProps: shapeFromPropTypes(SpriteLibrary.propTypes, {omit: ['vm']}),
spriteSelectorProps: shapeFromPropTypes(SpriteSelector.propTypes, {omit: ['vm']}),
stageProps: shapeFromPropTypes(Stage.propTypes, {omit: ['vm']}),
stopAllProps: shapeFromPropTypes(StopAll.propTypes, {omit: ['vm']}),
vm: React.PropTypes.instanceOf(VM),
};
GUI.defaultProps = {
-61
View File
@@ -1,61 +0,0 @@
const bindAll = require('lodash.bindall');
const React = require('react');
const VM = require('scratch-vm');
const MediaLibrary = require('../lib/media-library');
const LibaryComponent = require('../components/library');
class SpriteLibrary extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['setData', 'selectItem', 'setSpriteData']);
this.state = {data: [], spriteData: {}};
}
componentWillReceiveProps (nextProps) {
if (nextProps.visible && this.state.data.length === 0) {
this.props.mediaLibrary.getMediaLibrary('sprite', this.setData);
}
}
setData (data) {
this.setState({data: data});
for (let sprite of data) {
this.props.mediaLibrary.getSprite(sprite.md5, this.setSpriteData);
}
}
setSpriteData (md5, data) {
let spriteData = this.state.spriteData;
spriteData[md5] = data;
this.setState({spriteData: spriteData});
}
selectItem (item) {
var spriteData = JSON.stringify(this.state.spriteData[item.json]);
this.props.vm.addSprite2(spriteData);
}
render () {
let libraryData = Object.keys(this.state.spriteData).map((libraryKey) => {
let libraryItem = this.state.spriteData[libraryKey];
return {
name: libraryItem.objName,
md5: libraryItem.costumes[0].baseLayerMD5,
json: libraryKey
};
});
return <LibaryComponent
title="Sprite Library"
visible={this.props.visible}
data={libraryData}
mediaLibrary={this.props.mediaLibrary}
onRequestClose={this.props.onRequestClose}
onItemSelected={this.selectItem}
/>;
}
}
SpriteLibrary.propTypes = {
vm: React.PropTypes.instanceOf(VM).isRequired,
mediaLibrary: React.PropTypes.instanceOf(MediaLibrary),
visible: React.PropTypes.bool,
onRequestClose: React.PropTypes.func
};
module.exports = SpriteLibrary;
+62
View File
@@ -0,0 +1,62 @@
const bindAll = require('lodash.bindall');
const React = require('react');
const VM = require('scratch-vm');
const MediaLibrary = require('../lib/media-library');
const LibaryComponent = require('../components/library.jsx');
class SpriteLibrary extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['setData', 'handleItemSelect', 'setSpriteData']);
this.state = {data: [], spriteData: {}};
}
componentWillReceiveProps (nextProps) {
if (nextProps.visible && this.state.data.length === 0) {
this.props.mediaLibrary.getMediaLibrary('sprite', this.setData);
}
}
setData (data) {
this.setState({data: data});
for (const sprite of data) {
this.props.mediaLibrary.getSprite(sprite.md5, this.setSpriteData);
}
}
setSpriteData (md5, data) {
this.setState({
spriteData: Object.assign({}, this.state.spriteData, {[md5]: data})
});
}
handleItemSelect (item) {
const spriteData = JSON.stringify(this.state.spriteData[item.json]);
this.props.vm.addSprite2(spriteData);
}
render () {
return (
<LibaryComponent
data={Object.keys(this.state.spriteData).map(libraryKey => {
const libraryItem = this.state.spriteData[libraryKey];
return {
name: libraryItem.objName,
md5: libraryItem.costumes[0].baseLayerMD5,
json: libraryKey
};
})}
mediaLibrary={this.props.mediaLibrary}
title="Sprite Library"
visible={this.props.visible}
onItemSelected={this.handleItemSelect}
onRequestClose={this.props.onRequestClose}
/>
);
}
}
SpriteLibrary.propTypes = {
mediaLibrary: React.PropTypes.instanceOf(MediaLibrary),
onRequestClose: React.PropTypes.func,
visible: React.PropTypes.bool,
vm: React.PropTypes.instanceOf(VM).isRequired
};
module.exports = SpriteLibrary;
@@ -1,12 +1,13 @@
const bindAll = require('lodash.bindall');
const React = require('react');
const VM = require('scratch-vm');
const SpriteSelectorComponent = require('../components/sprite-selector');
const SpriteSelectorComponent = require('../components/sprite-selector.jsx');
class SpriteSelector extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['onChange', 'targetsUpdate']);
bindAll(this, ['handleChange', 'targetsUpdate']);
this.state = {
targets: {
targetList: []
@@ -16,7 +17,7 @@ class SpriteSelector extends React.Component {
componentDidMount () {
this.props.vm.on('targetsUpdate', this.targetsUpdate);
}
onChange (event) {
handleChange (event) {
this.props.vm.setEditingTarget(event.target.value);
}
targetsUpdate (data) {
@@ -32,17 +33,17 @@ class SpriteSelector extends React.Component {
} = this.props;
return (
<SpriteSelectorComponent
value={this.state.targets.editingTarget && [this.state.targets.editingTarget]}
onChange={this.onChange}
openNewSprite={openNewSprite}
openNewCostume={openNewCostume}
openNewBackdrop={openNewBackdrop}
openNewCostume={openNewCostume}
openNewSprite={openNewSprite}
sprites={this.state.targets.targetList.map(target => (
{
id: target[0],
name: target[1]
}
))}
value={this.state.targets.editingTarget && [this.state.targets.editingTarget]}
onChange={this.handleChange}
{...props}
/>
);
@@ -50,10 +51,10 @@ class SpriteSelector extends React.Component {
}
SpriteSelector.propTypes = {
vm: React.PropTypes.object.isRequired,
openNewSprite: React.PropTypes.func,
openNewBackdrop: React.PropTypes.func,
openNewCostume: React.PropTypes.func,
openNewBackdrop: React.PropTypes.func
openNewSprite: React.PropTypes.func,
vm: React.PropTypes.instanceOf(VM)
};
module.exports = SpriteSelector;
@@ -3,7 +3,7 @@ const React = require('react');
const Renderer = require('scratch-render');
const VM = require('scratch-vm');
const StageComponent = require('../components/stage');
const StageComponent = require('../components/stage.jsx');
class Stage extends React.Component {
constructor (props) {
@@ -40,8 +40,8 @@ class Stage extends React.Component {
canvas.removeEventListener('mousedown', this.onMouseDown);
}
onMouseMove (e) {
let rect = this.canvas.getBoundingClientRect();
let coordinates = {
const rect = this.canvas.getBoundingClientRect();
const coordinates = {
x: e.clientX - rect.left,
y: e.clientY - rect.top,
canvasWidth: rect.width,
@@ -50,8 +50,8 @@ class Stage extends React.Component {
this.props.vm.postIOData('mouse', coordinates);
}
onMouseUp (e) {
let rect = this.canvas.getBoundingClientRect();
let data = {
const rect = this.canvas.getBoundingClientRect();
const data = {
isDown: false,
x: e.clientX - rect.left,
y: e.clientY - rect.top,
@@ -62,8 +62,8 @@ class Stage extends React.Component {
e.preventDefault();
}
onMouseDown (e) {
let rect = this.canvas.getBoundingClientRect();
let data = {
const rect = this.canvas.getBoundingClientRect();
const data = {
isDown: true,
x: e.clientX - rect.left,
y: e.clientY - rect.top,
@@ -90,7 +90,7 @@ class Stage extends React.Component {
} = this.props;
return (
<StageComponent
canvasRef={canvas => this.canvas = canvas}
canvasRef={canvas => (this.canvas = canvas)}
{...props}
/>
);
@@ -1,14 +1,15 @@
const bindAll = require('lodash.bindall');
const React = require('react');
const VM = require('scratch-vm');
const StopAllComponent = require('../components/stop-all');
const StopAllComponent = require('../components/stop-all.jsx');
class StopAll extends React.Component {
constructor (props) {
super(props);
bindAll(this, ['onClick']);
bindAll(this, ['handleClick']);
}
onClick (e) {
handleClick (e) {
e.preventDefault();
this.props.vm.stopAll();
}
@@ -19,7 +20,7 @@ class StopAll extends React.Component {
} = this.props;
return (
<StopAllComponent
onClick={this.onClick}
onClick={this.handleClick}
{...props}
/>
);
@@ -27,7 +28,7 @@ class StopAll extends React.Component {
}
StopAll.propTypes = {
vm: React.PropTypes.object
vm: React.PropTypes.instanceOf(VM)
};
module.exports = StopAll;
+2 -2
View File
@@ -1,6 +1,6 @@
const React = require('react');
const ReactDOM = require('react-dom');
const GUI = require('./containers/gui');
const GUI = require('./containers/gui.jsx');
const log = require('./lib/log');
const ProjectLoader = require('./lib/project-loader');
@@ -25,7 +25,7 @@ class App extends React.Component {
return location.hash.substring(1);
}
updateProject () {
let projectId = this.fetchProjectId();
const projectId = this.fetchProjectId();
if (projectId !== this.state.projectId) {
if (projectId.length < 1) {
return this.setState({
+2 -2
View File
@@ -1,4 +1,4 @@
var minilog = require('minilog');
const minilog = require('minilog');
minilog.enable();
module.exports = minilog('www');
module.exports = minilog('gui');
+5 -5
View File
@@ -3,9 +3,9 @@ const xhr = require('xhr');
const LIBRARY_PREFIX = 'https://cdn.scratch.mit.edu/scratchr2/static/' +
'__8d9c95eb5aa1272a311775ca32568417__/medialibraries/';
const LIBRARY_URL = {
sprite: LIBRARY_PREFIX + 'spriteLibrary.json',
costume: LIBRARY_PREFIX + 'costumeLibrary.json',
backdrop: LIBRARY_PREFIX + 'backdropLibrary.json'
sprite: `${LIBRARY_PREFIX}spriteLibrary.json`,
costume: `${LIBRARY_PREFIX}costumeLibrary.json`,
backdrop: `${LIBRARY_PREFIX}backdropLibrary.json`
};
const SPRITE_OBJECT_PREFIX = 'https://cdn.assets.scratch.mit.edu/internalapi/asset/';
const SPRITE_OBJECT_SUFFIX = '/get/';
@@ -44,7 +44,7 @@ class MediaLibrary {
url: LIBRARY_URL[libraryType]
}, (err, response, body) => {
if (!err) {
let data = JSON.parse(body);
const data = JSON.parse(body);
this._libraryData[libraryType] = data;
callback(this._libraryData[libraryType]);
}
@@ -68,7 +68,7 @@ class MediaLibrary {
url: SPRITE_OBJECT_PREFIX + url + SPRITE_OBJECT_SUFFIX
}, (err, response, body) => {
if (!err) {
let data = JSON.parse(body);
const data = JSON.parse(body);
this._spriteData[url] = data;
callback(url, data);
}
+13
View File
@@ -0,0 +1,13 @@
const React = require('react');
module.exports = function shapeFromPropTypes (propTypes, opts) {
opts = Object.assign({}, opts, {omit: []});
const shape = Object
.keys(propTypes)
.filter(key => opts.omit.indexOf(key) !== -1)
.reduce((newPropTypes, key) => {
newPropTypes[key] = propTypes[key];
return newPropTypes;
}, {});
return React.PropTypes.shape(shape);
};
+3 -2
View File
@@ -21,7 +21,7 @@ class VMManager {
}
onKeyDown (e) {
// Don't capture keys intended for Blockly inputs.
if (e.target != document && e.target != document.body) {
if (e.target !== document && e.target !== document.body) {
return;
}
this.vm.postIOData('keyboard', {
@@ -37,8 +37,9 @@ class VMManager {
keyCode: e.keyCode,
isDown: false
});
// E.g., prevent scroll.
if (e.target != document && e.target != document.body) {
if (e.target !== document && e.target !== document.body) {
e.preventDefault();
}
}
+4 -3
View File
@@ -2,10 +2,11 @@ var path = require('path');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpack = require('webpack');
module.exports = {
entry: {
vendor: ['react', 'react-dom'],
gui: './src/index.js'
gui: './src/index.jsx'
},
output: {
path: path.resolve(__dirname, 'build'),
@@ -17,7 +18,7 @@ module.exports = {
ReactDOM: 'react-dom'
},
loaders: [{
test: /\.js$/,
test: /\.jsx?$/,
loader: 'babel-loader',
include: path.resolve(__dirname, 'src'),
query: {
@@ -45,7 +46,7 @@ module.exports = {
from: 'node_modules/scratch-blocks/media',
to: 'static/blocks-media'
}])
].concat(process.env.NODE_ENV == 'production' ? [
].concat(process.env.NODE_ENV === 'production' ? [
new webpack.optimize.UglifyJsPlugin({
include: /\.min\.js$/,
minimize: true,