Compare commits

..
Author SHA1 Message Date
felixerdy d20d8b9e97 add xml code changes 2021-09-16 16:51:10 +02:00
felixerdy 53b4f5dfeb keep workspace code and prepare dialog 2021-09-16 16:00:27 +02:00
Mario PeschandGitHub 9ed49f2972 Merge pull request #99 from sensebox/update-blockly-core
update blockly core and plugins
2021-08-20 10:47:17 +02:00
Mario Pesch 2a9eecd76b prevent edgeScroll 2021-08-20 10:42:37 +02:00
Mario Pesch c23b74ce8d update blockly core and plugins
closes #97
2021-08-18 15:18:47 +02:00
Mario PeschandGitHub f2d50a33c1 Merge pull request #98 from sensebox/remove-mybadges-integration
remove mybadges integration
2021-08-18 14:56:07 +02:00
Mario Pesch 5b2add4098 remove mybadges integration 2021-07-27 11:57:46 +02:00
Mario PeschandGitHub ed36a27ac2 Merge pull request #79 from sensebox/ui-updates
ui-updates
2021-07-01 15:58:35 +02:00
Mario Pesch 4e2b57d46a revert commit 2021-07-01 15:25:33 +02:00
Mario Pesch 9c02fa1ec6 Merge branch 'master' into ui-updates 2021-07-01 11:02:03 +02:00
Mario PeschandGitHub e7cfc5c5d3 Merge pull request #95 from sensebox/dependabot/npm_and_yarn/prismjs-1.24.0
Bump prismjs from 1.23.0 to 1.24.0
2021-06-29 15:21:27 +02:00
dependabot[bot]andGitHub 4f24ba607f Bump prismjs from 1.23.0 to 1.24.0
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.23.0 to 1.24.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.23.0...v1.24.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-28 20:28:48 +00:00
Mario PeschandGitHub c3bd3a5bef Merge pull request #94 from sensebox/add-curly-brackets
add curly brackets
2021-06-22 13:22:44 +02:00
Mario Pesch 1e979f948c add curly brackets
closes #93
2021-06-22 12:15:39 +02:00
Mario PeschandGitHub f6947f8c6b Merge pull request #92 from sensebox/add-matamo-image-tracker
Add matamo image tracker
2021-06-16 15:08:13 +02:00
Mario Pesch bb19a77896 fix mail in impressum 2021-06-16 12:59:50 +02:00
Mario Pesch f4344f842c add matamo image tracker 2021-06-16 11:17:08 +02:00
Mario PeschandGitHub ee19598728 Merge pull request #91 from sensebox/add-rtc
Add rtc
2021-06-16 10:59:53 +02:00
Mario Pesch d65948fca7 cleanup code and add translations 2021-06-14 14:36:22 +02:00
Mario Pesch c1eff07b7e fix timestamp 2021-06-11 11:19:39 +02:00
Mario Pesch aef8a164ce Merge branch 'master' into add-rtc 2021-06-11 10:10:51 +02:00
Mario Pesch 8c3a86b667 Merge branch 'master' into ui-updates 2021-06-02 14:49:58 +02:00
Mario PeschandGitHub 5ecc776db2 Merge pull request #89 from sensebox/add-phyphox
Add phyphox
2021-05-21 12:21:26 +02:00
Mario Pesch b6c90772ed add rtc blocks 2021-05-21 11:28:35 +02:00
Mario Pesch 283da13455 update tooltip 2021-05-18 13:46:35 +02:00
Mario Pesch 59142b4c25 update randomInt function 2021-05-17 17:03:53 +02:00
Mario Pesch da65e23d3f remove experiment field a 2021-05-17 17:03:42 +02:00
Mario Pesch 531db63b85 add tooltips and en translations 2021-05-17 15:51:57 +02:00
Mario Pesch 44d48997d4 update phyphox blocks 2021-05-16 20:03:21 +02:00
Mario Pesch 47984fa66c add first phyphox blocks 2021-05-06 15:21:54 +02:00
Mario Pesch 4522760e9c update blockly version and add zoom to fit plugin 2021-05-04 11:53:15 +02:00
Mario Pesch 21d282ee1b add multiplexer
closes #81
2021-03-30 15:03:34 +02:00
Mario Pesch 6b12c501a0 fix variable naming 2021-03-30 12:26:26 +02:00
Mario Pesch 255b1619b8 update variable names 2021-03-29 15:07:39 +02:00
Mario Pesch 687ac32166 add ide output fixes #71 2021-03-25 10:38:32 +01:00
Mario Pesch 6a6b2e2f58 get rid of console.log 2021-03-24 17:07:23 +01:00
Mario Pesch d835ffc449 fix load projects 2021-03-24 17:05:21 +01:00
Mario Pesch 190d676e5b fix #58 2021-03-24 15:33:08 +01:00
Mario Pesch 65fa627aeb add dialog before reset workspace
fixes #78
2021-03-24 11:46:05 +01:00
Mario PeschandGitHub bc5cbb6b33 Merge pull request #77 from sensebox/fix/remove-warnings
resolve warnings
2021-03-21 11:48:18 +01:00
Mario Pesch 31e0880e7a resolve warnings 2021-03-19 15:27:18 +01:00
Mario PeschandGitHub 09a9318b24 Merge pull request #76 from sensebox/fix-double-wirelib
fix duplicate wire library
2021-03-19 11:21:41 +01:00
mariopesch 8dea4d97c5 fix npm (hopefully) 2021-03-19 11:12:01 +01:00
mariopesch d442b2f100 fix duplicate wire library 2021-03-19 10:54:17 +01:00
Mario PeschandGitHub a163c76463 Merge pull request #70 from sensebox/fix/gps-library
update to new gps library
2021-03-13 19:24:11 +01:00
Mario PeschandGitHub 7a34575314 Merge pull request #73 from sensebox/add/copyToClipboardButton
add copy to clipboard Button
2021-03-13 19:23:57 +01:00
Mario 5c843db50b add copy to clipboard Button 2021-03-13 19:20:29 +01:00
Mario 2e00fdaa1c update to new gps library 2021-03-11 10:57:43 +01:00
Mario PeschandGitHub a8f57b200c Merge pull request #68 from sensebox/dependabot/npm_and_yarn/prismjs-1.23.0
Bump prismjs from 1.21.0 to 1.23.0
2021-03-10 14:01:21 +01:00
Mario PeschandGitHub 4626addcfb Merge pull request #67 from sensebox/fix/update-lightsensor-code
update code for new lightsensor
2021-03-10 14:01:01 +01:00
dependabot[bot]andGitHub 421f7d00b1 Bump prismjs from 1.21.0 to 1.23.0
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.21.0 to 1.23.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.21.0...v1.23.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-01 21:31:05 +00:00
Mario 6d7e2782d6 update code for new lightsensor
need to use Board Support Package V1.4.0 with MCU Lib V1.4.0
2021-02-15 17:16:46 +01:00
Mario PeschandGitHub 5e4021d6d9 Merge pull request #65 from sensebox/fix-mqtt
fix for custom mqtt server
2021-02-15 16:21:26 +01:00
Mario 269afa4b76 fix for custom mqtt server 2021-02-15 10:47:01 +01:00
Mario PeschandGitHub 1963ca3051 Merge pull request #56 from sensebox/feat/add-sentry
Feat/add sentry
2021-01-20 11:56:27 +01:00
Mario 0d8c30c1ee add account information 2021-01-20 11:33:06 +01:00
Mario 957ccd566e add sentry 2021-01-19 19:54:33 +01:00
Mario 126dc3ecf4 add missing imports 2021-01-13 15:37:41 +01:00
Mario PeschandGitHub 851400e1c1 Merge pull request #55 from sensebox/fix-languageselection
fix the language selection
2021-01-13 15:05:15 +01:00
Mario b25a4d602a fix the language selection 2021-01-13 14:08:36 +01:00
Mario PeschandGitHub 97e28b62f8 Merge pull request #53 from sensebox/add-help-card
add tooltip viewer
2021-01-12 10:27:22 +01:00
Mario de9141c25c small fixes 2021-01-12 10:18:11 +01:00
Mario 7a31d94a21 complete sensor translations 2021-01-11 14:13:02 +01:00
Mario 8f47ae4fc8 reorder language files 2021-01-08 16:55:58 +01:00
Mario PeschandGitHub 4256d340c4 Merge pull request #47 from sensebox/dependabot/npm_and_yarn/ini-1.3.8
Bump ini from 1.3.5 to 1.3.8
2021-01-06 11:32:54 +01:00
Mario 48e63fe898 update RGB-Block 2020-12-29 15:13:33 +01:00
Mario f6f6d6f1da add tooltip viewer 2020-12-22 09:36:13 +01:00
Mario PeschandGitHub 5eb6a94a0b Merge pull request #52 from sensebox/new-blocks
add new blocks
2020-12-21 12:12:31 +01:00
Mario 40f8c62696 remove field slider from rgb block 2020-12-21 11:57:32 +01:00
Mario 842b4522f0 add soundsensor 2020-12-21 11:22:54 +01:00
Mario c52e9db4c8 add watertemperature sensor 2020-12-21 10:59:05 +01:00
Mario 5658aa603c add soil moisture sensor 2020-12-21 10:43:08 +01:00
Mario PeschandGitHub 59fa90d43f Merge pull request #51 from sensebox/add-faq
Add faq
2020-12-21 10:24:29 +01:00
Mario 7940885388 add help text 2020-12-21 10:18:11 +01:00
Mario bf82a396fc add en translations 2020-12-21 10:12:00 +01:00
Mario 889fba21cc add faq page 2020-12-19 10:32:42 +01:00
Mario PeschandGitHub d91d22cdee Merge pull request #50 from sensebox/add-default-types
add default types
2020-12-18 10:21:09 +01:00
Mario a70e333d4d add default types 2020-12-18 10:17:20 +01:00
Mario PeschandGitHub ad1e5f1b82 Merge pull request #49 from sensebox/add-tour
Add tour
2020-12-18 09:17:54 +01:00
Mario 3e01ede7f1 add container to imprint and privacy 2020-12-17 14:46:15 +01:00
Mario 41739e7fb3 add news page 2020-12-17 14:43:35 +01:00
Mario fdcd5c9c5d add tour in de and en 2020-12-17 11:02:29 +01:00
Delucse b4a9f76d99 password placeholder 2020-12-15 22:30:55 +01:00
Delucse 1e9361b730 example of multilanguage tour 2020-12-15 16:18:47 +01:00
Delucse e4bab3d9ca add assessment tour 2020-12-15 16:09:29 +01:00
Delucse dce73e6a54 hide assessment-tour on various pages 2020-12-15 15:55:16 +01:00
Mario PeschandGitHub 307607191e Merge pull request #48 from sensebox/backend-connection
Backend connection
2020-12-15 15:22:23 +01:00
Mario 127c9551a0 hide tour on various pages 2020-12-15 15:19:06 +01:00
Mario 8504dacc38 add tour 2020-12-15 15:01:26 +01:00
Delucse 0239ae28aa create tutorial buttons 2020-12-15 11:33:04 +01:00
Delucse 84ce074aec aprovement of adding badge to tutorial 2020-12-15 11:18:59 +01:00
Mario 7d876e8bf9 codeviewer translations 2020-12-15 10:39:22 +01:00
Mario 813582bf9d translations for login page 2020-12-15 10:27:50 +01:00
Mario 256593164f add navbar translations 2020-12-15 10:04:33 +01:00
Mario 9d65f7b944 add en translations 2020-12-15 09:51:12 +01:00
Delucse b04a5bc591 store locale in localStorage only if user is not logged in 2020-12-14 20:04:49 +01:00
Delucse 49730f51ac public route 2020-12-14 19:26:07 +01:00
Delucse 4588e2a69b Merge branch 'add-translations' into backend-connection 2020-12-14 15:23:01 +01:00
Delucse a99ecc36a4 routing improvement 2020-12-14 15:15:08 +01:00
Delucse 5a7e62adcf Merge branch 'add-translations' of https://github.com/sensebox/React-Ardublockly into add-translations 2020-12-14 14:48:16 +01:00
Delucse c6a1e854d2 get locale from user if exists 2020-12-14 14:48:12 +01:00
Mario e5204bb4d5 add more translations and resolve issues 2020-12-14 13:50:44 +01:00
Delucse e52e3943c1 add generalReducer to store settings 2020-12-14 13:06:55 +01:00
Mario 7d1d2409e4 add first translations 2020-12-14 08:51:31 +01:00
Delucse 42981a4f11 badge selection 2020-12-13 20:52:23 +01:00
dependabot[bot]andGitHub a6e800c91b Bump ini from 1.3.5 to 1.3.8
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-13 06:33:56 +00:00
Delucse 4f002d8694 definig success and error callbacks for every private axios request 2020-12-11 14:35:24 +01:00
Delucse 1821ac4e40 tutorial status is stored in user account if exists or in local storage 2020-12-11 13:06:38 +01:00
Mario PeschandGitHub 3d2a18c1db Merge pull request #46 from sensebox/slice-empty-sensor
slice first empty option from sensor array
2020-12-10 14:53:49 +01:00
Mario PeschandGitHub a929c3d8e6 Merge pull request #37 from sensebox/backend-connection
Backend connection
2020-12-10 14:42:11 +01:00
Delucse 5430e783cc show assigned badge 2020-12-10 10:31:43 +01:00
Delucse 101dfc7692 assigne badge after tutorial-success 2020-12-09 19:34:44 +01:00
Delucse f9caeb619e connect to MyBadges-account 2020-12-09 18:10:45 +01:00
Mario ac127dcca2 slice first empty option from sensor array 2020-12-09 16:10:37 +01:00
Delucse c47d98d2eb compile button 2020-12-09 09:34:33 +01:00
Delucse 3655063eaa Merge branch 'backend-connection' of https://github.com/sensebox/React-Ardublockly into backend-connection 2020-12-08 20:16:15 +01:00
Delucse a4cf0d32b0 adjustment of the project object property 'shared' 2020-12-08 20:15:54 +01:00
Mario PeschandGitHub c4c9ddc127 Merge pull request #40 from sensebox/compile-button-color
update compile button color
2020-12-08 20:14:40 +01:00
Mario f53baf2536 update compile button color 2020-12-08 20:06:51 +01:00
Delucse 3cf7f10d34 delete tutorial button at tutorial builder 2020-12-08 15:33:03 +01:00
Delucse e6813ba2d3 create modular structure of WorkspaceFunc component 2020-12-08 13:53:43 +01:00
Mario a1834875a0 Update store.js 2020-12-08 10:34:11 +01:00
Mario PeschandGitHub 2285f52a0c Merge pull request #38 from sensebox/add-access-token
add access-token
2020-12-08 09:43:30 +01:00
Delucse 646254017c display account information 2020-12-07 20:12:33 +01:00
Delucse 80fd3b83a9 Merge branch 'backend-connection' of https://github.com/sensebox/React-Ardublockly into backend-connection 2020-12-07 18:19:08 +01:00
Delucse 50e22fdf92 possiblilty to change title of project, get share link, delete project for every project via button 2020-12-07 18:18:08 +01:00
Mario 0e05cdca5c add access-token 2020-12-07 16:26:18 +01:00
Mario 49fb018703 fix build process 2020-12-07 15:44:56 +01:00
Delucse b2f6b1d012 display of the sharing link validity 2020-12-07 14:15:08 +01:00
Delucse dddb00bd79 osem boxes dropdown blockly menu 2020-12-07 12:33:47 +01:00
Delucse 6a8036e075 restrictions in the accessibility of URLs 2020-12-03 16:56:04 +01:00
Delucse 31dbda57df load user, if valid token exists 2020-12-03 15:38:47 +01:00
Delucse 80fd112658 private routes and redirecting 2020-12-03 12:09:01 +01:00
Delucse 5d9bfa97af login 2020-12-03 11:17:39 +01:00
Delucse 4f57e7fd32 note, if no data are available in database 2020-12-02 18:49:08 +01:00
Delucse e2915e8cd0 update gallery-project 2020-12-02 18:04:03 +01:00
Delucse 155675821a delete (gallery-)project 2020-12-02 17:16:40 +01:00
Delucse c5fd5c6239 update project 2020-12-02 15:21:28 +01:00
Delucse a30747c608 project redux store 2020-12-02 14:02:03 +01:00
Delucse a8e36a4f06 create and display projects 2020-12-02 12:42:45 +01:00
Delucse e600c19679 new script: npm run dev 2020-12-01 19:35:53 +01:00
Delucse 0d4072ab17 redirection to home if no share or gallery content is available 2020-12-01 19:05:14 +01:00
Delucse 2dfd146d18 display gallery content 2020-12-01 18:01:52 +01:00
Delucse 2e330d1215 Merge branch 'assessment' into backend-connection 2020-12-01 14:43:25 +01:00
Delucse 47f0ebb80d restriction of workspace functions in context tutorials 2020-12-01 14:37:32 +01:00
Delucse 6db8c094ea create and display content to share 2020-12-01 13:29:52 +01:00
Delucse d0dda4038e change existing tutorial with Tutorial-Builder 2020-11-30 17:19:32 +01:00
Delucse c8f01f8273 load pictures from the api server 2020-11-30 13:44:05 +01:00
Delucse a2c571c1e7 adjustments do mongoDB output 2020-11-27 17:21:42 +01:00
Delucse 2d29b8d7bd load tutorial only once 2020-11-27 13:31:03 +01:00
Delucse 28720edeea linear progress at navbar 2020-11-27 12:26:16 +01:00
Delucse cbe091db27 updated status reading 2020-11-27 12:06:13 +01:00
Delucse b8a2f87321 get all tutorials about the API 2020-11-27 09:30:42 +01:00
Delucse ea00d173c5 get a tutorial about the API 2020-11-27 08:41:34 +01:00
Mario PeschandGitHub 28d674b6cd Merge pull request #34 from sensebox/add-impressum
add impressum
2020-11-25 18:23:06 +01:00
Mario aae3771020 add impressum 2020-11-25 18:18:45 +01:00
Mario PeschandGitHub 18ac32893c Merge pull request #30 from sensebox/add-lora-tutorial
add lora tutorial
2020-11-18 12:06:04 +01:00
Mario 14260efa3b add lora tutorial 2020-11-17 16:49:49 +01:00
Mario PeschandGitHub 73aa1ef878 Merge pull request #29 from sensebox/add-markdown
Add markdown
2020-11-17 16:47:17 +01:00
Mario 38700bf57c remove lora tutorial 2020-11-17 16:38:39 +01:00
Mario 0829522743 fix build error 2020-11-17 16:36:23 +01:00
Mario 7ffe9ff18b add some styling 2020-11-16 15:51:44 +01:00
Mario PeschandGitHub 1b0743b0cf Merge pull request #28 from sensebox/small-fixes
Small fixes
2020-11-16 14:16:03 +01:00
Mario PeschandGitHub b4fb4f8501 Merge branch 'add-markdown' into small-fixes 2020-11-16 14:15:32 +01:00
Mario 02a64b9a8f add new tutorial and hardware 2020-11-16 14:14:43 +01:00
Mario PeschandGitHub 4255d14873 Merge pull request #27 from sensebox/small-fixes
small code fixes
2020-11-16 09:35:13 +01:00
Mario c17fc8a50f small code fixes 2020-11-16 09:27:26 +01:00
Mario fd21bd76f9 update tutorials 2020-11-16 09:05:47 +01:00
Mario b60ec9136a allow markdown in tutorial text 2020-11-13 15:33:21 +01:00
Mario PeschandGitHub 13d2d3d301 Merge pull request #26 from sensebox/fix-logic-block
fix logic block
2020-11-12 11:47:06 +01:00
Mario b68fb77663 fix logic block 2020-11-12 11:40:38 +01:00
Mario PeschandGitHub e81627b8ec Merge pull request #25 from sensebox/blocks/webserver
Blocks/webserver
2020-11-12 09:05:44 +01:00
Mario 4e34c63f08 fix color in mutator 2020-11-11 15:48:41 +01:00
Mario dad91d0a93 resolve warnings 2020-11-11 15:29:56 +01:00
Mario 0183679041 add webserver blocks 2020-11-11 15:24:33 +01:00
Mario d649c3d395 small spelling changes 2020-11-11 14:46:29 +01:00
Mario PeschandGitHub bbc3022644 Merge pull request #23 from sensebox/add-procedures
[WIP] - Add procedures
2020-11-11 14:10:41 +01:00
Mario PeschandGitHub aa8b1067dc Merge pull request #24 from sensebox/blocks/mqtt
Blocks/mqtt
2020-11-11 14:08:44 +01:00
Mario 9318d3ef12 add services 2020-11-11 12:37:51 +01:00
Mario fe328f9da3 add first draft for mqtt blocks 2020-11-11 11:09:19 +01:00
Mario PeschandGitHub 3df66cd425 Merge pull request #22 from sensebox/gps-ttn-mapper
[WIP] initial gps ttn mapper code
2020-11-06 11:56:19 +01:00
Mario 3dfcffc2ad add translations 2020-11-06 11:02:28 +01:00
Mario 0cba423749 switch order 2020-11-06 10:27:58 +01:00
Mario b1b80f8af0 Update Toolbox.js 2020-11-06 10:23:44 +01:00
Mario 2e4df70ddd add gps blocks to toolbox 2020-11-06 10:16:41 +01:00
felixerdy 5621fdc620 add some delay and fix type limit 2020-11-05 20:57:17 +01:00
Mario b4a59d3875 put initLora always to the end of the setup 2020-11-05 18:48:19 +01:00
Mario 70c8a1db60 add feature to hide Workspace stats 2020-11-05 18:30:27 +01:00
Mario 5da3006e75 small fixes 2020-11-05 14:38:38 +01:00
Mario 8e2deed1d5 init implementation of procedures 2020-11-05 11:05:14 +01:00
felixerdy 7b89897e54 initial gps ttn mapper code 2020-10-30 12:25:03 +01:00
Mario PeschandGitHub 4601439ae3 Merge pull request #21 from sensebox/add-cookie-consent
add cookie consent
2020-10-29 11:23:19 +01:00
Mario fd1d8c35e5 add cookie consent
fix #15
2020-10-29 11:09:50 +01:00
Mario PeschandGitHub b07d753e6c Merge pull request #19 from sensebox/feat/blockly-gallery
add blockly project gallery
2020-10-29 10:58:40 +01:00
Mario f1ea8ca2e8 Merge branch 'feat/blockly-gallery' of https://github.com/sensebox/React-Ardublockly into feat/blockly-gallery 2020-10-29 10:51:17 +01:00
Mario cc54c18b47 update osem block 2020-10-29 10:50:48 +01:00
Mario PeschandGitHub bc819f224b Merge branch 'master' into feat/blockly-gallery 2020-10-29 08:50:41 +01:00
Mario 14947267d1 add language selection 2020-10-29 08:48:35 +01:00
Delucse 104d432278 block labeling in german 2020-10-28 13:57:38 +01:00
Delucse 345aa57b7e consideration of higher-level parent node 2020-10-28 12:21:13 +01:00
Mario PeschandGitHub 0a459938a8 Merge branch 'master' into feat/blockly-gallery 2020-10-20 10:49:31 +02:00
Delucse f95beb9623 correcting loop tutorial tasks 2020-10-19 08:43:40 +02:00
Mario PeschandGitHub 61ca2e8799 Merge pull request #20 from sensebox/dynamic-osem-dropdown
Dynamic osem dropdown
2020-10-17 14:18:54 +02:00
Mario 71a73ddd1d cleanup code 2020-10-17 14:18:05 +02:00
Mario 9dedc9ccd1 generate dynamic dropdowns 2020-10-17 14:17:37 +02:00
Delucse 5999daa332 dialog - hint tutorials exists 2020-10-17 11:09:25 +02:00
Delucse a0fd63a2ca fix vertical stepper bug 2020-10-17 09:47:03 +02:00
Mario 145c14c0cc Update WorkspaceFunc.js 2020-10-17 09:42:54 +02:00
Mario d7b725d1fd add margin 2020-10-16 23:58:00 +02:00
Mario 09c5ef5aae update api endpoint 2020-10-16 22:52:13 +02:00
Mario dbebb25b17 fix variable Name 2020-10-16 22:36:43 +02:00
Mario e647d6e58e add block sharing 2020-10-16 22:33:02 +02:00
Mario PeschandGitHub b310d290cf Merge pull request #18 from sensebox/fix/boolean-return-type
Fix/boolean return type
2020-10-16 15:01:06 +02:00
Mario 3f7ba6fbac fix checks 2020-10-16 14:51:39 +02:00
Mario 1950344862 fix return type 2020-10-16 14:46:34 +02:00
Mario 0cb7bba521 add blockly project gallery 2020-10-16 14:32:52 +02:00
Mario PeschandGitHub 40d4c67be8 Merge pull request #16 from sensebox/resize-hardware-images
resize hardware images
2020-10-13 10:44:35 +02:00
Mario a809946899 resize hardware images 2020-10-13 10:35:31 +02:00
Mario PeschandGitHub e1f3bbdf03 Merge pull request #12 from sensebox/new-tutorial-structure
New tutorial structure
2020-10-13 10:06:32 +02:00
Mario PeschandGitHub b53a5b277c Merge pull request #14 from sensebox/block/co2-sensor
add co2 sensor
2020-10-13 10:03:38 +02:00
Mario 9f16e07c59 add co2 sensor 2020-10-12 15:06:33 +02:00
Mario PeschandGitHub 15ff312d48 Merge pull request #13 from sensebox/add-license-1
Create LICENSE
2020-10-08 18:05:51 +00:00
Mario PeschandGitHub 8b475cd0d8 Create LICENSE 2020-10-08 20:05:38 +02:00
Mario 08ee8b3b5c add display tutorial 2020-10-08 16:25:37 +02:00
Mario 83c8a4f296 change tile color in builder 2020-10-08 15:33:30 +02:00
Mario f660814897 resolve warnings 2020-10-08 15:31:33 +02:00
Mario 89d0cc380b update tutorial structure 2020-10-08 15:29:28 +02:00
Mario aaeaf7a5aa update logic and text blocks 2020-10-08 15:28:26 +02:00
Mario f709b4b757 update breadboard image 2020-10-08 15:28:07 +02:00
Mario 2a2c1e1c25 update loop blocks 2020-10-07 09:47:24 +02:00
Mario 40d8301990 update loops tutorial 2020-10-06 11:35:58 +02:00
Mario PeschandGitHub c99ca92a4e Merge pull request #10 from sensebox/use-viewport-height
use viewport height for blocklywindow
2020-10-05 07:21:44 +00:00
Delucse fc785b8b8d ensure that fill-opacity is 1 (blockly-svg) 2020-10-02 16:01:11 +02:00
Mario 14455547a4 use viewport height for blocklywindow 2020-10-02 14:55:16 +02:00
Mario PeschandGitHub 182b5ada77 Merge pull request #9 from sensebox/add-button-block
add block for the button
2020-10-02 12:33:37 +00:00
Mario 4fc0f14aed add block for the button 2020-10-02 14:30:24 +02:00
Delucse 5daa336a04 setting the maximum display size of the embedded youtube video 2020-09-30 16:58:02 +02:00
Delucse 1cd00dab3f Merge branch 'tutorial' 2020-09-30 15:59:22 +02:00
Delucse 9da57c5067 embed youtube video 2020-09-30 15:58:49 +02:00
Delucse f97ab10a53 Merge branch 'tutorial-builder' into tutorial 2020-09-30 15:41:52 +02:00
Delucse 56820a04fc possibility to add media (picture or youtube-video) to the instructions 2020-09-30 15:41:24 +02:00
Delucse 1cef36e0f2 embed picture 2020-09-30 09:41:31 +02:00
Delucse f7a0e7594d ensure that the correct xml-file is displayed in the workspace 2020-09-30 09:20:29 +02:00
Delucse 8991e2b40b possibility to add pictures to the instructions 2020-09-29 20:12:33 +02:00
Mario PeschandGitHub 67cc477d28 Merge pull request #7 from sensebox/typed-variables
Typed variables
2020-09-29 12:21:58 +00:00
Mario 44d14687be update code generation 2020-09-29 11:33:06 +02:00
Mario eceaa91713 Merge branch 'master' into typed-variables 2020-09-29 11:28:57 +02:00
Mario d64512ed9e add math types 2020-09-29 11:25:07 +02:00
Mario 5304907fd0 add block type to setter and getter 2020-09-29 10:30:35 +02:00
Mario da4c8840ea update blockly version 2020-09-29 10:30:13 +02:00
Delucse 3a92a6a08c fix error status in tutorial-builder 2020-09-28 15:54:39 +02:00
Delucse 8d752e0430 precondition for each tutorial is at least one instruction and one task 2020-09-28 15:41:17 +02:00
Delucse 4a5d24f2d1 template created for not deactivated blocks in the instructions 2020-09-28 15:12:19 +02:00
Delucse 8ec8409504 Update WorkspaceFunc.js 2020-09-27 20:57:56 +02:00
Delucse 078d53e7e2 Merge branch 'tutorial' 2020-09-27 20:36:07 +02:00
Delucse 7ca3b466ea create screenshot of workspace 2020-09-27 20:35:03 +02:00
Delucse 9d99c5c30b display of the blocks as SVG in instruction-component 2020-09-27 20:15:11 +02:00
Delucse 9b2d66aee7 fix bug in local storage logic 2020-09-25 13:40:42 +02:00
Delucse 1d3f356fe7 fix warning "no-loop-func" 2020-09-25 13:22:09 +02:00
Delucse 5044b09701 updated links to get more specific information about hardware 2020-09-25 12:51:37 +02:00
DelucseandGitHub 994f74d7ad Update README.md 2020-09-22 14:19:26 +02:00
Delucse b1038c447b create redirect file to get access to links based on react-router-dom 2020-09-22 12:44:45 +02:00
Delucse 3f4e559866 Merge branch 'tutorial-builder' 2020-09-22 11:57:02 +02:00
Delucse 2a7b9dd4d7 Merge branch 'snackbar' 2020-09-22 11:56:56 +02:00
Delucse 59d347de41 fix warnings in tutorial builder 2020-09-22 11:56:36 +02:00
Delucse 6cfcd97647 key prop to ensure independent treatment 2020-09-22 11:35:29 +02:00
Delucse 6a21410709 hide snackbar after 5 seconds 2020-09-22 11:34:03 +02:00
Delucse 9e9c523955 Merge branch 'snackbar' 2020-09-21 12:16:57 +02:00
Delucse 9df7de05f4 adjustment of colours and messages in case of error 2020-09-21 12:16:10 +02:00
Delucse 0f0bfb98c6 add snackbar to tutorial builder 2020-09-21 11:41:19 +02:00
Delucse 9574462fbf add snackbar to workspace functions 2020-09-21 11:41:01 +02:00
Delucse ece3514cb3 initialize snackbar 2020-09-21 11:40:33 +02:00
Delucse 0029f7cc26 another way to initialize an array to fix bug 2020-09-20 16:45:24 +02:00
Delucse 420477e02c breadcrumbs adjustment 2020-09-20 16:31:14 +02:00
Delucse 1518787e13 Merge branch 'tutorial-builder' 2020-09-20 16:29:03 +02:00
Delucse a46ca93763 navlink tutorial-builder 2020-09-20 16:26:37 +02:00
Delucse 660abe9712 reorganize data files like tutorials.json 2020-09-20 16:23:18 +02:00
Delucse e20a40aaf5 definig specific error in step component 2020-09-20 16:22:07 +02:00
Delucse b03ef6b54a completing the metadata in hardware.json 2020-09-20 14:58:27 +02:00
Delucse 15a83f56fc fix bug in blockly example 2020-09-20 14:15:18 +02:00
Delucse 812c01d6bc layout tutorial builder 2020-09-20 13:59:42 +02:00
Delucse fc1b898c80 upload JSON string 2020-09-20 13:48:19 +02:00
Delucse 3ba35751ea fix bugs concerning uploading json 2020-09-20 00:09:05 +02:00
Delucse 7579be52c9 upload JSON file 2020-09-19 23:21:43 +02:00
Delucse 28ced177bd generate JSON-file 2020-09-19 09:57:16 +02:00
Delucse 111b924988 error validation 2020-09-19 09:38:38 +02:00
felixerdy 3e3f0be41f typed variables working partially 2020-09-18 16:21:49 +02:00
Delucse b20bde4e83 tutorial builder 2020-09-18 16:21:27 +02:00
Delucse 253424037c step builder 2020-09-18 16:21:17 +02:00
Delucse 6d7f0fe609 blockly example creator 2020-09-18 16:21:00 +02:00
Delucse 07042ae055 hardware of steps 2020-09-18 16:20:10 +02:00
Delucse b78b704755 requirements of step 2020-09-18 16:20:00 +02:00
Delucse 45ac72a16e type of step 2020-09-18 16:19:50 +02:00
Delucse da29619694 textfield input 2020-09-18 16:19:36 +02:00
Delucse 458770e0c4 redux store of builder 2020-09-18 16:19:18 +02:00
felixerdy 136b85e027 initial implementation of typed variables 2020-09-18 15:19:58 +02:00
Delucse 1c2b025493 add id and title 2020-09-17 18:55:51 +02:00
Mario PeschandGitHub 38b025e012 Merge branch 'master' into new-blocks 2020-09-17 13:25:43 +00:00
Mario 42299a374a minor changes 2020-09-17 15:16:41 +02:00
Delucse d70207ea1a breadcrumbs with inital home-link 2020-09-17 14:13:30 +02:00
Delucse b726f5f42c Merge branch 'blockly-functions' 2020-09-17 13:24:38 +02:00
Delucse bde430dd40 detect whitespaces and return readable filename 2020-09-17 13:24:00 +02:00
Delucse 8bed9f4b7f Merge branch 'blockly-functions' 2020-09-17 12:57:07 +02:00
Delucse c85c96468c name of tutorial workspace is automatically derived from the tutorial title and the step heading 2020-09-17 12:56:43 +02:00
Delucse 5c43ff4648 name of the workspace and display of its 2020-09-17 11:55:46 +02:00
Delucse ba84bc512c set filename to save compiled blocks 2020-09-17 10:06:29 +02:00
Mario 6a4de9c7a2 fix warnings 2020-09-16 15:50:55 +02:00
Delucse 3c9404c5be deactivate redux devtools extension 2020-09-16 15:18:28 +02:00
Mario bbd14c58b5 add new blocks 2020-09-16 14:59:09 +02:00
Delucse 3d146155d0 Merge branch 'instruction' 2020-09-16 11:16:06 +02:00
Delucse 73c721f237 improved colour contrasts concerning tutorial status 2020-09-16 11:15:55 +02:00
Delucse 71e881283d improved feedback in terms of incorrect block count and success 2020-09-16 11:05:20 +02:00
Delucse 68af341816 cogs symbol to illustrate compiling 2020-09-16 10:49:56 +02:00
Delucse 11c3198c82 set filename to save blocks as xml-file 2020-09-16 10:42:18 +02:00
Delucse d3159d5204 Merge branch 'blockly-functions' into instruction 2020-09-15 18:50:26 +02:00
Delucse f7f95bbf9f solution check tooltip arrow 2020-09-15 18:50:12 +02:00
Delucse 7f3ad89623 Merge branch 'blockly-functions' into instruction 2020-09-15 18:44:37 +02:00
Delucse 20ac45a48d Merge branch 'assessment' into instruction 2020-09-15 18:44:23 +02:00
Delucse 02040bb656 Merge branch 'blockly-window' into instruction 2020-09-15 18:43:21 +02:00
Delucse 5cfb3c18de code-window is always visible for an assessment 2020-09-15 18:42:04 +02:00
Delucse 427467eb8a add workspace functions to assessment 2020-09-15 17:21:02 +02:00
Delucse 1c29dd2109 display statistics as menu, if screen is too small 2020-09-15 17:05:22 +02:00
Delucse 28fb2c3bab Merge branch 'instruction' into blockly-functions 2020-09-15 15:31:20 +02:00
Delucse 25134d4d86 hardware images without distortion 2020-09-15 15:29:59 +02:00
Delucse 4550977471 upload, download, compile and reset blocks 2020-09-15 14:39:47 +02:00
Delucse 567f94135b reorganize media files 2020-09-15 10:29:53 +02:00
Delucse 8060927cc6 adjustment of the hardware images so that the full image is visible 2020-09-15 10:21:50 +02:00
Mario 4df5b64eb0 add basic hardware images 2020-09-14 19:24:55 +02:00
Delucse 0f582e6d7d Merge branch 'instruction' 2020-09-14 19:00:57 +02:00
Delucse 84d4166cab display requirements 2020-09-14 19:00:15 +02:00
Mario PeschandGitHub edbf60d92e Merge pull request #5 from sensebox/add-slider
add led block
2020-09-14 14:24:51 +00:00
Mario 97ef7ab1bb update led pins 2020-09-14 15:58:22 +02:00
Mario 9a764b7e74 add led block 2020-09-14 15:41:57 +02:00
Delucse 93e047f4bf xs-display showing only two hardware-pictures 2020-09-14 13:33:21 +02:00
Delucse 9724d01b76 Merge branch 'master' into instruction 2020-09-14 13:26:29 +02:00
Delucse 823bb042ff showing needed hardware 2020-09-14 13:24:29 +02:00
Delucse 01c662b00f Merge remote-tracking branch 'origin/add-slider' 2020-09-13 16:04:06 +02:00
Delucse 7300cade5d each task (step) has its own id within a tutorial 2020-09-13 16:02:47 +02:00
Delucse 6f77b460cb add/ delete tutorials/steps in initial state of redux based on tutorials.json 2020-09-13 15:18:11 +02:00
Delucse f997bb661f update initialXml 2020-09-13 13:19:09 +02:00
Delucse e7723487c9 next step button or tutorial-overview button after solving task 2020-09-11 17:47:05 +02:00
Delucse f19842ccae status of tutorial and belonging tasks 2020-09-11 17:31:06 +02:00
Delucse 825075d656 next and back step - buttons 2020-09-11 11:00:57 +02:00
Delucse 6c3709fde8 adjustment of the tutorial component and all dependencies to the new tutorial.json 2020-09-11 10:13:33 +02:00
Delucse 33445cf67c tutorial.json 2020-09-11 09:08:31 +02:00
Delucse ab016610bd checking the Blocks with the solution using the XML strings 2020-09-10 13:46:31 +02:00
Delucse f14508a5ca own blocklyWindow for an instruction 2020-09-09 13:36:41 +02:00
Delucse 2908bc464f generalised BlocklyWindow 2020-09-09 13:35:35 +02:00
Mario 78f8bad4b3 add slider 2020-09-09 11:54:30 +02:00
Delucse 4f34811a94 store only xml if tutorial-id exists 2020-09-08 15:06:26 +02:00
Delucse eea893a071 stored xml in tutorial redux store 2020-09-08 14:43:30 +02:00
Delucse 7e0fbf1f75 current tutorial id stored in redux store 2020-09-08 13:42:55 +02:00
Delucse c1d3962fb4 Merge branch 'assessment' into tutorial 2020-09-08 12:07:55 +02:00
Delucse 29d77d0bc6 Revert "Revert "CodeViewer with referenced height of parent div""
This reverts commit 3297d01e78.
2020-09-08 12:03:49 +02:00
Delucse e766b05dba Merge branch 'tutorial' into assessment 2020-09-08 11:56:09 +02:00
Delucse de0bfd5d49 fixed status update of tutorials 2020-09-08 11:55:08 +02:00
Delucse 3297d01e78 Revert "CodeViewer with referenced height of parent div"
This reverts commit dddd9432db.
2020-09-08 11:30:34 +02:00
Delucse 6a94ce618c Revert "Merge branch 'assessment' into tutorial"
This reverts commit e322795f25, reversing
changes made to dddd9432db.
2020-09-08 11:30:25 +02:00
Delucse e322795f25 Merge branch 'assessment' into tutorial 2020-09-07 17:17:14 +02:00
Delucse dddd9432db CodeViewer with referenced height of parent div 2020-09-07 17:16:59 +02:00
Delucse 4c66ab9173 displaying the status of the tutorial 2020-09-07 15:57:09 +02:00
Delucse b42e466304 merge 2020-09-04 15:33:57 +02:00
Delucse c11ff8fc6c show vertical stepper not on extrasmall displays 2020-09-04 15:26:59 +02:00
Delucse 0e18c0bd23 elimination of password-bug 2020-09-04 15:15:22 +02:00
Delucse 1586e74cdc checked if wifi is initialized 2020-09-04 15:06:55 +02:00
Delucse c00c0949e4 clear workspace after changing tutorial 2020-09-04 11:50:04 +02:00
Delucse 7148d66d19 vertical tutorial stepper 2020-09-03 15:22:14 +02:00
Delucse ccf901d20b error page requesting a tutorial that does not (longer) exist 2020-09-02 11:43:17 +02:00
Delucse bcc4c35c9e improvement of tutorial stepper via material-ui 2020-09-01 13:23:56 +02:00
Delucse 5443932bf6 tutorial stepper 2020-08-31 17:26:58 +02:00
Delucse 8c13a9e316 splitting a tutorial into introduction and assessment 2020-08-31 16:52:30 +02:00
Delucse d379489a91 breadcrumbs 2020-08-31 13:53:39 +02:00
Delucse ab95f9eee6 overview of tutorials 2020-08-31 13:15:50 +02:00
Delucse f38a33fd4a URL dependent labeling of the toolbar 2020-08-31 12:35:33 +02:00
Delucse baa047f8d7 "code-on", "close trashcan", "delete trashcan" buttons 2020-08-10 14:30:08 +02:00
Delucse fdde372ef3 reset Workspace with initial XML-Block 2020-08-10 11:54:36 +02:00
Delucse 08dab82d00 showing CircularProgress while compiling 2020-08-10 10:06:34 +02:00
DelucseandGitHub c009674c46 Merge pull request #2 from sensebox/add-new-blocks
Add new blocks
2020-08-10 09:06:50 +02:00
Mario PeschandGitHub 30d8c0158e Merge pull request #4 from sensebox/compile
Compile
2020-08-04 13:14:48 +02:00
felixerdy ddd3fa1fcf online compiling 2020-08-03 16:38:18 +02:00
felixerdy fd4afa9e60 cleanup 2020-08-03 15:48:33 +02:00
Mario 6e56054d1d remove typography warning 2020-07-31 16:42:41 +02:00
Mario PeschandGitHub 736f3411df Merge pull request #3 from sensebox/styling
some styling
2020-07-31 16:37:30 +02:00
Mario dd874a2384 add LoRa Blocks 2020-07-31 16:37:09 +02:00
Mario 6678afbdff add map block 2020-07-31 16:18:45 +02:00
felixerdy 25aae52da3 some styling 2020-07-31 16:15:41 +02:00
Mario ef80f15782 add display and web blocks 2020-07-31 12:31:47 +02:00
Mario 0d70f66935 remove devtools 2020-07-31 12:31:34 +02:00
Mario b808474913 add language key 2020-07-31 11:36:02 +02:00
Mario 4e2b25947d solve compiling warnings 2020-07-31 11:27:53 +02:00
Mario 440622a66c add sensebox sensor blocks 2020-07-31 11:10:22 +02:00
Mario 44f2f3ca94 Merge branch 'master' into add-new-blocks 2020-07-26 12:15:57 +02:00
Delucse bd28c388be styling: cahnging color to 'white" 2020-07-24 19:49:40 +02:00
Delucse 9f33b93fdd recalculating positions of trash, zoom, etc 2020-07-24 19:15:41 +02:00
Delucse 338bec2d59 accordion to view code of different languages 2020-07-24 18:18:47 +02:00
Delucse b4a273b32a pretty code as output 2020-07-24 15:45:30 +02:00
Delucse 393c89877e code on/off 2020-07-24 12:24:14 +02:00
Delucse cacde16ab2 outsourcing BlocklyComponent to blockly/BlocklyWindow.js 2020-07-24 11:52:49 +02:00
Delucse a505fa7ad8 add grid 2020-07-24 11:07:20 +02:00
Delucse 7de0ffdebd trashcan, zoom-control and media 2020-07-24 11:02:07 +02:00
Mario eca3bf16a1 add io blocks 2020-07-23 16:04:00 +02:00
Delucse 168c5fb575 removing workspace from Redux 2020-07-23 15:55:54 +02:00
Delucse c2405de04a adaptation of the functionalities to Blockly package 2020-07-23 15:42:01 +02:00
DelucseandGitHub d1d7a447bc Merge pull request #1 from sensebox/add-arduino-generator
add arduino code generator
2020-07-23 12:05:54 +02:00
277 changed files with 73624 additions and 6627 deletions
+6
View File
@@ -0,0 +1,6 @@
REACT_APP_COMPILER_URL=https://compiler.sensebox.de
REACT_APP_BOARD=sensebox-mcu
REACT_APP_BLOCKLY_API=https://api.blockly.sensebox.de
# in days
REACT_APP_SHARE_LINK_EXPIRES=30
+1
View File
@@ -22,3 +22,4 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
package-lock.json
+49
View File
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="a119841b-a70a-4b0e-91b6-4da6cd81f169" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/src/components/Tutorial/tutorials.json" beforeDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="a119841b-a70a-4b0e-91b6-4da6cd81f169" name="Default Changelist" comment="" />
<created>1599559503505</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1599559503505</updated>
</task>
<servers />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
</project>
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+93
View File
@@ -0,0 +1,93 @@
# Blockly 2020
(aktuelles Preview unter: https://deploy-preview-37--blockly-react.netlify.app/)
In den letzten Wochen haben wir eine komplett neue Lern- und Programmierumgebung für die senseBox geschaffen. Die Basis bildet hierbei weiterhin Google Blockly und das Frontend wird über React realisiert. Fast alle Blöcke wurden bereits aus der alten Version in die neue Version migriert.
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_880bb55f28e0dbb0bb9c2160d8e50594.png)
## Blockly Core
Nachdem die bisherige Version, die unter [blockly.sensebox.de](https://blockly.sensebox.de) verfügbar ist, auf einen Google Blockly Core von 2016 aufbaut, wurde es Zeit ein großes Update durchzuführen. Durch den neuen Blockly Core lassen sich auch andere Renderer der Blöcke verwenden. In den Einstellungen kannst du zwischen den zwei Renderern Geras und Zelos auswählen. Geras ist der klassische Blockly Renderer während Zelos vor allem für Touchoberfläche optimiert worden ist.
### Typed Variablen
Neue Variablen werden nun direkt mit einem bestimmten Datentyp angelegt. Ein einfacher Check überprüft ob der zurückgegeben Typ eines Blockes mit dem der Variablen kompatibel ist.
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_0d505fc2472178182995732af226e736.png)
### Funktionen (funktioniert aktuell nicht!)
Funktionen mit Rückgabe Wert und Eingabeparametern können angelegt werden. Durch die Verwendung von Funktionen lassen sich auch komplexere Programme übersichtlicher darstellen und bearbeiten. Beim Anlegen einer Funktion kann über das Zahnrad weitere Eingabeparameter hinzuefügt werden.
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_bd9544b118a1dbe83d149c00678eb39d.png)
### GPS
Der Code für das GPS Modul wurde neu aufgebaut und ermöglicht es deutlich schneller einen GPS Fix zu bekommen. Zusätzlich lassen sich bald! die Koordinaten in zwei verschiedenen Formaten zurückgebenlassen. Zum einen als Kommazahl zum anderen als Zahl ohne nachkommastellen
### MQTT
Zwei einfache Blöcke ermöglichen es nun die Daten über MQTT an einen Broker zu versenden. Zwei Broker sind bereits "vorprogrammiert" (Adafruit IO und DIOTY). Natürlich können auch eigene Broker verwendet werden. Falls ihr gute freie Broker kennt, die wir hinzufügen sollten meldet euch einfach bei uns.
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_a9df4b0b9b1e6f39f09cf3b1743caad2.png)
### TTN Mapper
Bisher war es möglich einen "kleinen" TTN Mapper zu bauen, der die Daten als Cayenne Payload versendet hat. Es gibt nun einen Block der es direkt ermöglicht einen vollständigen TTN Mapper zu Programmieren, der die Daten auch auf [TTNMapper](https://ttnmapper.org/) veröffentlichen kann.
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_b59691f2ebcf04d8b67a5f4e7fbe70b6.png)
## Fronted
In der Oberfläche gibt es einige Neuigkeiten. Ziel ist es Blockly für die senseBox zu einer vollständigen Lern- und Programmierumgebung weiterzuentwickeln.
Die Codeanzeige ist standardmäßig ausgeblendet kann aber einfach durch eine Klick auf das `</>` Icon hinzugefügt werden.
### Login mit openSenseMap/senseBox Account
Im Menü unter Login könnt ihr euch mit eurem openSenseMap Account anmelden. Sobald ihr angemeldet seid habt ihr die Möglichkeit Projekte online zu speichern.
Sobald der Login mit dem openSenseMap Account erfolgreich war lassen sich die bereits registrierten senseBox unter Account einsehen.
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_c3965edc99021339a30b8d6704471e50.png)
Im Block zum senden an die openSenseMap müssen dann auch keine IDs mehr ausgewählt werden sondern die registrierten senseBox können einfach aus dem Dropdown Menü ausgewählt werden.
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_57284cea57bfa5df3d55fe456f9d7cfa.png)
### Speichern von Projekten
Nach dem Login über den openSenseMap Account lassen sich Projekte online speichern und wieder abrufen
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_148146b1206fde184afff6edce26b515.png)
### Tutorials
Es gibt jetzt Tutorials! Eine reihe von verschiedenen Tutorials zeigt dir die ersten Schritte in der Programmierung mit Blockly. (Inhalte werden noch ausgebaut)
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_db0e64df48d4c34a9540ffb089e95769.png)
### Gallery
In der Gallery finden sich Beispiele mit verschiedenen Programmen. Die Beispiele können direkt in Blockly geöffnet werden, um Änderungen vorzunehmen oder das Programm direkt auf deine senseBox zu übertragen.
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_c61e1fa98f9d840507a8a53b00605484.png)
### Teilen von Programmen
Über den Share Button kann ein Link zum Teilen der aktuellen Blöcke erstellt werden. Wann immer du dein Projekt mit anderen Teilen willst musst du nicht mehr eine XML Datei erstellen und verschicken sondern kannst einen Link erstellen, der direkt zu deinem Programm führt. Beachte, dass vor dem Teilen von Blöcken sämtliche sensiblen Daten, wie zum Beispiel Passwörter, Netzwerknamen, Lora oder openSenseMap Keys entfernt werden sollten. Die Links zum teilen von Programmen laufen nach 30 Tagen ab.
![](https://radosgw.public.os.wwu.de/pad/uploads/upload_a8dba6720fe2fb39cadf129d9bb04a62.png)
## Fehler
Falls ihr Fehler findet legt bitte ein Issue in folgendem Repository an: https://github.com/sensebox/React-Ardublockly/issues
+18 -58
View File
@@ -1,68 +1,28 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
<img src="/src/components/sensebox_logo.svg?raw=true" height="128" alt="senseBox Logo"/>
## Available Scripts
# React Ardublockly
In the project directory, you can run:
This repository contains the source code and documentation of [sensebox-ardublockly](https://sensebox-ardublockly.netlify.app/).
### `npm start`
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).
Runs the app in the development mode.<br />
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br />
You will also see any lint errors in the console.
## Getting Started
### `npm test`
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``.
Launches the test runner in the interactive watch mode.<br />
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
2. install [Node.js v10.xx](https://nodejs.org/en/) on your local machine
### `npm run build`
3. open shell and navigate inside folder ``React-Ardublockly``
* run ``npm install``
* run ``npm start``
4. open [localhost:3000](http://localhost:3000)
Builds the app for production to the `build` folder.<br />
It correctly bundles React in production mode and optimizes the build for the best performance.
## Troubleshoot
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/).
The build is minified and the filenames include the hashes.<br />
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
### Analyzing the Bundle Size
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
### Making a Progressive Web App
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
### Advanced Configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
### Deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
### `npm run build` fails to minify
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
## Demo
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/)
* [Tutorial Overview](https://sensebox-ardublockly.netlify.app/tutorial)
* [Tutorial-Builder](https://sensebox-ardublockly.netlify.app/tutorial/builder)
+34931 -4237
View File
File diff suppressed because it is too large Load Diff
+26 -6
View File
@@ -3,24 +3,44 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@blockly/block-plus-minus": "^2.0.10",
"@blockly/field-slider": "^2.1.1",
"@blockly/plugin-scroll-options": "^1.0.2",
"@blockly/plugin-typed-variable-modal": "^3.1.26",
"@blockly/zoom-to-fit": "^2.0.7",
"@fortawesome/fontawesome-svg-core": "^1.2.30",
"@fortawesome/free-solid-svg-icons": "^5.14.0",
"@fortawesome/react-fontawesome": "^0.1.11",
"@material-ui/core": "^4.11.0",
"@sentry/react": "^6.0.0",
"@sentry/tracing": "^6.0.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"blockly": "^3.20200625.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-redux": "^7.2.0",
"axios": "^0.21.0",
"blockly": "^6.20210701.0",
"diff-js-xml": "^1.0.6",
"file-saver": "^2.0.2",
"mnemonic-id": "^3.2.7",
"moment": "^2.28.0",
"prismjs": "^1.24.0",
"react": "^17.0.2",
"react-cookie-consent": "^5.2.0",
"react-dom": "^17.0.2",
"react-markdown": "^5.0.2",
"react-mde": "^11.5.0",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"react-scripts": "^4.0.3",
"reactour": "^1.18.0",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0"
"redux-thunk": "^2.3.0",
"styled-components": "^4.4.1",
"uuid": "^8.3.1"
},
"scripts": {
"start": "react-scripts start",
"dev": "set \"REACT_APP_BLOCKLY_API=http://localhost:8080\" && npm start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
+1
View File
@@ -0,0 +1 @@
/* /index.html 200
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+10 -7
View File
@@ -2,13 +2,9 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="icon" href="%PUBLIC_URL%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<meta name="theme-color" content="#4EAF47" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
@@ -24,10 +20,17 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>senseBox Blockly</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<!-- Matomo Image Tracker-->
<img
src="https://piwik.sensebox.kaufen/matomo.php?idsite=9&amp;rec=1"
style="border: 0; display: none"
alt=""
/>
<!-- End Matomo -->
<div id="root"></div>
<!--
This HTML file is a template.
+4 -4
View File
@@ -3,9 +3,9 @@
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"src": "favicon.png",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
"type": "image/png"
},
{
"src": "logo192.png",
@@ -20,6 +20,6 @@
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
"theme_color": "#4EAF47",
"background_color": "#4EAF47"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="12.71" height="8.79" viewBox="0 0 12.71 8.79"><title>dropdown-arrow</title><g opacity="0.1"><path d="M12.71,2.44A2.41,2.41,0,0,1,12,4.16L8.08,8.08a2.45,2.45,0,0,1-3.45,0L0.72,4.16A2.42,2.42,0,0,1,0,2.44,2.48,2.48,0,0,1,.71.71C1,0.47,1.43,0,6.36,0S11.75,0.46,12,.71A2.44,2.44,0,0,1,12.71,2.44Z" fill="#231f20"/></g><path d="M6.36,7.79a1.43,1.43,0,0,1-1-.42L1.42,3.45a1.44,1.44,0,0,1,0-2c0.56-.56,9.31-0.56,9.87,0a1.44,1.44,0,0,1,0,2L7.37,7.37A1.43,1.43,0,0,1,6.36,7.79Z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+74
View File
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="96px" height="124px">
<style type="text/css">
#background {
fill: none;
}
.arrows {
fill: #000;
stroke: none;
}
.selected>.arrows {
fill: #fff;
}
.checkmark {
fill: #000;
font-family: sans-serif;
font-size: 10pt;
text-anchor: middle;
}
.trash {
fill: #888;
}
.zoom {
fill: none;
stroke: #888;
stroke-width: 2;
stroke-linecap: round;
}
.zoom>.center {
fill: #888;
stroke-width: 0;
}
</style>
<rect id="background" width="96" height="124" x="0" y="0" />
<g>
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
</g>
<g class="selected" transform="translate(0, 16)">
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
</g>
<text class="checkmark" x="55.5" y="28">&#10003;</text>
<g class="trash">
<path d="M 2,41 v 6 h 42 v -6 h -10.5 l -3,-3 h -15 l -3,3 z" />
<rect width="36" height="20" x="5" y="50" />
<rect width="36" height="42" x="5" y="50" rx="4" ry="4" />
</g>
<g class="zoom">
<circle r="11.5" cx="16" cy="108" />
<circle r="4.3" cx="16" cy="108" class="center" />
<path d="m 28,108 h3" />
<path d="m 1,108 h3" />
<path d="m 16,120 v3" />
<path d="m 16,93 v3" />
</g>
<g class="zoom">
<circle r="15" cx="48" cy="108" />
<path d="m 48,101.6 v12.8" />
<path d="m 41.6,108 h12.8" />
</g>
<g class="zoom">
<circle r="15" cx="80" cy="108" />
<path d="m 73.6,108 h12.8" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

+46 -2
View File
@@ -1,7 +1,51 @@
.wrapper {
min-height: 100vh; /* will cover the 100% of viewport */
min-height: calc(100vh - 60px); /* will cover the 100% of viewport - height of footer (padding-bottom) */
overflow: hidden;
display: block;
position: relative;
padding-bottom: 60px; /* height of your footer + 30px*/y
padding-bottom: 60px; /* height of your footer + 30px*/
}
.tutorial img{
display: flex;
align-items: center;
max-height: 40vH;
max-width: 100%;
margin: auto;
}
.news 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;
}
.overlay {
display: flex;
flex-direction: column;
align-items: center;
}
+30 -20
View File
@@ -1,41 +1,51 @@
import React from 'react';
import React, { Component } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { createBrowserHistory } from "history";
import { Provider } from 'react-redux';
import store from './store';
import { loadUser } from './actions/authActions';
import './App.css';
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import Navbar from './components/Navbar';
import Footer from './components/Footer';
import Routes from './components/Routes';
import Content from './components/Content';
const theme = createMuiTheme({
palette: {
primary: {
main: '#4EAF47',
contrastText: '#ffffff'
},
secondary: {
main: '#DDDDDD'
},
button: {
compile: '#e27136'
}
}
});
class App extends Component {
function App() {
return (
<ThemeProvider theme={theme}>
<Provider store={store}>
<Router>
<div className="wrapper">
<Navbar />
<div style={{ margin: '0 22px' }}>
<Routes />
</div>
<Footer />
</div>
</Router>
</Provider>
</ThemeProvider>
);
componentDidMount() {
store.dispatch(loadUser());
}
render() {
const customHistory = createBrowserHistory();
return (
<ThemeProvider theme={theme}>
<Provider store={store}>
<Router history={customHistory}>
<Content />
</Router>
</Provider>
</ThemeProvider>
);
}
}
export default App;
+264
View File
@@ -0,0 +1,264 @@
import {
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,
});
});
};
// 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);
}
);
};
+32
View File
@@ -0,0 +1,32 @@
import { VISIT, LANGUAGE, RENDERER, STATISTICS } from './types';
export const visitPage = () => (dispatch) => {
dispatch({
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
});
};
+32
View File
@@ -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
};
};
+204
View File
@@ -0,0 +1,204 @@
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) => {
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(''));
};
+274
View File
@@ -0,0 +1,274 @@
import {
TUTORIAL_PROGRESS,
GET_TUTORIAL,
GET_TUTORIALS,
TUTORIAL_SUCCESS,
TUTORIAL_ERROR,
TUTORIAL_CHANGE,
TUTORIAL_XML,
TUTORIAL_STEP,
} from "./types";
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;
existingTutorials(tutorials, getState().tutorial.status).then(
(status) => {
dispatch({
type: TUTORIAL_SUCCESS,
payload: status,
});
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 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) => {})
.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) => {
dispatch({
type: TUTORIAL_CHANGE,
});
};
export const tutorialCheck = (status, step) => (dispatch, getState) => {
var tutorialsStatus = getState().tutorial.status;
var id = getState().tutorial.tutorials[0]._id;
var tutorialsStatusIndex = tutorialsStatus.findIndex(
(tutorialStatus) => tutorialStatus._id === id
);
var tasksIndex = tutorialsStatus[tutorialsStatusIndex].tasks.findIndex(
(task) => task._id === step._id
);
tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex] = {
...tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex],
type: status,
};
dispatch({
type: status === "success" ? TUTORIAL_SUCCESS : TUTORIAL_ERROR,
payload: tutorialsStatus,
});
dispatch(updateStatus(tutorialsStatus));
dispatch(tutorialChange());
dispatch(returnSuccess("", "", "TUTORIAL_CHECK_SUCCESS"));
};
export const storeTutorialXml = (code) => (dispatch, getState) => {
var tutorial = getState().tutorial.tutorials[0];
if (tutorial) {
var id = tutorial._id;
var activeStep = getState().tutorial.activeStep;
var steps = tutorial.steps;
if (steps && steps[activeStep].type === "task") {
var tutorialsStatus = getState().tutorial.status;
var tutorialsStatusIndex = tutorialsStatus.findIndex(
(tutorialStatus) => tutorialStatus._id === id
);
var tasksIndex = tutorialsStatus[tutorialsStatusIndex].tasks.findIndex(
(task) => task._id === steps[activeStep]._id
);
tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex] = {
...tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex],
xml: code,
};
dispatch({
type: TUTORIAL_XML,
payload: tutorialsStatus,
});
dispatch(updateStatus(tutorialsStatus));
}
}
};
export const tutorialStep = (step) => (dispatch) => {
dispatch({
type: TUTORIAL_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);
});
+326
View File
@@ -0,0 +1,326 @@
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 data from "../data/hardware.json";
export const changeTutorialBuilder = () => (dispatch) => {
dispatch({
type: BUILDER_CHANGE,
});
};
export const jsonString = (json) => (dispatch) => {
dispatch({
type: JSON_STRING,
payload: json,
});
};
export const tutorialTitle = (title) => (dispatch) => {
dispatch({
type: BUILDER_TITLE,
payload: title,
});
dispatch(changeTutorialBuilder());
};
export const tutorialSteps = (steps) => (dispatch) => {
dispatch({
type: BUILDER_ADD_STEP,
payload: steps,
});
dispatch(changeTutorialBuilder());
};
export const tutorialId = (id) => (dispatch) => {
dispatch({
type: BUILDER_ID,
payload: id,
});
dispatch(changeTutorialBuilder());
};
export const addStep = (index) => (dispatch, getState) => {
var steps = getState().builder.steps;
var step = {
id: index + 1,
type: "instruction",
headline: "",
text: "",
};
steps.splice(index, 0, step);
dispatch({
type: BUILDER_ADD_STEP,
payload: steps,
});
dispatch(addErrorStep(index));
dispatch(changeTutorialBuilder());
};
export const addErrorStep = (index) => (dispatch, getState) => {
var error = getState().builder.error;
error.steps.splice(index, 0, {});
dispatch({
type: BUILDER_ERROR,
payload: error,
});
};
export const removeStep = (index) => (dispatch, getState) => {
var steps = getState().builder.steps;
steps.splice(index, 1);
dispatch({
type: BUILDER_DELETE_STEP,
payload: steps,
});
dispatch(removeErrorStep(index));
dispatch(changeTutorialBuilder());
};
export const removeErrorStep = (index) => (dispatch, getState) => {
var error = getState().builder.error;
error.steps.splice(index, 1);
dispatch({
type: BUILDER_ERROR,
payload: error,
});
};
export const changeContent =
(content, index, property1, property2) => (dispatch, getState) => {
var steps = getState().builder.steps;
var step = steps[index];
if (property2) {
if (step[property1] && step[property1][property2]) {
step[property1][property2] = content;
} else {
step[property1] = { [property2]: content };
}
} else {
step[property1] = content;
}
dispatch({
type: BUILDER_CHANGE_STEP,
payload: steps,
});
dispatch(changeTutorialBuilder());
};
export const deleteProperty =
(index, property1, property2) => (dispatch, getState) => {
var steps = getState().builder.steps;
var step = steps[index];
if (property2) {
if (step[property1] && step[property1][property2]) {
delete step[property1][property2];
}
} else {
delete step[property1];
}
dispatch({
type: BUILDER_DELETE_PROPERTY,
payload: steps,
});
dispatch(changeTutorialBuilder());
};
export const changeStepIndex = (fromIndex, toIndex) => (dispatch, getState) => {
var steps = getState().builder.steps;
var step = steps[fromIndex];
steps.splice(fromIndex, 1);
steps.splice(toIndex, 0, step);
dispatch({
type: BUILDER_CHANGE_ORDER,
payload: steps,
});
dispatch(changeErrorStepIndex(fromIndex, toIndex));
dispatch(changeTutorialBuilder());
};
export const changeErrorStepIndex =
(fromIndex, toIndex) => (dispatch, getState) => {
var error = getState().builder.error;
var errorStep = error.steps[fromIndex];
error.steps.splice(fromIndex, 1);
error.steps.splice(toIndex, 0, errorStep);
dispatch({
type: BUILDER_ERROR,
payload: error,
});
};
export const setError = (index, property) => (dispatch, getState) => {
var error = getState().builder.error;
if (index !== undefined) {
error.steps[index][property] = true;
} else {
error[property] = true;
}
dispatch({
type: BUILDER_ERROR,
payload: error,
});
dispatch(changeTutorialBuilder());
};
export const deleteError = (index, property) => (dispatch, getState) => {
var error = getState().builder.error;
if (index !== undefined) {
delete error.steps[index][property];
} else {
delete error[property];
}
dispatch({
type: BUILDER_ERROR,
payload: error,
});
dispatch(changeTutorialBuilder());
};
export const setSubmitError = () => (dispatch, getState) => {
var builder = getState().builder;
// if(builder.id === undefined || builder.id === ''){
// dispatch(setError(undefined, 'id'));
// }
if (builder.title === "") {
dispatch(setError(undefined, "title"));
}
if (builder.title === null) {
dispatch(setError(undefined, "title"));
}
var type = builder.steps.map((step, i) => {
// media and xml are directly checked for errors in their components and
// therefore do not have to be checked again
step.id = i + 1;
if (i === 0) {
if (step.requirements && step.requirements.length > 0) {
var requirements = step.requirements.filter((requirement) =>
/^[0-9a-fA-F]{24}$/.test(requirement)
);
if (requirements.length < step.requirements.length) {
dispatch(changeContent(requirements, i, "requirements"));
}
}
if (step.hardware === undefined || step.hardware.length < 1) {
dispatch(setError(i, "hardware"));
} else {
var hardwareIds = data.map((hardware) => hardware.id);
var hardware = step.hardware.filter((hardware) =>
hardwareIds.includes(hardware)
);
if (hardware.length < step.hardware.length) {
dispatch(changeContent(hardware, i, "hardware"));
}
}
}
if (step.headline === undefined || step.headline === "") {
dispatch(setError(i, "headline"));
}
if (step.text === undefined || step.text === "") {
dispatch(setError(i, "text"));
}
return step.type;
});
if (
!(
type.filter((item) => item === "task").length > 0 &&
type.filter((item) => item === "instruction").length > 0
)
) {
dispatch(setError(undefined, "type"));
}
};
export const checkError = () => (dispatch, getState) => {
dispatch(setSubmitError());
var error = getState().builder.error;
if (error.id || error.title || error.type) {
return true;
}
for (var i = 0; i < error.steps.length; i++) {
if (Object.keys(error.steps[i]).length > 0) {
return true;
}
}
return false;
};
export const progress = (inProgress) => (dispatch) => {
dispatch({
type: PROGRESS,
payload: inProgress,
});
};
export const resetTutorial = () => (dispatch, getState) => {
dispatch(jsonString(""));
dispatch(tutorialTitle(""));
var steps = [
{
type: "instruction",
headline: "",
text: "",
hardware: [],
requirements: [],
},
];
dispatch(tutorialSteps(steps));
dispatch({
type: BUILDER_ERROR,
payload: {
steps: [{}],
},
});
};
export const readJSON = (json) => (dispatch, getState) => {
dispatch(resetTutorial());
dispatch({
type: BUILDER_ERROR,
payload: {
steps: json.steps.map(() => {
return {};
}),
},
});
// accept only valid attributes
var steps = json.steps.map((step, i) => {
var object = {
_id: step._id,
type: step.type,
headline: step.headline,
text: step.text,
};
if (i === 0) {
object.hardware = step.hardware;
object.requirements = step.requirements;
}
if (step.xml) {
object.xml = step.xml;
}
if (step.media && step.type === "instruction") {
object.media = {};
if (step.media.picture) {
object.media.picture = step.media.picture;
} else if (step.media.youtube) {
object.media.youtube = step.media.youtube;
}
}
return object;
});
dispatch(tutorialTitle(json.title));
dispatch(tutorialSteps(steps));
dispatch(setSubmitError());
dispatch(progress(false));
};
+59 -5
View File
@@ -1,5 +1,59 @@
export const NEW_WORKSPACE = 'NEW_WORKSPACE';
export const CREATE_BLOCK = 'CREATE_BLOCK';
export const CHANGE_BLOCK = 'CHANGE_BLOCK';
export const DELETE_BLOCK = 'DELETE_BLOCK';
export const CLEAR_STATS = 'CLEAR_STATS';
// 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 NEW_CODE = "NEW_CODE";
export const CHANGE_WORKSPACE = "CHANGE_WORKSPACE";
export const CREATE_BLOCK = "CREATE_BLOCK";
export const MOVE_BLOCK = "MOVE_BLOCK";
export const CHANGE_BLOCK = "CHANGE_BLOCK";
export const DELETE_BLOCK = "DELETE_BLOCK";
export const CLEAR_STATS = "CLEAR_STATS";
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_ERROR = "TUTORIAL_ERROR";
export const TUTORIAL_CHANGE = "TUTORIAL_CHANGE";
export const TUTORIAL_XML = "TUTORIAL_XML";
export const TUTORIAL_ID = "TUTORIAL_ID";
export const TUTORIAL_STEP = "TUTORIAL_STEP";
export const JSON_STRING = "JSON_STRING";
export const BUILDER_CHANGE = "BUILDER_CHANGE";
export const BUILDER_TITLE = "BUILDER_TITLE";
export const BUILDER_ID = "BUILDER_ID";
export const BUILDER_ADD_STEP = "BUILDER_ADD_STEP";
export const BUILDER_DELETE_STEP = "BUILDER_DELETE_STEP";
export const BUILDER_CHANGE_STEP = "BUILDER_CHANGE_STEP";
export const BUILDER_CHANGE_ORDER = "BUILDER_CHANGE_ORDER";
export const BUILDER_DELETE_PROPERTY = "BUILDER_DELETE_PROPERTY";
export const BUILDER_ERROR = "BUILDER_ERROR";
export const PROGRESS = "PROGRESS";
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";
+70 -32
View File
@@ -1,43 +1,81 @@
import { NEW_WORKSPACE, CREATE_BLOCK, CHANGE_BLOCK, DELETE_BLOCK, CLEAR_STATS } from './types';
import { NEW_CODE, CHANGE_WORKSPACE, CREATE_BLOCK, MOVE_BLOCK, CHANGE_BLOCK, DELETE_BLOCK, CLEAR_STATS, NAME } from './types';
import * as Blockly from 'blockly/core';
import { storeTutorialXml } from './tutorialActions';
export const workspaceChange = () => (dispatch) => {
dispatch({
type: CHANGE_WORKSPACE
});
};
export const onChangeCode = () => (dispatch, getState) => {
const workspace = Blockly.getMainWorkspace();
var code = getState().workspace.code;
code.arduino = Blockly.Arduino.workspaceToCode(workspace);
var xmlDom = Blockly.Xml.workspaceToDom(workspace);
code.xml = Blockly.Xml.domToPrettyText(xmlDom);
var selectedBlock = Blockly.selected
if (selectedBlock !== null) {
code.helpurl = selectedBlock.helpUrl
code.tooltip = selectedBlock.tooltip
} else if (selectedBlock === null) {
code.tooltip = Blockly.Msg.tooltip_hint
code.helpurl = ''
}
dispatch({
type: NEW_CODE,
payload: code
});
return code;
};
export const onChangeWorkspace = (event) => (dispatch, getState) => {
var oldWorkspace = getState().workspace.new; // stored 'new workspace' is from now on old
var newWorkspace = window.Ardublockly.workspace;
dispatch(workspaceChange());
var code = dispatch(onChangeCode());
dispatch(storeTutorialXml(code.xml));
var stats = getState().workspace.stats;
if (event.type === Blockly.Events.BLOCK_CREATE) {
stats.create += event.ids.length;
dispatch({
type: NEW_WORKSPACE,
payload: {new: newWorkspace, old: oldWorkspace}
type: CREATE_BLOCK,
payload: stats
});
var stats = getState().workspace.stats;
if (event.type === window.Blockly.Events.CREATE){
stats.create += event.ids.length;
}
else if (event.type === Blockly.Events.BLOCK_MOVE) {
stats.move += 1;
dispatch({
type: MOVE_BLOCK,
payload: stats
});
}
else if (event.type === Blockly.Events.BLOCK_CHANGE) {
stats.change += 1;
dispatch({
type: CHANGE_BLOCK,
payload: stats
});
}
else if (event.type === Blockly.Events.BLOCK_DELETE) {
if (stats.create > 0) {
stats.delete += event.ids.length;
dispatch({
type: CREATE_BLOCK,
type: DELETE_BLOCK,
payload: stats
});
}
else if (event.type === window.Blockly.Events.CHANGE){
stats.change += 1;
dispatch({
type: CHANGE_BLOCK,
payload: stats
});
}
else if (event.type === window.Blockly.Events.DELETE){
if(stats.create > 0){
stats.delete += event.ids.length;
dispatch({
type: DELETE_BLOCK,
payload: stats
});
}
}
}
};
export const clearStats = () => (dispatch) => {
var stats = {
create: 0,
create: -1, // initialXML is created automatically, Block is not part of the statistics
change: 0,
delete: 0
delete: 0,
move: -1 // initialXML is moved automatically, Block is not part of the statistics
};
dispatch({
type: CLEAR_STATS,
@@ -45,9 +83,9 @@ export const clearStats = () => (dispatch) => {
});
};
export const setWorkspace = (workspace) => (dispatch, getState) => {
export const workspaceName = (name) => (dispatch) => {
dispatch({
type: NEW_WORKSPACE,
payload: {new: workspace, old: getState().workspace.new}
});
};
type: NAME,
payload: name
})
}
+34
View File
@@ -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);
@@ -1,6 +0,0 @@
#blocklyDiv {
height: 90vH;
width: 50%;
position: absolute;
bottom: 0;
}
+60 -41
View File
@@ -21,55 +21,74 @@
* @author samelh@google.com (Sam El-Husseini)
*/
import React from 'react';
import './BlocklyComponent.css';
import React from "react";
import Blockly from 'blockly/core';
//import locale from 'blockly/msg/en';
import 'blockly/blocks';
import Blockly from "blockly/core";
import "blockly/blocks";
import Toolbox from "./toolbox/Toolbox";
//Blockly.setLocale(locale);
import { Card } from "@material-ui/core";
import {
ScrollOptions,
ScrollBlockDragger,
ScrollMetricsManager,
} from "@blockly/plugin-scroll-options";
class BlocklyComponent extends React.Component {
constructor(props) {
super(props);
this.blocklyDiv = React.createRef();
this.toolbox = React.createRef();
constructor(props) {
super(props);
this.blocklyDiv = React.createRef();
this.toolbox = React.createRef();
this.state = { workspace: undefined };
}
componentDidMount() {
const { initialXml, children, ...rest } = this.props;
this.primaryWorkspace = Blockly.inject(this.blocklyDiv.current, {
toolbox: this.toolbox.current,
plugins: {
// These are both required.
blockDragger: ScrollBlockDragger,
metricsManager: ScrollMetricsManager,
},
...rest,
});
// Initialize plugin.
this.setState({ workspace: this.primaryWorkspace });
const plugin = new ScrollOptions(this.workspace);
plugin.init({ enableWheelScroll: true, enableEdgeScroll: false });
if (initialXml) {
Blockly.Xml.domToWorkspace(
Blockly.Xml.textToDom(initialXml),
this.primaryWorkspace
);
}
}
componentDidMount() {
const { initialXml, children, ...rest } = this.props;
this.primaryWorkspace = Blockly.inject(
this.blocklyDiv.current,
{
toolbox: this.toolbox.current,
...rest
},
);
get workspace() {
return this.primaryWorkspace;
}
if (initialXml) {
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(initialXml), this.primaryWorkspace);
}
}
setXml(xml) {
Blockly.Xml.domToWorkspace(
Blockly.Xml.textToDom(xml),
this.primaryWorkspace
);
}
get workspace() {
return this.primaryWorkspace;
}
setXml(xml) {
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), this.primaryWorkspace);
}
render() {
const { children } = this.props;
return <React.Fragment>
<div ref={this.blocklyDiv} id="blocklyDiv" />
<xml xmlns="https://developers.google.com/blockly/xml" is="blockly" style={{ display: 'none' }} ref={this.toolbox}>
{children}
</xml>
</React.Fragment>;
}
render() {
return (
<React.Fragment>
<Card
ref={this.blocklyDiv}
id="blocklyDiv"
style={this.props.style ? this.props.style : {}}
/>
<Toolbox toolbox={this.toolbox} workspace={this.state.workspace} />
</React.Fragment>
);
}
}
export default BlocklyComponent;
+74
View File
@@ -0,0 +1,74 @@
import React, { Component } from 'react';
import * as Blockly from 'blockly/core';
class BlocklySvg extends Component {
constructor(props) {
super(props);
this.state = {
svg: ''
};
}
componentDidMount() {
this.getSvg();
}
componentDidUpdate(props) {
if(props.initialXml !== this.props.initialXml){
this.getSvg();
}
}
getSvg = () => {
const workspace = Blockly.getMainWorkspace();
workspace.clear();
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(this.props.initialXml), workspace);
var canvas = workspace.svgBlockCanvas_.cloneNode(true);
if (canvas.children[0] !== undefined) {
canvas.removeAttribute("transform");
// does not work in react
// var cssContent = Blockly.Css.CONTENT.join('');
var cssContent = '';
for (var i = 0; i < document.getElementsByTagName('style').length; i++) {
if(/^blockly.*$/.test(document.getElementsByTagName('style')[i].id)){
cssContent += document.getElementsByTagName('style')[i].firstChild.data.replace(/\..* \./g, '.');
}
}
// ensure that fill-opacity is 1, because there cannot be a replacing
// https://github.com/google/blockly/pull/3431/files#diff-00254795773903d3c0430915a68c9521R328
cssContent += `.blocklyPath {
fill-opacity: 1;
}
.blocklyPathDark {
display: flex;
}
.blocklyPathLight {
display: flex;
} `;
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 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"
width="${bbox.width}" height="${bbox.height}" viewBox="${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}">
${css}">${content}</svg>`;
this.setState({svg: xml});
}
}
render() {
return (
<div
style={{display: 'inline-flex', justifyContent: 'center', transform: 'scale(0.8) translate(0, calc(100% * -0.2 / 2))'}}
dangerouslySetInnerHTML={{ __html: this.state.svg }}
/>
);
};
}
export default BlocklySvg;
+136
View File
@@ -0,0 +1,136 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { onChangeWorkspace, clearStats } from "../../actions/workspaceActions";
import BlocklyComponent from "./BlocklyComponent";
import BlocklySvg from "./BlocklySvg";
import * as Blockly from "blockly/core";
import "./blocks/index";
import "./generator/index";
import { ZoomToFitControl } from "@blockly/zoom-to-fit";
import { initialXml } from "./initialXml.js";
class BlocklyWindow extends Component {
constructor(props) {
super(props);
this.simpleWorkspace = React.createRef();
}
componentDidMount() {
const workspace = Blockly.getMainWorkspace();
if (!this.props.readOnly) {
this.props.onChangeWorkspace({});
this.props.clearStats();
workspace.addChangeListener((event) => {
this.props.onChangeWorkspace(event);
// switch on that a block is displayed disabled or not depending on whether it is correctly connected
// for SVG display, a deactivated block in the display is undesirable
if (this.props.blockDisabled) {
Blockly.Events.disableOrphans(event);
}
});
}
Blockly.svgResize(workspace);
const zoomToFit = new ZoomToFitControl(workspace);
zoomToFit.init();
}
componentDidUpdate(props) {
const workspace = Blockly.getMainWorkspace();
if (!this.props.readOnly) {
var xml = this.props.initialXml;
// if svg is true, then the update process is done in the BlocklySvg component
if (props.initialXml !== xml && !this.props.svg) {
// guarantees that the current xml-code (this.props.initialXml) is rendered
workspace.clear();
if (!xml) xml = initialXml;
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();
// workspace.updateToolbox(toolbox.toolboxDef_);
}
}
Blockly.svgResize(workspace);
}
render() {
return (
<div>
<BlocklyComponent
ref={this.simpleWorkspace}
style={this.props.svg ? { height: 0 } : this.props.blocklyCSS}
readOnly={
this.props.readOnly !== undefined ? this.props.readOnly : false
}
trashcan={
this.props.trashcan !== undefined ? this.props.trashcan : true
}
renderer={this.props.renderer}
zoom={{
// https://developers.google.com/blockly/guides/configure/web/zoom
controls:
this.props.zoomControls !== undefined
? this.props.zoomControls
: true,
wheel: false,
startScale: 1,
maxScale: 3,
minScale: 0.3,
scaleSpeed: 1.2,
}}
grid={
this.props.grid !== undefined && !this.props.grid
? {}
: {
// https://developers.google.com/blockly/guides/configure/web/grid
spacing: 20,
length: 1,
colour: "#4EAF47", // senseBox-green
snap: false,
}
}
media={"/media/blockly/"}
move={
this.props.move !== undefined && !this.props.move
? {}
: {
// https://developers.google.com/blockly/guides/configure/web/move
scrollbars: true,
drag: true,
wheel: true,
}
}
initialXml={
this.props.initialXml ? this.props.initialXml : initialXml
}
></BlocklyComponent>
{this.props.svg && this.props.initialXml ? (
<BlocklySvg initialXml={this.props.initialXml} />
) : null}
</div>
);
}
}
BlocklyWindow.propTypes = {
onChangeWorkspace: 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(mapStateToProps, { onChangeWorkspace, clearStats })(
BlocklyWindow
);
+61
View File
@@ -0,0 +1,61 @@
import Blockly from 'blockly/core';
import { selectedBoard } from '../helpers/board'
import * as Types from '../helpers/types'
import { getColour } from '../helpers/colour';
Blockly.Blocks['io_tone'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_SETTONE)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), "TONEPIN");
this.appendValueInput("FREQUENCY")
.setCheck(Types.getCompatibleTypes('int'))
.appendField(Blockly.Msg.ARD_TONEFREQ);
this.appendDummyInput()
.appendField("Hz");
this.setInputsInline(true);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setColour(getColour().audio);
this.setTooltip(Blockly.Msg.ARD_TONE_TIP);
this.setHelpUrl('https://www.arduino.cc/en/Reference/tone');
},
/**
* Called whenever anything on the workspace changes.
* It checks frequency values and sets a warning if out of range.
* @this Blockly.Block
*/
onchange: function (event) {
if (!this.workspace || event.type === Blockly.Events.MOVE ||
event.type === Blockly.Events.UI) {
return; // Block deleted or irrelevant event
}
var freq = Blockly.Arduino.valueToCode(
this, "FREQUENCY", Blockly.Arduino.ORDER_ATOMIC)
if (freq < 31 || freq > 65535) {
this.setWarningText(Blockly.Msg.ARD_TONE_WARNING, 'io_tone');
} else {
this.setWarningText(null, 'io_tone');
}
}
};
Blockly.Blocks['io_notone'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_NOTONE)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), "TONEPIN");
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setColour(getColour().audio);
this.setTooltip(Blockly.Msg.ARD_NOTONE_TIP);
this.setHelpUrl('https://www.arduino.cc/en/Reference/noTone');
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Blockly.Types.NUMBER;
}
};
+26 -4
View File
@@ -1,4 +1,26 @@
import './loops';
import './sensebox';
import './logic';
import './sensebox-sensors';
import "./loops";
import "./sensebox";
import "./logic";
import "./sensebox-sensors";
import "./sensebox-telegram";
import "./sensebox-osem";
import "./sensebox-web";
import "./sensebox-display";
import "./sensebox-lora";
import "./sensebox-led";
import "./sensebox-rtc";
import "./sensebox-ble";
import "./sensebox-sd";
import "./mqtt";
import "./text";
import "./io";
import "./audio";
import "./math";
import "./map";
import "./procedures";
import "./time";
import "./variables";
import "./lists";
import "./webserver";
import "../helpers/types";
+257
View File
@@ -0,0 +1,257 @@
/**
* @license Licensed under the Apache License, Version 2.0 (the "License"):
* http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* @fileoverview Blocks for Arduino Digital and Analogue input and output
* functions. The Arduino function syntax can be found at
* http://arduino.cc/en/Reference/HomePage
*
* TODO: maybe change this to a "PIN" BlocklyType
*/
import Blockly from 'blockly/core';
import { selectedBoard } from '../helpers/board'
import * as Types from '../helpers/types'
Blockly.Blocks['io_digitalwrite'] = {
/**
* Block for creating a 'set pin' to a state.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/DigitalWrite');
this.setColour(250);
this.appendValueInput('STATE')
.appendField(Blockly.Msg.ARD_DIGITALWRITE)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), 'PIN')
.appendField(Blockly.Msg.ARD_WRITE_TO)
.setCheck(Types.BOOLEAN.checkList);
this.setInputsInline(false);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_DIGITALWRITE_TIP);
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(
this, 'PIN', 'digitalPins');
}
};
Blockly.Blocks['io_digitalread'] = {
/**
* Block for creating a 'read pin'.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/DigitalRead');
this.setColour(250);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_DIGITALREAD)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), 'PIN');
this.setOutput(true, 'boolean');
this.setTooltip(Blockly.Msg.ARD_DIGITALREAD_TIP);
},
/** @return {!string} The type of return value for the block, an integer. */
getBlockType: function () {
return Types.BOOLEAN;
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(
this, 'PIN', 'digitalPins');
}
};
Blockly.Blocks['io_builtin_led'] = {
/**
* Block for setting built-in LED to a state.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/DigitalWrite');
this.setColour(250);
this.appendValueInput('STATE')
.appendField(Blockly.Msg.ARD_BUILTIN_LED)
.appendField(new Blockly.FieldDropdown(
selectedBoard().builtinLed), 'BUILT_IN_LED')
.appendField(Blockly.Msg.ARD_WRITE_TO)
.setCheck(Types.BOOLEAN.compatibleTypes);
this.setInputsInline(false);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_BUILTIN_LED_TIP);
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(
this, 'BUILT_IN_LED', 'builtinLed');
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Types.BOOLEAN;
},
};
Blockly.Blocks['io_analogwrite'] = {
/**
* Block for creating a 'set pin' to an analogue value.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/AnalogWrite');
this.setColour(250);
this.appendValueInput('NUM')
.appendField(Blockly.Msg.ARD_ANALOGWRITE)
.appendField(new Blockly.FieldDropdown(
selectedBoard().pwmPins), 'PIN')
.appendField(Blockly.Msg.ARD_WRITE_TO)
.setCheck(Types.NUMBER.compatibleTypes);
this.setInputsInline(false);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_ANALOGWRITE_TIP);
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(this, 'PIN', 'pwmPins');
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER;
},
};
Blockly.Blocks['io_analogread'] = {
/**
* Block for reading an analogue input.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/AnalogRead');
this.setColour(250);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_ANALOGREAD)
.appendField(new Blockly.FieldDropdown(
selectedBoard().analogPins), 'PIN');
this.setOutput(true, Types.NUMBER.typeId);
this.setTooltip(Blockly.Msg.ARD_ANALOGREAD_TIP);
},
/** @return {!string} The type of return value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER.typeId;
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(this, 'PIN', 'analogPins');
}
};
Blockly.Blocks['io_highlow'] = {
/**
* Block for creating a pin state.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Constants');
this.setColour(250);
this.appendDummyInput()
.appendField(
new Blockly.FieldDropdown([[Blockly.Msg.ARD_HIGH, 'HIGH'], [Blockly.Msg.ARD_LOW, 'LOW']]),
'STATE');
this.setOutput(true, Types.BOOLEAN.typeId);
this.setTooltip(Blockly.Msg.ARD_HIGHLOW_TIP);
},
/** @return {!string} The type of return value for the block, an integer. */
getBlockType: function () {
return Types.BOOLEAN;
}
};
Blockly.Blocks['io_pulsein'] = {
/**
* Block for measuring the duration of a pulse in an input pin.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"type": "math_foo",
"message0": Blockly.Msg.ARD_PULSE_READ,
"args0": [{
"type": "input_value",
"name": "PULSETYPE",
"check": Types.BOOLEAN.compatibleTypes
}, {
"type": "field_dropdown",
"name": "PULSEPIN",
"options": selectedBoard().digitalPins,
}
],
"output": Types.NUMBER.typeId,
"inputsInline": true,
"colour": 250,
"tooltip": Blockly.Msg.ARD_PULSE_TIP,
"helpUrl": 'https://www.arduino.cc/en/Reference/PulseIn'
});
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER.typeId;
}
};
Blockly.Blocks['io_pulsetimeout'] = {
/**
* Block for measuring (with a time-out) the duration of a pulse in an input
* pin.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"type": "math_foo",
"message0": Blockly.Msg.ARD_PULSE_READ_TIMEOUT,
"args0": [{
"type": "input_value",
"name": "PULSETYPE",
"check": Types.BOOLEAN.compatibleTypes
}, {
"type": "field_dropdown",
"name": "PULSEPIN",
"options": selectedBoard().digitalPins,
}, {
"type": "input_value",
"name": "TIMEOUT",
"check": Types.NUMBER.compatibleTypes
}
],
"output": Types.NUMBER.typeId,
"inputsInline": true,
"colour": 250,
"tooltip": Blockly.Msg.ARD_PULSETIMEOUT_TIP,
"helpUrl": 'https://www.arduino.cc/en/Reference/PulseIn'
});
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER.typeId;
}
};
+59
View File
@@ -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);
},
};
+630 -43
View File
@@ -1,61 +1,648 @@
import { defineBlocksWithJsonArray } from 'blockly';
import Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types';
import { getCompatibleTypes } from '../helpers/types';
defineBlocksWithJsonArray([
// If/else block that does not use a mutator.
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;
var inputDo;
while (clauseBlock) {
switch (clauseBlock.type) {
case 'controls_if_elseif':
var inputIf = this.getInput('IF' + i);
inputDo = this.getInput('DO' + i);
clauseBlock.valueConnection_ =
inputIf && inputIf.connection.targetConnection;
clauseBlock.statementConnection_ =
inputDo && inputDo.connection.targetConnection;
i++;
break;
case 'controls_if_else':
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 j = 1;
while (this.getInput('IF' + j)) {
this.removeInput('IF' + j);
this.removeInput('DO' + j);
j++;
}
// 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
// Block for boolean data type: true and false.
{
type: 'control_if',
message0: '%{BKY_CONTROLS_IF_MSG_IF} %1',
args0: [
"type": "logic_boolean",
"message0": "%1",
"args0": [
{
type: 'input_value',
name: 'IF0',
check: 'Boolean'
"type": "field_dropdown",
"name": "BOOL",
"options": [
["%{BKY_LOGIC_BOOLEAN_TRUE}", "TRUE"],
["%{BKY_LOGIC_BOOLEAN_FALSE}", "FALSE"]
]
}
],
message1: '%{BKY_CONTROLS_IF_MSG_THEN} %1',
args1: [
{
type: 'input_statement',
name: 'DO0'
}
],
previousStatement: null,
nextStatement: null,
colour: '#b063c5',
tooltip: '%{BKYCONTROLS_IF_TOOLTIP_2}',
helpUrl: '%{BKY_CONTROLS_IF_HELPURL}',
extensions: ['controls_if_tooltip']
"output": Types.BOOLEAN.typeName,
"style": "logic_blocks",
"tooltip": "%{BKY_LOGIC_BOOLEAN_TOOLTIP}",
"helpUrl": "%{BKY_LOGIC_BOOLEAN_HELPURL}"
},
{
type: 'controls_ifelse',
message0: '%{BKY_CONTROLS_IF_MSG_IF} %1',
args0: [
"type": "controls_ifelse",
"message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
"args0": [
{
type: 'input_value',
name: 'IF0',
check: 'Boolean'
"type": "input_value",
"name": "IF0",
"check": Types.getCompatibleTypes('boolean')
}
],
message1: '%{BKY_CONTROLS_IF_MSG_THEN} %1',
args1: [
"message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1",
"args1": [
{
type: 'input_statement',
name: 'DO0'
"type": "input_statement",
"name": "DO0"
}
],
message2: '%{BKY_CONTROLS_IF_MSG_ELSE} %1',
args2: [
"message2": "%{BKY_CONTROLS_IF_MSG_ELSE} %1",
"args2": [
{
type: 'input_statement',
name: 'ELSE'
"type": "input_statement",
"name": "ELSE"
}
],
previousStatement: null,
nextStatement: null,
colour: '#b063c5',
tooltip: '%{BKYCONTROLS_IF_TOOLTIP_2}',
helpUrl: '%{BKY_CONTROLS_IF_HELPURL}',
extensions: ['controls_if_tooltip']
"previousStatement": null,
"nextStatement": null,
"style": "logic_blocks",
"tooltip": "%{BKYCONTROLS_IF_TOOLTIP_2}",
"helpUrl": "%{BKY_CONTROLS_IF_HELPURL}",
"extensions": ["controls_if_tooltip"]
},
// Block for comparison operator.
{
"type": "logic_compare",
"message0": "%1 %2 %3",
"args0": [
{
"type": "input_value",
"name": "A"
},
{
"type": "field_dropdown",
"name": "OP",
"options": [
["=", "EQ"],
["\u2260", "NEQ"],
["\u200F<", "LT"],
["\u200F\u2264", "LTE"],
["\u200F>", "GT"],
["\u200F\u2265", "GTE"]
]
},
{
"type": "input_value",
"name": "B"
}
],
"inputsInline": true,
"output": Types.BOOLEAN.typeName,
"style": "logic_blocks",
"helpUrl": "%{BKY_LOGIC_COMPARE_HELPURL}",
"extensions": ["logic_compare", "logic_op_tooltip"]
},
// Block for logical operations: 'and', 'or'.
{
"type": "logic_operation",
"message0": "%1 %2 %3",
"args0": [
{
"type": "input_value",
"name": "A",
"check": Types.getCompatibleTypes('boolean')
},
{
"type": "field_dropdown",
"name": "OP",
"options": [
["%{BKY_LOGIC_OPERATION_AND}", "AND"],
["%{BKY_LOGIC_OPERATION_OR}", "OR"]
]
},
{
"type": "input_value",
"name": "B",
"check": Types.getCompatibleTypes('boolean')
}
],
"inputsInline": true,
"output": Types.BOOLEAN.typeName,
"style": "logic_blocks",
"helpUrl": "%{BKY_LOGIC_OPERATION_HELPURL}",
"extensions": ["logic_op_tooltip"]
},
// Block for negation.
{
"type": "logic_negate",
"message0": "%{BKY_LOGIC_NEGATE_TITLE}",
"args0": [
{
"type": "input_value",
"name": "BOOL",
"check": Types.getCompatibleTypes('boolean'),
}
],
"output": Types.BOOLEAN.typeName,
"style": "logic_blocks",
"tooltip": "%{BKY_LOGIC_NEGATE_TOOLTIP}",
"helpUrl": "%{BKY_LOGIC_NEGATE_HELPURL}"
},
// Block for null data type.
{
"type": "logic_null",
"message0": "%{BKY_LOGIC_NULL}",
"output": null,
"style": "logic_blocks",
"tooltip": "%{BKY_LOGIC_NULL_TOOLTIP}",
"helpUrl": "%{BKY_LOGIC_NULL_HELPURL}"
},
// Block for ternary operator.
{
"type": "logic_ternary",
"message0": "%{BKY_LOGIC_TERNARY_CONDITION} %1",
"args0": [
{
"type": "input_value",
"name": "IF",
"check": Types.getCompatibleTypes('boolean'),
}
],
"message1": "%{BKY_LOGIC_TERNARY_IF_TRUE} %1",
"args1": [
{
"type": "input_value",
"name": "THEN",
"check": Types.getCompatibleTypes('boolean'),
}
],
"message2": "%{BKY_LOGIC_TERNARY_IF_FALSE} %1",
"args2": [
{
"type": "input_value",
"name": "ELSE",
"check": Types.getCompatibleTypes('boolean'),
}
],
"output": null,
"style": "logic_blocks",
"tooltip": "%{BKY_LOGIC_TERNARY_TOOLTIP}",
"helpUrl": "%{BKY_LOGIC_TERNARY_HELPURL}",
"extensions": ["logic_ternary"]
}
]);
]); // END JSON EXTRACT (Do not delete this comment.)
Blockly.Blocks['logic_compare'] = {
/**
* Block for comparison operator.
* @this Blockly.Block
*/
init: function () {
var OPERATORS = this.RTL ? [
['=', 'EQ'],
['\u2260', 'NEQ'],
['>', 'LT'],
['\u2265', 'LTE'],
['<', 'GT'],
['\u2264', 'GTE']
] : [
['=', 'EQ'],
['\u2260', 'NEQ'],
['<', 'LT'],
['\u2264', 'LTE'],
['>', 'GT'],
['\u2265', 'GTE']
];
this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);
this.setColour(getColour().logic);
this.setOutput(true, Types.BOOLEAN.typeName);
this.appendValueInput('A');
this.appendValueInput('B')
.appendField(new Blockly.FieldDropdown(OPERATORS), 'OP');
this.setInputsInline(true);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var op = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'EQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,
'NEQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,
'LT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,
'LTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,
'GT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,
'GTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE
};
return TOOLTIPS[op];
});
},
/**
* Called whenever anything on the workspace changes.
* Prevent mismatched types from being compared.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var blockA = this.getInputTargetBlock('A');
var blockB = this.getInputTargetBlock('B');
if (blockA === null && blockB === null) {
this.getInput('A').setCheck(null);
this.getInput('B').setCheck(null);
}
if (blockA !== null && blockB === null) {
this.getInput('A').setCheck(getCompatibleTypes(blockA.outputConnection.check_[0]));
this.getInput('B').setCheck(getCompatibleTypes(blockA.outputConnection.check_[0]));
}
if (blockB !== null && blockA === null) {
this.getInput('B').setCheck(getCompatibleTypes(blockB.outputConnection.check_[0]));
this.getInput('A').setCheck(getCompatibleTypes(blockB.outputConnection.check_[0]));
}
}
};
Blockly.Blocks['switch_case'] = {
init: function () {
this.setColour(getColour().logic);
this.setPreviousStatement(true);
this.setTooltip(Blockly.Msg.cases_tooltip);
this.setNextStatement(true);
this.appendValueInput('CONDITION')
.appendField(Blockly.Msg.cases_switch);
this.appendValueInput('CASECONDITION0')
.appendField(Blockly.Msg.cases_condition);
this.appendStatementInput('CASE0')
.appendField(Blockly.Msg.cases_do);
this.setMutator(new Blockly.Mutator(['case_incaseof', 'case_default']));
this.caseCount_ = 0;
this.defaultCount_ = 0;
},
mutationToDom: function () {
if (!this.caseCount_ && !this.defaultCount_) {
return null;
}
var container = document.createElement('mutation');
if (this.caseCount_) {
container.setAttribute('case', this.caseCount_);
}
if (this.defaultCount_) {
container.setAttribute('default', 1);
}
return container;
},
domToMutation: function (xmlElement) {
this.caseCount_ = parseInt(xmlElement.getAttribute('case'), 10);
this.defaultCount_ = parseInt(xmlElement.getAttribute('default'), 10);
for (var x = 0; x <= this.caseCount_; x++) {
this.appendValueInput('CASECONDITION' + x)
.appendField(Blockly.Msg.cases_condition);
this.appendStatementInput('CASE' + x)
.appendField(Blockly.Msg.cases_do);
}
if (this.defaultCount_) {
this.appendStatementInput('ONDEFAULT')
.appendField('default');
}
},
decompose: function (workspace) {
var containerBlock = workspace.newBlock('control_case');
containerBlock.initSvg();
var connection = containerBlock.getInput('STACK').connection;
for (var x = 1; x <= this.caseCount_; x++) {
var caseBlock = workspace.newBlock('case_incaseof');
caseBlock.initSvg();
connection.connect(caseBlock.previousConnection);
connection = caseBlock.nextConnection;
}
if (this.defaultCount_) {
var defaultBlock = Blockly.Block.obtain(workspace, 'case_default');
defaultBlock.initSvg();
connection.connect(defaultBlock.previousConnection);
}
return containerBlock;
},
compose: function (containerBlock) {
//Disconnect all input blocks and remove all inputs.
if (this.defaultCount_) {
this.removeInput('ONDEFAULT');
}
this.defaultCount_ = 0;
for (var x = this.caseCount_; x > 0; x--) {
this.removeInput('CASECONDITION' + x);
this.removeInput('CASE' + x);
}
this.caseCount_ = 0;
var caseBlock = containerBlock.getInputTargetBlock('STACK');
while (caseBlock) {
switch (caseBlock.type) {
case 'case_incaseof':
this.caseCount_++;
var caseconditionInput = this.appendValueInput('CASECONDITION' + this.caseCount_)
.appendField(Blockly.Msg.cases_condition);
var caseInput = this.appendStatementInput('CASE' + this.caseCount_)
.appendField(Blockly.Msg.cases_do);
if (caseBlock.valueConnection_) {
caseconditionInput.connection.connect(caseBlock.valueConnection_);
}
if (caseBlock.statementConnection_) {
caseInput.connection.connect(caseBlock.statementConnection_);
}
break;
case 'case_default':
this.defaultCount_++;
var defaultInput = this.appendStatementInput('ONDEFAULT')
.appendField('default');
if (caseBlock.statementConnection_) {
defaultInput.connection.connect(caseBlock.statementConnection_);
}
break;
default:
throw new Error('Unknown block type.');
}
caseBlock = caseBlock.nextConnection &&
caseBlock.nextConnection.targetBlock();
}
},
saveConnections: function (containerBlock) {
var caseBlock = containerBlock.getInputTargetBlock('STACK');
var x = 1;
while (caseBlock) {
switch (caseBlock.type) {
case 'case_incaseof':
var caseconditionInput = this.getInput('CASECONDITION' + x);
var caseInput = this.getInput('CASE' + x);
caseBlock.valueConnection_ = caseconditionInput && caseconditionInput.connection.targetConnection;
caseBlock.statementConnection_ = caseInput && caseInput.connection.targetConnection;
x++;
break;
case 'case_default':
var defaultInput = this.getInput('ONDEFAULT');
caseBlock.satementConnection_ = defaultInput && defaultInput.connection.targetConnection;
break;
default:
throw new Error('Unknown block type');
}
caseBlock = caseBlock.nextConnection &&
caseBlock.nextConnection.targetBlock();
}
}
};
Blockly.Blocks['control_case'] = {
init: function () {
this.setColour(getColour().logic);
this.appendDummyInput()
.appendField(Blockly.Msg.cases_switch);
this.appendStatementInput('STACK');
this.setTooltip('--Placeholder--');
this.contextMenu = false;
}
};
Blockly.Blocks['case_incaseof'] = {
init: function () {
this.setColour(getColour().logic);
this.appendDummyInput()
.appendField(Blockly.Msg.cases_add);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip('--Placeholder--');
this.contextMenu = false;
}
};
Blockly.Blocks['case_default'] = {
init: function () {
this.setColour(getColour().logic);
this.appendValueInput('default')
.appendField('default');
this.setPreviousStatement(true);
this.setNextStatement(false);
this.setTooltip('This function will run if there aren\'t any matching cases.');
this.contextMenu = false;
}
};
+208 -46
View File
@@ -1,51 +1,213 @@
import Blockly from 'blockly';
import { getColour } from '../helpers/colour';
import { getCompatibleTypes } from '../helpers/types'
import * as Types from '../helpers/types';
Blockly.defineBlocksWithJsonArray([
{
type: 'controls_for',
message0: 'count with %1 from %2 to %3 by adding %4',
args0: [
{
type: 'field_variable',
name: 'VAR',
variable: null,
variableTypes: ['Number'],
defaultType: 'Number',
createNewVariable: true,
showOnlyVariableAssigned: false,
},
{
type: 'input_value',
name: 'FROM',
check: 'Number',
align: 'RIGHT',
},
{
type: 'input_value',
name: 'TO',
check: 'Number',
align: 'RIGHT',
},
{
type: 'input_value',
name: 'BY',
check: 'Number',
align: 'RIGHT',
},
],
message1: '%{BKY_CONTROLS_REPEAT_INPUT_DO} %1',
args1: [
{
type: 'input_statement',
name: 'DO',
},
],
inputsInline: false,
previousStatement: null,
nextStatement: null,
helpUrl: '%{BKY_CONTROLS_FOR_HELPURL}',
extensions: ['contextMenu_newGetVariableBlock', 'controls_for_tooltip'],
Blockly.Blocks['controls_whileUntil'] = {
/**
* Block for 'do while/until' loop.
* @this Blockly.Block
*/
init: function () {
var OPERATORS =
[[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE, 'WHILE'],
[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL, 'UNTIL']];
this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL);
this.setColour(getColour().loops);
this.appendValueInput('BOOL')
.setCheck(getCompatibleTypes('boolean'))
.appendField(new Blockly.FieldDropdown(OPERATORS), 'MODE');
this.appendStatementInput('DO')
.appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO);
this.setPreviousStatement(true);
this.setNextStatement(true);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var op = thisBlock.getFieldValue('MODE');
var TOOLTIPS = {
'WHILE': Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE,
'UNTIL': Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL
};
return TOOLTIPS[op];
});
}
};
Blockly.Blocks['controls_for'] = {
/**
* Block for 'for' loop.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.CONTROLS_FOR_TITLE,
"args0": [
{
"type": "field_variable",
"name": "VAR",
"defaultType": Types.NUMBER.typeName,
"variable": null
},
{
"type": "input_value",
"name": "FROM",
"check": getCompatibleTypes('int'),
"align": "RIGHT"
},
{
"type": "input_value",
"name": "TO",
"check": getCompatibleTypes('int'),
"align": "RIGHT"
},
{
"type": "input_value",
"name": "BY",
"check": getCompatibleTypes('int'),
"align": "RIGHT"
}
],
"inputsInline": true,
"previousStatement": null,
"nextStatement": null,
"colour": getColour().loops,
"helpUrl": Blockly.Msg.CONTROLS_FOR_HELPURL
});
this.appendStatementInput('DO')
.appendField(Blockly.Msg.CONTROLS_FOR_INPUT_DO);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
return Blockly.Msg.CONTROLS_FOR_TOOLTIP.replace('%1',
thisBlock.getFieldValue('VAR'));
});
}
};
Blockly.Blocks['controls_forEach'] = {
/**
* Block for 'for each' loop.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.CONTROLS_FOREACH_TITLE,
"args0": [
{
"type": "field_variable",
"name": "VAR",
"defaultType": Types.NUMBER.typeName,
"variable": null
},
{
"type": "input_value",
"name": "LIST",
"check": getCompatibleTypes('Array')
}
],
"previousStatement": null,
"nextStatement": null,
"colour": getColour().loops,
"helpUrl": Blockly.Msg.CONTROLS_FOREACH_HELPURL
});
this.appendStatementInput('DO')
.appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_DO);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
return Blockly.Msg.CONTROLS_FOREACH_TOOLTIP.replace('%1',
thisBlock.getFieldValue('VAR'));
});
},
]);
customContextMenu: Blockly.Blocks['controls_for'].customContextMenu,
/** @returns {!string} The type of the variable used in this block */
getVarType: function (varName) {
return Blockly.Types.NUMBER;
}
};
Blockly.Blocks['controls_flow_statements'] = {
/**
* Block for flow statements: continue, break.
* @this Blockly.Block
*/
init: function () {
var OPERATORS =
[[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK, 'BREAK'],
[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE, 'CONTINUE']];
this.setHelpUrl(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL);
this.setColour(getColour().loops);
this.appendDummyInput()
.appendField(new Blockly.FieldDropdown(OPERATORS), 'FLOW');
this.setPreviousStatement(true);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var op = thisBlock.getFieldValue('FLOW');
var TOOLTIPS = {
'BREAK': Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK,
'CONTINUE': Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE
};
return TOOLTIPS[op];
});
},
/**
* Called whenever anything on the workspace changes.
* Add warning if this flow block is not nested inside a 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);
}
},
/**
* 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: ['controls_repeat', 'controls_repeat_ext', 'controls_forEach',
'controls_for', 'controls_whileUntil']
};
Blockly.Blocks['controls_repeat_ext'] = {
/**
* Block for repeat n times (external number).
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.CONTROLS_REPEAT_TITLE,
"args0": [
{
"type": "input_value",
"name": "TIMES",
"check": getCompatibleTypes('int'),
}
],
"previousStatement": null,
"nextStatement": null,
"colour": getColour().loops,
"tooltip": Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,
"helpUrl": Blockly.Msg.CONTROLS_REPEAT_HELPURL
});
this.appendStatementInput('DO')
.appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);
}
};
+50
View File
@@ -0,0 +1,50 @@
/**
* @license Licensed under the Apache License, Version 2.0 (the "License"):
* http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* @fileoverview Block for the Arduino map functionality.
* The Arduino built in functions syntax can be found at:
* http://arduino.cc/en/Reference/HomePage
*
* TODO: This block can be improved to set the new range properly.
*/
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types'
Blockly.Blocks['base_map'] = {
/**
* Block for creating a the map function.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/map');
this.setColour(getColour().math);
this.appendValueInput('NUM')
.appendField(Blockly.Msg.ARD_MAP)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('FMIN')
.appendField(Blockly.Msg.ARD_MAP_FROMMIN)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('FMAX')
.appendField(Blockly.Msg.ARD_MAP_FROMMAX)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('DMIN')
.appendField(Blockly.Msg.ARD_MAP_TOMIN)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('DMAX')
.appendField(Blockly.Msg.ARD_MAP_TOMAX)
.setCheck(Types.NUMBER.compatibleTypes);
this.setOutput(true);
this.setInputsInline(false);
this.setTooltip(Blockly.Msg.ARD_MAP_TIP);
},
/** @return {string} The type of return value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER.typeId;
}
};
+529
View File
@@ -0,0 +1,529 @@
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types'
Blockly.Blocks['math_number'] = {
/**
* Block for numeric value.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl(Blockly.Msg.MATH_NUMBER_HELPURL);
this.setColour(getColour().math);
this.appendDummyInput()
.appendField(
new Blockly.FieldTextInput(
'0', Blockly.FieldTextInput.numberValidator),
'NUM');
this.setOutput(true, Types.NUMBER.typeName);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
// Number block is trivial. Use tooltip of parent block if it exists.
this.setTooltip(function () {
var parent = thisBlock.getParent();
return (parent && parent.getInputsInline() && parent.tooltip) ||
Blockly.Msg.MATH_NUMBER_TOOLTIP;
});
}
};
Blockly.Blocks['math_arithmetic'] = {
/**
* Block for basic arithmetic operator.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1 %2 %3",
"args0": [
{
"type": "input_value",
"name": "A",
"check": Types.getCompatibleTypes('int')
},
{
"type": "field_dropdown",
"name": "OP",
"options":
[[Blockly.Msg.MATH_ADDITION_SYMBOL, 'ADD'],
[Blockly.Msg.MATH_SUBTRACTION_SYMBOL, 'MINUS'],
[Blockly.Msg.MATH_MULTIPLICATION_SYMBOL, 'MULTIPLY'],
[Blockly.Msg.MATH_DIVISION_SYMBOL, 'DIVIDE'],
[Blockly.Msg.MATH_POWER_SYMBOL, 'POWER']]
},
{
"type": "input_value",
"name": "B",
"check": Types.getCompatibleTypes('int')
}
],
"inputsInline": true,
"output": Types.NUMBER.typeName,
"colour": getColour().math,
"helpUrl": Blockly.Msg.MATH_ARITHMETIC_HELPURL
});
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var mode = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'ADD': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
'MINUS': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
'MULTIPLY': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
'DIVIDE': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
'POWER': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER
};
return TOOLTIPS[mode];
});
}
//TODO: a getBlockType based on the two input types following C++ rules
};
Blockly.Blocks['math_single'] = {
/**
* Block for advanced math operators with single operand.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1 %2",
"args0": [
{
"type": "field_dropdown",
"name": "OP",
"options": [
[Blockly.Msg.MATH_SINGLE_OP_ROOT, 'ROOT'],
[Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE, 'ABS'],
['-', 'NEG'],
['ln', 'LN'],
['log10', 'LOG10'],
['e^', 'EXP'],
['10^', 'POW10']
]
},
{
"type": "input_value",
"name": "NUM",
"check": Types.getCompatibleTypes('float')
}
],
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"helpUrl": Blockly.Msg.MATH_SINGLE_HELPURL
});
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var mode = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'ROOT': Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT,
'ABS': Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS,
'NEG': Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG,
'LN': Blockly.Msg.MATH_SINGLE_TOOLTIP_LN,
'LOG10': Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10,
'EXP': Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP,
'POW10': Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10
};
return TOOLTIPS[mode];
});
}
};
Blockly.Blocks['math_trig'] = {
/**
* Block for trigonometry operators.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1 %2",
"args0": [
{
"type": "field_dropdown",
"name": "OP",
"options": [
[Blockly.Msg.MATH_TRIG_SIN, 'SIN'],
[Blockly.Msg.MATH_TRIG_COS, 'COS'],
[Blockly.Msg.MATH_TRIG_TAN, 'TAN'],
[Blockly.Msg.MATH_TRIG_ASIN, 'ASIN'],
[Blockly.Msg.MATH_TRIG_ACOS, 'ACOS'],
[Blockly.Msg.MATH_TRIG_ATAN, 'ATAN']
]
},
{
"type": "input_value",
"name": "NUM",
"check": Types.getCompatibleTypes('float')
}
],
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"helpUrl": Blockly.Msg.MATH_TRIG_HELPURL
});
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var mode = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'SIN': Blockly.Msg.MATH_TRIG_TOOLTIP_SIN,
'COS': Blockly.Msg.MATH_TRIG_TOOLTIP_COS,
'TAN': Blockly.Msg.MATH_TRIG_TOOLTIP_TAN,
'ASIN': Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN,
'ACOS': Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS,
'ATAN': Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN
};
return TOOLTIPS[mode];
});
}
};
Blockly.Blocks['math_constant'] = {
/**
* Block for constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1",
"args0": [
{
"type": "field_dropdown",
"name": "CONSTANT",
"options": [
['\u03c0', 'PI'],
['e', 'E'],
['\u03c6', 'GOLDEN_RATIO'],
['sqrt(2)', 'SQRT2'],
['sqrt(\u00bd)', 'SQRT1_2'],
['\u221e', 'INFINITY']
]
}
],
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_CONSTANT_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_CONSTANT_HELPURL
});
}
};
Blockly.Blocks['math_number_property'] = {
/**
* Block for checking if a number is even, odd, prime, whole, positive,
* negative or if it is divisible by certain number.
* @this Blockly.Block
*/
init: function () {
var PROPERTIES =
[[Blockly.Msg.MATH_IS_EVEN, 'EVEN'],
[Blockly.Msg.MATH_IS_ODD, 'ODD'],
[Blockly.Msg.MATH_IS_PRIME, 'PRIME'],
[Blockly.Msg.MATH_IS_WHOLE, 'WHOLE'],
[Blockly.Msg.MATH_IS_POSITIVE, 'POSITIVE'],
[Blockly.Msg.MATH_IS_NEGATIVE, 'NEGATIVE'],
[Blockly.Msg.MATH_IS_DIVISIBLE_BY, 'DIVISIBLE_BY']];
this.setColour(getColour().math);
this.appendValueInput('NUMBER_TO_CHECK')
.setCheck(Types.getCompatibleTypes('int'));
var dropdown = new Blockly.FieldDropdown(PROPERTIES, function (option) {
var divisorInput = (option === 'DIVISIBLE_BY');
this.sourceBlock_.updateShape_(divisorInput);
});
this.appendDummyInput()
.appendField(dropdown, 'PROPERTY');
this.setInputsInline(true);
this.setOutput(true, Types.BOOLEAN.typeName);
this.setTooltip(Blockly.Msg.MATH_IS_TOOLTIP);
},
/**
* Create XML to represent whether the 'divisorInput' should be present.
* @return {Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function () {
var container = document.createElement('mutation');
var divisorInput = (this.getFieldValue('PROPERTY') === 'DIVISIBLE_BY');
container.setAttribute('divisor_input', divisorInput);
return container;
},
/**
* Parse XML to restore the 'divisorInput'.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function (xmlElement) {
var divisorInput = (xmlElement.getAttribute('divisor_input') === 'true');
this.updateShape_(divisorInput);
},
/**
* Modify this block to have (or not have) an input for 'is divisible by'.
* @param {boolean} divisorInput True if this block has a divisor input.
* @private
* @this Blockly.Block
*/
updateShape_: function (divisorInput) {
// Add or remove a Value Input.
var inputExists = this.getInput('DIVISOR');
if (divisorInput) {
if (!inputExists) {
this.appendValueInput('DIVISOR')
.setCheck(Types.getCompatibleTypes('int'));
}
} else if (inputExists) {
this.removeInput('DIVISOR');
}
}
};
Blockly.Blocks['math_change'] = {
/**
* Block for adding to a variable in place.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_CHANGE_TITLE,
"args0": [
{
"type": "field_variable",
"name": "VAR",
"defaultType": Types.NUMBER.typeName,
"variable": null
},
{
"type": "input_value",
"name": "DELTA",
"check": Types.getCompatibleTypes('int'),
"align": "RIGHT"
}
],
"previousStatement": null,
"nextStatement": null,
"colour": getColour().math,
"helpUrl": Blockly.Msg.MATH_CHANGE_HELPURL
});
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
return Blockly.Msg.MATH_CHANGE_TOOLTIP.replace('%1',
thisBlock.getFieldValue('VAR'));
});
}
};
Blockly.Blocks['math_round'] = {
/**
* Block for rounding functions.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1 %2",
"args0": [
{
"type": "field_dropdown",
"name": "OP",
"options": [
[Blockly.Msg.MATH_ROUND_OPERATOR_ROUND, 'ROUND'],
[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP, 'ROUNDUP'],
[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN, 'ROUNDDOWN']
]
},
{
"type": "input_value",
"name": "NUM",
"check": Types.getCompatibleTypes('float')
}
],
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_ROUND_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_ROUND_HELPURL
});
}
};
Blockly.Blocks['math_on_list'] = {
/**
* Block for evaluating a list of numbers to return sum, average, min, max,
* etc. Some functions also work on text (min, max, mode, median).
* @this Blockly.Block
*/
init: function () {
var OPERATORS =
[[Blockly.Msg.MATH_ONLIST_OPERATOR_SUM, 'SUM'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_MIN, 'MIN'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_MAX, 'MAX'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE, 'AVERAGE'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN, 'MEDIAN'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_MODE, 'MODE'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV, 'STD_DEV'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM, 'RANDOM']];
// Assign 'this' to a variable for use in the closures below.
var thisBlock = this;
this.setHelpUrl(Blockly.Msg.MATH_ONLIST_HELPURL);
this.setColour(getColour().math);
this.setOutput(true, Types.NUMBER.typeName);
var dropdown = new Blockly.FieldDropdown(OPERATORS, function (newOp) {
thisBlock.updateType_(newOp);
});
this.appendValueInput('LIST')
.setCheck(Types.getCompatibleTypes('array'))
.appendField(dropdown, 'OP');
this.setTooltip(function () {
var mode = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'SUM': Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM,
'MIN': Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN,
'MAX': Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX,
'AVERAGE': Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE,
'MEDIAN': Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN,
'MODE': Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE,
'STD_DEV': Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV,
'RANDOM': Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM
};
return TOOLTIPS[mode];
});
},
/**
* Modify this block to have the correct output type.
* @param {string} newOp Either 'MODE' or some op than returns a number.
* @private
* @this Blockly.Block
*/
updateType_: function (newOp) {
if (newOp === 'MODE') {
this.outputConnection.setCheck(Types.getCompatibleTypes('array'));
} else {
this.outputConnection.setCheck(Types.getCompatibleTypes('int'));
}
},
/**
* Create XML to represent the output type.
* @return {Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function () {
var container = document.createElement('mutation');
container.setAttribute('op', this.getFieldValue('OP'));
return container;
},
/**
* Parse XML to restore the output type.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function (xmlElement) {
this.updateType_(xmlElement.getAttribute('op'));
}
//TODO: a getBlockType once the list code is finished.
};
Blockly.Blocks['math_modulo'] = {
/**
* Block for remainder of a division.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_MODULO_TITLE,
"args0": [
{
"type": "input_value",
"name": "DIVIDEND",
"check": Types.getCompatibleTypes('int')
},
{
"type": "input_value",
"name": "DIVISOR",
"check": Types.getCompatibleTypes('int')
}
],
"inputsInline": true,
"output": Types.NUMBER.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_MODULO_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_MODULO_HELPURL
});
}
};
Blockly.Blocks['math_constrain'] = {
/**
* Block for constraining a number between two limits.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_CONSTRAIN_TITLE,
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": Types.getCompatibleTypes('int')
},
{
"type": "input_value",
"name": "LOW",
"check": Types.getCompatibleTypes('int')
},
{
"type": "input_value",
"name": "HIGH",
"check": Types.getCompatibleTypes('int')
}
],
"inputsInline": true,
"output": Types.NUMBER.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_CONSTRAIN_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_CONSTRAIN_HELPURL
});
}
//TODO: a getBlockType of the same type as the inputs.
};
Blockly.Blocks['math_random_int'] = {
/**
* Block for random integer between [X] and [Y].
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_RANDOM_INT_TITLE,
"args0": [
{
"type": "input_value",
"name": "FROM",
"check": Types.getCompatibleTypes('int')
},
{
"type": "input_value",
"name": "TO",
"check": Types.getCompatibleTypes('int')
}
],
"inputsInline": true,
"output": Types.NUMBER.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_RANDOM_INT_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_RANDOM_INT_HELPURL
});
}
};
Blockly.Blocks['math_random_float'] = {
/**
* Block for random fraction between 0 and 1.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM,
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_RANDOM_FLOAT_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_RANDOM_FLOAT_HELPURL
});
}
};
+86
View File
@@ -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);
this.setTooltip(Blockly.Msg.senseBox_mqtt_init_tooltip);
},
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":
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);
this.setTooltip(Blockly.Msg.senseBox_mqtt_publish_tooltip);
}
};
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);
}
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,145 @@
import * as Blockly from "blockly";
import { getColour } from "../helpers/colour";
Blockly.Blocks["sensebox_phyphox_init"] = {
init: function () {
this.setColour(getColour().phyphox);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_init)
.appendField(new Blockly.FieldTextInput("Geräte Name"), "devicename");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.sensebox_phyphox_init_tooltip);
},
};
Blockly.Blocks["sensebox_phyphox_experiment"] = {
init: function () {
this.setColour(getColour().phyphox);
this.appendDummyInput().appendField(
Blockly.Msg.sensebox_phyphox_createExperiment
);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_experimentTitle)
.appendField(new Blockly.FieldTextInput("Experiment Title"), "title");
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_experimentDescription)
.appendField(
new Blockly.FieldTextInput(
Blockly.Msg.sensebox_phyphox_experiment_description
),
"description"
);
this.appendStatementInput("view").appendField(
Blockly.Msg.sensebox_phyphox_createView
);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.sensebox_phyphox_experiment_tooltip);
},
};
Blockly.Blocks["sensebox_phyphox_graph"] = {
init: function () {
this.setColour(getColour().phyphox);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_createGraph)
.appendField(Blockly.Msg.sensebox_phyphox_graphLabel)
.appendField(new Blockly.FieldTextInput("Label"), "label");
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_unitx)
.appendField(new Blockly.FieldTextInput("Unit X"), "unitx");
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_unity)
.appendField(new Blockly.FieldTextInput("Unit Y"), "unity");
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_labelx)
.appendField(new Blockly.FieldTextInput("Label X"), "labelx");
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_labely)
.appendField(new Blockly.FieldTextInput("Label Y"), "labely");
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_graphStyle)
.appendField(
new Blockly.FieldDropdown([
[Blockly.Msg.sensebox_phyphox_style_dots, "dots"],
[Blockly.Msg.sensebox_phyphox_style_line, "line"],
]),
"style"
);
this.appendValueInput("channel0").appendField(
Blockly.Msg.sensebox_phyphox_channel0
);
this.appendValueInput("channel1").appendField(
Blockly.Msg.sensebox_phyphox_channel1
);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.sensebox_phyphox_graph_tooltip);
},
};
Blockly.Blocks["sensebox_phyphox_timestamp"] = {
init: function () {
this.setColour(getColour().phyphox);
this.appendDummyInput().appendField(Blockly.Msg.sensebox_phyphox_timestamp);
this.setOutput(true);
this.setTooltip(Blockly.Msg.sensebox_phyphox_timestamp_tooltip);
},
};
Blockly.Blocks["sensebox_phyphox_channel"] = {
init: function () {
this.setColour(getColour().phyphox);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_phyphox_channel)
.appendField(
new Blockly.FieldDropdown([
["1", "1"],
["2", "2"],
["3", "3"],
["4", "4"],
["5", "5"],
]),
"channel"
);
this.setOutput(true);
this.setTooltip(Blockly.Msg.sensebox_phyphox_channel_tooltip);
},
};
Blockly.Blocks["sensebox_phyphox_sendchannel"] = {
init: function () {
this.setColour(getColour().phyphox);
this.appendValueInput("value")
.appendField(Blockly.Msg.sensebox_phyphox_sendchannel)
.appendField(
new Blockly.FieldDropdown([
["1", "1"],
["2", "2"],
["3", "3"],
["4", "4"],
["5", "5"],
]),
"channel"
);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.sensebox_phyphox_sendchannel_tooltip);
},
};
Blockly.Blocks["sensebox_phyphox_experiment_send"] = {
init: function () {
this.setColour(getColour().phyphox);
this.appendStatementInput("sendValues").appendField(
Blockly.Msg.sensebox_phyphox_writeValues
);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.sensebox_phyphox_experiment_send_tooltip);
},
};
@@ -0,0 +1,304 @@
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types'
import { FieldSlider } from '@blockly/field-slider';
Blockly.Blocks['sensebox_display_beginDisplay'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_beginDisplay)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_display_beginDisplay_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_display_helpurl);
}
};
Blockly.Blocks['sensebox_display_clearDisplay'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_clearDisplay)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_display_clearDisplay_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_display_helpurl);
}
};
Blockly.Blocks['sensebox_display_printDisplay'] = {
init: function (block) {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_printDisplay);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_color)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_display_white, "WHITE,BLACK"], [Blockly.Msg.senseBox_display_black, "BLACK,WHITE"]]), "COLOR");
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_setSize)
.appendField(new FieldSlider(1, 1, 4), "SIZE");
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_printDisplay_x)
.appendField(new FieldSlider(0, 0, 64), "X");
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_printDisplay_y)
.appendField(new FieldSlider(0, 0, 128), "Y");
this.appendValueInput('printDisplay')
.appendField(Blockly.Msg.senseBox_display_printDisplay_value)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_display_printDisplay_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_display_helpurl);
},
/**
* 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_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_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_display_helpurl);
},
/**
* 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'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_plotDisplay)
this.appendValueInput("Title", 'Text')
.appendField(Blockly.Msg.senseBox_display_plotTitle);
this.appendValueInput("YLabel", 'Text')
.appendField(Blockly.Msg.senseBox_display_plotYLabel);
this.appendValueInput("XLabel", 'Text')
.appendField(Blockly.Msg.senseBox_display_plotXLabel);
this.appendValueInput("XRange1", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotXRange1);
this.appendValueInput("XRange2", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotXRange2)
this.appendValueInput("YRange1", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotYRange1);
this.appendValueInput("YRange2", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotYRange2);
this.setInputsInline(false);
this.appendValueInput("XTick", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotXTick);
this.appendValueInput("YTick", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotYTick);
this.appendValueInput("TimeFrame", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotTimeFrame);
this.appendValueInput('plotDisplay')
.appendField(Blockly.Msg.senseBox_display_printDisplay_value)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_display_printDisplay_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_display_helpurl);
},
/**
* 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_show'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_display_show);
this.appendStatementInput('SHOW');
this.setTooltip(Blockly.Msg.sensebox_display_show_tip);
this.setHelpUrl('');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
Blockly.Blocks['sensebox_display_fillCircle'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_display_fillCircle);
this.appendValueInput('X')
.appendField(Blockly.Msg.senseBox_display_printDisplay_x)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('Y')
.appendField(Blockly.Msg.senseBox_display_printDisplay_y)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('Radius')
.appendField(Blockly.Msg.sensebox_display_fillCircle_radius)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendDummyInput('fill')
.appendField(Blockly.Msg.senseBox_display_filled)
.appendField(new Blockly.FieldCheckbox("TRUE"), "FILL");
this.setInputsInline(false);
this.setTooltip(Blockly.Msg.senseBox_display_fillCircle_tooltip)
this.setHelpUrl(Blockly.Msg.senseBox_display_helpurl)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
/**
* 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_drawRectangle'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_display_drawRectangle);
this.appendValueInput('X')
.appendField(Blockly.Msg.senseBox_display_printDisplay_x)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('Y')
.appendField(Blockly.Msg.senseBox_display_printDisplay_y)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('width')
.appendField(Blockly.Msg.sensebox_display_drawRectangle_width)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('height')
.appendField(Blockly.Msg.sensebox_display_drawRectangle_height)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendDummyInput('fill')
.appendField(Blockly.Msg.senseBox_display_filled)
.appendField(new Blockly.FieldCheckbox("TRUE"), "FILL");
this.setInputsInline(false);
this.setTooltip(Blockly.Msg.senseBox_display_drawRectangle_tooltip)
this.setHelpUrl(Blockly.Msg.senseBox_display_helpurl)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
/**
* 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'],
};
@@ -0,0 +1,180 @@
import * as Blockly from 'blockly';
import { getColour } from '../helpers/colour'
import { selectedBoard } from '../helpers/board'
import * as Types from '../helpers/types'
Blockly.Blocks['sensebox_led'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_led)
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPinsLED), "PIN")
.appendField(Blockly.Msg.senseBox_basic_state)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_on, "HIGH"], [Blockly.Msg.senseBox_off, "LOW"]]), "STAT");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_led_tooltip);
}
};
Blockly.Blocks['sensebox_rgb_led'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_rgb_led)
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPins), "PIN");
this.appendValueInput("COLOR", 'Number')
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led_color)
.setCheck("Colour");
// 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);
}
};
Blockly.Blocks['sensebox_ws2818_led_init'] = {
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_init)
.appendField("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
this.appendValueInput("BRIGHTNESS", "brightness")
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_brightness));
this.appendValueInput("NUMBER", "number")
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_number));
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_ws2818_rgb_led_init_tooltip);
}
};
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("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
this.appendValueInput("POSITION", "position")
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_position));
this.appendValueInput("COLOR", 'Number')
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led_color)
.setCheck("Colour");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_ws2818_rgb_led_tooltip);
}
};
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
// Block for colour picker.
{
"type": "colour_picker",
"message0": "%1",
"args0": [
{
"type": "field_colour",
"name": "COLOUR",
"colour": "#ff0000"
}
],
"output": "Colour",
"helpUrl": "%{BKY_COLOUR_PICKER_HELPURL}",
"colour": getColour().sensebox,
"tooltip": "%{BKY_COLOUR_PICKER_TOOLTIP}",
"extensions": ["parent_tooltip_when_inline"]
},
// Block for random colour.
{
"type": "colour_random",
"message0": "%{BKY_COLOUR_RANDOM_TITLE}",
"output": "Colour",
"helpUrl": "%{BKY_COLOUR_RANDOM_HELPURL}",
"colour": getColour().sensebox,
"tooltip": "%{BKY_COLOUR_RANDOM_TOOLTIP}"
},
// Block for composing a colour from RGB components.
{
"type": "colour_rgb",
"message0": "%{BKY_COLOUR_RGB_TITLE} %{BKY_COLOUR_RGB_RED} %1 %{BKY_COLOUR_RGB_GREEN} %2 %{BKY_COLOUR_RGB_BLUE} %3",
"args0": [
{
"type": "input_value",
"name": "RED",
"check": Types.getCompatibleTypes('int'),
"align": "RIGHT"
},
{
"type": "input_value",
"name": "GREEN",
"check": Types.getCompatibleTypes('int'),
"align": "RIGHT"
},
{
"type": "input_value",
"name": "BLUE",
"check": Types.getCompatibleTypes('int'),
"align": "RIGHT"
}
],
"output": "Colour",
"helpUrl": "%{BKY_COLOUR_RGB_HELPURL}",
"colour": getColour().sensebox,
"tooltip": "%{BKY_COLOUR_RGB_TOOLTIP}"
},
// Block for blending two colours together.
{
"type": "colour_blend",
"message0": "%{BKY_COLOUR_BLEND_TITLE} %{BKY_COLOUR_BLEND_COLOUR1} " +
"%1 %{BKY_COLOUR_BLEND_COLOUR2} %2 %{BKY_COLOUR_BLEND_RATIO} %3",
"args0": [
{
"type": "input_value",
"name": "COLOUR1",
"check": "Colour",
"align": "RIGHT"
},
{
"type": "input_value",
"name": "COLOUR2",
"check": "Colour",
"align": "RIGHT"
},
{
"type": "input_value",
"name": "RATIO",
"check": "Number",
"align": "RIGHT"
}
],
"output": "Colour",
"helpUrl": "%{BKY_COLOUR_BLEND_HELPURL}",
"style": "colour_blocks",
"tooltip": "%{BKY_COLOUR_BLEND_TOOLTIP}"
}
]); // END JSON EXTRACT (Do not delete this comment.)
@@ -0,0 +1,301 @@
import * as Blockly from "blockly/core";
import { getColour } from "../helpers/colour";
/*
----------------------------------LoRa--------------------------------------------------
*/
Blockly.Blocks["sensebox_lora_initialize_otaa"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_init_otaa_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_LoRa_init_helpurl);
this.setColour(getColour().sensebox);
this.appendDummyInput().appendField("Initialize LoRa (OTAA)");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_device_id)
.appendField("{")
.appendField(new Blockly.FieldTextInput("DEVICE ID"), "DEVICEID")
.appendField("}");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_app_id)
.appendField("{")
.appendField(new Blockly.FieldTextInput("APP ID"), "APPID")
.appendField("}");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_app_key)
.appendField("{")
.appendField(new Blockly.FieldTextInput("APP KEY"), "APPKEY")
.appendField("}");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_interval)
.appendField(new Blockly.FieldTextInput("5"), "INTERVAL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
};
Blockly.Blocks["sensebox_lora_initialize_abp"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_init_abp_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_LoRa_init_helpurl);
this.setColour(getColour().sensebox);
this.appendDummyInput().appendField("Initialize LoRa (ABP)");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_nwskey_id)
.appendField("{")
.appendField(new Blockly.FieldTextInput("NWSKEY"), "NWSKEY")
.appendField("}");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_appskey_id)
.appendField("{")
.appendField(new Blockly.FieldTextInput("APPSKEY"), "APPSKEY")
.appendField("}");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_devaddr_id)
.appendField(new Blockly.FieldTextInput("DEVADDR"), "DEVADDR");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_interval)
.appendField(new Blockly.FieldTextInput("5"), "INTERVAL");
// this.appendStatementInput('DO')
// .appendField(Blockly.Msg.senseBox_measurements)
// .setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
};
Blockly.Blocks["sensebox_lora_message_send"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_message_tooltip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendStatementInput("DO")
.appendField(Blockly.Msg.senseBox_LoRa_send_message)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
};
Blockly.Blocks["sensebox_send_lora_sensor_value"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_sensor_tip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendValueInput("Value").appendField(
Blockly.Msg.senseBox_measurement
);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField("Bytes")
.appendField(new Blockly.FieldTextInput("2"), "MESSAGE_BYTES");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
/**
* 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_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"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_tip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendStatementInput("DO")
.appendField(Blockly.Msg.senseBox_LoRa_send_cayenne)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
};
Blockly.Blocks["sensebox_lora_cayenne_temperature"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_temperature_tip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendValueInput("Value").appendField(
Blockly.Msg.senseBox_LoRa_cayenne_temperature
);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ["sensebox_lora_cayenne_send"],
};
Blockly.Blocks["sensebox_lora_cayenne_humidity"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_humidity_tip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendValueInput("Value").appendField(
Blockly.Msg.senseBox_LoRa_cayenne_humidity
);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ["sensebox_lora_cayenne_send"],
};
Blockly.Blocks["sensebox_lora_cayenne_pressure"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_pressure_tip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendValueInput("Value").appendField(
Blockly.Msg.senseBox_LoRa_cayenne_pressure
);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ["sensebox_lora_cayenne_send"],
};
Blockly.Blocks["sensebox_lora_cayenne_luminosity"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_luminosity_tip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendValueInput("Value").appendField(
Blockly.Msg.senseBox_LoRa_cayenne_luminosity
);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ["sensebox_lora_cayenne_send"],
};
Blockly.Blocks["sensebox_lora_cayenne_sensor"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_analog_tip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendValueInput("Value").appendField(
Blockly.Msg.senseBox_LoRa_cayenne_analog
);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ["sensebox_lora_cayenne_send"],
};
Blockly.Blocks["sensebox_lora_cayenne_accelerometer"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_gyros_tip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendValueInput("X").appendField(Blockly.Msg.senseBox_LoRa_cayenne_x);
this.appendValueInput("Y").appendField(Blockly.Msg.senseBox_LoRa_cayenne_y);
this.appendValueInput("Z").appendField(Blockly.Msg.senseBox_LoRa_cayenne_z);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ["sensebox_lora_cayenne_send"],
};
Blockly.Blocks["sensebox_lora_cayenne_gps"] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_gps_tip);
this.setHelpUrl("");
this.setColour(getColour().sensebox);
this.appendValueInput("LAT").appendField(
Blockly.Msg.senseBox_LoRa_cayenne_lat
);
this.appendValueInput("LNG").appendField(
Blockly.Msg.senseBox_LoRa_cayenne_lng
);
this.appendValueInput("ALT").appendField(
Blockly.Msg.senseBox_LoRa_cayenne_alt
);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ["sensebox_lora_cayenne_send"],
};
@@ -0,0 +1,202 @@
import * as Blockly from 'blockly/core';
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'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_osem_connection_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_osem_connection)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_osem_host, '"ingress.opensensemap.org"'], [Blockly.Msg.senseBox_osem_host_workshop, '"ingress.workshop.opensensemap.org"']]), "host")
.appendField('SSL')
.appendField(new Blockly.FieldCheckbox("TRUE"), "SSL");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_osem_exposure)
.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()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_osem_access_token)
.appendField(new Blockly.FieldTextInput("access_token"), "access_token");
this.appendStatementInput('DO')
.appendField(Blockly.Msg.senseBox_sensor)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
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);
}
/**
* 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');
*/
selectedBox = this.getFieldValue('BoxID');
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 () {
var container = document.createElement('mutation');
var input = this.getFieldValue('type');
this.updateShape_(input);
container.setAttribute('type', input);
return container;
},
domToMutation: function (xmlElement) {
var connections = xmlElement.getAttribute('connections');
this.updateShape_(connections);
},
/**
* Modify this block to have the correct number of pins available.
* @param {boolean}
* @private
* @this Blockly.Block
*/
updateShape_: function () {
var extraFieldExist = this.getFieldValue('gps');
var input = this.getFieldValue('type');
if ((input === 'Mobile') && extraFieldExist === null) {
this.appendValueInput('lat', 'Number')
.appendField(Blockly.Msg.senseBox_gps_lat, 'gps');
this.appendValueInput('lng', 'Number')
.appendField(Blockly.Msg.senseBox_gps_lng);
this.appendValueInput('altitude', 'Number')
.appendField(Blockly.Msg.senseBox_gps_alt);
this.appendValueInput('timeStamp', 'Number')
.appendField(Blockly.Msg.senseBox_gps_timeStamp);
}
if (input === 'Stationary' && extraFieldExist !== null) {
this.removeInput('lat');
this.removeInput('lng');
this.removeInput('altitude');
this.removeInput('timeStamp');
}
},
LOOP_TYPES: ['sensebox_interval_timer']
};
Blockly.Blocks['sensebox_send_to_osem'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_send_to_osem_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_send_to_osem);
if (boxes) {
this.appendValueInput('Value')
.appendField('Phänomen')
.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.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])
}
}
if (dropdown.length > 1) {
var options = dropdown.slice(1)
return options
} else {
return dropdown
}
}
return dropdown
},
/**
* 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 () {
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);
}
},
/**
* 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']
};
@@ -0,0 +1,78 @@
import * as Blockly from "blockly";
import { getColour } from "../helpers/colour";
import * as Types from "../helpers/types";
Blockly.Blocks["sensebox_rtc_init"] = {
init: function () {
this.setHelpUrl(Blockly.Msg.sensebox_rtc_helpurl);
this.setColour(getColour().time);
this.appendDummyInput().appendField(Blockly.Msg.sensebox_rtc_init);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip(Blockly.Msg.sensebox_rtc_init_tooltip);
},
};
Blockly.Blocks["sensebox_rtc_set"] = {
init: function () {
this.setHelpUrl(Blockly.Msg.sensebox_rtc_helpurl);
this.setColour(getColour().time);
this.appendDummyInput().appendField(Blockly.Msg.sensebox_rtc_set);
this.appendValueInput("second").appendField(
Blockly.Msg.sensebox_rtc_second
);
this.appendValueInput("minutes").appendField(
Blockly.Msg.sensebox_rtc_minutes
);
this.appendValueInput("hour").appendField(Blockly.Msg.sensebox_rtc_hour);
this.appendValueInput("day").appendField(Blockly.Msg.sensebox_rtc_day);
this.appendValueInput("month").appendField(Blockly.Msg.sensebox_rtc_month);
this.appendValueInput("year").appendField(Blockly.Msg.sensebox_rtc_year);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip(Blockly.Msg.sensebox_rtc_set_tooltip);
},
};
Blockly.Blocks["sensebox_rtc_set_ntp"] = {
init: function () {
this.setHelpUrl(Blockly.Msg.sensebox_rtc_helpurl);
this.setColour(getColour().time);
this.appendValueInput("time").appendField(Blockly.Msg.sensebox_rtc_set_ntp);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip(Blockly.Msg.sensebox_rtc_set_ntp_tooltip);
},
};
Blockly.Blocks["sensebox_rtc_get"] = {
init: function () {
this.setHelpUrl(Blockly.Msg.sensebox_rtc_helpurl);
this.setColour(getColour().time);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_rtc_get)
.appendField(
new Blockly.FieldDropdown([
[Blockly.Msg.sensebox_rtc_hour, "hour"],
[Blockly.Msg.sensebox_rtc_minutes, "minutes"],
[Blockly.Msg.sensebox_rtc_second, "seconds"],
[Blockly.Msg.sensebox_rtc_day, "day"],
[Blockly.Msg.sensebox_rtc_month, "month"],
[Blockly.Msg.sensebox_rtc_year, "year"],
]),
"dropdown"
);
this.setOutput(true, Types.LARGE_NUMBER.typeId);
this.setTooltip(Blockly.Msg.sensebox_rtc_get_tooltip);
},
};
Blockly.Blocks["sensebox_rtc_get_timestamp"] = {
init: function () {
this.setHelpUrl(Blockly.Msg.sensebox_rtc_helpurl);
this.setColour(getColour().time);
this.appendDummyInput().appendField(Blockly.Msg.sensebox_rtc_get_timestamp);
this.setOutput(true);
this.setTooltip(Blockly.Msg.sensebox_rtc_get_timestamp_tooltip);
},
};
@@ -0,0 +1,80 @@
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
Blockly.Blocks['sensebox_sd_open_file'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sd_open_file)
.setAlign(Blockly.ALIGN_LEFT)
.appendField(
new Blockly.FieldTextInput('Data.txt'),
'Filename');
this.appendStatementInput('SD')
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_sd_open_file_tooltip);
this.setHelpUrl('https://docs.sensebox.de/hardware/bee-sd/');
}
};
Blockly.Blocks['sensebox_sd_create_file'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sd_create_file)
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_output_filename)
.appendField(
new Blockly.FieldTextInput('Data.txt'),
'Filename');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_sd_create_file_tooltip);
this.setHelpUrl('https://docs.sensebox.de/hardware/bee-sd/');
}
};
Blockly.Blocks['sensebox_sd_write_file'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sd_write_file)
.setAlign(Blockly.ALIGN_LEFT);
this.appendValueInput('DATA')
.setCheck(null);
this.appendDummyInput('CheckboxText')
.appendField(Blockly.Msg.senseBox_output_linebreak)
.appendField(new Blockly.FieldCheckbox('TRUE'), 'linebreak');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_sd_write_file_tooltip);
this.setHelpUrl('https://docs.sensebox.de/hardware/bee-sd/');
},
/**
* 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_sd_open_file'],
};
@@ -1,5 +1,12 @@
import Blockly from 'blockly';
import { getColour } from '../helpers/colour'
import * as Types from '../helpers/types'
import { selectedBoard } from '../helpers/board'
/**
* HDC1080 Temperature and Humidity Sensor
*
*/
Blockly.Blocks['sensebox_sensor_temp_hum'] = {
init: function () {
@@ -9,12 +16,420 @@ Blockly.Blocks['sensebox_sensor_temp_hum'] = {
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_value)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_temp, "Temperature"], [Blockly.Msg.senseBox_hum, "Humidity"]]), "NAME");
this.setOutput(true, "Number");
this.setColour(120);
this.setTooltip(Blockly.Msg.senseBox_temp_hum_tip);
this.setHelpUrl('https://edu.books.sensebox.de/de/projekte/diy_umweltstation/temp_und_luftfeuchte.html');
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_temp_hum_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_temp_hum_helpurl);
}
};
/**
* VEML6070 and TSL4513
*
*/
Blockly.Blocks['sensebox_sensor_uv_light'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_uv_light);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_value)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_light, "Illuminance"], [Blockly.Msg.senseBox_uv, "UvIntensity"]]), "NAME");
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_uv_light_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_uv_light_helpurl);
}
};
/*
BMX055 Three differen Blocks for Accelerometer, Gyroscope, Compass
*/
Blockly.Blocks['sensebox_sensor_bmx055_accelerometer'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_bmx055_accelerometer);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_bmx055_accelerometer_direction)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_bmx055_accelerometer_direction_x, "X"], [Blockly.Msg.senseBox_bmx055_accelerometer_direction_y, "Y"], [Blockly.Msg.senseBox_bmx055_accelerometer_direction_z, "Z"], [Blockly.Msg.senseBox_bmx055_accelerometer_direction_total, "Total"]]), "VALUE");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_bmx055_accelerometer_range)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_bmx055_accelerometer_range_2g, "0x3"], [Blockly.Msg.senseBox_bmx055_accelerometer_range_4g, "0x5"], [Blockly.Msg.senseBox_bmx055_accelerometer_range_8g, "0x8"], [Blockly.Msg.senseBox_bmx055_accelerometer_range_16g, "0x0C"]]), "RANGE");
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_bmx055_accelerometer_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_bmx055_helpurl);
}
};
/**
* SDS011 Fine Particular Matter Sensor
*
*/
Blockly.Blocks['sensebox_sensor_sds011'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sds011);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_value)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_sds011_pm25, "Pm25"], [Blockly.Msg.senseBox_sds011_pm10, "Pm10"]]), "NAME")
.appendField(Blockly.Msg.senseBox_sds011_dimension)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_sds011_serial1, "Serial1"], [Blockly.Msg.senseBox_sds011_serial2, "Serial2"]]), "SERIAL");
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_sds011_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_sds011_helpurl);
}
};
/**
* BMP280 Pressure Sensor
*
*/
Blockly.Blocks['sensebox_sensor_pressure'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_pressure, "Pressure"], [Blockly.Msg.senseBox_temp, "Temperature"], [Blockly.Msg.senseBox_gps_alt, "Altitude"]];
var dropdown = new Blockly.FieldDropdown(dropdownOptions, function (option) {
var input = (option === 'Pressure') || (option === 'Temperature') || (option === 'Altitude');
this.sourceBlock_.updateShape_(input);
});
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_pressure_sensor);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_value)
.appendField(dropdown, "NAME");
this.setColour(getColour().sensebox);
this.setOutput(true, Types.DECIMAL.typeName);
this.setTooltip(Blockly.Msg.senseBox_pressure_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_pressure_helpurl);
},
getBlockType: function () {
return Blockly.Types.DECIMAL;
/**
* Parse XML to restore the number of pins available.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function (xmlElement) {
(xmlElement.getAttribute('port'));
},
/**
* Create XML to represent number of pins selection.
* @return {!Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function () {
var container = document.createElement('mutation');
var input = this.getFieldValue('NAME');
this.updateShape_(input);
container.setAttribute('NAME', input);
return container;
},
/**
* Modify this block to have the correct number of pins available.
* @param {boolean}
* @private
* @this Blockly.Block
*/
updateShape_: function () {
var extraFieldExist = this.getFieldValue('referencePressure');
var input = this.getFieldValue('NAME');
if (input === 'Altitude' && extraFieldExist === null) {
this.appendDummyInput('extraField')
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_pressure_referencePressure)
.appendField(new Blockly.FieldTextInput("1013"), "referencePressure")
.appendField(Blockly.Msg.senseBox_pressure_referencePressure_dim);
}
if ((input === 'Pressure' || input === 'Temperature') && extraFieldExist !== null) {
this.removeInput('extraField');
}
}
};
/**
* BME680 Environmental Sensor
*
*/
Blockly.Blocks['sensebox_sensor_bme680_bsec'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_temp, "temperature"], [Blockly.Msg.senseBox_hum, "humidity"], [Blockly.Msg.senseBox_pressure, "pressure"], [Blockly.Msg.senseBox_bme_iaq, "IAQ"], [Blockly.Msg.senseBox_bme_iaq_accuracy, "IAQAccuracy"], [Blockly.Msg.senseBox_bme_co2, "CO2"], [Blockly.Msg.senseBox_bme_breatheVocEquivalent, "breathVocEquivalent"]];
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_bme680);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_value)
.appendField(new Blockly.FieldDropdown(dropdownOptions), "dropdown")
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_bme_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_bme680_helpurl)
}
};
/**
* Ultrasonic Sensor
*
*
*/
Blockly.Blocks['sensebox_sensor_ultrasonic_ranger'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, 'A'],
[Blockly.Msg.senseBox_ultrasonic_port_B, 'B'], [Blockly.Msg.senseBox_ultrasonic_port_C, 'C']];
var dropdown = new Blockly.FieldDropdown(dropdownOptions, function (option) {
var input = (option === 'A') || (option === 'B') || (option === 'C');
this.sourceBlock_.updateShape_(input);
});
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_ultrasonic)
.appendField(dropdown, "port");
this.appendDummyInput('TrigEcho')
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_ultrasonic_trigger)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), 'ultrasonic_trigger')
.appendField(Blockly.Msg.senseBox_ultrasonic_echo)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), 'ultrasonic_echo');
this.setOutput(true, Types.NUMBER.typeName);
this.setTooltip(Blockly.Msg.senseBox_ultrasonic_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_ultrasonic_helpurl);
},
/**
* Parse XML to restore the number of pins available.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function (xmlElement) {
(xmlElement.getAttribute('port'));
},
/**
* Create XML to represent number of pins selection.
* @return {!Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function () {
var container = document.createElement('mutation');
var input = this.getFieldValue('port');
this.updateShape_(input);
container.setAttribute("port", input);
return container;
},
/**
* Modify this block to have the correct number of pins available.
* @param {boolean}
* @private
* @this Blockly.Block
*/
updateShape_: function () {
var input = this.getFieldValue('port');
switch (input) {
case 'A':
this.setFieldValue('1', 'ultrasonic_trigger');
this.setFieldValue('2', 'ultrasonic_echo');
break;
case 'B':
this.setFieldValue('3', 'ultrasonic_trigger');
this.setFieldValue('4', 'ultrasonic_echo');
break;
case 'C':
this.setFieldValue('5', 'ultrasonic_trigger');
this.setFieldValue('6', 'ultrasonic_echo');
break;
default:
break;
}
}
};
/**
* Microphone
*
*/
Blockly.Blocks['sensebox_sensor_sound'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sound)
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(selectedBoard().analogPins), "PIN")
this.setOutput(true, Types.NUMBER.typeName);
this.setHelpUrl(Blockly.Msg.senseBox_sound_helpurl);
this.setTooltip(Blockly.Msg.senseBox_sound_tooltip);
}
};
/**
* Button
*
*
*/
Blockly.Blocks['sensebox_button'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_button)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_button_isPressed, "isPressed"], [Blockly.Msg.senseBox_button_wasPressed, "wasPressed"], [Blockly.Msg.senseBox_button_switch, "Switch"]]), "FUNCTION")
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPinsButton), "PIN");
this.setOutput(true, Types.BOOLEAN.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_button_tooltip);
}
};
/**
* SCD30 CO2 Sensor
*
*/
Blockly.Blocks['sensebox_scd30'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_scd_co2, "CO2"], [Blockly.Msg.senseBox_temp, "temperature"], [Blockly.Msg.senseBox_hum, "humidity"]];
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_scd30);
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_scd_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_scd_helpurl);
},
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_gps_tooltip);
}
};
/**
* Block for Truebner STM50
*/
Blockly.Blocks['sensebox_sensor_truebner_smt50'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, 'A'],
[Blockly.Msg.senseBox_ultrasonic_port_B, 'B'], [Blockly.Msg.senseBox_ultrasonic_port_C, 'C']];
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_smt50);
this.appendDummyInput()
.appendField("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_value)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_temp, "temp"], [Blockly.Msg.senseBox_soil, "soil"]]), 'value')
this.setOutput(true, Types.NUMBER.typeName);
this.setTooltip(Blockly.Msg.senseBox_smt50_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_smt50_helpurl);
}
};
/**
* DS18B20 Watertemperature
*
*/
Blockly.Blocks['sensebox_sensor_watertemperature'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, 'A'],
[Blockly.Msg.senseBox_ultrasonic_port_B, 'B'], [Blockly.Msg.senseBox_ultrasonic_port_C, 'C']];
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_watertemperature)
.appendField("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
this.setOutput(true, Types.NUMBER.typeName);
this.setTooltip(Blockly.Msg.senseBox_watertemperature_tip);
}
};
/**
* Windspeed
* removed for now
Blockly.Blocks['sensebox_windspeed'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_windspeed)
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(selectedBoard().analogPins), "PIN")
this.setOutput(true, Types.DECIMAL.typeName);
}
};
*/
/**
* DF Robot Soundsensor
*/
Blockly.Blocks['sensebox_soundsensor_dfrobot'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, 'A'],
[Blockly.Msg.senseBox_ultrasonic_port_B, 'B'], [Blockly.Msg.senseBox_ultrasonic_port_C, 'C']];
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_soundsensor_dfrobot)
.appendField("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
this.setOutput(true, Types.DECIMAL.typeName);
this.setTooltip(Blockly.Msg.senseBox_soundsensor_dfrobot_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_soundsensor_dfrobot_helpurl)
}
};
@@ -0,0 +1,58 @@
import Blockly from 'blockly';
import { getColour } from '../helpers/colour'
Blockly.Blocks["sensebox_telegram"] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_telegram_init);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField("telegram")
.appendField(new Blockly.FieldTextInput("token"), "telegram_token");
this.setPreviousStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_telegram_init_tooltip);
this.setNextStatement(true, null);
}
};
Blockly.Blocks["sensebox_telegram_do"] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput().appendField(Blockly.Msg.senseBox_telegram_do);
this.appendStatementInput("telegram_do");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_telegram_do_tooltip)
}
};
Blockly.Blocks["sensebox_telegram_do_on_message"] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput().appendField(Blockly.Msg.senseBox_telegram_do_on_message);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_telegram_message)
.appendField(new Blockly.FieldTextInput("/message"), 'telegram_message');
this.appendStatementInput("telegram_do_on_message").setCheck(null);
this.setTooltip(Blockly.Msg.senseBox_telegram_message_tooltip)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
Blockly.Blocks["sensebox_telegram_send"] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput().appendField(Blockly.Msg.senseBox_telegram_send);
this.appendValueInput("telegram_text_to_send").setCheck(null);
this.setTooltip(Blockly.Msg.senseBox_telegram_send_tooltip)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ["sensebox_telegram_do_on_message"]
};
@@ -0,0 +1,60 @@
import Blockly from 'blockly';
import { getColour } from '../helpers/colour'
Blockly.Blocks['sensebox_wifi'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_wifi_tooltip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_wifi_connect);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_wifi_ssid)
.appendField(new Blockly.FieldTextInput("SSID"), "SSID");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_output_password)
.appendField(new Blockly.FieldTextInput("Password"), "Password");
this.setHelpUrl(Blockly.Msg.senseBox_wifi_helpurl)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
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: ['arduino_functions'],
};
Blockly.Blocks['sensebox_startap'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_wifi_startap_tooltip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_wifi_startap);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_wifi_ssid)
.appendField(new Blockly.FieldTextInput("SSID"), "SSID");
this.setHelpUrl(Blockly.Msg.senseBox_wifi_helpurl)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
+33 -13
View File
@@ -1,16 +1,36 @@
import Blockly from 'blockly';
import * as Blockly from "blockly/core";
import { getColour } from "../helpers/colour";
import * as Types from "../helpers/types";
Blockly.Blocks["sensebox_telegram"] = {
init: function () {
this.setColour(120);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_telegram_init);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField("telegram")
.appendField(new Blockly.FieldTextInput("token"), "telegram_token");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
Blockly.Blocks["sensebox_multiplexer_init"] = {
init: function () {
this.appendDummyInput().appendField(Blockly.Msg.senseBox_multiplexer_init);
this.appendValueInput("nrChannels").setCheck(
Types.getCompatibleTypes("int")
);
this.appendDummyInput().appendField(
Blockly.Msg.senseBox_multplexer_nchannels
);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setInputsInline("true");
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_multiplexer_init_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_multiplexer_init_helpurl);
},
};
Blockly.Blocks["sensebox_multiplexer_changeChannel"] = {
init: function () {
this.appendDummyInput().appendField(
Blockly.Msg.senseBox_multiplexer_changeChannel
);
this.appendValueInput("Channel").setCheck(Types.getCompatibleTypes("int"));
this.setInputsInline("true");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.sensebox_multiplexer_changeChannel_tooltip);
this.setHelpUrl(Blockly.Msg.sensebox_multiplexer_changeChannel_helpurl);
},
};
+202
View File
@@ -0,0 +1,202 @@
import Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types';
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
// Block for text value
{
"type": "text",
"message0": "%1",
"args0": [{
"type": "field_input",
"name": "TEXT",
"text": ""
}],
"output": Types.TEXT.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_TEXT_HELPURL}",
"tooltip": "%{BKY_TEXT_TEXT_TOOLTIP}",
"extensions": [
"text_quotes",
"parent_tooltip_when_inline"
]
},
{
"type": "text_multiline",
"message0": "%1 %2",
"args0": [{
"type": "field_image",
"src": 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAARCAYAAADpP' +
'U2iAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAdhgAAHYYBXaITgQAAABh0RVh0' +
'U29mdHdhcmUAcGFpbnQubmV0IDQuMS42/U4J6AAAAP1JREFUOE+Vks0KQUEYhjm' +
'RIja4ABtZ2dm5A3t3Ia6AUm7CylYuQRaUhZSlLZJiQbFAyRnPN33y01HOW08z88' +
'73zpwzM4F3GWOCruvGIE4/rLaV+Nq1hVGMBqzhqlxgCys4wJA65xnogMHsQ5luj' +
'nYHTejBBCK2mE4abjCgMGhNxHgDFWjDSG07kdfVa2pZMf4ZyMAdWmpZMfYOsLiD' +
'MYMjlMB+K613QISRhTnITnsYg5yUd0DETmEoMlkFOeIT/A58iyK5E18BuTBfgYX' +
'fwNJv4P9/oEBerLylOnRhygmGdPpTTBZAPkde61lbQe4moWUvYUZYLfUNftIY4z' +
'wA5X2Z9AYnQrEAAAAASUVORK5CYII=',
"width": 12,
"height": 17,
"alt": '\u00B6'
}, {
"type": "field_multilinetext",
"name": "TEXT",
"text": ""
}],
"output": Types.TEXT.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_TEXT_HELPURL}",
"tooltip": "%{BKY_TEXT_TEXT_TOOLTIP}",
"extensions": [
"parent_tooltip_when_inline"
]
},
{
"type": "text_join",
"message0": "",
"output": Types.TEXT.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_JOIN_HELPURL}",
"tooltip": "%{BKY_TEXT_JOIN_TOOLTIP}",
"mutator": "text_join_mutator"
},
{
"type": "text_create_join_container",
"message0": "%{BKY_TEXT_CREATE_JOIN_TITLE_JOIN} %1 %2",
"args0": [{
"type": "input_dummy"
},
{
"type": "input_statement",
"name": "STACK"
}],
"style": "text_blocks",
"tooltip": "%{BKY_TEXT_CREATE_JOIN_TOOLTIP}",
"enableContextMenu": false
},
{
"type": "text_create_join_item",
"message0": "%{BKY_TEXT_CREATE_JOIN_ITEM_TITLE_ITEM}",
"previousStatement": null,
"nextStatement": null,
"style": getColour().text,
"tooltip": "%{BKY_TEXT_CREATE_JOIN_ITEM_TOOLTIP}",
"enableContextMenu": false
},
{
"type": "text_append",
"message0": "%{BKY_TEXT_APPEND_TITLE}",
"args0": [{
"type": "field_variable",
"name": "VAR",
"variable": "%{BKY_TEXT_APPEND_VARIABLE}"
},
{
"type": "input_value",
"name": "TEXT"
}],
"previousStatement": null,
"nextStatement": null,
"style": "text_blocks",
"extensions": [
"text_append_tooltip"
]
},
{
"type": "text_length",
"message0": "%{BKY_TEXT_LENGTH_TITLE}",
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": ['String', 'Array']
}
],
"output": Types.NUMBER.typeName,
"style": "text_blocks",
"tooltip": "%{BKY_TEXT_LENGTH_TOOLTIP}",
"helpUrl": "%{BKY_TEXT_LENGTH_HELPURL}"
},
{
"type": "text_isEmpty",
"message0": "%{BKY_TEXT_ISEMPTY_TITLE}",
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": ['String', 'Array']
}
],
"output": Types.BOOLEAN.typeName,
"style": "text_blocks",
"tooltip": "%{BKY_TEXT_ISEMPTY_TOOLTIP}",
"helpUrl": "%{BKY_TEXT_ISEMPTY_HELPURL}"
},
{
"type": "text_indexOf",
"message0": "%{BKY_TEXT_INDEXOF_TITLE}",
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": "String"
},
{
"type": "field_dropdown",
"name": "END",
"options": [
[
"%{BKY_TEXT_INDEXOF_OPERATOR_FIRST}",
"FIRST"
],
[
"%{BKY_TEXT_INDEXOF_OPERATOR_LAST}",
"LAST"
]
]
},
{
"type": "input_value",
"name": "FIND",
"check": "String"
}
],
"output": Types.NUMBER.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_INDEXOF_HELPURL}",
"inputsInline": true,
"extensions": [
"text_indexOf_tooltip"
]
},
{
"type": "text_charAt",
"message0": "%{BKY_TEXT_CHARAT_TITLE}", // "in text %1 %2"
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": "String"
},
{
"type": "field_dropdown",
"name": "WHERE",
"options": [
["%{BKY_TEXT_CHARAT_FROM_START}", "FROM_START"],
["%{BKY_TEXT_CHARAT_FROM_END}", "FROM_END"],
["%{BKY_TEXT_CHARAT_FIRST}", "FIRST"],
["%{BKY_TEXT_CHARAT_LAST}", "LAST"],
["%{BKY_TEXT_CHARAT_RANDOM}", "RANDOM"]
]
}
],
"output": Types.TEXT.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_CHARAT_HELPURL}",
"inputsInline": true,
"mutator": "text_charAt_mutator"
}
]); // END JSON EXTRACT (Do not delete this comment.)
+130
View File
@@ -0,0 +1,130 @@
/**
* @license Licensed under the Apache License, Version 2.0 (the "License"):
* http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* @fileoverview Blocks for Arduino Time functions.
* The arduino built in functions syntax can be found in
* http://arduino.cc/en/Reference/HomePage
*/
import Blockly from 'blockly';
import { getColour } from '../helpers/colour'
import * as Types from '../helpers/types'
Blockly.Blocks['time_delay'] = {
/**
* Delay block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Delay');
this.setColour(getColour().time);
this.appendValueInput('DELAY_TIME_MILI')
.setCheck(Types.NUMBER.checkList)
.appendField(Blockly.Msg.ARD_TIME_DELAY);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_MS);
this.setInputsInline(true);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_TIME_DELAY_TIP);
}
};
Blockly.Blocks['time_delaymicros'] = {
/**
* delayMicroseconds block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/DelayMicroseconds');
this.setColour(getColour().time);
this.appendValueInput('DELAY_TIME_MICRO')
.setCheck(Types.NUMBER.checkList)
.appendField(Blockly.Msg.ARD_TIME_DELAY);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_DELAY_MICROS);
this.setInputsInline(true);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_TIME_DELAY_MICRO_TIP);
}
};
Blockly.Blocks['time_millis'] = {
/**
* Elapsed time in milliseconds block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Millis');
this.setColour(getColour().time);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_MILLIS);
this.setOutput(true, Types.LARGE_NUMBER.typeId);
this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP);
},
/** @return {string} The type of return value for the block, an integer. */
getBlockType: function () {
return Blockly.Types.LARGE_NUMBER;
}
};
Blockly.Blocks['time_micros'] = {
/**
* Elapsed time in microseconds block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Micros');
this.setColour(getColour().time);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_MICROS);
this.setOutput(true, Types.LARGE_NUMBER.typeId);
this.setTooltip(Blockly.Msg.ARD_TIME_MICROS_TIP);
},
/**
* Should be a long (32bit), but for for now an int.
* @return {string} The type of return value for the block, an integer.
*/
getBlockType: function () {
return Types.LARGE_NUMBER;
}
};
Blockly.Blocks['infinite_loop'] = {
/**
* Waits forever, end of program.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('');
this.setColour(getColour().time);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_INF);
this.setInputsInline(true);
this.setPreviousStatement(true);
this.setTooltip(Blockly.Msg.ARD_TIME_INF_TIP);
}
};
Blockly.Blocks['sensebox_interval_timer'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_interval_timer_tip);
this.setInputsInline(true);
this.setHelpUrl('');
this.setColour(getColour().time);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_interval_timer);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(new Blockly.FieldTextInput("10000"), "interval")
.appendField(Blockly.Msg.senseBox_interval);
this.appendStatementInput('DO')
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
@@ -0,0 +1,46 @@
import Blockly from "blockly/core";
import { getColour } from "../helpers/colour";
import { getCompatibleTypes } from "../helpers/types";
Blockly.Blocks["variables_set_dynamic"] = {
init: function () {
// const type = myVar.type;
this.setColour(getColour().variables);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.appendValueInput("VALUE")
.appendField("set", "set")
.appendField("", "type")
.appendField(new Blockly.FieldVariable("VAR"), "VAR")
.appendField("to");
},
onchange: function (e) {
let variableID = this.getFieldValue("VAR");
let variable = Blockly.getMainWorkspace()
.getVariableMap()
.getVariableById(variableID);
if (variable !== null) {
this.getField("type").setValue(variable.type);
this.getInput("VALUE").setCheck(getCompatibleTypes(variable.type));
}
},
};
Blockly.Blocks["variables_get_dynamic"] = {
init: function () {
this.setColour(getColour().variables);
this.appendDummyInput()
.appendField("", "type")
.appendField(new Blockly.FieldVariable("VAR"), "VAR");
this.setOutput(true);
},
onchange: function (e) {
let variableID = this.getFieldValue("VAR");
let variable = Blockly.getMainWorkspace()
.getVariableMap()
.getVariableById(variableID);
if (variable !== null) {
this.getField("type").setValue(variable.type);
}
},
};

Some files were not shown because too many files have changed in this diff Show More