Merge branch 'tutorial-builder' into tutorial
This commit is contained in:
		
						commit
						f97ab10a53
					
				| @ -85,10 +85,18 @@ export const removeErrorStep = (index) => (dispatch, getState) => { | |||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const changeContent = (index, property, content) => (dispatch, getState) => { | export const changeContent = (content, index, property1, property2) => (dispatch, getState) => { | ||||||
|   var steps = getState().builder.steps; |   var steps = getState().builder.steps; | ||||||
|   var step = steps[index]; |   var step = steps[index]; | ||||||
|   step[property] = content; |   if(property2){ | ||||||
|  |     if(step[property1] && step[property1][property2]){ | ||||||
|  |       step[property1][property2] = content; | ||||||
|  |     } else { | ||||||
|  |       step[property1] = {[property2]: content}; | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     step[property1] = content; | ||||||
|  |   } | ||||||
|   dispatch({ |   dispatch({ | ||||||
|     type: BUILDER_CHANGE_STEP, |     type: BUILDER_CHANGE_STEP, | ||||||
|     payload: steps |     payload: steps | ||||||
| @ -96,10 +104,16 @@ export const changeContent = (index, property, content) => (dispatch, getState) | |||||||
|   dispatch(changeTutorialBuilder()); |   dispatch(changeTutorialBuilder()); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const deleteProperty = (index, property) => (dispatch, getState) => { | export const deleteProperty = (index, property1, property2) => (dispatch, getState) => { | ||||||
|   var steps = getState().builder.steps; |   var steps = getState().builder.steps; | ||||||
|   var step = steps[index]; |   var step = steps[index]; | ||||||
|   delete step[property]; |   if(property2){ | ||||||
|  |     if(step[property1] && step[property1][property2]){ | ||||||
|  |       delete step[property1][property2]; | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     delete step[property1]; | ||||||
|  |   } | ||||||
|   dispatch({ |   dispatch({ | ||||||
|     type: BUILDER_DELETE_PROPERTY, |     type: BUILDER_DELETE_PROPERTY, | ||||||
|     payload: steps |     payload: steps | ||||||
| @ -170,14 +184,14 @@ export const setSubmitError = () => (dispatch, getState) => { | |||||||
|     dispatch(setError(undefined, 'title')); |     dispatch(setError(undefined, 'title')); | ||||||
|   } |   } | ||||||
|   var type = builder.steps.map((step, i) => { |   var type = builder.steps.map((step, i) => { | ||||||
|     // picture and xml are directly checked for errors in their components and
 |     // media and xml are directly checked for errors in their components and
 | ||||||
|     // therefore do not have to be checked again
 |     // therefore do not have to be checked again
 | ||||||
|     step.id = i+1; |     step.id = i+1; | ||||||
|     if(i === 0){ |     if(i === 0){ | ||||||
|       if(step.requirements && step.requirements.length > 0){ |       if(step.requirements && step.requirements.length > 0){ | ||||||
|         var requirements = step.requirements.filter(requirement => typeof(requirement)==='number'); |         var requirements = step.requirements.filter(requirement => typeof(requirement)==='number'); | ||||||
|         if(requirements.length < step.requirements.length){ |         if(requirements.length < step.requirements.length){ | ||||||
|           dispatch(changeContent(i, 'requirements', requirements)); |           dispatch(changeContent(requirements, i, 'requirements')); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       if(step.hardware === undefined || step.hardware.length < 1){ |       if(step.hardware === undefined || step.hardware.length < 1){ | ||||||
| @ -187,7 +201,7 @@ export const setSubmitError = () => (dispatch, getState) => { | |||||||
|         var hardwareIds = data.map(hardware => hardware.id); |         var hardwareIds = data.map(hardware => hardware.id); | ||||||
|         var hardware = step.hardware.filter(hardware => hardwareIds.includes(hardware)); |         var hardware = step.hardware.filter(hardware => hardwareIds.includes(hardware)); | ||||||
|         if(hardware.length < step.hardware.length){ |         if(hardware.length < step.hardware.length){ | ||||||
|           dispatch(changeContent(i, 'hardware', hardware)); |           dispatch(changeContent(hardware, i, 'hardware')); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @ -272,8 +286,14 @@ export const readJSON = (json) => (dispatch, getState) => { | |||||||
|     if(step.xml){ |     if(step.xml){ | ||||||
|       object.xml = step.xml; |       object.xml = step.xml; | ||||||
|     } |     } | ||||||
|     if(step.picture && step.type === 'instruction'){ |     if(step.media && step.type === 'instruction'){ | ||||||
|       object.picture = step.picture; |       object.media = {}; | ||||||
|  |       if(step.media.picture){ | ||||||
|  |         object.media.picture = step.media.picture; | ||||||
|  |       } | ||||||
|  |       else if(step.media.youtube){ | ||||||
|  |         object.media.youtube = step.media.youtube; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|     return object; |     return object; | ||||||
|   }); |   }); | ||||||
|  | |||||||
| @ -107,7 +107,7 @@ class BlocklyExample extends Component { | |||||||
| 
 | 
 | ||||||
|   setXml = () => { |   setXml = () => { | ||||||
|     var xml = this.props.xml; |     var xml = this.props.xml; | ||||||
|     this.props.changeContent(this.props.index, 'xml', xml); |     this.props.changeContent(xml, this.props.index, 'xml'); | ||||||
|     this.setState({input: moment(Date.now()).format('LTS')}); |     this.setState({input: moment(Date.now()).format('LTS')}); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -56,7 +56,7 @@ class Requirements extends Component { | |||||||
|         this.props.deleteError(this.props.index, 'hardware'); |         this.props.deleteError(this.props.index, 'hardware'); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     this.props.changeContent(this.props.index, 'hardware', hardwareArray); |     this.props.changeContent(hardwareArray, this.props.index, 'hardware'); | ||||||
|     if(hardwareArray.length === 0){ |     if(hardwareArray.length === 0){ | ||||||
|       this.props.setError(this.props.index, 'hardware'); |       this.props.setError(this.props.index, 'hardware'); | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										178
									
								
								src/components/Tutorial/Builder/Media.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								src/components/Tutorial/Builder/Media.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,178 @@ | |||||||
|  | import React, { Component } from 'react'; | ||||||
|  | import PropTypes from 'prop-types'; | ||||||
|  | import { connect } from 'react-redux'; | ||||||
|  | import { changeContent, deleteProperty, setError, deleteError } from '../../../actions/tutorialBuilderActions'; | ||||||
|  | 
 | ||||||
|  | import Textfield from './Textfield'; | ||||||
|  | 
 | ||||||
|  | import { withStyles } from '@material-ui/core/styles'; | ||||||
|  | import Switch from '@material-ui/core/Switch'; | ||||||
|  | import FormControlLabel from '@material-ui/core/FormControlLabel'; | ||||||
|  | import FormHelperText from '@material-ui/core/FormHelperText'; | ||||||
|  | import Radio from '@material-ui/core/Radio'; | ||||||
|  | import RadioGroup from '@material-ui/core/RadioGroup'; | ||||||
|  | import Button from '@material-ui/core/Button'; | ||||||
|  | 
 | ||||||
|  | const styles = (theme) => ({ | ||||||
|  |   errorColor: { | ||||||
|  |     color: theme.palette.error.dark | ||||||
|  |   }, | ||||||
|  |   errorBorder: { | ||||||
|  |     border: `1px solid ${theme.palette.error.dark}` | ||||||
|  |   }, | ||||||
|  |   errorButton: { | ||||||
|  |     marginTop: '5px', | ||||||
|  |     height: '40px', | ||||||
|  |     backgroundColor: theme.palette.error.dark, | ||||||
|  |     '&:hover':{ | ||||||
|  |       backgroundColor: theme.palette.error.dark | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | class Media extends Component { | ||||||
|  | 
 | ||||||
|  |   constructor(props){ | ||||||
|  |     super(props); | ||||||
|  |     this.state={ | ||||||
|  |       checked: props.value ? true : false, | ||||||
|  |       error: false, | ||||||
|  |       radioValue: !props.picture && !props.youtube ? 'picture' : props.picture ? 'picture' : 'youtube' | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   componentDidUpdate(props){ | ||||||
|  |     if(props.value !== this.props.value){ | ||||||
|  |       this.setState({ checked: this.props.value ? true : false }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onChangeSwitch = (value) => { | ||||||
|  |     var oldValue = this.state.checked; | ||||||
|  |     this.setState({checked: value}); | ||||||
|  |     if(oldValue !== value){ | ||||||
|  |       if(value){ | ||||||
|  |         this.props.setError(this.props.index, 'media'); | ||||||
|  |       } else { | ||||||
|  |         this.props.deleteError(this.props.index, 'media'); | ||||||
|  |         this.props.deleteProperty(this.props.index, 'media'); | ||||||
|  |         this.props.deleteProperty(this.props.index, 'url'); | ||||||
|  |         this.setState({ error: false}); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onChangeRadio = (value) => { | ||||||
|  |     this.props.setError(this.props.index, 'media'); | ||||||
|  |     var oldValue = this.state.radioValue; | ||||||
|  |     this.setState({radioValue: value, error: false}); | ||||||
|  |     // delete property 'oldValue', so that all old media files are reset
 | ||||||
|  |     this.props.deleteProperty(this.props.index, 'media', oldValue); | ||||||
|  |     if(oldValue === 'picture'){ | ||||||
|  |       this.props.deleteProperty(this.props.index, 'url'); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   uploadPicture = (pic) => { | ||||||
|  |     if(!(/^image\/.*/.test(pic.type))){ | ||||||
|  |       this.props.setError(this.props.index, 'media'); | ||||||
|  |       this.setState({ error: true }); | ||||||
|  |       this.props.deleteProperty(this.props.index, 'url'); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |       this.props.deleteError(this.props.index, 'media'); | ||||||
|  |       this.setState({ error: false }); | ||||||
|  |       this.props.changeContent(URL.createObjectURL(pic), this.props.index, 'url'); | ||||||
|  |     } | ||||||
|  |     this.props.changeContent(pic.name, this.props.index, 'media', 'picture'); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   render() { | ||||||
|  |     return ( | ||||||
|  |       <div style={{marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)'}}> | ||||||
|  |         <FormControlLabel | ||||||
|  |           labelPlacement="end" | ||||||
|  |           label={"Medien"} | ||||||
|  |           control={ | ||||||
|  |             <Switch | ||||||
|  |               checked={this.state.checked} | ||||||
|  |               onChange={(e) => this.onChangeSwitch(e.target.checked)} | ||||||
|  |               color="primary" | ||||||
|  |             /> | ||||||
|  |           } | ||||||
|  |         /> | ||||||
|  |         {this.state.checked ? | ||||||
|  |           <div> | ||||||
|  |             <RadioGroup row value={this.state.radioValue} onChange={(e) => {this.onChangeRadio(e.target.value);}}> | ||||||
|  |               <FormControlLabel style={{color: 'black'}} | ||||||
|  |                 value="picture" | ||||||
|  |                 control={<Radio color="primary" />} | ||||||
|  |                 label="Bild" | ||||||
|  |                 labelPlacement="end" | ||||||
|  |               /> | ||||||
|  |               <FormControlLabel style={{color: 'black'}} | ||||||
|  |                 value="youtube" | ||||||
|  |                 control={<Radio color="primary" />} | ||||||
|  |                 label="Youtube-Video" | ||||||
|  |                 labelPlacement="end" | ||||||
|  |               /> | ||||||
|  |             </RadioGroup> | ||||||
|  |             {this.state.radioValue === 'picture' ? | ||||||
|  |               <div> | ||||||
|  |                 {!this.props.error ? | ||||||
|  |                   <div> | ||||||
|  |                     <FormHelperText style={{lineHeight: 'initial', marginBottom: '10px'}}>{`Beachte, dass das Foto zusätzlich in den Ordner public/media/tutorial unter dem Namen '${this.props.picture}' abgespeichert werden muss.`}</FormHelperText> | ||||||
|  |                     <img src={this.props.url ? this.props.url : `/media/tutorial/${this.props.picture}`} alt={this.props.url ? '' : `Das Bild '${this.props.picture}' konnte nicht im Ordner public/media/tutorial gefunden werden und kann daher nicht angezeigt werden.`} style={{maxHeight: '180px', maxWidth: '360px', marginBottom: '5px'}}/> | ||||||
|  |                   </div> | ||||||
|  |                 : <div | ||||||
|  |                     style={{height: '150px', maxWidth: '250px', marginBottom: '5px', justifyContent: "center", alignItems: "center", display:"flex", padding: '20px'}} | ||||||
|  |                     className={this.props.error ? this.props.classes.errorBorder : null} > | ||||||
|  |                     {this.state.error ? | ||||||
|  |                         <FormHelperText style={{lineHeight: 'initial', textAlign: 'center'}} className={this.props.classes.errorColor}>{`Die übergebene Datei entspricht nicht dem geforderten Bild-Format. Überprüfe, ob es sich um ein Bild handelt und versuche es nochmal.`}</FormHelperText> | ||||||
|  |                       : <FormHelperText style={{lineHeight: 'initial', textAlign: 'center'}} className={this.props.classes.errorColor}>{`Wähle ein Bild aus.`}</FormHelperText> | ||||||
|  |                     } | ||||||
|  |                   </div>} | ||||||
|  |                 {/*upload picture*/} | ||||||
|  |                 <div> | ||||||
|  |                   <input | ||||||
|  |                     style={{display: 'none'}} | ||||||
|  |                     accept="image/*" | ||||||
|  |                     onChange={(e) => {this.uploadPicture(e.target.files[0]);}} | ||||||
|  |                     id={`picture ${this.props.index}`} | ||||||
|  |                     type="file" | ||||||
|  |                   /> | ||||||
|  |                   <label htmlFor={`picture ${this.props.index}`}> | ||||||
|  |                     <Button component="span" className={this.props.error ? this.props.classes.errorButton : null} style={{marginRight: '10px', marginBottom: '10px'}} variant='contained' color='primary'>Bild auswählen</Button> | ||||||
|  |                   </label> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |             : | ||||||
|  |               /*youtube-video*/ | ||||||
|  |               <div> | ||||||
|  |                 <Textfield value={this.props.value && this.props.value.youtube} property={'media'} property2={'youtube'} label={'Youtube-ID'} index={this.props.index} error={this.props.error} errorText={`Gib eine Youtube-ID ein.`}/> | ||||||
|  |                 {this.props.youtube && !this.props.error ? | ||||||
|  |                   <div> | ||||||
|  |                     <FormHelperText style={{lineHeight: 'initial', margin: '0 25px 10px 25px'}}>{`Stelle sicher, dass das unten angezeigte Youtube-Video funktioniert, andernfalls überprüfe die Youtube-ID.`}</FormHelperText> | ||||||
|  |                     <div style={{position: 'relative', paddingBottom: '56.25%', height: 0}}> | ||||||
|  |                       <iframe title={this.props.youtube} style={{borderRadius: '25px', position: 'absolute', top: '0', left: '0', width: '100%', height: '100%'}} src={`https://www.youtube.com/embed/${this.props.youtube}`} frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen /> | ||||||
|  |                     </div> | ||||||
|  |                   </div> | ||||||
|  |                 : null} | ||||||
|  |               </div> | ||||||
|  |             } | ||||||
|  |           </div> | ||||||
|  |         : null} | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Media.propTypes = { | ||||||
|  |   changeContent: PropTypes.func.isRequired, | ||||||
|  |   deleteProperty: PropTypes.func.isRequired, | ||||||
|  |   setError: PropTypes.func.isRequired, | ||||||
|  |   deleteError: PropTypes.func.isRequired, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | export default connect(null, { changeContent, deleteProperty, setError, deleteError })(withStyles(styles, {withTheme: true})(Media)); | ||||||
| @ -1,132 +0,0 @@ | |||||||
| import React, { Component } from 'react'; |  | ||||||
| import PropTypes from 'prop-types'; |  | ||||||
| import { connect } from 'react-redux'; |  | ||||||
| import { changeContent, deleteProperty, setError, deleteError } from '../../../actions/tutorialBuilderActions'; |  | ||||||
| 
 |  | ||||||
| import { withStyles } from '@material-ui/core/styles'; |  | ||||||
| import Switch from '@material-ui/core/Switch'; |  | ||||||
| import FormControlLabel from '@material-ui/core/FormControlLabel'; |  | ||||||
| import FormHelperText from '@material-ui/core/FormHelperText'; |  | ||||||
| import Button from '@material-ui/core/Button'; |  | ||||||
| 
 |  | ||||||
| const styles = (theme) => ({ |  | ||||||
|   errorColor: { |  | ||||||
|     color: theme.palette.error.dark |  | ||||||
|   }, |  | ||||||
|   errorBorder: { |  | ||||||
|     border: `1px solid ${theme.palette.error.dark}` |  | ||||||
|   }, |  | ||||||
|   errorButton: { |  | ||||||
|     marginTop: '5px', |  | ||||||
|     height: '40px', |  | ||||||
|     backgroundColor: theme.palette.error.dark, |  | ||||||
|     '&:hover':{ |  | ||||||
|       backgroundColor: theme.palette.error.dark |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| class Picture extends Component { |  | ||||||
| 
 |  | ||||||
|   constructor(props){ |  | ||||||
|     super(props); |  | ||||||
|     this.state={ |  | ||||||
|       checked: props.value ? true : false, |  | ||||||
|       error: false |  | ||||||
|     }; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   componentDidUpdate(props){ |  | ||||||
|     if(props.value !== this.props.value){ |  | ||||||
|       this.setState({ checked: this.props.value ? true : false }); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   onChange = (value) => { |  | ||||||
|     var oldValue = this.state.checked; |  | ||||||
|     this.setState({checked: value}); |  | ||||||
|     if(oldValue !== value){ |  | ||||||
|       if(value){ |  | ||||||
|         this.props.setError(this.props.index, 'picture'); |  | ||||||
|       } else { |  | ||||||
|         this.props.deleteError(this.props.index, 'picture'); |  | ||||||
|         this.props.deleteProperty(this.props.index, 'picture'); |  | ||||||
|         this.props.deleteProperty(this.props.index, 'url'); |  | ||||||
|         this.setState({ error: false}); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   uploadPicture = (pic) => { |  | ||||||
|     if(!(/^image\/.*/.test(pic.type))){ |  | ||||||
|       this.props.setError(this.props.index, 'picture'); |  | ||||||
|       this.setState({ error: true }); |  | ||||||
|       this.props.deleteProperty(this.props.index, 'url'); |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|       this.props.deleteError(this.props.index, 'picture'); |  | ||||||
|       this.setState({ error: false }); |  | ||||||
|       this.props.changeContent(this.props.index, 'url', URL.createObjectURL(pic)); |  | ||||||
|     } |  | ||||||
|     this.props.changeContent(this.props.index, 'picture', pic.name); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   render() { |  | ||||||
|     return ( |  | ||||||
|       <div style={{marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)'}}> |  | ||||||
|         <FormControlLabel |  | ||||||
|           labelPlacement="end" |  | ||||||
|           label={"Bild"} |  | ||||||
|           control={ |  | ||||||
|             <Switch |  | ||||||
|               checked={this.state.checked} |  | ||||||
|               onChange={(e) => this.onChange(e.target.checked)} |  | ||||||
|               color="primary" |  | ||||||
|             /> |  | ||||||
|           } |  | ||||||
|         /> |  | ||||||
|         {this.state.checked ? |  | ||||||
|           <div> |  | ||||||
|             {!this.props.error ? |  | ||||||
|               <div> |  | ||||||
|                 <FormHelperText style={{lineHeight: 'initial', marginBottom: '10px'}}>{`Beachte, dass das Foto zusätzlich in den Ordner public/media/tutorial unter dem Namen '${this.props.value}' abgespeichert werden muss.`}</FormHelperText> |  | ||||||
|                 <img src={this.props.url ? this.props.url : `/media/tutorial/${this.props.value}`} alt={this.props.url ? '' : `Das Bild '${this.props.value}' konnte nicht im Ordner public/media/tutorial gefunden werden und kann daher nicht angezeigt werden.`} style={{maxHeight: '180px', maxWidth: '360px', marginBottom: '5px'}}/> |  | ||||||
|               </div> |  | ||||||
|             : <div |  | ||||||
|                 style={{height: '150px', maxWidth: '250px', marginBottom: '5px', justifyContent: "center", alignItems: "center", display:"flex", padding: '20px'}} |  | ||||||
|                 className={this.props.error ? this.props.classes.errorBorder : null} > |  | ||||||
|                 {this.props.error ? |  | ||||||
|                   this.state.error ? |  | ||||||
|                     <FormHelperText style={{lineHeight: 'initial', textAlign: 'center'}} className={this.props.classes.errorColor}>{`Die übergebene Datei entspricht nicht dem geforderten Bild-Format. Überprüfe, ob es sich um ein Bild handelt und versuche es nochmal.`}</FormHelperText> |  | ||||||
|                   : <FormHelperText style={{lineHeight: 'initial', textAlign: 'center'}} className={this.props.classes.errorColor}>{`Wähle ein Bild aus.`}</FormHelperText> |  | ||||||
|                 : null} |  | ||||||
|               </div>} |  | ||||||
|             {/*upload picture*/} |  | ||||||
|             <div ref={this.inputRef}> |  | ||||||
|               <input |  | ||||||
|                 style={{display: 'none'}} |  | ||||||
|                 accept="image/*" |  | ||||||
|                 onChange={(e) => {this.uploadPicture(e.target.files[0])}} |  | ||||||
|                 id="picture" |  | ||||||
|                 type="file" |  | ||||||
|               /> |  | ||||||
|               <label htmlFor="picture"> |  | ||||||
|                 <Button component="span" className={this.props.error ? this.props.classes.errorButton : null} style={{marginRight: '10px', marginBottom: '10px'}} variant='contained' color='primary'>Bild auswählen</Button> |  | ||||||
|               </label> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|         : null} |  | ||||||
|       </div> |  | ||||||
|     ); |  | ||||||
|   }; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Picture.propTypes = { |  | ||||||
|   changeContent: PropTypes.func.isRequired, |  | ||||||
|   deleteProperty: PropTypes.func.isRequired, |  | ||||||
|   setError: PropTypes.func.isRequired, |  | ||||||
|   deleteError: PropTypes.func.isRequired, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| export default connect(null, { changeContent, deleteProperty, setError, deleteError })(withStyles(styles, {withTheme: true})(Picture)); |  | ||||||
| @ -23,7 +23,7 @@ class Requirements extends Component { | |||||||
|     else { |     else { | ||||||
|       requirements = requirements.filter(requirement => requirement !== value); |       requirements = requirements.filter(requirement => requirement !== value); | ||||||
|     } |     } | ||||||
|     this.props.changeContent(this.props.index, 'requirements', requirements); |     this.props.changeContent(requirements, this.props.index, 'requirements'); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   render() { |   render() { | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ import StepType from './StepType'; | |||||||
| import BlocklyExample from './BlocklyExample'; | import BlocklyExample from './BlocklyExample'; | ||||||
| import Requirements from './Requirements'; | import Requirements from './Requirements'; | ||||||
| import Hardware from './Hardware'; | import Hardware from './Hardware'; | ||||||
| import Picture from './Picture'; | import Media from './Media'; | ||||||
| 
 | 
 | ||||||
| import { withStyles } from '@material-ui/core/styles'; | import { withStyles } from '@material-ui/core/styles'; | ||||||
| import Typography from '@material-ui/core/Typography'; | import Typography from '@material-ui/core/Typography'; | ||||||
| @ -105,7 +105,7 @@ class Step extends Component { | |||||||
|               </div> |               </div> | ||||||
|             : null} |             : null} | ||||||
|             {this.props.step.type === 'instruction' ? |             {this.props.step.type === 'instruction' ? | ||||||
|               <Picture value={this.props.step.picture} url={this.props.step.url} index={index} error={this.props.error.steps[index].picture} /> |               <Media value={this.props.step.media} picture={this.props.step.media && this.props.step.media.picture} youtube={this.props.step.media && this.props.step.media.youtube} url={this.props.step.url} index={index} error={this.props.error.steps[index].media} /> | ||||||
|             : null} |             : null} | ||||||
|             <BlocklyExample value={this.props.step.xml} index={index} task={this.props.step.type === 'task'} error={this.props.error.steps[index].xml ? true : false}/> |             <BlocklyExample value={this.props.step.xml} index={index} task={this.props.step.type === 'task'} error={this.props.error.steps[index].xml ? true : false}/> | ||||||
|           </div> |           </div> | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ import FormControlLabel from '@material-ui/core/FormControlLabel'; | |||||||
| class StepType extends Component { | class StepType extends Component { | ||||||
| 
 | 
 | ||||||
|   onChange = (value) => { |   onChange = (value) => { | ||||||
|     this.props.changeContent(this.props.index, 'type', value); |     this.props.changeContent(value, this.props.index, 'type'); | ||||||
|     // delete property 'xml', so that all used blocks are reset
 |     // delete property 'xml', so that all used blocks are reset
 | ||||||
|     this.props.deleteProperty(this.props.index, 'xml'); |     this.props.deleteProperty(this.props.index, 'xml'); | ||||||
|     if(value === 'task'){ |     if(value === 'task'){ | ||||||
|  | |||||||
| @ -28,9 +28,11 @@ class Textfield extends Component { | |||||||
| 
 | 
 | ||||||
|   componentDidMount(){ |   componentDidMount(){ | ||||||
|     if(this.props.error){ |     if(this.props.error){ | ||||||
|  |       if(this.props.property !== 'media'){ | ||||||
|         this.props.deleteError(this.props.index, this.props.property); |         this.props.deleteError(this.props.index, this.props.property); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   handleChange = (e) => { |   handleChange = (e) => { | ||||||
|     var value = e.target.value; |     var value = e.target.value; | ||||||
| @ -41,7 +43,7 @@ class Textfield extends Component { | |||||||
|       this.props.jsonString(value); |       this.props.jsonString(value); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       this.props.changeContent(this.props.index, this.props.property, value); |       this.props.changeContent(value, this.props.index, this.props.property, this.props.property2); | ||||||
|     } |     } | ||||||
|     if(value.replace(/\s/g,'') === ''){ |     if(value.replace(/\s/g,'') === ''){ | ||||||
|       this.props.setError(this.props.index, this.props.property); |       this.props.setError(this.props.index, this.props.property); | ||||||
|  | |||||||
| @ -57,6 +57,9 @@ | |||||||
|                 "type": "instruction", |                 "type": "instruction", | ||||||
|                 "headline": "Programmierung", |                 "headline": "Programmierung", | ||||||
|                 "text": "Man benötigt folgenden Block:", |                 "text": "Man benötigt folgenden Block:", | ||||||
|  |                 "media": { | ||||||
|  |                   "picture": "block_en.svg" | ||||||
|  |                 }, | ||||||
|                 "xml": "<xml xmlns='https://developers.google.com/blockly/xml'><block type='sensebox_wifi' id='-!X.Ay]z1ACt!f5+Vfr8'><field name='SSID'>SSID</field><field name='Password'>Password</field></block></xml>" |                 "xml": "<xml xmlns='https://developers.google.com/blockly/xml'><block type='sensebox_wifi' id='-!X.Ay]z1ACt!f5+Vfr8'><field name='SSID'>SSID</field><field name='Password'>Password</field></block></xml>" | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
| @ -64,7 +67,9 @@ | |||||||
|                 "type": "instruction", |                 "type": "instruction", | ||||||
|                 "headline": "Block richtig einbinden", |                 "headline": "Block richtig einbinden", | ||||||
|                 "text": "Dies ist ein Test.", |                 "text": "Dies ist ein Test.", | ||||||
|                 "picture": "block_en.svg" |                 "media": { | ||||||
|  |                   "youtube": "Q41MPMBCPto" | ||||||
|  |                 } | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 "id": 4, |                 "id": 4, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user