chore(demos): delete some duplicated demos (#6066)

* chore(demos): delete codelab folder

* chore(demos): delete custom dialog demo

* chore(demos): delete custom fields demos

* chore(demos): delete fixed injection demo

* chore(demos): delete generator demo

* chore(demos): delete interpreter demos

* chore(demos): delete max blocks demo

* chore(demos): delete graph demo

* chore(demos): remove deleted demos from index.html
This commit is contained in:
Rachel Fenichel
2022-04-07 17:04:36 -07:00
committed by GitHub
parent a202558950
commit c289b629c5
58 changed files with 0 additions and 3706 deletions

View File

@@ -1,16 +0,0 @@
# 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.

View File

@@ -1,73 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blockly for the Web Codelab</title>
<link rel="stylesheet" href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css">
<link rel="stylesheet" href="styles/index.css">
</head>
<body mode="maker">
<header class="mdl-color--cyan-500">
<h1 class="mode-maker">Music Maker</h1>
<h1 class="mode-edit mode-blockly">Music Maker Configuration</h1>
</header>
<main>
<button class="mode-maker mdl-button" id="edit">Edit</button>
<button class="mode-edit mdl-button mdl-js-button" id="done">Done</button>
<button class="mode-blockly mdl-button mdl-js-button" id="save">Save</button>
<p class="hint mode-edit">Tap any button to edit its code. <br/>When complete, press Done.</p>
<div class="maker">
<div>
<div class="button mdl-color--amber-500">1</div>
<div class="button mdl-color--yellow-500">2</div>
<div class="button mdl-color--lime-500">3</div>
</div>
<div>
<div class="button mdl-color--pink-500">4</div>
<div class="button mdl-color--red-500">5</div>
<div class="button mdl-color--light-green-500">6</div>
</div>
<div>
<div class="button mdl-color--cyan-500">7</div>
<div class="button mdl-color--teal-500">8</div>
<div class="button mdl-color--green-500">9</div>
</div>
</div>
<div class="blockly-editor">
<div id="blockly-div" style="height: 480px; width: 400px;"></div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<category name="Loops" colour="120">
<block type="controls_repeat_ext">
<value name="TIMES">
<shadow type="math_number">
<field name="NUM">5</field>
</shadow>
</value>
</block>
</category>
<category name="Sounds" colour="355">
<block type="play_sound"></block>
</category>
</xml>
</div>
</main>
<script src="../../../blockly_compressed.js"></script>
<script src="../../../blocks_compressed.js"></script>
<script src="../../../javascript_compressed.js"></script>
<script src="../../../msg/js/en.js"></script>
<script src="scripts/music_maker.js"></script>
<script src="scripts/sound_blocks.js"></script>
<script src="scripts/main.js"></script>
</body>
</html>

View File

@@ -1,77 +0,0 @@
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
(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
});
})();

View File

@@ -1,22 +0,0 @@
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
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));

View File

@@ -1,39 +0,0 @@
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
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';
};

View File

@@ -1,75 +0,0 @@
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;
}

View File

@@ -1,53 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blockly for the Web Codelab</title>
<link rel="stylesheet" href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css">
<link rel="stylesheet" href="styles/index.css">
</head>
<body mode="maker">
<header class="mdl-color--cyan-500">
<h1 class="mode-maker">Music Maker</h1>
<h1 class="mode-edit mode-blockly">Music Maker Configuration</h1>
</header>
<main>
<button class="mode-maker mdl-button" id="edit">Edit</button>
<button class="mode-edit mdl-button mdl-js-button" id="done">Done</button>
<button class="mode-blockly mdl-button mdl-js-button" id="save">Save</button>
<p class="hint mode-edit">Tap any button to edit its code. <br/>When complete, press Done.</p>
<div class="maker">
<div>
<div class="button mdl-color--amber-500">1</div>
<div class="button mdl-color--yellow-500">2</div>
<div class="button mdl-color--lime-500">3</div>
</div>
<div>
<div class="button mdl-color--pink-500">4</div>
<div class="button mdl-color--red-500">5</div>
<div class="button mdl-color--light-green-500">6</div>
</div>
<div>
<div class="button mdl-color--cyan-500">7</div>
<div class="button mdl-color--teal-500">8</div>
<div class="button mdl-color--green-500">9</div>
</div>
</div>
<div class="blockly-editor">
<div id="blockly-div" style="height: 480px; width: 400px;"></div>
</div>
</main>
<script src="scripts/music_maker.js"></script>
<script src="scripts/main.js"></script>
</body>
</html>

View File

@@ -1,50 +0,0 @@
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
(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();
})();

View File

@@ -1,22 +0,0 @@
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
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));

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,75 +0,0 @@
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;
}

View File

@@ -1,161 +0,0 @@
/**
* @license
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* An example implementation of how one might replace Blockly's browser
* dialogs. This is just an example, and applications are not encouraged to use
* it verbatim.
*
* @namespace
*/
CustomDialog = {};
/** Override Blockly.dialog.alert() with custom implementation. */
Blockly.dialog.setAlert(function(message, callback) {
console.log('Alert: ' + message);
CustomDialog.show('Alert', message, {
onCancel: callback
});
});
/** Override Blockly.dialog.confirm() with custom implementation. */
Blockly.dialog.setConfirm(function(message, callback) {
console.log('Confirm: ' + message);
CustomDialog.show('Confirm', message, {
showOkay: true,
onOkay: function() {
callback(true);
},
showCancel: true,
onCancel: function() {
callback(false);
}
});
});
/** Override Blockly.dialog.prompt() with custom implementation. */
Blockly.dialog.setPrompt(function(message, defaultValue, callback) {
console.log('Prompt: ' + message);
CustomDialog.show('Prompt', message, {
showInput: true,
showOkay: true,
onOkay: function() {
callback(CustomDialog.inputField.value);
},
showCancel: true,
onCancel: function() {
callback(null);
}
});
CustomDialog.inputField.value = defaultValue;
});
/** Hides any currently visible dialog. */
CustomDialog.hide = function() {
if (CustomDialog.backdropDiv_) {
CustomDialog.backdropDiv_.style.display = 'none';
CustomDialog.dialogDiv_.style.display = 'none';
}
};
/**
* Shows the dialog.
* Allowed options:
* - showOkay: Whether to show the OK button.
* - showCancel: Whether to show the Cancel button.
* - showInput: Whether to show the text input field.
* - onOkay: Callback to handle the okay button.
* - onCancel: Callback to handle the cancel button and backdrop clicks.
*/
CustomDialog.show = function(title, message, options) {
var backdropDiv = CustomDialog.backdropDiv_;
var dialogDiv = CustomDialog.dialogDiv_;
if (!dialogDiv) {
// Generate HTML
backdropDiv = document.createElement('div');
backdropDiv.id = 'customDialogBackdrop';
backdropDiv.style.cssText =
'position: absolute;' +
'top: 0; left: 0; right: 0; bottom: 0;' +
'background-color: rgba(0, 0, 0, .7);' +
'z-index: 100;';
document.body.appendChild(backdropDiv);
dialogDiv = document.createElement('div');
dialogDiv.id = 'customDialog';
dialogDiv.style.cssText =
'background-color: #fff;' +
'width: 400px;' +
'margin: 20px auto 0;' +
'padding: 10px;';
backdropDiv.appendChild(dialogDiv);
dialogDiv.onclick = function(event) {
event.stopPropagation();
};
CustomDialog.backdropDiv_ = backdropDiv;
CustomDialog.dialogDiv_ = dialogDiv;
}
backdropDiv.style.display = 'block';
dialogDiv.style.display = 'block';
dialogDiv.innerHTML =
'<header class="customDialogTitle"></header>' +
'<p class="customDialogMessage"></p>' +
(options.showInput ? '<div><input id="customDialogInput"></div>' : '') +
'<div class="customDialogButtons">' +
(options.showCancel ? '<button id="customDialogCancel">Cancel</button>': '') +
(options.showOkay ? '<button id="customDialogOkay">OK</button>': '') +
'</div>';
dialogDiv.getElementsByClassName('customDialogTitle')[0]
.appendChild(document.createTextNode(title));
dialogDiv.getElementsByClassName('customDialogMessage')[0]
.appendChild(document.createTextNode(message));
var onOkay = function(event) {
CustomDialog.hide();
options.onOkay && options.onOkay();
event && event.stopPropagation();
};
var onCancel = function(event) {
CustomDialog.hide();
options.onCancel && options.onCancel();
event && event.stopPropagation();
};
var dialogInput = document.getElementById('customDialogInput');
CustomDialog.inputField = dialogInput;
if (dialogInput) {
dialogInput.focus();
dialogInput.onkeyup = function(event) {
if (event.keyCode === 13) {
// Process as OK when user hits enter.
onOkay();
return false;
} else if (event.keyCode === 27) {
// Process as cancel when user hits esc.
onCancel();
return false;
}
};
} else {
var okay = document.getElementById('customDialogOkay');
okay && okay.focus();
}
if (options.showOkay) {
document.getElementById('customDialogOkay')
.addEventListener('click', onOkay);
}
if (options.showCancel) {
document.getElementById('customDialogCancel')
.addEventListener('click', onCancel);
}
backdropDiv.onclick = onCancel;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,62 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Custom Dialog</title>
<script src="../../blockly_compressed.js"></script>
<script src="../../blocks_compressed.js"></script>
<script src="../../msg/js/en.js"></script>
<style>
body {
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Custom Dialog</h1>
<p>This is a simple demo of replacing modal browser dialogs with HTML.
To see how it works, see the source code in
<a href="custom-dialog.js">custom-dialog.js</a>
</p>
<p>Try creating new variables, creating variables with names already in
use, or deleting multiple blocks on the workspace.
</p>
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<category name="Inputs" colour="%{BKY_MATH_HUE}">
<block type="math_number" gap="32">
<field name="NUM">123</field>
</block>
<block type="text"></block>
<block type="text_prompt_ext">
<value name="TEXT">
<shadow type="text">
<field name="TEXT">abc</field>
</shadow>
</value>
</block>
</category>
<sep></sep>
<category name="Variables" colour="%{BKY_VARIABLES_HUE}" custom="VARIABLE"></category>
<category name="Functions" colour="%{BKY_PROCEDURES_HUE}" custom="PROCEDURE"></category>
</xml>
<script>
var demoWorkspace = Blockly.inject('blocklyDiv',
{media: '../../media/',
toolbox: document.getElementById('toolbox')});
</script>
<script src="custom-dialog.js"></script>
</body>
</html>

View File

@@ -1,54 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Custom Fields</title>
<style>
body {
margin: 0 10%;
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
td {
padding: 1ex;
}
img {
border: none;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Custom Fields</h1>
<p>These demos are intended for developers who want creating custom block fields.</p>
<table>
<tr>
<td>
<a href="turtle/index.html">
<img src="turtle/icon.png" height=80 width=100>
</a>
</td>
<td>
<div><a href="turtle/index.html">Turtle Field</a></div>
</td>
</tr>
<tr>
<td>
<a href="pitch/index.html">
<img src="pitch/media/notes.png" height=40 width=100>
</a>
</td>
<td>
<div><a href="pitch/index.html">Pitch Field</a></div>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,18 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Pitch field demo blocks.
*/
Blockly.Blocks['test_pitch_field'] = {
init: function() {
this.appendDummyInput()
.appendField('pitch')
.appendField(new CustomFields.FieldPitch('7'), 'PITCH');
this.setStyle('loop_blocks');
}
};

View File

@@ -1,235 +0,0 @@
/**
* @license
* Copyright 2016 Google LLC
* https://github.com/google/blockly-games
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Music pitch input field. Borrowed from Blockly Games.
*/
'use strict';
goog.provide('CustomFields.FieldPitch');
goog.require('Blockly.FieldTextInput');
goog.require('Blockly.utils.math');
goog.require('Blockly.utils.object');
var CustomFields = CustomFields || {};
/**
* Class for an editable pitch field.
* @param {string} text The initial content of the field.
* @extends {Blockly.FieldTextInput}
* @constructor
*/
CustomFields.FieldPitch = function(text) {
CustomFields.FieldPitch.superClass_.constructor.call(this, text);
/**
* Click event data.
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.clickWrapper_ = null;
/**
* Move event data.
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.moveWrapper_ = null;
};
Blockly.utils.object.inherits(CustomFields.FieldPitch, Blockly.FieldTextInput);
/**
* Construct a FieldPitch from a JSON arg object.
* @param {!Object} options A JSON object with options (pitch).
* @return {!CustomFields.FieldPitch} The new field instance.
* @package
* @nocollapse
*/
CustomFields.FieldPitch.fromJson = function(options) {
return new CustomFields.FieldPitch(options['pitch']);
};
/**
* All notes available for the picker.
*/
CustomFields.FieldPitch.NOTES = 'C3 D3 E3 F3 G3 A3 B3 C4 D4 E4 F4 G4 A4'.split(/ /);
/**
* Show the inline free-text editor on top of the text and the note picker.
* @protected
*/
CustomFields.FieldPitch.prototype.showEditor_ = function() {
CustomFields.FieldPitch.superClass_.showEditor_.call(this);
var div = Blockly.WidgetDiv.getDiv();
if (!div.firstChild) {
// Mobile interface uses Blockly.dialog.prompt.
return;
}
// Build the DOM.
var editor = this.dropdownCreate_();
Blockly.DropDownDiv.getContentDiv().appendChild(editor);
Blockly.DropDownDiv.setColour(this.sourceBlock_.style.colourPrimary,
this.sourceBlock_.style.colourTertiary);
Blockly.DropDownDiv.showPositionedByField(
this, this.dropdownDispose_.bind(this));
// The note picker is different from other fields in that it updates on
// mousemove even if it's not in the middle of a drag. In future we may
// change this behaviour. For now, using bindEvent_ instead of
// bindEventWithChecks_ allows it to work without a mousedown/touchstart.
this.clickWrapper_ =
Blockly.browserEvents.bind(this.imageElement_, 'click', this, this.hide_);
this.moveWrapper_ = Blockly.browserEvents.bind(
this.imageElement_, 'mousemove', this, this.onMouseMove);
this.updateGraph_();
};
/**
* Create the pitch editor.
* @return {!Element} The newly created pitch picker.
* @private
*/
CustomFields.FieldPitch.prototype.dropdownCreate_ = function() {
this.imageElement_ = document.createElement('div');
this.imageElement_.id = 'notePicker';
return this.imageElement_;
};
/**
* Dispose of events belonging to the pitch editor.
* @private
*/
CustomFields.FieldPitch.prototype.dropdownDispose_ = function() {
if (this.clickWrapper_) {
Blockly.browserEvents.unbind(this.clickWrapper_);
this.clickWrapper_ = null;
}
if (this.moveWrapper_) {
Blockly.browserEvents.unbind(this.moveWrapper_);
this.moveWrapper_ = null;
}
this.imageElement_ = null;
};
/**
* Hide the editor.
* @private
*/
CustomFields.FieldPitch.prototype.hide_ = function() {
Blockly.WidgetDiv.hide();
Blockly.DropDownDiv.hideWithoutAnimation();
};
/**
* Set the note to match the mouse's position.
* @param {!Event} e Mouse move event.
*/
CustomFields.FieldPitch.prototype.onMouseMove = function(e) {
var bBox = this.imageElement_.getBoundingClientRect();
var dy = e.clientY - bBox.top;
var note = Blockly.utils.math.clamp(Math.round(13.5 - dy / 7.5), 0, 12);
this.imageElement_.style.backgroundPosition = (-note * 37) + 'px 0';
this.setEditorValue_(note);
};
/**
* Convert the machine-readable value (0-12) to human-readable text (C3-A4).
* @param {number|string} value The provided value.
* @return {string|undefined} The respective note, or undefined if invalid.
*/
CustomFields.FieldPitch.prototype.valueToNote = function(value) {
return CustomFields.FieldPitch.NOTES[Number(value)];
};
/**
* Convert the human-readable text (C3-A4) to machine-readable value (0-12).
* @param {string} text The provided note.
* @return {number|undefined} The respective value, or undefined if invalid.
*/
CustomFields.FieldPitch.prototype.noteToValue = function(text) {
var normalizedText = text.trim().toUpperCase();
var i = CustomFields.FieldPitch.NOTES.indexOf(normalizedText);
return i > -1 ? i : undefined;
};
/**
* Get the text to be displayed on the field node.
* @return {?string} The HTML value if we're editing, otherwise null. Null means
* the super class will handle it, likely a string cast of value.
* @protected
*/
CustomFields.FieldPitch.prototype.getText_ = function() {
if (this.isBeingEdited_) {
return CustomFields.FieldPitch.superClass_.getText_.call(this);
}
return this.valueToNote(this.getValue()) || null;
};
/**
* Transform the provided value into a text to show in the HTML input.
* @param {*} value The value stored in this field.
* @return {string} The text to show on the HTML input.
*/
CustomFields.FieldPitch.prototype.getEditorText_ = function(value) {
return this.valueToNote(value);
};
/**
* Transform the text received from the HTML input (note) into a value
* to store in this field.
* @param {string} text Text received from the HTML input.
* @return {*} The value to store.
*/
CustomFields.FieldPitch.prototype.getValueFromEditorText_ = function(text) {
return this.noteToValue(text);
};
/**
* Updates the graph when the field rerenders.
* @private
* @override
*/
CustomFields.FieldPitch.prototype.render_ = function() {
CustomFields.FieldPitch.superClass_.render_.call(this);
this.updateGraph_();
};
/**
* Redraw the note picker with the current note.
* @private
*/
CustomFields.FieldPitch.prototype.updateGraph_ = function() {
if (!this.imageElement_) {
return;
}
var i = this.getValue();
this.imageElement_.style.backgroundPosition = (-i * 37) + 'px 0';
};
/**
* Ensure that only a valid value may be entered.
* @param {*} opt_newValue The input value.
* @return {*} A valid value, or null if invalid.
*/
CustomFields.FieldPitch.prototype.doClassValidation_ = function(opt_newValue) {
if (opt_newValue === null || opt_newValue === undefined) {
return null;
}
var note = this.valueToNote(opt_newValue);
if (note) {
return opt_newValue;
}
return null;
};
Blockly.fieldRegistry.register('field_pitch', CustomFields.FieldPitch);

View File

@@ -1,118 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Blockly Demo: Custom Pitch Field</title>
<script src="../../../blockly_uncompressed.js"></script>
<script src="blocks.js"></script>
<script src="field_pitch.js"></script>
<script src="../../../msg/js/en.js"></script>
<style>
body {
margin: 0 10%;
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
td {
padding: 1ex;
}
img {
border: none;
}
</style>
<link rel="stylesheet" type="text/css" href="pitch.css">
</head>
<body onload="start()">
<h1>
<a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../../index.html">Demos</a> &gt;
<a href="../index.html">Custom Fields</a> &gt; Pitch Field</h1>
<p>This is a demo of creating custom block fields. In this case the field
is used to select a note pitch.
</p>
<p>All of the custom field implementation is in
demos/custom-fields/pitch/field_pitch.js, including comments on each required
function.
</p>
<p>
<input type="button" value="Export to XML" onclick="toXml()">
<input type="button" value="Import from XML" onclick="fromXml()">
</p>
<table>
<tr>
<td>
<textarea id="importExport"
style="width: 200px; height: 480px;"></textarea>
</td>
<td>
<div id="blocklyDiv" style="width: 600px; height: 480px;"></div>
</td>
</tr>
</table>
<script>
function toXml() {
var output = document.getElementById('importExport');
var xml = Blockly.Xml.workspaceToDom(workspace);
output.value = Blockly.Xml.domToPrettyText(xml);
output.focus();
output.select();
}
function fromXml() {
var input = document.getElementById('importExport');
var xml = Blockly.Xml.textToDom(input.value);
Blockly.Xml.domToWorkspace(xml, workspace);
}
function appendDom() {
var blocks = document.getElementById('workspace-blocks');
if (blocks.firstElementChild) {
Blockly.Xml.appendDomToWorkspace(blocks, workspace);
}
}
function start() {
workspace = Blockly.inject('blocklyDiv', options);
appendDom();
workspace.scrollCenter();
}
var options = {
media: '../../../media/',
grid: {
spacing: 25,
length: 3,
colour: '#ccc'
},
move: {
scrollbars: true,
drag: true,
wheel: true,
},
zoom: {
controls: true,
startScale: 1.0,
maxScale: 4,
minScale: 0.25,
scaleSpeed: 1.1
}
/*toolbox: document.getElementById('toolbox')*/
}
</script>
<xml xmlns="https://developers.google.com/blockly/xml" id="workspace-blocks" style="display: none">
<block type="test_pitch_field"></block>
</xml>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 894 B

View File

@@ -1,13 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
#notePicker {
background-image: url(media/notes.png);
border: 1px solid #ccc;
height: 109px;
width: 46px;
}

View File

@@ -1,91 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Turtle field demo blocks.
*/
Blockly.Blocks['turtle_basic'] = {
init: function() {
this.appendDummyInput()
.appendField('simple turtle');
this.appendDummyInput()
.setAlign(Blockly.ALIGN_CENTRE)
.appendField(new CustomFields.FieldTurtle(), 'TURTLE');
this.setStyle('loop_blocks');
this.setCommentText('Demonstrates a turtle field with no validator.');
}
};
Blockly.Blocks['turtle_nullifier'] = {
init: function() {
this.appendDummyInput()
.appendField('no trademarks');
this.appendDummyInput()
.setAlign(Blockly.ALIGN_CENTRE)
.appendField(new CustomFields.FieldTurtle(null, null, null, this.validate)
, 'TURTLE');
this.setStyle('loop_blocks');
this.setCommentText('Validates combinations of names and hats to null' +
' (invalid) if they could be considered infringe-y. This turns the' +
' turtle field red. Infringe-y combinations are: (Leonardo, Mask),' +
' (Yertle, Crown), and (Franklin, Propeller).');
},
validate: function(newValue) {
this.cachedValidatedValue_ = {
turtleName: newValue.turtleName,
pattern: newValue.pattern,
hat: newValue.hat,
};
if ((newValue.turtleName === 'Leonardo' && newValue.hat === 'Mask') ||
(newValue.turtleName === 'Yertle' && newValue.hat === 'Crown') ||
(newValue.turtleName === 'Franklin') && newValue.hat === 'Propeller') {
var currentValue = this.getValue();
if (newValue.turtleName !== currentValue.turtleName) {
// Turtle name changed.
this.cachedValidatedValue_.turtleName = null;
} else {
// Hat must have changed.
this.cachedValidatedValue_.hat = null;
}
return null;
}
return newValue;
}
};
Blockly.Blocks['turtle_changer'] = {
init: function() {
this.appendDummyInput()
.setAlign(Blockly.ALIGN_CENTRE)
.appendField('force hats');
this.appendDummyInput()
.appendField(new CustomFields.FieldTurtle(
'Dots', 'Crown', 'Yertle', this.validate), 'TURTLE');
this.setStyle('loop_blocks');
this.setCommentText('Validates the input so that certain names always' +
' have specific hats. The name-hat combinations are: (Leonardo, Mask),' +
' (Yertle, Crown), (Franklin, Propeller).');
},
validate: function(newValue) {
switch(newValue.turtleName) {
case 'Leonardo':
newValue.hat = 'Mask';
break;
case 'Yertle':
newValue.hat = 'Crown';
break;
case 'Franklin':
newValue.hat = 'Propeller';
break;
}
return newValue;
}
};

View File

@@ -1,747 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview A field used to customize a turtle.
*/
'use strict';
// You must provide the constructor for your custom field.
goog.provide('CustomFields.FieldTurtle');
// You must require the abstract field class to inherit from.
goog.require('Blockly.Field');
goog.require('Blockly.fieldRegistry');
goog.require('Blockly.utils');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Size');
var CustomFields = CustomFields || {};
// Generally field's values should be optional, and have logical defaults.
// If this is not possible (for example image fields can't have logical
// defaults) the field should throw a clear error when a value is not provided.
// Editable fields also generally accept validators, so we will accept a
// validator.
CustomFields.FieldTurtle = function(
opt_pattern, opt_hat, opt_turtleName, opt_validator) {
// The turtle field contains an object as its value, so we need to compile
// the parameters into an object.
var value = {};
value.pattern = opt_pattern || CustomFields.FieldTurtle.PATTERNS[0];
value.hat = opt_hat || CustomFields.FieldTurtle.HATS[0];
value.turtleName = opt_turtleName || CustomFields.FieldTurtle.NAMES[0];
// A field constructor should always call its parent constructor, because
// that helps keep the code organized and DRY.
CustomFields.FieldTurtle.superClass_.constructor.call(
this, value, opt_validator);
/**
* The size of the area rendered by the field.
* @type {Blockly.utils.Size}
* @protected
* @override
*/
this.size_ = new Blockly.utils.Size(0, 0);
};
Blockly.utils.object.inherits(CustomFields.FieldTurtle, Blockly.Field);
// This allows the field to be constructed using a JSON block definition.
CustomFields.FieldTurtle.fromJson = function(options) {
// In this case we simply pass the JSON options along to the constructor,
// but you can also use this to get message references, and other such things.
return new CustomFields.FieldTurtle(
options['pattern'],
options['hat'],
options['turtleName']);
};
// Since this field is editable we must also define serializable as true
// (for backwards compatibility reasons serializable is false by default).
CustomFields.FieldTurtle.prototype.SERIALIZABLE = true;
// The cursor property defines what the mouse will look like when the user
// hovers over the field. By default the cursor will be whatever
// .blocklyDraggable's cursor is defined as (vis. grab). Most fields define
// this property as 'default'.
CustomFields.FieldTurtle.prototype.CURSOR = 'pointer';
// How far to move the text to keep it to the right of the turtle.
// May change if the turtle gets fancy enough.
CustomFields.FieldTurtle.prototype.TEXT_OFFSET_X = 80;
// These are the different options for our turtle. Being declared this way
// means they are static, and not translatable. If you want to do something
// similar, but make it translatable you should set up your options like a
// dropdown field, with language-neutral keys and human-readable values.
CustomFields.FieldTurtle.PATTERNS =
['Dots', 'Stripes', 'Hexagons'];
CustomFields.FieldTurtle.HATS =
['Stovepipe', 'Crown', 'Propeller', 'Mask', 'Fedora'];
CustomFields.FieldTurtle.NAMES =
['Yertle', 'Franklin', 'Crush', 'Leonardo', 'Bowser', 'Squirtle', 'Oogway'];
// Used to keep track of our editor event listeners, so they can be
// properly disposed of when the field closes. You can keep track of your
// listeners however you want, just be sure to dispose of them!
CustomFields.FieldTurtle.prototype.editorListeners_ = [];
// Used to create the DOM of our field.
CustomFields.FieldTurtle.prototype.initView = function() {
// Because we want to have both a borderRect_ (background) and a
// textElement_ (text) we can call the super-function. If we only wanted
// one or the other, we could call their individual createX functions.
CustomFields.FieldTurtle.superClass_.initView.call(this);
// Note that the field group is created by the abstract field's init_
// function. This means that *all elements* should be children of the
// fieldGroup_.
this.createView_();
};
// Updates how the field looks depending on if it is editable or not.
CustomFields.FieldTurtle.prototype.updateEditable = function() {
if (!this.fieldGroup_) {
// Not initialized yet.
return;
}
// The default functionality just makes it so the borderRect_ does not
// highlight when hovered.
Blockly.FieldColour.superClass_.updateEditable.call(this);
// Things like this are best applied to the clickTarget_. By default the
// click target is the same as getSvgRoot, which by default is the
// fieldGroup_.
var group = this.getClickTarget_();
if (!this.isCurrentlyEditable()) {
group.style.cursor = 'not-allowed';
} else {
group.style.cursor = this.CURSOR;
}
};
// Gets the text to display when the block is collapsed
CustomFields.FieldTurtle.prototype.getText = function() {
var text = this.value_.turtleName + ' wearing a ' + this.value_.hat;
if (this.value_.hat === 'Stovepipe' || this.value_.hat === 'Propeller') {
text += ' hat';
}
return text;
};
// Makes sure new field values (given to setValue) are valid, meaning
// something this field can legally "hold". Class validators can either change
// the input value, or return null if the input value is invalid. Called by
// the setValue() function.
CustomFields.FieldTurtle.prototype.doClassValidation_ = function(newValue) {
// Undefined signals that we want the value to remain unchanged. This is a
// special feature of turtle fields, but could be useful for other
// multi-part fields.
if (newValue.pattern === undefined) {
newValue.pattern = this.displayValue_ && this.displayValue_.pattern;
// We only want to allow patterns that are part of our pattern list.
// Anything else is invalid, so we return null.
} else if (CustomFields.FieldTurtle.PATTERNS.indexOf(newValue.pattern) === -1) {
newValue.pattern = null;
}
if (newValue.hat === undefined) {
newValue.hat = this.displayValue_ && this.displayValue_.hat;
} else if (CustomFields.FieldTurtle.HATS.indexOf(newValue.hat) === -1) {
newValue.hat = null;
}
if (newValue.turtleName === undefined) {
newValue.turtleName = this.displayValue_ && this.displayValue_.turtleName;
} else if (CustomFields.FieldTurtle.NAMES.indexOf(newValue.turtleName) === -1) {
newValue.turtleName = null;
}
// This is a strategy for dealing with defaults on multi-part values.
// The class validator sets individual properties of the object to null
// to indicate that they are invalid, and then caches that object to the
// cachedValidatedValue_ property. This way the field can, for
// example, properly handle an invalid pattern, combined with a valid hat.
// This can also be done with local validators.
this.cachedValidatedValue_ = newValue;
// Always be sure to return!
if (!newValue.pattern || !newValue.hat || !newValue.turtleName) {
return null;
}
return newValue;
};
// Saves the new field value. Called by the setValue function.
CustomFields.FieldTurtle.prototype.doValueUpdate_ = function(newValue) {
// The default function sets this field's this.value_ property to the
// newValue, and its this.isDirty_ property to true. The isDirty_ property
// tells the setValue function whether the field needs to be re-rendered.
CustomFields.FieldTurtle.superClass_.doValueUpdate_.call(this, newValue);
this.displayValue_ = newValue;
// Since this field has custom UI for invalid values, we also want to make
// sure it knows it is now valid.
this.isValueInvalid_ = false;
};
// Notifies that the field that the new value was invalid. Called by
// setValue function. Can either be triggered by the class validator, or the
// local validator.
CustomFields.FieldTurtle.prototype.doValueInvalid_ = function(invalidValue) {
// By default this function is no-op, meaning if the new value is invalid
// the field simply won't be updated. This field has custom UI for invalid
// values, so we override this function.
// We want the value to be displayed like normal.
// But we want to flag it as invalid, so the render_ function knows to
// make the borderRect_ red.
this.displayValue_ = invalidValue;
this.isDirty_ = true;
this.isValueInvalid_ = true;
};
// Updates the field's on-block display based on the current display value.
CustomFields.FieldTurtle.prototype.render_ = function() {
var value = this.displayValue_;
// Always do editor updates inside render. This makes sure the editor
// always displays the correct value, even if a validator changes it.
if (this.editor_) {
this.renderEditor_();
}
this.stovepipe_.style.display = 'none';
this.crown_.style.display = 'none';
this.mask_.style.display = 'none';
this.propeller_.style.display = 'none';
this.fedora_.style.display = 'none';
switch(value.hat) {
case 'Stovepipe':
this.stovepipe_.style.display = '';
this.turtleGroup_.setAttribute('transform', 'translate(0,12)');
this.textElement_.setAttribute(
'transform', 'translate(' + this.TEXT_OFFSET_X + ',20)');
break;
case 'Crown':
this.crown_.style.display = '';
this.turtleGroup_.setAttribute('transform', 'translate(0,9)');
this.textElement_.setAttribute(
'transform', 'translate(' + this.TEXT_OFFSET_X + ',16)');
break;
case 'Mask':
this.mask_.style.display = '';
this.turtleGroup_.setAttribute('transform', 'translate(0,6)');
this.textElement_.setAttribute('transform',
'translate(' + this.TEXT_OFFSET_X + ',12)');
break;
case 'Propeller':
this.propeller_.style.display = '';
this.turtleGroup_.setAttribute('transform', 'translate(0,6)');
this.textElement_.setAttribute('transform',
'translate(' + this.TEXT_OFFSET_X + ',12)');
break;
case 'Fedora':
this.fedora_.style.display = '';
this.turtleGroup_.setAttribute('transform', 'translate(0,6)');
this.textElement_.setAttribute('transform',
'translate(' + this.TEXT_OFFSET_X + ',12)');
break;
}
switch(value.pattern) {
case 'Dots':
this.shellPattern_.setAttribute('fill', 'url(#polkadots)');
break;
case 'Stripes':
this.shellPattern_.setAttribute('fill', 'url(#stripes)');
break;
case 'Hexagons':
this.shellPattern_.setAttribute('fill', 'url(#hexagons)');
break;
}
// Always modify the textContent_ rather than the textElement_. This
// allows fields to append DOM to the textElement (e.g. the angle field).
this.textContent_.nodeValue = value.turtleName;
if (this.isValueInvalid_) {
this.borderRect_.style.fill = '#f99';
this.borderRect_.style.fillOpacity = 1;
} else {
this.borderRect_.style.fill = '#fff';
this.borderRect_.style.fillOpacity = 0.6;
}
this.updateSize_();
};
CustomFields.FieldTurtle.prototype.renderEditor_ = function() {
var value = this.displayValue_;
// .textElement is a property assigned to the element.
// It allows the text to be edited without destroying the warning icon.
this.editor_.patternText.textElement.nodeValue = value.pattern;
this.editor_.hatText.textElement.nodeValue = value.hat;
this.editor_.turtleNameText.textElement.nodeValue = value.turtleName;
this.editor_.patternText.warningIcon.style.display =
this.cachedValidatedValue_.pattern ? 'none' : '';
this.editor_.hatText.warningIcon.style.display =
this.cachedValidatedValue_.hat ? 'none' : '';
this.editor_.turtleNameText.warningIcon.style.display =
this.cachedValidatedValue_.turtleName ? 'none' : '';
};
// Used to update the size of the field. This function's logic could be simply
// included inside render_ (it is not called anywhere else), but it is
// usually separated to keep code more organized.
CustomFields.FieldTurtle.prototype.updateSize_ = function() {
var bbox = this.movableGroup_.getBBox();
var width = bbox.width;
var height = bbox.height;
if (this.borderRect_) {
width += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
height += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
this.borderRect_.setAttribute('width', width);
this.borderRect_.setAttribute('height', height);
}
// Note how both the width and the height can be dynamic.
this.size_.width = width;
this.size_.height = height;
};
// Called when the field is clicked. It is usually used to show an editor,
// but it can also be used for other things e.g. the checkbox field uses
// this function to check/uncheck itself.
CustomFields.FieldTurtle.prototype.showEditor_ = function() {
this.editor_ = this.dropdownCreate_();
this.renderEditor_();
Blockly.DropDownDiv.getContentDiv().appendChild(this.editor_);
// These allow us to have the editor match the block's colour.
var fillColour = this.sourceBlock_.getColour();
Blockly.DropDownDiv.setColour(fillColour,
this.sourceBlock_.style.colourTertiary);
// Always pass the dropdown div a dispose function so that you can clean
// up event listeners when the editor closes.
Blockly.DropDownDiv.showPositionedByField(
this, this.dropdownDispose_.bind(this));
};
// Creates the UI of the editor, and adds event listeners to it.
CustomFields.FieldTurtle.prototype.dropdownCreate_ = function() {
var createRow = function(table) {
var row = table.appendChild(document.createElement('tr'));
row.className = 'row';
return row;
};
var createLeftArrow = function(row) {
var cell = document.createElement('div');
cell.className = 'arrow';
var leftArrow = document.createElement('button');
leftArrow.setAttribute('type', 'button');
leftArrow.textContent = '<';
cell.appendChild(leftArrow);
row.appendChild(cell);
return cell;
};
var createTextNode = function(row, text) {
var cell = document.createElement('div');
cell.className = 'text';
var text = document.createTextNode(text);
cell.appendChild(text);
cell.textElement = text;
var warning = document.createElement('img');
warning.setAttribute('src', 'media/warning.svg');
warning.setAttribute('height', '16px');
warning.setAttribute('width', '16px');
warning.style.marginLeft = '4px';
cell.appendChild(warning);
cell.warningIcon = warning;
row.appendChild(cell);
return cell;
};
var createRightArrow = function(row) {
var cell = document.createElement('div');
cell.className = 'arrow';
var rightArrow = document.createElement('button');
rightArrow.setAttribute('type', 'button');
rightArrow.textContent = '>';
cell.appendChild(rightArrow);
row.appendChild(cell);
return cell;
};
var createArrowListener = function(variable, array, direction) {
return function() {
var currentIndex = array.indexOf(this.displayValue_[variable]);
currentIndex += direction;
if (currentIndex <= -1) {
currentIndex = array.length - 1;
} else if (currentIndex >= array.length) {
currentIndex = 0;
}
var value = {};
value[variable] = array[currentIndex];
this.setValue(value);
};
};
var widget = document.createElement('div');
widget.className = 'customFieldsTurtleWidget blocklyNonSelectable';
var table = document.createElement('div');
table.className = 'table';
widget.appendChild(table);
var row = createRow(table);
var leftArrow = createLeftArrow(row);
widget.patternText = createTextNode(row, this.displayValue_.pattern);
var rightArrow = createRightArrow(row);
this.editorListeners_.push(Blockly.browserEvents.bind(
leftArrow, 'mouseup', this,
createArrowListener('pattern', CustomFields.FieldTurtle.PATTERNS, -1)));
this.editorListeners_.push(Blockly.browserEvents.bind(
rightArrow, 'mouseup', this,
createArrowListener('pattern', CustomFields.FieldTurtle.PATTERNS, 1)));
row = createRow(table);
leftArrow = createLeftArrow(row);
widget.hatText = createTextNode(row, this.displayValue_.hat);
rightArrow = createRightArrow(row);
this.editorListeners_.push(Blockly.browserEvents.bind(
leftArrow, 'mouseup', this,
createArrowListener('hat', CustomFields.FieldTurtle.HATS, -1)));
this.editorListeners_.push(Blockly.browserEvents.bind(
rightArrow, 'mouseup', this,
createArrowListener('hat', CustomFields.FieldTurtle.HATS, 1)));
row = createRow(table);
leftArrow = createLeftArrow(row);
widget.turtleNameText = createTextNode(row, this.displayValue_.turtleName);
rightArrow = createRightArrow(row);
this.editorListeners_.push(Blockly.browserEvents.bind(
leftArrow, 'mouseup', this,
createArrowListener('turtleName', CustomFields.FieldTurtle.NAMES, -1)));
this.editorListeners_.push(Blockly.browserEvents.bind(
rightArrow, 'mouseup', this,
createArrowListener('turtleName', CustomFields.FieldTurtle.NAMES, 1)));
var randomizeButton = document.createElement('button');
randomizeButton.className = 'randomize';
randomizeButton.setAttribute('type', 'button');
randomizeButton.textContent = 'randomize turtle';
this.editorListeners_.push(
Blockly.browserEvents.bind(randomizeButton, 'mouseup', this, function() {
var value = {};
value.pattern = CustomFields.FieldTurtle.PATTERNS[Math.floor(
Math.random() * CustomFields.FieldTurtle.PATTERNS.length)];
value.hat = CustomFields.FieldTurtle.HATS[Math.floor(
Math.random() * CustomFields.FieldTurtle.HATS.length)];
value.turtleName = CustomFields.FieldTurtle.NAMES[Math.floor(
Math.random() * CustomFields.FieldTurtle.NAMES.length)];
this.setValue(value);
}));
widget.appendChild(randomizeButton);
return widget;
};
// Cleans up any event listeners that were attached to the now hidden editor.
CustomFields.FieldTurtle.prototype.dropdownDispose_ = function() {
for (var i = this.editorListeners_.length, listener;
listener = this.editorListeners_[i]; i--) {
Blockly.browserEvents.unbind(listener);
this.editorListeners_.pop();
}
};
// Updates the field's colour based on the colour of the block. Called by
// block.applyColour.
CustomFields.FieldTurtle.prototype.applyColour = function() {
if (!this.sourceBlock_) {
return;
}
// The getColourX functions are the best way to access the colours of a block.
var isShadow = this.sourceBlock_.isShadow();
var fillColour = isShadow ?
this.sourceBlock_.getColourShadow() : this.sourceBlock_.getColour();
// This is technically a package function, meaning it could change.
var borderColour = isShadow ? fillColour :
this.sourceBlock_.style.colourTertiary;
if (this.turtleGroup_) {
var child = this.turtleGroup_.firstChild;
while(child) {
// If it is a text node, continue.
if (child.nodeType === 3) {
child = child.nextSibling;
continue;
}
// Or if it is a non-turtle node, continue.
var className = child.getAttribute('class');
if (!className || className.indexOf('turtleBody') === -1) {
child = child.nextSibling;
continue;
}
child.style.fill = fillColour;
child.style.stroke = borderColour;
child = child.nextSibling;
}
}
};
// Saves the field's value to an XML node. Allows for custom serialization.
CustomFields.FieldTurtle.prototype.toXml = function(fieldElement) {
// The default implementation of this function creates a node that looks
// like this: (where value is returned by getValue())
// <field name="FIELDNAME">value</field>
// But this doesn't work for our field because it stores an /object/.
fieldElement.setAttribute('pattern', this.value_.pattern);
fieldElement.setAttribute('hat', this.value_.hat);
// The textContent usually contains whatever is closest to the field's
// 'value'. The textContent doesn't need to contain anything, but saving
// something to it does aid in readability.
fieldElement.textContent = this.value_.turtleName;
// Always return the element!
return fieldElement;
};
// Sets the field's value based on an XML node. Allows for custom
// de-serialization.
CustomFields.FieldTurtle.prototype.fromXml = function(fieldElement) {
// Because we had to do custom serialization for this field, we also need
// to do custom de-serialization.
var value = {};
value.pattern = fieldElement.getAttribute('pattern');
value.hat = fieldElement.getAttribute('hat');
value.turtleName = fieldElement.textContent;
// The end goal is to call this.setValue()
this.setValue(value);
};
// Blockly needs to know the JSON name of this field. Usually this is
// registered at the bottom of the field class.
Blockly.fieldRegistry.register('field_turtle', CustomFields.FieldTurtle);
// Called by initView to create all of the SVGs. This is just used to keep
// the code more organized.
CustomFields.FieldTurtle.prototype.createView_ = function() {
this.movableGroup_ = Blockly.utils.dom.createSvgElement('g',
{
'transform': 'translate(0,5)'
}, this.fieldGroup_);
var scaleGroup = Blockly.utils.dom.createSvgElement('g',
{
'transform': 'scale(1.5)'
}, this.movableGroup_);
this.turtleGroup_ = Blockly.utils.dom.createSvgElement('g',
{
// Makes the smaller turtle graphic align with the hats.
'class': 'turtleBody'
}, scaleGroup);
var tail = Blockly.utils.dom.createSvgElement('path',
{
'class': 'turtleBody',
'd': 'M7,27.5H0.188c3.959-2,6.547-2.708,8.776-5.237',
'transform': 'translate(0.312 -12.994)'
}, this.turtleGroup_);
var legLeft = Blockly.utils.dom.createSvgElement('rect',
{
'class': 'turtleBody',
'x': 8.812,
'y': 12.506,
'width': 4,
'height': 10
}, this.turtleGroup_);
var legRight = Blockly.utils.dom.createSvgElement('rect',
{
'class': 'turtleBody',
'x': 28.812,
'y': 12.506,
'width': 4,
'height': 10
}, this.turtleGroup_);
var head = Blockly.utils.dom.createSvgElement('path',
{
'class': 'turtleBody',
'd': 'M47.991,17.884c0,1.92-2.144,3.477-4.788,3.477a6.262,6.262,0,0,1-2.212-.392c-0.2-.077-1.995,2.343-4.866,3.112a17.019,17.019,0,0,1-6.01.588c-4.413-.053-2.5-3.412-2.745-3.819-0.147-.242,2.232.144,6.126-0.376a7.392,7.392,0,0,0,4.919-2.588c0-1.92,2.144-3.477,4.788-3.477S47.991,15.964,47.991,17.884Z',
'transform': 'translate(0.312 -12.994)'
}, this.turtleGroup_);
var smile = Blockly.utils.dom.createSvgElement('path',
{
'class': 'turtleBody',
'd': 'M42.223,18.668a3.614,3.614,0,0,0,2.728,2.38',
'transform': 'translate(0.312 -12.994)'
}, this.turtleGroup_);
var sclera = Blockly.utils.dom.createSvgElement('ellipse',
{
'cx': 43.435,
'cy': 2.61,
'rx': 2.247,
'ry': 2.61,
'fill': '#fff'
}, this.turtleGroup_);
var pupil = Blockly.utils.dom.createSvgElement('ellipse',
{
'cx': 44.166,
'cy': 3.403,
'rx': 1.318,
'ry': 1.62
}, this.turtleGroup_);
var shell = Blockly.utils.dom.createSvgElement('path',
{
'class': 'turtleBody',
'd': 'M33.4,27.5H7.193c0-6,5.866-13.021,13.1-13.021S33.4,21.5,33.4,27.5Z',
'transform': 'translate(0.312 -12.994)'
}, this.turtleGroup_);
this.shellPattern_ = Blockly.utils.dom.createSvgElement('path',
{
'd': 'M33.4,27.5H7.193c0-6,5.866-13.021,13.1-13.021S33.4,21.5,33.4,27.5Z',
'transform': 'translate(0.312 -12.994)'
}, this.turtleGroup_);
this.stovepipe_ = Blockly.utils.dom.createSvgElement('image',
{
'width': '50',
'height': '18'
}, scaleGroup);
this.stovepipe_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
'media/stovepipe.svg');
this.crown_ = Blockly.utils.dom.createSvgElement('image',
{
'width': '50',
'height': '15'
}, scaleGroup);
this.crown_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
'media/crown.svg');
this.mask_ = Blockly.utils.dom.createSvgElement('image',
{
'width': '50',
'height': '24'
}, scaleGroup);
this.mask_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
'media/mask.svg');
this.propeller_ = Blockly.utils.dom.createSvgElement('image',
{
'width': '50',
'height': '11'
}, scaleGroup);
this.propeller_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
'media/propeller.svg');
this.fedora_ = Blockly.utils.dom.createSvgElement('image',
{
'width': '50',
'height': '12'
}, scaleGroup);
this.fedora_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
'media/fedora.svg');
// Even if we're not going to display it right away, we want to create all
// of our DOM elements inside this function.
this.crown_.style.display = 'none';
this.mask_.style.display = 'none';
this.propeller_.style.display = 'none';
this.fedora_.style.display = 'none';
this.movableGroup_.appendChild(this.textElement_);
this.textElement_.setAttribute(
'transform', 'translate(' + this.TEXT_OFFSET_X + ',20)');
this.defs_ = Blockly.utils.dom.createSvgElement('defs', {}, this.fieldGroup_);
this.polkadotPattern_ = Blockly.utils.dom.createSvgElement('pattern',
{
'id': 'polkadots',
'patternUnits': 'userSpaceOnUse',
'width': 10,
'height': 10
}, this.defs_);
this.polkadotGroup_ = Blockly.utils.dom.createSvgElement(
'g', {}, this.polkadotPattern_);
Blockly.utils.dom.createSvgElement('circle',
{
'cx': 2.5,
'cy': 2.5,
'r': 2.5,
'fill': '#000',
'fill-opacity': .3
}, this.polkadotGroup_);
Blockly.utils.dom.createSvgElement('circle',
{
'cx': 7.5,
'cy': 7.5,
'r': 2.5,
'fill': '#000',
'fill-opacity': .3
}, this.polkadotGroup_);
this.hexagonPattern_ = Blockly.utils.dom.createSvgElement('pattern',
{
'id': 'hexagons',
'patternUnits': 'userSpaceOnUse',
'width': 10,
'height': 8.68,
'patternTransform': 'translate(2) rotate(45)'
}, this.defs_);
Blockly.utils.dom.createSvgElement('polygon',
{
'id': 'hex',
'points': '4.96,4.4 7.46,5.84 7.46,8.74 4.96,10.18 2.46,8.74 2.46,5.84',
'stroke': '#000',
'stroke-opacity': .3,
'fill-opacity': 0
}, this.hexagonPattern_);
var use = Blockly.utils.dom.createSvgElement('use',
{
'x': 5,
}, this.hexagonPattern_);
use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#hex');
use = Blockly.utils.dom.createSvgElement('use',
{
'x': -5,
}, this.hexagonPattern_);
use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#hex');
use = Blockly.utils.dom.createSvgElement('use',
{
'x': 2.5,
'y': -4.34
}, this.hexagonPattern_);
use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#hex');
use = Blockly.utils.dom.createSvgElement('use',
{
'x': -2.5,
'y': -4.34
}, this.hexagonPattern_);
use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#hex');
this.stripesPattern_ = Blockly.utils.dom.createSvgElement('pattern',
{
'id': 'stripes',
'patternUnits': 'userSpaceOnUse',
'width': 5,
'height': 10,
'patternTransform': 'rotate(45)'
}, this.defs_);
Blockly.utils.dom.createSvgElement('line',
{
'x1': 0,
'y1': 0,
'x2': 0,
'y2': 10,
'stroke-width': 4,
'stroke': '#000',
'stroke-opacity': .3
}, this.stripesPattern_);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -1,173 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Blockly Demo: Custom Turtle Field</title>
<script src="../../../blockly_uncompressed.js"></script>
<script src="blocks.js"></script>
<script src="field_turtle.js"></script>
<script src="../../../msg/js/en.js"></script>
<style>
body {
margin: 0 10%;
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
td {
padding: 1ex;
}
img {
border: none;
}
</style>
<link rel="stylesheet" type="text/css" href="turtle.css">
</head>
<body onload="start()">
<h1>
<a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../../index.html">Demos</a> &gt;
<a href="../index.html">Custom Fields</a> &gt; Turtle Field</h1>
<p>This is a demo of creating custom block fields. In this case the field
is used to define a turtle.
</p>
<p>All of the custom field implementation is in
demos/custom-fields/turtle/field_turtle.js, including comments on each required
function.
</p>
<p>Click on the blocks' comment icons to learn what they are demonstrating.
Use the buttons below to see how the fields react to changes.
</p>
<p>
<input type="button" value="set random style" onclick="setRandomStyle()">
<input type="button" value="toggle shadow" onclick="toggleShadow()">
<input type="button" value="toggle enabled" onclick="toggleEnabled()">
<input type="button" value="toggle editable" onclick="toggleEditable()">
<input type="button" value="toggle collapsed" onclick="toggleCollapsed()">
</p>
<p>
<input type="button" value="Export to XML" onclick="toXml()">
<input type="button" value="Import from XML" onclick="fromXml()">
</p>
<table>
<tr>
<td>
<textarea id="importExport"
style="width: 200px; height: 480px;"></textarea>
</td>
<td>
<div id="blocklyDiv" style="width: 600px; height: 480px;"></div>
</td>
</tr>
</table>
<script>
function toXml() {
var output = document.getElementById('importExport');
var xml = Blockly.Xml.workspaceToDom(workspace);
output.value = Blockly.Xml.domToPrettyText(xml);
output.focus();
output.select();
}
function fromXml() {
var input = document.getElementById('importExport');
var xml = Blockly.Xml.textToDom(input.value);
Blockly.Xml.domToWorkspace(xml, workspace);
}
function setRandomStyle() {
var blocks = workspace.getAllBlocks(false);
var styles =
Object.keys(workspace.getRenderer().getConstants().blockStyles);
styles.splice(styles.indexOf(blocks[0].getStyleName()), 1);
var style = styles[Math.floor(Math.random() * styles.length)];
for(var i = 0, block; block = blocks[i]; i++) {
block.setStyle(style);
}
}
function toggleShadow() {
var blocks = workspace.getAllBlocks(false);
for(var i = 0, block; block = blocks[i]; i++) {
block.setShadow(!block.isShadow());
}
}
function toggleEnabled() {
var blocks = workspace.getAllBlocks(false);
for(var i = 0, block; block = blocks[i]; i++) {
block.setEnabled(!block.isEnabled());
}
}
function toggleEditable() {
workspace.hideChaff();
var blocks = workspace.getAllBlocks(false);
for(var i = 0, block; block = blocks[i]; i++) {
block.setEditable(!block.isEditable());
}
}
function toggleCollapsed() {
workspace.hideChaff();
var blocks = workspace.getAllBlocks(false);
for(var i = 0, block; block = blocks[i]; i++) {
block.setCollapsed(!block.isCollapsed());
}
}
function appendDom() {
var blocks = document.getElementById('workspace-blocks');
if (blocks.firstElementChild) {
Blockly.Xml.appendDomToWorkspace(blocks, workspace);
}
}
function start() {
workspace = Blockly.inject('blocklyDiv', options);
appendDom();
workspace.scrollCenter();
}
var options = {
media: '../../../media/',
grid: {
spacing: 25,
length: 3,
colour: '#ccc'
},
move: {
scrollbars: true,
drag: true,
wheel: true,
},
zoom: {
controls: true,
startScale: 1.0,
maxScale: 4,
minScale: 0.25,
scaleSpeed: 1.1
}
/*toolbox: document.getElementById('toolbox')*/
}
</script>
<xml xmlns="https://developers.google.com/blockly/xml" id="workspace-blocks" style="display: none">
<block type="turtle_basic"></block>
<block type="turtle_nullifier" y="120"></block>
<block type="turtle_changer" y="230"></block>
</xml>
</body>
</html>

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 15"><defs><style>.a{fill:#fff200;}.b{fill:#f3bd1f;}</style></defs><title>crown</title><polygon class="a" points="38.778 13.941 46.824 9.457 44.8 1.575 43.401 7.589 38.826 4.23 39.147 9.918 33.292 8.096 38.778 13.941"/><circle class="a" cx="33.228" cy="7.972" r="1.194" transform="translate(0.253 16.931) rotate(-28.691)"/><circle class="a" cx="38.785" cy="4.3" r="1.194" transform="translate(2.698 19.148) rotate(-28.691)"/><circle class="a" cx="44.662" cy="1.663" r="1.194" transform="translate(4.685 21.646) rotate(-28.691)"/><polygon class="b" points="37.846 12.954 46.508 8.199 46.154 6.836 36.888 11.921 37.846 12.954"/></svg>

Before

Width:  |  Height:  |  Size: 687 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 12"><defs><style>.a{fill:#8b5e3c;}.b{fill:#3c2415;}.c{fill:none;stroke:#754c29;stroke-linecap:round;stroke-miterlimit:10;}</style></defs><title>fedora</title><polygon class="a" points="38.548 9.742 38.264 4.844 41.403 5.223 42.508 1.407 47.846 5.918 46.334 7.664 38.548 9.742"/><path class="b" d="M41.133,8.362l1.1,0.236c1.9-1.066,3.844-2.051,4.741-3.392L45.78,4.193A22.044,22.044,0,0,1,41.133,8.362Z"/><path class="c" d="M37.233,11.3A12.1,12.1,0,0,1,40.4,9.09c1.7-.743,3.625-0.71,5.325-1.3a5.62,5.62,0,0,0,2.678-2.5"/></svg>

Before

Width:  |  Height:  |  Size: 581 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 14"><defs><style>.a{fill:#00aeef;}</style></defs><title>mask</title><path class="a" d="M43.5,0.94C42.329,1.2,39.032,3.75,39,4.531a21.249,21.249,0,0,0,3.5,1.811,10.847,10.847,0,0,0,4.065,0c0.751-.189,2.812-1.03,2.729-1.893-0.116-1.2-1.7-2.561-2.478-3.007A4.983,4.983,0,0,0,43.5.94Zm0.64,5.29a2.409,2.409,0,0,1-2.251-2.564,2.272,2.272,0,1,1,4.493,0A2.4,2.4,0,0,1,44.139,6.23Z"/><polygon class="a" points="38.996 4.531 42.106 9.154 40.018 13.776 38.996 4.531"/><polygon class="a" points="38.996 4.531 37.456 9.544 33.559 11.437 38.996 4.531"/></svg>

Before

Width:  |  Height:  |  Size: 602 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 11"><defs><style>.a{fill:#00aeef;}.b{fill:#ed1c24;}.c{fill:#fff200;}</style></defs><title>propeller</title><path class="a" d="M39.974,3.854c-2.022.99-2.948,3.89-1.509,6.828L40.716,9.56A10.329,10.329,0,0,1,39.974,3.854Z"/><path class="b" d="M39.974,3.854c1.975-.967,4.846-0.012,6.319,3L44.277,7.873A8.089,8.089,0,0,0,39.974,3.854Z"/><path class="c" d="M39.974,3.854a8.088,8.088,0,0,1,4.3,4.02l-3.55,1.71A10.011,10.011,0,0,1,39.974,3.854Z"/><path class="c" d="M35.795,4.493a3.81,3.81,0,0,1,1.016-.871A3.548,3.548,0,0,1,38.032,3.1a4.2,4.2,0,0,0,1.483-.434,9.15,9.15,0,0,0,1.245-.92A4.585,4.585,0,0,1,41.926,1.1a3.941,3.941,0,0,1,1.3-.3L43.364,1.1a3.941,3.941,0,0,1-1.031.84,4.585,4.585,0,0,1-1.219.53,9.149,9.149,0,0,0-1.49.419,4.194,4.194,0,0,0-1.252.905,3.549,3.549,0,0,1-1.164.642A3.81,3.81,0,0,1,35.9,4.7Z"/></svg>

Before

Width:  |  Height:  |  Size: 871 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 18"><defs><style>.a,.c{fill:#231f20;stroke:#231f20;}.a,.b,.c{stroke-linejoin:round;}.b{fill:#fff;stroke:#fff;}.c{stroke-linecap:round;}</style></defs><title>stovepipe</title><rect class="a" x="33.995" y="2.114" width="8.322" height="11.675" transform="translate(0.82 19.139) rotate(-28.453)"/><rect class="b" x="36.206" y="10.835" width="8.322" height="2.394" transform="translate(-0.856 20.686) rotate(-28.453)"/><line class="c" x1="35.164" y1="16.971" x2="47.341" y2="10.373"/></svg>

Before

Width:  |  Height:  |  Size: 541 B

View File

@@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path style="fill: #00c; stroke: #fff; stroke-width: 1px;" d="M2,15Q-1,15 0.5,12L6.5,1.7Q8,-1 9.5,1.7L15.5,12Q17,15 14,15z"></path>
<path style="fill: #fff;" d="m7,4.8v3.16l0.27,2.27h1.46l0.27,-2.27v-3.16z"></path>
<rect style="fill: #fff;" x="7" y="11" height="2" width="2"></rect>
</svg>

Before

Width:  |  Height:  |  Size: 363 B

View File

@@ -1,48 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
.customFieldsTurtleWidget {
width: 150px;
}
.customFieldsTurtleWidget button {
border-radius: 4px;
border: none;
background-color: #fff;
opacity: .6;
color: #000;
}
.customFieldsTurtleWidget .table {
width: 100%;
}
.customFieldsTurtleWidget .row {
width: 100%;
display: flex;
}
.customFieldsTurtleWidget .arrow {
text-align: center;
padding: 0;
flex-grow: 0;
}
.customFieldsTurtleWidget .text {
height: 20px;
color: #fff;
flex-grow: 1;
text-align: center;
}
.customFieldsTurtleWidget .randomize {
width: 100%;
}
.blocklySvg .blocklyNonEditableText text,
.blocklySvg .blocklyEditableText text {
fill: #000;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,49 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Fixed Blockly</title>
<script src="../../blockly_compressed.js"></script>
<script src="../../blocks_compressed.js"></script>
<script src="../../msg/js/en.js"></script>
<style>
body {
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Fixed Blockly</h1>
<p>This is a simple demo of injecting Blockly into a fixed-sized 'div' element.</p>
<p>&rarr; More info on <a href="https://developers.google.com/blockly/guides/configure-blockly/web/fixed-size">injecting fixed-sized Blockly</a>&hellip;</p>
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="controls_repeat_ext"></block>
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="text"></block>
<block type="text_print"></block>
</xml>
<script>
var demoWorkspace = Blockly.inject('blocklyDiv',
{media: '../../media/',
toolbox: document.getElementById('toolbox')});
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -1,148 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Generating JavaScript</title>
<script src="../../blockly_compressed.js"></script>
<script src="../../blocks_compressed.js"></script>
<script src="../../javascript_compressed.js"></script>
<script src="../../msg/js/en.js"></script>
<style>
body {
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Generating JavaScript</h1>
<p>This is a simple demo of generating code from blocks and running
the code in a sandboxed JavaScript interpreter.</p>
<p>&rarr; More info on <a href="https://developers.google.com/blockly/guides/configure/web/code-generators">Code Generators</a> and <a href="https://developers.google.com/blockly/guides/app-integration/running-javascript">Running JavaScript</a>.</p>
<p>
<button onclick="showCode()">Show JavaScript</button>
<button onclick="runCode()">Run JavaScript</button>
</p>
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
</category>
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
<field name="NUM">10</field>
</block>
</value>
</block>
<block type="controls_whileUntil"></block>
</category>
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
</category>
<category name="Text" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
</category>
</xml>
<xml xmlns="https://developers.google.com/blockly/xml" id="startBlocks" style="display: none">
<block type="controls_if" inline="false" x="20" y="20">
<mutation else="1"></mutation>
<value name="IF0">
<block type="logic_compare" inline="true">
<field name="OP">EQ</field>
<value name="A">
<block type="math_arithmetic" inline="true">
<field name="OP">MULTIPLY</field>
<value name="A">
<block type="math_number">
<field name="NUM">6</field>
</block>
</value>
<value name="B">
<block type="math_number">
<field name="NUM">7</field>
</block>
</value>
</block>
</value>
<value name="B">
<block type="math_number">
<field name="NUM">42</field>
</block>
</value>
</block>
</value>
<statement name="DO0">
<block type="text_print" inline="false">
<value name="TEXT">
<block type="text">
<field name="TEXT">Don't panic</field>
</block>
</value>
</block>
</statement>
<statement name="ELSE">
<block type="text_print" inline="false">
<value name="TEXT">
<block type="text">
<field name="TEXT">Panic</field>
</block>
</value>
</block>
</statement>
</block>
</xml>
<script>
var demoWorkspace = Blockly.inject('blocklyDiv',
{media: '../../media/',
toolbox: document.getElementById('toolbox')});
Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'),
demoWorkspace);
function showCode() {
// Generate JavaScript code and display it.
Blockly.JavaScript.INFINITE_LOOP_TRAP = null;
var code = Blockly.JavaScript.workspaceToCode(demoWorkspace);
alert(code);
}
function runCode() {
// Generate JavaScript code and run it.
window.LoopTrap = 1000;
Blockly.JavaScript.INFINITE_LOOP_TRAP =
'if (--window.LoopTrap === 0) throw "Infinite loop.";\n';
var code = Blockly.JavaScript.workspaceToCode(demoWorkspace);
Blockly.JavaScript.INFINITE_LOOP_TRAP = null;
try {
eval(code);
} catch (e) {
alert(e);
}
}
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,364 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Graph</title>
<script src="https://www.google.com/jsapi"></script>
<script src="../../blockly_compressed.js"></script>
<script src="../../blocks_compressed.js"></script>
<script src="../../javascript_compressed.js"></script>
<script src="../../msg/js/en.js"></script>
<style>
body {
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
#funcText {
margin-top: 1em;
margin-left: 1.5em;
font-family: sans-serif;
}
#funcText>img {
height: 3px;
width: 15px;
vertical-align: middle;
margin-right: .5em;
}
#y1 {
background-color: #36c;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Graph</h1>
<p>This is a demo of giving instant feedback as blocks are changed.</p>
<p>&rarr; More info on <a href="https://developers.google.com/blockly/guides/configure/web/code-generators#generating_code">Realtime generation</a>&hellip;</p>
<table>
<tr>
<td>
<div id="visualization" style="width: 400px"></div>
</td>
<td>
<div id="blocklyDiv" style="height: 400px"></div>
</td>
</tr>
</table>
<div id="funcText">
<img id="y1" src="../../media/1x1.gif">
...
</div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic">
<value name="A">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
<value name="B">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
</block>
<block type="math_single">
<value name="NUM">
<shadow type="math_number">
<field name="NUM">9</field>
</shadow>
</value>
</block>
<block type="math_trig">
<value name="NUM">
<shadow type="math_number">
<field name="NUM">45</field>
</shadow>
</value>
</block>
<block type="math_constant"></block>
<block type="math_number_property">
<value name="NUMBER_TO_CHECK">
<shadow type="math_number">
<field name="NUM">0</field>
</shadow>
</value>
</block>
<block type="math_round">
<value name="NUM">
<shadow type="math_number">
<field name="NUM">3.1</field>
</shadow>
</value>
</block>
<block type="math_modulo">
<value name="DIVIDEND">
<shadow type="math_number">
<field name="NUM">64</field>
</shadow>
</value>
<value name="DIVISOR">
<shadow type="math_number">
<field name="NUM">10</field>
</shadow>
</value>
</block>
<block type="math_constrain">
<value name="VALUE">
<shadow type="math_number">
<field name="NUM">50</field>
</shadow>
</value>
<value name="LOW">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
<value name="HIGH">
<shadow type="math_number">
<field name="NUM">100</field>
</shadow>
</value>
</block>
<block type="math_random_int">
<value name="FROM">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
<value name="TO">
<shadow type="math_number">
<field name="NUM">100</field>
</shadow>
</value>
</block>
<block type="math_random_float"></block>
<block type="math_atan2">
<value name="X">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
<value name="Y">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
</block>
</category>
<category name="Variables" colour="%{BKY_VARIABLES_HUE}">
<block type="graph_get_x"></block>
</category>
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
<block type="logic_ternary"></block>
</category>
</xml>
<xml xmlns="https://developers.google.com/blockly/xml" id="startBlocks" style="display: none">
<block type="graph_set_y" deletable="false" x="100" y="100">
<value name="VALUE">
<block type="math_arithmetic">
<field name="OP">POWER</field>
<value name="A">
<block type="graph_get_x"></block>
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
<value name="B">
<block type="math_number">
<field name="NUM">2</field>
</block>
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
</block>
</value>
</block>
</xml>
<script>
// Load the Google Chart Tools Visualization API and the chart package.
if (typeof google === 'object') {
google.load('visualization', '1', {packages: ['corechart']});
} else {
alert('Unable to load Google\'s chart API.\n' +
'Are you connected to the Internet?');
}
// Define the custom blocks and their JS generators.
Blockly.defineBlocksWithJsonArray([{
"type": "graph_get_x",
"message0": "x",
"output": "Number",
"colour": Blockly.Msg['VARIABLES_HUE'],
"tooltip": Blockly.Msg['VARIABLES_GET_TOOLTIP'],
"helpUrl": Blockly.Msg['VARIABLES_GET_HELPURL']
}]);
Blockly.JavaScript['graph_get_x'] = function(block) {
// x variable getter.
return ['x', Blockly.JavaScript.ORDER_ATOMIC];
};
Blockly.defineBlocksWithJsonArray([{
"type": "graph_set_y",
"message0": "y = %1",
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": "Number"
}
],
"colour": Blockly.Msg['VARIABLES_HUE'],
"tooltip": Blockly.Msg['VARIABLES_SET_TOOLTIP'],
"helpUrl": Blockly.Msg['VARIABLES_SET_HELPURL']
}]);
Blockly.JavaScript['graph_set_y'] = function(block) {
// y variable setter.
var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE',
Blockly.JavaScript.ORDER_ASSIGNMENT) || '';
return 'y = ' + argument0 + ';';
};
/**
* Create a namespace for the application.
*/
var Graph = {};
/**
* Main Blockly workspace.
* @type {Blockly.WorkspaceSvg}
*/
Graph.workspace = null;
/**
* Cached copy of the function string.
* @type {?string}
* @private
*/
Graph.oldFormula_ = null;
/**
* Drawing options for the Chart API.
* @type {!Object}
* @private
*/
Graph.options_ = {
//curveType: 'function',
width: 400, height: 400,
chartArea: {left: '10%', width: '85%', height: '85%'}
};
/**
* Visualize the graph of y = f(x) using Google Chart Tools.
* For more documentation on Google Chart Tools, see this linechart example:
* https://developers.google.com/chart/interactive/docs/gallery/linechart
*/
Graph.drawVisualization = function() {
var formula = Blockly.JavaScript.workspaceToCode(Graph.workspace);
if (formula === Graph.oldFormula_) {
// No change in the formula, don't recompute.
return;
}
Graph.oldFormula_ = formula;
// Create and populate the data table.
var data = google.visualization.arrayToDataTable(Graph.plot(formula));
// Create and draw the visualization, passing in the data and options.
new google.visualization.LineChart(document.getElementById('visualization')).
draw(data, Graph.options_);
// Create the "y = ..." label. Find the relevant part of the code.
formula = formula.substring(formula.indexOf('y = '));
formula = formula.substring(0, formula.indexOf(';'));
var funcText = document.getElementById('funcText');
funcText.replaceChild(document.createTextNode(formula), funcText.lastChild);
};
/**
* Plot points on the function y = f(x).
* @param {string} code JavaScript code.
* @return {!Array<!Array>} 2D Array of points on the graph.
*/
Graph.plot = function(code) {
// Initialize a table with two column headings.
var table = [];
var y;
// TODO: Improve range and scale of graph.
for (var x = -10; x <= 10; x = Math.round((x + 0.1) * 10) / 10) {
try {
eval(code);
} catch (e) {
y = NaN;
}
if (!isNaN(y)) {
// Prevent y from being displayed inconsistently, some in decimals, some
// in scientific notation, often when y has accumulated rounding errors.
y = Math.round(y * Math.pow(10, 14)) / Math.pow(10, 14);
table.push([x, y]);
}
}
// Add column heading to table.
if (table.length) {
table.unshift(['x', 'y']);
} else {
// If the table is empty, add a [0, 0] row to prevent graph error.
table.unshift(['x', 'y'], [0, 0]);
}
return table;
};
/**
* Force Blockly to resize into the available width.
*/
Graph.resize = function() {
var width = Math.max(window.innerWidth - 440, 250);
document.getElementById('blocklyDiv').style.width = width + 'px';
Blockly.svgResize(Graph.workspace);
};
/**
* Initialize Blockly and the graph. Called on page load.
*/
Graph.init = function() {
Graph.workspace = Blockly.inject('blocklyDiv',
{collapse: false,
disable: false,
media: '../../media/',
toolbox: document.getElementById('toolbox')});
Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'),
Graph.workspace);
Graph.workspace.clearUndo();
// When Blockly changes, update the graph.
Graph.workspace.addChangeListener(Graph.drawVisualization);
Graph.workspace.addChangeListener(Blockly.Events.disableOrphans);
Graph.resize();
};
window.addEventListener('load', Graph.init);
window.addEventListener('resize', Graph.resize);
</script>
</body>
</html>

View File

@@ -28,18 +28,6 @@
their own applications.</p>
<table>
<tr>
<td>
<a href="fixed/index.html">
<img src="fixed/icon.png" height=80 width=100>
</a>
</td>
<td>
<div><a href="fixed/index.html">Fixed Blockly</a></div>
<div>Inject Blockly into a page as a fixed element.</div>
</td>
</tr>
<tr>
<td>
<a href="resizable/index.html">
@@ -64,30 +52,6 @@
</td>
</tr>
<tr>
<td>
<a href="maxBlocks/index.html">
<img src="maxBlocks/icon.png" height=80 width=100>
</a>
</td>
<td>
<div><a href="maxBlocks/index.html">Maximum Block Limit</a></div>
<div>Limit the total number of blocks allowed (for academic exercises).</div>
</td>
</tr>
<tr>
<td>
<a href="generator/index.html">
<img src="generator/icon.png" height=80 width=100>
</a>
</td>
<td>
<div><a href="generator/index.html">Generate JavaScript</a></div>
<div>Turn blocks into code and execute it.</div>
</td>
</tr>
<tr>
<td>
<a href="headless/index.html">
@@ -100,31 +64,6 @@
</td>
</tr>
<tr>
<td>
<a href="interpreter/index.html">
<img src="interpreter/icon.png" height=80 width=100>
</a>
</td>
<td>
<div style="font-weight: bold">JS Interpreter</div>
<div>Demo #1: <a href="interpreter/step-execution.html">Step by step execution in JavaScript.</a></div>
<div>Demo #2: <a href="interpreter/async-execution.html">Asynchronous execution in JavaScript.</a></div>
</td>
</tr>
<tr>
<td>
<a href="graph/index.html">
<img src="graph/icon.png" height=80 width=100>
</a>
</td>
<td>
<div><a href="graph/index.html">Graph</a></div>
<div>Instant updates when blocks are changed.</div>
</td>
</tr>
<tr>
<td>
<a href="rtl/index.html">
@@ -137,30 +76,6 @@
</td>
</tr>
<tr>
<td>
<a href="custom-dialogs/index.html">
<img src="custom-dialogs/icon.png" height=80 width=100>
</a>
</td>
<td>
<div><a href="custom-dialogs/index.html">Custom Dialogs</a></div>
<div>Override Blockly browser dialogs with custom implementations.</div>
</td>
</tr>
<tr>
<td>
<a href="custom-fields/index.html">
<img src="custom-fields/turtle/icon.png" height=80 width=100>
</a>
</td>
<td>
<div><a href="custom-fields/index.html">Custom Fields</a></div>
<div>Implement a custom field.</div>
</td>
</tr>
<tr>
<td>
<a href="storage/index.html">

File diff suppressed because one or more lines are too long

View File

@@ -1,267 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Asynchronous Execution with JS Interpreter</title>
<script src="acorn_interpreter.js"></script>
<script src="../../blockly_compressed.js"></script>
<script src="../../blocks_compressed.js"></script>
<script src="../../javascript_compressed.js"></script>
<script src="../../msg/js/en.js"></script>
<script src="wait_block.js"></script>
<style>
body {
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Asynchronous Execution with JS Interpreter</h1>
<p>This is a demo of executing code asynchronously (e.g., waiting for delays or user input) using the JavaScript interpreter.</p>
<p>&rarr; <a href="https://developers.google.com/blockly/guides/configure-blockly/web/running-javascript#js_interpreter">More info on running code with JS Interpreter</a></p>
<p>
<button onclick="runCode()" id="runButton">Run JavaScript</button>
</p>
<div style="width: 100%">
<div id="blocklyDiv"
style="display: inline-block; height: 480px; width: 58%"></div>
<textarea id="output" disabled="disabled"
style="display: inline-block; height: 480px; width: 38%;">
</textarea>
</div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
</category>
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
<field name="NUM">10</field>
</block>
</value>
</block>
<block type="controls_whileUntil"></block>
</category>
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
</category>
<category name="Text" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
<block type="text_prompt_ext">
<value name="TEXT">
<block type="text"></block>
</value>
</block>
</category>
<sep></sep>
<category name="Variables" custom="VARIABLE" colour="%{BKY_VARIABLES_HUE}">
</category>
<category name="Functions" custom="PROCEDURE" colour="%{BKY_PROCEDURES_HUE}">
</category>
</xml>
<xml xmlns="https://developers.google.com/blockly/xml" id="startBlocks" style="display: none">
<block type="variables_set" id="set_n_initial" inline="true" x="20" y="20">
<field name="VAR">n</field>
<value name="VALUE">
<block type="math_number">
<field name="NUM">1</field>
</block>
</value>
<next>
<block type="controls_repeat_ext" id="repeat" inline="true">
<value name="TIMES">
<block type="math_number">
<field name="NUM">4</field>
</block>
</value>
<statement name="DO">
<block type="wait_seconds" id="wait">
<field name="SECONDS">1.0</field>
<next>
<block type="variables_set" id="set_n_update" inline="true">
<field name="VAR">n</field>
<value name="VALUE">
<block type="math_arithmetic" inline="true">
<field name="OP">MULTIPLY</field>
<value name="A">
<block type="variables_get">
<field name="VAR">n</field>
</block>
</value>
<value name="B">
<block type="math_number">
<field name="NUM">2</field>
</block>
</value>
</block>
</value>
<next>
<block type="text_print" id="print" inline="false">
<value name="TEXT">
<block type="variables_get">
<field name="VAR">n</field>
</block>
</value>
</block>
</next>
</block>
</next>
</block>
</statement>
</block>
</next>
</block>
</xml>
<script>
var demoWorkspace = Blockly.inject('blocklyDiv',
{media: '../../media/',
toolbox: document.getElementById('toolbox')});
Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'),
demoWorkspace);
// Exit is used to signal the end of a script.
Blockly.JavaScript.addReservedWords('exit');
var outputArea = document.getElementById('output');
var runButton = document.getElementById('runButton');
var myInterpreter = null;
var runner;
function initApi(interpreter, globalObject) {
// Add an API function for the alert() block, generated for "text_print" blocks.
var wrapper = function(text) {
text = text ? text.toString() : '';
outputArea.value = outputArea.value + '\n' + text;
};
interpreter.setProperty(globalObject, 'alert',
interpreter.createNativeFunction(wrapper));
// Add an API function for the prompt() block.
var wrapper = function(text) {
text = text ? text.toString() : '';
return interpreter.createPrimitive(prompt(text));
};
interpreter.setProperty(globalObject, 'prompt',
interpreter.createNativeFunction(wrapper));
// Add an API for the wait block. See wait_block.js
initInterpreterWaitForSeconds(interpreter, globalObject);
// Add an API function for highlighting blocks.
var wrapper = function(id) {
id = id ? id.toString() : '';
return interpreter.createPrimitive(highlightBlock(id));
};
interpreter.setProperty(globalObject, 'highlightBlock',
interpreter.createNativeFunction(wrapper));
}
var highlightPause = false;
var latestCode = '';
function highlightBlock(id) {
demoWorkspace.highlightBlock(id);
highlightPause = true;
}
function resetStepUi(clearOutput) {
demoWorkspace.highlightBlock(null);
highlightPause = false;
runButton.disabled = '';
if (clearOutput) {
outputArea.value = 'Program output:\n=================';
}
}
function generateCodeAndLoadIntoInterpreter() {
// Generate JavaScript code and parse it.
Blockly.JavaScript.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
Blockly.JavaScript.addReservedWords('highlightBlock');
latestCode = Blockly.JavaScript.workspaceToCode(demoWorkspace);
resetStepUi(true);
}
function resetInterpreter() {
myInterpreter = null;
if (runner) {
clearTimeout(runner);
runner = null;
}
}
function runCode() {
if (!myInterpreter) {
// First statement of this code.
// Clear the program output.
resetStepUi(true);
runButton.disabled = 'disabled';
// And then show generated code in an alert.
// In a timeout to allow the outputArea.value to reset first.
setTimeout(function() {
alert('Ready to execute the following code\n' +
'===================================\n' +
latestCode);
// Begin execution
highlightPause = false;
myInterpreter = new Interpreter(latestCode, initApi);
runner = function() {
if (myInterpreter) {
var hasMore = myInterpreter.run();
if (hasMore) {
// Execution is currently blocked by some async call.
// Try again later.
setTimeout(runner, 10);
} else {
// Program is complete.
outputArea.value += '\n\n<< Program complete >>';
resetInterpreter();
resetStepUi(false);
}
}
};
runner();
}, 1);
return;
}
}
// Load the interpreter now, and upon future changes.
generateCodeAndLoadIntoInterpreter();
demoWorkspace.addChangeListener(function(event) {
if (!(event instanceof Blockly.Events.Ui)) {
// Something changed. Parser needs to be reloaded.
resetInterpreter();
generateCodeAndLoadIntoInterpreter();
}
});
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Redirecting...</title>
<meta http-equiv="refresh" content="0;URL='step-execution.html'"/>
</head>
<body>
Redirecting to <a href="step-execution.html">step execution JS-Interpreter demo</a>.
</body>
</html>

View File

@@ -1,254 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Step Execution with JS Interpreter</title>
<script src="acorn_interpreter.js"></script>
<script src="../../blockly_compressed.js"></script>
<script src="../../blocks_compressed.js"></script>
<script src="../../javascript_compressed.js"></script>
<script src="../../msg/js/en.js"></script>
<style>
body {
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Step Execution with JS Interpreter</h1>
<p>This is a demo of executing code step-by-step with a sandboxed JavaScript interpreter.</p>
<p>The generator's <code>Blockly.JavaScript.STATEMENT_PREFIX</code> is assigned <code>'highlightBlock(%1);\n'</code>,
where <code>%1</code> is the block id. The call to <code>highlightBlock()</code> will highlight the identified block
and set the variable <code>highlightPause</code> to <code>true</code>.</p>
<p>"Parse JavaScript" will generate the code and load it into the interpreter. Then, each press of the
"Step JavaScript" button will run the interpreter one step until the <code>highlightPause</code> is true.
That is, until <code>highlightBlock()</code> has highlighted the block that will be executed on the next step.</p>
<p>&rarr; <a href="https://developers.google.com/blockly/guides/configure-blockly/web/running-javascript#js_interpreter">More info on running code with JS Interpreter</a></p>
<p>
<button onclick="stepCode()" id="stepButton">Step JavaScript</button>
</p>
<div style="width: 100%">
<div id="blocklyDiv"
style="display: inline-block; height: 480px; width: 58%"></div>
<textarea id="output" disabled="disabled"
style="display: inline-block; height: 480px; width: 38%;">
</textarea>
</div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
</category>
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
<field name="NUM">10</field>
</block>
</value>
</block>
<block type="controls_whileUntil"></block>
</category>
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
</category>
<category name="Text" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
<block type="text_prompt_ext">
<value name="TEXT">
<block type="text"></block>
</value>
</block>
</category>
<sep></sep>
<category name="Variables" custom="VARIABLE" colour="%{BKY_VARIABLES_HUE}">
</category>
<category name="Functions" custom="PROCEDURE" colour="%{BKY_PROCEDURES_HUE}">
</category>
</xml>
<xml xmlns="https://developers.google.com/blockly/xml" id="startBlocks" style="display: none">
<block type="variables_set" id="set_n_initial" inline="true" x="20" y="20">
<field name="VAR">n</field>
<value name="VALUE">
<block type="math_number">
<field name="NUM">1</field>
</block>
</value>
<next>
<block type="controls_repeat_ext" id="repeat" inline="true">
<value name="TIMES">
<block type="math_number">
<field name="NUM">4</field>
</block>
</value>
<statement name="DO">
<block type="variables_set" id="set_n_update" inline="true">
<field name="VAR">n</field>
<value name="VALUE">
<block type="math_arithmetic" inline="true">
<field name="OP">MULTIPLY</field>
<value name="A">
<block type="variables_get">
<field name="VAR">n</field>
</block>
</value>
<value name="B">
<block type="math_number">
<field name="NUM">2</field>
</block>
</value>
</block>
</value>
<next>
<block type="text_print" id="print">
<value name="TEXT">
<block type="variables_get">
<field name="VAR">n</field>
</block>
</value>
</block>
</next>
</block>
</statement>
</block>
</next>
</block>
</xml>
<script>
var demoWorkspace = Blockly.inject('blocklyDiv',
{media: '../../media/',
toolbox: document.getElementById('toolbox')});
Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'),
demoWorkspace);
var outputArea = document.getElementById('output');
var stepButton = document.getElementById('stepButton');
var myInterpreter = null;
function initApi(interpreter, globalObject) {
// Add an API function for the alert() block, generated for "text_print" blocks.
interpreter.setProperty(globalObject, 'alert',
interpreter.createNativeFunction(function(text) {
text = arguments.length ? text : '';
outputArea.value += '\n' + text;
}));
// Add an API function for the prompt() block.
var wrapper = function(text) {
return interpreter.createPrimitive(prompt(text));
};
interpreter.setProperty(globalObject, 'prompt',
interpreter.createNativeFunction(wrapper));
// Add an API function for highlighting blocks.
var wrapper = function(id) {
id = String(id || '');
return interpreter.createPrimitive(highlightBlock(id));
};
interpreter.setProperty(globalObject, 'highlightBlock',
interpreter.createNativeFunction(wrapper));
}
var highlightPause = false;
var latestCode = '';
function highlightBlock(id) {
demoWorkspace.highlightBlock(id);
highlightPause = true;
}
function resetStepUi(clearOutput) {
demoWorkspace.highlightBlock(null);
highlightPause = false;
if (clearOutput) {
outputArea.value = 'Program output:\n=================';
}
}
function generateCodeAndLoadIntoInterpreter() {
// Generate JavaScript code and parse it.
Blockly.JavaScript.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
Blockly.JavaScript.addReservedWords('highlightBlock');
latestCode = Blockly.JavaScript.workspaceToCode(demoWorkspace);
resetStepUi(true);
}
function stepCode() {
if (!myInterpreter) {
// First statement of this code.
// Clear the program output.
resetStepUi(true);
myInterpreter = new Interpreter(latestCode, initApi);
// And then show generated code in an alert.
// In a timeout to allow the outputArea.value to reset first.
setTimeout(function() {
alert('Ready to execute the following code\n' +
'===================================\n' + latestCode);
highlightPause = true;
stepCode();
}, 1);
return;
}
highlightPause = false;
do {
try {
var hasMoreCode = myInterpreter.step();
} finally {
if (!hasMoreCode) {
// Program complete, no more code to execute.
outputArea.value += '\n\n<< Program complete >>';
myInterpreter = null;
resetStepUi(false);
// Cool down, to discourage accidentally restarting the program.
stepButton.disabled = 'disabled';
setTimeout(function() {
stepButton.disabled = '';
}, 2000);
return;
}
}
// Keep executing until a highlight statement is reached,
// or the code completes or errors.
} while (hasMoreCode && !highlightPause);
}
// Load the interpreter now, and upon future changes.
generateCodeAndLoadIntoInterpreter();
demoWorkspace.addChangeListener(function(event) {
if (!(event instanceof Blockly.Events.Ui)) {
// Something changed. Parser needs to be reloaded.
generateCodeAndLoadIntoInterpreter();
}
});
</script>
</body>
</html>

View File

@@ -1,53 +0,0 @@
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Example "wait" block that will pause the interpreter for a
* number of seconds. Because wait is a blocking behavior, such blocks will
* only work in interpreted environments.
*
* See https://neil.fraser.name/software/JS-Interpreter/docs.html
*/
Blockly.defineBlocksWithJsonArray([{
"type": "wait_seconds",
"message0": " wait %1 seconds",
"args0": [{
"type": "field_number",
"name": "SECONDS",
"min": 0,
"max": 600,
"value": 1
}],
"previousStatement": null,
"nextStatement": null,
"colour": "%{BKY_LOOPS_HUE}"
}]);
/**
* Generator for wait block creates call to new method
* <code>waitForSeconds()</code>.
*/
Blockly.JavaScript['wait_seconds'] = function(block) {
var seconds = Number(block.getFieldValue('SECONDS'));
var code = 'waitForSeconds(' + seconds + ');\n';
return code;
};
/**
* Register the interpreter asynchronous function
* <code>waitForSeconds()</code>.
*/
function initInterpreterWaitForSeconds(interpreter, globalObject) {
// Ensure function name does not conflict with variable names.
Blockly.JavaScript.addReservedWords('waitForSeconds');
var wrapper = interpreter.createAsyncFunction(
function(timeInSeconds, callback) {
// Delay the call to the callback.
setTimeout(callback, timeInSeconds * 1000);
});
interpreter.setProperty(globalObject, 'waitForSeconds', wrapper);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,100 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Maximum Block Limit</title>
<script src="../../blockly_compressed.js"></script>
<script src="../../blocks_compressed.js"></script>
<script src="../../msg/js/en.js"></script>
<style>
body {
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
#capacity {
color: red;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Maximum Block Limit</h1>
<p>This is a demo of Blockly which has been restricted to a maximum of
five blocks.</p>
<p><b>You have <span id="capacity"></span> block(s) left.</b></p>
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
</category>
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
<field name="NUM">10</field>
</block>
</value>
</block>
<block type="controls_whileUntil"></block>
<block type="controls_for">
<field name="VAR">i</field>
<value name="FROM">
<block type="math_number">
<field name="NUM">1</field>
</block>
</value>
<value name="TO">
<block type="math_number">
<field name="NUM">10</field>
</block>
</value>
<value name="BY">
<block type="math_number">
<field name="NUM">1</field>
</block>
</value>
</block>
</category>
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
</category>
<category name="Text" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
</category>
</xml>
<script>
var demoWorkspace = Blockly.inject('blocklyDiv',
{media: '../../media/',
maxBlocks: 5,
toolbox: document.getElementById('toolbox')});
function onchange(event) {
document.getElementById('capacity').textContent =
demoWorkspace.remainingCapacity();
}
demoWorkspace.addChangeListener(onchange);
onchange();
</script>
</body>
</html>