mirror of
https://github.com/google/blockly.git
synced 2025-12-15 13:50:08 +01:00
1281 lines
40 KiB
HTML
1281 lines
40 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<title>Blockly Playground</title>
|
|
|
|
<script type="module">
|
|
import {COMPRESSED, loadScript} from './scripts/load.mjs';
|
|
|
|
import * as Blockly from '../build/blockly.loader.mjs';
|
|
import '../build/blocks.loader.mjs';
|
|
import {dartGenerator} from '../build/dart.loader.mjs';
|
|
import {luaGenerator} from '../build/lua.loader.mjs';
|
|
import {javascriptGenerator} from '../build/javascript.loader.mjs';
|
|
import {phpGenerator} from '../build/php.loader.mjs';
|
|
import {pythonGenerator} from '../build/python.loader.mjs';
|
|
|
|
await loadScript('../build/msg/en.js');
|
|
await loadScript('playgrounds/screenshot.js');
|
|
await loadScript('../node_modules/@blockly/dev-tools/dist/index.js');
|
|
|
|
var workspace = null;
|
|
|
|
function start() {
|
|
setBackgroundColour();
|
|
|
|
// Parse the URL arguments.
|
|
var match = location.search.match(/dir=([^&]+)/);
|
|
var rtl = match && match[1] == 'rtl';
|
|
document.forms.options.elements.dir.selectedIndex = Number(rtl);
|
|
var toolbox = getToolboxElement();
|
|
setToolboxDropdown();
|
|
match = location.search.match(/side=([^&]+)/);
|
|
var autoimport = !!location.search.match(/autoimport=([^&]+)/);
|
|
// Create main workspace.
|
|
workspace = Blockly.inject('blocklyDiv', {
|
|
comments: true,
|
|
collapse: true,
|
|
disable: true,
|
|
grid: {
|
|
spacing: 25,
|
|
length: 3,
|
|
colour: '#ccc',
|
|
snap: true,
|
|
},
|
|
horizontalLayout: false,
|
|
maxBlocks: Infinity,
|
|
maxInstances: {'test_basic_limit_instances': 3},
|
|
maxTrashcanContents: 256,
|
|
media: '../media/',
|
|
oneBasedIndex: true,
|
|
readOnly: false,
|
|
rtl: rtl,
|
|
move: {
|
|
scrollbars: true,
|
|
drag: true,
|
|
wheel: false,
|
|
},
|
|
toolbox: toolbox,
|
|
toolboxPosition: 'start',
|
|
renderer: 'geras',
|
|
zoom: {
|
|
controls: true,
|
|
wheel: true,
|
|
startScale: 1.0,
|
|
maxScale: 4,
|
|
minScale: 0.25,
|
|
scaleSpeed: 1.1,
|
|
},
|
|
});
|
|
initToolbox(workspace);
|
|
|
|
workspace.configureContextMenu = configureContextMenu;
|
|
Blockly.ContextMenuItems.registerCommentOptions();
|
|
|
|
// Restore previously displayed text.
|
|
if (sessionStorage) {
|
|
var text = sessionStorage.getItem('textarea');
|
|
if (text) {
|
|
document.getElementById('importExport').value = text;
|
|
}
|
|
// Restore event logging state.
|
|
var logMainEventsState = sessionStorage.getItem('logEvents');
|
|
logEvents(Boolean(Number(logMainEventsState)));
|
|
var logToolboxFlyoutEventsState =
|
|
sessionStorage.getItem('logFlyoutEvents');
|
|
logFlyoutEvents(Boolean(Number(logToolboxFlyoutEventsState)));
|
|
} else {
|
|
// MSIE 11 does not support sessionStorage on file:// URLs.
|
|
logEvents(false);
|
|
}
|
|
taChange();
|
|
if (autoimport) {
|
|
load();
|
|
}
|
|
|
|
addEventHandlers();
|
|
}
|
|
|
|
/**
|
|
* Set background colour to differentiate between compressed and
|
|
* uncompressed mode.
|
|
*/
|
|
function setBackgroundColour() {
|
|
if (!COMPRESSED) {
|
|
document.body.style.backgroundColor = '#d6d6ff'; // Familiar lilac.
|
|
} else {
|
|
document.body.style.backgroundColor = '#60fcfc'; // Unfamiliar blue.
|
|
}
|
|
}
|
|
|
|
function getToolboxSuffix() {
|
|
var match = location.search.match(/toolbox=([^&]+)/);
|
|
// Default to the basic toolbox with categories and untyped variables,
|
|
// but override that if the toolbox type is set in the URL.
|
|
return match ? match[1] : 'categories';
|
|
}
|
|
|
|
function getToolboxElement() {
|
|
var toolboxSuffix = getToolboxSuffix();
|
|
if (toolboxSuffix == 'test-blocks') {
|
|
if (typeof window.toolboxTestBlocks !== 'undefined') {
|
|
return toolboxTestBlocks;
|
|
} else {
|
|
alert(
|
|
"You need to run 'npm install' in order to use the test blocks.",
|
|
);
|
|
toolboxSuffix = 'categories';
|
|
}
|
|
}
|
|
// The three possible values are: "simple", "categories",
|
|
// "categories-typed-variables".
|
|
return document.getElementById('toolbox-' + toolboxSuffix);
|
|
}
|
|
|
|
function setToolboxDropdown() {
|
|
var toolboxNames = [
|
|
'toolbox-categories',
|
|
'toolbox-categories-typed-variables',
|
|
'toolbox-simple',
|
|
'toolbox-test-blocks',
|
|
];
|
|
var toolboxSuffix = getToolboxSuffix();
|
|
document.forms.options.elements.toolbox.selectedIndex =
|
|
toolboxNames.indexOf('toolbox-' + toolboxSuffix);
|
|
}
|
|
|
|
function initToolbox(workspace) {
|
|
var toolboxSuffix = getToolboxSuffix();
|
|
if (
|
|
toolboxSuffix == 'test-blocks' &&
|
|
typeof window.toolboxTestBlocksInit !== 'undefined'
|
|
) {
|
|
toolboxTestBlocksInit(workspace);
|
|
}
|
|
}
|
|
|
|
function saveXml() {
|
|
var output = document.getElementById('importExport');
|
|
var xml = Blockly.Xml.workspaceToDom(workspace);
|
|
output.value = Blockly.Xml.domToPrettyText(xml);
|
|
output.focus();
|
|
output.select();
|
|
taChange();
|
|
}
|
|
|
|
function saveJson() {
|
|
var output = document.getElementById('importExport');
|
|
var state = Blockly.serialization.workspaces.save(workspace);
|
|
output.value = JSON.stringify(state, null, 2);
|
|
output.focus();
|
|
output.select();
|
|
taChange();
|
|
}
|
|
|
|
function load() {
|
|
var input = document.getElementById('importExport');
|
|
if (!input.value) {
|
|
return;
|
|
}
|
|
var valid = saveIsValid(input.value);
|
|
if (valid.json) {
|
|
var state = JSON.parse(input.value);
|
|
Blockly.serialization.workspaces.load(state, workspace);
|
|
} else if (valid.xml) {
|
|
var xml = Blockly.utils.xml.textToDom(input.value);
|
|
Blockly.Xml.domToWorkspace(xml, workspace);
|
|
}
|
|
taChange();
|
|
}
|
|
|
|
function toCode(lang) {
|
|
var generator = {
|
|
'JavaScript': javascriptGenerator,
|
|
'Python': pythonGenerator,
|
|
'PHP': phpGenerator,
|
|
'Lua': luaGenerator,
|
|
'Dart': dartGenerator,
|
|
}[lang];
|
|
var output = document.getElementById('importExport');
|
|
output.value = generator.workspaceToCode(workspace);
|
|
taChange();
|
|
}
|
|
|
|
// Disable the "Load" button if the save state is invalid.
|
|
// Preserve text between page reloads.
|
|
function taChange() {
|
|
var textarea = document.getElementById('importExport');
|
|
if (sessionStorage) {
|
|
sessionStorage.setItem('textarea', textarea.value);
|
|
}
|
|
var valid = saveIsValid(textarea.value);
|
|
document.getElementById('import').disabled = !valid.json && !valid.xml;
|
|
}
|
|
|
|
function saveIsValid(save) {
|
|
var validJson = true;
|
|
try {
|
|
JSON.parse(save);
|
|
} catch (e) {
|
|
validJson = false;
|
|
}
|
|
var validXml = true;
|
|
try {
|
|
Blockly.utils.xml.textToDom(save);
|
|
} catch (e) {
|
|
validXml = false;
|
|
}
|
|
return {
|
|
json: validJson,
|
|
xml: validXml,
|
|
};
|
|
}
|
|
|
|
function logEvents(state) {
|
|
var checkbox = document.getElementById('logCheck');
|
|
checkbox.checked = state;
|
|
if (sessionStorage) {
|
|
sessionStorage.setItem('logEvents', Number(state));
|
|
}
|
|
if (state) {
|
|
workspace.addChangeListener(logger);
|
|
} else {
|
|
workspace.removeChangeListener(logger);
|
|
}
|
|
}
|
|
|
|
function logFlyoutEvents(state) {
|
|
var checkbox = document.getElementById('logFlyoutCheck');
|
|
checkbox.checked = state;
|
|
if (sessionStorage) {
|
|
sessionStorage.setItem('logFlyoutEvents', Number(state));
|
|
}
|
|
var flyoutWorkspace = workspace.getFlyout()?.getWorkspace();
|
|
if (!flyoutWorkspace) return;
|
|
if (state) {
|
|
flyoutWorkspace.addChangeListener(logger);
|
|
} else {
|
|
flyoutWorkspace.removeChangeListener(logger);
|
|
}
|
|
}
|
|
|
|
function configureContextMenu(menuOptions, e) {
|
|
var screenshotOption = {
|
|
text: 'Download Screenshot',
|
|
enabled: workspace.getTopBlocks().length,
|
|
callback: function () {
|
|
downloadScreenshot(workspace);
|
|
},
|
|
};
|
|
menuOptions.push(screenshotOption);
|
|
}
|
|
|
|
function logger(e) {
|
|
console.log(e);
|
|
}
|
|
|
|
function scatter(n) {
|
|
var prototypes = [];
|
|
var toolbox = getToolboxElement();
|
|
var blocks = toolbox.getElementsByTagName('block');
|
|
for (var i = 0, block; (block = blocks[i]); i++) {
|
|
prototypes.push(block.getAttribute('type'));
|
|
}
|
|
for (var i = 0; i < n; i++) {
|
|
var prototype =
|
|
prototypes[Math.floor(Math.random() * prototypes.length)];
|
|
var block = workspace.newBlock(prototype);
|
|
block.initSvg();
|
|
block
|
|
.getSvgRoot()
|
|
.setAttribute(
|
|
'transform',
|
|
'translate(' +
|
|
Math.round(Math.random() * 450 + 40) +
|
|
', ' +
|
|
Math.round(Math.random() * 600 + 40) +
|
|
')',
|
|
);
|
|
block.render();
|
|
}
|
|
}
|
|
|
|
function spaghetti(n) {
|
|
var xml = spaghettiXml;
|
|
for (var i = 0; i < n; i++) {
|
|
xml = xml.replace(
|
|
/(<(statement|next)( name="DO0")?>)<\//g,
|
|
'$1' + spaghettiXml + '</',
|
|
);
|
|
}
|
|
xml =
|
|
'<xml xmlns="https://developers.google.com/blockly/xml">' +
|
|
xml +
|
|
'</xml>';
|
|
var dom = Blockly.utils.xml.textToDom(xml);
|
|
console.time('Spaghetti domToWorkspace');
|
|
Blockly.Xml.domToWorkspace(dom, workspace);
|
|
console.timeEnd('Spaghetti domToWorkspace');
|
|
}
|
|
var spaghettiXml = [
|
|
' <block type="controls_if">',
|
|
' <value name="IF0">',
|
|
' <block type="logic_compare">',
|
|
' <field name="OP">EQ</field>',
|
|
' <value name="A">',
|
|
' <block type="math_arithmetic">',
|
|
' <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"></statement>',
|
|
' <next></next>',
|
|
' </block>',
|
|
].join('\n');
|
|
|
|
function jsoSpaghetti(n) {
|
|
var str = spaghettiJs;
|
|
for (var i = 0; i < n; i++) {
|
|
str = str.replace(/{}/g, `{"block":${spaghettiJs}}`);
|
|
}
|
|
var obj = {
|
|
'blocks': {
|
|
'blocks': [JSON.parse(str)],
|
|
},
|
|
};
|
|
console.time('Spaghetti serialization');
|
|
Blockly.serialization.workspaces.load(obj, workspace);
|
|
console.timeEnd('Spaghetti serialization');
|
|
}
|
|
var spaghettiJs = JSON.stringify({
|
|
'type': 'controls_if',
|
|
'inputs': {
|
|
'IF0': {
|
|
'block': {
|
|
'type': 'logic_compare',
|
|
'fields': {
|
|
'OP': 'EQ',
|
|
},
|
|
'inputs': {
|
|
'A': {
|
|
'block': {
|
|
'type': 'math_arithmetic',
|
|
'fields': {
|
|
'OP': 'MULTIPLY',
|
|
},
|
|
'inputs': {
|
|
'A': {
|
|
'block': {
|
|
'type': 'math_number',
|
|
'fields': {
|
|
'NUM': 6,
|
|
},
|
|
},
|
|
},
|
|
'B': {
|
|
'block': {
|
|
'type': 'math_number',
|
|
'fields': {
|
|
'NUM': 7,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'B': {
|
|
'block': {
|
|
'type': 'math_number',
|
|
'fields': {
|
|
'NUM': 42,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'DO0': {},
|
|
},
|
|
'next': {},
|
|
});
|
|
|
|
function addEventHandlers() {
|
|
document
|
|
.getElementById('save-json')
|
|
.addEventListener('click', saveJson);
|
|
document.getElementById('save-xml').addEventListener('click', saveXml);
|
|
document.getElementById('import').addEventListener('click', load);
|
|
|
|
document
|
|
.getElementById('to-code-js')
|
|
.addEventListener('click', () => toCode('JavaScript'));
|
|
document
|
|
.getElementById('to-code-py')
|
|
.addEventListener('click', () => toCode('Python'));
|
|
document
|
|
.getElementById('to-code-php')
|
|
.addEventListener('click', () => toCode('PHP'));
|
|
document
|
|
.getElementById('to-code-lua')
|
|
.addEventListener('click', () => toCode('Lua'));
|
|
document
|
|
.getElementById('to-code-dart')
|
|
.addEventListener('click', () => toCode('Dart'));
|
|
|
|
document
|
|
.getElementById('scatter')
|
|
.addEventListener('click', () => scatter(100));
|
|
document
|
|
.getElementById('spaghetti-xml')
|
|
.addEventListener('click', () => spaghetti(8));
|
|
document
|
|
.getElementById('spaghetti-js')
|
|
.addEventListener('click', () => jsoSpaghetti(8));
|
|
|
|
document
|
|
.getElementById('logCheck')
|
|
.addEventListener('click', function () {
|
|
logEvents(this.checked);
|
|
});
|
|
document
|
|
.getElementById('logFlyoutCheck')
|
|
.addEventListener('click', function () {
|
|
logFlyoutEvents(this.checked);
|
|
});
|
|
|
|
document
|
|
.getElementById('importExport')
|
|
.addEventListener('change', taChange);
|
|
document
|
|
.getElementById('importExport')
|
|
.addEventListener('keyup', taChange);
|
|
|
|
document.getElementById('show').addEventListener('click', function () {
|
|
workspace.setVisible(true);
|
|
});
|
|
document.getElementById('hide').addEventListener('click', function () {
|
|
workspace.setVisible(false);
|
|
});
|
|
}
|
|
|
|
// Call start(). Because this <script> has type=module, it is
|
|
// automatically deferred, so it will not be run until after the
|
|
// document has been parsed, but before firing DOMContentLoaded.
|
|
start();
|
|
</script>
|
|
|
|
<style>
|
|
html,
|
|
body {
|
|
height: 100%;
|
|
}
|
|
body {
|
|
background-color: #fff;
|
|
font-family: sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
h1 {
|
|
font-weight: normal;
|
|
font-size: 140%;
|
|
}
|
|
#blocklyDiv {
|
|
float: right;
|
|
height: 95%;
|
|
width: 70%;
|
|
}
|
|
#importExport {
|
|
font-family: monospace;
|
|
}
|
|
|
|
.ioLabel > .blocklyFlyoutLabelText {
|
|
font-style: italic;
|
|
}
|
|
|
|
#blocklyDiv.renderingDebug .blockRenderDebug {
|
|
display: block;
|
|
}
|
|
|
|
.playgroundToggleOptions {
|
|
list-style: none;
|
|
padding: 0;
|
|
}
|
|
.playgroundToggleOptions li {
|
|
margin-top: 1em;
|
|
}
|
|
|
|
.zelos-renderer .blocklyFlyoutButton .blocklyText {
|
|
font-size: 1.5rem;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="blocklyDiv"></div>
|
|
|
|
<h1>Blockly Playground</h1>
|
|
|
|
<p>
|
|
<input id="show" type="button" value="Show" /> -
|
|
<input id="hide" type="button" value="Hide" /> -
|
|
<a href="playgrounds/advanced_playground.html">Advanced</a>
|
|
</p>
|
|
|
|
<form id="options">
|
|
<select name="dir" onchange="document.forms.options.submit()">
|
|
<option value="ltr">LTR</option>
|
|
<option value="rtl">RTL</option>
|
|
</select>
|
|
<select name="toolbox" onchange="document.forms.options.submit()">
|
|
<option value="categories">Categories (untyped variables)</option>
|
|
<option value="categories-typed-variables">
|
|
Categories (typed variables)
|
|
</option>
|
|
<option value="simple">Simple</option>
|
|
<option value="test-blocks">Test Blocks</option>
|
|
</select>
|
|
</form>
|
|
<p>
|
|
<input id="save-json" type="button" value="Save JSON" />
|
|
<input id="save-xml" type="button" value="Save XML" />
|
|
<input type="button" value="Load" id="import" />
|
|
<br />
|
|
<input id="to-code-js" type="button" value="To JavaScript" />
|
|
<input id="to-code-py" type="button" value="To Python" />
|
|
<input id="to-code-php" type="button" value="To PHP" />
|
|
<input id="to-code-lua" type="button" value="To Lua" />
|
|
<input id="to-code-dart" type="button" value="To Dart" />
|
|
<br />
|
|
<textarea id="importExport" style="width: 26%; height: 12em"></textarea>
|
|
</p>
|
|
|
|
<p>
|
|
Stress test:
|
|
<input id="scatter" type="button" value="Scatter!" />
|
|
<input id="spaghetti-xml" type="button" value="Spaghetti!" />
|
|
<input id="spaghetti-js" type="button" value="JS Spaghetti!" />
|
|
</p>
|
|
<ul class="playgroundToggleOptions">
|
|
<li>
|
|
<label for="logCheck">Log main workspace events:</label>
|
|
<input type="checkbox" id="logCheck" />
|
|
</li>
|
|
<li>
|
|
<label for="logFlyoutCheck">Log flyout events:</label>
|
|
<input type="checkbox" id="logFlyoutCheck" />
|
|
</li>
|
|
</ul>
|
|
|
|
<!-- The next three blocks of XML are sample toolboxes for testing basic
|
|
configurations. For more information on building toolboxes, see https://developers.google.com/blockly/guides/configure/web/toolbox -->
|
|
|
|
<!-- toolbox-simple is an always-open flyout with no category menu.
|
|
Always-open flyouts are a good idea if you have a small number of blocks. -->
|
|
<xml
|
|
xmlns="https://developers.google.com/blockly/xml"
|
|
id="toolbox-simple"
|
|
style="display: none">
|
|
<block type="controls_ifelse"></block>
|
|
<block type="logic_compare"></block>
|
|
<!-- <block type="control_repeat"></block> -->
|
|
<block type="logic_operation"></block>
|
|
<block type="controls_repeat_ext">
|
|
<value name="TIMES">
|
|
<shadow type="math_number">
|
|
<field name="NUM">10</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="logic_operation"></block>
|
|
<block type="logic_negate"></block>
|
|
<block type="logic_boolean"></block>
|
|
<block type="logic_null" disabled="true"></block>
|
|
<block type="logic_ternary"></block>
|
|
<block type="text_charAt">
|
|
<value name="VALUE">
|
|
<block type="variables_get">
|
|
<field name="VAR">text</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
</xml>
|
|
|
|
<!-- toolbox-categories has a category menu and an auto-closing flyout. The
|
|
Variables category uses untyped variable blocks.
|
|
See https://developers.google.com/blockly/guides/create-custom-blocks/variables#untyped_variable_blocks for more information. -->
|
|
<xml
|
|
xmlns="https://developers.google.com/blockly/xml"
|
|
id="toolbox-categories"
|
|
style="display: none">
|
|
<category name="Logic" categorystyle="logic_category">
|
|
<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>
|
|
<block type="logic_null" disabled="true"></block>
|
|
<block type="logic_ternary"></block>
|
|
</category>
|
|
<category name="Loops" categorystyle="loop_category">
|
|
<block type="controls_repeat_ext">
|
|
<value name="TIMES">
|
|
<shadow type="math_number">
|
|
<field name="NUM">10</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="controls_repeat" disabled="true"></block>
|
|
<block type="controls_whileUntil"></block>
|
|
<block type="controls_for">
|
|
<value name="FROM">
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="TO">
|
|
<shadow type="math_number">
|
|
<field name="NUM">10</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="BY">
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="controls_forEach"></block>
|
|
<block type="controls_flow_statements"></block>
|
|
</category>
|
|
<category name="Math" categorystyle="math_category">
|
|
<block type="math_number" gap="32">
|
|
<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_on_list"></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="Text" categorystyle="text_category">
|
|
<block type="text"></block>
|
|
<block type="text_join"></block>
|
|
<block type="text_append">
|
|
<value name="TEXT">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_length">
|
|
<value name="VALUE">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_isEmpty">
|
|
<value name="VALUE">
|
|
<shadow type="text">
|
|
<field name="TEXT"></field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_indexOf">
|
|
<value name="VALUE">
|
|
<block type="variables_get">
|
|
<field name="VAR">text</field>
|
|
</block>
|
|
</value>
|
|
<value name="FIND">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_charAt">
|
|
<value name="VALUE">
|
|
<block type="variables_get">
|
|
<field name="VAR">text</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="text_getSubstring">
|
|
<value name="STRING">
|
|
<block type="variables_get">
|
|
<field name="VAR">text</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="text_changeCase">
|
|
<value name="TEXT">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_trim">
|
|
<value name="TEXT">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_count">
|
|
<value name="SUB">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
<value name="TEXT">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_replace">
|
|
<value name="FROM">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
<value name="TO">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
<value name="TEXT">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_reverse">
|
|
<value name="TEXT">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
</block>
|
|
<label text="Input/Output:" web-class="ioLabel"></label>
|
|
<block type="text_print">
|
|
<value name="TEXT">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_prompt_ext">
|
|
<value name="TEXT">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
</category>
|
|
<category name="Lists" categorystyle="list_category">
|
|
<block type="lists_create_with">
|
|
<mutation items="0"></mutation>
|
|
</block>
|
|
<block type="lists_create_with"></block>
|
|
<block type="lists_repeat">
|
|
<value name="NUM">
|
|
<shadow type="math_number">
|
|
<field name="NUM">5</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="lists_length"></block>
|
|
<block type="lists_isEmpty"></block>
|
|
<block type="lists_indexOf">
|
|
<value name="VALUE">
|
|
<block type="variables_get">
|
|
<field name="VAR">list</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="lists_getIndex">
|
|
<value name="VALUE">
|
|
<block type="variables_get">
|
|
<field name="VAR">list</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="lists_setIndex">
|
|
<value name="LIST">
|
|
<block type="variables_get">
|
|
<field name="VAR">list</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="lists_getSublist">
|
|
<value name="LIST">
|
|
<block type="variables_get">
|
|
<field name="VAR">list</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="lists_split">
|
|
<value name="DELIM">
|
|
<shadow type="text">
|
|
<field name="TEXT">,</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="lists_sort"></block>
|
|
<block type="lists_reverse"></block>
|
|
</category>
|
|
<sep></sep>
|
|
<category
|
|
name="Variables"
|
|
categorystyle="variable_category"
|
|
custom="VARIABLE"></category>
|
|
<category
|
|
name="Functions"
|
|
categorystyle="procedure_category"
|
|
custom="PROCEDURE"></category>
|
|
</xml>
|
|
|
|
<!-- toolbox-categories-typed-variables has a category menu and an
|
|
auto-closing flyout. The Variables category uses typed variable blocks.
|
|
See https://developers.google.com/blockly/guides/create-custom-blocks/variables#typed_variable_blocks for more information. -->
|
|
<xml
|
|
xmlns="https://developers.google.com/blockly/xml"
|
|
id="toolbox-categories-typed-variables"
|
|
style="display: none">
|
|
<category name="Logic" categorystyle="logic_category">
|
|
<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>
|
|
<block type="logic_null" disabled="true"></block>
|
|
<block type="logic_ternary"></block>
|
|
</category>
|
|
<category name="Loops" categorystyle="loop_category">
|
|
<block type="controls_repeat_ext">
|
|
<value name="TIMES">
|
|
<shadow type="math_number">
|
|
<field name="NUM">10</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="controls_repeat" disabled="true"></block>
|
|
<block type="controls_whileUntil"></block>
|
|
<block type="controls_for">
|
|
<value name="FROM">
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="TO">
|
|
<shadow type="math_number">
|
|
<field name="NUM">10</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="BY">
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="controls_forEach"></block>
|
|
<block type="controls_flow_statements"></block>
|
|
</category>
|
|
<category name="Math" categorystyle="math_category">
|
|
<block type="math_number" gap="32">
|
|
<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_on_list"></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="Text" categorystyle="text_category">
|
|
<block type="text"></block>
|
|
<block type="text_join"></block>
|
|
<block type="text_append">
|
|
<value name="TEXT">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_length">
|
|
<value name="VALUE">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_isEmpty">
|
|
<value name="VALUE">
|
|
<shadow type="text">
|
|
<field name="TEXT"></field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_indexOf">
|
|
<value name="VALUE">
|
|
<block type="variables_get">
|
|
<field name="VAR">text</field>
|
|
</block>
|
|
</value>
|
|
<value name="FIND">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_charAt">
|
|
<value name="VALUE">
|
|
<block type="variables_get">
|
|
<field name="VAR">text</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="text_getSubstring">
|
|
<value name="STRING">
|
|
<block type="variables_get">
|
|
<field name="VAR">text</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="text_changeCase">
|
|
<value name="TEXT">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_trim">
|
|
<value name="TEXT">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_count">
|
|
<value name="SUB">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
<value name="TEXT">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_replace">
|
|
<value name="FROM">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
<value name="TO">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
<value name="TEXT">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_reverse">
|
|
<value name="TEXT">
|
|
<shadow type="text"></shadow>
|
|
</value>
|
|
</block>
|
|
<label text="Input/Output:" web-class="ioLabel"></label>
|
|
<block type="text_print">
|
|
<value name="TEXT">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="text_prompt_ext">
|
|
<value name="TEXT">
|
|
<shadow type="text">
|
|
<field name="TEXT">abc</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
</category>
|
|
<category name="Lists" categorystyle="list_category">
|
|
<block type="lists_create_with">
|
|
<mutation items="0"></mutation>
|
|
</block>
|
|
<block type="lists_create_with"></block>
|
|
<block type="lists_repeat">
|
|
<value name="NUM">
|
|
<shadow type="math_number">
|
|
<field name="NUM">5</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="lists_length"></block>
|
|
<block type="lists_isEmpty"></block>
|
|
<block type="lists_indexOf">
|
|
<value name="VALUE">
|
|
<block type="variables_get">
|
|
<field name="VAR">list</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="lists_getIndex">
|
|
<value name="VALUE">
|
|
<block type="variables_get">
|
|
<field name="VAR">list</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="lists_setIndex">
|
|
<value name="LIST">
|
|
<block type="variables_get">
|
|
<field name="VAR">list</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="lists_getSublist">
|
|
<value name="LIST">
|
|
<block type="variables_get">
|
|
<field name="VAR">list</field>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
<block type="lists_split">
|
|
<value name="DELIM">
|
|
<shadow type="text">
|
|
<field name="TEXT">,</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="lists_sort"></block>
|
|
<block type="lists_reverse"></block>
|
|
</category>
|
|
<category name="Colour" categorystyle="colour_category">
|
|
<block type="colour_picker"></block>
|
|
<block type="colour_random"></block>
|
|
<block type="colour_rgb">
|
|
<value name="RED">
|
|
<shadow type="math_number">
|
|
<field name="NUM">100</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="GREEN">
|
|
<shadow type="math_number">
|
|
<field name="NUM">50</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="BLUE">
|
|
<shadow type="math_number">
|
|
<field name="NUM">0</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="colour_blend">
|
|
<value name="COLOUR1">
|
|
<shadow type="colour_picker">
|
|
<field name="COLOUR">#ff0000</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="COLOUR2">
|
|
<shadow type="colour_picker">
|
|
<field name="COLOUR">#3333ff</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="RATIO">
|
|
<shadow type="math_number">
|
|
<field name="NUM">0.5</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
</category>
|
|
<sep></sep>
|
|
<category
|
|
name="Variables"
|
|
categorystyle="variable_category"
|
|
custom="VARIABLE_DYNAMIC"></category>
|
|
<category
|
|
name="Functions"
|
|
categorystyle="procedure_category"
|
|
custom="PROCEDURE"></category>
|
|
</xml>
|
|
</body>
|
|
</html>
|