template created for not deactivated blocks in the instructions

This commit is contained in:
Delucse 2020-09-28 15:12:19 +02:00
parent 8ec8409504
commit 4a5d24f2d1
8 changed files with 65 additions and 25 deletions

View File

@ -26,14 +26,18 @@ class BlocklyWindow extends Component {
this.props.clearStats(); this.props.clearStats();
workspace.addChangeListener((event) => { workspace.addChangeListener((event) => {
this.props.onChangeWorkspace(event); this.props.onChangeWorkspace(event);
Blockly.Events.disableOrphans(event); // switch on that a block is displayed disabled or not depending on whether it is correctly connected
// for SVG display, a deactivated block in the display is undesirable
if(this.props.blockDisabled){
Blockly.Events.disableOrphans(event);
}
}); });
Blockly.svgResize(workspace); Blockly.svgResize(workspace);
} }
componentDidUpdate(props) { componentDidUpdate(props) {
const workspace = Blockly.getMainWorkspace(); const workspace = Blockly.getMainWorkspace();
var xml = this.props.initialXml var xml = this.props.initialXml;
// if svg is true, then the update process is done in the BlocklySvg component // if svg is true, then the update process is done in the BlocklySvg component
if(props.initialXml !== xml && !this.props.svg){ if(props.initialXml !== xml && !this.props.svg){
// guarantees that the current xml-code (this.props.initialXml) is rendered // guarantees that the current xml-code (this.props.initialXml) is rendered

View File

@ -87,7 +87,7 @@ class Home extends Component {
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<TrashcanButtons /> <TrashcanButtons />
<BlocklyWindow blocklyCSS={{height: '500px'}}/> <BlocklyWindow blocklyCSS={{height: '500px'}} blockDisabled/>
</Grid> </Grid>
{this.state.codeOn ? {this.state.codeOn ?
<Grid item xs={12} md={6}> <Grid item xs={12} md={6}>

View File

@ -41,6 +41,7 @@ class Assessment extends Component {
<Grid item xs={12} md={6} lg={8}> <Grid item xs={12} md={6} lg={8}>
<BlocklyWindow <BlocklyWindow
initialXml={statusTask ? statusTask.xml ? statusTask.xml : null : null} initialXml={statusTask ? statusTask.xml ? statusTask.xml : null : null}
blockDisabled
blocklyCSS={{height: '500px'}} blocklyCSS={{height: '500px'}}
/> />
</Grid> </Grid>

View File

@ -7,6 +7,7 @@ import moment from 'moment';
import localization from 'moment/locale/de'; import localization from 'moment/locale/de';
import * as Blockly from 'blockly/core'; import * as Blockly from 'blockly/core';
import { initialXml } from '../../Blockly//initialXml.js';
import BlocklyWindow from '../../Blockly/BlocklyWindow'; import BlocklyWindow from '../../Blockly/BlocklyWindow';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
@ -41,10 +42,12 @@ class BlocklyExample extends Component {
this.state={ this.state={
checked: props.task ? props.task : props.value ? true : false, checked: props.task ? props.task : props.value ? true : false,
input: null, input: null,
disabled: false
}; };
} }
componentDidMount(){ componentDidMount(){
moment.updateLocale('de', localization);
this.isError(); this.isError();
// if(this.props.task){ // if(this.props.task){
// this.props.setError(this.props.index, 'xml'); // this.props.setError(this.props.index, 'xml');
@ -57,14 +60,36 @@ class BlocklyExample extends Component {
() => this.isError() () => this.isError()
); );
} }
if(state.checked !== this.state.checked){ if(state.checked !== this.state.checked && this.state.checked){
this.isError(); this.isError();
} }
if(props.xml !== this.props.xml){
// check if there is at least one block, otherwise the workspace cannot be submitted
var workspace = Blockly.getMainWorkspace();
var areBlocks = workspace.getAllBlocks().length > 0;
this.setState({disabled: !areBlocks});
}
} }
isError = () => { isError = () => {
if(this.state.checked && !this.props.value){ if(this.state.checked){
this.props.setError(this.props.index, 'xml'); var xml = this.props.value;
// check if value is valid xml;
try{
Blockly.Xml.textToDom(xml);
this.props.deleteError(this.props.index, 'xml');
}
catch(err){
xml = initialXml;
// not valid xml, throw error in redux store
this.props.setError(this.props.index, 'xml');
}
if(!this.props.task){
// instruction can also display only one block, which does not necessarily
// have to be the initial block
xml = xml.replace('deletable="false"', 'deletable="true"');
}
this.setState({xml: xml});
} }
else { else {
this.props.deleteError(this.props.index, 'xml'); this.props.deleteError(this.props.index, 'xml');
@ -79,8 +104,13 @@ class BlocklyExample extends Component {
} }
} }
setXml = () => {
var xml = this.props.xml;
this.props.changeContent(this.props.index, 'xml', xml);
this.setState({input: moment(Date.now()).format('LTS')});
}
render() { render() {
moment.locale('de', localization);
return ( return (
<div style={{marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)'}}> <div style={{marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)'}}>
{!this.props.task ? {!this.props.task ?
@ -100,22 +130,18 @@ class BlocklyExample extends Component {
<FormHelperText style={{lineHeight: 'initial'}} className={this.props.classes.errorColor}>{`Reiche deine Blöcke ein, indem du auf den '${this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'}'-Button klickst.`}</FormHelperText> <FormHelperText style={{lineHeight: 'initial'}} className={this.props.classes.errorColor}>{`Reiche deine Blöcke ein, indem du auf den '${this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'}'-Button klickst.`}</FormHelperText>
: this.state.input ? <FormHelperText style={{lineHeight: 'initial'}}>Die letzte Einreichung erfolgte um {this.state.input} Uhr.</FormHelperText> : null : this.state.input ? <FormHelperText style={{lineHeight: 'initial'}}>Die letzte Einreichung erfolgte um {this.state.input} Uhr.</FormHelperText> : null
: null} : null}
{this.state.checked && !this.props.task ?
<FormHelperText style={{lineHeight: 'initial'}}>Anmerkung: Man kann den initialen Setup()- bzw. Endlosschleifen()-Block löschen. Zusätzlich ist es möglich u.a. nur einen beliebigen Block auszuwählen, ohne dass dieser als deaktiviert dargestellt wird.</FormHelperText>
: null}
{this.state.checked ? (() => { {this.state.checked ? (() => {
var initialXml = this.props.value; return(
// check if value is valid xml;
try{
Blockly.Xml.textToDom(initialXml);
}
catch(err){
initialXml = null;
// this.props.setError(this.props.index, 'xml');
}
return (
<div style={{marginTop: '10px'}}> <div style={{marginTop: '10px'}}>
<Grid container className={!this.props.value || this.props.error ? this.props.classes.errorBorder : null}> <Grid container className={!this.props.value || this.props.error ? this.props.classes.errorBorder : null}>
<Grid item xs={12}> <Grid item xs={12}>
<BlocklyWindow <BlocklyWindow
initialXml={initialXml} blockDisabled={this.props.task}
trashcan={false}
initialXml={this.state.xml}
blocklyCSS={{height: '500px'}} blocklyCSS={{height: '500px'}}
/> />
</Grid> </Grid>
@ -125,7 +151,8 @@ class BlocklyExample extends Component {
style={{marginTop: '5px', height: '40px'}} style={{marginTop: '5px', height: '40px'}}
variant='contained' variant='contained'
color='primary' color='primary'
onClick={() => {this.props.changeContent(this.props.index, 'xml', this.props.xml); this.setState({input: moment(Date.now()).format('LTS')})}} disabled={this.state.disabled}
onClick={() => this.setXml()}
> >
{this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'} {this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'}
</Button> </Button>

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { changeContent } from '../../../actions/tutorialBuilderActions'; import { changeContent, deleteProperty } from '../../../actions/tutorialBuilderActions';
import Radio from '@material-ui/core/Radio'; import Radio from '@material-ui/core/Radio';
import RadioGroup from '@material-ui/core/RadioGroup'; import RadioGroup from '@material-ui/core/RadioGroup';
@ -9,9 +9,15 @@ import FormControlLabel from '@material-ui/core/FormControlLabel';
class StepType extends Component { class StepType extends Component {
onChange = (value) => {
this.props.changeContent(this.props.index, 'type', value);
// delete property 'xml', so that all used blocks are reset
this.props.deleteProperty(this.props.index, 'xml');
}
render() { render() {
return ( return (
<RadioGroup row value={this.props.value === 'task' ? 'task' : 'instruction'} onChange={(e) => {this.props.changeContent(this.props.index, 'type', e.target.value)}}> <RadioGroup row value={this.props.value === 'task' ? 'task' : 'instruction'} onChange={(e) => this.onChange(e.target.value)}>
<FormControlLabel style={{color: 'black'}} <FormControlLabel style={{color: 'black'}}
value="instruction" value="instruction"
control={<Radio color="primary" />} control={<Radio color="primary" />}
@ -31,7 +37,8 @@ class StepType extends Component {
} }
StepType.propTypes = { StepType.propTypes = {
changeContent: PropTypes.func.isRequired changeContent: PropTypes.func.isRequired,
deleteProperty: PropTypes.func.isRequired
}; };
export default connect(null, { changeContent })(StepType); export default connect(null, { changeContent, deleteProperty })(StepType);

View File

@ -28,6 +28,7 @@ class Instruction extends Component {
<Grid item xs={12}> <Grid item xs={12}>
<BlocklyWindow <BlocklyWindow
svg svg
blockDisabled
initialXml={step.xml} initialXml={step.xml}
/> />
</Grid> </Grid>

View File

@ -42,7 +42,7 @@ class Tutorial extends Component {
var step = steps ? steps[this.props.activeStep] : null; var step = steps ? steps[this.props.activeStep] : null;
var name = step ? `${detectWhitespacesAndReturnReadableResult(tutorial.title)}_${detectWhitespacesAndReturnReadableResult(step.headline)}` : null; var name = step ? `${detectWhitespacesAndReturnReadableResult(tutorial.title)}_${detectWhitespacesAndReturnReadableResult(step.headline)}` : null;
return ( return (
!Number.isInteger(currentTutorialId) || currentTutorialId < 1 || currentTutorialId > tutorials.length ? !Number.isInteger(currentTutorialId) || currentTutorialId < 1 || !tutorial ?
<NotFound button={{title: 'Zurück zur Tutorials-Übersicht', link: '/tutorial'}}/> <NotFound button={{title: 'Zurück zur Tutorials-Übersicht', link: '/tutorial'}}/>
: :
<div> <div>

View File

@ -125,7 +125,7 @@ class WorkspaceFunc extends Component {
this.state.file === 'xml' ? this.saveXmlFile() : this.getSvg() this.state.file === 'xml' ? this.saveXmlFile() : this.getSvg()
} }
else{ else{
this.setState({ saveFile: true, file: filetype, open: true, title: this.state.file === 'xml' ? 'Blöcke speichern' : 'Screenshot erstellen', content: `Bitte gib einen Namen für die Bennenung der ${this.state.file === 'xml' ? 'XML' : 'SVG'}-Datei ein und bestätige diesen mit einem Klick auf \'Eingabe\'.` }); this.setState({ saveFile: true, file: filetype, open: true, title: this.state.file === 'xml' ? 'Blöcke speichern' : 'Screenshot erstellen', content: `Bitte gib einen Namen für die Bennenung der ${this.state.file === 'xml' ? 'XML' : 'SVG'}-Datei ein und bestätige diesen mit einem Klick auf 'Eingabe'.` });
} }
}); });
} }