UNPKG

scratch-gui

Version:

GraphicaL User Interface for creating and running Scratch 3.0 projects

156 lines (146 loc) 5.11 kB
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);