scratch-gui
Version:
GraphicaL User Interface for creating and running Scratch 3.0 projects
156 lines (146 loc) • 5.11 kB
JSX
import bindAll from 'lodash.bindall';
import defaultsDeep from 'lodash.defaultsdeep';
import PropTypes from 'prop-types';
import React from 'react';
import CustomProceduresComponent from '../components/custom-procedures/custom-procedures.jsx';
import ScratchBlocks from 'scratch-blocks';
import {connect} from 'react-redux';
class CustomProcedures extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'handleAddLabel',
'handleAddBoolean',
'handleAddTextNumber',
'handleToggleWarp',
'handleCancel',
'handleOk',
'setBlocks'
]);
this.state = {
warp: false
};
}
componentWillUnmount () {
if (this.workspace) {
this.workspace.dispose();
}
}
setBlocks (blocksRef) {
if (!blocksRef) return;
this.blocks = blocksRef;
const workspaceConfig = defaultsDeep({},
CustomProcedures.defaultOptions,
this.props.options
);
// @todo This is a hack to make there be no toolbox.
const oldDefaultToolbox = ScratchBlocks.Blocks.defaultToolbox;
ScratchBlocks.Blocks.defaultToolbox = null;
this.workspace = ScratchBlocks.inject(this.blocks, workspaceConfig);
ScratchBlocks.Blocks.defaultToolbox = oldDefaultToolbox;
// Create the procedure declaration block for editing the mutation.
this.mutationRoot = this.workspace.newBlock('procedures_declaration');
// Make the declaration immovable, undeletable and have no context menu
this.mutationRoot.setMovable(false);
this.mutationRoot.setDeletable(false);
this.mutationRoot.contextMenu = false;
this.workspace.addChangeListener(() => {
this.mutationRoot.onChangeFn();
// Keep the block centered on the workspace
const metrics = this.workspace.getMetrics();
const {x, y} = this.mutationRoot.getRelativeToSurfaceXY();
const dy = (metrics.viewHeight / 2) - (this.mutationRoot.height / 2) - y;
let dx = (metrics.viewWidth / 2) - (this.mutationRoot.width / 2) - x;
// If the procedure declaration is wider than the view width,
// keep the right-hand side of the procedure in view.
if (this.mutationRoot.width > metrics.viewWidth) {
dx = metrics.viewWidth - this.mutationRoot.width - x;
}
this.mutationRoot.moveBy(dx, dy);
});
this.mutationRoot.domToMutation(this.props.mutator);
this.mutationRoot.initSvg();
this.mutationRoot.render();
this.setState({warp: this.mutationRoot.getWarp()});
// Allow the initial events to run to position this block, then focus.
setTimeout(() => {
this.mutationRoot.focusLastEditor_();
});
}
handleCancel () {
this.props.onRequestClose();
}
handleOk () {
const newMutation = this.mutationRoot ? this.mutationRoot.mutationToDom(true) : null;
this.props.onRequestClose(newMutation);
}
handleAddLabel () {
if (this.mutationRoot) {
this.mutationRoot.addLabelExternal();
}
}
handleAddBoolean () {
if (this.mutationRoot) {
this.mutationRoot.addBooleanExternal();
}
}
handleAddTextNumber () {
if (this.mutationRoot) {
this.mutationRoot.addStringNumberExternal();
}
}
handleToggleWarp () {
if (this.mutationRoot) {
const newWarp = !this.mutationRoot.getWarp();
this.mutationRoot.setWarp(newWarp);
this.setState({warp: newWarp});
}
}
render () {
return (
<CustomProceduresComponent
componentRef={this.setBlocks}
warp={this.state.warp}
onAddBoolean={this.handleAddBoolean}
onAddLabel={this.handleAddLabel}
onAddTextNumber={this.handleAddTextNumber}
onCancel={this.handleCancel}
onOk={this.handleOk}
onToggleWarp={this.handleToggleWarp}
/>
);
}
}
CustomProcedures.propTypes = {
mutator: PropTypes.instanceOf(Element),
onRequestClose: PropTypes.func.isRequired,
options: PropTypes.shape({
media: PropTypes.string,
zoom: PropTypes.shape({
controls: PropTypes.bool,
wheel: PropTypes.bool,
startScale: PropTypes.number
}),
comments: PropTypes.bool,
collapse: PropTypes.bool
})
};
CustomProcedures.defaultOptions = {
zoom: {
controls: false,
wheel: false,
startScale: 0.9
},
comments: false,
collapse: false,
scrollbars: true
};
CustomProcedures.defaultProps = {
options: CustomProcedures.defaultOptions
};
const mapStateToProps = state => ({
mutator: state.customProcedures.mutator
});
export default connect(
mapStateToProps
)(CustomProcedures);