Merge pull request #19 from sensebox/feat/blockly-gallery
add blockly project gallery
This commit is contained in:
commit
b07d753e6c
1
.env
1
.env
@ -1,2 +1,3 @@
|
|||||||
REACT_APP_COMPILER_URL=https://compiler.sensebox.de
|
REACT_APP_COMPILER_URL=https://compiler.sensebox.de
|
||||||
REACT_APP_BOARD=sensebox-mcu
|
REACT_APP_BOARD=sensebox-mcu
|
||||||
|
REACT_APP_BLOCKLY_API=https://api.blockly.sensebox.de
|
||||||
|
32
package-lock.json
generated
32
package-lock.json
generated
@ -8720,6 +8720,11 @@
|
|||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mnemonic-id": {
|
||||||
|
"version": "3.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/mnemonic-id/-/mnemonic-id-3.2.7.tgz",
|
||||||
|
"integrity": "sha512-kysx9gAGbvrzuFYxKkcRjnsg/NK61ovJOV4F1cHTRl9T5leg+bo6WI0pWIvOFh1Z/yDL0cjA5R3EEGPPLDv/XA=="
|
||||||
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.29.0",
|
"version": "2.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz",
|
||||||
@ -11394,6 +11399,13 @@
|
|||||||
"tough-cookie": "~2.5.0",
|
"tough-cookie": "~2.5.0",
|
||||||
"tunnel-agent": "^0.6.0",
|
"tunnel-agent": "^0.6.0",
|
||||||
"uuid": "^3.3.2"
|
"uuid": "^3.3.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"request-promise-core": {
|
"request-promise-core": {
|
||||||
@ -12125,6 +12137,13 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"faye-websocket": "^0.10.0",
|
"faye-websocket": "^0.10.0",
|
||||||
"uuid": "^3.0.1"
|
"uuid": "^3.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sockjs-client": {
|
"sockjs-client": {
|
||||||
@ -13269,9 +13288,9 @@
|
|||||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||||
},
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "3.4.0",
|
"version": "8.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
|
||||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
"integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg=="
|
||||||
},
|
},
|
||||||
"v8-compile-cache": {
|
"v8-compile-cache": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
@ -13929,6 +13948,13 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"ansi-colors": "^3.0.0",
|
"ansi-colors": "^3.0.0",
|
||||||
"uuid": "^3.3.2"
|
"uuid": "^3.3.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"webpack-manifest-plugin": {
|
"webpack-manifest-plugin": {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
"@testing-library/user-event": "^7.2.1",
|
"@testing-library/user-event": "^7.2.1",
|
||||||
"blockly": "^3.20200924.0",
|
"blockly": "^3.20200924.0",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.2",
|
||||||
|
"mnemonic-id": "^3.2.7",
|
||||||
"moment": "^2.28.0",
|
"moment": "^2.28.0",
|
||||||
"prismjs": "^1.20.0",
|
"prismjs": "^1.20.0",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
@ -23,7 +24,8 @@
|
|||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "3.4.1",
|
"react-scripts": "3.4.1",
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.0.5",
|
||||||
"redux-thunk": "^2.3.0"
|
"redux-thunk": "^2.3.0",
|
||||||
|
"uuid": "^8.3.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
@ -24,22 +24,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Blockly from 'blockly/core';
|
import Blockly from 'blockly/core';
|
||||||
import locale from 'blockly/msg/en';
|
|
||||||
import 'blockly/blocks';
|
import 'blockly/blocks';
|
||||||
import Toolbox from './toolbox/Toolbox';
|
import Toolbox from './toolbox/Toolbox';
|
||||||
|
|
||||||
import { Card } from '@material-ui/core';
|
import { Card } from '@material-ui/core';
|
||||||
|
|
||||||
|
|
||||||
Blockly.setLocale(locale);
|
|
||||||
|
|
||||||
class BlocklyComponent extends React.Component {
|
class BlocklyComponent extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.blocklyDiv = React.createRef();
|
this.blocklyDiv = React.createRef();
|
||||||
this.toolbox = React.createRef();
|
this.toolbox = React.createRef();
|
||||||
this.state = {workspace: undefined};
|
this.state = { workspace: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -51,7 +49,7 @@ class BlocklyComponent extends React.Component {
|
|||||||
...rest
|
...rest
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.setState({workspace: this.primaryWorkspace})
|
this.setState({ workspace: this.primaryWorkspace })
|
||||||
|
|
||||||
if (initialXml) {
|
if (initialXml) {
|
||||||
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(initialXml), this.primaryWorkspace);
|
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(initialXml), this.primaryWorkspace);
|
||||||
@ -68,7 +66,7 @@ class BlocklyComponent extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
<Card ref={this.blocklyDiv} id="blocklyDiv" style={this.props.style ? this.props.style : {}}/>
|
<Card ref={this.blocklyDiv} id="blocklyDiv" style={this.props.style ? this.props.style : {}} />
|
||||||
<Toolbox toolbox={this.toolbox} workspace={this.state.workspace} />
|
<Toolbox toolbox={this.toolbox} workspace={this.state.workspace} />
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ 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 { onChangeWorkspace, clearStats } from '../../actions/workspaceActions';
|
import { onChangeWorkspace, clearStats } from '../../actions/workspaceActions';
|
||||||
// import * as De from 'blockly/msg/de';
|
import { De } from './msg/de';
|
||||||
import {De} from './msg/de';
|
import { En } from './msg/en';
|
||||||
import BlocklyComponent from './BlocklyComponent';
|
import BlocklyComponent from './BlocklyComponent';
|
||||||
import BlocklySvg from './BlocklySvg';
|
import BlocklySvg from './BlocklySvg';
|
||||||
import * as Blockly from 'blockly/core';
|
import * as Blockly from 'blockly/core';
|
||||||
@ -18,10 +18,26 @@ class BlocklyWindow extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.simpleWorkspace = React.createRef();
|
this.simpleWorkspace = React.createRef();
|
||||||
Blockly.setLocale(De);
|
var locale = window.localStorage.getItem('locale');
|
||||||
|
this.state = {
|
||||||
|
renderer: window.localStorage.getItem('renderer'),
|
||||||
|
};
|
||||||
|
if (locale === null) {
|
||||||
|
if (navigator.language === 'de-DE') {
|
||||||
|
locale = 'de';
|
||||||
|
} else {
|
||||||
|
locale = 'en';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (locale === 'de') {
|
||||||
|
Blockly.setLocale(De);
|
||||||
|
} else if (locale === 'en') {
|
||||||
|
Blockly.setLocale(En);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
|
||||||
const workspace = Blockly.getMainWorkspace();
|
const workspace = Blockly.getMainWorkspace();
|
||||||
this.props.onChangeWorkspace({});
|
this.props.onChangeWorkspace({});
|
||||||
this.props.clearStats();
|
this.props.clearStats();
|
||||||
@ -56,7 +72,7 @@ class BlocklyWindow extends Component {
|
|||||||
style={this.props.svg ? { height: 0 } : this.props.blocklyCSS}
|
style={this.props.svg ? { height: 0 } : this.props.blocklyCSS}
|
||||||
readOnly={this.props.readOnly !== undefined ? this.props.readOnly : false}
|
readOnly={this.props.readOnly !== undefined ? this.props.readOnly : false}
|
||||||
trashcan={this.props.trashcan !== undefined ? this.props.trashcan : true}
|
trashcan={this.props.trashcan !== undefined ? this.props.trashcan : true}
|
||||||
renderer='geras'
|
renderer={this.state.renderer}
|
||||||
zoom={{ // https://developers.google.com/blockly/guides/configure/web/zoom
|
zoom={{ // https://developers.google.com/blockly/guides/configure/web/zoom
|
||||||
controls: this.props.zoomControls !== undefined ? this.props.zoomControls : true,
|
controls: this.props.zoomControls !== undefined ? this.props.zoomControls : true,
|
||||||
wheel: false,
|
wheel: false,
|
||||||
|
@ -17,5 +17,6 @@ import './map';
|
|||||||
import './procedures';
|
import './procedures';
|
||||||
import './time';
|
import './time';
|
||||||
import './variables';
|
import './variables';
|
||||||
|
import './lists';
|
||||||
|
|
||||||
import '../helpers/types'
|
import '../helpers/types'
|
60
src/components/Blockly/blocks/lists.js
Normal file
60
src/components/Blockly/blocks/lists.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import Blockly, { FieldDropdown } from 'blockly/core';
|
||||||
|
import { selectedBoard } from '../helpers/board'
|
||||||
|
import * as Types from '../helpers/types'
|
||||||
|
import { getColour } from '../helpers/colour';
|
||||||
|
|
||||||
|
Blockly.Blocks['lists_create_empty'] = {
|
||||||
|
/**
|
||||||
|
* Elapsed time in milliseconds block definition
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
init: function () {
|
||||||
|
this.setHelpUrl('http://arduino.cc/en/Reference/Millis');
|
||||||
|
this.setColour(getColour().arrays);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField("create List with")
|
||||||
|
this.appendValueInput('NUMBER');
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField("Items of Type")
|
||||||
|
.appendField(new FieldDropdown(Types.VARIABLE_TYPES), 'type');
|
||||||
|
this.setOutput(true, Types.ARRAY.typeId);
|
||||||
|
this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['array_getIndex'] = {
|
||||||
|
/**
|
||||||
|
* Elapsed time in milliseconds block definition
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
init: function () {
|
||||||
|
this.setHelpUrl('http://arduino.cc/en/Reference/Millis');
|
||||||
|
this.setColour(getColour().arrays);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(new Blockly.FieldVariable(
|
||||||
|
'X',
|
||||||
|
null,
|
||||||
|
['Array'],
|
||||||
|
'Array'
|
||||||
|
), 'FIELDNAME');
|
||||||
|
this.setOutput(true, Types.ARRAY.typeId);
|
||||||
|
this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['lists_length'] = {
|
||||||
|
/**
|
||||||
|
* Elapsed time in milliseconds block definition
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
init: function () {
|
||||||
|
this.setHelpUrl('http://arduino.cc/en/Reference/Millis');
|
||||||
|
this.setColour(getColour().arrays);
|
||||||
|
this.appendValueInput('ARRAY')
|
||||||
|
.appendField('length of')
|
||||||
|
.setCheck(Types.ARRAY.compatibleTypes);
|
||||||
|
this.setOutput(true, Types.NUMBER.typeName);
|
||||||
|
this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP);
|
||||||
|
},
|
||||||
|
};
|
@ -81,6 +81,54 @@ Blockly.Blocks['sensebox_display_printDisplay'] = {
|
|||||||
LOOP_TYPES: ['sensebox_display_show'],
|
LOOP_TYPES: ['sensebox_display_show'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_display_fastPrint'] = {
|
||||||
|
init: function (block) {
|
||||||
|
this.setColour(getColour().sensebox);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_display_fastPrint_show);
|
||||||
|
this.appendValueInput("Title1", 'Title1')
|
||||||
|
.appendField(Blockly.Msg.senseBox_display_fastPrint_title);
|
||||||
|
this.appendValueInput("Value1", 'Value1')
|
||||||
|
.appendField(Blockly.Msg.senseBox_display_fastPrint_value);
|
||||||
|
this.appendValueInput("Dimension1", 'Dimension1')
|
||||||
|
.appendField(Blockly.Msg.senseBox_display_fastPrint_dimension);
|
||||||
|
this.appendValueInput("Title2", 'Title2')
|
||||||
|
.appendField(Blockly.Msg.senseBox_display_fastPrint_title);
|
||||||
|
this.appendValueInput("Value2", 'Value2')
|
||||||
|
.appendField(Blockly.Msg.senseBox_display_fastPrint_value);
|
||||||
|
this.appendValueInput("Dimension2", 'Dimension2')
|
||||||
|
.appendField(Blockly.Msg.senseBox_display_fastPrint_dimension);
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
this.setTooltip(Blockly.Msg.sensebox_display_fastPrint_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Called whenever anything on the workspace changes.
|
||||||
|
* Add warning if block is not nested inside a the correct loop.
|
||||||
|
* @param {!Blockly.Events.Abstract} e Change event.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
onchange: function (e) {
|
||||||
|
var legal = false;
|
||||||
|
// Is the block nested in a loop?
|
||||||
|
var block = this;
|
||||||
|
do {
|
||||||
|
if (this.LOOP_TYPES.indexOf(block.type) != -1) {
|
||||||
|
legal = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block = block.getSurroundParent();
|
||||||
|
} while (block);
|
||||||
|
if (legal) {
|
||||||
|
this.setWarningText(null);
|
||||||
|
} else {
|
||||||
|
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LOOP_TYPES: ['sensebox_display_show'],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Blockly.Blocks['sensebox_display_plotDisplay'] = {
|
Blockly.Blocks['sensebox_display_plotDisplay'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
|
@ -41,4 +41,33 @@ Blockly.Blocks['sensebox_rgb_led'] = {
|
|||||||
this.setTooltip(Blockly.Msg.senseBox_rgb_led_tip);
|
this.setTooltip(Blockly.Msg.senseBox_rgb_led_tip);
|
||||||
this.setHelpUrl('https://sensebox.de/books');
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_ws2818_led'] = {
|
||||||
|
init: function () {
|
||||||
|
|
||||||
|
var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, '1'],
|
||||||
|
[Blockly.Msg.senseBox_ultrasonic_port_B, '3'], [Blockly.Msg.senseBox_ultrasonic_port_C, '5']];
|
||||||
|
|
||||||
|
this.setColour(getColour().sensebox);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led)
|
||||||
|
.appendField("Pin:")
|
||||||
|
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
|
||||||
|
this.appendValueInput("BRIGHTNESS", "brightness")
|
||||||
|
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_brightness));
|
||||||
|
this.appendValueInput("POSITION", "position")
|
||||||
|
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_position));
|
||||||
|
this.appendValueInput("RED", 'Number')
|
||||||
|
.appendField(Blockly.Msg.COLOUR_RGB_RED);//Blockly.Msg.senseBox_basic_red
|
||||||
|
this.appendValueInput("GREEN", 'Number')
|
||||||
|
.appendField(Blockly.Msg.COLOUR_RGB_GREEN);//Blockly.Msg.senseBox_basic_green
|
||||||
|
this.appendValueInput("BLUE", 'Number')
|
||||||
|
.appendField(Blockly.Msg.COLOUR_RGB_BLUE);
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_rgb_led_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
}
|
||||||
};
|
};
|
@ -1,6 +1,7 @@
|
|||||||
import * as Blockly from 'blockly/core';
|
import * as Blockly from 'blockly/core';
|
||||||
import { getColour } from '../helpers/colour';
|
import { getColour } from '../helpers/colour';
|
||||||
|
|
||||||
|
var apiData = '[{"_id":"5e6073fe57703e001bb99453","createdAt":"2020-03-05T03:37:34.151Z","updatedAt":"2020-10-17T10:49:51.636Z","name":"Vtuzgorodok","currentLocation":{"timestamp":"2020-03-05T03:37:34.146Z","coordinates":[60.658676,56.833041,51],"type":"Point"},"exposure":"outdoor","sensors":[{"title":"PM10","unit":"µg/m³","sensorType":"SDS 011","icon":"osem-cloud","_id":"5e6073fe57703e001bb99458","lastMeasurement":{"value":"3.30","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"PM2.5","unit":"µg/m³","sensorType":"SDS 011","icon":"osem-cloud","_id":"5e6073fe57703e001bb99457","lastMeasurement":{"value":"0.90","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"Temperatur","unit":"°C","sensorType":"BME280","icon":"osem-thermometer","_id":"5e6073fe57703e001bb99456","lastMeasurement":{"value":"6.58","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"rel. Luftfeuchte","unit":"%","sensorType":"BME280","icon":"osem-humidity","_id":"5e6073fe57703e001bb99455","lastMeasurement":{"value":"53.76","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"Luftdruck","unit":"Pa","sensorType":"BME280","icon":"osem-barometer","_id":"5e6073fe57703e001bb99454","lastMeasurement":{"value":"96937.66","createdAt":"2020-10-17T10:49:51.627Z"}}],"model":"luftdaten_sds011_bme280","lastMeasurementAt":"2020-10-17T10:49:51.627Z","loc":[{"geometry":{"timestamp":"2020-03-05T03:37:34.146Z","coordinates":[60.658676,56.833041,51],"type":"Point"},"type":"Feature"}]}]';
|
||||||
|
|
||||||
Blockly.Blocks['sensebox_osem_connection'] = {
|
Blockly.Blocks['sensebox_osem_connection'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
@ -20,6 +21,10 @@ Blockly.Blocks['sensebox_osem_connection'] = {
|
|||||||
.setAlign(Blockly.ALIGN_LEFT)
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
.appendField("senseBox ID")
|
.appendField("senseBox ID")
|
||||||
.appendField(new Blockly.FieldTextInput("senseBox ID"), "BoxID");
|
.appendField(new Blockly.FieldTextInput("senseBox ID"), "BoxID");
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.senseBox_osem_access_token)
|
||||||
|
.appendField(new Blockly.FieldTextInput("access_token"), "access_token");
|
||||||
this.appendStatementInput('DO')
|
this.appendStatementInput('DO')
|
||||||
.appendField(Blockly.Msg.senseBox_sensor)
|
.appendField(Blockly.Msg.senseBox_sensor)
|
||||||
.setCheck(null);
|
.setCheck(null);
|
||||||
@ -27,9 +32,14 @@ Blockly.Blocks['sensebox_osem_connection'] = {
|
|||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
},
|
},
|
||||||
onchange: function (e) {
|
onchange: function (e) {
|
||||||
|
let boxID = this.getFieldValue('BoxID');
|
||||||
//Blockly.Blocks.sensebox.getDescendants = blocks;
|
if (boxID !== 'senseBox ID') {
|
||||||
|
fetch('https://api.opensensemap.org/boxes/ ' + boxID)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
apiData = data;
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mutationToDom: function () {
|
mutationToDom: function () {
|
||||||
var container = document.createElement('mutation');
|
var container = document.createElement('mutation');
|
||||||
@ -73,25 +83,47 @@ Blockly.Blocks['sensebox_osem_connection'] = {
|
|||||||
};
|
};
|
||||||
Blockly.Blocks['sensebox_send_to_osem'] = {
|
Blockly.Blocks['sensebox_send_to_osem'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
|
|
||||||
this.setTooltip(Blockly.Msg.senseBox_send_to_osem_tip);
|
this.setTooltip(Blockly.Msg.senseBox_send_to_osem_tip);
|
||||||
this.setHelpUrl('');
|
this.setHelpUrl('');
|
||||||
this.setColour(getColour().sensebox);
|
this.setColour(getColour().sensebox);
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(Blockly.Msg.senseBox_send_to_osem);
|
.appendField(Blockly.Msg.senseBox_send_to_osem);
|
||||||
this.appendValueInput('Value')
|
this.appendValueInput('Value')
|
||||||
.setCheck(null)
|
.appendField('Phänomen')
|
||||||
.appendField('Sensor ID')
|
.appendField(new Blockly.FieldDropdown(
|
||||||
.appendField(new Blockly.FieldTextInput('Sensor ID'), 'SensorID');
|
this.generateOptions), 'SensorID');
|
||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
generateOptions: function () {
|
||||||
|
var options = [['', '']];
|
||||||
|
if (apiData.sensors != undefined) {
|
||||||
|
for (var i = 0; i < apiData.sensors.length; i++) {
|
||||||
|
options.push([apiData.sensors[i].title, apiData.sensors[i]._id]);
|
||||||
|
}
|
||||||
|
console.log(options);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (options.length > 1) {
|
||||||
|
|
||||||
|
var dropdown = options.slice(1)
|
||||||
|
console.log(dropdown);
|
||||||
|
return dropdown;
|
||||||
|
} else
|
||||||
|
return options;
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Called whenever anything on the workspace changes.
|
* Called whenever anything on the workspace changes.
|
||||||
* Add warning if block is not nested inside a the correct loop.
|
* Add warning if block is not nested inside a the correct loop.
|
||||||
* @param {!Blockly.Events.Abstract} e Change event.
|
* @param {!Blockly.Events.Abstract} e Change event.
|
||||||
* @this Blockly.Block
|
* @this Blockly.Block
|
||||||
*/
|
*/
|
||||||
onchange: function (e) {
|
onchange: function () {
|
||||||
|
|
||||||
var legal = false;
|
var legal = false;
|
||||||
// Is the block nested in a loop?
|
// Is the block nested in a loop?
|
||||||
var block = this;
|
var block = this;
|
||||||
@ -108,5 +140,10 @@ Blockly.Blocks['sensebox_send_to_osem'] = {
|
|||||||
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
|
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
LOOP_TYPES: ['sensebox_osem_connection'],
|
/**
|
||||||
|
* List of block types that are loops and thus do not need warnings.
|
||||||
|
* To add a new loop type add this to your code:
|
||||||
|
* Blockly.Blocks['controls_flow_statements'].LOOP_TYPES.push('custom_loop');
|
||||||
|
*/
|
||||||
|
LOOP_TYPES: ['sensebox_osem_connection']
|
||||||
};
|
};
|
@ -17,5 +17,6 @@ import './audio';
|
|||||||
import './procedures';
|
import './procedures';
|
||||||
import './time';
|
import './time';
|
||||||
import './variables';
|
import './variables';
|
||||||
|
import './lists';
|
||||||
|
|
||||||
|
|
||||||
|
19
src/components/Blockly/generator/lists.js
Normal file
19
src/components/Blockly/generator/lists.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import * as Blockly from 'blockly/core';
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Arduino['lists_create_empty'] = function () {
|
||||||
|
var code = '';
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
}
|
||||||
|
|
||||||
|
Blockly.Arduino['array_getIndex'] = function () {
|
||||||
|
var code = '';
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Arduino['lists_length'] = function () {
|
||||||
|
var array = Blockly.Arduino.valueToCode(this, 'ARRAY', Blockly.Arduino.ORDER_ATOMIC);
|
||||||
|
var code = `${array}.length`;
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
}
|
@ -31,6 +31,42 @@ Blockly.Arduino.sensebox_display_printDisplay = function () {
|
|||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_display_fastPrint = function () {
|
||||||
|
var title1 = Blockly.Arduino.valueToCode(this, 'Title1', Blockly.Arduino.ORDER_ATOMIC) || '0'
|
||||||
|
var value1 = Blockly.Arduino.valueToCode(this, 'Value1', Blockly.Arduino.ORDER_ATOMIC);
|
||||||
|
var dimension1 = Blockly.Arduino.valueToCode(this, 'Dimension1', Blockly.Arduino.ORDER_ATOMIC) || '0'
|
||||||
|
var title2 = Blockly.Arduino.valueToCode(this, 'Title2', Blockly.Arduino.ORDER_ATOMIC) || '0'
|
||||||
|
var value2 = Blockly.Arduino.valueToCode(this, 'Value2', Blockly.Arduino.ORDER_ATOMIC);
|
||||||
|
var dimension2 = Blockly.Arduino.valueToCode(this, 'Dimension2', Blockly.Arduino.ORDER_ATOMIC) || '0'
|
||||||
|
Blockly.Arduino.codeFunctions_['sensebox_fastPrint'] = `
|
||||||
|
void printOnDisplay(String title1, String measurement1, String unit1, String title2, String measurement2, String unit2) {
|
||||||
|
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setTextColor(WHITE, BLACK);
|
||||||
|
display.println(title1);
|
||||||
|
display.setCursor(0, 10);
|
||||||
|
display.setTextSize(2);
|
||||||
|
display.print(measurement1);
|
||||||
|
display.print(" ");
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.println(unit1);
|
||||||
|
display.setCursor(0, 30);
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.println(title2);
|
||||||
|
display.setCursor(0, 40);
|
||||||
|
display.setTextSize(2);
|
||||||
|
display.print(measurement2);
|
||||||
|
display.print(" ");
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.println(unit2);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
var code = ` printOnDisplay(${title1}, String(${value1}), ${dimension1}, ${title2}, String(${value2}), ${dimension2});\n`;
|
||||||
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_display_show = function (block) {
|
Blockly.Arduino.sensebox_display_show = function (block) {
|
||||||
var show = Blockly.Arduino.statementToCode(block, 'SHOW');
|
var show = Blockly.Arduino.statementToCode(block, 'SHOW');
|
||||||
var code = '';
|
var code = '';
|
||||||
|
@ -19,4 +19,28 @@ Blockly.Arduino.sensebox_rgb_led = function () {
|
|||||||
var code = 'rgb_led_' + dropdown_pin + '.setPixelColor(0,rgb_led_' + dropdown_pin + '.Color(' + red + ',' + green + ',' + blue + '));\n';
|
var code = 'rgb_led_' + dropdown_pin + '.setPixelColor(0,rgb_led_' + dropdown_pin + '.Color(' + red + ',' + green + ',' + blue + '));\n';
|
||||||
code += 'rgb_led_' + dropdown_pin + '.show();';
|
code += 'rgb_led_' + dropdown_pin + '.show();';
|
||||||
return code;
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_ws2818_led = function () {
|
||||||
|
var dropdown_pin = this.getFieldValue('Port');
|
||||||
|
var blocks = Blockly.mainWorkspace.getAllBlocks();
|
||||||
|
var count = 0;
|
||||||
|
for (var i = 0; i < blocks.length; i++) {
|
||||||
|
if (blocks[i].type === 'sensebox_ws2818_led' && blocks[i].getFieldValue('Port') === dropdown_pin) {
|
||||||
|
count++;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var numPixel = count;
|
||||||
|
var brightness = Blockly.Arduino.valueToCode(this, 'BRIGHTNESS', Blockly.Arduino.ORDER_ATOMIC) || '50'
|
||||||
|
var position = Blockly.Arduino.valueToCode(this, 'POSITION', Blockly.Arduino.ORDER_ATOMIC) || '0';
|
||||||
|
var red = Blockly.Arduino.valueToCode(this, 'RED', Blockly.Arduino.ORDER_ATOMIC) || '0'
|
||||||
|
var green = Blockly.Arduino.valueToCode(this, 'GREEN', Blockly.Arduino.ORDER_ATOMIC) || '0'
|
||||||
|
var blue = Blockly.Arduino.valueToCode(this, 'BLUE', Blockly.Arduino.ORDER_ATOMIC) || '0'
|
||||||
|
Blockly.Arduino.definitions_['define_rgb_led' + dropdown_pin] = `#include <Adafruit_NeoPixel.h>\n Adafruit_NeoPixel rgb_led_${dropdown_pin}= Adafruit_NeoPixel(${numPixel}, ${dropdown_pin},NEO_GRB + NEO_KHZ800);\n`;
|
||||||
|
Blockly.Arduino.setupCode_['setup_rgb_led' + dropdown_pin] = 'rgb_led_' + dropdown_pin + '.begin();\n';
|
||||||
|
Blockly.Arduino.setupCode_['setup_rgb_led_brightness' + dropdown_pin] = `rgb_led_${dropdown_pin}.setBrightness(${brightness});\n`;
|
||||||
|
var code = `rgb_led_${dropdown_pin}.setPixelColor(${position},rgb_led_${dropdown_pin}.Color(${red},${green},${blue}));\nrgb_led_${dropdown_pin}.show();\n`;
|
||||||
|
return code;
|
||||||
};
|
};
|
@ -18,17 +18,20 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) {
|
|||||||
var box_id = this.getFieldValue('BoxID');
|
var box_id = this.getFieldValue('BoxID');
|
||||||
var host = this.getFieldValue('host');
|
var host = this.getFieldValue('host');
|
||||||
var branch = Blockly.Arduino.statementToCode(Block, 'DO');
|
var branch = Blockly.Arduino.statementToCode(Block, 'DO');
|
||||||
//var blocks = Blockly.Block.getDescendants;
|
var access_token = this.getFieldValue('access_token');
|
||||||
|
var blocks = this.getDescendants();
|
||||||
var type = this.getFieldValue('type');
|
var type = this.getFieldValue('type');
|
||||||
var ssl = this.getFieldValue('SSL');
|
var ssl = this.getFieldValue('SSL');
|
||||||
var port = 0;
|
var port = 0;
|
||||||
var count = 0;
|
var count = 0;
|
||||||
// for (var i = 0; i < blocks.length; i++) {
|
if (blocks != undefined) {
|
||||||
// if (blocks[i].type === 'sensebox_send_to_osem') {
|
for (var i = 0; i < blocks.length; i++) {
|
||||||
// count++;
|
if (blocks[i].type === 'sensebox_send_to_osem') {
|
||||||
|
count++;
|
||||||
|
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
var num_sensors = count;
|
var num_sensors = count;
|
||||||
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
|
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
|
||||||
Blockly.Arduino.definitions_['num_sensors'] = 'static const uint8_t NUM_SENSORS = ' + num_sensors + ';'
|
Blockly.Arduino.definitions_['num_sensors'] = 'static const uint8_t NUM_SENSORS = ' + num_sensors + ';'
|
||||||
@ -84,7 +87,7 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) {
|
|||||||
if (connected == true) {
|
if (connected == true) {
|
||||||
// construct the HTTP POST request:
|
// construct the HTTP POST request:
|
||||||
sprintf_P(buffer,
|
sprintf_P(buffer,
|
||||||
PSTR("POST /boxes/%s/data HTTP/1.1\\nHost: %s\\nContent-Type: "
|
PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nHost: %s\\nContent-Type: "
|
||||||
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
|
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
|
||||||
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
|
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
|
||||||
// send the HTTP POST request:
|
// send the HTTP POST request:
|
||||||
@ -144,7 +147,7 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) {
|
|||||||
if (connected == true) {
|
if (connected == true) {
|
||||||
// construct the HTTP POST request:
|
// construct the HTTP POST request:
|
||||||
sprintf_P(buffer,
|
sprintf_P(buffer,
|
||||||
PSTR("POST /boxes/%s/data HTTP/1.1\\nHost: %s\\nContent-Type: "
|
PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nHost: %s\\nContent-Type: "
|
||||||
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
|
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
|
||||||
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
|
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
|
||||||
// send the HTTP POST request:
|
// send the HTTP POST request:
|
||||||
|
@ -14,9 +14,28 @@ const setVariableFunction = function (defaultValue) {
|
|||||||
|
|
||||||
const allVars = Blockly.getMainWorkspace().getVariableMap().getAllVariables();
|
const allVars = Blockly.getMainWorkspace().getVariableMap().getAllVariables();
|
||||||
const myVar = allVars.filter(v => v.name === variableName)[0]
|
const myVar = allVars.filter(v => v.name === variableName)[0]
|
||||||
|
var code = ''
|
||||||
|
|
||||||
Blockly.Arduino.variables_[myVar + myVar.type] = myVar.type + " " + myVar.name + ';\n';
|
switch (myVar.type) {
|
||||||
return variableName + ' = ' + (variableValue || defaultValue) + ';\n';
|
default:
|
||||||
|
Blockly.Arduino.variables_[myVar + myVar.type] = myVar.type + " " + myVar.name + ';\n';
|
||||||
|
code = variableName + ' = ' + (variableValue || defaultValue) + ';\n';
|
||||||
|
break;
|
||||||
|
case 'Array':
|
||||||
|
var arrayType;
|
||||||
|
var number;
|
||||||
|
|
||||||
|
if (this.getChildren().length > 0) {
|
||||||
|
if (this.getChildren()[0].type === 'lists_create_empty') {
|
||||||
|
|
||||||
|
arrayType = this.getChildren()[0].getFieldValue('type');
|
||||||
|
number = Blockly.Arduino.valueToCode(this.getChildren()[0], 'NUMBER', Blockly['Arduino'].ORDER_ATOMIC);
|
||||||
|
Blockly.Arduino.variables_[myVar + myVar.type] = `${arrayType} ${myVar.name} [${number}];\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return code;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -25,8 +44,8 @@ const getVariableFunction = function (block) {
|
|||||||
block.getFieldValue('VAR'),
|
block.getFieldValue('VAR'),
|
||||||
Blockly.Variables.NAME_TYPE
|
Blockly.Variables.NAME_TYPE
|
||||||
);
|
);
|
||||||
|
var code = variableName;
|
||||||
return [variableName, Blockly['Arduino'].ORDER_ATOMIC];
|
return [code, Blockly['Arduino'].ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
|
|
||||||
Blockly['Arduino']['variables_set_dynamic'] = setVariableFunction()
|
Blockly['Arduino']['variables_set_dynamic'] = setVariableFunction()
|
||||||
|
@ -10,6 +10,7 @@ const colours = {
|
|||||||
text: 160,
|
text: 160,
|
||||||
variables: 330,
|
variables: 330,
|
||||||
audio: 250,
|
audio: 250,
|
||||||
|
arrays: 33
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ export const DECIMAL = {
|
|||||||
/** Array/List of items. */
|
/** Array/List of items. */
|
||||||
export const ARRAY = {
|
export const ARRAY = {
|
||||||
typeId: 'Array',
|
typeId: 'Array',
|
||||||
typeName: 'array',
|
typeName: 'Array',
|
||||||
typeMsgName: 'ARD_TYPE_ARRAY',
|
typeMsgName: 'ARD_TYPE_ARRAY',
|
||||||
compatibleTypes: []
|
compatibleTypes: []
|
||||||
}
|
}
|
||||||
@ -87,6 +87,7 @@ export const CHILD_BLOCK_MISSING = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const compatibleTypes = {
|
const compatibleTypes = {
|
||||||
|
Array: ['Array'],
|
||||||
boolean: ['boolean'],
|
boolean: ['boolean'],
|
||||||
int: ['int'],
|
int: ['int'],
|
||||||
char: ['char'],
|
char: ['char'],
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
// import * as Blockly from 'blockly/core';
|
|
||||||
|
|
||||||
// https://developers.google.com/blockly/guides/configure/web/translations
|
|
||||||
|
|
||||||
const Blockly = {};
|
const Blockly = {};
|
||||||
Blockly.Msg = {};
|
Blockly.Msg = {};
|
||||||
|
|
||||||
@ -610,6 +606,7 @@ Blockly.Msg.senseBox_osem_connection = "Verbinde mit openSenseMap";
|
|||||||
Blockly.Msg.senseBox_osem_exposure = "Typ";
|
Blockly.Msg.senseBox_osem_exposure = "Typ";
|
||||||
Blockly.Msg.senseBox_osem_stationary = "Stationär";
|
Blockly.Msg.senseBox_osem_stationary = "Stationär";
|
||||||
Blockly.Msg.senseBox_osem_mobile = "Mobil";
|
Blockly.Msg.senseBox_osem_mobile = "Mobil";
|
||||||
|
Blockly.Msg.senseBox_osem_access_token = "API Schlüssel";
|
||||||
Blockly.Msg.senseBox_sds011 = "Feinstaubsensor";
|
Blockly.Msg.senseBox_sds011 = "Feinstaubsensor";
|
||||||
Blockly.Msg.senseBox_sds011_dimension = "in µg/m³ an";
|
Blockly.Msg.senseBox_sds011_dimension = "in µg/m³ an";
|
||||||
Blockly.Msg.senseBox_sds011_pm25 = "PM2.5";
|
Blockly.Msg.senseBox_sds011_pm25 = "PM2.5";
|
||||||
@ -650,7 +647,11 @@ Blockly.Msg.sensebox_display_fillCircle_radius = "Radius";
|
|||||||
Blockly.Msg.sensebox_display_drawRectangle = "Zeichne Rechteck";
|
Blockly.Msg.sensebox_display_drawRectangle = "Zeichne Rechteck";
|
||||||
Blockly.Msg.sensebox_display_drawRectangle_width = "Breite";
|
Blockly.Msg.sensebox_display_drawRectangle_width = "Breite";
|
||||||
Blockly.Msg.sensebox_display_drawRectangle_height = "Höhe";
|
Blockly.Msg.sensebox_display_drawRectangle_height = "Höhe";
|
||||||
Blockly.Msg.senseBox_display_filled = "Ausgefüllt"
|
Blockly.Msg.senseBox_display_filled = "Ausgefüllt";
|
||||||
|
Blockly.Msg.senseBox_display_fastPrint_show = "Zeige Messwerte";
|
||||||
|
Blockly.Msg.senseBox_display_fastPrint_title = "Titel";
|
||||||
|
Blockly.Msg.senseBox_display_fastPrint_value = "Messwert";
|
||||||
|
Blockly.Msg.senseBox_display_fastPrint_dimension = "Einheit";
|
||||||
// GPS
|
// GPS
|
||||||
Blockly.Msg.senseBox_gps_getValues = "GPS Modul";
|
Blockly.Msg.senseBox_gps_getValues = "GPS Modul";
|
||||||
Blockly.Msg.senseBox_gps_getValues_tip = "ruft das GPS Signal ab";
|
Blockly.Msg.senseBox_gps_getValues_tip = "ruft das GPS Signal ab";
|
||||||
@ -771,7 +772,11 @@ Blockly.Msg.senseBox_telegram_do = "Telegram mache"
|
|||||||
Blockly.Msg.senseBox_telegram_do_on_message = "bei Nachricht"
|
Blockly.Msg.senseBox_telegram_do_on_message = "bei Nachricht"
|
||||||
Blockly.Msg.senseBox_telegram_message = "Nachricht"
|
Blockly.Msg.senseBox_telegram_message = "Nachricht"
|
||||||
Blockly.Msg.senseBox_telegram_send = "Sende Nachricht"
|
Blockly.Msg.senseBox_telegram_send = "Sende Nachricht"
|
||||||
|
//SCD30 CO2 Sensor
|
||||||
Blockly.Msg.senseBox_scd30 = "CO2 Sensor (Sensirion SCD30)";
|
Blockly.Msg.senseBox_scd30 = "CO2 Sensor (Sensirion SCD30)";
|
||||||
|
//WS2818 RGB LED
|
||||||
|
Blockly.Msg.senseBox_ws2818_rgb_led = "senseBox WS2812 - RGB LED";
|
||||||
|
Blockly.Msg.senseBox_ws2818_rgb_led_position = "Position";
|
||||||
|
Blockly.Msg.senseBox_ws2818_rgb_led_brightness = "Helligkeit";
|
||||||
|
|
||||||
export const De = Blockly.Msg;
|
export const De = Blockly.Msg;
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
// import * as Blockly from 'blockly/core';
|
|
||||||
|
|
||||||
// https://developers.google.com/blockly/guides/configure/web/translations
|
|
||||||
|
|
||||||
const Blockly = {};
|
const Blockly = {};
|
||||||
Blockly.Msg = {};
|
Blockly.Msg = {};
|
||||||
|
|
||||||
@ -613,6 +609,11 @@ Blockly.Msg.senseBox_display_printDisplay_y = "y-coordinates";
|
|||||||
Blockly.Msg.senseBox_display_setSize = "set font size to";
|
Blockly.Msg.senseBox_display_setSize = "set font size to";
|
||||||
Blockly.Msg.senseBox_display_setSize_tip = "Change the font size. Set a Value between 1-10.";
|
Blockly.Msg.senseBox_display_setSize_tip = "Change the font size. Set a Value between 1-10.";
|
||||||
Blockly.Msg.senseBox_display_white = "White";
|
Blockly.Msg.senseBox_display_white = "White";
|
||||||
|
Blockly.Msg.senseBox_display_fastPrint_dimension = "Unit";
|
||||||
|
Blockly.Msg.senseBox_display_fastPrint_show = "Show Measurements";
|
||||||
|
Blockly.Msg.senseBox_display_fastPrint_tip = "Show two measurements with title and dimension on the display";
|
||||||
|
Blockly.Msg.senseBox_display_fastPrint_title = "Title";
|
||||||
|
Blockly.Msg.senseBox_display_fastPrint_value = "Measurement";
|
||||||
Blockly.Msg.senseBox_foto = "Light Dependent Resistor";
|
Blockly.Msg.senseBox_foto = "Light Dependent Resistor";
|
||||||
Blockly.Msg.senseBox_foto_tip = "simple light depending resistor, gives values between 0 and 1023";
|
Blockly.Msg.senseBox_foto_tip = "simple light depending resistor, gives values between 0 and 1023";
|
||||||
Blockly.Msg.senseBox_gas = "Gas (VOC)";
|
Blockly.Msg.senseBox_gas = "Gas (VOC)";
|
||||||
@ -676,6 +677,7 @@ Blockly.Msg.senseBox_osem_host = "opensensemap.org";
|
|||||||
Blockly.Msg.senseBox_osem_host_workshop = "workshop.opensensemap.org";
|
Blockly.Msg.senseBox_osem_host_workshop = "workshop.opensensemap.org";
|
||||||
Blockly.Msg.senseBox_osem_mobile = "Mobile";
|
Blockly.Msg.senseBox_osem_mobile = "Mobile";
|
||||||
Blockly.Msg.senseBox_osem_stationary = "Stationary";
|
Blockly.Msg.senseBox_osem_stationary = "Stationary";
|
||||||
|
Blockly.Msg.senseBox_osem_access_token = "API Key";
|
||||||
Blockly.Msg.senseBox_output_filename = "filename";
|
Blockly.Msg.senseBox_output_filename = "filename";
|
||||||
Blockly.Msg.senseBox_output_format = "format:";
|
Blockly.Msg.senseBox_output_format = "format:";
|
||||||
Blockly.Msg.senseBox_output_linebreak = "linebreak";
|
Blockly.Msg.senseBox_output_linebreak = "linebreak";
|
||||||
@ -753,7 +755,13 @@ Blockly.Msg.sensebox_display_show_tip = "Print on Display";
|
|||||||
Blockly.Msg.sensebox_sd_filename = "data";
|
Blockly.Msg.sensebox_sd_filename = "data";
|
||||||
Blockly.Msg.sensebox_soil_smt50 = "Soil Moisture and Temperature (SMT50)";
|
Blockly.Msg.sensebox_soil_smt50 = "Soil Moisture and Temperature (SMT50)";
|
||||||
Blockly.Msg.sensebox_web_readHTML_filename = "File:";
|
Blockly.Msg.sensebox_web_readHTML_filename = "File:";
|
||||||
|
//SCD30 CO2 Sensor
|
||||||
Blockly.Msg.senseBox_scd30 = "CO2 Sensor (Sensirion SCD30)";
|
Blockly.Msg.senseBox_scd30 = "CO2 Sensor (Sensirion SCD30)";
|
||||||
|
|
||||||
|
//WS2818 RGB LED
|
||||||
|
Blockly.Msg.senseBox_ws2818_rgb_led = "senseBox WS2812 - RGB LED";
|
||||||
|
Blockly.Msg.senseBox_ws2818_rgb_led_brightness = "Helligkeit";
|
||||||
|
Blockly.Msg.senseBox_ws2818_rgb_led_position = "Position";
|
||||||
|
|
||||||
|
|
||||||
export const En = Blockly.Msg;
|
export const En = Blockly.Msg;
|
||||||
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||||||
import { Block, Value, Field, Shadow, Category } from '../';
|
import { Block, Value, Field, Shadow, Category } from '../';
|
||||||
import { getColour } from '../helpers/colour'
|
import { getColour } from '../helpers/colour'
|
||||||
import '@blockly/block-plus-minus';
|
import '@blockly/block-plus-minus';
|
||||||
|
|
||||||
import { TypedVariableModal } from '@blockly/plugin-typed-variable-modal';
|
import { TypedVariableModal } from '@blockly/plugin-typed-variable-modal';
|
||||||
import * as Blockly from 'blockly/core';
|
import * as Blockly from 'blockly/core';
|
||||||
|
|
||||||
@ -14,12 +13,14 @@ class Toolbox extends React.Component {
|
|||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
this.props.workspace.registerToolboxCategoryCallback('CREATE_TYPED_VARIABLE', this.createFlyout);
|
this.props.workspace.registerToolboxCategoryCallback('CREATE_TYPED_VARIABLE', this.createFlyout);
|
||||||
|
|
||||||
const typedVarModal = new TypedVariableModal(this.props.workspace, 'callbackName', [['SHORT_NUMBER', 'char'], ['NUMBER', 'int'], ['DECIMAL', 'float'], ['TEXT', 'String'], ['CHARACTER', 'char'], ['BOOLEAN', 'boolean'], ['NULL', 'void'], ['UNDEF', 'undefined']]);
|
const typedVarModal = new TypedVariableModal(this.props.workspace, 'callbackName', [['SHORT_NUMBER', 'char'], ['NUMBER', 'int'], ['DECIMAL', 'float'], ['TEXT', 'String'], ['ARRAY', 'Array'], ['CHARACTER', 'char'], ['BOOLEAN', 'boolean'], ['NULL', 'void'], ['UNDEF', 'undefined']]);
|
||||||
typedVarModal.init();
|
typedVarModal.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
createFlyout(workspace) {
|
createFlyout(workspace) {
|
||||||
|
|
||||||
let xmlList = [];
|
let xmlList = [];
|
||||||
|
|
||||||
// Add your button and give it a callback name.
|
// Add your button and give it a callback name.
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
button.setAttribute('text', 'Create Typed Variable');
|
button.setAttribute('text', 'Create Typed Variable');
|
||||||
@ -61,6 +62,33 @@ class Toolbox extends React.Component {
|
|||||||
<Category name="LED" colour={getColour().sensebox}>
|
<Category name="LED" colour={getColour().sensebox}>
|
||||||
<Block type="sensebox_rgb_led" />
|
<Block type="sensebox_rgb_led" />
|
||||||
<Block type="sensebox_led" />
|
<Block type="sensebox_led" />
|
||||||
|
<Block type="sensebox_ws2818_led">
|
||||||
|
<Value name="POSITION">
|
||||||
|
<Block type="math_number">
|
||||||
|
<Field name="NUM">0</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="BRIGHTNESS">
|
||||||
|
<Block type="math_number">
|
||||||
|
<Field name="NUM">30</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="RED">
|
||||||
|
<Block type="math_number">
|
||||||
|
<Field name="NUM">0</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="GREEN">
|
||||||
|
<Block type="math_number">
|
||||||
|
<Field name="NUM">0</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="BLUE">
|
||||||
|
<Block type="math_number">
|
||||||
|
<Field name="NUM">0</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
</Block>
|
||||||
</Category>
|
</Category>
|
||||||
<Category name="Display" colour={getColour().sensebox}>
|
<Category name="Display" colour={getColour().sensebox}>
|
||||||
<Block type="sensebox_display_beginDisplay" />
|
<Block type="sensebox_display_beginDisplay" />
|
||||||
@ -83,6 +111,28 @@ class Toolbox extends React.Component {
|
|||||||
</Block>
|
</Block>
|
||||||
</Value>
|
</Value>
|
||||||
</Block>
|
</Block>
|
||||||
|
<Block type="sensebox_display_fastPrint">
|
||||||
|
<Value name="Title1">
|
||||||
|
<Block type="text">
|
||||||
|
<Field name="TEXT">Title</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="Dimension1">
|
||||||
|
<Block type="text">
|
||||||
|
<Field name="TEXT">Unit</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="Title2">
|
||||||
|
<Block type="text">
|
||||||
|
<Field name="TEXT">Title</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="Dimension2">
|
||||||
|
<Block type="text">
|
||||||
|
<Field name="TEXT">Unit</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
</Block >
|
||||||
<Block type="sensebox_display_plotDisplay">
|
<Block type="sensebox_display_plotDisplay">
|
||||||
<Value name="Title">
|
<Value name="Title">
|
||||||
<Block type="text">
|
<Block type="text">
|
||||||
@ -323,7 +373,12 @@ class Toolbox extends React.Component {
|
|||||||
</Block>
|
</Block>
|
||||||
<Block type="io_notone"></Block>
|
<Block type="io_notone"></Block>
|
||||||
</Category>
|
</Category>
|
||||||
<Category name="Variablen" colour={getColour().variables} custom="CREATE_TYPED_VARIABLE"></Category>;
|
<Category name="Variablen" colour={getColour().variables} custom="CREATE_TYPED_VARIABLE"></Category>
|
||||||
|
<Category name="Arrays" colour={getColour().arrays} >
|
||||||
|
<Block type="lists_create_empty" />
|
||||||
|
<Block type="array_getIndex" />
|
||||||
|
<Block type="lists_length" />
|
||||||
|
</Category>
|
||||||
<sep></sep>
|
<sep></sep>
|
||||||
<Category name="Eingang/Ausgang" colour={getColour().io}>
|
<Category name="Eingang/Ausgang" colour={getColour().io}>
|
||||||
<Block type="io_digitalwrite"></Block>
|
<Block type="io_digitalwrite"></Block>
|
||||||
|
122
src/components/Gallery/GalleryHome.js
Normal file
122
src/components/Gallery/GalleryHome.js
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import Breadcrumbs from '../Breadcrumbs';
|
||||||
|
|
||||||
|
// import gallery from './gallery.json';
|
||||||
|
// import tutorials from '../../data/tutorials.json';
|
||||||
|
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { fade } from '@material-ui/core/styles/colorManipulator';
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import Grid from '@material-ui/core/Grid';
|
||||||
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
import BlocklyWindow from '../Blockly/BlocklyWindow';
|
||||||
|
import Divider from '@material-ui/core/Divider';
|
||||||
|
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
outerDiv: {
|
||||||
|
position: 'absolute',
|
||||||
|
right: '-30px',
|
||||||
|
bottom: '-30px',
|
||||||
|
width: '160px',
|
||||||
|
height: '160px',
|
||||||
|
color: fade(theme.palette.secondary.main, 0.6)
|
||||||
|
},
|
||||||
|
outerDivError: {
|
||||||
|
stroke: fade(theme.palette.error.dark, 0.6),
|
||||||
|
color: fade(theme.palette.error.dark, 0.6)
|
||||||
|
},
|
||||||
|
outerDivSuccess: {
|
||||||
|
stroke: fade(theme.palette.primary.main, 0.6),
|
||||||
|
color: fade(theme.palette.primary.main, 0.6)
|
||||||
|
},
|
||||||
|
outerDivOther: {
|
||||||
|
stroke: fade(theme.palette.secondary.main, 0.6)
|
||||||
|
},
|
||||||
|
innerDiv: {
|
||||||
|
width: 'inherit',
|
||||||
|
height: 'inherit',
|
||||||
|
display: 'table-cell',
|
||||||
|
verticalAlign: 'middle',
|
||||||
|
textAlign: 'center'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class GalleryHome extends Component {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
gallery: []
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
console.log(process.env.REACT_APP_BLOCKLY_API)
|
||||||
|
fetch(process.env.REACT_APP_BLOCKLY_API + this.props.location.pathname)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
this.setState({ gallery: data })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Breadcrumbs content={[{ link: '/gallery', title: 'Gallery' }]} />
|
||||||
|
|
||||||
|
<h1>Gallery</h1>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{this.state.gallery.map((gallery, i) => {
|
||||||
|
return (
|
||||||
|
<Grid item xs={12} sm={6} md={4} xl={3} key={i} style={{}}>
|
||||||
|
<Link to={`/gallery/${gallery.id}`} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||||
|
<Paper style={{ height: '400px', padding: '2rem', position: 'relative', overflow: 'hidden' }}>
|
||||||
|
<h3>{gallery.title}</h3>
|
||||||
|
<Divider />
|
||||||
|
<Grid container spacing={10} style={{ marginBottom: '5px' }}>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<BlocklyWindow
|
||||||
|
trashcan={false}
|
||||||
|
zoomControls={false}
|
||||||
|
|
||||||
|
blockDisabled
|
||||||
|
blocklyCSS={{ height: '18vH' }}
|
||||||
|
initialXml={gallery.xml}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<p>{gallery.text}</p>
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<div className={clsx(this.props.classes.outerDiv)} style={{ width: '160px', height: '160px', border: 0 }}>
|
||||||
|
</div>
|
||||||
|
</Paper>
|
||||||
|
</Link>
|
||||||
|
</Grid>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
GalleryHome.propTypes = {
|
||||||
|
status: PropTypes.array.isRequired,
|
||||||
|
change: PropTypes.number.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
change: state.tutorial.change,
|
||||||
|
status: state.tutorial.status
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(GalleryHome));
|
37
src/components/Gallery/gallery.json
Normal file
37
src/components/Gallery/gallery.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 15212,
|
||||||
|
"title": "Das senseBox Buch Kapitel 1",
|
||||||
|
"name": "Mario",
|
||||||
|
"text": "Die Blöcke findest du in der Kategorie \"Schleifen\". Die einfachste Schleife, die du Verwenden kannst, ist der Block \"Wiederhole 10 mal\". Bei diesem Block kannst du die Blöcke, die eine bestimmte Zahl wiederholt werden soll einfach in den offenen Block abschnitt ziehen. ",
|
||||||
|
"xml": "<xml xmlns=\"https://developers.google.com/blockly/xml\">\n <block type=\"controls_repeat_ext\" id=\"!|`dyF$`~*!l~D[TUc4N\" x=\"38\" y=\"32\">\n <value name=\"TIMES\">\n <block type=\"math_number\" id=\"ktgQ[7pD~M{sq;r^kLuz\">\n <field name=\"NUM\">10</field>\n </block>\n </value>\n </block>\n</xml>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 25451,
|
||||||
|
"title": "Das senseBox Buch Kapitel 2",
|
||||||
|
"name": "Mario",
|
||||||
|
"text": "",
|
||||||
|
"xml": "<xml xmlns=\"https://developers.google.com/blockly/xml\">\n <block type=\"arduino_functions\" id=\"5KebY,-ltvxB7K^El}1(\" x=\"30\" y=\"34\">\n <statement name=\"LOOP_FUNC\">\n <block type=\"sensebox_led\" id=\"Y(DUYI_.t1V!_9Qf7lgl\">\n <field name=\"PIN\">1</field>\n <field name=\"STAT\">HIGH</field>\n <next>\n <block type=\"time_delay\" id=\"C2.adlos#1/Ns)1@K!Or\">\n <value name=\"DELAY_TIME_MILI\">\n <block type=\"math_number\" id=\")uPzh6_L+SQaIr+v8B,\">\n <field name=\"NUM\">1000</field>\n </block>\n </value>\n <next>\n <block type=\"sensebox_led\" id=\"w215h=etDdQ(Aao86qG2\">\n <field name=\"PIN\">1</field>\n <field name=\"STAT\">LOW</field>\n <next>\n <block type=\"time_delay\" id=\"1pPNxT#ag6fFP|=fy(,%\">\n <value name=\"DELAY_TIME_MILI\">\n <block type=\"math_number\" id=\"%xCj(nr,]@f{ALe^{vH}\">\n <field name=\"NUM\">1000</field>\n </block>\n </value>\n </block>\n </next>\n </block>\n </next>\n </block>\n </next>\n </block>\n </statement>\n </block>\n</xml>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3541512,
|
||||||
|
"title": "Das senseBox Buch Kapitel 3",
|
||||||
|
"name": "Mario",
|
||||||
|
"text": "",
|
||||||
|
"xml": "<xml xmlns=\"http://www.w3.org/1999/xhtml\">\n <block type=\"arduino_functions\" id=\"5KebY,-ltvxB7K^El}1(\" x=\"30\" y=\"34\">\n <statement name=\"SETUP_FUNC\">\n <block type=\"sensebox_display_beginDisplay\" id=\")Z4]CI*ibRqWkqLr^pjb\"></block>\n </statement>\n <statement name=\"LOOP_FUNC\">\n <block type=\"sensebox_display_show\" id=\"r)I#b]xjcH,b@8g*,Pf^\">\n <statement name=\"SHOW\">\n <block type=\"sensebox_display_printDisplay\" id=\"o{6DR6H4f;Qj%n=@XgaW\">\n <field name=\"COLOR\">WHITE,BLACK</field>\n <value name=\"SIZE\">\n <block type=\"math_number\" id=\"u}2t2rIa6Wx2)42.Ij]}\">\n <field name=\"NUM\">1</field>\n </block>\n </value>\n <value name=\"X\">\n <block type=\"math_number\" id=\"6n/}z0xXtJLhHm0E9kF/\">\n <field name=\"NUM\">0</field>\n </block>\n </value>\n <value name=\"Y\">\n <block type=\"math_number\" id=\"Y-NwVU`0,j73ON)ODL^Y\">\n <field name=\"NUM\">0</field>\n </block>\n </value>\n <value name=\"printDisplay\">\n <block type=\"text_join\" id=\"t*`nvkah#B@JrGRge`u[\">\n <mutation items=\"2\"></mutation>\n <value name=\"ADD0\">\n <block type=\"text\" id=\"*n^fD@DZEq^eLPc|CvJ[\">\n <field name=\"TEXT\">Helligkeit:</field>\n </block>\n </value>\n <value name=\"ADD1\">\n <block type=\"sensebox_sensor_uv_light\" id=\"tT8cG:UHho:SUKZQLVG{\">\n <field name=\"NAME\">Illuminance</field>\n </block>\n </value>\n </block>\n </value>\n </block>\n </statement>\n </block>\n </statement>\n </block>\n</xml>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7487454,
|
||||||
|
"title": "Das senseBox Buch Kapitel 4",
|
||||||
|
"name": "Mario",
|
||||||
|
"text": "",
|
||||||
|
"xml": "<xml xmlns=\"http://www.w3.org/1999/xhtml\">\n <block type=\"arduino_functions\" id=\"5KebY,-ltvxB7K^El}1(\" x=\"30\" y=\"34\">\n <statement name=\"SETUP_FUNC\">\n <block type=\"sensebox_display_beginDisplay\" id=\")Z4]CI*ibRqWkqLr^pjb\"></block>\n </statement>\n <statement name=\"LOOP_FUNC\">\n <block type=\"sensebox_display_show\" id=\"r)I#b]xjcH,b@8g*,Pf^\">\n <statement name=\"SHOW\">\n <block type=\"sensebox_display_printDisplay\" id=\"o{6DR6H4f;Qj%n=@XgaW\">\n <field name=\"COLOR\">WHITE,BLACK</field>\n <value name=\"SIZE\">\n <block type=\"math_number\" id=\"u}2t2rIa6Wx2)42.Ij]}\">\n <field name=\"NUM\">1</field>\n </block>\n </value>\n <value name=\"X\">\n <block type=\"math_number\" id=\"6n/}z0xXtJLhHm0E9kF/\">\n <field name=\"NUM\">0</field>\n </block>\n </value>\n <value name=\"Y\">\n <block type=\"math_number\" id=\"Y-NwVU`0,j73ON)ODL^Y\">\n <field name=\"NUM\">0</field>\n </block>\n </value>\n <value name=\"printDisplay\">\n <block type=\"text_join\" id=\"t*`nvkah#B@JrGRge`u[\">\n <mutation items=\"2\"></mutation>\n <value name=\"ADD0\">\n <block type=\"text\" id=\"*n^fD@DZEq^eLPc|CvJ[\">\n <field name=\"TEXT\">Helligkeit:</field>\n </block>\n </value>\n <value name=\"ADD1\">\n <block type=\"sensebox_sensor_uv_light\" id=\"tT8cG:UHho:SUKZQLVG{\">\n <field name=\"NAME\">Illuminance</field>\n </block>\n </value>\n </block>\n </value>\n </block>\n </statement>\n </block>\n </statement>\n </block>\n</xml>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 54541251,
|
||||||
|
"title": "Das senseBox Buch Kapitel 5",
|
||||||
|
"name": "Mario",
|
||||||
|
"text": "",
|
||||||
|
"xml": ""
|
||||||
|
}
|
||||||
|
]
|
@ -10,6 +10,7 @@ import WorkspaceFunc from './WorkspaceFunc';
|
|||||||
import BlocklyWindow from './Blockly/BlocklyWindow';
|
import BlocklyWindow from './Blockly/BlocklyWindow';
|
||||||
import CodeViewer from './CodeViewer';
|
import CodeViewer from './CodeViewer';
|
||||||
import TrashcanButtons from './TrashcanButtons';
|
import TrashcanButtons from './TrashcanButtons';
|
||||||
|
import { createNameId } from 'mnemonic-id';
|
||||||
import HintTutorialExists from './Tutorial/HintTutorialExists';
|
import HintTutorialExists from './Tutorial/HintTutorialExists';
|
||||||
|
|
||||||
import Grid from '@material-ui/core/Grid';
|
import Grid from '@material-ui/core/Grid';
|
||||||
@ -45,14 +46,29 @@ const styles = (theme) => ({
|
|||||||
class Home extends Component {
|
class Home extends Component {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
codeOn: false
|
codeOn: false,
|
||||||
|
gallery: [],
|
||||||
|
share: [],
|
||||||
|
projectToLoad: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
|
||||||
|
this.props.workspaceName(createNameId());
|
||||||
|
fetch(process.env.REACT_APP_BLOCKLY_API + this.props.location.pathname)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
this.setState({ projectToLoad: data })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
/* Resize and reposition all of the workspace chrome (toolbox, trash,
|
/* Resize and reposition all of the workspace chrome (toolbox, trash,
|
||||||
scrollbars etc.) This should be called when something changes that requires
|
scrollbars etc.) This should be called when something changes that requires
|
||||||
recalculating dimensions and positions of the trash, zoom, toolbox, etc.
|
recalculating dimensions and positions of the trash, zoom, toolbox, etc.
|
||||||
(e.g. window resize). */
|
(e.g. window resize). */
|
||||||
|
|
||||||
const workspace = Blockly.getMainWorkspace();
|
const workspace = Blockly.getMainWorkspace();
|
||||||
Blockly.svgResize(workspace);
|
Blockly.svgResize(workspace);
|
||||||
}
|
}
|
||||||
@ -72,6 +88,13 @@ class Home extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
// console.log(this.props.match.params.galleryId);
|
||||||
|
// console.log(gallery);
|
||||||
|
// console.log(gallery.filter(project => project.id == this.props.match.params.galleryId));
|
||||||
|
if (this.state.projectToLoad) {
|
||||||
|
console.log(this.state.projectToLoad.xml)
|
||||||
|
}
|
||||||
|
console.log(this.props);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ float: 'right', height: '40px', marginBottom: '20px' }}><WorkspaceFunc /></div>
|
<div style={{ float: 'right', height: '40px', marginBottom: '20px' }}><WorkspaceFunc /></div>
|
||||||
@ -88,7 +111,10 @@ class Home extends Component {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<TrashcanButtons />
|
<TrashcanButtons />
|
||||||
<BlocklyWindow blocklyCSS={{ height: '80vH' }} blockDisabled />
|
{this.state.projectToLoad ?
|
||||||
|
< BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.state.projectToLoad.xml} /> : < BlocklyWindow blocklyCSS={{ height: '80vH' }} />
|
||||||
|
}
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
{this.state.codeOn ?
|
{this.state.codeOn ?
|
||||||
<Grid item xs={12} md={6}>
|
<Grid item xs={12} md={6}>
|
||||||
|
@ -45,32 +45,32 @@ class Navbar extends Component {
|
|||||||
this.setState({ open: !this.state.open });
|
this.setState({ open: !this.state.open });
|
||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<AppBar
|
<AppBar
|
||||||
position="relative"
|
position="relative"
|
||||||
style={{height: '50px', marginBottom: '30px'}}
|
style={{ height: '50px', marginBottom: '30px' }}
|
||||||
classes={{root: this.props.classes.appBarColor}}
|
classes={{ root: this.props.classes.appBarColor }}
|
||||||
>
|
>
|
||||||
<Toolbar style={{height: '50px', minHeight: '50px', padding: 0, color: 'white'}}>
|
<Toolbar style={{ height: '50px', minHeight: '50px', padding: 0, color: 'white' }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
color="inherit"
|
color="inherit"
|
||||||
onClick={this.toggleDrawer}
|
onClick={this.toggleDrawer}
|
||||||
style={{margin: '0 10px'}}
|
style={{ margin: '0 10px' }}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faBars} />
|
<FontAwesomeIcon icon={faBars} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Link to={"/"} style={{textDecoration: 'none', color: 'inherit'}}>
|
<Link to={"/"} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||||
<Typography variant="h6" noWrap>
|
<Typography variant="h6" noWrap>
|
||||||
senseBox Blockly
|
senseBox Blockly
|
||||||
</Typography>
|
</Typography>
|
||||||
</Link>
|
</Link>
|
||||||
<Link to={"/"} style={{marginLeft: '10px'}}>
|
<Link to={"/"} style={{ marginLeft: '10px' }}>
|
||||||
<img src={senseboxLogo} alt="senseBox-Logo" width="30"/>
|
<img src={senseboxLogo} alt="senseBox-Logo" width="30" />
|
||||||
</Link>
|
</Link>
|
||||||
{/^\/tutorial(\/.*$|$)/g.test(this.props.location.pathname) ?
|
{/^\/tutorial(\/.*$|$)/g.test(this.props.location.pathname) ?
|
||||||
<Link to={"/tutorial"} style={{textDecoration: 'none', color: 'inherit', marginLeft: '10px'}}>
|
<Link to={"/tutorial"} style={{ textDecoration: 'none', color: 'inherit', marginLeft: '10px' }}>
|
||||||
<Typography variant="h6" noWrap>
|
<Typography variant="h6" noWrap>
|
||||||
Tutorial
|
Tutorial
|
||||||
</Typography>
|
</Typography>
|
||||||
@ -82,34 +82,34 @@ class Navbar extends Component {
|
|||||||
anchor="left"
|
anchor="left"
|
||||||
onClose={this.toggleDrawer}
|
onClose={this.toggleDrawer}
|
||||||
open={this.state.open}
|
open={this.state.open}
|
||||||
classes={{paper: this.props.classes.drawerWidth}}
|
classes={{ paper: this.props.classes.drawerWidth }}
|
||||||
ModalProps={{keepMounted: true}} // Better open performance on mobile.
|
ModalProps={{ keepMounted: true }} // Better open performance on mobile.
|
||||||
>
|
>
|
||||||
<div style={{height: '50px', cursor: 'pointer', color: 'white', padding: '0 22px'}} className={this.props.classes.appBarColor} onClick={this.toggleDrawer}>
|
<div style={{ height: '50px', cursor: 'pointer', color: 'white', padding: '0 22px' }} className={this.props.classes.appBarColor} onClick={this.toggleDrawer}>
|
||||||
<div style={{display:' table-cell', verticalAlign: 'middle', height: 'inherit', width: '0.1%'}}>
|
<div style={{ display: ' table-cell', verticalAlign: 'middle', height: 'inherit', width: '0.1%' }}>
|
||||||
<Typography variant="h6" style={{display:'inline'}}>
|
<Typography variant="h6" style={{ display: 'inline' }}>
|
||||||
Menü
|
Menü
|
||||||
</Typography>
|
</Typography>
|
||||||
<div style={{float: 'right'}}>
|
<div style={{ float: 'right' }}>
|
||||||
<FontAwesomeIcon icon={faChevronLeft} />
|
<FontAwesomeIcon icon={faChevronLeft} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<List>
|
<List>
|
||||||
{[{text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial"}, {text: 'Tutorial-Builder', icon: faFolderPlus, link: "/tutorial/builder"}, {text: 'Einstellungen', icon: faCog, link: "/settings"}].map((item, index) => (
|
{[{ text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial" }, { text: 'Tutorial-Builder', icon: faFolderPlus, link: "/tutorial/builder" }, { text: 'Gallery', icon: faFolderPlus, link: "/gallery" }, { text: 'Einstellungen', icon: faCog, link: "/settings" }].map((item, index) => (
|
||||||
<Link to={item.link} key={index} style={{textDecoration: 'none', color: 'inherit'}}>
|
<Link to={item.link} key={index} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||||
<ListItem button onClick={this.toggleDrawer}>
|
<ListItem button onClick={this.toggleDrawer}>
|
||||||
<ListItemIcon><FontAwesomeIcon icon={item.icon}/></ListItemIcon>
|
<ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon>
|
||||||
<ListItemText primary={item.text} />
|
<ListItemText primary={item.text} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
<Divider classes={{root: this.props.classes.appBarColor}} style={{marginTop: 'auto'}}/>
|
<Divider classes={{ root: this.props.classes.appBarColor }} style={{ marginTop: 'auto' }} />
|
||||||
<List>
|
<List>
|
||||||
{[{text: 'Über uns', icon: faBuilding},{text: 'Kontakt', icon: faEnvelope}, {text: 'Impressum', icon: faIdCard}].map((item, index) => (
|
{[{ text: 'Über uns', icon: faBuilding }, { text: 'Kontakt', icon: faEnvelope }, { text: 'Impressum', icon: faIdCard }].map((item, index) => (
|
||||||
<ListItem button key={index} onClick={this.toggleDrawer}>
|
<ListItem button key={index} onClick={this.toggleDrawer}>
|
||||||
<ListItemIcon><FontAwesomeIcon icon={item.icon}/></ListItemIcon>
|
<ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon>
|
||||||
<ListItemText primary={item.text} />
|
<ListItemText primary={item.text} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
@ -120,4 +120,4 @@ class Navbar extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withStyles(styles, {withTheme: true})(withRouter(Navbar));
|
export default withStyles(styles, { withTheme: true })(withRouter(Navbar));
|
||||||
|
@ -10,10 +10,13 @@ import Tutorial from './Tutorial/Tutorial';
|
|||||||
import TutorialHome from './Tutorial/TutorialHome';
|
import TutorialHome from './Tutorial/TutorialHome';
|
||||||
import Builder from './Tutorial/Builder/Builder';
|
import Builder from './Tutorial/Builder/Builder';
|
||||||
import NotFound from './NotFound';
|
import NotFound from './NotFound';
|
||||||
|
import GalleryHome from './Gallery/GalleryHome';
|
||||||
|
import Settings from './Settings/Settings';
|
||||||
|
|
||||||
|
|
||||||
class Routes extends Component {
|
class Routes extends Component {
|
||||||
|
|
||||||
componentDidUpdate(){
|
componentDidUpdate() {
|
||||||
this.props.visitPage();
|
this.props.visitPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +26,11 @@ class Routes extends Component {
|
|||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/" exact component={Home} />
|
<Route path="/" exact component={Home} />
|
||||||
<Route path="/tutorial" exact component={TutorialHome} />
|
<Route path="/tutorial" exact component={TutorialHome} />
|
||||||
<Route path="/tutorial/builder" exact component={Builder}/>
|
<Route path="/settings" exact component={Settings} />
|
||||||
|
<Route path="/gallery" exact component={GalleryHome} />
|
||||||
|
<Route path="/gallery/:galleryId" exact component={Home} />
|
||||||
|
<Route path="/share/:shareId" exact component={Home} />
|
||||||
|
<Route path="/tutorial/builder" exact component={Builder} />
|
||||||
<Route path="/tutorial/:tutorialId" exact component={Tutorial} />
|
<Route path="/tutorial/:tutorialId" exact component={Tutorial} />
|
||||||
<Route component={NotFound} />
|
<Route component={NotFound} />
|
||||||
</Switch>
|
</Switch>
|
||||||
|
43
src/components/Settings/LanguageSelector.js
Normal file
43
src/components/Settings/LanguageSelector.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
|
import InputLabel from '@material-ui/core/InputLabel';
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
import Select from '@material-ui/core/Select';
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
formControl: {
|
||||||
|
margin: theme.spacing(1),
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
selectEmpty: {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function LanguageSelector() {
|
||||||
|
const classes = useStyles();
|
||||||
|
const [lang, setLang] = React.useState(window.localStorage.getItem('locale'));
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
setLang(event.target.value);
|
||||||
|
window.localStorage.setItem('locale', event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<FormControl className={classes.formControl}>
|
||||||
|
<InputLabel id="demo-simple-select-label">Sprache</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
value={lang}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
<MenuItem value={'de'}>Deutsch</MenuItem>
|
||||||
|
<MenuItem value={'en'}>English</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
45
src/components/Settings/RenderSelector.js
Normal file
45
src/components/Settings/RenderSelector.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
|
import InputLabel from '@material-ui/core/InputLabel';
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
import Select from '@material-ui/core/Select';
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
formControl: {
|
||||||
|
margin: theme.spacing(1),
|
||||||
|
minWidth: 400,
|
||||||
|
},
|
||||||
|
selectEmpty: {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function LanguageSelector() {
|
||||||
|
const classes = useStyles();
|
||||||
|
const [renderer, setRenderer] = React.useState(window.localStorage.getItem('renderer'));
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
setRenderer(event.target.value);
|
||||||
|
window.localStorage.setItem('renderer', event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<FormControl className={classes.formControl}>
|
||||||
|
<InputLabel id="demo-simple-select-label">Renderer</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
value={renderer}
|
||||||
|
onChange={handleChange}
|
||||||
|
|
||||||
|
>
|
||||||
|
<MenuItem value={'geras'}>Geras</MenuItem>
|
||||||
|
<MenuItem value={'zelos'}>Zelos</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
<p>Der Renderer bestimmt das aussehen der Blöcke</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
30
src/components/Settings/Settings.js
Normal file
30
src/components/Settings/Settings.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import LanguageSelector from './LanguageSelector';
|
||||||
|
import RenderSelector from './RenderSelector';
|
||||||
|
|
||||||
|
|
||||||
|
class Settings extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Typography variant='h4' style={{ marginBottom: '5px' }}>Einstellungen</Typography>
|
||||||
|
<LanguageSelector />
|
||||||
|
<RenderSelector />
|
||||||
|
<Button
|
||||||
|
style={{ marginTop: '20px' }}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => { this.props.history.push('/') }}
|
||||||
|
>
|
||||||
|
Zurück zur Startseite
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(Settings);
|
@ -12,7 +12,6 @@ import { initialXml } from './Blockly/initialXml.js';
|
|||||||
|
|
||||||
import Compile from './Compile';
|
import Compile from './Compile';
|
||||||
import SolutionCheck from './Tutorial/SolutionCheck';
|
import SolutionCheck from './Tutorial/SolutionCheck';
|
||||||
import Dialog from './Dialog';
|
|
||||||
import Snackbar from './Snackbar';
|
import Snackbar from './Snackbar';
|
||||||
|
|
||||||
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
|
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
|
||||||
@ -22,8 +21,19 @@ import IconButton from '@material-ui/core/IconButton';
|
|||||||
import Tooltip from '@material-ui/core/Tooltip';
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import TextField from '@material-ui/core/TextField';
|
import TextField from '@material-ui/core/TextField';
|
||||||
import Typography from '@material-ui/core/Typography';
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import { createId } from 'mnemonic-id';
|
||||||
|
|
||||||
import { faPen, faSave, faUpload, faCamera, faShare } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
|
import Dialog from './Dialog';
|
||||||
|
// import Dialog from '@material-ui/core/Dialog';
|
||||||
|
import DialogActions from '@material-ui/core/DialogActions';
|
||||||
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
|
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||||
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import { faPen, faSave, faUpload, faCamera, faShare, faShareAlt } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
@ -49,9 +59,10 @@ const styles = (theme) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WorkspaceFunc extends Component {
|
class WorkspaceFunc extends Component {
|
||||||
|
|
||||||
constructor(props){
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.inputRef = React.createRef();
|
this.inputRef = React.createRef();
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -60,21 +71,25 @@ class WorkspaceFunc extends Component {
|
|||||||
open: false,
|
open: false,
|
||||||
file: false,
|
file: false,
|
||||||
saveFile: false,
|
saveFile: false,
|
||||||
|
share: false,
|
||||||
name: props.name,
|
name: props.name,
|
||||||
snackbar: false,
|
snackbar: false,
|
||||||
key: '',
|
key: '',
|
||||||
message: ''
|
message: '',
|
||||||
|
id: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(props){
|
|
||||||
if(props.name !== this.props.name){
|
|
||||||
this.setState({name: this.props.name});
|
componentDidUpdate(props) {
|
||||||
|
if (props.name !== this.props.name) {
|
||||||
|
this.setState({ name: this.props.name });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleDialog = () => {
|
toggleDialog = () => {
|
||||||
this.setState({ open: !this.state });
|
this.setState({ open: !this.state, share: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
saveXmlFile = () => {
|
saveXmlFile = () => {
|
||||||
@ -87,6 +102,41 @@ class WorkspaceFunc extends Component {
|
|||||||
saveAs(blob, fileName);
|
saveAs(blob, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shareBlocks = () => {
|
||||||
|
let code = this.props.xml;
|
||||||
|
let requestOptions = '';
|
||||||
|
let id = '';
|
||||||
|
if (this.state.id !== '') {
|
||||||
|
requestOptions = {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: this.state.id,
|
||||||
|
name: this.state.name,
|
||||||
|
xml: code
|
||||||
|
})
|
||||||
|
};
|
||||||
|
fetch(process.env.REACT_APP_BLOCKLY_API + '/share' + this.state.id, requestOptions)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => this.setState({ share: true }));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
id = createId(10);
|
||||||
|
requestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: id,
|
||||||
|
name: this.state.name,
|
||||||
|
xml: code
|
||||||
|
})
|
||||||
|
};
|
||||||
|
fetch(process.env.REACT_APP_BLOCKLY_API + '/share', requestOptions)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => this.setState({ id: data.id, share: true }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getSvg = () => {
|
getSvg = () => {
|
||||||
const workspace = Blockly.getMainWorkspace();
|
const workspace = Blockly.getMainWorkspace();
|
||||||
var canvas = workspace.svgBlockCanvas_.cloneNode(true);
|
var canvas = workspace.svgBlockCanvas_.cloneNode(true);
|
||||||
@ -98,7 +148,7 @@ class WorkspaceFunc extends Component {
|
|||||||
// var cssContent = Blockly.Css.CONTENT.join('');
|
// var cssContent = Blockly.Css.CONTENT.join('');
|
||||||
var cssContent = '';
|
var cssContent = '';
|
||||||
for (var i = 0; i < document.getElementsByTagName('style').length; i++) {
|
for (var i = 0; i < document.getElementsByTagName('style').length; i++) {
|
||||||
if(/^blockly.*$/.test(document.getElementsByTagName('style')[i].id)){
|
if (/^blockly.*$/.test(document.getElementsByTagName('style')[i].id)) {
|
||||||
cssContent += document.getElementsByTagName('style')[i].firstChild.data.replace(/\..* \./g, '.');
|
cssContent += document.getElementsByTagName('style')[i].firstChild.data.replace(/\..* \./g, '.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,22 +181,22 @@ class WorkspaceFunc extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createFileName = (filetype) => {
|
createFileName = (filetype) => {
|
||||||
this.setState({file: filetype}, () => {
|
this.setState({ file: filetype }, () => {
|
||||||
if(this.state.name){
|
if (this.state.name) {
|
||||||
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'.` });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setFileName = (e) => {
|
setFileName = (e) => {
|
||||||
this.setState({name: e.target.value});
|
this.setState({ name: e.target.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadXmlFile = (xmlFile) => {
|
uploadXmlFile = (xmlFile) => {
|
||||||
if(xmlFile.type !== 'text/xml'){
|
if (xmlFile.type !== 'text/xml') {
|
||||||
this.setState({ open: true, file: false, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entsprach nicht dem geforderten Format. Es sind nur XML-Dateien zulässig.' });
|
this.setState({ open: true, file: false, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entsprach nicht dem geforderten Format. Es sind nur XML-Dateien zulässig.' });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -161,18 +211,18 @@ class WorkspaceFunc extends Component {
|
|||||||
workspace.clear();
|
workspace.clear();
|
||||||
this.props.clearStats();
|
this.props.clearStats();
|
||||||
Blockly.Xml.domToWorkspace(xmlDom, workspace);
|
Blockly.Xml.domToWorkspace(xmlDom, workspace);
|
||||||
if(workspace.getAllBlocks().length < 1){
|
if (workspace.getAllBlocks().length < 1) {
|
||||||
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xmlBefore), workspace)
|
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xmlBefore), workspace)
|
||||||
this.setState({ open: true, file: false, title: 'Keine Blöcke', content: 'Es wurden keine Blöcke detektiert. Bitte überprüfe den XML-Code und versuche es erneut.' });
|
this.setState({ open: true, file: false, title: 'Keine Blöcke', content: 'Es wurden keine Blöcke detektiert. Bitte überprüfe den XML-Code und versuche es erneut.' });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(!this.props.solutionCheck){
|
if (!this.props.solutionCheck) {
|
||||||
var extensionPosition = xmlFile.name.lastIndexOf('.');
|
var extensionPosition = xmlFile.name.lastIndexOf('.');
|
||||||
this.props.workspaceName(xmlFile.name.substr(0, extensionPosition));
|
this.props.workspaceName(xmlFile.name.substr(0, extensionPosition));
|
||||||
}
|
}
|
||||||
this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt aus gegebener XML-Datei wurde erfolgreich eingefügt.' });
|
this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt aus gegebener XML-Datei wurde erfolgreich eingefügt.' });
|
||||||
}
|
}
|
||||||
} catch(err){
|
} catch (err) {
|
||||||
this.setState({ open: true, file: false, title: 'Ungültige XML', content: 'Die XML-Datei konnte nicht in Blöcke zerlegt werden. Bitte überprüfe den XML-Code und versuche es erneut.' });
|
this.setState({ open: true, file: false, title: 'Ungültige XML', content: 'Die XML-Datei konnte nicht in Blöcke zerlegt werden. Bitte überprüfe den XML-Code und versuche es erneut.' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -195,83 +245,118 @@ class WorkspaceFunc extends Component {
|
|||||||
workspace.options.maxBlocks = Infinity;
|
workspace.options.maxBlocks = Infinity;
|
||||||
this.props.onChangeCode();
|
this.props.onChangeCode();
|
||||||
this.props.clearStats();
|
this.props.clearStats();
|
||||||
if(!this.props.solutionCheck){
|
if (!this.props.solutionCheck) {
|
||||||
this.props.workspaceName(null);
|
this.props.workspaceName(null);
|
||||||
}
|
}
|
||||||
this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt wurde erfolgreich zurückgesetzt.' });
|
this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt wurde erfolgreich zurückgesetzt.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{width: 'max-content', display: 'flex'}}>
|
<div style={{ width: 'max-content', display: 'flex' }}>
|
||||||
{!this.props.solutionCheck ?
|
{!this.props.solutionCheck ?
|
||||||
<Tooltip title={`Name des Projekts${this.props.name ? `: ${this.props.name}` : ''}`} arrow style={{marginRight: '5px'}}>
|
<Tooltip title={`Name des Projekts${this.props.name ? `: ${this.props.name}` : ''}`} arrow style={{ marginRight: '5px' }}>
|
||||||
<div className={this.props.classes.workspaceName} onClick={() => {this.setState({file: true, open: true, saveFile: false, title: 'Projekt benennen', content: 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.'})}}>
|
<div className={this.props.classes.workspaceName} onClick={() => { this.setState({ file: true, open: true, saveFile: false, title: 'Projekt benennen', content: 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' }) }}>
|
||||||
{this.props.name && !isWidthDown('xs', this.props.width) ? <Typography style={{margin: 'auto -3px auto 12px'}}>{this.props.name}</Typography> : null}
|
{this.props.name && !isWidthDown('xs', this.props.width) ? <Typography style={{ margin: 'auto -3px auto 12px' }}>{this.props.name}</Typography> : null}
|
||||||
<div style={{width: '40px', display: 'flex'}}>
|
<div style={{ width: '40px', display: 'flex' }}>
|
||||||
<FontAwesomeIcon icon={faPen} style={{height: '18px', width: '18px', margin: 'auto'}}/>
|
<FontAwesomeIcon icon={faPen} style={{ height: '18px', width: '18px', margin: 'auto' }} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
: null}
|
: null}
|
||||||
{this.props.solutionCheck ? <SolutionCheck /> : <Compile iconButton />}
|
{this.props.solutionCheck ? <SolutionCheck /> : <Compile iconButton />}
|
||||||
<Tooltip title='Blöcke speichern' arrow style={{marginRight: '5px'}}>
|
<Tooltip title='Blöcke speichern' arrow style={{ marginRight: '5px' }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
onClick={() => {this.createFileName('xml');}}
|
onClick={() => { this.createFileName('xml'); }}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faSave} size="xs"/>
|
<FontAwesomeIcon icon={faSave} size="xs" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<div ref={this.inputRef} style={{width: 'max-content', height: '40px', marginRight: '5px'}}>
|
<div ref={this.inputRef} style={{ width: 'max-content', height: '40px', marginRight: '5px' }}>
|
||||||
<input
|
<input
|
||||||
style={{display: 'none'}}
|
style={{ display: 'none' }}
|
||||||
accept="text/xml"
|
accept="text/xml"
|
||||||
onChange={(e) => {this.uploadXmlFile(e.target.files[0])}}
|
onChange={(e) => { this.uploadXmlFile(e.target.files[0]) }}
|
||||||
id="open-blocks"
|
id="open-blocks"
|
||||||
type="file"
|
type="file"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="open-blocks">
|
<label htmlFor="open-blocks">
|
||||||
<Tooltip title='Blöcke öffnen' arrow style={{marginRight: '5px'}}>
|
<Tooltip title='Blöcke öffnen' arrow style={{ marginRight: '5px' }}>
|
||||||
<div className={this.props.classes.button} style={{borderRadius: '50%', cursor: 'pointer', display: 'table-cell',
|
<div className={this.props.classes.button} style={{
|
||||||
verticalAlign: 'middle',
|
borderRadius: '50%', cursor: 'pointer', display: 'table-cell',
|
||||||
textAlign: 'center'}}>
|
verticalAlign: 'middle',
|
||||||
<FontAwesomeIcon icon={faUpload} style={{width: '18px', height: '18px'}}/>
|
textAlign: 'center'
|
||||||
|
}}>
|
||||||
|
<FontAwesomeIcon icon={faUpload} style={{ width: '18px', height: '18px' }} />
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<Tooltip title='Screenshot erstellen' arrow style={{marginRight: '5px'}}>
|
<Tooltip title='Screenshot erstellen' arrow style={{ marginRight: '5px' }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
onClick={() => {this.createFileName('svg');}}
|
onClick={() => { this.createFileName('svg'); }}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faCamera} size="xs" />
|
<FontAwesomeIcon icon={faCamera} size="xs" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title='Workspace zurücksetzen' arrow>
|
<Tooltip title='Workspace zurücksetzen' arrow style={{ marginRight: '5px' }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
onClick={() => this.resetWorkspace()}
|
onClick={() => this.resetWorkspace()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faShare} size="xs" flip='horizontal'/>
|
<FontAwesomeIcon icon={faShare} size="xs" flip='horizontal' />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<Tooltip title='Blöcke teilen' arrow>
|
||||||
|
<IconButton
|
||||||
|
className={this.props.classes.button}
|
||||||
|
onClick={() => this.shareBlocks()}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faShareAlt} size="xs" flip='horizontal' />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Dialog open={this.state.share} onClose={this.toggleDialog} aria-labelledby="form-dialog-title">
|
||||||
|
<DialogTitle id="form-dialog-title">Dein Link wurde erstellt.</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogContentText>
|
||||||
|
Über den folgenden Link kannst du dein Programm teilen.
|
||||||
|
</DialogContentText>
|
||||||
|
<TextField
|
||||||
|
autoFocus
|
||||||
|
margin="dense"
|
||||||
|
id="name"
|
||||||
|
defaultValue={window.location.origin + "/share/" + this.state.id}
|
||||||
|
label="url"
|
||||||
|
type="email"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={this.toggleDialog} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
open={this.state.open}
|
open={this.state.open}
|
||||||
title={this.state.title}
|
title={this.state.title}
|
||||||
content={this.state.content}
|
content={this.state.content}
|
||||||
onClose={this.toggleDialog}
|
onClose={this.toggleDialog}
|
||||||
onClick={this.state.file ? () => {this.toggleDialog(); this.setState({name: this.props.name})} : this.toggleDialog}
|
onClick={this.state.file ? () => { this.toggleDialog(); this.setState({ name: this.props.name }) } : this.toggleDialog}
|
||||||
button={this.state.file ? 'Abbrechen' : 'Schließen'}
|
button={this.state.file ? 'Abbrechen' : 'Schließen'}
|
||||||
>
|
>
|
||||||
{this.state.file ?
|
{this.state.file ?
|
||||||
<div style={{marginTop: '10px'}}>
|
<div style={{ marginTop: '10px' }}>
|
||||||
<TextField autoFocus placeholder={this.state.saveXml ?'Dateiname' : 'Projektname'} value={this.state.name} onChange={this.setFileName} style={{marginRight: '10px'}}/>
|
<TextField autoFocus placeholder={this.state.saveXml ? 'Dateiname' : 'Projektname'} value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} />
|
||||||
<Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => {this.state.saveFile ? this.state.file === 'xml' ? this.saveXmlFile() : this.getSvg() : this.renameWorkspace(); this.toggleDialog();}}>Eingabe</Button>
|
<Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => { this.state.saveFile ? this.state.file === 'xml' ? this.saveXmlFile() : this.getSvg() : this.renameWorkspace(); this.toggleDialog(); }}>Eingabe</Button>
|
||||||
</div>
|
</div>
|
||||||
: null}
|
: null}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<Snackbar
|
<Snackbar
|
||||||
@ -301,4 +386,4 @@ const mapStateToProps = state => ({
|
|||||||
name: state.workspace.name
|
name: state.workspace.name
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, { clearStats, onChangeCode, workspaceName })(withStyles(styles, {withTheme: true})(withWidth()(WorkspaceFunc)));
|
export default connect(mapStateToProps, { clearStats, onChangeCode, workspaceName })(withStyles(styles, { withTheme: true })(withWidth()(WorkspaceFunc)));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user