diff --git a/demos/codelab/README.md b/demos/codelab/README.md new file mode 100644 index 000000000..2a5e91315 --- /dev/null +++ b/demos/codelab/README.md @@ -0,0 +1,16 @@ +# Blockly for the Web codelab + +Code for the [Blockly for the Web codelab](https://developers.google.com/TODO). + +In this codelab, you'll learn how to use Blockly JavaScript library +to add a block code editor to a web application. + +## What you'll learn + +* How to add Blockly to a sample web app. +* How to set up a Blockly workspace. +* How to create a new block in Blockly. +* How to generate and run JavaScript code from blocks. + +Example code for each step of the codelab is available from +the [completed](completed/) directory. diff --git a/demos/codelab/app/index.html b/demos/codelab/app/index.html new file mode 100644 index 000000000..31eeff776 --- /dev/null +++ b/demos/codelab/app/index.html @@ -0,0 +1,53 @@ + + + + + + + + Blockly for the Web Codelab + + + + + + +
+

Music Maker

+

Music Maker Configuration

+
+ +
+ + + +

Tap any button to edit its code.
When complete, press Done.

+ +
+
+
1
+
2
+
3
+
+
+
4
+
5
+
6
+
+
+
7
+
8
+
9
+
+
+ +
+
+
+
+ + + + + + diff --git a/demos/codelab/app/scripts/main.js b/demos/codelab/app/scripts/main.js new file mode 100644 index 000000000..31fba5a97 --- /dev/null +++ b/demos/codelab/app/scripts/main.js @@ -0,0 +1,61 @@ +/** + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * 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. + */ + (function() { + + let currentButton; + + function handlePlay(event) { + // Add code for playing sound. + } + + function save(button) { + // Add code for saving the behavior of a button. + } + + function handleSave() { + document.body.setAttribute('mode', 'edit'); + save(currentButton); + } + + function enableEditMode() { + document.body.setAttribute('mode', 'edit'); + document.querySelectorAll('.button').forEach(btn => { + btn.removeEventListener('click', handlePlay); + btn.addEventListener('click', enableBlocklyMode); + }); + } + + function enableMakerMode() { + document.body.setAttribute('mode', 'maker'); + document.querySelectorAll('.button').forEach(btn => { + btn.addEventListener('click', handlePlay); + btn.removeEventListener('click', enableBlocklyMode); + }); + } + + function enableBlocklyMode(e) { + document.body.setAttribute('mode', 'blockly'); + currentButton = e.target; + } + + document.querySelector('#edit').addEventListener('click', enableEditMode); + document.querySelector('#done').addEventListener('click', enableMakerMode); + document.querySelector('#save').addEventListener('click', handleSave); + + enableMakerMode(); + +})(); diff --git a/demos/codelab/app/scripts/music_maker.js b/demos/codelab/app/scripts/music_maker.js new file mode 100644 index 000000000..50a8a3b7f --- /dev/null +++ b/demos/codelab/app/scripts/music_maker.js @@ -0,0 +1,33 @@ +/** + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * 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. + */ + const MusicMaker = { + queue_: [], + player_: new Audio(), + queueSound: function(soundUrl) { + this.queue_.push(soundUrl); + }, + play: function() { + let next = this.queue_.shift(); + if (next) { + this.player_.src = next; + this.player_.play(); + } + }, +}; + +MusicMaker.player_.addEventListener( + 'ended', MusicMaker.play.bind(MusicMaker)); diff --git a/demos/codelab/app/sounds/c4.m4a b/demos/codelab/app/sounds/c4.m4a new file mode 100644 index 000000000..33941cfae Binary files /dev/null and b/demos/codelab/app/sounds/c4.m4a differ diff --git a/demos/codelab/app/sounds/c5.m4a b/demos/codelab/app/sounds/c5.m4a new file mode 100644 index 000000000..49721cd31 Binary files /dev/null and b/demos/codelab/app/sounds/c5.m4a differ diff --git a/demos/codelab/app/sounds/d4.m4a b/demos/codelab/app/sounds/d4.m4a new file mode 100644 index 000000000..51bcad6c2 Binary files /dev/null and b/demos/codelab/app/sounds/d4.m4a differ diff --git a/demos/codelab/app/sounds/e4.m4a b/demos/codelab/app/sounds/e4.m4a new file mode 100644 index 000000000..d910052ef Binary files /dev/null and b/demos/codelab/app/sounds/e4.m4a differ diff --git a/demos/codelab/app/sounds/f4.m4a b/demos/codelab/app/sounds/f4.m4a new file mode 100644 index 000000000..c80a0bfd3 Binary files /dev/null and b/demos/codelab/app/sounds/f4.m4a differ diff --git a/demos/codelab/app/sounds/g4.m4a b/demos/codelab/app/sounds/g4.m4a new file mode 100644 index 000000000..45ea44830 Binary files /dev/null and b/demos/codelab/app/sounds/g4.m4a differ diff --git a/demos/codelab/app/styles/index.css b/demos/codelab/app/styles/index.css new file mode 100644 index 000000000..0ef8f3bfc --- /dev/null +++ b/demos/codelab/app/styles/index.css @@ -0,0 +1,75 @@ +main { + width: 400px; + position: relative; + margin: 0 auto; + overflow:hidden; + height: 600px; +} + +header { + background-color: green; + width: 100%; +} + +h1 { + width: 400px; + position: relative; + margin: 0 auto; + color: #fff; + font-size: 1.8em; + line-height: 2.4em; +} + +.mode-edit, +.mode-maker, +.mode-blockly { + display: none; +} + +[mode="maker"] .mode-maker, +[mode="edit"] .mode-edit, +[mode="blockly"] .mode-blockly { + display: block; +} + +.blockly-editor { + position: absolute; + top: 64px; + left: -400px; + transition: left .4s; + height: 460px; + width: 400px; + background-color: #eee; +} + +[mode="blockly"] .blockly-editor { + left: 0; +} + +.maker { + display: flex; + flex-flow: column; + justify-content: space-between; + height: 460px; + width: 400px; +} + +.maker > div { + display: flex; + justify-content: space-between; +} + +.button { + width: 120px; + height: 140px; + color: #fff; + font-size: 3em; + text-align: center; + vertical-align: middle; + line-height: 140px; +} + +.mdl-button { + margin: 1em 0; + float: right; +} diff --git a/demos/codelab/completed/finish/index.html b/demos/codelab/completed/finish/index.html new file mode 100644 index 000000000..e2d12af1b --- /dev/null +++ b/demos/codelab/completed/finish/index.html @@ -0,0 +1,73 @@ + + + + + + + + Blockly for the Web Codelab + + + + + + +
+

Music Maker

+

Music Maker Configuration

+
+ +
+ + + +

Tap any button to edit its code.
When complete, press Done.

+ +
+
+
1
+
2
+
3
+
+
+
4
+
5
+
6
+
+
+
7
+
8
+
9
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + diff --git a/demos/codelab/completed/finish/scripts/main.js b/demos/codelab/completed/finish/scripts/main.js new file mode 100644 index 000000000..03a47e050 --- /dev/null +++ b/demos/codelab/completed/finish/scripts/main.js @@ -0,0 +1,88 @@ +/** + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * 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. + */ + (function() { + + let currentButton; + + function handlePlay(event) { + loadWorkspace(event.target); + Blockly.JavaScript.addReservedWords('code'); + var code = Blockly.JavaScript.workspaceToCode(Blockly.getMainWorkspace()); + code += 'MusicMaker.play();'; + // Eval can be dangerous. For more controlled execution, check + // https://github.com/NeilFraser/JS-Interpreter. + try { + eval(code); + } catch (error) { + console.log(error); + } + } + + function loadWorkspace(button) { + let workspace = Blockly.getMainWorkspace(); + workspace.clear(); + if (button.blocklyXml) { + Blockly.Xml.domToWorkspace(button.blocklyXml, workspace); + } + } + + function save(button) { + let xml = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()); + button.blocklyXml = xml; + } + + function handleSave() { + document.body.setAttribute('mode', 'edit'); + save(currentButton); + } + + function enableEditMode() { + document.body.setAttribute('mode', 'edit'); + document.querySelectorAll('.button').forEach(btn => { + btn.removeEventListener('click', handlePlay); + btn.addEventListener('click', enableBlocklyMode); + }); + } + + function enableMakerMode() { + document.body.setAttribute('mode', 'maker'); + document.querySelectorAll('.button').forEach(btn => { + btn.addEventListener('click', handlePlay); + btn.removeEventListener('click', enableBlocklyMode); + }); + } + + function enableBlocklyMode(e) { + document.body.setAttribute('mode', 'blockly'); + currentButton = e.target; + loadWorkspace(currentButton); + } + + document.querySelector('#edit').addEventListener('click', enableEditMode); + document.querySelector('#done').addEventListener('click', enableMakerMode); + document.querySelector('#save').addEventListener('click', handleSave); + + enableMakerMode(); + + Blockly.inject('blockly-div', { + media: '/media/', + toolbox: document.getElementById('toolbox'), + toolboxPosition: 'end', + horizontalLayout: true, + scrollbars: false + }); +})(); diff --git a/demos/codelab/completed/finish/scripts/music_maker.js b/demos/codelab/completed/finish/scripts/music_maker.js new file mode 100644 index 000000000..50a8a3b7f --- /dev/null +++ b/demos/codelab/completed/finish/scripts/music_maker.js @@ -0,0 +1,33 @@ +/** + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * 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. + */ + const MusicMaker = { + queue_: [], + player_: new Audio(), + queueSound: function(soundUrl) { + this.queue_.push(soundUrl); + }, + play: function() { + let next = this.queue_.shift(); + if (next) { + this.player_.src = next; + this.player_.play(); + } + }, +}; + +MusicMaker.player_.addEventListener( + 'ended', MusicMaker.play.bind(MusicMaker)); diff --git a/demos/codelab/completed/finish/scripts/sound_blocks.js b/demos/codelab/completed/finish/scripts/sound_blocks.js new file mode 100644 index 000000000..b666d4f4d --- /dev/null +++ b/demos/codelab/completed/finish/scripts/sound_blocks.js @@ -0,0 +1,50 @@ +/** + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * 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. + */ + +Blockly.defineBlocksWithJsonArray([ + // Block for colour picker. + { + "type": "play_sound", + "message0": "Play %1", + "args0": [ + { + "type": "field_dropdown", + "name": "VALUE", + "options": [ + ["C4", "sounds/c4.m4a"], + ["D4", "sounds/d4.m4a"], + ["E4", "sounds/e4.m4a"], + ["F4", "sounds/f4.m4a"], + ["G4", "sounds/g4.m4a"], + ["A5", "sounds/a5.m4a"], + ["B5", "sounds/b5.m4a"], + ["C5", "sounds/c5.m4a"] + ] + } + ], + "previousStatement": null, + "nextStatement": null, + "colour": 355, + "tooltip": "", + "helpUrl": "" + } +]); + +Blockly.JavaScript['play_sound'] = function(block) { + var value = '\'' + block.getFieldValue('VALUE') + '\''; + return 'MusicMaker.queueSound(' + value + ');\n'; +}; diff --git a/demos/codelab/completed/finish/sounds/c4.m4a b/demos/codelab/completed/finish/sounds/c4.m4a new file mode 100644 index 000000000..33941cfae Binary files /dev/null and b/demos/codelab/completed/finish/sounds/c4.m4a differ diff --git a/demos/codelab/completed/finish/sounds/c5.m4a b/demos/codelab/completed/finish/sounds/c5.m4a new file mode 100644 index 000000000..49721cd31 Binary files /dev/null and b/demos/codelab/completed/finish/sounds/c5.m4a differ diff --git a/demos/codelab/completed/finish/sounds/d4.m4a b/demos/codelab/completed/finish/sounds/d4.m4a new file mode 100644 index 000000000..51bcad6c2 Binary files /dev/null and b/demos/codelab/completed/finish/sounds/d4.m4a differ diff --git a/demos/codelab/completed/finish/sounds/e4.m4a b/demos/codelab/completed/finish/sounds/e4.m4a new file mode 100644 index 000000000..d910052ef Binary files /dev/null and b/demos/codelab/completed/finish/sounds/e4.m4a differ diff --git a/demos/codelab/completed/finish/sounds/f4.m4a b/demos/codelab/completed/finish/sounds/f4.m4a new file mode 100644 index 000000000..c80a0bfd3 Binary files /dev/null and b/demos/codelab/completed/finish/sounds/f4.m4a differ diff --git a/demos/codelab/completed/finish/sounds/g4.m4a b/demos/codelab/completed/finish/sounds/g4.m4a new file mode 100644 index 000000000..45ea44830 Binary files /dev/null and b/demos/codelab/completed/finish/sounds/g4.m4a differ diff --git a/demos/codelab/completed/finish/styles/index.css b/demos/codelab/completed/finish/styles/index.css new file mode 100644 index 000000000..0ef8f3bfc --- /dev/null +++ b/demos/codelab/completed/finish/styles/index.css @@ -0,0 +1,75 @@ +main { + width: 400px; + position: relative; + margin: 0 auto; + overflow:hidden; + height: 600px; +} + +header { + background-color: green; + width: 100%; +} + +h1 { + width: 400px; + position: relative; + margin: 0 auto; + color: #fff; + font-size: 1.8em; + line-height: 2.4em; +} + +.mode-edit, +.mode-maker, +.mode-blockly { + display: none; +} + +[mode="maker"] .mode-maker, +[mode="edit"] .mode-edit, +[mode="blockly"] .mode-blockly { + display: block; +} + +.blockly-editor { + position: absolute; + top: 64px; + left: -400px; + transition: left .4s; + height: 460px; + width: 400px; + background-color: #eee; +} + +[mode="blockly"] .blockly-editor { + left: 0; +} + +.maker { + display: flex; + flex-flow: column; + justify-content: space-between; + height: 460px; + width: 400px; +} + +.maker > div { + display: flex; + justify-content: space-between; +} + +.button { + width: 120px; + height: 140px; + color: #fff; + font-size: 3em; + text-align: center; + vertical-align: middle; + line-height: 140px; +} + +.mdl-button { + margin: 1em 0; + float: right; +}