Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0239ae28aa | ||
|
|
84ce074aec | ||
|
|
7d876e8bf9 | ||
|
|
813582bf9d | ||
|
|
256593164f | ||
|
|
9d65f7b944 | ||
|
|
b04a5bc591 | ||
|
|
49730f51ac | ||
|
|
4588e2a69b | ||
|
|
a99ecc36a4 | ||
|
|
5a7e62adcf | ||
|
|
c6a1e854d2 | ||
|
|
e5204bb4d5 | ||
|
|
e52e3943c1 | ||
|
|
7d1d2409e4 | ||
|
|
42981a4f11 | ||
|
|
4f002d8694 | ||
|
|
1821ac4e40 | ||
|
|
3d2a18c1db | ||
|
|
a929c3d8e6 | ||
|
|
5430e783cc | ||
|
|
101dfc7692 | ||
|
|
f9caeb619e | ||
|
|
ac127dcca2 | ||
|
|
c47d98d2eb | ||
|
|
3655063eaa | ||
|
|
a4cf0d32b0 | ||
|
|
c4c9ddc127 | ||
|
|
f53baf2536 | ||
|
|
3cf7f10d34 | ||
|
|
e6813ba2d3 | ||
|
|
a1834875a0 | ||
|
|
2285f52a0c | ||
|
|
646254017c | ||
|
|
80fd3b83a9 | ||
|
|
50e22fdf92 | ||
|
|
0e05cdca5c | ||
|
|
49fb018703 | ||
|
|
b2f6b1d012 | ||
|
|
dddb00bd79 | ||
|
|
6a8036e075 | ||
|
|
31dbda57df | ||
|
|
80fd112658 | ||
|
|
5d9bfa97af | ||
|
|
4f57e7fd32 | ||
|
|
e2915e8cd0 | ||
|
|
155675821a | ||
|
|
c5fd5c6239 | ||
|
|
a30747c608 | ||
|
|
a8e36a4f06 | ||
|
|
e600c19679 | ||
|
|
0d4072ab17 | ||
|
|
2dfd146d18 | ||
|
|
2e330d1215 | ||
|
|
47f0ebb80d | ||
|
|
6db8c094ea | ||
|
|
d0dda4038e | ||
|
|
c8f01f8273 | ||
|
|
a2c571c1e7 | ||
|
|
2d29b8d7bd | ||
|
|
28720edeea | ||
|
|
cbe091db27 | ||
|
|
b8a2f87321 | ||
|
|
ea00d173c5 | ||
|
|
28d674b6cd | ||
|
|
aae3771020 | ||
|
|
18ac32893c | ||
|
|
14260efa3b | ||
|
|
73aa1ef878 | ||
|
|
38700bf57c | ||
|
|
0829522743 | ||
|
|
7ffe9ff18b | ||
|
|
1b0743b0cf | ||
|
|
b4fb4f8501 | ||
|
|
02a64b9a8f | ||
|
|
4255d14873 | ||
|
|
c17fc8a50f | ||
|
|
fd21bd76f9 | ||
|
|
b60ec9136a | ||
|
|
13d2d3d301 | ||
|
|
b68fb77663 | ||
|
|
e81627b8ec | ||
|
|
4e34c63f08 | ||
|
|
dad91d0a93 | ||
|
|
0183679041 | ||
|
|
d649c3d395 | ||
|
|
bbc3022644 | ||
|
|
aa8b1067dc | ||
|
|
9318d3ef12 | ||
|
|
fe328f9da3 | ||
|
|
3df66cd425 | ||
|
|
3dfcffc2ad | ||
|
|
0cba423749 | ||
|
|
b1b80f8af0 | ||
|
|
2e4df70ddd | ||
|
|
5621fdc620 | ||
|
|
b4a59d3875 | ||
|
|
70c8a1db60 | ||
|
|
5da3006e75 | ||
|
|
8e2deed1d5 | ||
|
|
7b89897e54 | ||
|
|
4601439ae3 | ||
|
|
fd1d8c35e5 | ||
|
|
b07d753e6c | ||
|
|
f1ea8ca2e8 | ||
|
|
cc54c18b47 | ||
|
|
bc819f224b | ||
|
|
14947267d1 | ||
|
|
0a459938a8 | ||
|
|
61ca2e8799 | ||
|
|
71a73ddd1d | ||
|
|
9dedc9ccd1 | ||
|
|
145c14c0cc | ||
|
|
d7b725d1fd | ||
|
|
09c5ef5aae | ||
|
|
dbebb25b17 | ||
|
|
e647d6e58e | ||
|
|
0cb7bba521 |
@@ -1,2 +1,9 @@
|
|||||||
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
|
||||||
|
|
||||||
|
REACT_APP_MYBADGES=https://mybadges.org
|
||||||
|
REACT_APP_MYBADGES_API=https://mybadges.org/api/v1
|
||||||
|
|
||||||
|
# in days
|
||||||
|
REACT_APP_SHARE_LINK_EXPIRES=30
|
||||||
|
|||||||
@@ -2,18 +2,18 @@
|
|||||||
|
|
||||||
# React Ardublockly
|
# React Ardublockly
|
||||||
|
|
||||||
This repository contains the source code and documentation of [sensebox-ardublockly](https://sensebox-ardublockly.netlify.app/) :rocket:.
|
This repository contains the source code and documentation of [sensebox-ardublockly](https://sensebox-ardublockly.netlify.app/).
|
||||||
|
|
||||||
This project was created with [Create React App](https://github.com/facebook/create-react-app) and represents the continuation or improvement of [blockly.sensebox.de](https://blockly.sensebox.de/ardublockly/?lang=de&board=sensebox-mcu).
|
This project was created with [Create React App](https://github.com/facebook/create-react-app) and represents the continuation or improvement of [blockly.sensebox.de](https://blockly.sensebox.de/ardublockly/?lang=de&board=sensebox-mcu).
|
||||||
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
1. [Download](https://github.com/sensebox/React-Ardublockly/archive/bachelor.zip) or clone the GitHub Repository ``git clone https://github.com/sensebox/React-Ardublockly`` and checkout to branch ``bachelor``.
|
1. [Download](https://github.com/sensebox/React-Ardublockly/archive/master.zip) or clone the GitHub Repository ``git clone https://github.com/sensebox/React-Ardublockly`` and checkout to branch ``master``.
|
||||||
|
|
||||||
2. install [Node.js v10.xx](https://nodejs.org/en/) on your local machine
|
2. install [Node.js v10.xx](https://nodejs.org/en/) on your local machine
|
||||||
|
|
||||||
3. open shell and navigate inside folder ``React-Ardublockly`` or rather ``Quellcode``
|
3. open shell and navigate inside folder ``React-Ardublockly``
|
||||||
* run ``npm install``
|
* run ``npm install``
|
||||||
* run ``npm start``
|
* run ``npm start``
|
||||||
4. open [localhost:3000](http://localhost:3000)
|
4. open [localhost:3000](http://localhost:3000)
|
||||||
@@ -22,7 +22,7 @@ This project was created with [Create React App](https://github.com/facebook/cre
|
|||||||
Ensure that line 14 in [store.js](https://github.com/sensebox/React-Ardublockly/blob/master/src/store.js#L14) is commented out or otherwise you have installed [Redux DevTools Extension](http://extension.remotedev.io/).
|
Ensure that line 14 in [store.js](https://github.com/sensebox/React-Ardublockly/blob/master/src/store.js#L14) is commented out or otherwise you have installed [Redux DevTools Extension](http://extension.remotedev.io/).
|
||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
A demo of the current status of the bachelor branch can be accessed via [sensebox-ardublockly.netlify.app](https://sensebox-ardublockly.netlify.app/) :rocket:.
|
A demo of the current status of the master branch can be accessed via [sensebox-ardublockly.netlify.app](https://sensebox-ardublockly.netlify.app/) :rocket:.
|
||||||
* [Home](https://sensebox-ardublockly.netlify.app/)
|
* [Home](https://sensebox-ardublockly.netlify.app/)
|
||||||
* [Tutorial Overview](https://sensebox-ardublockly.netlify.app/tutorial)
|
* [Tutorial Overview](https://sensebox-ardublockly.netlify.app/tutorial)
|
||||||
* [Tutorial-Builder](https://sensebox-ardublockly.netlify.app/tutorial/builder)
|
* [Tutorial-Builder](https://sensebox-ardublockly.netlify.app/tutorial/builder)
|
||||||
|
|||||||
@@ -1806,6 +1806,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz",
|
||||||
"integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ=="
|
"integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ=="
|
||||||
},
|
},
|
||||||
|
"@types/mdast": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/unist": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/minimatch": {
|
"@types/minimatch": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||||
@@ -1955,6 +1963,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/unist": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ=="
|
||||||
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "13.0.9",
|
"version": "13.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz",
|
||||||
@@ -2568,6 +2581,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
|
||||||
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
|
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
|
||||||
},
|
},
|
||||||
|
"axios": {
|
||||||
|
"version": "0.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz",
|
||||||
|
"integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==",
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"axobject-query": {
|
"axobject-query": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
|
||||||
@@ -2980,6 +3001,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
|
||||||
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
|
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
|
||||||
},
|
},
|
||||||
|
"bail": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ=="
|
||||||
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
@@ -3571,6 +3597,21 @@
|
|||||||
"supports-color": "^5.3.0"
|
"supports-color": "^5.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"character-entities": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw=="
|
||||||
|
},
|
||||||
|
"character-entities-legacy": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA=="
|
||||||
|
},
|
||||||
|
"character-reference-invalid": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg=="
|
||||||
|
},
|
||||||
"chardet": {
|
"chardet": {
|
||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
|
||||||
@@ -6677,6 +6718,63 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"html-to-react": {
|
||||||
|
"version": "1.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.4.5.tgz",
|
||||||
|
"integrity": "sha512-KONZUDFPg5OodWaQu2ymfkDmU0JA7zB1iPfvyHehTmMUZnk0DS7/TyCMTzsLH6b4BvxX15g88qZCXFhJWktsmA==",
|
||||||
|
"requires": {
|
||||||
|
"domhandler": "^3.3.0",
|
||||||
|
"htmlparser2": "^5.0",
|
||||||
|
"lodash.camelcase": "^4.3.0",
|
||||||
|
"ramda": "^0.27.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"dom-serializer": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-ox7bvGXt2n+uLWtCRLybYx60IrOlWL/aCebWJk1T0d4m3y2tzf4U3ij9wBMUb6YJZpz06HCCYuyCDveE2xXmzQ==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.0.1",
|
||||||
|
"domhandler": "^3.0.0",
|
||||||
|
"entities": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domelementtype": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA=="
|
||||||
|
},
|
||||||
|
"domhandler": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domutils": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-NKbgaM8ZJOecTZsIzW5gSuplsX2IWW2mIK7xVr8hTQF2v1CJWTmLZ1HOCh5sH+IzVPAGE5IucooOkvwBRAdowA==",
|
||||||
|
"requires": {
|
||||||
|
"dom-serializer": "^1.0.1",
|
||||||
|
"domelementtype": "^2.0.1",
|
||||||
|
"domhandler": "^3.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"htmlparser2": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.0.1",
|
||||||
|
"domhandler": "^3.3.0",
|
||||||
|
"domutils": "^2.4.2",
|
||||||
|
"entities": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"html-webpack-plugin": {
|
"html-webpack-plugin": {
|
||||||
"version": "4.0.0-beta.11",
|
"version": "4.0.0-beta.11",
|
||||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz",
|
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz",
|
||||||
@@ -7042,6 +7140,20 @@
|
|||||||
"kind-of": "^3.0.2"
|
"kind-of": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"is-alphabetical": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="
|
||||||
|
},
|
||||||
|
"is-alphanumerical": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
|
||||||
|
"requires": {
|
||||||
|
"is-alphabetical": "^1.0.0",
|
||||||
|
"is-decimal": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"is-arguments": {
|
"is-arguments": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
|
||||||
@@ -7104,6 +7216,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
|
||||||
"integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g=="
|
"integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g=="
|
||||||
},
|
},
|
||||||
|
"is-decimal": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw=="
|
||||||
|
},
|
||||||
"is-descriptor": {
|
"is-descriptor": {
|
||||||
"version": "0.1.6",
|
"version": "0.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
|
||||||
@@ -7159,6 +7276,11 @@
|
|||||||
"is-extglob": "^2.1.1"
|
"is-extglob": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"is-hexadecimal": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw=="
|
||||||
|
},
|
||||||
"is-in-browser": {
|
"is-in-browser": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
|
||||||
@@ -7887,6 +8009,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"js-cookie": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
|
||||||
|
},
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@@ -8281,6 +8408,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
|
||||||
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
|
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
|
||||||
},
|
},
|
||||||
|
"lodash.camelcase": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||||
|
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
|
||||||
|
},
|
||||||
"lodash.memoize": {
|
"lodash.memoize": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||||
@@ -8414,6 +8546,30 @@
|
|||||||
"safe-buffer": "^5.1.2"
|
"safe-buffer": "^5.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mdast-add-list-metadata": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA==",
|
||||||
|
"requires": {
|
||||||
|
"unist-util-visit-parents": "1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mdast-util-from-markdown": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-qJXNcFcuCSPqUF0Tb0uYcFDIq67qwB3sxo9RPdf9vG8T90ViKnksFqdB/Coq2a7sTnxL/Ify2y7aIQXDkQFH0w==",
|
||||||
|
"requires": {
|
||||||
|
"@types/mdast": "^3.0.0",
|
||||||
|
"mdast-util-to-string": "^1.0.0",
|
||||||
|
"micromark": "~2.10.0",
|
||||||
|
"parse-entities": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mdast-util-to-string": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A=="
|
||||||
|
},
|
||||||
"mdn-data": {
|
"mdn-data": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
|
||||||
@@ -8502,6 +8658,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz",
|
||||||
"integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g=="
|
"integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g=="
|
||||||
},
|
},
|
||||||
|
"micromark": {
|
||||||
|
"version": "2.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromark/-/micromark-2.10.1.tgz",
|
||||||
|
"integrity": "sha512-fUuVF8sC1X7wsCS29SYQ2ZfIZYbTymp0EYr6sab3idFjigFFjGa5UwoniPlV9tAgntjuapW1t9U+S0yDYeGKHQ==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.0.0",
|
||||||
|
"parse-entities": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"micromatch": {
|
"micromatch": {
|
||||||
"version": "3.1.10",
|
"version": "3.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
|
||||||
@@ -8720,6 +8885,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",
|
||||||
@@ -8828,9 +8998,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-forge": {
|
"node-forge": {
|
||||||
"version": "0.9.0",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
||||||
"integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ=="
|
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="
|
||||||
},
|
},
|
||||||
"node-int64": {
|
"node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
@@ -9394,6 +9564,19 @@
|
|||||||
"safe-buffer": "^5.1.1"
|
"safe-buffer": "^5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"parse-entities": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
||||||
|
"requires": {
|
||||||
|
"character-entities": "^1.0.0",
|
||||||
|
"character-entities-legacy": "^1.0.0",
|
||||||
|
"character-reference-invalid": "^1.0.0",
|
||||||
|
"is-alphanumerical": "^1.0.0",
|
||||||
|
"is-decimal": "^1.0.0",
|
||||||
|
"is-hexadecimal": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"parse-json": {
|
"parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||||
@@ -10720,6 +10903,11 @@
|
|||||||
"performance-now": "^2.1.0"
|
"performance-now": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ramda": {
|
||||||
|
"version": "0.27.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz",
|
||||||
|
"integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw=="
|
||||||
|
},
|
||||||
"randombytes": {
|
"randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
@@ -10783,6 +10971,14 @@
|
|||||||
"whatwg-fetch": "^3.0.0"
|
"whatwg-fetch": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-cookie-consent": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-cookie-consent/-/react-cookie-consent-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-iRIDynmivejZgLICcpfGbQl94qLn6cjdEHZP0e+ibxzQ7t3zXzdDhsGDSYax8Qu6nGJnlv0bCBd8K0UJUQ5zwQ==",
|
||||||
|
"requires": {
|
||||||
|
"js-cookie": "^2.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-dev-utils": {
|
"react-dev-utils": {
|
||||||
"version": "10.2.1",
|
"version": "10.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz",
|
||||||
@@ -11005,6 +11201,23 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"react-markdown": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-kmkB4JbV7LqkDAjvaKRKtodB3n3Id76/DalaDun1U8FuLB0SenPfvH+jAQ5Pcpo54cACRQc1LB1yXmuuuIVecw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/mdast": "^3.0.3",
|
||||||
|
"@types/unist": "^2.0.3",
|
||||||
|
"html-to-react": "^1.3.4",
|
||||||
|
"mdast-add-list-metadata": "1.0.1",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react-is": "^16.8.6",
|
||||||
|
"remark-parse": "^9.0.0",
|
||||||
|
"unified": "^9.0.0",
|
||||||
|
"unist-util-visit": "^2.0.0",
|
||||||
|
"xtend": "^4.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-redux": {
|
"react-redux": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.0.tgz",
|
||||||
@@ -11302,6 +11515,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||||
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
|
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
|
||||||
},
|
},
|
||||||
|
"remark-parse": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==",
|
||||||
|
"requires": {
|
||||||
|
"mdast-util-from-markdown": "^0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"remove-trailing-separator": {
|
"remove-trailing-separator": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||||
@@ -11369,6 +11590,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
|
||||||
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
|
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
|
||||||
},
|
},
|
||||||
|
"replace-ext": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs="
|
||||||
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"version": "2.88.2",
|
"version": "2.88.2",
|
||||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
|
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
|
||||||
@@ -11394,6 +11620,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": {
|
||||||
@@ -11738,11 +11971,11 @@
|
|||||||
"integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo="
|
"integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo="
|
||||||
},
|
},
|
||||||
"selfsigned": {
|
"selfsigned": {
|
||||||
"version": "1.10.7",
|
"version": "1.10.8",
|
||||||
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz",
|
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
|
||||||
"integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==",
|
"integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"node-forge": "0.9.0"
|
"node-forge": "^0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
@@ -12125,6 +12358,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": {
|
||||||
@@ -12989,6 +13229,11 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"trough": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA=="
|
||||||
|
},
|
||||||
"ts-pnp": {
|
"ts-pnp": {
|
||||||
"version": "1.1.6",
|
"version": "1.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz",
|
||||||
@@ -13081,6 +13326,31 @@
|
|||||||
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz",
|
||||||
"integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg=="
|
"integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg=="
|
||||||
},
|
},
|
||||||
|
"unified": {
|
||||||
|
"version": "9.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz",
|
||||||
|
"integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==",
|
||||||
|
"requires": {
|
||||||
|
"bail": "^1.0.0",
|
||||||
|
"extend": "^3.0.0",
|
||||||
|
"is-buffer": "^2.0.0",
|
||||||
|
"is-plain-obj": "^2.0.0",
|
||||||
|
"trough": "^1.0.0",
|
||||||
|
"vfile": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"is-buffer": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
|
||||||
|
},
|
||||||
|
"is-plain-obj": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"union-value": {
|
"union-value": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
|
||||||
@@ -13118,6 +13388,45 @@
|
|||||||
"imurmurhash": "^0.1.4"
|
"imurmurhash": "^0.1.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"unist-util-is": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-bTofCFVx0iQM8Jqb1TBDVRIQW03YkD3p66JOd/aCWuqzlLyUtx1ZAGw/u+Zw+SttKvSVcvTiKYbfrtLoLefykw=="
|
||||||
|
},
|
||||||
|
"unist-util-stringify-position": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
|
||||||
|
"requires": {
|
||||||
|
"@types/unist": "^2.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unist-util-visit": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==",
|
||||||
|
"requires": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"unist-util-is": "^4.0.0",
|
||||||
|
"unist-util-visit-parents": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"unist-util-visit-parents": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==",
|
||||||
|
"requires": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"unist-util-is": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unist-util-visit-parents": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q=="
|
||||||
|
},
|
||||||
"universalify": {
|
"universalify": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||||
@@ -13269,9 +13578,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",
|
||||||
@@ -13312,6 +13621,34 @@
|
|||||||
"extsprintf": "^1.2.0"
|
"extsprintf": "^1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vfile": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-a/alcwCvtuc8OX92rqqo7PflxiCgXRFjdyoGVuYV+qbgCb0GgZJRvIgCD4+U/Kl1yhaRsaTwksF88xbPyGsgpw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"is-buffer": "^2.0.0",
|
||||||
|
"replace-ext": "1.0.0",
|
||||||
|
"unist-util-stringify-position": "^2.0.0",
|
||||||
|
"vfile-message": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"is-buffer": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"vfile-message": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"unist-util-stringify-position": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"vm-browserify": {
|
"vm-browserify": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
|
||||||
@@ -13929,6 +14266,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": {
|
||||||
|
|||||||
@@ -13,20 +13,26 @@
|
|||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.5.0",
|
"@testing-library/react": "^9.5.0",
|
||||||
"@testing-library/user-event": "^7.2.1",
|
"@testing-library/user-event": "^7.2.1",
|
||||||
|
"axios": "^0.21.0",
|
||||||
"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",
|
||||||
|
"react-cookie-consent": "^5.2.0",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
|
"react-markdown": "^5.0.2",
|
||||||
"react-redux": "^7.2.0",
|
"react-redux": "^7.2.0",
|
||||||
"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",
|
||||||
|
"dev": "set \"REACT_APP_BLOCKLY_API=http://localhost:8080\" && set \"REACT_APP_MYBADGES_API=http://localhost:3001/api/v1\"&& npm start",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 239 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 319 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 274 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 196 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 218 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 641 KiB After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 253 KiB After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 47 KiB |
@@ -5,3 +5,31 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
padding-bottom: 60px; /* height of your footer + 30px*/
|
padding-bottom: 60px; /* height of your footer + 30px*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tutorial img{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
max-height: 40vH;
|
||||||
|
max-width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tutorial blockquote{
|
||||||
|
background: #f9f9f9;
|
||||||
|
border-left: 10px solid#4EAF47;
|
||||||
|
margin: 1.5em 10px;
|
||||||
|
padding: 0.5em 10px;
|
||||||
|
quotes: "\201C""\201D""\2018""\2019";
|
||||||
|
}
|
||||||
|
blockquote:before {
|
||||||
|
color:#4EAF47;
|
||||||
|
content: open-quote;
|
||||||
|
font-size: 4em;
|
||||||
|
line-height: 0.1em;
|
||||||
|
margin-right: 0.25em;
|
||||||
|
vertical-align: -0.4em;
|
||||||
|
}
|
||||||
|
blockquote p {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import React from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
import { createBrowserHistory } from "history";
|
import { createBrowserHistory } from "history";
|
||||||
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
import { loadUser } from './actions/authActions';
|
||||||
|
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
|
||||||
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||||
|
|
||||||
import Navbar from './components/Navbar';
|
import Content from './components/Content';
|
||||||
import Footer from './components/Footer';
|
|
||||||
import Routes from './components/Routes';
|
|
||||||
|
|
||||||
const theme = createMuiTheme({
|
const theme = createMuiTheme({
|
||||||
palette: {
|
palette: {
|
||||||
@@ -22,27 +21,31 @@ const theme = createMuiTheme({
|
|||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
main: '#DDDDDD'
|
main: '#DDDDDD'
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
compile: '#e27136'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const customHistory = createBrowserHistory();
|
class App extends Component {
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
store.dispatch(loadUser());
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
render() {
|
||||||
return (
|
const customHistory = createBrowserHistory();
|
||||||
<ThemeProvider theme={theme}>
|
return (
|
||||||
<Provider store={store}>
|
<ThemeProvider theme={theme}>
|
||||||
<Router history={customHistory}>
|
<Provider store={store}>
|
||||||
<div className="wrapper">
|
<Router history={customHistory}>
|
||||||
<Navbar />
|
<Content />
|
||||||
<Routes />
|
</Router>
|
||||||
<Footer />
|
</Provider>
|
||||||
</div>
|
</ThemeProvider>
|
||||||
</Router>
|
);
|
||||||
</Provider>
|
}
|
||||||
</ThemeProvider>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -0,0 +1,294 @@
|
|||||||
|
import { MYBADGES_CONNECT, MYBADGES_DISCONNECT, GET_STATUS, USER_LOADED, USER_LOADING, AUTH_ERROR, LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT_SUCCESS, LOGOUT_FAIL, REFRESH_TOKEN_SUCCESS } from '../actions/types';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { returnErrors, returnSuccess } from './messageActions';
|
||||||
|
import { setLanguage } from './generalActions';
|
||||||
|
|
||||||
|
// Check token & load user
|
||||||
|
export const loadUser = () => (dispatch) => {
|
||||||
|
// user loading
|
||||||
|
dispatch({
|
||||||
|
type: USER_LOADING
|
||||||
|
});
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
dispatch({
|
||||||
|
type: GET_STATUS,
|
||||||
|
payload: res.data.user.status
|
||||||
|
});
|
||||||
|
dispatch(setLanguage(res.data.user.language));
|
||||||
|
dispatch({
|
||||||
|
type: USER_LOADED,
|
||||||
|
payload: res.data.user
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
if(err.response){
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status));
|
||||||
|
}
|
||||||
|
var status = [];
|
||||||
|
if (window.localStorage.getItem('status')) {
|
||||||
|
status = JSON.parse(window.localStorage.getItem('status'));
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: GET_STATUS,
|
||||||
|
payload: status
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
type: AUTH_ERROR
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
axios.get(`${process.env.REACT_APP_BLOCKLY_API}/user`, config, dispatch(authInterceptor()))
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
err.config.error(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var logoutTimerId;
|
||||||
|
const timeToLogout = 14.9*60*1000; // nearly 15 minutes corresponding to the API
|
||||||
|
|
||||||
|
// Login user
|
||||||
|
export const login = ({ email, password }) => (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: USER_LOADING
|
||||||
|
});
|
||||||
|
// Headers
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Request Body
|
||||||
|
const body = JSON.stringify({ email, password });
|
||||||
|
axios.post(`${process.env.REACT_APP_BLOCKLY_API}/user`, body, config)
|
||||||
|
.then(res => {
|
||||||
|
// Logout automatically if refreshToken "expired"
|
||||||
|
const logoutTimer = () => setTimeout(
|
||||||
|
() => dispatch(logout()),
|
||||||
|
timeToLogout
|
||||||
|
);
|
||||||
|
logoutTimerId = logoutTimer();
|
||||||
|
dispatch(setLanguage(res.data.user.language));
|
||||||
|
dispatch({
|
||||||
|
type: LOGIN_SUCCESS,
|
||||||
|
payload: res.data
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
type: GET_STATUS,
|
||||||
|
payload: res.data.user.status
|
||||||
|
});
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'LOGIN_SUCCESS'));
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'LOGIN_FAIL'));
|
||||||
|
dispatch({
|
||||||
|
type: LOGIN_FAIL
|
||||||
|
});
|
||||||
|
var status = [];
|
||||||
|
if (window.localStorage.getItem('status')) {
|
||||||
|
status = JSON.parse(window.localStorage.getItem('status'));
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: GET_STATUS,
|
||||||
|
payload: status
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Connect to MyBadges-Account
|
||||||
|
export const connectMyBadges = ({ username, password }) => (dispatch, getState) => {
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
var user = getState().auth.user;
|
||||||
|
user.badge = res.data.account;
|
||||||
|
user.badges = res.data.badges;
|
||||||
|
dispatch({
|
||||||
|
type: MYBADGES_CONNECT,
|
||||||
|
payload: user
|
||||||
|
});
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'MYBADGES_CONNECT_SUCCESS'));
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'MYBADGES_CONNECT_FAIL'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Request Body
|
||||||
|
const body = JSON.stringify({ username, password });
|
||||||
|
axios.post(`${process.env.REACT_APP_BLOCKLY_API}/user/badge`, body, config)
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if(err.response && err.response.status !== 401){
|
||||||
|
err.config.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Disconnect MyBadges-Account
|
||||||
|
export const disconnectMyBadges = () => (dispatch, getState) => {
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
var user = getState().auth.user;
|
||||||
|
user.badge = null;
|
||||||
|
user.badges = null;
|
||||||
|
dispatch({
|
||||||
|
type: MYBADGES_DISCONNECT,
|
||||||
|
payload: user
|
||||||
|
});
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'MYBADGES_DISCONNECT_SUCCESS'));
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'MYBADGES_DISCONNECT_FAIL'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
axios.put(`${process.env.REACT_APP_BLOCKLY_API}/user/badge`, {}, config)
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if(err.response && err.response.status !== 401){
|
||||||
|
err.config.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Logout User
|
||||||
|
export const logout = () => (dispatch) => {
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
dispatch({
|
||||||
|
type: LOGOUT_SUCCESS
|
||||||
|
});
|
||||||
|
var status = [];
|
||||||
|
if (window.localStorage.getItem('status')) {
|
||||||
|
status = JSON.parse(window.localStorage.getItem('status'));
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: GET_STATUS,
|
||||||
|
payload: status
|
||||||
|
});
|
||||||
|
var locale = 'en_US';
|
||||||
|
if (window.localStorage.getItem('locale')) {
|
||||||
|
locale = window.localStorage.getItem('locale');
|
||||||
|
}
|
||||||
|
else if (navigator.language === 'de-DE'){
|
||||||
|
locale = 'de_DE';
|
||||||
|
}
|
||||||
|
dispatch(setLanguage(locale));
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'LOGOUT_SUCCESS'));
|
||||||
|
clearTimeout(logoutTimerId);
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'LOGOUT_FAIL'));
|
||||||
|
dispatch({
|
||||||
|
type: LOGOUT_FAIL
|
||||||
|
});
|
||||||
|
var status = [];
|
||||||
|
if (window.localStorage.getItem('status')) {
|
||||||
|
status = JSON.parse(window.localStorage.getItem('status'));
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: GET_STATUS,
|
||||||
|
payload: status
|
||||||
|
});
|
||||||
|
clearTimeout(logoutTimerId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
axios.post('https://api.opensensemap.org/users/sign-out', {}, config)
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if(err.response && err.response.status !== 401){
|
||||||
|
err.config.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const authInterceptor = () => (dispatch, getState) => {
|
||||||
|
// Add a request interceptor
|
||||||
|
axios.interceptors.request.use(
|
||||||
|
config => {
|
||||||
|
config.headers['Content-Type'] = 'application/json';
|
||||||
|
const token = getState().auth.token;
|
||||||
|
if (token) {
|
||||||
|
config.headers['Authorization'] = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add a response interceptor
|
||||||
|
axios.interceptors.response.use(
|
||||||
|
response => {
|
||||||
|
// request was successfull
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
const originalRequest = error.config;
|
||||||
|
const refreshToken = getState().auth.refreshToken;
|
||||||
|
if(refreshToken){
|
||||||
|
// try to refresh the token failed
|
||||||
|
if (error.response.status === 401 && originalRequest._retry) {
|
||||||
|
// router.push('/login');
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
// token was not valid and 1st try to refresh the token
|
||||||
|
if (error.response.status === 401 && !originalRequest._retry) {
|
||||||
|
originalRequest._retry = true;
|
||||||
|
const refreshToken = getState().auth.refreshToken;
|
||||||
|
// request to refresh the token, in request-body is the refreshToken
|
||||||
|
axios.post('https://api.opensensemap.org/users/refresh-auth', {"token": refreshToken})
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
clearTimeout(logoutTimerId);
|
||||||
|
const logoutTimer = () => setTimeout(
|
||||||
|
() => dispatch(logout()),
|
||||||
|
timeToLogout
|
||||||
|
);
|
||||||
|
logoutTimerId = logoutTimer();
|
||||||
|
dispatch({
|
||||||
|
type: REFRESH_TOKEN_SUCCESS,
|
||||||
|
payload: res.data
|
||||||
|
});
|
||||||
|
axios.defaults.headers.common['Authorization'] = 'Bearer ' + getState().auth.token;
|
||||||
|
// request was successfull, new request with the old parameters and the refreshed token
|
||||||
|
return axios(originalRequest)
|
||||||
|
.then(res => {
|
||||||
|
originalRequest.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
originalRequest.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
// request failed, token could not be refreshed
|
||||||
|
if(err.response){
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status));
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: AUTH_ERROR
|
||||||
|
});
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// request status was unequal to 401, no possibility to refresh the token
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { VISIT } from './types';
|
import { VISIT, LANGUAGE, RENDERER, STATISTICS } from './types';
|
||||||
|
|
||||||
|
|
||||||
export const visitPage = () => (dispatch) => {
|
export const visitPage = () => (dispatch) => {
|
||||||
@@ -6,3 +6,27 @@ export const visitPage = () => (dispatch) => {
|
|||||||
type: VISIT
|
type: VISIT
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setLanguage = (language) => (dispatch, getState) => {
|
||||||
|
if(!getState().auth.progress && !getState().auth.isAuthenticated){
|
||||||
|
window.localStorage.setItem('locale', language);
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: LANGUAGE,
|
||||||
|
payload: language
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setRenderer = (renderer) => (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: RENDERER,
|
||||||
|
payload: renderer
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setStatistics = (showStatistics) => (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: STATISTICS,
|
||||||
|
payload: showStatistics
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { GET_ERRORS, CLEAR_MESSAGES, GET_SUCCESS } from './types';
|
||||||
|
|
||||||
|
// RETURN Errors
|
||||||
|
export const returnErrors = (msg, status, id = null) => {
|
||||||
|
return {
|
||||||
|
type: GET_ERRORS,
|
||||||
|
payload: {
|
||||||
|
msg: msg,
|
||||||
|
status: status,
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// RETURN Success
|
||||||
|
export const returnSuccess = (msg, status, id = null) => {
|
||||||
|
return {
|
||||||
|
type: GET_SUCCESS,
|
||||||
|
payload: {
|
||||||
|
msg: msg,
|
||||||
|
status: status,
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// CLEAR_MESSAGES
|
||||||
|
export const clearMessages = () => {
|
||||||
|
return {
|
||||||
|
type: CLEAR_MESSAGES
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
import { PROJECT_PROGRESS, GET_PROJECT, GET_PROJECTS, PROJECT_TYPE, PROJECT_DESCRIPTION } from './types';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { returnErrors, returnSuccess } from './messageActions';
|
||||||
|
|
||||||
|
export const setType = (type) => (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: PROJECT_TYPE,
|
||||||
|
payload: type
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setDescription = (description) => (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: PROJECT_DESCRIPTION,
|
||||||
|
payload: description
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getProject = (type, id) => (dispatch) => {
|
||||||
|
dispatch({ type: PROJECT_PROGRESS });
|
||||||
|
dispatch(setType(type));
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
var data = type === 'share' ? 'content' : type;
|
||||||
|
var project = res.data[data];
|
||||||
|
if (project) {
|
||||||
|
dispatch({
|
||||||
|
type: GET_PROJECT,
|
||||||
|
payload: project
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
type: PROJECT_DESCRIPTION,
|
||||||
|
payload: project.description
|
||||||
|
});
|
||||||
|
dispatch({ type: PROJECT_PROGRESS });
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'GET_PROJECT_SUCCESS'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dispatch({ type: PROJECT_PROGRESS });
|
||||||
|
dispatch(returnErrors(res.data.message, res.status, 'PROJECT_EMPTY'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
if(err.response){
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'GET_PROJECT_FAIL'));
|
||||||
|
}
|
||||||
|
dispatch({type: PROJECT_PROGRESS});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
axios.get(`${process.env.REACT_APP_BLOCKLY_API}/${type}/${id}`, config)
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
err.config.error(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getProjects = (type) => (dispatch) => {
|
||||||
|
dispatch({type: PROJECT_PROGRESS});
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
var data = type === 'project' ? 'projects' : 'galleries';
|
||||||
|
var projects = res.data[data];
|
||||||
|
dispatch({
|
||||||
|
type: GET_PROJECTS,
|
||||||
|
payload: projects
|
||||||
|
});
|
||||||
|
dispatch({ type: PROJECT_PROGRESS });
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status));
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
if(err.response){
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'GET_PROJECTS_FAIL'));
|
||||||
|
}
|
||||||
|
dispatch({type: PROJECT_PROGRESS});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
axios.get(`${process.env.REACT_APP_BLOCKLY_API}/${type}`, config)
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
err.config.error(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateProject = (type, id) => (dispatch, getState) => {
|
||||||
|
var workspace = getState().workspace;
|
||||||
|
var body = {
|
||||||
|
xml: workspace.code.xml,
|
||||||
|
title: workspace.name
|
||||||
|
};
|
||||||
|
var project = getState().project;
|
||||||
|
if (type === 'gallery') {
|
||||||
|
body.description = project.description;
|
||||||
|
}
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
var project = res.data[type];
|
||||||
|
var projects = getState().project.projects;
|
||||||
|
var index = projects.findIndex(res => res._id === project._id);
|
||||||
|
projects[index] = project;
|
||||||
|
dispatch({
|
||||||
|
type: GET_PROJECTS,
|
||||||
|
payload: projects
|
||||||
|
});
|
||||||
|
if (type === 'project') {
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'PROJECT_UPDATE_SUCCESS'));
|
||||||
|
} else {
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'GALLERY_UPDATE_SUCCESS'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
if(err.response){
|
||||||
|
if(type === 'project'){
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'PROJECT_UPDATE_FAIL'));
|
||||||
|
} else {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'GALLERY_UPDATE_FAIL'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
axios.put(`${process.env.REACT_APP_BLOCKLY_API}/${type}/${id}`, body, config)
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
err.config.error(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteProject = (type, id) => (dispatch, getState) => {
|
||||||
|
var project = getState().project;
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
var projects = getState().project.projects;
|
||||||
|
var index = projects.findIndex(res => res._id === id);
|
||||||
|
projects.splice(index, 1)
|
||||||
|
dispatch({
|
||||||
|
type: GET_PROJECTS,
|
||||||
|
payload: projects
|
||||||
|
});
|
||||||
|
if (type === 'project') {
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'PROJECT_DELETE_SUCCESS'));
|
||||||
|
} else {
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'GALLERY_DELETE_SUCCESS'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'PROJECT_DELETE_FAIL'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
axios.delete(`${process.env.REACT_APP_BLOCKLY_API}/${type}/${id}`, config)
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if(err.response && err.response.status !== 401){
|
||||||
|
err.config.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const shareProject = (title, type, id) => (dispatch, getState) => {
|
||||||
|
var body = {
|
||||||
|
title: title
|
||||||
|
};
|
||||||
|
if (type === 'project') {
|
||||||
|
body.projectId = id;
|
||||||
|
} else {
|
||||||
|
body.xml = getState().workspace.code.xml;
|
||||||
|
}
|
||||||
|
axios.post(`${process.env.REACT_APP_BLOCKLY_API}/share`, body)
|
||||||
|
.then(res => {
|
||||||
|
var shareContent = res.data.content;
|
||||||
|
if (body.projectId) {
|
||||||
|
var projects = getState().project.projects;
|
||||||
|
var index = projects.findIndex(res => res._id === id);
|
||||||
|
projects[index].shared = shareContent.expiresAt;
|
||||||
|
dispatch({
|
||||||
|
type: GET_PROJECTS,
|
||||||
|
payload: projects
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dispatch(returnSuccess(res.data.message, shareContent._id, 'SHARE_SUCCESS'));
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if (err.response) {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'SHARE_FAIL'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const resetProject = () => (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: GET_PROJECTS,
|
||||||
|
payload: []
|
||||||
|
});
|
||||||
|
dispatch(setType(''));
|
||||||
|
dispatch(setDescription(''));
|
||||||
|
};
|
||||||
@@ -1,6 +1,152 @@
|
|||||||
import { TUTORIAL_SUCCESS, TUTORIAL_ERROR, TUTORIAL_CHANGE, TUTORIAL_XML, TUTORIAL_ID, TUTORIAL_STEP } from './types';
|
import { MYBADGES_DISCONNECT, TUTORIAL_PROGRESS, GET_TUTORIAL, GET_TUTORIALS, TUTORIAL_SUCCESS, TUTORIAL_ERROR, TUTORIAL_CHANGE, TUTORIAL_XML, TUTORIAL_STEP } from './types';
|
||||||
|
|
||||||
import tutorials from '../data/tutorials';
|
import axios from 'axios';
|
||||||
|
import { returnErrors, returnSuccess } from './messageActions';
|
||||||
|
|
||||||
|
export const tutorialProgress = () => (dispatch) => {
|
||||||
|
dispatch({type: TUTORIAL_PROGRESS});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const getTutorial = (id) => (dispatch, getState) => {
|
||||||
|
axios.get(`${process.env.REACT_APP_BLOCKLY_API}/tutorial/${id}`)
|
||||||
|
.then(res => {
|
||||||
|
var tutorial = res.data.tutorial;
|
||||||
|
existingTutorial(tutorial, getState().tutorial.status).then(status => {
|
||||||
|
dispatch({
|
||||||
|
type: TUTORIAL_SUCCESS,
|
||||||
|
payload: status
|
||||||
|
});
|
||||||
|
dispatch(updateStatus(status));
|
||||||
|
dispatch({
|
||||||
|
type: GET_TUTORIAL,
|
||||||
|
payload: tutorial
|
||||||
|
});
|
||||||
|
dispatch({type: TUTORIAL_PROGRESS});
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if (err.response) {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'GET_TUTORIAL_FAIL'));
|
||||||
|
}
|
||||||
|
dispatch({ type: TUTORIAL_PROGRESS });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTutorials = () => (dispatch, getState) => {
|
||||||
|
axios.get(`${process.env.REACT_APP_BLOCKLY_API}/tutorial`)
|
||||||
|
.then(res => {
|
||||||
|
var tutorials = res.data.tutorials;
|
||||||
|
console.log(tutorials);
|
||||||
|
existingTutorials(tutorials, getState().tutorial.status).then(status => {
|
||||||
|
dispatch({
|
||||||
|
type: TUTORIAL_SUCCESS,
|
||||||
|
payload: status
|
||||||
|
});
|
||||||
|
console.log('zwei');
|
||||||
|
dispatch(updateStatus(status));
|
||||||
|
dispatch({
|
||||||
|
type: GET_TUTORIALS,
|
||||||
|
payload: tutorials
|
||||||
|
});
|
||||||
|
dispatch({ type: TUTORIAL_PROGRESS });
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if (err.response) {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'GET_TUTORIALS_FAIL'));
|
||||||
|
}
|
||||||
|
dispatch({ type: TUTORIAL_PROGRESS });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const assigneBadge = (id) => (dispatch, getState) => {
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
var badge = res.data.badge;
|
||||||
|
var user = getState().auth.user;
|
||||||
|
user.badges.push(badge._id);
|
||||||
|
dispatch({
|
||||||
|
type: MYBADGES_DISCONNECT,
|
||||||
|
payload: user
|
||||||
|
});
|
||||||
|
dispatch(returnSuccess(badge, res.status, 'ASSIGNE_BADGE_SUCCESS'));
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'ASSIGNE_BADGE_FAIL'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
axios.put(`${process.env.REACT_APP_BLOCKLY_API}/user/badge/${id}`, {}, config)
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if(err.response && err.response.status !== 401){
|
||||||
|
err.config.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateStatus = (status) => (dispatch, getState) => {
|
||||||
|
if(getState().auth.isAuthenticated){
|
||||||
|
// update user account in database - sync with redux store
|
||||||
|
axios.put(`${process.env.REACT_APP_BLOCKLY_API}/user/status`, {status: status})
|
||||||
|
.then(res => {
|
||||||
|
// dispatch(returnSuccess(badge, res.status, 'UPDATE_STATUS_SUCCESS'));
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if(err.response){
|
||||||
|
// dispatch(returnErrors(err.response.data.message, err.response.status, 'UPDATE_STATUS_FAIL'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// update locale storage - sync with redux store
|
||||||
|
window.localStorage.setItem('status', JSON.stringify(status));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteTutorial = (id) => (dispatch, getState) => {
|
||||||
|
var tutorial = getState().tutorial;
|
||||||
|
var id = getState().builder.id;
|
||||||
|
const config = {
|
||||||
|
success: res => {
|
||||||
|
var tutorials = tutorial.tutorials;
|
||||||
|
var index = tutorials.findIndex(res => res._id === id);
|
||||||
|
tutorials.splice(index, 1)
|
||||||
|
dispatch({
|
||||||
|
type: GET_TUTORIALS,
|
||||||
|
payload: tutorials
|
||||||
|
});
|
||||||
|
dispatch(returnSuccess(res.data.message, res.status, 'TUTORIAL_DELETE_SUCCESS'));
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
dispatch(returnErrors(err.response.data.message, err.response.status, 'TUTORIAL_DELETE_FAIL'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
axios.delete(`${process.env.REACT_APP_BLOCKLY_API}/tutorial/${id}`, config)
|
||||||
|
.then(res => {
|
||||||
|
res.config.success(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if(err.response && err.response.status !== 401){
|
||||||
|
err.config.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const resetTutorial = () => (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: GET_TUTORIALS,
|
||||||
|
payload: []
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
type: TUTORIAL_STEP,
|
||||||
|
payload: 0
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const tutorialChange = () => (dispatch) => {
|
export const tutorialChange = () => (dispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -10,9 +156,9 @@ export const tutorialChange = () => (dispatch) => {
|
|||||||
|
|
||||||
export const tutorialCheck = (status, step) => (dispatch, getState) => {
|
export const tutorialCheck = (status, step) => (dispatch, getState) => {
|
||||||
var tutorialsStatus = getState().tutorial.status;
|
var tutorialsStatus = getState().tutorial.status;
|
||||||
var id = getState().tutorial.currentId;
|
var id = getState().tutorial.tutorials[0]._id;
|
||||||
var tutorialsStatusIndex = tutorialsStatus.findIndex(tutorialStatus => tutorialStatus.id === id);
|
var tutorialsStatusIndex = tutorialsStatus.findIndex(tutorialStatus => tutorialStatus._id === id);
|
||||||
var tasksIndex = tutorialsStatus[tutorialsStatusIndex].tasks.findIndex(task => task.id === step.id);
|
var tasksIndex = tutorialsStatus[tutorialsStatusIndex].tasks.findIndex(task => task._id === step._id);
|
||||||
tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex] = {
|
tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex] = {
|
||||||
...tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex],
|
...tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex],
|
||||||
type: status
|
type: status
|
||||||
@@ -21,18 +167,22 @@ export const tutorialCheck = (status, step) => (dispatch, getState) => {
|
|||||||
type: status === 'success' ? TUTORIAL_SUCCESS : TUTORIAL_ERROR,
|
type: status === 'success' ? TUTORIAL_SUCCESS : TUTORIAL_ERROR,
|
||||||
payload: tutorialsStatus
|
payload: tutorialsStatus
|
||||||
});
|
});
|
||||||
|
console.log('drei');
|
||||||
|
dispatch(updateStatus(tutorialsStatus));
|
||||||
dispatch(tutorialChange());
|
dispatch(tutorialChange());
|
||||||
|
dispatch(returnSuccess('', '', 'TUTORIAL_CHECK_SUCCESS'));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const storeTutorialXml = (code) => (dispatch, getState) => {
|
export const storeTutorialXml = (code) => (dispatch, getState) => {
|
||||||
var id = getState().tutorial.currentId;
|
var tutorial = getState().tutorial.tutorials[0];
|
||||||
if (id !== null) {
|
if (tutorial) {
|
||||||
|
var id = tutorial._id;
|
||||||
var activeStep = getState().tutorial.activeStep;
|
var activeStep = getState().tutorial.activeStep;
|
||||||
var steps = tutorials.filter(tutorial => tutorial.id === id)[0].steps;
|
var steps = tutorial.steps;
|
||||||
if (steps[activeStep].type === 'task') {
|
if (steps && steps[activeStep].type === 'task') {
|
||||||
var tutorialsStatus = getState().tutorial.status;
|
var tutorialsStatus = getState().tutorial.status;
|
||||||
var tutorialsStatusIndex = tutorialsStatus.findIndex(tutorialStatus => tutorialStatus.id === id);
|
var tutorialsStatusIndex = tutorialsStatus.findIndex(tutorialStatus => tutorialStatus._id === id);
|
||||||
var tasksIndex = tutorialsStatus[tutorialsStatusIndex].tasks.findIndex(task => task.id === steps[activeStep].id);
|
var tasksIndex = tutorialsStatus[tutorialsStatusIndex].tasks.findIndex(task => task._id === steps[activeStep]._id);
|
||||||
tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex] = {
|
tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex] = {
|
||||||
...tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex],
|
...tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex],
|
||||||
xml: code
|
xml: code
|
||||||
@@ -41,21 +191,58 @@ export const storeTutorialXml = (code) => (dispatch, getState) => {
|
|||||||
type: TUTORIAL_XML,
|
type: TUTORIAL_XML,
|
||||||
payload: tutorialsStatus
|
payload: tutorialsStatus
|
||||||
});
|
});
|
||||||
|
dispatch(updateStatus(tutorialsStatus));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const tutorialId = (id) => (dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: TUTORIAL_ID,
|
|
||||||
payload: id
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const tutorialStep = (step) => (dispatch) => {
|
export const tutorialStep = (step) => (dispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: TUTORIAL_STEP,
|
type: TUTORIAL_STEP,
|
||||||
payload: step
|
payload: step
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const existingTutorials = (tutorials, status) => new Promise(function (resolve, reject) {
|
||||||
|
var newstatus;
|
||||||
|
new Promise(function (resolve, reject) {
|
||||||
|
var existingTutorialIds = tutorials.map((tutorial, i) => {
|
||||||
|
existingTutorial(tutorial, status).then(status => {
|
||||||
|
newstatus = status;
|
||||||
|
});
|
||||||
|
return tutorial._id;
|
||||||
|
});
|
||||||
|
resolve(existingTutorialIds)
|
||||||
|
}).then(existingTutorialIds => {
|
||||||
|
// deleting old tutorials which do not longer exist
|
||||||
|
if (existingTutorialIds.length > 0) {
|
||||||
|
status = newstatus.filter(status => existingTutorialIds.indexOf(status._id) > -1);
|
||||||
|
}
|
||||||
|
resolve(status);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const existingTutorial = (tutorial, status) => new Promise(function(resolve, reject){
|
||||||
|
var tutorialsId = tutorial._id;
|
||||||
|
var statusIndex = status.findIndex(status => status._id === tutorialsId);
|
||||||
|
if (statusIndex > -1) {
|
||||||
|
var tasks = tutorial.steps.filter(step => step.type === 'task');
|
||||||
|
var existingTaskIds = tasks.map((task, j) => {
|
||||||
|
var tasksId = task._id;
|
||||||
|
if (status[statusIndex].tasks.findIndex(task => task._id === tasksId) === -1) {
|
||||||
|
// task does not exist
|
||||||
|
status[statusIndex].tasks.push({ _id: tasksId });
|
||||||
|
}
|
||||||
|
return tasksId;
|
||||||
|
});
|
||||||
|
// deleting old tasks which do not longer exist
|
||||||
|
if (existingTaskIds.length > 0) {
|
||||||
|
status[statusIndex].tasks = status[statusIndex].tasks.filter(task => existingTaskIds.indexOf(task._id) > -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status.push({ _id: tutorialsId, tasks: tutorial.steps.filter(step => step.type === 'task').map(task => { return { _id: task._id }; }) });
|
||||||
|
}
|
||||||
|
resolve(status);
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PROGRESS, JSON_STRING, BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP, BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from './types';
|
import { PROGRESS, JSON_STRING, BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_BADGE, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP, BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from './types';
|
||||||
|
|
||||||
import data from '../data/hardware.json';
|
import data from '../data/hardware.json';
|
||||||
|
|
||||||
@@ -39,6 +39,14 @@ export const tutorialId = (id) => (dispatch) => {
|
|||||||
dispatch(changeTutorialBuilder());
|
dispatch(changeTutorialBuilder());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const tutorialBadge = (badge) => (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: BUILDER_BADGE,
|
||||||
|
payload: badge
|
||||||
|
});
|
||||||
|
dispatch(changeTutorialBuilder());
|
||||||
|
};
|
||||||
|
|
||||||
export const addStep = (index) => (dispatch, getState) => {
|
export const addStep = (index) => (dispatch, getState) => {
|
||||||
var steps = getState().builder.steps;
|
var steps = getState().builder.steps;
|
||||||
var step = {
|
var step = {
|
||||||
@@ -180,16 +188,19 @@ export const setSubmitError = () => (dispatch, getState) => {
|
|||||||
// if(builder.id === undefined || builder.id === ''){
|
// if(builder.id === undefined || builder.id === ''){
|
||||||
// dispatch(setError(undefined, 'id'));
|
// dispatch(setError(undefined, 'id'));
|
||||||
// }
|
// }
|
||||||
if (builder.id === undefined || builder.title === '') {
|
if (builder.title === '') {
|
||||||
dispatch(setError(undefined, 'title'));
|
dispatch(setError(undefined, 'title'));
|
||||||
}
|
}
|
||||||
|
if (builder.title === null) {
|
||||||
|
dispatch(setError(undefined, 'badge'));
|
||||||
|
}
|
||||||
var type = builder.steps.map((step, i) => {
|
var type = builder.steps.map((step, i) => {
|
||||||
// media 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 => /^[0-9a-fA-F]{24}$/.test(requirement));
|
||||||
if (requirements.length < step.requirements.length) {
|
if (requirements.length < step.requirements.length) {
|
||||||
dispatch(changeContent(requirements, i, 'requirements'));
|
dispatch(changeContent(requirements, i, 'requirements'));
|
||||||
}
|
}
|
||||||
@@ -222,7 +233,7 @@ export const setSubmitError = () => (dispatch, getState) => {
|
|||||||
export const checkError = () => (dispatch, getState) => {
|
export const checkError = () => (dispatch, getState) => {
|
||||||
dispatch(setSubmitError());
|
dispatch(setSubmitError());
|
||||||
var error = getState().builder.error;
|
var error = getState().builder.error;
|
||||||
if (error.id || error.title || error.type) {
|
if (error.id || error.title || error.badge ||error.type) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (var i = 0; i < error.steps.length; i++) {
|
for (var i = 0; i < error.steps.length; i++) {
|
||||||
@@ -243,10 +254,9 @@ export const progress = (inProgress) => (dispatch) => {
|
|||||||
export const resetTutorial = () => (dispatch, getState) => {
|
export const resetTutorial = () => (dispatch, getState) => {
|
||||||
dispatch(jsonString(''));
|
dispatch(jsonString(''));
|
||||||
dispatch(tutorialTitle(''));
|
dispatch(tutorialTitle(''));
|
||||||
dispatch(tutorialId(''));
|
dispatch(tutorialBadge(undefined));
|
||||||
var steps = [
|
var steps = [
|
||||||
{
|
{
|
||||||
id: 1,
|
|
||||||
type: 'instruction',
|
type: 'instruction',
|
||||||
headline: '',
|
headline: '',
|
||||||
text: '',
|
text: '',
|
||||||
@@ -274,7 +284,7 @@ export const readJSON = (json) => (dispatch, getState) => {
|
|||||||
// accept only valid attributes
|
// accept only valid attributes
|
||||||
var steps = json.steps.map((step, i) => {
|
var steps = json.steps.map((step, i) => {
|
||||||
var object = {
|
var object = {
|
||||||
id: step.id,
|
_id: step._id,
|
||||||
type: step.type,
|
type: step.type,
|
||||||
headline: step.headline,
|
headline: step.headline,
|
||||||
text: step.text
|
text: step.text
|
||||||
@@ -298,7 +308,7 @@ export const readJSON = (json) => (dispatch, getState) => {
|
|||||||
return object;
|
return object;
|
||||||
});
|
});
|
||||||
dispatch(tutorialTitle(json.title));
|
dispatch(tutorialTitle(json.title));
|
||||||
dispatch(tutorialId(json.id));
|
dispatch(tutorialBadge(json.badge));
|
||||||
dispatch(tutorialSteps(steps));
|
dispatch(tutorialSteps(steps));
|
||||||
dispatch(setSubmitError());
|
dispatch(setSubmitError());
|
||||||
dispatch(progress(false));
|
dispatch(progress(false));
|
||||||
|
|||||||
@@ -1,3 +1,16 @@
|
|||||||
|
// authentication
|
||||||
|
export const USER_LOADING = 'USER_LOADING';
|
||||||
|
export const USER_LOADED = 'USER_LOADED';
|
||||||
|
export const AUTH_ERROR = 'AUTH_ERROR';
|
||||||
|
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
|
||||||
|
export const LOGIN_FAIL = 'LOGIN_FAIL';
|
||||||
|
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';
|
||||||
|
export const LOGOUT_FAIL = 'LOGOUT_FAIL';
|
||||||
|
export const REFRESH_TOKEN_FAIL = 'REFRESH_TOKEN_FAIL';
|
||||||
|
export const REFRESH_TOKEN_SUCCESS = 'REFRESH_TOKEN_SUCCESS';
|
||||||
|
export const MYBADGES_CONNECT = 'MYBADGES_CONNECT';
|
||||||
|
export const MYBADGES_DISCONNECT = 'MYBADGES_DISCONNECT';
|
||||||
|
|
||||||
export const NEW_CODE = 'NEW_CODE';
|
export const NEW_CODE = 'NEW_CODE';
|
||||||
export const CHANGE_WORKSPACE = 'CHANGE_WORKSPACE';
|
export const CHANGE_WORKSPACE = 'CHANGE_WORKSPACE';
|
||||||
export const CREATE_BLOCK = 'CREATE_BLOCK';
|
export const CREATE_BLOCK = 'CREATE_BLOCK';
|
||||||
@@ -7,7 +20,10 @@ export const DELETE_BLOCK = 'DELETE_BLOCK';
|
|||||||
export const CLEAR_STATS = 'CLEAR_STATS';
|
export const CLEAR_STATS = 'CLEAR_STATS';
|
||||||
export const NAME = 'NAME';
|
export const NAME = 'NAME';
|
||||||
|
|
||||||
|
export const TUTORIAL_PROGRESS = 'TUTORIAL_PROGRESS';
|
||||||
|
export const GET_TUTORIAL = 'GET_TUTORIAL';
|
||||||
|
export const GET_TUTORIALS = 'GET_TUTORIALS';
|
||||||
|
export const GET_STATUS = 'GET_STATUS';
|
||||||
export const TUTORIAL_SUCCESS = 'TUTORIAL_SUCCESS';
|
export const TUTORIAL_SUCCESS = 'TUTORIAL_SUCCESS';
|
||||||
export const TUTORIAL_ERROR = 'TUTORIAL_ERROR';
|
export const TUTORIAL_ERROR = 'TUTORIAL_ERROR';
|
||||||
export const TUTORIAL_CHANGE = 'TUTORIAL_CHANGE';
|
export const TUTORIAL_CHANGE = 'TUTORIAL_CHANGE';
|
||||||
@@ -19,6 +35,7 @@ export const JSON_STRING = 'JSON_STRING';
|
|||||||
|
|
||||||
export const BUILDER_CHANGE = 'BUILDER_CHANGE';
|
export const BUILDER_CHANGE = 'BUILDER_CHANGE';
|
||||||
export const BUILDER_TITLE = 'BUILDER_TITLE';
|
export const BUILDER_TITLE = 'BUILDER_TITLE';
|
||||||
|
export const BUILDER_BADGE = 'BUILDER_BADGE';
|
||||||
export const BUILDER_ID = 'BUILDER_ID';
|
export const BUILDER_ID = 'BUILDER_ID';
|
||||||
export const BUILDER_ADD_STEP = 'BUILDER_ADD_STEP';
|
export const BUILDER_ADD_STEP = 'BUILDER_ADD_STEP';
|
||||||
export const BUILDER_DELETE_STEP = 'BUILDER_DELETE_STEP';
|
export const BUILDER_DELETE_STEP = 'BUILDER_DELETE_STEP';
|
||||||
@@ -30,3 +47,19 @@ export const PROGRESS = 'PROGRESS';
|
|||||||
|
|
||||||
|
|
||||||
export const VISIT = 'VISIT';
|
export const VISIT = 'VISIT';
|
||||||
|
export const LANGUAGE = 'LANGUAGE';
|
||||||
|
export const RENDERER = 'RENDERER';
|
||||||
|
export const STATISTICS = 'STATISTICS';
|
||||||
|
|
||||||
|
// messages
|
||||||
|
export const GET_ERRORS = 'GET_ERRORS';
|
||||||
|
export const GET_SUCCESS = 'GET_SUCCESS';
|
||||||
|
export const CLEAR_MESSAGES = 'CLEAR_MESSAGES';
|
||||||
|
|
||||||
|
|
||||||
|
// projects: share, gallery, project
|
||||||
|
export const PROJECT_PROGRESS = 'PROJECT_PROGRESS';
|
||||||
|
export const GET_PROJECT = 'GET_PROJECT';
|
||||||
|
export const GET_PROJECTS = 'GET_PROJECTS';
|
||||||
|
export const PROJECT_TYPE = 'PROJECT_TYPE';
|
||||||
|
export const PROJECT_DESCRIPTION = 'PROJECT_DESCRIPTION';
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import { fade } from '@material-ui/core/styles/colorManipulator';
|
||||||
|
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
alert: {
|
||||||
|
marginBottom: '20px',
|
||||||
|
border: `1px solid ${theme.palette.primary.main}`,
|
||||||
|
padding: '10px 20px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
background: fade(theme.palette.primary.main, 0.3),
|
||||||
|
color: 'rgb(70,70,70)'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export class Alert extends Component {
|
||||||
|
|
||||||
|
render(){
|
||||||
|
return(
|
||||||
|
<div className={this.props.classes.alert}>
|
||||||
|
<Typography>
|
||||||
|
{this.props.children}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default withStyles(styles, { withTheme: true })(Alert);
|
||||||
@@ -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>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ class BlocklySvg extends Component {
|
|||||||
var css = '<defs><style type="text/css" xmlns="http://www.w3.org/1999/xhtml"><![CDATA[' + cssContent + ']]></style></defs>';
|
var css = '<defs><style type="text/css" xmlns="http://www.w3.org/1999/xhtml"><![CDATA[' + cssContent + ']]></style></defs>';
|
||||||
var bbox = document.getElementsByClassName("blocklyBlockCanvas")[0].getBBox();
|
var bbox = document.getElementsByClassName("blocklyBlockCanvas")[0].getBBox();
|
||||||
var content = new XMLSerializer().serializeToString(canvas);
|
var content = new XMLSerializer().serializeToString(canvas);
|
||||||
|
|
||||||
var xml = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
var xml = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
width="${bbox.width}" height="${bbox.height}" viewBox="${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}">
|
width="${bbox.width}" height="${bbox.height}" viewBox="${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}">
|
||||||
${css}">${content}</svg>`;
|
${css}">${content}</svg>`;
|
||||||
@@ -65,7 +64,7 @@ class BlocklySvg extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{display: 'flex', justifyContent: 'center', transform: 'scale(0.8) translate(0, calc(100% * -0.2 / 2))'}}
|
style={{display: 'inline-flex', justifyContent: 'center', transform: 'scale(0.8) translate(0, calc(100% * -0.2 / 2))'}}
|
||||||
dangerouslySetInnerHTML={{ __html: this.state.svg }}
|
dangerouslySetInnerHTML={{ __html: this.state.svg }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ 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 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';
|
||||||
import './blocks/index';
|
import './blocks/index';
|
||||||
import './generator/index';
|
import './generator/index';
|
||||||
import { initialXml } from './initialXml.js';
|
|
||||||
|
|
||||||
|
import { initialXml } from './initialXml.js';
|
||||||
|
|
||||||
|
|
||||||
class BlocklyWindow extends Component {
|
class BlocklyWindow extends Component {
|
||||||
@@ -18,7 +18,6 @@ class BlocklyWindow extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.simpleWorkspace = React.createRef();
|
this.simpleWorkspace = React.createRef();
|
||||||
Blockly.setLocale(De);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -46,6 +45,15 @@ class BlocklyWindow extends Component {
|
|||||||
if (!xml) xml = initialXml;
|
if (!xml) xml = initialXml;
|
||||||
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), workspace);
|
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), workspace);
|
||||||
}
|
}
|
||||||
|
if(props.language !== this.props.language){
|
||||||
|
// change language
|
||||||
|
if (!xml) xml = initialXml;
|
||||||
|
var xmlDom = Blockly.Xml.textToDom(xml);
|
||||||
|
Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace);
|
||||||
|
// var toolbox = workspace.getToolbox();
|
||||||
|
// console.log(toolbox);
|
||||||
|
// workspace.updateToolbox(toolbox.toolboxDef_);
|
||||||
|
}
|
||||||
Blockly.svgResize(workspace);
|
Blockly.svgResize(workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +64,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.props.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,
|
||||||
@@ -90,8 +98,14 @@ class BlocklyWindow extends Component {
|
|||||||
|
|
||||||
BlocklyWindow.propTypes = {
|
BlocklyWindow.propTypes = {
|
||||||
onChangeWorkspace: PropTypes.func.isRequired,
|
onChangeWorkspace: PropTypes.func.isRequired,
|
||||||
clearStats: PropTypes.func.isRequired
|
clearStats: PropTypes.func.isRequired,
|
||||||
|
renderer: PropTypes.string.isRequired,
|
||||||
|
language: PropTypes.string.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
renderer: state.general.renderer,
|
||||||
|
language: state.general.language
|
||||||
|
});
|
||||||
|
|
||||||
export default connect(null, { onChangeWorkspace, clearStats })(BlocklyWindow);
|
export default connect(mapStateToProps, { onChangeWorkspace, clearStats })(BlocklyWindow);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import './sensebox-display';
|
|||||||
import './sensebox-lora';
|
import './sensebox-lora';
|
||||||
import './sensebox-led';
|
import './sensebox-led';
|
||||||
import './sensebox-sd';
|
import './sensebox-sd';
|
||||||
|
import './mqtt';
|
||||||
import './text';
|
import './text';
|
||||||
import './io';
|
import './io';
|
||||||
import './audio';
|
import './audio';
|
||||||
@@ -17,5 +18,7 @@ import './map';
|
|||||||
import './procedures';
|
import './procedures';
|
||||||
import './time';
|
import './time';
|
||||||
import './variables';
|
import './variables';
|
||||||
|
import './lists';
|
||||||
|
import './webserver';
|
||||||
|
|
||||||
import '../helpers/types'
|
import '../helpers/types'
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import Blockly, { FieldDropdown } from 'blockly/core'
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -4,6 +4,239 @@ import * as Types from '../helpers/types';
|
|||||||
import { getCompatibleTypes } from '../helpers/types';
|
import { getCompatibleTypes } from '../helpers/types';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['controls_if'] = {
|
||||||
|
/**
|
||||||
|
* Block for if/elseif/else condition.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
init: function () {
|
||||||
|
this.setHelpUrl(Blockly.Msg.CONTROLS_IF_HELPURL);
|
||||||
|
this.setColour(getColour().logic);
|
||||||
|
this.appendValueInput('IF0')
|
||||||
|
.setCheck(Types.getCompatibleTypes('boolean'))
|
||||||
|
.appendField(Blockly.Msg.CONTROLS_IF_MSG_IF);
|
||||||
|
this.appendStatementInput('DO0')
|
||||||
|
.appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);
|
||||||
|
this.setPreviousStatement(true);
|
||||||
|
this.setNextStatement(true);
|
||||||
|
this.setMutator(new Blockly.Mutator(['controls_if_elseif',
|
||||||
|
'controls_if_else']));
|
||||||
|
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||||
|
var thisBlock = this;
|
||||||
|
this.setTooltip(function () {
|
||||||
|
if (!thisBlock.elseifCount_ && !thisBlock.elseCount_) {
|
||||||
|
return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;
|
||||||
|
} else if (!thisBlock.elseifCount_ && thisBlock.elseCount_) {
|
||||||
|
return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;
|
||||||
|
} else if (thisBlock.elseifCount_ && !thisBlock.elseCount_) {
|
||||||
|
return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;
|
||||||
|
} else if (thisBlock.elseifCount_ && thisBlock.elseCount_) {
|
||||||
|
return Blockly.Msg.CONTROLS_IF_TOOLTIP_4;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
this.elseifCount_ = 0;
|
||||||
|
this.elseCount_ = 0;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Create XML to represent the number of else-if and else inputs.
|
||||||
|
* @return {Element} XML storage element.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
mutationToDom: function () {
|
||||||
|
if (!this.elseifCount_ && !this.elseCount_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var container = document.createElement('mutation');
|
||||||
|
if (this.elseifCount_) {
|
||||||
|
container.setAttribute('elseif', this.elseifCount_);
|
||||||
|
}
|
||||||
|
if (this.elseCount_) {
|
||||||
|
container.setAttribute('else', 1);
|
||||||
|
}
|
||||||
|
return container;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Parse XML to restore the else-if and else inputs.
|
||||||
|
* @param {!Element} xmlElement XML storage element.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
domToMutation: function (xmlElement) {
|
||||||
|
this.elseifCount_ = parseInt(xmlElement.getAttribute('elseif'), 10) || 0;
|
||||||
|
this.elseCount_ = parseInt(xmlElement.getAttribute('else'), 10) || 0;
|
||||||
|
this.updateShape_();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Populate the mutator's dialog with this block's components.
|
||||||
|
* @param {!Blockly.Workspace} workspace Mutator's workspace.
|
||||||
|
* @return {!Blockly.Block} Root block in mutator.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
decompose: function (workspace) {
|
||||||
|
var containerBlock = workspace.newBlock('controls_if_if');
|
||||||
|
containerBlock.initSvg();
|
||||||
|
var connection = containerBlock.nextConnection;
|
||||||
|
for (var i = 1; i <= this.elseifCount_; i++) {
|
||||||
|
var elseifBlock = workspace.newBlock('controls_if_elseif');
|
||||||
|
elseifBlock.initSvg();
|
||||||
|
connection.connect(elseifBlock.previousConnection);
|
||||||
|
connection = elseifBlock.nextConnection;
|
||||||
|
}
|
||||||
|
if (this.elseCount_) {
|
||||||
|
var elseBlock = workspace.newBlock('controls_if_else');
|
||||||
|
elseBlock.initSvg();
|
||||||
|
connection.connect(elseBlock.previousConnection);
|
||||||
|
}
|
||||||
|
return containerBlock;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Reconfigure this block based on the mutator dialog's components.
|
||||||
|
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
compose: function (containerBlock) {
|
||||||
|
var clauseBlock = containerBlock.nextConnection.targetBlock();
|
||||||
|
// Count number of inputs.
|
||||||
|
this.elseifCount_ = 0;
|
||||||
|
this.elseCount_ = 0;
|
||||||
|
var valueConnections = [null];
|
||||||
|
var statementConnections = [null];
|
||||||
|
var elseStatementConnection = null;
|
||||||
|
while (clauseBlock) {
|
||||||
|
switch (clauseBlock.type) {
|
||||||
|
case 'controls_if_elseif':
|
||||||
|
this.elseifCount_++;
|
||||||
|
valueConnections.push(clauseBlock.valueConnection_);
|
||||||
|
statementConnections.push(clauseBlock.statementConnection_);
|
||||||
|
break;
|
||||||
|
case 'controls_if_else':
|
||||||
|
this.elseCount_++;
|
||||||
|
elseStatementConnection = clauseBlock.statementConnection_;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown block type.');
|
||||||
|
}
|
||||||
|
clauseBlock = clauseBlock.nextConnection &&
|
||||||
|
clauseBlock.nextConnection.targetBlock();
|
||||||
|
}
|
||||||
|
this.updateShape_();
|
||||||
|
// Reconnect any child blocks.
|
||||||
|
for (var i = 1; i <= this.elseifCount_; i++) {
|
||||||
|
Blockly.Mutator.reconnect(valueConnections[i], this, 'IF' + i);
|
||||||
|
Blockly.Mutator.reconnect(statementConnections[i], this, 'DO' + i);
|
||||||
|
}
|
||||||
|
Blockly.Mutator.reconnect(elseStatementConnection, this, 'ELSE');
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Store pointers to any connected child blocks.
|
||||||
|
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
saveConnections: function (containerBlock) {
|
||||||
|
var clauseBlock = containerBlock.nextConnection.targetBlock();
|
||||||
|
var i = 1;
|
||||||
|
while (clauseBlock) {
|
||||||
|
switch (clauseBlock.type) {
|
||||||
|
case 'controls_if_elseif':
|
||||||
|
var inputIf = this.getInput('IF' + i);
|
||||||
|
var inputDo = this.getInput('DO' + i);
|
||||||
|
clauseBlock.valueConnection_ =
|
||||||
|
inputIf && inputIf.connection.targetConnection;
|
||||||
|
clauseBlock.statementConnection_ =
|
||||||
|
inputDo && inputDo.connection.targetConnection;
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
case 'controls_if_else':
|
||||||
|
var inputDo = this.getInput('ELSE');
|
||||||
|
clauseBlock.statementConnection_ =
|
||||||
|
inputDo && inputDo.connection.targetConnection;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown block type.');
|
||||||
|
}
|
||||||
|
clauseBlock = clauseBlock.nextConnection &&
|
||||||
|
clauseBlock.nextConnection.targetBlock();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Modify this block to have the correct number of inputs.
|
||||||
|
* @private
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
updateShape_: function () {
|
||||||
|
// Delete everything.
|
||||||
|
if (this.getInput('ELSE')) {
|
||||||
|
this.removeInput('ELSE');
|
||||||
|
}
|
||||||
|
var i = 1;
|
||||||
|
while (this.getInput('IF' + i)) {
|
||||||
|
this.removeInput('IF' + i);
|
||||||
|
this.removeInput('DO' + i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
// Rebuild block.
|
||||||
|
for (var i = 1; i <= this.elseifCount_; i++) {
|
||||||
|
this.appendValueInput('IF' + i)
|
||||||
|
.setCheck(Types.getCompatibleTypes('boolean'))
|
||||||
|
.appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF);
|
||||||
|
this.appendStatementInput('DO' + i)
|
||||||
|
.appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);
|
||||||
|
}
|
||||||
|
if (this.elseCount_) {
|
||||||
|
this.appendStatementInput('ELSE')
|
||||||
|
.appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['controls_if_if'] = {
|
||||||
|
/**
|
||||||
|
* Mutator block for if container.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
init: function () {
|
||||||
|
this.setColour(getColour().logic);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.CONTROLS_IF_IF_TITLE_IF);
|
||||||
|
this.setNextStatement(true);
|
||||||
|
this.setTooltip(Blockly.Msg.CONTROLS_IF_IF_TOOLTIP);
|
||||||
|
this.contextMenu = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['controls_if_elseif'] = {
|
||||||
|
/**
|
||||||
|
* Mutator bolck for else-if condition.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
init: function () {
|
||||||
|
this.setColour(getColour().logic);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.CONTROLS_IF_ELSEIF_TITLE_ELSEIF);
|
||||||
|
this.setPreviousStatement(true);
|
||||||
|
this.setNextStatement(true);
|
||||||
|
this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSEIF_TOOLTIP);
|
||||||
|
this.contextMenu = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['controls_if_else'] = {
|
||||||
|
/**
|
||||||
|
* Mutator block for else condition.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
init: function () {
|
||||||
|
this.setColour(getColour().logic);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE);
|
||||||
|
this.setPreviousStatement(true);
|
||||||
|
this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP);
|
||||||
|
this.contextMenu = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||||
// Block for boolean data type: true and false.
|
// Block for boolean data type: true and false.
|
||||||
{
|
{
|
||||||
@@ -24,32 +257,6 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
|||||||
"tooltip": "%{BKY_LOGIC_BOOLEAN_TOOLTIP}",
|
"tooltip": "%{BKY_LOGIC_BOOLEAN_TOOLTIP}",
|
||||||
"helpUrl": "%{BKY_LOGIC_BOOLEAN_HELPURL}"
|
"helpUrl": "%{BKY_LOGIC_BOOLEAN_HELPURL}"
|
||||||
},
|
},
|
||||||
// Block for if/elseif/else condition.
|
|
||||||
{
|
|
||||||
"type": "controls_if",
|
|
||||||
"message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
|
|
||||||
"args0": [
|
|
||||||
{
|
|
||||||
"type": "input_value",
|
|
||||||
"name": "IF0",
|
|
||||||
"check": Types.getCompatibleTypes('boolean')
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1",
|
|
||||||
"args1": [
|
|
||||||
{
|
|
||||||
"type": "input_statement",
|
|
||||||
"name": "DO0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"previousStatement": null,
|
|
||||||
"nextStatement": null,
|
|
||||||
"style": "logic_blocks",
|
|
||||||
"helpUrl": "%{BKY_CONTROLS_IF_HELPURL}",
|
|
||||||
"mutator": "controls_if_mutator",
|
|
||||||
"extensions": ["controls_if_tooltip"]
|
|
||||||
},
|
|
||||||
// If/else block that does not use a mutator.
|
|
||||||
{
|
{
|
||||||
"type": "controls_ifelse",
|
"type": "controls_ifelse",
|
||||||
"message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
|
"message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
|
||||||
@@ -183,14 +390,16 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
|||||||
"args1": [
|
"args1": [
|
||||||
{
|
{
|
||||||
"type": "input_value",
|
"type": "input_value",
|
||||||
"name": "THEN"
|
"name": "THEN",
|
||||||
|
"check": Types.getCompatibleTypes('boolean'),
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"message2": "%{BKY_LOGIC_TERNARY_IF_FALSE} %1",
|
"message2": "%{BKY_LOGIC_TERNARY_IF_FALSE} %1",
|
||||||
"args2": [
|
"args2": [
|
||||||
{
|
{
|
||||||
"type": "input_value",
|
"type": "input_value",
|
||||||
"name": "ELSE"
|
"name": "ELSE",
|
||||||
|
"check": Types.getCompatibleTypes('boolean'),
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"output": null,
|
"output": null,
|
||||||
@@ -201,36 +410,6 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
|||||||
}
|
}
|
||||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||||
|
|
||||||
Blockly.defineBlocksWithJsonArray([ // Mutator blocks. Do not extract.
|
|
||||||
// Block representing the if statement in the controls_if mutator.
|
|
||||||
{
|
|
||||||
"type": "controls_if_if",
|
|
||||||
"message0": "%{BKY_CONTROLS_IF_IF_TITLE_IF}",
|
|
||||||
"nextStatement": null,
|
|
||||||
"enableContextMenu": false,
|
|
||||||
"style": "logic_blocks",
|
|
||||||
"tooltip": "%{BKY_CONTROLS_IF_IF_TOOLTIP}"
|
|
||||||
},
|
|
||||||
// Block representing the else-if statement in the controls_if mutator.
|
|
||||||
{
|
|
||||||
"type": "controls_if_elseif",
|
|
||||||
"message0": "%{BKY_CONTROLS_IF_ELSEIF_TITLE_ELSEIF}",
|
|
||||||
"previousStatement": null,
|
|
||||||
"nextStatement": null,
|
|
||||||
"enableContextMenu": false,
|
|
||||||
"style": "logic_blocks",
|
|
||||||
"tooltip": "%{BKY_CONTROLS_IF_ELSEIF_TOOLTIP}"
|
|
||||||
},
|
|
||||||
// Block representing the else statement in the controls_if mutator.
|
|
||||||
{
|
|
||||||
"type": "controls_if_else",
|
|
||||||
"message0": "%{BKY_CONTROLS_IF_ELSE_TITLE_ELSE}",
|
|
||||||
"previousStatement": null,
|
|
||||||
"enableContextMenu": false,
|
|
||||||
"style": "logic_blocks",
|
|
||||||
"tooltip": "%{BKY_CONTROLS_IF_ELSE_TOOLTIP}"
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
Blockly.Blocks['logic_compare'] = {
|
Blockly.Blocks['logic_compare'] = {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import * as Blockly from 'blockly/core';
|
||||||
|
import { getColour } from '../helpers/colour';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQTT Blocks
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Blocks["sensebox_mqtt_setup"] = {
|
||||||
|
init: function () {
|
||||||
|
|
||||||
|
//this.setTooltip(Blockly.Msg.senseBox_wifi_);
|
||||||
|
this.setHelpUrl('');
|
||||||
|
this.setColour(getColour().mqtt);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_mqtt_init)
|
||||||
|
.appendField(new Blockly.FieldDropdown([["Adafruit IO", 'adafruitio'], ["DIOTY", 'dioty'], ["Other Service", 'custom']]), "service");
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.senseBox_mqtt_server)
|
||||||
|
.appendField(new Blockly.FieldTextInput("Server"), "server");
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.senseBox_mqtt_port)
|
||||||
|
.appendField(new Blockly.FieldTextInput("Port"), "port");
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.senseBox_mqtt_username)
|
||||||
|
.appendField(new Blockly.FieldTextInput("Username"), "username");
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.senseBox_mqtt_password, "passwordmsg")
|
||||||
|
.appendField(new Blockly.FieldTextInput("Password"), "password");
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
},
|
||||||
|
onchange: function (e) {
|
||||||
|
let service = this.getFieldValue('service');
|
||||||
|
switch (service) {
|
||||||
|
case 'adafruitio':
|
||||||
|
this.getField('server').setValue("io.adafruit.com");
|
||||||
|
this.getField('port').setValue("1883");
|
||||||
|
this.getField('passwordmsg').setValue("Adafruit IO Key");
|
||||||
|
break;
|
||||||
|
case 'dioty':
|
||||||
|
this.getField('server').setValue("mqtt.dioty.co");
|
||||||
|
this.getField('port').setValue("1883");
|
||||||
|
this.getField('passwordmsg').setValue(Blockly.Msg.senseBox_mqtt_password);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "custom":
|
||||||
|
this.getField('server').setValue("server");
|
||||||
|
this.getField('port').setValue("port");
|
||||||
|
this.getField('passwordmsg').setValue(Blockly.Msg.senseBox_mqtt_password);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks["sensebox_mqtt_publish"] = {
|
||||||
|
init: function () {
|
||||||
|
this.setColour(getColour().mqtt);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_mqtt_publish);
|
||||||
|
this.appendValueInput('value')
|
||||||
|
.setCheck(null)
|
||||||
|
.appendField('Feed/Topic')
|
||||||
|
.appendField(new Blockly.FieldTextInput('Name'), 'publishfeed');
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks["sensebox_mqtt_subscribe"] = {
|
||||||
|
init: function () {
|
||||||
|
this.setColour(getColour().mqtt);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.sensebox_mqtt_subscribe);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(new Blockly.FieldTextInput('Feedname'), 'subscribefeed');
|
||||||
|
this.setOutput(true, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -50,8 +50,6 @@ Blockly.Blocks['sensebox_display_printDisplay'] = {
|
|||||||
.setCheck(null);
|
.setCheck(null);
|
||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
let variableName = this.getField('COLOR');
|
|
||||||
console.log(variableName.getValue());
|
|
||||||
this.setTooltip(Blockly.Msg.senseBox_display_printDisplay_tip);
|
this.setTooltip(Blockly.Msg.senseBox_display_printDisplay_tip);
|
||||||
this.setHelpUrl('https://sensebox.de/books');
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
},
|
},
|
||||||
@@ -81,6 +79,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');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -119,6 +119,38 @@ Blockly.Blocks['sensebox_send_lora_sensor_value'] = {
|
|||||||
LOOP_TYPES: ['sensebox_lora_message_send'],
|
LOOP_TYPES: ['sensebox_lora_message_send'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_lora_ttn_mapper'] = {
|
||||||
|
init: function (block) {
|
||||||
|
this.setColour(getColour().sensebox);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField("TTN Mapper");
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField("Fix Type Limit")
|
||||||
|
.appendField(new Blockly.FieldDropdown([["0", "0"], ["1", "1"], ["2", "2"], ["3", "3"]].reverse()), "dropdown");
|
||||||
|
// reverse() because i want 3 be be at first and i'm to lazy to write the array again
|
||||||
|
this.appendValueInput('Latitude')
|
||||||
|
.appendField(Blockly.Msg.senseBox_gps_lat)
|
||||||
|
.setCheck(null);
|
||||||
|
this.appendValueInput('Longitude')
|
||||||
|
.appendField(Blockly.Msg.senseBox_gps_lng)
|
||||||
|
.setCheck(null);
|
||||||
|
this.appendValueInput('Altitude')
|
||||||
|
.appendField(Blockly.Msg.senseBox_gps_alt)
|
||||||
|
.setCheck(null);
|
||||||
|
this.appendValueInput('pDOP')
|
||||||
|
.appendField('pDOP')
|
||||||
|
.setCheck(null);
|
||||||
|
this.appendValueInput('Fix Type')
|
||||||
|
.appendField('Fix Type')
|
||||||
|
.setCheck(null);
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_display_printDisplay_tip);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Blockly.Blocks['sensebox_lora_cayenne_send'] = {
|
Blockly.Blocks['sensebox_lora_cayenne_send'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_tip);
|
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_tip);
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
import * as Blockly from 'blockly/core';
|
import * as Blockly from 'blockly/core';
|
||||||
import { getColour } from '../helpers/colour';
|
import { getColour } from '../helpers/colour';
|
||||||
|
|
||||||
|
import store from '../../../store';
|
||||||
|
|
||||||
|
var boxes = store.getState().auth.user ? store.getState().auth.user.boxes : null;
|
||||||
|
store.subscribe(() => {
|
||||||
|
boxes = store.getState().auth.user ? store.getState().auth.user.boxes : null;
|
||||||
|
});
|
||||||
|
var selectedBox = '';
|
||||||
|
|
||||||
|
|
||||||
Blockly.Blocks['sensebox_osem_connection'] = {
|
Blockly.Blocks['sensebox_osem_connection'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
@@ -16,10 +24,25 @@ Blockly.Blocks['sensebox_osem_connection'] = {
|
|||||||
.setAlign(Blockly.ALIGN_LEFT)
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
.appendField(Blockly.Msg.senseBox_osem_exposure)
|
.appendField(Blockly.Msg.senseBox_osem_exposure)
|
||||||
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_osem_stationary, 'Stationary'], [Blockly.Msg.senseBox_osem_mobile, 'Mobile']]), "type");
|
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_osem_stationary, 'Stationary'], [Blockly.Msg.senseBox_osem_mobile, 'Mobile']]), "type");
|
||||||
|
if (!boxes) {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField("senseBox ID")
|
||||||
|
.appendField(new Blockly.FieldTextInput("senseBox ID"), "BoxID");
|
||||||
|
} else {
|
||||||
|
var dropdown = []
|
||||||
|
for (var i = 0; i < boxes.length; i++) {
|
||||||
|
dropdown.push([boxes[i].name, boxes[i]._id])
|
||||||
|
}
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField("senseBox ID")
|
||||||
|
.appendField(new Blockly.FieldDropdown(dropdown), 'BoxID');
|
||||||
|
}
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.setAlign(Blockly.ALIGN_LEFT)
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
.appendField("senseBox ID")
|
.appendField(Blockly.Msg.senseBox_osem_access_token)
|
||||||
.appendField(new Blockly.FieldTextInput("senseBox ID"), "BoxID");
|
.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,8 +50,16 @@ Blockly.Blocks['sensebox_osem_connection'] = {
|
|||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
},
|
},
|
||||||
onchange: function (e) {
|
onchange: function (e) {
|
||||||
|
selectedBox = this.getFieldValue('BoxID');
|
||||||
//Blockly.Blocks.sensebox.getDescendants = blocks;
|
console.log(selectedBox)
|
||||||
|
if (selectedBox !== '' && boxes) {
|
||||||
|
var accessToken = boxes.find(element => element._id === selectedBox).access_token
|
||||||
|
if (accessToken !== undefined) {
|
||||||
|
this.getField('access_token').setValue(accessToken)
|
||||||
|
} else {
|
||||||
|
this.getField('access_token').setValue('access_token')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
mutationToDom: function () {
|
mutationToDom: function () {
|
||||||
@@ -78,20 +109,52 @@ Blockly.Blocks['sensebox_send_to_osem'] = {
|
|||||||
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')
|
if (boxes) {
|
||||||
.setCheck(null)
|
this.appendValueInput('Value')
|
||||||
.appendField('Sensor ID')
|
.appendField('Phänomen')
|
||||||
.appendField(new Blockly.FieldTextInput('Sensor ID'), 'SensorID');
|
.appendField(new Blockly.FieldDropdown(
|
||||||
|
this.generateOptions), 'SensorID');
|
||||||
|
} else {
|
||||||
|
this.appendValueInput('Value')
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField('Phänomen')
|
||||||
|
.appendField(new Blockly.FieldTextInput(
|
||||||
|
'sensorID'), 'SensorID')
|
||||||
|
}
|
||||||
|
|
||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
generateOptions: function () {
|
||||||
|
var dropdown = [['', '']];
|
||||||
|
var boxID = selectedBox;
|
||||||
|
if (boxID !== '' && boxes) {
|
||||||
|
|
||||||
|
let box = boxes.find(el => el._id === boxID);
|
||||||
|
if (box !== undefined) {
|
||||||
|
for (var i = 0; i < box.sensors.length; i++) {
|
||||||
|
dropdown.push([box.sensors[i].title, box.sensors[i]._id])
|
||||||
|
}
|
||||||
|
console.log(dropdown)
|
||||||
|
}
|
||||||
|
if (dropdown.length > 1) {
|
||||||
|
var options = dropdown.slice(1)
|
||||||
|
return options
|
||||||
|
} else {
|
||||||
|
return dropdown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dropdown
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 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 +171,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']
|
||||||
|
};
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ Blockly.Blocks['sensebox_button'] = {
|
|||||||
|
|
||||||
Blockly.Blocks['sensebox_scd30'] = {
|
Blockly.Blocks['sensebox_scd30'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
var dropdownOptions = [[Blockly.Msg.senseBox_temp, "temperature"], [Blockly.Msg.senseBox_hum, "humidity"], [Blockly.Msg.senseBox_bme_co2, "CO2"]];
|
var dropdownOptions = [[Blockly.Msg.senseBox_scd_co2, "CO2"], [Blockly.Msg.senseBox_temp, "temperature"], [Blockly.Msg.senseBox_hum, "humidity"]];
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(Blockly.Msg.senseBox_scd30);
|
.appendField(Blockly.Msg.senseBox_scd30);
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
@@ -318,6 +318,36 @@ Blockly.Blocks['sensebox_scd30'] = {
|
|||||||
.appendField(new Blockly.FieldDropdown(dropdownOptions), "dropdown")
|
.appendField(new Blockly.FieldDropdown(dropdownOptions), "dropdown")
|
||||||
this.setOutput(true, Types.NUMBER.typeName);
|
this.setOutput(true, Types.NUMBER.typeName);
|
||||||
this.setColour(getColour().sensebox);
|
this.setColour(getColour().sensebox);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_scd_tip);
|
||||||
|
},
|
||||||
|
onchange: function (e) {
|
||||||
|
var dropdown = this.getFieldValue('dropdown');
|
||||||
|
if (dropdown === 'temperature' || dropdown === 'humidity') {
|
||||||
|
this.setOutput(true, Types.DECIMAL.typeName);
|
||||||
|
} else if (dropdown === 'CO2') {
|
||||||
|
this.setOutput(true, Types.NUMBER.typeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GPS Module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_gps'] = {
|
||||||
|
init: function () {
|
||||||
|
var dropdownOptions = [[Blockly.Msg.senseBox_gps_lat, "latitude"], [Blockly.Msg.senseBox_gps_lng, "longitude"], [Blockly.Msg.senseBox_gps_alt, "altitude"], ["pDOP", "pDOP"], ["Fix Type", "fixType"]];
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField("GPS Modul");
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField(Blockly.Msg.senseBox_value)
|
||||||
|
.appendField(new Blockly.FieldDropdown(dropdownOptions), "dropdown")
|
||||||
|
this.setOutput(true, Types.NUMBER.typeName);
|
||||||
|
this.setColour(getColour().sensebox);
|
||||||
this.setTooltip(Blockly.Msg.senseBox_bme_tip);
|
this.setTooltip(Blockly.Msg.senseBox_bme_tip);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,334 @@
|
|||||||
|
import Blockly from 'blockly/core';
|
||||||
|
import { getColour } from '../helpers/colour';
|
||||||
|
import { getCompatibleTypes } from '../helpers/types'
|
||||||
|
import * as Types from '../helpers/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webserver Blocks By Lucas Steinmann
|
||||||
|
* */
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_initialize_http_server'] = {
|
||||||
|
init: function () {
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_init_http_server_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_init_http_server);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField("Port")
|
||||||
|
.appendField(new Blockly.FieldNumber(80), "Port");
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
},
|
||||||
|
onchange: function (e) {
|
||||||
|
// Is the block nested in a loop?
|
||||||
|
var block = this;
|
||||||
|
do {
|
||||||
|
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block = block.getSurroundParent();
|
||||||
|
} while (block);
|
||||||
|
},
|
||||||
|
LOOP_TYPES: ['arduino_functions'],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_http_on_client_connect'] = {
|
||||||
|
init: function () {
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_http_on_client_connect_tip);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.appendDummyInput().appendField(Blockly.Msg.senseBox_http_on_client_connect);
|
||||||
|
this.appendStatementInput('ON_CONNECT');
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_http_method'] = {
|
||||||
|
init: function () {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_http_method)
|
||||||
|
this.setOutput(true, Types.TEXT.typeName);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_http_method_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
},
|
||||||
|
getBlockType: function () {
|
||||||
|
return Blockly.Types.TEXT;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_http_uri'] = {
|
||||||
|
init: function () {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_http_uri)
|
||||||
|
this.setOutput(true, Types.TEXT.typeName);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_http_uri_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_http_protocol_version'] = {
|
||||||
|
init: function () {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_http_protocol_version)
|
||||||
|
this.setOutput(true, Types.TEXT.typeName);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_http_protocol_version_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_ip_address'] = {
|
||||||
|
init: function () {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_ip_address);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_ip_address_tip);
|
||||||
|
this.setHelpUrl('');
|
||||||
|
this.setOutput(true, Types.TEXT.typeName);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_http_user_agent'] = {
|
||||||
|
init: function () {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_http_user_agent)
|
||||||
|
this.setOutput(true, Types.TEXT.typeName);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_http_user_agent_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_generate_html_doc'] = {
|
||||||
|
init: function () {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_html_document);
|
||||||
|
this.appendValueInput('HEADER')
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.setCheck(getCompatibleTypes('String'))
|
||||||
|
.appendField(Blockly.Msg.senseBox_html_header);
|
||||||
|
this.appendValueInput('BODY')
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.setCheck(getCompatibleTypes('String'))
|
||||||
|
.appendField(Blockly.Msg.senseBox_html_body);
|
||||||
|
this.setInputsInline(false);
|
||||||
|
this.setOutput(true, Types.TEXT.typeName);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_html_document_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_generate_http_succesful_response'] = {
|
||||||
|
init: function () {
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_http_success);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_http_success_l2);
|
||||||
|
this.appendValueInput('CONTENT')
|
||||||
|
.appendField(Blockly.Msg.senseBox_http_success_buildhtml)
|
||||||
|
.setCheck(getCompatibleTypes('String'));
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_http_success_tip);
|
||||||
|
this.setInputsInline(false);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_generate_http_not_found_response'] = {
|
||||||
|
init: function () {
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.appendDummyInput().appendField(Blockly.Msg.senseBox_http_not_found);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_http_not_found_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_general_html_tag'] = {
|
||||||
|
init: function () {
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_html_general_tag_tip);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField("<")
|
||||||
|
.appendField(new Blockly.FieldTextInput("Tag"), "TAG")
|
||||||
|
.appendField(">");
|
||||||
|
this.appendValueInput('DO0')
|
||||||
|
.setCheck(getCompatibleTypes('String'));
|
||||||
|
this.setInputsInline(false);
|
||||||
|
this.setOutput(true, Types.TEXT.typeName);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
this.setPreviousStatement(false);
|
||||||
|
this.setNextStatement(false);
|
||||||
|
this.setMutator(new Blockly.Mutator(['additional_child']));
|
||||||
|
this.additionalChildCount_ = 0;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Create XML to represent the number of else-if and else inputs.
|
||||||
|
* @return {Element} XML storage element.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
mutationToDom: function () {
|
||||||
|
if (!this.additionalChildCount_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var container = document.createElement('mutation');
|
||||||
|
if (this.additionalChildCount_) {
|
||||||
|
container.setAttribute('add_child', this.additionalChildCount_);
|
||||||
|
}
|
||||||
|
return container;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Parse XML to restore the else-if and else inputs.
|
||||||
|
* @param {!Element} xmlElement XML storage element.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
domToMutation: function (xmlElement) {
|
||||||
|
this.additionalChildCount_ = parseInt(xmlElement.getAttribute('add_child'), 10) || 0;
|
||||||
|
this.updateShape_();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Populate the mutator's dialog with this block's components.
|
||||||
|
* @param {!Blockly.Workspace} workspace Mutator's workspace.
|
||||||
|
* @return {!Blockly.Block} Root block in mutator.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
decompose: function (workspace) {
|
||||||
|
var containerBlock = workspace.newBlock('first_child');
|
||||||
|
containerBlock.initSvg();
|
||||||
|
var connection = containerBlock.nextConnection;
|
||||||
|
for (var i = 1; i <= this.additionalChildCount_; i++) {
|
||||||
|
var elseifBlock = workspace.newBlock('additional_child');
|
||||||
|
elseifBlock.initSvg();
|
||||||
|
connection.connect(elseifBlock.previousConnection);
|
||||||
|
connection = elseifBlock.nextConnection;
|
||||||
|
}
|
||||||
|
return containerBlock;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Reconfigure this block based on the mutator dialog's components.
|
||||||
|
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
compose: function (containerBlock) {
|
||||||
|
var clauseBlock = containerBlock.nextConnection.targetBlock();
|
||||||
|
// Count number of inputs.
|
||||||
|
this.additionalChildCount_ = 0;
|
||||||
|
var statementConnections = [null];
|
||||||
|
while (clauseBlock) {
|
||||||
|
switch (clauseBlock.type) {
|
||||||
|
case 'additional_child':
|
||||||
|
this.additionalChildCount_++;
|
||||||
|
statementConnections.push(clauseBlock.statementConnection_);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Unknown block type.");
|
||||||
|
}
|
||||||
|
clauseBlock = clauseBlock.nextConnection &&
|
||||||
|
clauseBlock.nextConnection.targetBlock();
|
||||||
|
}
|
||||||
|
this.updateShape_();
|
||||||
|
// Reconnect any child blocks.
|
||||||
|
for (var i = 1; i <= this.additionalChildCount_; i++) {
|
||||||
|
Blockly.Mutator.reconnect(statementConnections[i], this, 'DO' + i);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Store pointers to any connected child blocks.
|
||||||
|
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
saveConnections: function (containerBlock) {
|
||||||
|
var clauseBlock = containerBlock.nextConnection.targetBlock();
|
||||||
|
var i = 1;
|
||||||
|
while (clauseBlock) {
|
||||||
|
switch (clauseBlock.type) {
|
||||||
|
case 'additional_child':
|
||||||
|
var inputDo = this.getInput('DO' + i);
|
||||||
|
clauseBlock.statementConnection_ =
|
||||||
|
inputDo && inputDo.connection.targetConnection;
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown block type.');
|
||||||
|
}
|
||||||
|
clauseBlock = clauseBlock.nextConnection &&
|
||||||
|
clauseBlock.nextConnection.targetBlock();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Modify this block to have the correct number of inputs.
|
||||||
|
* @private
|
||||||
|
* @this Blockly.Block
|
||||||
|
*/
|
||||||
|
updateShape_: function () {
|
||||||
|
// Delete everything.
|
||||||
|
var i = 1;
|
||||||
|
while (this.getInput('DO' + i)) {
|
||||||
|
this.removeInput('DO' + i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
// Rebuild block.
|
||||||
|
for (i = 1; i <= this.additionalChildCount_; i++) {
|
||||||
|
this.appendValueInput('DO' + i, Blockly.Arduino.ORDER_NONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['first_child'] = {
|
||||||
|
init: function () {
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField("<Tag>");
|
||||||
|
this.setNextStatement(true);
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_tag_first_mutator_tip);
|
||||||
|
this.contextMenu = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Blocks['additional_child'] = {
|
||||||
|
init: function () {
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField("<Tag>");
|
||||||
|
this.setPreviousStatement(true);
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setNextStatement(true);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_tag_optional_mutator_tip);
|
||||||
|
this.contextMenu = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Additional Webserver Blocks
|
||||||
|
|
||||||
|
Blockly.Blocks['sensebox_web_readHTML'] = {
|
||||||
|
init: function () {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.senseBox_sd_web_readHTML)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.sensebox_web_readHTML_filename)
|
||||||
|
.appendField(new Blockly.FieldTextInput("index.txt"), "FILENAME");
|
||||||
|
this.setOutput(true, Types.TEXT.typeName);
|
||||||
|
this.setColour(getColour().webserver);
|
||||||
|
this.setTooltip(Blockly.Msg.senseBox_output_safetosd_tip);
|
||||||
|
this.setHelpUrl('https://sensebox.de/books');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -44,7 +44,7 @@ Blockly['Arduino'].addReservedWords(
|
|||||||
'setup,loop,if,else,for,switch,case,while,' +
|
'setup,loop,if,else,for,switch,case,while,' +
|
||||||
'do,break,continue,return,goto,define,include,' +
|
'do,break,continue,return,goto,define,include,' +
|
||||||
'HIGH,LOW,INPUT,OUTPUT,INPUT_PULLUP,true,false,' +
|
'HIGH,LOW,INPUT,OUTPUT,INPUT_PULLUP,true,false,' +
|
||||||
'interger, constants,floating,point,void,bookean,char,' +
|
'interger, constants,floating,point,void,boolean,char,' +
|
||||||
'unsigned,byte,int,word,long,float,double,string,String,array,' +
|
'unsigned,byte,int,word,long,float,double,string,String,array,' +
|
||||||
'static, volatile,const,sizeof,pinMode,digitalWrite,digitalRead,' +
|
'static, volatile,const,sizeof,pinMode,digitalWrite,digitalRead,' +
|
||||||
'analogReference,analogRead,analogWrite,tone,noTone,shiftOut,shitIn,' +
|
'analogReference,analogRead,analogWrite,tone,noTone,shiftOut,shitIn,' +
|
||||||
@@ -106,6 +106,9 @@ Blockly['Arduino'].init = function (workspace) {
|
|||||||
// creates a list of code to be setup before the setup block
|
// creates a list of code to be setup before the setup block
|
||||||
Blockly['Arduino'].setupCode_ = Object.create(null);
|
Blockly['Arduino'].setupCode_ = Object.create(null);
|
||||||
|
|
||||||
|
// creates a list of code to be setup before the setup block
|
||||||
|
Blockly['Arduino'].loraSetupCode_ = Object.create(null);
|
||||||
|
|
||||||
// creates a list of code for the loop to be runned once
|
// creates a list of code for the loop to be runned once
|
||||||
Blockly['Arduino'].loopCodeOnce_ = Object.create(null)
|
Blockly['Arduino'].loopCodeOnce_ = Object.create(null)
|
||||||
|
|
||||||
@@ -202,6 +205,7 @@ Blockly['Arduino'].finish = function (code) {
|
|||||||
let loopCodeOnce = '';
|
let loopCodeOnce = '';
|
||||||
let setupCode = '';
|
let setupCode = '';
|
||||||
let preSetupCode = '';
|
let preSetupCode = '';
|
||||||
|
let loraSetupCode = '';
|
||||||
let devVariables = '\n';
|
let devVariables = '\n';
|
||||||
|
|
||||||
for (const key in Blockly['Arduino'].libraries_) {
|
for (const key in Blockly['Arduino'].libraries_) {
|
||||||
@@ -233,7 +237,13 @@ Blockly['Arduino'].finish = function (code) {
|
|||||||
for (const key in Blockly['Arduino'].setupCode_) {
|
for (const key in Blockly['Arduino'].setupCode_) {
|
||||||
preSetupCode += Blockly['Arduino'].setupCode_[key] || '';
|
preSetupCode += Blockly['Arduino'].setupCode_[key] || '';
|
||||||
}
|
}
|
||||||
setupCode = '\nvoid setup() { \n' + preSetupCode + '\n}\n';
|
|
||||||
|
for (const key in Blockly['Arduino'].loraSetupCode_) {
|
||||||
|
loraSetupCode += Blockly['Arduino'].loraSetupCode_[key] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setupCode = '\nvoid setup() { \n' + preSetupCode + '\n' + loraSetupCode + '\n}\n';
|
||||||
|
|
||||||
let loopCode = '\nvoid loop() { \n' + loopCodeOnce + code + '\n}\n';
|
let loopCode = '\nvoid loop() { \n' + loopCodeOnce + code + '\n}\n';
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import './sensebox-display';
|
|||||||
import './sensebox-lora';
|
import './sensebox-lora';
|
||||||
import './sensebox-led';
|
import './sensebox-led';
|
||||||
import './sensebox-sd';
|
import './sensebox-sd';
|
||||||
|
import './mqtt';
|
||||||
import './logic';
|
import './logic';
|
||||||
import './text';
|
import './text';
|
||||||
import './math';
|
import './math';
|
||||||
@@ -17,5 +18,7 @@ import './audio';
|
|||||||
import './procedures';
|
import './procedures';
|
||||||
import './time';
|
import './time';
|
||||||
import './variables';
|
import './variables';
|
||||||
|
import './lists';
|
||||||
|
import './webserver';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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];
|
||||||
|
}
|
||||||
@@ -74,14 +74,14 @@ Blockly.Arduino['controls_if'] = function (Block) {
|
|||||||
conditionCode +
|
conditionCode +
|
||||||
') {\n' +
|
') {\n' +
|
||||||
branchCode +
|
branchCode +
|
||||||
'}';
|
'}\n';
|
||||||
|
|
||||||
++n;
|
++n;
|
||||||
} while (Block.getInput('IF' + n));
|
} while (Block.getInput('IF' + n));
|
||||||
|
|
||||||
if (Block.getInput('ELSE')) {
|
if (Block.getInput('ELSE')) {
|
||||||
branchCode = Blockly.Arduino.statementToCode(Block, 'ELSE');
|
branchCode = Blockly.Arduino.statementToCode(Block, 'ELSE');
|
||||||
code += ' else {\n' + branchCode + '}';
|
code += ' else {\n' + branchCode + '}\n';
|
||||||
}
|
}
|
||||||
return code + '\n';
|
return code + '\n';
|
||||||
};
|
};
|
||||||
@@ -106,14 +106,14 @@ Blockly.Arduino['controls_ifelse'] = function (Block) {
|
|||||||
conditionCode +
|
conditionCode +
|
||||||
') {\n' +
|
') {\n' +
|
||||||
branchCode +
|
branchCode +
|
||||||
'}';
|
'}\n';
|
||||||
|
|
||||||
++n;
|
++n;
|
||||||
} while (Block.getInput('IF' + n));
|
} while (Block.getInput('IF' + n));
|
||||||
|
|
||||||
if (Block.getInput('ELSE')) {
|
if (Block.getInput('ELSE')) {
|
||||||
branchCode = Blockly.Arduino.statementToCode(Block, 'ELSE');
|
branchCode = Blockly.Arduino.statementToCode(Block, 'ELSE');
|
||||||
code += ' else {\n' + branchCode + '}';
|
code += ' else {\n' + branchCode + '}\n';
|
||||||
}
|
}
|
||||||
return code + '\n';
|
return code + '\n';
|
||||||
}
|
}
|
||||||
@@ -127,9 +127,6 @@ Blockly.Arduino['logic_negate'] = function (Block) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Blockly.Arduino['switch_case'] = function (block) {
|
Blockly.Arduino['switch_case'] = function (block) {
|
||||||
var n = 0;
|
var n = 0;
|
||||||
var argument = Blockly.Arduino.valueToCode(this, 'CONDITION',
|
var argument = Blockly.Arduino.valueToCode(this, 'CONDITION',
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import * as Blockly from 'blockly/core';
|
||||||
|
/**
|
||||||
|
* MQTT Blocks
|
||||||
|
*/
|
||||||
|
|
||||||
|
let service;
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_mqtt_setup = function () {
|
||||||
|
var server = this.getFieldValue('server');
|
||||||
|
var port = this.getFieldValue('port');
|
||||||
|
var username = this.getFieldValue('username');
|
||||||
|
var pass = this.getFieldValue('password');
|
||||||
|
service = this.getFieldValue('service');
|
||||||
|
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
|
||||||
|
Blockly.Arduino.libraries_['library_adafruitmqtt'] = '#include "Adafruit_MQTT.h"';
|
||||||
|
Blockly.Arduino.libraries_['library_adafruitmqttclient'] = '#include "Adafruit_MQTT_Client.h"';
|
||||||
|
Blockly.Arduino.definitions_['mqtt_server'] = '#define SERVER "' + server + '"';
|
||||||
|
Blockly.Arduino.definitions_['mqtt_port'] = '#define SERVERPORT ' + port + '';
|
||||||
|
Blockly.Arduino.definitions_['mqtt_username'] = '#define USERNAME "' + username + '"';
|
||||||
|
Blockly.Arduino.definitions_['mqtt_pass'] = '#define PASS "' + pass + '"';
|
||||||
|
Blockly.Arduino.definitions_['wifi_client'] = 'WiFiClient client;';
|
||||||
|
Blockly.Arduino.definitions_['mqtt_client'] = 'Adafruit_MQTT_Client mqtt(&client, SERVER, SERVERPORT, USERNAME, PASS);'
|
||||||
|
var code = '';
|
||||||
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_mqtt_publish = function (block) {
|
||||||
|
var feedname = this.getFieldValue('publishfeed');
|
||||||
|
var res = feedname.split("/");
|
||||||
|
var feed_client = res[res.length - 1];
|
||||||
|
var value = Blockly.Arduino.valueToCode(this, 'value', Blockly.Arduino.ORDER_ATOMIC) || '"No Block connected"';
|
||||||
|
|
||||||
|
switch (service) {
|
||||||
|
case 'adafruitio':
|
||||||
|
Blockly.Arduino.definitions_['mqtt_' + feed_client + ''] = 'Adafruit_MQTT_Publish ' + feed_client + ' = Adafruit_MQTT_Publish(&mqtt, USERNAME "/feeds/' + feedname + '");'
|
||||||
|
break;
|
||||||
|
case 'dioty':
|
||||||
|
Blockly.Arduino.definitions_['mqtt_' + feed_client + ''] = 'Adafruit_MQTT_Publish ' + feed_client + ' = Adafruit_MQTT_Publish(&mqtt, "/"USERNAME"/' + feedname + '");'
|
||||||
|
break;
|
||||||
|
case 'custom':
|
||||||
|
Blockly.Arduino.definitions_['mqtt_' + feed_client + ''] = 'Adafruit_MQTT_Publish ' + feed_client + ' = Adafruit_MQTT_Publish(&mqtt, ' + feedname + ');'
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Blockly.Arduino.definitions_['mqtt_' + feed_client + ''] = 'Adafruit_MQTT_Publish ' + feed_client + ' = Adafruit_MQTT_Publish(&mqtt, USERNAME "/feeds/' + feedname + '");'
|
||||||
|
Blockly.Arduino.codeFunctions_['mqtt_connect_function'] = `// Function to connect and reconnect as necessary to the MQTT server.
|
||||||
|
// Should be called in the loop function and it will take care if connecting.
|
||||||
|
void MQTT_connect() {
|
||||||
|
int8_t ret;
|
||||||
|
// Stop if already connected.
|
||||||
|
if (mqtt.connected()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
|
||||||
|
mqtt.disconnect();
|
||||||
|
delay(5000); // wait 5 seconds
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
Blockly.Arduino.loopCodeOnce_['mqtt_connect'] = 'MQTT_connect();';
|
||||||
|
var code = '' + feed_client + '.publish(' + value + ');';
|
||||||
|
return code
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_mqtt_subscribe = function (block) {
|
||||||
|
var feedname = this.getFieldValue('subscribefeed');
|
||||||
|
var x = 5, feed_client;
|
||||||
|
feed_client = feedname.substr(feedname.length - x, x);
|
||||||
|
Blockly.Arduino.definitions_['mqtt_' + feed_client + ''] = 'Adafruit_MQTT_Subscribe ' + feed_client + '= Adafruit_MQTT_Subscribe(&mqtt,' + feedname + ');';
|
||||||
|
Blockly.Arduino.codeFunctions_['mqtt_' + feed_client + 'callbackFunction'] = `void ` + feed_client + `Callback (double x){
|
||||||
|
Serial.println(x);
|
||||||
|
}`;
|
||||||
|
Blockly.Arduino.setupCode_['mqtt_' + feed_client + '_callback'] = '' + feed_client + '.setCallback(' + feed_client + 'Callback);';
|
||||||
|
Blockly.Arduino.setupCode_['mqtt_' + feed_client + '_subscribe'] = 'mqtt.subscribe(&' + feed_client + ');';
|
||||||
|
Blockly.Arduino.loopCodeOnce_['mqtt_processPackages'] = 'mqtt.processPackets(10);';
|
||||||
|
var code = '';
|
||||||
|
return code;
|
||||||
|
};
|
||||||
@@ -28,3 +28,101 @@ Blockly.Arduino['arduino_functions'] = function (block) {
|
|||||||
//var loopcode = Blockly.Arduino.scrub_(block, loopBranch); No comment block
|
//var loopcode = Blockly.Arduino.scrub_(block, loopBranch); No comment block
|
||||||
return loopBranch;
|
return loopBranch;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino['procedures_defreturn'] = function (block) {
|
||||||
|
// Define a procedure with a return value.
|
||||||
|
const funcName = Blockly.Arduino.variableDB_.getName(
|
||||||
|
block.getFieldValue('NAME'),
|
||||||
|
Blockly.Procedures.NAME_TYPE
|
||||||
|
);
|
||||||
|
const branch = Blockly.Arduino.statementToCode(block, 'STACK');
|
||||||
|
const returnType = block.getFieldValue('RETURN TYPE') || 'void';
|
||||||
|
|
||||||
|
let returnValue =
|
||||||
|
Blockly.Arduino.valueToCode(block, 'RETURN', Blockly.Arduino.ORDER_NONE) ||
|
||||||
|
'';
|
||||||
|
if (returnValue) {
|
||||||
|
returnValue = Blockly.Arduino.INDENT + 'return ' + returnValue + ';\n';
|
||||||
|
}
|
||||||
|
const args = [];
|
||||||
|
for (let i = 0; i < block.argumentVarModels_.length; i++) {
|
||||||
|
args[i] =
|
||||||
|
translateType(block.argumentVarModels_[i].type) +
|
||||||
|
' ' +
|
||||||
|
block.argumentVarModels_[i].name;
|
||||||
|
}
|
||||||
|
let code =
|
||||||
|
translateType(returnType) +
|
||||||
|
' ' +
|
||||||
|
funcName +
|
||||||
|
'(' +
|
||||||
|
args.join(', ') +
|
||||||
|
') {\n' +
|
||||||
|
branch +
|
||||||
|
returnValue +
|
||||||
|
'}';
|
||||||
|
code = Blockly.Arduino.scrub_(block, code);
|
||||||
|
// Add % so as not to collide with helper functions in definitions list.
|
||||||
|
Blockly.Arduino.functionNames_['%' + funcName] = code;
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function translateType(type) {
|
||||||
|
console.log(type);
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case 'int':
|
||||||
|
return 'int';
|
||||||
|
case 'String':
|
||||||
|
return 'String';
|
||||||
|
case 'void':
|
||||||
|
return 'void';
|
||||||
|
case 'boolean':
|
||||||
|
return 'boolean';
|
||||||
|
case 'float':
|
||||||
|
return 'float'
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid Parameter Type');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Blockly.Arduino['procedures_defnoreturn'] =
|
||||||
|
Blockly.Arduino['procedures_defreturn'];
|
||||||
|
|
||||||
|
Blockly.Arduino['procedures_callreturn'] = function (block) {
|
||||||
|
// Call a procedure with a return value.
|
||||||
|
const funcName = Blockly.Arduino.variableDB_.getName(
|
||||||
|
block.getFieldValue('NAME'),
|
||||||
|
Blockly.Procedures.NAME_TYPE
|
||||||
|
);
|
||||||
|
const args = [];
|
||||||
|
for (let i = 0; i < block.arguments_.length; i++) {
|
||||||
|
args[i] =
|
||||||
|
Blockly.Arduino.valueToCode(
|
||||||
|
block,
|
||||||
|
'ARG' + i,
|
||||||
|
Blockly.Arduino.ORDER_COMMA
|
||||||
|
) || 'null';
|
||||||
|
}
|
||||||
|
const code = funcName + '(' + args.join(', ') + ')';
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino['procedures_callnoreturn'] = function (block) {
|
||||||
|
// Call a procedure with no return value.
|
||||||
|
const funcName = Blockly.Arduino.variableDB_.getName(
|
||||||
|
block.getFieldValue('NAME'),
|
||||||
|
Blockly.Procedures.NAME_TYPE
|
||||||
|
);
|
||||||
|
const args = [];
|
||||||
|
for (let i = 0; i < block.arguments_.length; i++) {
|
||||||
|
args[i] =
|
||||||
|
Blockly.Arduino.valueToCode(
|
||||||
|
block,
|
||||||
|
'ARG' + i,
|
||||||
|
Blockly.Arduino.ORDER_COMMA
|
||||||
|
) || 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
return funcName + '(' + args.join(', ') + ');\n';
|
||||||
|
};
|
||||||
@@ -19,10 +19,10 @@ Blockly.Arduino.sensebox_display_clearDisplay = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_display_printDisplay = function () {
|
Blockly.Arduino.sensebox_display_printDisplay = function () {
|
||||||
var x = Blockly.Arduino.valueToCode(this, 'X', Blockly.Arduino.ORDER_ATOMIC) || '0'
|
var x = this.getFieldValue('X');
|
||||||
var y = Blockly.Arduino.valueToCode(this, 'Y', Blockly.Arduino.ORDER_ATOMIC) || '0'
|
var y = this.getFieldValue('Y');
|
||||||
var printDisplay = Blockly.Arduino.valueToCode(this, 'printDisplay', Blockly.Arduino.ORDER_ATOMIC) || '"Keine Eingabe"';
|
var printDisplay = Blockly.Arduino.valueToCode(this, 'printDisplay', Blockly.Arduino.ORDER_ATOMIC) || '"Keine Eingabe"';
|
||||||
var size = Blockly.Arduino.valueToCode(this, 'SIZE', Blockly.Arduino.ORDER_ATOMIC) || '1'
|
var size = this.getFieldValue('SIZE');
|
||||||
var color = this.getFieldValue('COLOR');
|
var color = this.getFieldValue('COLOR');
|
||||||
var code = 'display.setCursor(' + x + ',' + y + ');\n';
|
var code = 'display.setCursor(' + x + ',' + y + ');\n';
|
||||||
code += 'display.setTextSize(' + size + ');\n';
|
code += 'display.setTextSize(' + size + ');\n';
|
||||||
@@ -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;
|
||||||
};
|
};
|
||||||
@@ -120,9 +120,9 @@ Blockly.Arduino.sensebox_lora_initialize_otaa = function (block) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
Blockly.Arduino.setupCode_['initLora'] = 'initLora();';
|
Blockly.Arduino.loraSetupCode_['initLora'] = 'initLora();\n';
|
||||||
Blockly.Arduino.setupCode_['serial.begin'] = 'Serial.begin(9600);';
|
Blockly.Arduino.setupCode_['serial.begin'] = 'Serial.begin(9600);\ndelay(1000);\n';
|
||||||
var code = ''
|
var code = '';
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -195,6 +195,60 @@ Blockly.Arduino.sensebox_lora_cayenne_send = function (block) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_lora_ttn_mapper = function (block) {
|
||||||
|
var latitude = Blockly.Arduino.valueToCode(this, 'Latitude', Blockly.Arduino.ORDER_ATOMIC)
|
||||||
|
var longitude = Blockly.Arduino.valueToCode(this, 'Longitude', Blockly.Arduino.ORDER_ATOMIC)
|
||||||
|
var altitude = Blockly.Arduino.valueToCode(this, 'Altitude', Blockly.Arduino.ORDER_ATOMIC)
|
||||||
|
var pDOP = Blockly.Arduino.valueToCode(this, 'pDOP', Blockly.Arduino.ORDER_ATOMIC)
|
||||||
|
var fixType = Blockly.Arduino.valueToCode(this, 'Fix Type', Blockly.Arduino.ORDER_ATOMIC)
|
||||||
|
var fixTypeLimit = this.getFieldValue('dropdown');
|
||||||
|
Blockly.Arduino.functionNames_['functions_do_send'] = `
|
||||||
|
void do_send(osjob_t* j){
|
||||||
|
// Check if there is not a current TX/RX job running
|
||||||
|
if (LMIC.opmode & OP_TXRXPEND) {
|
||||||
|
Serial.println(F("OP_TXRXPEND, not sending"));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
int fixType = ${fixType};
|
||||||
|
if (fixType >= ${fixTypeLimit}) { // we have a 3D fix
|
||||||
|
int32_t latitude = ${latitude}; // in degrees * 10^-7
|
||||||
|
int32_t longitude = ${longitude}; // in degrees * 10^-7
|
||||||
|
int32_t altitude = ${altitude} / 100; // in dm above mean sea level
|
||||||
|
uint16_t pDOP = ${pDOP}; // positional dillution of precision
|
||||||
|
|
||||||
|
uint8_t data[12];
|
||||||
|
|
||||||
|
data[0] = latitude;
|
||||||
|
data[1] = latitude >> 8;
|
||||||
|
data[2] = latitude >> 16;
|
||||||
|
data[3] = latitude >> 24;
|
||||||
|
|
||||||
|
data[4] = longitude;
|
||||||
|
data[5] = longitude >> 8;
|
||||||
|
data[6] = longitude >> 16;
|
||||||
|
data[7] = longitude >> 24;
|
||||||
|
|
||||||
|
data[8] = altitude;
|
||||||
|
data[9] = altitude >> 8;
|
||||||
|
|
||||||
|
data[10] = pDOP;
|
||||||
|
data[11] = pDOP >> 8;
|
||||||
|
|
||||||
|
|
||||||
|
// Prepare upstream data transmission at the next possible time.
|
||||||
|
LMIC_setTxData2(1, data, sizeof(data), 0);
|
||||||
|
Serial.println(F("Packet queued"));
|
||||||
|
} else {
|
||||||
|
// wait for better fix type
|
||||||
|
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Next TX is scheduled after TX_COMPLETE event.
|
||||||
|
}`;
|
||||||
|
Blockly.Arduino.loopCodeOnce_['os_runloop'] = 'os_runloop_once();'
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_lora_initialize_abp = function (block) {
|
Blockly.Arduino.sensebox_lora_initialize_abp = function (block) {
|
||||||
var nwskey = this.getFieldValue('NWSKEY');
|
var nwskey = this.getFieldValue('NWSKEY');
|
||||||
var appskey = this.getFieldValue('APPSKEY');
|
var appskey = this.getFieldValue('APPSKEY');
|
||||||
@@ -372,8 +426,8 @@ Blockly.Arduino.sensebox_lora_initialize_abp = function (block) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
Blockly.Arduino.setupCode_['initLora'] = 'initLora();';
|
Blockly.Arduino.loraSetupCode_['initLora'] = 'initLora();\n';
|
||||||
Blockly.Arduino.setupCode_['serial.begin'] = 'Serial.begin(9600);';
|
Blockly.Arduino.setupCode_['serial.begin'] = 'Serial.begin(9600);\ndelay(1000);\n';
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -263,32 +263,68 @@ Blockly.Arduino.sensebox_scd30 = function () {
|
|||||||
Blockly.Arduino.libraries_['scd30_library'] = '#include "SparkFun_SCD30_Arduino_Library.h"'
|
Blockly.Arduino.libraries_['scd30_library'] = '#include "SparkFun_SCD30_Arduino_Library.h"'
|
||||||
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
|
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
|
||||||
Blockly.Arduino.definitions_['SCD30'] = 'SCD30 airSensor;';
|
Blockly.Arduino.definitions_['SCD30'] = 'SCD30 airSensor;';
|
||||||
Blockly.Arduino.variables_['scd30_temp'] = 'float scd30_temp;';
|
|
||||||
Blockly.Arduino.variables_['scd30_humi'] = 'float scd30_humi;';
|
|
||||||
Blockly.Arduino.variables_['scd30_co2'] = 'float scd30_co2;';
|
|
||||||
Blockly.Arduino.setupCode_['init_scd30'] = ` Wire.begin();
|
Blockly.Arduino.setupCode_['init_scd30'] = ` Wire.begin();
|
||||||
if (airSensor.begin() == false)
|
if (airSensor.begin() == false)
|
||||||
{
|
{
|
||||||
Serial.println("Air sensor not detected. Please check wiring. Freezing...");
|
|
||||||
while (1)
|
while (1)
|
||||||
;
|
;
|
||||||
}`;
|
}`;
|
||||||
Blockly.Arduino.loopCodeOnce_['scd30_getData'] = `if (airSensor.dataAvailable())
|
|
||||||
{
|
|
||||||
scd30_co2 = airSensor.getCO2();
|
|
||||||
scd30_temp = airSensor.getTemperature();
|
|
||||||
scd30_humi = airSensor.getHumidity();
|
|
||||||
}`
|
|
||||||
var code = '';
|
var code = '';
|
||||||
switch (dropdown) {
|
switch (dropdown) {
|
||||||
case 'temperature':
|
case 'temperature':
|
||||||
code = 'scd30_temp';
|
code = 'airSensor.getTemperature()';
|
||||||
break;
|
break;
|
||||||
case 'humidity':
|
case 'humidity':
|
||||||
code = 'scd30_humi';
|
code = 'airSensor.getHumiditiy()';
|
||||||
break;
|
break;
|
||||||
case 'CO2':
|
case 'CO2':
|
||||||
code = 'scd30_co2';
|
code = 'airSensor.getCO2()';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
code = ''
|
||||||
|
}
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GPS Module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_gps = function () {
|
||||||
|
var dropdown = this.getFieldValue('dropdown');
|
||||||
|
Blockly.Arduino.libraries_['gps_library'] = '#include "SparkFun_Ublox_Arduino_Library.h"'
|
||||||
|
Blockly.Arduino.libraries_['wire'] = '#include <Wire.h>'
|
||||||
|
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
|
||||||
|
Blockly.Arduino.definitions_['GPS'] = 'SFE_UBLOX_GPS myGPS;';
|
||||||
|
Blockly.Arduino.setupCode_['init_gps'] = ` Wire.begin();
|
||||||
|
|
||||||
|
if (myGPS.begin() == false) //Connect to the Ublox module using Wire port
|
||||||
|
{
|
||||||
|
Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing."));
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||||
|
myGPS.saveConfiguration(); //Save the current settings to flash and BBR`;
|
||||||
|
var code = '';
|
||||||
|
switch (dropdown) {
|
||||||
|
case 'latitude':
|
||||||
|
code = 'myGPS.getLatitude()';
|
||||||
|
break;
|
||||||
|
case 'longitude':
|
||||||
|
code = 'myGPS.getLongitude()';
|
||||||
|
break;
|
||||||
|
case 'altitude':
|
||||||
|
code = 'myGPS.getAltitudeMSL()';
|
||||||
|
break;
|
||||||
|
case 'pDOP':
|
||||||
|
code = 'myGPS.getPDOP()';
|
||||||
|
break;
|
||||||
|
case 'fixType':
|
||||||
|
code = 'myGPS.getFixType()';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
code = ''
|
code = ''
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import Blockly from 'blockly';
|
||||||
|
/**
|
||||||
|
* Webserver Blocks by Lucas Steinmann
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_initialize_http_server = function (block) {
|
||||||
|
var box_id = this.getFieldValue('Port');
|
||||||
|
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
|
||||||
|
Blockly.Arduino.codeFunctions_['define_wifi_server'] = 'WiFiServer server(' + box_id + ');';
|
||||||
|
Blockly.Arduino.setupCode_['sensebox_wifi_server_beging'] = 'server.begin();';
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_http_on_client_connect = function (block) {
|
||||||
|
var onConnect = Blockly.Arduino.statementToCode(block, 'ON_CONNECT');
|
||||||
|
var code = '';
|
||||||
|
code += 'WiFiClient client = server.available();\n';
|
||||||
|
code += 'if (client && client.available()) {\n';
|
||||||
|
code += ' String request_string = listenClient(client);\n';
|
||||||
|
code += ' Request request;\n';
|
||||||
|
code += ' if (parseRequestSafe(request_string, request)) {\n';
|
||||||
|
code += onConnect;
|
||||||
|
code += ' }\n';
|
||||||
|
code += ' delay(1);\n';
|
||||||
|
code += ' client.stop();\n';
|
||||||
|
code += ' delay(1);\n';
|
||||||
|
code += '}\n';
|
||||||
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_http_method = function (block) {
|
||||||
|
var code = "request.method";
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_http_uri = function (block) {
|
||||||
|
var code = "request.uri";
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_http_protocol_version = function (block) {
|
||||||
|
var code = "request.protocol_version";
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_http_user_agent = function (block) {
|
||||||
|
var code = "request.user_agent";
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_generate_html_doc = function (block) {
|
||||||
|
var header = Blockly.Arduino.valueToCode(block, 'HEADER', Blockly.Arduino.ORDER_NONE) || '""';
|
||||||
|
var body = Blockly.Arduino.valueToCode(block, 'BODY', Blockly.Arduino.ORDER_NONE) || '""';
|
||||||
|
var code = 'buildHTML(' + header + ', ' + body + ')';
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_generate_http_succesful_response = function (block) {
|
||||||
|
var content = Blockly.Arduino.valueToCode(block, 'CONTENT', Blockly.Arduino.ORDER_NONE) || '""';
|
||||||
|
var code = 'client.println(buildSuccessfulResponse(request, ' + content + '));\n';
|
||||||
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_generate_http_not_found_response = function (block) {
|
||||||
|
var code = 'client.println(buildNotFoundResponse(request));\n';
|
||||||
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_ip_address = function (block) {
|
||||||
|
var code = "b->getIpAddress()";
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_general_html_tag = function (block) {
|
||||||
|
var tag = this.getFieldValue('TAG');
|
||||||
|
var code = 'buildTag("' + tag + '",';
|
||||||
|
var n = 0;
|
||||||
|
var branch = Blockly.Arduino.valueToCode(block, 'DO' + n, Blockly.Arduino.ORDER_NONE);
|
||||||
|
if (branch.length > 0) {
|
||||||
|
code += '\n ' + branch;
|
||||||
|
} else {
|
||||||
|
code += '""';
|
||||||
|
}
|
||||||
|
for (n = 1; n <= block.additionalChildCount_; n++) {
|
||||||
|
branch = Blockly.Arduino.valueToCode(block, 'DO' + n, Blockly.Arduino.ORDER_NONE);
|
||||||
|
code += ' +' + branch;
|
||||||
|
}
|
||||||
|
return [code + ')', Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_web_readHTML = function (block) {
|
||||||
|
var filename = this.getFieldValue('FILENAME');
|
||||||
|
Blockly.Arduino.libraries_['library_spi'] = '#include <SPI.h>';
|
||||||
|
Blockly.Arduino.libraries_['library_sd'] = '#include <SD.h>';
|
||||||
|
Blockly.Arduino.codeFunctions_['define_sd' + filename] = 'File webFile;';
|
||||||
|
Blockly.Arduino.setupCode_['sensebox_sd'] = 'SD.begin(28);';
|
||||||
|
var func = [
|
||||||
|
'String generateHTML(){',
|
||||||
|
' webFile = SD.open("' + filename + '", FILE_READ);',
|
||||||
|
' String finalString ="";',
|
||||||
|
' while (webFile.available())',
|
||||||
|
' {',
|
||||||
|
' finalString+=(char)webFile.read();',
|
||||||
|
' }',
|
||||||
|
' return finalString;',
|
||||||
|
'}'];
|
||||||
|
var functionName = Blockly.Arduino.addFunction(
|
||||||
|
'generateHTML', func.join('\n'));
|
||||||
|
var code = functionName + '()';
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
@@ -10,6 +10,9 @@ const colours = {
|
|||||||
text: 160,
|
text: 160,
|
||||||
variables: 330,
|
variables: 330,
|
||||||
audio: 250,
|
audio: 250,
|
||||||
|
arrays: 33,
|
||||||
|
mqtt: 90,
|
||||||
|
webserver: 40
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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,14 +87,16 @@ export const CHILD_BLOCK_MISSING = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const compatibleTypes = {
|
const compatibleTypes = {
|
||||||
|
Array: ['Array'],
|
||||||
boolean: ['boolean'],
|
boolean: ['boolean'],
|
||||||
int: ['int'],
|
int: ['int', 'long', 'double', 'float'],
|
||||||
char: ['char'],
|
char: ['char'],
|
||||||
String: ['String'],
|
String: ['String'],
|
||||||
void: ['void'],
|
void: ['void'],
|
||||||
long: ['int', 'long'],
|
long: ['int', 'long'],
|
||||||
double: ['int', 'long', 'double'],
|
double: ['int', 'long', 'double'],
|
||||||
float: ['int', 'long', 'double', 'float']
|
float: ['int', 'long', 'double', 'float'],
|
||||||
|
null: ['null']
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 = {};
|
||||||
|
|
||||||
@@ -276,6 +272,11 @@ Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL = "https://de.wikipedia.org/wiki/Pro
|
|||||||
Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP = "Rufe einen Funktionsblock ohne Rückgabewert auf.";
|
Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP = "Rufe einen Funktionsblock ohne Rückgabewert auf.";
|
||||||
Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL = "https://de.wikipedia.org/wiki/Prozedur_%28Programmierung%29";
|
Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL = "https://de.wikipedia.org/wiki/Prozedur_%28Programmierung%29";
|
||||||
Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP = "Rufe einen Funktionsblock mit Rückgabewert auf.";
|
Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP = "Rufe einen Funktionsblock mit Rückgabewert auf.";
|
||||||
|
Blockly.Msg.PROCEDURES_CALL = "Rufe";
|
||||||
|
Blockly.Msg.PROCEDURES_CALL_END = "auf";
|
||||||
|
Blockly.Msg.PROCEDURES_DEFNORETURN = "Erstelle Funktion";
|
||||||
|
Blockly.Msg.PROCEDURES_BEFORE_PARAMS = "mit Eingabeparameter:";
|
||||||
|
Blockly.Msg.PROCEDURES_DEFRETURN_RETURN_TYPE = "Rückgabetype";
|
||||||
Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS = "mit:";
|
Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS = "mit:";
|
||||||
Blockly.Msg.PROCEDURES_CREATE_DO = "Erzeuge \"Aufruf %1\"";
|
Blockly.Msg.PROCEDURES_CREATE_DO = "Erzeuge \"Aufruf %1\"";
|
||||||
Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT = "Beschreibe diese Funktion …";
|
Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT = "Beschreibe diese Funktion …";
|
||||||
@@ -610,6 +611,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 +652,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 +777,251 @@ 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)";
|
||||||
|
Blockly.Msg.senseBox_scd_tip = "Gibt den Wert des CO2 Sensors";
|
||||||
|
Blockly.Msg.senseBox_scd_co2 = "CO2 in ppm";
|
||||||
|
//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";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
* MQTT
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.senseBox_mqtt_init = "Verbinde mit MQTT Broker";
|
||||||
|
Blockly.Msg.senseBox_mqtt_server = "Server";
|
||||||
|
Blockly.Msg.senseBox_mqtt_port = "Port";
|
||||||
|
Blockly.Msg.senseBox_mqtt_username = "Benutzername";
|
||||||
|
Blockly.Msg.senseBox_mqtt_password = "Passwort";
|
||||||
|
Blockly.Msg.sensebox_mqtt_subscribe = "Subscribe to Feed"
|
||||||
|
Blockly.Msg.senseBox_mqtt_publish = "Sende an Feed/Topic";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typed Variable Modal
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Msg.TYPED_VAR_MODAL_CONFIRM_BUTTON = "Ok";
|
||||||
|
Blockly.Msg.TYPED_VAR_MODAL_VARIABLE_NAME_LABEL = "Variablen Name: ";
|
||||||
|
Blockly.Msg.TYPED_VAR_MODAL_TYPES_LABEL = "Variable Typen";
|
||||||
|
Blockly.Msg.TYPED_VAR_MODAL_CANCEL_BUTTON = "Abbrechen";
|
||||||
|
Blockly.Msg.TYPED_VAR_MODAL_TITLE = "Erstelle Variable";
|
||||||
|
Blockly.Msg.TYPED_VAR_MODAL_INVALID_NAME = "Der Name ist ungültig, bitte versuche einen anderen."
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Translation for Blocks above
|
||||||
|
* ---------------------------------------------------------------
|
||||||
|
* Add Translation for the UI below
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toolbox
|
||||||
|
*/
|
||||||
|
Blockly.Msg.toolbox_sensors = "Sensoren";
|
||||||
|
Blockly.Msg.toolbox_logic = "Logik";
|
||||||
|
Blockly.Msg.toolbox_loops = "Schleifen";
|
||||||
|
Blockly.Msg.toolbox_math = "Mathematik";
|
||||||
|
Blockly.Msg.toolbox_io = "Eingang/Ausgang";
|
||||||
|
Blockly.Msg.toolbox_time = "Zeit";
|
||||||
|
Blockly.Msg.toolbox_functions = "Funktionen";
|
||||||
|
Blockly.Msg.toolbox_variables = "Variablen";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tooltips
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.tooltip_compile_code = "Code kompilieren"
|
||||||
|
Blockly.Msg.tooltip_save_blocks = "Blöcke speichern";
|
||||||
|
Blockly.Msg.tooltip_open_blocks = "Blöcke öffnen";
|
||||||
|
Blockly.Msg.tooltip_screenshot = "Screenshot erstellen";
|
||||||
|
Blockly.Msg.tooltip_clear_workspace = "Workspace zurücksetzen";
|
||||||
|
Blockly.Msg.tooltip_share_blocks = "Blöcke teilen";
|
||||||
|
Blockly.Msg.tooltip_show_code = "Code anzeigen";
|
||||||
|
Blockly.Msg.tooltip_hide_code = "Code ausblenden"
|
||||||
|
Blockly.Msg.tooltip_delete_project = "Projekt löschen"
|
||||||
|
Blockly.Msg.tooltip_project_name = "Name des Projektes"
|
||||||
|
Blockly.Msg.tooltip_download_project = "Projekt herunterladen"
|
||||||
|
Blockly.Msg.tooltip_open_project = "Projekt öffnen"
|
||||||
|
Blockly.Msg.tooltip_update_project = "Projekt aktualisieren"
|
||||||
|
Blockly.Msg.tooltip_save_project = "Projekt speichern"
|
||||||
|
Blockly.Msg.tooltip_create_project = "Projekt erstellen"
|
||||||
|
Blockly.Msg.tooltip_share_project = "Projekt teilen"
|
||||||
|
Blockly.Msg.tooltip_reset_workspace = "Workspace zurücksetzen"
|
||||||
|
Blockly.Msg.tooltip_copy_link = "Link kopieren"
|
||||||
|
Blockly.Msg.tooltip_trashcan_hide = 'gelöschte Blöcke ausblenden'
|
||||||
|
Blockly.Msg.tooltip_trashcan_delete = 'Blöcke endgültig löschen'
|
||||||
|
Blockly.Msg.tooltip_project_title = "Titel des Projektes"
|
||||||
|
Blockly.Msg.tooltip_check_solution = "Lösung kontrollieren"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Messages
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.messages_delete_project_failed = "Fehler beim Löschen des Projektes. Versuche es noch einmal."
|
||||||
|
Blockly.Msg.messages_reset_workspace_success = "Das Projekt wurde erfolgreich zurückgesetzt"
|
||||||
|
Blockly.Msg.messages_PROJECT_UPDATE_SUCCESS = "Das Projekt wurde erfolgreich aktualisiert."
|
||||||
|
Blockly.Msg.messages_GALLERY_UPDATE_SUCCESS = "Das Galerie-Projekt wurde erfolgreich aktualisiert."
|
||||||
|
Blockly.Msg.messages_PROJECT_UPDATE_FAIL = "Fehler beim Aktualisieren des Projektes. Versuche es noch einmal."
|
||||||
|
Blockly.Msg.messages_GALLERY_UPDATE_FAIL = "Fehler beim Aktualisieren des Galerie-Projektes. Versuche es noch einmal."
|
||||||
|
Blockly.Msg.messages_gallery_save_fail_1 = "Fehler beim Speichern des "
|
||||||
|
Blockly.Msg.messages_gallery_save_fail_2 = "Projektes. Versuche es noch einmal."
|
||||||
|
Blockly.Msg.messages_SHARE_SUCCESS = 'Programm teilen'
|
||||||
|
Blockly.Msg.messages_SHARE_FAIL = "Fehler beim Erstellen eines Links zum Teilen deines Programmes. Versuche es noch einmal."
|
||||||
|
Blockly.Msg.messages_copylink_success = 'Link erfolgreich in Zwischenablage gespeichert.'
|
||||||
|
Blockly.Msg.messages_rename_success_01 = 'Das Projekt wurde erfolgreich in '
|
||||||
|
Blockly.Msg.messages_rename_success_02 = 'umbenannt.'
|
||||||
|
Blockly.Msg.messages_newblockly_head = "Willkommen zur neuen Version Blockly für die senseBox"
|
||||||
|
Blockly.Msg.messages_newblockly_text = "Die neue Blockly Version befindet sich zurzeit in der Testphase. Alle Neuigkeiten findet ihr hier:"
|
||||||
|
Blockly.Msg.messages_GET_TUTORIAL_FAIL = 'Zurück zur Tutorials-Übersicht'
|
||||||
|
Blockly.Msg.messages_LOGIN_FAIL = 'Der Benutzername oder das Passwort ist nicht korrekt.'
|
||||||
|
/**
|
||||||
|
* Share Dialog
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.sharedialog_headline = "Dein Link wurde erstellt.";
|
||||||
|
Blockly.Msg.sharedialog_text = "Über den folgenden Link kannst du dein Programm teilen.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project rename Dialog
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.renamedialog_headline = "Projekt benennen";
|
||||||
|
Blockly.Msg.renamedialog_text = "Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf 'Bestätigen'."
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile Dialog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.compiledialog_headline = "Fehler"
|
||||||
|
Blockly.Msg.compiledialog_text = "Beim kompilieren ist ein Fehler aufgetreten. Überprüfe deine Blöcke und versuche es erneut"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buttons
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.button_cancel = "Abbrechen";
|
||||||
|
Blockly.Msg.button_close = "Schließen";
|
||||||
|
Blockly.Msg.button_accept = "Bestätigen";
|
||||||
|
Blockly.Msg.button_compile = "Kompilieren";
|
||||||
|
Blockly.Msg.button_create_variableCreate = "Erstelle Variable";
|
||||||
|
Blockly.Msg.button_back = "Zurück"
|
||||||
|
Blockly.Msg.button_next = "nächster Schritt"
|
||||||
|
Blockly.Msg.button_tutorial_overview = "Tutorial Übersicht"
|
||||||
|
Blockly.Msg.button_login = "Anmelden"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.filename = "Dateiname";
|
||||||
|
Blockly.Msg.projectname = "Projektname";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings
|
||||||
|
*/
|
||||||
|
Blockly.Msg.settings_head = "Einstellungen"
|
||||||
|
Blockly.Msg.settings_language = "Sprache"
|
||||||
|
Blockly.Msg.settings_language_text = "Auswahl der Sprache gilt für die gesamte Anwendung. Es kann zwischen Deutsch und Englisch unterschieden werden."
|
||||||
|
Blockly.Msg.settings_language_de = "Deutsch"
|
||||||
|
Blockly.Msg.settings_language_en = "Englisch"
|
||||||
|
Blockly.Msg.settings_renderer = "Renderer"
|
||||||
|
Blockly.Msg.settings_renderer_text = "Der eingestellte Renderer bestimmt das Aussehen der Blöcke. Es kann zwischen 'Geras' und 'Zelos' unterschieden werden, wobei 'Zelos' insbesondere für eine Touch-Anwendung geeignet ist."
|
||||||
|
Blockly.Msg.settings_statistics = "Statistiken"
|
||||||
|
Blockly.Msg.settings_statistics_text = "Die Anzeige von Statistiken zur Nutzung der Blöcke oberhalb der Arbeitsfläche kann ein- oder ausgeblendet werden."
|
||||||
|
Blockly.Msg.settings_statistics_on = "An"
|
||||||
|
Blockly.Msg.settings_statistics_off = "Aus"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 404
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.notfound_head = "Die von Ihnen angeforderte Seite kann nicht gefunden werden."
|
||||||
|
Blockly.Msg.notfound_text = "Die gesuchte Seite wurde möglicherweise entfernt, ihr Name wurde geändert oder sie ist vorübergehend nicht verfügbar."
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Labels
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.labels_donotshowagain = 'Dialog nicht mehr anzeigen'
|
||||||
|
Blockly.Msg.labels_here = "hier"
|
||||||
|
Blockly.Msg.labels_username = 'E-Mail oder Nutzername'
|
||||||
|
Blockly.Msg.labels_password = "Passwort"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Badges
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.badges_explaination = "Eine Übersicht über alle erhaltenen Badges im Kontext Blockly for senseBox findest du "
|
||||||
|
Blockly.Msg.badges_ASSIGNE_BADGE_SUCCESS_01 = "Herzlichen Glückwunsch! Du hast den Badge "
|
||||||
|
Blockly.Msg.badges_ASSIGNE_BADGE_SUCCESS_02 = " erhalten."
|
||||||
|
/**
|
||||||
|
* Tutorials
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.tutorials_assessment_task = "Aufgabe"
|
||||||
|
Blockly.Msg.tutorials_hardware_head = "Für die Umsetzung benötigst du folgende Hardware:"
|
||||||
|
Blockly.Msg.tutorials_hardware_moreInformation = "Weitere Informationen zur Hardware-Komponente findest du"
|
||||||
|
Blockly.Msg.tutorials_hardware_here = "hier";
|
||||||
|
Blockly.Msg.tutorials_requirements = "Bevor du mit diesem Tutorial fortfährst solltest du folgende Tutorials erfolgreich abgeschlossen haben:"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tutorial Builder
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.builder_solution = "Lösung"
|
||||||
|
Blockly.Msg.builder_solution_submit = "Lösung einreichen"
|
||||||
|
Blockly.Msg.builder_example_submit = "Beispiel einreichen"
|
||||||
|
Blockly.Msg.builder_comment = "Anmerkung: Man kann den initialen Setup()- bzw. Endlosschleifen()-Block löschen. Zusätzlich ist es möglich u.a. nur einen beliebigen Block auszuwählen, ohne dass dieser als deaktiviert dargestellt wird."
|
||||||
|
Blockly.Msg.builder_hardware_order = "Beachte, dass die Reihenfolge des Auswählens maßgebend ist."
|
||||||
|
Blockly.Msg.builder_hardware_helper = "Wähle mindestens eine Hardware-Komponente aus."
|
||||||
|
Blockly.Msg.builder_requirements_head = "Voraussetzungen"
|
||||||
|
Blockly.Msg.builder_requirements_order = "Beachte, dass die Reihenfolge des Anhakens maßgebend ist."
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Msg.login_head = "Anmelden"
|
||||||
|
Blockly.Msg.login_osem_account_01 = "Du benötigst einen "
|
||||||
|
Blockly.Msg.login_osem_account_02 = "Account um dich einzuloggen"
|
||||||
|
Blockly.Msg.login_lostpassword = "Du hast dein Passwort vergessen?"
|
||||||
|
Blockly.Msg.login_createaccount = "Falls du noch keinen Account hast erstellen einen auf "
|
||||||
|
/**
|
||||||
|
* Navbar
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.navbar_tutorials = "Tutorials"
|
||||||
|
Blockly.Msg.navbar_tutorialbuilder = "Tutorial erstellen"
|
||||||
|
Blockly.Msg.navbar_gallery = "Gallerie"
|
||||||
|
Blockly.Msg.navbar_projects = "Projekte"
|
||||||
|
|
||||||
|
Blockly.Msg.navbar_menu = "Menü"
|
||||||
|
Blockly.Msg.navbar_login = "Einloggen"
|
||||||
|
Blockly.Msg.navbar_mybadges = "myBadges"
|
||||||
|
Blockly.Msg.navbar_account = "Konto"
|
||||||
|
Blockly.Msg.navbar_logout = "Abmelden"
|
||||||
|
Blockly.Msg.navbar_settings = "Einstellungen"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Codeviewer
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.codeviewer_arduino = "Arduino Quellcode"
|
||||||
|
Blockly.Msg.codeviewer_xml = "XML Blöcke"
|
||||||
|
|
||||||
|
|
||||||
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 = {};
|
||||||
|
|
||||||
@@ -271,20 +267,24 @@ Blockly.Msg.NEW_VARIABLE = "New variable...";
|
|||||||
Blockly.Msg.NEW_VARIABLE_TITLE = "New variable name:";
|
Blockly.Msg.NEW_VARIABLE_TITLE = "New variable name:";
|
||||||
Blockly.Msg.ORDINAL_NUMBER_SUFFIX = "";
|
Blockly.Msg.ORDINAL_NUMBER_SUFFIX = "";
|
||||||
Blockly.Msg.PROCEDURES_ALLOW_STATEMENTS = "allow statements";
|
Blockly.Msg.PROCEDURES_ALLOW_STATEMENTS = "allow statements";
|
||||||
Blockly.Msg.PROCEDURES_BEFORE_PARAMS = "with:";
|
Blockly.Msg.PROCEDURES_BEFORE_PARAMS = "with inputs:";
|
||||||
Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL = "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29";
|
Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL = "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29";
|
||||||
Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP = "Run the user-defined function '%1'.";
|
Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP = "Run the user-defined function '%1'.";
|
||||||
Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL = "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29";
|
Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL = "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29";
|
||||||
Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP = "Run the user-defined function '%1' and use its output.";
|
Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP = "Run the user-defined function '%1' and use its output.";
|
||||||
Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS = "with:";
|
Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS = "with Inputs:";
|
||||||
|
Blockly.Msg.PROCEDURES_CALL = "Call";
|
||||||
|
Blockly.Msg.PROCEDURES_CALL_END = '';
|
||||||
Blockly.Msg.PROCEDURES_CREATE_DO = "Create '%1'";
|
Blockly.Msg.PROCEDURES_CREATE_DO = "Create '%1'";
|
||||||
Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT = "Describe this function...";
|
Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT = "Describe this function...";
|
||||||
|
Blockly.Msg.PROCEDURES_DEFNORETURN = "Create Function";
|
||||||
Blockly.Msg.PROCEDURES_DEFNORETURN_DO = "";
|
Blockly.Msg.PROCEDURES_DEFNORETURN_DO = "";
|
||||||
Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL = "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29";
|
Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL = "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29";
|
||||||
Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE = "do something";
|
Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE = "do something";
|
||||||
Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE = "to";
|
Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE = "to";
|
||||||
Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP = "Creates a function with no output.";
|
Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP = "Creates a function with no output.";
|
||||||
Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL = "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29";
|
Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL = "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29";
|
||||||
|
Blockly.Msg.PROCEDURES_DEFRETURN_RETURN_TYPE = "return Type";
|
||||||
Blockly.Msg.PROCEDURES_DEFRETURN_RETURN = "return";
|
Blockly.Msg.PROCEDURES_DEFRETURN_RETURN = "return";
|
||||||
Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP = "Creates a function with an output.";
|
Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP = "Creates a function with an output.";
|
||||||
Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING = "Warning: This function has duplicate parameters.";
|
Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING = "Warning: This function has duplicate parameters.";
|
||||||
@@ -613,6 +613,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 +681,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 +759,232 @@ 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)";
|
||||||
|
Blockly.Msg.senseBox_scd_co2 = "CO2 in ppm";
|
||||||
|
Blockly.Msg.senseBox_scd_tip = "Returns value of the CO2 Sensor";
|
||||||
|
|
||||||
|
|
||||||
|
//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";
|
||||||
|
|
||||||
|
/***
|
||||||
|
* MQTT
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.senseBox_mqtt_init = "Connect to MQTT Broker";
|
||||||
|
Blockly.Msg.senseBox_mqtt_server = "Server";
|
||||||
|
Blockly.Msg.senseBox_mqtt_port = "Port";
|
||||||
|
Blockly.Msg.senseBox_mqtt_username = "Username";
|
||||||
|
Blockly.Msg.senseBox_mqtt_password = "Password";
|
||||||
|
Blockly.Msg.sensebox_mqtt_subscribe = "Subscribe to Feed"
|
||||||
|
Blockly.Msg.senseBox_mqtt_publish = "Publish to Feed/Topic";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Translation for Blocks above
|
||||||
|
* ---------------------------------------------------------------
|
||||||
|
* Add Translation for the UI below
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toolbox
|
||||||
|
*/
|
||||||
|
Blockly.Msg.toolbox_sensors = "Sensors";
|
||||||
|
Blockly.Msg.toolbox_logic = "Logic";
|
||||||
|
Blockly.Msg.toolbox_loops = "Loops";
|
||||||
|
Blockly.Msg.toolbox_math = "Math";
|
||||||
|
Blockly.Msg.toolbox_io = "Input/Output";
|
||||||
|
Blockly.Msg.toolbox_time = "Time";
|
||||||
|
Blockly.Msg.toolbox_functions = "Functions";
|
||||||
|
Blockly.Msg.toolbox_variables = "Variables";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tooltips
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.tooltip_compile_code = "Compile code"
|
||||||
|
Blockly.Msg.tooltip_save_blocks = "Save blocks";
|
||||||
|
Blockly.Msg.tooltip_open_blocks = "Open blocks";
|
||||||
|
Blockly.Msg.tooltip_screenshot = "Download screenshot";
|
||||||
|
Blockly.Msg.tooltip_clear_workspace = "Reset workspace";
|
||||||
|
Blockly.Msg.tooltip_share_blocks = "Share blocks";
|
||||||
|
Blockly.Msg.tooltip_show_code = "Show code";
|
||||||
|
Blockly.Msg.tooltip_hide_code = "Hide code "
|
||||||
|
Blockly.Msg.tooltip_delete_project = "Delete project"
|
||||||
|
Blockly.Msg.tooltip_project_name = "Project name"
|
||||||
|
Blockly.Msg.tooltip_download_project = "Download project"
|
||||||
|
Blockly.Msg.tooltip_open_project = "Open project"
|
||||||
|
Blockly.Msg.tooltip_update_project = "Update project"
|
||||||
|
Blockly.Msg.tooltip_save_project = "Save project"
|
||||||
|
Blockly.Msg.tooltip_create_project = "Create project"
|
||||||
|
Blockly.Msg.tooltip_share_project = "Share project"
|
||||||
|
Blockly.Msg.tooltip_reset_workspace = "Reset workspace"
|
||||||
|
Blockly.Msg.tooltip_copy_link = "Cooy link"
|
||||||
|
Blockly.Msg.tooltip_trashcan_hide = "hide deleted blocks"
|
||||||
|
Blockly.Msg.tooltip_trashcan_delete = "empty trashcan"
|
||||||
|
Blockly.Msg.tooltip_project_title = "Project title"
|
||||||
|
Blockly.Msg.tooltip_check_solution = "Check solution"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Messages
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.messages_delete_project_failed = "Error deleting the project. Try again."
|
||||||
|
Blockly.Msg.messages_reset_workspace_success = "The project has been successfully reset."
|
||||||
|
Blockly.Msg.messages_PROJECT_UPDATE_SUCCESS = "The project was successfully updated."
|
||||||
|
Blockly.Msg.messages_GALLERY_UPDATE_SUCCESS = "The gallery project was successfully updated."
|
||||||
|
Blockly.Msg.messages_PROJECT_UPDATE_FAIL = "Error updating the project. Try again."
|
||||||
|
Blockly.Msg.messages_GALLERY_UPDATE_FAIL = "Error updating the gallery project. Try again."
|
||||||
|
Blockly.Msg.messages_gallery_save_fail_1 = "Error saving the "
|
||||||
|
Blockly.Msg.messages_gallery_save_fail_2 = "Project. Try again."
|
||||||
|
Blockly.Msg.messages_SHARE_SUCCESS = 'Share program'
|
||||||
|
Blockly.Msg.messages_SHARE_FAIL = "Error creating a link to share your program. Try again."
|
||||||
|
Blockly.Msg.messages_copylink_success = 'Link successfully saved to clipboard.'
|
||||||
|
Blockly.Msg.messages_rename_success_01 = 'The project was successfully saved to '
|
||||||
|
Blockly.Msg.messages_rename_success_02 = 'renamed.'
|
||||||
|
Blockly.Msg.messages_newblockly_head = 'Welcome to the new version Blockly for the senseBox'
|
||||||
|
Blockly.Msg.messages_newblockly_text = "The new Blockly version is currently in testing. You can find all the news here:"
|
||||||
|
Blockly.Msg.messages_GET_TUTORIAL_FAIL = 'Back to tutorials overview'
|
||||||
|
Blockly.Msg.messages_LOGIN_FAIL = 'The username or password is incorrect.'
|
||||||
|
Blockly.Msg.messages_login_error = "Enter both a username and a password."
|
||||||
|
/**
|
||||||
|
* Share Dialog
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.sharedialog_headline = "Your link has been created.";
|
||||||
|
Blockly.Msg.sharedialog_text = "You can share your program using the following link.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project rename Dialog
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.renamedialog_headline = "Rename project";
|
||||||
|
Blockly.Msg.renamedialog_text = "Please enter a name for the project and confirm it by clicking 'Confirm'."
|
||||||
|
/**
|
||||||
|
* Compile Dialog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.compiledialog_headline = "Error"
|
||||||
|
Blockly.Msg.compiledialog_text = "While compiling an error occured. Please check your blocks and try again"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buttons
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.button_cancel = "Cancel";
|
||||||
|
Blockly.Msg.button_close = "Close";
|
||||||
|
Blockly.Msg.button_accept = "Ok";
|
||||||
|
Blockly.Msg.button_compile = "Compile";
|
||||||
|
Blockly.Msg.button_create_variableCreate = "Create Variable";
|
||||||
|
Blockly.Msg.button_back = "Back"
|
||||||
|
Blockly.Msg.button_next = "Next step"
|
||||||
|
Blockly.Msg.button_tutorial_overview = "Tutorial overview"
|
||||||
|
Blockly.Msg.button_login = "Login"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.filename = "Filename";
|
||||||
|
Blockly.Msg.projectname = "Projectname";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 404
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.notfound_head = "The page you requested cannot be found."
|
||||||
|
Blockly.Msg.notfound_text = "The page you are looking for may have been removed, its name changed, or it may be temporarily unavailable."
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Labels
|
||||||
|
*/
|
||||||
|
Blockly.Msg.labels_donotshowagain = 'Do not show dialog again'
|
||||||
|
Blockly.Msg.labels_here = 'here'
|
||||||
|
Blockly.Msg.labels_username = 'Email or username'
|
||||||
|
Blockly.Msg.labels_password = "Password"
|
||||||
|
/**
|
||||||
|
* Badges
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.badges_explaination = "An overview of all badges received in the Blockly for senseBox context can be found "
|
||||||
|
Blockly.Msg.badges_ASSIGNE_BADGE_SUCCESS_01 = "Congratulations! You have received the badge "
|
||||||
|
Blockly.Msg.badges_ASSIGNE_BADGE_SUCCESS_02 = "."
|
||||||
|
/**
|
||||||
|
* Tutorials
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.tutorials_assessment_task = "Task"
|
||||||
|
Blockly.Msg.tutorials_hardware_head = "For the implementation you need the following hardware:"
|
||||||
|
Blockly.Msg.tutorials_hardware_moreInformation = "You can find more information about the hardware component."
|
||||||
|
Blockly.Msg.tutorials_hardware_here = "here";
|
||||||
|
Blockly.Msg.tutorials_requirements = "Before continuing with this tutorial, you should have successfully completed the following tutorials:"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tutorial Builder
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.builder_solution = "Solution"
|
||||||
|
Blockly.Msg.builder_solution_submit = "Submit Solution"
|
||||||
|
Blockly.Msg.builder_example_submit = "Submit example"
|
||||||
|
Blockly.Msg.builder_comment = "Note: You can delete the initial setup() or infinite loop() block. Additionally, it is possible to select only any block, among others, without displaying it as disabled."
|
||||||
|
Blockly.Msg.builder_hardware_order = "Note that the order of selection is authoritative."
|
||||||
|
Blockly.Msg.builder_hardware_helper = "Select at least one hardware component."
|
||||||
|
Blockly.Msg.builder_requirements_head = "Requirements."
|
||||||
|
Blockly.Msg.builder_requirements_order = "Note that the order of ticking is authoritative."
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Msg.login_head = "Login"
|
||||||
|
Blockly.Msg.login_osem_account_01 = "You need to have an "
|
||||||
|
Blockly.Msg.login_osem_account_02 = "Account to login"
|
||||||
|
Blockly.Msg.login_lostpassword = "Lost your password?"
|
||||||
|
Blockly.Msg.login_createaccount = "If you don't have an openSenseMap account please register on "
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings
|
||||||
|
*/
|
||||||
|
Blockly.Msg.settings_head = "Settings"
|
||||||
|
Blockly.Msg.settings_language = "Language"
|
||||||
|
Blockly.Msg.settings_language_text = "Selection of the language applies to the entire application. A distinction can be made between German and English."
|
||||||
|
Blockly.Msg.settings_language_de = "German"
|
||||||
|
Blockly.Msg.settings_language_en = "English"
|
||||||
|
Blockly.Msg.settings_renderer = "Renderer"
|
||||||
|
Blockly.Msg.settings_renderer_text = "The selected renderer determines the appearance of the blocks. A distinction can be made between 'Geras' and 'Zelos', whereby 'Zelos' is particularly suitable for a touch application."
|
||||||
|
Blockly.Msg.settings_statistics = "Statistics"
|
||||||
|
Blockly.Msg.settings_statistics_text = "The display of statistics on the usage of the blocks above the workspace can be shown or hidden."
|
||||||
|
Blockly.Msg.settings_statistics_on = "On"
|
||||||
|
Blockly.Msg.settings_statistics_off = "Off"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navbar
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Msg.navbar_tutorials = "Tutorials"
|
||||||
|
Blockly.Msg.navbar_tutorialbuilder = "Create tutorial"
|
||||||
|
Blockly.Msg.navbar_gallery = "Gallery"
|
||||||
|
Blockly.Msg.navbar_projects = "Projects"
|
||||||
|
|
||||||
|
Blockly.Msg.navbar_menu = "Menu"
|
||||||
|
Blockly.Msg.navbar_login = "Login"
|
||||||
|
Blockly.Msg.navbar_mybadges = "myBadges"
|
||||||
|
Blockly.Msg.navbar_account = "Account"
|
||||||
|
Blockly.Msg.navbar_logout = "Logout"
|
||||||
|
Blockly.Msg.navbar_settings = "Settings"
|
||||||
|
|
||||||
|
|
||||||
|
Blockly.Msg.codeviewer_arduino = "Arduino Source Code"
|
||||||
|
Blockly.Msg.codeviewer_xml = "XML Blocks"
|
||||||
|
|
||||||
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');
|
||||||
@@ -37,7 +38,7 @@ class Toolbox extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<xml xmlns="https://developers.google.com/blockly/xml" id="blockly" style={{ display: 'none' }} ref={this.props.toolbox}>
|
<xml xmlns="https://developers.google.com/blockly/xml" id="blockly" style={{ display: 'none' }} ref={this.props.toolbox}>
|
||||||
<Category name="Sensoren" colour={getColour().sensebox}>
|
<Category name={Blockly.Msg.toolbox_sensors} colour={getColour().sensebox}>
|
||||||
<Block type="sensebox_sensor_temp_hum" />
|
<Block type="sensebox_sensor_temp_hum" />
|
||||||
<Block type="sensebox_sensor_uv_light" />
|
<Block type="sensebox_sensor_uv_light" />
|
||||||
<Block type="sensebox_sensor_bmx055_accelerometer" />
|
<Block type="sensebox_sensor_bmx055_accelerometer" />
|
||||||
@@ -45,6 +46,7 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="sensebox_sensor_pressure" />
|
<Block type="sensebox_sensor_pressure" />
|
||||||
<Block type="sensebox_sensor_bme680_bsec" />
|
<Block type="sensebox_sensor_bme680_bsec" />
|
||||||
<Block type="sensebox_scd30" />
|
<Block type="sensebox_scd30" />
|
||||||
|
<Block type="sensebox_gps" />
|
||||||
<Block type="sensebox_sensor_ultrasonic_ranger" />
|
<Block type="sensebox_sensor_ultrasonic_ranger" />
|
||||||
<Block type="sensebox_sensor_sound" />
|
<Block type="sensebox_sensor_sound" />
|
||||||
<Block type="sensebox_button" />
|
<Block type="sensebox_button" />
|
||||||
@@ -61,6 +63,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 +112,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">
|
||||||
@@ -183,7 +234,7 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="sensebox_send_to_osem" />
|
<Block type="sensebox_send_to_osem" />
|
||||||
</Category>
|
</Category>
|
||||||
<Category id="catSenseBoxOutput_LoRa" name=" LoRa" colour={getColour().sensebox}>
|
<Category id="catSenseBoxOutput_LoRa" name=" LoRa" colour={getColour().sensebox}>
|
||||||
<Category id="catSenseBoxOutput_LoRa_activation" name=" Aktiviereung" colour={getColour().sensebox}>
|
<Category id="catSenseBoxOutput_LoRa_activation" name=" Aktivierung" colour={getColour().sensebox}>
|
||||||
<Block type="sensebox_lora_initialize_otaa" />
|
<Block type="sensebox_lora_initialize_otaa" />
|
||||||
<Block type="sensebox_lora_initialize_abp" />
|
<Block type="sensebox_lora_initialize_abp" />
|
||||||
</Category>
|
</Category>
|
||||||
@@ -191,6 +242,35 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="sensebox_lora_message_send" />
|
<Block type="sensebox_lora_message_send" />
|
||||||
<Block type="sensebox_send_lora_sensor_value" />
|
<Block type="sensebox_send_lora_sensor_value" />
|
||||||
</Category>
|
</Category>
|
||||||
|
<Category id="catSenseBoxOutput_Map" name=" TTN Mapper" colour={getColour().sensebox}>
|
||||||
|
<Block type="sensebox_lora_ttn_mapper">
|
||||||
|
<Value name="Latitude">
|
||||||
|
<Block type="sensebox_gps">
|
||||||
|
<Field name="dropdown">latitude</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="Longitude">
|
||||||
|
<Block type="sensebox_gps">
|
||||||
|
<Field name="dropdown">longitude</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="Altitude">
|
||||||
|
<Block type="sensebox_gps">
|
||||||
|
<Field name="dropdown">altitude</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="pDOP">
|
||||||
|
<Block type="sensebox_gps">
|
||||||
|
<Field name="dropdown">pDOP</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
<Value name="Fix Type">
|
||||||
|
<Block type="sensebox_gps">
|
||||||
|
<Field name="dropdown">fixType</Field>
|
||||||
|
</Block>
|
||||||
|
</Value>
|
||||||
|
</Block>
|
||||||
|
</Category>
|
||||||
<Category id="catSenseBoxOutput_LoRa_cayenne" name=" Cayenne LPP" colour={getColour().sensebox}>
|
<Category id="catSenseBoxOutput_LoRa_cayenne" name=" Cayenne LPP" colour={getColour().sensebox}>
|
||||||
<Block type="sensebox_lora_cayenne_send" />
|
<Block type="sensebox_lora_cayenne_send" />
|
||||||
<Block type="sensebox_lora_cayenne_temperature" />
|
<Block type="sensebox_lora_cayenne_temperature" />
|
||||||
@@ -202,7 +282,26 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="sensebox_lora_cayenne_gps" />
|
<Block type="sensebox_lora_cayenne_gps" />
|
||||||
</Category>
|
</Category>
|
||||||
</Category>
|
</Category>
|
||||||
<Category name="Logik" colour={getColour().logic}>
|
<Category id="webserver" name="Webserver" colour={getColour().webserver}>
|
||||||
|
<Block type="sensebox_initialize_http_server"></Block>
|
||||||
|
<Block type="sensebox_http_on_client_connect"></Block>
|
||||||
|
<Block type="sensebox_ip_address"></Block>
|
||||||
|
<Block type="sensebox_http_method"></Block>
|
||||||
|
<Block type="sensebox_http_uri"></Block>
|
||||||
|
<Block type="sensebox_http_protocol_version"></Block>
|
||||||
|
<Block type="sensebox_http_user_agent"></Block>
|
||||||
|
<Block type="sensebox_generate_http_succesful_response"></Block>
|
||||||
|
<Block type="sensebox_generate_http_not_found_response"></Block>
|
||||||
|
<Block type="sensebox_generate_html_doc"></Block>
|
||||||
|
<Block type="sensebox_general_html_tag"></Block>
|
||||||
|
<Block type="sensebox_web_readHTML"></Block>
|
||||||
|
</Category>
|
||||||
|
<Category id="mqtt" name="MQTT" colour={getColour().mqtt}>
|
||||||
|
<Block type="sensebox_mqtt_setup" />
|
||||||
|
<Block type="sensebox_mqtt_publish" />
|
||||||
|
{/* <Block type="sensebox_mqtt_subscribe" /> */}
|
||||||
|
</Category>
|
||||||
|
<Category name={Blockly.Msg.toolbox_logic} colour={getColour().logic}>
|
||||||
<Block type="controls_if" />
|
<Block type="controls_if" />
|
||||||
<Block type="controls_ifelse" />
|
<Block type="controls_ifelse" />
|
||||||
<Block type="logic_compare" />
|
<Block type="logic_compare" />
|
||||||
@@ -211,7 +310,7 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="logic_boolean" />
|
<Block type="logic_boolean" />
|
||||||
<Block type="switch_case" />
|
<Block type="switch_case" />
|
||||||
</Category>
|
</Category>
|
||||||
<Category id="loops" name="Schleifen" colour={getColour().loops}>
|
<Category id="loops" name={Blockly.Msg.toolbox_loops} colour={getColour().loops}>
|
||||||
<Block type="controls_repeat_ext">
|
<Block type="controls_repeat_ext">
|
||||||
<Value name="TIMES">
|
<Value name="TIMES">
|
||||||
<Block type="math_number">
|
<Block type="math_number">
|
||||||
@@ -250,7 +349,7 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="text_length" />
|
<Block type="text_length" />
|
||||||
<Block type="text_isEmpty" />
|
<Block type="text_isEmpty" />
|
||||||
</Category>
|
</Category>
|
||||||
<Category id="time" name="Zeit" colour={getColour().time}>
|
<Category id="time" name={Blockly.Msg.toolbox_time} colour={getColour().time}>
|
||||||
<Block type="time_delay">
|
<Block type="time_delay">
|
||||||
<Value name="DELAY_TIME_MILI">
|
<Value name="DELAY_TIME_MILI">
|
||||||
<Block type="math_number">
|
<Block type="math_number">
|
||||||
@@ -270,7 +369,7 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="infinite_loop"></Block>
|
<Block type="infinite_loop"></Block>
|
||||||
<Block type="sensebox_interval_timer"></Block>
|
<Block type="sensebox_interval_timer"></Block>
|
||||||
</Category>
|
</Category>
|
||||||
<Category id="catMath" name="Mathematik" colour={getColour().math}>
|
<Category id="math" name={Blockly.Msg.toolbox_math} colour={getColour().math}>
|
||||||
<Block type="math_number"></Block>
|
<Block type="math_number"></Block>
|
||||||
<Block type="math_arithmetic"></Block>
|
<Block type="math_arithmetic"></Block>
|
||||||
<Block type="math_single"></Block>
|
<Block type="math_single"></Block>
|
||||||
@@ -323,9 +422,15 @@ 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={Blockly.Msg.toolbox_variables} 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>
|
||||||
|
<Category name={Blockly.Msg.toolbox_functions} colour={getColour().procedures} custom="PROCEDURE"></Category>
|
||||||
<sep></sep>
|
<sep></sep>
|
||||||
<Category name="Eingang/Ausgang" colour={getColour().io}>
|
<Category name={Blockly.Msg.toolbox_io} colour={getColour().io}>
|
||||||
<Block type="io_digitalwrite"></Block>
|
<Block type="io_digitalwrite"></Block>
|
||||||
<Block type="io_digitalread"></Block>
|
<Block type="io_digitalread"></Block>
|
||||||
<Block type="io_builtin_led"></Block>
|
<Block type="io_builtin_led"></Block>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import MuiAccordion from '@material-ui/core/Accordion';
|
|||||||
import MuiAccordionSummary from '@material-ui/core/AccordionSummary';
|
import MuiAccordionSummary from '@material-ui/core/AccordionSummary';
|
||||||
import MuiAccordionDetails from '@material-ui/core/AccordionDetails';
|
import MuiAccordionDetails from '@material-ui/core/AccordionDetails';
|
||||||
import { Card } from '@material-ui/core';
|
import { Card } from '@material-ui/core';
|
||||||
|
import * as Blockly from 'blockly'
|
||||||
|
|
||||||
|
|
||||||
const Accordion = withStyles((theme) => ({
|
const Accordion = withStyles((theme) => ({
|
||||||
@@ -94,7 +95,7 @@ class CodeViewer extends Component {
|
|||||||
>
|
>
|
||||||
<AccordionSummary>
|
<AccordionSummary>
|
||||||
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{curlyBrackets}</b>
|
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{curlyBrackets}</b>
|
||||||
<div style={{ margin: 'auto 5px 2px 0px' }}>Arduino Quellcode</div>
|
<div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_arduino}</div>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
|
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
|
||||||
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}>
|
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}>
|
||||||
@@ -112,7 +113,7 @@ class CodeViewer extends Component {
|
|||||||
>
|
>
|
||||||
<AccordionSummary>
|
<AccordionSummary>
|
||||||
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{unequal}</b>
|
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{unequal}</b>
|
||||||
<div style={{ margin: 'auto 5px 2px 0px' }}>XML Blöcke</div>
|
<div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_xml}</div>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
|
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
|
||||||
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}>
|
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}>
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import * as Blockly from 'blockly/core';
|
||||||
|
import { De } from './Blockly/msg/de';
|
||||||
|
import { En } from './Blockly/msg/en';
|
||||||
|
|
||||||
|
import Navbar from './Navbar';
|
||||||
|
import Footer from './Footer';
|
||||||
|
import Routes from './Route/Routes';
|
||||||
|
import Cookies from './Cookies';
|
||||||
|
|
||||||
|
class Content extends Component {
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.language === 'de_DE') {
|
||||||
|
Blockly.setLocale(De);
|
||||||
|
} else if (this.props.language === 'en_US') {
|
||||||
|
Blockly.setLocale(En);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props){
|
||||||
|
if(props.language !== this.props.language){
|
||||||
|
if (this.props.language === 'de_DE') {
|
||||||
|
Blockly.setLocale(De);
|
||||||
|
} else if (this.props.language === 'en_US') {
|
||||||
|
Blockly.setLocale(En);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="wrapper">
|
||||||
|
<Navbar />
|
||||||
|
<Routes />
|
||||||
|
<Cookies />
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Content.propTypes = {
|
||||||
|
language: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
language: state.general.language
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(Content);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import CookieConsent from "react-cookie-consent";
|
||||||
|
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
class Cookies extends Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<CookieConsent
|
||||||
|
location="bottom"
|
||||||
|
buttonText="Okay!!"
|
||||||
|
cookieName="cookieConsent"
|
||||||
|
style={{ background: "#2B373B" }}
|
||||||
|
buttonStyle={{ background: "white", color: "#4EAF47", fontSize: "1rem" }}
|
||||||
|
expires={150}
|
||||||
|
>
|
||||||
|
This website uses cookies to enhance the user experience.{" "}
|
||||||
|
</CookieConsent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default Cookies;
|
||||||
@@ -7,14 +7,14 @@ import Typography from '@material-ui/core/Typography';
|
|||||||
class Footer extends Component {
|
class Footer extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<footer style={{position:'absolute', bottom: '0', width: '100%'}}>
|
<footer style={{ position: 'absolute', bottom: '0', width: '100%' }}>
|
||||||
<div style={{minHeight:'30px', backgroundColor:'#DDDDDD', textAlign: 'center', paddingTop: '2px'}}>
|
<div style={{ minHeight: '30px', backgroundColor: '#4EAF47', textAlign: 'center', paddingTop: '2px' }}>
|
||||||
<div style={{color: 'grey', height: '100%'}}>
|
<div style={{ color: 'white', height: '100%' }}>
|
||||||
<Link to={"/impressum"} style={{textDecoration: 'none', color: 'inherit'}}>Impressum</Link>
|
<Link to={"/impressum"} style={{ textDecoration: 'none', color: 'inherit' }}>Impressum</Link>
|
||||||
<Typography style={{margin: '0px 10px 0px 10px', display: 'initial', fontSize: '1rem'}}>|</Typography>
|
<Typography style={{ margin: '0px 10px 0px 10px', display: 'initial', fontSize: '1rem' }}>|</Typography>
|
||||||
<Link to={"/ueberuns"} style={{textDecoration: 'none', color: 'inherit'}}>Über uns</Link>
|
<Link to={"/privacy"} style={{ textDecoration: 'none', color: 'inherit' }}>Privacy</Link>
|
||||||
<Typography style={{margin: '0px 10px 0px 10px', display: 'initial', fontSize: '1rem'}}>|</Typography>
|
<Typography style={{ margin: '0px 10px 0px 10px', display: 'initial', fontSize: '1rem' }}>|</Typography>
|
||||||
<Link to={"/faq"} style={{textDecoration: 'none', color: 'inherit'}}>FAQ</Link>
|
<a href="https://sensebox.de" style={{ textDecoration: 'none', color: 'inherit' }}>sensebox.de</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ import { connect } from 'react-redux';
|
|||||||
import { clearStats, workspaceName } from '../actions/workspaceActions';
|
import { clearStats, workspaceName } from '../actions/workspaceActions';
|
||||||
|
|
||||||
import * as Blockly from 'blockly/core';
|
import * as Blockly from 'blockly/core';
|
||||||
|
import { createNameId } from 'mnemonic-id';
|
||||||
|
|
||||||
import WorkspaceStats from './WorkspaceStats';
|
import WorkspaceStats from './Workspace/WorkspaceStats';
|
||||||
import WorkspaceFunc from './WorkspaceFunc';
|
import WorkspaceFunc from './Workspace/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 './Workspace/TrashcanButtons';
|
||||||
import HintTutorialExists from './Tutorial/HintTutorialExists';
|
import HintTutorialExists from './Tutorial/HintTutorialExists';
|
||||||
|
import Snackbar from './Snackbar';
|
||||||
|
|
||||||
import Grid from '@material-ui/core/Grid';
|
import Grid from '@material-ui/core/Grid';
|
||||||
import IconButton from '@material-ui/core/IconButton';
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
@@ -45,10 +47,24 @@ const styles = (theme) => ({
|
|||||||
class Home extends Component {
|
class Home extends Component {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
codeOn: false
|
codeOn: false,
|
||||||
|
snackbar: false,
|
||||||
|
type: '',
|
||||||
|
key: '',
|
||||||
|
message: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidMount() {
|
||||||
|
this.setState({ stats: window.localStorage.getItem('stats') });
|
||||||
|
if(!this.props.project){
|
||||||
|
this.props.workspaceName(createNameId());
|
||||||
|
}
|
||||||
|
if(this.props.message && this.props.message.id === 'GET_SHARE_FAIL'){
|
||||||
|
this.setState({ snackbar: true, key: Date.now(), message: `Das angefragte geteilte Projekt konnte nicht gefunden werden.`, type: 'error' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props) {
|
||||||
/* 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.
|
||||||
@@ -74,10 +90,15 @@ class Home extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ float: 'right', height: '40px', marginBottom: '20px' }}><WorkspaceFunc /></div>
|
{this.props.statistics ?
|
||||||
<div style={{ float: 'left', height: '40px', position: 'relative' }}><WorkspaceStats /></div>
|
<div style={{ float: 'left', height: '40px', position: 'relative' }}><WorkspaceStats /></div>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
<div style={{ float: 'right', height: '40px', marginBottom: '20px' }}>
|
||||||
|
<WorkspaceFunc project={this.props.project} projectType={this.props.projectType}/>
|
||||||
|
</div>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={12} md={this.state.codeOn ? 6 : 12} style={{ position: 'relative' }}>
|
<Grid item xs={12} md={this.state.codeOn ? 8 : 12} style={{ position: 'relative' }}>
|
||||||
<Tooltip title={this.state.codeOn ? 'Code ausblenden' : 'Code anzeigen'} >
|
<Tooltip title={this.state.codeOn ? 'Code ausblenden' : 'Code anzeigen'} >
|
||||||
<IconButton
|
<IconButton
|
||||||
className={this.state.codeOn ? this.props.classes.codeOn : this.props.classes.codeOff}
|
className={this.state.codeOn ? this.props.classes.codeOn : this.props.classes.codeOff}
|
||||||
@@ -88,15 +109,24 @@ class Home extends Component {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<TrashcanButtons />
|
<TrashcanButtons />
|
||||||
<BlocklyWindow blocklyCSS={{ height: '80vH' }} blockDisabled />
|
{this.props.project ?
|
||||||
|
< BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.props.project.xml} />
|
||||||
|
: < BlocklyWindow blocklyCSS={{ height: '80vH' }} />
|
||||||
|
}
|
||||||
</Grid>
|
</Grid>
|
||||||
{this.state.codeOn ?
|
{this.state.codeOn ?
|
||||||
<Grid item xs={12} md={6}>
|
<Grid item xs={12} md={4}>
|
||||||
<CodeViewer />
|
<CodeViewer />
|
||||||
</Grid>
|
</Grid>
|
||||||
: null}
|
: null}
|
||||||
</Grid>
|
</Grid>
|
||||||
<HintTutorialExists />
|
<HintTutorialExists />
|
||||||
|
<Snackbar
|
||||||
|
open={this.state.snackbar}
|
||||||
|
message={this.state.message}
|
||||||
|
type={this.state.type}
|
||||||
|
key={this.state.key}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -104,8 +134,15 @@ class Home extends Component {
|
|||||||
|
|
||||||
Home.propTypes = {
|
Home.propTypes = {
|
||||||
clearStats: PropTypes.func.isRequired,
|
clearStats: PropTypes.func.isRequired,
|
||||||
workspaceName: PropTypes.func.isRequired
|
workspaceName: PropTypes.func.isRequired,
|
||||||
|
message: PropTypes.object.isRequired,
|
||||||
|
statistics: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
message: state.message,
|
||||||
|
statistics: state.general.statistics
|
||||||
|
});
|
||||||
|
|
||||||
export default connect(null, { clearStats, workspaceName })(withStyles(styles, { withTheme: true })(Home));
|
|
||||||
|
export default connect(mapStateToProps, { clearStats, workspaceName })(withStyles(styles, { withTheme: true })(Home));
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
class Impressum extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{ margin: '0px 24px 0px 24px' }}>
|
||||||
|
<h1>Impressum</h1>
|
||||||
|
|
||||||
|
<h2>Angaben gemäß § 5 TMG:</h2>
|
||||||
|
Institut für Geoinformatik<br />
|
||||||
|
Heisenbergstraße 2<br />
|
||||||
|
Geo 1<br />
|
||||||
|
48149 Münster
|
||||||
|
|
||||||
|
<h2>Kontakt:</h2>
|
||||||
|
E-Mail: <a href="mailto:info@mybadges.org!">info@mybadges.org</a>
|
||||||
|
|
||||||
|
<h2>Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV:</h2>
|
||||||
|
Geschäftsführende Direktorin Prof. Dr. Angela Schwering<br />
|
||||||
|
Heisenbergstraße 2<br />
|
||||||
|
Geo 1<br />
|
||||||
|
48149 Münster
|
||||||
|
|
||||||
|
<h2>Streitschlichtung</h2>
|
||||||
|
Die Europäische Kommission stellt eine Plattform zur Online-Streitbeilegung (OS) bereit: <a href="https://ec.europa.eu/consumers/odr" target="_blank" rel="noopener noreferrer">https://ec.europa.eu/consumers/odr</a>.<br />
|
||||||
|
Unsere E-Mail-Adresse finden Sie oben im Impressum.<br />
|
||||||
|
<p>Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen.</p>
|
||||||
|
|
||||||
|
<h3>Haftung für Inhalte</h3>
|
||||||
|
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen.
|
||||||
|
<p>Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.</p>
|
||||||
|
|
||||||
|
<h3>Haftung für Links</h3>
|
||||||
|
Unser Angebot enthält Links zu externen Websites Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar.
|
||||||
|
<p>Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.</p>
|
||||||
|
|
||||||
|
<h3>Urheberrecht</h3>
|
||||||
|
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet.
|
||||||
|
<p>Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(Impressum);
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { logout } from '../actions/authActions';
|
||||||
|
|
||||||
import senseboxLogo from './sensebox_logo.svg';
|
import senseboxLogo from './sensebox_logo.svg';
|
||||||
|
|
||||||
@@ -16,9 +19,12 @@ import IconButton from '@material-ui/core/IconButton';
|
|||||||
import ListItem from '@material-ui/core/ListItem';
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||||
import ListItemText from '@material-ui/core/ListItemText';
|
import ListItemText from '@material-ui/core/ListItemText';
|
||||||
|
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||||
|
|
||||||
import { faBars, faChevronLeft, faBuilding, faIdCard, faEnvelope, faCog, faChalkboardTeacher, faFolderPlus } from "@fortawesome/free-solid-svg-icons";
|
import { faBars, faChevronLeft, faLayerGroup, faSignInAlt, faSignOutAlt, faCertificate, faUserCircle, faCog, faChalkboardTeacher, faTools, faLightbulb } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import * as Blockly from 'blockly'
|
||||||
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
drawerWidth: {
|
drawerWidth: {
|
||||||
@@ -45,32 +51,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: this.props.tutorialIsLoading || this.props.projectIsLoading ? '0px' : '30px', boxShadow: this.props.tutorialIsLoading || this.props.projectIsLoading ? 'none' : '0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)' }}
|
||||||
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,42 +88,78 @@ 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ü
|
{Blockly.Msg.navbar_menu}
|
||||||
</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: Blockly.Msg.navbar_tutorials, icon: faChalkboardTeacher, link: "/tutorial" },
|
||||||
<Link to={item.link} key={index} style={{textDecoration: 'none', color: 'inherit'}}>
|
{ text: Blockly.Msg.navbar_tutorialbuilder, icon: faTools, link: "/tutorial/builder", restriction: this.props.user && this.props.user.blocklyRole !== 'user' && this.props.isAuthenticated },
|
||||||
<ListItem button onClick={this.toggleDrawer}>
|
{ text: Blockly.Msg.navbar_gallery, icon: faLightbulb, link: "/gallery" },
|
||||||
<ListItemIcon><FontAwesomeIcon icon={item.icon}/></ListItemIcon>
|
{ text: Blockly.Msg.navbar_projects, icon: faLayerGroup, link: "/project", restriction: this.props.isAuthenticated }].map((item, index) => {
|
||||||
<ListItemText primary={item.text} />
|
if (item.restriction || Object.keys(item).filter(attribute => attribute === 'restriction').length === 0) {
|
||||||
</ListItem>
|
return (
|
||||||
</Link>
|
<Link to={item.link} key={index} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||||
))}
|
<ListItem button onClick={this.toggleDrawer}>
|
||||||
|
<ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon>
|
||||||
|
<ListItemText primary={item.text} />
|
||||||
|
</ListItem>
|
||||||
|
</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: Blockly.Msg.navbar_login, icon: faSignInAlt, link: '/user/login', restriction: !this.props.isAuthenticated },
|
||||||
<ListItem button key={index} onClick={this.toggleDrawer}>
|
{ text: Blockly.Msg.navbar_account, icon: faUserCircle, link: '/user', restriction: this.props.isAuthenticated },
|
||||||
<ListItemIcon><FontAwesomeIcon icon={item.icon}/></ListItemIcon>
|
{ text: Blockly.Msg.navbar_mybadges, icon: faCertificate, link: '/user/badge', restriction: this.props.isAuthenticated },
|
||||||
<ListItemText primary={item.text} />
|
{ text: Blockly.Msg.navbar_logout, icon: faSignOutAlt, function: this.props.logout, restriction: this.props.isAuthenticated },
|
||||||
</ListItem>
|
{ text: Blockly.Msg.navbar_settings, icon: faCog, link: "/settings" }].map((item, index) => {
|
||||||
))}
|
if (item.restriction || Object.keys(item).filter(attribute => attribute === 'restriction').length === 0) {
|
||||||
|
return (
|
||||||
|
<Link to={item.link} key={index} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||||
|
<ListItem button onClick={item.function ? () => { item.function(); this.toggleDrawer(); } : this.toggleDrawer}>
|
||||||
|
<ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon>
|
||||||
|
<ListItemText primary={item.text} />
|
||||||
|
</ListItem>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)}
|
||||||
</List>
|
</List>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
{this.props.tutorialIsLoading || this.props.projectIsLoading ?
|
||||||
|
<LinearProgress style={{ marginBottom: '30px', boxShadow: '0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)' }} />
|
||||||
|
: null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withStyles(styles, {withTheme: true})(withRouter(Navbar));
|
Navbar.propTypes = {
|
||||||
|
tutorialIsLoading: PropTypes.bool.isRequired,
|
||||||
|
projectIsLoading: PropTypes.bool.isRequired,
|
||||||
|
isAuthenticated: PropTypes.bool.isRequired,
|
||||||
|
user: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
tutorialIsLoading: state.tutorial.progress,
|
||||||
|
projectIsLoading: state.project.progress,
|
||||||
|
isAuthenticated: state.auth.isAuthenticated,
|
||||||
|
user: state.auth.user
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, { logout })(withStyles(styles, { withTheme: true })(withRouter(Navbar)));
|
||||||
|
|||||||
@@ -6,31 +6,39 @@ import { withRouter } from 'react-router-dom';
|
|||||||
|
|
||||||
import Button from '@material-ui/core/Button';
|
import Button from '@material-ui/core/Button';
|
||||||
import Typography from '@material-ui/core/Typography';
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import * as Blockly from 'blockly'
|
||||||
|
|
||||||
class NotFound extends Component {
|
class NotFound extends Component {
|
||||||
|
|
||||||
|
componentDidMount(){
|
||||||
|
// Ensure that Blockly.setLocale is adopted in the component.
|
||||||
|
// Otherwise, the text will not be displayed until the next update of the component.
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Breadcrumbs content={[{link: this.props.location.pathname, title: 'Error'}]}/>
|
<Breadcrumbs content={[{ link: this.props.location.pathname, title: 'Error' }]} />
|
||||||
<Typography variant='h4' style={{marginBottom: '5px'}}>Die von Ihnen angeforderte Seite kann nicht gefunden werden.</Typography>
|
<Typography variant='h4' style={{ marginBottom: '5px' }}>{Blockly.Msg.notfound_head}</Typography>
|
||||||
<Typography variant='body1'>Die gesuchte Seite wurde möglicherweise entfernt, ihr Name wurde geändert oder sie ist vorübergehend nicht verfügbar.</Typography>
|
<Typography variant='body1'>{Blockly.Msg.notfound_text}</Typography>
|
||||||
{this.props.button ?
|
{this.props.button ?
|
||||||
<Button
|
<Button
|
||||||
style={{marginTop: '20px'}}
|
style={{ marginTop: '20px' }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {this.props.history.push(this.props.button.link)}}
|
onClick={() => { this.props.history.push(this.props.button.link) }}
|
||||||
>
|
>
|
||||||
{this.props.button.title}
|
{this.props.button.title}
|
||||||
</Button>
|
</Button>
|
||||||
:
|
:
|
||||||
<Button
|
<Button
|
||||||
style={{marginTop: '20px'}}
|
style={{ marginTop: '20px' }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {this.props.history.push('/')}}
|
onClick={() => { this.props.history.push('/') }}
|
||||||
>
|
>
|
||||||
Zurück zur Startseite
|
{Blockly.Msg.button_back}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,187 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
class Privay extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{ margin: '0px 24px 0px 24px' }}>
|
||||||
|
<h1>Datenschutzerklärung</h1>
|
||||||
|
|
||||||
|
<h2>1. Datenschutz auf einen Blick</h2>
|
||||||
|
<h3>Allgemeine Hinweise</h3>
|
||||||
|
Die folgenden Hinweise geben einen einfachen Überblick darüber, was mit Ihren personenbezogenen Daten passiert, wenn Sie unsere Website besuchen. Personenbezogene Daten sind alle Daten, mit denen Sie persönlich identifiziert werden können. Ausführliche Informationen zum Thema Datenschutz entnehmen Sie unserer unter diesem Text aufgeführten Datenschutzerklärung.
|
||||||
|
<h3>Datenerfassung auf unserer Website</h3>
|
||||||
|
|
||||||
|
<h4>Wer ist verantwortlich für die Datenerfassung auf dieser Website?</h4>
|
||||||
|
|
||||||
|
Die Datenverarbeitung auf dieser Website erfolgt durch den Websitebetreiber. Dessen Kontaktdaten können Sie dem Impressum dieser Website entnehmen.
|
||||||
|
|
||||||
|
Wie erfassen wir Ihre Daten?
|
||||||
|
|
||||||
|
Ihre Daten werden zum einen dadurch erhoben, dass Sie uns diese mitteilen. Hierbei kann es sich z.B. um Daten handeln, die Sie in ein Kontaktformular eingeben.
|
||||||
|
|
||||||
|
Andere Daten werden automatisch beim Besuch der Website durch unsere IT-Systeme erfasst. Das sind vor allem technische Daten (z.B. Internetbrowser, Betriebssystem oder Uhrzeit des Seitenaufrufs). Die Erfassung dieser Daten erfolgt automatisch, sobald Sie unsere Website betreten.
|
||||||
|
|
||||||
|
<h4>Wofür nutzen wir Ihre Daten?</h4>
|
||||||
|
Ein Teil der Daten wird erhoben, um eine fehlerfreie Bereitstellung der Website zu gewährleisten. Andere Daten können zur Analyse Ihres Nutzerverhaltens verwendet werden.
|
||||||
|
|
||||||
|
<h4>Welche Rechte haben Sie bezüglich Ihrer Daten?</h4>
|
||||||
|
|
||||||
|
Sie haben jederzeit das Recht unentgeltlich Auskunft über Herkunft, Empfänger und Zweck Ihrer gespeicherten personenbezogenen Daten zu erhalten. Sie haben außerdem ein Recht, die Berichtigung, Sperrung oder Löschung dieser Daten zu verlangen. Hierzu sowie zu weiteren Fragen zum Thema Datenschutz können Sie sich jederzeit unter der im Impressum angegebenen Adresse an uns wenden. Des Weiteren steht Ihnen ein Beschwerderecht bei der zuständigen Aufsichtsbehörde zu.
|
||||||
|
|
||||||
|
<h4>Analyse-Tools und Tools von Drittanbietern</h4>
|
||||||
|
Beim Besuch unserer Website kann Ihr Surf-Verhalten statistisch ausgewertet werden. Das geschieht vor allem mit Cookies und mit sogenannten Analyseprogrammen. Die Analyse Ihres Surf-Verhaltens erfolgt in der Regel anonym; das Surf-Verhalten kann nicht zu Ihnen zurückverfolgt werden. Sie können dieser Analyse widersprechen oder sie durch die Nichtbenutzung bestimmter Tools verhindern. Detaillierte Informationen dazu finden Sie in der folgenden Datenschutzerklärung.
|
||||||
|
|
||||||
|
Sie können dieser Analyse widersprechen. Über die Widerspruchsmöglichkeiten werden wir Sie in dieser Datenschutzerklärung informieren.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2>2. Allgemeine Hinweise und Pflichtinformationen</h2>
|
||||||
|
<h3>Datenschutz</h3>
|
||||||
|
Die Betreiber dieser Seiten nehmen den Schutz Ihrer persönlichen Daten sehr ernst.Wir behandeln Ihre personenbezogenen Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften sowie dieser Datenschutzerklärung.
|
||||||
|
|
||||||
|
Wenn Sie diese Website benutzen, werden verschiedene personenbezogene Daten erhoben.Personenbezogene Daten sind Daten, mit denen Sie persönlich identifiziert werden können.Die vorliegende Datenschutzerklärung erläutert, welche Daten wir erheben und wofür wir sie nutzen.Sie erläutert auch, wie und zu welchem Zweck das geschieht.
|
||||||
|
|
||||||
|
Wir weisen darauf hin, dass die Datenübertragung im Internet(z.B.bei der Kommunikation per E - Mail) Sicherheitslücken aufweisen kann.Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich.
|
||||||
|
|
||||||
|
Die verantwortliche Stelle für die Datenverarbeitung auf dieser Website ist:
|
||||||
|
|
||||||
|
Institut für Geoinformatik
|
||||||
|
Heisenbergstraße 2
|
||||||
|
48149 Münster
|
||||||
|
|
||||||
|
Telefon: +49(251) 83 - 33 083
|
||||||
|
E - Mail: info@sensebox.de
|
||||||
|
|
||||||
|
Verantwortliche Stelle ist die natürliche oder juristische Person, die allein oder gemeinsam mit anderen über die Zwecke und Mittel der Verarbeitung von personenbezogenen Daten(z.B.Namen, E - Mail - Adressen o.Ä.) entscheidet.
|
||||||
|
|
||||||
|
<h4>Widerruf Ihrer Einwilligung zur Datenverarbeitung</h4>
|
||||||
|
Viele Datenverarbeitungsvorgänge sind nur mit Ihrer ausdrücklichen Einwilligung möglich.Sie können eine bereits erteilte Einwilligung jederzeit widerrufen.Dazu reicht eine formlose Mitteilung per E - Mail an uns.Die Rechtmäßigkeit der bis zum Widerruf erfolgten Datenverarbeitung bleibt vom Widerruf unberührt.
|
||||||
|
|
||||||
|
<h4>Beschwerderecht bei der zuständigen Aufsichtsbehörde</h4>
|
||||||
|
Im Falle datenschutzrechtlicher Verstöße steht dem Betroffenen ein Beschwerderecht bei der zuständigen Aufsichtsbehörde zu.Zuständige Aufsichtsbehörde in datenschutzrechtlichen Fragen ist der Landesdatenschutzbeauftragte des Bundeslandes, in dem unser Unternehmen seinen Sitz hat.Eine Liste der Datenschutzbeauftragten sowie deren Kontaktdaten können folgendem Link entnommen werden: https://www.bfdi.bund.de/DE/Infothek/Anschriften_Links/anschriften_links-node.html.
|
||||||
|
|
||||||
|
<h4>Recht auf Datenübertragbarkeit</h4>
|
||||||
|
Sie haben das Recht, Daten, die wir auf Grundlage Ihrer Einwilligung oder in Erfüllung eines Vertrags automatisiert verarbeiten, an sich oder an einen Dritten in einem gängigen, maschinenlesbaren Format aushändigen zu lassen.Sofern Sie die direkte Übertragung der Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur, soweit es technisch machbar ist.
|
||||||
|
|
||||||
|
<h4>SSL - bzw.TLS - Verschlüsselung</h4>
|
||||||
|
Diese Seite nutzt aus Sicherheitsgründen und zum Schutz der Übertragung vertraulicher Inhalte, wie zum Beispiel Bestellungen oder Anfragen, die Sie an uns als Seitenbetreiber senden, eine SSL - bzw.TLS - Verschlüsselung.Eine verschlüsselte Verbindung erkennen Sie daran, dass die Adresszeile des Browsers von “http://” auf “https://” wechselt und an dem Schloss-Symbol in Ihrer Browserzeile.
|
||||||
|
|
||||||
|
Wenn die SSL - bzw.TLS - Verschlüsselung aktiviert ist, können die Daten, die Sie an uns übermitteln, nicht von Dritten mitgelesen werden.
|
||||||
|
|
||||||
|
<h4>Auskunft, Sperrung, Löschung</h4>
|
||||||
|
Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen jederzeit das Recht auf unentgeltliche Auskunft über Ihre gespeicherten personenbezogenen Daten, deren Herkunft und Empfänger und den Zweck der Datenverarbeitung und ggf.ein Recht auf Berichtigung, Sperrung oder Löschung dieser Daten.Hierzu sowie zu weiteren Fragen zum Thema personenbezogene Daten können Sie sich jederzeit unter der im Impressum angegebenen Adresse an uns wenden.
|
||||||
|
|
||||||
|
<h4>Widerspruch gegen Werbe - Mails</h4>
|
||||||
|
Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit widersprochen.Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam - E - Mails, vor.
|
||||||
|
|
||||||
|
<h2>3. Datenschutzbeauftragter</h2>
|
||||||
|
Gesetzlich vorgeschriebener Datenschutzbeauftragter
|
||||||
|
Wir haben für unser Unternehmen einen Datenschutzbeauftragten bestellt.
|
||||||
|
|
||||||
|
<p>Institut für Geoinformatik</p>
|
||||||
|
<p>Heisenbergstraße 2</p>
|
||||||
|
<p>48149 Münster</p>
|
||||||
|
|
||||||
|
<p>Telefon: +49(251) 83 - 33 083</p>
|
||||||
|
<p>E - Mail: info@sensebox.de</p>
|
||||||
|
|
||||||
|
<h2>4. Datenerfassung auf unserer Website</h2>
|
||||||
|
<h3>Cookies</h3>
|
||||||
|
Die Internetseiten verwenden teilweise so genannte Cookies.Cookies richten auf Ihrem Rechner keinen Schaden an und enthalten keine Viren.Cookies dienen dazu, unser Angebot nutzerfreundlicher, effektiver und sicherer zu machen.Cookies sind kleine Textdateien, die auf Ihrem Rechner abgelegt werden und die Ihr Browser speichert.
|
||||||
|
|
||||||
|
Die meisten der von uns verwendeten Cookies sind so genannte “Session - Cookies”.Sie werden nach Ende Ihres Besuchs automatisch gelöscht.Andere Cookies bleiben auf Ihrem Endgerät gespeichert bis Sie diese löschen.Diese Cookies ermöglichen es uns, Ihren Browser beim nächsten Besuch wiederzuerkennen.
|
||||||
|
|
||||||
|
Sie können Ihren Browser so einstellen, dass Sie über das Setzen von Cookies informiert werden und Cookies nur im Einzelfall erlauben, die Annahme von Cookies für bestimmte Fälle oder generell ausschließen sowie das automatische Löschen der Cookies beim Schließen des Browser aktivieren.Bei der Deaktivierung von Cookies kann die Funktionalität dieser Website eingeschränkt sein.
|
||||||
|
|
||||||
|
Cookies, die zur Durchführung des elektronischen Kommunikationsvorgangs oder zur Bereitstellung bestimmter, von Ihnen erwünschter Funktionen(z.B.Warenkorbfunktion) erforderlich sind, werden auf Grundlage von Art. 6 Abs. 1 lit.f DSGVO gespeichert.Der Websitebetreiber hat ein berechtigtes Interesse an der Speicherung von Cookies zur technisch fehlerfreien und optimierten Bereitstellung seiner Dienste.Soweit andere Cookies(z.B.Cookies zur Analyse Ihres Surfverhaltens) gespeichert werden, werden diese in dieser Datenschutzerklärung gesondert behandelt.
|
||||||
|
|
||||||
|
<h4> Server - Log - Dateien</h4>
|
||||||
|
Der Provider der Seiten erhebt und speichert automatisch Informationen in so genannten Server - Log - Dateien, die Ihr Browser automatisch an uns übermittelt.Dies sind:
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>Browsertyp und Browserversion</li>
|
||||||
|
<li>verwendetes Betriebssystem</li>
|
||||||
|
<li>Referrer URL</li>
|
||||||
|
<li>Hostname des zugreifenden Rechners</li>
|
||||||
|
<li>Uhrzeit der Serveranfrage</li>
|
||||||
|
<li>
|
||||||
|
IP - Adresse</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Eine Zusammenführung dieser Daten mit anderen Datenquellen wird nicht vorgenommen.
|
||||||
|
|
||||||
|
Grundlage für die Datenverarbeitung ist Art. 6 Abs. 1 lit.b DSGVO, der die Verarbeitung von Daten zur Erfüllung eines Vertrags oder vorvertraglicher Maßnahmen gestattet.
|
||||||
|
|
||||||
|
<h4>Kontaktformular</h4>
|
||||||
|
Wenn Sie uns per Kontaktformular Anfragen zukommen lassen, werden Ihre Angaben aus dem Anfrageformular inklusive der von Ihnen dort angegebenen Kontaktdaten zwecks Bearbeitung der Anfrage und für den Fall von Anschlussfragen bei uns gespeichert.Diese Daten geben wir nicht ohne Ihre Einwilligung weiter.
|
||||||
|
|
||||||
|
Die Verarbeitung der in das Kontaktformular eingegebenen Daten erfolgt somit ausschließlich auf Grundlage Ihrer Einwilligung(Art. 6 Abs. 1 lit.a DSGVO).Sie können diese Einwilligung jederzeit widerrufen.Dazu reicht eine formlose Mitteilung per E - Mail an uns.Die Rechtmäßigkeit der bis zum Widerruf erfolgten Datenverarbeitungsvorgänge bleibt vom Widerruf unberührt.
|
||||||
|
|
||||||
|
Die von Ihnen im Kontaktformular eingegebenen Daten verbleiben bei uns, bis Sie uns zur Löschung auffordern, Ihre Einwilligung zur Speicherung widerrufen oder der Zweck für die Datenspeicherung entfällt(z.B.nach abgeschlossener Bearbeitung Ihrer Anfrage).Zwingende gesetzliche Bestimmungen – insbesondere Aufbewahrungsfristen – bleiben unberührt.
|
||||||
|
|
||||||
|
<h4>Registrierung auf dieser Website</h4>
|
||||||
|
Sie können sich auf unserer Website registrieren, um zusätzliche Funktionen auf der Seite zu nutzen. Die dazu eingegebenen Daten verwenden wir nur zum Zwecke der Nutzung des jeweiligen Angebotes oder Dienstes, für den Sie sich registriert haben.Die bei der Registrierung abgefragten Pflichtangaben müssen vollständig angegeben werden.Anderenfalls werden wir die Registrierung ablehnen.
|
||||||
|
|
||||||
|
Für wichtige Änderungen etwa beim Angebotsumfang oder bei technisch notwendigen Änderungen nutzen wir die bei der Registrierung angegebene E - Mail - Adresse, um Sie auf diesem Wege zu informieren.
|
||||||
|
|
||||||
|
Die Verarbeitung der bei der Registrierung eingegebenen Daten erfolgt auf Grundlage Ihrer Einwilligung(Art. 6 Abs. 1 lit.a DSGVO).Sie können eine von Ihnen erteilte Einwilligung jederzeit widerrufen.Dazu reicht eine formlose Mitteilung per E - Mail an uns.Die Rechtmäßigkeit der bereits erfolgten Datenverarbeitung bleibt vom Widerruf unberührt.
|
||||||
|
|
||||||
|
Die bei der Registrierung erfassten Daten werden von uns gespeichert, solange Sie auf unserer Website registriert sind und werden anschließend gelöscht.Gesetzliche Aufbewahrungsfristen bleiben unberührt.
|
||||||
|
|
||||||
|
<h4>Kommentarfunktion auf dieser Website</h4>
|
||||||
|
Für die Kommentarfunktion auf dieser Seite werden neben Ihrem Kommentar auch Angaben zum Zeitpunkt der Erstellung des Kommentars, Ihre E - Mail - Adresse und, wenn Sie nicht anonym posten, der von Ihnen gewählte Nutzername gespeichert.
|
||||||
|
|
||||||
|
<h4>Speicherung der IP - Adresse</h4>
|
||||||
|
|
||||||
|
Unsere Kommentarfunktion speichert die IP - Adressen der Nutzer, die Kommentare verfassen.Da wir Kommentare auf unserer Seite nicht vor der Freischaltung prüfen, benötigen wir diese Daten, um im Falle von Rechtsverletzungen wie Beleidigungen oder Propaganda gegen den Verfasser vorgehen zu können.
|
||||||
|
|
||||||
|
<h4>Abonnieren von Kommentaren</h4>
|
||||||
|
|
||||||
|
Als Nutzer der Seite können Sie nach einer Anmeldung Kommentare abonnieren.Sie erhalten eine Bestätigungsemail, um zu prüfen, ob Sie der Inhaber der angegebenen E - Mail - Adresse sind.Sie können diese Funktion jederzeit über einen Link in den Info - Mails abbestellen.Die im Rahmen des Abonnierens von Kommentaren eingegebenen Daten werden in diesem Fall gelöscht; wenn Sie diese Daten für andere Zwecke und an anderer Stelle(z.B.Newsletterbestellung) an uns übermittelt haben, verbleiben die jedoch bei uns.
|
||||||
|
|
||||||
|
<h4>Speicherdauer der Kommentare</h4>
|
||||||
|
|
||||||
|
Die Kommentare und die damit verbundenen Daten(z.B.IP - Adresse) werden gespeichert und verbleiben auf unserer Website, bis der kommentierte Inhalt vollständig gelöscht wurde oder die Kommentare aus rechtlichen Gründen gelöscht werden müssen(z.B.beleidigende Kommentare).
|
||||||
|
|
||||||
|
<h4>Rechtsgrundlage</h4>
|
||||||
|
|
||||||
|
Die Speicherung der Kommentare erfolgt auf Grundlage Ihrer Einwilligung(Art. 6 Abs. 1 lit.a DSGVO).Sie können eine von Ihnen erteilte Einwilligung jederzeit widerrufen.Dazu reicht eine formlose Mitteilung per E - Mail an uns.Die Rechtmäßigkeit der bereits erfolgten Datenverarbeitungsvorgänge bleibt vom Widerruf unberührt.
|
||||||
|
|
||||||
|
<h4>Verarbeiten von Daten(Kunden - und Vertragsdaten)</h4>
|
||||||
|
Wir erheben, verarbeiten und nutzen personenbezogene Daten nur, soweit sie für die Begründung, inhaltliche Ausgestaltung oder Änderung des Rechtsverhältnisses erforderlich sind(Bestandsdaten).Dies erfolgt auf Grundlage von Art. 6 Abs. 1 lit.b DSGVO, der die Verarbeitung von Daten zur Erfüllung eines Vertrags oder vorvertraglicher Maßnahmen gestattet.Personenbezogene Daten über die Inanspruchnahme unserer Internetseiten(Nutzungsdaten) erheben, verarbeiten und nutzen wir nur, soweit dies erforderlich ist, um dem Nutzer die Inanspruchnahme des Dienstes zu ermöglichen oder abzurechnen.
|
||||||
|
|
||||||
|
Die erhobenen Kundendaten werden nach Abschluss des Auftrags oder Beendigung der Geschäftsbeziehung gelöscht.Gesetzliche Aufbewahrungsfristen bleiben unberührt.
|
||||||
|
|
||||||
|
{/* 5. Analyse Tools und Werbung
|
||||||
|
Matomo(ehemals Piwik)
|
||||||
|
Diese Website benutzt den Open Source Webanalysedienst Matomo.Matomo verwendet so genannte "Cookies".Das sind Textdateien, die auf Ihrem Computer gespeichert werden und die eine Analyse der Benutzung der Website durch Sie ermöglichen.Dazu werden die durch den Cookie erzeugten Informationen über die Benutzung dieser Website auf unserem Server gespeichert.Die IP - Adresse wird vor der Speicherung anonymisiert.
|
||||||
|
Matomo - Cookies verbleiben auf Ihrem Endgerät, bis Sie sie löschen.
|
||||||
|
Die Speicherung von Matomo - Cookies erfolgt auf Grundlage von Art. 6 Abs. 1 lit.f DSGVO.Der Websitebetreiber hat ein berechtigtes Interesse an der anonymisierten Analyse des Nutzerverhaltens, um sowohl sein Webangebot als auch seine Werbung zu optimieren.
|
||||||
|
Die durch den Cookie erzeugten Informationen über die Benutzung dieser Website werden nicht an Dritte weitergegeben.Sie können die Speicherung der Cookies durch eine entsprechende Einstellung Ihrer Browser - Software verhindern; wir weisen Sie jedoch darauf hin, dass Sie in diesem Fall gegebenenfalls nicht sämtliche Funktionen dieser Website vollumfänglich werden nutzen können.
|
||||||
|
Wenn Sie mit der Speicherung und Nutzung Ihrer Daten nicht einverstanden sind, können Sie die Speicherung und Nutzung hier deaktivieren.In diesem Fall wird in Ihrem Browser ein Opt - Out - Cookie hinterlegt, der verhindert, dass Matomo Nutzungsdaten speichert.Wenn Sie Ihre Cookies löschen, hat dies zur Folge, dass auch das Matomo Opt - Out - Cookie gelöscht wird.Das Opt - Out muss bei einem erneuten Besuch unserer Seite wieder aktiviert werden. */}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Plugins und Tools</h2>
|
||||||
|
<h3>YouTube</h3>
|
||||||
|
Unsere Website nutzt Plugins der von Google betriebenen Seite YouTube.Betreiber der Seiten ist die YouTube, LLC, 901 Cherry Ave., San Bruno, CA 94066, USA.
|
||||||
|
|
||||||
|
Wenn Sie eine unserer mit einem YouTube - Plugin ausgestatteten Seiten besuchen, wird eine Verbindung zu den Servern von YouTube hergestellt.Dabei wird dem YouTube - Server mitgeteilt, welche unserer Seiten Sie besucht haben.
|
||||||
|
|
||||||
|
Wenn Sie in Ihrem YouTube - Account eingeloggt sind, ermöglichen Sie YouTube, Ihr Surfverhalten direkt Ihrem persönlichen Profil zuzuordnen.Dies können Sie verhindern, indem Sie sich aus Ihrem YouTube - Account ausloggen.
|
||||||
|
|
||||||
|
Die Nutzung von YouTube erfolgt im Interesse einer ansprechenden Darstellung unserer Online - Angebote.Dies stellt ein berechtigtes Interesse im Sinne von Art. 6 Abs. 1 lit.f DSGVO dar.
|
||||||
|
|
||||||
|
Weitere Informationen zum Umgang mit Nutzerdaten finden Sie in der Datenschutzerklärung von YouTube unter: https://www.google.de/intl/de/policies/privacy.
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(Privay);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { workspaceName } from '../../actions/workspaceActions';
|
||||||
|
import { getProject, resetProject } from '../../actions/projectActions';
|
||||||
|
import { clearMessages, returnErrors } from '../../actions/messageActions';
|
||||||
|
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
import Home from '../Home';
|
||||||
|
import Breadcrumbs from '../Breadcrumbs';
|
||||||
|
|
||||||
|
import Backdrop from '@material-ui/core/Backdrop';
|
||||||
|
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||||
|
|
||||||
|
|
||||||
|
class Project extends Component {
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.resetProject();
|
||||||
|
this.getProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props) {
|
||||||
|
if (props.location.pathname !== this.props.location.pathname ||
|
||||||
|
props.match.params[`${this.props.type}Id`] !== this.props.match.params[`${this.props.type}Id`]) {
|
||||||
|
if (this.props.message.msg) {
|
||||||
|
this.props.clearMessages();
|
||||||
|
}
|
||||||
|
this.getProject();
|
||||||
|
}
|
||||||
|
if (this.props.message !== props.message) {
|
||||||
|
if (this.props.message.id === 'PROJECT_EMPTY' || this.props.message.id === 'GET_PROJECT_FAIL') {
|
||||||
|
if (this.props.type !== 'share') {
|
||||||
|
this.props.returnErrors('', 404, 'GET_PROJECT_FAIL');
|
||||||
|
this.props.history.push(`/${this.props.type}`);
|
||||||
|
} else {
|
||||||
|
this.props.history.push('/');
|
||||||
|
this.props.returnErrors('', 404, 'GET_SHARE_FAIL');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.props.message.id === 'GET_PROJECT_SUCCESS') {
|
||||||
|
this.props.workspaceName(this.props.project.title);
|
||||||
|
}
|
||||||
|
else if (this.props.message.id === 'PROJECT_DELETE_SUCCESS' || this.props.message.id === 'GALLERY_DELETE_SUCCESS') {
|
||||||
|
this.props.history.push(`/${this.props.type}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.props.resetProject();
|
||||||
|
this.props.workspaceName(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
getProject = () => {
|
||||||
|
var id = this.props.location.pathname.replace(/\/[a-z]{1,}\//, '');
|
||||||
|
var param = this.props.location.pathname.replace(`/${id}`, '').replace('/', '');
|
||||||
|
console.log('param', param);
|
||||||
|
console.log(id);
|
||||||
|
this.props.getProject(param, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var data = this.props.type === 'project' ? 'Projekte' : 'Galerie';
|
||||||
|
return (
|
||||||
|
this.props.progress ?
|
||||||
|
<Backdrop open invisible>
|
||||||
|
<CircularProgress color="primary" />
|
||||||
|
</Backdrop>
|
||||||
|
: this.props.project ?
|
||||||
|
<div>
|
||||||
|
{this.props.type !== 'share' ?
|
||||||
|
<Breadcrumbs content={[{ link: `/${this.props.type}`, title: data }, { link: this.props.location.pathname, title: this.props.project.title }]} />
|
||||||
|
: null}
|
||||||
|
<Home project={this.props.project} projectType={this.props.type} />
|
||||||
|
</div> : null
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Project.propTypes = {
|
||||||
|
workspaceName: PropTypes.func.isRequired,
|
||||||
|
getProject: PropTypes.func.isRequired,
|
||||||
|
resetProject: PropTypes.func.isRequired,
|
||||||
|
clearMessages: PropTypes.func.isRequired,
|
||||||
|
returnErrors: PropTypes.func.isRequired,
|
||||||
|
project: PropTypes.object.isRequired,
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
message: PropTypes.object.isRequired,
|
||||||
|
progress: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
project: state.project.projects[0],
|
||||||
|
progress: state.project.progress,
|
||||||
|
type: state.project.type,
|
||||||
|
message: state.message
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, { workspaceName, getProject, resetProject, clearMessages, returnErrors })(withRouter(Project));
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { getProjects, resetProject } from '../../actions/projectActions';
|
||||||
|
import { clearMessages } from '../../actions/messageActions';
|
||||||
|
|
||||||
|
import { Link, withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
import Breadcrumbs from '../Breadcrumbs';
|
||||||
|
import BlocklyWindow from '../Blockly/BlocklyWindow';
|
||||||
|
import Snackbar from '../Snackbar';
|
||||||
|
import WorkspaceFunc from '../Workspace/WorkspaceFunc';
|
||||||
|
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import Grid from '@material-ui/core/Grid';
|
||||||
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
import Divider from '@material-ui/core/Divider';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import Backdrop from '@material-ui/core/Backdrop';
|
||||||
|
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
link: {
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
textDecoration: 'none',
|
||||||
|
'&:hover': {
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
textDecoration: 'underline'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectHome extends Component {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
snackbar: false,
|
||||||
|
type: '',
|
||||||
|
key: '',
|
||||||
|
message: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
var type = this.props.location.pathname.replace('/', '');
|
||||||
|
this.props.getProjects(type);
|
||||||
|
if (this.props.message) {
|
||||||
|
if (this.props.message.id === 'PROJECT_DELETE_SUCCESS') {
|
||||||
|
this.setState({ snackbar: true, key: Date.now(), message: `Dein Projekt wurde erfolgreich gelöscht.`, type: 'success' });
|
||||||
|
}
|
||||||
|
else if (this.props.message.id === 'GALLERY_DELETE_SUCCESS') {
|
||||||
|
this.setState({ snackbar: true, key: Date.now(), message: `Dein Galerie-Projekt wurde erfolgreich gelöscht.`, type: 'success' });
|
||||||
|
}
|
||||||
|
else if (this.props.message.id === 'GET_PROJECT_FAIL') {
|
||||||
|
this.setState({ snackbar: true, key: Date.now(), message: `Dein angefragtes ${type === 'gallery' ? 'Galerie-' : ''}Projekt konnte nicht gefunden werden.`, type: 'error' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props) {
|
||||||
|
if (props.location.pathname !== this.props.location.pathname) {
|
||||||
|
this.setState({ snackbar: false });
|
||||||
|
this.props.getProjects(this.props.location.pathname.replace('/', ''));
|
||||||
|
}
|
||||||
|
if (props.message !== this.props.message) {
|
||||||
|
if (this.props.message.id === 'PROJECT_DELETE_SUCCESS') {
|
||||||
|
this.setState({ snackbar: true, key: Date.now(), message: `Dein Projekt wurde erfolgreich gelöscht.`, type: 'success' });
|
||||||
|
}
|
||||||
|
else if (this.props.message.id === 'GALLERY_DELETE_SUCCESS') {
|
||||||
|
this.setState({ snackbar: true, key: Date.now(), message: `Dein Galerie-Projekt wurde erfolgreich gelöscht.`, type: 'success' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.props.resetProject();
|
||||||
|
this.props.clearMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var data = this.props.location.pathname === '/project' ? 'Projekte' : 'Galerie';
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Breadcrumbs content={[{ link: this.props.location.pathname, title: data }]} />
|
||||||
|
|
||||||
|
<h1>{data}</h1>
|
||||||
|
{this.props.progress ?
|
||||||
|
<Backdrop open invisible>
|
||||||
|
<CircularProgress color="primary" />
|
||||||
|
</Backdrop>
|
||||||
|
:
|
||||||
|
<div>
|
||||||
|
{this.props.projects.length > 0 ?
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{this.props.projects.map((project, i) => {
|
||||||
|
return (
|
||||||
|
<Grid item xs={12} sm={6} md={4} xl={3} key={i}>
|
||||||
|
<Paper style={{ padding: '1rem', position: 'relative', overflow: 'hidden' }}>
|
||||||
|
<Link to={`/${data === 'Projekte' ? 'project' : 'gallery'}/${project._id}`} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||||
|
<h3 style={{ marginTop: 0 }}>{project.title}</h3>
|
||||||
|
<Divider style={{ marginTop: '1rem', marginBottom: '10px' }} />
|
||||||
|
<BlocklyWindow
|
||||||
|
svg
|
||||||
|
blockDisabled
|
||||||
|
initialXml={project.xml}
|
||||||
|
/>
|
||||||
|
<Typography variant='body2' style={{ fontStyle: 'italic', margin: 0, marginTop: '-10px' }}>{project.description}</Typography>
|
||||||
|
</Link>
|
||||||
|
{this.props.user && this.props.user.email === project.creator ?
|
||||||
|
<div>
|
||||||
|
<Divider style={{ marginTop: '10px', marginBottom: '10px' }} />
|
||||||
|
<div style={{ float: 'right' }}>
|
||||||
|
<WorkspaceFunc
|
||||||
|
multiple
|
||||||
|
project={project}
|
||||||
|
projectType={this.props.location.pathname.replace('/', '')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
: <div>
|
||||||
|
<Typography style={{ marginBottom: '10px' }}>Es sind aktuell keine Projekte vorhanden.</Typography>
|
||||||
|
{this.props.location.pathname.replace('/', '') === 'project' ?
|
||||||
|
<Typography>Erstelle jetzt dein <Link to={'/'} className={this.props.classes.link}>eigenes Projekt</Link> oder lasse dich von Projektbeispielen in der <Link to={'/gallery'} className={this.props.classes.link}>Galerie</Link> inspirieren.</Typography>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<Snackbar
|
||||||
|
open={this.state.snackbar}
|
||||||
|
message={this.state.message}
|
||||||
|
type={this.state.type}
|
||||||
|
key={this.state.key}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectHome.propTypes = {
|
||||||
|
getProjects: PropTypes.func.isRequired,
|
||||||
|
resetProject: PropTypes.func.isRequired,
|
||||||
|
clearMessages: PropTypes.func.isRequired,
|
||||||
|
projects: PropTypes.array.isRequired,
|
||||||
|
progress: PropTypes.bool.isRequired,
|
||||||
|
user: PropTypes.object,
|
||||||
|
message: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
projects: state.project.projects,
|
||||||
|
progress: state.project.progress,
|
||||||
|
user: state.auth.user,
|
||||||
|
message: state.message
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, { getProjects, resetProject, clearMessages })(withStyles(styles, { withTheme: true })(withRouter(ProjectHome)));
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { Route, Redirect } from 'react-router-dom';
|
||||||
|
|
||||||
|
|
||||||
|
class IsLoggedRoute extends Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
!this.props.progress ?
|
||||||
|
<Route
|
||||||
|
{...this.props.exact}
|
||||||
|
render={({ location }) =>
|
||||||
|
!this.props.isAuthenticated ? (
|
||||||
|
this.props.children
|
||||||
|
) : (
|
||||||
|
<Redirect
|
||||||
|
to={{
|
||||||
|
pathname: "/",
|
||||||
|
state: { from: location }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/> : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IsLoggedRoute.propTypes = {
|
||||||
|
isAuthenticated: PropTypes.bool.isRequired,
|
||||||
|
progress: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
isAuthenticated: state.auth.isAuthenticated,
|
||||||
|
progress: state.auth.progress
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(IsLoggedRoute);
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { Route, Redirect, withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
|
||||||
|
class PrivateRoute extends Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
!this.props.progress ?
|
||||||
|
<Route
|
||||||
|
{...this.props.exact}
|
||||||
|
render={({ location }) =>
|
||||||
|
this.props.isAuthenticated ? (
|
||||||
|
this.props.children
|
||||||
|
) : (()=>{
|
||||||
|
return (
|
||||||
|
<Redirect
|
||||||
|
to={{
|
||||||
|
pathname: "/user/login",
|
||||||
|
state: { from: location }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
/> : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivateRoute.propTypes = {
|
||||||
|
isAuthenticated: PropTypes.bool.isRequired,
|
||||||
|
progress: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
isAuthenticated: state.auth.isAuthenticated,
|
||||||
|
progress: state.auth.progress
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(withRouter(PrivateRoute));
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { Route, Redirect, withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
|
||||||
|
class PrivateRoute extends Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
!this.props.progress ?
|
||||||
|
<Route
|
||||||
|
{...this.props.exact}
|
||||||
|
render={({ location }) =>
|
||||||
|
this.props.isAuthenticated &&
|
||||||
|
this.props.user &&
|
||||||
|
this.props.user.blocklyRole !== 'user' ? (
|
||||||
|
this.props.children
|
||||||
|
) : (()=>{
|
||||||
|
return (
|
||||||
|
<Redirect
|
||||||
|
to={{
|
||||||
|
pathname: "/",
|
||||||
|
state: { from: location }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
/> : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivateRoute.propTypes = {
|
||||||
|
isAuthenticated: PropTypes.bool.isRequired,
|
||||||
|
user: PropTypes.object,
|
||||||
|
progress: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
isAuthenticated: state.auth.isAuthenticated,
|
||||||
|
user: state.auth.user,
|
||||||
|
progress: state.auth.progress
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(withRouter(PrivateRoute));
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { Route } from 'react-router-dom';
|
||||||
|
|
||||||
|
|
||||||
|
class PublicRoute extends Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
!this.props.progress ?
|
||||||
|
<Route
|
||||||
|
{...this.props.exact}
|
||||||
|
render={({ location }) =>
|
||||||
|
this.props.children
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PublicRoute.propTypes = {
|
||||||
|
progress: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
progress: state.auth.progress
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(PublicRoute);
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { visitPage } from '../../actions/generalActions';
|
||||||
|
|
||||||
|
import { Route, Switch, withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
import PublicRoute from './PublicRoute';
|
||||||
|
import PrivateRoute from './PrivateRoute';
|
||||||
|
import PrivateRouteCreator from './PrivateRouteCreator';
|
||||||
|
import IsLoggedRoute from './IsLoggedRoute';
|
||||||
|
|
||||||
|
import Home from '../Home';
|
||||||
|
import Tutorial from '../Tutorial/Tutorial';
|
||||||
|
import TutorialHome from '../Tutorial/TutorialHome';
|
||||||
|
import Builder from '../Tutorial/Builder/Builder';
|
||||||
|
import NotFound from '../NotFound';
|
||||||
|
import ProjectHome from '../Project/ProjectHome';
|
||||||
|
import Project from '../Project/Project';
|
||||||
|
import Settings from '../Settings/Settings';
|
||||||
|
import Impressum from '../Impressum';
|
||||||
|
import Privacy from '../Privacy';
|
||||||
|
import Login from '../User/Login';
|
||||||
|
import Account from '../User/Account';
|
||||||
|
import MyBadges from '../User/MyBadges';
|
||||||
|
|
||||||
|
|
||||||
|
class Routes extends Component {
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.props.visitPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{ margin: '0 22px' }}>
|
||||||
|
<Switch>
|
||||||
|
<PublicRoute path="/" exact>
|
||||||
|
<Home/>
|
||||||
|
</PublicRoute>
|
||||||
|
{/* Tutorials */}
|
||||||
|
<PublicRoute path="/tutorial" exact>
|
||||||
|
<TutorialHome />
|
||||||
|
</PublicRoute>
|
||||||
|
<PrivateRouteCreator path="/tutorial/builder" exact>
|
||||||
|
<Builder />
|
||||||
|
</PrivateRouteCreator>
|
||||||
|
<Route path="/tutorial/:tutorialId" exact>
|
||||||
|
<Tutorial />
|
||||||
|
</Route>
|
||||||
|
{/* Sharing */}
|
||||||
|
<PublicRoute path="/share/:shareId" exact>
|
||||||
|
<Project />
|
||||||
|
</PublicRoute>
|
||||||
|
{/* Gallery-Projects */}
|
||||||
|
<PublicRoute path="/gallery" exact>
|
||||||
|
<ProjectHome />
|
||||||
|
</PublicRoute>
|
||||||
|
<PublicRoute path="/gallery/:galleryId" exact>
|
||||||
|
<Project />
|
||||||
|
</PublicRoute>
|
||||||
|
{/* User-Projects */}
|
||||||
|
<PrivateRoute path="/project" exact>
|
||||||
|
<ProjectHome/>
|
||||||
|
</PrivateRoute>
|
||||||
|
<PrivateRoute path="/project/:projectId" exact>
|
||||||
|
<Project/>
|
||||||
|
</PrivateRoute>
|
||||||
|
{/* User */}
|
||||||
|
<IsLoggedRoute path="/user/login" exact>
|
||||||
|
<Login />
|
||||||
|
</IsLoggedRoute>
|
||||||
|
<PrivateRoute path="/user" exact>
|
||||||
|
<Account />
|
||||||
|
</PrivateRoute>
|
||||||
|
<PrivateRoute path="/user/badge" exact>
|
||||||
|
<MyBadges />
|
||||||
|
</PrivateRoute>
|
||||||
|
{/* settings */}
|
||||||
|
<PublicRoute path="/settings" exact>
|
||||||
|
<Settings />
|
||||||
|
</PublicRoute>
|
||||||
|
{/* privacy */}
|
||||||
|
<PublicRoute path="/impressum" exact>
|
||||||
|
<Impressum />
|
||||||
|
</PublicRoute>
|
||||||
|
<PublicRoute path="/privacy" exact>
|
||||||
|
<Privacy />
|
||||||
|
</PublicRoute>
|
||||||
|
{/* Not Found */}
|
||||||
|
<PublicRoute>
|
||||||
|
<NotFound />
|
||||||
|
</PublicRoute>
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Home.propTypes = {
|
||||||
|
visitPage: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(null, { visitPage })(withRouter(Routes));
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { visitPage } from '../actions/generalActions';
|
|
||||||
|
|
||||||
import { Route, Switch, withRouter } from 'react-router-dom';
|
|
||||||
|
|
||||||
import Home from './Home';
|
|
||||||
import Tutorial from './Tutorial/Tutorial';
|
|
||||||
import TutorialHome from './Tutorial/TutorialHome';
|
|
||||||
import Builder from './Tutorial/Builder/Builder';
|
|
||||||
import NotFound from './NotFound';
|
|
||||||
|
|
||||||
class Routes extends Component {
|
|
||||||
|
|
||||||
componentDidUpdate(){
|
|
||||||
this.props.visitPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div style={{ margin: '0 22px' }}>
|
|
||||||
<Switch>
|
|
||||||
<Route path="/" exact component={Home} />
|
|
||||||
<Route path="/tutorial" exact component={TutorialHome} />
|
|
||||||
<Route path="/tutorial/builder" exact component={Builder}/>
|
|
||||||
<Route path="/tutorial/:tutorialId" exact component={Tutorial} />
|
|
||||||
<Route component={NotFound} />
|
|
||||||
</Switch>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Home.propTypes = {
|
|
||||||
visitPage: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(null, { visitPage })(withRouter(Routes));
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { setLanguage } from '../../actions/generalActions';
|
||||||
|
|
||||||
|
import * as Blockly from 'blockly/core';
|
||||||
|
|
||||||
|
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';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||||
|
|
||||||
|
class LanguageSelector extends Component {
|
||||||
|
|
||||||
|
componentDidMount(){
|
||||||
|
// Ensure that Blockly.setLocale is adopted in the component.
|
||||||
|
// Otherwise, the text will not be displayed until the next update of the component.
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange = (event) => {
|
||||||
|
this.props.setLanguage(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(){
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<Typography style={{fontWeight: 'bold'}}>{Blockly.Msg.settings_language}</Typography>
|
||||||
|
<FormHelperText style={{color: 'black', lineHeight: 1.3, marginBottom: '8px'}}>{Blockly.Msg.settings_language_text}</FormHelperText>
|
||||||
|
<FormControl>
|
||||||
|
<InputLabel id="demo-simple-select-label">{Blockly.Msg.settings_language}</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
value={this.props.language}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
>
|
||||||
|
<MenuItem value={'de_DE'}>{Blockly.Msg.settings_language_de}</MenuItem>
|
||||||
|
<MenuItem value={'en_US'}>{Blockly.Msg.settings_language_en}</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LanguageSelector.propTypes = {
|
||||||
|
setLanguage: PropTypes.func.isRequired,
|
||||||
|
language: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
language: state.general.language
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, { setLanguage })(LanguageSelector);
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { setRenderer } from '../../actions/generalActions';
|
||||||
|
|
||||||
|
import * as Blockly from 'blockly/core'
|
||||||
|
|
||||||
|
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';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||||
|
|
||||||
|
|
||||||
|
class RenderSelector extends Component {
|
||||||
|
|
||||||
|
componentDidMount(){
|
||||||
|
// Ensure that Blockly.setLocale is adopted in the component.
|
||||||
|
// Otherwise, the text will not be displayed until the next update of the component.
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
render(){
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Typography style={{fontWeight: 'bold'}}>{Blockly.Msg.settings_renderer}</Typography>
|
||||||
|
<FormHelperText style={{color: 'black', lineHeight: 1.3, marginBottom: '8px'}}>{Blockly.Msg.settings_renderer_text}</FormHelperText>
|
||||||
|
<FormControl>
|
||||||
|
<InputLabel id="demo-simple-select-label">{Blockly.Msg.settings_renderer}</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
value={this.props.renderer}
|
||||||
|
onChange={(e) => this.props.setRenderer(e.target.value)}
|
||||||
|
>
|
||||||
|
<MenuItem value={'geras'}>Geras</MenuItem>
|
||||||
|
<MenuItem value={'zelos'}>Zelos</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSelector.propTypes = {
|
||||||
|
setRenderer: PropTypes.func.isRequired,
|
||||||
|
language: PropTypes.string.isRequired,
|
||||||
|
renderer: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
renderer: state.general.renderer,
|
||||||
|
language: state.general.language
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, { setRenderer })(RenderSelector);
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
import * as Blockly from 'blockly/core';
|
||||||
|
|
||||||
|
import Breadcrumbs from '../Breadcrumbs';
|
||||||
|
import LanguageSelector from './LanguageSelector';
|
||||||
|
import RenderSelector from './RenderSelector';
|
||||||
|
import StatsSelector from './StatsSelector';
|
||||||
|
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
|
||||||
|
class Settings extends Component {
|
||||||
|
|
||||||
|
componentDidMount(){
|
||||||
|
// Ensure that Blockly.setLocale is adopted in the component.
|
||||||
|
// Otherwise, the text will not be displayed until the next update of the component.
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Breadcrumbs content={[{ link: this.props.location.pathname, title: Blockly.Msg.settings_head }]} />
|
||||||
|
|
||||||
|
<h1>{Blockly.Msg.settings_head}</h1>
|
||||||
|
|
||||||
|
<Paper style={{margin: '10px 0px', padding: '10px'}}>
|
||||||
|
<LanguageSelector />
|
||||||
|
</Paper>
|
||||||
|
<Paper style={{margin: '10px 0px', padding: '10px'}}>
|
||||||
|
<RenderSelector />
|
||||||
|
</Paper>
|
||||||
|
<Paper style={{margin: '10px 0px', padding: '10px'}}>
|
||||||
|
<StatsSelector />
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style={{ marginTop: '10px' }}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={this.props.pageVisits > 0 ? () => this.props.history.goBack() : () => this.props.history.push('/')}
|
||||||
|
>
|
||||||
|
{Blockly.Msg.button_back}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings.propTypes = {
|
||||||
|
language: PropTypes.string.isRequired,
|
||||||
|
pageVisits: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
language: state.general.language,
|
||||||
|
pageVisits: state.general.pageVisits
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(withRouter(Settings));
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { setStatistics } from '../../actions/generalActions';
|
||||||
|
|
||||||
|
import * as Blockly from 'blockly/core'
|
||||||
|
|
||||||
|
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';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||||
|
|
||||||
|
class StatsSelector extends Component {
|
||||||
|
|
||||||
|
componentDidMount(){
|
||||||
|
// Ensure that Blockly.setLocale is adopted in the component.
|
||||||
|
// Otherwise, the text will not be displayed until the next update of the component.
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
render(){
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Typography style={{fontWeight: 'bold'}}>{Blockly.Msg.settings_statistics}</Typography>
|
||||||
|
<FormHelperText style={{color: 'black', lineHeight: 1.3, marginBottom: '8px'}}>{Blockly.Msg.settings_statistics_text}</FormHelperText>
|
||||||
|
<FormControl>
|
||||||
|
<InputLabel id="demo-simple-select-label">{Blockly.Msg.settings_statistics}</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
value={this.props.statistics}
|
||||||
|
onChange={(e) => this.props.setStatistics(e.target.value)}
|
||||||
|
>
|
||||||
|
<MenuItem value={true}>{Blockly.Msg.settings_statistics_on}</MenuItem>
|
||||||
|
<MenuItem value={false}>{Blockly.Msg.settings_statistics_off}</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatsSelector.propTypes = {
|
||||||
|
setStatistics: PropTypes.func.isRequired,
|
||||||
|
language: PropTypes.string.isRequired,
|
||||||
|
statistics: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
statistics: state.general.statistics,
|
||||||
|
language: state.general.language
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, { setStatistics })(StatsSelector);
|
||||||
@@ -35,6 +35,12 @@ class Snackbar extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(){
|
||||||
|
if(!this.state.open){
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount(){
|
componentWillUnmount(){
|
||||||
if(this.state.open){
|
if(this.state.open){
|
||||||
clearTimeout(this.timeout);
|
clearTimeout(this.timeout);
|
||||||
|
|||||||
@@ -5,38 +5,37 @@ import { workspaceName } from '../../actions/workspaceActions';
|
|||||||
|
|
||||||
import BlocklyWindow from '../Blockly/BlocklyWindow';
|
import BlocklyWindow from '../Blockly/BlocklyWindow';
|
||||||
import CodeViewer from '../CodeViewer';
|
import CodeViewer from '../CodeViewer';
|
||||||
import WorkspaceFunc from '../WorkspaceFunc';
|
import WorkspaceFunc from '../Workspace/WorkspaceFunc';
|
||||||
|
|
||||||
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
|
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
|
||||||
import Grid from '@material-ui/core/Grid';
|
import Grid from '@material-ui/core/Grid';
|
||||||
import Card from '@material-ui/core/Card';
|
import Card from '@material-ui/core/Card';
|
||||||
import Typography from '@material-ui/core/Typography';
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import * as Blockly from 'blockly'
|
||||||
|
|
||||||
class Assessment extends Component {
|
class Assessment extends Component {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// alert(this.props.name);
|
|
||||||
this.props.workspaceName(this.props.name);
|
this.props.workspaceName(this.props.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(props) {
|
componentDidUpdate(props) {
|
||||||
if (props.name !== this.props.name) {
|
if (props.name !== this.props.name) {
|
||||||
// alert(this.props.name);
|
|
||||||
this.props.workspaceName(this.props.name);
|
this.props.workspaceName(this.props.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var tutorialId = this.props.currentTutorialId;
|
var tutorialId = this.props.tutorial._id;
|
||||||
var currentTask = this.props.step;
|
var currentTask = this.props.step;
|
||||||
var status = this.props.status.filter(status => status.id === tutorialId)[0];
|
var status = this.props.status.filter(status => status._id === tutorialId)[0];
|
||||||
var taskIndex = status.tasks.findIndex(task => task.id === currentTask.id);
|
var taskIndex = status.tasks.findIndex(task => task._id === currentTask._id);
|
||||||
var statusTask = status.tasks[taskIndex];
|
var statusTask = status.tasks[taskIndex];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '100%' }}>
|
<div style={{ width: '100%' }}>
|
||||||
<Typography variant='h4' style={{ float: 'left', marginBottom: '5px', height: '40px', display: 'table' }}>{currentTask.headline}</Typography>
|
<Typography variant='h4' style={{ float: 'left', marginBottom: '5px', height: '40px', display: 'table' }}>{currentTask.headline}</Typography>
|
||||||
<div style={{ float: 'right', height: '40px' }}><WorkspaceFunc solutionCheck /></div>
|
<div style={{ float: 'right', height: '40px' }}><WorkspaceFunc assessment /></div>
|
||||||
<Grid container spacing={2} style={{ marginBottom: '5px' }}>
|
<Grid container spacing={2} style={{ marginBottom: '5px' }}>
|
||||||
<Grid item xs={12} md={6} lg={8}>
|
<Grid item xs={12} md={6} lg={8}>
|
||||||
<BlocklyWindow
|
<BlocklyWindow
|
||||||
@@ -47,7 +46,7 @@ class Assessment extends Component {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={6} lg={4} style={isWidthDown('sm', this.props.width) ? { height: 'max-content' } : {}}>
|
<Grid item xs={12} md={6} lg={4} style={isWidthDown('sm', this.props.width) ? { height: 'max-content' } : {}}>
|
||||||
<Card style={{ height: 'calc(50% - 30px)', padding: '10px', marginBottom: '10px' }}>
|
<Card style={{ height: 'calc(50% - 30px)', padding: '10px', marginBottom: '10px' }}>
|
||||||
<Typography variant='h5'>Arbeitsauftrag</Typography>
|
<Typography variant='h5'>{Blockly.Msg.tutorials_assessment_task}</Typography>
|
||||||
<Typography>{currentTask.text}</Typography>
|
<Typography>{currentTask.text}</Typography>
|
||||||
</Card>
|
</Card>
|
||||||
<div style={isWidthDown('sm', this.props.width) ? { height: '500px' } : { height: '50%' }}>
|
<div style={isWidthDown('sm', this.props.width) ? { height: '500px' } : { height: '50%' }}>
|
||||||
@@ -61,16 +60,16 @@ class Assessment extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Assessment.propTypes = {
|
Assessment.propTypes = {
|
||||||
currentTutorialId: PropTypes.number,
|
|
||||||
status: PropTypes.array.isRequired,
|
status: PropTypes.array.isRequired,
|
||||||
change: PropTypes.number.isRequired,
|
change: PropTypes.number.isRequired,
|
||||||
workspaceName: PropTypes.func.isRequired
|
workspaceName: PropTypes.func.isRequired,
|
||||||
|
tutorial: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
change: state.tutorial.change,
|
change: state.tutorial.change,
|
||||||
status: state.tutorial.status,
|
status: state.tutorial.status,
|
||||||
currentTutorialId: state.tutorial.currentId
|
tutorial: state.tutorial.tutorials[0]
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, { workspaceName })(withWidth()(Assessment));
|
export default connect(mapStateToProps, { workspaceName })(withWidth()(Assessment));
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { assigneBadge } from '../../actions/tutorialActions';
|
||||||
|
|
||||||
|
import Dialog from '../Dialog';
|
||||||
|
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import Avatar from '@material-ui/core/Avatar';
|
||||||
|
import * as Blockly from 'blockly';
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
link: {
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
textDecoration: 'none',
|
||||||
|
'&:hover': {
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
textDecoration: 'underline'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
class Badge extends Component {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
open: false,
|
||||||
|
title: '',
|
||||||
|
content: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidUpdate(props) {
|
||||||
|
if (this.props.message.id === 'TUTORIAL_CHECK_SUCCESS') {
|
||||||
|
if (this.props.tutorial.badge) {
|
||||||
|
// is connected to MyBadges?
|
||||||
|
if (this.props.isAuthenticated && this.props.user && this.props.user.badge) {
|
||||||
|
if (this.props.user.badges && !this.props.user.badges.includes(this.props.tutorial.badge)) {
|
||||||
|
if (this.isSuccess()) {
|
||||||
|
this.props.assigneBadge(this.props.tutorial.badge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (props.message !== this.props.message) {
|
||||||
|
if (this.props.message.id === 'ASSIGNE_BADGE_SUCCESS') {
|
||||||
|
this.setState({ title: `Badge: ${this.props.message.msg.name}`, content: `${Blockly.Msg.badges_ASSIGNE_BADGE_SUCCESS_01} ${this.props.message.msg.name} ${Blockly.Msg.badges_ASSIGNE_BADGE_SUCCESS_02}`, open: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isSuccess = () => {
|
||||||
|
var tutorialId = this.props.tutorial._id;
|
||||||
|
var status = this.props.status.filter(status => status._id === tutorialId)[0];
|
||||||
|
var tasks = status.tasks;
|
||||||
|
var success = tasks.filter(task => task.type === 'success').length / tasks.length;
|
||||||
|
if (success === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleDialog = () => {
|
||||||
|
this.setState({ open: !this.state, title: '', content: '' });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
style={{ zIndex: 99999999 }}
|
||||||
|
open={this.state.open}
|
||||||
|
title={this.state.title}
|
||||||
|
content={this.state.content}
|
||||||
|
onClose={() => { this.toggleDialog(); }}
|
||||||
|
onClick={() => { this.toggleDialog(); }}
|
||||||
|
button={Blockly.Msg.button_close}
|
||||||
|
>
|
||||||
|
<div style={{ marginTop: '10px' }}>
|
||||||
|
<Paper style={{ textAlign: 'center' }}>
|
||||||
|
{this.props.message.msg.image && this.props.message.msg.image.path ?
|
||||||
|
<Avatar src={`${process.env.REACT_APP_MYBADGES}/media/${this.props.message.msg.image.path}`} style={{ width: '200px', height: '200px', marginLeft: 'auto', marginRight: 'auto' }} />
|
||||||
|
: <Avatar style={{ width: '200px', height: '200px', marginLeft: 'auto', marginRight: 'auto' }}></Avatar>}
|
||||||
|
<Typography variant='h6' style={{ display: 'flex', cursor: 'default', paddingBottom: '6px' }}>
|
||||||
|
<div style={{ flexGrow: 1, marginLeft: '10px', marginRight: '10px' }}>{this.props.message.msg.name}</div>
|
||||||
|
</Typography>
|
||||||
|
</Paper>
|
||||||
|
<Typography style={{ marginTop: '10px' }}>
|
||||||
|
{Blockly.Msg.badges_explaination}<Link to={'/user/badge'} className={this.props.classes.link}>{Blockly.Msg.labels_here}</Link>.
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Badge.propTypes = {
|
||||||
|
assigneBadge: PropTypes.func.isRequired,
|
||||||
|
status: PropTypes.array.isRequired,
|
||||||
|
change: PropTypes.number.isRequired,
|
||||||
|
tutorial: PropTypes.object.isRequired,
|
||||||
|
user: PropTypes.object,
|
||||||
|
isAuthenticated: PropTypes.bool.isRequired,
|
||||||
|
message: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
change: state.tutorial.change,
|
||||||
|
status: state.tutorial.status,
|
||||||
|
tutorial: state.tutorial.tutorials[0],
|
||||||
|
user: state.auth.user,
|
||||||
|
isAuthenticated: state.auth.isAuthenticated,
|
||||||
|
message: state.message
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, { assigneBadge })(withStyles(styles, { withTheme: true })(Badge));
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { tutorialBadge, deleteProperty, setError, deleteError } from '../../../actions/tutorialBuilderActions';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
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 List from '@material-ui/core/List';
|
||||||
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
|
import ListItemText from '@material-ui/core/ListItemText';
|
||||||
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
|
import OutlinedInput from '@material-ui/core/OutlinedInput';
|
||||||
|
import InputLabel from '@material-ui/core/InputLabel';
|
||||||
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { faTimes } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
errorColor: {
|
||||||
|
color: `${theme.palette.error.dark} !important`
|
||||||
|
},
|
||||||
|
errorColorShrink: {
|
||||||
|
color: `rgba(0, 0, 0, 0.54) !important`
|
||||||
|
},
|
||||||
|
errorBorder: {
|
||||||
|
borderColor: `${theme.palette.error.dark} !important`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class Badge extends Component {
|
||||||
|
|
||||||
|
constructor(props){
|
||||||
|
super(props);
|
||||||
|
this.state={
|
||||||
|
checked: props.badge ? true : false,
|
||||||
|
badgeName: '',
|
||||||
|
filteredBadges: [],
|
||||||
|
badges: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(){
|
||||||
|
this.getBadges();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props){
|
||||||
|
if(props.badge !== this.props.badge){
|
||||||
|
this.setState({ checked: this.props.badge !== undefined ? true : false, badgeName: this.props.badge ? this.state.badges.filter(badge => badge._id === this.props.badge)[0].name : '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getBadges = () => {
|
||||||
|
axios.get(`${process.env.REACT_APP_MYBADGES_API}/badge`)
|
||||||
|
.then(res => {
|
||||||
|
this.setState({badges: res.data.badges, badgeName: this.props.badge ? res.data.badges.filter(badge => badge._id === this.props.badge)[0].name : '' });
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
deleteBadge = () => {
|
||||||
|
this.setState({ filteredBadges: [], badgeName: '' });
|
||||||
|
this.props.tutorialBadge(null);
|
||||||
|
this.props.setError(this.props.index, 'badge');
|
||||||
|
};
|
||||||
|
|
||||||
|
setBadge = (badge) => {
|
||||||
|
this.setState({ filteredBadges: [] });
|
||||||
|
this.props.tutorialBadge(badge._id);
|
||||||
|
this.props.deleteError(this.props.index, 'badge');
|
||||||
|
};
|
||||||
|
|
||||||
|
onChange = e => {
|
||||||
|
this.setState({ badgeName: e.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
onChangeBadge = e => {
|
||||||
|
if(e.target.value && this.props.badge === null){
|
||||||
|
var filteredBadges = this.state.badges.filter(badge => new RegExp(e.target.value, 'i').test(badge.name));
|
||||||
|
if(filteredBadges.length < 1){
|
||||||
|
filteredBadges = ['Keine Übereinstimmung gefunden.'];
|
||||||
|
}
|
||||||
|
this.setState({filteredBadges: filteredBadges});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setState({filteredBadges: []});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onChangeSwitch = (value) => {
|
||||||
|
var oldValue = this.state.checked;
|
||||||
|
this.setState({checked: value});
|
||||||
|
if(oldValue !== value){
|
||||||
|
if(value){
|
||||||
|
this.props.setError(this.props.index, 'badge');
|
||||||
|
this.props.tutorialBadge(null);
|
||||||
|
} else {
|
||||||
|
this.props.deleteError(this.props.index, 'badge');
|
||||||
|
this.props.tutorialBadge(undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)'}}>
|
||||||
|
<FormControlLabel
|
||||||
|
labelPlacement="end"
|
||||||
|
label={"Badge"}
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={this.state.checked}
|
||||||
|
onChange={(e) => this.onChangeSwitch(e.target.checked)}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{this.state.checked ?
|
||||||
|
<div style={{marginTop: '10px'}}>
|
||||||
|
<FormControl variant="outlined" fullWidth>
|
||||||
|
<InputLabel
|
||||||
|
htmlFor={'badge'}
|
||||||
|
classes={{shrink: this.props.error ? this.props.classes.errorColorShrink : null}}
|
||||||
|
>
|
||||||
|
{'Badge'}
|
||||||
|
</InputLabel>
|
||||||
|
<OutlinedInput
|
||||||
|
style={{borderRadius: '25px'}}
|
||||||
|
classes={{notchedOutline: this.props.error ? this.props.classes.errorBorder : null}}
|
||||||
|
error={this.props.error}
|
||||||
|
value={this.state.badgeName}
|
||||||
|
label={'Badge'}
|
||||||
|
id={'badge'}
|
||||||
|
disabled={this.props.badge}
|
||||||
|
onChange={(e) => this.onChange(e)}
|
||||||
|
onInput={(e) => this.onChangeBadge(e)}
|
||||||
|
fullWidth={true}
|
||||||
|
endAdornment={
|
||||||
|
<IconButton
|
||||||
|
onClick={this.deleteBadge}
|
||||||
|
edge="end"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon size='xs' icon={faTimes} />
|
||||||
|
</IconButton>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{this.props.error && this.state.filteredBadges.length === 0 ?
|
||||||
|
<FormHelperText className={this.props.classes.errorColor}>Wähle ein Badge aus.</FormHelperText>
|
||||||
|
: null}
|
||||||
|
</FormControl>
|
||||||
|
<List style={{paddingTop: 0}}>
|
||||||
|
{this.state.filteredBadges.map((badge, i) => (
|
||||||
|
badge === 'Keine Übereinstimmung gefunden.' ?
|
||||||
|
<ListItem button key={i} onClick={this.deleteBadge} style={{border: '1px solid rgba(0, 0, 0, 0.23)', borderRadius: '25px'}}>
|
||||||
|
<ListItemText>{badge}</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
:
|
||||||
|
<ListItem button key={i} onClick={() => {this.setBadge(badge)}} style={{border: '1px solid rgba(0, 0, 0, 0.23)', borderRadius: '25px'}}>
|
||||||
|
<ListItemText>{`${badge.name}`}</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Badge.propTypes = {
|
||||||
|
tutorialBadge: PropTypes.func.isRequired,
|
||||||
|
deleteProperty: PropTypes.func.isRequired,
|
||||||
|
setError: PropTypes.func.isRequired,
|
||||||
|
deleteError: PropTypes.func.isRequired,
|
||||||
|
badge: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
badge: state.builder.badge,
|
||||||
|
change: state.builder.change
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, { tutorialBadge, deleteProperty, setError, deleteError })(withStyles(styles, {withTheme: true})(Badge));
|
||||||
@@ -29,7 +29,7 @@ const styles = (theme) => ({
|
|||||||
marginTop: '5px',
|
marginTop: '5px',
|
||||||
height: '40px',
|
height: '40px',
|
||||||
backgroundColor: theme.palette.error.dark,
|
backgroundColor: theme.palette.error.dark,
|
||||||
'&:hover':{
|
'&:hover': {
|
||||||
backgroundColor: theme.palette.error.dark
|
backgroundColor: theme.palette.error.dark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,16 +37,16 @@ const styles = (theme) => ({
|
|||||||
|
|
||||||
class BlocklyExample extends Component {
|
class BlocklyExample extends Component {
|
||||||
|
|
||||||
constructor(props){
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state={
|
this.state = {
|
||||||
checked: props.task ? props.task : props.value ? true : false,
|
checked: props.task ? props.task : props.value ? true : false,
|
||||||
input: null,
|
input: null,
|
||||||
disabled: false
|
disabled: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(){
|
componentDidMount() {
|
||||||
moment.updateLocale('de', localization);
|
moment.updateLocale('de', localization);
|
||||||
this.isError();
|
this.isError();
|
||||||
// if(this.props.task){
|
// if(this.props.task){
|
||||||
@@ -54,42 +54,42 @@ class BlocklyExample extends Component {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(props, state){
|
componentDidUpdate(props, state) {
|
||||||
if(props.task !== this.props.task || props.value !== this.props.value){
|
if (props.task !== this.props.task || props.value !== this.props.value) {
|
||||||
this.setState({checked: this.props.task ? this.props.task : this.props.value ? true : false},
|
this.setState({ checked: this.props.task ? this.props.task : this.props.value ? true : false },
|
||||||
() => this.isError()
|
() => this.isError()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(state.checked !== this.state.checked && this.state.checked){
|
if (state.checked !== this.state.checked && this.state.checked) {
|
||||||
this.isError();
|
this.isError();
|
||||||
}
|
}
|
||||||
if(props.xml !== this.props.xml){
|
if (props.xml !== this.props.xml) {
|
||||||
// check if there is at least one block, otherwise the workspace cannot be submitted
|
// check if there is at least one block, otherwise the workspace cannot be submitted
|
||||||
var workspace = Blockly.getMainWorkspace();
|
var workspace = Blockly.getMainWorkspace();
|
||||||
var areBlocks = workspace.getAllBlocks().length > 0;
|
var areBlocks = workspace.getAllBlocks().length > 0;
|
||||||
this.setState({disabled: !areBlocks});
|
this.setState({ disabled: !areBlocks });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isError = () => {
|
isError = () => {
|
||||||
if(this.state.checked){
|
if (this.state.checked) {
|
||||||
var xml = this.props.value;
|
var xml = this.props.value;
|
||||||
// check if value is valid xml;
|
// check if value is valid xml;
|
||||||
try{
|
try {
|
||||||
Blockly.Xml.textToDom(xml);
|
Blockly.Xml.textToDom(xml);
|
||||||
this.props.deleteError(this.props.index, 'xml');
|
this.props.deleteError(this.props.index, 'xml');
|
||||||
}
|
}
|
||||||
catch(err){
|
catch (err) {
|
||||||
xml = initialXml;
|
xml = initialXml;
|
||||||
// not valid xml, throw error in redux store
|
// not valid xml, throw error in redux store
|
||||||
this.props.setError(this.props.index, 'xml');
|
this.props.setError(this.props.index, 'xml');
|
||||||
}
|
}
|
||||||
if(!this.props.task){
|
if (!this.props.task) {
|
||||||
// instruction can also display only one block, which does not necessarily
|
// instruction can also display only one block, which does not necessarily
|
||||||
// have to be the initial block
|
// have to be the initial block
|
||||||
xml = xml.replace('deletable="false"', 'deletable="true"');
|
xml = xml.replace('deletable="false"', 'deletable="true"');
|
||||||
}
|
}
|
||||||
this.setState({xml: xml});
|
this.setState({ xml: xml });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.props.deleteError(this.props.index, 'xml');
|
this.props.deleteError(this.props.index, 'xml');
|
||||||
@@ -98,8 +98,8 @@ class BlocklyExample extends Component {
|
|||||||
|
|
||||||
onChange = (value) => {
|
onChange = (value) => {
|
||||||
var oldValue = this.state.checked;
|
var oldValue = this.state.checked;
|
||||||
this.setState({checked: value});
|
this.setState({ checked: value });
|
||||||
if(oldValue !== value && !value){
|
if (oldValue !== value && !value) {
|
||||||
this.props.deleteError(this.props.index, 'xml');
|
this.props.deleteError(this.props.index, 'xml');
|
||||||
this.props.deleteProperty(this.props.index, 'xml');
|
this.props.deleteProperty(this.props.index, 'xml');
|
||||||
}
|
}
|
||||||
@@ -108,12 +108,12 @@ class BlocklyExample extends Component {
|
|||||||
setXml = () => {
|
setXml = () => {
|
||||||
var xml = this.props.xml;
|
var xml = this.props.xml;
|
||||||
this.props.changeContent(xml, this.props.index, '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') });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)'}}>
|
<div style={{ marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)' }}>
|
||||||
{!this.props.task ?
|
{!this.props.task ?
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
labelPlacement="end"
|
labelPlacement="end"
|
||||||
@@ -126,41 +126,42 @@ class BlocklyExample extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
: <FormLabel style={{color: 'black'}}>Musterlösung</FormLabel>}
|
: <FormLabel style={{ color: 'black' }}>{Blockly.Msg.builder_solution}</FormLabel>}
|
||||||
{this.state.checked ? !this.props.value || this.props.error ?
|
{this.state.checked ? !this.props.value || this.props.error ?
|
||||||
<FormHelperText style={{lineHeight: 'initial'}} className={this.props.classes.errorColor}>{`Reiche deine Blöcke ein, indem du auf den '${this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'}'-Button klickst.`}</FormHelperText>
|
<FormHelperText style={{ lineHeight: 'initial' }} className={this.props.classes.errorColor}>{`Reiche deine Blöcke ein, indem du auf den '${this.props.task ? Blockly.Msg.builder_solution_submit : Blockly.Msg.builder_example_submit}'-Button klickst.`}</FormHelperText>
|
||||||
: this.state.input ? <FormHelperText style={{lineHeight: 'initial'}}>Die letzte Einreichung erfolgte um {this.state.input} Uhr.</FormHelperText> : null
|
: this.state.input ? <FormHelperText style={{ lineHeight: 'initial' }}>Die letzte Einreichung erfolgte um {this.state.input} Uhr.</FormHelperText> : null
|
||||||
: null}
|
: null}
|
||||||
{this.state.checked && !this.props.task ?
|
{this.state.checked && !this.props.task ?
|
||||||
<FormHelperText style={{lineHeight: 'initial'}}>Anmerkung: Man kann den initialen Setup()- bzw. Endlosschleifen()-Block löschen. Zusätzlich ist es möglich u.a. nur einen beliebigen Block auszuwählen, ohne dass dieser als deaktiviert dargestellt wird.</FormHelperText>
|
<FormHelperText style={{ lineHeight: 'initial' }}>{Blockly.Msg.builder_comment}</FormHelperText>
|
||||||
: null}
|
: null}
|
||||||
{/* ensure that the correct xml-file is displayed in the workspace */}
|
{/* ensure that the correct xml-file is displayed in the workspace */}
|
||||||
{this.state.checked && this.state.xml? (() => {
|
{this.state.checked && this.state.xml ? (() => {
|
||||||
return(
|
return (
|
||||||
<div style={{marginTop: '10px'}}>
|
<div style={{ marginTop: '10px' }}>
|
||||||
<Grid container className={!this.props.value || this.props.error ? this.props.classes.errorBorder : null}>
|
<Grid container className={!this.props.value || this.props.error ? this.props.classes.errorBorder : null}>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<BlocklyWindow
|
<BlocklyWindow
|
||||||
blockDisabled={this.props.task}
|
blockDisabled={this.props.task}
|
||||||
trashcan={false}
|
trashcan={false}
|
||||||
initialXml={this.state.xml}
|
initialXml={this.state.xml}
|
||||||
blocklyCSS={{height: '500px'}}
|
blocklyCSS={{ height: '500px' }}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Button
|
<Button
|
||||||
className={!this.props.value || this.props.error ? this.props.classes.errorButton : null }
|
className={!this.props.value || this.props.error ? this.props.classes.errorButton : null}
|
||||||
style={{marginTop: '5px', height: '40px'}}
|
style={{ marginTop: '5px', height: '40px' }}
|
||||||
variant='contained'
|
variant='contained'
|
||||||
color='primary'
|
color='primary'
|
||||||
disabled={this.state.disabled}
|
disabled={this.state.disabled}
|
||||||
onClick={() => this.setXml()}
|
onClick={() => this.setXml()}
|
||||||
>
|
>
|
||||||
{this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'}
|
{this.props.task ? Blockly.Msg.builder_solution_submit : Blockly.Msg.builder_example_submit}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)})()
|
)
|
||||||
: null}
|
})()
|
||||||
|
: null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -179,4 +180,4 @@ const mapStateToProps = state => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, { changeContent, deleteProperty, setError, deleteError })(withStyles(styles, {withTheme: true})(BlocklyExample));
|
export default connect(mapStateToProps, { changeContent, deleteProperty, setError, deleteError })(withStyles(styles, { withTheme: true })(BlocklyExample));
|
||||||
|
|||||||